]> git.proxmox.com Git - grub2.git/blame - grub-core/loader/i386/xen.c
Decrease number of strings to translate.
[grub2.git] / grub-core / loader / i386 / xen.c
CommitLineData
9612ebc0
VS
1/*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2013 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <grub/loader.h>
20#include <grub/memory.h>
21#include <grub/normal.h>
22#include <grub/file.h>
23#include <grub/disk.h>
24#include <grub/err.h>
25#include <grub/misc.h>
26#include <grub/types.h>
27#include <grub/dl.h>
28#include <grub/mm.h>
29#include <grub/term.h>
30#include <grub/cpu/linux.h>
31#include <grub/video.h>
32#include <grub/video_fb.h>
33#include <grub/command.h>
34#include <grub/xen/relocator.h>
35#include <grub/i18n.h>
36#include <grub/elf.h>
37#include <grub/elfload.h>
38#include <grub/lib/cmdline.h>
39#include <grub/xen.h>
40#include <grub/xen_file.h>
41#include <grub/linux.h>
42
43GRUB_MOD_LICENSE ("GPLv3+");
44
45static struct grub_relocator *relocator = NULL;
46static grub_uint64_t max_addr;
47static grub_dl_t my_mod;
48static int loaded = 0;
49static struct start_info next_start;
50static void *kern_chunk_src;
51static struct grub_xen_file_info xen_inf;
52static struct xen_multiboot_mod_list *xen_module_info_page;
53static grub_uint64_t modules_target_start;
54static grub_size_t n_modules;
55
56#define PAGE_SIZE 4096
57#define MAX_MODULES (PAGE_SIZE / sizeof (struct xen_multiboot_mod_list))
58#define PAGE_SHIFT 12
59#define STACK_SIZE 1048576
60#define ADDITIONAL_SIZE (1 << 19)
61#define ALIGN_SIZE (1 << 22)
62#define LOG_POINTERS_PER_PAGE 9
63#define POINTERS_PER_PAGE (1 << LOG_POINTERS_PER_PAGE)
64
65static grub_uint64_t
66page2offset (grub_uint64_t page)
67{
68 return page << PAGE_SHIFT;
69}
70
71#ifdef __x86_64__
72#define NUMBER_OF_LEVELS 4
73#define INTERMEDIATE_OR 7
74#else
75#define NUMBER_OF_LEVELS 3
76#define INTERMEDIATE_OR 3
77#endif
78
79static grub_uint64_t
80get_pgtable_size (grub_uint64_t total_pages, grub_uint64_t virt_base)
81{
82 if (!virt_base)
83 total_pages++;
84 grub_uint64_t ret = 0;
85 grub_uint64_t ll = total_pages;
86 int i;
87 for (i = 0; i < NUMBER_OF_LEVELS; i++)
88 {
89 ll = (ll + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
90 /* PAE wants all 4 root directories present. */
91#ifdef __i386__
92 if (i == 1)
93 ll = 4;
94#endif
95 ret += ll;
96 }
97 for (i = 1; i < NUMBER_OF_LEVELS; i++)
98 if (virt_base >> (PAGE_SHIFT + i * LOG_POINTERS_PER_PAGE))
99 ret++;
100 return ret;
101}
102
103static void
104generate_page_table (grub_uint64_t *where, grub_uint64_t paging_start,
105 grub_uint64_t total_pages, grub_uint64_t virt_base,
106 grub_xen_mfn_t *mfn_list)
107{
108 if (!virt_base)
109 total_pages++;
110
111 grub_uint64_t lx[NUMBER_OF_LEVELS], lxs[NUMBER_OF_LEVELS];
112 grub_uint64_t nlx, nls, sz = 0;
113 int l;
114
115 nlx = total_pages;
116 nls = virt_base >> PAGE_SHIFT;
117 for (l = 0; l < NUMBER_OF_LEVELS; l++)
118 {
119 nlx = (nlx + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
120 /* PAE wants all 4 root directories present. */
121#ifdef __i386__
122 if (l == 1)
123 nlx = 4;
124#endif
125 lx[l] = nlx;
126 sz += lx[l];
127 lxs[l] = nls & (POINTERS_PER_PAGE - 1);
128 if (nls && l != 0)
129 sz++;
130 nls >>= LOG_POINTERS_PER_PAGE;
131 }
132
133 grub_uint64_t lp;
134 grub_uint64_t j;
135 grub_uint64_t *pg = (grub_uint64_t *) where;
136 int pr = 0;
137
138 grub_memset (pg, 0, sz * PAGE_SIZE);
139
140 lp = paging_start + lx[NUMBER_OF_LEVELS - 1];
141 for (l = NUMBER_OF_LEVELS - 1; l >= 1; l--)
142 {
143 if (lxs[l] || pr)
144 pg[0] = page2offset (mfn_list[lp++]) | INTERMEDIATE_OR;
145 if (pr)
146 pg += POINTERS_PER_PAGE;
147 for (j = 0; j < lx[l - 1]; j++)
148 pg[j + lxs[l]] = page2offset (mfn_list[lp++]) | INTERMEDIATE_OR;
149 pg += lx[l] * POINTERS_PER_PAGE;
150 if (lxs[l])
151 pr = 1;
152 }
153
154 if (lxs[0] || pr)
155 pg[0] = page2offset (mfn_list[total_pages]) | 5;
156 if (pr)
157 pg += POINTERS_PER_PAGE;
158
159 for (j = 0; j < total_pages; j++)
160 {
161 if (j >= paging_start && j < lp)
162 pg[j + lxs[0]] = page2offset (mfn_list[j]) | 5;
163 else
164 pg[j + lxs[0]] = page2offset (mfn_list[j]) | 7;
165 }
166}
167
168static grub_err_t
169set_mfns (grub_xen_mfn_t * new_mfn_list, grub_xen_mfn_t pfn)
170{
171 grub_xen_mfn_t i, t;
172 grub_xen_mfn_t cn_pfn = -1, st_pfn = -1;
173 struct mmu_update m2p_updates[4];
174
175
176 for (i = 0; i < grub_xen_start_page_addr->nr_pages; i++)
177 {
178 if (new_mfn_list[i] == grub_xen_start_page_addr->console.domU.mfn)
179 cn_pfn = i;
180 if (new_mfn_list[i] == grub_xen_start_page_addr->store_mfn)
181 st_pfn = i;
182 }
183 if (cn_pfn == (grub_xen_mfn_t)-1)
184 return grub_error (GRUB_ERR_BUG, "no console");
185 if (st_pfn == (grub_xen_mfn_t)-1)
186 return grub_error (GRUB_ERR_BUG, "no store");
187 t = new_mfn_list[pfn];
188 new_mfn_list[pfn] = new_mfn_list[cn_pfn];
189 new_mfn_list[cn_pfn] = t;
190 t = new_mfn_list[pfn + 1];
191 new_mfn_list[pfn + 1] = new_mfn_list[st_pfn];
192 new_mfn_list[st_pfn] = t;
193
194 m2p_updates[0].ptr = page2offset (new_mfn_list[pfn]) | MMU_MACHPHYS_UPDATE;
195 m2p_updates[0].val = pfn;
196 m2p_updates[1].ptr =
197 page2offset (new_mfn_list[pfn + 1]) | MMU_MACHPHYS_UPDATE;
198 m2p_updates[1].val = pfn + 1;
199 m2p_updates[2].ptr =
200 page2offset (new_mfn_list[cn_pfn]) | MMU_MACHPHYS_UPDATE;
201 m2p_updates[2].val = cn_pfn;
202 m2p_updates[3].ptr =
203 page2offset (new_mfn_list[st_pfn]) | MMU_MACHPHYS_UPDATE;
204 m2p_updates[3].val = st_pfn;
205
206 grub_xen_mmu_update (m2p_updates, 4, NULL, DOMID_SELF);
207
208 return GRUB_ERR_NONE;
209}
210
211static grub_err_t
212grub_xen_boot (void)
213{
214 struct grub_relocator_xen_state state;
215 grub_relocator_chunk_t ch;
216 grub_err_t err;
217 grub_size_t pgtsize;
218 struct start_info *nst;
219 grub_uint64_t nr_info_pages;
220 grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
221 struct gnttab_set_version gnttab_setver;
222 grub_xen_mfn_t *new_mfn_list;
223 grub_size_t i;
224
71669c3b
VS
225 grub_video_restore ();
226
9612ebc0
VS
227 if (grub_xen_n_allocated_shared_pages)
228 return grub_error (GRUB_ERR_BUG, "active grants");
229
230 state.mfn_list = max_addr;
231 next_start.mfn_list = max_addr + xen_inf.virt_base;
232 next_start.first_p2m_pfn = max_addr >> PAGE_SHIFT; /* Is this right? */
233 pgtsize = sizeof (grub_xen_mfn_t) * grub_xen_start_page_addr->nr_pages;
234 err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, pgtsize);
235 next_start.nr_p2m_frames = (pgtsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
236 if (err)
237 return err;
238 new_mfn_list = get_virtual_current_address (ch);
239 grub_memcpy (new_mfn_list,
240 (void *) grub_xen_start_page_addr->mfn_list, pgtsize);
241 max_addr = ALIGN_UP (max_addr + pgtsize, PAGE_SIZE);
242
243 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
244 max_addr, sizeof (next_start));
245 if (err)
246 return err;
247 state.start_info = max_addr + xen_inf.virt_base;
248 nst = get_virtual_current_address (ch);
249 max_addr = ALIGN_UP (max_addr + sizeof (next_start), PAGE_SIZE);
250
251 next_start.nr_pages = grub_xen_start_page_addr->nr_pages;
252 grub_memcpy (next_start.magic, grub_xen_start_page_addr->magic,
253 sizeof (next_start.magic));
254 next_start.store_mfn = grub_xen_start_page_addr->store_mfn;
255 next_start.store_evtchn = grub_xen_start_page_addr->store_evtchn;
256 next_start.console.domU = grub_xen_start_page_addr->console.domU;
257 next_start.shared_info = grub_xen_start_page_addr->shared_info;
258
259 err = set_mfns (new_mfn_list, max_addr >> PAGE_SHIFT);
260 if (err)
261 return err;
262 max_addr += 2 * PAGE_SIZE;
263
264 next_start.pt_base = max_addr + xen_inf.virt_base;
265 state.paging_start = max_addr >> PAGE_SHIFT;
266
267 nr_info_pages = max_addr >> PAGE_SHIFT;
268 nr_pages = nr_info_pages;
269
270 while (1)
271 {
272 nr_pages = ALIGN_UP (nr_pages, (ALIGN_SIZE >> PAGE_SHIFT));
273 nr_pt_pages = get_pgtable_size (nr_pages, xen_inf.virt_base);
274 nr_need_pages =
275 nr_info_pages + nr_pt_pages +
276 ((ADDITIONAL_SIZE + STACK_SIZE) >> PAGE_SHIFT);
277 if (nr_pages >= nr_need_pages)
278 break;
279 nr_pages = nr_need_pages;
280 }
281
282 grub_dprintf ("xen", "bootstrap domain %llx+%llx\n",
283 (unsigned long long) xen_inf.virt_base,
284 (unsigned long long) page2offset (nr_pages));
285
286 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
287 max_addr, page2offset (nr_pt_pages));
288 if (err)
289 return err;
290
291 generate_page_table (get_virtual_current_address (ch),
292 max_addr >> PAGE_SHIFT, nr_pages,
293 xen_inf.virt_base, new_mfn_list);
294
295 max_addr += page2offset (nr_pt_pages);
296 state.stack = max_addr + STACK_SIZE + xen_inf.virt_base;
297 state.entry_point = xen_inf.entry_point;
298
299 next_start.nr_p2m_frames += nr_pt_pages;
300 next_start.nr_pt_frames = nr_pt_pages;
301 state.paging_size = nr_pt_pages;
302
303 *nst = next_start;
304
305 grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
306
307 gnttab_setver.version = 1;
308 grub_xen_grant_table_op (GNTTABOP_set_version, &gnttab_setver, 1);
309
310 for (i = 0; i < ARRAY_SIZE (grub_xen_shared_info->evtchn_pending); i++)
311 grub_xen_shared_info->evtchn_pending[i] = 0;
312
313 return grub_relocator_xen_boot (relocator, state, nr_pages,
314 xen_inf.virt_base <
315 PAGE_SIZE ? page2offset (nr_pages) : 0,
316 nr_pages - 1,
317 page2offset (nr_pages - 1) +
318 xen_inf.virt_base);
319}
320
321static grub_err_t
322grub_xen_unload (void)
323{
324 grub_dl_unref (my_mod);
325 loaded = 0;
326 return GRUB_ERR_NONE;
327}
328
329#define HYPERCALL_INTERFACE_SIZE 32
330
331#ifdef __x86_64__
332static grub_uint8_t template[] =
333 {
334 0x51, /* push %rcx */
335 0x41, 0x53, /* push %r11 */
336 0x48, 0xc7, 0xc0, 0xbb, 0xaa, 0x00, 0x00, /* mov $0xaabb,%rax */
337 0x0f, 0x05, /* syscall */
338 0x41, 0x5b, /* pop %r11 */
339 0x59, /* pop %rcx */
340 0xc3 /* ret */
341 };
342
343static grub_uint8_t template_iret[] =
344 {
345 0x51, /* push %rcx */
346 0x41, 0x53, /* push %r11 */
347 0x50, /* push %rax */
348 0x48, 0xc7, 0xc0, 0x17, 0x00, 0x00, 0x00, /* mov $0x17,%rax */
349 0x0f, 0x05 /* syscall */
350 };
351#define CALLNO_OFFSET 6
352#else
353
354static grub_uint8_t template[] =
355 {
356 0xb8, 0xbb, 0xaa, 0x00, 0x00, /* mov imm32, %eax */
357 0xcd, 0x82, /* int $0x82 */
358 0xc3 /* ret */
359 };
360
361static grub_uint8_t template_iret[] =
362 {
363 0x50, /* push %eax */
364 0xb8, 0x17, 0x00, 0x00, 0x00, /* mov $0x17,%eax */
365 0xcd, 0x82, /* int $0x82 */
366 };
367#define CALLNO_OFFSET 1
368
369#endif
370
371
372static void
373set_hypercall_interface (grub_uint8_t *tgt, unsigned callno)
374{
375 if (callno == 0x17)
376 {
377 grub_memcpy (tgt, template_iret, ARRAY_SIZE (template_iret));
378 grub_memset (tgt + ARRAY_SIZE (template_iret), 0xcc,
379 HYPERCALL_INTERFACE_SIZE - ARRAY_SIZE (template_iret));
380 return;
381 }
382 grub_memcpy (tgt, template, ARRAY_SIZE (template));
383 grub_memset (tgt + ARRAY_SIZE (template), 0xcc,
384 HYPERCALL_INTERFACE_SIZE - ARRAY_SIZE (template));
385 tgt[CALLNO_OFFSET] = callno & 0xff;
386 tgt[CALLNO_OFFSET + 1] = callno >> 8;
387}
388
389#ifdef __x86_64__
390#define grub_elfXX_load grub_elf64_load
391#else
392#define grub_elfXX_load grub_elf32_load
393#endif
394
395static grub_err_t
396grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
397 int argc, char *argv[])
398{
399 grub_file_t file;
400 grub_elf_t elf;
401 grub_err_t err;
402
403 if (argc == 0)
404 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
405
406 grub_loader_unset ();
407
408 grub_memset (&next_start, 0, sizeof (next_start));
409
410 xen_module_info_page = NULL;
411 n_modules = 0;
412
413 grub_create_loader_cmdline (argc - 1, argv + 1,
414 (char *) next_start.cmd_line,
415 sizeof (next_start.cmd_line) - 1);
416
417 file = grub_file_open (argv[0]);
418 if (!file)
419 return grub_errno;
420
421 elf = grub_xen_file (file);
422 if (!elf)
423 goto fail;
424
425 err = grub_xen_get_info (elf, &xen_inf);
426 if (err)
427 goto fail;
428#ifdef __x86_64__
429 if (xen_inf.arch != GRUB_XEN_FILE_X86_64)
430#else
431 if (xen_inf.arch != GRUB_XEN_FILE_I386_PAE
432 && xen_inf.arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
433#endif
434 {
435 grub_error (GRUB_ERR_BAD_OS, "incompatible architecture: %d",
436 xen_inf.arch);
437 goto fail;
438 }
439
440 if (xen_inf.virt_base & (PAGE_SIZE - 1))
441 {
442 grub_error (GRUB_ERR_BAD_OS, "unaligned virt_base");
443 goto fail;
444 }
445 grub_dprintf ("xen", "virt_base = %llx, entry = %llx\n",
446 (unsigned long long) xen_inf.virt_base,
447 (unsigned long long) xen_inf.entry_point);
448
449 relocator = grub_relocator_new ();
450 if (!relocator)
451 goto fail;
452
453 grub_relocator_chunk_t ch;
454 grub_addr_t kern_start = xen_inf.kern_start - xen_inf.paddr_offset;
455 grub_addr_t kern_end = xen_inf.kern_end - xen_inf.paddr_offset;
456
457 if (xen_inf.has_hypercall_page)
458 {
459 grub_dprintf ("xen", "hypercall page at 0x%llx\n",
460 (unsigned long long) xen_inf.hypercall_page);
461 if (xen_inf.hypercall_page - xen_inf.virt_base < kern_start)
462 kern_start = xen_inf.hypercall_page - xen_inf.virt_base;
463
464 if (xen_inf.hypercall_page - xen_inf.virt_base + PAGE_SIZE > kern_end)
465 kern_end = xen_inf.hypercall_page - xen_inf.virt_base + PAGE_SIZE;
466 }
467
468 max_addr = ALIGN_UP (kern_end, PAGE_SIZE);
469
470 err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
471 kern_end - kern_start);
472 if (err)
473 goto fail;
474 kern_chunk_src = get_virtual_current_address (ch);
475
476 grub_dprintf ("xen", "paddr_offset = 0x%llx\n",
477 (unsigned long long) xen_inf.paddr_offset);
478 grub_dprintf ("xen", "kern_start = 0x%llx, kern_end = 0x%llx\n",
479 (unsigned long long) xen_inf.kern_start,
480 (unsigned long long) xen_inf.kern_end);
481
482 err = grub_elfXX_load (elf, argv[0],
483 (grub_uint8_t *) kern_chunk_src - kern_start
484 - xen_inf.paddr_offset, 0, 0, 0);
485
486 if (xen_inf.has_hypercall_page)
487 {
488 unsigned i;
489 for (i = 0; i < PAGE_SIZE / HYPERCALL_INTERFACE_SIZE; i++)
490 set_hypercall_interface ((grub_uint8_t *) kern_chunk_src +
491 i * HYPERCALL_INTERFACE_SIZE +
492 xen_inf.hypercall_page - xen_inf.virt_base -
493 kern_start, i);
494 }
495
496 if (err)
497 goto fail;
498
499 grub_dl_ref (my_mod);
500 loaded = 1;
501
502 grub_loader_set (grub_xen_boot, grub_xen_unload, 0);
503 loaded = 1;
504
505 goto fail;
506
507fail:
508
509 if (elf)
510 grub_elf_close (elf);
511 else if (file)
512 grub_file_close (file);
513
514 if (grub_errno != GRUB_ERR_NONE)
515 loaded = 0;
516
517 return grub_errno;
518}
519
520static grub_err_t
521grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
522 int argc, char *argv[])
523{
524 grub_size_t size = 0;
525 grub_err_t err;
526 struct grub_linux_initrd_context initrd_ctx;
527 grub_relocator_chunk_t ch;
528
529 if (argc == 0)
530 {
531 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
532 goto fail;
533 }
534
535 if (!loaded)
536 {
537 grub_error (GRUB_ERR_BAD_ARGUMENT,
538 N_("you need to load the kernel first"));
539 goto fail;
540 }
541
542 if (next_start.mod_start || next_start.mod_len)
543 {
544 grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
545 goto fail;
546 }
547
548 if (grub_initrd_init (argc, argv, &initrd_ctx))
549 goto fail;
550
551 size = grub_get_initrd_size (&initrd_ctx);
552
553 if (size)
554 {
555 err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
556 if (err)
557 return err;
558
559 if (grub_initrd_load (&initrd_ctx, argv,
560 get_virtual_current_address (ch)))
561 goto fail;
562 }
563
564 next_start.mod_start = max_addr + xen_inf.virt_base;
565 next_start.mod_len = size;
566
567 max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
568
569 grub_dprintf ("xen", "Initrd, addr=0x%x, size=0x%x\n",
570 (unsigned) next_start.mod_start, (unsigned) size);
571
572fail:
573 grub_initrd_close (&initrd_ctx);
574
575 return grub_errno;
576}
577
578static grub_err_t
579grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
580 int argc, char *argv[])
581{
582 grub_size_t size = 0;
583 grub_err_t err;
584 grub_relocator_chunk_t ch;
585 grub_size_t cmdline_len;
586 int nounzip = 0;
587 grub_file_t file;
588
589 if (argc == 0)
590 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
591
592 if (grub_strcmp (argv[0], "--nounzip") == 0)
593 {
594 argv++;
595 argc--;
596 nounzip = 1;
597 }
598
599 if (argc == 0)
600 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
601
602 if (!loaded)
603 {
604 return grub_error (GRUB_ERR_BAD_ARGUMENT,
605 N_("you need to load the kernel first"));
606 }
607
608 if ((next_start.mod_start || next_start.mod_len) && !xen_module_info_page)
609 {
610 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
611 }
612
613 /* Leave one space for terminator. */
614 if (n_modules >= MAX_MODULES - 1)
615 {
616 return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many modules");
617 }
618
619 if (!xen_module_info_page)
620 {
621 n_modules = 0;
622 max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
623 modules_target_start = max_addr;
624 next_start.mod_start = max_addr + xen_inf.virt_base;
625 next_start.flags |= SIF_MULTIBOOT_MOD;
626
627 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
628 max_addr, MAX_MODULES
629 *
630 sizeof (xen_module_info_page
631 [0]));
632 if (err)
633 return err;
634 xen_module_info_page = get_virtual_current_address (ch);
635 grub_memset (xen_module_info_page, 0, MAX_MODULES
636 * sizeof (xen_module_info_page[0]));
637 max_addr += MAX_MODULES * sizeof (xen_module_info_page[0]);
638 }
639
640 max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
641
642 if (nounzip)
643 grub_file_filter_disable_compression ();
644 file = grub_file_open (argv[0]);
645 if (!file)
646 return grub_errno;
647 size = grub_file_size (file);
648
649 cmdline_len = grub_loader_cmdline_size (argc - 1, argv + 1);
650
651 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
652 max_addr, cmdline_len);
653 if (err)
654 goto fail;
655
656 grub_create_loader_cmdline (argc - 1, argv + 1,
657 get_virtual_current_address (ch), cmdline_len);
658
659 xen_module_info_page[n_modules].cmdline = max_addr - modules_target_start;
660 max_addr = ALIGN_UP (max_addr + cmdline_len, PAGE_SIZE);
661
662 if (size)
663 {
664 err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
665 if (err)
666 goto fail;
667 if (grub_file_read (file, get_virtual_current_address (ch), size)
668 != (grub_ssize_t) size)
669 {
670 if (!grub_errno)
671 grub_error (GRUB_ERR_FILE_READ_ERROR,
672 N_("premature end of file %s"), argv[0]);
673 goto fail;
674 }
675 }
676 next_start.mod_len = max_addr + size - modules_target_start;
677 xen_module_info_page[n_modules].mod_start = max_addr - modules_target_start;
678 xen_module_info_page[n_modules].mod_end =
679 max_addr + size - modules_target_start;
680
681 n_modules++;
682 grub_dprintf ("xen", "module, addr=0x%x, size=0x%x\n",
683 (unsigned) max_addr, (unsigned) size);
684 max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
685
686
687fail:
688 grub_file_close (file);
689
690 return grub_errno;
691}
692
693static grub_command_t cmd_xen, cmd_initrd, cmd_module, cmd_multiboot;
694
695GRUB_MOD_INIT (xen)
696{
697 cmd_xen = grub_register_command ("linux", grub_cmd_xen,
57a691b7 698 0, N_("Load Linux."));
9612ebc0 699 cmd_multiboot = grub_register_command ("multiboot", grub_cmd_xen,
57a691b7 700 0, N_("Load Linux."));
9612ebc0
VS
701 cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
702 0, N_("Load initrd."));
703 cmd_module = grub_register_command ("module", grub_cmd_module,
704 0, N_("Load module."));
705 my_mod = mod;
706}
707
708GRUB_MOD_FINI (xen)
709{
710 grub_unregister_command (cmd_xen);
711 grub_unregister_command (cmd_initrd);
712 grub_unregister_command (cmd_multiboot);
713 grub_unregister_command (cmd_module);
714}