📄 disk.c
字号:
//==========================================================================
//
// disk.c
//
// RedBoot disk support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Gary Thomas
//
// eCos 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 2 or (at your option) any later version.
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): msalter
// Contributors: msalter
// Date: 2001-07-14
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <redboot.h>
#include <fs/disk.h>
#ifdef CYGSEM_REDBOOT_DISK_EXT2FS
#include <fs/e2fs.h>
#endif
#ifdef CYGSEM_REDBOOT_DISK_ISO9660
#include <fs/iso9660fs.h>
#endif
static void do_disks(int argc, char *argv[]);
RedBoot_cmd("disks",
"Display disks/partitions.",
"",
do_disks
);
static disk_t disk_table[CYGNUM_REDBOOT_MAX_DISKS];
static int disk_count = 0;
static int
find_dos_partitions(disk_t *d, cyg_uint8 *mbr)
{
cyg_uint32 s, n, tmp;
struct mbr_partition *p;
int i, found = 0;
p = (struct mbr_partition *)(mbr + MBR_PTABLE_OFFSET);
// Look for primary partitions
for (i = 0; i < 4 && i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
// Have to use memcpy because of alignment
memcpy(&tmp, p->start_sect, 4);
s = SWAB_LE32(tmp);
memcpy(&tmp, p->nr_sects, 4);
n = SWAB_LE32(tmp);
if (s && n) {
++found;
d->partitions[i].disk = d;
d->partitions[i].start_sector = s;
d->partitions[i].nr_sectors = n;
d->partitions[i].systype = p->sys_ind;
d->partitions[i].bootflag = p->boot_ind;
}
p++;
}
#if CYGNUM_REDBOOT_MAX_PARTITIONS > 4
{
cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], xoffset;
cyg_uint16 magic;
int nextp;
// Go back through and find extended partitions
for (i = 0, nextp = 4; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
if (d->partitions[i].systype == SYSTYPE_EXTENDED) {
// sector offsets in partition tables are relative to start
// of extended partition.
xoffset = d->partitions[i].start_sector;
for ( ; nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; ++nextp) {
// read partition boot record (same format as mbr except
// there should only be 2 entries max: a normal partition
// and another extended partition
if (DISK_READ(d, xoffset, buf, 1) <= 0)
break;
magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
if (SWAB_LE16(magic) != MBR_MAGIC)
break;
p = (struct mbr_partition *)((char *)buf + MBR_PTABLE_OFFSET);
// Have to use memcpy because of alignment
memcpy(&tmp, p->start_sect, 4);
s = SWAB_LE32(tmp);
memcpy(&tmp, p->nr_sects, 4);
n = SWAB_LE32(tmp);
if (s && n) {
++found;
d->partitions[nextp].disk = d;
d->partitions[nextp].start_sector = s + xoffset;
d->partitions[nextp].nr_sectors = n;
d->partitions[nextp].systype = p->sys_ind;
d->partitions[nextp].bootflag = p->boot_ind;
}
++p;
memcpy(&tmp, p->start_sect, 4);
s = SWAB_LE32(tmp);
memcpy(&tmp, p->nr_sects, 4);
n = SWAB_LE32(tmp);
// more extended partitions?
if (p->sys_ind != SYSTYPE_EXTENDED || !s || !n)
break;
xoffset += s;
}
}
}
}
#endif
return found;
}
// Find partitions on given disk.
// Return number of partitions found
static int
find_partitions(disk_t *d)
{
cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)];
cyg_uint16 magic;
partition_t *p;
int i, found = 0;
if (d->kind == DISK_IDE_CDROM) {
#ifdef CYGSEM_REDBOOT_DISK_ISO9660
// no partition table, so fake it
p = d->partitions;
p->disk = d;
p->start_sector = 0;
p->nr_sectors = d->nr_sectors;
p->funs = &redboot_iso9660fs_funs;
return 1;
#else
return 0;
#endif
}
// read Master Boot Record
if (DISK_READ(d, 0, buf, 1) <= 0)
return 0;
// Check for DOS MBR
magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
if (SWAB_LE16(magic) == MBR_MAGIC) {
found = find_dos_partitions(d, (cyg_uint8 *)buf);
} else {
// Might want to handle other MBR types, here...
}
// Now go through all partitions and install the correct
// funcs for supported filesystems.
for (i = 0, p = d->partitions; i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++, p++) {
switch (p->systype) {
#ifdef CYGSEM_REDBOOT_DISK_EXT2FS
case SYSTYPE_LINUX:
p->funs = &redboot_e2fs_funs;
break;
#endif
#ifdef CYGSEM_REDBOOT_DISK_FAT16
case SYSTYPE_FAT16:
p->funs = &redboot_fat16_funs;
break;
#endif
#ifdef CYGSEM_REDBOOT_DISK_FAT32
case SYSTYPE_FAT32:
p->funs = &redboot_fat32_funs;
break;
#endif
default:
break; // ignore unsupported filesystems
}
}
return found;
}
// Add a disk to the disk table.
// Return zero if no more room in table.
externC int
disk_register(disk_t *d)
{
int i;
// make sure we have room for it
if (disk_count >= CYGNUM_REDBOOT_MAX_DISKS)
return 0;
// Set the index
d->index = 0;
for (i = 0; i < disk_count; i++)
if (disk_table[i].kind == d->kind)
d->index++;
// put it in the table
disk_table[disk_count] = *d;
// fill in partition info
find_partitions(&disk_table[disk_count++]);
return 1;
}
// Convert a filename in the form <partition_name>:<filename> into
// a partition and path.
//
static int
disk_parse_filename(const char *name, partition_t **part, const char **path)
{
int i, kind, index, pindex;
kind = index = pindex = 0;
if (name[0] == 'h' && name[1] == 'd') {
// IDE hard drives
kind = DISK_IDE_HD;
if (name[2] < 'a' || name[2] > 'z')
return 0;
index = name[2] - 'a';
if (name[3] < '1' || name[3] >= ('1' + CYGNUM_REDBOOT_MAX_PARTITIONS))
return 0;
pindex = name[3] - '1';
if (name[4] != ':')
return 0;
*path = &name[5];
}
#ifdef CYGSEM_REDBOOT_DISK_ISO9660
else if (name[0] == 'c' && name[1] == 'd') {
// CD drives
kind = DISK_IDE_CDROM;
if (name[2] < '0' || name[2] > '9')
return 0;
index = name[2] - '0';
if (name[3] != ':')
return 0;
*path = &name[4];
}
#endif
if (kind) {
for (i = 0; i < CYGNUM_REDBOOT_MAX_DISKS; i++) {
if (disk_table[i].kind == kind && disk_table[i].index == index) {
*part = &disk_table[i].partitions[pindex];
return 1;
}
}
}
return 0;
}
static const struct {
int kind;
const char *str;
} systype_names[] = {
{ SYSTYPE_FAT12, "FAT12" },
{ SYSTYPE_FAT16_32M, "FAT16 <32M" },
{ SYSTYPE_FAT16, "FAT16" },
{ SYSTYPE_EXTENDED, "Extended" },
{ SYSTYPE_LINUX_SWAP, "Linux Swap" },
{ SYSTYPE_LINUX, "Linux" }
};
static const char *
systype_name(int systype)
{
int i;
for (i = 0; i < sizeof(systype_names)/sizeof(systype_names[0]); i++)
if (systype_names[i].kind == systype)
return systype_names[i].str;
return "Unknown";
}
// List disk partitions
static void
do_disks(int argc, char *argv[])
{
int i, j;
disk_t *d;
partition_t *p;
char name[16];
for (i = 0, d = disk_table; i < disk_count; i++, d++) {
switch (d->kind) {
case DISK_IDE_HD:
for (j = 0, p = d->partitions;
j < CYGNUM_REDBOOT_MAX_PARTITIONS;
j++, p++) {
if (p->systype) {
diag_sprintf(name, "hd%c%d", 'a' + d->index, j+1);
diag_printf("%-8s %s\n", name, systype_name(p->systype));
}
}
break;
case DISK_IDE_CDROM:
diag_sprintf(name, "cd%d", d->index);
diag_printf("%-8s ISO9660\n", name);
break;
}
}
}
static void *fileptr;
static partition_t *file_part;
externC int
disk_stream_open(connection_info_t *info, int *err)
{
const char *filepath;
char *filename = info->filename;
// The filename is in <disk>:<path> format.
// Convert to a partition and path.
if (!disk_parse_filename(filename, &file_part, &filepath)) {
*err = diskerr_badname;
return -1;
}
if (file_part->disk->kind != DISK_IDE_CDROM && file_part->systype == 0) {
*err = diskerr_partition;
return -1;
}
if (file_part->funs == (fs_funs_t *)0) {
*err = diskerr_partition;
return -1;
}
fileptr = (file_part->funs->open)(file_part, filepath);
if (fileptr == NULL) {
*err = diskerr_open;
return -1;
}
return 0;
}
externC int
disk_stream_read(char *buf, int size, int *err)
{
int nread;
if ((nread = (file_part->funs->read)(fileptr, buf, size)) < 0) {
*err = diskerr_read;
return -1;
}
return nread;
}
externC void
disk_stream_close(int *err)
{
fileptr = NULL;
}
externC char *
disk_error(int err)
{
switch (err) {
case diskerr_badname:
return "Bad filename";
break;
case diskerr_partition:
return "Unsupported filesystem";
break;
case diskerr_open:
return "Can't open file";
break;
case diskerr_read:
return "Can't read file";
break;
default:
return "Unknown error";
break;
}
}
//
// RedBoot interface
//
GETC_IO_FUNCS(disk_io, disk_stream_open, disk_stream_close,
0, disk_stream_read, disk_error);
RedBoot_load(disk, disk_io, true, true, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -