a5bd9f6
From c545d0bb2fe87b5a8ea6a903e4e9c113595ccfff Mon Sep 17 00:00:00 2001
a5bd9f6
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
a5bd9f6
Date: Mon, 2 Jul 2012 11:28:42 +0200
a5bd9f6
Subject: [PATCH 007/364] 	* grub-core/fs/ext2.c: Experimental support
a5bd9f6
 for 64-bit.
a5bd9f6
a5bd9f6
---
a5bd9f6
 ChangeLog           |  4 ++++
a5bd9f6
 grub-core/fs/ext2.c | 56 +++++++++++++++++++++++++++++++++++++++++------------
a5bd9f6
 2 files changed, 48 insertions(+), 12 deletions(-)
a5bd9f6
a5bd9f6
diff --git a/ChangeLog b/ChangeLog
a5bd9f6
index 12de11f..93ad0ac 100644
a5bd9f6
--- a/ChangeLog
a5bd9f6
+++ b/ChangeLog
a5bd9f6
@@ -1,5 +1,9 @@
a5bd9f6
 2012-07-02  Vladimir Serbinenko  <phcoder@gmail.com>
a5bd9f6
 
a5bd9f6
+	* grub-core/fs/ext2.c: Experimental support for 64-bit.
a5bd9f6
+
a5bd9f6
+2012-07-02  Vladimir Serbinenko  <phcoder@gmail.com>
a5bd9f6
+
a5bd9f6
 	* grub-core/net/tftp.c (ack): Fix endianness problem.
a5bd9f6
 	(tftp_receive): Likewise.
a5bd9f6
 	Reported by: Michael Davidsaver.
a5bd9f6
diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
a5bd9f6
index c50e379..bd1ab24 100644
a5bd9f6
--- a/grub-core/fs/ext2.c
a5bd9f6
+++ b/grub-core/fs/ext2.c
a5bd9f6
@@ -65,7 +65,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
a5bd9f6
 
a5bd9f6
 /* The inode size.  */
a5bd9f6
 #define EXT2_INODE_SIZE(data)	\
a5bd9f6
-        (EXT2_REVISION (data) == EXT2_GOOD_OLD_REVISION \
a5bd9f6
+  (data->sblock.revision_level \
a5bd9f6
+   == grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION)	\
a5bd9f6
          ? EXT2_GOOD_OLD_INODE_SIZE \
a5bd9f6
          : grub_le_to_cpu16 (data->sblock.inode_size))
a5bd9f6
 
a5bd9f6
@@ -105,7 +106,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
a5bd9f6
  * flags here as the related features are implemented into the driver.  */
a5bd9f6
 #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
a5bd9f6
                                        | EXT4_FEATURE_INCOMPAT_EXTENTS  \
a5bd9f6
-                                       | EXT4_FEATURE_INCOMPAT_FLEX_BG )
a5bd9f6
+                                       | EXT4_FEATURE_INCOMPAT_FLEX_BG \
a5bd9f6
+                                       | EXT4_FEATURE_INCOMPAT_64BIT)
a5bd9f6
 /* List of rationales for the ignored "incompatible" features:
a5bd9f6
  * needs_recovery: Not really back-incompatible - was added as such to forbid
a5bd9f6
  *                 ext2 drivers from mounting an ext3 volume with a dirty
a5bd9f6
@@ -179,7 +181,7 @@ struct grub_ext2_sblock
a5bd9f6
   grub_uint32_t hash_seed[4];
a5bd9f6
   grub_uint8_t def_hash_version;
a5bd9f6
   grub_uint8_t jnl_backup_type;
a5bd9f6
-  grub_uint16_t reserved_word_pad;
a5bd9f6
+  grub_uint16_t group_desc_size;
a5bd9f6
   grub_uint32_t default_mount_opts;
a5bd9f6
   grub_uint32_t first_meta_bg;
a5bd9f6
   grub_uint32_t mkfs_time;
a5bd9f6
@@ -197,6 +199,14 @@ struct grub_ext2_block_group
a5bd9f6
   grub_uint16_t used_dirs;
a5bd9f6
   grub_uint16_t pad;
a5bd9f6
   grub_uint32_t reserved[3];
a5bd9f6
+  grub_uint32_t block_id_hi;
a5bd9f6
+  grub_uint32_t inode_id_hi;
a5bd9f6
+  grub_uint32_t inode_table_id_hi;
a5bd9f6
+  grub_uint16_t free_blocks_hi;
a5bd9f6
+  grub_uint16_t free_inodes_hi;
a5bd9f6
+  grub_uint16_t used_dirs_hi;
a5bd9f6
+  grub_uint16_t pad2;
a5bd9f6
+  grub_uint32_t reserved2[3];
a5bd9f6
 };
a5bd9f6
 
a5bd9f6
 /* The ext2 inode.  */
a5bd9f6
@@ -310,6 +320,7 @@ struct grub_fshelp_node
a5bd9f6
 struct grub_ext2_data
a5bd9f6
 {
a5bd9f6
   struct grub_ext2_sblock sblock;
a5bd9f6
+  int log_group_desc_size;
a5bd9f6
   grub_disk_t disk;
a5bd9f6
   struct grub_ext2_inode *inode;
a5bd9f6
   struct grub_fshelp_node diropen;
a5bd9f6
@@ -328,7 +339,7 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
a5bd9f6
   return grub_disk_read (data->disk,
a5bd9f6
                          ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1)
a5bd9f6
                           << LOG2_EXT2_BLOCK_SIZE (data)),
a5bd9f6
-			 group * sizeof (struct grub_ext2_block_group),
a5bd9f6
+			 group << data->log_group_desc_size,
a5bd9f6
 			 sizeof (struct grub_ext2_block_group), blkgrp);
a5bd9f6
 }
a5bd9f6
 
a5bd9f6
@@ -362,7 +373,7 @@ grub_ext4_find_leaf (struct grub_ext2_data *data, grub_properly_aligned_t *buf,
a5bd9f6
         return 0;
a5bd9f6
 
a5bd9f6
       block = grub_le_to_cpu16 (index[i].leaf_hi);
a5bd9f6
-      block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
a5bd9f6
+      block = (block << 32) | grub_le_to_cpu32 (index[i].leaf);
a5bd9f6
       if (grub_disk_read (data->disk,
a5bd9f6
                           block << LOG2_EXT2_BLOCK_SIZE (data),
a5bd9f6
                           0, EXT2_BLOCK_SIZE(data), buf))
a5bd9f6
@@ -377,11 +388,11 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
a5bd9f6
 {
a5bd9f6
   struct grub_ext2_data *data = node->data;
a5bd9f6
   struct grub_ext2_inode *inode = &node->inode;
a5bd9f6
-  int blknr = -1;
a5bd9f6
+  grub_disk_addr_t blknr = -1;
a5bd9f6
   unsigned int blksz = EXT2_BLOCK_SIZE (data);
a5bd9f6
   int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
a5bd9f6
 
a5bd9f6
-  if (grub_le_to_cpu32(inode->flags) & EXT4_EXTENTS_FLAG)
a5bd9f6
+  if (inode->flags & grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG))
a5bd9f6
     {
a5bd9f6
       GRUB_PROPERLY_ALIGNED_ARRAY (buf, EXT2_BLOCK_SIZE(data));
a5bd9f6
       struct grub_ext4_extent_header *leaf;
a5bd9f6
@@ -535,6 +546,7 @@ grub_ext2_read_inode (struct grub_ext2_data *data,
a5bd9f6
   int inodes_per_block;
a5bd9f6
   unsigned int blkno;
a5bd9f6
   unsigned int blkoff;
a5bd9f6
+  grub_disk_addr_t base;
a5bd9f6
 
a5bd9f6
   /* It is easier to calculate if the first inode is 0.  */
a5bd9f6
   ino--;
a5bd9f6
@@ -551,10 +563,14 @@ grub_ext2_read_inode (struct grub_ext2_data *data,
a5bd9f6
   blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group))
a5bd9f6
     % inodes_per_block;
a5bd9f6
 
a5bd9f6
+  base = grub_le_to_cpu32 (blkgrp.inode_table_id);
a5bd9f6
+  if (data->log_group_desc_size >= 6)
a5bd9f6
+    base |= (((grub_disk_addr_t) grub_le_to_cpu32 (blkgrp.inode_table_id_hi))
a5bd9f6
+	     << 32);
a5bd9f6
+
a5bd9f6
   /* Read the inode.  */
a5bd9f6
   if (grub_disk_read (data->disk,
a5bd9f6
-		      (((grub_disk_addr_t) grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno)
a5bd9f6
-		        << LOG2_EXT2_BLOCK_SIZE (data)),
a5bd9f6
+		      ((base + blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
a5bd9f6
 		      EXT2_INODE_SIZE (data) * blkoff,
a5bd9f6
 		      sizeof (struct grub_ext2_inode), inode))
a5bd9f6
     return grub_errno;
a5bd9f6
@@ -578,7 +594,7 @@ grub_ext2_mount (grub_disk_t disk)
a5bd9f6
     goto fail;
a5bd9f6
 
a5bd9f6
   /* Make sure this is an ext2 filesystem.  */
a5bd9f6
-  if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC
a5bd9f6
+  if (data->sblock.magic != grub_cpu_to_le16_compile_time (EXT2_MAGIC)
a5bd9f6
       || grub_le_to_cpu32 (data->sblock.log2_block_size) >= 16)
a5bd9f6
     {
a5bd9f6
       grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem");
a5bd9f6
@@ -586,13 +602,29 @@ grub_ext2_mount (grub_disk_t disk)
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
   /* Check the FS doesn't have feature bits enabled that we don't support. */
a5bd9f6
-  if (grub_le_to_cpu32 (data->sblock.feature_incompat)
a5bd9f6
-        & ~(EXT2_DRIVER_SUPPORTED_INCOMPAT | EXT2_DRIVER_IGNORED_INCOMPAT))
a5bd9f6
+  if (data->sblock.revision_level != grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION)
a5bd9f6
+      && (data->sblock.feature_incompat
a5bd9f6
+	  & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT
a5bd9f6
+					     | EXT2_DRIVER_IGNORED_INCOMPAT))))
a5bd9f6
     {
a5bd9f6
       grub_error (GRUB_ERR_BAD_FS, "filesystem has unsupported incompatible features");
a5bd9f6
       goto fail;
a5bd9f6
     }
a5bd9f6
 
a5bd9f6
+  if (data->sblock.revision_level != grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION)
a5bd9f6
+      && (data->sblock.feature_incompat
a5bd9f6
+	  & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT))
a5bd9f6
+      && data->sblock.group_desc_size != 0
a5bd9f6
+      && ((data->sblock.group_desc_size & (data->sblock.group_desc_size - 1))
a5bd9f6
+	  == 0)
a5bd9f6
+      && (data->sblock.group_desc_size & grub_cpu_to_le16_compile_time (0x1fe0)))
a5bd9f6
+    {
a5bd9f6
+      grub_uint16_t b = grub_le_to_cpu16 (data->sblock.group_desc_size);
a5bd9f6
+      for (data->log_group_desc_size = 0; b != (1 << data->log_group_desc_size);
a5bd9f6
+	   data->log_group_desc_size++);
a5bd9f6
+    }
a5bd9f6
+  else
a5bd9f6
+    data->log_group_desc_size = 5;
a5bd9f6
 
a5bd9f6
   data->disk = disk;
a5bd9f6
 
a5bd9f6
-- 
a5bd9f6
1.8.1.4
a5bd9f6