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

Archive Download this file

Revision: 1929