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 const char MACHINE_SIG_PROP[] = "machine-signature";
454static EFI_UINT32 DevPathSup = 1;
455
456/*
457 * Get an smbios option string option to convert to EFI_CHAR16 string
458 */
459static EFI_CHAR16 *getSmbiosChar16(const char *key, size_t *len)
460{
461const char*src = getStringForKey(key, &bootInfo->smbiosConfig);
462EFI_CHAR16* dst = 0;
463size_t i = 0;
464
465if (!key || !(*key) || !len || !src)
466{
467return 0;
468}
469
470*len = strlen(src);
471dst = (EFI_CHAR16 *) malloc( ((*len)+1) * 2 );
472for (; i < (*len); i++)
473{
474dst[i] = src[i];
475}
476dst[(*len)] = '\0';
477*len = ((*len)+1)*2; // return the CHAR16 bufsize including zero terminated CHAR16
478return dst;
479}
480
481// Bungo
482/*
483 * Get the SystemID from the bios dmi info
484
485staticEFI_CHAR8 *getSmbiosUUID()
486{
487static EFI_CHAR8uuid[UUID_LEN];
488inti;
489intisZero;
490intisOnes;
491SMBByte*p;
492
493p = (SMBByte *)Platform.UUID;
494
495for (i=0, isZero=1, isOnes=1; i<UUID_LEN; i++)
496{
497if (p[i] != 0x00)
498{
499isZero = 0;
500}
501
502if (p[i] != 0xff)
503{
504isOnes = 0;
505}
506}
507
508if (isZero || isOnes) // empty or setable means: no uuid present
509{
510verbose("No UUID present in SMBIOS System Information Table\n");
511return 0;
512}
513
514memcpy(uuid, p, UUID_LEN);
515return uuid;
516}
517
518
519// return a binary UUID value from the overriden SystemID and SMUUID if found,
520// or from the bios if not, or from a fixed value if no bios value is found
521
522static EFI_CHAR8 *getSystemID()
523{
524// unable to determine UUID for host. Error: 35 fix
525// Rek: new SMsystemid option conforming to smbios notation standards, this option should
526// belong to smbios config only ...
527const char *sysId = getStringForKey(kSystemID, &bootInfo->chameleonConfig);
528EFI_CHAR8*ret = getUUIDFromString(sysId);
529
530if (!sysId || !ret) // try bios dmi info UUID extraction
531{
532ret = getSmbiosUUID();
533sysId = 0;
534}
535
536if (!ret)
537{
538// no bios dmi UUID available, set a fixed value for system-id
539ret=getUUIDFromString((sysId = (const char *) SYSTEM_ID));
540}
541verbose("Customizing SystemID with : %s\n", getStringFromUUID(ret)); // apply a nice formatting to the displayed output
542return ret;
543}
544 */
545
546/*
547 * Must be called AFTER setupAcpi because we need to take care of correct
548 * FACP content to reflect in ioregs
549 */
550void setupSystemType()
551{
552Node *node = DT__FindNode("/", false);
553if (node == 0)
554{
555stop("Couldn't get root '/' node");
556}
557// we need to write this property after facp parsing
558// Export system-type only if it has been overrriden by the SystemType option
559DT__AddProperty(node, SYSTEM_TYPE_PROP, sizeof(Platform.Type), &Platform.Type);
560}
561
562static void setupEfiDeviceTree(void)
563{
564// EFI_CHAR8*ret = 0; Bungo: not used
565EFI_CHAR16*ret16 = 0;
566size_t len = 0;
567Node*node;
568
569node = DT__FindNode("/", false);
570
571if (node == 0)
572{
573stop("Couldn't get root node");
574}
575
576// We could also just do DT__FindNode("/efi/platform", true)
577// But I think eventually we want to fill stuff in the efi node
578// too so we might as well create it so we have a pointer for it too.
579node = DT__AddChild(node, "efi");
580
581if (archCpuType == CPU_TYPE_I386)
582{
583DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char *)FIRMWARE_ABI_32_PROP_VALUE);
584}
585else
586{
587DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char *)FIRMWARE_ABI_64_PROP_VALUE);
588}
589
590DT__AddProperty(node, EFI_MODE_PROP, sizeof(EFI_UINT8), (EFI_UINT8 *)&bootArgs->efiMode);
591
592DT__AddProperty(node, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32 *)&FIRMWARE_REVISION);
593DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16 *)FIRMWARE_VENDOR);
594
595// TODO: Fill in other efi properties if necessary
596
597// Set up the /efi/runtime-services table node similar to the way a child node of configuration-table
598// is set up. That is, name and table properties
599Node *runtimeServicesNode = DT__AddChild(node, "runtime-services");
600
601if (archCpuType == CPU_TYPE_I386)
602{
603// The value of the table property is the 32-bit physical address for the RuntimeServices table.
604// Since the EFI system table already has a pointer to it, we simply use the address of that pointer
605// for the pointer to the property data. Warning.. DT finalization calls free on that but we're not
606// the only thing to use a non-malloc'd pointer for something in the DT
607
608DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST32->RuntimeServices);
609}
610else
611{
612DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST64->RuntimeServices);
613}
614
615// Set up the /efi/configuration-table node which will eventually have several child nodes for
616// all of the configuration tables needed by various kernel extensions.
617gEfiConfigurationTableNode = DT__AddChild(node, "configuration-table");
618
619// New node: /efi/kernel-compatibility
620Node *efiKernelComNode = DT__AddChild(node, "kernel-compatibility");
621len = 1;
622DT__AddProperty(efiKernelComNode, "x86_64", sizeof(uint32_t), (EFI_UINT32 *)&len);
623
624// Now fill in the /efi/platform Node
625Node *efiPlatformNode = DT__AddChild(node, "platform");
626
627// NOTE WELL: If you do add FSB Frequency detection, make sure to store
628// the value in the fsbFrequency global and not an malloc'd pointer
629// because the DT_AddProperty function does not copy its args.
630
631if (Platform.CPU.FSBFrequency != 0)
632{
633DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &Platform.CPU.FSBFrequency);
634}
635
636// Export TSC and CPU frequencies for use by the kernel or KEXTs
637if (Platform.CPU.TSCFrequency != 0)
638{
639DT__AddProperty(efiPlatformNode, TSC_Frequency_prop, sizeof(uint64_t), &Platform.CPU.TSCFrequency);
640}
641
642if (Platform.CPU.CPUFrequency != 0)
643{
644DT__AddProperty(efiPlatformNode, CPU_Frequency_prop, sizeof(uint64_t), &Platform.CPU.CPUFrequency);
645}
646
647DT__AddProperty(efiPlatformNode,DEV_PATH_SUP, sizeof(EFI_UINT32), &DevPathSup);
648
649// Bungo
650/* Export system-id. Can be disabled with SystemId=No in com.apple.Boot.plist
651if ((ret=getSystemID()))
652{
653DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32 *) ret);
654}
655*/
656
657DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32 *)Platform.UUID);
658
659// Export SystemSerialNumber if present
660if ((ret16=getSmbiosChar16("SMserial", &len)))
661{
662DT__AddProperty(efiPlatformNode, SYSTEM_SERIAL_PROP, len, ret16);
663}
664
665// Export Model if present
666if ((ret16=getSmbiosChar16("SMproductname", &len)))
667{
668DT__AddProperty(efiPlatformNode, MODEL_PROP, len, ret16);
669}
670
671// Fill /efi/device-properties node.
672setupDeviceProperties(node);
673}
674
675/*
676 * Must be called AFTER getSmbios
677 */
678void setupBoardId()
679{
680Node *node;
681node = DT__FindNode("/", false);
682if (node == 0)
683{
684stop("Couldn't get root '/' node");
685}
686const char *boardid = getStringForKey("SMboardproduct", &bootInfo->smbiosConfig);
687if (boardid)
688{
689DT__AddProperty(node, BOARDID_PROP, strlen(boardid)+1, (EFI_CHAR16*)boardid);
690}
691}
692
693/*
694 * Populate the chosen node
695 */
696
697void setupChosenNode()
698{
699Node *chosenNode;
700chosenNode = DT__FindNode("/chosen", false);
701if (chosenNode == 0)
702{
703stop("setupChosenNode: Couldn't get '/chosen' node");
704}
705
706int length = strlen(gBootUUIDString);
707if (length)
708{
709DT__AddProperty(chosenNode, "boot-uuid", length + 1, gBootUUIDString);
710}
711
712length = strlen(bootArgs->CommandLine);
713DT__AddProperty(chosenNode, "boot-args", length + 1, bootArgs->CommandLine);
714
715length = strlen(bootInfo->bootFile);
716DT__AddProperty(chosenNode, "boot-file", length + 1, bootInfo->bootFile);
717
718//DT__AddProperty(chosenNode, "boot-device-path", bootDPsize, gBootDP);
719
720//DT__AddProperty(chosenNode, "boot-file-path", bootFPsize, gBootFP);
721
722//DT__AddProperty(chosenNode, "boot-kernelcache-adler32", sizeof(adler32), adler32);
723
724DT__AddProperty(chosenNode, MACHINE_SIG_PROP, sizeof(Platform.HWSignature), (EFI_UINT32 *)&Platform.HWSignature);
725
726if (MacOSVerCurrent >= MacOSVer2Int("10.10"))
727{
728//
729// Pike R. Alpha - 12 October 2014
730//
731UInt8 index = 0;
732EFI_UINT16 PMTimerValue = 0;
733EFI_UINT32 randomValue = 0, cpuTick = 0;
734EFI_UINT32 ecx = 0, edx = 0, esi = 0, edi = 0;
735
736// LEAF_1 - Feature Information (Function 01h).
737if (Platform.CPU.CPUID[CPUID_1][2] & 0x40000000)// Checking ecx:bit-30
738{
739//
740// i5/i7 Ivy Bridge and Haswell processors with RDRAND support.
741//
742EFI_UINT32 seedBuffer[16] = {0};
743//
744// Main loop to get 16 dwords (four bytes each).
745//
746for (index = 0; index < 16; index++)// 0x17e12:
747{
748randomValue = computeRand();// callq0x18e20
749cpuTick = (EFI_UINT32) getCPUTick();// callq0x121a7
750randomValue = (randomValue ^ cpuTick);// xor%rdi,%rax
751seedBuffer[index] = randomValue;// mov%rax,(%r15,%rsi,8)
752}// jb0x17e12
753
754DT__AddProperty(chosenNode, "random-seed", sizeof(seedBuffer), (EFI_UINT32*) &seedBuffer);
755}
756else
757{
758//
759// All other processors without RDRAND support.
760//
761EFI_UINT8 seedBuffer[64] = {0};
762//
763// Main loop to get the 64 bytes.
764//
765do// 0x17e55:
766{
767//
768// FIXME: PM Timer is usually @ 0x408, but its position is relocatable
769// via PCI-to-ISA bridge. The location is reported in ACPI FADT,
770// PM Timer Block address - zenith432
771//
772PMTimerValue = inw(0x408);// in(%dx),%ax
773esi = PMTimerValue;// movzwl%ax,%esi
774
775if (esi < ecx)// cmp%ecx,%esi
776{
777continue;// jb0x17e55(retry)
778}
779
780cpuTick = (EFI_UINT32) getCPUTick();// callq0x121a7
781//printf("value: 0x%x\n", getCPUTick());
782ecx = (cpuTick >> 8);// mov%rax,%rcx
783// shr$0x8,%rcx
784edx = (cpuTick >> 0x10);// mov%rax,%rdx
785// shr$0x10,%rdx
786edi = esi;// mov%rsi,%rdi
787edi = (edi ^ cpuTick);// xor%rax,%rdi
788edi = (edi ^ ecx);// xor%rcx,%rdi
789edi = (edi ^ edx);// xor%rdx,%rdi
790
791seedBuffer[index] = (edi & 0xff);// mov%dil,(%r15,%r12,1)
792
793edi = (edi & 0x2f);// and$0x2f,%edi
794edi = (edi + esi);// add%esi,%edi
795index++;// incr12
796ecx = (edi & 0xffff);// movzwl%di,%ecx
797
798} while (index < 64);// cmp%r14d,%r12d
799// jne0x17e55(next)
800
801DT__AddProperty(chosenNode, "random-seed", sizeof(seedBuffer), (EFI_UINT8*) &seedBuffer);
802
803}
804}
805}
806
807/*
808 * Load the smbios.plist override config file if any
809 */
810static void setupSmbiosConfigFile(const char *filename)
811{
812chardirSpecSMBIOS[128];
813const char*override_pathname = NULL;
814intlen = 0, err = 0;
815extern void scan_mem();
816
817// Take in account user overriding
818if (getValueForKey(kSMBIOSKey, &override_pathname, &len, &bootInfo->chameleonConfig) && len > 0)
819{
820// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
821strcpy(dirSpecSMBIOS, override_pathname);
822err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
823}
824else
825{
826// Check selected volume's Extra.
827sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
828err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
829}
830
831if (err)
832{
833verbose("No SMBIOS replacement found.\n");
834}
835
836// get a chance to scan mem dynamically if user asks for it while having the config options
837// loaded as well, as opposed to when it was in scan_platform(); also load the orig. smbios
838// so that we can access dmi info, without patching the smbios yet.
839scan_mem();
840}
841
842/*
843 * Installs all the needed configuration table entries
844 */
845static void setupEfiConfigurationTable()
846{
847smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED);
848addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
849
850setupBoardId(); //need to be called after getSmbios
851
852// Setup ACPI with DSDT overrides (mackerintel's patch)
853setupAcpi();
854
855// We've obviously changed the count.. so fix up the CRC32
856if (archCpuType == CPU_TYPE_I386)
857{
858gST32->Hdr.CRC32 = 0;
859gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
860}
861else
862{
863gST64->Hdr.CRC32 = 0;
864gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
865}
866
867// Setup the chosen node
868setupChosenNode();
869}
870
871void saveOriginalSMBIOS(void)
872{
873Node *node;
874SMBEntryPoint *origeps;
875void *tableAddress;
876
877node = DT__FindNode("/efi/platform", false);
878if (!node)
879{
880verbose("/efi/platform node not found\n");
881return;
882}
883
884origeps = getSmbios(SMBIOS_ORIGINAL);
885if (!origeps)
886{
887return;
888}
889
890tableAddress = (void *)AllocateKernelMemory(origeps->dmi.tableLength);
891if (!tableAddress)
892{
893return;
894}
895
896memcpy(tableAddress, (void *)origeps->dmi.tableAddress, origeps->dmi.tableLength);
897DT__AddProperty(node, "SMBIOS", origeps->dmi.tableLength, tableAddress);
898}
899
900/*
901 * Entrypoint from boot.c
902 */
903void setupFakeEfi(void)
904{
905// Generate efi device strings
906setup_pci_devs(root_pci_dev);
907
908readSMBIOSInfo(getSmbios(SMBIOS_ORIGINAL));
909
910// load smbios.plist file if any
911setupSmbiosConfigFile("smbios.plist");
912
913setupSMBIOSTable();
914
915// Initialize the base table
916if (archCpuType == CPU_TYPE_I386)
917{
918setupEfiTables32();
919}
920else
921{
922setupEfiTables64();
923}
924
925// Initialize the device tree
926setupEfiDeviceTree();
927
928saveOriginalSMBIOS();
929
930// Add configuration table entries to both the services table and the device tree
931setupEfiConfigurationTable();
932}
933

Archive Download this file

Revision: 2639