1 /** @file
2
3 Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
4
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "LoadLinuxLib.h"
16
17
18 /**
19 A simple check of the kernel setup image
20
21 An assumption is made that the size of the data is at least the
22 size of struct boot_params.
23
24 @param[in] KernelSetup - The kernel setup image
25
26 @retval EFI_SUCCESS - The kernel setup looks valid and supported
27 @retval EFI_INVALID_PARAMETER - KernelSetup was NULL
28 @retval EFI_UNSUPPORTED - The kernel setup is not valid or supported
29
30 **/
31 STATIC
32 EFI_STATUS
33 EFIAPI
BasicKernelSetupCheck(IN VOID * KernelSetup)34 BasicKernelSetupCheck (
35 IN VOID *KernelSetup
36 )
37 {
38 return LoadLinuxCheckKernelSetup(KernelSetup, sizeof (struct boot_params));
39 }
40
41
42 EFI_STATUS
43 EFIAPI
LoadLinuxCheckKernelSetup(IN VOID * KernelSetup,IN UINTN KernelSetupSize)44 LoadLinuxCheckKernelSetup (
45 IN VOID *KernelSetup,
46 IN UINTN KernelSetupSize
47 )
48 {
49 struct boot_params *Bp;
50
51 if (KernelSetup == NULL) {
52 return EFI_INVALID_PARAMETER;
53 }
54
55 if (KernelSetupSize < sizeof (*Bp)) {
56 return EFI_UNSUPPORTED;
57 }
58
59 Bp = (struct boot_params*) KernelSetup;
60
61 if ((Bp->hdr.signature != 0xAA55) || // Check boot sector signature
62 (Bp->hdr.header != SETUP_HDR) ||
63 (Bp->hdr.version < 0x205) || // We only support relocatable kernels
64 (!Bp->hdr.relocatable_kernel)
65 ) {
66 return EFI_UNSUPPORTED;
67 } else {
68 return EFI_SUCCESS;
69 }
70 }
71
72
73 UINTN
74 EFIAPI
LoadLinuxGetKernelSize(IN VOID * KernelSetup,IN UINTN KernelSize)75 LoadLinuxGetKernelSize (
76 IN VOID *KernelSetup,
77 IN UINTN KernelSize
78 )
79 {
80 struct boot_params *Bp;
81
82 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
83 return 0;
84 }
85
86 Bp = (struct boot_params*) KernelSetup;
87
88 if (Bp->hdr.version > 0x20a) {
89 return Bp->hdr.init_size;
90 } else {
91 //
92 // Add extra size for kernel decompression
93 //
94 return 3 * KernelSize;
95 }
96 }
97
98
99 VOID*
100 EFIAPI
LoadLinuxAllocateKernelSetupPages(IN UINTN Pages)101 LoadLinuxAllocateKernelSetupPages (
102 IN UINTN Pages
103 )
104 {
105 EFI_STATUS Status;
106 EFI_PHYSICAL_ADDRESS Address;
107
108 Address = BASE_1GB;
109 Status = gBS->AllocatePages (
110 AllocateMaxAddress,
111 EfiLoaderData,
112 Pages,
113 &Address
114 );
115 if (!EFI_ERROR (Status)) {
116 return (VOID*)(UINTN) Address;
117 } else {
118 return NULL;
119 }
120 }
121
122 EFI_STATUS
123 EFIAPI
LoadLinuxInitializeKernelSetup(IN VOID * KernelSetup)124 LoadLinuxInitializeKernelSetup (
125 IN VOID *KernelSetup
126 )
127 {
128 EFI_STATUS Status;
129 UINTN SetupEnd;
130 struct boot_params *Bp;
131
132 Status = BasicKernelSetupCheck (KernelSetup);
133 if (EFI_ERROR (Status)) {
134 return Status;
135 }
136
137 Bp = (struct boot_params*) KernelSetup;
138
139 SetupEnd = 0x202 + (Bp->hdr.jump & 0xff);
140
141 //
142 // Clear all but the setup_header
143 //
144 ZeroMem (KernelSetup, 0x1f1);
145 ZeroMem (((UINT8 *)KernelSetup) + SetupEnd, 4096 - SetupEnd);
146 DEBUG ((EFI_D_INFO, "Cleared kernel setup 0-0x1f1, 0x%Lx-0x1000\n",
147 (UINT64)SetupEnd));
148
149 return EFI_SUCCESS;
150 }
151
152 VOID*
153 EFIAPI
LoadLinuxAllocateKernelPages(IN VOID * KernelSetup,IN UINTN Pages)154 LoadLinuxAllocateKernelPages (
155 IN VOID *KernelSetup,
156 IN UINTN Pages
157 )
158 {
159 EFI_STATUS Status;
160 EFI_PHYSICAL_ADDRESS KernelAddress;
161 UINT32 Loop;
162 struct boot_params *Bp;
163
164 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
165 return NULL;
166 }
167
168 Bp = (struct boot_params*) KernelSetup;
169
170 for (Loop = 1; Loop < 512; Loop++) {
171 KernelAddress = MultU64x32 (
172 2 * Bp->hdr.kernel_alignment,
173 Loop
174 );
175 Status = gBS->AllocatePages (
176 AllocateAddress,
177 EfiLoaderData,
178 Pages,
179 &KernelAddress
180 );
181 if (!EFI_ERROR (Status)) {
182 return (VOID*)(UINTN) KernelAddress;
183 }
184 }
185
186 return NULL;
187 }
188
189
190 VOID*
191 EFIAPI
LoadLinuxAllocateCommandLinePages(IN UINTN Pages)192 LoadLinuxAllocateCommandLinePages (
193 IN UINTN Pages
194 )
195 {
196 EFI_STATUS Status;
197 EFI_PHYSICAL_ADDRESS Address;
198
199 Address = 0xa0000;
200 Status = gBS->AllocatePages (
201 AllocateMaxAddress,
202 EfiLoaderData,
203 Pages,
204 &Address
205 );
206 if (!EFI_ERROR (Status)) {
207 return (VOID*)(UINTN) Address;
208 } else {
209 return NULL;
210 }
211 }
212
213
214 VOID*
215 EFIAPI
LoadLinuxAllocateInitrdPages(IN VOID * KernelSetup,IN UINTN Pages)216 LoadLinuxAllocateInitrdPages (
217 IN VOID *KernelSetup,
218 IN UINTN Pages
219 )
220 {
221 EFI_STATUS Status;
222 EFI_PHYSICAL_ADDRESS Address;
223
224 struct boot_params *Bp;
225
226 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
227 return NULL;
228 }
229
230 Bp = (struct boot_params*) KernelSetup;
231
232 Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Bp->hdr.ramdisk_max;
233 Status = gBS->AllocatePages (
234 AllocateMaxAddress,
235 EfiLoaderData,
236 Pages,
237 &Address
238 );
239 if (!EFI_ERROR (Status)) {
240 return (VOID*)(UINTN) Address;
241 } else {
242 return NULL;
243 }
244 }
245
246
247 STATIC
248 VOID
SetupLinuxMemmap(IN OUT struct boot_params * Bp)249 SetupLinuxMemmap (
250 IN OUT struct boot_params *Bp
251 )
252 {
253 EFI_STATUS Status;
254 UINT8 TmpMemoryMap[1];
255 UINTN MapKey;
256 UINTN DescriptorSize;
257 UINT32 DescriptorVersion;
258 UINTN MemoryMapSize;
259 EFI_MEMORY_DESCRIPTOR *MemoryMap;
260 EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;
261 UINTN Index;
262 struct efi_info *Efi;
263 struct e820_entry *LastE820;
264 struct e820_entry *E820;
265 UINTN E820EntryCount;
266 EFI_PHYSICAL_ADDRESS LastEndAddr;
267
268 //
269 // Get System MemoryMapSize
270 //
271 MemoryMapSize = sizeof (TmpMemoryMap);
272 Status = gBS->GetMemoryMap (
273 &MemoryMapSize,
274 (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
275 &MapKey,
276 &DescriptorSize,
277 &DescriptorVersion
278 );
279 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
280 //
281 // Enlarge space here, because we will allocate pool now.
282 //
283 MemoryMapSize += EFI_PAGE_SIZE;
284 Status = gBS->AllocatePool (
285 EfiLoaderData,
286 MemoryMapSize,
287 (VOID **) &MemoryMap
288 );
289 ASSERT_EFI_ERROR (Status);
290
291 //
292 // Get System MemoryMap
293 //
294 Status = gBS->GetMemoryMap (
295 &MemoryMapSize,
296 MemoryMap,
297 &MapKey,
298 &DescriptorSize,
299 &DescriptorVersion
300 );
301 ASSERT_EFI_ERROR (Status);
302
303 LastE820 = NULL;
304 E820 = &Bp->e820_map[0];
305 E820EntryCount = 0;
306 LastEndAddr = 0;
307 MemoryMapPtr = MemoryMap;
308 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
309 UINTN E820Type = 0;
310
311 if (MemoryMap->NumberOfPages == 0) {
312 continue;
313 }
314
315 switch(MemoryMap->Type) {
316 case EfiReservedMemoryType:
317 case EfiRuntimeServicesCode:
318 case EfiRuntimeServicesData:
319 case EfiMemoryMappedIO:
320 case EfiMemoryMappedIOPortSpace:
321 case EfiPalCode:
322 E820Type = E820_RESERVED;
323 break;
324
325 case EfiUnusableMemory:
326 E820Type = E820_UNUSABLE;
327 break;
328
329 case EfiACPIReclaimMemory:
330 E820Type = E820_ACPI;
331 break;
332
333 case EfiLoaderCode:
334 case EfiLoaderData:
335 case EfiBootServicesCode:
336 case EfiBootServicesData:
337 case EfiConventionalMemory:
338 E820Type = E820_RAM;
339 break;
340
341 case EfiACPIMemoryNVS:
342 E820Type = E820_NVS;
343 break;
344
345 default:
346 DEBUG ((
347 EFI_D_ERROR,
348 "Invalid EFI memory descriptor type (0x%x)!\n",
349 MemoryMap->Type
350 ));
351 continue;
352 }
353
354 if ((LastE820 != NULL) &&
355 (LastE820->type == (UINT32) E820Type) &&
356 (MemoryMap->PhysicalStart == LastEndAddr)) {
357 LastE820->size += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
358 LastEndAddr += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
359 } else {
360 if (E820EntryCount >= ARRAY_SIZE (Bp->e820_map)) {
361 break;
362 }
363 E820->type = (UINT32) E820Type;
364 E820->addr = MemoryMap->PhysicalStart;
365 E820->size = EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
366 LastE820 = E820;
367 LastEndAddr = E820->addr + E820->size;
368 E820++;
369 E820EntryCount++;
370 }
371
372 //
373 // Get next item
374 //
375 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
376 }
377 Bp->e820_entries = (UINT8) E820EntryCount;
378
379 Efi = &Bp->efi_info;
380 Efi->efi_systab = (UINT32)(UINTN) gST;
381 Efi->efi_memdesc_size = (UINT32) DescriptorSize;
382 Efi->efi_memdesc_version = DescriptorVersion;
383 Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr;
384 Efi->efi_memmap_size = (UINT32) MemoryMapSize;
385 #ifdef MDE_CPU_IA32
386 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2');
387 #else
388 Efi->efi_systab_hi = (UINT32) (((UINT64)(UINTN) gST) >> 32);
389 Efi->efi_memmap_hi = (UINT32) (((UINT64)(UINTN) MemoryMapPtr) >> 32);
390 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4');
391 #endif
392
393 gBS->ExitBootServices (gImageHandle, MapKey);
394 }
395
396
397 EFI_STATUS
398 EFIAPI
LoadLinuxSetCommandLine(IN OUT VOID * KernelSetup,IN CHAR8 * CommandLine)399 LoadLinuxSetCommandLine (
400 IN OUT VOID *KernelSetup,
401 IN CHAR8 *CommandLine
402 )
403 {
404 EFI_STATUS Status;
405 struct boot_params *Bp;
406
407 Status = BasicKernelSetupCheck (KernelSetup);
408 if (EFI_ERROR (Status)) {
409 return Status;
410 }
411
412 Bp = (struct boot_params*) KernelSetup;
413
414 Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine;
415
416 return EFI_SUCCESS;
417 }
418
419
420 EFI_STATUS
421 EFIAPI
LoadLinuxSetInitrd(IN OUT VOID * KernelSetup,IN VOID * Initrd,IN UINTN InitrdSize)422 LoadLinuxSetInitrd (
423 IN OUT VOID *KernelSetup,
424 IN VOID *Initrd,
425 IN UINTN InitrdSize
426 )
427 {
428 EFI_STATUS Status;
429 struct boot_params *Bp;
430
431 Status = BasicKernelSetupCheck (KernelSetup);
432 if (EFI_ERROR (Status)) {
433 return Status;
434 }
435
436 Bp = (struct boot_params*) KernelSetup;
437
438 Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd;
439 Bp->hdr.ramdisk_len = (UINT32) InitrdSize;
440
441 return EFI_SUCCESS;
442 }
443
444
445 STATIC VOID
FindBits(unsigned long Mask,UINT8 * Pos,UINT8 * Size)446 FindBits (
447 unsigned long Mask,
448 UINT8 *Pos,
449 UINT8 *Size
450 )
451 {
452 UINT8 First, Len;
453
454 First = 0;
455 Len = 0;
456
457 if (Mask) {
458 while (!(Mask & 0x1)) {
459 Mask = Mask >> 1;
460 First++;
461 }
462
463 while (Mask & 0x1) {
464 Mask = Mask >> 1;
465 Len++;
466 }
467 }
468 *Pos = First;
469 *Size = Len;
470 }
471
472
473 STATIC
474 EFI_STATUS
SetupGraphicsFromGop(struct screen_info * Si,EFI_GRAPHICS_OUTPUT_PROTOCOL * Gop)475 SetupGraphicsFromGop (
476 struct screen_info *Si,
477 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
478 )
479 {
480 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
481 EFI_STATUS Status;
482 UINTN Size;
483
484 Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info);
485 if (EFI_ERROR (Status)) {
486 return Status;
487 }
488
489 /* We found a GOP */
490
491 /* EFI framebuffer */
492 Si->orig_video_isVGA = 0x70;
493
494 Si->orig_x = 0;
495 Si->orig_y = 0;
496 Si->orig_video_page = 0;
497 Si->orig_video_mode = 0;
498 Si->orig_video_cols = 0;
499 Si->orig_video_lines = 0;
500 Si->orig_video_ega_bx = 0;
501 Si->orig_video_points = 0;
502
503 Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
504 Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
505 Si->lfb_width = (UINT16) Info->HorizontalResolution;
506 Si->lfb_height = (UINT16) Info->VerticalResolution;
507 Si->pages = 1;
508 Si->vesapm_seg = 0;
509 Si->vesapm_off = 0;
510
511 if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
512 Si->lfb_depth = 32;
513 Si->red_size = 8;
514 Si->red_pos = 0;
515 Si->green_size = 8;
516 Si->green_pos = 8;
517 Si->blue_size = 8;
518 Si->blue_pos = 16;
519 Si->rsvd_size = 8;
520 Si->rsvd_pos = 24;
521 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
522
523 } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
524 Si->lfb_depth = 32;
525 Si->red_size = 8;
526 Si->red_pos = 16;
527 Si->green_size = 8;
528 Si->green_pos = 8;
529 Si->blue_size = 8;
530 Si->blue_pos = 0;
531 Si->rsvd_size = 8;
532 Si->rsvd_pos = 24;
533 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
534 } else if (Info->PixelFormat == PixelBitMask) {
535 FindBits(Info->PixelInformation.RedMask,
536 &Si->red_pos, &Si->red_size);
537 FindBits(Info->PixelInformation.GreenMask,
538 &Si->green_pos, &Si->green_size);
539 FindBits(Info->PixelInformation.BlueMask,
540 &Si->blue_pos, &Si->blue_size);
541 FindBits(Info->PixelInformation.ReservedMask,
542 &Si->rsvd_pos, &Si->rsvd_size);
543 Si->lfb_depth = Si->red_size + Si->green_size +
544 Si->blue_size + Si->rsvd_size;
545 Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
546 } else {
547 Si->lfb_depth = 4;
548 Si->red_size = 0;
549 Si->red_pos = 0;
550 Si->green_size = 0;
551 Si->green_pos = 0;
552 Si->blue_size = 0;
553 Si->blue_pos = 0;
554 Si->rsvd_size = 0;
555 Si->rsvd_pos = 0;
556 Si->lfb_linelength = Si->lfb_width / 2;
557 }
558
559 return Status;
560 }
561
562
563 STATIC
564 EFI_STATUS
SetupGraphics(IN OUT struct boot_params * Bp)565 SetupGraphics (
566 IN OUT struct boot_params *Bp
567 )
568 {
569 EFI_STATUS Status;
570 EFI_HANDLE *HandleBuffer;
571 UINTN HandleCount;
572 UINTN Index;
573 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
574
575 ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info));
576
577 Status = gBS->LocateHandleBuffer (
578 ByProtocol,
579 &gEfiGraphicsOutputProtocolGuid,
580 NULL,
581 &HandleCount,
582 &HandleBuffer
583 );
584 if (!EFI_ERROR (Status)) {
585 for (Index = 0; Index < HandleCount; Index++) {
586 Status = gBS->HandleProtocol (
587 HandleBuffer[Index],
588 &gEfiGraphicsOutputProtocolGuid,
589 (VOID*) &Gop
590 );
591 if (EFI_ERROR (Status)) {
592 continue;
593 }
594
595 Status = SetupGraphicsFromGop (&Bp->screen_info, Gop);
596 if (!EFI_ERROR (Status)) {
597 FreePool (HandleBuffer);
598 return EFI_SUCCESS;
599 }
600 }
601
602 FreePool (HandleBuffer);
603 }
604
605 return EFI_NOT_FOUND;
606 }
607
608
609 STATIC
610 EFI_STATUS
SetupLinuxBootParams(IN OUT struct boot_params * Bp)611 SetupLinuxBootParams (
612 IN OUT struct boot_params *Bp
613 )
614 {
615 SetupGraphics (Bp);
616
617 SetupLinuxMemmap (Bp);
618
619 return EFI_SUCCESS;
620 }
621
622
623 EFI_STATUS
624 EFIAPI
LoadLinux(IN VOID * Kernel,IN OUT VOID * KernelSetup)625 LoadLinux (
626 IN VOID *Kernel,
627 IN OUT VOID *KernelSetup
628 )
629 {
630 EFI_STATUS Status;
631 struct boot_params *Bp;
632
633 Status = BasicKernelSetupCheck (KernelSetup);
634 if (EFI_ERROR (Status)) {
635 return Status;
636 }
637
638 Bp = (struct boot_params *) KernelSetup;
639
640 if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) {
641 //
642 // We only support relocatable kernels
643 //
644 return EFI_UNSUPPORTED;
645 }
646
647 InitLinuxDescriptorTables ();
648
649 Bp->hdr.code32_start = (UINT32)(UINTN) Kernel;
650 if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset &&
651 (Bp->hdr.xloadflags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) {
652 DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset));
653
654 DisableInterrupts ();
655 JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel);
656 }
657
658 //
659 // Old kernels without EFI handover protocol
660 //
661 SetupLinuxBootParams (KernelSetup);
662
663 DEBUG ((EFI_D_INFO, "Jumping to kernel\n"));
664 DisableInterrupts ();
665 SetLinuxDescriptorTables ();
666 JumpToKernel (Kernel, (VOID*) KernelSetup);
667
668 return EFI_SUCCESS;
669 }
670
671