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

Archive Download this file

Revision: 2641