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

Archive Download this file

Revision: 2640