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

Archive Download this file

Revision: 2117