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

Archive Download this file

Revision: 2819