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

Archive Download this file

Revision: 2524