/* acorn.c - Read Linux/ADFS partition tables. */ /* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2005,2007 Free Software Foundation, Inc. * * VAS_EBOOT 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. * * VAS_EBOOT 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 VAS_EBOOT. If not, see . */ #include #include #include #include #include VAS_EBOOT_MOD_LICENSE ("GPLv3+"); #define LINUX_NATIVE_MAGIC VasEBoot_cpu_to_le32_compile_time (0xdeafa1de) #define LINUX_SWAP_MAGIC VasEBoot_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 VasEBoot_acorn_boot_block { union { struct { VasEBoot_uint8_t misc[0x1C0]; struct VasEBoot_filecore_disc_record disc_record; VasEBoot_uint8_t flags; VasEBoot_uint16_t start_cylinder; VasEBoot_uint8_t checksum; } VAS_EBOOT_PACKED; VasEBoot_uint8_t bin[0x200]; }; } VAS_EBOOT_PACKED; struct linux_part { VasEBoot_uint32_t magic; VasEBoot_uint32_t start; VasEBoot_uint32_t size; }; static struct VasEBoot_partition_map VasEBoot_acorn_partition_map; static VasEBoot_err_t acorn_partition_map_find (VasEBoot_disk_t disk, struct linux_part *m, VasEBoot_disk_addr_t *sector) { struct VasEBoot_acorn_boot_block boot; VasEBoot_err_t err; unsigned int checksum = 0; unsigned int heads; unsigned int sectors_per_cylinder; int i; err = VasEBoot_disk_read (disk, 0xC00 / VAS_EBOOT_DISK_SECTOR_SIZE, 0, sizeof (struct VasEBoot_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 ((VasEBoot_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 = VasEBoot_le_to_cpu16 (boot.start_cylinder) * sectors_per_cylinder; return VasEBoot_disk_read (disk, *sector, 0, sizeof (struct linux_part) * LINUX_MAP_ENTRIES, m); fail: return VasEBoot_error (VAS_EBOOT_ERR_BAD_PART_TABLE, "Linux/ADFS partition map not found"); } static VasEBoot_err_t acorn_partition_map_iterate (VasEBoot_disk_t disk, VasEBoot_partition_iterate_hook_t hook, void *hook_data) { struct VasEBoot_partition part; struct linux_part map[LINUX_MAP_ENTRIES]; int i; VasEBoot_disk_addr_t sector = 0; VasEBoot_err_t err; err = acorn_partition_map_find (disk, map, §or); if (err) return err; part.partmap = &VasEBoot_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 VAS_EBOOT_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 VasEBoot_errno; } return VAS_EBOOT_ERR_NONE; } /* Partition map type. */ static struct VasEBoot_partition_map VasEBoot_acorn_partition_map = { .name = "acorn", .iterate = acorn_partition_map_iterate, }; VAS_EBOOT_MOD_INIT(part_acorn) { VasEBoot_partition_map_register (&VasEBoot_acorn_partition_map); } VAS_EBOOT_MOD_FINI(part_acorn) { VasEBoot_partition_map_unregister (&VasEBoot_acorn_partition_map); }