xref: /xnu-11417.121.6/iokit/Kernel/IONVRAMV3Handler.cpp (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1*a1e26a70SApple OSS Distributions /*
2*a1e26a70SApple OSS Distributions  * Copyright (c) 2021-2022 Apple Inc. All rights reserved.
3*a1e26a70SApple OSS Distributions  *
4*a1e26a70SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*a1e26a70SApple OSS Distributions  *
6*a1e26a70SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*a1e26a70SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*a1e26a70SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*a1e26a70SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*a1e26a70SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*a1e26a70SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*a1e26a70SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*a1e26a70SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*a1e26a70SApple OSS Distributions  *
15*a1e26a70SApple OSS Distributions  * Please obtain a copy of the License at
16*a1e26a70SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*a1e26a70SApple OSS Distributions  *
18*a1e26a70SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*a1e26a70SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*a1e26a70SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*a1e26a70SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*a1e26a70SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*a1e26a70SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*a1e26a70SApple OSS Distributions  * limitations under the License.
25*a1e26a70SApple OSS Distributions  *
26*a1e26a70SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*a1e26a70SApple OSS Distributions  */
28*a1e26a70SApple OSS Distributions 
29*a1e26a70SApple OSS Distributions #include <libkern/libkern.h>
30*a1e26a70SApple OSS Distributions 
31*a1e26a70SApple OSS Distributions #define VARIABLE_STORE_SIGNATURE         'NVV3'
32*a1e26a70SApple OSS Distributions 
33*a1e26a70SApple OSS Distributions // Variable Store Version
34*a1e26a70SApple OSS Distributions #define VARIABLE_STORE_VERSION           0x1
35*a1e26a70SApple OSS Distributions 
36*a1e26a70SApple OSS Distributions #define VARIABLE_DATA                    0x55AA
37*a1e26a70SApple OSS Distributions #define INVALIDATED_VARIABLE_DATA        0x0000
38*a1e26a70SApple OSS Distributions 
39*a1e26a70SApple OSS Distributions // Variable State flags
40*a1e26a70SApple OSS Distributions #define VAR_IN_DELETED_TRANSITION     0xFE  // Variable is in obsolete transistion
41*a1e26a70SApple OSS Distributions #define VAR_DELETED                   0xFD  // Variable is obsolete
42*a1e26a70SApple OSS Distributions #define VAR_INACTIVE                  0xFB  // Variable is inactive due to failing CRC
43*a1e26a70SApple OSS Distributions #define VAR_ADDED                     0x7F  // Variable has been completely added
44*a1e26a70SApple OSS Distributions 
45*a1e26a70SApple OSS Distributions // No changes needed on save
46*a1e26a70SApple OSS Distributions #define VAR_NEW_STATE_NONE            0x01
47*a1e26a70SApple OSS Distributions // Remove existing entry on save
48*a1e26a70SApple OSS Distributions #define VAR_NEW_STATE_REMOVE          0x02
49*a1e26a70SApple OSS Distributions // Add new value on save, mark previous as inactive
50*a1e26a70SApple OSS Distributions #define VAR_NEW_STATE_APPEND          0x03
51*a1e26a70SApple OSS Distributions 
52*a1e26a70SApple OSS Distributions #pragma pack(1)
53*a1e26a70SApple OSS Distributions struct v3_store_header {
54*a1e26a70SApple OSS Distributions 	uint32_t     name;
55*a1e26a70SApple OSS Distributions 	uint32_t     size;
56*a1e26a70SApple OSS Distributions 	uint32_t     generation;
57*a1e26a70SApple OSS Distributions 	uint8_t      state;
58*a1e26a70SApple OSS Distributions 	uint8_t      flags;
59*a1e26a70SApple OSS Distributions 	uint8_t      version;
60*a1e26a70SApple OSS Distributions 	uint8_t      reserved1;
61*a1e26a70SApple OSS Distributions 	uint32_t     system_size;
62*a1e26a70SApple OSS Distributions 	uint32_t     common_size;
63*a1e26a70SApple OSS Distributions };
64*a1e26a70SApple OSS Distributions 
65*a1e26a70SApple OSS Distributions struct v3_var_header {
66*a1e26a70SApple OSS Distributions 	uint16_t     startId;
67*a1e26a70SApple OSS Distributions 	uint8_t      state;
68*a1e26a70SApple OSS Distributions 	uint8_t      reserved;
69*a1e26a70SApple OSS Distributions 	uint32_t     attributes;
70*a1e26a70SApple OSS Distributions 	uint32_t     nameSize;
71*a1e26a70SApple OSS Distributions 	uint32_t     dataSize;
72*a1e26a70SApple OSS Distributions 	uuid_t       guid;
73*a1e26a70SApple OSS Distributions 	uint32_t     crc;
74*a1e26a70SApple OSS Distributions 	uint8_t      name_data_buf[];
75*a1e26a70SApple OSS Distributions };
76*a1e26a70SApple OSS Distributions #pragma pack()
77*a1e26a70SApple OSS Distributions 
78*a1e26a70SApple OSS Distributions struct nvram_v3_var_entry {
79*a1e26a70SApple OSS Distributions 	uint8_t                new_state;
80*a1e26a70SApple OSS Distributions 	size_t                 existing_offset;
81*a1e26a70SApple OSS Distributions 	struct v3_var_header   header;
82*a1e26a70SApple OSS Distributions };
83*a1e26a70SApple OSS Distributions 
84*a1e26a70SApple OSS Distributions static size_t
nvram_v3_var_container_size(const struct v3_var_header * header)85*a1e26a70SApple OSS Distributions nvram_v3_var_container_size(const struct v3_var_header *header)
86*a1e26a70SApple OSS Distributions {
87*a1e26a70SApple OSS Distributions 	return sizeof(struct nvram_v3_var_entry) + header->nameSize + header->dataSize;
88*a1e26a70SApple OSS Distributions }
89*a1e26a70SApple OSS Distributions 
90*a1e26a70SApple OSS Distributions static size_t
variable_length(const struct v3_var_header * header)91*a1e26a70SApple OSS Distributions variable_length(const struct v3_var_header *header)
92*a1e26a70SApple OSS Distributions {
93*a1e26a70SApple OSS Distributions 	return sizeof(struct v3_var_header) + header->nameSize + header->dataSize;
94*a1e26a70SApple OSS Distributions }
95*a1e26a70SApple OSS Distributions 
96*a1e26a70SApple OSS Distributions static bool
valid_store_header(const struct v3_store_header * header)97*a1e26a70SApple OSS Distributions valid_store_header(const struct v3_store_header *header)
98*a1e26a70SApple OSS Distributions {
99*a1e26a70SApple OSS Distributions 	return (header->name == VARIABLE_STORE_SIGNATURE) && (header->version == VARIABLE_STORE_VERSION);
100*a1e26a70SApple OSS Distributions }
101*a1e26a70SApple OSS Distributions 
102*a1e26a70SApple OSS Distributions static bool
valid_variable_header(const struct v3_var_header * header,size_t buf_len)103*a1e26a70SApple OSS Distributions valid_variable_header(const struct v3_var_header *header, size_t buf_len)
104*a1e26a70SApple OSS Distributions {
105*a1e26a70SApple OSS Distributions 	return (buf_len > sizeof(struct v3_var_header)) &&
106*a1e26a70SApple OSS Distributions 	       (header->startId == VARIABLE_DATA) &&
107*a1e26a70SApple OSS Distributions 	       (variable_length(header) <= buf_len);
108*a1e26a70SApple OSS Distributions }
109*a1e26a70SApple OSS Distributions 
110*a1e26a70SApple OSS Distributions static uint32_t
find_active_var_in_image(const struct v3_var_header * var,const uint8_t * image,uint32_t offset,uint32_t len)111*a1e26a70SApple OSS Distributions find_active_var_in_image(const struct v3_var_header *var, const uint8_t *image, uint32_t offset, uint32_t len)
112*a1e26a70SApple OSS Distributions {
113*a1e26a70SApple OSS Distributions 	const struct v3_var_header *store_var;
114*a1e26a70SApple OSS Distributions 	uint32_t var_offset = 0;
115*a1e26a70SApple OSS Distributions 
116*a1e26a70SApple OSS Distributions 	while ((offset + sizeof(struct v3_var_header) < len)) {
117*a1e26a70SApple OSS Distributions 		store_var = (const struct v3_var_header *)(image + offset);
118*a1e26a70SApple OSS Distributions 
119*a1e26a70SApple OSS Distributions 		if (valid_variable_header(store_var, len - offset)) {
120*a1e26a70SApple OSS Distributions 			if ((store_var->state == VAR_ADDED) &&
121*a1e26a70SApple OSS Distributions 			    (uuid_compare(var->guid, store_var->guid) == 0) &&
122*a1e26a70SApple OSS Distributions 			    (var->nameSize == store_var->nameSize) &&
123*a1e26a70SApple OSS Distributions 			    (memcmp(var->name_data_buf, store_var->name_data_buf, var->nameSize) == 0)) {
124*a1e26a70SApple OSS Distributions 				var_offset = offset;
125*a1e26a70SApple OSS Distributions 				break;
126*a1e26a70SApple OSS Distributions 			}
127*a1e26a70SApple OSS Distributions 		} else {
128*a1e26a70SApple OSS Distributions 			break;
129*a1e26a70SApple OSS Distributions 		}
130*a1e26a70SApple OSS Distributions 
131*a1e26a70SApple OSS Distributions 		offset += variable_length(store_var);
132*a1e26a70SApple OSS Distributions 	}
133*a1e26a70SApple OSS Distributions 
134*a1e26a70SApple OSS Distributions 	return var_offset;
135*a1e26a70SApple OSS Distributions }
136*a1e26a70SApple OSS Distributions 
137*a1e26a70SApple OSS Distributions static IOReturn
find_current_offset_in_image(const uint8_t * image,uint32_t len,uint32_t * newOffset)138*a1e26a70SApple OSS Distributions find_current_offset_in_image(const uint8_t *image, uint32_t len, uint32_t *newOffset)
139*a1e26a70SApple OSS Distributions {
140*a1e26a70SApple OSS Distributions 	uint32_t offset = 0;
141*a1e26a70SApple OSS Distributions 	uint32_t inner_offset = 0;
142*a1e26a70SApple OSS Distributions 
143*a1e26a70SApple OSS Distributions 	if (valid_store_header((const struct v3_store_header *)(image + offset))) {
144*a1e26a70SApple OSS Distributions 		DEBUG_INFO("valid store header @ %#x\n", offset);
145*a1e26a70SApple OSS Distributions 		offset += sizeof(struct v3_store_header);
146*a1e26a70SApple OSS Distributions 	}
147*a1e26a70SApple OSS Distributions 
148*a1e26a70SApple OSS Distributions 	while (offset < len) {
149*a1e26a70SApple OSS Distributions 		const struct v3_var_header *store_var = (const struct v3_var_header *)(image + offset);
150*a1e26a70SApple OSS Distributions 		uuid_string_t uuidString;
151*a1e26a70SApple OSS Distributions 
152*a1e26a70SApple OSS Distributions 		if (valid_variable_header(store_var, len - offset)) {
153*a1e26a70SApple OSS Distributions 			uuid_unparse(store_var->guid, uuidString);
154*a1e26a70SApple OSS Distributions 			DEBUG_INFO("Valid var @ %#08x, state=%#02x, length=%#08zx, %s:%s\n", offset, store_var->state,
155*a1e26a70SApple OSS Distributions 			    variable_length(store_var), uuidString, store_var->name_data_buf);
156*a1e26a70SApple OSS Distributions 			offset += variable_length(store_var);
157*a1e26a70SApple OSS Distributions 		} else {
158*a1e26a70SApple OSS Distributions 			break;
159*a1e26a70SApple OSS Distributions 		}
160*a1e26a70SApple OSS Distributions 	}
161*a1e26a70SApple OSS Distributions 
162*a1e26a70SApple OSS Distributions 	while (offset < len) {
163*a1e26a70SApple OSS Distributions 		if (image[offset] == 0xFF) {
164*a1e26a70SApple OSS Distributions 			DEBUG_INFO("scanning for clear memory @ %#x\n", offset);
165*a1e26a70SApple OSS Distributions 
166*a1e26a70SApple OSS Distributions 			inner_offset = offset;
167*a1e26a70SApple OSS Distributions 
168*a1e26a70SApple OSS Distributions 			while ((inner_offset < len) && (image[inner_offset] == 0xFF)) {
169*a1e26a70SApple OSS Distributions 				inner_offset++;
170*a1e26a70SApple OSS Distributions 			}
171*a1e26a70SApple OSS Distributions 
172*a1e26a70SApple OSS Distributions 			if (inner_offset == len) {
173*a1e26a70SApple OSS Distributions 				DEBUG_INFO("found start of clear mem @ %#x\n", offset);
174*a1e26a70SApple OSS Distributions 				break;
175*a1e26a70SApple OSS Distributions 			} else {
176*a1e26a70SApple OSS Distributions 				DEBUG_ERROR("ERROR!!!!! found non-clear byte @ %#x\n", offset);
177*a1e26a70SApple OSS Distributions 				return kIOReturnInvalid;
178*a1e26a70SApple OSS Distributions 			}
179*a1e26a70SApple OSS Distributions 		}
180*a1e26a70SApple OSS Distributions 		offset++;
181*a1e26a70SApple OSS Distributions 	}
182*a1e26a70SApple OSS Distributions 
183*a1e26a70SApple OSS Distributions 	*newOffset = offset;
184*a1e26a70SApple OSS Distributions 
185*a1e26a70SApple OSS Distributions 	return kIOReturnSuccess;
186*a1e26a70SApple OSS Distributions }
187*a1e26a70SApple OSS Distributions 
188*a1e26a70SApple OSS Distributions class IONVRAMV3Handler : public IODTNVRAMFormatHandler, IOTypedOperatorsMixin<IONVRAMV3Handler>
189*a1e26a70SApple OSS Distributions {
190*a1e26a70SApple OSS Distributions private:
191*a1e26a70SApple OSS Distributions 	IONVRAMController            *_nvramController;
192*a1e26a70SApple OSS Distributions 	IODTNVRAM                    *_provider;
193*a1e26a70SApple OSS Distributions 
194*a1e26a70SApple OSS Distributions 	bool                         _newData;
195*a1e26a70SApple OSS Distributions 	bool                         _resetData;
196*a1e26a70SApple OSS Distributions 	bool                         _reload;
197*a1e26a70SApple OSS Distributions 
198*a1e26a70SApple OSS Distributions 	bool                         _rawController;
199*a1e26a70SApple OSS Distributions 
200*a1e26a70SApple OSS Distributions 	uint32_t                     _generation;
201*a1e26a70SApple OSS Distributions 
202*a1e26a70SApple OSS Distributions 	uint8_t                      *_nvramImage;
203*a1e26a70SApple OSS Distributions 
204*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSDictionary>    _varDict;
205*a1e26a70SApple OSS Distributions 
206*a1e26a70SApple OSS Distributions 	uint32_t                     _commonSize;
207*a1e26a70SApple OSS Distributions 	uint32_t                     _systemSize;
208*a1e26a70SApple OSS Distributions 
209*a1e26a70SApple OSS Distributions 	uint32_t                     _commonUsed;
210*a1e26a70SApple OSS Distributions 	uint32_t                     _systemUsed;
211*a1e26a70SApple OSS Distributions 
212*a1e26a70SApple OSS Distributions 	uint32_t                     _currentOffset;
213*a1e26a70SApple OSS Distributions 
214*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSArray>         _varEntries;
215*a1e26a70SApple OSS Distributions 
216*a1e26a70SApple OSS Distributions 	IORWLock                     *_variableLock;
217*a1e26a70SApple OSS Distributions 	IOLock                       *_controllerLock;
218*a1e26a70SApple OSS Distributions 
219*a1e26a70SApple OSS Distributions 	IOReturn unserializeImage(const uint8_t *image, IOByteCount length);
220*a1e26a70SApple OSS Distributions 	IOReturn reclaim(void);
221*a1e26a70SApple OSS Distributions 	uint32_t findCurrentBank(void);
222*a1e26a70SApple OSS Distributions 	size_t   getAppendSize(void);
223*a1e26a70SApple OSS Distributions 
224*a1e26a70SApple OSS Distributions 	static bool convertObjectToProp(uint8_t *buffer, uint32_t *length, const char *propSymbol, OSObject *propObject);
225*a1e26a70SApple OSS Distributions 	static bool convertPropToObject(const uint8_t *propName, uint32_t propNameLength, const uint8_t *propData, uint32_t propDataLength,
226*a1e26a70SApple OSS Distributions 	    OSSharedPtr<const OSSymbol>& propSymbol, OSSharedPtr<OSObject>& propObject);
227*a1e26a70SApple OSS Distributions 
228*a1e26a70SApple OSS Distributions 	IOReturn reloadInternal(void);
229*a1e26a70SApple OSS Distributions 	IOReturn setVariableInternal(const uuid_t varGuid, const char *variableName, OSObject *object);
230*a1e26a70SApple OSS Distributions 
231*a1e26a70SApple OSS Distributions 	void setEntryForRemove(struct nvram_v3_var_entry *v3Entry, bool system);
232*a1e26a70SApple OSS Distributions 	void findExistingEntry(const uuid_t varGuid, const char *varName, struct nvram_v3_var_entry **existing, unsigned int *existingIndex);
233*a1e26a70SApple OSS Distributions 	IOReturn syncRaw(void);
234*a1e26a70SApple OSS Distributions 	IOReturn syncBlock(void);
235*a1e26a70SApple OSS Distributions 	IOReturn handleEphDM(void);
236*a1e26a70SApple OSS Distributions 
237*a1e26a70SApple OSS Distributions public:
238*a1e26a70SApple OSS Distributions 	virtual
239*a1e26a70SApple OSS Distributions 	~IONVRAMV3Handler() APPLE_KEXT_OVERRIDE;
240*a1e26a70SApple OSS Distributions 	IONVRAMV3Handler();
241*a1e26a70SApple OSS Distributions 	static bool isValidImage(const uint8_t *image, IOByteCount length);
242*a1e26a70SApple OSS Distributions 	static  IONVRAMV3Handler *init(IODTNVRAM *provider, const uint8_t *image, IOByteCount length);
243*a1e26a70SApple OSS Distributions 
244*a1e26a70SApple OSS Distributions 	virtual bool     getNVRAMProperties(void) APPLE_KEXT_OVERRIDE;
245*a1e26a70SApple OSS Distributions 	virtual IOReturn unserializeVariables(void) APPLE_KEXT_OVERRIDE;
246*a1e26a70SApple OSS Distributions 	virtual IOReturn setVariable(const uuid_t varGuid, const char *variableName, OSObject *object) APPLE_KEXT_OVERRIDE;
247*a1e26a70SApple OSS Distributions 	virtual bool     setController(IONVRAMController *controller) APPLE_KEXT_OVERRIDE;
248*a1e26a70SApple OSS Distributions 	virtual IOReturn sync(void) APPLE_KEXT_OVERRIDE;
249*a1e26a70SApple OSS Distributions 	virtual IOReturn flush(const uuid_t guid, IONVRAMOperation op) APPLE_KEXT_OVERRIDE;
250*a1e26a70SApple OSS Distributions 	virtual void     reload(void) APPLE_KEXT_OVERRIDE;
251*a1e26a70SApple OSS Distributions 	virtual uint32_t getGeneration(void) const APPLE_KEXT_OVERRIDE;
252*a1e26a70SApple OSS Distributions 	virtual uint32_t getVersion(void) const APPLE_KEXT_OVERRIDE;
253*a1e26a70SApple OSS Distributions 	virtual uint32_t getSystemUsed(void) const APPLE_KEXT_OVERRIDE;
254*a1e26a70SApple OSS Distributions 	virtual uint32_t getCommonUsed(void) const APPLE_KEXT_OVERRIDE;
255*a1e26a70SApple OSS Distributions 	virtual bool     getSystemPartitionActive(void) const APPLE_KEXT_OVERRIDE;
256*a1e26a70SApple OSS Distributions 	virtual IOReturn getVarDict(OSSharedPtr<OSDictionary> &varDictCopy) APPLE_KEXT_OVERRIDE;
257*a1e26a70SApple OSS Distributions };
258*a1e26a70SApple OSS Distributions 
~IONVRAMV3Handler()259*a1e26a70SApple OSS Distributions IONVRAMV3Handler::~IONVRAMV3Handler()
260*a1e26a70SApple OSS Distributions {
261*a1e26a70SApple OSS Distributions }
262*a1e26a70SApple OSS Distributions 
IONVRAMV3Handler()263*a1e26a70SApple OSS Distributions IONVRAMV3Handler::IONVRAMV3Handler()
264*a1e26a70SApple OSS Distributions {
265*a1e26a70SApple OSS Distributions }
266*a1e26a70SApple OSS Distributions 
267*a1e26a70SApple OSS Distributions bool
isValidImage(const uint8_t * image,IOByteCount length)268*a1e26a70SApple OSS Distributions IONVRAMV3Handler::isValidImage(const uint8_t *image, IOByteCount length)
269*a1e26a70SApple OSS Distributions {
270*a1e26a70SApple OSS Distributions 	const struct v3_store_header *header = (const struct v3_store_header *)image;
271*a1e26a70SApple OSS Distributions 
272*a1e26a70SApple OSS Distributions 	if ((header == nullptr) || (length < sizeof(*header))) {
273*a1e26a70SApple OSS Distributions 		return false;
274*a1e26a70SApple OSS Distributions 	}
275*a1e26a70SApple OSS Distributions 
276*a1e26a70SApple OSS Distributions 	return valid_store_header(header);
277*a1e26a70SApple OSS Distributions }
278*a1e26a70SApple OSS Distributions 
279*a1e26a70SApple OSS Distributions IONVRAMV3Handler*
init(IODTNVRAM * provider,const uint8_t * image,IOByteCount length)280*a1e26a70SApple OSS Distributions IONVRAMV3Handler::init(IODTNVRAM *provider, const uint8_t *image, IOByteCount length)
281*a1e26a70SApple OSS Distributions {
282*a1e26a70SApple OSS Distributions 	OSSharedPtr<IORegistryEntry> entry;
283*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSObject>        prop;
284*a1e26a70SApple OSS Distributions 	bool                         propertiesOk;
285*a1e26a70SApple OSS Distributions 
286*a1e26a70SApple OSS Distributions 	IONVRAMV3Handler *handler = new IONVRAMV3Handler();
287*a1e26a70SApple OSS Distributions 
288*a1e26a70SApple OSS Distributions 	handler->_provider = provider;
289*a1e26a70SApple OSS Distributions 
290*a1e26a70SApple OSS Distributions 	handler->_variableLock = IORWLockAlloc();
291*a1e26a70SApple OSS Distributions 	require(handler->_variableLock != nullptr, exit);
292*a1e26a70SApple OSS Distributions 
293*a1e26a70SApple OSS Distributions 	handler->_controllerLock = IOLockAlloc();
294*a1e26a70SApple OSS Distributions 	require(handler->_controllerLock != nullptr, exit);
295*a1e26a70SApple OSS Distributions 
296*a1e26a70SApple OSS Distributions 	propertiesOk = handler->getNVRAMProperties();
297*a1e26a70SApple OSS Distributions 	require_action(propertiesOk, exit, DEBUG_ERROR("Unable to get NVRAM properties\n"));
298*a1e26a70SApple OSS Distributions 
299*a1e26a70SApple OSS Distributions 	require_action(length == handler->_bankSize, exit, DEBUG_ERROR("length %#llx != _bankSize %#x\n", length, handler->_bankSize));
300*a1e26a70SApple OSS Distributions 
301*a1e26a70SApple OSS Distributions 	if ((image != nullptr) && (length != 0)) {
302*a1e26a70SApple OSS Distributions 		if (handler->unserializeImage(image, length) != kIOReturnSuccess) {
303*a1e26a70SApple OSS Distributions 			DEBUG_ERROR("Unable to unserialize image, len=%#x\n", (unsigned int)length);
304*a1e26a70SApple OSS Distributions 		}
305*a1e26a70SApple OSS Distributions 	}
306*a1e26a70SApple OSS Distributions 
307*a1e26a70SApple OSS Distributions 	return handler;
308*a1e26a70SApple OSS Distributions 
309*a1e26a70SApple OSS Distributions exit:
310*a1e26a70SApple OSS Distributions 	delete handler;
311*a1e26a70SApple OSS Distributions 
312*a1e26a70SApple OSS Distributions 	return nullptr;
313*a1e26a70SApple OSS Distributions }
314*a1e26a70SApple OSS Distributions 
315*a1e26a70SApple OSS Distributions bool
getNVRAMProperties()316*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getNVRAMProperties()
317*a1e26a70SApple OSS Distributions {
318*a1e26a70SApple OSS Distributions 	bool                         ok    = false;
319*a1e26a70SApple OSS Distributions 	const char                   *rawControllerKey = "nvram-raw";
320*a1e26a70SApple OSS Distributions 	OSSharedPtr<IORegistryEntry> entry;
321*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSObject>        prop;
322*a1e26a70SApple OSS Distributions 	OSData *                     data;
323*a1e26a70SApple OSS Distributions 
324*a1e26a70SApple OSS Distributions 	require_action(IODTNVRAMFormatHandler::getNVRAMProperties(), exit, DEBUG_ERROR("parent getNVRAMProperties failed\n"));
325*a1e26a70SApple OSS Distributions 
326*a1e26a70SApple OSS Distributions 	entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
327*a1e26a70SApple OSS Distributions 	require_action(entry, exit, DEBUG_ERROR("Unable to find chosen node\n"));
328*a1e26a70SApple OSS Distributions 
329*a1e26a70SApple OSS Distributions 	prop = entry->copyProperty(rawControllerKey);
330*a1e26a70SApple OSS Distributions 	require_action(prop != nullptr, exit, DEBUG_ERROR("No %s entry\n", rawControllerKey));
331*a1e26a70SApple OSS Distributions 
332*a1e26a70SApple OSS Distributions 	data = OSDynamicCast(OSData, prop.get());
333*a1e26a70SApple OSS Distributions 	require(data != nullptr, exit);
334*a1e26a70SApple OSS Distributions 
335*a1e26a70SApple OSS Distributions 	_rawController = *((uint32_t*)data->getBytesNoCopy());
336*a1e26a70SApple OSS Distributions 	DEBUG_INFO("_rawController = %d\n", _rawController);
337*a1e26a70SApple OSS Distributions 
338*a1e26a70SApple OSS Distributions 	ok = true;
339*a1e26a70SApple OSS Distributions 
340*a1e26a70SApple OSS Distributions exit:
341*a1e26a70SApple OSS Distributions 	return ok;
342*a1e26a70SApple OSS Distributions }
343*a1e26a70SApple OSS Distributions 
344*a1e26a70SApple OSS Distributions IOReturn
flush(const uuid_t guid,IONVRAMOperation op)345*a1e26a70SApple OSS Distributions IONVRAMV3Handler::flush(const uuid_t guid, IONVRAMOperation op)
346*a1e26a70SApple OSS Distributions {
347*a1e26a70SApple OSS Distributions 	IOReturn ret = kIOReturnSuccess;
348*a1e26a70SApple OSS Distributions 	bool     flushSystem;
349*a1e26a70SApple OSS Distributions 	bool     flushCommon;
350*a1e26a70SApple OSS Distributions 
351*a1e26a70SApple OSS Distributions 	flushSystem = getSystemPartitionActive() && (uuid_compare(guid, gAppleSystemVariableGuid) == 0);
352*a1e26a70SApple OSS Distributions 	flushCommon = uuid_compare(guid, gAppleNVRAMGuid) == 0;
353*a1e26a70SApple OSS Distributions 
354*a1e26a70SApple OSS Distributions 	DEBUG_INFO("flushSystem=%d, flushCommon=%d\n", flushSystem, flushCommon);
355*a1e26a70SApple OSS Distributions 
356*a1e26a70SApple OSS Distributions 	NVRAMWRITELOCK(_variableLock);
357*a1e26a70SApple OSS Distributions 	if (flushSystem || flushCommon) {
358*a1e26a70SApple OSS Distributions 		const OSSymbol                    *canonicalKey;
359*a1e26a70SApple OSS Distributions 		OSSharedPtr<OSDictionary>         dictCopy;
360*a1e26a70SApple OSS Distributions 		OSSharedPtr<OSCollectionIterator> iter;
361*a1e26a70SApple OSS Distributions 		uuid_string_t                     uuidString;
362*a1e26a70SApple OSS Distributions 
363*a1e26a70SApple OSS Distributions 		dictCopy = OSDictionary::withDictionary(_varDict.get());
364*a1e26a70SApple OSS Distributions 		iter = OSCollectionIterator::withCollection(dictCopy.get());
365*a1e26a70SApple OSS Distributions 		require_action(dictCopy && iter, exit, ret = kIOReturnNoMemory);
366*a1e26a70SApple OSS Distributions 
367*a1e26a70SApple OSS Distributions 		while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
368*a1e26a70SApple OSS Distributions 			const char *varName;
369*a1e26a70SApple OSS Distributions 			uuid_t     varGuid;
370*a1e26a70SApple OSS Distributions 			bool       clear;
371*a1e26a70SApple OSS Distributions 
372*a1e26a70SApple OSS Distributions 			parseVariableName(canonicalKey->getCStringNoCopy(), &varGuid, &varName);
373*a1e26a70SApple OSS Distributions 
374*a1e26a70SApple OSS Distributions 			uuid_unparse(varGuid, uuidString);
375*a1e26a70SApple OSS Distributions 
376*a1e26a70SApple OSS Distributions 			clear = ((flushSystem && (uuid_compare(varGuid, gAppleSystemVariableGuid) == 0)) ||
377*a1e26a70SApple OSS Distributions 			    (flushCommon && (uuid_compare(varGuid, gAppleSystemVariableGuid) != 0))) &&
378*a1e26a70SApple OSS Distributions 			    verifyPermission(op, varGuid, varName, getSystemPartitionActive());
379*a1e26a70SApple OSS Distributions 
380*a1e26a70SApple OSS Distributions 			if (clear) {
381*a1e26a70SApple OSS Distributions 				DEBUG_INFO("Clearing entry for %s:%s\n", uuidString, varName);
382*a1e26a70SApple OSS Distributions 				setVariableInternal(varGuid, varName, nullptr);
383*a1e26a70SApple OSS Distributions 			} else {
384*a1e26a70SApple OSS Distributions 				DEBUG_INFO("Keeping entry for %s:%s\n", uuidString, varName);
385*a1e26a70SApple OSS Distributions 			}
386*a1e26a70SApple OSS Distributions 		}
387*a1e26a70SApple OSS Distributions 
388*a1e26a70SApple OSS Distributions 		_newData = true;
389*a1e26a70SApple OSS Distributions 	}
390*a1e26a70SApple OSS Distributions 
391*a1e26a70SApple OSS Distributions 	DEBUG_INFO("_commonUsed %#x, _systemUsed %#x\n", _commonUsed, _systemUsed);
392*a1e26a70SApple OSS Distributions 
393*a1e26a70SApple OSS Distributions exit:
394*a1e26a70SApple OSS Distributions 	NVRAMRWUNLOCK(_variableLock);
395*a1e26a70SApple OSS Distributions 	return ret;
396*a1e26a70SApple OSS Distributions }
397*a1e26a70SApple OSS Distributions 
398*a1e26a70SApple OSS Distributions IOReturn
reloadInternal(void)399*a1e26a70SApple OSS Distributions IONVRAMV3Handler::reloadInternal(void)
400*a1e26a70SApple OSS Distributions {
401*a1e26a70SApple OSS Distributions 	IOReturn                     ret;
402*a1e26a70SApple OSS Distributions 	uint32_t                     controllerBank;
403*a1e26a70SApple OSS Distributions 	uint8_t                      *controllerImage;
404*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry    *v3Entry;
405*a1e26a70SApple OSS Distributions 	const struct v3_store_header *storeHeader;
406*a1e26a70SApple OSS Distributions 	const struct v3_var_header   *storeVar;
407*a1e26a70SApple OSS Distributions 	OSData                       *entryContainer;
408*a1e26a70SApple OSS Distributions 
409*a1e26a70SApple OSS Distributions 	NVRAMLOCKASSERTHELD(_controllerLock);
410*a1e26a70SApple OSS Distributions 
411*a1e26a70SApple OSS Distributions 	controllerBank = findCurrentBank();
412*a1e26a70SApple OSS Distributions 
413*a1e26a70SApple OSS Distributions 	if (_currentBank != controllerBank) {
414*a1e26a70SApple OSS Distributions 		DEBUG_ERROR("_currentBank %#x != controllerBank %#x\n", _currentBank, controllerBank);
415*a1e26a70SApple OSS Distributions 	}
416*a1e26a70SApple OSS Distributions 
417*a1e26a70SApple OSS Distributions 	_currentBank = controllerBank;
418*a1e26a70SApple OSS Distributions 
419*a1e26a70SApple OSS Distributions 	controllerImage = (uint8_t *)IOMallocData(_bankSize);
420*a1e26a70SApple OSS Distributions 
421*a1e26a70SApple OSS Distributions 	_nvramController->select(_currentBank);
422*a1e26a70SApple OSS Distributions 	_nvramController->read(0, controllerImage, _bankSize);
423*a1e26a70SApple OSS Distributions 
424*a1e26a70SApple OSS Distributions 	require_action(isValidImage(controllerImage, _bankSize), exit,
425*a1e26a70SApple OSS Distributions 	    (ret = kIOReturnInvalid, DEBUG_ERROR("Invalid image at bank %d\n", _currentBank)));
426*a1e26a70SApple OSS Distributions 
427*a1e26a70SApple OSS Distributions 	DEBUG_INFO("valid image found\n");
428*a1e26a70SApple OSS Distributions 
429*a1e26a70SApple OSS Distributions 	storeHeader = (const struct v3_store_header *)controllerImage;
430*a1e26a70SApple OSS Distributions 
431*a1e26a70SApple OSS Distributions 	_generation = storeHeader->generation;
432*a1e26a70SApple OSS Distributions 
433*a1e26a70SApple OSS Distributions 	// We must sync any existing variables offset on the controller image with our internal representation
434*a1e26a70SApple OSS Distributions 	// If we find an existing entry and the data is still the same we record the existing offset and mark it
435*a1e26a70SApple OSS Distributions 	// as VAR_NEW_STATE_NONE meaning no action needed
436*a1e26a70SApple OSS Distributions 	// Otherwise if the data is different or it is not found on the controller image we mark it as VAR_NEW_STATE_APPEND
437*a1e26a70SApple OSS Distributions 	// which will have us invalidate the existing entry if there is one and append it on the next save
438*a1e26a70SApple OSS Distributions 	NVRAMREADLOCK(_variableLock);
439*a1e26a70SApple OSS Distributions 	for (unsigned int i = 0; i < _varEntries->getCount(); i++) {
440*a1e26a70SApple OSS Distributions 		uint32_t offset = sizeof(struct v3_store_header);
441*a1e26a70SApple OSS Distributions 		uint32_t latestOffset;
442*a1e26a70SApple OSS Distributions 		uint32_t prevOffset = 0;
443*a1e26a70SApple OSS Distributions 
444*a1e26a70SApple OSS Distributions 		entryContainer = (OSDynamicCast(OSData, _varEntries->getObject(i)));
445*a1e26a70SApple OSS Distributions 		v3Entry = (struct nvram_v3_var_entry *)entryContainer->getBytesNoCopy();
446*a1e26a70SApple OSS Distributions 
447*a1e26a70SApple OSS Distributions 		DEBUG_INFO("Looking for %s\n", v3Entry->header.name_data_buf);
448*a1e26a70SApple OSS Distributions 		while ((latestOffset = find_active_var_in_image(&v3Entry->header, controllerImage, offset, _bankSize))) {
449*a1e26a70SApple OSS Distributions 			DEBUG_INFO("Found offset for %s @ %#08x\n", v3Entry->header.name_data_buf, latestOffset);
450*a1e26a70SApple OSS Distributions 			if (prevOffset) {
451*a1e26a70SApple OSS Distributions 				DEBUG_INFO("Marking prev offset for %s at %#08x invalid\n", v3Entry->header.name_data_buf, offset);
452*a1e26a70SApple OSS Distributions 				// Invalidate any previous duplicate entries in the store
453*a1e26a70SApple OSS Distributions 				struct v3_var_header *prevVarHeader = (struct v3_var_header *)(controllerImage + prevOffset);
454*a1e26a70SApple OSS Distributions 				uint8_t state = prevVarHeader->state & VAR_DELETED & VAR_IN_DELETED_TRANSITION;
455*a1e26a70SApple OSS Distributions 
456*a1e26a70SApple OSS Distributions 				ret = _nvramController->write(prevOffset + offsetof(struct v3_var_header, state), &state, sizeof(state));
457*a1e26a70SApple OSS Distributions 				require_noerr_action(ret, unlock, DEBUG_ERROR("existing state w fail, ret=%#x\n", ret));
458*a1e26a70SApple OSS Distributions 			}
459*a1e26a70SApple OSS Distributions 
460*a1e26a70SApple OSS Distributions 			prevOffset = latestOffset;
461*a1e26a70SApple OSS Distributions 			offset += latestOffset;
462*a1e26a70SApple OSS Distributions 		}
463*a1e26a70SApple OSS Distributions 
464*a1e26a70SApple OSS Distributions 		v3Entry->existing_offset = latestOffset ? latestOffset : prevOffset;
465*a1e26a70SApple OSS Distributions 		DEBUG_INFO("Existing offset for %s at %#08zx\n", v3Entry->header.name_data_buf, v3Entry->existing_offset);
466*a1e26a70SApple OSS Distributions 
467*a1e26a70SApple OSS Distributions 		if (v3Entry->existing_offset == 0) {
468*a1e26a70SApple OSS Distributions 			DEBUG_ERROR("%s is not in the NOR image\n", v3Entry->header.name_data_buf);
469*a1e26a70SApple OSS Distributions 			if (v3Entry->new_state != VAR_NEW_STATE_REMOVE) {
470*a1e26a70SApple OSS Distributions 				DEBUG_INFO("%s marked for append\n", v3Entry->header.name_data_buf);
471*a1e26a70SApple OSS Distributions 				// Doesn't exist in the store, just append it on next sync
472*a1e26a70SApple OSS Distributions 				v3Entry->new_state = VAR_NEW_STATE_APPEND;
473*a1e26a70SApple OSS Distributions 			}
474*a1e26a70SApple OSS Distributions 		} else {
475*a1e26a70SApple OSS Distributions 			DEBUG_INFO("Found offset for %s @ %#zx\n", v3Entry->header.name_data_buf, v3Entry->existing_offset);
476*a1e26a70SApple OSS Distributions 			storeVar = (const struct v3_var_header *)&controllerImage[v3Entry->existing_offset];
477*a1e26a70SApple OSS Distributions 
478*a1e26a70SApple OSS Distributions 			if (v3Entry->new_state != VAR_NEW_STATE_REMOVE) {
479*a1e26a70SApple OSS Distributions 				// Verify that the existing data matches the store data
480*a1e26a70SApple OSS Distributions 				if ((variable_length(&v3Entry->header) == variable_length(storeVar)) &&
481*a1e26a70SApple OSS Distributions 				    (memcmp(v3Entry->header.name_data_buf, storeVar->name_data_buf, storeVar->nameSize + storeVar->dataSize) == 0)) {
482*a1e26a70SApple OSS Distributions 					DEBUG_INFO("Store var data for %s matches, marking new state none\n", v3Entry->header.name_data_buf);
483*a1e26a70SApple OSS Distributions 					v3Entry->new_state = VAR_NEW_STATE_NONE;
484*a1e26a70SApple OSS Distributions 				} else {
485*a1e26a70SApple OSS Distributions 					DEBUG_INFO("Store var data for %s differs, marking new state append\n", v3Entry->header.name_data_buf);
486*a1e26a70SApple OSS Distributions 					v3Entry->new_state = VAR_NEW_STATE_APPEND;
487*a1e26a70SApple OSS Distributions 				}
488*a1e26a70SApple OSS Distributions 			} else {
489*a1e26a70SApple OSS Distributions 				// Store has entry but it has been removed from our collection, keep it marked for delete but with updated
490*a1e26a70SApple OSS Distributions 				// existing_offset for coherence
491*a1e26a70SApple OSS Distributions 				DEBUG_INFO("Removing entry at %#08zx with next sync\n", v3Entry->existing_offset);
492*a1e26a70SApple OSS Distributions 			}
493*a1e26a70SApple OSS Distributions 		}
494*a1e26a70SApple OSS Distributions 	}
495*a1e26a70SApple OSS Distributions 	ret = find_current_offset_in_image(controllerImage, _bankSize, &_currentOffset);
496*a1e26a70SApple OSS Distributions 	require_noerr_action(ret, unlock, DEBUG_ERROR("Unidentified bytes in image\n"));
497*a1e26a70SApple OSS Distributions 	DEBUG_INFO("New _currentOffset=%#x\n", _currentOffset);
498*a1e26a70SApple OSS Distributions 
499*a1e26a70SApple OSS Distributions unlock:
500*a1e26a70SApple OSS Distributions 	NVRAMRWUNLOCK(_variableLock);
501*a1e26a70SApple OSS Distributions exit:
502*a1e26a70SApple OSS Distributions 	IOFreeData(controllerImage, _bankSize);
503*a1e26a70SApple OSS Distributions 	return ret;
504*a1e26a70SApple OSS Distributions }
505*a1e26a70SApple OSS Distributions 
506*a1e26a70SApple OSS Distributions void
reload(void)507*a1e26a70SApple OSS Distributions IONVRAMV3Handler::reload(void)
508*a1e26a70SApple OSS Distributions {
509*a1e26a70SApple OSS Distributions 	_reload = true;
510*a1e26a70SApple OSS Distributions 
511*a1e26a70SApple OSS Distributions 	DEBUG_INFO("reload marked\n");
512*a1e26a70SApple OSS Distributions }
513*a1e26a70SApple OSS Distributions 
514*a1e26a70SApple OSS Distributions void
setEntryForRemove(struct nvram_v3_var_entry * v3Entry,bool system)515*a1e26a70SApple OSS Distributions IONVRAMV3Handler::setEntryForRemove(struct nvram_v3_var_entry *v3Entry, bool system)
516*a1e26a70SApple OSS Distributions {
517*a1e26a70SApple OSS Distributions 	OSSharedPtr<const OSSymbol> canonicalKey;
518*a1e26a70SApple OSS Distributions 	const char                  *variableName;
519*a1e26a70SApple OSS Distributions 	uint32_t                    variableSize;
520*a1e26a70SApple OSS Distributions 
521*a1e26a70SApple OSS Distributions 	// Anyone calling setEntryForRemove should've already held the lock for write.
522*a1e26a70SApple OSS Distributions 	NVRAMRWLOCKASSERTEXCLUSIVE(_variableLock);
523*a1e26a70SApple OSS Distributions 
524*a1e26a70SApple OSS Distributions 	require_action(v3Entry != nullptr, exit, DEBUG_INFO("remove with no entry\n"));
525*a1e26a70SApple OSS Distributions 
526*a1e26a70SApple OSS Distributions 	variableName = (const char *)v3Entry->header.name_data_buf;
527*a1e26a70SApple OSS Distributions 	variableSize = (uint32_t)variable_length(&v3Entry->header);
528*a1e26a70SApple OSS Distributions 	canonicalKey = keyWithGuidAndCString(v3Entry->header.guid, variableName);
529*a1e26a70SApple OSS Distributions 
530*a1e26a70SApple OSS Distributions 	if (v3Entry->new_state == VAR_NEW_STATE_REMOVE) {
531*a1e26a70SApple OSS Distributions 		DEBUG_INFO("entry %s already marked for remove\n", variableName);
532*a1e26a70SApple OSS Distributions 	} else {
533*a1e26a70SApple OSS Distributions 		DEBUG_INFO("marking entry %s for remove\n", variableName);
534*a1e26a70SApple OSS Distributions 
535*a1e26a70SApple OSS Distributions 		v3Entry->new_state = VAR_NEW_STATE_REMOVE;
536*a1e26a70SApple OSS Distributions 
537*a1e26a70SApple OSS Distributions 		_varDict->removeObject(canonicalKey.get());
538*a1e26a70SApple OSS Distributions 
539*a1e26a70SApple OSS Distributions 		if (system) {
540*a1e26a70SApple OSS Distributions 			if (_systemUsed < variableSize) {
541*a1e26a70SApple OSS Distributions 				panic("Invalid _systemUsed size\n");
542*a1e26a70SApple OSS Distributions 			}
543*a1e26a70SApple OSS Distributions 			_systemUsed -= variableSize;
544*a1e26a70SApple OSS Distributions 		} else {
545*a1e26a70SApple OSS Distributions 			if (_commonUsed < variableSize) {
546*a1e26a70SApple OSS Distributions 				panic("Invalid _commonUsed size\n");
547*a1e26a70SApple OSS Distributions 			}
548*a1e26a70SApple OSS Distributions 			_commonUsed -= variableSize;
549*a1e26a70SApple OSS Distributions 		}
550*a1e26a70SApple OSS Distributions 
551*a1e26a70SApple OSS Distributions 		if (_provider->_diags) {
552*a1e26a70SApple OSS Distributions 			_provider->_diags->logVariable(getPartitionTypeForGUID(v3Entry->header.guid),
553*a1e26a70SApple OSS Distributions 			    kIONVRAMOperationDelete,
554*a1e26a70SApple OSS Distributions 			    variableName,
555*a1e26a70SApple OSS Distributions 			    nullptr);
556*a1e26a70SApple OSS Distributions 		}
557*a1e26a70SApple OSS Distributions 	}
558*a1e26a70SApple OSS Distributions 
559*a1e26a70SApple OSS Distributions exit:
560*a1e26a70SApple OSS Distributions 	return;
561*a1e26a70SApple OSS Distributions }
562*a1e26a70SApple OSS Distributions 
563*a1e26a70SApple OSS Distributions void
findExistingEntry(const uuid_t varGuid,const char * varName,struct nvram_v3_var_entry ** existing,unsigned int * existingIndex)564*a1e26a70SApple OSS Distributions IONVRAMV3Handler::findExistingEntry(const uuid_t varGuid, const char *varName, struct nvram_v3_var_entry **existing, unsigned int *existingIndex)
565*a1e26a70SApple OSS Distributions {
566*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry *v3Entry = nullptr;
567*a1e26a70SApple OSS Distributions 	OSData                    *entryContainer = nullptr;
568*a1e26a70SApple OSS Distributions 	unsigned int              index = 0;
569*a1e26a70SApple OSS Distributions 	uint32_t                  nameLen = (uint32_t)strlen(varName) + 1;
570*a1e26a70SApple OSS Distributions 
571*a1e26a70SApple OSS Distributions 	for (index = 0; index < _varEntries->getCount(); index++) {
572*a1e26a70SApple OSS Distributions 		entryContainer = (OSDynamicCast(OSData, _varEntries->getObject(index)));
573*a1e26a70SApple OSS Distributions 		v3Entry = (struct nvram_v3_var_entry *)entryContainer->getBytesNoCopy();
574*a1e26a70SApple OSS Distributions 
575*a1e26a70SApple OSS Distributions 		if ((v3Entry->header.nameSize == nameLen) &&
576*a1e26a70SApple OSS Distributions 		    (memcmp(v3Entry->header.name_data_buf, varName, nameLen) == 0)) {
577*a1e26a70SApple OSS Distributions 			if (varGuid) {
578*a1e26a70SApple OSS Distributions 				if (uuid_compare(varGuid, v3Entry->header.guid) == 0) {
579*a1e26a70SApple OSS Distributions 					uuid_string_t uuidString;
580*a1e26a70SApple OSS Distributions 					uuid_unparse(varGuid, uuidString);
581*a1e26a70SApple OSS Distributions 					DEBUG_INFO("found existing entry for %s:%s, e_off=%#lx, len=%#lx, new_state=%#x\n", uuidString, varName,
582*a1e26a70SApple OSS Distributions 					    v3Entry->existing_offset, variable_length(&v3Entry->header), v3Entry->new_state);
583*a1e26a70SApple OSS Distributions 					break;
584*a1e26a70SApple OSS Distributions 				}
585*a1e26a70SApple OSS Distributions 			} else {
586*a1e26a70SApple OSS Distributions 				DEBUG_INFO("found existing entry for %s, e_off=%#lx, len=%#lx\n", varName, v3Entry->existing_offset, variable_length(&v3Entry->header));
587*a1e26a70SApple OSS Distributions 				break;
588*a1e26a70SApple OSS Distributions 			}
589*a1e26a70SApple OSS Distributions 		}
590*a1e26a70SApple OSS Distributions 
591*a1e26a70SApple OSS Distributions 		v3Entry = nullptr;
592*a1e26a70SApple OSS Distributions 	}
593*a1e26a70SApple OSS Distributions 
594*a1e26a70SApple OSS Distributions 	if (v3Entry != nullptr) {
595*a1e26a70SApple OSS Distributions 		if (existing) {
596*a1e26a70SApple OSS Distributions 			*existing = v3Entry;
597*a1e26a70SApple OSS Distributions 		}
598*a1e26a70SApple OSS Distributions 
599*a1e26a70SApple OSS Distributions 		if (existingIndex) {
600*a1e26a70SApple OSS Distributions 			*existingIndex = index;
601*a1e26a70SApple OSS Distributions 		}
602*a1e26a70SApple OSS Distributions 	}
603*a1e26a70SApple OSS Distributions }
604*a1e26a70SApple OSS Distributions 
605*a1e26a70SApple OSS Distributions IOReturn
unserializeImage(const uint8_t * image,IOByteCount length)606*a1e26a70SApple OSS Distributions IONVRAMV3Handler::unserializeImage(const uint8_t *image, IOByteCount length)
607*a1e26a70SApple OSS Distributions {
608*a1e26a70SApple OSS Distributions 	IOReturn                     ret = kIOReturnInvalid;
609*a1e26a70SApple OSS Distributions 	const struct v3_store_header *storeHeader;
610*a1e26a70SApple OSS Distributions 
611*a1e26a70SApple OSS Distributions 	require(isValidImage(image, length), exit);
612*a1e26a70SApple OSS Distributions 
613*a1e26a70SApple OSS Distributions 	storeHeader = (const struct v3_store_header *)image;
614*a1e26a70SApple OSS Distributions 	require_action(storeHeader->size == (uint32_t)length, exit,
615*a1e26a70SApple OSS Distributions 	    DEBUG_ERROR("Image size %#x != header size %#x\n", (unsigned int)length, storeHeader->size));
616*a1e26a70SApple OSS Distributions 
617*a1e26a70SApple OSS Distributions 	_generation = storeHeader->generation;
618*a1e26a70SApple OSS Distributions 	_systemSize = storeHeader->system_size;
619*a1e26a70SApple OSS Distributions 	_commonSize = storeHeader->common_size - sizeof(struct v3_store_header);
620*a1e26a70SApple OSS Distributions 
621*a1e26a70SApple OSS Distributions 	_systemUsed = 0;
622*a1e26a70SApple OSS Distributions 	_commonUsed = 0;
623*a1e26a70SApple OSS Distributions 
624*a1e26a70SApple OSS Distributions 	if (_nvramImage) {
625*a1e26a70SApple OSS Distributions 		IOFreeData(_nvramImage, _bankSize);
626*a1e26a70SApple OSS Distributions 	}
627*a1e26a70SApple OSS Distributions 
628*a1e26a70SApple OSS Distributions 	_varEntries.reset();
629*a1e26a70SApple OSS Distributions 	_varEntries = OSArray::withCapacity(40);
630*a1e26a70SApple OSS Distributions 
631*a1e26a70SApple OSS Distributions 	_nvramImage = IONewData(uint8_t, length);
632*a1e26a70SApple OSS Distributions 	_bankSize = (uint32_t)length;
633*a1e26a70SApple OSS Distributions 	bcopy(image, _nvramImage, _bankSize);
634*a1e26a70SApple OSS Distributions 
635*a1e26a70SApple OSS Distributions 	ret = kIOReturnSuccess;
636*a1e26a70SApple OSS Distributions 
637*a1e26a70SApple OSS Distributions exit:
638*a1e26a70SApple OSS Distributions 	return ret;
639*a1e26a70SApple OSS Distributions }
640*a1e26a70SApple OSS Distributions 
641*a1e26a70SApple OSS Distributions typedef struct {
642*a1e26a70SApple OSS Distributions 	const char            *name;
643*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSObject> value;
644*a1e26a70SApple OSS Distributions } ephDMAllowListEntry;
645*a1e26a70SApple OSS Distributions 
646*a1e26a70SApple OSS Distributions static
647*a1e26a70SApple OSS Distributions ephDMAllowListEntry ephDMEntries[] = {
648*a1e26a70SApple OSS Distributions 	// Mobile Obliteration clears the following variables after it runs
649*a1e26a70SApple OSS Distributions 	{ .name = "oblit-begins" },
650*a1e26a70SApple OSS Distributions 	{ .name = "orig-oblit" },
651*a1e26a70SApple OSS Distributions 	{ .name = "oblit-failure" },
652*a1e26a70SApple OSS Distributions 	{ .name = "oblit-inprogress" },
653*a1e26a70SApple OSS Distributions 	{ .name = "obliteration" },
654*a1e26a70SApple OSS Distributions 	// darwin-init is used for configuring internal builds
655*a1e26a70SApple OSS Distributions 	{ .name = "darwin-init" }
656*a1e26a70SApple OSS Distributions };
657*a1e26a70SApple OSS Distributions 
658*a1e26a70SApple OSS Distributions IOReturn
handleEphDM(void)659*a1e26a70SApple OSS Distributions IONVRAMV3Handler::handleEphDM(void)
660*a1e26a70SApple OSS Distributions {
661*a1e26a70SApple OSS Distributions 	OSSharedPtr<IORegistryEntry> entry;
662*a1e26a70SApple OSS Distributions 	OSData*                      data;
663*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSObject>        prop;
664*a1e26a70SApple OSS Distributions 	uint32_t                     ephDM = 0;
665*a1e26a70SApple OSS Distributions 	IOReturn                     ret = kIOReturnSuccess;
666*a1e26a70SApple OSS Distributions 	OSSharedPtr<const OSSymbol>  canonicalKey;
667*a1e26a70SApple OSS Distributions 	uint32_t                     skip = 0;
668*a1e26a70SApple OSS Distributions 
669*a1e26a70SApple OSS Distributions 	// For ephemeral data mode, NVRAM needs to be cleared on every boot
670*a1e26a70SApple OSS Distributions 	// For system region supported targets, iBoot clears the system region
671*a1e26a70SApple OSS Distributions 	// For other targets, iBoot clears all the persistent variables
672*a1e26a70SApple OSS Distributions 	// So xnu only needs to clear the common region
673*a1e26a70SApple OSS Distributions 	entry = IORegistryEntry::fromPath("/product", gIODTPlane);
674*a1e26a70SApple OSS Distributions 	if (entry) {
675*a1e26a70SApple OSS Distributions 		prop = entry->copyProperty("ephemeral-data-mode");
676*a1e26a70SApple OSS Distributions 		if (prop) {
677*a1e26a70SApple OSS Distributions 			data = OSDynamicCast(OSData, prop.get());
678*a1e26a70SApple OSS Distributions 			if (data) {
679*a1e26a70SApple OSS Distributions 				ephDM = *((uint32_t *)data->getBytesNoCopy());
680*a1e26a70SApple OSS Distributions 			}
681*a1e26a70SApple OSS Distributions 		}
682*a1e26a70SApple OSS Distributions 	}
683*a1e26a70SApple OSS Distributions 
684*a1e26a70SApple OSS Distributions 	require_action(ephDM != 0, exit, DEBUG_ALWAYS("ephemeral-data-mode not supported\n"));
685*a1e26a70SApple OSS Distributions 	require_action(_systemSize != 0, exit, DEBUG_ALWAYS("No system region, no need to clear\n"));
686*a1e26a70SApple OSS Distributions 
687*a1e26a70SApple OSS Distributions 	if (PE_parse_boot_argn("epdm-skip-nvram", &skip, sizeof(skip))) {
688*a1e26a70SApple OSS Distributions 		require_action(!(gInternalBuild && (skip == 1)), exit, DEBUG_ALWAYS("Internal build + epdm-skip-nvram set to true, skip nvram clearing\n"));
689*a1e26a70SApple OSS Distributions 	}
690*a1e26a70SApple OSS Distributions 
691*a1e26a70SApple OSS Distributions 	// Go through the allowlist and stash the values
692*a1e26a70SApple OSS Distributions 	for (uint32_t entry = 0; entry < ARRAY_SIZE(ephDMEntries); entry++) {
693*a1e26a70SApple OSS Distributions 		canonicalKey = keyWithGuidAndCString(gAppleNVRAMGuid, ephDMEntries[entry].name);
694*a1e26a70SApple OSS Distributions 		ephDMEntries[entry].value.reset(OSDynamicCast(OSData, _varDict->getObject(canonicalKey.get())), OSRetain);
695*a1e26a70SApple OSS Distributions 	}
696*a1e26a70SApple OSS Distributions 
697*a1e26a70SApple OSS Distributions 	DEBUG_ALWAYS("Obliterating common region\n");
698*a1e26a70SApple OSS Distributions 	ret = flush(gAppleNVRAMGuid, kIONVRAMOperationObliterate);
699*a1e26a70SApple OSS Distributions 	require_noerr_action(ret, exit, DEBUG_ERROR("Flushing common region failed, ret=%#08x\n", ret));
700*a1e26a70SApple OSS Distributions 
701*a1e26a70SApple OSS Distributions 	// Now write the allowlist variables back
702*a1e26a70SApple OSS Distributions 	for (uint32_t entry = 0; entry < ARRAY_SIZE(ephDMEntries); entry++) {
703*a1e26a70SApple OSS Distributions 		if (ephDMEntries[entry].value.get() == nullptr) {
704*a1e26a70SApple OSS Distributions 			continue;
705*a1e26a70SApple OSS Distributions 		}
706*a1e26a70SApple OSS Distributions 		ret = setVariableInternal(gAppleNVRAMGuid, ephDMEntries[entry].name, ephDMEntries[entry].value.get());
707*a1e26a70SApple OSS Distributions 		require_noerr_action(ret, exit, DEBUG_ERROR("Setting allowlist variable %s failed, ret=%#08x\n", ephDMEntries[entry].name, ret));
708*a1e26a70SApple OSS Distributions 	}
709*a1e26a70SApple OSS Distributions 
710*a1e26a70SApple OSS Distributions exit:
711*a1e26a70SApple OSS Distributions 	return ret;
712*a1e26a70SApple OSS Distributions }
713*a1e26a70SApple OSS Distributions 
714*a1e26a70SApple OSS Distributions IOReturn
unserializeVariables(void)715*a1e26a70SApple OSS Distributions IONVRAMV3Handler::unserializeVariables(void)
716*a1e26a70SApple OSS Distributions {
717*a1e26a70SApple OSS Distributions 	IOReturn                     ret = kIOReturnSuccess;
718*a1e26a70SApple OSS Distributions 	OSSharedPtr<const OSSymbol>  propSymbol;
719*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSObject>        propObject;
720*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSData>          entryContainer;
721*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry    *v3Entry;
722*a1e26a70SApple OSS Distributions 	const struct v3_var_header   *header;
723*a1e26a70SApple OSS Distributions 	size_t                       offset = sizeof(struct v3_store_header);
724*a1e26a70SApple OSS Distributions 	uint32_t                     crc;
725*a1e26a70SApple OSS Distributions 	unsigned int                 i;
726*a1e26a70SApple OSS Distributions 	bool                         system;
727*a1e26a70SApple OSS Distributions 	uuid_string_t                uuidString;
728*a1e26a70SApple OSS Distributions 	size_t                       existingSize;
729*a1e26a70SApple OSS Distributions 
730*a1e26a70SApple OSS Distributions 	if (_systemSize || _commonSize) {
731*a1e26a70SApple OSS Distributions 		_varDict = OSDictionary::withCapacity(1);
732*a1e26a70SApple OSS Distributions 	}
733*a1e26a70SApple OSS Distributions 
734*a1e26a70SApple OSS Distributions 	while ((offset + sizeof(struct v3_var_header)) < _bankSize) {
735*a1e26a70SApple OSS Distributions 		struct nvram_v3_var_entry *existingEntry = nullptr;
736*a1e26a70SApple OSS Distributions 		unsigned int              existingIndex = 0;
737*a1e26a70SApple OSS Distributions 
738*a1e26a70SApple OSS Distributions 		header = (const struct v3_var_header *)(_nvramImage + offset);
739*a1e26a70SApple OSS Distributions 
740*a1e26a70SApple OSS Distributions 		for (i = 0; i < sizeof(struct v3_var_header); i++) {
741*a1e26a70SApple OSS Distributions 			if ((_nvramImage[offset + i] != 0) && (_nvramImage[offset + i] != 0xFF)) {
742*a1e26a70SApple OSS Distributions 				break;
743*a1e26a70SApple OSS Distributions 			}
744*a1e26a70SApple OSS Distributions 		}
745*a1e26a70SApple OSS Distributions 
746*a1e26a70SApple OSS Distributions 		if (i == sizeof(struct v3_var_header)) {
747*a1e26a70SApple OSS Distributions 			DEBUG_INFO("No more variables after offset %#lx\n", offset);
748*a1e26a70SApple OSS Distributions 			break;
749*a1e26a70SApple OSS Distributions 		}
750*a1e26a70SApple OSS Distributions 
751*a1e26a70SApple OSS Distributions 		if (!valid_variable_header(header, _bankSize - offset)) {
752*a1e26a70SApple OSS Distributions 			DEBUG_ERROR("invalid header @ %#lx\n", offset);
753*a1e26a70SApple OSS Distributions 			offset += sizeof(struct v3_var_header);
754*a1e26a70SApple OSS Distributions 			continue;
755*a1e26a70SApple OSS Distributions 		}
756*a1e26a70SApple OSS Distributions 
757*a1e26a70SApple OSS Distributions 		uuid_unparse(header->guid, uuidString);
758*a1e26a70SApple OSS Distributions 		DEBUG_INFO("Valid var @ %#08zx, state=%#02x, length=%#08zx, %s:%s\n", offset, header->state,
759*a1e26a70SApple OSS Distributions 		    variable_length(header), uuidString, header->name_data_buf);
760*a1e26a70SApple OSS Distributions 
761*a1e26a70SApple OSS Distributions 		if (header->state != VAR_ADDED) {
762*a1e26a70SApple OSS Distributions 			goto skip;
763*a1e26a70SApple OSS Distributions 		}
764*a1e26a70SApple OSS Distributions 
765*a1e26a70SApple OSS Distributions 		crc = crc32(0, header->name_data_buf + header->nameSize, header->dataSize);
766*a1e26a70SApple OSS Distributions 
767*a1e26a70SApple OSS Distributions 		if (crc != header->crc) {
768*a1e26a70SApple OSS Distributions 			DEBUG_ERROR("invalid crc @ %#lx, calculated=%#x, read=%#x\n", offset, crc, header->crc);
769*a1e26a70SApple OSS Distributions 			goto skip;
770*a1e26a70SApple OSS Distributions 		}
771*a1e26a70SApple OSS Distributions 
772*a1e26a70SApple OSS Distributions 		v3Entry = (struct nvram_v3_var_entry *)IOMallocZeroData(nvram_v3_var_container_size(header));
773*a1e26a70SApple OSS Distributions 		__nochk_memcpy(&v3Entry->header, _nvramImage + offset, variable_length(header));
774*a1e26a70SApple OSS Distributions 
775*a1e26a70SApple OSS Distributions 		// It is assumed that the initial image being unserialized here is going to be the proxy data from EDT and not the image
776*a1e26a70SApple OSS Distributions 		// read from the controller, which for various reasons due to the setting of states and saves from iBoot, can be
777*a1e26a70SApple OSS Distributions 		// different. We will have an initial existing_offset of 0 and once the controller is set we will read
778*a1e26a70SApple OSS Distributions 		// out the image there and update the existing offset with what is present on the NOR image
779*a1e26a70SApple OSS Distributions 		v3Entry->existing_offset = 0;
780*a1e26a70SApple OSS Distributions 		v3Entry->new_state = VAR_NEW_STATE_NONE;
781*a1e26a70SApple OSS Distributions 
782*a1e26a70SApple OSS Distributions 		// safe guard for any strange duplicate entries in the store
783*a1e26a70SApple OSS Distributions 		findExistingEntry(v3Entry->header.guid, (const char *)v3Entry->header.name_data_buf, &existingEntry, &existingIndex);
784*a1e26a70SApple OSS Distributions 
785*a1e26a70SApple OSS Distributions 		if (existingEntry != nullptr) {
786*a1e26a70SApple OSS Distributions 			existingSize = variable_length(&existingEntry->header);
787*a1e26a70SApple OSS Distributions 
788*a1e26a70SApple OSS Distributions 			entryContainer = OSData::withBytes(v3Entry, (uint32_t)nvram_v3_var_container_size(header));
789*a1e26a70SApple OSS Distributions 			_varEntries->replaceObject(existingIndex, entryContainer.get());
790*a1e26a70SApple OSS Distributions 
791*a1e26a70SApple OSS Distributions 			DEBUG_INFO("Found existing for %s, resetting when controller available\n", v3Entry->header.name_data_buf);
792*a1e26a70SApple OSS Distributions 			_resetData = true;
793*a1e26a70SApple OSS Distributions 		} else {
794*a1e26a70SApple OSS Distributions 			entryContainer = OSData::withBytes(v3Entry, (uint32_t)nvram_v3_var_container_size(header));
795*a1e26a70SApple OSS Distributions 			_varEntries->setObject(entryContainer.get());
796*a1e26a70SApple OSS Distributions 			existingSize = 0;
797*a1e26a70SApple OSS Distributions 		}
798*a1e26a70SApple OSS Distributions 
799*a1e26a70SApple OSS Distributions 		system = (_systemSize != 0) && (uuid_compare(v3Entry->header.guid, gAppleSystemVariableGuid) == 0);
800*a1e26a70SApple OSS Distributions 		if (system) {
801*a1e26a70SApple OSS Distributions 			_systemUsed = _systemUsed + (uint32_t)variable_length(header) - (uint32_t)existingSize;
802*a1e26a70SApple OSS Distributions 		} else {
803*a1e26a70SApple OSS Distributions 			_commonUsed = _commonUsed + (uint32_t)variable_length(header) - (uint32_t)existingSize;
804*a1e26a70SApple OSS Distributions 		}
805*a1e26a70SApple OSS Distributions 
806*a1e26a70SApple OSS Distributions 		if (convertPropToObject(v3Entry->header.name_data_buf, v3Entry->header.nameSize,
807*a1e26a70SApple OSS Distributions 		    v3Entry->header.name_data_buf + v3Entry->header.nameSize, v3Entry->header.dataSize,
808*a1e26a70SApple OSS Distributions 		    propSymbol, propObject)) {
809*a1e26a70SApple OSS Distributions 			OSSharedPtr<const OSSymbol> canonicalKey = keyWithGuidAndCString(v3Entry->header.guid, (const char *)v3Entry->header.name_data_buf);
810*a1e26a70SApple OSS Distributions 
811*a1e26a70SApple OSS Distributions 			DEBUG_INFO("adding %s, dataLength=%u, system=%d\n",
812*a1e26a70SApple OSS Distributions 			    canonicalKey->getCStringNoCopy(), v3Entry->header.dataSize, system);
813*a1e26a70SApple OSS Distributions 
814*a1e26a70SApple OSS Distributions 			_varDict->setObject(canonicalKey.get(), propObject.get());
815*a1e26a70SApple OSS Distributions 
816*a1e26a70SApple OSS Distributions 			if (_provider->_diags) {
817*a1e26a70SApple OSS Distributions 				_provider->_diags->logVariable(getPartitionTypeForGUID(v3Entry->header.guid),
818*a1e26a70SApple OSS Distributions 				    kIONVRAMOperationInit, propSymbol.get()->getCStringNoCopy(),
819*a1e26a70SApple OSS Distributions 				    (void *)(uintptr_t)(header->name_data_buf + header->nameSize));
820*a1e26a70SApple OSS Distributions 			}
821*a1e26a70SApple OSS Distributions 		}
822*a1e26a70SApple OSS Distributions 		IOFreeData(v3Entry, nvram_v3_var_container_size(header));
823*a1e26a70SApple OSS Distributions skip:
824*a1e26a70SApple OSS Distributions 		offset += variable_length(header);
825*a1e26a70SApple OSS Distributions 	}
826*a1e26a70SApple OSS Distributions 
827*a1e26a70SApple OSS Distributions 	_currentOffset = (uint32_t)offset;
828*a1e26a70SApple OSS Distributions 
829*a1e26a70SApple OSS Distributions 	DEBUG_ALWAYS("_commonSize %#x, _systemSize %#x, _currentOffset %#x\n", _commonSize, _systemSize, _currentOffset);
830*a1e26a70SApple OSS Distributions 
831*a1e26a70SApple OSS Distributions 	ret = handleEphDM();
832*a1e26a70SApple OSS Distributions 	verify_noerr_action(ret, panic("handleEphDM failed with ret=%08x", ret));
833*a1e26a70SApple OSS Distributions 
834*a1e26a70SApple OSS Distributions 	DEBUG_INFO("_commonUsed %#x, _systemUsed %#x\n", _commonUsed, _systemUsed);
835*a1e26a70SApple OSS Distributions 
836*a1e26a70SApple OSS Distributions 	_newData = true;
837*a1e26a70SApple OSS Distributions 
838*a1e26a70SApple OSS Distributions 	if (_provider->_diags) {
839*a1e26a70SApple OSS Distributions 		OSSharedPtr<OSNumber> val = OSNumber::withNumber(getSystemUsed(), 32);
840*a1e26a70SApple OSS Distributions 		_provider->_diags->setProperty(kNVRAMSystemUsedKey, val.get());
841*a1e26a70SApple OSS Distributions 		DEBUG_INFO("%s=%u\n", kNVRAMSystemUsedKey, getSystemUsed());
842*a1e26a70SApple OSS Distributions 
843*a1e26a70SApple OSS Distributions 		val = OSNumber::withNumber(getCommonUsed(), 32);
844*a1e26a70SApple OSS Distributions 		_provider->_diags->setProperty(kNVRAMCommonUsedKey, val.get());
845*a1e26a70SApple OSS Distributions 		DEBUG_INFO("%s=%u\n", kNVRAMCommonUsedKey, getCommonUsed());
846*a1e26a70SApple OSS Distributions 	}
847*a1e26a70SApple OSS Distributions 
848*a1e26a70SApple OSS Distributions 	return ret;
849*a1e26a70SApple OSS Distributions }
850*a1e26a70SApple OSS Distributions 
851*a1e26a70SApple OSS Distributions IOReturn
setVariableInternal(const uuid_t varGuid,const char * variableName,OSObject * object)852*a1e26a70SApple OSS Distributions IONVRAMV3Handler::setVariableInternal(const uuid_t varGuid, const char *variableName, OSObject *object)
853*a1e26a70SApple OSS Distributions {
854*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry   *v3Entry = nullptr;
855*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry   *newV3Entry;
856*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSData>         newContainer;
857*a1e26a70SApple OSS Distributions 	OSSharedPtr<const OSSymbol> canonicalKey;
858*a1e26a70SApple OSS Distributions 	bool                        unset = (object == nullptr);
859*a1e26a70SApple OSS Distributions 	bool                        system = false;
860*a1e26a70SApple OSS Distributions 	IOReturn                    ret = kIOReturnSuccess;
861*a1e26a70SApple OSS Distributions 	size_t                      entryNameLen = strlen(variableName) + 1;
862*a1e26a70SApple OSS Distributions 	unsigned int                existingEntryIndex;
863*a1e26a70SApple OSS Distributions 	uint32_t                    dataSize = 0;
864*a1e26a70SApple OSS Distributions 	size_t                      existingVariableSize = 0;
865*a1e26a70SApple OSS Distributions 	size_t                      newVariableSize = 0;
866*a1e26a70SApple OSS Distributions 	size_t                      newEntrySize;
867*a1e26a70SApple OSS Distributions 	uuid_string_t               uuidString;
868*a1e26a70SApple OSS Distributions 
869*a1e26a70SApple OSS Distributions 	// Anyone calling setVariableInternal should've already held the lock for write.
870*a1e26a70SApple OSS Distributions 	NVRAMRWLOCKASSERTEXCLUSIVE(_variableLock);
871*a1e26a70SApple OSS Distributions 
872*a1e26a70SApple OSS Distributions 	system = (uuid_compare(varGuid, gAppleSystemVariableGuid) == 0);
873*a1e26a70SApple OSS Distributions 	canonicalKey = keyWithGuidAndCString(varGuid, variableName);
874*a1e26a70SApple OSS Distributions 
875*a1e26a70SApple OSS Distributions 	uuid_unparse(varGuid, uuidString);
876*a1e26a70SApple OSS Distributions 	DEBUG_INFO("setting %s:%s, system=%d, current var count=%u\n", uuidString, variableName, system, _varEntries->getCount());
877*a1e26a70SApple OSS Distributions 
878*a1e26a70SApple OSS Distributions 	findExistingEntry(varGuid, variableName, &v3Entry, &existingEntryIndex);
879*a1e26a70SApple OSS Distributions 
880*a1e26a70SApple OSS Distributions 	if (unset == true) {
881*a1e26a70SApple OSS Distributions 		setEntryForRemove(v3Entry, system);
882*a1e26a70SApple OSS Distributions 	} else {
883*a1e26a70SApple OSS Distributions 		if ((v3Entry != nullptr) && (v3Entry->new_state != VAR_NEW_STATE_REMOVE)) {
884*a1e26a70SApple OSS Distributions 			// Sizing was subtracted in setEntryForRemove
885*a1e26a70SApple OSS Distributions 			existingVariableSize = variable_length(&v3Entry->header);
886*a1e26a70SApple OSS Distributions 		}
887*a1e26a70SApple OSS Distributions 
888*a1e26a70SApple OSS Distributions 		convertObjectToProp(nullptr, &dataSize, variableName, object);
889*a1e26a70SApple OSS Distributions 
890*a1e26a70SApple OSS Distributions 		newVariableSize = sizeof(struct v3_var_header) + entryNameLen + dataSize;
891*a1e26a70SApple OSS Distributions 		newEntrySize = sizeof(struct nvram_v3_var_entry) + entryNameLen + dataSize;
892*a1e26a70SApple OSS Distributions 
893*a1e26a70SApple OSS Distributions 		if (system) {
894*a1e26a70SApple OSS Distributions 			if (_systemUsed - existingVariableSize + newVariableSize > _systemSize) {
895*a1e26a70SApple OSS Distributions 				DEBUG_ERROR("system region full\n");
896*a1e26a70SApple OSS Distributions 				ret = kIOReturnNoSpace;
897*a1e26a70SApple OSS Distributions 				goto exit;
898*a1e26a70SApple OSS Distributions 			}
899*a1e26a70SApple OSS Distributions 		} else if (_commonUsed - existingVariableSize + newVariableSize > _commonSize) {
900*a1e26a70SApple OSS Distributions 			DEBUG_ERROR("common region full\n");
901*a1e26a70SApple OSS Distributions 			ret = kIOReturnNoSpace;
902*a1e26a70SApple OSS Distributions 			goto exit;
903*a1e26a70SApple OSS Distributions 		}
904*a1e26a70SApple OSS Distributions 
905*a1e26a70SApple OSS Distributions 		DEBUG_INFO("creating new entry for %s, existingVariableSize=%#zx, newVariableSize=%#zx\n", variableName, existingVariableSize, newVariableSize);
906*a1e26a70SApple OSS Distributions 		newV3Entry = (struct nvram_v3_var_entry *)IOMallocZeroData(newEntrySize);
907*a1e26a70SApple OSS Distributions 
908*a1e26a70SApple OSS Distributions 		memcpy(newV3Entry->header.name_data_buf, variableName, entryNameLen);
909*a1e26a70SApple OSS Distributions 		convertObjectToProp(newV3Entry->header.name_data_buf + entryNameLen, &dataSize, variableName, object);
910*a1e26a70SApple OSS Distributions 
911*a1e26a70SApple OSS Distributions 		newV3Entry->header.startId = VARIABLE_DATA;
912*a1e26a70SApple OSS Distributions 		newV3Entry->header.nameSize = (uint32_t)entryNameLen;
913*a1e26a70SApple OSS Distributions 		newV3Entry->header.dataSize = dataSize;
914*a1e26a70SApple OSS Distributions 		newV3Entry->header.crc = crc32(0, newV3Entry->header.name_data_buf + entryNameLen, dataSize);
915*a1e26a70SApple OSS Distributions 		memcpy(newV3Entry->header.guid, varGuid, sizeof(gAppleNVRAMGuid));
916*a1e26a70SApple OSS Distributions 		newV3Entry->new_state = VAR_NEW_STATE_APPEND;
917*a1e26a70SApple OSS Distributions 
918*a1e26a70SApple OSS Distributions 		if (v3Entry) {
919*a1e26a70SApple OSS Distributions 			newV3Entry->existing_offset = v3Entry->existing_offset;
920*a1e26a70SApple OSS Distributions 			newV3Entry->header.state = v3Entry->header.state;
921*a1e26a70SApple OSS Distributions 			newV3Entry->header.attributes = v3Entry->header.attributes;
922*a1e26a70SApple OSS Distributions 
923*a1e26a70SApple OSS Distributions 			newContainer = OSData::withBytes(newV3Entry, (uint32_t)newEntrySize);
924*a1e26a70SApple OSS Distributions 			_varEntries->replaceObject(existingEntryIndex, newContainer.get());
925*a1e26a70SApple OSS Distributions 		} else {
926*a1e26a70SApple OSS Distributions 			newContainer = OSData::withBytes(newV3Entry, (uint32_t)newEntrySize);
927*a1e26a70SApple OSS Distributions 			_varEntries->setObject(newContainer.get());
928*a1e26a70SApple OSS Distributions 		}
929*a1e26a70SApple OSS Distributions 
930*a1e26a70SApple OSS Distributions 		if (system) {
931*a1e26a70SApple OSS Distributions 			_systemUsed = _systemUsed + (uint32_t)newVariableSize - (uint32_t)existingVariableSize;
932*a1e26a70SApple OSS Distributions 		} else {
933*a1e26a70SApple OSS Distributions 			_commonUsed = _commonUsed + (uint32_t)newVariableSize - (uint32_t)existingVariableSize;
934*a1e26a70SApple OSS Distributions 		}
935*a1e26a70SApple OSS Distributions 
936*a1e26a70SApple OSS Distributions 		_varDict->setObject(canonicalKey.get(), object);
937*a1e26a70SApple OSS Distributions 
938*a1e26a70SApple OSS Distributions 		if (_provider->_diags) {
939*a1e26a70SApple OSS Distributions 			_provider->_diags->logVariable(getPartitionTypeForGUID(varGuid),
940*a1e26a70SApple OSS Distributions 			    kIONVRAMOperationWrite, variableName,
941*a1e26a70SApple OSS Distributions 			    (void *)(uintptr_t)dataSize);
942*a1e26a70SApple OSS Distributions 		}
943*a1e26a70SApple OSS Distributions 
944*a1e26a70SApple OSS Distributions 		IOFreeData(newV3Entry, newEntrySize);
945*a1e26a70SApple OSS Distributions 	}
946*a1e26a70SApple OSS Distributions 
947*a1e26a70SApple OSS Distributions exit:
948*a1e26a70SApple OSS Distributions 	_newData = true;
949*a1e26a70SApple OSS Distributions 
950*a1e26a70SApple OSS Distributions 	if (_provider->_diags) {
951*a1e26a70SApple OSS Distributions 		OSSharedPtr<OSNumber> val = OSNumber::withNumber(getSystemUsed(), 32);
952*a1e26a70SApple OSS Distributions 		_provider->_diags->setProperty(kNVRAMSystemUsedKey, val.get());
953*a1e26a70SApple OSS Distributions 
954*a1e26a70SApple OSS Distributions 		val = OSNumber::withNumber(getCommonUsed(), 32);
955*a1e26a70SApple OSS Distributions 		_provider->_diags->setProperty(kNVRAMCommonUsedKey, val.get());
956*a1e26a70SApple OSS Distributions 	}
957*a1e26a70SApple OSS Distributions 
958*a1e26a70SApple OSS Distributions 	DEBUG_INFO("_commonUsed %#x, _systemUsed %#x\n", _commonUsed, _systemUsed);
959*a1e26a70SApple OSS Distributions 
960*a1e26a70SApple OSS Distributions 	return ret;
961*a1e26a70SApple OSS Distributions }
962*a1e26a70SApple OSS Distributions 
963*a1e26a70SApple OSS Distributions IOReturn
setVariable(const uuid_t varGuid,const char * variableName,OSObject * object)964*a1e26a70SApple OSS Distributions IONVRAMV3Handler::setVariable(const uuid_t varGuid, const char *variableName, OSObject *object)
965*a1e26a70SApple OSS Distributions {
966*a1e26a70SApple OSS Distributions 	uuid_t destGuid;
967*a1e26a70SApple OSS Distributions 	IOReturn ret = kIOReturnError;
968*a1e26a70SApple OSS Distributions 
969*a1e26a70SApple OSS Distributions 	if (strcmp(variableName, "reclaim-int") == 0) {
970*a1e26a70SApple OSS Distributions 		NVRAMLOCK(_controllerLock);
971*a1e26a70SApple OSS Distributions 		ret = reclaim();
972*a1e26a70SApple OSS Distributions 		NVRAMUNLOCK(_controllerLock);
973*a1e26a70SApple OSS Distributions 		return ret;
974*a1e26a70SApple OSS Distributions 	}
975*a1e26a70SApple OSS Distributions 
976*a1e26a70SApple OSS Distributions 	if (getSystemPartitionActive()) {
977*a1e26a70SApple OSS Distributions 		// System region case, if they're using the GUID directly or it's on the system allow list
978*a1e26a70SApple OSS Distributions 		// force it to use the System GUID
979*a1e26a70SApple OSS Distributions 		if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) || variableInAllowList(variableName)) {
980*a1e26a70SApple OSS Distributions 			uuid_copy(destGuid, gAppleSystemVariableGuid);
981*a1e26a70SApple OSS Distributions 		} else {
982*a1e26a70SApple OSS Distributions 			uuid_copy(destGuid, varGuid);
983*a1e26a70SApple OSS Distributions 		}
984*a1e26a70SApple OSS Distributions 	} else {
985*a1e26a70SApple OSS Distributions 		// No system region, store System GUID as Common GUID
986*a1e26a70SApple OSS Distributions 		if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) || variableInAllowList(variableName)) {
987*a1e26a70SApple OSS Distributions 			uuid_copy(destGuid, gAppleNVRAMGuid);
988*a1e26a70SApple OSS Distributions 		} else {
989*a1e26a70SApple OSS Distributions 			uuid_copy(destGuid, varGuid);
990*a1e26a70SApple OSS Distributions 		}
991*a1e26a70SApple OSS Distributions 	}
992*a1e26a70SApple OSS Distributions 
993*a1e26a70SApple OSS Distributions 	NVRAMWRITELOCK(_variableLock);
994*a1e26a70SApple OSS Distributions 	ret = setVariableInternal(destGuid, variableName, object);
995*a1e26a70SApple OSS Distributions 	NVRAMRWUNLOCK(_variableLock);
996*a1e26a70SApple OSS Distributions 
997*a1e26a70SApple OSS Distributions 	return ret;
998*a1e26a70SApple OSS Distributions }
999*a1e26a70SApple OSS Distributions 
1000*a1e26a70SApple OSS Distributions uint32_t
findCurrentBank(void)1001*a1e26a70SApple OSS Distributions IONVRAMV3Handler::findCurrentBank(void)
1002*a1e26a70SApple OSS Distributions {
1003*a1e26a70SApple OSS Distributions 	struct v3_store_header storeHeader;
1004*a1e26a70SApple OSS Distributions 	uint32_t               maxGen = 0;
1005*a1e26a70SApple OSS Distributions 	uint32_t               currentBank = 0;
1006*a1e26a70SApple OSS Distributions 
1007*a1e26a70SApple OSS Distributions 	NVRAMLOCKASSERTHELD(_controllerLock);
1008*a1e26a70SApple OSS Distributions 
1009*a1e26a70SApple OSS Distributions 	for (unsigned int i = 0; i < _bankCount; i++) {
1010*a1e26a70SApple OSS Distributions 		_nvramController->select(i);
1011*a1e26a70SApple OSS Distributions 		_nvramController->read(0, (uint8_t *)&storeHeader, sizeof(storeHeader));
1012*a1e26a70SApple OSS Distributions 
1013*a1e26a70SApple OSS Distributions 		if (valid_store_header(&storeHeader) && (storeHeader.generation >= maxGen)) {
1014*a1e26a70SApple OSS Distributions 			currentBank = i;
1015*a1e26a70SApple OSS Distributions 			maxGen = storeHeader.generation;
1016*a1e26a70SApple OSS Distributions 		}
1017*a1e26a70SApple OSS Distributions 	}
1018*a1e26a70SApple OSS Distributions 
1019*a1e26a70SApple OSS Distributions 	DEBUG_ALWAYS("currentBank=%#x, gen=%#x\n", currentBank, maxGen);
1020*a1e26a70SApple OSS Distributions 
1021*a1e26a70SApple OSS Distributions 	return currentBank;
1022*a1e26a70SApple OSS Distributions }
1023*a1e26a70SApple OSS Distributions 
1024*a1e26a70SApple OSS Distributions bool
setController(IONVRAMController * controller)1025*a1e26a70SApple OSS Distributions IONVRAMV3Handler::setController(IONVRAMController *controller)
1026*a1e26a70SApple OSS Distributions {
1027*a1e26a70SApple OSS Distributions 	IOReturn ret = kIOReturnSuccess;
1028*a1e26a70SApple OSS Distributions 
1029*a1e26a70SApple OSS Distributions 	NVRAMLOCK(_controllerLock);
1030*a1e26a70SApple OSS Distributions 
1031*a1e26a70SApple OSS Distributions 	if (_nvramController == NULL) {
1032*a1e26a70SApple OSS Distributions 		_nvramController = controller;
1033*a1e26a70SApple OSS Distributions 	}
1034*a1e26a70SApple OSS Distributions 
1035*a1e26a70SApple OSS Distributions 	DEBUG_INFO("Controller name: %s\n", _nvramController->getName());
1036*a1e26a70SApple OSS Distributions 
1037*a1e26a70SApple OSS Distributions 	require(_bankSize != 0, exit);
1038*a1e26a70SApple OSS Distributions 
1039*a1e26a70SApple OSS Distributions 	if (_resetData) {
1040*a1e26a70SApple OSS Distributions 		_resetData = false;
1041*a1e26a70SApple OSS Distributions 		DEBUG_ERROR("_resetData set, issuing reclaim recovery\n");
1042*a1e26a70SApple OSS Distributions 		goto reclaim;
1043*a1e26a70SApple OSS Distributions 	}
1044*a1e26a70SApple OSS Distributions 
1045*a1e26a70SApple OSS Distributions 	if (reloadInternal() == kIOReturnSuccess) {
1046*a1e26a70SApple OSS Distributions 		goto exit;
1047*a1e26a70SApple OSS Distributions 	}
1048*a1e26a70SApple OSS Distributions 
1049*a1e26a70SApple OSS Distributions reclaim:
1050*a1e26a70SApple OSS Distributions 	ret = reclaim();
1051*a1e26a70SApple OSS Distributions 	require_noerr_action(ret, exit, DEBUG_ERROR("Reclaim recovery failed, invalid controller state!!! ret=%#x\n", ret));
1052*a1e26a70SApple OSS Distributions exit:
1053*a1e26a70SApple OSS Distributions 	NVRAMUNLOCK(_controllerLock);
1054*a1e26a70SApple OSS Distributions 	return ret == kIOReturnSuccess;
1055*a1e26a70SApple OSS Distributions }
1056*a1e26a70SApple OSS Distributions 
1057*a1e26a70SApple OSS Distributions IOReturn
reclaim(void)1058*a1e26a70SApple OSS Distributions IONVRAMV3Handler::reclaim(void)
1059*a1e26a70SApple OSS Distributions {
1060*a1e26a70SApple OSS Distributions 	IOReturn             ret;
1061*a1e26a70SApple OSS Distributions 	struct               v3_store_header newStoreHeader;
1062*a1e26a70SApple OSS Distributions 	struct               v3_var_header *varHeader;
1063*a1e26a70SApple OSS Distributions 	struct               nvram_v3_var_entry *varEntry;
1064*a1e26a70SApple OSS Distributions 	OSData               *entryContainer;
1065*a1e26a70SApple OSS Distributions 	size_t               new_bank_offset = sizeof(struct v3_store_header);
1066*a1e26a70SApple OSS Distributions 	uint32_t             next_bank = (_currentBank + 1) % _bankCount;
1067*a1e26a70SApple OSS Distributions 	uint8_t              *bankData;
1068*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSArray> remainingEntries;
1069*a1e26a70SApple OSS Distributions 
1070*a1e26a70SApple OSS Distributions 	DEBUG_INFO("called\n");
1071*a1e26a70SApple OSS Distributions 	NVRAMLOCKASSERTHELD(_controllerLock);
1072*a1e26a70SApple OSS Distributions 
1073*a1e26a70SApple OSS Distributions 	bankData = (uint8_t *)IOMallocData(_bankSize);
1074*a1e26a70SApple OSS Distributions 	require_action(bankData != nullptr, exit, ret = kIOReturnNoMemory);
1075*a1e26a70SApple OSS Distributions 
1076*a1e26a70SApple OSS Distributions 	ret = _nvramController->select(next_bank);
1077*a1e26a70SApple OSS Distributions 	verify_noerr_action(ret, DEBUG_INFO("select of bank %#08x failed\n", next_bank));
1078*a1e26a70SApple OSS Distributions 
1079*a1e26a70SApple OSS Distributions 	ret = _nvramController->eraseBank();
1080*a1e26a70SApple OSS Distributions 	verify_noerr_action(ret, DEBUG_INFO("eraseBank failed, ret=%#08x\n", ret));
1081*a1e26a70SApple OSS Distributions 
1082*a1e26a70SApple OSS Distributions 	_currentBank = next_bank;
1083*a1e26a70SApple OSS Distributions 
1084*a1e26a70SApple OSS Distributions 	NVRAMREADLOCK(_variableLock);
1085*a1e26a70SApple OSS Distributions 
1086*a1e26a70SApple OSS Distributions 	remainingEntries = OSArray::withCapacity(_varEntries->getCapacity());
1087*a1e26a70SApple OSS Distributions 
1088*a1e26a70SApple OSS Distributions 	for (unsigned int i = 0; i < _varEntries->getCount(); i++) {
1089*a1e26a70SApple OSS Distributions 		entryContainer = OSDynamicCast(OSData, _varEntries->getObject(i));
1090*a1e26a70SApple OSS Distributions 		varEntry = (struct nvram_v3_var_entry *)entryContainer->getBytesNoCopy();
1091*a1e26a70SApple OSS Distributions 		varHeader = &varEntry->header;
1092*a1e26a70SApple OSS Distributions 
1093*a1e26a70SApple OSS Distributions 		DEBUG_INFO("entry %u %s, new_state=%#x, e_offset=%#lx, state=%#x\n",
1094*a1e26a70SApple OSS Distributions 		    i, varEntry->header.name_data_buf, varEntry->new_state, varEntry->existing_offset, varHeader->state);
1095*a1e26a70SApple OSS Distributions 
1096*a1e26a70SApple OSS Distributions 		if ((varEntry->new_state == VAR_NEW_STATE_NONE) ||
1097*a1e26a70SApple OSS Distributions 		    (varEntry->new_state == VAR_NEW_STATE_APPEND)) {
1098*a1e26a70SApple OSS Distributions 			varHeader->state = VAR_ADDED;
1099*a1e26a70SApple OSS Distributions 
1100*a1e26a70SApple OSS Distributions 			memcpy(bankData + new_bank_offset, (uint8_t *)varHeader, variable_length(varHeader));
1101*a1e26a70SApple OSS Distributions 
1102*a1e26a70SApple OSS Distributions 			varEntry->new_state = VAR_NEW_STATE_NONE;
1103*a1e26a70SApple OSS Distributions 			varEntry->existing_offset = new_bank_offset;
1104*a1e26a70SApple OSS Distributions 			new_bank_offset += variable_length(varHeader);
1105*a1e26a70SApple OSS Distributions 
1106*a1e26a70SApple OSS Distributions 			remainingEntries->setObject(entryContainer);
1107*a1e26a70SApple OSS Distributions 		} else {
1108*a1e26a70SApple OSS Distributions 			// entryContainer not added to remainingEntries, entry dropped
1109*a1e26a70SApple OSS Distributions 		}
1110*a1e26a70SApple OSS Distributions 	}
1111*a1e26a70SApple OSS Distributions 
1112*a1e26a70SApple OSS Distributions 	memcpy(&newStoreHeader, _nvramImage, sizeof(newStoreHeader));
1113*a1e26a70SApple OSS Distributions 
1114*a1e26a70SApple OSS Distributions 	_generation += 1;
1115*a1e26a70SApple OSS Distributions 
1116*a1e26a70SApple OSS Distributions 	newStoreHeader.generation = _generation;
1117*a1e26a70SApple OSS Distributions 
1118*a1e26a70SApple OSS Distributions 	memcpy(bankData, (uint8_t *)&newStoreHeader, sizeof(newStoreHeader));
1119*a1e26a70SApple OSS Distributions 
1120*a1e26a70SApple OSS Distributions 	ret = _nvramController->write(0, bankData, new_bank_offset);
1121*a1e26a70SApple OSS Distributions 	require_noerr_action(ret, unlock, DEBUG_ERROR("reclaim bank write failed, ret=%08x\n", ret));
1122*a1e26a70SApple OSS Distributions 
1123*a1e26a70SApple OSS Distributions 	_currentOffset = (uint32_t)new_bank_offset;
1124*a1e26a70SApple OSS Distributions 
1125*a1e26a70SApple OSS Distributions 	DEBUG_INFO("Reclaim complete, _currentBank=%u _generation=%u, _currentOffset=%#x\n", _currentBank, _generation, _currentOffset);
1126*a1e26a70SApple OSS Distributions 
1127*a1e26a70SApple OSS Distributions 	_newData = false;
1128*a1e26a70SApple OSS Distributions 	_varEntries.reset(remainingEntries.get(), OSRetain);
1129*a1e26a70SApple OSS Distributions 
1130*a1e26a70SApple OSS Distributions unlock:
1131*a1e26a70SApple OSS Distributions 	NVRAMRWUNLOCK(_variableLock);
1132*a1e26a70SApple OSS Distributions exit:
1133*a1e26a70SApple OSS Distributions 	IOFreeData(bankData, _bankSize);
1134*a1e26a70SApple OSS Distributions 
1135*a1e26a70SApple OSS Distributions 	return ret;
1136*a1e26a70SApple OSS Distributions }
1137*a1e26a70SApple OSS Distributions 
1138*a1e26a70SApple OSS Distributions size_t
getAppendSize(void)1139*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getAppendSize(void)
1140*a1e26a70SApple OSS Distributions {
1141*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry *varEntry;
1142*a1e26a70SApple OSS Distributions 	struct v3_var_header      *varHeader;
1143*a1e26a70SApple OSS Distributions 	OSData                    *entryContainer;
1144*a1e26a70SApple OSS Distributions 	size_t                    appendSize = 0;
1145*a1e26a70SApple OSS Distributions 
1146*a1e26a70SApple OSS Distributions 	NVRAMRWLOCKASSERTHELD(_variableLock);
1147*a1e26a70SApple OSS Distributions 
1148*a1e26a70SApple OSS Distributions 	for (unsigned int i = 0; i < _varEntries->getCount(); i++) {
1149*a1e26a70SApple OSS Distributions 		entryContainer = OSDynamicCast(OSData, _varEntries->getObject(i));
1150*a1e26a70SApple OSS Distributions 		varEntry = (struct nvram_v3_var_entry *)entryContainer->getBytesNoCopy();
1151*a1e26a70SApple OSS Distributions 		varHeader = &varEntry->header;
1152*a1e26a70SApple OSS Distributions 
1153*a1e26a70SApple OSS Distributions 		if (varEntry->new_state == VAR_NEW_STATE_APPEND) {
1154*a1e26a70SApple OSS Distributions 			appendSize += variable_length(varHeader);
1155*a1e26a70SApple OSS Distributions 		}
1156*a1e26a70SApple OSS Distributions 	}
1157*a1e26a70SApple OSS Distributions 
1158*a1e26a70SApple OSS Distributions 	return appendSize;
1159*a1e26a70SApple OSS Distributions }
1160*a1e26a70SApple OSS Distributions 
1161*a1e26a70SApple OSS Distributions IOReturn
syncRaw(void)1162*a1e26a70SApple OSS Distributions IONVRAMV3Handler::syncRaw(void)
1163*a1e26a70SApple OSS Distributions {
1164*a1e26a70SApple OSS Distributions 	IOReturn                  ret = kIOReturnSuccess;
1165*a1e26a70SApple OSS Distributions 	struct nvram_v3_var_entry *varEntry;
1166*a1e26a70SApple OSS Distributions 	struct v3_var_header      *varHeader;
1167*a1e26a70SApple OSS Distributions 	OSData                    *entryContainer;
1168*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSArray>      remainingEntries;
1169*a1e26a70SApple OSS Distributions 	uint8_t                   *appendBuffer = nullptr;
1170*a1e26a70SApple OSS Distributions 	size_t                    appendBufferOffset = 0;
1171*a1e26a70SApple OSS Distributions 	size_t                    *invalidateOffsets = nullptr;
1172*a1e26a70SApple OSS Distributions 	size_t                    invalidateOffsetsCount = 0;
1173*a1e26a70SApple OSS Distributions 	size_t                    invalidateOffsetIndex = 0;
1174*a1e26a70SApple OSS Distributions 	size_t                    invalidatedSize = 0;
1175*a1e26a70SApple OSS Distributions 
1176*a1e26a70SApple OSS Distributions 	require_action(_nvramController != nullptr, exit, DEBUG_INFO("No _nvramController\n"));
1177*a1e26a70SApple OSS Distributions 	require_action(_newData == true, exit, DEBUG_INFO("No _newData to sync\n"));
1178*a1e26a70SApple OSS Distributions 	require_action(_bankSize != 0, exit, DEBUG_INFO("No nvram size info\n"));
1179*a1e26a70SApple OSS Distributions 
1180*a1e26a70SApple OSS Distributions 	NVRAMREADLOCK(_variableLock);
1181*a1e26a70SApple OSS Distributions 	DEBUG_INFO("_varEntries->getCount()=%#x\n", _varEntries->getCount());
1182*a1e26a70SApple OSS Distributions 
1183*a1e26a70SApple OSS Distributions 	if (getAppendSize() + _currentOffset < _bankSize) {
1184*a1e26a70SApple OSS Distributions 		// No reclaim, build append and invalidate list
1185*a1e26a70SApple OSS Distributions 		remainingEntries = OSArray::withCapacity(_varEntries->getCapacity());
1186*a1e26a70SApple OSS Distributions 
1187*a1e26a70SApple OSS Distributions 		appendBuffer = (uint8_t *)IOMallocData(_bankSize);
1188*a1e26a70SApple OSS Distributions 		require_action(appendBuffer, unlock, ret = kIOReturnNoMemory);
1189*a1e26a70SApple OSS Distributions 
1190*a1e26a70SApple OSS Distributions 		invalidateOffsetsCount = _varEntries->getCount();
1191*a1e26a70SApple OSS Distributions 		invalidateOffsets = (size_t *)IOMallocData(invalidateOffsetsCount * sizeof(size_t));
1192*a1e26a70SApple OSS Distributions 		require_action(invalidateOffsets, unlock, ret = kIOReturnNoMemory);
1193*a1e26a70SApple OSS Distributions 
1194*a1e26a70SApple OSS Distributions 		for (unsigned int i = 0; i < _varEntries->getCount(); i++) {
1195*a1e26a70SApple OSS Distributions 			entryContainer = OSDynamicCast(OSData, _varEntries->getObject(i));
1196*a1e26a70SApple OSS Distributions 			varEntry = (struct nvram_v3_var_entry *)entryContainer->getBytesNoCopy();
1197*a1e26a70SApple OSS Distributions 			varHeader = &varEntry->header;
1198*a1e26a70SApple OSS Distributions 
1199*a1e26a70SApple OSS Distributions 			DEBUG_INFO("entry %s, new_state=%#02x state=%#02x, existing_offset=%#zx\n",
1200*a1e26a70SApple OSS Distributions 			    varEntry->header.name_data_buf, varEntry->new_state, varEntry->header.state, varEntry->existing_offset);
1201*a1e26a70SApple OSS Distributions 
1202*a1e26a70SApple OSS Distributions 			if (varEntry->new_state == VAR_NEW_STATE_APPEND) {
1203*a1e26a70SApple OSS Distributions 				size_t varSize = variable_length(varHeader);
1204*a1e26a70SApple OSS Distributions 				size_t prevOffset = varEntry->existing_offset;
1205*a1e26a70SApple OSS Distributions 
1206*a1e26a70SApple OSS Distributions 				varHeader->state = VAR_ADDED;
1207*a1e26a70SApple OSS Distributions 				varEntry->existing_offset = _currentOffset + appendBufferOffset;
1208*a1e26a70SApple OSS Distributions 				varEntry->new_state = VAR_NEW_STATE_NONE;
1209*a1e26a70SApple OSS Distributions 
1210*a1e26a70SApple OSS Distributions 				DEBUG_INFO("Appending %s in append buffer offset %#zx, actual offset %#zx, prevOffset %#zx, varsize=%#zx\n",
1211*a1e26a70SApple OSS Distributions 				    varEntry->header.name_data_buf, appendBufferOffset, varEntry->existing_offset, prevOffset, varSize);
1212*a1e26a70SApple OSS Distributions 
1213*a1e26a70SApple OSS Distributions 				// Write to append buffer
1214*a1e26a70SApple OSS Distributions 				memcpy(appendBuffer + appendBufferOffset, (uint8_t *)varHeader, varSize);
1215*a1e26a70SApple OSS Distributions 				appendBufferOffset += varSize;
1216*a1e26a70SApple OSS Distributions 
1217*a1e26a70SApple OSS Distributions 				if (prevOffset) {
1218*a1e26a70SApple OSS Distributions 					invalidateOffsets[invalidateOffsetIndex++] = prevOffset;
1219*a1e26a70SApple OSS Distributions 					invalidatedSize += variable_length((struct v3_var_header *)prevOffset);
1220*a1e26a70SApple OSS Distributions 				}
1221*a1e26a70SApple OSS Distributions 
1222*a1e26a70SApple OSS Distributions 				remainingEntries->setObject(entryContainer);
1223*a1e26a70SApple OSS Distributions 			} else if (varEntry->new_state == VAR_NEW_STATE_REMOVE) {
1224*a1e26a70SApple OSS Distributions 				if (varEntry->existing_offset) {
1225*a1e26a70SApple OSS Distributions 					DEBUG_INFO("marking entry at offset %#lx deleted\n", varEntry->existing_offset);
1226*a1e26a70SApple OSS Distributions 
1227*a1e26a70SApple OSS Distributions 					invalidateOffsets[invalidateOffsetIndex++] = varEntry->existing_offset;
1228*a1e26a70SApple OSS Distributions 					invalidatedSize += variable_length((struct v3_var_header *)varEntry->existing_offset);
1229*a1e26a70SApple OSS Distributions 				} else {
1230*a1e26a70SApple OSS Distributions 					DEBUG_INFO("No existing_offset , removing\n");
1231*a1e26a70SApple OSS Distributions 				}
1232*a1e26a70SApple OSS Distributions 
1233*a1e26a70SApple OSS Distributions 				// not re-added to remainingEntries
1234*a1e26a70SApple OSS Distributions 			} else {
1235*a1e26a70SApple OSS Distributions 				DEBUG_INFO("skipping\n");
1236*a1e26a70SApple OSS Distributions 				remainingEntries->setObject(entryContainer);
1237*a1e26a70SApple OSS Distributions 			}
1238*a1e26a70SApple OSS Distributions 		}
1239*a1e26a70SApple OSS Distributions 
1240*a1e26a70SApple OSS Distributions 		if (appendBufferOffset > 0) {
1241*a1e26a70SApple OSS Distributions 			// Write appendBuffer
1242*a1e26a70SApple OSS Distributions 			DEBUG_INFO("Appending append buffer size=%#zx at offset=%#x\n", appendBufferOffset, _currentOffset);
1243*a1e26a70SApple OSS Distributions 			ret = _nvramController->write(_currentOffset, appendBuffer, appendBufferOffset);
1244*a1e26a70SApple OSS Distributions 			require_noerr_action(ret, unlock, DEBUG_ERROR("could not re-append, ret=%#x\n", ret));
1245*a1e26a70SApple OSS Distributions 
1246*a1e26a70SApple OSS Distributions 			_currentOffset += appendBufferOffset;
1247*a1e26a70SApple OSS Distributions 		} else {
1248*a1e26a70SApple OSS Distributions 			DEBUG_INFO("No entries to append\n");
1249*a1e26a70SApple OSS Distributions 		}
1250*a1e26a70SApple OSS Distributions 
1251*a1e26a70SApple OSS Distributions 		if (invalidateOffsetIndex > 0) {
1252*a1e26a70SApple OSS Distributions 			// Invalidate Entries
1253*a1e26a70SApple OSS Distributions 			for (unsigned int i = 0; i < invalidateOffsetIndex; i++) {
1254*a1e26a70SApple OSS Distributions 				uint8_t state = VAR_ADDED & VAR_DELETED & VAR_IN_DELETED_TRANSITION;
1255*a1e26a70SApple OSS Distributions 
1256*a1e26a70SApple OSS Distributions 				ret = _nvramController->write(invalidateOffsets[i] + offsetof(struct v3_var_header, state), &state, sizeof(state));
1257*a1e26a70SApple OSS Distributions 				require_noerr_action(ret, unlock, DEBUG_ERROR("unable to invalidate at offset %#zx, ret=%#x\n", invalidateOffsets[i], ret));
1258*a1e26a70SApple OSS Distributions 				DEBUG_INFO("Invalidated entry at offset=%#zx\n", invalidateOffsets[i]);
1259*a1e26a70SApple OSS Distributions 			}
1260*a1e26a70SApple OSS Distributions 		} else {
1261*a1e26a70SApple OSS Distributions 			DEBUG_INFO("No entries to invalidate\n");
1262*a1e26a70SApple OSS Distributions 		}
1263*a1e26a70SApple OSS Distributions 
1264*a1e26a70SApple OSS Distributions 		_newData = false;
1265*a1e26a70SApple OSS Distributions 		_varEntries.reset(remainingEntries.get(), OSRetain);
1266*a1e26a70SApple OSS Distributions unlock:
1267*a1e26a70SApple OSS Distributions 		NVRAMRWUNLOCK(_variableLock);
1268*a1e26a70SApple OSS Distributions 	} else {
1269*a1e26a70SApple OSS Distributions 		// Will need to reclaim, rebuild store and write everything at once
1270*a1e26a70SApple OSS Distributions 		NVRAMRWUNLOCK(_variableLock);
1271*a1e26a70SApple OSS Distributions 		ret = reclaim();
1272*a1e26a70SApple OSS Distributions 	}
1273*a1e26a70SApple OSS Distributions 
1274*a1e26a70SApple OSS Distributions exit:
1275*a1e26a70SApple OSS Distributions 	IOFreeData(appendBuffer, _bankSize);
1276*a1e26a70SApple OSS Distributions 	IOFreeData(invalidateOffsets, invalidateOffsetsCount * sizeof(size_t));
1277*a1e26a70SApple OSS Distributions 
1278*a1e26a70SApple OSS Distributions 	return ret;
1279*a1e26a70SApple OSS Distributions }
1280*a1e26a70SApple OSS Distributions 
1281*a1e26a70SApple OSS Distributions IOReturn
syncBlock(void)1282*a1e26a70SApple OSS Distributions IONVRAMV3Handler::syncBlock(void)
1283*a1e26a70SApple OSS Distributions {
1284*a1e26a70SApple OSS Distributions 	IOReturn             ret = kIOReturnSuccess;
1285*a1e26a70SApple OSS Distributions 	struct               v3_store_header newStoreHeader;
1286*a1e26a70SApple OSS Distributions 	struct               v3_var_header *varHeader;
1287*a1e26a70SApple OSS Distributions 	struct               nvram_v3_var_entry *varEntry;
1288*a1e26a70SApple OSS Distributions 	OSData               *entryContainer;
1289*a1e26a70SApple OSS Distributions 	size_t               new_bank_offset = sizeof(struct v3_store_header);
1290*a1e26a70SApple OSS Distributions 	uint8_t              *block;
1291*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSArray> remainingEntries;
1292*a1e26a70SApple OSS Distributions 	uint32_t             next_bank = (_currentBank + 1) % _bankCount;
1293*a1e26a70SApple OSS Distributions 
1294*a1e26a70SApple OSS Distributions 	DEBUG_INFO("called\n");
1295*a1e26a70SApple OSS Distributions 
1296*a1e26a70SApple OSS Distributions 	require_action(_nvramController != nullptr, exit, DEBUG_INFO("No _nvramController\n"));
1297*a1e26a70SApple OSS Distributions 	require_action(_newData == true, exit, DEBUG_INFO("No _newData to sync\n"));
1298*a1e26a70SApple OSS Distributions 	require_action(_bankSize != 0, exit, DEBUG_INFO("No nvram size info\n"));
1299*a1e26a70SApple OSS Distributions 
1300*a1e26a70SApple OSS Distributions 	block = (uint8_t *)IOMallocData(_bankSize);
1301*a1e26a70SApple OSS Distributions 
1302*a1e26a70SApple OSS Distributions 	NVRAMREADLOCK(_variableLock);
1303*a1e26a70SApple OSS Distributions 	remainingEntries = OSArray::withCapacity(_varEntries->getCapacity());
1304*a1e26a70SApple OSS Distributions 
1305*a1e26a70SApple OSS Distributions 	ret = _nvramController->select(next_bank);
1306*a1e26a70SApple OSS Distributions 	verify_noerr_action(ret, DEBUG_INFO("select of bank %#x failed\n", next_bank));
1307*a1e26a70SApple OSS Distributions 
1308*a1e26a70SApple OSS Distributions 	ret = _nvramController->eraseBank();
1309*a1e26a70SApple OSS Distributions 	verify_noerr_action(ret, DEBUG_INFO("eraseBank failed, ret=%#08x\n", ret));
1310*a1e26a70SApple OSS Distributions 
1311*a1e26a70SApple OSS Distributions 	_currentBank = next_bank;
1312*a1e26a70SApple OSS Distributions 
1313*a1e26a70SApple OSS Distributions 	memcpy(&newStoreHeader, _nvramImage, sizeof(newStoreHeader));
1314*a1e26a70SApple OSS Distributions 
1315*a1e26a70SApple OSS Distributions 	_generation += 1;
1316*a1e26a70SApple OSS Distributions 
1317*a1e26a70SApple OSS Distributions 	newStoreHeader.generation = _generation;
1318*a1e26a70SApple OSS Distributions 
1319*a1e26a70SApple OSS Distributions 	memcpy(block, (uint8_t *)&newStoreHeader, sizeof(newStoreHeader));
1320*a1e26a70SApple OSS Distributions 
1321*a1e26a70SApple OSS Distributions 	for (unsigned int i = 0; i < _varEntries->getCount(); i++) {
1322*a1e26a70SApple OSS Distributions 		entryContainer = OSDynamicCast(OSData, _varEntries->getObject(i));
1323*a1e26a70SApple OSS Distributions 		varEntry = (struct nvram_v3_var_entry *)entryContainer->getBytesNoCopy();
1324*a1e26a70SApple OSS Distributions 		varHeader = &varEntry->header;
1325*a1e26a70SApple OSS Distributions 
1326*a1e26a70SApple OSS Distributions 		DEBUG_INFO("entry %u %s, new_state=%#x, e_offset=%#lx, state=%#x\n",
1327*a1e26a70SApple OSS Distributions 		    i, varEntry->header.name_data_buf, varEntry->new_state, varEntry->existing_offset, varHeader->state);
1328*a1e26a70SApple OSS Distributions 
1329*a1e26a70SApple OSS Distributions 		if (varEntry->new_state != VAR_NEW_STATE_REMOVE) {
1330*a1e26a70SApple OSS Distributions 			varHeader->state = VAR_ADDED;
1331*a1e26a70SApple OSS Distributions 
1332*a1e26a70SApple OSS Distributions 			memcpy(block + new_bank_offset, (uint8_t *)varHeader, variable_length(varHeader));
1333*a1e26a70SApple OSS Distributions 
1334*a1e26a70SApple OSS Distributions 			varEntry->existing_offset = new_bank_offset;
1335*a1e26a70SApple OSS Distributions 			new_bank_offset += variable_length(varHeader);
1336*a1e26a70SApple OSS Distributions 			varEntry->new_state = VAR_NEW_STATE_NONE;
1337*a1e26a70SApple OSS Distributions 
1338*a1e26a70SApple OSS Distributions 			remainingEntries->setObject(entryContainer);
1339*a1e26a70SApple OSS Distributions 		} else {
1340*a1e26a70SApple OSS Distributions 			DEBUG_INFO("Dropping %s\n", varEntry->header.name_data_buf);
1341*a1e26a70SApple OSS Distributions 		}
1342*a1e26a70SApple OSS Distributions 	}
1343*a1e26a70SApple OSS Distributions 
1344*a1e26a70SApple OSS Distributions 	ret = _nvramController->write(0, block, _bankSize);
1345*a1e26a70SApple OSS Distributions 	verify_noerr_action(ret, DEBUG_ERROR("w fail, ret=%#x\n", ret));
1346*a1e26a70SApple OSS Distributions 
1347*a1e26a70SApple OSS Distributions 	_nvramController->sync();
1348*a1e26a70SApple OSS Distributions 
1349*a1e26a70SApple OSS Distributions 	_varEntries.reset(remainingEntries.get(), OSRetain);
1350*a1e26a70SApple OSS Distributions 	NVRAMRWUNLOCK(_variableLock);
1351*a1e26a70SApple OSS Distributions 
1352*a1e26a70SApple OSS Distributions 	_newData = false;
1353*a1e26a70SApple OSS Distributions 
1354*a1e26a70SApple OSS Distributions 	DEBUG_INFO("Save complete, _generation=%u\n", _generation);
1355*a1e26a70SApple OSS Distributions 
1356*a1e26a70SApple OSS Distributions 	IOFreeData(block, _bankSize);
1357*a1e26a70SApple OSS Distributions 
1358*a1e26a70SApple OSS Distributions exit:
1359*a1e26a70SApple OSS Distributions 	return ret;
1360*a1e26a70SApple OSS Distributions }
1361*a1e26a70SApple OSS Distributions 
1362*a1e26a70SApple OSS Distributions IOReturn
sync(void)1363*a1e26a70SApple OSS Distributions IONVRAMV3Handler::sync(void)
1364*a1e26a70SApple OSS Distributions {
1365*a1e26a70SApple OSS Distributions 	IOReturn ret;
1366*a1e26a70SApple OSS Distributions 
1367*a1e26a70SApple OSS Distributions 	NVRAMLOCK(_controllerLock);
1368*a1e26a70SApple OSS Distributions 
1369*a1e26a70SApple OSS Distributions 	if (_reload) {
1370*a1e26a70SApple OSS Distributions 		ret = reloadInternal();
1371*a1e26a70SApple OSS Distributions 		if (ret != kIOReturnSuccess) {
1372*a1e26a70SApple OSS Distributions 			DEBUG_ERROR("Reload failed, ret=%#x, reclaiming\n", ret);
1373*a1e26a70SApple OSS Distributions 			ret = reclaim();
1374*a1e26a70SApple OSS Distributions 			require_noerr_action(ret, exit, DEBUG_ERROR("Reclaim recovery failed, ret=%#x\n", ret));
1375*a1e26a70SApple OSS Distributions 		}
1376*a1e26a70SApple OSS Distributions 		_reload = false;
1377*a1e26a70SApple OSS Distributions 	}
1378*a1e26a70SApple OSS Distributions 
1379*a1e26a70SApple OSS Distributions 	if (_rawController == true) {
1380*a1e26a70SApple OSS Distributions 		ret = syncRaw();
1381*a1e26a70SApple OSS Distributions 
1382*a1e26a70SApple OSS Distributions 		if (ret != kIOReturnSuccess) {
1383*a1e26a70SApple OSS Distributions 			ret = reclaim();
1384*a1e26a70SApple OSS Distributions 			require_noerr_action(ret, exit, DEBUG_ERROR("Reclaim recovery failed, ret=%#x\n", ret));
1385*a1e26a70SApple OSS Distributions 		}
1386*a1e26a70SApple OSS Distributions 	} else {
1387*a1e26a70SApple OSS Distributions 		ret = syncBlock();
1388*a1e26a70SApple OSS Distributions 	}
1389*a1e26a70SApple OSS Distributions 
1390*a1e26a70SApple OSS Distributions exit:
1391*a1e26a70SApple OSS Distributions 	NVRAMUNLOCK(_controllerLock);
1392*a1e26a70SApple OSS Distributions 	return ret;
1393*a1e26a70SApple OSS Distributions }
1394*a1e26a70SApple OSS Distributions 
1395*a1e26a70SApple OSS Distributions uint32_t
getGeneration(void) const1396*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getGeneration(void) const
1397*a1e26a70SApple OSS Distributions {
1398*a1e26a70SApple OSS Distributions 	return _generation;
1399*a1e26a70SApple OSS Distributions }
1400*a1e26a70SApple OSS Distributions 
1401*a1e26a70SApple OSS Distributions uint32_t
getVersion(void) const1402*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getVersion(void) const
1403*a1e26a70SApple OSS Distributions {
1404*a1e26a70SApple OSS Distributions 	return kNVRAMVersion3;
1405*a1e26a70SApple OSS Distributions }
1406*a1e26a70SApple OSS Distributions 
1407*a1e26a70SApple OSS Distributions uint32_t
getSystemUsed(void) const1408*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getSystemUsed(void) const
1409*a1e26a70SApple OSS Distributions {
1410*a1e26a70SApple OSS Distributions 	return _systemUsed;
1411*a1e26a70SApple OSS Distributions }
1412*a1e26a70SApple OSS Distributions 
1413*a1e26a70SApple OSS Distributions uint32_t
getCommonUsed(void) const1414*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getCommonUsed(void) const
1415*a1e26a70SApple OSS Distributions {
1416*a1e26a70SApple OSS Distributions 	return _commonUsed;
1417*a1e26a70SApple OSS Distributions }
1418*a1e26a70SApple OSS Distributions 
1419*a1e26a70SApple OSS Distributions bool
getSystemPartitionActive(void) const1420*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getSystemPartitionActive(void) const
1421*a1e26a70SApple OSS Distributions {
1422*a1e26a70SApple OSS Distributions 	return _systemSize != 0;
1423*a1e26a70SApple OSS Distributions }
1424*a1e26a70SApple OSS Distributions 
1425*a1e26a70SApple OSS Distributions bool
convertObjectToProp(uint8_t * buffer,uint32_t * length,const char * propName,OSObject * propObject)1426*a1e26a70SApple OSS Distributions IONVRAMV3Handler::convertObjectToProp(uint8_t *buffer, uint32_t *length,
1427*a1e26a70SApple OSS Distributions     const char *propName, OSObject *propObject)
1428*a1e26a70SApple OSS Distributions {
1429*a1e26a70SApple OSS Distributions 	uint32_t             offset;
1430*a1e26a70SApple OSS Distributions 	IONVRAMVariableType  propType;
1431*a1e26a70SApple OSS Distributions 	OSBoolean            *tmpBoolean = nullptr;
1432*a1e26a70SApple OSS Distributions 	OSNumber             *tmpNumber = nullptr;
1433*a1e26a70SApple OSS Distributions 	OSString             *tmpString = nullptr;
1434*a1e26a70SApple OSS Distributions 	OSData               *tmpData = nullptr;
1435*a1e26a70SApple OSS Distributions 
1436*a1e26a70SApple OSS Distributions 	propType = getVariableType(propName);
1437*a1e26a70SApple OSS Distributions 
1438*a1e26a70SApple OSS Distributions 	// Get the size of the data.
1439*a1e26a70SApple OSS Distributions 	offset = 0;
1440*a1e26a70SApple OSS Distributions 	switch (propType) {
1441*a1e26a70SApple OSS Distributions 	case kOFVariableTypeBoolean:
1442*a1e26a70SApple OSS Distributions 		tmpBoolean = OSDynamicCast(OSBoolean, propObject);
1443*a1e26a70SApple OSS Distributions 		if (tmpBoolean != nullptr) {
1444*a1e26a70SApple OSS Distributions 			const char *bool_buf;
1445*a1e26a70SApple OSS Distributions 			if (tmpBoolean->getValue()) {
1446*a1e26a70SApple OSS Distributions 				bool_buf = "true";
1447*a1e26a70SApple OSS Distributions 			} else {
1448*a1e26a70SApple OSS Distributions 				bool_buf = "false";
1449*a1e26a70SApple OSS Distributions 			}
1450*a1e26a70SApple OSS Distributions 
1451*a1e26a70SApple OSS Distributions 			offset = (uint32_t)strlen(bool_buf);
1452*a1e26a70SApple OSS Distributions 
1453*a1e26a70SApple OSS Distributions 			if (buffer) {
1454*a1e26a70SApple OSS Distributions 				if (*length < offset) {
1455*a1e26a70SApple OSS Distributions 					return false;
1456*a1e26a70SApple OSS Distributions 				} else {
1457*a1e26a70SApple OSS Distributions 					memcpy(buffer, bool_buf, offset);
1458*a1e26a70SApple OSS Distributions 				}
1459*a1e26a70SApple OSS Distributions 			}
1460*a1e26a70SApple OSS Distributions 		}
1461*a1e26a70SApple OSS Distributions 		break;
1462*a1e26a70SApple OSS Distributions 
1463*a1e26a70SApple OSS Distributions 	case kOFVariableTypeNumber:
1464*a1e26a70SApple OSS Distributions 		tmpNumber = OSDynamicCast(OSNumber, propObject);
1465*a1e26a70SApple OSS Distributions 		if (tmpNumber != nullptr) {
1466*a1e26a70SApple OSS Distributions 			char num_buf[12];
1467*a1e26a70SApple OSS Distributions 			char *end_buf = num_buf;
1468*a1e26a70SApple OSS Distributions 			uint32_t tmpValue = tmpNumber->unsigned32BitValue();
1469*a1e26a70SApple OSS Distributions 			if (tmpValue == 0xFFFFFFFF) {
1470*a1e26a70SApple OSS Distributions 				end_buf += snprintf(end_buf, sizeof(num_buf), "-1");
1471*a1e26a70SApple OSS Distributions 			} else if (tmpValue < 1000) {
1472*a1e26a70SApple OSS Distributions 				end_buf += snprintf(end_buf, sizeof(num_buf), "%d", (uint32_t)tmpValue);
1473*a1e26a70SApple OSS Distributions 			} else {
1474*a1e26a70SApple OSS Distributions 				end_buf += snprintf(end_buf, sizeof(num_buf), "%#x", (uint32_t)tmpValue);
1475*a1e26a70SApple OSS Distributions 			}
1476*a1e26a70SApple OSS Distributions 
1477*a1e26a70SApple OSS Distributions 			offset = (uint32_t)(end_buf - num_buf);
1478*a1e26a70SApple OSS Distributions 			if (buffer) {
1479*a1e26a70SApple OSS Distributions 				if (*length < offset) {
1480*a1e26a70SApple OSS Distributions 					return false;
1481*a1e26a70SApple OSS Distributions 				} else {
1482*a1e26a70SApple OSS Distributions 					memcpy(buffer, num_buf, offset);
1483*a1e26a70SApple OSS Distributions 				}
1484*a1e26a70SApple OSS Distributions 			}
1485*a1e26a70SApple OSS Distributions 		}
1486*a1e26a70SApple OSS Distributions 		break;
1487*a1e26a70SApple OSS Distributions 
1488*a1e26a70SApple OSS Distributions 	case kOFVariableTypeString:
1489*a1e26a70SApple OSS Distributions 		tmpString = OSDynamicCast(OSString, propObject);
1490*a1e26a70SApple OSS Distributions 		if (tmpString != nullptr) {
1491*a1e26a70SApple OSS Distributions 			offset = tmpString->getLength();
1492*a1e26a70SApple OSS Distributions 
1493*a1e26a70SApple OSS Distributions 			if (buffer) {
1494*a1e26a70SApple OSS Distributions 				if (*length < offset) {
1495*a1e26a70SApple OSS Distributions 					return false;
1496*a1e26a70SApple OSS Distributions 				} else {
1497*a1e26a70SApple OSS Distributions 					bcopy(tmpString->getCStringNoCopy(), buffer, offset);
1498*a1e26a70SApple OSS Distributions 				}
1499*a1e26a70SApple OSS Distributions 			}
1500*a1e26a70SApple OSS Distributions 		}
1501*a1e26a70SApple OSS Distributions 		break;
1502*a1e26a70SApple OSS Distributions 
1503*a1e26a70SApple OSS Distributions 	case kOFVariableTypeData:
1504*a1e26a70SApple OSS Distributions 		tmpData = OSDynamicCast(OSData, propObject);
1505*a1e26a70SApple OSS Distributions 		if (tmpData != nullptr) {
1506*a1e26a70SApple OSS Distributions 			offset = tmpData->getLength();
1507*a1e26a70SApple OSS Distributions 
1508*a1e26a70SApple OSS Distributions 			if (buffer) {
1509*a1e26a70SApple OSS Distributions 				if (*length < offset) {
1510*a1e26a70SApple OSS Distributions 					return false;
1511*a1e26a70SApple OSS Distributions 				} else {
1512*a1e26a70SApple OSS Distributions 					bcopy(tmpData->getBytesNoCopy(), buffer, offset);
1513*a1e26a70SApple OSS Distributions 				}
1514*a1e26a70SApple OSS Distributions 			}
1515*a1e26a70SApple OSS Distributions 		}
1516*a1e26a70SApple OSS Distributions 		break;
1517*a1e26a70SApple OSS Distributions 
1518*a1e26a70SApple OSS Distributions 	default:
1519*a1e26a70SApple OSS Distributions 		return false;
1520*a1e26a70SApple OSS Distributions 	}
1521*a1e26a70SApple OSS Distributions 
1522*a1e26a70SApple OSS Distributions 	*length = offset;
1523*a1e26a70SApple OSS Distributions 
1524*a1e26a70SApple OSS Distributions 	return offset != 0;
1525*a1e26a70SApple OSS Distributions }
1526*a1e26a70SApple OSS Distributions 
1527*a1e26a70SApple OSS Distributions 
1528*a1e26a70SApple OSS Distributions bool
convertPropToObject(const uint8_t * propName,uint32_t propNameLength,const uint8_t * propData,uint32_t propDataLength,OSSharedPtr<const OSSymbol> & propSymbol,OSSharedPtr<OSObject> & propObject)1529*a1e26a70SApple OSS Distributions IONVRAMV3Handler::convertPropToObject(const uint8_t *propName, uint32_t propNameLength,
1530*a1e26a70SApple OSS Distributions     const uint8_t *propData, uint32_t propDataLength,
1531*a1e26a70SApple OSS Distributions     OSSharedPtr<const OSSymbol>& propSymbol,
1532*a1e26a70SApple OSS Distributions     OSSharedPtr<OSObject>& propObject)
1533*a1e26a70SApple OSS Distributions {
1534*a1e26a70SApple OSS Distributions 	OSSharedPtr<const OSSymbol> tmpSymbol;
1535*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSNumber>       tmpNumber;
1536*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSString>       tmpString;
1537*a1e26a70SApple OSS Distributions 	OSSharedPtr<OSObject>       tmpObject = nullptr;
1538*a1e26a70SApple OSS Distributions 
1539*a1e26a70SApple OSS Distributions 	tmpSymbol = OSSymbol::withCString((const char *)propName);
1540*a1e26a70SApple OSS Distributions 
1541*a1e26a70SApple OSS Distributions 	if (tmpSymbol == nullptr) {
1542*a1e26a70SApple OSS Distributions 		return false;
1543*a1e26a70SApple OSS Distributions 	}
1544*a1e26a70SApple OSS Distributions 
1545*a1e26a70SApple OSS Distributions 	switch (getVariableType(tmpSymbol.get())) {
1546*a1e26a70SApple OSS Distributions 	case kOFVariableTypeBoolean:
1547*a1e26a70SApple OSS Distributions 		if (!strncmp("true", (const char *)propData, propDataLength)) {
1548*a1e26a70SApple OSS Distributions 			tmpObject.reset(kOSBooleanTrue, OSRetain);
1549*a1e26a70SApple OSS Distributions 		} else if (!strncmp("false", (const char *)propData, propDataLength)) {
1550*a1e26a70SApple OSS Distributions 			tmpObject.reset(kOSBooleanFalse, OSRetain);
1551*a1e26a70SApple OSS Distributions 		}
1552*a1e26a70SApple OSS Distributions 		break;
1553*a1e26a70SApple OSS Distributions 
1554*a1e26a70SApple OSS Distributions 	case kOFVariableTypeNumber:
1555*a1e26a70SApple OSS Distributions 		tmpNumber = OSNumber::withNumber(strtol((const char *)propData, nullptr, 0), 32);
1556*a1e26a70SApple OSS Distributions 		if (tmpNumber != nullptr) {
1557*a1e26a70SApple OSS Distributions 			tmpObject = tmpNumber;
1558*a1e26a70SApple OSS Distributions 		}
1559*a1e26a70SApple OSS Distributions 		break;
1560*a1e26a70SApple OSS Distributions 
1561*a1e26a70SApple OSS Distributions 	case kOFVariableTypeString:
1562*a1e26a70SApple OSS Distributions 		tmpString = OSString::withCString((const char *)propData, propDataLength);
1563*a1e26a70SApple OSS Distributions 		if (tmpString != nullptr) {
1564*a1e26a70SApple OSS Distributions 			tmpObject = tmpString;
1565*a1e26a70SApple OSS Distributions 		}
1566*a1e26a70SApple OSS Distributions 		break;
1567*a1e26a70SApple OSS Distributions 
1568*a1e26a70SApple OSS Distributions 	case kOFVariableTypeData:
1569*a1e26a70SApple OSS Distributions 		tmpObject = OSData::withBytes(propData, propDataLength);
1570*a1e26a70SApple OSS Distributions 		break;
1571*a1e26a70SApple OSS Distributions 
1572*a1e26a70SApple OSS Distributions 	default:
1573*a1e26a70SApple OSS Distributions 		break;
1574*a1e26a70SApple OSS Distributions 	}
1575*a1e26a70SApple OSS Distributions 
1576*a1e26a70SApple OSS Distributions 	if (tmpObject == nullptr) {
1577*a1e26a70SApple OSS Distributions 		tmpSymbol.reset();
1578*a1e26a70SApple OSS Distributions 		return false;
1579*a1e26a70SApple OSS Distributions 	}
1580*a1e26a70SApple OSS Distributions 
1581*a1e26a70SApple OSS Distributions 	propSymbol = tmpSymbol;
1582*a1e26a70SApple OSS Distributions 	propObject = tmpObject;
1583*a1e26a70SApple OSS Distributions 
1584*a1e26a70SApple OSS Distributions 	return true;
1585*a1e26a70SApple OSS Distributions }
1586*a1e26a70SApple OSS Distributions 
1587*a1e26a70SApple OSS Distributions IOReturn
getVarDict(OSSharedPtr<OSDictionary> & varDictCopy)1588*a1e26a70SApple OSS Distributions IONVRAMV3Handler::getVarDict(OSSharedPtr<OSDictionary> &varDictCopy)
1589*a1e26a70SApple OSS Distributions {
1590*a1e26a70SApple OSS Distributions 	IOReturn ret = kIOReturnNotFound;
1591*a1e26a70SApple OSS Distributions 
1592*a1e26a70SApple OSS Distributions 	NVRAMREADLOCK(_variableLock);
1593*a1e26a70SApple OSS Distributions 	if (_varDict) {
1594*a1e26a70SApple OSS Distributions 		varDictCopy = OSDictionary::withDictionary(_varDict.get());
1595*a1e26a70SApple OSS Distributions 		if (varDictCopy) {
1596*a1e26a70SApple OSS Distributions 			if (OSDictionary::withCapacity(varDictCopy->getCount()) != nullptr) {
1597*a1e26a70SApple OSS Distributions 				ret = kIOReturnSuccess;
1598*a1e26a70SApple OSS Distributions 			}
1599*a1e26a70SApple OSS Distributions 		}
1600*a1e26a70SApple OSS Distributions 	}
1601*a1e26a70SApple OSS Distributions 	NVRAMRWUNLOCK(_variableLock);
1602*a1e26a70SApple OSS Distributions 
1603*a1e26a70SApple OSS Distributions 	return ret;
1604*a1e26a70SApple OSS Distributions }
1605