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