Chameleon

Chameleon Svn Source Tree

Root/branches/slice/i386/libsaio/fake_efi.c

1
2/*
3 * Copyright 2007 David F. Elliott. All rights reserved.
4 */
5
6#include "libsaio.h"
7#include "boot.h"
8#include "bootstruct.h"
9#include "efi.h"
10#include "acpi.h"
11#include "fake_efi.h"
12#include "efi_tables.h"
13#include "platform.h"
14//#include "acpi_patcher.h"
15#include "smbios_patcher.h"
16#include "device_inject.h"
17#include "convert.h"
18#include "pci.h"
19#include "sl.h"
20//#include "mem.h"
21#include "modules.h"
22
23#ifdef static
24#undef static
25#endif
26
27extern struct SMBEntryPoint * getSmbios(int which); // now cached
28//extern void setup_pci_devs(pci_dt_t *pci_dt);
29
30#define kBL_GLOBAL_NVRAM_GUID "8BE4DF61-93CA-11D2-AA0D-00E098032B8C"
31
32// Check if a system supports CSM legacy mode
33#define kBL_APPLE_VENDOR_NVRAM_GUID "4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14"
34
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 */
64
65/*==========================================================================
66 * Utility function to make a device tree string from an EFI_GUID
67 */
68
69static inline char * mallocStringForGuid(EFI_GUID const *pGuid)
70{
71char *string = malloc(37);
72efi_guid_unparse_upper(pGuid, string);
73return string;
74}
75
76/*==========================================================================
77 * Function to map 32 bit physical address to 64 bit virtual address
78 */
79
80static uint64_t ptov64(uint32_t addr)
81{
82return ((uint64_t)addr | 0xFFFFFF8000000000ULL);
83}
84
85/*==========================================================================
86 * Fake EFI implementation
87 */
88
89/* Identify ourselves as the EFI firmware vendor */
90static EFI_CHAR16 const FIRMWARE_VENDOR[] = {'C','h','a','m','e','l','e','o','n','_','2','.','5','M', 0};
91static EFI_UINT32 const FIRMWARE_REVISION = 0x0001000a;
92static EFI_UINT32 const FIRMWARE_FEATURE_MASK = 0x000003FF;
93static EFI_UINT32 const STATIC_ZERO = 0;
94
95/* Default platform system_id (fix by IntVar) */
96//static EFI_CHAR8 const SYSTEM_ID[] = "0123456789ABCDEF"; //random value gen by uuidgen
97
98/* Just a ret instruction */
99static uint8_t const VOIDRET_INSTRUCTIONS[] = {0xc3};
100
101/* movl $0x80000003,%eax; ret */
102static uint8_t const UNSUPPORTEDRET_INSTRUCTIONS[] = {0xb8, 0x03, 0x00, 0x00, 0x80, 0xc3};
103//#define SYSTEM_ID_DEFAULT {0x41, 0x73, 0x65, 0x72, 0x65, 0x42, 0x4c, 0x4e, 0x66, 0x75, 0x63, 0x6b, 0x45, 0x46, 0x49, 0x58}
104EFI_GUID const SYSTEM_ID_DEFAULT = {0x72657341, 0x4265, 0x4e4C, 0x66, 0x75, {0x63, 0x6b, 0x45, 0x46, 0x49, 0x58}};
105EFI_SYSTEM_TABLE_32 *gST32 = NULL;
106EFI_SYSTEM_TABLE_64 *gST64 = NULL;
107Node *gEfiConfigurationTableNode = NULL;
108
109extern EFI_STATUS addConfigurationTable(EFI_GUID const *pGuid, void *table, char const *alias)
110{
111EFI_UINTN i = 0;
112
113//Azi: as is, cpu's with em64t will use EFI64 on pre 10.6 systems,
114// wich seems to cause no problem. In case it does, force i386 arch.
115if (archCpuType == CPU_TYPE_I386)
116{
117i = gST32->NumberOfTableEntries;
118}
119else
120{
121i = gST64->NumberOfTableEntries;
122}
123
124// We only do adds, not modifications and deletes like InstallConfigurationTable
125if (i >= MAX_CONFIGURATION_TABLE_ENTRIES)
126stop("Ran out of space for configuration tables. Increase the reserved size in the code.\n");
127
128if (pGuid == NULL)
129return EFI_INVALID_PARAMETER;
130
131if (table != NULL)
132{
133// FIXME
134//((EFI_CONFIGURATION_TABLE_64 *)gST->ConfigurationTable)[i].VendorGuid = *pGuid;
135//((EFI_CONFIGURATION_TABLE_64 *)gST->ConfigurationTable)[i].VendorTable = (EFI_PTR64)table;
136
137//++gST->NumberOfTableEntries;
138
139Node *tableNode = DT__AddChild(gEfiConfigurationTableNode, mallocStringForGuid(pGuid));
140
141// Use the pointer to the GUID we just stuffed into the system table
142DT__AddProperty(tableNode, "guid", sizeof(EFI_GUID), (void*)pGuid);
143
144// The "table" property is the 32-bit (in our implementation) physical address of the table
145DT__AddProperty(tableNode, "table", sizeof(void*) * 2, table);
146
147// Assume the alias pointer is a global or static piece of data
148if (alias != NULL)
149DT__AddProperty(tableNode, "alias", strlen(alias)+1, (char*)alias);
150
151return EFI_SUCCESS;
152}
153return EFI_UNSUPPORTED;
154}
155
156//Azi: crc32 done in place, on the cases were it wasn't.
157/*static inline void fixupEfiSystemTableCRC32(EFI_SYSTEM_TABLE_64 *efiSystemTable)
158{
159efiSystemTable->Hdr.CRC32 = 0;
160efiSystemTable->Hdr.CRC32 = crc32(0L, efiSystemTable, efiSystemTable->Hdr.HeaderSize);
161}*/
162
163/*
164 * What we do here is simply allocate a fake EFI system table and a fake EFI
165 * runtime services table.
166 *
167 * Because we build against modern headers with kBootArgsRevision 4 we
168 * also take care to set efiMode = 32.
169 */
170
171void setupEfiTables32(void)
172{
173// We use the fake_efi_pages struct so that we only need to do one kernel
174// memory allocation for all needed EFI data. Otherwise, small allocations
175// like the FIRMWARE_VENDOR string would take up an entire page.
176// NOTE WELL: Do NOT assume this struct has any particular layout within itself.
177// It is absolutely not intended to be publicly exposed anywhere
178// We say pages (plural) although right now we are well within the 1 page size
179// and probably will stay that way.
180struct fake_efi_pages
181{
182EFI_SYSTEM_TABLE_32 efiSystemTable;
183EFI_RUNTIME_SERVICES_32 efiRuntimeServices;
184EFI_CONFIGURATION_TABLE_32 efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];
185EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];
186uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];
187uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS)/sizeof(uint8_t)];
188};
189
190struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));
191
192// Zero out all the tables in case fields are added later
193bzero(fakeEfiPages, sizeof(struct fake_efi_pages));
194
195// --------------------------------------------------------------------
196// Initialize some machine code that will return EFI_UNSUPPORTED for
197// functions returning int and simply return for void functions.
198memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));
199memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS, sizeof(UNSUPPORTEDRET_INSTRUCTIONS));
200
201// --------------------------------------------------------------------
202// System table
203EFI_SYSTEM_TABLE_32 *efiSystemTable = gST32 = &fakeEfiPages->efiSystemTable;
204efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
205efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;
206efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_32);
207efiSystemTable->Hdr.CRC32 = 0; // Initialize to zero and then do CRC32
208efiSystemTable->Hdr.Reserved = 0;
209
210efiSystemTable->FirmwareVendor = (EFI_PTR32)&fakeEfiPages->firmwareVendor;
211memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));
212efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;
213
214// XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
215// The EFI spec states that all handles are invalid after boot services have been
216// exited so we can probably get by with leaving the handles as zero.
217efiSystemTable->ConsoleInHandle = 0;
218efiSystemTable->ConIn = 0;
219
220efiSystemTable->ConsoleOutHandle = 0;
221efiSystemTable->ConOut = 0;
222
223efiSystemTable->StandardErrorHandle = 0;
224efiSystemTable->StdErr = 0;
225
226efiSystemTable->RuntimeServices = (EFI_PTR32)&fakeEfiPages->efiRuntimeServices;
227
228// According to the EFI spec, BootServices aren't valid after the
229// boot process is exited so we can probably do without it.
230// Apple didn't provide a definition for it in pexpert/i386/efi.h
231// so I'm guessing they don't use it.
232efiSystemTable->BootServices = 0;
233
234efiSystemTable->NumberOfTableEntries = 0;
235efiSystemTable->ConfigurationTable = (EFI_PTR32)fakeEfiPages->efiConfigurationTable;
236
237// We're done. Now CRC32 the thing so the kernel will accept it.
238// Must be initialized to zero before CRC32, done above.
239gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
240
241// --------------------------------------------------------------------
242// Runtime services
243EFI_RUNTIME_SERVICES_32 *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;
244efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;
245efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;
246efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_32);
247efiRuntimeServices->Hdr.CRC32 = 0;
248efiRuntimeServices->Hdr.Reserved = 0;
249
250// There are a number of function pointers in the efiRuntimeServices table.
251// These are the Foundation (e.g. core) services and are expected to be present on
252// all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
253// will call these without checking to see if they are null.
254//
255// We don't really feel like doing an EFI implementation in the bootloader
256// but it is nice if we can at least prevent a complete crash by
257// at least providing some sort of implementation until one can be provided
258// nicely in a kext.
259void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;
260void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;
261efiRuntimeServices->GetTime = (EFI_PTR32)unsupportedret_fp;
262efiRuntimeServices->SetTime = (EFI_PTR32)unsupportedret_fp;
263efiRuntimeServices->GetWakeupTime = (EFI_PTR32)unsupportedret_fp;
264efiRuntimeServices->SetWakeupTime = (EFI_PTR32)unsupportedret_fp;
265efiRuntimeServices->SetVirtualAddressMap = (EFI_PTR32)unsupportedret_fp;
266efiRuntimeServices->ConvertPointer = (EFI_PTR32)unsupportedret_fp;
267efiRuntimeServices->GetVariable = (EFI_PTR32)unsupportedret_fp;
268efiRuntimeServices->GetNextVariableName = (EFI_PTR32)unsupportedret_fp;
269efiRuntimeServices->SetVariable = (EFI_PTR32)unsupportedret_fp;
270efiRuntimeServices->GetNextHighMonotonicCount = (EFI_PTR32)unsupportedret_fp;
271efiRuntimeServices->ResetSystem = (EFI_PTR32)voidret_fp;
272
273// We're done.Now CRC32 the thing so the kernel will accept it
274efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);
275
276// --------------------------------------------------------------------
277// Finish filling in the rest of the boot args that we need.
278bootArgs->efiSystemTable = (uint32_t)efiSystemTable;
279bootArgs->efiMode = kBootArgsEfiMode32;
280
281// The bootArgs structure as a whole is bzero'd so we don't need to fill in
282// things like efiRuntimeServices* and what not.
283//
284// In fact, the only code that seems to use that is the hibernate code so it
285// knows not to save the pages. It even checks to make sure its nonzero.
286}
287
288void setupEfiTables64(void)
289{
290struct fake_efi_pages
291{
292EFI_SYSTEM_TABLE_64 efiSystemTable;
293EFI_RUNTIME_SERVICES_64 efiRuntimeServices;
294EFI_CONFIGURATION_TABLE_64 efiConfigurationTable[MAX_CONFIGURATION_TABLE_ENTRIES];
295EFI_CHAR16 firmwareVendor[sizeof(FIRMWARE_VENDOR)/sizeof(EFI_CHAR16)];
296uint8_t voidret_instructions[sizeof(VOIDRET_INSTRUCTIONS)/sizeof(uint8_t)];
297uint8_t unsupportedret_instructions[sizeof(UNSUPPORTEDRET_INSTRUCTIONS)/sizeof(uint8_t)];
298};
299
300struct fake_efi_pages *fakeEfiPages = (struct fake_efi_pages*)AllocateKernelMemory(sizeof(struct fake_efi_pages));
301
302// Zero out all the tables in case fields are added later
303bzero(fakeEfiPages, sizeof(struct fake_efi_pages));
304
305// --------------------------------------------------------------------
306// Initialize some machine code that will return EFI_UNSUPPORTED for
307// functions returning int and simply return for void functions.
308memcpy(fakeEfiPages->voidret_instructions, VOIDRET_INSTRUCTIONS, sizeof(VOIDRET_INSTRUCTIONS));
309memcpy(fakeEfiPages->unsupportedret_instructions, UNSUPPORTEDRET_INSTRUCTIONS, sizeof(UNSUPPORTEDRET_INSTRUCTIONS));
310
311// --------------------------------------------------------------------
312// System table
313EFI_SYSTEM_TABLE_64 *efiSystemTable = gST64 = &fakeEfiPages->efiSystemTable;
314efiSystemTable->Hdr.Signature = EFI_SYSTEM_TABLE_SIGNATURE;
315efiSystemTable->Hdr.Revision = EFI_SYSTEM_TABLE_REVISION;
316efiSystemTable->Hdr.HeaderSize = sizeof(EFI_SYSTEM_TABLE_64);
317efiSystemTable->Hdr.CRC32 = 0; // Initialize to zero and then do CRC32
318efiSystemTable->Hdr.Reserved = 0;
319
320efiSystemTable->FirmwareVendor = ptov64((EFI_PTR32)&fakeEfiPages->firmwareVendor);
321memcpy(fakeEfiPages->firmwareVendor, FIRMWARE_VENDOR, sizeof(FIRMWARE_VENDOR));
322efiSystemTable->FirmwareRevision = FIRMWARE_REVISION;
323
324// XXX: We may need to have basic implementations of ConIn/ConOut/StdErr
325// The EFI spec states that all handles are invalid after boot services have been
326// exited so we can probably get by with leaving the handles as zero.
327efiSystemTable->ConsoleInHandle = 0;
328efiSystemTable->ConIn = 0;
329
330efiSystemTable->ConsoleOutHandle = 0;
331efiSystemTable->ConOut = 0;
332
333efiSystemTable->StandardErrorHandle = 0;
334efiSystemTable->StdErr = 0;
335
336efiSystemTable->RuntimeServices = ptov64((EFI_PTR32)&fakeEfiPages->efiRuntimeServices);
337// According to the EFI spec, BootServices aren't valid after the
338// boot process is exited so we can probably do without it.
339// Apple didn't provide a definition for it in pexpert/i386/efi.h
340// so I'm guessing they don't use it.
341efiSystemTable->BootServices = 0;
342
343efiSystemTable->NumberOfTableEntries = 0;
344efiSystemTable->ConfigurationTable = ptov64((EFI_PTR32)fakeEfiPages->efiConfigurationTable);
345
346// We're done.Now CRC32 the thing so the kernel will accept it
347gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
348
349// --------------------------------------------------------------------
350// Runtime services
351EFI_RUNTIME_SERVICES_64 *efiRuntimeServices = &fakeEfiPages->efiRuntimeServices;
352efiRuntimeServices->Hdr.Signature = EFI_RUNTIME_SERVICES_SIGNATURE;
353efiRuntimeServices->Hdr.Revision = EFI_RUNTIME_SERVICES_REVISION;
354efiRuntimeServices->Hdr.HeaderSize = sizeof(EFI_RUNTIME_SERVICES_64);
355efiRuntimeServices->Hdr.CRC32 = 0;
356efiRuntimeServices->Hdr.Reserved = 0;
357
358// There are a number of function pointers in the efiRuntimeServices table.
359// These are the Foundation (e.g. core) services and are expected to be present on
360// all EFI-compliant machines.Some kernel extensions (notably AppleEFIRuntime)
361// will call these without checking to see if they are null.
362//
363// We don't really feel like doing an EFI implementation in the bootloader
364// but it is nice if we can at least prevent a complete crash by
365// at least providing some sort of implementation until one can be provided
366// nicely in a kext.
367
368void (*voidret_fp)() = (void*)fakeEfiPages->voidret_instructions;
369void (*unsupportedret_fp)() = (void*)fakeEfiPages->unsupportedret_instructions;
370efiRuntimeServices->GetTime = ptov64((EFI_PTR32)unsupportedret_fp);
371efiRuntimeServices->SetTime = ptov64((EFI_PTR32)unsupportedret_fp);
372efiRuntimeServices->GetWakeupTime = ptov64((EFI_PTR32)unsupportedret_fp);
373efiRuntimeServices->SetWakeupTime = ptov64((EFI_PTR32)unsupportedret_fp);
374efiRuntimeServices->SetVirtualAddressMap = ptov64((EFI_PTR32)unsupportedret_fp);
375efiRuntimeServices->ConvertPointer = ptov64((EFI_PTR32)unsupportedret_fp);
376efiRuntimeServices->GetVariable = ptov64((EFI_PTR32)unsupportedret_fp);
377efiRuntimeServices->GetNextVariableName = ptov64((EFI_PTR32)unsupportedret_fp);
378efiRuntimeServices->SetVariable = ptov64((EFI_PTR32)unsupportedret_fp);
379efiRuntimeServices->GetNextHighMonotonicCount = ptov64((EFI_PTR32)unsupportedret_fp);
380efiRuntimeServices->ResetSystem = ptov64((EFI_PTR32)voidret_fp);
381
382// We're done.Now CRC32 the thing so the kernel will accept it
383efiRuntimeServices->Hdr.CRC32 = crc32(0L, efiRuntimeServices, efiRuntimeServices->Hdr.HeaderSize);
384
385// --------------------------------------------------------------------
386// Finish filling in the rest of the boot args that we need.
387bootArgs->efiSystemTable = (uint32_t)efiSystemTable;
388bootArgs->efiMode = kBootArgsEfiMode64;
389
390// The bootArgs structure as a whole is bzero'd so we don't need to fill in
391// things like efiRuntimeServices* and what not.
392//
393// In fact, the only code that seems to use that is the hibernate code so it
394// knows not to save the pages. It even checks to make sure its nonzero.
395}
396
397/*
398 * In addition to the EFI tables there is also the EFI device tree node.
399 * In particular, we need /efi/platform to have an FSBFrequency key. Without it,
400 * the tsc_init function will panic very early on in kernel startup, before
401 * the console is available.
402 */
403
404/*==========================================================================
405 * FSB Frequency detection
406 */
407
408/* These should be const but DT__AddProperty takes char* */
409static const char const TSC_Frequency_prop[] = "TSCFrequency";
410static const char const FSB_Frequency_prop[] = "FSBFrequency";
411static const char const CPU_Frequency_prop[] = "CPUFrequency";
412
413/*==========================================================================
414 * SMBIOS
415 */
416
417/* From Foundation/Efi/Guid/Smbios/SmBios.c */
418EFI_GUID constgEfiSmbiosTableGuid = EFI_SMBIOS_TABLE_GUID;
419
420#define SMBIOS_RANGE_START0x000F0000
421#define SMBIOS_RANGE_END0x000FFFFF
422
423/* '_SM_' in little endian: */
424#define SMBIOS_ANCHOR_UINT32_LE 0x5f4d535f
425
426#define EFI_ACPI_TABLE_GUID \
427 { \
4280xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, {0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
429 }
430
431#define EFI_ACPI_20_TABLE_GUID \
432 { \
4330x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, {0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \
434 }
435
436EFI_GUID gEfiAcpiTableGuid = EFI_ACPI_TABLE_GUID;
437EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID;
438
439
440/*==========================================================================
441 * Fake EFI implementation
442 */
443
444/* These should be const but DT__AddProperty takes char* */
445static const char const FIRMWARE_REVISION_PROP[] = "firmware-revision";
446static const char const FIRMWARE_ABI_PROP[] = "firmware-abi";
447static const char const FIRMWARE_VENDOR_PROP[] = "firmware-vendor";
448static const char const FIRMWARE_ABI_32_PROP_VALUE[] = "EFI32";
449static const char const FIRMWARE_ABI_64_PROP_VALUE[] = "EFI64";
450static const char const SYSTEM_ID_PROP[] = "system-id";
451static const char const SYSTEM_SERIAL_PROP[] = "SystemSerialNumber";
452static const char const SYSTEM_TYPE_PROP[] = "system-type";
453static const char const MODEL_PROP[] = "Model";
454//static const char const PLATFORM_UUID[] = "platform-uuid";
455
456
457/*
458 * Get an smbios option string option to convert to EFI_CHAR16 string
459 */
460
461static EFI_CHAR16* getSmbiosChar16(const char * key, size_t* len)
462{
463const char*src = getStringForKey(key, &bootInfo->smbiosConfig);
464EFI_CHAR16* dst = 0;
465size_t i = 0;
466
467if (!key || !(*key) || !len || !src) return 0;
468
469*len = strlen(src);
470dst = (EFI_CHAR16*) malloc( ((*len)+1) * 2 );
471for (; i < (*len); i++) dst[i] = src[i];
472dst[(*len)] = '\0';
473*len = ((*len)+1)*2; // return the CHAR16 bufsize including zero terminated CHAR16
474return dst;
475}
476
477/*
478 * Get the SystemID from the bios dmi info
479 */
480static EFI_GUID uuid;
481staticEFI_GUID * getSmbiosUUID()
482{
483int i, isZero, isOnes;
484//struct SMBEntryPoint*smbios;
485SMBByte*p, *u;
486//Slice - already done
487//smbios = getSmbios(SMBIOS_PATCHED); // checks for _SM_ anchor and table header checksum
488//if (smbios==NULL) return 0; // getSmbios() return a non null value if smbios is found
489
490p = (SMBByte*) FindFirstDmiTableOfType(1, 0x19); // Type 1: (3.3.2) System Information
491if (p==NULL) return NULL;
492p += 8;
493verbose("Found SMBIOS System Information Table 1\n");
494
495for (i=0, isZero=1, isOnes=1; i<UUID_LEN; i++)
496{
497if (p[i] != 0x00) isZero = 0;
498if (p[i] != 0xff) isOnes = 0;
499}
500
501if (isZero || isOnes) // empty or setable means: no uuid present
502{
503verbose("No UUID present in SMBIOS System Information Table\n");
504return 0;
505}
506
507//memcpy((void*)&uuid, p, UUID_LEN);
508//LE byte order while BE in SMBIOS
509u = (SMBByte *)&uuid;
510u[0] = p[3]; u[1] = p[2]; u[2] = p[1]; u[3] = p[0];
511u[4] = p[5]; u[5] = p[4]; u[6] = p[7]; u[7] = p[6];
512for (i=8; i<16; i++) {
513u[i] = p[i];
514}
515return &uuid;
516}
517
518/*
519 * return a binary UUID value from the overriden SystemID and SMUUID if found,
520 * or from the bios if not, or from a fixed value if no bios value is found
521 */
522
523extern EFI_GUID* getSystemID()
524{
525EFI_GUID*ret = NULL;
526// unable to determine UUID for host. Error: 35 fix
527// Rek: new SMsystemid option conforming to smbios notation standards, this option should
528// belong to smbios config only ...
529const char *sysId = getStringForKey(kSystemID, &bootInfo->bootConfig);
530if (sysId) {
531ret = (EFI_GUID*)getUUIDFromString(sysId);
532}
533
534if (!sysId || !ret) // try bios dmi info UUID extraction
535{
536ret = getSmbiosUUID();
537sysId = 0;
538}
539
540if (!ret) {
541// no bios dmi UUID available, set a fixed value for system-id
542//ret=getUUIDFromString((sysId = (const char*) SYSTEM_ID));
543ret = (EFI_GUID*)&SYSTEM_ID_DEFAULT;
544}
545#ifndef OPTION_ROM
546verbose("Customizing SystemID with : %s\n", getStringFromUUID(ret)); // apply a nice formatting to the displayed output
547#endif
548return ret;
549}
550/*
551 * Must be called AFTER setup Acpi because we need to take care of correct
552 * facp content to reflect in ioregs
553 */
554
555void setupSystemType()
556{
557Node *node = DT__FindNode("/", false);
558if (node == 0) stop("Couldn't get root node");
559// we need to write this property after facp parsing
560// Export system-type only if it has been overrriden by the SystemType option
561DT__AddProperty(node, SYSTEM_TYPE_PROP, sizeof(Platform->Type), &Platform->Type);
562}
563
564void setupEfiDeviceTree(void)
565{
566EFI_GUID*ret = 0;
567EFI_CHAR16* ret16 = 0;
568size_t len = 0;
569Node*node;
570
571node = DT__FindNode("/", false);
572
573if (node == 0) stop("Couldn't get root node");
574
575// We could also just do DT__FindNode("/efi/platform", true)
576// But I think eventually we want to fill stuff in the efi node
577// too so we might as well create it so we have a pointer for it too.
578node = DT__AddChild(node, "efi");
579
580if (archCpuType == CPU_TYPE_I386)
581{
582DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_32_PROP_VALUE), (char*)FIRMWARE_ABI_32_PROP_VALUE);
583}
584else
585{
586DT__AddProperty(node, FIRMWARE_ABI_PROP, sizeof(FIRMWARE_ABI_64_PROP_VALUE), (char*)FIRMWARE_ABI_64_PROP_VALUE);
587}
588
589DT__AddProperty(node, FIRMWARE_REVISION_PROP, sizeof(FIRMWARE_REVISION), (EFI_UINT32*)&FIRMWARE_REVISION);
590DT__AddProperty(node, FIRMWARE_VENDOR_PROP, sizeof(FIRMWARE_VENDOR), (EFI_CHAR16*)FIRMWARE_VENDOR);
591
592// TODO: Fill in other efi properties if necessary
593
594// Set up the /efi/runtime-services table node similar to the way a child node of configuration-table
595// is set up. That is, name and table properties
596Node *runtimeServicesNode = DT__AddChild(node, "runtime-services");
597
598if (archCpuType == CPU_TYPE_I386)
599{
600// The value of the table property is the 32-bit physical address for the RuntimeServices table.
601// Since the EFI system table already has a pointer to it, we simply use the address of that pointer
602// for the pointer to the property data. Warning.. DT finalization calls free on that but we're not
603// the only thing to use a non-malloc'd pointer for something in the DT
604
605DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST32->RuntimeServices);
606}
607else
608{
609DT__AddProperty(runtimeServicesNode, "table", sizeof(uint64_t), &gST64->RuntimeServices);
610}
611
612// Set up the /efi/configuration-table node which will eventually have several child nodes for
613// all of the configuration tables needed by various kernel extensions.
614gEfiConfigurationTableNode = DT__AddChild(node, "configuration-table");
615
616// Now fill in the /efi/platform Node
617Node *efiPlatformNode = DT__AddChild(node, "platform");
618
619// NOTE WELL: If you do add FSB Frequency detection, make sure to store
620// the value in the fsbFrequency global and not an malloc'd pointer
621// because the DT_AddProperty function does not copy its args.
622
623if (Platform->CPU.FSBFrequency != 0)
624DT__AddProperty(efiPlatformNode, FSB_Frequency_prop, sizeof(uint64_t), &Platform->CPU.FSBFrequency);
625
626// Export TSC and CPU frequencies for use by the kernel or KEXTs
627if (Platform->CPU.TSCFrequency != 0)
628DT__AddProperty(efiPlatformNode, TSC_Frequency_prop, sizeof(uint64_t), &Platform->CPU.TSCFrequency);
629
630if (Platform->CPU.CPUFrequency != 0)
631DT__AddProperty(efiPlatformNode, CPU_Frequency_prop, sizeof(uint64_t), &Platform->CPU.CPUFrequency);
632
633// Export system-id. Can be disabled with SystemId=No in com.apple.Boot.plist
634if ((ret=getSystemID()))
635DT__AddProperty(efiPlatformNode, SYSTEM_ID_PROP, UUID_LEN, (EFI_UINT32*) ret);
636
637 // Export SystemSerialNumber if present
638if ((ret16=getSmbiosChar16("SMserial", &len)))
639DT__AddProperty(efiPlatformNode, SYSTEM_SERIAL_PROP, len, ret16);
640
641// Export Model if present
642if ((ret16=getSmbiosChar16("SMproductname", &len)))
643DT__AddProperty(efiPlatformNode, MODEL_PROP, len, ret16);
644
645// Fill /efi/device-properties node.
646setupDeviceProperties(node);
647}
648
649/*
650 * Load the smbios.plist override config file if any
651 */
652
653static void setupSmbiosConfigFile(const char *filename)
654{
655chardirSpecSMBIOS[128] = "";
656const char *override_pathname = NULL;
657intlen = 0, err = 0;
658extern void scan_mem();
659
660// Take in account user overriding
661if (getValueForKey(kSMBIOSKey, &override_pathname, &len, &bootInfo->bootConfig) && len > 0)
662{
663// Specify a path to a file, e.g. SMBIOS=/Extra/macProXY.plist
664sprintf(dirSpecSMBIOS, override_pathname);
665err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
666}
667else
668{
669// Check selected volume's Extra.
670sprintf(dirSpecSMBIOS, "/Extra/%s", filename);
671if (err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig))
672{
673// Check booter volume/rdbt Extra.
674sprintf(dirSpecSMBIOS, "bt(0,0)/Extra/%s", filename);
675err = loadConfigFile(dirSpecSMBIOS, &bootInfo->smbiosConfig);
676}
677}
678
679if (err)
680{
681verbose("No SMBIOS replacement found.\n");
682}
683
684// get a chance to scan mem dynamically if user asks for it while having the config options loaded as well,
685// as opposed to when it was in scan_platform(); also load the orig. smbios so that we can access dmi info without
686// patching the smbios yet
687getSmbios(SMBIOS_ORIGINAL); //Slice - first encounter
688scan_mem();
689smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED);// process smbios asap
690//Slice - no more getSMBIOS needed
691bool useDMIinfoCPU = true;
692 getBoolForKey(kUseCPUDMI, &useDMIinfoCPU, &bootInfo->bootConfig);
693if (useDMIinfoCPU) {
694scan_cpu_DMI(); //&Platform);
695}
696// PM_Model
697//if ((Platform->CPU.Features & CPU_FEATURE_MOBILE)) {
698if ((Platform->CPU.Mobile)) {
699Platform->Type = 2;
700} else {
701Platform->Type = 1;
702}
703
704//Slice - overclock CPU patch
705struct DMIProcessorInformation* p = (struct DMIProcessorInformation*) FindFirstDmiTableOfType(4, 0x28);
706
707if (useDMIinfoCPU && ((p->currentClock) &&
708//(p->currentClock > p->maximumClock) &&
709//(p->maximumClock != 3800) && (p->maximumClock != 4000) &&
710(p->currentClock < 10000)))
711{
712verbose("Overclocked CPU from %dMHz to %dMHz\n", p->maximumClock, p->currentClock);
713p->maximumClock = p->currentClock;
714Platform->CPU.TSCFrequency = p->currentClock * MEGA;
715}
716}
717
718/*
719 * Installs all the needed configuration table entries
720 */
721
722static void setupEfiConfigurationTable()
723{
724//smbios_p = (EFI_PTR32)getSmbios(SMBIOS_PATCHED); //cached
725addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
726
727// Setup ACPI with DSDT overrides (mackerintel's patch)
728//setupAcpi(); // in module
729
730// We've obviously changed the count.. so fix up the CRC32
731if (archCpuType == CPU_TYPE_I386)
732{
733gST32->Hdr.CRC32 = 0;
734gST32->Hdr.CRC32 = crc32(0L, gST32, gST32->Hdr.HeaderSize);
735}
736else
737{
738gST64->Hdr.CRC32 = 0;
739gST64->Hdr.CRC32 = crc32(0L, gST64, gST64->Hdr.HeaderSize);
740}
741}
742
743/*
744 * Entrypoint from boot.c
745 */
746
747void setupFakeEfi(void)
748{
749// Generate efi device strings
750//Slice - remember globals
751Platform = (PlatformInfo_t *)gPlatform;
752root_pci_dev = (pci_dt_t*)gRootPCIDev;
753//verbose("setupFakeEfi: root_pci_dev_Vendor=%04x\n", (root_pci_dev->children)->vendor_id);
754setup_pci_devs((pci_dt_t*)gRootPCIDev);
755
756// load smbios.plist file if any
757setupSmbiosConfigFile("SMBIOS.plist");
758
759// Initialize the base table
760if (archCpuType == CPU_TYPE_I386)
761{
762setupEfiTables32();
763}
764else
765{
766setupEfiTables64();
767}
768
769// Initialize the device tree
770setupEfiDeviceTree();
771
772//getSmbios(SMBIOS_ORIGINAL); //Slice - already done
773getSmbiosProductName();
774
775
776execute_hook("setupEfiConfigurationTable", NULL, NULL, NULL, NULL);
777
778// Add configuration table entries to both the services table and the device tree
779setupEfiConfigurationTable();
780#if 1 //DEBUG
781struct DMIProcessorInformation* cpuInfo;
782struct DMIHeader * dmihdr;
783//Slice - Debug SMBIOS
784for (dmihdr = FindFirstDmiTableOfType(4, 30); dmihdr; dmihdr = FindNextDmiTableOfType(4, 30))
785{
786cpuInfo = (struct DMIProcessorInformation*)dmihdr;
787if (cpuInfo->processorType != 3) { // CPU
788continue;
789}
790//TODO validate
791msglog("Patched platform CPU Info:\n FSB=%d\n MaxSpeed=%d\n CurrentSpeed=%d\n", Platform->CPU.FSBFrequency/MEGA, Platform->CPU.TSCFrequency/MEGA, Platform->CPU.CPUFrequency/MEGA);
792
793msglog("Patched SMBIOS CPU Info:\n FSB=%d\n MaxSpeed=%d\n CurrentSpeed=%d\n", cpuInfo->externalClock, cpuInfo->maximumClock, cpuInfo->currentClock);
794msglog("\n Family=%x\n Socket=%x\n Cores=%d Enabled=%d Threads=%d\n", cpuInfo->processorFamily, cpuInfo->processorUpgrade, cpuInfo->coreCount, cpuInfo->coreEnabled, cpuInfo->Threads);
795}
796#endif
797}
798
799

Archive Download this file

Revision: 676