1 //==========================================================================
5 // RedBoot disk support
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
12 // Copyright (C) 2002 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: msalter
50 // This code is part of RedBoot (tm).
52 //####DESCRIPTIONEND####
54 //==========================================================================
59 #ifdef CYGSEM_REDBOOT_DISK_EXT2FS
62 #ifdef CYGSEM_REDBOOT_DISK_ISO9660
63 #include <fs/iso9660fs.h>
66 static void do_disks(int argc, char *argv[]);
69 "Display disks/partitions.",
74 static disk_t disk_table[CYGNUM_REDBOOT_MAX_DISKS];
75 static int disk_count = 0;
77 static inline cyg_uint32
78 u32_unaligned(void *p)
81 char *d = (char *)&val;
85 for (i = 0; i < 4; i++)
92 find_dos_partitions(disk_t *d, cyg_uint8 *mbr)
95 struct mbr_partition *p;
98 p = (struct mbr_partition *)(mbr + MBR_PTABLE_OFFSET);
100 // Look for primary partitions
101 for (i = 0; i < 4 && i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
103 s = SWAB_LE32(u32_unaligned(p->start_sect));
104 n = SWAB_LE32(u32_unaligned(p->nr_sects));
108 d->partitions[i].disk = d;
109 d->partitions[i].start_sector = s;
110 d->partitions[i].nr_sectors = n;
111 d->partitions[i].systype = p->sys_ind;
112 d->partitions[i].bootflag = p->boot_ind;
117 #if CYGNUM_REDBOOT_MAX_PARTITIONS > 4
119 cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], xoffset;
123 // Go back through and find extended partitions
124 for (i = 0, nextp = 4; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
125 if (d->partitions[i].systype == SYSTYPE_EXTENDED) {
126 // sector offsets in partition tables are relative to start
127 // of extended partition.
128 xoffset = d->partitions[i].start_sector;
129 for ( ; nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; ++nextp) {
131 // read partition boot record (same format as mbr except
132 // there should only be 2 entries max: a normal partition
133 // and another extended partition
134 if (DISK_READ(d, xoffset, buf, 1) <= 0)
137 magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
138 if (SWAB_LE16(magic) != MBR_MAGIC)
141 p = (struct mbr_partition *)((char *)buf + MBR_PTABLE_OFFSET);
143 s = SWAB_LE32(u32_unaligned(p->start_sect));
144 n = SWAB_LE32(u32_unaligned(p->nr_sects));
148 d->partitions[nextp].disk = d;
149 d->partitions[nextp].start_sector = s + xoffset;
150 d->partitions[nextp].nr_sectors = n;
151 d->partitions[nextp].systype = p->sys_ind;
152 d->partitions[nextp].bootflag = p->boot_ind;
156 s = SWAB_LE32(u32_unaligned(p->start_sect));
157 n = SWAB_LE32(u32_unaligned(p->nr_sects));
159 // more extended partitions?
160 if (p->sys_ind != SYSTYPE_EXTENDED || !s || !n)
173 // Find partitions on given disk.
174 // Return number of partitions found
176 find_partitions(disk_t *d)
178 cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)];
184 if (d->kind == DISK_IDE_CDROM) {
185 #ifdef CYGSEM_REDBOOT_DISK_ISO9660
186 // no partition table, so fake it
190 p->nr_sectors = d->nr_sectors;
191 p->funs = &redboot_iso9660fs_funs;
198 // read Master Boot Record
199 if (DISK_READ(d, 0, buf, 1) <= 0)
203 magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
204 if (SWAB_LE16(magic) == MBR_MAGIC) {
205 found = find_dos_partitions(d, (cyg_uint8 *)buf);
207 // Might want to handle other MBR types, here...
210 // Now go through all partitions and install the correct
211 // funcs for supported filesystems.
212 for (i = 0, p = d->partitions; i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++, p++) {
213 switch (p->systype) {
214 #ifdef CYGSEM_REDBOOT_DISK_EXT2FS
216 p->funs = &redboot_e2fs_funs;
219 #ifdef CYGSEM_REDBOOT_DISK_FAT16
221 p->funs = &redboot_fat16_funs;
224 #ifdef CYGSEM_REDBOOT_DISK_FAT32
226 p->funs = &redboot_fat32_funs;
230 break; // ignore unsupported filesystems
237 // Add a disk to the disk table.
238 // Return zero if no more room in table.
240 disk_register(disk_t *d)
244 // make sure we have room for it
245 if (disk_count >= CYGNUM_REDBOOT_MAX_DISKS)
250 for (i = 0; i < disk_count; i++)
251 if (disk_table[i].kind == d->kind)
254 // put it in the table
255 disk_table[disk_count] = *d;
257 // fill in partition info
258 find_partitions(&disk_table[disk_count++]);
263 // Convert a filename in the form <partition_name>:<filename> into
264 // a partition and path.
267 disk_parse_filename(const char *name, partition_t **part, const char **path)
269 int i, kind, index, pindex;
271 kind = index = pindex = 0;
273 if (name[0] == 'h' && name[1] == 'd') {
276 if (name[2] < 'a' || name[2] > 'z')
278 index = name[2] - 'a';
279 if (name[3] < '1' || name[3] >= ('1' + CYGNUM_REDBOOT_MAX_PARTITIONS))
281 pindex = name[3] - '1';
286 #ifdef CYGSEM_REDBOOT_DISK_ISO9660
287 else if (name[0] == 'c' && name[1] == 'd') {
289 kind = DISK_IDE_CDROM;
290 if (name[2] < '0' || name[2] > '9')
292 index = name[2] - '0';
300 for (i = 0; i < CYGNUM_REDBOOT_MAX_DISKS; i++) {
301 if (disk_table[i].kind == kind && disk_table[i].index == index) {
302 *part = &disk_table[i].partitions[pindex];
310 static const struct {
313 } systype_names[] = {
314 { SYSTYPE_FAT12, "FAT12" },
315 { SYSTYPE_FAT16_32M, "FAT16 <32M" },
316 { SYSTYPE_FAT16, "FAT16" },
317 { SYSTYPE_EXTENDED, "Extended" },
318 { SYSTYPE_LINUX_SWAP, "Linux Swap" },
319 { SYSTYPE_LINUX, "Linux" }
323 systype_name(int systype)
327 for (i = 0; i < sizeof(systype_names)/sizeof(systype_names[0]); i++)
328 if (systype_names[i].kind == systype)
329 return systype_names[i].str;
333 // List disk partitions
335 do_disks(int argc, char *argv[])
342 for (i = 0, d = disk_table; i < disk_count; i++, d++) {
345 for (j = 0, p = d->partitions;
346 j < CYGNUM_REDBOOT_MAX_PARTITIONS;
349 diag_sprintf(name, "hd%c%d", 'a' + d->index, j+1);
350 diag_printf("%-8s %s\n", name, systype_name(p->systype));
355 diag_sprintf(name, "cd%d", d->index);
356 diag_printf("%-8s ISO9660\n", name);
362 static void *fileptr;
363 static partition_t *file_part;
366 disk_stream_open(connection_info_t *info, int *err)
368 const char *filepath;
369 char *filename = info->filename;
371 // The filename is in <disk>:<path> format.
372 // Convert to a partition and path.
373 if (!disk_parse_filename(filename, &file_part, &filepath)) {
374 *err = diskerr_badname;
378 if (file_part->disk->kind != DISK_IDE_CDROM && file_part->systype == 0) {
379 *err = diskerr_partition;
383 if (file_part->funs == (fs_funs_t *)0) {
384 *err = diskerr_partition;
388 fileptr = (file_part->funs->open)(file_part, filepath);
389 if (fileptr == NULL) {
397 disk_stream_read(char *buf, int size, int *err)
401 if ((nread = (file_part->funs->read)(fileptr, buf, size)) < 0) {
409 disk_stream_close(int *err)
418 case diskerr_badname:
419 return "Bad filename";
421 case diskerr_partition:
422 return "Unsupported filesystem";
425 return "Can't open file";
428 return "Can't read file";
431 return "Unknown error";
439 GETC_IO_FUNCS(disk_io, disk_stream_open, disk_stream_close,
440 0, disk_stream_read, disk_error);
441 RedBoot_load(disk, disk_io, true, true, 0);