Chameleon

Chameleon Svn Source Tree

Root/branches/Bungo/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
21extern void setup_pci_devs(pci_dt_t *pci_dt);
22
23/*
24 * Modern Darwin kernels require some amount of EFI because Apple machines all
25 * have EFI. Modifying the kernel source to not require EFI is of course
26 * possible but would have to be maintained as a separate patch because it is
27 * unlikely that Apple wishes to add legacy support to their kernel.
28 *
29 * As you can see from the Apple-supplied code in bootstruct.c, it seems that
30 * the intention was clearly to modify this booter to provide EFI-like structures
31 * to the kernel rather than modifying the kernel to handle non-EFI stuff. This
32 * makes a lot of sense from an engineering point of view as it means the kernel
33 * for the as yet unreleased EFI-only Macs could still be booted by the non-EFI
34 * DTK systems so long as the kernel checked to ensure the boot tables were
35 * filled in appropriately.Modern xnu requires a system table and a runtime
36 * services table and performs no checks whatsoever to ensure the pointers to
37 * these tables are non-NULL. Therefore, any modern xnu kernel will page fault
38 * early on in the boot process if the system table pointer is zero.
39 *
40 * Even before that happens, the tsc_init function in modern xnu requires the FSB
41 * Frequency to be a property in the /efi/platform node of the device tree or else
42 * it panics the bootstrap process very early on.
43 *
44 * As of this writing, the current implementation found here is good enough
45 * to make the currently available xnu kernel boot without modification on a
46 * system with an appropriate processor. With a minor source modification to
47 * the tsc_init function to remove the explicit check for Core or Core 2
48 * processors the kernel can be made to boot on other processors so long as
49 * the code can be executed by the processor and the machine contains the
50 * necessary hardware.
51 */
52
53/*==========================================================================
54 * Utility function to make a device tree string from an EFI_GUID
55 */
56static inline char * mallocStringForGuid(EFI_GUID const *pGuid)
57{
58char *string = malloc(37);
59efi_guid_unparse_upper(pGuid, string);
60return string;
61}
62
63/*==========================================================================
64 * Function to map 32 bit physical address to 64 bit virtual address
65 */
66static uint64_t ptov64(uint32_t addr)
67{
68return ((uint64_t)addr | 0xFFFFFF8000000000ULL);
69}
70
71/*==========================================================================
72 * Fake EFI implementation
73 */
74
75/* Identify ourselves as the EFI firmware vendor */
76static EFI_CHAR16 const FIRMWARE_VENDOR[] = {'C','h','a','m','e','l','e','o','n','_','2','.','2', 0};
77// Bungo
78//static EFI_UINT32 const FIRMWARE_REVISION = 132; /* FIXME: Find a constant for this. */
79static EFI_UINT32 const FIRMWARE_REVISION = 0x0001000a; // got from real MBP6,1
80// Bungo
81/* Default platform system_id (fix by IntVar)
82 static EFI_CHAR8 const SYSTEM_ID[] = "0123456789ABCDEF"; //random value gen by uuidgen
83 */
84
85/* Just a ret instruction */
86static uint8_t const VOIDRET_INSTRUCTIONS[] = {0xc3};
87
88/* movl $0x80000003,%eax; ret */
89static uint8_t const UNSUPPORTEDRET_INSTRUCTIONS_32[] = {0xb8, 0x03, 0x00, 0x00, 0x80, 0xc3};
90static uint8_t const UNSUPPORTEDRET_INSTRUCTIONS_64[] = {0x48, 0xb8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc3};
91
92EFI_SYSTEM_TABLE_32 *gST32 = NULL;
93EFI_SYSTEM_TABLE_64 *gST64 = NULL;
94Node *gEfiConfigurationTableNode = NULL;
95
96extern EFI_STATUS addConfigurationTable(EFI_GUID const *pGuid, void *table, char const *alias)
97{
98EFI_UINTN i = 0;
99
100//Azi: as is, cpu's with em64t will use EFI64 on pre 10.6 systems,
101// wich seems to cause no problem. In case it does, force i386 arch.
102if (archCpuType == CPU_TYPE_I386)
103{
104i = gST32->NumberOfTableEntries;
105}
106else
107{
108i = gST64->NumberOfTableEntries;
109}
110
111// We only do adds, not modifications and deletes like InstallConfigurationTable
112if (i >= MAX_CONFIGURATION_TABLE_ENTRIES)
113{
114stop("Ran out of space for configuration tables. Increase the reserved size in the code.\n");
115}
116
117if (pGuid == NULL)
118{
119return EFI_INVALID_PARAMETER;
120}
121
122if (table != NULL)
123{
124// FIXME
125//((EFI_CONFIGURATION_TABLE_64 *)gST->ConfigurationTable)[i].VendorGuid = *pGuid;
126//((EFI_CONFIGURATION_TABLE_64 *)gST->ConfigurationTable)[i].VendorTable = (EFI_PTR64)table;
127
128//++gST->NumberOfTableEntries;
129
130Node *tableNode = DT__AddChild(gEfiConfigurationTableNode, mallocStringForGuid(pGuid));
131
132// Use the pointer to the GUID we just stuffed into the system table
133DT__AddProperty(tableNode, "guid", sizeof(EFI_GUID), (void*)pGuid);
134
135// The "table" property is the 32-bit (in our implementation) physical address of the table
136DT__AddProperty(tableNode, "table", sizeof(void*) * 2, table);
137
138// Assume the alias pointer is a global or static piece of data
139if (alias != NULL)
140{
141DT__AddProperty(tableNode, "alias", strlen(alias)+1, (char*)alias);
142}
143
144return EFI_SUCCESS;
145}
146return EFI_UNSUPPORTED;
147}
148
149//Azi: crc32 done in place, on the cases were it wasn't.
150/*static inline void fixupEfiSystemTableCRC32(EFI_SYSTEM_TABLE_64 *efiSystemTable)
151{
152efiSystemTable->Hdr.CRC32 = 0;
153efiSystemTable->Hdr.CRC32 = crc32(0L, efiSystemTable, efiSystemTable->Hdr.HeaderSize);
154}*/
155
156/*
157 * What we do here is simply allocate a fake EFI system table and a fake EFI
158 * runtime services table.
159 *
160 * Because we build against modern headers with kBootArgsRevision 4 we
161 * also take care to set efiMode = 32.
162 */
163void setupEfiTables32(void)
164{
165// We use the fake_efi_pages struct so that we only need to do one kernel
166// memory allocation for all needed EFI data. Otherwise, small allocations
167// like the FIRMWARE_VENDOR string would take up an entire page.
168// NOTE WELL: Do NOT assume this struct has any particular layout within itself.
169// It is absolutely not intended to be publicly exposed anywhere
170// We say pages (plural) although right now we are well within the 1 page size
171// and probably will stay that way.
172struct fake_efi_pages
173{
174EFI_SYSTEM_TABLE_32 efiSystemTable;
175EFI_RUNTIME_SERVICES_32 efiRuntimeServices;
176EFI_CONFIGURATION_TABLE_32 efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];
177EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];
178uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];
179uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS_32)/sizeof(uint8_t)];
180};
181
182struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));
183
184// Zero out all the tables in case fields are added later
185//bzero(fakeEfiPages, sizeof(struct fake_efi_pages));
186
187// --------------------------------------------------------------------
188// Initialize some machine code that will return EFI_UNSUPPORTED for
189// functions returning int and simply return for void functions.
190memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));
191memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS_32, sizeof(UNSUPPORTEDRET_INSTRUCTIONS_32));
192
193// --------------------------------------------------------------------
194// System table
195EFI_SYSTEM_TABLE_32 *efiSystemTable = gST32 = &fakeEfiPages->efiSystemTable;
196efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
197efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;
198efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_32);
199efiSystemTable->Hdr.CRC32 = 0; // Initialize to zero and then do CRC32
200efiSystemTable->Hdr.Reserved = 0;
201
202efiSystemTable->FirmwareVendor = (EFI_PTR32)&fakeEfiPages->firmwareVendor;
203memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));
204efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;
205
206// XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
207// The EFI spec states that all handles are invalid after boot services have been
208// exited so we can probably get by with leaving the handles as zero.
209efiSystemTable->ConsoleInHandle = 0;
210efiSystemTable->ConIn = 0;
211
212efiSystemTable->ConsoleOutHandle = 0;
213efiSystemTable->ConOut = 0;
214
215efiSystemTable->StandardErrorHandle = 0;
216efiSystemTable->StdErr = 0;
217
218efiSystemTable->RuntimeServices = (EFI_PTR32)&fakeEfiPages->efiRuntimeServices;
219
220// According to the EFI spec, BootServices aren't valid after the
221// boot process is exited so we can probably do without it.
222// Apple didn't provide a definition for it in pexpert/i386/efi.h
223// so I'm guessing they don't use it.
224efiSystemTable->BootServices = 0;
225
226efiSystemTable->NumberOfTableEntries = 0;
227efiSystemTable->ConfigurationTable = (EFI_PTR32)fakeEfiPages->efiConfigurationTable;
228
229// We're done. Now CRC32 the thing so the kernel will accept it.
230// Must be initialized to zero before CRC32, done above.
231gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
232
233// --------------------------------------------------------------------
234// Runtime services
235EFI_RUNTIME_SERVICES_32 *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;
236efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;
237efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;
238efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_32);
239efiRuntimeServices->Hdr.CRC32 = 0;
240efiRuntimeServices->Hdr.Reserved = 0;
241
242// There are a number of function pointers in the efiRuntimeServices table.
243// These are the Foundation (e.g. core) services and are expected to be present on
244// all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
245// will call these without checking to see if they are null.
246//
247// We don't really feel like doing an EFI implementation in the bootloader
248// but it is nice if we can at least prevent a complete crash by
249// at least providing some sort of implementation until one can be provided
250// nicely in a kext.
251void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;
252void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;
253efiRuntimeServices->GetTime = (EFI_PTR32)unsupportedret_fp;
254efiRuntimeServices->SetTime = (EFI_PTR32)unsupportedret_fp;
255efiRuntimeServices->GetWakeupTime = (EFI_PTR32)unsupportedret_fp;
256efiRuntimeServices->SetWakeupTime = (EFI_PTR32)unsupportedret_fp;
257efiRuntimeServices->SetVirtualAddressMap = (EFI_PTR32)unsupportedret_fp;
258efiRuntimeServices->ConvertPointer = (EFI_PTR32)unsupportedret_fp;
259efiRuntimeServices->GetVariable = (EFI_PTR32)unsupportedret_fp;
260efiRuntimeServices->GetNextVariableName = (EFI_PTR32)unsupportedret_fp;
261efiRuntimeServices->SetVariable = (EFI_PTR32)unsupportedret_fp;
262efiRuntimeServices->GetNextHighMonotonicCount = (EFI_PTR32)unsupportedret_fp;
263efiRuntimeServices->ResetSystem = (EFI_PTR32)voidret_fp;
264
265// We're done.Now CRC32 the thing so the kernel will accept it
266efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);
267
268// --------------------------------------------------------------------
269// Finish filling in the rest of the boot args that we need.
270bootArgs->efiSystemTable = (uint32_t)efiSystemTable;
271bootArgs->efiMode = kBootArgsEfiMode32;
272
273// The bootArgs structure as a whole is bzero'd so we don't need to fill in
274// things like efiRuntimeServices* and what not.
275//
276// In fact, the only code that seems to use that is the hibernate code so it
277// knows not to save the pages. It even checks to make sure its nonzero.
278}
279
280void setupEfiTables64(void)
281{
282struct fake_efi_pages
283{
284EFI_SYSTEM_TABLE_64 efiSystemTable;
285EFI_RUNTIME_SERVICES_64 efiRuntimeServices;
286EFI_CONFIGURATION_TABLE_64 efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];
287EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];
288uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];
289uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS_64)/sizeof(uint8_t)];
290};
291
292struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));
293
294// Zero out all the tables in case fields are added later
295//bzero(fakeEfiPages, sizeof(struct fake_efi_pages));
296
297// --------------------------------------------------------------------
298// Initialize some machine code that will return EFI_UNSUPPORTED for
299// functions returning int and simply return for void functions.
300memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));
301memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS_64, sizeof(UNSUPPORTEDRET_INSTRUCTIONS_64));
302
303// --------------------------------------------------------------------
304// System table
305EFI_SYSTEM_TABLE_64 *efiSystemTable = gST64 = &fakeEfiPages->efiSystemTable;
306efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
307efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;
308efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_64);
309efiSystemTable->Hdr.CRC32 = 0; // Initialize to zero and then do CRC32
310efiSystemTable->Hdr.Reserved = 0;
311
312efiSystemTable->FirmwareVendor = ptov64((EFI_PTR32)&fakeEfiPages->firmwareVendor);
313memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));
314efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;
315
316// XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
317// The EFI spec states that all handles are invalid after boot services have been
318// exited so we can probably get by with leaving the handles as zero.
319efiSystemTable->ConsoleInHandle = 0;
320efiSystemTable->ConIn = 0;
321
322efiSystemTable->ConsoleOutHandle = 0;
323efiSystemTable->ConOut = 0;
324
325efiSystemTable->StandardErrorHandle = 0;
326efiSystemTable->StdErr = 0;
327
328efiSystemTable->RuntimeServices = ptov64((EFI_PTR32)&fakeEfiPages->efiRuntimeServices);
329// According to the EFI spec, BootServices aren't valid after the
330// boot process is exited so we can probably do without it.
331// Apple didn't provide a definition for it in pexpert/i386/efi.h
332// so I'm guessing they don't use it.
333efiSystemTable->BootServices = 0;
334
335efiSystemTable->NumberOfTableEntries = 0;
336efiSystemTable->ConfigurationTable = ptov64((EFI_PTR32)fakeEfiPages->efiConfigurationTable);
337
338// We're done.Now CRC32 the thing so the kernel will accept it
339gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
340
341// --------------------------------------------------------------------
342// Runtime services
343EFI_RUNTIME_SERVICES_64 *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;
344efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;
345efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;
346efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_64);
347efiRuntimeServices->Hdr.CRC32 = 0;
348efiRuntimeServices->Hdr.Reserved = 0;
349
350// There are a number of function pointers in the efiRuntimeServices table.
351// These are the Foundation (e.g. core) services and are expected to be present on
352// all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
353// will call these without checking to see if they are null.
354//
355// We don't really feel like doing an EFI implementation in the bootloader
356// but it is nice if we can at least prevent a complete crash by
357// at least providing some sort of implementation until one can be provided
358// nicely in a kext.
359
360void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;
361void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;
362efiRuntimeServices->GetTime = ptov64((EFI_PTR32)unsupportedret_fp);
363efiRuntimeServices->SetTime = ptov64((EFI_PTR32)unsupportedret_fp);
364efiRuntimeServices->GetWakeupTime = ptov64((EFI_PTR32)unsupportedret_fp);
365efiRuntimeServices->SetWakeupTime = ptov64((EFI_PTR32)unsupportedret_fp);
366efiRuntimeServices->SetVirtualAddressMap = ptov64((EFI_PTR32)unsupportedret_fp);
367efiRuntimeServices->ConvertPointer = ptov64((EFI_PTR32)unsupportedret_fp);
368efiRuntimeServices->GetVariable = ptov64((EFI_PTR32)unsupportedret_fp);
369efiRuntimeServices->GetNextVariableName = ptov64((EFI_PTR32)unsupportedret_fp);
370efiRuntimeServices->SetVariable = ptov64((EFI_PTR32)unsupportedret_fp);
371efiRuntimeServices->GetNextHighMonotonicCount = ptov64((EFI_PTR32)unsupportedret_fp);
372efiRuntimeServices->ResetSystem = ptov64((EFI_PTR32)voidret_fp);
373
374// We're done.Now CRC32 the thing so the kernel will accept it
375efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);
376
377// --------------------------------------------------------------------
378// Finish filling in the rest of the boot args that we need.
379bootArgs->efiSystemTable = (uint32_t)efiSystemTable;
380bootArgs->efiMode = kBootArgsEfiMode64;
381
382// The bootArgs structure as a whole is bzero'd so we don't need to fill in
383// things like efiRuntimeServices* and what not.
384//
385// In fact, the only code that seems to use that is the hibernate code so it
386// knows not to save the pages. It even checks to make sure its nonzero.
387}
388
389/*
390 * In addition to the EFI tables there is also the EFI device tree node.
391 * In particular, we need /efi/platform to have an FSBFrequency key. Without it,
392 * the tsc_init function will panic very early on in kernel startup, before
393 * the console is available.
394 */
395
396/*==========================================================================
397 * FSB Frequency detection
398 */
399
400/* These should be const but DT__AddProperty takes char* */
401static const char TSC_Frequency_prop[] = "TSCFrequency";
402static const char FSB_Frequency_prop[] = "FSBFrequency";
403static const char CPU_Frequency_prop[] = "CPUFrequency";
404
405/*==========================================================================
406 * SMBIOS
407 */
408
409/* From Foundation/Efi/Guid/Smbios/SmBios.c */
410EFI_GUID constgEfiSmbiosTableGuid = EFI_SMBIOS_TABLE_GUID;
411
412#define SMBIOS_RANGE_START0x000F0000
413#define SMBIOS_RANGE_END0x000FFFFF
414
415/* '_SM_' in little endian: */
416#define SMBIOS_ANCHOR_UINT32_LE 0x5f4d535f
417
418#define EFI_ACPI_TABLE_GUID \
419{ \
4200xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
421}
422
423#define EFI_ACPI_20_TABLE_GUID \
424{ \
4250x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \
426}
427
428EFI_GUID gEfiAcpiTableGuid = EFI_ACPI_TABLE_GUID;
429EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID;
430
431
432/*==========================================================================
433 * Fake EFI implementation
434 */
435
436/* These should be const but DT__AddProperty takes char* */
437static const char FIRMWARE_REVISION_PROP[] = "firmware-revision";
438static const char FIRMWARE_ABI_PROP[] = "firmware-abi";
439static const char FIRMWARE_VENDOR_PROP[] = "firmware-vendor";
440static const char FIRMWARE_ABI_32_PROP_VALUE[] = "EFI32";
441static const char FIRMWARE_ABI_64_PROP_VALUE[] = "EFI64";
442static const char EFI_MODE_PROP[] = "efi-mode"; //Bungo
443static const char SYSTEM_ID_PROP[] = "system-id";
444static const char SYSTEM_SERIAL_PROP[] = "SystemSerialNumber";
445static const char SYSTEM_TYPE_PROP[] = "system-type";
446static const char MODEL_PROP[] = "Model";
447static const char BOARDID_PROP[] = "board-id";
448static const char DEV_PATH_SUP[] = "DevicePathsSupported";
449static EFI_UINT32 DevPathSup = 1;
450static EFI_UINT32 MachineSig = 0; //Bungo
451static EFI_UINT8 const RANDOM_SEED[] =
452{
453 0x40, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00,
454 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x62, 0x00, 0x72, 0x00, 0x61, 0x00, 0x72, 0x00,
455 0x79, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x53, 0x00, 0x65, 0x00,
456 0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x62, 0x00
457};
458
459/*
460 * Get an smbios option string option to convert to EFI_CHAR16 string
461 */
462static EFI_CHAR16* getSmbiosChar16(const char * key, size_t* len)
463{
464const char*src = getStringForKey(key, &bootInfo->smbiosConfig);
465EFI_CHAR16* dst = 0;
466size_t i = 0;
467
468if (!key || !(*key) || !len || !src)
469{
470return 0;
471}
472
473*len = strlen(src);
474dst = (EFI_CHAR16*) malloc( ((*len)+1) * 2 );
475for (; i < (*len); i++)
476{
477dst[i] = src[i];
478}
479dst[(*len)] = '\0';
480*len = ((*len)+1)*2; // return the CHAR16 bufsize including zero terminated CHAR16
481return dst;
482}
483
484// Bungo
485/*
486 * Get the SystemID from the bios dmi info
487
488staticEFI_CHAR8* getSmbiosUUID()
489{
490static EFI_CHAR8 uuid[UUID_LEN];
491int i, isZero, isOnes;
492SMBByte*p;
493
494p = (SMBByte*)Platform.UUID;
495
496for (i=0, isZero=1, isOnes=1; i<UUID_LEN; i++)
497{
498if (p[i] != 0x00)
499{
500isZero = 0;
501}
502
503if (p[i] != 0xff)
504{
505isOnes = 0;
506}
507}
508
509if (isZero || isOnes) // empty or setable means: no uuid present
510{
511verbose("No UUID present in SMBIOS System Information Table\n");
512return 0;
513}
514
515memcpy(uuid, p, UUID_LEN);
516return uuid;
517}
518
519
520// return a binary UUID value from the overriden SystemID and SMUUID if found,
521// or from the bios if not, or from a fixed value if no bios value is found
522
523static EFI_CHAR8* getSystemID()
524{
525// unable to determine UUID for host. Error: 35 fix
526// Rek: new SMsystemid option conforming to smbios notation standards, this option should
527// belong to smbios config only ...
528const char *sysId = getStringForKey(kSystemID, &bootInfo->chameleonConfig);
529EFI_CHAR8*ret = getUUIDFromString(sysId);
530
531if (!sysId || !ret) // try bios dmi info UUID extraction
532{
533ret = getSmbiosUUID();
534sysId = 0;
535}
536
537if (!ret)
538{
539// no bios dmi UUID available, set a fixed value for system-id
540ret=getUUIDFromString((sysId = (const char*) SYSTEM_ID));
541}
542verbose("Customizing SystemID with : %s\n", getStringFromUUID(ret)); // apply a nice formatting to the displayed output
543return ret;
544}
545 */
546
547/*
548 * Must be called AFTER setup Acpi because we need to take care of correct
549 * facp content to reflect in ioregs
550 */
551void setupSystemType()
552{
553Node *node = DT__FindNode("/", false);
554if (node == 0)
555{
556stop("Couldn't get root node");
557}
558// we need to write this property after facp parsing
559// Export system-type only if it has been overrriden by the SystemType option
560DT__AddProperty(node, SYSTEM_TYPE_PROP, sizeof(Platform.Type), &Platform.Type);
561}
562
563void setupEfiDeviceTree(void)
564{
565// EFI_CHAR8* ret = 0; Bungo: not used
566EFI_CHAR16* ret16 = 0;
567size_t len = 0;
568Node*node;
569
570node = DT__FindNode("/", false);
571
572if (node == 0)
573{
574stop("Couldn't get root node");
575}
576
577// We could also just do DT__FindNode("/efi/platform", true)
578// But I think eventually we want to fill stuff in the efi node
579// too so we might as well create it so we have a pointer for it too.
580node = DT__AddChild(node, "efi");
581/* Bungo
582if (archCpuType == CPU_TYPE_I386) {
583DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char*)FIRMWARE_ABI_32_PROP_VALUE);
584} else { */
585DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char *)FIRMWARE_ABI_64_PROP_VALUE);
586//}
587
588DT__AddProperty(node, EFI_MODE_PROP, sizeof(EFI_UINT8), (EFI_UINT8 *)&bootArgs->efiMode);
589
590DT__AddProperty(node, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32 *)&FIRMWARE_REVISION);
591DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16 *)FIRMWARE_VENDOR);
592
593// TODO: Fill in other efi properties if necessary
594
595// Set up the /efi/runtime-services table node similar to the way a child node of configuration-table
596// is set up. That is, name and table properties
597Node *runtimeServicesNode = DT__AddChild(node, "runtime-services");
598
599if (archCpuType == CPU_TYPE_I386) {
600// The value of the table property is the 32-bit physical address for the RuntimeServices table.
601// Since the EFI system table already has a pointer to it, we simply use the address of that pointer
602// for the pointer to the property data. Warning.. DT finalization calls free on that but we're not
603// the only thing to use a non-malloc'd pointer for something in the DT
604
605DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST32->RuntimeServices);
606} else {
607DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST64->RuntimeServices);
608}
609
610// Set up the /efi/configuration-table node which will eventually have several child nodes for
611// all of the configuration tables needed by various kernel extensions.
612gEfiConfigurationTableNode = DT__AddChild(node, "configuration-table");
613
614// New node: /efi/kernel-compatibility
615Node *efiKernelComNode = DT__AddChild(node, "kernel-compatibility");
616 len = 1;
617 DT__AddProperty(efiKernelComNode, "x86_64", sizeof(uint32_t), (EFI_UINT32 *)&len);
618
619 // Now fill in the /efi/platform Node
620Node *efiPlatformNode = DT__AddChild(node, "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) {
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) {
632DT__AddProperty(efiPlatformNode, TSC_Frequency_prop, sizeof(uint64_t), &Platform.CPU.TSCFrequency);
633}
634
635if (Platform.CPU.CPUFrequency != 0) {
636DT__AddProperty(efiPlatformNode, CPU_Frequency_prop, sizeof(uint64_t), &Platform.CPU.CPUFrequency);
637}
638
639DT__AddProperty(efiPlatformNode,DEV_PATH_SUP, sizeof(EFI_UINT32), &DevPathSup);
640
641// Bungo
642/* Export system-id. Can be disabled with SystemId=No in com.apple.Boot.plist
643if ((ret=getSystemID())) {
644DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32*) ret);
645}
646*/
647
648DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32 *)Platform.UUID);
649
650// Export SystemSerialNumber if present
651if ((ret16=getSmbiosChar16("SMserial", &len))) {
652DT__AddProperty(efiPlatformNode, SYSTEM_SERIAL_PROP, len, ret16);
653}
654
655// Export Model if present
656if ((ret16=getSmbiosChar16("SMproductname", &len))) {
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);
676if (boardid)
677{
678DT__AddProperty(node, BOARDID_PROP, strlen(boardid)+1, (EFI_CHAR16*)boardid);
679}
680}
681
682/*
683 * Populate the chosen node
684 */
685
686void setupChosenNode()
687{
688Node *chosenNode;
689chosenNode = DT__FindNode("/chosen", false);
690if (chosenNode == 0)
691{
692stop("Couldn't get chosen node");
693}
694
695int length = strlen(gBootUUIDString);
696if (length)
697{
698DT__AddProperty(chosenNode, "boot-uuid", length + 1, gBootUUIDString);
699}
700
701 length = strlen(bootArgs->CommandLine);
702 DT__AddProperty(chosenNode, "boot-args", length + 1, bootArgs->CommandLine);
703
704 length = strlen(bootInfo->bootFile);
705 DT__AddProperty(chosenNode, "boot-file", length + 1, bootInfo->bootFile);
706// DT__AddProperty(chosenNode, "boot-device-path", bootDPsize, gBootDP);
707// DT__AddProperty(chosenNode, "boot-file-path", bootFPsize, gBootFP);
708// DT__AddProperty(chosenNode, "boot-kernelchache-adler32", sizeof(adler32), adler32);
709
710 DT__AddProperty(chosenNode, "machine-signature", sizeof(EFI_UINT32), (EFI_UINT32 *)&MachineSig);
711 DT__AddProperty(chosenNode, "random-seed", sizeof(RANDOM_SEED), (EFI_UINT8*) &RANDOM_SEED);
712}
713
714/*
715 * Load the smbios.plist override config file if any
716 */
717static void setupSmbiosConfigFile(const char *filename)
718{
719chardirSpecSMBIOS[128];
720const char*override_pathname = NULL;
721intlen = 0, err = 0;
722extern void scan_mem();
723
724// Take in account user overriding
725if (getValueForKey(kSMBIOSKey, &override_pathname, &len, &bootInfo->chameleonConfig) && len > 0)
726{
727// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
728sprintf(dirSpecSMBIOS, override_pathname);
729err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
730}
731else
732{
733// Check selected volume's Extra.
734sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
735if ( (err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig)) )
736{
737// Check booter volume/rdbt Extra.
738sprintf(dirSpecSMBIOS, "bt(0,0)/Extra/%s", filename);
739err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
740}
741}
742
743if (err)
744{
745verbose("No SMBIOS replacement found.\n");
746}
747
748// get a chance to scan mem dynamically if user asks for it while having the config options
749// loaded as well, as opposed to when it was in scan_platform(); also load the orig. smbios
750// so that we can access dmi info, without patching the smbios yet.
751scan_mem();
752}
753
754/*
755 * Installs all the needed configuration table entries
756 */
757static void setupEfiConfigurationTable()
758{
759smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED);
760addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
761
762setupBoardId(); //need to be called after getSmbios
763
764// Setup ACPI with DSDT overrides (mackerintel's patch)
765setupAcpi();
766
767// We've obviously changed the count.. so fix up the CRC32
768if (archCpuType == CPU_TYPE_I386)
769{
770gST32->Hdr.CRC32 = 0;
771gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
772}
773else
774{
775gST64->Hdr.CRC32 = 0;
776gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
777}
778
779// Setup the chosen node
780setupChosenNode();
781}
782
783void saveOriginalSMBIOS(void)
784{
785Node *node;
786SMBEntryPoint *origeps;
787void *tableAddress;
788
789node = DT__FindNode("/efi/platform", false);
790if (!node)
791{
792verbose("/efi/platform node not found\n");
793return;
794}
795
796origeps = getSmbios(SMBIOS_ORIGINAL);
797if (!origeps)
798{
799return;
800}
801
802tableAddress = (void *)AllocateKernelMemory(origeps->dmi.tableLength);
803if (!tableAddress)
804{
805return;
806}
807
808memcpy(tableAddress, (void *)origeps->dmi.tableAddress, origeps->dmi.tableLength);
809DT__AddProperty(node, "SMBIOS", origeps->dmi.tableLength, tableAddress);
810}
811
812/*
813 * Entrypoint from boot.c
814 */
815void setupFakeEfi(void)
816{
817// Generate efi device strings
818setup_pci_devs(root_pci_dev);
819
820readSMBIOSInfo(getSmbios(SMBIOS_ORIGINAL));
821
822// load smbios.plist file if any
823setupSmbiosConfigFile("smbios.plist");
824
825setupSMBIOSTable();
826
827// Initialize the base table
828if (archCpuType == CPU_TYPE_I386)
829{
830setupEfiTables32();
831}
832else
833{
834setupEfiTables64();
835}
836
837// Initialize the device tree
838setupEfiDeviceTree();
839
840saveOriginalSMBIOS();
841
842// Add configuration table entries to both the services table and the device tree
843setupEfiConfigurationTable();
844}
845

Archive Download this file

Revision: 2379