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

Archive Download this file

Revision: HEAD