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