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

Archive Download this file

Revision: 2808