]> git.proxmox.com Git - grub2.git/commitdiff
BPB patching support (untested)
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 5 Apr 2011 12:40:15 +0000 (14:40 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 5 Apr 2011 12:40:15 +0000 (14:40 +0200)
grub-core/fs/fat.c
grub-core/loader/i386/pc/chainloader.c
grub-core/loader/i386/pc/ntldr.c
grub-core/normal/main.c
include/grub/i386/pc/chainloader.h
include/grub/ntfs.h

index 89050943ccaf7bab6383a6c4de8803e71f603ad9..7906cf1b2cb287267600343ad281fc3ff300a203 100644 (file)
@@ -26,6 +26,7 @@
 #include <grub/err.h>
 #include <grub/dl.h>
 #include <grub/charset.h>
+#include <grub/fat.h>
 
 #define GRUB_FAT_DIR_ENTRY_SIZE        32
 
                                 | GRUB_FAT_ATTR_ARCHIVE \
                                 | GRUB_FAT_ATTR_VOLUME_ID)
 
-struct grub_fat_bpb
-{
-  grub_uint8_t jmp_boot[3];
-  grub_uint8_t oem_name[8];
-  grub_uint16_t bytes_per_sector;
-  grub_uint8_t sectors_per_cluster;
-  grub_uint16_t num_reserved_sectors;
-  grub_uint8_t num_fats;
-  grub_uint16_t num_root_entries;
-  grub_uint16_t num_total_sectors_16;
-  grub_uint8_t media;
-  grub_uint16_t sectors_per_fat_16;
-  grub_uint16_t sectors_per_track;
-  grub_uint16_t num_heads;
-  grub_uint32_t num_hidden_sectors;
-  grub_uint32_t num_total_sectors_32;
-  union
-  {
-    struct
-    {
-      grub_uint8_t num_ph_drive;
-      grub_uint8_t reserved;
-      grub_uint8_t boot_sig;
-      grub_uint32_t num_serial;
-      grub_uint8_t label[11];
-      grub_uint8_t fstype[8];
-    } __attribute__ ((packed)) fat12_or_fat16;
-    struct
-    {
-      grub_uint32_t sectors_per_fat_32;
-      grub_uint16_t extended_flags;
-      grub_uint16_t fs_version;
-      grub_uint32_t root_cluster;
-      grub_uint16_t fs_info;
-      grub_uint16_t backup_boot_sector;
-      grub_uint8_t reserved[12];
-      grub_uint8_t num_ph_drive;
-      grub_uint8_t reserved1;
-      grub_uint8_t boot_sig;
-      grub_uint32_t num_serial;
-      grub_uint8_t label[11];
-      grub_uint8_t fstype[8];
-    } __attribute__ ((packed)) fat32;
-  } __attribute__ ((packed)) version_specific;
-} __attribute__ ((packed));
-
 struct grub_fat_dir_entry
 {
   grub_uint8_t name[11];
index fd99c81d583b1a32775be3d4e3491e390be9184e..174e5b7a5a86d50d6d75df532fb4378e029ef343 100644 (file)
 #include <grub/i18n.h>
 #include <grub/video.h>
 #include <grub/mm.h>
+#include <grub/fat.h>
+#include <grub/ntfs.h>
 
 static grub_dl_t my_mod;
 static int boot_drive;
 static void *boot_part_addr;
 
+typedef enum
+  {
+    GRUB_CHAINLOADER_FORCE = 0x1,
+    GRUB_CHAINLOADER_BPB = 0x2,
+  } grub_chainloader_flags_t;
+
 static grub_err_t
 grub_chainloader_boot (void)
 {
@@ -59,6 +67,63 @@ grub_chainloader_unload (void)
   return GRUB_ERR_NONE;
 }
 
+void
+grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl)
+{
+  grub_uint32_t part_start = 0;
+  if (dev && dev->disk)
+    part_start = grub_partition_get_start (dev->disk->partition);
+  if (grub_memcmp ((char *) &((struct grub_ntfs_bpb *) bs)->oem_name,
+                  "NTFS", 4) == 0)
+    {
+      struct grub_ntfs_bpb *bpb = (struct grub_ntfs_bpb *) bs;
+      bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
+      bpb->bios_drive = dl;
+      return;
+    }
+
+  do
+    {
+      struct grub_fat_bpb *bpb = (struct grub_fat_bpb *) bs;
+      if (grub_strncmp((const char *) bpb->version_specific.fat12_or_fat16.fstype, "FAT12", 5)
+         && grub_strncmp((const char *) bpb->version_specific.fat12_or_fat16.fstype, "FAT16", 5)
+         && grub_strncmp((const char *) bpb->version_specific.fat32.fstype, "FAT32", 5))
+       break;
+
+      if (grub_le_to_cpu16 (bpb->bytes_per_sector) < 512
+         || (grub_le_to_cpu16 (bpb->bytes_per_sector)
+             & (grub_le_to_cpu16 (bpb->bytes_per_sector) - 1)))
+       break;
+         
+      if (bpb->sectors_per_cluster == 0
+         || (bpb->sectors_per_cluster & (bpb->sectors_per_cluster - 1)))
+       break;
+
+      if (bpb->num_reserved_sectors == 0)
+       break;
+      if (bpb->num_total_sectors_16 == 0 || bpb->num_total_sectors_32 == 0)
+       break;
+
+      if (bpb->num_fats == 0)
+       break;
+
+      if (bpb->sectors_per_fat_16)
+       {
+         bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
+         bpb->version_specific.fat12_or_fat16.num_ph_drive = dl;
+         return;
+       }
+      if (bpb->version_specific.fat32.sectors_per_fat_32)
+       {
+         bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
+         bpb->version_specific.fat32.num_ph_drive = dl;
+         return;
+       }
+      break;
+    }
+  while (0);
+}
+
 static void
 grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
 {
@@ -119,6 +184,9 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
        }
     }
 
+  if (flags & GRUB_CHAINLOADER_BPB)
+    grub_chainloader_patch_bpb ((void *) 0x7C00, dev, drive);
+
   if (dev)
     grub_device_close (dev);
  
@@ -145,11 +213,23 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
 {
   grub_chainloader_flags_t flags = 0;
 
-  if (argc > 0 && grub_strcmp (argv[0], "--force") == 0)
+  while (argc > 0)
     {
-      flags |= GRUB_CHAINLOADER_FORCE;
-      argc--;
-      argv++;
+      if (grub_strcmp (argv[0], "--force") == 0)
+       {
+         flags |= GRUB_CHAINLOADER_FORCE;
+         argc--;
+         argv++;
+         continue;
+       }
+      if (grub_strcmp (argv[0], "--bpb") == 0)
+       {
+         flags |= GRUB_CHAINLOADER_BPB;
+         argc--;
+         argv++;
+         continue;
+       }
+      break;
     }
 
   if (argc == 0)
@@ -165,7 +245,8 @@ static grub_command_t cmd;
 GRUB_MOD_INIT(chainloader)
 {
   cmd = grub_register_command ("chainloader", grub_cmd_chainloader,
-                              0, N_("Load another boot loader."));
+                              "[--force|--bpb] FILE",
+                              N_("Load another boot loader."));
   my_mod = mod;
 }
 
index 0c33a068049de230be23710820b81804bb8029d4..9649cdfbe95762ba00c3cd3d794d02a324f028e5 100644 (file)
@@ -32,6 +32,7 @@
 #include <grub/video.h>
 #include <grub/mm.h>
 #include <grub/cpu/relocator.h>
+#include <grub/machine/chainloader.h>
 
 static grub_dl_t my_mod;
 static struct grub_relocator *rel;
@@ -110,6 +111,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)),
          grub_device_close (dev);
          goto fail;
        }
+      grub_chainloader_patch_bpb (bs, dev, edx);
     }
 
   if (dev)
index cefb1cb9b167865346f0df5718c6b4a8f76831a3..c04accb6de1253d0c2d6685f89e2789e148146a4 100644 (file)
@@ -515,6 +515,9 @@ GRUB_MOD_INIT(normal)
   /* Set default color names.  */
   grub_env_set ("color_normal", "white/black");
   grub_env_set ("color_highlight", "black/white");
+
+  grub_env_set ("grub_feature_chainloader_bpb", "--bpb");
+  grub_env_export ("grub_feature_chainloader_bpb");
 }
 
 GRUB_MOD_FINI(normal)
index ca1da23a744bb070740f339525db520050013a68..4776b181bbd4af1d64579229acda782a376669bf 100644 (file)
 
 #include <grub/dl.h>
 
-/* Common function for normal and rescue mode commands. */
-typedef enum
-  {
-    GRUB_CHAINLOADER_FORCE = 0x1
-  } grub_chainloader_flags_t;
+void
+grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl);
 
 #endif /* GRUB_CHAINLOADER_MACHINE_HEADER */
index 31b99398bed04644e282c7647198be2498a94c5c..9e2e3470769c107bf9068b9e38a475b96913aded 100644 (file)
@@ -106,14 +106,16 @@ struct grub_ntfs_bpb
   grub_uint16_t sectors_per_track;
   grub_uint16_t num_heads;
   grub_uint32_t num_hidden_sectors;
-  grub_uint32_t reserved_3[2];
+  grub_uint32_t reserved_3;
+  grub_uint8_t bios_drive;
+  grub_uint8_t reserved_4[3];
   grub_uint64_t num_total_sectors;
   grub_uint64_t mft_lcn;
   grub_uint64_t mft_mirr_lcn;
   grub_int8_t clusters_per_mft;
-  grub_int8_t reserved_4[3];
-  grub_int8_t clusters_per_index;
   grub_int8_t reserved_5[3];
+  grub_int8_t clusters_per_index;
+  grub_int8_t reserved_6[3];
   grub_uint64_t num_serial;
   grub_uint32_t checksum;
 } __attribute__ ((packed));