source: grub-pc/trunk/fuentes/grub-core/loader/i386/pc/chainloader.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 7.0 KB
Line 
1/* chainloader.c - boot another boot loader */
2/*
3 *  GRUB  --  GRand Unified Bootloader
4 *  Copyright (C) 2002,2004,2007,2009,2010  Free Software Foundation, Inc.
5 *
6 *  GRUB is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  GRUB is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <grub/loader.h>
21#include <grub/machine/chainloader.h>
22#include <grub/machine/memory.h>
23#include <grub/file.h>
24#include <grub/err.h>
25#include <grub/device.h>
26#include <grub/disk.h>
27#include <grub/misc.h>
28#include <grub/types.h>
29#include <grub/partition.h>
30#include <grub/memory.h>
31#include <grub/dl.h>
32#include <grub/command.h>
33#include <grub/msdos_partition.h>
34#include <grub/machine/biosnum.h>
35#include <grub/cpu/floppy.h>
36#include <grub/i18n.h>
37#include <grub/video.h>
38#include <grub/mm.h>
39#include <grub/fat.h>
40#include <grub/ntfs.h>
41#include <grub/i386/relocator.h>
42
43GRUB_MOD_LICENSE ("GPLv3+");
44
45static grub_dl_t my_mod;
46static int boot_drive;
47static grub_addr_t boot_part_addr;
48static struct grub_relocator *rel;
49
50typedef enum
51  {
52    GRUB_CHAINLOADER_FORCE = 0x1,
53    GRUB_CHAINLOADER_BPB = 0x2,
54  } grub_chainloader_flags_t;
55
56static grub_err_t
57grub_chainloader_boot (void)
58{
59  struct grub_relocator16_state state = { 
60    .edx = boot_drive,
61    .esi = boot_part_addr,
62    .ds = 0,
63    .es = 0,
64    .fs = 0,
65    .gs = 0,
66    .ss = 0,
67    .cs = 0,
68    .sp = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR,
69    .ip = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR,
70    .a20 = 0
71  };
72  grub_video_set_mode ("text", 0, 0);
73
74  return grub_relocator16_boot (rel, state);
75}
76
77static grub_err_t
78grub_chainloader_unload (void)
79{
80  grub_relocator_unload (rel);
81  rel = NULL;
82  grub_dl_unref (my_mod);
83  return GRUB_ERR_NONE;
84}
85
86void
87grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl)
88{
89  grub_uint32_t part_start = 0;
90  if (dev && dev->disk)
91    part_start = grub_partition_get_start (dev->disk->partition);
92  if (grub_memcmp ((char *) &((struct grub_ntfs_bpb *) bs)->oem_name,
93                   "NTFS", 4) == 0)
94    {
95      struct grub_ntfs_bpb *bpb = (struct grub_ntfs_bpb *) bs;
96      bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
97      bpb->bios_drive = dl;
98      return;
99    }
100
101  do
102    {
103      struct grub_fat_bpb *bpb = (struct grub_fat_bpb *) bs;
104      if (grub_strncmp((const char *) bpb->version_specific.fat12_or_fat16.fstype, "FAT12", 5)
105          && grub_strncmp((const char *) bpb->version_specific.fat12_or_fat16.fstype, "FAT16", 5)
106          && grub_strncmp((const char *) bpb->version_specific.fat32.fstype, "FAT32", 5))
107        break;
108
109      if (grub_le_to_cpu16 (bpb->bytes_per_sector) < 512
110          || (grub_le_to_cpu16 (bpb->bytes_per_sector)
111              & (grub_le_to_cpu16 (bpb->bytes_per_sector) - 1)))
112        break;
113         
114      if (bpb->sectors_per_cluster == 0
115          || (bpb->sectors_per_cluster & (bpb->sectors_per_cluster - 1)))
116        break;
117
118      if (bpb->num_reserved_sectors == 0)
119        break;
120      if (bpb->num_total_sectors_16 == 0 || bpb->num_total_sectors_32 == 0)
121        break;
122
123      if (bpb->num_fats == 0)
124        break;
125
126      if (bpb->sectors_per_fat_16)
127        {
128          bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
129          bpb->version_specific.fat12_or_fat16.num_ph_drive = dl;
130          return;
131        }
132      if (bpb->version_specific.fat32.sectors_per_fat_32)
133        {
134          bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
135          bpb->version_specific.fat32.num_ph_drive = dl;
136          return;
137        }
138      break;
139    }
140  while (0);
141}
142
143static void
144grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
145{
146  grub_file_t file = 0;
147  grub_uint16_t signature;
148  grub_device_t dev;
149  int drive = -1;
150  grub_addr_t part_addr = 0;
151  grub_uint8_t *bs, *ptable;
152
153  rel = grub_relocator_new ();
154  if (!rel)
155    goto fail;
156
157  grub_dl_ref (my_mod);
158
159  grub_file_filter_disable_compression ();
160  file = grub_file_open (filename);
161  if (! file)
162    goto fail;
163
164  {
165    grub_relocator_chunk_t ch;
166    grub_err_t err;
167
168    err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00,
169                                           GRUB_DISK_SECTOR_SIZE);
170    if (err)
171      goto fail;
172    bs = get_virtual_current_address (ch);
173    err = grub_relocator_alloc_chunk_addr (rel, &ch,
174                                           GRUB_MEMORY_MACHINE_PART_TABLE_ADDR,
175                                           64);
176    if (err)
177      goto fail;
178    ptable = get_virtual_current_address (ch);
179  }
180
181  /* Read the first block.  */
182  if (grub_file_read (file, bs, GRUB_DISK_SECTOR_SIZE)
183      != GRUB_DISK_SECTOR_SIZE)
184    {
185      if (!grub_errno)
186        grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
187                    filename);
188
189      goto fail;
190    }
191
192  /* Check the signature.  */
193  signature = *((grub_uint16_t *) (bs + GRUB_DISK_SECTOR_SIZE - 2));
194  if (signature != grub_le_to_cpu16 (0xaa55)
195      && ! (flags & GRUB_CHAINLOADER_FORCE))
196    {
197      grub_error (GRUB_ERR_BAD_OS, "invalid signature");
198      goto fail;
199    }
200
201  grub_file_close (file);
202
203  /* Obtain the partition table from the root device.  */
204  drive = grub_get_root_biosnumber ();
205  dev = grub_device_open (0);
206  if (dev && dev->disk && dev->disk->partition)
207    {
208      grub_disk_t disk = dev->disk;
209
210      if (disk)
211        {
212          grub_partition_t p = disk->partition;
213
214          if (p && grub_strcmp (p->partmap->name, "msdos") == 0)
215            {
216              disk->partition = p->parent;
217              grub_disk_read (disk, p->offset, 446, 64, ptable);
218              part_addr = (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
219                           + (p->index << 4));
220              disk->partition = p;
221            }
222        }
223    }
224
225  if (flags & GRUB_CHAINLOADER_BPB)
226    grub_chainloader_patch_bpb ((void *) 0x7C00, dev, drive);
227
228  if (dev)
229    grub_device_close (dev);
230 
231  /* Ignore errors. Perhaps it's not fatal.  */
232  grub_errno = GRUB_ERR_NONE;
233
234  boot_drive = drive;
235  boot_part_addr = part_addr;
236
237  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 1);
238  return;
239
240 fail:
241
242  if (file)
243    grub_file_close (file);
244
245  grub_dl_unref (my_mod);
246}
247
248static grub_err_t
249grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
250                      int argc, char *argv[])
251{
252  grub_chainloader_flags_t flags = 0;
253
254  while (argc > 0)
255    {
256      if (grub_strcmp (argv[0], "--force") == 0)
257        {
258          flags |= GRUB_CHAINLOADER_FORCE;
259          argc--;
260          argv++;
261          continue;
262        }
263      if (grub_strcmp (argv[0], "--bpb") == 0)
264        {
265          flags |= GRUB_CHAINLOADER_BPB;
266          argc--;
267          argv++;
268          continue;
269        }
270      break;
271    }
272
273  if (argc == 0)
274    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
275
276  grub_chainloader_cmd (argv[0], flags);
277
278  return grub_errno;
279}
280
281static grub_command_t cmd;
282
283GRUB_MOD_INIT(chainloader)
284{
285  cmd = grub_register_command ("chainloader", grub_cmd_chainloader,
286                               N_("[--force|--bpb] FILE"),
287                               N_("Load another boot loader."));
288  my_mod = mod;
289}
290
291GRUB_MOD_FINI(chainloader)
292{
293  grub_unregister_command (cmd);
294}
Note: See TracBrowser for help on using the repository browser.