Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/libsaio/fake_efi.c

1
2/*
3 * Copyright 2007 David F. Elliott. All rights reserved.
4 */
5
6/*
7 * Copyright 2010,2011 Cadet-petit Armel <armelcadetpetit@gmail.com>. All rights reserved.
8 */
9
10#include "libsaio.h"
11#include "boot.h"
12#include "bootstruct.h"
13#include "efi.h"
14#include "acpi.h"
15#include "fake_efi.h"
16#include "efi_tables.h"
17#include "platform.h"
18#include "device_inject.h"
19#include "convert.h"
20#include "pci.h"
21#include "sl.h"
22#include "modules.h"
23#include "vers.h"
24#include "smp.h"
25
26#ifndef DEBUG_EFI
27#define DEBUG_EFI 0
28#endif
29
30#if DEBUG_EFI
31#define DBG(x...)printf(x)
32#else
33#define DBG(x...)
34#endif
35/*
36 * Modern Darwin kernels require some amount of EFI because Apple machines all
37 * have EFI. Modifying the kernel source to not require EFI is of course
38 * possible but would have to be maintained as a separate patch because it is
39 * unlikely that Apple wishes to add legacy support to their kernel.
40 *
41 * As you can see from the Apple-supplied code in bootstruct.c, it seems that
42 * the intention was clearly to modify this booter to provide EFI-like structures
43 * to the kernel rather than modifying the kernel to handle non-EFI stuff. This
44 * makes a lot of sense from an engineering point of view as it means the kernel
45 * for the as yet unreleased EFI-only Macs could still be booted by the non-EFI
46 * DTK systems so long as the kernel checked to ensure the boot tables were
47 * filled in appropriately. Modern xnu requires a system table and a runtime
48 * services table and performs no checks whatsoever to ensure the pointers to
49 * these tables are non-NULL.Therefore, any modern xnu kernel will page fault
50 * early on in the boot process if the system table pointer is zero.
51 *
52 * Even before that happens, the tsc_init function in modern xnu requires the FSB
53 * Frequency to be a property in the /efi/platform node of the device tree or else
54 * it panics the bootstrap process very early on.
55 *
56 * As of this writing, the current implementation found here is good enough
57 * to make the currently available xnu kernel boot without modification on a
58 * system with an appropriate processor. With a minor source modification to
59 * the tsc_init function to remove the explicit check for Core or Core 2
60 * processors the kernel can be made to boot on other processors so long as
61 * the code can be executed by the processor and the machine contains the
62 * necessary hardware.
63 */
64
65/*==========================================================================
66 * Utility function to make a device tree string from an EFI_GUID
67 */
68
69static inline char * mallocStringForGuid(EFI_GUID const *pGuid)
70{
71char *string = malloc(37);
72efi_guid_unparse_upper(pGuid, string);
73return string;
74}
75
76/*==========================================================================
77 * Function to map 32 bit physical address to 64 bit virtual address
78 */
79
80#define ptov64(addr) (uint64_t)((uint64_t)addr | 0xFFFFFF8000000000ULL)
81
82/*==========================================================================
83 * Fake EFI implementation
84 */
85
86static EFI_CHAR16 const FIRMWARE_VENDOR[] = {'A','p','p','l','e', 0};
87
88/* Info About the current Firmware */
89#define FIRMWARE_MAINTENER "cparm, armelcadetpetit@gmail.com"
90static EFI_CHAR16 const FIRMWARE_NAME[] = {'M','t','.','H','o','o','d', 0}; //a.k.a Galak.
91static EFI_UINT32 const FIRMWARE_REVISION = 0x00010400; //1.4
92static EFI_UINT32 const DEVICE_SUPPORTED = 0x00000001;
93
94/* Default platform system_id (fix by IntVar) */
95static EFI_CHAR8 const SYSTEM_ID[] = "0123456789ABCDEF"; //random value gen by uuidgen
96
97/* Just a ret instruction */
98static uint8_t const VOIDRET_INSTRUCTIONS[] = {0xc3};
99
100/* movl $0x80000003,%eax; ret */
101static uint8_t const UNSUPPORTEDRET_INSTRUCTIONS[] = {0xb8, 0x03, 0x00, 0x00, 0x80, 0xc3};
102
103EFI_SYSTEM_TABLE_32 *gST32 = NULL;
104EFI_SYSTEM_TABLE_64 *gST64 = NULL;
105Node *gEfiConfigurationTableNode = NULL;
106
107/* From Foundation/Efi/Guid/Smbios/SmBios.h */
108/* Modified to wrap Data4 array init with {} */
109#define EFI_SMBIOS_TABLE_GUID {0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d}}
110
111#define EFI_ACPI_TABLE_GUID \
112{ \
1130xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
114}
115
116#define EFI_ACPI_20_TABLE_GUID \
117{ \
1180x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \
119}
120
121#define EFI_MPS_TABLE_GUID \
122{ \
1230xeb9d2d2f,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d} \
124}
125/* From Foundation/Efi/Guid/Smbios/SmBios.c */
126EFI_GUID constgEfiSmbiosTableGuid = EFI_SMBIOS_TABLE_GUID;
127
128EFI_GUID gEfiAcpiTableGuid = EFI_ACPI_TABLE_GUID;
129EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID;
130EFI_GUID gEfiMpsTableGuid = EFI_MPS_TABLE_GUID;
131
132EFI_UINT32 gNumTables32 = 0;
133EFI_UINT64 gNumTables64 = 0;
134EFI_CONFIGURATION_TABLE_32 gEfiConfigurationTable32[MAX_CONFIGURATION_TABLE_ENTRIES];
135EFI_CONFIGURATION_TABLE_64 gEfiConfigurationTable64[MAX_CONFIGURATION_TABLE_ENTRIES];
136extern EFI_STATUS addConfigurationTable(EFI_GUID const *pGuid, void *table, char const *alias)
137{
138EFI_UINTN i = 0;
139
140 if (pGuid == NULL || table == NULL)
141return EFI_INVALID_PARAMETER;
142
143//Azi: as is, cpu's with em64t will use EFI64 on pre 10.6 systems,
144// wich seems to cause no problem. In case it does, force i386 arch.
145if (archCpuType == CPU_TYPE_I386)
146{
147i = gNumTables32;
148}
149else
150{
151i = (EFI_UINTN)gNumTables64;
152}
153
154// We only do adds, not modifications and deletes like InstallConfigurationTable
155if (i >= MAX_CONFIGURATION_TABLE_ENTRIES){
156
157
158 printf("Ran out of space for configuration tables (max = %d). Please, increase the reserved size in the code.\n", (int)MAX_CONFIGURATION_TABLE_ENTRIES);
159 return EFI_ABORTED;
160 }
161
162
163
164 if (archCpuType == CPU_TYPE_I386)
165{
166
167 gEfiConfigurationTable32[i].VendorGuid = *pGuid;
168 gEfiConfigurationTable32[i].VendorTable = (EFI_PTR32)table;
169
170gNumTables32++;
171}
172else
173{
174 gEfiConfigurationTable64[i].VendorGuid = *pGuid;
175 gEfiConfigurationTable64[i].VendorTable = (EFI_PTR32)table;
176gNumTables64++ ;
177}
178
179
180 Node *tableNode = DT__AddChild(gEfiConfigurationTableNode, mallocStringForGuid(pGuid));
181
182 // Use the pointer to the GUID we just stuffed into the system table
183 DT__AddProperty(tableNode, "guid", sizeof(EFI_GUID), (void*)pGuid);
184
185 // The "table" property is the 32-bit (in our implementation) physical address of the table
186 DT__AddProperty(tableNode, "table", sizeof(void*) * 2, table);
187
188 // Assume the alias pointer is a global or static piece of data
189 if (alias != NULL)
190 DT__AddProperty(tableNode, "alias", strlen(alias)+1, (char*)alias);
191
192 return EFI_SUCCESS;
193
194}
195
196static VOID EFI_ST_FIX_CRC32(void)
197{
198if (archCpuType == CPU_TYPE_I386)
199{
200gST32->Hdr.CRC32 = 0;
201gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
202}
203else
204{
205gST64->Hdr.CRC32 = 0;
206gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
207}
208}
209
210void finalizeEFIConfigTable(void ) {
211
212 if (archCpuType == CPU_TYPE_I386)
213{
214EFI_SYSTEM_TABLE_32 *efiSystemTable = gST32;
215
216 efiSystemTable->NumberOfTableEntries = gNumTables32;
217 efiSystemTable->ConfigurationTable = (EFI_PTR32)gEfiConfigurationTable32;
218
219}
220else
221{
222EFI_SYSTEM_TABLE_64 *efiSystemTable = gST64;
223
224 efiSystemTable->NumberOfTableEntries = gNumTables64;
225 efiSystemTable->ConfigurationTable = ptov64((EFI_PTR32)gEfiConfigurationTable64);
226
227
228}
229 EFI_ST_FIX_CRC32();
230
231#if DEBUG_EFI
232 EFI_UINTN i;
233 EFI_UINTN num = 0;
234 uint32_t table ;
235 EFI_GUID Guid;
236
237 if (archCpuType == CPU_TYPE_I386)
238{
239num = gST32->NumberOfTableEntries;
240
241}
242else
243{
244num = (EFI_UINTN)gST64->NumberOfTableEntries;
245
246}
247 msglog("EFI Configuration table :\n");
248 for (i=0; i<num; i++) {
249 if (archCpuType == CPU_TYPE_I386)
250 {
251 table = gEfiConfigurationTable32[i].VendorTable;
252 Guid = gEfiConfigurationTable32[i].VendorGuid;
253
254 }
255 else
256 {
257 table = gEfiConfigurationTable64[i].VendorTable;
258 Guid = gEfiConfigurationTable64[i].VendorGuid;
259
260 }
261 char id[4];
262
263 if (memcmp(&Guid, &gEfiSmbiosTableGuid, sizeof(EFI_GUID)) == 0) {
264 sprintf(id, "%s", "_SM_");
265 } else if (memcmp(&Guid, &gEfiAcpiTableGuid, sizeof(EFI_GUID)) == 0) {
266 sprintf(id, "%s", "RSD1");
267 } else if (memcmp(&Guid, &gEfiAcpi20TableGuid, sizeof(EFI_GUID)) == 0) {
268 sprintf(id, "%s", "RSD2");
269 } else if (memcmp(&Guid, &gEfiMpsTableGuid, sizeof(EFI_GUID)) == 0) {
270 sprintf(id, "%s", "_MP_");
271 }
272
273 msglog("table [%d]:%s , 32Bit addr : 0x%x\n",i,id,table);
274
275 }
276 msglog("\n");
277#endif
278
279}
280
281/*
282 * What we do here is simply allocate a fake EFI system table and a fake EFI
283 * runtime services table.
284 *
285 * Because we build against modern headers with kBootArgsRevision 4 we
286 * also take care to set efiMode = 32.
287 */
288
289#define pto(mode, addr) (mode == 64) ? ptov64((EFI_PTR32)addr) : (EFI_PTR32)addr
290
291
292#define setupEfiTables(mode) \
293{ \
294struct fake_efi_pages \
295{\
296/* We use the fake_efi_pages struct so that we only need to do one kernel
297 * memory allocation for all needed EFI data. Otherwise, small allocations
298 * like the FIRMWARE_VENDOR string would take up an entire page.
299 * NOTE WELL: Do NOT assume this struct has any particular layout within itself.
300 * It is absolutely not intended to be publicly exposed anywhere
301 * We say pages (plural) although right now we are well within the 1 page size
302 * and probably will stay that way.
303 */\
304EFI_SYSTEM_TABLE_##mode efiSystemTable;\
305EFI_RUNTIME_SERVICES_##mode efiRuntimeServices;\
306EFI_CONFIGURATION_TABLE_##mode efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];\
307EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];\
308uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];\
309uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS)/sizeof(uint8_t)];\
310};\
311struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));\
312/* Zero out all the tables in case fields are added later*/\
313bzero(fakeEfiPages, sizeof(struct fake_efi_pages));\
314/*--------------------------------------------------------------------
315 * Initialize some machine code that will return EFI_UNSUPPORTED for
316 * functions returning int and simply return for void functions.*/\
317memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));\
318memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS, sizeof(UNSUPPORTEDRET_INSTRUCTIONS));\
319/*--------------------------------------------------------------------
320 * System table*/\
321EFI_SYSTEM_TABLE_##mode *efiSystemTable = gST##mode = &fakeEfiPages->efiSystemTable;\
322efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;\
323efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;\
324efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_##mode);\
325efiSystemTable->Hdr.CRC32 = 0;/*Initialize to zero and then do CRC32*/ \
326efiSystemTable->Hdr.Reserved = 0;\
327efiSystemTable->FirmwareVendor = pto(mode, &fakeEfiPages->firmwareVendor);\
328memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));\
329efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;\
330/* XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
331 * The EFI spec states that all handles are invalid after boot services have been
332 * exited so we can probably get by with leaving the handles as zero.
333 */\
334efiSystemTable->ConsoleInHandle = 0;\
335efiSystemTable->ConIn = 0;\
336efiSystemTable->ConsoleOutHandle = 0;\
337efiSystemTable->ConOut = 0;\
338efiSystemTable->StandardErrorHandle = 0;\
339efiSystemTable->StdErr = 0;\
340efiSystemTable->RuntimeServices = pto(mode,&fakeEfiPages->efiRuntimeServices) ;\
341/* According to the EFI spec, BootServices aren't valid after the
342 * boot process is exited so we can probably do without it.
343 * Apple didn't provide a definition for it in pexpert/i386/efi.h
344 * so I'm guessing they don't use it.
345 */\
346efiSystemTable->BootServices = 0;\
347efiSystemTable->NumberOfTableEntries = 0;\
348efiSystemTable->ConfigurationTable = pto(mode,fakeEfiPages->efiConfigurationTable);\
349/* We're done. Now CRC32 the thing so the kernel will accept it.
350 * Must be initialized to zero before CRC32, done above.
351 */\
352gST##mode->Hdr.CRC32 = crc32(0L, gST##mode, gST##mode->Hdr.HeaderSize);\
353/*--------------------------------------------------------------------
354 * Runtime services*/\
355EFI_RUNTIME_SERVICES_##mode *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;\
356efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;\
357efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;\
358efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_##mode);\
359efiRuntimeServices->Hdr.CRC32 = 0;\
360efiRuntimeServices->Hdr.Reserved = 0;\
361/* There are a number of function pointers in the efiRuntimeServices table.
362 * These are the Foundation (e.g. core) services and are expected to be present on
363 * all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
364 * will call these without checking to see if they are null.
365 *
366 * We don't really feel like doing an EFI implementation in the bootloader
367 * but it is nice if we can at least prevent a complete crash by
368 * at least providing some sort of implementation until one can be provided
369 * nicely in a kext.
370 */\
371void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;\
372void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;\
373efiRuntimeServices->GetTime = pto(mode,unsupportedret_fp);\
374efiRuntimeServices->SetTime = pto(mode,unsupportedret_fp);\
375efiRuntimeServices->GetWakeupTime = pto(mode,unsupportedret_fp);\
376efiRuntimeServices->SetWakeupTime = pto(mode,unsupportedret_fp);\
377efiRuntimeServices->SetVirtualAddressMap = pto(mode,unsupportedret_fp);\
378efiRuntimeServices->ConvertPointer = pto(mode,unsupportedret_fp);\
379efiRuntimeServices->GetVariable = pto(mode,unsupportedret_fp);\
380efiRuntimeServices->GetNextVariableName = pto(mode,unsupportedret_fp);\
381efiRuntimeServices->SetVariable = pto(mode,unsupportedret_fp);\
382efiRuntimeServices->GetNextHighMonotonicCount = pto(mode,unsupportedret_fp);\
383efiRuntimeServices->ResetSystem = pto(mode,voidret_fp);\
384/*We're done.Now CRC32 the thing so the kernel will accept it*/\
385efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);\
386/*--------------------------------------------------------------------
387 * Finish filling in the rest of the boot args that we need.*/\
388bootArgs->efiSystemTable = (uint32_t)efiSystemTable;\
389bootArgs->efiMode = kBootArgsEfiMode##mode;\
390/* The bootArgs structure as a whole is bzero'd so we don't need to fill in
391 * things like efiRuntimeServices* and what not.
392 *
393 * In fact, the only code that seems to use that is the hibernate code so it
394 * knows not to save the pages. It even checks to make sure its nonzero.
395*/\
396}
397
398
399/*
400 * In addition to the EFI tables there is also the EFI device tree node.
401 * In particular, we need /efi/platform to have an FSBFrequency key. Without it,
402 * the tsc_init function will panic very early on in kernel startup, before
403 * the console is available.
404 */
405
406/*==========================================================================
407 * FSB Frequency detection
408 */
409
410/* These should be const but DT__AddProperty takes char* */
411static const char const TSC_Frequency_prop[] = "TSCFrequency";
412static const char const FSB_Frequency_prop[] = "FSBFrequency";
413static const char const CPU_Frequency_prop[] = "CPUFrequency";
414
415/*==========================================================================
416 * SMBIOS
417 */
418
419uint64_t smbios_p;
420
421/*==========================================================================
422 * ACPI
423 */
424
425static uint64_t local_rsd_p;
426static ACPI_TABLES acpi_tables;
427
428/* Setup ACPI without any patch. */
429static EFI_STATUS setupAcpiNoMod()
430{
431
432EFI_STATUS ret = EFI_UNSUPPORTED;
433
434 ACPI_TABLE_RSDP* rsdp = (ACPI_TABLE_RSDP*)((uint32_t)local_rsd_p);
435 if(rsdp->Revision > 0 && checksum8(rsdp, sizeof(ACPI_TABLE_RSDP))) {
436ret = addConfigurationTable(&gEfiAcpi20TableGuid, &local_rsd_p, "ACPI_20");
437} else {
438ret = addConfigurationTable(&gEfiAcpiTableGuid, &local_rsd_p, "ACPI");
439}
440
441return ret;
442}
443
444static EFI_STATUS setup_acpi (void)
445{
446EFI_STATUS ret = EFI_UNSUPPORTED;
447
448execute_hook("setupEfiConfigurationTable", &ret, NULL, NULL, NULL, NULL, NULL);
449
450if (ret != EFI_SUCCESS) {
451
452
453 if (!FindAcpiTables(&acpi_tables)){
454printf("Failed to detect ACPI tables.\n");
455return EFI_NOT_FOUND;
456 }
457
458 local_rsd_p = ((uint64_t)((uint32_t)acpi_tables.RsdPointer));
459
460 ACPI_TABLE_FADT *FacpPointer = (acpi_tables.FacpPointer64 != (void*)0ul) ? (ACPI_TABLE_FADT *)acpi_tables.FacpPointer64 : (ACPI_TABLE_FADT *)acpi_tables.FacpPointer;
461
462 uint8_t type = FacpPointer->PreferredProfile;
463 if (type <= MaxSupportedPMProfile)
464 Platform->Type = type;
465
466 ret = setupAcpiNoMod();
467}
468
469return ret;
470
471}
472
473/*==========================================================================
474 * Fake EFI implementation
475 */
476
477/* These should be const but DT__AddProperty takes char* */
478static const char const FIRMWARE_REVISION_PROP[] = "firmware-revision";
479static const char const FIRMWARE_ABI_PROP[] = "firmware-abi";
480static const char const FIRMWARE_VENDOR_PROP[] = "firmware-vendor";
481static const char const FIRMWARE_NAME_PROP[] = "firmware-name";
482static const char const FIRMWARE_DATE_PROP[] = "firmware-date";
483static const char const FIRMWARE_DEV_PROP[] = "firmware-maintener";
484static const char const FIRMWARE_PUBLISH_PROP[] = "firmware-publisher";
485
486static const char const FIRMWARE_ABI_32_PROP_VALUE[] = "EFI32";
487static const char const FIRMWARE_ABI_64_PROP_VALUE[] = "EFI64";
488static const char const SYSTEM_ID_PROP[] = "system-id";
489static const char const SYSTEM_SERIAL_PROP[] = "SystemSerialNumber";
490static const char const SYSTEM_TYPE_PROP[] = "system-type";
491static const char const MODEL_PROP[] = "Model";
492
493
494/*
495 * Get an smbios option string option to convert to EFI_CHAR16 string
496 */
497
498static EFI_CHAR16* getSmbiosChar16(const char * key, size_t* len)
499{
500if (!gPlatformName && strcmp(key, "SMproductname") == 0)
501readSMBIOS(thePlatformName);
502
503const char*src = (strcmp(key, "SMproductname") == 0) ? gPlatformName : getStringForKey(key, &bootInfo->smbiosConfig);
504
505EFI_CHAR16* dst = 0;
506size_t i = 0;
507
508if (!key || !(*key) || !src) return 0;
509
510*len = strlen(src);
511dst = (EFI_CHAR16*) malloc( ((*len)+1) * 2 );
512for (; i < (*len); i++) dst[i] = src[i];
513dst[(*len)] = '\0';
514*len = ((*len)+1)*2; // return the CHAR16 bufsize in cluding zero terminated CHAR16
515return dst;
516}
517
518/*
519 * Get the SystemID from the bios dmi info
520 */
521
522static EFI_CHAR8* getSmbiosUUID()
523{
524static EFI_CHAR8 uuid[UUID_LEN];
525int i, isZero, isOnes;
526SMBByte*p;
527
528 p = (SMBByte*)Platform->UUID;
529
530 if ( p == NULL ) {
531 DBG("No patched UUID found, fallback to original UUID (if exist) \n");
532
533 readSMBIOS(theUUID);
534 p = (SMBByte*)Platform->UUID;
535
536 }
537
538for (i=0, isZero=1, isOnes=1; i<UUID_LEN; i++)
539{
540if (p[i] != 0x00) isZero = 0;
541if (p[i] != 0xff) isOnes = 0;
542}
543
544if (isZero || isOnes) // empty or setable means: no uuid present
545{
546verbose("No UUID present in SMBIOS System Information Table\n");
547return 0;
548}
549#if DEBUG_EFI
550else
551verbose("Found UUID in SMBIOS System Information Table\n");
552#endif
553
554memcpy(uuid, p, UUID_LEN);
555return uuid;
556}
557
558/*
559 * return a binary UUID value from the overriden SystemID and SMUUID if found,
560 * or from the bios if not, or from a fixed value if no bios value is found
561 */
562
563static EFI_STATUS getSystemID()
564{
565// unable to determine UUID for host. Error: 35 fix
566// Rek: new SMsystemid option conforming to smbios notation standards, this option should
567// belong to smbios config only ...
568EFI_STATUS status = EFI_NOT_FOUND;
569EFI_CHAR8*ret = getUUIDFromString(getStringForKey(kSystemID, &bootInfo->bootConfig));
570
571if (!ret) // try bios dmi info UUID extraction
572ret = getSmbiosUUID();
573
574
575if (!ret) {
576// no bios dmi UUID available, set a fixed value for system-id
577ret=getUUIDFromString((const char*) SYSTEM_ID);
578verbose("Customizing SystemID with : %s\n", getStringFromUUID(ret)); // apply a nice formatting to the displayed output
579}
580else
581{
582const char *mac = getStringFromUUID(ret);
583verbose("MAC address : %c%c:%c%c:%c%c:%c%c:%c%c:%c%c\n",mac[24],mac[25],mac[26],mac[27],mac[28],mac[29]
584,mac[30],mac[31],mac[32],mac[33],mac[34],mac[35]);
585
586}
587
588if (ret) {
589memcpy(Platform->sysid, ret, UUID_LEN);
590status = EFI_SUCCESS;
591}
592
593return status;
594}
595
596/*
597 * Must be called AFTER setup Acpi because we need to take care of correct
598 * facp content to reflect in ioregs
599 */
600
601static VOID setupSystemType()
602{
603Node *node = DT__FindNode("/", false);
604if (node == 0) stop("Couldn't get root node");
605// we need to write this property after facp parsing
606// Export system-type only if it has been overrriden by the SystemType option
607DT__AddProperty(node, SYSTEM_TYPE_PROP, sizeof(Platform->Type), &Platform->Type);
608}
609
610struct boot_progress_element {
611unsigned intwidth;
612unsigned intheight;
613intyOffset;
614unsigned intres[5];
615unsigned chardata[0];
616};
617typedef struct boot_progress_element boot_progress_element;
618
619static VOID setupEfiDeviceTree(void)
620{
621EFI_CHAR16* serial = 0, *productname = 0;
622size_t len = 0;
623Node*node;
624long size;
625extern char gMacOSVersion[];
626node = DT__FindNode("/", false);
627
628if (node == 0) stop("Couldn't get root node");
629
630#include "appleClut8.h"
631size = sizeof(appleClut8);
632long clut = AllocateKernelMemory(size);
633bcopy(&appleClut8, (void*)clut, size);
634#if UNUSED
635 AllocateMemoryRange( "BootCLUT", clut, size,-1);
636
637#else
638 AllocateMemoryRange( "BootCLUT", clut, size);
639
640#endif
641#include "failedboot.h"
642size = 32 + kFailedBootWidth * kFailedBootHeight;
643long bootPict = AllocateKernelMemory(size);
644#if UNUSED
645 AllocateMemoryRange( "Pict-FailedBoot", bootPict, size,-1);
646#else
647 AllocateMemoryRange( "Pict-FailedBoot", bootPict, size);
648#endif
649((boot_progress_element *)bootPict)->width = kFailedBootWidth;
650 ((boot_progress_element *)bootPict)->height = kFailedBootHeight;
651 ((boot_progress_element *)bootPict)->yOffset = kFailedBootOffset;
652bcopy((char *)gFailedBootPict, (char *)(bootPict + 32), size - 32);
653
654//Fix error message with Lion DP2+ installer
655if (execute_hook("getboardproductPatched", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS) {
656
657gboardproduct = (char *)getStringForKey("SMboardproduct", &bootInfo->smbiosConfig);
658
659if (!gboardproduct) readSMBIOS(theProducBoard);
660
661}
662if (gboardproduct) {
663DT__AddProperty(node, "board-id", strlen(gboardproduct)+1, gboardproduct);
664}
665
666
667Node *chosenNode = DT__FindNode("/chosen", true);
668if (chosenNode) {
669
670DT__AddProperty(chosenNode, "boot-args", strlen(bootArgs->CommandLine)+1, (EFI_CHAR16*)bootArgs->CommandLine);
671
672if (uuidSet &&bootInfo->uuidStr[0])
673DT__AddProperty(chosenNode, kBootUUIDKey, strlen(bootInfo->uuidStr)+1, bootInfo->uuidStr);
674
675/*if (gRootPath[0]) {
676
677DT__AddProperty(chosenNode, "rootpath", 256, gRootPath);
678
679} else */if (gRootDevice) {
680
681DT__AddProperty(chosenNode, "boot-device-path", strlen(gRootDevice)+1, gRootDevice);
682
683}
684
685
686// "boot-file" is not used by kextcache if there is no "boot-device-path" or if there is a valid "rootpath" ,
687// but i let it by default since it may be used by another service
688DT__AddProperty(chosenNode, "boot-file", strlen(bootInfo->bootFile)+1, (EFI_CHAR16*)bootInfo->bootFile);
689
690
691if (bootInfo->adler32)
692DT__AddProperty(chosenNode, "boot-kernelcache-adler32", sizeof(unsigned long), &bootInfo->adler32);
693
694}
695
696// We could also just do DT__FindNode("/efi/platform", true)
697// But I think eventually we want to fill stuff in the efi node
698// too so we might as well create it so we have a pointer for it too.
699Node *efiNode = DT__AddChild(node, "efi");
700// Set up the /efi/runtime-services table node similar to the way a child node of configuration-table
701// is set up. That is, name and table properties
702Node *runtimeServicesNode = DT__AddChild(efiNode, "runtime-services");
703
704Node *kernelCompatibilityNode = 0; // ??? not sure that it should be used like that (because it's maybe the kernel capability and not the cpu capability)
705if (gMacOSVersion[3] == '7'){
706kernelCompatibilityNode = DT__AddChild(efiNode, "kernel-compatibility");
707DT__AddProperty(kernelCompatibilityNode, "i386", sizeof(uint32_t), (EFI_UINT32*)&DEVICE_SUPPORTED);
708}
709
710if (archCpuType == CPU_TYPE_I386)
711{
712// The value of the table property is the 32-bit physical address for the RuntimeServices table.
713// Since the EFI system table already has a pointer to it, we simply use the address of that pointer
714// for the pointer to the property data. Warning.. DT finalization calls free on that but we're not
715// the only thing to use a non-malloc'd pointer for something in the DT
716
717DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST32->RuntimeServices);
718DT__AddProperty(efiNode, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char*)FIRMWARE_ABI_32_PROP_VALUE);
719}
720else
721{
722if (kernelCompatibilityNode)
723DT__AddProperty(kernelCompatibilityNode, "x86_64", sizeof(uint32_t), (EFI_UINT32*)&DEVICE_SUPPORTED);
724
725DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST64->RuntimeServices);
726DT__AddProperty(efiNode, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char*)FIRMWARE_ABI_64_PROP_VALUE);
727}
728DT__AddProperty(efiNode, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32*)&FIRMWARE_REVISION);
729DT__AddProperty(efiNode, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16*)FIRMWARE_VENDOR);
730DT__AddProperty(efiNode, FIRMWARE_NAME_PROP, sizeof(FIRMWARE_NAME), (EFI_CHAR16*)FIRMWARE_NAME);
731DT__AddProperty(efiNode, FIRMWARE_DATE_PROP, strlen(I386BOOT_BUILDDATE)+1, I386BOOT_BUILDDATE);
732DT__AddProperty(efiNode, FIRMWARE_DEV_PROP, strlen(FIRMWARE_MAINTENER)+1, FIRMWARE_MAINTENER);
733DT__AddProperty(efiNode, FIRMWARE_PUBLISH_PROP, strlen(FIRMWARE_PUBLISHER)+1, FIRMWARE_PUBLISHER);
734
735// Set up the /efi/configuration-table node which will eventually have several child nodes for
736// all of the configuration tables needed by various kernel extensions.
737gEfiConfigurationTableNode = DT__AddChild(efiNode, "configuration-table");
738
739// Now fill in the /efi/platform Node
740Node *efiPlatformNode = DT__AddChild(efiNode, "platform");
741
742DT__AddProperty(efiPlatformNode, "DevicePathsSupported", sizeof(uint32_t), (EFI_UINT32*)&DEVICE_SUPPORTED);
743
744// NOTE WELL: If you do add FSB Frequency detection, make sure to store
745// the value in the fsbFrequency global and not an malloc'd pointer
746// because the DT_AddProperty function does not copy its args.
747
748if (Platform->CPU.FSBFrequency != 0)
749DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &Platform->CPU.FSBFrequency);
750
751
752#if UNUSED
753// Export TSC and CPU frequencies for use by the kernel or KEXTs
754if (Platform->CPU.TSCFrequency != 0)
755DT__AddProperty(efiPlatformNode, TSC_Frequency_prop, sizeof(uint64_t), &Platform->CPU.TSCFrequency);
756
757if (Platform->CPU.CPUFrequency != 0)
758DT__AddProperty(efiPlatformNode, CPU_Frequency_prop, sizeof(uint64_t), &Platform->CPU.CPUFrequency);
759#endif
760
761// Export system-id. Can be disabled with SystemId=No in com.apple.Boot.plist
762
763if (getSystemID() == EFI_SUCCESS)
764DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32*) Platform->sysid);
765
766 // Export SystemSerialNumber if present
767if ((serial=getSmbiosChar16("SMserial", &len)))
768DT__AddProperty(efiPlatformNode, SYSTEM_SERIAL_PROP, len, serial);
769
770// Export Model if present
771if ((productname=getSmbiosChar16("SMproductname", &len)))
772DT__AddProperty(efiPlatformNode, MODEL_PROP, len, productname);
773
774// Fill /efi/device-properties node.
775setupDeviceProperties(efiNode);
776}
777
778/*
779 * Load the smbios.plist override config file if any
780 */
781
782void setupSmbiosConfigFile(const char *filename)
783{
784static bool readSmbConfigFile = true;
785
786if (readSmbConfigFile == true) {
787
788chardirSpecSMBIOS[128] = "";
789const char *override_pathname = NULL;
790intlen = 0, err = 0;
791
792// Take in account user overriding
793if (getValueForKey("SMBIOS", &override_pathname, &len, &bootInfo->bootConfig) && len > 0)
794{
795// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
796sprintf(dirSpecSMBIOS, override_pathname);
797err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
798}
799else
800{
801// Check selected volume's Extra.
802sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
803if ((err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig)))
804{
805// Check booter volume/rdbt Extra.
806sprintf(dirSpecSMBIOS, "bt(0,0)/Extra/%s", filename);
807err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
808}
809}
810
811if (err)
812{
813verbose("No SMBIOS config file found.\n");
814}
815readSmbConfigFile = false;
816}
817}
818
819static VOID setup_Smbios()
820{
821if (execute_hook("getSmbiosPatched",NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS) {
822DBG("Using the original SMBIOS !!\n");
823 struct SMBEntryPoint *smbios_o = getSmbiosOriginal();
824 smbios_p = ((uint64_t)((uint32_t)smbios_o));
825}
826}
827
828static VOID setup_machine_signature()
829{
830Node *chosenNode = DT__FindNode("/chosen", false);
831if (chosenNode) {
832if (Platform->hardware_signature == 0xFFFFFFFF)
833{
834 if (!local_rsd_p)
835 {
836
837 if (!FindAcpiTables(&acpi_tables)){
838printf("Failed to detect ACPI tables.\n");
839goto out;
840}
841
842 local_rsd_p = ((uint64_t)((uint32_t)acpi_tables.RsdPointer));
843 }
844 ACPI_TABLE_FACS *FacsPointer;
845
846if (acpi_tables.RsdRevision > 0 )
847FacsPointer = (ACPI_TABLE_FACS *)acpi_tables.FacsPointer64;
848 else
849 FacsPointer = (ACPI_TABLE_FACS *)acpi_tables.FacsPointer;
850
851 Platform->hardware_signature = FacsPointer->HardwareSignature;
852
853}
854out:
855// Verify that we have a valid hardware signature
856if (Platform->hardware_signature == 0xFFFFFFFF)
857{
858verbose("Warning: hardware_signature is invalid, defaulting to 0 \n");
859 Platform->hardware_signature = 0;
860}
861
862DT__AddProperty(chosenNode, "machine-signature", sizeof(uint32_t), &Platform->hardware_signature);
863}
864
865}
866
867/*
868 * Installs all the needed configuration table entries
869 */
870
871static VOID setupEfiConfigurationTable()
872{
873 if (smbios_p)
874 addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
875
876
877void *mps_p = getMPSTable();
878
879 if (mps_p)
880 {
881 uint64_t mps = ((uint64_t)((uint32_t)mps_p));
882
883 addConfigurationTable(&gEfiMpsTableGuid, &mps, NULL);
884}
885
886//Slice
887// PM_Model
888if (Platform->CPU.isServer == true)
889 {
890Platform->Type = Workstation;
891}
892else if (Platform->CPU.isMobile == true) {
893Platform->Type = Mobile;
894} else {
895Platform->Type = Desktop;
896}
897
898// Invalidate the platform hardware signature (this needs to be verified with acpica, but i guess that 0xFFFFFFFF is an invalid signature)
899Platform->hardware_signature = 0xFFFFFFFF;
900
901// Setup ACPI (mackerintel's patch)
902setup_acpi();
903
904setup_machine_signature();
905// We now have to write the systemm-type in ioregs: we cannot do it before in setupDeviceTree()
906// because we need to take care of facp original content, if it is correct.
907setupSystemType();
908
909// We've obviously changed the count.. so fix up the CRC32
910 EFI_ST_FIX_CRC32();
911}
912
913/*
914 * Entrypoint from boot.c
915 */
916
917void setupFakeEfi(void)
918{
919// Collect PCI info &| Generate device prop string
920setup_pci_devs(root_pci_dev);
921
922// load smbios.plist file if any
923setupSmbiosConfigFile("SMBIOS.plist");
924setup_Smbios();
925
926// Initialize the base table
927if (archCpuType == CPU_TYPE_I386)
928{
929setupEfiTables(32);
930}
931else
932{
933setupEfiTables(64);
934}
935
936// Initialize the device tree
937setupEfiDeviceTree();
938
939// Add configuration table entries to both the services table and the device tree
940setupEfiConfigurationTable();
941
942}
943
944

Archive Download this file

Revision: 1122