Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2853