Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: HEAD