Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2636