|
@@ -25,7 +25,7 @@
|
25
|
25
|
|
26
|
26
|
#include <errno.h>
|
27
|
27
|
#include <assert.h>
|
28
|
|
-#include <alloca.h>
|
|
28
|
+#include <realmode.h>
|
29
|
29
|
#include <multiboot.h>
|
30
|
30
|
#include <gpxe/uaccess.h>
|
31
|
31
|
#include <gpxe/image.h>
|
|
@@ -35,6 +35,18 @@
|
35
|
35
|
|
36
|
36
|
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
|
37
|
37
|
|
|
38
|
+/**
|
|
39
|
+ * Maximum number of modules we will allow for
|
|
40
|
+ *
|
|
41
|
+ * If this has bitten you: sorry. I did have a perfect scheme with a
|
|
42
|
+ * dynamically allocated list of modules on the protected-mode stack,
|
|
43
|
+ * but it was incompatible with some broken OSes that can only access
|
|
44
|
+ * low memory at boot time (even though we kindly set up 4GB flat
|
|
45
|
+ * physical addressing as per the multiboot specification.
|
|
46
|
+ *
|
|
47
|
+ */
|
|
48
|
+#define MAX_MODULES 8
|
|
49
|
+
|
38
|
50
|
/** Multiboot flags that we support */
|
39
|
51
|
#define MB_SUPPORTED_FLAGS ( MB_FLAG_PGALIGN | MB_FLAG_MEMMAP | \
|
40
|
52
|
MB_FLAG_VIDMODE | MB_FLAG_RAW )
|
|
@@ -66,9 +78,11 @@ struct multiboot_header_info {
|
66
|
78
|
*
|
67
|
79
|
* @v mbinfo Multiboot information structure
|
68
|
80
|
* @v mbmemmap Multiboot memory map
|
|
81
|
+ * @v limit Maxmimum number of memory map entries
|
69
|
82
|
*/
|
70
|
83
|
static void multiboot_build_memmap ( struct multiboot_info *mbinfo,
|
71
|
|
- struct multiboot_memory_map *mbmemmap ) {
|
|
84
|
+ struct multiboot_memory_map *mbmemmap,
|
|
85
|
+ unsigned int limit ) {
|
72
|
86
|
struct memory_map memmap;
|
73
|
87
|
unsigned int i;
|
74
|
88
|
|
|
@@ -78,6 +92,11 @@ static void multiboot_build_memmap ( struct multiboot_info *mbinfo,
|
78
|
92
|
/* Translate into multiboot format */
|
79
|
93
|
memset ( mbmemmap, 0, sizeof ( *mbmemmap ) );
|
80
|
94
|
for ( i = 0 ; i < memmap.count ; i++ ) {
|
|
95
|
+ if ( i >= limit ) {
|
|
96
|
+ DBG ( "Multiboot limit of %d memmap entries reached\n",
|
|
97
|
+ limit );
|
|
98
|
+ break;
|
|
99
|
+ }
|
81
|
100
|
mbmemmap[i].size = ( sizeof ( mbmemmap[i] ) -
|
82
|
101
|
sizeof ( mbmemmap[i].size ) );
|
83
|
102
|
mbmemmap[i].base_addr = memmap.regions[i].start;
|
|
@@ -102,7 +121,8 @@ static void multiboot_build_memmap ( struct multiboot_info *mbinfo,
|
102
|
121
|
*/
|
103
|
122
|
static unsigned int
|
104
|
123
|
multiboot_build_module_list ( struct image *image,
|
105
|
|
- struct multiboot_module *modules ) {
|
|
124
|
+ struct multiboot_module *modules,
|
|
125
|
+ unsigned int limit ) {
|
106
|
126
|
struct image *module_image;
|
107
|
127
|
struct multiboot_module *module;
|
108
|
128
|
unsigned int count = 0;
|
|
@@ -114,6 +134,12 @@ multiboot_build_module_list ( struct image *image,
|
114
|
134
|
/* Add each image as a multiboot module */
|
115
|
135
|
for_each_image ( module_image ) {
|
116
|
136
|
|
|
137
|
+ if ( count >= limit ) {
|
|
138
|
+ DBG ( "Multiboot limit of %d modules reached\n",
|
|
139
|
+ limit );
|
|
140
|
+ break;
|
|
141
|
+ }
|
|
142
|
+
|
117
|
143
|
/* Do not include kernel image itself as a module */
|
118
|
144
|
if ( module_image == image )
|
119
|
145
|
continue;
|
|
@@ -158,6 +184,29 @@ multiboot_build_module_list ( struct image *image,
|
158
|
184
|
return count;
|
159
|
185
|
}
|
160
|
186
|
|
|
187
|
+/**
|
|
188
|
+ * The multiboot information structure
|
|
189
|
+ *
|
|
190
|
+ * Kept in base memory because some OSes won't find it elsewhere,
|
|
191
|
+ * along with the other structures belonging to the Multiboot
|
|
192
|
+ * information table.
|
|
193
|
+ */
|
|
194
|
+static struct multiboot_info __data16 ( mbinfo );
|
|
195
|
+#define mbinfo __use_data16 ( mbinfo )
|
|
196
|
+
|
|
197
|
+/** The multiboot bootloader name */
|
|
198
|
+static const char * __data16 ( mb_bootloader_name ) = "gPXE " VERSION;
|
|
199
|
+#define mb_bootloader_name __use_data16 ( mb_bootloader_name )
|
|
200
|
+
|
|
201
|
+/** The multiboot memory map */
|
|
202
|
+static struct multiboot_memory_map
|
|
203
|
+ __data16_array ( mbmemmap, [MAX_MEMORY_REGIONS] );
|
|
204
|
+#define mbmemmap __use_data16 ( mbmemmap )
|
|
205
|
+
|
|
206
|
+/** The multiboot module list */
|
|
207
|
+static struct multiboot_module __data16_array ( mbmodules, [MAX_MODULES] );
|
|
208
|
+#define mbmodules __use_data16 ( mbmodules )
|
|
209
|
+
|
161
|
210
|
/**
|
162
|
211
|
* Execute multiboot image
|
163
|
212
|
*
|
|
@@ -165,45 +214,26 @@ multiboot_build_module_list ( struct image *image,
|
165
|
214
|
* @ret rc Return status code
|
166
|
215
|
*/
|
167
|
216
|
static int multiboot_exec ( struct image *image ) {
|
168
|
|
- static const char *bootloader_name = "gPXE " VERSION;
|
169
|
|
- struct multiboot_info mbinfo;
|
170
|
|
- struct multiboot_memory_map mbmemmap[MAX_MEMORY_REGIONS];
|
171
|
|
- struct multiboot_module *modules;
|
172
|
|
- unsigned int num_modules;
|
173
|
217
|
|
174
|
218
|
/* Populate multiboot information structure */
|
175
|
219
|
memset ( &mbinfo, 0, sizeof ( mbinfo ) );
|
176
|
|
-
|
177
|
|
- /* Set boot loader name */
|
178
|
|
- mbinfo.boot_loader_name = virt_to_phys ( bootloader_name );
|
179
|
|
- mbinfo.flags |= MBI_FLAG_LOADER;
|
180
|
|
-
|
181
|
|
- /* Build memory map */
|
182
|
|
- multiboot_build_memmap ( &mbinfo, mbmemmap );
|
183
|
|
- mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
|
184
|
|
- mbinfo.flags |= ( MBI_FLAG_MEM | MBI_FLAG_MMAP );
|
185
|
|
-
|
186
|
|
- /* Set command line */
|
|
220
|
+ mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
|
|
221
|
+ MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
|
|
222
|
+ multiboot_build_memmap ( &mbinfo, mbmemmap,
|
|
223
|
+ ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
|
187
|
224
|
mbinfo.cmdline = virt_to_phys ( image->cmdline );
|
188
|
|
- mbinfo.flags |= MBI_FLAG_CMDLINE;
|
189
|
|
-
|
190
|
|
- /* Construct module list */
|
191
|
|
- num_modules = multiboot_build_module_list ( image, NULL );
|
192
|
|
- modules = alloca ( num_modules * sizeof ( *modules ) );
|
193
|
|
- multiboot_build_module_list ( image, modules );
|
194
|
|
- mbinfo.mods_count = num_modules;
|
195
|
|
- mbinfo.mods_addr = virt_to_phys ( modules );
|
196
|
|
- mbinfo.flags |= MBI_FLAG_MODS;
|
197
|
|
-
|
|
225
|
+ mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
|
|
226
|
+ ( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
|
|
227
|
+ mbinfo.mods_addr = virt_to_phys ( mbmodules );
|
|
228
|
+ mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
|
|
229
|
+ mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
|
|
230
|
+
|
198
|
231
|
/* Jump to OS with flat physical addressing */
|
199
|
|
- __asm__ __volatile__ ( PHYS_CODE ( /* Preserve %ebp for alloca() */
|
200
|
|
- "pushl %%ebp\n\t"
|
201
|
|
- "call *%%edi\n\t"
|
202
|
|
- "popl %%ebp\n\t" )
|
|
232
|
+ __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
|
203
|
233
|
: : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
|
204
|
234
|
"b" ( virt_to_phys ( &mbinfo ) ),
|
205
|
235
|
"D" ( image->entry )
|
206
|
|
- : "ecx", "edx", "esi", "memory" );
|
|
236
|
+ : "ecx", "edx", "esi", "ebp", "memory" );
|
207
|
237
|
|
208
|
238
|
return -ECANCELED;
|
209
|
239
|
}
|