Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Chameleon/i386/libsaio/fake_efi.c

Source at commit 307 created 12 years 11 months ago.
By ifabio, merge changes from trunk (929). Also merge the module changes from Azimutz branche (fix compile error) Also edited the info.plist into AHCIPortInjector.kext: http://forum.voodooprojects.org/index.php/topic,1170.0.html
1
2/*
3 * Copyright 2007 David F. Elliott. All rights reserved.
4 */
5
6#include "libsaio.h"
7#include "boot.h"
8#include "bootstruct.h"
9#include "efi.h"
10#include "acpi.h"
11#include "fake_efi.h"
12#include "efi_tables.h"
13#include "platform.h"
14#include "acpi_patcher.h"
15#include "smbios.h"
16#include "device_inject.h"
17#include "convert.h"
18#include "pci.h"
19#include "sl.h"
20
21extern void setup_pci_devs(pci_dt_t *pci_dt);
22
23/*
24 * Modern Darwin kernels require some amount of EFI because Apple machines all
25 * have EFI. Modifying the kernel source to not require EFI is of course
26 * possible but would have to be maintained as a separate patch because it is
27 * unlikely that Apple wishes to add legacy support to their kernel.
28 *
29 * As you can see from the Apple-supplied code in bootstruct.c, it seems that
30 * the intention was clearly to modify this booter to provide EFI-like structures
31 * to the kernel rather than modifying the kernel to handle non-EFI stuff. This
32 * makes a lot of sense from an engineering point of view as it means the kernel
33 * for the as yet unreleased EFI-only Macs could still be booted by the non-EFI
34 * DTK systems so long as the kernel checked to ensure the boot tables were
35 * filled in appropriately.Modern xnu requires a system table and a runtime
36 * services table and performs no checks whatsoever to ensure the pointers to
37 * these tables are non-NULL. Therefore, any modern xnu kernel will page fault
38 * early on in the boot process if the system table pointer is zero.
39 *
40 * Even before that happens, the tsc_init function in modern xnu requires the FSB
41 * Frequency to be a property in the /efi/platform node of the device tree or else
42 * it panics the bootstrap process very early on.
43 *
44 * As of this writing, the current implementation found here is good enough
45 * to make the currently available xnu kernel boot without modification on a
46 * system with an appropriate processor. With a minor source modification to
47 * the tsc_init function to remove the explicit check for Core or Core 2
48 * processors the kernel can be made to boot on other processors so long as
49 * the code can be executed by the processor and the machine contains the
50 * necessary hardware.
51 */
52
53/*==========================================================================
54 * Utility function to make a device tree string from an EFI_GUID
55 */
56static inline char * mallocStringForGuid(EFI_GUID const *pGuid)
57{
58char *string = malloc(37);
59efi_guid_unparse_upper(pGuid, string);
60return string;
61}
62
63/*==========================================================================
64 * Function to map 32 bit physical address to 64 bit virtual address
65 */
66static uint64_t ptov64(uint32_t addr)
67{
68return ((uint64_t)addr | 0xFFFFFF8000000000ULL);
69}
70
71/*==========================================================================
72 * Fake EFI implementation
73 */
74
75/* Identify ourselves as the EFI firmware vendor */
76static EFI_CHAR16 const FIRMWARE_VENDOR[] = {'C','h','a','m','e','l','e','o','n','_','2','.','0', 0};
77static EFI_UINT32 const FIRMWARE_REVISION = 132; /* FIXME: Find a constant for this. */
78
79/* Default platform system_id (fix by IntVar) */
80static EFI_CHAR8 const SYSTEM_ID[] = "0123456789ABCDEF"; //random value gen by uuidgen
81
82/* Just a ret instruction */
83static uint8_t const VOIDRET_INSTRUCTIONS[] = {0xc3};
84
85/* movl $0x80000003,%eax; ret */
86static uint8_t const UNSUPPORTEDRET_INSTRUCTIONS[] = {0xb8, 0x03, 0x00, 0x00, 0x80, 0xc3};
87
88EFI_SYSTEM_TABLE_32 *gST32 = NULL;
89EFI_SYSTEM_TABLE_64 *gST64 = NULL;
90Node *gEfiConfigurationTableNode = NULL;
91
92extern EFI_STATUS addConfigurationTable(EFI_GUID const *pGuid, void *table, char const *alias)
93{
94EFI_UINTN i = 0;
95
96//Azi: as is, cpu's with em64t will use EFI64 on pre 10.6 systems,
97// wich seems to cause no problem. In case it does, force i386 arch.
98if (archCpuType == CPU_TYPE_I386)
99{
100i = gST32->NumberOfTableEntries;
101}
102else
103{
104i = gST64->NumberOfTableEntries;
105}
106
107// We only do adds, not modifications and deletes like InstallConfigurationTable
108if (i >= MAX_CONFIGURATION_TABLE_ENTRIES)
109stop("Ran out of space for configuration tables. Increase the reserved size in the code.\n");
110
111if (pGuid == NULL)
112return EFI_INVALID_PARAMETER;
113
114if (table != NULL)
115{
116// FIXME
117//((EFI_CONFIGURATION_TABLE_64 *)gST->ConfigurationTable)[i].VendorGuid = *pGuid;
118//((EFI_CONFIGURATION_TABLE_64 *)gST->ConfigurationTable)[i].VendorTable = (EFI_PTR64)table;
119
120//++gST->NumberOfTableEntries;
121
122Node *tableNode = DT__AddChild(gEfiConfigurationTableNode, mallocStringForGuid(pGuid));
123
124// Use the pointer to the GUID we just stuffed into the system table
125DT__AddProperty(tableNode, "guid", sizeof(EFI_GUID), (void*)pGuid);
126
127// The "table" property is the 32-bit (in our implementation) physical address of the table
128DT__AddProperty(tableNode, "table", sizeof(void*) * 2, table);
129
130// Assume the alias pointer is a global or static piece of data
131if (alias != NULL)
132DT__AddProperty(tableNode, "alias", strlen(alias)+1, (char*)alias);
133
134return EFI_SUCCESS;
135}
136return EFI_UNSUPPORTED;
137}
138
139//Azi: crc32 done in place, on the cases were it wasn't.
140/*static inline void fixupEfiSystemTableCRC32(EFI_SYSTEM_TABLE_64 *efiSystemTable)
141{
142efiSystemTable->Hdr.CRC32 = 0;
143efiSystemTable->Hdr.CRC32 = crc32(0L, efiSystemTable, efiSystemTable->Hdr.HeaderSize);
144}*/
145
146/*
147 * What we do here is simply allocate a fake EFI system table and a fake EFI
148 * runtime services table.
149 *
150 * Because we build against modern headers with kBootArgsRevision 4 we
151 * also take care to set efiMode = 32.
152 */
153void setupEfiTables32(void)
154{
155// We use the fake_efi_pages struct so that we only need to do one kernel
156// memory allocation for all needed EFI data. Otherwise, small allocations
157// like the FIRMWARE_VENDOR string would take up an entire page.
158// NOTE WELL: Do NOT assume this struct has any particular layout within itself.
159// It is absolutely not intended to be publicly exposed anywhere
160// We say pages (plural) although right now we are well within the 1 page size
161// and probably will stay that way.
162struct fake_efi_pages
163{
164EFI_SYSTEM_TABLE_32 efiSystemTable;
165EFI_RUNTIME_SERVICES_32 efiRuntimeServices;
166EFI_CONFIGURATION_TABLE_32 efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];
167EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];
168uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];
169uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS)/sizeof(uint8_t)];
170};
171
172struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));
173
174// Zero out all the tables in case fields are added later
175bzero(fakeEfiPages, sizeof(struct fake_efi_pages));
176
177// --------------------------------------------------------------------
178// Initialize some machine code that will return EFI_UNSUPPORTED for
179// functions returning int and simply return for void functions.
180memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));
181memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS, sizeof(UNSUPPORTEDRET_INSTRUCTIONS));
182
183// --------------------------------------------------------------------
184// System table
185EFI_SYSTEM_TABLE_32 *efiSystemTable = gST32 = &fakeEfiPages->efiSystemTable;
186efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
187efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;
188efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_32);
189efiSystemTable->Hdr.CRC32 = 0; // Initialize to zero and then do CRC32
190efiSystemTable->Hdr.Reserved = 0;
191
192efiSystemTable->FirmwareVendor = (EFI_PTR32)&fakeEfiPages->firmwareVendor;
193memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));
194efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;
195
196// XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
197// The EFI spec states that all handles are invalid after boot services have been
198// exited so we can probably get by with leaving the handles as zero.
199efiSystemTable->ConsoleInHandle = 0;
200efiSystemTable->ConIn = 0;
201
202efiSystemTable->ConsoleOutHandle = 0;
203efiSystemTable->ConOut = 0;
204
205efiSystemTable->StandardErrorHandle = 0;
206efiSystemTable->StdErr = 0;
207
208efiSystemTable->RuntimeServices = (EFI_PTR32)&fakeEfiPages->efiRuntimeServices;
209
210// According to the EFI spec, BootServices aren't valid after the
211// boot process is exited so we can probably do without it.
212// Apple didn't provide a definition for it in pexpert/i386/efi.h
213// so I'm guessing they don't use it.
214efiSystemTable->BootServices = 0;
215
216efiSystemTable->NumberOfTableEntries = 0;
217efiSystemTable->ConfigurationTable = (EFI_PTR32)fakeEfiPages->efiConfigurationTable;
218
219// We're done. Now CRC32 the thing so the kernel will accept it.
220// Must be initialized to zero before CRC32, done above.
221gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
222
223// --------------------------------------------------------------------
224// Runtime services
225EFI_RUNTIME_SERVICES_32 *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;
226efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;
227efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;
228efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_32);
229efiRuntimeServices->Hdr.CRC32 = 0;
230efiRuntimeServices->Hdr.Reserved = 0;
231
232// There are a number of function pointers in the efiRuntimeServices table.
233// These are the Foundation (e.g. core) services and are expected to be present on
234// all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
235// will call these without checking to see if they are null.
236//
237// We don't really feel like doing an EFI implementation in the bootloader
238// but it is nice if we can at least prevent a complete crash by
239// at least providing some sort of implementation until one can be provided
240// nicely in a kext.
241void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;
242void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;
243efiRuntimeServices->GetTime = (EFI_PTR32)unsupportedret_fp;
244efiRuntimeServices->SetTime = (EFI_PTR32)unsupportedret_fp;
245efiRuntimeServices->GetWakeupTime = (EFI_PTR32)unsupportedret_fp;
246efiRuntimeServices->SetWakeupTime = (EFI_PTR32)unsupportedret_fp;
247efiRuntimeServices->SetVirtualAddressMap = (EFI_PTR32)unsupportedret_fp;
248efiRuntimeServices->ConvertPointer = (EFI_PTR32)unsupportedret_fp;
249efiRuntimeServices->GetVariable = (EFI_PTR32)unsupportedret_fp;
250efiRuntimeServices->GetNextVariableName = (EFI_PTR32)unsupportedret_fp;
251efiRuntimeServices->SetVariable = (EFI_PTR32)unsupportedret_fp;
252efiRuntimeServices->GetNextHighMonotonicCount = (EFI_PTR32)unsupportedret_fp;
253efiRuntimeServices->ResetSystem = (EFI_PTR32)voidret_fp;
254
255// We're done.Now CRC32 the thing so the kernel will accept it
256efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);
257
258// --------------------------------------------------------------------
259// Finish filling in the rest of the boot args that we need.
260bootArgs->efiSystemTable = (uint32_t)efiSystemTable;
261bootArgs->efiMode = kBootArgsEfiMode32;
262
263// The bootArgs structure as a whole is bzero'd so we don't need to fill in
264// things like efiRuntimeServices* and what not.
265//
266// In fact, the only code that seems to use that is the hibernate code so it
267// knows not to save the pages. It even checks to make sure its nonzero.
268}
269
270void setupEfiTables64(void)
271{
272struct fake_efi_pages
273{
274EFI_SYSTEM_TABLE_64 efiSystemTable;
275EFI_RUNTIME_SERVICES_64 efiRuntimeServices;
276EFI_CONFIGURATION_TABLE_64 efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];
277EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];
278uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];
279uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS)/sizeof(uint8_t)];
280};
281
282struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));
283
284// Zero out all the tables in case fields are added later
285bzero(fakeEfiPages, sizeof(struct fake_efi_pages));
286
287// --------------------------------------------------------------------
288// Initialize some machine code that will return EFI_UNSUPPORTED for
289// functions returning int and simply return for void functions.
290memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));
291memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS, sizeof(UNSUPPORTEDRET_INSTRUCTIONS));
292
293// --------------------------------------------------------------------
294// System table
295EFI_SYSTEM_TABLE_64 *efiSystemTable = gST64 = &fakeEfiPages->efiSystemTable;
296efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
297efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;
298efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_64);
299efiSystemTable->Hdr.CRC32 = 0; // Initialize to zero and then do CRC32
300efiSystemTable->Hdr.Reserved = 0;
301
302efiSystemTable->FirmwareVendor = ptov64((EFI_PTR32)&fakeEfiPages->firmwareVendor);
303memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));
304efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;
305
306// XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
307// The EFI spec states that all handles are invalid after boot services have been
308// exited so we can probably get by with leaving the handles as zero.
309efiSystemTable->ConsoleInHandle = 0;
310efiSystemTable->ConIn = 0;
311
312efiSystemTable->ConsoleOutHandle = 0;
313efiSystemTable->ConOut = 0;
314
315efiSystemTable->StandardErrorHandle = 0;
316efiSystemTable->StdErr = 0;
317
318efiSystemTable->RuntimeServices = ptov64((EFI_PTR32)&fakeEfiPages->efiRuntimeServices);
319// According to the EFI spec, BootServices aren't valid after the
320// boot process is exited so we can probably do without it.
321// Apple didn't provide a definition for it in pexpert/i386/efi.h
322// so I'm guessing they don't use it.
323efiSystemTable->BootServices = 0;
324
325efiSystemTable->NumberOfTableEntries = 0;
326efiSystemTable->ConfigurationTable = ptov64((EFI_PTR32)fakeEfiPages->efiConfigurationTable);
327
328// We're done.Now CRC32 the thing so the kernel will accept it
329gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
330
331// --------------------------------------------------------------------
332// Runtime services
333EFI_RUNTIME_SERVICES_64 *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;
334efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;
335efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;
336efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_64);
337efiRuntimeServices->Hdr.CRC32 = 0;
338efiRuntimeServices->Hdr.Reserved = 0;
339
340// There are a number of function pointers in the efiRuntimeServices table.
341// These are the Foundation (e.g. core) services and are expected to be present on
342// all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
343// will call these without checking to see if they are null.
344//
345// We don't really feel like doing an EFI implementation in the bootloader
346// but it is nice if we can at least prevent a complete crash by
347// at least providing some sort of implementation until one can be provided
348// nicely in a kext.
349
350void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;
351void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;
352efiRuntimeServices->GetTime = ptov64((EFI_PTR32)unsupportedret_fp);
353efiRuntimeServices->SetTime = ptov64((EFI_PTR32)unsupportedret_fp);
354efiRuntimeServices->GetWakeupTime = ptov64((EFI_PTR32)unsupportedret_fp);
355efiRuntimeServices->SetWakeupTime = ptov64((EFI_PTR32)unsupportedret_fp);
356efiRuntimeServices->SetVirtualAddressMap = ptov64((EFI_PTR32)unsupportedret_fp);
357efiRuntimeServices->ConvertPointer = ptov64((EFI_PTR32)unsupportedret_fp);
358efiRuntimeServices->GetVariable = ptov64((EFI_PTR32)unsupportedret_fp);
359efiRuntimeServices->GetNextVariableName = ptov64((EFI_PTR32)unsupportedret_fp);
360efiRuntimeServices->SetVariable = ptov64((EFI_PTR32)unsupportedret_fp);
361efiRuntimeServices->GetNextHighMonotonicCount = ptov64((EFI_PTR32)unsupportedret_fp);
362efiRuntimeServices->ResetSystem = ptov64((EFI_PTR32)voidret_fp);
363
364// We're done.Now CRC32 the thing so the kernel will accept it
365efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);
366
367// --------------------------------------------------------------------
368// Finish filling in the rest of the boot args that we need.
369bootArgs->efiSystemTable = (uint32_t)efiSystemTable;
370bootArgs->efiMode = kBootArgsEfiMode64;
371
372// The bootArgs structure as a whole is bzero'd so we don't need to fill in
373// things like efiRuntimeServices* and what not.
374//
375// In fact, the only code that seems to use that is the hibernate code so it
376// knows not to save the pages. It even checks to make sure its nonzero.
377}
378
379/*
380 * In addition to the EFI tables there is also the EFI device tree node.
381 * In particular, we need /efi/platform to have an FSBFrequency key. Without it,
382 * the tsc_init function will panic very early on in kernel startup, before
383 * the console is available.
384 */
385
386/*==========================================================================
387 * FSB Frequency detection
388 */
389
390/* These should be const but DT__AddProperty takes char* */
391static const char const TSC_Frequency_prop[] = "TSCFrequency";
392static const char const FSB_Frequency_prop[] = "FSBFrequency";
393static const char const CPU_Frequency_prop[] = "CPUFrequency";
394
395/*==========================================================================
396 * SMBIOS
397 */
398
399/* From Foundation/Efi/Guid/Smbios/SmBios.c */
400EFI_GUID constgEfiSmbiosTableGuid = EFI_SMBIOS_TABLE_GUID;
401
402#define SMBIOS_RANGE_START0x000F0000
403#define SMBIOS_RANGE_END0x000FFFFF
404
405/* '_SM_' in little endian: */
406#define SMBIOS_ANCHOR_UINT32_LE 0x5f4d535f
407
408#define EFI_ACPI_TABLE_GUID \
409{ \
4100xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
411}
412
413#define EFI_ACPI_20_TABLE_GUID \
414{ \
4150x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \
416}
417
418EFI_GUID gEfiAcpiTableGuid = EFI_ACPI_TABLE_GUID;
419EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID;
420
421
422/*==========================================================================
423 * Fake EFI implementation
424 */
425
426/* These should be const but DT__AddProperty takes char* */
427static const char const FIRMWARE_REVISION_PROP[] = "firmware-revision";
428static const char const FIRMWARE_ABI_PROP[] = "firmware-abi";
429static const char const FIRMWARE_VENDOR_PROP[] = "firmware-vendor";
430static const char const FIRMWARE_ABI_32_PROP_VALUE[] = "EFI32";
431static const char const FIRMWARE_ABI_64_PROP_VALUE[] = "EFI64";
432static const char const SYSTEM_ID_PROP[] = "system-id";
433static const char const SYSTEM_SERIAL_PROP[] = "SystemSerialNumber";
434static const char const SYSTEM_TYPE_PROP[] = "system-type";
435static const char const MODEL_PROP[] = "Model";
436static const char const BOARDID_PROP[] = "board-id";
437
438/*
439 * Get an smbios option string option to convert to EFI_CHAR16 string
440 */
441static EFI_CHAR16* getSmbiosChar16(const char * key, size_t* len)
442{
443const char*src = getStringForKey(key, &bootInfo->smbiosConfig);
444EFI_CHAR16* dst = 0;
445size_t i = 0;
446
447if (!key || !(*key) || !len || !src) return 0;
448
449*len = strlen(src);
450dst = (EFI_CHAR16*) malloc( ((*len)+1) * 2 );
451for (; i < (*len); i++) dst[i] = src[i];
452dst[(*len)] = '\0';
453*len = ((*len)+1)*2; // return the CHAR16 bufsize in cluding zero terminated CHAR16
454return dst;
455}
456
457/*
458 * Get the SystemID from the bios dmi info
459 */
460staticEFI_CHAR8* getSmbiosUUID()
461{
462static EFI_CHAR8 uuid[UUID_LEN];
463int i, isZero, isOnes;
464SMBByte*p;
465
466p = (SMBByte*)Platform.UUID;
467
468for (i=0, isZero=1, isOnes=1; i<UUID_LEN; i++)
469{
470if (p[i] != 0x00) isZero = 0;
471if (p[i] != 0xff) isOnes = 0;
472}
473
474if (isZero || isOnes) // empty or setable means: no uuid present
475{
476verbose("No UUID present in SMBIOS System Information Table\n");
477return 0;
478}
479
480memcpy(uuid, p, UUID_LEN);
481return uuid;
482}
483
484/*
485 * return a binary UUID value from the overriden SystemID and SMUUID if found,
486 * or from the bios if not, or from a fixed value if no bios value is found
487 */
488static EFI_CHAR8* getSystemID()
489{
490// unable to determine UUID for host. Error: 35 fix
491// Rek: new SMsystemid option conforming to smbios notation standards, this option should
492// belong to smbios config only ...
493const char *sysId = getStringForKey(kSystemID, &bootInfo->bootConfig);
494EFI_CHAR8*ret = getUUIDFromString(sysId);
495
496if (!sysId || !ret) // try bios dmi info UUID extraction
497{
498ret = getSmbiosUUID();
499sysId = 0;
500}
501
502if (!ret) // no bios dmi UUID available, set a fixed value for system-id
503ret=getUUIDFromString((sysId = (const char*) SYSTEM_ID));
504
505verbose("Customizing SystemID with : %s\n", getStringFromUUID(ret)); // apply a nice formatting to the displayed output
506return ret;
507}
508
509/*
510 * Must be called AFTER setup Acpi because we need to take care of correct
511 * facp content to reflect in ioregs
512 */
513void setupSystemType()
514{
515Node *node = DT__FindNode("/", false);
516if (node == 0) stop("Couldn't get root node");
517// we need to write this property after facp parsing
518// Export system-type only if it has been overrriden by the SystemType option
519DT__AddProperty(node, SYSTEM_TYPE_PROP, sizeof(Platform.Type), &Platform.Type);
520}
521
522void setupEfiDeviceTree(void)
523{
524EFI_CHAR8* ret = 0;
525EFI_CHAR16* ret16 = 0;
526size_t len = 0;
527Node*node;
528
529node = DT__FindNode("/", false);
530
531if (node == 0) stop("Couldn't get root node");
532
533// We could also just do DT__FindNode("/efi/platform", true)
534// But I think eventually we want to fill stuff in the efi node
535// too so we might as well create it so we have a pointer for it too.
536node = DT__AddChild(node, "efi");
537
538if (archCpuType == CPU_TYPE_I386)
539{
540DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char*)FIRMWARE_ABI_32_PROP_VALUE);
541}
542else
543{
544DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char*)FIRMWARE_ABI_64_PROP_VALUE);
545}
546
547DT__AddProperty(node, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32*)&FIRMWARE_REVISION);
548DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16*)FIRMWARE_VENDOR);
549
550// TODO: Fill in other efi properties if necessary
551
552// Set up the /efi/runtime-services table node similar to the way a child node of configuration-table
553// is set up. That is, name and table properties
554Node *runtimeServicesNode = DT__AddChild(node, "runtime-services");
555
556if (archCpuType == CPU_TYPE_I386)
557{
558// The value of the table property is the 32-bit physical address for the RuntimeServices table.
559// Since the EFI system table already has a pointer to it, we simply use the address of that pointer
560// for the pointer to the property data. Warning.. DT finalization calls free on that but we're not
561// the only thing to use a non-malloc'd pointer for something in the DT
562
563DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST32->RuntimeServices);
564}
565else
566{
567DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST64->RuntimeServices);
568}
569
570// Set up the /efi/configuration-table node which will eventually have several child nodes for
571// all of the configuration tables needed by various kernel extensions.
572gEfiConfigurationTableNode = DT__AddChild(node, "configuration-table");
573
574// Now fill in the /efi/platform Node
575Node *efiPlatformNode = DT__AddChild(node, "platform");
576
577// NOTE WELL: If you do add FSB Frequency detection, make sure to store
578// the value in the fsbFrequency global and not an malloc'd pointer
579// because the DT_AddProperty function does not copy its args.
580
581if (Platform.CPU.FSBFrequency != 0)
582DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &Platform.CPU.FSBFrequency);
583
584// Export TSC and CPU frequencies for use by the kernel or KEXTs
585if (Platform.CPU.TSCFrequency != 0)
586DT__AddProperty(efiPlatformNode, TSC_Frequency_prop, sizeof(uint64_t), &Platform.CPU.TSCFrequency);
587
588if (Platform.CPU.CPUFrequency != 0)
589DT__AddProperty(efiPlatformNode, CPU_Frequency_prop, sizeof(uint64_t), &Platform.CPU.CPUFrequency);
590
591// Export system-id. Can be disabled with SystemId=No in com.apple.Boot.plist
592if ((ret=getSystemID()))
593DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32*) ret);
594
595// Export SystemSerialNumber if present
596if ((ret16=getSmbiosChar16("SMserial", &len)))
597DT__AddProperty(efiPlatformNode, SYSTEM_SERIAL_PROP, len, ret16);
598
599// Export Model if present
600if ((ret16=getSmbiosChar16("SMproductname", &len)))
601DT__AddProperty(efiPlatformNode, MODEL_PROP, len, ret16);
602
603// Fill /efi/device-properties node.
604setupDeviceProperties(node);
605}
606
607/*
608 * Must be called AFTER getSmbios
609 */
610void setupBoardId()
611{
612Node *node;
613node = DT__FindNode("/", false);
614if (node == 0) {
615stop("Couldn't get root node");
616}
617const char *boardid = getStringForKey("SMboardproduct", &bootInfo->smbiosConfig);
618if (boardid)
619DT__AddProperty(node, BOARDID_PROP, strlen(boardid)+1, (EFI_CHAR16*)boardid);
620}
621
622/*
623 * Load the smbios.plist override config file if any
624 */
625static void setupSmbiosConfigFile(const char *filename)
626{
627chardirSpecSMBIOS[128] = "";
628const char *override_pathname = NULL;
629intlen = 0, err = 0;
630extern void scan_mem();
631
632// Take in account user overriding
633if (getValueForKey(kSMBIOSKey, &override_pathname, &len, &bootInfo->bootConfig) && len > 0)
634{
635// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
636sprintf(dirSpecSMBIOS, override_pathname);
637err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
638}
639else
640{
641// Check selected volume's Extra.
642sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
643if (err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig))
644{
645// Check booter volume/rdbt Extra.
646sprintf(dirSpecSMBIOS, "bt(0,0)/Extra/%s", filename);
647err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
648}
649}
650
651if (err)
652{
653verbose("No SMBIOS replacement found.\n");
654}
655
656// get a chance to scan mem dynamically if user asks for it while having the config options loaded as well,
657// as opposed to when it was in scan_platform(); also load the orig. smbios so that we can access dmi info without
658// patching the smbios yet
659scan_mem();
660}
661
662/*
663 * Installs all the needed configuration table entries
664 */
665static void setupEfiConfigurationTable()
666{
667smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED);
668addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
669
670setupBoardId(); //need to be called after getSmbios
671
672// Setup ACPI with DSDT overrides (mackerintel's patch)
673setupAcpi();
674
675// We've obviously changed the count.. so fix up the CRC32
676if (archCpuType == CPU_TYPE_I386)
677{
678gST32->Hdr.CRC32 = 0;
679gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
680}
681else
682{
683gST64->Hdr.CRC32 = 0;
684gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
685}
686}
687
688void saveOriginalSMBIOS(void)
689{
690Node *node;
691SMBEntryPoint *origeps;
692void *tableAddress;
693
694node = DT__FindNode("/efi/platform", false);
695if (!node)
696{
697verbose("/efi/platform node not found\n");
698return;
699}
700
701origeps = getSmbios(SMBIOS_ORIGINAL);
702if (!origeps)
703{
704return;
705}
706
707tableAddress = (void *)AllocateKernelMemory(origeps->dmi.tableLength);
708if (!tableAddress)
709{
710return;
711}
712
713memcpy(tableAddress, (void *)origeps->dmi.tableAddress, origeps->dmi.tableLength);
714DT__AddProperty(node, "SMBIOS", origeps->dmi.tableLength, tableAddress);
715}
716
717/*
718 * Entrypoint from boot.c
719 */
720void setupFakeEfi(void)
721{
722// Generate efi device strings
723setup_pci_devs(root_pci_dev);
724
725readSMBIOSInfo(getSmbios(SMBIOS_ORIGINAL));
726
727// load smbios.plist file if any
728setupSmbiosConfigFile("smbios.plist");
729
730setupSMBIOSTable();
731
732// Initialize the base table
733if (archCpuType == CPU_TYPE_I386)
734{
735setupEfiTables32();
736}
737else
738{
739setupEfiTables64();
740}
741
742// Initialize the device tree
743setupEfiDeviceTree();
744
745saveOriginalSMBIOS();
746
747// Add configuration table entries to both the services table and the device tree
748setupEfiConfigurationTable();
749}
750
751

Archive Download this file

Revision: 307