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

Archive Download this file

Revision: 2182