Chameleon

Chameleon Svn Source Tree

Root/branches/Chimera/i386/libsaio/fake_efi.c

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

Archive Download this file

Revision: 2463