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

Archive Download this file

Revision: 1984