]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/LoadLinuxLib/Linux.c
c714225e55bfff6173e35330523bd7fa5453c4d5
[mirror_edk2.git] / OvmfPkg / Library / LoadLinuxLib / Linux.c
1 /** @file
2
3 Copyright (c) 2011 - 2013, 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
34 BasicKernelSetupCheck (
35 IN VOID *KernelSetup
36 )
37 {
38 return LoadLinuxCheckKernelSetup(KernelSetup, sizeof (struct boot_params));
39 }
40
41
42 EFI_STATUS
43 EFIAPI
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
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
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
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%x-0x1000\n", SetupEnd));
147
148 return EFI_SUCCESS;
149 }
150
151 VOID*
152 EFIAPI
153 LoadLinuxAllocateKernelPages (
154 IN VOID *KernelSetup,
155 IN UINTN Pages
156 )
157 {
158 EFI_STATUS Status;
159 EFI_PHYSICAL_ADDRESS KernelAddress;
160 UINT32 Loop;
161 struct boot_params *Bp;
162
163 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
164 return NULL;
165 }
166
167 Bp = (struct boot_params*) KernelSetup;
168
169 for (Loop = 1; Loop < 512; Loop++) {
170 KernelAddress = MultU64x32 (
171 2 * Bp->hdr.kernel_alignment,
172 Loop
173 );
174 Status = gBS->AllocatePages (
175 AllocateAddress,
176 EfiLoaderData,
177 Pages,
178 &KernelAddress
179 );
180 if (!EFI_ERROR (Status)) {
181 return (VOID*)(UINTN) KernelAddress;
182 }
183 }
184
185 return NULL;
186 }
187
188
189 VOID*
190 EFIAPI
191 LoadLinuxAllocateCommandLinePages (
192 IN UINTN Pages
193 )
194 {
195 EFI_STATUS Status;
196 EFI_PHYSICAL_ADDRESS Address;
197
198 Address = 0xa0000;
199 Status = gBS->AllocatePages (
200 AllocateMaxAddress,
201 EfiLoaderData,
202 Pages,
203 &Address
204 );
205 if (!EFI_ERROR (Status)) {
206 return (VOID*)(UINTN) Address;
207 } else {
208 return NULL;
209 }
210 }
211
212
213 VOID*
214 EFIAPI
215 LoadLinuxAllocateInitrdPages (
216 IN VOID *KernelSetup,
217 IN UINTN Pages
218 )
219 {
220 EFI_STATUS Status;
221 EFI_PHYSICAL_ADDRESS Address;
222
223 struct boot_params *Bp;
224
225 if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
226 return NULL;
227 }
228
229 Bp = (struct boot_params*) KernelSetup;
230
231 Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Bp->hdr.ramdisk_max;
232 Status = gBS->AllocatePages (
233 AllocateMaxAddress,
234 EfiLoaderData,
235 Pages,
236 &Address
237 );
238 if (!EFI_ERROR (Status)) {
239 return (VOID*)(UINTN) Address;
240 } else {
241 return NULL;
242 }
243 }
244
245
246 STATIC
247 VOID
248 SetupLinuxMemmap (
249 IN OUT struct boot_params *Bp
250 )
251 {
252 EFI_STATUS Status;
253 UINT8 TmpMemoryMap[1];
254 UINTN MapKey;
255 UINTN DescriptorSize;
256 UINT32 DescriptorVersion;
257 UINTN MemoryMapSize;
258 EFI_MEMORY_DESCRIPTOR *MemoryMap;
259 EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;
260 UINTN Index;
261 struct efi_info *Efi;
262 struct e820_entry *LastE820;
263 struct e820_entry *E820;
264 UINTN E820EntryCount;
265 EFI_PHYSICAL_ADDRESS LastEndAddr;
266
267 //
268 // Get System MemoryMapSize
269 //
270 MemoryMapSize = sizeof (TmpMemoryMap);
271 Status = gBS->GetMemoryMap (
272 &MemoryMapSize,
273 (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
274 &MapKey,
275 &DescriptorSize,
276 &DescriptorVersion
277 );
278 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
279 //
280 // Enlarge space here, because we will allocate pool now.
281 //
282 MemoryMapSize += EFI_PAGE_SIZE;
283 MemoryMap = AllocatePool (MemoryMapSize);
284 ASSERT (MemoryMap != NULL);
285
286 //
287 // Get System MemoryMap
288 //
289 Status = gBS->GetMemoryMap (
290 &MemoryMapSize,
291 MemoryMap,
292 &MapKey,
293 &DescriptorSize,
294 &DescriptorVersion
295 );
296 ASSERT_EFI_ERROR (Status);
297
298 LastE820 = NULL;
299 E820 = &Bp->e820_map[0];
300 E820EntryCount = 0;
301 LastEndAddr = 0;
302 MemoryMapPtr = MemoryMap;
303 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
304 UINTN E820Type = 0;
305
306 if (MemoryMap->NumberOfPages == 0) {
307 continue;
308 }
309
310 switch(MemoryMap->Type) {
311 case EfiReservedMemoryType:
312 case EfiRuntimeServicesCode:
313 case EfiRuntimeServicesData:
314 case EfiMemoryMappedIO:
315 case EfiMemoryMappedIOPortSpace:
316 case EfiPalCode:
317 E820Type = E820_RESERVED;
318 break;
319
320 case EfiUnusableMemory:
321 E820Type = E820_UNUSABLE;
322 break;
323
324 case EfiACPIReclaimMemory:
325 E820Type = E820_ACPI;
326 break;
327
328 case EfiLoaderCode:
329 case EfiLoaderData:
330 case EfiBootServicesCode:
331 case EfiBootServicesData:
332 case EfiConventionalMemory:
333 E820Type = E820_RAM;
334 break;
335
336 case EfiACPIMemoryNVS:
337 E820Type = E820_NVS;
338 break;
339
340 default:
341 DEBUG ((
342 EFI_D_ERROR,
343 "Invalid EFI memory descriptor type (0x%x)!\n",
344 MemoryMap->Type
345 ));
346 continue;
347 }
348
349 if ((LastE820 != NULL) &&
350 (LastE820->type == (UINT32) E820Type) &&
351 (MemoryMap->PhysicalStart == LastEndAddr)) {
352 LastE820->size += EFI_PAGES_TO_SIZE (MemoryMap->NumberOfPages);
353 LastEndAddr += EFI_PAGES_TO_SIZE (MemoryMap->NumberOfPages);
354 } else {
355 if (E820EntryCount >= (sizeof (Bp->e820_map) / sizeof (Bp->e820_map[0]))) {
356 break;
357 }
358 E820->type = (UINT32) E820Type;
359 E820->addr = MemoryMap->PhysicalStart;
360 E820->size = EFI_PAGES_TO_SIZE (MemoryMap->NumberOfPages);
361 LastE820 = E820;
362 LastEndAddr = E820->addr + E820->size;
363 E820++;
364 E820EntryCount++;
365 }
366
367 //
368 // Get next item
369 //
370 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
371 }
372 Bp->e820_entries = (UINT8) E820EntryCount;
373
374 Efi = &Bp->efi_info;
375 Efi->efi_systab = (UINT32)(UINTN) gST;
376 Efi->efi_memdesc_size = (UINT32) DescriptorSize;
377 Efi->efi_memdesc_version = DescriptorVersion;
378 Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr;
379 Efi->efi_memmap_size = (UINT32) MemoryMapSize;
380 #ifdef MDE_CPU_IA32
381 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2');
382 #else
383 Efi->efi_systab_hi = ((UINT64)(UINTN) gST) >> 32;
384 Efi->efi_memmap_hi = ((UINT64)(UINTN) MemoryMapPtr) >> 32;
385 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4');
386 #endif
387
388 gBS->ExitBootServices (gImageHandle, MapKey);
389 }
390
391
392 EFI_STATUS
393 EFIAPI
394 LoadLinuxSetCommandLine (
395 IN OUT VOID *KernelSetup,
396 IN CHAR8 *CommandLine
397 )
398 {
399 EFI_STATUS Status;
400 struct boot_params *Bp;
401
402 Status = BasicKernelSetupCheck (KernelSetup);
403 if (EFI_ERROR (Status)) {
404 return Status;
405 }
406
407 Bp = (struct boot_params*) KernelSetup;
408
409 Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine;
410
411 return EFI_SUCCESS;
412 }
413
414
415 EFI_STATUS
416 EFIAPI
417 LoadLinuxSetInitrd (
418 IN OUT VOID *KernelSetup,
419 IN VOID *Initrd,
420 IN UINTN InitrdSize
421 )
422 {
423 EFI_STATUS Status;
424 struct boot_params *Bp;
425
426 Status = BasicKernelSetupCheck (KernelSetup);
427 if (EFI_ERROR (Status)) {
428 return Status;
429 }
430
431 Bp = (struct boot_params*) KernelSetup;
432
433 Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd;
434 Bp->hdr.ramdisk_len = (UINT32) InitrdSize;
435
436 return EFI_SUCCESS;
437 }
438
439
440 STATIC VOID
441 FindBits (
442 unsigned long Mask,
443 UINT8 *Pos,
444 UINT8 *Size
445 )
446 {
447 UINT8 First, Len;
448
449 First = 0;
450 Len = 0;
451
452 if (Mask) {
453 while (!(Mask & 0x1)) {
454 Mask = Mask >> 1;
455 First++;
456 }
457
458 while (Mask & 0x1) {
459 Mask = Mask >> 1;
460 Len++;
461 }
462 }
463 *Pos = First;
464 *Size = Len;
465 }
466
467
468 STATIC
469 EFI_STATUS
470 SetupGraphicsFromGop (
471 struct screen_info *Si,
472 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
473 )
474 {
475 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
476 EFI_STATUS Status;
477 UINTN Size;
478
479 Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info);
480 if (EFI_ERROR (Status)) {
481 return Status;
482 }
483
484 /* We found a GOP */
485
486 /* EFI framebuffer */
487 Si->orig_video_isVGA = 0x70;
488
489 Si->orig_x = 0;
490 Si->orig_y = 0;
491 Si->orig_video_page = 0;
492 Si->orig_video_mode = 0;
493 Si->orig_video_cols = 0;
494 Si->orig_video_lines = 0;
495 Si->orig_video_ega_bx = 0;
496 Si->orig_video_points = 0;
497
498 Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
499 Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
500 Si->lfb_width = (UINT16) Info->HorizontalResolution;
501 Si->lfb_height = (UINT16) Info->VerticalResolution;
502 Si->pages = 1;
503 Si->vesapm_seg = 0;
504 Si->vesapm_off = 0;
505
506 if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
507 Si->lfb_depth = 32;
508 Si->red_size = 8;
509 Si->red_pos = 0;
510 Si->green_size = 8;
511 Si->green_pos = 8;
512 Si->blue_size = 8;
513 Si->blue_pos = 16;
514 Si->rsvd_size = 8;
515 Si->rsvd_pos = 24;
516 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
517
518 } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
519 Si->lfb_depth = 32;
520 Si->red_size = 8;
521 Si->red_pos = 16;
522 Si->green_size = 8;
523 Si->green_pos = 8;
524 Si->blue_size = 8;
525 Si->blue_pos = 0;
526 Si->rsvd_size = 8;
527 Si->rsvd_pos = 24;
528 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
529 } else if (Info->PixelFormat == PixelBitMask) {
530 FindBits(Info->PixelInformation.RedMask,
531 &Si->red_pos, &Si->red_size);
532 FindBits(Info->PixelInformation.GreenMask,
533 &Si->green_pos, &Si->green_size);
534 FindBits(Info->PixelInformation.BlueMask,
535 &Si->blue_pos, &Si->blue_size);
536 FindBits(Info->PixelInformation.ReservedMask,
537 &Si->rsvd_pos, &Si->rsvd_size);
538 Si->lfb_depth = Si->red_size + Si->green_size +
539 Si->blue_size + Si->rsvd_size;
540 Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
541 } else {
542 Si->lfb_depth = 4;
543 Si->red_size = 0;
544 Si->red_pos = 0;
545 Si->green_size = 0;
546 Si->green_pos = 0;
547 Si->blue_size = 0;
548 Si->blue_pos = 0;
549 Si->rsvd_size = 0;
550 Si->rsvd_pos = 0;
551 Si->lfb_linelength = Si->lfb_width / 2;
552 }
553
554 return Status;
555 }
556
557
558 STATIC
559 EFI_STATUS
560 SetupGraphics (
561 IN OUT struct boot_params *Bp
562 )
563 {
564 EFI_STATUS Status;
565 EFI_HANDLE *HandleBuffer;
566 UINTN HandleCount;
567 UINTN Index;
568 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
569
570 ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info));
571
572 Status = gBS->LocateHandleBuffer (
573 ByProtocol,
574 &gEfiGraphicsOutputProtocolGuid,
575 NULL,
576 &HandleCount,
577 &HandleBuffer
578 );
579 if (!EFI_ERROR (Status)) {
580 for (Index = 0; Index < HandleCount; Index++) {
581 Status = gBS->HandleProtocol (
582 HandleBuffer[Index],
583 &gEfiGraphicsOutputProtocolGuid,
584 (VOID*) &Gop
585 );
586 if (EFI_ERROR (Status)) {
587 continue;
588 }
589
590 Status = SetupGraphicsFromGop (&Bp->screen_info, Gop);
591 if (!EFI_ERROR (Status)) {
592 FreePool (HandleBuffer);
593 return EFI_SUCCESS;
594 }
595 }
596
597 FreePool (HandleBuffer);
598 }
599
600 return EFI_NOT_FOUND;
601 }
602
603
604 STATIC
605 EFI_STATUS
606 SetupLinuxBootParams (
607 IN OUT struct boot_params *Bp
608 )
609 {
610 SetupGraphics (Bp);
611
612 SetupLinuxMemmap (Bp);
613
614 return EFI_SUCCESS;
615 }
616
617
618 EFI_STATUS
619 EFIAPI
620 LoadLinux (
621 IN VOID *Kernel,
622 IN OUT VOID *KernelSetup
623 )
624 {
625 EFI_STATUS Status;
626 struct boot_params *Bp;
627
628 Status = BasicKernelSetupCheck (KernelSetup);
629 if (EFI_ERROR (Status)) {
630 return Status;
631 }
632
633 Bp = (struct boot_params *) KernelSetup;
634
635 if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) {
636 //
637 // We only support relocatable kernels
638 //
639 return EFI_UNSUPPORTED;
640 }
641
642 InitLinuxDescriptorTables ();
643
644 Bp->hdr.code32_start = (UINT32)(UINTN) Kernel;
645 if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset &&
646 (Bp->hdr.load_flags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) {
647 DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset));
648
649 DisableInterrupts ();
650 JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel);
651 }
652
653 //
654 // Old kernels without EFI handover protocol
655 //
656 SetupLinuxBootParams (KernelSetup);
657
658 DEBUG ((EFI_D_INFO, "Jumping to kernel\n"));
659 DisableInterrupts ();
660 SetLinuxDescriptorTables ();
661 JumpToKernel (Kernel, (VOID*) KernelSetup);
662
663 return EFI_SUCCESS;
664 }
665