]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/LoadLinuxLib/Linux.c
4a3e2c13cb349eb9ce481bf419c7a61045ab6e9b
[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 Status = gBS->AllocatePool (
284 EfiLoaderData,
285 MemoryMapSize,
286 (VOID **) &MemoryMap
287 );
288 ASSERT_EFI_ERROR (Status);
289
290 //
291 // Get System MemoryMap
292 //
293 Status = gBS->GetMemoryMap (
294 &MemoryMapSize,
295 MemoryMap,
296 &MapKey,
297 &DescriptorSize,
298 &DescriptorVersion
299 );
300 ASSERT_EFI_ERROR (Status);
301
302 LastE820 = NULL;
303 E820 = &Bp->e820_map[0];
304 E820EntryCount = 0;
305 LastEndAddr = 0;
306 MemoryMapPtr = MemoryMap;
307 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
308 UINTN E820Type = 0;
309
310 if (MemoryMap->NumberOfPages == 0) {
311 continue;
312 }
313
314 switch(MemoryMap->Type) {
315 case EfiReservedMemoryType:
316 case EfiRuntimeServicesCode:
317 case EfiRuntimeServicesData:
318 case EfiMemoryMappedIO:
319 case EfiMemoryMappedIOPortSpace:
320 case EfiPalCode:
321 E820Type = E820_RESERVED;
322 break;
323
324 case EfiUnusableMemory:
325 E820Type = E820_UNUSABLE;
326 break;
327
328 case EfiACPIReclaimMemory:
329 E820Type = E820_ACPI;
330 break;
331
332 case EfiLoaderCode:
333 case EfiLoaderData:
334 case EfiBootServicesCode:
335 case EfiBootServicesData:
336 case EfiConventionalMemory:
337 E820Type = E820_RAM;
338 break;
339
340 case EfiACPIMemoryNVS:
341 E820Type = E820_NVS;
342 break;
343
344 default:
345 DEBUG ((
346 EFI_D_ERROR,
347 "Invalid EFI memory descriptor type (0x%x)!\n",
348 MemoryMap->Type
349 ));
350 continue;
351 }
352
353 if ((LastE820 != NULL) &&
354 (LastE820->type == (UINT32) E820Type) &&
355 (MemoryMap->PhysicalStart == LastEndAddr)) {
356 LastE820->size += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
357 LastEndAddr += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
358 } else {
359 if (E820EntryCount >= (sizeof (Bp->e820_map) / sizeof (Bp->e820_map[0]))) {
360 break;
361 }
362 E820->type = (UINT32) E820Type;
363 E820->addr = MemoryMap->PhysicalStart;
364 E820->size = EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
365 LastE820 = E820;
366 LastEndAddr = E820->addr + E820->size;
367 E820++;
368 E820EntryCount++;
369 }
370
371 //
372 // Get next item
373 //
374 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
375 }
376 Bp->e820_entries = (UINT8) E820EntryCount;
377
378 Efi = &Bp->efi_info;
379 Efi->efi_systab = (UINT32)(UINTN) gST;
380 Efi->efi_memdesc_size = (UINT32) DescriptorSize;
381 Efi->efi_memdesc_version = DescriptorVersion;
382 Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr;
383 Efi->efi_memmap_size = (UINT32) MemoryMapSize;
384 #ifdef MDE_CPU_IA32
385 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2');
386 #else
387 Efi->efi_systab_hi = ((UINT64)(UINTN) gST) >> 32;
388 Efi->efi_memmap_hi = ((UINT64)(UINTN) MemoryMapPtr) >> 32;
389 Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4');
390 #endif
391
392 gBS->ExitBootServices (gImageHandle, MapKey);
393 }
394
395
396 EFI_STATUS
397 EFIAPI
398 LoadLinuxSetCommandLine (
399 IN OUT VOID *KernelSetup,
400 IN CHAR8 *CommandLine
401 )
402 {
403 EFI_STATUS Status;
404 struct boot_params *Bp;
405
406 Status = BasicKernelSetupCheck (KernelSetup);
407 if (EFI_ERROR (Status)) {
408 return Status;
409 }
410
411 Bp = (struct boot_params*) KernelSetup;
412
413 Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine;
414
415 return EFI_SUCCESS;
416 }
417
418
419 EFI_STATUS
420 EFIAPI
421 LoadLinuxSetInitrd (
422 IN OUT VOID *KernelSetup,
423 IN VOID *Initrd,
424 IN UINTN InitrdSize
425 )
426 {
427 EFI_STATUS Status;
428 struct boot_params *Bp;
429
430 Status = BasicKernelSetupCheck (KernelSetup);
431 if (EFI_ERROR (Status)) {
432 return Status;
433 }
434
435 Bp = (struct boot_params*) KernelSetup;
436
437 Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd;
438 Bp->hdr.ramdisk_len = (UINT32) InitrdSize;
439
440 return EFI_SUCCESS;
441 }
442
443
444 STATIC VOID
445 FindBits (
446 unsigned long Mask,
447 UINT8 *Pos,
448 UINT8 *Size
449 )
450 {
451 UINT8 First, Len;
452
453 First = 0;
454 Len = 0;
455
456 if (Mask) {
457 while (!(Mask & 0x1)) {
458 Mask = Mask >> 1;
459 First++;
460 }
461
462 while (Mask & 0x1) {
463 Mask = Mask >> 1;
464 Len++;
465 }
466 }
467 *Pos = First;
468 *Size = Len;
469 }
470
471
472 STATIC
473 EFI_STATUS
474 SetupGraphicsFromGop (
475 struct screen_info *Si,
476 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
477 )
478 {
479 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
480 EFI_STATUS Status;
481 UINTN Size;
482
483 Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info);
484 if (EFI_ERROR (Status)) {
485 return Status;
486 }
487
488 /* We found a GOP */
489
490 /* EFI framebuffer */
491 Si->orig_video_isVGA = 0x70;
492
493 Si->orig_x = 0;
494 Si->orig_y = 0;
495 Si->orig_video_page = 0;
496 Si->orig_video_mode = 0;
497 Si->orig_video_cols = 0;
498 Si->orig_video_lines = 0;
499 Si->orig_video_ega_bx = 0;
500 Si->orig_video_points = 0;
501
502 Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
503 Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
504 Si->lfb_width = (UINT16) Info->HorizontalResolution;
505 Si->lfb_height = (UINT16) Info->VerticalResolution;
506 Si->pages = 1;
507 Si->vesapm_seg = 0;
508 Si->vesapm_off = 0;
509
510 if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
511 Si->lfb_depth = 32;
512 Si->red_size = 8;
513 Si->red_pos = 0;
514 Si->green_size = 8;
515 Si->green_pos = 8;
516 Si->blue_size = 8;
517 Si->blue_pos = 16;
518 Si->rsvd_size = 8;
519 Si->rsvd_pos = 24;
520 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
521
522 } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
523 Si->lfb_depth = 32;
524 Si->red_size = 8;
525 Si->red_pos = 16;
526 Si->green_size = 8;
527 Si->green_pos = 8;
528 Si->blue_size = 8;
529 Si->blue_pos = 0;
530 Si->rsvd_size = 8;
531 Si->rsvd_pos = 24;
532 Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
533 } else if (Info->PixelFormat == PixelBitMask) {
534 FindBits(Info->PixelInformation.RedMask,
535 &Si->red_pos, &Si->red_size);
536 FindBits(Info->PixelInformation.GreenMask,
537 &Si->green_pos, &Si->green_size);
538 FindBits(Info->PixelInformation.BlueMask,
539 &Si->blue_pos, &Si->blue_size);
540 FindBits(Info->PixelInformation.ReservedMask,
541 &Si->rsvd_pos, &Si->rsvd_size);
542 Si->lfb_depth = Si->red_size + Si->green_size +
543 Si->blue_size + Si->rsvd_size;
544 Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
545 } else {
546 Si->lfb_depth = 4;
547 Si->red_size = 0;
548 Si->red_pos = 0;
549 Si->green_size = 0;
550 Si->green_pos = 0;
551 Si->blue_size = 0;
552 Si->blue_pos = 0;
553 Si->rsvd_size = 0;
554 Si->rsvd_pos = 0;
555 Si->lfb_linelength = Si->lfb_width / 2;
556 }
557
558 return Status;
559 }
560
561
562 STATIC
563 EFI_STATUS
564 SetupGraphics (
565 IN OUT struct boot_params *Bp
566 )
567 {
568 EFI_STATUS Status;
569 EFI_HANDLE *HandleBuffer;
570 UINTN HandleCount;
571 UINTN Index;
572 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
573
574 ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info));
575
576 Status = gBS->LocateHandleBuffer (
577 ByProtocol,
578 &gEfiGraphicsOutputProtocolGuid,
579 NULL,
580 &HandleCount,
581 &HandleBuffer
582 );
583 if (!EFI_ERROR (Status)) {
584 for (Index = 0; Index < HandleCount; Index++) {
585 Status = gBS->HandleProtocol (
586 HandleBuffer[Index],
587 &gEfiGraphicsOutputProtocolGuid,
588 (VOID*) &Gop
589 );
590 if (EFI_ERROR (Status)) {
591 continue;
592 }
593
594 Status = SetupGraphicsFromGop (&Bp->screen_info, Gop);
595 if (!EFI_ERROR (Status)) {
596 FreePool (HandleBuffer);
597 return EFI_SUCCESS;
598 }
599 }
600
601 FreePool (HandleBuffer);
602 }
603
604 return EFI_NOT_FOUND;
605 }
606
607
608 STATIC
609 EFI_STATUS
610 SetupLinuxBootParams (
611 IN OUT struct boot_params *Bp
612 )
613 {
614 SetupGraphics (Bp);
615
616 SetupLinuxMemmap (Bp);
617
618 return EFI_SUCCESS;
619 }
620
621
622 EFI_STATUS
623 EFIAPI
624 LoadLinux (
625 IN VOID *Kernel,
626 IN OUT VOID *KernelSetup
627 )
628 {
629 EFI_STATUS Status;
630 struct boot_params *Bp;
631
632 Status = BasicKernelSetupCheck (KernelSetup);
633 if (EFI_ERROR (Status)) {
634 return Status;
635 }
636
637 Bp = (struct boot_params *) KernelSetup;
638
639 if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) {
640 //
641 // We only support relocatable kernels
642 //
643 return EFI_UNSUPPORTED;
644 }
645
646 InitLinuxDescriptorTables ();
647
648 Bp->hdr.code32_start = (UINT32)(UINTN) Kernel;
649 if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset &&
650 (Bp->hdr.load_flags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) {
651 DEBUG ((EFI_D_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset));
652
653 DisableInterrupts ();
654 JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel);
655 }
656
657 //
658 // Old kernels without EFI handover protocol
659 //
660 SetupLinuxBootParams (KernelSetup);
661
662 DEBUG ((EFI_D_INFO, "Jumping to kernel\n"));
663 DisableInterrupts ();
664 SetLinuxDescriptorTables ();
665 JumpToKernel (Kernel, (VOID*) KernelSetup);
666
667 return EFI_SUCCESS;
668 }
669