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
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_COLORS[] = "device-colors";
470static const char DEV_PATH_SUP[] = "DevicePathsSupported";
471static const char START_POWER_EV[] = "StartupPowerEvents";
472static const char MACHINE_SIG_PROP[] = "machine-signature";
473static EFI_UINT8 const DEVICE_PATHS_SUPPORTED[] = { 0x01, 0x00, 0x00, 0x00 };
474static EFI_UINT8 const STARTUP_POWER_EVENTS[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
475static EFI_UINT8 const COMPAT_MODE[] = { 0x01, 0x00, 0x00, 0x00 };
476
477// Pike R. Alpha
478static EFI_UINT8 const BOOT_DEVICE_PATH[] =
479{
480 0x02, 0x01, 0x0C, 0x00, 0xD0, 0x41, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00,
481 0x02, 0x1F, 0x03, 0x12, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x2A, 0x00,
482 0x02, 0x00, 0x00, 0x00, 0x28, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0B, 0x63, 0x34,
483 0x00, 0x00, 0x00, 0x00, 0x65, 0x8C, 0x53, 0x3F, 0x1B, 0xCA, 0x83, 0x38, 0xA9, 0xD0, 0xF0, 0x46,
484 0x19, 0x14, 0x8E, 0x31, 0x02, 0x02, 0x7F, 0xFF, 0x04, 0x00
485};
486// Pike R. Alpha
487static EFI_UINT8 const BOOT_FILE_PATH[] =
488{
489 0x04, 0x04, 0x50, 0x00, 0x5c, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00,
490 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x62, 0x00, 0x72, 0x00, 0x61, 0x00, 0x72, 0x00,
491 0x79, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x53, 0x00, 0x65, 0x00,
492 0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x62, 0x00,
493 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x00, 0x00,
494 0x7f, 0xff, 0x04, 0x00
495};
496
497/*
498 * Get an smbios option string option to convert to EFI_CHAR16 string
499 */
500static EFI_CHAR16 *getSmbiosChar16(const char *key, size_t *len)
501{
502const char*src = getStringForKey(key, &bootInfo->smbiosConfig);
503EFI_CHAR16*dst = 0;
504size_t i = 0;
505
506if (!key || !(*key) || !len || !src)
507{
508return 0;
509}
510
511*len = strlen(src);
512dst = (EFI_CHAR16 *) malloc( ((*len)+1) * 2 );
513for (; i < (*len); i++)
514{
515dst[i] = src[i];
516}
517dst[(*len)] = '\0';
518*len = ((*len)+1)*2; // return the CHAR16 bufsize including zero terminated CHAR16
519return dst;
520}
521
522/*
523 * Must be called AFTER setupAcpi because we need to take care of correct
524 * FACP content to reflect in ioregs
525 */
526void setupSystemType()
527{
528Node *node = DT__FindNode("/", false);
529if (node == 0)
530{
531stop("Couldn't get root '/' node");
532}
533// we need to write this property after facp parsing
534// Export system-type only if it has been overrriden by the SystemType option
535DT__AddProperty(node, SYSTEM_TYPE_PROP, sizeof(Platform.Type), &Platform.Type);
536}
537
538static void setupEfiDeviceTree(void)
539{
540// EFI_CHAR8*ret = 0; Bungo: not used
541EFI_CHAR16*ret16 = 0;
542size_t len = 0;
543Node*node;
544
545node = DT__FindNode("/", false);
546
547if (node == 0)
548{
549stop("Couldn't get root node");
550}
551
552// We could also just do DT__FindNode("/efi/platform", true)
553// But I think eventually we want to fill stuff in the efi node
554// too so we might as well create it so we have a pointer for it too.
555node = DT__AddChild(node, "efi");
556
557if (archCpuType == CPU_TYPE_I386)
558{
559DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char *)FIRMWARE_ABI_32_PROP_VALUE);
560}
561else
562{
563DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char *)FIRMWARE_ABI_64_PROP_VALUE);
564}
565
566DT__AddProperty(node, EFI_MODE_PROP, sizeof(EFI_UINT8), (EFI_UINT8 *)&bootArgs->efiMode);
567
568DT__AddProperty(node, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32 *)&FIRMWARE_REVISION);
569DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16 *)FIRMWARE_VENDOR);
570
571// TODO: Fill in other efi properties if necessary
572
573// Set up the /efi/runtime-services table node similar to the way a child node of configuration-table
574// is set up. That is, name and table properties
575Node *runtimeServicesNode = DT__AddChild(node, "runtime-services");
576
577if (archCpuType == CPU_TYPE_I386)
578{
579// The value of the table property is the 32-bit physical address for the RuntimeServices table.
580// Since the EFI system table already has a pointer to it, we simply use the address of that pointer
581// for the pointer to the property data. Warning.. DT finalization calls free on that but we're not
582// the only thing to use a non-malloc'd pointer for something in the DT
583
584DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST32->RuntimeServices);
585}
586else
587{
588DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST64->RuntimeServices);
589}
590
591// Set up the /efi/configuration-table node which will eventually have several child nodes for
592// all of the configuration tables needed by various kernel extensions.
593gEfiConfigurationTableNode = DT__AddChild(node, "configuration-table");
594
595// New node: /efi/kernel-compatibility
596Node *efiKernelComNode = DT__AddChild(node, "kernel-compatibility");
597
598if (MacOSVerCurrent >= MacOSVer2Int("10.9"))
599{
600DT__AddProperty(efiKernelComNode, "x86_64", sizeof(COMPAT_MODE), (EFI_UINT8 *) &COMPAT_MODE);
601}
602else
603{
604DT__AddProperty(efiKernelComNode, "i386", sizeof(COMPAT_MODE), (EFI_UINT8 *) &COMPAT_MODE);
605DT__AddProperty(efiKernelComNode, "x86_64", sizeof(COMPAT_MODE), (EFI_UINT8 *) &COMPAT_MODE);
606}
607
608// Now fill in the /efi/platform Node
609Node *efiPlatformNode = DT__AddChild(node, "platform"); // "/efi/platform"
610
611// NOTE WELL: If you do add FSB Frequency detection, make sure to store
612// the value in the fsbFrequency global and not an malloc'd pointer
613// because the DT_AddProperty function does not copy its args.
614
615if (Platform.CPU.FSBFrequency != 0)
616{
617DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &Platform.CPU.FSBFrequency);
618}
619
620// Export TSC and CPU frequencies for use by the kernel or KEXTs
621if (Platform.CPU.TSCFrequency != 0)
622{
623DT__AddProperty(efiPlatformNode, TSC_Frequency_prop, sizeof(uint64_t), &Platform.CPU.TSCFrequency);
624}
625
626if (Platform.CPU.CPUFrequency != 0)
627{
628DT__AddProperty(efiPlatformNode, CPU_Frequency_prop, sizeof(uint64_t), &Platform.CPU.CPUFrequency);
629}
630
631DT__AddProperty(efiPlatformNode, START_POWER_EV, sizeof(STARTUP_POWER_EVENTS), (EFI_UINT8 *) &STARTUP_POWER_EVENTS);
632
633DT__AddProperty(efiPlatformNode, DEV_COLORS, sizeof(DEV_COLORS), (EFI_UINT8 *) &DEV_COLORS);
634
635DT__AddProperty(efiPlatformNode, DEV_PATH_SUP, sizeof(DEVICE_PATHS_SUPPORTED), (EFI_UINT8 *) &DEVICE_PATHS_SUPPORTED);
636
637DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32 *)Platform.UUID);
638
639// Export SystemSerialNumber if present
640if ((ret16=getSmbiosChar16("SMserial", &len)))
641{
642DT__AddProperty(efiPlatformNode, SYSTEM_SERIAL_PROP, len, ret16);
643}
644
645// Export Model if present
646if ((ret16=getSmbiosChar16("SMproductname", &len)))
647{
648DT__AddProperty(efiPlatformNode, MODEL_PROP, len, ret16);
649}
650
651// Fill /efi/device-properties node.
652setupDeviceProperties(node);
653}
654
655/*
656 * Must be called AFTER getSmbios
657 */
658void setupBoardId()
659{
660Node *node;
661node = DT__FindNode("/", false);
662if (node == 0)
663{
664stop("Couldn't get root '/' node");
665}
666const char *boardid = getStringForKey("SMboardproduct", &bootInfo->smbiosConfig); // SMboardserial
667if (boardid)
668{
669DT__AddProperty(node, BOARDID_PROP, strlen(boardid)+1, (EFI_CHAR16 *)boardid);
670}
671}
672
673/*
674 * Populate the chosen node
675 */
676void setupChosenNode()
677{
678Node *chosenNode;
679chosenNode = DT__FindNode("/chosen", false);
680unsigned long adler32 = 0;
681
682if (chosenNode == NULL)
683{
684stop("setupChosenNode: Couldn't get '/chosen' node");
685}
686
687// Only accept a UUID with the correct length.
688if (strlen(gBootUUIDString) == 36)
689{
690DT__AddProperty(chosenNode, "boot-uuid", 37, gBootUUIDString);
691}
692
693DT__AddProperty(chosenNode, "boot-args", sizeof(bootArgs->CommandLine), (EFI_UINT8 *)bootArgs->CommandLine);
694
695// Adding the default kernel name (mach_kernel) for kextcache.
696DT__AddProperty(chosenNode, "boot-file", sizeof(bootInfo->bootFile), bootInfo->bootFile);
697
698DT__AddProperty(chosenNode, "boot-file-path", sizeof(BOOT_FILE_PATH), (EFI_UINT8 *) &BOOT_FILE_PATH);
699
700// Adding the root path for kextcache.
701DT__AddProperty(chosenNode, "boot-device-path", sizeof(BOOT_DEVICE_PATH), (EFI_UINT8 *) &BOOT_DEVICE_PATH);
702
703DT__AddProperty(chosenNode, "boot-kernelcache-adler32", sizeof(unsigned long), &adler32);
704
705DT__AddProperty(chosenNode, MACHINE_SIG_PROP, sizeof(Platform.HWSignature), (EFI_UINT32 *)&Platform.HWSignature);
706
707if ( MacOSVerCurrent >= MacOSVer2Int("10.10") ) // Yosemite+
708{
709//
710// Pike R. Alpha - 12 October 2014
711//
712UInt8 index = 0;
713EFI_UINT16 PMTimerValue = 0, PMRepeatCount = 0xffff;
714
715#if RANDOMSEED
716EFI_UINT32 randomValue = 0, cpuTick = 0;
717EFI_UINT32 ecx = 0, edx = 0, esi = 0, edi = 0;
718#else
719EFI_UINT32 randomValue, tempValue, cpuTick;
720EFI_UINT32 ecx, esi, edi = 0;
721EFI_UINT64 rcx, rdx, rsi, rdi;
722
723randomValue = tempValue = ecx = esi = edi = 0;// xor%ecx,%ecx
724cpuTick = rcx = rdx = rsi = rdi = 0;
725#endif
726// LEAF_1 - Feature Information (Function 01h).
727if (Platform.CPU.CPUID[CPUID_1][2] & 0x40000000)// Checking ecx:bit-30
728{
729//
730// i5/i7 Ivy Bridge and Haswell processors with RDRAND support.
731//
732EFI_UINT32 seedBuffer[16] = {0};
733//
734// Main loop to get 16 dwords (four bytes each).
735//
736for (index = 0; index < 16; index++)// 0x17e12:
737{
738randomValue = computeRand();// callq0x18e20
739cpuTick = (EFI_UINT32) getCPUTick();// callq0x121a7
740randomValue = (randomValue ^ cpuTick);// xor%rdi,%rax
741seedBuffer[index] = randomValue;// mov%rax,(%r15,%rsi,8)
742}// jb0x17e12
743
744DT__AddProperty(chosenNode, "random-seed", sizeof(seedBuffer), (EFI_UINT32 *) &seedBuffer);
745}
746else
747{
748//
749// All other processors without RDRAND support.
750//
751EFI_UINT8 seedBuffer[64] = {0};
752//
753// Main loop to get the 64 bytes.
754//
755do// 0x17e55:
756{
757//
758// FIXME: PM Timer is usually @ 0x408, but its position is relocatable
759// via PCI-to-ISA bridge. The location is reported in ACPI FADT,
760// PM Timer Block address - zenith432
761//
762PMTimerValue = inw(0x408);// in(%dx),%ax
763esi = PMTimerValue;// movzwl%ax,%esi
764
765if (esi < ecx)// cmp%ecx,%esi
766{
767/*
768 * This is a workaround to prevent an infinite loop
769 * if PMTimer is not at port 0x408 - zenith432
770 */
771if (PMRepeatCount)
772{
773--PMRepeatCount;
774continue;// jb0x17e55(retry)
775}
776}
777else
778{
779PMRepeatCount = 0xffff;
780}
781
782cpuTick = (EFI_UINT32) getCPUTick();// callq0x121a7
783//printf("value: 0x%x\n", getCPUTick());
784
785#if RANDOMSEED
786ecx = (cpuTick >> 8);// mov%rax,%rcx
787// shr$0x8,%rcx
788edx = (cpuTick >> 0x10);// mov%rax,%rdx
789// shr$0x10,%rdx
790edi = esi;// mov%rsi,%rdi
791edi = (edi ^ cpuTick);// xor%rax,%rdi
792edi = (edi ^ ecx);// xor%rcx,%rdi
793edi = (edi ^ edx);// xor%rdx,%rdi
794
795seedBuffer[index] = (edi & 0xff);
796#else
797rcx = (cpuTick >> 8);// mov%rax,%rcx
798// shr$0x8,%rcx
799rdx = (cpuTick >> 0x10);// mov%rax,%rdx
800// shr$0x10,%rdx
801/*
802 * Note: In x86 assembly, rXX is upper part of eXX register.
803 * In C they're different variables.
804 * The code is identical with or without RANDOMSEED. - zenith432
805 */
806rdi = rsi = esi;// mov%rsi,%rdi
807rdi = (rdi ^ cpuTick);// xor%rax,%rdi
808rdi = (rdi ^ rcx);// xor%rcx,%rdi
809rdi = (rdi ^ rdx);// xor%rdx,%rdi
810edi = (EFI_UINT32) rdi;
811
812seedBuffer[index] = (rdi & 0xff);// mov%dil,(%r15,%r12,1)
813#endif
814edi = (edi & 0x2f);// and$0x2f,%edi
815edi = (edi + esi);// add%esi,%edi
816index++;// incr12
817ecx = (edi & 0xffff);// movzwl%di,%ecx
818
819} while (index < 64);// cmp%r14d,%r12d
820// jne0x17e55(next)
821
822DT__AddProperty(chosenNode, "random-seed", sizeof(seedBuffer), (EFI_UINT8 *) &seedBuffer);
823
824}
825}
826
827// Micky1979 : MIMIC booter entry for El Capitan
828if ( MacOSVerCurrent >= MacOSVer2Int("10.11") ) // El Capitan
829{
830
831verbose("Adding booter spec to the Platform Expert \n");
832
833// booter-build-time (Fri Apr 14 16:21:16 PDT 2017) 10.12.5
834DT__AddProperty(chosenNode, "booter-build-time", sizeof(I386BOOT_BUILDDATE), I386BOOT_BUILDDATE);
835
836// booter-name
837DT__AddProperty(chosenNode, "booter-name", sizeof("Chameleon"), "Chameleon");
838
839// booter-version (version:324.50.13) 10.12.5
840DT__AddProperty(chosenNode, "booter-version", sizeof(I386BOOT_CHAMELEONREVISION), I386BOOT_CHAMELEONREVISION);
841}
842}
843
844/*
845 * Load the smbios.plist override config file if any
846 */
847static void setupSmbiosConfigFile(const char *filename)
848{
849chardirSpecSMBIOS[128];
850const char*override_pathname = NULL;
851intlen = 0, err = 0;
852extern void scan_mem();
853
854// Take in account user overriding
855if (getValueForKey(kSMBIOSKey, &override_pathname, &len, &bootInfo->chameleonConfig) && len > 0)
856{
857// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
858strcpy(dirSpecSMBIOS, override_pathname);
859err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
860}
861else
862{
863// Check selected volume's Extra.
864sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
865err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
866}
867
868if (err)
869{
870verbose("No SMBIOS replacement found.\n");
871}
872
873// get a chance to scan mem dynamically if user asks for it while having the config options
874// loaded as well, as opposed to when it was in scan_platform(); also load the orig. smbios
875// so that we can access dmi info, without patching the smbios yet.
876scan_mem();
877}
878
879/*
880 * Installs all the needed configuration table entries
881 */
882static void setupEfiConfigurationTable()
883{
884smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED);
885addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
886
887setupBoardId(); //need to be called after getSmbios
888
889// Setup ACPI with DSDT overrides (mackerintel's patch)
890setupAcpi();
891
892// We've obviously changed the count.. so fix up the CRC32
893if (archCpuType == CPU_TYPE_I386)
894{
895gST32->Hdr.CRC32 = 0;
896gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
897}
898else
899{
900gST64->Hdr.CRC32 = 0;
901gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
902}
903
904// Setup the chosen node
905setupChosenNode();
906}
907
908void saveOriginalSMBIOS(void)
909{
910Node *node;
911SMBEntryPoint *origeps;
912void *tableAddress;
913
914node = DT__FindNode("/efi/platform", false);
915if (!node)
916{
917DBG("saveOriginalSMBIOS: '/efi/platform' node not found\n");
918return;
919}
920
921origeps = getSmbios(SMBIOS_ORIGINAL);
922if (!origeps)
923{
924DBG("saveOriginalSMBIOS: original SMBIOS not found\n");
925return;
926}
927
928tableAddress = (void *)AllocateKernelMemory(origeps->dmi.tableLength);
929if (!tableAddress)
930{
931DBG("saveOriginalSMBIOS: can not allocate memory for original SMBIOS\n");
932return;
933}
934
935memcpy(tableAddress, (void *)origeps->dmi.tableAddress, origeps->dmi.tableLength);
936DT__AddProperty(node, "SMBIOS", origeps->dmi.tableLength, tableAddress);
937}
938
939/*
940 * Entrypoint from boot.c
941 */
942void setupFakeEfi(void)
943{
944// Generate efi device strings
945setup_pci_devs(root_pci_dev);
946
947readSMBIOSInfo(getSmbios(SMBIOS_ORIGINAL));
948
949// load smbios.plist file if any
950setupSmbiosConfigFile("smbios.plist");
951
952setupSMBIOSTable();
953
954// Initialize the base table
955if (archCpuType == CPU_TYPE_I386)
956{
957setupEfiTables32();
958}
959else
960{
961setupEfiTables64();
962}
963
964// Initialize the device tree
965setupEfiDeviceTree();
966
967saveOriginalSMBIOS();
968
969// Add configuration table entries to both the services table and the device tree
970setupEfiConfigurationTable();
971}
972

Archive Download this file

Revision: 2918