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

Archive Download this file

Revision: 1714