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