summaryrefslogtreecommitdiffstats
path: root/grub-core/partmap/acorn.c
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/partmap/acorn.c')
-rw-r--r--grub-core/partmap/acorn.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/grub-core/partmap/acorn.c b/grub-core/partmap/acorn.c
new file mode 100644
index 0000000..c022c61
--- /dev/null
+++ b/grub-core/partmap/acorn.c
@@ -0,0 +1,154 @@
+/* acorn.c - Read Linux/ADFS partition tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007 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/misc.h>
+#include <grub/mm.h>
+#include <grub/partition.h>
+#include <grub/acorn_filecore.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define LINUX_NATIVE_MAGIC grub_cpu_to_le32_compile_time (0xdeafa1de)
+#define LINUX_SWAP_MAGIC grub_cpu_to_le32_compile_time (0xdeafab1e)
+#define LINUX_MAP_ENTRIES (512 / 12)
+
+#define NONADFS_PARTITION_TYPE_LINUX 9
+#define NONADFS_PARTITION_TYPE_MASK 15
+
+struct grub_acorn_boot_block
+{
+ union
+ {
+ struct
+ {
+ grub_uint8_t misc[0x1C0];
+ struct grub_filecore_disc_record disc_record;
+ grub_uint8_t flags;
+ grub_uint16_t start_cylinder;
+ grub_uint8_t checksum;
+ } GRUB_PACKED;
+ grub_uint8_t bin[0x200];
+ };
+} GRUB_PACKED;
+
+struct linux_part
+{
+ grub_uint32_t magic;
+ grub_uint32_t start;
+ grub_uint32_t size;
+};
+
+static struct grub_partition_map grub_acorn_partition_map;
+
+static grub_err_t
+acorn_partition_map_find (grub_disk_t disk, struct linux_part *m,
+ grub_disk_addr_t *sector)
+{
+ struct grub_acorn_boot_block boot;
+ grub_err_t err;
+ unsigned int checksum = 0;
+ unsigned int heads;
+ unsigned int sectors_per_cylinder;
+ int i;
+
+ err = grub_disk_read (disk, 0xC00 / GRUB_DISK_SECTOR_SIZE, 0,
+ sizeof (struct grub_acorn_boot_block),
+ &boot);
+ if (err)
+ return err;
+
+ if ((boot.flags & NONADFS_PARTITION_TYPE_MASK) != NONADFS_PARTITION_TYPE_LINUX)
+ goto fail;
+
+ for (i = 0; i != 0x1ff; ++i)
+ checksum = ((checksum & 0xff) + (checksum >> 8) + boot.bin[i]);
+
+ if ((grub_uint8_t) checksum != boot.checksum)
+ goto fail;
+
+ heads = (boot.disc_record.heads
+ + ((boot.disc_record.lowsector >> 6) & 1));
+ sectors_per_cylinder = boot.disc_record.secspertrack * heads;
+ *sector = grub_le_to_cpu16 (boot.start_cylinder) * sectors_per_cylinder;
+
+ return grub_disk_read (disk, *sector, 0,
+ sizeof (struct linux_part) * LINUX_MAP_ENTRIES,
+ m);
+
+fail:
+ return grub_error (GRUB_ERR_BAD_PART_TABLE,
+ "Linux/ADFS partition map not found");
+
+}
+
+
+static grub_err_t
+acorn_partition_map_iterate (grub_disk_t disk,
+ grub_partition_iterate_hook_t hook,
+ void *hook_data)
+{
+ struct grub_partition part;
+ struct linux_part map[LINUX_MAP_ENTRIES];
+ int i;
+ grub_disk_addr_t sector = 0;
+ grub_err_t err;
+
+ err = acorn_partition_map_find (disk, map, &sector);
+ if (err)
+ return err;
+
+ part.partmap = &grub_acorn_partition_map;
+
+ for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
+ {
+ if (map[i].magic != LINUX_NATIVE_MAGIC
+ && map[i].magic != LINUX_SWAP_MAGIC)
+ return GRUB_ERR_NONE;
+
+ part.start = sector + map[i].start;
+ part.len = map[i].size;
+ part.offset = 6;
+ part.number = part.index = i;
+
+ if (hook (disk, &part, hook_data))
+ return grub_errno;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+
+
+/* Partition map type. */
+static struct grub_partition_map grub_acorn_partition_map =
+{
+ .name = "acorn",
+ .iterate = acorn_partition_map_iterate,
+};
+
+GRUB_MOD_INIT(part_acorn)
+{
+ grub_partition_map_register (&grub_acorn_partition_map);
+}
+
+GRUB_MOD_FINI(part_acorn)
+{
+ grub_partition_map_unregister (&grub_acorn_partition_map);
+}