]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Move grub_disk_write out of kernel into disk.mod.
authorVladimir Serbinenko <phcoder@gmail.com>
Sun, 27 Oct 2013 14:44:55 +0000 (15:44 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Sun, 27 Oct 2013 14:44:55 +0000 (15:44 +0100)
ChangeLog
Makefile.util.def
grub-core/Makefile.core.def
grub-core/disk/cryptodisk.c
grub-core/kern/disk.c
grub-core/kern/disk_common.c [new file with mode: 0644]
grub-core/lib/disk.c [new file with mode: 0644]
include/grub/disk.h

index 7ce7c3a0c2d8db686e06f4889a9c9fd05f708624..46e3cce73f1dbebbb22ed32826b827aa7c67a261 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-10-27  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Move grub_disk_write out of kernel into disk.mod.
+
 2013-10-27  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/kern/misc.c (grub_vsnprintf_real): Unify int and wchar
index 193bc4531d69ec04951bf448841fed95805b5261..2c38b53dd76876dfe96bc47d6c6f9dc425e47723 100644 (file)
@@ -9,6 +9,7 @@ library = {
   common = grub-core/kern/command.c;
   common = grub-core/kern/device.c;
   common = grub-core/kern/disk.c;
+  common = grub-core/lib/disk.c;
   common = util/getroot.c;
   common = grub-core/osdep/unix/getroot.c;
   common = grub-core/osdep/getroot.c;
index abd54bae4e09f013139447606bf6dcdd2b49d53d..2fb1cc9447159192b7a1918e9cae93939cb812c3 100644 (file)
@@ -455,6 +455,11 @@ image = {
   enable = mips_loongson;
 };
 
+module = {
+  name = disk;
+  common = lib/disk.c;
+};
+
 module = {
   name = trig;
   common_nodist = trigtables.c;
index 5856dfffa45e75f5af6dc1a8076a4865ae056798..673101001573ebe885fdd93ebb2974616a89a1b7 100644 (file)
@@ -631,10 +631,16 @@ grub_cryptodisk_write (grub_disk_t disk, grub_disk_addr_t sector,
       return grub_crypto_gcry_error (gcry_err);
     }
 
-  err = grub_disk_write (dev->source_disk,
-                         (sector << (disk->log_sector_size
-                                     - GRUB_DISK_SECTOR_BITS)) + dev->offset,
-                         0, size << disk->log_sector_size, tmp);
+  /* Since ->write was called so disk.mod is loaded but be paranoid  */
+  
+  if (grub_disk_write_weak)
+    err = grub_disk_write_weak (dev->source_disk,
+                               (sector << (disk->log_sector_size
+                                           - GRUB_DISK_SECTOR_BITS))
+                               + dev->offset,
+                               0, size << disk->log_sector_size, tmp);
+  else
+    err = grub_error (GRUB_ERR_BUG, "disk.mod not loaded");
   grub_free (tmp);
   return err;
 }
index b0b2715124b1b44217dbc4b520c2bd9a37ec7ee4..1d0a11cb2e2442109dfb8118fb9fdae65906fb26 100644 (file)
 /* The last time the disk was used.  */
 static grub_uint64_t grub_last_time = 0;
 
-
-/* Disk cache.  */
-struct grub_disk_cache
-{
-  enum grub_disk_dev_id dev_id;
-  unsigned long disk_id;
-  grub_disk_addr_t sector;
-  char *data;
-  int lock;
-};
-
-static struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
+struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
 
 void (*grub_disk_firmware_fini) (void);
 int grub_disk_firmware_is_tainted;
@@ -59,35 +48,12 @@ grub_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
 }
 #endif
 
-static unsigned
-grub_disk_cache_get_index (unsigned long dev_id, unsigned long disk_id,
-                          grub_disk_addr_t sector)
-{
-  return ((dev_id * 524287UL + disk_id * 2606459UL
-          + ((unsigned) (sector >> GRUB_DISK_CACHE_BITS)))
-         % GRUB_DISK_CACHE_NUM);
-}
-
-static void
-grub_disk_cache_invalidate (unsigned long dev_id, unsigned long disk_id,
-                           grub_disk_addr_t sector)
-{
-  unsigned cache_index;
-  struct grub_disk_cache *cache;
-
-  sector &= ~(GRUB_DISK_CACHE_SIZE - 1);
-  cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
-  cache = grub_disk_cache_table + cache_index;
-
-  if (cache->dev_id == dev_id && cache->disk_id == disk_id
-      && cache->sector == sector && cache->data)
-    {
-      cache->lock = 1;
-      grub_free (cache->data);
-      cache->data = 0;
-      cache->lock = 0;
-    }
-}
+grub_err_t (*grub_disk_write_weak) (grub_disk_t disk,
+                                   grub_disk_addr_t sector,
+                                   grub_off_t offset,
+                                   grub_size_t size,
+                                   const void *buf);
+#include "disk_common.c"
 
 void
 grub_disk_cache_invalidate_all (void)
@@ -341,53 +307,6 @@ grub_disk_close (grub_disk_t disk)
   grub_free (disk);
 }
 
-/* This function performs three tasks:
-   - Make sectors disk relative from partition relative.
-   - Normalize offset to be less than the sector size.
-   - Verify that the range is inside the partition.  */
-static grub_err_t
-grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-                       grub_off_t *offset, grub_size_t size)
-{
-  grub_partition_t part;
-  *sector += *offset >> GRUB_DISK_SECTOR_BITS;
-  *offset &= GRUB_DISK_SECTOR_SIZE - 1;
-
-  for (part = disk->partition; part; part = part->parent)
-    {
-      grub_disk_addr_t start;
-      grub_uint64_t len;
-
-      start = part->start;
-      len = part->len;
-
-      if (*sector >= len
-         || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
-                             >> GRUB_DISK_SECTOR_BITS))
-       return grub_error (GRUB_ERR_OUT_OF_RANGE,
-                          N_("attempt to read or write outside of partition"));
-
-      *sector += start;
-    }
-
-  if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN
-      && ((disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) <= *sector
-         || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
-         >> GRUB_DISK_SECTOR_BITS) > (disk->total_sectors
-                                      << (disk->log_sector_size
-                                          - GRUB_DISK_SECTOR_BITS)) - *sector))
-    return grub_error (GRUB_ERR_OUT_OF_RANGE,
-                      N_("attempt to read or write outside of disk `%s'"), disk->name);
-
-  return GRUB_ERR_NONE;
-}
-
-static inline grub_disk_addr_t
-transform_sector (grub_disk_t disk, grub_disk_addr_t sector)
-{
-  return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
-}
-
 /* Small read (less than cache size and not pass across cache unit boundaries).
    sector is already adjusted and is divisible by cache unit size.
  */
@@ -613,98 +532,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
   return grub_errno;
 }
 
-grub_err_t
-grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
-                grub_off_t offset, grub_size_t size, const void *buf)
-{
-  unsigned real_offset;
-  grub_disk_addr_t aligned_sector;
-
-  grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
-
-  if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
-    return -1;
-
-  aligned_sector = (sector & ~((1 << (disk->log_sector_size
-                                     - GRUB_DISK_SECTOR_BITS)) - 1));
-  real_offset = offset + ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
-  sector = aligned_sector;
-
-  while (size)
-    {
-      if (real_offset != 0 || (size < (1U << disk->log_sector_size)
-                              && size != 0))
-       {
-         char *tmp_buf;
-         grub_size_t len;
-         grub_partition_t part;
-
-         tmp_buf = grub_malloc (1 << disk->log_sector_size);
-         if (!tmp_buf)
-           return grub_errno;
-
-         part = disk->partition;
-         disk->partition = 0;
-         if (grub_disk_read (disk, sector,
-                             0, (1 << disk->log_sector_size), tmp_buf)
-             != GRUB_ERR_NONE)
-           {
-             disk->partition = part;
-             grub_free (tmp_buf);
-             goto finish;
-           }
-         disk->partition = part;
-
-         len = (1 << disk->log_sector_size) - real_offset;
-         if (len > size)
-           len = size;
-
-         grub_memcpy (tmp_buf + real_offset, buf, len);
-
-         grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
-
-         if ((disk->dev->write) (disk, transform_sector (disk, sector),
-                                 1, tmp_buf) != GRUB_ERR_NONE)
-           {
-             grub_free (tmp_buf);
-             goto finish;
-           }
-
-         grub_free (tmp_buf);
-
-         sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
-         buf = (const char *) buf + len;
-         size -= len;
-         real_offset = 0;
-       }
-      else
-       {
-         grub_size_t len;
-         grub_size_t n;
-
-         len = size & ~((1 << disk->log_sector_size) - 1);
-         n = size >> disk->log_sector_size;
-
-         if ((disk->dev->write) (disk, transform_sector (disk, sector),
-                                 n, buf) != GRUB_ERR_NONE)
-           goto finish;
-
-         while (n--)
-           {
-             grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
-             sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
-           }
-
-         buf = (const char *) buf + len;
-         size -= len;
-       }
-    }
-
- finish:
-
-  return grub_errno;
-}
-
 grub_uint64_t
 grub_disk_get_size (grub_disk_t disk)
 {
diff --git a/grub-core/kern/disk_common.c b/grub-core/kern/disk_common.c
new file mode 100644 (file)
index 0000000..fb19778
--- /dev/null
@@ -0,0 +1,55 @@
+/* This function performs three tasks:
+   - Make sectors disk relative from partition relative.
+   - Normalize offset to be less than the sector size.
+   - Verify that the range is inside the partition.  */
+static grub_err_t
+grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
+                       grub_off_t *offset, grub_size_t size)
+{
+  grub_partition_t part;
+  *sector += *offset >> GRUB_DISK_SECTOR_BITS;
+  *offset &= GRUB_DISK_SECTOR_SIZE - 1;
+
+  for (part = disk->partition; part; part = part->parent)
+    {
+      grub_disk_addr_t start;
+      grub_uint64_t len;
+
+      start = part->start;
+      len = part->len;
+
+      if (*sector >= len
+         || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+                             >> GRUB_DISK_SECTOR_BITS))
+       return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                          N_("attempt to read or write outside of partition"));
+
+      *sector += start;
+    }
+
+  if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN
+      && ((disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) <= *sector
+         || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+         >> GRUB_DISK_SECTOR_BITS) > (disk->total_sectors
+                                      << (disk->log_sector_size
+                                          - GRUB_DISK_SECTOR_BITS)) - *sector))
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+                      N_("attempt to read or write outside of disk `%s'"), disk->name);
+
+  return GRUB_ERR_NONE;
+}
+
+static inline grub_disk_addr_t
+transform_sector (grub_disk_t disk, grub_disk_addr_t sector)
+{
+  return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+}
+
+static unsigned
+grub_disk_cache_get_index (unsigned long dev_id, unsigned long disk_id,
+                          grub_disk_addr_t sector)
+{
+  return ((dev_id * 524287UL + disk_id * 2606459UL
+          + ((unsigned) (sector >> GRUB_DISK_CACHE_BITS)))
+         % GRUB_DISK_CACHE_NUM);
+}
diff --git a/grub-core/lib/disk.c b/grub-core/lib/disk.c
new file mode 100644 (file)
index 0000000..9527e29
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/disk.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+#include <grub/partition.h>
+#include <grub/misc.h>
+#include <grub/time.h>
+#include <grub/file.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#include "../kern/disk_common.c"
+
+static void
+grub_disk_cache_invalidate (unsigned long dev_id, unsigned long disk_id,
+                           grub_disk_addr_t sector)
+{
+  unsigned cache_index;
+  struct grub_disk_cache *cache;
+
+  sector &= ~(GRUB_DISK_CACHE_SIZE - 1);
+  cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+  cache = grub_disk_cache_table + cache_index;
+
+  if (cache->dev_id == dev_id && cache->disk_id == disk_id
+      && cache->sector == sector && cache->data)
+    {
+      cache->lock = 1;
+      grub_free (cache->data);
+      cache->data = 0;
+      cache->lock = 0;
+    }
+}
+
+grub_err_t
+grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
+                grub_off_t offset, grub_size_t size, const void *buf)
+{
+  unsigned real_offset;
+  grub_disk_addr_t aligned_sector;
+
+  grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
+
+  if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
+    return -1;
+
+  aligned_sector = (sector & ~((1 << (disk->log_sector_size
+                                     - GRUB_DISK_SECTOR_BITS)) - 1));
+  real_offset = offset + ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
+  sector = aligned_sector;
+
+  while (size)
+    {
+      if (real_offset != 0 || (size < (1U << disk->log_sector_size)
+                              && size != 0))
+       {
+         char *tmp_buf;
+         grub_size_t len;
+         grub_partition_t part;
+
+         tmp_buf = grub_malloc (1 << disk->log_sector_size);
+         if (!tmp_buf)
+           return grub_errno;
+
+         part = disk->partition;
+         disk->partition = 0;
+         if (grub_disk_read (disk, sector,
+                             0, (1 << disk->log_sector_size), tmp_buf)
+             != GRUB_ERR_NONE)
+           {
+             disk->partition = part;
+             grub_free (tmp_buf);
+             goto finish;
+           }
+         disk->partition = part;
+
+         len = (1 << disk->log_sector_size) - real_offset;
+         if (len > size)
+           len = size;
+
+         grub_memcpy (tmp_buf + real_offset, buf, len);
+
+         grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
+
+         if ((disk->dev->write) (disk, transform_sector (disk, sector),
+                                 1, tmp_buf) != GRUB_ERR_NONE)
+           {
+             grub_free (tmp_buf);
+             goto finish;
+           }
+
+         grub_free (tmp_buf);
+
+         sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
+         buf = (const char *) buf + len;
+         size -= len;
+         real_offset = 0;
+       }
+      else
+       {
+         grub_size_t len;
+         grub_size_t n;
+
+         len = size & ~((1 << disk->log_sector_size) - 1);
+         n = size >> disk->log_sector_size;
+
+         if ((disk->dev->write) (disk, transform_sector (disk, sector),
+                                 n, buf) != GRUB_ERR_NONE)
+           goto finish;
+
+         while (n--)
+           {
+             grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
+             sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
+           }
+
+         buf = (const char *) buf + len;
+         size -= len;
+       }
+    }
+
+ finish:
+
+  return grub_errno;
+}
+
+GRUB_MOD_INIT(disk)
+{
+  grub_disk_write_weak = grub_disk_write;
+}
+
+GRUB_MOD_FINI(disk)
+{
+  grub_disk_write_weak = NULL;
+}
index bf21473ca6f7af99d280d52f148ab39ee041bc10..42d170e3190eee8499013bd6bdaee86674aa7829 100644 (file)
@@ -193,11 +193,17 @@ grub_err_t EXPORT_FUNC(grub_disk_read) (grub_disk_t disk,
                                        grub_off_t offset,
                                        grub_size_t size,
                                        void *buf);
-grub_err_t EXPORT_FUNC(grub_disk_write) (grub_disk_t disk,
-                                        grub_disk_addr_t sector,
-                                        grub_off_t offset,
-                                        grub_size_t size,
-                                        const void *buf);
+grub_err_t grub_disk_write (grub_disk_t disk,
+                           grub_disk_addr_t sector,
+                           grub_off_t offset,
+                           grub_size_t size,
+                           const void *buf);
+extern grub_err_t (*EXPORT_VAR(grub_disk_write_weak)) (grub_disk_t disk,
+                                                      grub_disk_addr_t sector,
+                                                      grub_off_t offset,
+                                                      grub_size_t size,
+                                                      const void *buf);
+
 
 grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk);
 
@@ -221,6 +227,18 @@ grub_stop_disk_firmware (void)
     }
 }
 
+/* Disk cache.  */
+struct grub_disk_cache
+{
+  enum grub_disk_dev_id dev_id;
+  unsigned long disk_id;
+  grub_disk_addr_t sector;
+  char *data;
+  int lock;
+};
+
+extern struct grub_disk_cache EXPORT_VAR(grub_disk_cache_table)[GRUB_DISK_CACHE_NUM];
+
 #if defined (GRUB_UTIL)
 void grub_lvm_init (void);
 void grub_ldm_init (void);