acorn.c 3.8 KB
Newer Older
1 2 3
/* acorn.c - Read Linux/ADFS partition tables.  */
/*
 *  GRUB  --  GRand Unified Bootloader
4
 *  Copyright (C) 2005,2007  Free Software Foundation, Inc.
5
 *
6
 *  GRUB is free software: you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation, either version 3 of the License, or
9 10
 *  (at your option) any later version.
 *
11
 *  GRUB is distributed in the hope that it will be useful,
12 13 14 15 16
 *  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
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18 19 20 21 22 23 24 25
 */

#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/partition.h>
#include <grub/acorn_filecore.h>

26 27
GRUB_MOD_LICENSE ("GPLv3+");

28 29
#define LINUX_NATIVE_MAGIC grub_cpu_to_le32_compile_time (0xdeafa1de)
#define LINUX_SWAP_MAGIC   grub_cpu_to_le32_compile_time (0xdeafab1e)
30 31
#define LINUX_MAP_ENTRIES  (512 / 12)

32 33
#define NONADFS_PARTITION_TYPE_LINUX 9
#define NONADFS_PARTITION_TYPE_MASK 15
34 35 36

struct grub_acorn_boot_block
{
37 38 39 40 41 42 43 44 45
  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;
46
    } GRUB_PACKED;
47 48
    grub_uint8_t bin[0x200];
  };
49
} GRUB_PACKED;
50 51 52 53 54 55 56 57 58 59 60

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
61
acorn_partition_map_find (grub_disk_t disk, struct linux_part *m,
62
			  grub_disk_addr_t *sector)
63 64
{
  struct grub_acorn_boot_block boot;
65 66 67 68 69 70 71
  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,
72
			sizeof (struct grub_acorn_boot_block),
73
			&boot);
74 75 76
  if (err)
    return err;

77
  if ((boot.flags & NONADFS_PARTITION_TYPE_MASK) != NONADFS_PARTITION_TYPE_LINUX)
78 79 80
    goto fail;

  for (i = 0; i != 0x1ff; ++i)
81
    checksum = ((checksum & 0xff) + (checksum >> 8) + boot.bin[i]);
82 83 84 85

  if ((grub_uint8_t) checksum != boot.checksum)
    goto fail;

86
  heads = (boot.disc_record.heads
87
		    + ((boot.disc_record.lowsector >> 6) & 1));
88
  sectors_per_cylinder = boot.disc_record.secspertrack * heads;
89 90 91
  *sector = grub_le_to_cpu16 (boot.start_cylinder) * sectors_per_cylinder;

  return grub_disk_read (disk, *sector, 0,
92
			 sizeof (struct linux_part) * LINUX_MAP_ENTRIES,
93
			 m);
94 95 96

fail:
  return grub_error (GRUB_ERR_BAD_PART_TABLE,
97
		     "Linux/ADFS partition map not found");
98 99 100 101 102 103

}


static grub_err_t
acorn_partition_map_iterate (grub_disk_t disk,
104 105
			     grub_partition_iterate_hook_t hook,
			     void *hook_data)
106 107 108
{
  struct grub_partition part;
  struct linux_part map[LINUX_MAP_ENTRIES];
109
  int i;
110
  grub_disk_addr_t sector = 0;
111
  grub_err_t err;
112

113
  err = acorn_partition_map_find (disk, map, &sector);
114 115 116 117 118 119 120 121 122 123 124
  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;

125
      part.start = sector + map[i].start;
126 127
      part.len = map[i].size;
      part.offset = 6;
128
      part.number = part.index = i;
129

130
      if (hook (disk, &part, hook_data))
131 132 133 134 135 136 137 138 139 140 141
	return grub_errno;
    }

  return GRUB_ERR_NONE;
}



/* Partition map type.  */
static struct grub_partition_map grub_acorn_partition_map =
{
142
  .name = "acorn",
143 144 145
  .iterate = acorn_partition_map_iterate,
};

146
GRUB_MOD_INIT(part_acorn)
147 148 149 150
{
  grub_partition_map_register (&grub_acorn_partition_map);
}

151
GRUB_MOD_FINI(part_acorn)
152 153 154
{
  grub_partition_map_unregister (&grub_acorn_partition_map);
}