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

Archive Download this file

Revision: 2118