1 /** @file
2 
3   Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4   This program and the accompanying materials
5   are licensed and made available under the terms and conditions of the BSD License
6   which accompanies this distribution.  The full text of the license may be found at
7   http://opensource.org/licenses/bsd-license.php
8 
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include <Uefi.h>
15 
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/LoadLinuxLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/QemuFwCfgLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 
23 
24 EFI_STATUS
TryRunningQemuKernel(VOID)25 TryRunningQemuKernel (
26   VOID
27   )
28 {
29   EFI_STATUS                Status;
30   UINTN                     KernelSize;
31   UINTN                     KernelInitialSize;
32   VOID                      *KernelBuf;
33   UINTN                     SetupSize;
34   VOID                      *SetupBuf;
35   UINTN                     CommandLineSize;
36   CHAR8                     *CommandLine;
37   UINTN                     InitrdSize;
38   VOID*                     InitrdData;
39 
40   SetupBuf = NULL;
41   SetupSize = 0;
42   KernelBuf = NULL;
43   KernelInitialSize = 0;
44   CommandLine = NULL;
45   CommandLineSize = 0;
46   InitrdData = NULL;
47   InitrdSize = 0;
48 
49   if (!QemuFwCfgIsAvailable ()) {
50     return EFI_NOT_FOUND;
51   }
52 
53   QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
54   KernelSize = (UINTN) QemuFwCfgRead64 ();
55 
56   QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
57   SetupSize = (UINTN) QemuFwCfgRead64 ();
58 
59   if (KernelSize == 0 || SetupSize == 0) {
60     DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n"));
61     return EFI_NOT_FOUND;
62   }
63 
64   SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES (SetupSize));
65   if (SetupBuf == NULL) {
66     DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n"));
67     return EFI_OUT_OF_RESOURCES;
68   }
69 
70   DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize));
71   DEBUG ((EFI_D_INFO, "Reading kernel setup image ..."));
72   QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
73   QemuFwCfgReadBytes (SetupSize, SetupBuf);
74   DEBUG ((EFI_D_INFO, " [done]\n"));
75 
76   Status = LoadLinuxCheckKernelSetup (SetupBuf, SetupSize);
77   if (EFI_ERROR (Status)) {
78     goto FreeAndReturn;
79   }
80 
81   Status = LoadLinuxInitializeKernelSetup (SetupBuf);
82   if (EFI_ERROR (Status)) {
83     goto FreeAndReturn;
84   }
85 
86   KernelInitialSize = LoadLinuxGetKernelSize (SetupBuf, KernelSize);
87   if (KernelInitialSize == 0) {
88     Status = EFI_UNSUPPORTED;
89     goto FreeAndReturn;
90   }
91 
92   KernelBuf = LoadLinuxAllocateKernelPages (
93                 SetupBuf,
94                 EFI_SIZE_TO_PAGES (KernelInitialSize));
95   if (KernelBuf == NULL) {
96     DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel!\n"));
97     Status = EFI_OUT_OF_RESOURCES;
98     goto FreeAndReturn;
99   }
100 
101   DEBUG ((EFI_D_INFO, "Kernel size: 0x%x\n", (UINT32) KernelSize));
102   DEBUG ((EFI_D_INFO, "Reading kernel image ..."));
103   QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
104   QemuFwCfgReadBytes (KernelSize, KernelBuf);
105   DEBUG ((EFI_D_INFO, " [done]\n"));
106 
107   QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
108   CommandLineSize = (UINTN) QemuFwCfgRead64 ();
109 
110   if (CommandLineSize > 0) {
111     CommandLine = LoadLinuxAllocateCommandLinePages (
112                     EFI_SIZE_TO_PAGES (CommandLineSize));
113     QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
114     QemuFwCfgReadBytes (CommandLineSize, CommandLine);
115   } else {
116     CommandLine = NULL;
117   }
118 
119   Status = LoadLinuxSetCommandLine (SetupBuf, CommandLine);
120   if (EFI_ERROR (Status)) {
121     goto FreeAndReturn;
122   }
123 
124   QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
125   InitrdSize = (UINTN) QemuFwCfgRead64 ();
126 
127   if (InitrdSize > 0) {
128     InitrdData = LoadLinuxAllocateInitrdPages (
129                    SetupBuf,
130                    EFI_SIZE_TO_PAGES (InitrdSize)
131                    );
132     DEBUG ((EFI_D_INFO, "Initrd size: 0x%x\n", (UINT32) InitrdSize));
133     DEBUG ((EFI_D_INFO, "Reading initrd image ..."));
134     QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);
135     QemuFwCfgReadBytes (InitrdSize, InitrdData);
136     DEBUG ((EFI_D_INFO, " [done]\n"));
137   } else {
138     InitrdData = NULL;
139   }
140 
141   Status = LoadLinuxSetInitrd (SetupBuf, InitrdData, InitrdSize);
142   if (EFI_ERROR (Status)) {
143     goto FreeAndReturn;
144   }
145 
146   Status = LoadLinux (KernelBuf, SetupBuf);
147 
148 FreeAndReturn:
149   if (SetupBuf != NULL) {
150     FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize));
151   }
152   if (KernelBuf != NULL) {
153     FreePages (KernelBuf, EFI_SIZE_TO_PAGES (KernelInitialSize));
154   }
155   if (CommandLine != NULL) {
156     FreePages (CommandLine, EFI_SIZE_TO_PAGES (CommandLineSize));
157   }
158   if (InitrdData != NULL) {
159     FreePages (InitrdData, EFI_SIZE_TO_PAGES (InitrdSize));
160   }
161 
162   return Status;
163 }
164 
165