99fad4cadae42ab09497babca15cd9606557fcd2
[grub.git] / grub-core / loader / i386 / xen_file.c
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/xen_file.h>
20 #include <grub/i386/linux.h>
21 #include <grub/misc.h>
22
23 #define XZ_MAGIC "\3757zXZ\0"
24
25 grub_elf_t
26 grub_xen_file (grub_file_t file)
27 {
28   grub_elf_t elf;
29   struct linux_kernel_header lh;
30   grub_file_t off_file;
31   grub_uint32_t payload_offset, payload_length;
32   grub_uint8_t magic[6];
33
34   elf = grub_elf_file (file, file->name);
35   if (elf)
36     return elf;
37   grub_errno = GRUB_ERR_NONE;
38
39   if (grub_file_seek (file, 0) == (grub_off_t) -1)
40     goto fail;
41
42   if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
43     goto fail;
44
45   if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)
46       || lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
47       || grub_le_to_cpu16 (lh.version) < 0x0208)
48     {
49       grub_error (GRUB_ERR_BAD_OS, "version too old for xen boot");
50       return NULL;
51     }
52
53   payload_length = lh.payload_length;
54   payload_offset = (lh.setup_sects + 1) * 512
55     + lh.payload_offset;
56
57   if (payload_length < sizeof (magic))
58     {
59       grub_error (GRUB_ERR_BAD_OS, "payload too short");
60       return NULL;
61     }
62
63   grub_dprintf ("xen", "found bzimage payload 0x%llx-0x%llx\n",
64                 (unsigned long long) payload_offset,
65                 (unsigned long long) lh.payload_length);
66
67   grub_file_seek (file, payload_offset);
68
69   if (grub_file_read (file, &magic, sizeof (magic)) != sizeof (magic))
70     {
71       if (!grub_errno)
72         grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
73                     file->name);
74       goto fail;
75     }
76
77   /* Kernel suffixes xz payload with their uncompressed size.
78      Trim it.  */
79   if (grub_memcmp (magic, XZ_MAGIC, sizeof (XZ_MAGIC) - 1) == 0)
80     payload_length -= 4;
81   off_file = grub_file_offset_open (file, payload_offset,
82                                     payload_length);
83   if (!off_file)
84     goto fail;
85
86   elf = grub_elf_file (off_file, file->name);
87   if (elf)
88     return elf;
89   grub_file_offset_close (off_file);
90
91 fail:
92   grub_error (GRUB_ERR_BAD_OS, "not xen image");
93   return NULL;
94 }
95
96 grub_err_t
97 grub_xen_get_info (grub_elf_t elf, struct grub_xen_file_info * xi)
98 {
99   grub_memset (xi, 0, sizeof (*xi));
100
101   if (grub_elf_is_elf64 (elf)
102       && elf->ehdr.ehdr64.e_machine
103       == grub_cpu_to_le16_compile_time (EM_X86_64)
104       && elf->ehdr.ehdr64.e_ident[EI_DATA] == ELFDATA2LSB)
105     {
106       xi->arch = GRUB_XEN_FILE_X86_64;
107       return grub_xen_get_info64 (elf, xi);
108     }
109   if (grub_elf_is_elf32 (elf)
110       && elf->ehdr.ehdr32.e_machine == grub_cpu_to_le16_compile_time (EM_386)
111       && elf->ehdr.ehdr32.e_ident[EI_DATA] == ELFDATA2LSB)
112     {
113       xi->arch = GRUB_XEN_FILE_I386;
114       return grub_xen_get_info32 (elf, xi);
115     }
116   return grub_error (GRUB_ERR_BAD_OS, "unknown ELF type");
117 }