50
50
static struct grub_multiboot_info *mbi;
51
51
static grub_addr_t entry;
53
static char *playground = NULL;
55
static grub_uint8_t forward_relocator[] =
58
0x89, 0xf2, /* movl %esi, %edx */
59
0xf3, 0xa4, /* rep movsb */
60
0x01, 0xc2, /* addl %eax, %edx */
61
0xb8, 0x02, 0xb0, 0xad, 0x2b, /* movl $MULTIBOOT_MAGIC2, %eax */
62
0xff, 0xe2, /* jmp *%edx */
65
static grub_uint8_t backward_relocator[] =
68
0x01, 0xce, /* addl %ecx, %esi */
69
0x01, 0xcf, /* addl %ecx, %edi */
70
/* backward movsb is implicitly off-by-one. compensate that. */
72
0xf3, 0xa4, /* rep movsb */
73
/* same problem again. */
75
0x01, 0xc7, /* addl %eax, %edi */
76
0xb8, 0x02, 0xb0, 0xad, 0x2b, /* movl $MULTIBOOT_MAGIC2, %eax */
77
0xff, 0xe7, /* jmp *%edi */
54
81
grub_multiboot_boot (void)
114
142
if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
115
143
return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
117
entry = ehdr->e_entry;
145
phdr_base = (char *) buffer + ehdr->e_phoff;
146
#define phdr(i) ((Elf32_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
148
for (i = 0; i < ehdr->e_phnum; i++)
149
if (phdr(i)->p_type == PT_LOAD)
151
if (phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr)
153
if (phdr(i)->p_paddr > phdr(highest_segment)->p_paddr)
156
grub_multiboot_payload_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr;
157
grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr;
160
grub_free (playground);
161
playground = grub_malloc (sizeof (forward_relocator) + grub_multiboot_payload_size + sizeof (backward_relocator));
165
grub_multiboot_payload_orig = playground + sizeof (forward_relocator);
167
grub_memmove (playground, forward_relocator, sizeof (forward_relocator));
168
grub_memmove (grub_multiboot_payload_orig + grub_multiboot_payload_size, backward_relocator, sizeof (backward_relocator));
119
170
/* Load every loadable segment in memory. */
120
171
for (i = 0; i < ehdr->e_phnum; i++)
122
phdr = (Elf32_Phdr *) ((char *) buffer + ehdr->e_phoff
123
+ i * ehdr->e_phentsize);
124
if (phdr->p_type == PT_LOAD)
173
if (phdr(i)->p_type == PT_LOAD)
126
/* The segment should fit in the area reserved for the OS. */
127
if (phdr->p_paddr < grub_os_area_addr)
128
return grub_error (GRUB_ERR_BAD_OS,
129
"segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)",
130
phdr->p_paddr, grub_os_area_addr);
131
if (phdr->p_paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)
132
return grub_error (GRUB_ERR_BAD_OS,
133
"segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
134
phdr->p_paddr + phdr->p_memsz,
135
grub_os_area_addr + grub_os_area_size);
137
if (grub_file_seek (file, (grub_off_t) phdr->p_offset)
175
char *load_this_module_at = grub_multiboot_payload_orig + (phdr(i)->p_paddr - phdr(0)->p_paddr);
177
grub_dprintf ("multiboot_loader", "segment %d: paddr=%p, memsz=%p\n",
178
i, phdr(i)->p_paddr, phdr(i)->p_memsz);
180
if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
138
181
== (grub_off_t) -1)
139
182
return grub_error (GRUB_ERR_BAD_OS,
140
183
"invalid offset in program header");
142
if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz)
143
!= (grub_ssize_t) phdr->p_filesz)
185
if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz)
186
!= (grub_ssize_t) phdr(i)->p_filesz)
144
187
return grub_error (GRUB_ERR_BAD_OS,
145
188
"couldn't read segment from file");
147
if (phdr->p_filesz < phdr->p_memsz)
148
grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0,
149
phdr->p_memsz - phdr->p_filesz);
151
if ((entry >= phdr->p_vaddr) &&
152
(entry < phdr->p_vaddr + phdr->p_memsz))
153
physical_entry_addr = entry + phdr->p_paddr - phdr->p_vaddr;
190
if (phdr(i)->p_filesz < phdr(i)->p_memsz)
191
grub_memset (load_this_module_at + phdr(i)->p_filesz, 0,
192
phdr(i)->p_memsz - phdr(i)->p_filesz);
157
if (physical_entry_addr)
158
entry = physical_entry_addr;
196
grub_multiboot_payload_entry_offset = ehdr->e_entry - phdr(lowest_segment)->p_vaddr;
200
if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig)
201
entry = (grub_addr_t) playground;
203
entry = (grub_addr_t) grub_multiboot_payload_orig + grub_multiboot_payload_size;
205
grub_dprintf ("multiboot_loader", "dest=%p, size=%p, entry_offset=%p\n",
206
grub_multiboot_payload_dest,
207
grub_multiboot_payload_size,
208
grub_multiboot_payload_entry_offset);
160
210
return grub_errno;
203
253
entry = ehdr->e_entry;
255
phdr_base = (char *) buffer + ehdr->e_phoff;
256
#define phdr(i) ((Elf64_Phdr *) (phdr_base + (i) * ehdr->e_phentsize))
205
258
/* Load every loadable segment in memory. */
206
259
for (i = 0; i < ehdr->e_phnum; i++)
208
phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff
209
+ i * ehdr->e_phentsize);
210
if (phdr->p_type == PT_LOAD)
261
if (phdr(i)->p_type == PT_LOAD)
212
263
/* The segment should fit in the area reserved for the OS. */
213
if (phdr->p_paddr < (grub_uint64_t) grub_os_area_addr)
264
if (phdr(i)->p_paddr < (grub_uint64_t) grub_os_area_addr)
214
265
return grub_error (GRUB_ERR_BAD_OS,
215
266
"segment doesn't fit in memory reserved for the OS (0x%lx < 0x%lx)",
216
phdr->p_paddr, (grub_uint64_t) grub_os_area_addr);
217
if (phdr->p_paddr + phdr->p_memsz
267
phdr(i)->p_paddr, (grub_uint64_t) grub_os_area_addr);
268
if (phdr(i)->p_paddr + phdr(i)->p_memsz
218
269
> (grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size)
219
270
return grub_error (GRUB_ERR_BAD_OS,
220
271
"segment doesn't fit in memory reserved for the OS (0x%lx > 0x%lx)",
221
phdr->p_paddr + phdr->p_memsz,
272
phdr(i)->p_paddr + phdr(i)->p_memsz,
222
273
(grub_uint64_t) grub_os_area_addr + (grub_uint64_t) grub_os_area_size);
224
if (grub_file_seek (file, (grub_off_t) phdr->p_offset)
275
if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset)
225
276
== (grub_off_t) -1)
226
277
return grub_error (GRUB_ERR_BAD_OS,
227
278
"invalid offset in program header");
229
if (grub_file_read (file, (void *) ((grub_uint32_t) phdr->p_paddr),
231
!= (grub_ssize_t) phdr->p_filesz)
280
if (grub_file_read (file, (void *) ((grub_uint32_t) phdr(i)->p_paddr),
282
!= (grub_ssize_t) phdr(i)->p_filesz)
232
283
return grub_error (GRUB_ERR_BAD_OS,
233
284
"couldn't read segment from file");
235
if (phdr->p_filesz < phdr->p_memsz)
236
grub_memset (((char *) ((grub_uint32_t) phdr->p_paddr)
286
if (phdr(i)->p_filesz < phdr(i)->p_memsz)
287
grub_memset (((char *) ((grub_uint32_t) phdr(i)->p_paddr)
288
+ phdr(i)->p_filesz),
239
phdr->p_memsz - phdr->p_filesz);
290
phdr(i)->p_memsz - phdr(i)->p_filesz);
241
if ((entry >= phdr->p_vaddr) &&
242
(entry < phdr->p_vaddr + phdr->p_memsz))
243
physical_entry_addr = entry + phdr->p_paddr - phdr->p_vaddr;
292
if ((entry >= phdr(i)->p_vaddr) &&
293
(entry < phdr(i)->p_vaddr + phdr(i)->p_memsz))
294
physical_entry_addr = entry + phdr(i)->p_paddr - phdr(i)->p_vaddr;
247
299
if (physical_entry_addr)
248
300
entry = physical_entry_addr;