Chameleon

Chameleon Svn Source Tree

Root/tags/2.3/i386/libsaio/fake_efi.c

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

Archive Download this file

Revision: HEAD