]> git.proxmox.com Git - grub2.git/blob - partmap/acorn.c
2005-11-22 Hollis Blanchard <hollis@penguinppc.org>
[grub2.git] / partmap / acorn.c
1 /* acorn.c - Read Linux/ADFS partition tables. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005 Free Software Foundation, Inc.
5 *
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <grub/disk.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/partition.h>
25 #include <grub/acorn_filecore.h>
26
27 #define LINUX_NATIVE_MAGIC grub_cpu_to_le32 (0xdeafa1de)
28 #define LINUX_SWAP_MAGIC grub_cpu_to_le32 (0xdeafab1e)
29 #define LINUX_MAP_ENTRIES (512 / 12)
30
31 #define NONADFS_PARTITON_TYPE_LINUX 9
32 #define NONADFS_PARTITON_TYPE_MASK 15
33
34 struct grub_acorn_boot_block
35 {
36 grub_uint8_t misc[0x1C0];
37 struct grub_filecore_disc_record disc_record;
38 grub_uint8_t flags;
39 grub_uint16_t start_cylinder;
40 grub_uint8_t checksum;
41 } __attribute__ ((packed, aligned));
42
43 struct linux_part
44 {
45 grub_uint32_t magic;
46 grub_uint32_t start;
47 grub_uint32_t size;
48 };
49
50 static struct grub_partition_map grub_acorn_partition_map;
51
52 static grub_err_t
53 acorn_partition_map_find (grub_disk_t disk, struct linux_part *m,
54 unsigned int *sector)
55 {
56 struct grub_acorn_boot_block boot;
57 grub_err_t err;
58 unsigned int checksum = 0;
59 unsigned int heads;
60 unsigned int sectors_per_cylinder;
61 int i;
62
63 err = grub_disk_read (disk, 0xC00 / GRUB_DISK_SECTOR_SIZE, 0,
64 sizeof (struct grub_acorn_boot_block),
65 (char *)&boot);
66 if (err)
67 return err;
68
69 if ((boot.flags & NONADFS_PARTITON_TYPE_MASK) != NONADFS_PARTITON_TYPE_LINUX)
70 goto fail;
71
72 for (i = 0; i != 0x1ff; ++i)
73 checksum = (checksum & 0xff) + (checksum >> 8) + boot.misc[i];
74
75 if ((grub_uint8_t) checksum != boot.checksum)
76 goto fail;
77
78 heads = (boot.disc_record.heads
79 + ((boot.disc_record.lowsector >> 6) & 1));
80 sectors_per_cylinder = boot.disc_record.secspertrack * heads;
81 *sector = grub_le_to_cpu16 (boot.start_cylinder) * sectors_per_cylinder;
82
83 return grub_disk_read (disk, *sector, 0,
84 sizeof (struct linux_part) * LINUX_MAP_ENTRIES,
85 (char *)m);
86
87 fail:
88 return grub_error (GRUB_ERR_BAD_PART_TABLE,
89 "Linux/ADFS partition map not found.");
90
91 }
92
93
94 static grub_err_t
95 acorn_partition_map_iterate (grub_disk_t disk,
96 int (*hook) (grub_disk_t disk,
97 const grub_partition_t partition))
98 {
99 struct grub_partition part;
100 struct grub_disk raw;
101 struct linux_part map[LINUX_MAP_ENTRIES];
102 int i;
103 unsigned int sector;
104 grub_err_t err;
105
106 /* Enforce raw disk access. */
107 raw = *disk;
108 raw.partition = 0;
109
110 err = acorn_partition_map_find (&raw, map, &sector);
111 if (err)
112 return err;
113
114 part.partmap = &grub_acorn_partition_map;
115
116 for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
117 {
118 if (map[i].magic != LINUX_NATIVE_MAGIC
119 && map[i].magic != LINUX_SWAP_MAGIC)
120 return GRUB_ERR_NONE;
121
122 part.start = (grub_disk_addr_t)sector + map[i].start;
123 part.len = map[i].size;
124 part.offset = 6;
125 part.index = i;
126
127 if (hook (disk, &part))
128 return grub_errno;
129 }
130
131 return GRUB_ERR_NONE;
132 }
133
134
135 static grub_partition_t
136 acorn_partition_map_probe (grub_disk_t disk, const char *str)
137 {
138 struct linux_part map[LINUX_MAP_ENTRIES];
139 struct grub_disk raw = *disk;
140 unsigned long partnum = grub_strtoul (str, 0, 10);
141 unsigned int sector;
142 grub_err_t err;
143
144 /* Enforce raw disk access. */
145 raw.partition = 0;
146
147 /* Get the partition number. */
148 if (partnum > LINUX_MAP_ENTRIES)
149 goto fail;
150
151 err = acorn_partition_map_find (&raw, map, &sector);
152 if (err)
153 return 0;
154
155 if (map[partnum].magic != LINUX_NATIVE_MAGIC
156 && map[partnum].magic != LINUX_SWAP_MAGIC)
157 goto fail;
158
159 grub_partition_t p = grub_malloc (sizeof (struct grub_partition));
160 if (!p)
161 return 0;
162
163 p->start = (grub_disk_addr_t)sector + map[partnum].start;
164 p->len = map[partnum].size;
165 p->offset = 6;
166 p->index = partnum;
167 return p;
168
169 fail:
170 grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
171 return 0;
172 }
173
174
175 static char *
176 acorn_partition_map_get_name (const grub_partition_t p)
177 {
178 char *name;
179
180 name = grub_malloc (13);
181 if (!name)
182 return 0;
183
184 grub_sprintf (name, "%d", p->index);
185 return name;
186 }
187 \f
188
189 /* Partition map type. */
190 static struct grub_partition_map grub_acorn_partition_map =
191 {
192 .name = "Linux/ADFS partition map",
193 .iterate = acorn_partition_map_iterate,
194 .probe = acorn_partition_map_probe,
195 .get_name = acorn_partition_map_get_name
196 };
197
198 GRUB_MOD_INIT(acorn_partition_map)
199 {
200 grub_partition_map_register (&grub_acorn_partition_map);
201 }
202
203 GRUB_MOD_FINI(acorn_partition_map)
204 {
205 grub_partition_map_unregister (&grub_acorn_partition_map);
206 }