blob: bbdcfafe5f4c6583dca6b8c2e7db447f7d3368eb [file] [log] [blame]
Stefan Reinauercc5b3442013-01-15 17:02:58 -08001/*
2 * This file is part of the TianoCoreBoot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Stefan Reinauercc5b3442013-01-15 17:02:58 -080018 */
19
20#include <libpayload.h>
21#include <endian.h>
22#include <cbfs.h>
23#include <efi.h>
24#include <coff.h>
25
26#define DXE_CORE_SIZE (256*1024)
27#define UEFI_STACK_SIZE (128*1024)
28#define HOB_LIST_SIZE (16*1024)
29
30#undef VERBOSE
31#undef INVENTORY
32
33static void print_guid(EFI_GUID *guid)
34{
35 printf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
36 guid->Data1, guid->Data2, guid->Data3,
37 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
38 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
39}
40
41static void dump_uefi_firmware_volume_header(EFI_FIRMWARE_VOLUME_HEADER *fvh)
42{
43 printf("Found UEFI firmware volume.\n");
44 printf(" GUID: ");
45 print_guid(&(fvh->FileSystemGuid));
46 printf("\n");
47 printf(" length: 0x%016llx\n", fvh->FvLength);
48#ifdef VERBOSE
49 printf(" signature: 0x%08x\n", fvh->Signature);
50 printf(" attributes: 0x%08x\n", fvh->Attributes);
51 printf(" header length: 0x%04x\n", fvh->HeaderLength);
52 printf(" checksum: 0x%04x\n", fvh->Checksum);
53 printf(" revision: 0x%02x\n", fvh->Revision);
54 printf(" block map:\n");
55 int i = 0;
56 EFI_FV_BLOCK_MAP_ENTRY *fbm = &(fvh->FvBlockMap[0]);
57 while (fbm[i].NumBlocks || fbm[i].BlockLength) {
58 printf(" %2d. numblocks = 0x%08x length = 0x%08x\n",
59 i+1, fbm[i].NumBlocks, fbm[i].BlockLength);
60 i++;
61 }
62#endif
63 printf("\n");
64}
65
66#ifdef INVENTORY
67static void dump_uefi_ffs_file_header(EFI_FFS_FILE_HEADER *file)
68{
69 int size;
70
71#ifdef VERBOSE
72 printf("Found FFS file:\n GUID: ");
73#endif
74 print_guid(&(file->Name));
75#ifdef VERBOSE
76 printf("\n integrity check: %02x %02x\n",
77 file->IntegrityCheck.Checksum.Header,
78 file->IntegrityCheck.Checksum.File);
79 printf(" file type: ");
80#else
81 printf(" ");
82#endif
83 switch (file->Type) {
84 case EFI_FV_FILETYPE_RAW: printf("raw"); break;
85 case EFI_FV_FILETYPE_FREEFORM: printf("free form"); break;
86 case EFI_FV_FILETYPE_SECURITY_CORE: printf("security core"); break;
87 case EFI_FV_FILETYPE_PEI_CORE: printf("PEIM core"); break;
88 case EFI_FV_FILETYPE_DXE_CORE: printf("DXE core"); break;
89 case EFI_FV_FILETYPE_PEIM: printf("PEIM"); break;
90 case EFI_FV_FILETYPE_DRIVER: printf("driver"); break;
91 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: printf("combined PEIM driver"); break;
92 case EFI_FV_FILETYPE_APPLICATION: printf("application"); break;
93 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: printf("firmware volume image"); break;
94 case EFI_FV_FILETYPE_FFS_PAD: printf("FFS pad"); break;
95 default: printf("unknown");
96 }
97#ifdef VERBOSE
98 printf("\n");
99 printf(" attributes: 0x%02x\n", file->Attributes);
100#endif
101 size = file->Size[0] | (file->Size[1] << 8) | (file->Size[2] << 16);
102#ifdef VERBOSE
103 printf(" size: 0x%06x\n", size);
104 printf(" state: 0x%02x\n", file->State);
105#else
106 printf(" (%d bytes)\n", size);
107#endif
108}
109#endif
110
111void *load_dxe_core(void *pe, void *target)
112{
113 dos_header_t *dos_hdr = (dos_header_t *)pe;
114
115#if VERBOSE
116 printf("Loading DXE core at %p\n", pe);
117#endif
118
119 if (*(uint16_t *)pe != 0x5a4d) {
120 printf("DXE core not a PE binary.\n");
121 return NULL;
122 }
123
124#ifdef VERBOSE
125 printf("e_lfanew = 0x%08x\n", dos_hdr->e_lfanew);
126#endif
127
128 coff_header_t *coff_hdr = (coff_header_t *)(pe + dos_hdr->e_lfanew);
129#ifdef VERBOSE
130 printf("Machine: %x\n", coff_hdr->Machine);
131 printf("NumberOfSections: %x\n", coff_hdr->NumberOfSections);
132 printf("TimeDateStamp: %x\n", coff_hdr->TimeDateStamp);
133 printf("PointerToSymbolTable: %x\n", coff_hdr->PointerToSymbolTable);
134 printf("NumberOfSymbols: %x\n", coff_hdr->NumberOfSymbols);
135 printf("SizeOfOptionalHeader: %x\n", coff_hdr->SizeOfOptionalHeader);
136 printf("Characteristics: %x\n", coff_hdr->Characteristics);
137#endif
138 if (coff_hdr->Machine != 0x14c) {
139 printf("Only x86 supported right now.\n");
140 return NULL;
141 }
142
143 /* Right after the coff header */
144 pe_opt_header_t *pe_hdr = (pe_opt_header_t *)(&coff_hdr[1]);
145 if (pe_hdr->signature != 267) {
146 printf("No valid PE opt header\n");
147 return NULL;
148 }
149
150#ifdef VERBOSE
151 printf("\n");
152 printf("MajorLinkerVersion: %x\n", pe_hdr->MajorLinkerVersion);
153 printf("MinorLinkerVersion: %x\n", pe_hdr->MinorLinkerVersion);
154 printf("SizeOfCode: %x\n", pe_hdr->SizeOfCode);
155 printf("SizeOfInitializedData: %x\n", pe_hdr->SizeOfInitializedData);
156 printf("SizeOfUninitializedData: %x\n", pe_hdr->SizeOfUninitializedData);
157 printf("AddressOfEntryPoint: %x\n", pe_hdr->AddressOfEntryPoint);
158 printf("BaseOfCode: %x\n", pe_hdr->BaseOfCode);
159 printf("BaseOfData: %x\n", pe_hdr->BaseOfData);
160 printf("ImageBase: %x\n", pe_hdr->ImageBase);
161 printf("SectionAlignment: %x\n", pe_hdr->SectionAlignment);
162 printf("FileAlignment: %x\n", pe_hdr->FileAlignment);
163 printf("MajorOSVersion: %x\n", pe_hdr->MajorOSVersion);
164 printf("MinorOSVersion: %x\n", pe_hdr->MinorOSVersion);
165 printf("MajorImageVersion: %x\n", pe_hdr->MajorImageVersion);
166 printf("MinorImageVersion: %x\n", pe_hdr->MinorImageVersion);
167 printf("MajorSubsystemVersion: %x\n", pe_hdr->MajorSubsystemVersion);
168 printf("MinorSubsystemVersion: %x\n", pe_hdr->MinorSubsystemVersion);
169 printf("Reserved: %x\n", pe_hdr->Reserved);
170 printf("SizeOfImage: %x\n", pe_hdr->SizeOfImage);
171 printf("SizeOfHeaders: %x\n", pe_hdr->SizeOfHeaders);
172 printf("Checksum: %x\n", pe_hdr->Checksum);
173 printf("Subsystem: %x\n", pe_hdr->Subsystem);
174 printf("DLLCharacteristics: %x\n", pe_hdr->DLLCharacteristics);
175 printf("SizeOfStackReserve: %x\n", pe_hdr->SizeOfStackReserve);
176 printf("SizeOfStackCommit: %x\n", pe_hdr->SizeOfStackCommit);
177 printf("SizeOfHeapReserve: %x\n", pe_hdr->SizeOfHeapReserve);
178 printf("SizeOfHeapCommit: %x\n", pe_hdr->SizeOfHeapCommit);
179 printf("LoaderFlags: %x\n", pe_hdr->LoaderFlags);
180 printf("NumberOfRvaAndSizes: %x\n", pe_hdr->NumberOfRvaAndSizes);
181#endif
182
183 if(pe_hdr->Subsystem != 0xb) {
184 printf("Not an EFI binary.\n");
185 return NULL;
186 }
187
188 int i;
189#ifdef VERBOSE
190 for (i = 0; i < pe_hdr->NumberOfRvaAndSizes; i++) {
191 if (!pe_hdr->DataDirectory[i].Size)
192 continue;
193 printf("Data Directory %d\n", i+1);
194 printf(" VirtualAddress %x\n", pe_hdr->DataDirectory[i].VirtualAddress);
195 printf(" Size %x\n", pe_hdr->DataDirectory[i].Size);
196 }
197#endif
198
199 pe_section_t *sections = (pe_section_t *)(&pe_hdr[1]);
200
201 int offset = 0;
202
203 for (i = 0; i < coff_hdr->NumberOfSections; i++) {
204 int j;
205 printf(" Section %d: ", i);
206 for (j = 0; j < 8; j++)
207 printf("%c", sections[i].SectionName[j] ? sections[i].SectionName[j] : ' ');
208
209 printf(" size=%08x rva=%08x in file=%08x/%08x flags=%08x\n",
210 sections[i].Size, sections[i].RVA, sections[i].PhysicalSizeOnDisk,
211 sections[i].PhysicalLocationOnDisk, sections[i].SectionFlags);
212
213 if (!strncmp((char *)sections[i].SectionName, ".text", 6)) {
214 // .text section
215 // size=157a0 rva=240 size on disk=157a0 location on disk=240 flags=60000020
216 memcpy(target, pe + sections[i].PhysicalLocationOnDisk,
217 sections[i].PhysicalSizeOnDisk);
218 offset = sections[i].RVA;
219 } else
220 if (!strncmp((char *)sections[i].SectionName, ".data", 6)) {
221 // .data section
222 // size=6820 rva=159e0 size on disk=6820 location on disk=159e0 flags=c0000040
223 memcpy(target + sections[i].RVA - offset, pe + sections[i].PhysicalLocationOnDisk,
224 sections[i].PhysicalSizeOnDisk);
225 } else
226 if (!strncmp((char *)sections[i].SectionName, ".reloc", 7)) {
227 // .reloc section
228 // section 2: .reloc
229 // size=1080 rva=1c200 size on disk=1080 location on disk=1c200 flags=42000040
230 relocation_t *reloc = (relocation_t *)
231 (pe + sections[i].PhysicalLocationOnDisk);
232 while (reloc && reloc->SizeOfBlock) {
233#ifdef VERBOSE
234 printf("Relocation Block Virtual %08x Size %08x\n",
235 reloc->VirtualAddress, reloc->SizeOfBlock);
236#endif
237 for (i = sizeof(relocation_t); i < reloc->SizeOfBlock; i+= 2) {
238 uint16_t r = *(uint16_t *)((void *)reloc + i);
239 switch (r>>12) {
240 case 3:
241#ifdef VERBOSE
242 printf(" HIGHLOW %08x\n",
243 reloc->VirtualAddress + (r & 0xfff));
244#endif
245 *(uint32_t *)(target - offset + reloc->VirtualAddress + (r & 0xfff))
246 += (unsigned long)target - offset;
247 break;
248 case 0:
249#ifdef VERBOSE
250 printf(" ABSOLUTE %08x\n", r & 0xfff);
251#endif
252 break;
253 default:
254 printf("Unknown relocation type %x\n", r);
255 return NULL;
256 }
257 }
258
259 reloc = (relocation_t *)(((void *)reloc) + reloc->SizeOfBlock);
260 }
261 } else
262 if (!strncmp((char *)sections[i].SectionName, ".debug", 7)) {
263 // debug section, silently ignored.
264 } else {
265 printf("section type ");
266 for (j = 0; j < 8; j++)
267 if (sections[i].SectionName[j])
268 printf("%c", sections[i].SectionName[j]);
269 printf(" unknown. ignored.\n");
270 }
271 }
272
273 return (target + pe_hdr->AddressOfEntryPoint - offset);
274}
275
276void start_dxe_core(void *entry, void *stack, void *hoblist)
277{
278 printf("\nJumping to DXE core at %p\n", entry);
279 asm volatile(
280 "movl %1, %%esp\n"
281 "pushl %2\n"
282 "call *%0\n"
283 : : "r"(entry), "r"(stack), "r"(hoblist) : "esp"
284 );
285}
286
287static const EFI_HOB_HANDOFF_INFO_TABLE HandoffInformationTable = {
288 { EFI_HOB_TYPE_HANDOFF, sizeof(EFI_HOB_HANDOFF_INFO_TABLE), 0 },
289 EFI_HOB_HANDOFF_TABLE_VERSION,
290 BOOT_WITH_FULL_CONFIGURATION,
291 0 /* EfiMemoryTop */,
292 0 /* EfiMemoryBottom */,
293 0 /* EfiFreeMemoryTop */,
294 0 /* EfiFreeMemoryBottom */,
295 0 /* EfiEndOfHobList */
296};
297
298static const EFI_HOB_FIRMWARE_VOLUME FirmwareVolume = {
299 { EFI_HOB_TYPE_FV, sizeof(EFI_HOB_FIRMWARE_VOLUME), 0 },
300 0 /* BaseAddress */,
301 0 /* Length */
302};
303
304/* 1..n */
305static const EFI_HOB_RESOURCE_DESCRIPTOR ResourceDescriptor = {
306 { EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof(EFI_HOB_RESOURCE_DESCRIPTOR), 0 },
307 { 0 }, // owner EFI_GUID
308 EFI_RESOURCE_SYSTEM_MEMORY,
309 EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
310 EFI_RESOURCE_ATTRIBUTE_TESTED,
311 0, /* PhysicalStart */
312 0 /* ResourceLength */
313};
314
315static const EFI_HOB_MEMORY_ALLOCATION_MODULE MemoryAllocationModule = {
316 { EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof(EFI_HOB_MEMORY_ALLOCATION_MODULE), 0 },
317 { EFI_HOB_MEMORY_ALLOC_MODULE_GUID, 0 /* MemoryBaseAddress */, 0 /* MemoryLength */, EfiBootServicesCode, {0,0,0,0} },
318 EFI_DXE_FILE_GUID,
319 0x0 // ADDR EntryPoint
320};
321
322static const EFI_HOB_CPU Cpu = {
323 { EFI_HOB_TYPE_CPU, sizeof(EFI_HOB_CPU), 0 },
324 32, /* SizeOfMemorySpace, u8 */
325 16, /* SizeOfIoSpace */
326 { 0,0,0,0,0,0 }
327};
328
329static const EFI_HOB_GENERIC_HEADER End =
330 { EFI_HOB_TYPE_END_OF_HOB_LIST, sizeof(EFI_HOB_GENERIC_HEADER), 0 };
331
332
333static void prepare_handoff_blocks(void *hoblist, EFI_FIRMWARE_VOLUME_HEADER *fvh,
334 unsigned long EfiMemoryTop, unsigned long EfiMemoryBottom,
335 unsigned long EfiFreeMemoryTop, unsigned long EfiFreeMemoryBottom,
336 unsigned long dxecore_base)
337{
338 void *ptr = hoblist;
339 int i;
340
341 EFI_HOB_HANDOFF_INFO_TABLE *hit = (EFI_HOB_HANDOFF_INFO_TABLE *)ptr;
342 memcpy(ptr, &HandoffInformationTable, sizeof(HandoffInformationTable));
343 ptr += sizeof(HandoffInformationTable);
344
345 EFI_HOB_FIRMWARE_VOLUME *fv = (EFI_HOB_FIRMWARE_VOLUME *)ptr;
346 memcpy(ptr, &FirmwareVolume, sizeof(FirmwareVolume));
347 ptr += sizeof(FirmwareVolume);
348
349 for (i = 0; i < lib_sysinfo.n_memranges; i++) {
350 EFI_HOB_RESOURCE_DESCRIPTOR *resource;
351 if (lib_sysinfo.memrange[i].type != CB_MEM_RAM)
352 continue;
353 resource = (EFI_HOB_RESOURCE_DESCRIPTOR *)ptr;
354 memcpy(ptr, &ResourceDescriptor, sizeof(ResourceDescriptor));
355 ptr += sizeof(ResourceDescriptor);
356 resource->PhysicalStart = lib_sysinfo.memrange[i].base;
357 resource->ResourceLength = lib_sysinfo.memrange[i].size;
358 }
359
360 EFI_HOB_MEMORY_ALLOCATION_MODULE *allocation = (EFI_HOB_MEMORY_ALLOCATION_MODULE *)ptr;
361 memcpy(ptr, &MemoryAllocationModule, sizeof(MemoryAllocationModule));
362 ptr += sizeof(MemoryAllocationModule);
363
364 memcpy(ptr, &Cpu, sizeof(Cpu));
365 ptr += sizeof(Cpu);
366
367 memcpy(ptr, &End, sizeof(End));
368 ptr += sizeof(Cpu);
369
370 /* Handoff Information Table HOB */
371 hit->EfiMemoryTop = EfiMemoryTop;
372 hit->EfiMemoryBottom = EfiMemoryBottom;
373 hit->EfiFreeMemoryTop = EfiFreeMemoryTop;
374 hit->EfiFreeMemoryBottom = EfiFreeMemoryBottom;
375 hit->EfiEndOfHobList = (unsigned long)ptr;
376
377 /* Firmware Volume HOB */
378 fv->BaseAddress = (unsigned long)fvh;
379 fv->Length = fvh->FvLength;
380
381 allocation->MemoryAllocationHeader.MemoryBaseAddress = dxecore_base;
382 allocation->MemoryAllocationHeader.MemoryLength = DXE_CORE_SIZE;
383}
384
385int main(void)
386{
387 int i;
388 struct cbfs_file *file;
389 void *tiano;
390 unsigned long long ram_seg_base = 0, ram_seg_size = 0;
391 EFI_FIRMWARE_VOLUME_HEADER *fvh = NULL;
392 EFI_PEI_HOB_POINTERS hoblist;
393 EFI_COMMON_SECTION_HEADER *dxecore = NULL;
394
395 printf("\nTiano Core Loader v1.0\n");
396 printf("Copyright (C) 2013 Google Inc. All rights reserved.\n\n");
397
398 printf("Memory Map (%d entries):\n", lib_sysinfo.n_memranges);
399 for (i = 0; i < lib_sysinfo.n_memranges; i++) {
400 printf(" %d. %016llx - %016llx [%02x]\n", i + 1,
401 lib_sysinfo.memrange[i].base,
402 lib_sysinfo.memrange[i].base +
403 lib_sysinfo.memrange[i].size - 1,
404 lib_sysinfo.memrange[i].type);
405
406 /* Look for the last chunk of memory below 4G */
407 if (lib_sysinfo.memrange[i].type == CB_MEM_RAM &&
408 lib_sysinfo.memrange[i].base < 0xffffffff) {
409 ram_seg_base = lib_sysinfo.memrange[i].base;
410 ram_seg_size = lib_sysinfo.memrange[i].size;
411 }
412 }
413 printf("\n");
414
415 if (!ram_seg_base || ram_seg_size < (1024*1024)) {
416 printf("No usable RAM found.\n");
417 halt();
418 }
419
420 /* Find the end of our memory block, align to 4K */
421 unsigned long memory = (ram_seg_base + ram_seg_size) & 0xfffff000;
422
423 /* 256K for DXE core. It's 116K on my system but you never know. */
424 memory -= DXE_CORE_SIZE;
425 unsigned long dxecore_base = memory;
426 memory -= UEFI_STACK_SIZE;
427 unsigned long uefi_stack = memory;
428
429 memory -= 1024*1024; // FIXME this should go away
430 unsigned long free_memory = memory; // FIXME this should go away
431
432 memory -= HOB_LIST_SIZE;
433 unsigned long hoblist_base = memory;
434
435 printf("DXE code: %08lx\n", dxecore_base);
436 printf("DXE stack: %08lx\n", uefi_stack);
437 printf("HOB list: %08lx\n\n", hoblist_base);
438
439 /* Find UEFI firmware volume in CBFS */
440 file = cbfs_find("fallback/tianocore.fd");
441 if (!file) {
442 printf("Could not find fallback/tianocore.fd in CBFS.\n");
443 halt();
444 }
445
446 tiano = CBFS_SUBHEADER(file);
447 while (tiano < (void *)CBFS_SUBHEADER(file) + ntohl(file->len)) {
448 /* Verify UEFI firmware volume consistency */
449 fvh = (EFI_FIRMWARE_VOLUME_HEADER *)tiano;
450 if (fvh->Signature != 0x4856465f) {
451 printf("Not an UEFI firmware volume.\n");
452 halt();
453 }
454
455 /* Dump UEFI firmware volume header */
456 dump_uefi_firmware_volume_header(fvh);
457
458 /* Dump UEFI firmware file headers */
459 for (i = fvh->HeaderLength; i < fvh->FvLength;) {
460 int size;
461 EFI_FFS_FILE_HEADER *ffs;
462
463 ffs = (EFI_FFS_FILE_HEADER *)(tiano + i);
464
465 size = ffs->Size[0] | (ffs->Size[1] << 8) | (ffs->Size[2] << 16);
466 if (size == 0xffffff)
467 break;
468#ifdef INVENTORY
469 printf("%08x - ", i);
470 dump_uefi_ffs_file_header(ffs);
471#endif
472
473 if (ffs->Type == EFI_FV_FILETYPE_DXE_CORE) {
474 dxecore = (EFI_COMMON_SECTION_HEADER *)&ffs[1];
475#ifndef INVENTORY
476 break;
477#endif
478 }
479
480 i = ALIGN(i + size, 8);
481 }
482
483 tiano += fvh->FvLength;
484#ifdef INVENTORY
485 printf("\n");
486#endif
487 }
488
489 /* Prepare Hand Off Blocks */
490 prepare_handoff_blocks((void *)hoblist_base, fvh,
491 // FIXME memory top, memory bottom
492 (ram_seg_base + ram_seg_size) & 0xfffff000, ram_seg_base,
493 // FIXME free memory top, free memory bottom
494 uefi_stack, free_memory,
495 dxecore_base);
496 hoblist.Raw = (void *)hoblist_base;
497
498 if (!dxecore) {
499 printf("No DXE core found.\n");
500 halt();
501 }
502
503 printf("Found DXE core at %p\n", &dxecore[1]);
504#ifdef VERBOSE
505 int size = dxecore->Size[0] | (dxecore->Size[1] << 8) | (dxecore->Size[2] << 16);
506 printf(" size = %d, type = %x\n", size, dxecore->Type);
507#endif
508
509 void *pe = (void *)&dxecore[1];
510
511 void *entry;
512 entry = load_dxe_core(pe, (void *)dxecore_base);
513
514 if (!entry) {
515 printf("Could not load DXE code.\n");
516 halt();
517 }
518
519 start_dxe_core(entry, (void *)(uefi_stack + UEFI_STACK_SIZE - 4), hoblist.Raw);
520
521 printf("The end.\n");
522 halt();
523
524 return 0;
525}
526
527PAYLOAD_INFO(name, "TianoCoreBoot");
528PAYLOAD_INFO(listname, "Tiano Core");
529PAYLOAD_INFO(desc, "Tiano Core Loader");