Chameleon

Chameleon Svn Source Tree

Root/trunk/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
578if (archCpuType == CPU_TYPE_I386) {
579DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char*)FIRMWARE_ABI_32_PROP_VALUE);
580} else { */
581DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char *)FIRMWARE_ABI_64_PROP_VALUE);
582//}
583
584DT__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
611Node *efiKernelComNode = DT__AddChild(node, "kernel-compatibility");
612len = 1;
613DT__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);
686if (chosenNode == 0)
687{
688stop("Couldn't get chosen node");
689}
690
691int length = strlen(gBootUUIDString);
692if (length)
693{
694DT__AddProperty(chosenNode, "boot-uuid", length + 1, gBootUUIDString);
695}
696
697length = strlen(bootArgs->CommandLine);
698DT__AddProperty(chosenNode, "boot-args", length + 1, bootArgs->CommandLine);
699
700length = strlen(bootInfo->bootFile);
701DT__AddProperty(chosenNode, "boot-file", length + 1, bootInfo->bootFile);
702
703DT__AddProperty(chosenNode, "machine-signature", sizeof(EFI_UINT32), (EFI_UINT32 *)&MachineSig);
704}
705
706/*
707 * Load the smbios.plist override config file if any
708 */
709static void setupSmbiosConfigFile(const char *filename)
710{
711chardirSpecSMBIOS[128];
712const char*override_pathname = NULL;
713intlen = 0, err = 0;
714extern void scan_mem();
715
716// Take in account user overriding
717if (getValueForKey(kSMBIOSKey, &override_pathname, &len, &bootInfo->chameleonConfig) && len > 0)
718{
719// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
720sprintf(dirSpecSMBIOS, override_pathname);
721err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
722}
723else
724{
725// Check selected volume's Extra.
726sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
727if ( (err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig)) )
728{
729// Check booter volume/rdbt Extra.
730sprintf(dirSpecSMBIOS, "bt(0,0)/Extra/%s", filename);
731err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
732}
733}
734
735if (err)
736{
737verbose("No SMBIOS replacement found.\n");
738}
739
740// get a chance to scan mem dynamically if user asks for it while having the config options
741// loaded as well, as opposed to when it was in scan_platform(); also load the orig. smbios
742// so that we can access dmi info, without patching the smbios yet.
743scan_mem();
744}
745
746/*
747 * Installs all the needed configuration table entries
748 */
749static void setupEfiConfigurationTable()
750{
751smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED);
752addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
753
754setupBoardId(); //need to be called after getSmbios
755
756// Setup ACPI with DSDT overrides (mackerintel's patch)
757setupAcpi();
758
759// We've obviously changed the count.. so fix up the CRC32
760if (archCpuType == CPU_TYPE_I386)
761{
762gST32->Hdr.CRC32 = 0;
763gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
764}
765else
766{
767gST64->Hdr.CRC32 = 0;
768gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
769}
770
771// Setup the chosen node
772setupChosenNode();
773}
774
775void saveOriginalSMBIOS(void)
776{
777Node *node;
778SMBEntryPoint *origeps;
779void *tableAddress;
780
781node = DT__FindNode("/efi/platform", false);
782if (!node)
783{
784verbose("/efi/platform node not found\n");
785return;
786}
787
788origeps = getSmbios(SMBIOS_ORIGINAL);
789if (!origeps)
790{
791return;
792}
793
794tableAddress = (void *)AllocateKernelMemory(origeps->dmi.tableLength);
795if (!tableAddress)
796{
797return;
798}
799
800memcpy(tableAddress, (void *)origeps->dmi.tableAddress, origeps->dmi.tableLength);
801DT__AddProperty(node, "SMBIOS", origeps->dmi.tableLength, tableAddress);
802}
803
804/*
805 * Entrypoint from boot.c
806 */
807void setupFakeEfi(void)
808{
809// Generate efi device strings
810setup_pci_devs(root_pci_dev);
811
812readSMBIOSInfo(getSmbios(SMBIOS_ORIGINAL));
813
814// load smbios.plist file if any
815setupSmbiosConfigFile("smbios.plist");
816
817setupSMBIOSTable();
818
819// Initialize the base table
820if (archCpuType == CPU_TYPE_I386)
821{
822setupEfiTables32();
823}
824else
825{
826setupEfiTables64();
827}
828
829// Initialize the device tree
830setupEfiDeviceTree();
831
832saveOriginalSMBIOS();
833
834// Add configuration table entries to both the services table and the device tree
835setupEfiConfigurationTable();
836}
837

Archive Download this file

Revision: 2425