mirror of https://github.com/ipxe/ipxe.git
GPXE code cleanup and purge.
parent
cdf1511d3e
commit
a2b15fd1fe
|
@ -1,68 +0,0 @@
|
|||
# !!! NOTE !!!
|
||||
# Do NOT add spaces or comments at the end of option lines.
|
||||
# It confuses some versions of make.
|
||||
|
||||
# Image filename for automatic boot and optional command line parameter
|
||||
#AUTOBOOT_FILE = "hda3:/boot/vmlinuz root=/dev/hda3 console=tty0 console=ttyS0,115200"
|
||||
AUTOBOOT_FILE = "hda2:/boot/vmlinuz initrd=/boot/initrd pci=noacpi ro root=/dev/hda2 console=tty0 console=ttyS0,115200"
|
||||
#AUTOBOOT_FILE = "mem@0xfff80000"
|
||||
#AUTOBOOT_FILE = "hde1@0"
|
||||
#AUTOBOOT_FILE = "uda1:/ram0_2.5_2.6.5_k8.2_mydisk7.elf"
|
||||
#AUTOBOOT_FILE = "hda5:/boot/vmlinuz initrd=/boot/initrd ro root=/dev/hda7 console=tty0 console=ttyS0,115200"
|
||||
|
||||
# Time in second before booting AUTOBOOT_FILE
|
||||
AUTOBOOT_DELAY = 2
|
||||
|
||||
# Driver for hard disk, CompactFlash, and CD-ROM on IDE bus
|
||||
IDE_DISK = 1
|
||||
|
||||
# Driver for USB disk
|
||||
USB_DISK = 1
|
||||
|
||||
# Filesystems
|
||||
# To make filo.zelf < 32 k, You may not enable JFS, MINIX, XFS
|
||||
# Is anyone still using these file system? BY LYH
|
||||
FSYS_EXT2FS = 1
|
||||
FSYS_FAT = 1
|
||||
#FSYS_JFS = 1
|
||||
#FSYS_MINIX = 1
|
||||
FSYS_REISERFS = 1
|
||||
#FSYS_XFS = 1
|
||||
FSYS_ISO9660 = 1
|
||||
|
||||
# Support for boot disk image in bootable CD-ROM (El Torito)
|
||||
ELTORITO = 1
|
||||
|
||||
# PCI support
|
||||
SUPPORT_PCI = 1
|
||||
|
||||
|
||||
# Debugging
|
||||
#DEBUG_ALL = 1
|
||||
#DEBUG_ELFBOOT = 1
|
||||
#DEBUG_ELFNOTE = 1
|
||||
#DEBUG_LINUXBIOS = 1
|
||||
#DEBUG_MALLOC = 1
|
||||
#DEBUG_MULTIBOOT = 1
|
||||
#DEBUG_SEGMENT = 1
|
||||
#DEBUG_SYS_INFO = 1
|
||||
#DEBUG_TIMER = 1
|
||||
#DEBUG_BLOCKDEV = 1
|
||||
#DEBUG_PCI = 1
|
||||
#DEBUG_LINUXLOAD = 1
|
||||
#DEBUG_IDE = 1
|
||||
#DEBUG_USB = 1
|
||||
#DEBUG_ELTORITO = 1
|
||||
|
||||
# i386 options
|
||||
|
||||
# Loader for standard Linux kernel image, a.k.a. /vmlinuz
|
||||
LINUX_LOADER = 1
|
||||
|
||||
# Boot FILO from Multiboot loader (eg. GRUB)
|
||||
# You need to modify i386/multiboot.c to use it. change mmrange to e820entries.
|
||||
# By LYH
|
||||
#MULTIBOOT_IMAGE = 1
|
||||
|
||||
# Use PCI Configuration Mechanism #1 (most boards)
|
||||
PCI_CONFIG_1 = 1
|
|
@ -1,125 +0,0 @@
|
|||
This is FILO, a bootloader which loads boot images from local filesystem,
|
||||
without help from legacy BIOS services.
|
||||
|
||||
Expected usage is to flash it into the BIOS ROM together with LinuxBIOS.
|
||||
|
||||
FEATURES
|
||||
|
||||
- Supported boot devices: IDE hard disk and CD-ROM, and system memory (ROM)
|
||||
- Supported filesystems: ext2, fat, jfs, minix, reiserfs, xfs, and iso9660
|
||||
- Supported image formats: ELF and [b]zImage (a.k.a. /vmlinuz)
|
||||
- Supports boot disk image of El Torito bootable CD-ROM
|
||||
- Supports loading image from raw device with user-specified offset
|
||||
- Console on VGA + keyboard, serial port, or both
|
||||
- Line editing with ^H, ^W and ^U keys to type arbitrary filename to boot
|
||||
- Full support for the ELF Boot Proposal (where is it btw, Eric?)
|
||||
- Auxiliary tool to compute checksum of ELF boot images
|
||||
- Full 32-bit code, no BIOS calls
|
||||
|
||||
REQUIREMENT
|
||||
|
||||
Only i386 PC architecture is currently supported.
|
||||
|
||||
x86-64 (AMD 64) machines in 32-bit mode should also work.
|
||||
(It looks like LinuxBIOS uses 32-bit mode and Linux kernel does
|
||||
the transition to 64-bit mode)
|
||||
|
||||
I'm using a VIA EPIA 5000 mini-ITX board, with a 2.5" IDE hard disk
|
||||
and a 32x CD-RW, for testing, and Bochs and VMware for development.
|
||||
|
||||
Recent version of GNU toolchain is required to build.
|
||||
I have tested with Debian/woody (gcc 2.95.4, binutils 2.12.90.0.1,
|
||||
make 3.79.1) and Debian/sid (gcc 3.3.2, binutils 2.14.90.0.6,
|
||||
make 3.80).
|
||||
|
||||
INSTALL
|
||||
|
||||
First invocation of make creates the default Config file.
|
||||
$ make
|
||||
Edit this file as you like. It's fairly straightforward (I hope).
|
||||
$ vi Config
|
||||
Then running make again will build filo.elf, the ELF boot image of FILO.
|
||||
$ make
|
||||
|
||||
Use filo.elf as your payload of LinuxBIOS, or a boot image for
|
||||
Etherboot.
|
||||
|
||||
If you enable MULTIBOOT_IMAGE option in Config, you can
|
||||
also boot filo.elf from GNU GRUB or other Multiboot bootloader.
|
||||
This feature is intended for testing or development purpose.
|
||||
|
||||
USING
|
||||
|
||||
When FILO starts, it displays "boot:" prompt.
|
||||
At "boot:" prompt, type the name of your boot image, and optionally
|
||||
the kernel parameter, in the form:
|
||||
DEVICE:FILENAME[ PARAM]
|
||||
for example:
|
||||
boot: hda1:/vmlinuz root=/dev/hda1
|
||||
|
||||
Notation of DEVICE for IDE disk and CD-ROM is same as in Linux
|
||||
(eg. hda1 means the first partition of master device on primary
|
||||
IDE channel).
|
||||
|
||||
FILENAME can be standard bzImage/zImage (vmlinuz) Linux kernels,
|
||||
Linux-compatible images such as memtest.bin of Memtest86,
|
||||
and any bootable ELF images, which include Linux kernel converted
|
||||
by mkelfImage, Etherboot .elf and .zelf, Memtest86, FILO itself, etc.
|
||||
|
||||
If AUTOBOOT_FILE is set in Config, FILO tries to boot this file
|
||||
first, and falls back to boot: prompt if it fails.
|
||||
|
||||
If AUTOBOOT_DELAY is also set, FILO waits for specified time in
|
||||
seconds before booting AUTOBOOT_FILE. If <Esc> key is pressed
|
||||
during this time period, automatic boot is canceled.
|
||||
Pressing <Enter> key also cancels the delay, but in this case
|
||||
AUTOBOOT_FILE is booted immediately.
|
||||
|
||||
Even if AUTOBOOT_DELAY is not set, automatic boot can be disabled
|
||||
by pressing <Esc> key beforehand.
|
||||
|
||||
FILO can also load separate initrd images along with vmlinuz
|
||||
kernels. (For ELF kernel, initrd images are embedded into the
|
||||
ELF file and cannot be altered).
|
||||
To do so, add "initrd=NAME" parameter to the kernel command line.
|
||||
NAME uses the same notation as kernel image name.
|
||||
(eg. boot: hda1:/vmlinuz initrd=hda1:/root.gz root=/dev/ram)
|
||||
|
||||
To boot an image in the BIOS flash (or whatever is mapped in the system
|
||||
memory space), use the notation "mem@OFFSET[,LENGTH]", like:
|
||||
boot: mem@0xfffe0000
|
||||
In this example, it loads the boot image from the last 128KB of BIOS
|
||||
flash.
|
||||
|
||||
The same notation can be used with IDE devices, eg:
|
||||
boot: hda@512,697344 initrd=hda@1M,4M
|
||||
In this case the 697344 bytes starting from second sector of IDE drive
|
||||
is loaded as kernel, and 4M bytes of offset 1M bytes of the same disk
|
||||
is loaded as initrd.
|
||||
Note that when you load vmlinuz kernel or initrd this way,
|
||||
you must specify the LENGTH parameter. You can omit it for ELF
|
||||
images since they have segment length internally.
|
||||
OFFSET and LENGTH parameters must be multiple of 512.
|
||||
|
||||
BUG REPORTING
|
||||
|
||||
If you have problem with FILO, set DEBUG_ALL in Config and send its
|
||||
console output to me at <ts1@tsn.or.jp>.
|
||||
|
||||
ACKNOWLEDGEMENTS
|
||||
|
||||
Filesystem code is taken from GNU GRUB and patches for it.
|
||||
IDE driver is originally taken from Etherboot.
|
||||
Steve Gehlbach wrote the original bzImage loader for FILO.
|
||||
|
||||
Besides, I have taken pieces of code and/or learned concepts
|
||||
from various standalone programs, including GNU GRUB, Etherboot,
|
||||
polled IDE patch by Adam Agnew, Memtest86, LinuxBIOS, and Linux.
|
||||
I must say thanks to all the developers of these wonderful software,
|
||||
especially to Eric Biederman for his great development work in this area.
|
||||
|
||||
LICENSE
|
||||
|
||||
Copyright (C) 2003 by SONE Takeshi <ts1@tsn.or.jp> and others.
|
||||
This program is licensed under the terms of GNU General Public License.
|
||||
See the COPYING file for details.
|
|
@ -1,48 +0,0 @@
|
|||
Moved from FILO into Etherboot, yhlu add boot from SATA disk and move usb boot framework
|
||||
from Steven James baremetal in LinuxBIOS, also add the OHCI support.
|
||||
|
||||
|
||||
1. refer to README.filo
|
||||
but don't need to use make config.
|
||||
2. CFLAG added
|
||||
CONSOLE_BTEXT --- for btext console support
|
||||
CONSOLE_PC_KBD --- for direct pc keyboard support
|
||||
CONFIG_FILO --- It will make main call pci_init
|
||||
3. to make:
|
||||
make bin/filo.zelf
|
||||
or
|
||||
make bin/tg3--filo.zelf
|
||||
|
||||
You can not use filo and ide_disk at the same time.
|
||||
|
||||
Some input for boot:
|
||||
|
||||
boot from BIOS ROM area
|
||||
4G-128K
|
||||
mem@0xfffe0000
|
||||
4G-512K
|
||||
mem@0xfff80000
|
||||
|
||||
boot from suse
|
||||
hda2:/boot/vmlinuz initrd=/boot/initrd ro root=/dev/hda2 console=tty0 console=ttyS0,115200
|
||||
for suse install from CD
|
||||
hdc:/boot/loader/linux initrd=/boot/loader/initrd ramdisk_size=65536 splash=silent showopts console=tty0 console=ttyS0,115200
|
||||
|
||||
boot from RH
|
||||
for RH install from CD
|
||||
hdc:/isolinux/vmlinuz initrd=/isolinux/initrd.img expert nofb acpi=off devfs=nomount ramdisk_size=65536 console=ttyS0,115200
|
||||
|
||||
for serial ATA support (using port1 and port2 only)
|
||||
1) if your kernel think SATA as SCSI
|
||||
hde2:/boot/vmlinuz initrd=/boot/initrd ro root=/dev/sda2 console=tty0 console=ttyS0,115200
|
||||
2) if your kernel think SATA as normal IDE
|
||||
hde2:/boot/vmlinuz initrd=/boot/initrd ro root=/dev/hde2 console=tty0 console=ttyS0,115200
|
||||
|
||||
for usb support
|
||||
uda1:/ram0_2.5_2.6.5_k8.2_mydisk7.elf
|
||||
|
||||
|
||||
Yinghai Lu yhlu@tyan.com
|
||||
|
||||
to do:
|
||||
add menu to filo boot
|
|
@ -1,15 +0,0 @@
|
|||
It is from steven james's baremetal in linuxbios util.
|
||||
yhlu seperate common functions from uhci.c to usb.c and create ohci.c to support ohci.
|
||||
ohci.c mainly cames from kernel 2.4.22 dirvers/usb/host/usb-ohci.c.
|
||||
it includes several parts
|
||||
1. UHCI+OHCI--->USB: privide usb init and usb_control_msg and usb_bulk_msg interface
|
||||
2. USB_SCSI: bulk only device
|
||||
3. USB_X interface to FILO
|
||||
|
||||
other changes in Etherboot
|
||||
1. Add allot2 and forget2, it will produce the required aligned memory.
|
||||
|
||||
todo:
|
||||
1. EHCI support
|
||||
|
||||
yhlu 6/2/2004
|
File diff suppressed because it is too large
Load Diff
|
@ -1,383 +0,0 @@
|
|||
#include <etherboot.h>
|
||||
|
||||
#include <lib.h>
|
||||
#include <fs.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_BLOCKDEV
|
||||
#include <debug.h>
|
||||
|
||||
#define NUM_CACHE 64
|
||||
static unsigned char buf_cache[NUM_CACHE][512];
|
||||
static unsigned long cache_sect[NUM_CACHE];
|
||||
|
||||
static char dev_name[256];
|
||||
|
||||
int dev_type = -1;
|
||||
int dev_drive = -1;
|
||||
unsigned long part_start;
|
||||
unsigned long part_length;
|
||||
int using_devsize;
|
||||
|
||||
static inline int has_pc_part_magic(unsigned char *sect)
|
||||
{
|
||||
return sect[510]==0x55 && sect[511]==0xAA;
|
||||
}
|
||||
|
||||
static inline int is_pc_extended_part(unsigned char type)
|
||||
{
|
||||
return type==5 || type==0xf || type==0x85;
|
||||
}
|
||||
|
||||
/* IBM-PC/MS-DOS style partitioning scheme */
|
||||
static int open_pc_partition(int part, unsigned long *start_p,
|
||||
unsigned long *length_p)
|
||||
{
|
||||
/* Layout of PC partition table */
|
||||
struct pc_partition {
|
||||
unsigned char boot;
|
||||
unsigned char head;
|
||||
unsigned char sector;
|
||||
unsigned char cyl;
|
||||
unsigned char type;
|
||||
unsigned char e_head;
|
||||
unsigned char e_sector;
|
||||
unsigned char e_cyl;
|
||||
unsigned char start_sect[4]; /* unaligned little endian */
|
||||
unsigned char nr_sects[4]; /* ditto */
|
||||
} *p;
|
||||
unsigned char buf[512];
|
||||
|
||||
/* PC partition probe */
|
||||
if (!devread(0, 0, sizeof(buf), buf)) {
|
||||
debug("device read failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (!has_pc_part_magic(buf)) {
|
||||
debug("pc partition magic number not found\n");
|
||||
//debug_hexdump(buf, 512);
|
||||
return PARTITION_UNKNOWN;
|
||||
}
|
||||
p = (struct pc_partition *) (buf + 0x1be);
|
||||
if (part < 4) {
|
||||
/* Primary partition */
|
||||
p += part;
|
||||
if (p->type==0 || is_pc_extended_part(p->type)) {
|
||||
printf("Partition %d does not exist\n", part+1);
|
||||
return 0;
|
||||
}
|
||||
*start_p = get_le32(p->start_sect);
|
||||
*length_p = get_le32(p->nr_sects);
|
||||
return 1;
|
||||
} else {
|
||||
/* Extended partition */
|
||||
int i;
|
||||
int cur_part;
|
||||
unsigned long ext_start, cur_table;
|
||||
/* Search for the extended partition
|
||||
* which contains logical partitions */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (is_pc_extended_part(p[i].type))
|
||||
break;
|
||||
}
|
||||
if (i >= 4) {
|
||||
printf("Extended partition not found\n");
|
||||
return 0;
|
||||
}
|
||||
debug("Extended partition at %d\n", i+1);
|
||||
/* Visit each logical partition labels */
|
||||
ext_start = get_le32(p[i].start_sect);
|
||||
cur_table = ext_start;
|
||||
cur_part = 4;
|
||||
for (;;) {
|
||||
debug("cur_part=%d at %lu\n", cur_part, cur_table);
|
||||
if (!devread(cur_table, 0, sizeof(buf), buf))
|
||||
return 0;
|
||||
if (!has_pc_part_magic(buf)) {
|
||||
debug("no magic\n");
|
||||
break;
|
||||
}
|
||||
|
||||
p = (struct pc_partition *) (buf + 0x1be);
|
||||
/* First entry is the logical partition */
|
||||
if (cur_part == part) {
|
||||
if (p->type==0) {
|
||||
printf("Partition %d is empty\n", part+1);
|
||||
return 0;
|
||||
}
|
||||
*start_p = cur_table + get_le32(p->start_sect);
|
||||
*length_p = get_le32(p->nr_sects);
|
||||
return 1;
|
||||
}
|
||||
/* Second entry is link to next partition */
|
||||
if (!is_pc_extended_part(p[1].type)) {
|
||||
debug("no link\n");
|
||||
break;
|
||||
}
|
||||
cur_table = ext_start + get_le32(p[1].start_sect);
|
||||
|
||||
cur_part++;
|
||||
}
|
||||
printf("Logical partition %d not exist\n", part+1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_cache(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE; i++)
|
||||
cache_sect[i] = (unsigned long) -1;
|
||||
}
|
||||
|
||||
static int parse_device_name(const char *name, int *type, int *drive,
|
||||
int *part, uint64_t *offset, uint64_t *length)
|
||||
{
|
||||
*offset = *length = 0;
|
||||
|
||||
if (memcmp(name, "hd", 2) == 0) {
|
||||
*type = DISK_IDE;
|
||||
name += 2;
|
||||
if (*name < 'a' || *name > 'z') {
|
||||
printf("Invalid drive\n");
|
||||
return 0;
|
||||
}
|
||||
*drive = *name - 'a';
|
||||
name++;
|
||||
} else if (memcmp(name, "mem", 3) == 0) {
|
||||
*type = DISK_MEM;
|
||||
name += 3;
|
||||
*drive = 0;
|
||||
} else if (memcmp(name, "ud", 2) == 0) {
|
||||
*type = DISK_USB;
|
||||
name += 2;
|
||||
if (*name < 'a' || *name > 'z') {
|
||||
printf("Invalid drive\n");
|
||||
return 0;
|
||||
}
|
||||
*drive = *name - 'a';
|
||||
name++;
|
||||
} else {
|
||||
printf("Unknown device type\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*part = (int) simple_strtoull(name, (char **)&name, 0);
|
||||
|
||||
if (*name == '@') {
|
||||
name++;
|
||||
*offset = strtoull_with_suffix(name, (char **)&name, 0);
|
||||
if (*name == ',')
|
||||
*length = strtoull_with_suffix(name+1, (char **)&name, 0);
|
||||
// debug("offset=%#Lx length=%#Lx\n", *offset, *length);
|
||||
}
|
||||
|
||||
if (*name != '\0') {
|
||||
printf("Can't parse device name\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int devopen(const char *name, int *reopen)
|
||||
{
|
||||
int type, drive, part;
|
||||
uint64_t offset, length;
|
||||
uint32_t disk_size = 0;
|
||||
|
||||
/* Don't re-open the device that's already open */
|
||||
if (strcmp(name, dev_name) == 0) {
|
||||
debug("already open\n");
|
||||
*reopen = 1;
|
||||
return 1;
|
||||
}
|
||||
*reopen = 0;
|
||||
|
||||
if (!parse_device_name(name, &type, &drive, &part, &offset, &length)) {
|
||||
debug("failed to parse device name: %s\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do simple sanity check first */
|
||||
if (offset & 0x1ff) {
|
||||
printf("Device offset must be multiple of 512\n");
|
||||
return 0;
|
||||
}
|
||||
if (length & 0x1ff) {
|
||||
debugx("WARNING: length is rounded up to multiple of 512\n");
|
||||
length = (length + 0x1ff) & ~0x1ff;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
#ifdef IDE_DISK
|
||||
case DISK_IDE:
|
||||
if (ide_probe(drive) != 0) {
|
||||
debug("failed to open ide\n");
|
||||
return 0;
|
||||
}
|
||||
disk_size = (uint32_t) -1; /* FIXME */
|
||||
break;
|
||||
#endif
|
||||
case DISK_MEM:
|
||||
disk_size = 1 << (32 - 9); /* 4GB/512-byte */
|
||||
break;
|
||||
#ifdef USB_DISK
|
||||
case DISK_USB:
|
||||
if (usb_probe(drive) != 0) {
|
||||
debug("failed to open usb\n");
|
||||
return 0;
|
||||
}
|
||||
disk_size = (uint32_t) -1; /* FIXME */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("Unknown device type %d\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev_type != type || dev_drive != drive)
|
||||
flush_cache();
|
||||
|
||||
/* start with whole disk */
|
||||
dev_type = type;
|
||||
dev_drive = drive;
|
||||
part_start = 0;
|
||||
part_length = disk_size;
|
||||
using_devsize = 1;
|
||||
|
||||
if (part != 0) {
|
||||
/* partition is specified */
|
||||
int ret;
|
||||
ret = open_pc_partition(part - 1, &part_start, &part_length);
|
||||
if (ret == PARTITION_UNKNOWN) {
|
||||
ret = open_eltorito_image(part - 1, &part_start, &part_length);
|
||||
if (ret == PARTITION_UNKNOWN) {
|
||||
printf("Unrecognized partitioning scheme\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
debug("can't open partition %d\n", part);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Partition %d start %lu length %lu\n", part,
|
||||
part_start, part_length);
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
if (offset >= (uint64_t) part_length << 9) {
|
||||
printf("Device offset is too high\n");
|
||||
return 0;
|
||||
}
|
||||
part_start += offset >> 9;
|
||||
part_length -= offset >> 9;
|
||||
debug("after offset: start %lu, length %lu\n", part_start, part_length);
|
||||
}
|
||||
|
||||
if (length) {
|
||||
if (length > (uint64_t) part_length << 9) {
|
||||
printf("Specified length exceeds the size of device\n");
|
||||
return 0;
|
||||
}
|
||||
part_length = length >> 9;
|
||||
debug("after length: length %lu\n", part_length);
|
||||
using_devsize = 0;
|
||||
}
|
||||
|
||||
strncpy(dev_name, name, sizeof(dev_name)-1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read a sector from opened device with simple/stupid buffer cache */
|
||||
static void *read_sector(unsigned long sector)
|
||||
{
|
||||
unsigned int hash;
|
||||
void *buf;
|
||||
int i;
|
||||
|
||||
/* If reading memory, just return the memory as the buffer */
|
||||
if (dev_type == DISK_MEM) {
|
||||
unsigned long phys = sector << 9;
|
||||
//debug("mem: %#lx\n", phys);
|
||||
return phys_to_virt(phys);
|
||||
}
|
||||
|
||||
/* Search in the cache */
|
||||
hash = sector % NUM_CACHE;
|
||||
buf = buf_cache[hash];
|
||||
if (cache_sect[hash] != sector) {
|
||||
cache_sect[hash] = (unsigned long) -1;
|
||||
switch (dev_type) {
|
||||
#ifdef IDE_DISK
|
||||
case DISK_IDE:
|
||||
if (ide_read(dev_drive, sector, buf) != 0)
|
||||
goto readerr;
|
||||
break;
|
||||
#endif
|
||||
#ifdef USB_DISK
|
||||
case DISK_USB:
|
||||
if (usb_read(dev_drive, sector, buf) != 0)
|
||||
goto readerr;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("read_sector: device not open\n");
|
||||
return 0;
|
||||
}
|
||||
cache_sect[hash] = sector;
|
||||
}
|
||||
#if 0
|
||||
printf("in read_sector:\n");
|
||||
for(i=0;i<128;i++) {
|
||||
if((i%4)==0) printf("\n %08x:",i*4);
|
||||
printf(" %08x ",(uint32_t)*((uint32_t *)buf+i));
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
|
||||
readerr:
|
||||
printf("Disk read error dev_type=%d drive=%d sector=%x\n",
|
||||
dev_type, dev_drive, sector);
|
||||
dev_name[0] = '\0'; /* force re-open the device next time */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int devread(unsigned long sector, unsigned long byte_offset,
|
||||
unsigned long byte_len, void *buf)
|
||||
{
|
||||
char *sector_buffer;
|
||||
char *dest = buf;
|
||||
unsigned long len;
|
||||
int i;
|
||||
|
||||
sector += byte_offset >> 9;
|
||||
byte_offset &= 0x1ff;
|
||||
|
||||
if (sector + ((byte_len + 0x1ff) >> 9) > part_length) {
|
||||
printf("Attempt to read out of device/partition\n");
|
||||
debug("sector=%x part_length=%x byte_len=%x\n",
|
||||
sector, part_length, byte_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (byte_len > 0) {
|
||||
sector_buffer = read_sector(part_start + sector);
|
||||
if (!sector_buffer) {
|
||||
debug("read sector failed\n");
|
||||
return 0;
|
||||
}
|
||||
len = 512 - byte_offset;
|
||||
if (len > byte_len)
|
||||
len = byte_len;
|
||||
memcpy(dest, sector_buffer + byte_offset, len);
|
||||
sector++;
|
||||
byte_offset = 0;
|
||||
byte_len -= len;
|
||||
dest += len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
|
||||
#include <etherboot.h>
|
||||
#include <fs.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_ELTORITO
|
||||
#include <debug.h>
|
||||
|
||||
#define ELTORITO_PLATFORM_X86 0
|
||||
#define ELTORITO_PLATFORM_PPC 1
|
||||
#define ELTORITO_PLATFORM_MAC 2
|
||||
#include <bits/eltorito.h>
|
||||
|
||||
#ifndef ELTORITO_PLATFORM
|
||||
#error "ELTORITO_PLATFORM is not defined for this arch"
|
||||
#endif
|
||||
|
||||
/* El Torito boot record at sector 0x11 of bootable CD */
|
||||
struct boot_record {
|
||||
uint8_t ind;
|
||||
uint8_t iso_id[5];
|
||||
uint8_t version;
|
||||
uint8_t boot_id[32];
|
||||
uint8_t reserved[32];
|
||||
uint8_t catalog_offset[4];
|
||||
};
|
||||
|
||||
/* First entry of the catalog */
|
||||
struct validation_entry {
|
||||
uint8_t header_id;
|
||||
uint8_t platform;
|
||||
uint8_t reserved[2];
|
||||
uint8_t id[24];
|
||||
uint8_t checksum[2];
|
||||
uint8_t key55;
|
||||
uint8_t keyAA;
|
||||
};
|
||||
|
||||
/* Initial/Default catalog entry */
|
||||
struct default_entry {
|
||||
uint8_t boot_id;
|
||||
uint8_t media_type;
|
||||
#define MEDIA_MASK 0x0f
|
||||
#define MEDIA_NOEMU 0
|
||||
#define MEDIA_1200_FD 1
|
||||
#define MEDIA_1440_FD 2
|
||||
#define MEDIA_2880_FD 3
|
||||
#define MEDIA_HD 4
|
||||
uint8_t load_segment[2];
|
||||
uint8_t system_type;
|
||||
uint8_t reserved;
|
||||
uint8_t sector_count[2];
|
||||
uint8_t start_sector[4];
|
||||
uint8_t reserved_too[20];
|
||||
};
|
||||
|
||||
/* Find El-Torito boot disk image */
|
||||
int open_eltorito_image(int part, unsigned long *offset_p,
|
||||
unsigned long *length_p)
|
||||
{
|
||||
struct boot_record boot_record;
|
||||
uint32_t cat_offset;
|
||||
uint8_t catalog[2048];
|
||||
struct validation_entry *ve;
|
||||
int i, sum;
|
||||
struct default_entry *de;
|
||||
|
||||
/* We always use 512-byte "soft sector", but
|
||||
* El-Torito uses 2048-byte CD-ROM sector */
|
||||
|
||||
/* Boot Record is at sector 0x11 */
|
||||
if (!devread(0x11<<2, 0, sizeof boot_record, &boot_record))
|
||||
return 0;
|
||||
|
||||
if (boot_record.ind != 0
|
||||
|| memcmp(boot_record.iso_id, "CD001", 5) != 0
|
||||
|| memcmp(boot_record.boot_id, "EL TORITO SPECIFICATION", 23)
|
||||
!= 0) {
|
||||
debug("No El-Torito signature\n");
|
||||
return PARTITION_UNKNOWN;
|
||||
}
|
||||
|
||||
if (part != 0) {
|
||||
printf("El-Torito entries other than Initial/Default is not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cat_offset = get_le32(boot_record.catalog_offset);
|
||||
debug("El-Torito boot catalog at sector %u\n", cat_offset);
|
||||
if (!devread(cat_offset<<2, 0, 2048, catalog))
|
||||
return 0;
|
||||
|
||||
/* Validate the catalog */
|
||||
ve = (void *) catalog;
|
||||
//debug_hexdump(ve, sizeof *ve);
|
||||
if (ve->header_id != 1 || ve->key55 != 0x55 || ve->keyAA != 0xAA) {
|
||||
printf("Invalid El Torito boot catalog\n");
|
||||
return 0;
|
||||
}
|
||||
/* All words must sum up to zero */
|
||||
sum = 0;
|
||||
for (i = 0; i < sizeof(*ve); i += 2)
|
||||
sum += get_le16(&catalog[i]);
|
||||
sum &= 0xffff;
|
||||
if (sum != 0) {
|
||||
printf("El Torito boot catalog verify failed\n");
|
||||
return 0;
|
||||
}
|
||||
debug("id='%.*s'\n", sizeof ve->id, ve->id);
|
||||
|
||||
/* Platform check is warning only, because we won't directly execute
|
||||
* the image. Just mounting it should be safe. */
|
||||
if (ve->platform != ELTORITO_PLATFORM){
|
||||
debugx("WARNING: Boot disk for different platform: %d\n", ve->platform);
|
||||
}
|
||||
|
||||
/* Just support initial/default entry for now */
|
||||
de = (void *) (ve + 1);
|
||||
if (de->boot_id != 0x88) {
|
||||
debugx("WARNING: Default boot entry is not bootable\n");
|
||||
}
|
||||
|
||||
switch (de->media_type & MEDIA_MASK) {
|
||||
case MEDIA_NOEMU:
|
||||
printf("Disc doesn't use boot disk emulation\n");
|
||||
return 0;
|
||||
case MEDIA_1200_FD:
|
||||
*length_p = 1200*1024/512;
|
||||
break;
|
||||
case MEDIA_1440_FD:
|
||||
*length_p = 1440*1024/512;
|
||||
break;
|
||||
case MEDIA_2880_FD:
|
||||
*length_p = 2880*1024/512;
|
||||
break;
|
||||
case MEDIA_HD:
|
||||
/* FIXME: read partition table and return first partition.
|
||||
* Spec states emulation HD has only one partition and it must
|
||||
* be the first partition */
|
||||
printf("Disc uses hard disk emulation - not supported\n");
|
||||
return 0;
|
||||
}
|
||||
*offset_p = get_le32(de->start_sector) << 2;
|
||||
debug("offset=%#lx length=%#lx\n", *offset_p, *length_p);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Defines for the FAT BIOS Parameter Block (embedded in the first block
|
||||
* of the partition.
|
||||
*/
|
||||
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
/* Note that some shorts are not aligned, and must therefore
|
||||
* be declared as array of two bytes.
|
||||
*/
|
||||
struct fat_bpb {
|
||||
__s8 ignored[3]; /* Boot strap short or near jump */
|
||||
__s8 system_id[8]; /* Name - can be used to special case
|
||||
partition manager volumes */
|
||||
__u8 bytes_per_sect[2]; /* bytes per logical sector */
|
||||
__u8 sects_per_clust;/* sectors/cluster */
|
||||
__u8 reserved_sects[2]; /* reserved sectors */
|
||||
__u8 num_fats; /* number of FATs */
|
||||
__u8 dir_entries[2]; /* root directory entries */
|
||||
__u8 short_sectors[2]; /* number of sectors */
|
||||
__u8 media; /* media code (unused) */
|
||||
__u16 fat_length; /* sectors/FAT */
|
||||
__u16 secs_track; /* sectors per track */
|
||||
__u16 heads; /* number of heads */
|
||||
__u32 hidden; /* hidden sectors (unused) */
|
||||
__u32 long_sectors; /* number of sectors (if short_sectors == 0) */
|
||||
|
||||
/* The following fields are only used by FAT32 */
|
||||
__u32 fat32_length; /* sectors/FAT */
|
||||
__u16 flags; /* bit 8: fat mirroring, low 4: active fat */
|
||||
__u8 version[2]; /* major, minor filesystem version */
|
||||
__u32 root_cluster; /* first cluster in root directory */
|
||||
__u16 info_sector; /* filesystem info sector */
|
||||
__u16 backup_boot; /* backup boot sector */
|
||||
__u16 reserved2[6]; /* Unused */
|
||||
};
|
||||
|
||||
#define FAT_CVT_U16(bytarr) (* (__u16*)(bytarr))
|
||||
|
||||
/*
|
||||
* Defines how to differentiate a 12-bit and 16-bit FAT.
|
||||
*/
|
||||
|
||||
#define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */
|
||||
|
||||
/*
|
||||
* Defines for the file "attribute" byte
|
||||
*/
|
||||
|
||||
#define FAT_ATTRIB_OK_MASK 0x37
|
||||
#define FAT_ATTRIB_NOT_OK_MASK 0xC8
|
||||
#define FAT_ATTRIB_DIR 0x10
|
||||
#define FAT_ATTRIB_LONGNAME 0x0F
|
||||
|
||||
/*
|
||||
* Defines for FAT directory entries
|
||||
*/
|
||||
|
||||
#define FAT_DIRENTRY_LENGTH 32
|
||||
|
||||
#define FAT_DIRENTRY_ATTRIB(entry) \
|
||||
(*((unsigned char *) (entry+11)))
|
||||
#define FAT_DIRENTRY_VALID(entry) \
|
||||
( ((*((unsigned char *) entry)) != 0) \
|
||||
&& ((*((unsigned char *) entry)) != 0xE5) \
|
||||
&& !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) )
|
||||
#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \
|
||||
((*((unsigned short *) (entry+26)))+(*((unsigned short *) (entry+20)) << 16))
|
||||
#define FAT_DIRENTRY_FILELENGTH(entry) \
|
||||
(*((unsigned long *) (entry+28)))
|
||||
|
||||
#define FAT_LONGDIR_ID(entry) \
|
||||
(*((unsigned char *) (entry)))
|
||||
#define FAT_LONGDIR_ALIASCHECKSUM(entry) \
|
||||
(*((unsigned char *) (entry+13)))
|
|
@ -1,233 +0,0 @@
|
|||
/* GRUB compatibility header */
|
||||
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
//#include <lib.h>
|
||||
#include <etherboot.h>
|
||||
|
||||
#include <fs.h>
|
||||
|
||||
/* This disables some portion of code */
|
||||
#define STAGE1_5 1
|
||||
|
||||
static inline int
|
||||
substring (const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 == *s2)
|
||||
{
|
||||
/* The strings match exactly. */
|
||||
if (! *(s1++))
|
||||
return 0;
|
||||
s2 ++;
|
||||
}
|
||||
|
||||
/* S1 is a substring of S2. */
|
||||
if (*s1 == 0)
|
||||
return -1;
|
||||
|
||||
/* S1 isn't a substring. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define grub_memmove memmove
|
||||
#define grub_strcmp strcmp
|
||||
|
||||
#define MAXINT 0x7fffffff
|
||||
|
||||
/* This is only used by fsys_* to determine if it's hard disk. If it is,
|
||||
* they try to guess filesystem type by partition type. I guess it is
|
||||
* not necessory, so hardcoded to 0 (first floppy) --ts1 */
|
||||
#define current_drive 0
|
||||
|
||||
/* Ditto */
|
||||
#define current_slice 0
|
||||
|
||||
extern unsigned long part_start;
|
||||
extern unsigned long part_length;
|
||||
extern int filepos;
|
||||
extern int filemax;
|
||||
extern int fsmax;
|
||||
|
||||
/* Error codes (descriptions are in common.c) */
|
||||
typedef enum
|
||||
{
|
||||
ERR_NONE = 0,
|
||||
ERR_BAD_FILENAME,
|
||||
ERR_BAD_FILETYPE,
|
||||
ERR_BAD_GZIP_DATA,
|
||||
ERR_BAD_GZIP_HEADER,
|
||||
ERR_BAD_PART_TABLE,
|
||||
ERR_BAD_VERSION,
|
||||
ERR_BELOW_1MB,
|
||||
ERR_BOOT_COMMAND,
|
||||
ERR_BOOT_FAILURE,
|
||||
ERR_BOOT_FEATURES,
|
||||
ERR_DEV_FORMAT,
|
||||
ERR_DEV_VALUES,
|
||||
ERR_EXEC_FORMAT,
|
||||
ERR_FILELENGTH,
|
||||
ERR_FILE_NOT_FOUND,
|
||||
ERR_FSYS_CORRUPT,
|
||||
ERR_FSYS_MOUNT,
|
||||
ERR_GEOM,
|
||||
ERR_NEED_LX_KERNEL,
|
||||
ERR_NEED_MB_KERNEL,
|
||||
ERR_NO_DISK,
|
||||
ERR_NO_PART,
|
||||
ERR_NUMBER_PARSING,
|
||||
ERR_OUTSIDE_PART,
|
||||
ERR_READ,
|
||||
ERR_SYMLINK_LOOP,
|
||||
ERR_UNRECOGNIZED,
|
||||
ERR_WONT_FIT,
|
||||
ERR_WRITE,
|
||||
ERR_BAD_ARGUMENT,
|
||||
ERR_UNALIGNED,
|
||||
ERR_PRIVILEGED,
|
||||
ERR_DEV_NEED_INIT,
|
||||
ERR_NO_DISK_SPACE,
|
||||
ERR_NUMBER_OVERFLOW,
|
||||
|
||||
MAX_ERR_NUM
|
||||
} grub_error_t;
|
||||
|
||||
extern grub_error_t errnum;
|
||||
|
||||
#define grub_open file_open
|
||||
#define grub_read file_read
|
||||
#define grub_seek file_seek
|
||||
#define grub_close file_close
|
||||
|
||||
/* instrumentation variables */
|
||||
/* (Not used in FILO) */
|
||||
extern void (*disk_read_hook) (int, int, int);
|
||||
extern void (*disk_read_func) (int, int, int);
|
||||
|
||||
#define FSYS_BUFLEN 0x8000
|
||||
extern char FSYS_BUF[FSYS_BUFLEN];
|
||||
|
||||
#define print_possibilities 0
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define SECTOR_BITS 9
|
||||
|
||||
#ifdef FSYS_FAT
|
||||
int fat_mount (void);
|
||||
int fat_read (char *buf, int len);
|
||||
int fat_dir (char *dirname);
|
||||
#endif
|
||||
|
||||
#ifdef FSYS_EXT2FS
|
||||
int ext2fs_mount (void);
|
||||
int ext2fs_read (char *buf, int len);
|
||||
int ext2fs_dir (char *dirname);
|
||||
#endif
|
||||
|
||||
#ifdef FSYS_MINIX
|
||||
int minix_mount (void);
|
||||
int minix_read (char *buf, int len);
|
||||
int minix_dir (char *dirname);
|
||||
#endif
|
||||
|
||||
#ifdef FSYS_REISERFS
|
||||
int reiserfs_mount (void);
|
||||
int reiserfs_read (char *buf, int len);
|
||||
int reiserfs_dir (char *dirname);
|
||||
int reiserfs_embed (int *start_sector, int needed_sectors);
|
||||
#endif
|
||||
|
||||
#ifdef FSYS_JFS
|
||||
int jfs_mount (void);
|
||||
int jfs_read (char *buf, int len);
|
||||
int jfs_dir (char *dirname);
|
||||
int jfs_embed (int *start_sector, int needed_sectors);
|
||||
#endif
|
||||
|
||||
#ifdef FSYS_XFS
|
||||
int xfs_mount (void);
|
||||
int xfs_read (char *buf, int len);
|
||||
int xfs_dir (char *dirname);
|
||||
#endif
|
||||
|
||||
#ifdef FSYS_ISO9660
|
||||
int iso9660_mount (void);
|
||||
int iso9660_read (char *buf, int len);
|
||||
int iso9660_dir (char *dirname);
|
||||
#endif
|
||||
|
||||
/* This is not a flag actually, but used as if it were a flag. */
|
||||
#define PC_SLICE_TYPE_HIDDEN_FLAG 0x10
|
||||
|
||||
#define PC_SLICE_TYPE_NONE 0
|
||||
#define PC_SLICE_TYPE_FAT12 1
|
||||
#define PC_SLICE_TYPE_FAT16_LT32M 4
|
||||
#define PC_SLICE_TYPE_EXTENDED 5
|
||||
#define PC_SLICE_TYPE_FAT16_GT32M 6
|
||||
#define PC_SLICE_TYPE_FAT32 0xb
|
||||
#define PC_SLICE_TYPE_FAT32_LBA 0xc
|
||||
#define PC_SLICE_TYPE_FAT16_LBA 0xe
|
||||
#define PC_SLICE_TYPE_WIN95_EXTENDED 0xf
|
||||
#define PC_SLICE_TYPE_EZD 0x55
|
||||
#define PC_SLICE_TYPE_MINIX 0x80
|
||||
#define PC_SLICE_TYPE_LINUX_MINIX 0x81
|
||||
#define PC_SLICE_TYPE_EXT2FS 0x83
|
||||
#define PC_SLICE_TYPE_LINUX_EXTENDED 0x85
|
||||
#define PC_SLICE_TYPE_VSTAFS 0x9e
|
||||
#define PC_SLICE_TYPE_DELL_UTIL 0xde
|
||||
#define PC_SLICE_TYPE_LINUX_RAID 0xfd
|
||||
|
||||
/* For convinience. */
|
||||
/* Check if TYPE is a FAT partition type. Clear the hidden flag before
|
||||
the check, to allow the user to mount a hidden partition in GRUB. */
|
||||
#define IS_PC_SLICE_TYPE_FAT(type) \
|
||||
({ int _type = (type) & ~PC_SLICE_TYPE_HIDDEN_FLAG; \
|
||||
_type == PC_SLICE_TYPE_FAT12 \
|
||||
|| _type == PC_SLICE_TYPE_FAT16_LT32M \
|
||||
|| _type == PC_SLICE_TYPE_FAT16_GT32M \
|
||||
|| _type == PC_SLICE_TYPE_FAT16_LBA \
|
||||
|| _type == PC_SLICE_TYPE_FAT32 \
|
||||
|| _type == PC_SLICE_TYPE_FAT32_LBA \
|
||||
|| _type == PC_SLICE_TYPE_DELL_UTIL; })
|
||||
|
||||
#define IS_PC_SLICE_TYPE_MINIX(type) \
|
||||
(((type) == PC_SLICE_TYPE_MINIX) \
|
||||
|| ((type) == PC_SLICE_TYPE_LINUX_MINIX))
|
||||
|
||||
#define IS_PC_SLICE_TYPE_BSD_WITH_FS(type,fs) 0
|
||||
|
||||
/* possible values for the *BSD-style partition type */
|
||||
#define FS_UNUSED 0 /* unused */
|
||||
#define FS_SWAP 1 /* swap */
|
||||
#define FS_V6 2 /* Sixth Edition */
|
||||
#define FS_V7 3 /* Seventh Edition */
|
||||
#define FS_SYSV 4 /* System V */
|
||||
#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
|
||||
#define FS_V8 6 /* Eighth Edition, 4K blocks */
|
||||
#define FS_BSDFFS 7 /* 4.2BSD fast file system */
|
||||
#define FS_MSDOS 8 /* MSDOS file system */
|
||||
#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */
|
||||
#define FS_OTHER 10 /* in use, but unknown/unsupported */
|
||||
#define FS_HPFS 11 /* OS/2 high-performance file system */
|
||||
#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
|
||||
#define FS_BOOT 13 /* partition contains bootstrap */
|
||||
#define FS_ADOS 14 /* AmigaDOS fast file system */
|
||||
#define FS_HFS 15 /* Macintosh HFS */
|
||||
#define FS_FILECORE 16 /* Acorn Filecore Filing System */
|
||||
#define FS_EXT2FS 17 /* Linux Extended 2 file system */
|
|
@ -1,779 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef FSYS_EXT2FS
|
||||
|
||||
#include "shared.h"
|
||||
#include "filesys.h"
|
||||
#include <lib.h>
|
||||
#include "string.h"
|
||||
|
||||
static int mapblock1, mapblock2;
|
||||
|
||||
/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
|
||||
#define DEV_BSIZE 512
|
||||
|
||||
/* include/linux/fs.h */
|
||||
#define BLOCK_SIZE 1024 /* initial block size for superblock read */
|
||||
/* made up, defaults to 1 but can be passed via mount_opts */
|
||||
#define WHICH_SUPER 1
|
||||
/* kind of from fs/ext2/super.c */
|
||||
#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
|
||||
|
||||
/* include/asm-i386/types.h */
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
/*
|
||||
* Constants relative to the data blocks, from ext2_fs.h
|
||||
*/
|
||||
#define EXT2_NDIR_BLOCKS 12
|
||||
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
|
||||
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
|
||||
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
||||
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
||||
|
||||
/* include/linux/ext2_fs.h */
|
||||
struct ext2_super_block
|
||||
{
|
||||
__u32 s_inodes_count; /* Inodes count */
|
||||
__u32 s_blocks_count; /* Blocks count */
|
||||
__u32 s_r_blocks_count; /* Reserved blocks count */
|
||||
__u32 s_free_blocks_count; /* Free blocks count */
|
||||
__u32 s_free_inodes_count; /* Free inodes count */
|
||||
__u32 s_first_data_block; /* First Data Block */
|
||||
__u32 s_log_block_size; /* Block size */
|
||||
__s32 s_log_frag_size; /* Fragment size */
|
||||
__u32 s_blocks_per_group; /* # Blocks per group */
|
||||
__u32 s_frags_per_group; /* # Fragments per group */
|
||||
__u32 s_inodes_per_group; /* # Inodes per group */
|
||||
__u32 s_mtime; /* Mount time */
|
||||
__u32 s_wtime; /* Write time */
|
||||
__u16 s_mnt_count; /* Mount count */
|
||||
__s16 s_max_mnt_count; /* Maximal mount count */
|
||||
__u16 s_magic; /* Magic signature */
|
||||
__u16 s_state; /* File system state */
|
||||
__u16 s_errors; /* Behaviour when detecting errors */
|
||||
__u16 s_pad;
|
||||
__u32 s_lastcheck; /* time of last check */
|
||||
__u32 s_checkinterval; /* max. time between checks */
|
||||
__u32 s_creator_os; /* OS */
|
||||
__u32 s_rev_level; /* Revision level */
|
||||
__u16 s_def_resuid; /* Default uid for reserved blocks */
|
||||
__u16 s_def_resgid; /* Default gid for reserved blocks */
|
||||
__u32 s_reserved[235]; /* Padding to the end of the block */
|
||||
};
|
||||
|
||||
struct ext2_group_desc
|
||||
{
|
||||
__u32 bg_block_bitmap; /* Blocks bitmap block */
|
||||
__u32 bg_inode_bitmap; /* Inodes bitmap block */
|
||||
__u32 bg_inode_table; /* Inodes table block */
|
||||
__u16 bg_free_blocks_count; /* Free blocks count */
|
||||
__u16 bg_free_inodes_count; /* Free inodes count */
|
||||
__u16 bg_used_dirs_count; /* Directories count */
|
||||
__u16 bg_pad;
|
||||
__u32 bg_reserved[3];
|
||||
};
|
||||
|
||||
struct ext2_inode
|
||||
{
|
||||
__u16 i_mode; /* File mode */
|
||||
__u16 i_uid; /* Owner Uid */
|
||||
__u32 i_size; /* 4: Size in bytes */
|
||||
__u32 i_atime; /* Access time */
|
||||
__u32 i_ctime; /* 12: Creation time */
|
||||
__u32 i_mtime; /* Modification time */
|
||||
__u32 i_dtime; /* 20: Deletion Time */
|
||||
__u16 i_gid; /* Group Id */
|
||||
__u16 i_links_count; /* 24: Links count */
|
||||
__u32 i_blocks; /* Blocks count */
|
||||
__u32 i_flags; /* 32: File flags */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
__u32 l_i_reserved1;
|
||||
}
|
||||
linux1;
|
||||
struct
|
||||
{
|
||||
__u32 h_i_translator;
|
||||
}
|
||||
hurd1;
|
||||
struct
|
||||
{
|
||||
__u32 m_i_reserved1;
|
||||
}
|
||||
masix1;
|
||||
}
|
||||
osd1; /* OS dependent 1 */
|
||||
__u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
|
||||
__u32 i_version; /* File version (for NFS) */
|
||||
__u32 i_file_acl; /* File ACL */
|
||||
__u32 i_dir_acl; /* Directory ACL */
|
||||
__u32 i_faddr; /* Fragment address */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
__u8 l_i_frag; /* Fragment number */
|
||||
__u8 l_i_fsize; /* Fragment size */
|
||||
__u16 i_pad1;
|
||||
__u32 l_i_reserved2[2];
|
||||
}
|
||||
linux2;
|
||||
struct
|
||||
{
|
||||
__u8 h_i_frag; /* Fragment number */
|
||||
__u8 h_i_fsize; /* Fragment size */
|
||||
__u16 h_i_mode_high;
|
||||
__u16 h_i_uid_high;
|
||||
__u16 h_i_gid_high;
|
||||
__u32 h_i_author;
|
||||
}
|
||||
hurd2;
|
||||
struct
|
||||
{
|
||||
__u8 m_i_frag; /* Fragment number */
|
||||
__u8 m_i_fsize; /* Fragment size */
|
||||
__u16 m_pad1;
|
||||
__u32 m_i_reserved2[2];
|
||||
}
|
||||
masix2;
|
||||
}
|
||||
osd2; /* OS dependent 2 */
|
||||
};
|
||||
|
||||
/* linux/limits.h */
|
||||
#define NAME_MAX 255 /* # chars in a file name */
|
||||
|
||||
/* linux/posix_type.h */
|
||||
typedef long linux_off_t;
|
||||
|
||||
/* linux/ext2fs.h */
|
||||
#define EXT2_NAME_LEN 255
|
||||
struct ext2_dir_entry
|
||||
{
|
||||
__u32 inode; /* Inode number */
|
||||
__u16 rec_len; /* Directory entry length */
|
||||
__u8 name_len; /* Name length */
|
||||
__u8 file_type;
|
||||
char name[EXT2_NAME_LEN]; /* File name */
|
||||
};
|
||||
|
||||
/* linux/ext2fs.h */
|
||||
/*
|
||||
* EXT2_DIR_PAD defines the directory entries boundaries
|
||||
*
|
||||
* NOTE: It must be a multiple of 4
|
||||
*/
|
||||
#define EXT2_DIR_PAD 4
|
||||
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
|
||||
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
|
||||
~EXT2_DIR_ROUND)
|
||||
|
||||
|
||||
/* ext2/super.c */
|
||||
#define log2(n) ffz(~(n))
|
||||
|
||||
#define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */
|
||||
#define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */
|
||||
#define PATH_MAX 1024 /* include/linux/limits.h */
|
||||
#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
|
||||
|
||||
/* made up, these are pointers into FSYS_BUF */
|
||||
/* read once, always stays there: */
|
||||
#define SUPERBLOCK \
|
||||
((struct ext2_super_block *)(FSYS_BUF))
|
||||
#define GROUP_DESC \
|
||||
((struct ext2_group_desc *) \
|
||||
((int)SUPERBLOCK + sizeof(struct ext2_super_block)))
|
||||
#define INODE \
|
||||
((struct ext2_inode *)((int)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
|
||||
#define DATABLOCK1 \
|
||||
((int)((int)INODE + sizeof(struct ext2_inode)))
|
||||
#define DATABLOCK2 \
|
||||
((int)((int)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
|
||||
|
||||
/* linux/ext2_fs.h */
|
||||
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
|
||||
#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s)))
|
||||
|
||||
/* linux/ext2_fs.h */
|
||||
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||||
/* kind of from ext2/super.c */
|
||||
#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s))
|
||||
/* linux/ext2fs.h */
|
||||
#define EXT2_DESC_PER_BLOCK(s) \
|
||||
(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
|
||||
/* linux/stat.h */
|
||||
#define S_IFMT 00170000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
|
||||
/* include/asm-i386/bitops.h */
|
||||
/*
|
||||
* ffz = Find First Zero in word. Undefined if no zero exists,
|
||||
* so code should check against ~0UL first..
|
||||
*/
|
||||
static __inline__ unsigned long
|
||||
ffz (unsigned long word)
|
||||
{
|
||||
__asm__ ("bsfl %1,%0"
|
||||
: "=r" (word)
|
||||
: "r" (~word));
|
||||
return word;
|
||||
}
|
||||
|
||||
/* check filesystem types and read superblock into memory buffer */
|
||||
int
|
||||
ext2fs_mount (void)
|
||||
{
|
||||
int retval = 1;
|
||||
|
||||
if ((((current_drive & 0x80) || (current_slice != 0))
|
||||
&& (current_slice != PC_SLICE_TYPE_EXT2FS)
|
||||
&& (current_slice != PC_SLICE_TYPE_LINUX_RAID)
|
||||
&& (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS))
|
||||
&& (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)))
|
||||
|| part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE))
|
||||
|| !devread (SBLOCK, 0, sizeof (struct ext2_super_block),
|
||||
(char *) SUPERBLOCK)
|
||||
|| SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC)
|
||||
retval = 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Takes a file system block number and reads it into BUFFER. */
|
||||
static int
|
||||
ext2_rdfsb (int fsblock, int buffer)
|
||||
{
|
||||
#ifdef E2DEBUG
|
||||
printf ("fsblock %d buffer %d\n", fsblock, buffer);
|
||||
#endif /* E2DEBUG */
|
||||
return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
|
||||
EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
|
||||
}
|
||||
|
||||
/* from
|
||||
ext2/inode.c:ext2_bmap()
|
||||
*/
|
||||
/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
|
||||
a physical block (the location in the file system) via an inode. */
|
||||
static int
|
||||
ext2fs_block_map (int logical_block)
|
||||
{
|
||||
|
||||
#ifdef E2DEBUG
|
||||
unsigned char *i;
|
||||
for (i = (unsigned char *) INODE;
|
||||
i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
|
||||
i++)
|
||||
{
|
||||
printf ("%c", "0123456789abcdef"[*i >> 4]);
|
||||
printf ("%c", "0123456789abcdef"[*i % 16]);
|
||||
if (!((i + 1 - (unsigned char *) INODE) % 16))
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
printf ("logical block %d\n", logical_block);
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
/* if it is directly pointed to by the inode, return that physical addr */
|
||||
if (logical_block < EXT2_NDIR_BLOCKS)
|
||||
{
|
||||
#ifdef E2DEBUG
|
||||
printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
|
||||
printf ("returning %d\n", INODE->i_block[logical_block]);
|
||||
#endif /* E2DEBUG */
|
||||
return INODE->i_block[logical_block];
|
||||
}
|
||||
/* else */
|
||||
logical_block -= EXT2_NDIR_BLOCKS;
|
||||
/* try the indirect block */
|
||||
if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
|
||||
{
|
||||
if (mapblock1 != 1
|
||||
&& !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock1 = 1;
|
||||
return ((__u32 *) DATABLOCK1)[logical_block];
|
||||
}
|
||||
/* else */
|
||||
logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
|
||||
/* now try the double indirect block */
|
||||
if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
|
||||
{
|
||||
int bnum;
|
||||
if (mapblock1 != 2
|
||||
&& !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock1 = 2;
|
||||
if ((bnum = (((__u32 *) DATABLOCK1)
|
||||
[logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
|
||||
!= mapblock2
|
||||
&& !ext2_rdfsb (bnum, DATABLOCK2))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock2 = bnum;
|
||||
return ((__u32 *) DATABLOCK2)
|
||||
[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
|
||||
}
|
||||
/* else */
|
||||
mapblock2 = -1;
|
||||
logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
|
||||
if (mapblock1 != 3
|
||||
&& !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock1 = 3;
|
||||
if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
|
||||
[logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
|
||||
* 2)],
|
||||
DATABLOCK2))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
|
||||
[(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
|
||||
& (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
|
||||
DATABLOCK2))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
return ((__u32 *) DATABLOCK2)
|
||||
[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
|
||||
}
|
||||
|
||||
/* preconditions: all preconds of ext2fs_block_map */
|
||||
int
|
||||
ext2fs_read (char *buf, int len)
|
||||
{
|
||||
int logical_block;
|
||||
int offset;
|
||||
int map;
|
||||
int ret = 0;
|
||||
int size = 0;
|
||||
|
||||
#ifdef E2DEBUG
|
||||
static char hexdigit[] = "0123456789abcdef";
|
||||
unsigned char *i;
|
||||
for (i = (unsigned char *) INODE;
|
||||
i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
|
||||
i++)
|
||||
{
|
||||
printf ("%c", hexdigit[*i >> 4]);
|
||||
printf ("%c", hexdigit[*i % 16]);
|
||||
if (!((i + 1 - (unsigned char *) INODE) % 16))
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
#endif /* E2DEBUG */
|
||||
while (len > 0)
|
||||
{
|
||||
/* find the (logical) block component of our location */
|
||||
logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
|
||||
offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
|
||||
map = ext2fs_block_map (logical_block);
|
||||
#ifdef E2DEBUG
|
||||
printf ("map=%d\n", map);
|
||||
#endif /* E2DEBUG */
|
||||
if (map < 0)
|
||||
break;
|
||||
|
||||
size = EXT2_BLOCK_SIZE (SUPERBLOCK);
|
||||
size -= offset;
|
||||
if (size > len)
|
||||
size = len;
|
||||
|
||||
disk_read_func = disk_read_hook;
|
||||
|
||||
devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
|
||||
offset, size, buf);
|
||||
|
||||
disk_read_func = NULL;
|
||||
|
||||
buf += size;
|
||||
len -= size;
|
||||
filepos += size;
|
||||
ret += size;
|
||||
}
|
||||
|
||||
if (errnum)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Based on:
|
||||
def_blk_fops points to
|
||||
blkdev_open, which calls (I think):
|
||||
sys_open()
|
||||
do_open()
|
||||
open_namei()
|
||||
dir_namei() which accesses current->fs->root
|
||||
fs->root was set during original mount:
|
||||
(something)... which calls (I think):
|
||||
ext2_read_super()
|
||||
iget()
|
||||
__iget()
|
||||
read_inode()
|
||||
ext2_read_inode()
|
||||
uses desc_per_block_bits, which is set in ext2_read_super()
|
||||
also uses group descriptors loaded during ext2_read_super()
|
||||
lookup()
|
||||
ext2_lookup()
|
||||
ext2_find_entry()
|
||||
ext2_getblk()
|
||||
|
||||
*/
|
||||
|
||||
/* preconditions: ext2fs_mount already executed, therefore supblk in buffer
|
||||
* known as SUPERBLOCK
|
||||
* returns: 0 if error, nonzero iff we were able to find the file successfully
|
||||
* postconditions: on a nonzero return, buffer known as INODE contains the
|
||||
* inode of the file we were trying to look up
|
||||
* side effects: messes up GROUP_DESC buffer area
|
||||
*/
|
||||
int
|
||||
ext2fs_dir (char *dirname)
|
||||
{
|
||||
int current_ino = EXT2_ROOT_INO; /* start at the root */
|
||||
int updir_ino = current_ino; /* the parent of the current directory */
|
||||
int group_id; /* which group the inode is in */
|
||||
int group_desc; /* fs pointer to that group */
|
||||
int desc; /* index within that group */
|
||||
int ino_blk; /* fs pointer of the inode's information */
|
||||
int str_chk = 0; /* used to hold the results of a string compare */
|
||||
struct ext2_group_desc *gdp;
|
||||
struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */
|
||||
|
||||
char linkbuf[PATH_MAX]; /* buffer for following symbolic links */
|
||||
int link_count = 0;
|
||||
|
||||
char *rest;
|
||||
char ch; /* temp char holder */
|
||||
|
||||
int off; /* offset within block of directory entry (off mod blocksize) */
|
||||
int loc; /* location within a directory */
|
||||
int blk; /* which data blk within dir entry (off div blocksize) */
|
||||
long map; /* fs pointer of a particular block from dir entry */
|
||||
struct ext2_dir_entry *dp; /* pointer to directory entry */
|
||||
#ifdef E2DEBUG
|
||||
unsigned char *i;
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
/* loop invariants:
|
||||
current_ino = inode to lookup
|
||||
dirname = pointer to filename component we are cur looking up within
|
||||
the directory known pointed to by current_ino (if any)
|
||||
*/
|
||||
|
||||
while (1)
|
||||
{
|
||||
#ifdef E2DEBUG
|
||||
printf ("inode %d\n", current_ino);
|
||||
printf ("dirname=%s\n", dirname);
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
/* look up an inode */
|
||||
group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
|
||||
group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
|
||||
desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
|
||||
#ifdef E2DEBUG
|
||||
printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group,
|
||||
EXT2_DESC_PER_BLOCK (SUPERBLOCK));
|
||||
printf ("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc);
|
||||
#endif /* E2DEBUG */
|
||||
if (!ext2_rdfsb (
|
||||
(WHICH_SUPER + group_desc + SUPERBLOCK->s_first_data_block),
|
||||
(int) GROUP_DESC))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
gdp = GROUP_DESC;
|
||||
ino_blk = gdp[desc].bg_inode_table +
|
||||
(((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
|
||||
>> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
|
||||
#ifdef E2DEBUG
|
||||
printf ("inode table fsblock=%d\n", ino_blk);
|
||||
#endif /* E2DEBUG */
|
||||
if (!ext2_rdfsb (ino_blk, (int) INODE))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reset indirect blocks! */
|
||||
mapblock2 = mapblock1 = -1;
|
||||
|
||||
raw_inode = INODE +
|
||||
((current_ino - 1)
|
||||
& (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
|
||||
#ifdef E2DEBUG
|
||||
printf ("ipb=%d, sizeof(inode)=%d\n",
|
||||
(EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
|
||||
sizeof (struct ext2_inode));
|
||||
printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
|
||||
printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
|
||||
for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
|
||||
i++)
|
||||
{
|
||||
printf ("%c", "0123456789abcdef"[*i >> 4]);
|
||||
printf ("%c", "0123456789abcdef"[*i % 16]);
|
||||
if (!((i + 1 - (unsigned char *) INODE) % 16))
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
printf ("first word=%x\n", *((int *) raw_inode));
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
/* copy inode to fixed location */
|
||||
memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
|
||||
|
||||
#ifdef E2DEBUG
|
||||
printf ("first word=%x\n", *((int *) INODE));
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
/* If we've got a symbolic link, then chase it. */
|
||||
if (S_ISLNK (INODE->i_mode))
|
||||
{
|
||||
int len;
|
||||
if (++link_count > MAX_LINK_COUNT)
|
||||
{
|
||||
errnum = ERR_SYMLINK_LOOP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find out how long our remaining name is. */
|
||||
len = 0;
|
||||
while (dirname[len] && !isspace (dirname[len]))
|
||||
len++;
|
||||
|
||||
/* Get the symlink size. */
|
||||
filemax = (INODE->i_size);
|
||||
if (filemax + len > sizeof (linkbuf) - 2)
|
||||
{
|
||||
errnum = ERR_FILELENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
/* Copy the remaining name to the end of the symlink data.
|
||||
Note that DIRNAME and LINKBUF may overlap! */
|
||||
memmove (linkbuf + filemax, dirname, len);
|
||||
}
|
||||
linkbuf[filemax + len] = '\0';
|
||||
|
||||
/* Read the symlink data. */
|
||||
if (INODE->i_blocks)
|
||||
{
|
||||
/* Read the necessary blocks, and reset the file pointer. */
|
||||
len = grub_read (linkbuf, filemax);
|
||||
filepos = 0;
|
||||
if (!len)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the data directly from the inode. */
|
||||
len = filemax;
|
||||
memmove (linkbuf, (char *) INODE->i_block, len);
|
||||
}
|
||||
|
||||
#ifdef E2DEBUG
|
||||
printf ("symlink=%s\n", linkbuf);
|
||||
#endif
|
||||
|
||||
dirname = linkbuf;
|
||||
if (*dirname == '/')
|
||||
{
|
||||
/* It's an absolute link, so look it up in root. */
|
||||
current_ino = EXT2_ROOT_INO;
|
||||
updir_ino = current_ino;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Relative, so look it up in our parent directory. */
|
||||
current_ino = updir_ino;
|
||||
}
|
||||
|
||||
/* Try again using the new name. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if end of filename, INODE points to the file's inode */
|
||||
if (!*dirname || isspace (*dirname))
|
||||
{
|
||||
if (!S_ISREG (INODE->i_mode))
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
filemax = (INODE->i_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* else we have to traverse a directory */
|
||||
updir_ino = current_ino;
|
||||
|
||||
/* skip over slashes */
|
||||
while (*dirname == '/')
|
||||
dirname++;
|
||||
|
||||
/* if this isn't a directory of sufficient size to hold our file, abort */
|
||||
if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip to next slash or end of filename (space) */
|
||||
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
|
||||
rest++);
|
||||
|
||||
/* look through this directory and find the next filename component */
|
||||
/* invariant: rest points to slash after the next filename component */
|
||||
*rest = 0;
|
||||
loc = 0;
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
#ifdef E2DEBUG
|
||||
printf ("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
/* if our location/byte offset into the directory exceeds the size,
|
||||
give up */
|
||||
if (loc >= INODE->i_size)
|
||||
{
|
||||
if (print_possibilities < 0)
|
||||
{
|
||||
# if 0
|
||||
putchar ('\n');
|
||||
# endif
|
||||
}
|
||||
else
|
||||
{
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
*rest = ch;
|
||||
}
|
||||
return (print_possibilities < 0);
|
||||
}
|
||||
|
||||
/* else, find the (logical) block component of our location */
|
||||
blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
|
||||
|
||||
/* we know which logical block of the directory entry we are looking
|
||||
for, now we have to translate that to the physical (fs) block on
|
||||
the disk */
|
||||
map = ext2fs_block_map (blk);
|
||||
#ifdef E2DEBUG
|
||||
printf ("fs block=%d\n", map);
|
||||
#endif /* E2DEBUG */
|
||||
mapblock2 = -1;
|
||||
if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
*rest = ch;
|
||||
return 0;
|
||||
}
|
||||
off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
|
||||
dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
|
||||
/* advance loc prematurely to next on-disk directory entry */
|
||||
loc += dp->rec_len;
|
||||
|
||||
/* NOTE: ext2fs filenames are NOT null-terminated */
|
||||
|
||||
#ifdef E2DEBUG
|
||||
printf ("directory entry ino=%d\n", dp->inode);
|
||||
if (dp->inode)
|
||||
printf ("entry=%s\n", dp->name);
|
||||
#endif /* E2DEBUG */
|
||||
|
||||
if (dp->inode)
|
||||
{
|
||||
int saved_c = dp->name[dp->name_len];
|
||||
|
||||
dp->name[dp->name_len] = 0;
|
||||
str_chk = substring (dirname, dp->name);
|
||||
|
||||
# ifndef STAGE1_5
|
||||
if (print_possibilities && ch != '/'
|
||||
&& (!*dirname || str_chk <= 0))
|
||||
{
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (dp->name);
|
||||
}
|
||||
# endif
|
||||
|
||||
dp->name[dp->name_len] = saved_c;
|
||||
}
|
||||
|
||||
}
|
||||
while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
|
||||
|
||||
current_ino = dp->inode;
|
||||
*(dirname = rest) = ch;
|
||||
}
|
||||
/* never get here */
|
||||
}
|
||||
|
||||
#endif /* FSYS_EXT2_FS */
|
|
@ -1,494 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef FSYS_FAT
|
||||
|
||||
#include "shared.h"
|
||||
#include "filesys.h"
|
||||
#include "fat.h"
|
||||
#include <lib.h>
|
||||
#include "string.h"
|
||||
|
||||
struct fat_superblock
|
||||
{
|
||||
int fat_offset;
|
||||
int fat_length;
|
||||
int fat_size;
|
||||
int root_offset;
|
||||
int root_max;
|
||||
int data_offset;
|
||||
|
||||
int num_sectors;
|
||||
int num_clust;
|
||||
int clust_eof_marker;
|
||||
int sects_per_clust;
|
||||
int sectsize_bits;
|
||||
int clustsize_bits;
|
||||
int root_cluster;
|
||||
|
||||
int cached_fat;
|
||||
int file_cluster;
|
||||
int current_cluster_num;
|
||||
int current_cluster;
|
||||
};
|
||||
|
||||
/* pointer(s) into filesystem info buffer for DOS stuff */
|
||||
#define FAT_SUPER ( (struct fat_superblock *) \
|
||||
( FSYS_BUF + 32256) )/* 512 bytes long */
|
||||
#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */
|
||||
#define NAME_BUF ( FSYS_BUF + 29184 ) /* Filename buffer (833 bytes) */
|
||||
|
||||
#define FAT_CACHE_SIZE 2048
|
||||
|
||||
static __inline__ unsigned long
|
||||
log2 (unsigned long word)
|
||||
{
|
||||
__asm__ ("bsfl %1,%0"
|
||||
: "=r" (word)
|
||||
: "r" (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
int
|
||||
fat_mount (void)
|
||||
{
|
||||
struct fat_bpb bpb;
|
||||
__u32 magic, first_fat;
|
||||
|
||||
/* Check partition type for harddisk */
|
||||
if (((current_drive & 0x80) || (current_slice != 0))
|
||||
&& ! IS_PC_SLICE_TYPE_FAT (current_slice)
|
||||
&& (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_MSDOS)))
|
||||
return 0;
|
||||
|
||||
/* Read bpb */
|
||||
if (! devread (0, 0, sizeof (bpb), (char *) &bpb))
|
||||
return 0;
|
||||
|
||||
/* Check if the number of sectors per cluster is zero here, to avoid
|
||||
zero division. */
|
||||
if (bpb.sects_per_clust == 0)
|
||||
return 0;
|
||||
|
||||
FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect));
|
||||
FAT_SUPER->clustsize_bits
|
||||
= FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust);
|
||||
|
||||
/* Fill in info about super block */
|
||||
FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors)
|
||||
? FAT_CVT_U16 (bpb.short_sectors) : bpb.long_sectors;
|
||||
|
||||
/* FAT offset and length */
|
||||
FAT_SUPER->fat_offset = FAT_CVT_U16 (bpb.reserved_sects);
|
||||
FAT_SUPER->fat_length =
|
||||
bpb.fat_length ? bpb.fat_length : bpb.fat32_length;
|
||||
|
||||
/* Rootdir offset and length for FAT12/16 */
|
||||
FAT_SUPER->root_offset =
|
||||
FAT_SUPER->fat_offset + bpb.num_fats * FAT_SUPER->fat_length;
|
||||
FAT_SUPER->root_max = FAT_DIRENTRY_LENGTH * FAT_CVT_U16(bpb.dir_entries);
|
||||
|
||||
/* Data offset and number of clusters */
|
||||
FAT_SUPER->data_offset =
|
||||
FAT_SUPER->root_offset
|
||||
+ ((FAT_SUPER->root_max - 1) >> FAT_SUPER->sectsize_bits) + 1;
|
||||
FAT_SUPER->num_clust =
|
||||
2 + ((FAT_SUPER->num_sectors - FAT_SUPER->data_offset)
|
||||
/ bpb.sects_per_clust);
|
||||
FAT_SUPER->sects_per_clust = bpb.sects_per_clust;
|
||||
|
||||
if (!bpb.fat_length)
|
||||
{
|
||||
/* This is a FAT32 */
|
||||
if (FAT_CVT_U16(bpb.dir_entries))
|
||||
return 0;
|
||||
|
||||
if (bpb.flags & 0x0080)
|
||||
{
|
||||
/* FAT mirroring is disabled, get active FAT */
|
||||
int active_fat = bpb.flags & 0x000f;
|
||||
if (active_fat >= bpb.num_fats)
|
||||
return 0;
|
||||
FAT_SUPER->fat_offset += active_fat * FAT_SUPER->fat_length;
|
||||
}
|
||||
|
||||
FAT_SUPER->fat_size = 8;
|
||||
FAT_SUPER->root_cluster = bpb.root_cluster;
|
||||
|
||||
/* Yes the following is correct. FAT32 should be called FAT28 :) */
|
||||
FAT_SUPER->clust_eof_marker = 0xffffff8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FAT_SUPER->root_max)
|
||||
return 0;
|
||||
|
||||
FAT_SUPER->root_cluster = -1;
|
||||
if (FAT_SUPER->num_clust > FAT_MAX_12BIT_CLUST)
|
||||
{
|
||||
FAT_SUPER->fat_size = 4;
|
||||
FAT_SUPER->clust_eof_marker = 0xfff8;
|
||||
}
|
||||
else
|
||||
{
|
||||
FAT_SUPER->fat_size = 3;
|
||||
FAT_SUPER->clust_eof_marker = 0xff8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now do some sanity checks */
|
||||
|
||||
if (FAT_CVT_U16(bpb.bytes_per_sect) != (1 << FAT_SUPER->sectsize_bits)
|
||||
|| FAT_CVT_U16(bpb.bytes_per_sect) != SECTOR_SIZE
|
||||
|| bpb.sects_per_clust != (1 << (FAT_SUPER->clustsize_bits
|
||||
- FAT_SUPER->sectsize_bits))
|
||||
|| FAT_SUPER->num_clust <= 2
|
||||
|| (FAT_SUPER->fat_size * FAT_SUPER->num_clust / (2 * SECTOR_SIZE)
|
||||
> FAT_SUPER->fat_length))
|
||||
return 0;
|
||||
|
||||
/* kbs: Media check on first FAT entry [ported from PUPA] */
|
||||
|
||||
if (!devread(FAT_SUPER->fat_offset, 0,
|
||||
sizeof(first_fat), (char *)&first_fat))
|
||||
return 0;
|
||||
|
||||
if (FAT_SUPER->fat_size == 8)
|
||||
{
|
||||
first_fat &= 0x0fffffff;
|
||||
magic = 0x0fffff00;
|
||||
}
|
||||
else if (FAT_SUPER->fat_size == 4)
|
||||
{
|
||||
first_fat &= 0x0000ffff;
|
||||
magic = 0xff00;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_fat &= 0x00000fff;
|
||||
magic = 0x0f00;
|
||||
}
|
||||
|
||||
if (first_fat != (magic | bpb.media))
|
||||
return 0;
|
||||
|
||||
FAT_SUPER->cached_fat = - 2 * FAT_CACHE_SIZE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fat_read (char *buf, int len)
|
||||
{
|
||||
int logical_clust;
|
||||
int offset;
|
||||
int ret = 0;
|
||||
int size;
|
||||
int count = 64;
|
||||
|
||||
if (FAT_SUPER->file_cluster < 0)
|
||||
{
|
||||
/* root directory for fat16 */
|
||||
size = FAT_SUPER->root_max - filepos;
|
||||
if (size > len)
|
||||
size = len;
|
||||
if (!devread(FAT_SUPER->root_offset, filepos, size, buf))
|
||||
return 0;
|
||||
filepos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
logical_clust = filepos >> FAT_SUPER->clustsize_bits;
|
||||
offset = (filepos & ((1 << FAT_SUPER->clustsize_bits) - 1));
|
||||
if (logical_clust < FAT_SUPER->current_cluster_num)
|
||||
{
|
||||
FAT_SUPER->current_cluster_num = 0;
|
||||
FAT_SUPER->current_cluster = FAT_SUPER->file_cluster;
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
int sector;
|
||||
while (logical_clust > FAT_SUPER->current_cluster_num)
|
||||
{
|
||||
/* calculate next cluster */
|
||||
int fat_entry =
|
||||
FAT_SUPER->current_cluster * FAT_SUPER->fat_size;
|
||||
int next_cluster;
|
||||
int cached_pos = (fat_entry - FAT_SUPER->cached_fat);
|
||||
|
||||
if (cached_pos < 0 ||
|
||||
(cached_pos + FAT_SUPER->fat_size) > 2*FAT_CACHE_SIZE)
|
||||
{
|
||||
FAT_SUPER->cached_fat = (fat_entry & ~(2*SECTOR_SIZE - 1));
|
||||
cached_pos = (fat_entry - FAT_SUPER->cached_fat);
|
||||
sector = FAT_SUPER->fat_offset
|
||||
+ FAT_SUPER->cached_fat / (2*SECTOR_SIZE);
|
||||
if (!devread (sector, 0, FAT_CACHE_SIZE, (char*) FAT_BUF))
|
||||
return 0;
|
||||
}
|
||||
next_cluster = * (unsigned long *) (FAT_BUF + (cached_pos >> 1));
|
||||
if (FAT_SUPER->fat_size == 3)
|
||||
{
|
||||
if (cached_pos & 1)
|
||||
next_cluster >>= 4;
|
||||
next_cluster &= 0xFFF;
|
||||
}
|
||||
else if (FAT_SUPER->fat_size == 4)
|
||||
next_cluster &= 0xFFFF;
|
||||
|
||||
if (next_cluster >= FAT_SUPER->clust_eof_marker)
|
||||
return ret;
|
||||
if (next_cluster < 2 || next_cluster >= FAT_SUPER->num_clust)
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FAT_SUPER->current_cluster = next_cluster;
|
||||
FAT_SUPER->current_cluster_num++;
|
||||
}
|
||||
|
||||
sector = FAT_SUPER->data_offset +
|
||||
((FAT_SUPER->current_cluster - 2) << (FAT_SUPER->clustsize_bits
|
||||
- FAT_SUPER->sectsize_bits));
|
||||
size = (1 << FAT_SUPER->clustsize_bits) - offset;
|
||||
if (size > len)
|
||||
size = len;
|
||||
|
||||
disk_read_func = disk_read_hook;
|
||||
|
||||
devread(sector, offset, size, buf);
|
||||
|
||||
disk_read_func = NULL;
|
||||
|
||||
len -= size;
|
||||
buf += size;
|
||||
ret += size;
|
||||
filepos += size;
|
||||
logical_clust++;
|
||||
offset = 0;
|
||||
if(count--==0) {
|
||||
count = 32;
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
|
||||
// printf("\n");
|
||||
return errnum ? 0 : ret;
|
||||
}
|
||||
|
||||
int
|
||||
fat_dir (char *dirname)
|
||||
{
|
||||
char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH];
|
||||
char *filename = (char *) NAME_BUF;
|
||||
int attrib = FAT_ATTRIB_DIR;
|
||||
#ifndef STAGE1_5
|
||||
int do_possibilities = 0;
|
||||
#endif
|
||||
|
||||
/* XXX I18N:
|
||||
* the positions 2,4,6 etc are high bytes of a 16 bit unicode char
|
||||
*/
|
||||
static unsigned char longdir_pos[] =
|
||||
{ 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
|
||||
int slot = -2;
|
||||
int alias_checksum = -1;
|
||||
|
||||
FAT_SUPER->file_cluster = FAT_SUPER->root_cluster;
|
||||
filepos = 0;
|
||||
FAT_SUPER->current_cluster_num = MAXINT;
|
||||
|
||||
/* main loop to find desired directory entry */
|
||||
loop:
|
||||
|
||||
/* if we have a real file (and we're not just printing possibilities),
|
||||
then this is where we want to exit */
|
||||
|
||||
if (!*dirname || isspace (*dirname))
|
||||
{
|
||||
if (attrib & FAT_ATTRIB_DIR)
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* continue with the file/directory name interpretation */
|
||||
|
||||
while (*dirname == '/')
|
||||
dirname++;
|
||||
|
||||
if (!(attrib & FAT_ATTRIB_DIR))
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
/* Directories don't have a file size */
|
||||
filemax = MAXINT;
|
||||
|
||||
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
|
||||
|
||||
*rest = 0;
|
||||
|
||||
# ifndef STAGE1_5
|
||||
if (print_possibilities && ch != '/')
|
||||
do_possibilities = 1;
|
||||
# endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (fat_read (dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH
|
||||
|| dir_buf[0] == 0)
|
||||
{
|
||||
if (!errnum)
|
||||
{
|
||||
# ifndef STAGE1_5
|
||||
if (print_possibilities < 0)
|
||||
{
|
||||
#if 0
|
||||
putchar ('\n');
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
# endif /* STAGE1_5 */
|
||||
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
*rest = ch;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FAT_DIRENTRY_ATTRIB (dir_buf) == FAT_ATTRIB_LONGNAME)
|
||||
{
|
||||
/* This is a long filename. The filename is build from back
|
||||
* to front and may span multiple entries. To bind these
|
||||
* entries together they all contain the same checksum over
|
||||
* the short alias.
|
||||
*
|
||||
* The id field tells if this is the first entry (the last
|
||||
* part) of the long filename, and also at which offset this
|
||||
* belongs.
|
||||
*
|
||||
* We just write the part of the long filename this entry
|
||||
* describes and continue with the next dir entry.
|
||||
*/
|
||||
int i, offset;
|
||||
unsigned char id = FAT_LONGDIR_ID(dir_buf);
|
||||
|
||||
if ((id & 0x40))
|
||||
{
|
||||
id &= 0x3f;
|
||||
slot = id;
|
||||
filename[slot * 13] = 0;
|
||||
alias_checksum = FAT_LONGDIR_ALIASCHECKSUM(dir_buf);
|
||||
}
|
||||
|
||||
if (id != slot || slot == 0
|
||||
|| alias_checksum != FAT_LONGDIR_ALIASCHECKSUM(dir_buf))
|
||||
{
|
||||
alias_checksum = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
slot--;
|
||||
offset = slot * 13;
|
||||
|
||||
for (i=0; i < 13; i++)
|
||||
filename[offset+i] = dir_buf[longdir_pos[i]];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!FAT_DIRENTRY_VALID (dir_buf))
|
||||
continue;
|
||||
|
||||
if (alias_checksum != -1 && slot == 0)
|
||||
{
|
||||
int i;
|
||||
unsigned char sum;
|
||||
|
||||
slot = -2;
|
||||
for (sum = 0, i = 0; i< 11; i++)
|
||||
sum = ((sum >> 1) | (sum << 7)) + dir_buf[i];
|
||||
|
||||
if (sum == alias_checksum)
|
||||
{
|
||||
# ifndef STAGE1_5
|
||||
if (do_possibilities)
|
||||
goto print_filename;
|
||||
# endif /* STAGE1_5 */
|
||||
|
||||
if (substring (dirname, filename) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX convert to 8.3 filename format here */
|
||||
{
|
||||
int i, j, c;
|
||||
|
||||
for (i = 0; i < 8 && (c = filename[i] = tolower (dir_buf[i]))
|
||||
&& !isspace (c); i++);
|
||||
|
||||
filename[i++] = '.';
|
||||
|
||||
for (j = 0; j < 3 && (c = filename[i + j] = tolower (dir_buf[8 + j]))
|
||||
&& !isspace (c); j++);
|
||||
|
||||
if (j == 0)
|
||||
i--;
|
||||
|
||||
filename[i + j] = 0;
|
||||
}
|
||||
|
||||
# ifndef STAGE1_5
|
||||
if (do_possibilities)
|
||||
{
|
||||
print_filename:
|
||||
if (substring (dirname, filename) <= 0)
|
||||
{
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (filename);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
# endif /* STAGE1_5 */
|
||||
|
||||
if (substring (dirname, filename) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
*(dirname = rest) = ch;
|
||||
|
||||
attrib = FAT_DIRENTRY_ATTRIB (dir_buf);
|
||||
filemax = FAT_DIRENTRY_FILELENGTH (dir_buf);
|
||||
filepos = 0;
|
||||
FAT_SUPER->file_cluster = FAT_DIRENTRY_FIRST_CLUSTER (dir_buf);
|
||||
FAT_SUPER->current_cluster_num = MAXINT;
|
||||
|
||||
/* go back to main loop at top of function */
|
||||
goto loop;
|
||||
}
|
||||
|
||||
#endif /* FSYS_FAT */
|
|
@ -1,348 +0,0 @@
|
|||
/*
|
||||
* ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
|
||||
* including Rock Ridge Extensions support
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Kousuke Takai <tak@kmc.kyoto-u.ac.jp>
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
* References:
|
||||
* linux/fs/isofs/rock.[ch]
|
||||
* mkisofs-1.11.1/diag/isoinfo.c
|
||||
* mkisofs-1.11.1/iso9660.h
|
||||
* (all are written by Eric Youngdale)
|
||||
*
|
||||
* Modifications by:
|
||||
* Leonid Lisovskiy <lly@pisem.net> 2003
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified to make it work with FILO
|
||||
* 2003-10 by SONE Takeshi
|
||||
*/
|
||||
|
||||
#ifdef FSYS_ISO9660
|
||||
|
||||
#include <lib.h>
|
||||
#include "string.h"
|
||||
#include "shared.h"
|
||||
#include "filesys.h"
|
||||
#include "iso9660.h"
|
||||
#define DEBUG_THIS 1
|
||||
#include <debug.h>
|
||||
|
||||
struct iso_superblock {
|
||||
unsigned long vol_sector;
|
||||
|
||||
unsigned long file_start;
|
||||
};
|
||||
|
||||
#define ISO_SUPER ((struct iso_superblock *)(FSYS_BUF))
|
||||
#define PRIMDESC ((struct iso_primary_descriptor *)(FSYS_BUF + 2048))
|
||||
#define DIRREC ((struct iso_directory_record *)(FSYS_BUF + 4096))
|
||||
#define RRCONT_BUF ((unsigned char *)(FSYS_BUF + 6144))
|
||||
#define NAME_BUF ((unsigned char *)(FSYS_BUF + 8192))
|
||||
|
||||
|
||||
static inline unsigned long
|
||||
log2 (unsigned long word)
|
||||
{
|
||||
asm volatile ("bsfl %1,%0"
|
||||
: "=r" (word)
|
||||
: "r" (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
static int
|
||||
iso9660_devread (int sector, int byte_offset, int byte_len, char *buf)
|
||||
{
|
||||
/* FILO uses 512-byte "soft" sector, and ISO-9660 uses 2048-byte
|
||||
* CD-ROM sector */
|
||||
return devread(sector<<2, byte_offset, byte_len, buf);
|
||||
}
|
||||
|
||||
int
|
||||
iso9660_mount (void)
|
||||
{
|
||||
unsigned int sector;
|
||||
|
||||
/*
|
||||
* Because there is no defined slice type ID for ISO-9660 filesystem,
|
||||
* this test will pass only either (1) if entire disk is used, or
|
||||
* (2) if current partition is BSD style sub-partition whose ID is
|
||||
* ISO-9660.
|
||||
*/
|
||||
/*if ((current_partition != 0xFFFFFF)
|
||||
&& !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660))
|
||||
return 0;*/
|
||||
|
||||
/*
|
||||
* Currently, only FIRST session of MultiSession disks are supported !!!
|
||||
*/
|
||||
for (sector = 16 ; sector < 32 ; sector++)
|
||||
{
|
||||
if (!iso9660_devread(sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC))
|
||||
break;
|
||||
/* check ISO_VD_PRIMARY and ISO_STANDARD_ID */
|
||||
if (CHECK4(&PRIMDESC->type, ISO_VD_PRIMARY, 'C', 'D', '0')
|
||||
&& CHECK2(PRIMDESC->id + 3, '0', '1'))
|
||||
{
|
||||
ISO_SUPER->vol_sector = sector;
|
||||
ISO_SUPER->file_start = 0;
|
||||
fsmax = PRIMDESC->volume_space_size.l;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iso9660_dir (char *dirname)
|
||||
{
|
||||
struct iso_directory_record *idr;
|
||||
RR_ptr_t rr_ptr;
|
||||
struct rock_ridge *ce_ptr;
|
||||
unsigned int pathlen;
|
||||
int size;
|
||||
unsigned int extent;
|
||||
unsigned int rr_len;
|
||||
unsigned char file_type;
|
||||
unsigned char rr_flag;
|
||||
|
||||
idr = &PRIMDESC->root_directory_record;
|
||||
ISO_SUPER->file_start = 0;
|
||||
|
||||
do
|
||||
{
|
||||
while (*dirname == '/') /* skip leading slashes */
|
||||
dirname++;
|
||||
/* pathlen = strcspn(dirname, "/\n\t "); */
|
||||
for (pathlen = 0 ;
|
||||
dirname[pathlen]
|
||||
&& !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ;
|
||||
pathlen++)
|
||||
;
|
||||
|
||||
size = idr->size.l;
|
||||
extent = idr->extent.l;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
if (!iso9660_devread(extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return 0;
|
||||
}
|
||||
extent++;
|
||||
|
||||
idr = (struct iso_directory_record *)DIRREC;
|
||||
for (; idr->length.l > 0;
|
||||
idr = (struct iso_directory_record *)((char *)idr + idr->length.l) )
|
||||
{
|
||||
const char *name = idr->name;
|
||||
unsigned int name_len = idr->name_len.l;
|
||||
|
||||
file_type = (idr->flags.l & 2) ? ISO_DIRECTORY : ISO_REGULAR;
|
||||
if (name_len == 1)
|
||||
{
|
||||
if ((name[0] == 0) || /* self */
|
||||
(name[0] == 1)) /* parent */
|
||||
continue;
|
||||
}
|
||||
if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1'))
|
||||
{
|
||||
name_len -= 2; /* truncate trailing file version */
|
||||
if (name_len > 1 && name[name_len - 1] == '.')
|
||||
name_len--; /* truncate trailing dot */
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse Rock-Ridge extension
|
||||
*/
|
||||
rr_len = (idr->length.l - idr->name_len.l
|
||||
- (unsigned char)sizeof(struct iso_directory_record)
|
||||
+ (unsigned char)sizeof(idr->name));
|
||||
rr_ptr.ptr = ((unsigned char *)idr + idr->name_len.l
|
||||
+ sizeof(struct iso_directory_record)
|
||||
- sizeof(idr->name));
|
||||
if (rr_ptr.i & 1)
|
||||
rr_ptr.i++, rr_len--;
|
||||
ce_ptr = NULL;
|
||||
rr_flag = RR_FLAG_NM | RR_FLAG_PX;
|
||||
|
||||
while (rr_len >= 4)
|
||||
{
|
||||
if (rr_ptr.rr->version != 1)
|
||||
{
|
||||
#ifndef STAGE1_5
|
||||
if (debug)
|
||||
printf(
|
||||
"Non-supported version (%d) RockRidge chunk "
|
||||
"`%c%c'\n", rr_ptr.rr->version,
|
||||
rr_ptr.rr->signature & 0xFF,
|
||||
rr_ptr.rr->signature >> 8);
|
||||
#endif
|
||||
}
|
||||
else if (rr_ptr.rr->signature == RRMAGIC('R', 'R')
|
||||
&& rr_ptr.rr->len >= 5)
|
||||
rr_flag &= rr_ptr.rr->u.rr.flags.l;
|
||||
else if (rr_ptr.rr->signature == RRMAGIC('N', 'M'))
|
||||
{
|
||||
name = rr_ptr.rr->u.nm.name;
|
||||
name_len = rr_ptr.rr->len - 5;
|
||||
rr_flag &= ~RR_FLAG_NM;
|
||||
}
|
||||
else if (rr_ptr.rr->signature == RRMAGIC('P', 'X')
|
||||
&& rr_ptr.rr->len >= 36)
|
||||
{
|
||||
file_type = ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT)
|
||||
== POSIX_S_IFREG
|
||||
? ISO_REGULAR
|
||||
: ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT)
|
||||
== POSIX_S_IFDIR
|
||||
? ISO_DIRECTORY : ISO_OTHER));
|
||||
rr_flag &= ~RR_FLAG_PX;
|
||||
}
|
||||
else if (rr_ptr.rr->signature == RRMAGIC('C', 'E')
|
||||
&& rr_ptr.rr->len >= 28)
|
||||
ce_ptr = rr_ptr.rr;
|
||||
if (!rr_flag)
|
||||
/*
|
||||
* There is no more extension we expects...
|
||||
*/
|
||||
break;
|
||||
rr_len -= rr_ptr.rr->len;
|
||||
rr_ptr.ptr += rr_ptr.rr->len;
|
||||
if (rr_len < 4 && ce_ptr != NULL)
|
||||
{
|
||||
/* preserve name before loading new extent. */
|
||||
if( RRCONT_BUF <= (unsigned char *)name
|
||||
&& (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE )
|
||||
{
|
||||
memcpy(NAME_BUF, name, name_len);
|
||||
name = NAME_BUF;
|
||||
}
|
||||
rr_ptr.ptr = RRCONT_BUF + ce_ptr->u.ce.offset.l;
|
||||
rr_len = ce_ptr->u.ce.size.l;
|
||||
if (!iso9660_devread(ce_ptr->u.ce.extent.l, 0, ISO_SECTOR_SIZE, RRCONT_BUF))
|
||||
{
|
||||
errnum = 0; /* this is not fatal. */
|
||||
break;
|
||||
}
|
||||
ce_ptr = NULL;
|
||||
}
|
||||
} /* rr_len >= 4 */
|
||||
|
||||
filemax = MAXINT;
|
||||
if (name_len >= pathlen
|
||||
&& !__builtin_memcmp(name, dirname, pathlen))
|
||||
{
|
||||
if (dirname[pathlen] == '/' || !print_possibilities)
|
||||
{
|
||||
/*
|
||||
* DIRNAME is directory component of pathname,
|
||||
* or we are to open a file.
|
||||
*/
|
||||
if (pathlen == name_len)
|
||||
{
|
||||
if (dirname[pathlen] == '/')
|
||||
{
|
||||
if (file_type != ISO_DIRECTORY)
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
goto next_dir_level;
|
||||
}
|
||||
if (file_type != ISO_REGULAR)
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
ISO_SUPER->file_start = idr->extent.l;
|
||||
filepos = 0;
|
||||
filemax = idr->size.l;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else /* Completion */
|
||||
{
|
||||
#ifndef STAGE1_5
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
memcpy(NAME_BUF, name, name_len);
|
||||
NAME_BUF[name_len] = '\0';
|
||||
print_a_completion (NAME_BUF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} /* for */
|
||||
|
||||
size -= ISO_SECTOR_SIZE;
|
||||
} /* size>0 */
|
||||
|
||||
if (dirname[pathlen] == '/' || print_possibilities >= 0)
|
||||
{
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_dir_level:
|
||||
dirname += pathlen;
|
||||
|
||||
} while (*dirname == '/');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
iso9660_read (char *buf, int len)
|
||||
{
|
||||
int sector, blkoffset, size, ret;
|
||||
|
||||
if (ISO_SUPER->file_start == 0)
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
blkoffset = filepos & (ISO_SECTOR_SIZE - 1);
|
||||
sector = filepos >> ISO_SECTOR_BITS;
|
||||
while (len > 0)
|
||||
{
|
||||
size = ISO_SECTOR_SIZE - blkoffset;
|
||||
if (size > len)
|
||||
size = len;
|
||||
|
||||
disk_read_func = disk_read_hook;
|
||||
|
||||
if (!iso9660_devread(ISO_SUPER->file_start + sector, blkoffset, size, buf))
|
||||
return 0;
|
||||
|
||||
disk_read_func = NULL;
|
||||
|
||||
len -= size;
|
||||
buf += size;
|
||||
ret += size;
|
||||
filepos += size;
|
||||
sector++;
|
||||
blkoffset = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* FSYS_ISO9660 */
|
||||
|
|
@ -1,403 +0,0 @@
|
|||
/* fsys_jfs.c - an implementation for the IBM JFS file system */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2001,2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef FSYS_JFS
|
||||
|
||||
#include "shared.h"
|
||||
#include "filesys.h"
|
||||
#include "jfs.h"
|
||||
|
||||
#define MAX_LINK_COUNT 8
|
||||
|
||||
#define DTTYPE_INLINE 0
|
||||
#define DTTYPE_PAGE 1
|
||||
|
||||
struct jfs_info
|
||||
{
|
||||
int bsize;
|
||||
int l2bsize;
|
||||
int bdlog;
|
||||
int xindex;
|
||||
int xlastindex;
|
||||
int sindex;
|
||||
int slastindex;
|
||||
int de_index;
|
||||
int dttype;
|
||||
xad_t *xad;
|
||||
ldtentry_t *de;
|
||||
};
|
||||
|
||||
static struct jfs_info jfs;
|
||||
|
||||
#define xtpage ((xtpage_t *)FSYS_BUF)
|
||||
#define dtpage ((dtpage_t *)((char *)FSYS_BUF + 4096))
|
||||
#define fileset ((dinode_t *)((char *)FSYS_BUF + 8192))
|
||||
#define inode ((dinode_t *)((char *)FSYS_BUF + 8192 + sizeof(dinode_t)))
|
||||
#define dtroot ((dtroot_t *)(&inode->di_btroot))
|
||||
|
||||
static ldtentry_t de_always[2] = {
|
||||
{1, -1, 2, {'.', '.'}},
|
||||
{1, -1, 1, {'.'}}
|
||||
};
|
||||
|
||||
static int
|
||||
isinxt (s64 key, s64 offset, s64 len)
|
||||
{
|
||||
return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
|
||||
}
|
||||
|
||||
static xad_t *
|
||||
first_extent (dinode_t *di)
|
||||
{
|
||||
xtpage_t *xtp;
|
||||
|
||||
jfs.xindex = 2;
|
||||
xtp = (xtpage_t *)&di->di_btroot;
|
||||
jfs.xad = &xtp->xad[2];
|
||||
if (xtp->header.flag & BT_LEAF) {
|
||||
jfs.xlastindex = xtp->header.nextindex;
|
||||
} else {
|
||||
do {
|
||||
devread (addressXAD (jfs.xad) << jfs.bdlog, 0,
|
||||
sizeof(xtpage_t), (char *)xtpage);
|
||||
jfs.xad = &xtpage->xad[2];
|
||||
} while (!(xtpage->header.flag & BT_LEAF));
|
||||
jfs.xlastindex = xtpage->header.nextindex;
|
||||
}
|
||||
|
||||
return jfs.xad;
|
||||
}
|
||||
|
||||
static xad_t *
|
||||
next_extent (void)
|
||||
{
|
||||
if (++jfs.xindex < jfs.xlastindex) {
|
||||
} else if (xtpage->header.next) {
|
||||
devread (xtpage->header.next << jfs.bdlog, 0,
|
||||
sizeof(xtpage_t), (char *)xtpage);
|
||||
jfs.xlastindex = xtpage->header.nextindex;
|
||||
jfs.xindex = XTENTRYSTART;
|
||||
jfs.xad = &xtpage->xad[XTENTRYSTART];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return ++jfs.xad;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
di_read (u32 inum, dinode_t *di)
|
||||
{
|
||||
s64 key;
|
||||
u32 xd, ioffset;
|
||||
s64 offset;
|
||||
xad_t *xad;
|
||||
pxd_t pxd;
|
||||
|
||||
key = (((inum >> L2INOSPERIAG) << L2INOSPERIAG) + 4096) >> jfs.l2bsize;
|
||||
xd = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT;
|
||||
ioffset = ((inum & (INOSPERIAG - 1)) & (INOSPEREXT - 1)) << L2DISIZE;
|
||||
xad = first_extent (fileset);
|
||||
do {
|
||||
offset = offsetXAD (xad);
|
||||
if (isinxt (key, offset, lengthXAD (xad))) {
|
||||
devread ((addressXAD (xad) + key - offset) << jfs.bdlog,
|
||||
3072 + xd*sizeof(pxd_t), sizeof(pxd_t), (char *)&pxd);
|
||||
devread (addressPXD (&pxd) << jfs.bdlog,
|
||||
ioffset, DISIZE, (char *)di);
|
||||
break;
|
||||
}
|
||||
} while ((xad = next_extent ()));
|
||||
}
|
||||
|
||||
static ldtentry_t *
|
||||
next_dentry (void)
|
||||
{
|
||||
ldtentry_t *de;
|
||||
s8 *stbl;
|
||||
|
||||
if (jfs.dttype == DTTYPE_INLINE) {
|
||||
if (jfs.sindex < jfs.slastindex) {
|
||||
return (ldtentry_t *)&dtroot->slot[(int)dtroot->header.stbl[jfs.sindex++]];
|
||||
}
|
||||
} else {
|
||||
de = (ldtentry_t *)dtpage->slot;
|
||||
stbl = (s8 *)&de[(int)dtpage->header.stblindex];
|
||||
if (jfs.sindex < jfs.slastindex) {
|
||||
return &de[(int)stbl[jfs.sindex++]];
|
||||
} else if (dtpage->header.next) {
|
||||
devread (dtpage->header.next << jfs.bdlog, 0,
|
||||
sizeof(dtpage_t), (char *)dtpage);
|
||||
jfs.slastindex = dtpage->header.nextindex;
|
||||
jfs.sindex = 1;
|
||||
return &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]];
|
||||
}
|
||||
}
|
||||
|
||||
return (jfs.de_index < 2) ? &de_always[jfs.de_index++] : NULL;
|
||||
}
|
||||
|
||||
static ldtentry_t *
|
||||
first_dentry (void)
|
||||
{
|
||||
dtroot_t *dtr;
|
||||
pxd_t *xd;
|
||||
idtentry_t *de;
|
||||
|
||||
dtr = (dtroot_t *)&inode->di_btroot;
|
||||
jfs.sindex = 0;
|
||||
jfs.de_index = 0;
|
||||
|
||||
de_always[0].inumber = inode->di_parent;
|
||||
de_always[1].inumber = inode->di_number;
|
||||
if (dtr->header.flag & BT_LEAF) {
|
||||
jfs.dttype = DTTYPE_INLINE;
|
||||
jfs.slastindex = dtr->header.nextindex;
|
||||
} else {
|
||||
de = (idtentry_t *)dtpage->slot;
|
||||
jfs.dttype = DTTYPE_PAGE;
|
||||
xd = &((idtentry_t *)dtr->slot)[(int)dtr->header.stbl[0]].xd;
|
||||
for (;;) {
|
||||
devread (addressPXD (xd) << jfs.bdlog, 0,
|
||||
sizeof(dtpage_t), (char *)dtpage);
|
||||
if (dtpage->header.flag & BT_LEAF)
|
||||
break;
|
||||
xd = &de[(int)((s8 *)&de[(int)dtpage->header.stblindex])[0]].xd;
|
||||
}
|
||||
jfs.slastindex = dtpage->header.nextindex;
|
||||
}
|
||||
|
||||
return next_dentry ();
|
||||
}
|
||||
|
||||
|
||||
static dtslot_t *
|
||||
next_dslot (int next)
|
||||
{
|
||||
return (jfs.dttype == DTTYPE_INLINE)
|
||||
? (dtslot_t *)&dtroot->slot[next]
|
||||
: &((dtslot_t *)dtpage->slot)[next];
|
||||
}
|
||||
|
||||
static void
|
||||
uni2ansi (UniChar *uni, char *ansi, int len)
|
||||
{
|
||||
for (; len; len--, uni++)
|
||||
*ansi++ = (*uni & 0xff80) ? '?' : *(char *)uni;
|
||||
}
|
||||
|
||||
int
|
||||
jfs_mount (void)
|
||||
{
|
||||
struct jfs_superblock super;
|
||||
|
||||
if (part_length < MINJFS >> SECTOR_BITS
|
||||
|| !devread (SUPER1_OFF >> SECTOR_BITS, 0,
|
||||
sizeof(struct jfs_superblock), (char *)&super)
|
||||
|| (super.s_magic != JFS_MAGIC)
|
||||
|| !devread ((AITBL_OFF >> SECTOR_BITS) + FILESYSTEM_I,
|
||||
0, DISIZE, (char*)fileset)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
jfs.bsize = super.s_bsize;
|
||||
jfs.l2bsize = super.s_l2bsize;
|
||||
jfs.bdlog = jfs.l2bsize - SECTOR_BITS;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
jfs_read (char *buf, int len)
|
||||
{
|
||||
xad_t *xad;
|
||||
s64 endofprev, endofcur;
|
||||
s64 offset, xadlen;
|
||||
int toread, startpos, endpos;
|
||||
|
||||
startpos = filepos;
|
||||
endpos = filepos + len;
|
||||
endofprev = (1ULL << 62) - 1;
|
||||
xad = first_extent (inode);
|
||||
do {
|
||||
offset = offsetXAD (xad);
|
||||
xadlen = lengthXAD (xad);
|
||||
if (isinxt (filepos >> jfs.l2bsize, offset, xadlen)) {
|
||||
endofcur = (offset + xadlen) << jfs.l2bsize;
|
||||
toread = (endofcur >= endpos)
|
||||
? len : (endofcur - filepos);
|
||||
|
||||
disk_read_func = disk_read_hook;
|
||||
devread (addressXAD (xad) << jfs.bdlog,
|
||||
filepos - (offset << jfs.l2bsize), toread, buf);
|
||||
disk_read_func = NULL;
|
||||
|
||||
buf += toread;
|
||||
len -= toread;
|
||||
filepos += toread;
|
||||
} else if (offset > endofprev) {
|
||||
toread = ((offset << jfs.l2bsize) >= endpos)
|
||||
? len : ((offset - endofprev) << jfs.l2bsize);
|
||||
len -= toread;
|
||||
filepos += toread;
|
||||
for (; toread; toread--) {
|
||||
*buf++ = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
endofprev = offset + xadlen;
|
||||
xad = next_extent ();
|
||||
} while (len > 0 && xad);
|
||||
|
||||
return filepos - startpos;
|
||||
}
|
||||
|
||||
int
|
||||
jfs_dir (char *dirname)
|
||||
{
|
||||
char *ptr, *rest, ch;
|
||||
ldtentry_t *de;
|
||||
dtslot_t *ds;
|
||||
u32 inum, parent_inum;
|
||||
s64 di_size;
|
||||
u32 di_mode;
|
||||
int namlen, cmp, n, link_count;
|
||||
char namebuf[JFS_NAME_MAX + 1], linkbuf[JFS_PATH_MAX];
|
||||
|
||||
parent_inum = inum = ROOT_I;
|
||||
link_count = 0;
|
||||
for (;;) {
|
||||
di_read (inum, inode);
|
||||
di_size = inode->di_size;
|
||||
di_mode = inode->di_mode;
|
||||
|
||||
if ((di_mode & IFMT) == IFLNK) {
|
||||
if (++link_count > MAX_LINK_COUNT) {
|
||||
errnum = ERR_SYMLINK_LOOP;
|
||||
return 0;
|
||||
}
|
||||
if (di_size < (di_mode & INLINEEA ? 256 : 128)) {
|
||||
grub_memmove (linkbuf, inode->di_fastsymlink, di_size);
|
||||
n = di_size;
|
||||
} else if (di_size < JFS_PATH_MAX - 1) {
|
||||
filepos = 0;
|
||||
filemax = di_size;
|
||||
n = jfs_read (linkbuf, filemax);
|
||||
} else {
|
||||
errnum = ERR_FILELENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inum = (linkbuf[0] == '/') ? ROOT_I : parent_inum;
|
||||
while (n < (JFS_PATH_MAX - 1) && (linkbuf[n++] = *dirname++));
|
||||
linkbuf[n] = 0;
|
||||
dirname = linkbuf;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!*dirname || isspace (*dirname)) {
|
||||
if ((di_mode & IFMT) != IFREG) {
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
filepos = 0;
|
||||
filemax = di_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((di_mode & IFMT) != IFDIR) {
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; *dirname == '/'; dirname++);
|
||||
|
||||
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
|
||||
*rest = 0;
|
||||
|
||||
de = first_dentry ();
|
||||
for (;;) {
|
||||
namlen = de->namlen;
|
||||
if (de->next == -1) {
|
||||
uni2ansi (de->name, namebuf, namlen);
|
||||
namebuf[namlen] = 0;
|
||||
} else {
|
||||
uni2ansi (de->name, namebuf, DTLHDRDATALEN);
|
||||
ptr = namebuf;
|
||||
ptr += DTLHDRDATALEN;
|
||||
namlen -= DTLHDRDATALEN;
|
||||
ds = next_dslot (de->next);
|
||||
while (ds->next != -1) {
|
||||
uni2ansi (ds->name, ptr, DTSLOTDATALEN);
|
||||
ptr += DTSLOTDATALEN;
|
||||
namlen -= DTSLOTDATALEN;
|
||||
ds = next_dslot (ds->next);
|
||||
}
|
||||
uni2ansi (ds->name, ptr, namlen);
|
||||
ptr += namlen;
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
cmp = (!*dirname) ? -1 : substring (dirname, namebuf);
|
||||
#ifndef STAGE1_5
|
||||
if (print_possibilities && ch != '/'
|
||||
&& cmp <= 0) {
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (namebuf);
|
||||
} else
|
||||
#endif
|
||||
if (cmp == 0) {
|
||||
parent_inum = inum;
|
||||
inum = de->inumber;
|
||||
*(dirname = rest) = ch;
|
||||
break;
|
||||
}
|
||||
de = next_dentry ();
|
||||
if (de == NULL) {
|
||||
if (print_possibilities < 0)
|
||||
return 1;
|
||||
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
*rest = ch;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
jfs_embed (int *start_sector, int needed_sectors)
|
||||
{
|
||||
struct jfs_superblock super;
|
||||
|
||||
if (needed_sectors > 63
|
||||
|| !devread (SUPER1_OFF >> SECTOR_BITS, 0,
|
||||
sizeof (struct jfs_superblock),
|
||||
(char *)&super)
|
||||
|| (super.s_magic != JFS_MAGIC)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start_sector = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* FSYS_JFS */
|
|
@ -1,534 +0,0 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* Restrictions:
|
||||
This is MINIX V1 only (yet)
|
||||
Disk creation is like:
|
||||
mkfs.minix -c DEVICE
|
||||
*/
|
||||
|
||||
#ifdef FSYS_MINIX
|
||||
|
||||
#include "shared.h"
|
||||
#include "filesys.h"
|
||||
|
||||
/* #define DEBUG_MINIX */
|
||||
|
||||
/* indirect blocks */
|
||||
static int mapblock1, mapblock2, namelen;
|
||||
|
||||
/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
|
||||
#define DEV_BSIZE 512
|
||||
|
||||
/* include/linux/fs.h */
|
||||
#define BLOCK_SIZE_BITS 10
|
||||
#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
|
||||
|
||||
/* made up, defaults to 1 but can be passed via mount_opts */
|
||||
#define WHICH_SUPER 1
|
||||
/* kind of from fs/ext2/super.c (is OK for minix) */
|
||||
#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
|
||||
|
||||
/* include/asm-i386/type.h */
|
||||
typedef __signed__ char __s8;
|
||||
typedef unsigned char __u8;
|
||||
typedef __signed__ short __s16;
|
||||
typedef unsigned short __u16;
|
||||
typedef __signed__ int __s32;
|
||||
typedef unsigned int __u32;
|
||||
|
||||
/* include/linux/minix_fs.h */
|
||||
#define MINIX_ROOT_INO 1
|
||||
|
||||
/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
|
||||
#define MINIX_LINK_MAX 250
|
||||
#define MINIX2_LINK_MAX 65530
|
||||
|
||||
#define MINIX_I_MAP_SLOTS 8
|
||||
#define MINIX_Z_MAP_SLOTS 64
|
||||
#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
|
||||
#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
|
||||
#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
|
||||
#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
|
||||
#define MINIX_VALID_FS 0x0001 /* Clean fs. */
|
||||
#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
|
||||
|
||||
#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
|
||||
#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
|
||||
|
||||
#define MINIX_V1 0x0001 /* original minix fs */
|
||||
#define MINIX_V2 0x0002 /* minix V2 fs */
|
||||
|
||||
/* originally this is :
|
||||
#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
|
||||
here we have */
|
||||
#define INODE_VERSION(inode) (SUPERBLOCK->s_version)
|
||||
|
||||
/*
|
||||
* This is the original minix inode layout on disk.
|
||||
* Note the 8-bit gid and atime and ctime.
|
||||
*/
|
||||
struct minix_inode {
|
||||
__u16 i_mode;
|
||||
__u16 i_uid;
|
||||
__u32 i_size;
|
||||
__u32 i_time;
|
||||
__u8 i_gid;
|
||||
__u8 i_nlinks;
|
||||
__u16 i_zone[9];
|
||||
};
|
||||
|
||||
/*
|
||||
* The new minix inode has all the time entries, as well as
|
||||
* long block numbers and a third indirect block (7+1+1+1
|
||||
* instead of 7+1+1). Also, some previously 8-bit values are
|
||||
* now 16-bit. The inode is now 64 bytes instead of 32.
|
||||
*/
|
||||
struct minix2_inode {
|
||||
__u16 i_mode;
|
||||
__u16 i_nlinks;
|
||||
__u16 i_uid;
|
||||
__u16 i_gid;
|
||||
__u32 i_size;
|
||||
__u32 i_atime;
|
||||
__u32 i_mtime;
|
||||
__u32 i_ctime;
|
||||
__u32 i_zone[10];
|
||||
};
|
||||
|
||||
/*
|
||||
* minix super-block data on disk
|
||||
*/
|
||||
struct minix_super_block {
|
||||
__u16 s_ninodes;
|
||||
__u16 s_nzones;
|
||||
__u16 s_imap_blocks;
|
||||
__u16 s_zmap_blocks;
|
||||
__u16 s_firstdatazone;
|
||||
__u16 s_log_zone_size;
|
||||
__u32 s_max_size;
|
||||
__u16 s_magic;
|
||||
__u16 s_state;
|
||||
__u32 s_zones;
|
||||
};
|
||||
|
||||
struct minix_dir_entry {
|
||||
__u16 inode;
|
||||
char name[0];
|
||||
};
|
||||
|
||||
/* made up, these are pointers into FSYS_BUF */
|
||||
/* read once, always stays there: */
|
||||
#define SUPERBLOCK \
|
||||
((struct minix_super_block *)(FSYS_BUF))
|
||||
#define INODE \
|
||||
((struct minix_inode *)((int) SUPERBLOCK + BLOCK_SIZE))
|
||||
#define DATABLOCK1 \
|
||||
((int)((int)INODE + sizeof(struct minix_inode)))
|
||||
#define DATABLOCK2 \
|
||||
((int)((int)DATABLOCK1 + BLOCK_SIZE))
|
||||
|
||||
/* linux/stat.h */
|
||||
#define S_IFMT 00170000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
|
||||
#define PATH_MAX 1024 /* include/linux/limits.h */
|
||||
#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
|
||||
|
||||
/* check filesystem types and read superblock into memory buffer */
|
||||
int
|
||||
minix_mount (void)
|
||||
{
|
||||
if (((current_drive & 0x80) || current_slice != 0)
|
||||
&& ! IS_PC_SLICE_TYPE_MINIX (current_slice)
|
||||
&& ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
|
||||
return 0; /* The partition is not of MINIX type */
|
||||
|
||||
if (part_length < (SBLOCK +
|
||||
(sizeof (struct minix_super_block) / DEV_BSIZE)))
|
||||
return 0; /* The partition is too short */
|
||||
|
||||
if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
|
||||
(char *) SUPERBLOCK))
|
||||
return 0; /* Cannot read superblock */
|
||||
|
||||
switch (SUPERBLOCK->s_magic)
|
||||
{
|
||||
case MINIX_SUPER_MAGIC:
|
||||
namelen = 14;
|
||||
break;
|
||||
case MINIX_SUPER_MAGIC2:
|
||||
namelen = 30;
|
||||
break;
|
||||
default:
|
||||
return 0; /* Unsupported type */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Takes a file system block number and reads it into BUFFER. */
|
||||
static int
|
||||
minix_rdfsb (int fsblock, int buffer)
|
||||
{
|
||||
return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
|
||||
BLOCK_SIZE, (char *) buffer);
|
||||
}
|
||||
|
||||
/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
|
||||
a physical block (the location in the file system) via an inode. */
|
||||
static int
|
||||
minix_block_map (int logical_block)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (logical_block < 7)
|
||||
return INODE->i_zone[logical_block];
|
||||
|
||||
logical_block -= 7;
|
||||
if (logical_block < 512)
|
||||
{
|
||||
i = INODE->i_zone[7];
|
||||
|
||||
if (!i || ((mapblock1 != 1)
|
||||
&& !minix_rdfsb (i, DATABLOCK1)))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock1 = 1;
|
||||
return ((__u16 *) DATABLOCK1) [logical_block];
|
||||
}
|
||||
|
||||
logical_block -= 512;
|
||||
i = INODE->i_zone[8];
|
||||
if (!i || ((mapblock1 != 2)
|
||||
&& !minix_rdfsb (i, DATABLOCK1)))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock1 = 2;
|
||||
i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
|
||||
if (!i || ((mapblock2 != i)
|
||||
&& !minix_rdfsb (i, DATABLOCK2)))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
return -1;
|
||||
}
|
||||
mapblock2 = i;
|
||||
return ((__u16 *) DATABLOCK2)[logical_block & 511];
|
||||
}
|
||||
|
||||
/* read from INODE into BUF */
|
||||
int
|
||||
minix_read (char *buf, int len)
|
||||
{
|
||||
int logical_block;
|
||||
int offset;
|
||||
int map;
|
||||
int ret = 0;
|
||||
int size = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
/* find the (logical) block component of our location */
|
||||
logical_block = filepos >> BLOCK_SIZE_BITS;
|
||||
offset = filepos & (BLOCK_SIZE - 1);
|
||||
map = minix_block_map (logical_block);
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("map=%d\n", map);
|
||||
#endif
|
||||
if (map < 0)
|
||||
break;
|
||||
|
||||
size = BLOCK_SIZE;
|
||||
size -= offset;
|
||||
if (size > len)
|
||||
size = len;
|
||||
|
||||
disk_read_func = disk_read_hook;
|
||||
|
||||
devread (map * (BLOCK_SIZE / DEV_BSIZE),
|
||||
offset, size, buf);
|
||||
|
||||
disk_read_func = NULL;
|
||||
|
||||
buf += size;
|
||||
len -= size;
|
||||
filepos += size;
|
||||
ret += size;
|
||||
}
|
||||
|
||||
if (errnum)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* preconditions: minix_mount already executed, therefore supblk in buffer
|
||||
known as SUPERBLOCK
|
||||
returns: 0 if error, nonzero iff we were able to find the file successfully
|
||||
postconditions: on a nonzero return, buffer known as INODE contains the
|
||||
inode of the file we were trying to look up
|
||||
side effects: none yet */
|
||||
int
|
||||
minix_dir (char *dirname)
|
||||
{
|
||||
int current_ino = MINIX_ROOT_INO; /* start at the root */
|
||||
int updir_ino = current_ino; /* the parent of the current directory */
|
||||
int ino_blk; /* fs pointer of the inode's info */
|
||||
|
||||
int str_chk = 0; /* used ot hold the results of a string
|
||||
compare */
|
||||
|
||||
struct minix_inode * raw_inode; /* inode info for current_ino */
|
||||
|
||||
char linkbuf[PATH_MAX]; /* buffer for following sym-links */
|
||||
int link_count = 0;
|
||||
|
||||
char * rest;
|
||||
char ch;
|
||||
|
||||
int off; /* offset within block of directory
|
||||
entry */
|
||||
int loc; /* location within a directory */
|
||||
int blk; /* which data blk within dir entry */
|
||||
long map; /* fs pointer of a particular block from
|
||||
dir entry */
|
||||
struct minix_dir_entry * dp; /* pointer to directory entry */
|
||||
|
||||
/* loop invariants:
|
||||
current_ino = inode to lookup
|
||||
dirname = pointer to filename component we are cur looking up within
|
||||
the directory known pointed to by current_ino (if any) */
|
||||
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("inode %d, dirname %s\n", current_ino, dirname);
|
||||
#endif
|
||||
|
||||
ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
|
||||
+ (current_ino - 1) / MINIX_INODES_PER_BLOCK);
|
||||
if (! minix_rdfsb (ino_blk, (int) INODE))
|
||||
return 0;
|
||||
|
||||
/* reset indirect blocks! */
|
||||
mapblock2 = mapblock1 = -1;
|
||||
|
||||
raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
|
||||
|
||||
/* copy inode to fixed location */
|
||||
memmove ((void *) INODE, (void *) raw_inode,
|
||||
sizeof (struct minix_inode));
|
||||
|
||||
/* If we've got a symbolic link, then chase it. */
|
||||
if (S_ISLNK (INODE->i_mode))
|
||||
{
|
||||
int len;
|
||||
|
||||
if (++link_count > MAX_LINK_COUNT)
|
||||
{
|
||||
errnum = ERR_SYMLINK_LOOP;
|
||||
return 0;
|
||||
}
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("S_ISLNK (%s)\n", dirname);
|
||||
#endif
|
||||
|
||||
/* Find out how long our remaining name is. */
|
||||
len = 0;
|
||||
while (dirname[len] && !isspace (dirname[len]))
|
||||
len++;
|
||||
|
||||
/* Get the symlink size. */
|
||||
filemax = (INODE->i_size);
|
||||
if (filemax + len > sizeof (linkbuf) - 2)
|
||||
{
|
||||
errnum = ERR_FILELENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
/* Copy the remaining name to the end of the symlink data.
|
||||
Note that DIRNAME and LINKBUF may overlap! */
|
||||
memmove (linkbuf + filemax, dirname, len);
|
||||
}
|
||||
linkbuf[filemax + len] = '\0';
|
||||
|
||||
/* Read the necessary blocks, and reset the file pointer. */
|
||||
len = grub_read (linkbuf, filemax);
|
||||
filepos = 0;
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("symlink=%s\n", linkbuf);
|
||||
#endif
|
||||
|
||||
dirname = linkbuf;
|
||||
if (*dirname == '/')
|
||||
{
|
||||
/* It's an absolute link, so look it up in root. */
|
||||
current_ino = MINIX_ROOT_INO;
|
||||
updir_ino = current_ino;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Relative, so look it up in our parent directory. */
|
||||
current_ino = updir_ino;
|
||||
}
|
||||
|
||||
/* Try again using the new name. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If end of filename, INODE points to the file's inode */
|
||||
if (!*dirname || isspace (*dirname))
|
||||
{
|
||||
if (!S_ISREG (INODE->i_mode))
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
filemax = (INODE->i_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* else we have to traverse a directory */
|
||||
updir_ino = current_ino;
|
||||
|
||||
/* skip over slashes */
|
||||
while (*dirname == '/')
|
||||
dirname++;
|
||||
|
||||
/* if this isn't a directory of sufficient size to hold our file,
|
||||
abort */
|
||||
if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
|
||||
{
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip to next slash or end of filename (space) */
|
||||
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
|
||||
rest++);
|
||||
|
||||
/* look through this directory and find the next filename component */
|
||||
/* invariant: rest points to slash after the next filename component */
|
||||
*rest = 0;
|
||||
loc = 0;
|
||||
|
||||
do
|
||||
{
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
|
||||
#endif
|
||||
|
||||
/* if our location/byte offset into the directory exceeds the size,
|
||||
give up */
|
||||
if (loc >= INODE->i_size)
|
||||
{
|
||||
if (print_possibilities < 0)
|
||||
{
|
||||
#if 0
|
||||
putchar ('\n');
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
*rest = ch;
|
||||
}
|
||||
return (print_possibilities < 0);
|
||||
}
|
||||
|
||||
/* else, find the (logical) block component of our location */
|
||||
blk = loc >> BLOCK_SIZE_BITS;
|
||||
|
||||
/* we know which logical block of the directory entry we are looking
|
||||
for, now we have to translate that to the physical (fs) block on
|
||||
the disk */
|
||||
map = minix_block_map (blk);
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("fs block=%d\n", map);
|
||||
#endif
|
||||
mapblock2 = -1;
|
||||
if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
|
||||
{
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
*rest = ch;
|
||||
return 0;
|
||||
}
|
||||
off = loc & (BLOCK_SIZE - 1);
|
||||
dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
|
||||
/* advance loc prematurely to next on-disk directory entry */
|
||||
loc += sizeof (dp->inode) + namelen;
|
||||
|
||||
/* NOTE: minix filenames are NULL terminated if < NAMELEN
|
||||
else exact */
|
||||
|
||||
#ifdef DEBUG_MINIX
|
||||
printf ("directory entry ino=%d\n", dp->inode);
|
||||
if (dp->inode)
|
||||
printf ("entry=%s\n", dp->name);
|
||||
#endif
|
||||
|
||||
if (dp->inode)
|
||||
{
|
||||
int saved_c = dp->name[namelen];
|
||||
|
||||
dp->name[namelen] = 0;
|
||||
str_chk = substring (dirname, dp->name);
|
||||
|
||||
# ifndef STAGE1_5
|
||||
if (print_possibilities && ch != '/'
|
||||
&& (!*dirname || str_chk <= 0))
|
||||
{
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (dp->name);
|
||||
}
|
||||
# endif
|
||||
|
||||
dp->name[namelen] = saved_c;
|
||||
}
|
||||
|
||||
}
|
||||
while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
|
||||
|
||||
current_ino = dp->inode;
|
||||
*(dirname = rest) = ch;
|
||||
}
|
||||
/* never get here */
|
||||
}
|
||||
|
||||
#endif /* FSYS_MINIX */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,624 +0,0 @@
|
|||
/* fsys_xfs.c - an implementation for the SGI XFS file system */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2001,2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifdef FSYS_XFS
|
||||
|
||||
#include "shared.h"
|
||||
#include "filesys.h"
|
||||
#include "xfs.h"
|
||||
|
||||
#define MAX_LINK_COUNT 8
|
||||
|
||||
typedef struct xad {
|
||||
xfs_fileoff_t offset;
|
||||
xfs_fsblock_t start;
|
||||
xfs_filblks_t len;
|
||||
} xad_t;
|
||||
|
||||
struct xfs_info {
|
||||
int bsize;
|
||||
int dirbsize;
|
||||
int isize;
|
||||
unsigned int agblocks;
|
||||
int bdlog;
|
||||
int blklog;
|
||||
int inopblog;
|
||||
int agblklog;
|
||||
int agnolog;
|
||||
unsigned int nextents;
|
||||
xfs_daddr_t next;
|
||||
xfs_daddr_t daddr;
|
||||
xfs_dablk_t forw;
|
||||
xfs_dablk_t dablk;
|
||||
xfs_bmbt_rec_32_t *xt;
|
||||
xfs_bmbt_ptr_t ptr0;
|
||||
int btnode_ptr0_off;
|
||||
int i8param;
|
||||
int dirpos;
|
||||
int dirmax;
|
||||
int blkoff;
|
||||
int fpos;
|
||||
xfs_ino_t rootino;
|
||||
};
|
||||
|
||||
static struct xfs_info xfs;
|
||||
|
||||
#define dirbuf ((char *)FSYS_BUF)
|
||||
#define filebuf ((char *)FSYS_BUF + 4096)
|
||||
#define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
|
||||
#define icore (inode->di_core)
|
||||
|
||||
#define mask32lo(n) (((__uint32_t)1 << (n)) - 1)
|
||||
|
||||
#define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1))
|
||||
#define XFS_INO_OFFSET_BITS xfs.inopblog
|
||||
#define XFS_INO_AGBNO_BITS xfs.agblklog
|
||||
#define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog)
|
||||
#define XFS_INO_AGNO_BITS xfs.agnolog
|
||||
|
||||
static inline xfs_agblock_t
|
||||
agino2agbno (xfs_agino_t agino)
|
||||
{
|
||||
return agino >> XFS_INO_OFFSET_BITS;
|
||||
}
|
||||
|
||||
static inline xfs_agnumber_t
|
||||
ino2agno (xfs_ino_t ino)
|
||||
{
|
||||
return ino >> XFS_INO_AGINO_BITS;
|
||||
}
|
||||
|
||||
static inline xfs_agino_t
|
||||
ino2agino (xfs_ino_t ino)
|
||||
{
|
||||
return ino & XFS_INO_MASK(XFS_INO_AGINO_BITS);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ino2offset (xfs_ino_t ino)
|
||||
{
|
||||
return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
|
||||
}
|
||||
|
||||
static inline __const__ __uint16_t
|
||||
le16 (__uint16_t x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0" \
|
||||
: "=q" (x) \
|
||||
: "0" (x)); \
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __const__ __uint32_t
|
||||
le32 (__uint32_t x)
|
||||
{
|
||||
#if 0
|
||||
/* 386 doesn't have bswap. */
|
||||
__asm__("bswap %0" : "=r" (x) : "0" (x));
|
||||
#else
|
||||
/* This is slower but this works on all x86 architectures. */
|
||||
__asm__("xchgb %b0, %h0" \
|
||||
"\n\troll $16, %0" \
|
||||
"\n\txchgb %b0, %h0" \
|
||||
: "=q" (x) : "0" (x));
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __const__ __uint64_t
|
||||
le64 (__uint64_t x)
|
||||
{
|
||||
__uint32_t h = x >> 32;
|
||||
__uint32_t l = x & ((1ULL<<32)-1);
|
||||
return (((__uint64_t)le32(l)) << 32) | ((__uint64_t)(le32(h)));
|
||||
}
|
||||
|
||||
|
||||
static xfs_fsblock_t
|
||||
xt_start (xfs_bmbt_rec_32_t *r)
|
||||
{
|
||||
return (((xfs_fsblock_t)(le32 (r->l1) & mask32lo(9))) << 43) |
|
||||
(((xfs_fsblock_t)le32 (r->l2)) << 11) |
|
||||
(((xfs_fsblock_t)le32 (r->l3)) >> 21);
|
||||
}
|
||||
|
||||
static xfs_fileoff_t
|
||||
xt_offset (xfs_bmbt_rec_32_t *r)
|
||||
{
|
||||
return (((xfs_fileoff_t)le32 (r->l0) &
|
||||
mask32lo(31)) << 23) |
|
||||
(((xfs_fileoff_t)le32 (r->l1)) >> 9);
|
||||
}
|
||||
|
||||
static xfs_filblks_t
|
||||
xt_len (xfs_bmbt_rec_32_t *r)
|
||||
{
|
||||
return le32(r->l3) & mask32lo(21);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xfs_highbit32(__uint32_t v)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (--v) {
|
||||
for (i = 0; i < 31; i++, v >>= 1) {
|
||||
if (v == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
|
||||
{
|
||||
return (key >= offset) ? (key < offset + len ? 1 : 0) : 0;
|
||||
}
|
||||
|
||||
static xfs_daddr_t
|
||||
agb2daddr (xfs_agnumber_t agno, xfs_agblock_t agbno)
|
||||
{
|
||||
return ((xfs_fsblock_t)agno*xfs.agblocks + agbno) << xfs.bdlog;
|
||||
}
|
||||
|
||||
static xfs_daddr_t
|
||||
fsb2daddr (xfs_fsblock_t fsbno)
|
||||
{
|
||||
return agb2daddr ((xfs_agnumber_t)(fsbno >> xfs.agblklog),
|
||||
(xfs_agblock_t)(fsbno & mask32lo(xfs.agblklog)));
|
||||
}
|
||||
|
||||
#undef offsetof
|
||||
#define offsetof(t,m) ((int)&(((t *)0)->m))
|
||||
|
||||
static inline int
|
||||
btroot_maxrecs (void)
|
||||
{
|
||||
int tmp = icore.di_forkoff ? (icore.di_forkoff << 3) : xfs.isize;
|
||||
|
||||
return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
|
||||
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
|
||||
}
|
||||
|
||||
static int
|
||||
di_read (xfs_ino_t ino)
|
||||
{
|
||||
xfs_agino_t agino;
|
||||
xfs_agnumber_t agno;
|
||||
xfs_agblock_t agbno;
|
||||
xfs_daddr_t daddr;
|
||||
int offset;
|
||||
|
||||
agno = ino2agno (ino);
|
||||
agino = ino2agino (ino);
|
||||
agbno = agino2agbno (agino);
|
||||
offset = ino2offset (ino);
|
||||
daddr = agb2daddr (agno, agbno);
|
||||
|
||||
devread (daddr, offset*xfs.isize, xfs.isize, (char *)inode);
|
||||
|
||||
xfs.ptr0 = *(xfs_bmbt_ptr_t *)
|
||||
(inode->di_u.di_c + sizeof(xfs_bmdr_block_t)
|
||||
+ btroot_maxrecs ()*sizeof(xfs_bmbt_key_t));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
init_extents (void)
|
||||
{
|
||||
xfs_bmbt_ptr_t ptr0;
|
||||
xfs_btree_lblock_t h;
|
||||
|
||||
switch (icore.di_format) {
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
xfs.xt = inode->di_u.di_bmx;
|
||||
xfs.nextents = le32 (icore.di_nextents);
|
||||
break;
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
ptr0 = xfs.ptr0;
|
||||
for (;;) {
|
||||
xfs.daddr = fsb2daddr (le64(ptr0));
|
||||
devread (xfs.daddr, 0,
|
||||
sizeof(xfs_btree_lblock_t), (char *)&h);
|
||||
if (!h.bb_level) {
|
||||
xfs.nextents = le16(h.bb_numrecs);
|
||||
xfs.next = fsb2daddr (le64(h.bb_rightsib));
|
||||
xfs.fpos = sizeof(xfs_btree_block_t);
|
||||
return;
|
||||
}
|
||||
devread (xfs.daddr, xfs.btnode_ptr0_off,
|
||||
sizeof(xfs_bmbt_ptr_t), (char *)&ptr0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static xad_t *
|
||||
next_extent (void)
|
||||
{
|
||||
static xad_t xad;
|
||||
|
||||
switch (icore.di_format) {
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
if (xfs.nextents == 0)
|
||||
return NULL;
|
||||
break;
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
if (xfs.nextents == 0) {
|
||||
xfs_btree_lblock_t h;
|
||||
if (xfs.next == 0)
|
||||
return NULL;
|
||||
xfs.daddr = xfs.next;
|
||||
devread (xfs.daddr, 0, sizeof(xfs_btree_lblock_t), (char *)&h);
|
||||
xfs.nextents = le16(h.bb_numrecs);
|
||||
xfs.next = fsb2daddr (le64(h.bb_rightsib));
|
||||
xfs.fpos = sizeof(xfs_btree_block_t);
|
||||
}
|
||||
/* Yeah, I know that's slow, but I really don't care */
|
||||
devread (xfs.daddr, xfs.fpos, sizeof(xfs_bmbt_rec_t), filebuf);
|
||||
xfs.xt = (xfs_bmbt_rec_32_t *)filebuf;
|
||||
xfs.fpos += sizeof(xfs_bmbt_rec_32_t);
|
||||
}
|
||||
xad.offset = xt_offset (xfs.xt);
|
||||
xad.start = xt_start (xfs.xt);
|
||||
xad.len = xt_len (xfs.xt);
|
||||
++xfs.xt;
|
||||
--xfs.nextents;
|
||||
|
||||
return &xad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name lies - the function reads only first 100 bytes
|
||||
*/
|
||||
static void
|
||||
xfs_dabread (void)
|
||||
{
|
||||
xad_t *xad;
|
||||
xfs_fileoff_t offset;;
|
||||
|
||||
init_extents ();
|
||||
while ((xad = next_extent ())) {
|
||||
offset = xad->offset;
|
||||
if (isinxt (xfs.dablk, offset, xad->len)) {
|
||||
devread (fsb2daddr (xad->start + xfs.dablk - offset),
|
||||
0, 100, dirbuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline xfs_ino_t
|
||||
sf_ino (char *sfe, int namelen)
|
||||
{
|
||||
void *p = sfe + namelen + 3;
|
||||
|
||||
return (xfs.i8param == 0)
|
||||
? le64(*(xfs_ino_t *)p) : le32(*(__uint32_t *)p);
|
||||
}
|
||||
|
||||
static inline xfs_ino_t
|
||||
sf_parent_ino (void)
|
||||
{
|
||||
return (xfs.i8param == 0)
|
||||
? le64(*(xfs_ino_t *)(&inode->di_u.di_dir2sf.hdr.parent))
|
||||
: le32(*(__uint32_t *)(&inode->di_u.di_dir2sf.hdr.parent));
|
||||
}
|
||||
|
||||
static inline int
|
||||
roundup8 (int n)
|
||||
{
|
||||
return ((n+7)&~7);
|
||||
}
|
||||
|
||||
static char *
|
||||
next_dentry (xfs_ino_t *ino)
|
||||
{
|
||||
int namelen = 1;
|
||||
int toread;
|
||||
static char *usual[2] = {".", ".."};
|
||||
static xfs_dir2_sf_entry_t *sfe;
|
||||
char *name = usual[0];
|
||||
|
||||
if (xfs.dirpos >= xfs.dirmax) {
|
||||
if (xfs.forw == 0)
|
||||
return NULL;
|
||||
xfs.dablk = xfs.forw;
|
||||
xfs_dabread ();
|
||||
#define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
|
||||
xfs.dirmax = le16 (h->count) - le16 (h->stale);
|
||||
xfs.forw = le32 (h->info.forw);
|
||||
#undef h
|
||||
xfs.dirpos = 0;
|
||||
}
|
||||
|
||||
switch (icore.di_format) {
|
||||
case XFS_DINODE_FMT_LOCAL:
|
||||
switch (xfs.dirpos) {
|
||||
case -2:
|
||||
*ino = 0;
|
||||
break;
|
||||
case -1:
|
||||
*ino = sf_parent_ino ();
|
||||
++name;
|
||||
++namelen;
|
||||
sfe = (xfs_dir2_sf_entry_t *)
|
||||
(inode->di_u.di_c
|
||||
+ sizeof(xfs_dir2_sf_hdr_t)
|
||||
- xfs.i8param);
|
||||
break;
|
||||
default:
|
||||
namelen = sfe->namelen;
|
||||
*ino = sf_ino ((char *)sfe, namelen);
|
||||
name = sfe->name;
|
||||
sfe = (xfs_dir2_sf_entry_t *)
|
||||
((char *)sfe + namelen + 11 - xfs.i8param);
|
||||
}
|
||||
break;
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
#define dau ((xfs_dir2_data_union_t *)dirbuf)
|
||||
for (;;) {
|
||||
if (xfs.blkoff >= xfs.dirbsize) {
|
||||
xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
|
||||
filepos &= ~(xfs.dirbsize - 1);
|
||||
filepos |= xfs.blkoff;
|
||||
}
|
||||
xfs_read (dirbuf, 4);
|
||||
xfs.blkoff += 4;
|
||||
if (dau->unused.freetag == XFS_DIR2_DATA_FREE_TAG) {
|
||||
toread = roundup8 (le16(dau->unused.length)) - 4;
|
||||
xfs.blkoff += toread;
|
||||
filepos += toread;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
xfs_read ((char *)dirbuf + 4, 5);
|
||||
*ino = le64 (dau->entry.inumber);
|
||||
namelen = dau->entry.namelen;
|
||||
#undef dau
|
||||
toread = roundup8 (namelen + 11) - 9;
|
||||
xfs_read (dirbuf, toread);
|
||||
name = (char *)dirbuf;
|
||||
xfs.blkoff += toread + 5;
|
||||
}
|
||||
++xfs.dirpos;
|
||||
name[namelen] = 0;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static char *
|
||||
first_dentry (xfs_ino_t *ino)
|
||||
{
|
||||
xfs.forw = 0;
|
||||
switch (icore.di_format) {
|
||||
case XFS_DINODE_FMT_LOCAL:
|
||||
xfs.dirmax = inode->di_u.di_dir2sf.hdr.count;
|
||||
xfs.i8param = inode->di_u.di_dir2sf.hdr.i8count ? 0 : 4;
|
||||
xfs.dirpos = -2;
|
||||
break;
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
filepos = 0;
|
||||
xfs_read (dirbuf, sizeof(xfs_dir2_data_hdr_t));
|
||||
if (((xfs_dir2_data_hdr_t *)dirbuf)->magic == le32(XFS_DIR2_BLOCK_MAGIC)) {
|
||||
#define tail ((xfs_dir2_block_tail_t *)dirbuf)
|
||||
filepos = xfs.dirbsize - sizeof(*tail);
|
||||
xfs_read (dirbuf, sizeof(*tail));
|
||||
xfs.dirmax = le32 (tail->count) - le32 (tail->stale);
|
||||
#undef tail
|
||||
} else {
|
||||
xfs.dablk = (1ULL << 35) >> xfs.blklog;
|
||||
#define h ((xfs_dir2_leaf_hdr_t *)dirbuf)
|
||||
#define n ((xfs_da_intnode_t *)dirbuf)
|
||||
for (;;) {
|
||||
xfs_dabread ();
|
||||
if ((n->hdr.info.magic == le16(XFS_DIR2_LEAFN_MAGIC))
|
||||
|| (n->hdr.info.magic == le16(XFS_DIR2_LEAF1_MAGIC))) {
|
||||
xfs.dirmax = le16 (h->count) - le16 (h->stale);
|
||||
xfs.forw = le32 (h->info.forw);
|
||||
break;
|
||||
}
|
||||
xfs.dablk = le32 (n->btree[0].before);
|
||||
}
|
||||
#undef n
|
||||
#undef h
|
||||
}
|
||||
xfs.blkoff = sizeof(xfs_dir2_data_hdr_t);
|
||||
filepos = xfs.blkoff;
|
||||
xfs.dirpos = 0;
|
||||
}
|
||||
return next_dentry (ino);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_mount (void)
|
||||
{
|
||||
xfs_sb_t super;
|
||||
|
||||
if (!devread (0, 0, sizeof(super), (char *)&super)
|
||||
|| (le32(super.sb_magicnum) != XFS_SB_MAGIC)
|
||||
|| ((le16(super.sb_versionnum)
|
||||
& XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
xfs.bsize = le32 (super.sb_blocksize);
|
||||
xfs.blklog = super.sb_blocklog;
|
||||
xfs.bdlog = xfs.blklog - SECTOR_BITS;
|
||||
xfs.rootino = le64 (super.sb_rootino);
|
||||
xfs.isize = le16 (super.sb_inodesize);
|
||||
xfs.agblocks = le32 (super.sb_agblocks);
|
||||
xfs.dirbsize = xfs.bsize << super.sb_dirblklog;
|
||||
|
||||
xfs.inopblog = super.sb_inopblog;
|
||||
xfs.agblklog = super.sb_agblklog;
|
||||
xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount));
|
||||
|
||||
xfs.btnode_ptr0_off =
|
||||
((xfs.bsize - sizeof(xfs_btree_block_t)) /
|
||||
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
|
||||
* sizeof(xfs_bmbt_key_t) + sizeof(xfs_btree_block_t);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_read (char *buf, int len)
|
||||
{
|
||||
xad_t *xad;
|
||||
xfs_fileoff_t endofprev, endofcur, offset;
|
||||
xfs_filblks_t xadlen;
|
||||
int toread, startpos, endpos;
|
||||
|
||||
if (icore.di_format == XFS_DINODE_FMT_LOCAL) {
|
||||
grub_memmove (buf, inode->di_u.di_c + filepos, len);
|
||||
filepos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
startpos = filepos;
|
||||
endpos = filepos + len;
|
||||
endofprev = (xfs_fileoff_t)-1;
|
||||
init_extents ();
|
||||
while (len > 0 && (xad = next_extent ())) {
|
||||
offset = xad->offset;
|
||||
xadlen = xad->len;
|
||||
if (isinxt (filepos >> xfs.blklog, offset, xadlen)) {
|
||||
endofcur = (offset + xadlen) << xfs.blklog;
|
||||
toread = (endofcur >= endpos)
|
||||
? len : (endofcur - filepos);
|
||||
|
||||
disk_read_func = disk_read_hook;
|
||||
devread (fsb2daddr (xad->start),
|
||||
filepos - (offset << xfs.blklog), toread, buf);
|
||||
disk_read_func = NULL;
|
||||
|
||||
buf += toread;
|
||||
len -= toread;
|
||||
filepos += toread;
|
||||
} else if (offset > endofprev) {
|
||||
toread = ((offset << xfs.blklog) >= endpos)
|
||||
? len : ((offset - endofprev) << xfs.blklog);
|
||||
len -= toread;
|
||||
filepos += toread;
|
||||
for (; toread; toread--) {
|
||||
*buf++ = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
endofprev = offset + xadlen;
|
||||
}
|
||||
|
||||
return filepos - startpos;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_dir (char *dirname)
|
||||
{
|
||||
xfs_ino_t ino, parent_ino, new_ino;
|
||||
xfs_fsize_t di_size;
|
||||
int di_mode;
|
||||
int cmp, n, link_count;
|
||||
char linkbuf[xfs.bsize];
|
||||
char *rest, *name, ch;
|
||||
|
||||
parent_ino = ino = xfs.rootino;
|
||||
link_count = 0;
|
||||
for (;;) {
|
||||
di_read (ino);
|
||||
di_size = le64 (icore.di_size);
|
||||
di_mode = le16 (icore.di_mode);
|
||||
|
||||
if ((di_mode & IFMT) == IFLNK) {
|
||||
if (++link_count > MAX_LINK_COUNT) {
|
||||
errnum = ERR_SYMLINK_LOOP;
|
||||
return 0;
|
||||
}
|
||||
if (di_size < xfs.bsize - 1) {
|
||||
filepos = 0;
|
||||
filemax = di_size;
|
||||
n = xfs_read (linkbuf, filemax);
|
||||
} else {
|
||||
errnum = ERR_FILELENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ino = (linkbuf[0] == '/') ? xfs.rootino : parent_ino;
|
||||
while (n < (xfs.bsize - 1) && (linkbuf[n++] = *dirname++));
|
||||
linkbuf[n] = 0;
|
||||
dirname = linkbuf;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!*dirname || isspace (*dirname)) {
|
||||
if ((di_mode & IFMT) != IFREG) {
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
filepos = 0;
|
||||
filemax = di_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((di_mode & IFMT) != IFDIR) {
|
||||
errnum = ERR_BAD_FILETYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; *dirname == '/'; dirname++);
|
||||
|
||||
for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
|
||||
*rest = 0;
|
||||
|
||||
name = first_dentry (&new_ino);
|
||||
for (;;) {
|
||||
cmp = (!*dirname) ? -1 : substring (dirname, name);
|
||||
#ifndef STAGE1_5
|
||||
if (print_possibilities && ch != '/' && cmp <= 0) {
|
||||
if (print_possibilities > 0)
|
||||
print_possibilities = -print_possibilities;
|
||||
print_a_completion (name);
|
||||
} else
|
||||
#endif
|
||||
if (cmp == 0) {
|
||||
parent_ino = ino;
|
||||
if (new_ino)
|
||||
ino = new_ino;
|
||||
*(dirname = rest) = ch;
|
||||
break;
|
||||
}
|
||||
name = next_dentry (&new_ino);
|
||||
if (name == NULL) {
|
||||
if (print_possibilities < 0)
|
||||
return 1;
|
||||
|
||||
errnum = ERR_FILE_NOT_FOUND;
|
||||
*rest = ch;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* FSYS_XFS */
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
* ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader)
|
||||
* including Rock Ridge Extensions support
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Kousuke Takai <tak@kmc.kyoto-u.ac.jp>
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
* References:
|
||||
* linux/fs/isofs/rock.[ch]
|
||||
* mkisofs-1.11.1/diag/isoinfo.c
|
||||
* mkisofs-1.11.1/iso9660.h
|
||||
* (all are written by Eric Youngdale)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by SONE Takeshi to work with FILO
|
||||
*/
|
||||
|
||||
#ifndef _ISO9660_H_
|
||||
#define _ISO9660_H_
|
||||
|
||||
#define ISO_SECTOR_BITS (11)
|
||||
#define ISO_SECTOR_SIZE (1<<ISO_SECTOR_BITS)
|
||||
|
||||
#define ISO_REGULAR 1 /* regular file */
|
||||
#define ISO_DIRECTORY 2 /* directory */
|
||||
#define ISO_OTHER 0 /* other file (with Rock Ridge) */
|
||||
|
||||
#define RR_FLAG_PX 0x01 /* have POSIX file attributes */
|
||||
#define RR_FLAG_NM 0x08 /* have alternate file name */
|
||||
|
||||
/* POSIX file attributes for Rock Ridge extensions */
|
||||
#define POSIX_S_IFMT 0xF000
|
||||
#define POSIX_S_IFREG 0x8000
|
||||
#define POSIX_S_IFDIR 0x4000
|
||||
|
||||
/* volume descriptor types */
|
||||
#define ISO_VD_PRIMARY 1
|
||||
#define ISO_VD_END 255
|
||||
|
||||
#define ISO_STANDARD_ID "CD001"
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
typedef uint8_t u_int8_t;
|
||||
typedef uint16_t u_int16_t;
|
||||
typedef uint32_t u_int32_t;
|
||||
|
||||
typedef union {
|
||||
u_int8_t l,b;
|
||||
} iso_8bit_t;
|
||||
|
||||
typedef struct __iso_16bit {
|
||||
u_int16_t l, b;
|
||||
} iso_16bit_t __attribute__ ((packed));
|
||||
|
||||
typedef struct __iso_32bit {
|
||||
u_int32_t l, b;
|
||||
} iso_32bit_t __attribute__ ((packed));
|
||||
|
||||
typedef u_int8_t iso_date_t[7];
|
||||
|
||||
struct iso_directory_record {
|
||||
iso_8bit_t length;
|
||||
iso_8bit_t ext_attr_length;
|
||||
iso_32bit_t extent;
|
||||
iso_32bit_t size;
|
||||
iso_date_t date;
|
||||
iso_8bit_t flags;
|
||||
iso_8bit_t file_unit_size;
|
||||
iso_8bit_t interleave;
|
||||
iso_16bit_t volume_seq_number;
|
||||
iso_8bit_t name_len;
|
||||
u_int8_t name[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct iso_primary_descriptor {
|
||||
iso_8bit_t type;
|
||||
u_int8_t id[5];
|
||||
iso_8bit_t version;
|
||||
u_int8_t _unused1[1];
|
||||
u_int8_t system_id[32];
|
||||
u_int8_t volume_id[32];
|
||||
u_int8_t _unused2[8];
|
||||
iso_32bit_t volume_space_size;
|
||||
u_int8_t _unused3[32];
|
||||
iso_16bit_t volume_set_size;
|
||||
iso_16bit_t volume_seq_number;
|
||||
iso_16bit_t logical_block_size;
|
||||
iso_32bit_t path_table_size;
|
||||
u_int8_t type_l_path_table[4];
|
||||
u_int8_t opt_type_l_path_table[4];
|
||||
u_int8_t type_m_path_table[4];
|
||||
u_int8_t opt_type_m_path_table[4];
|
||||
struct iso_directory_record root_directory_record;
|
||||
u_int8_t volume_set_id[128];
|
||||
u_int8_t publisher_id[128];
|
||||
u_int8_t preparer_id[128];
|
||||
u_int8_t application_id[128];
|
||||
u_int8_t copyright_file_id[37];
|
||||
u_int8_t abstract_file_id[37];
|
||||
u_int8_t bibliographic_file_id[37];
|
||||
u_int8_t creation_date[17];
|
||||
u_int8_t modification_date[17];
|
||||
u_int8_t expiration_date[17];
|
||||
u_int8_t effective_date[17];
|
||||
iso_8bit_t file_structure_version;
|
||||
u_int8_t _unused4[1];
|
||||
u_int8_t application_data[512];
|
||||
u_int8_t _unused5[653];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rock_ridge {
|
||||
u_int16_t signature;
|
||||
u_int8_t len;
|
||||
u_int8_t version;
|
||||
union {
|
||||
struct CE {
|
||||
iso_32bit_t extent;
|
||||
iso_32bit_t offset;
|
||||
iso_32bit_t size;
|
||||
} ce;
|
||||
struct NM {
|
||||
iso_8bit_t flags;
|
||||
u_int8_t name[0];
|
||||
} nm;
|
||||
struct PX {
|
||||
iso_32bit_t mode;
|
||||
iso_32bit_t nlink;
|
||||
iso_32bit_t uid;
|
||||
iso_32bit_t gid;
|
||||
} px;
|
||||
struct RR {
|
||||
iso_8bit_t flags;
|
||||
} rr;
|
||||
} u;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef union RR_ptr {
|
||||
struct rock_ridge *rr;
|
||||
char *ptr;
|
||||
int i;
|
||||
} RR_ptr_t;
|
||||
|
||||
#define RRMAGIC(c1, c2) ((c1)|(c2) << 8)
|
||||
|
||||
#define CHECK2(ptr, c1, c2) \
|
||||
(*(unsigned short *)(ptr) == (((c1) | (c2) << 8) & 0xFFFF))
|
||||
#define CHECK4(ptr, c1, c2, c3, c4) \
|
||||
(*(unsigned long *)(ptr) == ((c1) | (c2)<<8 | (c3)<<16 | (c4)<<24))
|
||||
|
||||
#endif /* !ASM_FILE */
|
||||
|
||||
#endif /* _ISO9660_H_ */
|
|
@ -1,601 +0,0 @@
|
|||
/* jfs.h - an extractions from linux/include/linux/jfs/jfs* into one file */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000 International Business Machines Corp.
|
||||
* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _JFS_H_
|
||||
#define _JFS_H_
|
||||
|
||||
/* those are from jfs_filsys.h */
|
||||
|
||||
/*
|
||||
* file system option (superblock flag)
|
||||
*/
|
||||
/* platform option (conditional compilation) */
|
||||
#define JFS_AIX 0x80000000 /* AIX support */
|
||||
/* POSIX name/directory support */
|
||||
|
||||
#define JFS_OS2 0x40000000 /* OS/2 support */
|
||||
/* case-insensitive name/directory support */
|
||||
|
||||
#define JFS_LINUX 0x10000000 /* Linux support */
|
||||
/* case-sensitive name/directory support */
|
||||
|
||||
/* directory option */
|
||||
#define JFS_UNICODE 0x00000001 /* unicode name */
|
||||
|
||||
/* bba */
|
||||
#define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */
|
||||
|
||||
|
||||
/*
|
||||
* buffer cache configuration
|
||||
*/
|
||||
/* page size */
|
||||
#ifdef PSIZE
|
||||
#undef PSIZE
|
||||
#endif
|
||||
#define PSIZE 4096 /* page size (in byte) */
|
||||
|
||||
/*
|
||||
* fs fundamental size
|
||||
*
|
||||
* PSIZE >= file system block size >= PBSIZE >= DISIZE
|
||||
*/
|
||||
#define PBSIZE 512 /* physical block size (in byte) */
|
||||
#define DISIZE 512 /* on-disk inode size (in byte) */
|
||||
#define L2DISIZE 9
|
||||
#define INOSPERIAG 4096 /* number of disk inodes per iag */
|
||||
#define L2INOSPERIAG 12
|
||||
#define INOSPEREXT 32 /* number of disk inode per extent */
|
||||
#define L2INOSPEREXT 5
|
||||
|
||||
/* Minimum number of bytes supported for a JFS partition */
|
||||
#define MINJFS (0x1000000)
|
||||
|
||||
/*
|
||||
* fixed byte offset address
|
||||
*/
|
||||
#define SUPER1_OFF 0x8000 /* primary superblock */
|
||||
|
||||
#define AITBL_OFF (SUPER1_OFF + PSIZE + (PSIZE << 1))
|
||||
|
||||
/*
|
||||
* fixed reserved inode number
|
||||
*/
|
||||
/* aggregate inode */
|
||||
#define AGGREGATE_I 1 /* aggregate inode map inode */
|
||||
#define FILESYSTEM_I 16 /* 1st/only fileset inode in ait:
|
||||
* fileset inode map inode
|
||||
*/
|
||||
|
||||
/* per fileset inode */
|
||||
#define ROOT_I 2 /* fileset root inode */
|
||||
|
||||
/*
|
||||
* directory configuration
|
||||
*/
|
||||
#define JFS_NAME_MAX 255
|
||||
#define JFS_PATH_MAX PSIZE
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef char s8;
|
||||
typedef unsigned short u16;
|
||||
typedef short s16;
|
||||
typedef unsigned int u32;
|
||||
typedef int s32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long s64;
|
||||
|
||||
typedef u16 UniChar;
|
||||
|
||||
/* these from jfs_btree.h */
|
||||
|
||||
/* btpaget_t flag */
|
||||
#define BT_TYPE 0x07 /* B+-tree index */
|
||||
#define BT_ROOT 0x01 /* root page */
|
||||
#define BT_LEAF 0x02 /* leaf page */
|
||||
#define BT_INTERNAL 0x04 /* internal page */
|
||||
#define BT_RIGHTMOST 0x10 /* rightmost page */
|
||||
#define BT_LEFTMOST 0x20 /* leftmost page */
|
||||
|
||||
/* those are from jfs_types.h */
|
||||
|
||||
struct timestruc_t {
|
||||
u32 tv_sec;
|
||||
u32 tv_nsec;
|
||||
};
|
||||
|
||||
/*
|
||||
* physical xd (pxd)
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned len:24;
|
||||
unsigned addr1:8;
|
||||
u32 addr2;
|
||||
} pxd_t;
|
||||
|
||||
/* xd_t field extraction */
|
||||
#define lengthPXD(pxd) ((pxd)->len)
|
||||
#define addressPXD(pxd) (((s64)((pxd)->addr1)) << 32 | ((pxd)->addr2))
|
||||
|
||||
/*
|
||||
* data extent descriptor (dxd)
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned flag:8; /* 1: flags */
|
||||
unsigned rsrvd:24; /* 3: */
|
||||
u32 size; /* 4: size in byte */
|
||||
unsigned len:24; /* 3: length in unit of fsblksize */
|
||||
unsigned addr1:8; /* 1: address in unit of fsblksize */
|
||||
u32 addr2; /* 4: address in unit of fsblksize */
|
||||
} dxd_t; /* - 16 - */
|
||||
|
||||
/*
|
||||
* DASD limit information - stored in directory inode
|
||||
*/
|
||||
typedef struct dasd {
|
||||
u8 thresh; /* Alert Threshold (in percent) */
|
||||
u8 delta; /* Alert Threshold delta (in percent) */
|
||||
u8 rsrvd1;
|
||||
u8 limit_hi; /* DASD limit (in logical blocks) */
|
||||
u32 limit_lo; /* DASD limit (in logical blocks) */
|
||||
u8 rsrvd2[3];
|
||||
u8 used_hi; /* DASD usage (in logical blocks) */
|
||||
u32 used_lo; /* DASD usage (in logical blocks) */
|
||||
} dasd_t;
|
||||
|
||||
|
||||
/* from jfs_superblock.h */
|
||||
|
||||
#define JFS_MAGIC 0x3153464A /* "JFS1" */
|
||||
|
||||
struct jfs_superblock
|
||||
{
|
||||
u32 s_magic; /* 4: magic number */
|
||||
u32 s_version; /* 4: version number */
|
||||
|
||||
s64 s_size; /* 8: aggregate size in hardware/LVM blocks;
|
||||
* VFS: number of blocks
|
||||
*/
|
||||
s32 s_bsize; /* 4: aggregate block size in bytes;
|
||||
* VFS: fragment size
|
||||
*/
|
||||
s16 s_l2bsize; /* 2: log2 of s_bsize */
|
||||
s16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */
|
||||
s32 s_pbsize; /* 4: hardware/LVM block size in bytes */
|
||||
s16 s_l2pbsize; /* 2: log2 of s_pbsize */
|
||||
s16 pad; /* 2: padding necessary for alignment */
|
||||
|
||||
u32 s_agsize; /* 4: allocation group size in aggr. blocks */
|
||||
|
||||
u32 s_flag; /* 4: aggregate attributes:
|
||||
* see jfs_filsys.h
|
||||
*/
|
||||
u32 s_state; /* 4: mount/unmount/recovery state:
|
||||
* see jfs_filsys.h
|
||||
*/
|
||||
s32 s_compress; /* 4: > 0 if data compression */
|
||||
|
||||
pxd_t s_ait2; /* 8: first extent of secondary
|
||||
* aggregate inode table
|
||||
*/
|
||||
|
||||
pxd_t s_aim2; /* 8: first extent of secondary
|
||||
* aggregate inode map
|
||||
*/
|
||||
u32 s_logdev; /* 4: device address of log */
|
||||
s32 s_logserial; /* 4: log serial number at aggregate mount */
|
||||
pxd_t s_logpxd; /* 8: inline log extent */
|
||||
|
||||
pxd_t s_fsckpxd; /* 8: inline fsck work space extent */
|
||||
|
||||
struct timestruc_t s_time; /* 8: time last updated */
|
||||
|
||||
s32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for
|
||||
* the fsck service log.
|
||||
* N.B. These blocks are divided among the
|
||||
* versions kept. This is not a per
|
||||
* version size.
|
||||
* N.B. These blocks are included in the
|
||||
* length field of s_fsckpxd.
|
||||
*/
|
||||
s8 s_fscklog; /* 1: which fsck service log is most recent
|
||||
* 0 => no service log data yet
|
||||
* 1 => the first one
|
||||
* 2 => the 2nd one
|
||||
*/
|
||||
char s_fpack[11]; /* 11: file system volume name
|
||||
* N.B. This must be 11 bytes to
|
||||
* conform with the OS/2 BootSector
|
||||
* requirements
|
||||
*/
|
||||
|
||||
/* extendfs() parameter under s_state & FM_EXTENDFS */
|
||||
s64 s_xsize; /* 8: extendfs s_size */
|
||||
pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */
|
||||
pxd_t s_xlogpxd; /* 8: extendfs logpxd */
|
||||
/* - 128 byte boundary - */
|
||||
|
||||
/*
|
||||
* DFS VFS support (preliminary)
|
||||
*/
|
||||
char s_attach; /* 1: VFS: flag: set when aggregate is attached
|
||||
*/
|
||||
u8 rsrvd4[7]; /* 7: reserved - set to 0 */
|
||||
|
||||
u64 totalUsable; /* 8: VFS: total of 1K blocks which are
|
||||
* available to "normal" (non-root) users.
|
||||
*/
|
||||
u64 minFree; /* 8: VFS: # of 1K blocks held in reserve for
|
||||
* exclusive use of root. This value can be 0,
|
||||
* and if it is then totalUsable will be equal
|
||||
* to # of blocks in aggregate. I believe this
|
||||
* means that minFree + totalUsable = # blocks.
|
||||
* In that case, we don't need to store both
|
||||
* totalUsable and minFree since we can compute
|
||||
* one from the other. I would guess minFree
|
||||
* would be the one we should store, and
|
||||
* totalUsable would be the one we should
|
||||
* compute. (Just a guess...)
|
||||
*/
|
||||
|
||||
u64 realFree; /* 8: VFS: # of free 1K blocks can be used by
|
||||
* "normal" users. It may be this is something
|
||||
* we should compute when asked for instead of
|
||||
* storing in the superblock. I don't know how
|
||||
* often this information is needed.
|
||||
*/
|
||||
/*
|
||||
* graffiti area
|
||||
*/
|
||||
};
|
||||
|
||||
/* from jfs_dtree.h */
|
||||
|
||||
/*
|
||||
* entry segment/slot
|
||||
*
|
||||
* an entry consists of type dependent head/only segment/slot and
|
||||
* additional segments/slots linked vi next field;
|
||||
* N.B. last/only segment of entry is terminated by next = -1;
|
||||
*/
|
||||
/*
|
||||
* directory page slot
|
||||
*/
|
||||
typedef struct {
|
||||
s8 next; /* 1: */
|
||||
s8 cnt; /* 1: */
|
||||
UniChar name[15]; /* 30: */
|
||||
} dtslot_t; /* (32) */
|
||||
|
||||
#define DTSLOTDATALEN 15
|
||||
|
||||
/*
|
||||
* internal node entry head/only segment
|
||||
*/
|
||||
typedef struct {
|
||||
pxd_t xd; /* 8: child extent descriptor */
|
||||
|
||||
s8 next; /* 1: */
|
||||
u8 namlen; /* 1: */
|
||||
UniChar name[11]; /* 22: 2-byte aligned */
|
||||
} idtentry_t; /* (32) */
|
||||
|
||||
/*
|
||||
* leaf node entry head/only segment
|
||||
*
|
||||
* For legacy filesystems, name contains 13 unichars -- no index field
|
||||
*/
|
||||
typedef struct {
|
||||
u32 inumber; /* 4: 4-byte aligned */
|
||||
s8 next; /* 1: */
|
||||
u8 namlen; /* 1: */
|
||||
UniChar name[11]; /* 22: 2-byte aligned */
|
||||
u32 index; /* 4: index into dir_table */
|
||||
} ldtentry_t; /* (32) */
|
||||
|
||||
#define DTLHDRDATALEN 11
|
||||
|
||||
/*
|
||||
* dir_table used for directory traversal during readdir
|
||||
*/
|
||||
|
||||
/*
|
||||
* Maximum entry in inline directory table
|
||||
*/
|
||||
|
||||
typedef struct dir_table_slot {
|
||||
u8 rsrvd; /* 1: */
|
||||
u8 flag; /* 1: 0 if free */
|
||||
u8 slot; /* 1: slot within leaf page of entry */
|
||||
u8 addr1; /* 1: upper 8 bits of leaf page address */
|
||||
u32 addr2; /* 4: lower 32 bits of leaf page address -OR-
|
||||
index of next entry when this entry was deleted */
|
||||
} dir_table_slot_t; /* (8) */
|
||||
|
||||
/*
|
||||
* directory root page (in-line in on-disk inode):
|
||||
*
|
||||
* cf. dtpage_t below.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
dasd_t DASD; /* 16: DASD limit/usage info F226941 */
|
||||
|
||||
u8 flag; /* 1: */
|
||||
s8 nextindex; /* 1: next free entry in stbl */
|
||||
s8 freecnt; /* 1: free count */
|
||||
s8 freelist; /* 1: freelist header */
|
||||
|
||||
u32 idotdot; /* 4: parent inode number */
|
||||
|
||||
s8 stbl[8]; /* 8: sorted entry index table */
|
||||
} header; /* (32) */
|
||||
|
||||
dtslot_t slot[9];
|
||||
} dtroot_t;
|
||||
|
||||
/*
|
||||
* directory regular page:
|
||||
*
|
||||
* entry slot array of 32 byte slot
|
||||
*
|
||||
* sorted entry slot index table (stbl):
|
||||
* contiguous slots at slot specified by stblindex,
|
||||
* 1-byte per entry
|
||||
* 512 byte block: 16 entry tbl (1 slot)
|
||||
* 1024 byte block: 32 entry tbl (1 slot)
|
||||
* 2048 byte block: 64 entry tbl (2 slot)
|
||||
* 4096 byte block: 128 entry tbl (4 slot)
|
||||
*
|
||||
* data area:
|
||||
* 512 byte block: 16 - 2 = 14 slot
|
||||
* 1024 byte block: 32 - 2 = 30 slot
|
||||
* 2048 byte block: 64 - 3 = 61 slot
|
||||
* 4096 byte block: 128 - 5 = 123 slot
|
||||
*
|
||||
* N.B. index is 0-based; index fields refer to slot index
|
||||
* except nextindex which refers to entry index in stbl;
|
||||
* end of entry stot list or freelist is marked with -1.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
s64 next; /* 8: next sibling */
|
||||
s64 prev; /* 8: previous sibling */
|
||||
|
||||
u8 flag; /* 1: */
|
||||
s8 nextindex; /* 1: next entry index in stbl */
|
||||
s8 freecnt; /* 1: */
|
||||
s8 freelist; /* 1: slot index of head of freelist */
|
||||
|
||||
u8 maxslot; /* 1: number of slots in page slot[] */
|
||||
s8 stblindex; /* 1: slot index of start of stbl */
|
||||
u8 rsrvd[2]; /* 2: */
|
||||
|
||||
pxd_t self; /* 8: self pxd */
|
||||
} header; /* (32) */
|
||||
|
||||
dtslot_t slot[128];
|
||||
} dtpage_t;
|
||||
|
||||
/* from jfs_xtree.h */
|
||||
|
||||
/*
|
||||
* extent allocation descriptor (xad)
|
||||
*/
|
||||
typedef struct xad {
|
||||
unsigned flag:8; /* 1: flag */
|
||||
unsigned rsvrd:16; /* 2: reserved */
|
||||
unsigned off1:8; /* 1: offset in unit of fsblksize */
|
||||
u32 off2; /* 4: offset in unit of fsblksize */
|
||||
unsigned len:24; /* 3: length in unit of fsblksize */
|
||||
unsigned addr1:8; /* 1: address in unit of fsblksize */
|
||||
u32 addr2; /* 4: address in unit of fsblksize */
|
||||
} xad_t; /* (16) */
|
||||
|
||||
/* xad_t field extraction */
|
||||
#define offsetXAD(xad) (((s64)((xad)->off1)) << 32 | ((xad)->off2))
|
||||
#define addressXAD(xad) (((s64)((xad)->addr1)) << 32 | ((xad)->addr2))
|
||||
#define lengthXAD(xad) ((xad)->len)
|
||||
|
||||
/* possible values for maxentry */
|
||||
#define XTPAGEMAXSLOT 256
|
||||
#define XTENTRYSTART 2
|
||||
|
||||
/*
|
||||
* xtree page:
|
||||
*/
|
||||
typedef union {
|
||||
struct xtheader {
|
||||
s64 next; /* 8: */
|
||||
s64 prev; /* 8: */
|
||||
|
||||
u8 flag; /* 1: */
|
||||
u8 rsrvd1; /* 1: */
|
||||
s16 nextindex; /* 2: next index = number of entries */
|
||||
s16 maxentry; /* 2: max number of entries */
|
||||
s16 rsrvd2; /* 2: */
|
||||
|
||||
pxd_t self; /* 8: self */
|
||||
} header; /* (32) */
|
||||
|
||||
xad_t xad[XTPAGEMAXSLOT]; /* 16 * maxentry: xad array */
|
||||
} xtpage_t;
|
||||
|
||||
/* from jfs_dinode.h */
|
||||
|
||||
struct dinode {
|
||||
/*
|
||||
* I. base area (128 bytes)
|
||||
* ------------------------
|
||||
*
|
||||
* define generic/POSIX attributes
|
||||
*/
|
||||
u32 di_inostamp; /* 4: stamp to show inode belongs to fileset */
|
||||
s32 di_fileset; /* 4: fileset number */
|
||||
u32 di_number; /* 4: inode number, aka file serial number */
|
||||
u32 di_gen; /* 4: inode generation number */
|
||||
|
||||
pxd_t di_ixpxd; /* 8: inode extent descriptor */
|
||||
|
||||
s64 di_size; /* 8: size */
|
||||
s64 di_nblocks; /* 8: number of blocks allocated */
|
||||
|
||||
u32 di_nlink; /* 4: number of links to the object */
|
||||
|
||||
u32 di_uid; /* 4: user id of owner */
|
||||
u32 di_gid; /* 4: group id of owner */
|
||||
|
||||
u32 di_mode; /* 4: attribute, format and permission */
|
||||
|
||||
struct timestruc_t di_atime; /* 8: time last data accessed */
|
||||
struct timestruc_t di_ctime; /* 8: time last status changed */
|
||||
struct timestruc_t di_mtime; /* 8: time last data modified */
|
||||
struct timestruc_t di_otime; /* 8: time created */
|
||||
|
||||
dxd_t di_acl; /* 16: acl descriptor */
|
||||
|
||||
dxd_t di_ea; /* 16: ea descriptor */
|
||||
|
||||
s32 di_next_index; /* 4: Next available dir_table index */
|
||||
|
||||
s32 di_acltype; /* 4: Type of ACL */
|
||||
|
||||
/*
|
||||
* Extension Areas.
|
||||
*
|
||||
* Historically, the inode was partitioned into 4 128-byte areas,
|
||||
* the last 3 being defined as unions which could have multiple
|
||||
* uses. The first 96 bytes had been completely unused until
|
||||
* an index table was added to the directory. It is now more
|
||||
* useful to describe the last 3/4 of the inode as a single
|
||||
* union. We would probably be better off redesigning the
|
||||
* entire structure from scratch, but we don't want to break
|
||||
* commonality with OS/2's JFS at this time.
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
/*
|
||||
* This table contains the information needed to
|
||||
* find a directory entry from a 32-bit index.
|
||||
* If the index is small enough, the table is inline,
|
||||
* otherwise, an x-tree root overlays this table
|
||||
*/
|
||||
dir_table_slot_t _table[12]; /* 96: inline */
|
||||
|
||||
dtroot_t _dtroot; /* 288: dtree root */
|
||||
} _dir; /* (384) */
|
||||
#define di_dirtable u._dir._table
|
||||
#define di_dtroot u._dir._dtroot
|
||||
#define di_parent di_dtroot.header.idotdot
|
||||
#define di_DASD di_dtroot.header.DASD
|
||||
|
||||
struct {
|
||||
union {
|
||||
u8 _data[96]; /* 96: unused */
|
||||
struct {
|
||||
void *_imap; /* 4: unused */
|
||||
u32 _gengen; /* 4: generator */
|
||||
} _imap;
|
||||
} _u1; /* 96: */
|
||||
#define di_gengen u._file._u1._imap._gengen
|
||||
|
||||
union {
|
||||
xtpage_t _xtroot;
|
||||
struct {
|
||||
u8 unused[16]; /* 16: */
|
||||
dxd_t _dxd; /* 16: */
|
||||
union {
|
||||
u32 _rdev; /* 4: */
|
||||
u8 _fastsymlink[128];
|
||||
} _u;
|
||||
u8 _inlineea[128];
|
||||
} _special;
|
||||
} _u2;
|
||||
} _file;
|
||||
#define di_xtroot u._file._u2._xtroot
|
||||
#define di_dxd u._file._u2._special._dxd
|
||||
#define di_btroot di_xtroot
|
||||
#define di_inlinedata u._file._u2._special._u
|
||||
#define di_rdev u._file._u2._special._u._rdev
|
||||
#define di_fastsymlink u._file._u2._special._u._fastsymlink
|
||||
#define di_inlineea u._file._u2._special._inlineea
|
||||
} u;
|
||||
};
|
||||
|
||||
typedef struct dinode dinode_t;
|
||||
|
||||
/* di_mode */
|
||||
#define IFMT 0xF000 /* S_IFMT - mask of file type */
|
||||
#define IFDIR 0x4000 /* S_IFDIR - directory */
|
||||
#define IFREG 0x8000 /* S_IFREG - regular file */
|
||||
#define IFLNK 0xA000 /* S_IFLNK - symbolic link */
|
||||
|
||||
/* extended mode bits (on-disk inode di_mode) */
|
||||
#define INLINEEA 0x00040000 /* inline EA area free */
|
||||
|
||||
/* from jfs_imap.h */
|
||||
|
||||
#define EXTSPERIAG 128 /* number of disk inode extent per iag */
|
||||
#define SMAPSZ 4 /* number of words per summary map */
|
||||
#define MAXAG 128 /* maximum number of allocation groups */
|
||||
|
||||
/*
|
||||
* inode allocation map:
|
||||
*
|
||||
* inode allocation map consists of
|
||||
* . the inode map control page and
|
||||
* . inode allocation group pages (per 4096 inodes)
|
||||
* which are addressed by standard JFS xtree.
|
||||
*/
|
||||
/*
|
||||
* inode allocation group page (per 4096 inodes of an AG)
|
||||
*/
|
||||
typedef struct {
|
||||
s64 agstart; /* 8: starting block of ag */
|
||||
s32 iagnum; /* 4: inode allocation group number */
|
||||
s32 inofreefwd; /* 4: ag inode free list forward */
|
||||
s32 inofreeback; /* 4: ag inode free list back */
|
||||
s32 extfreefwd; /* 4: ag inode extent free list forward */
|
||||
s32 extfreeback; /* 4: ag inode extent free list back */
|
||||
s32 iagfree; /* 4: iag free list */
|
||||
|
||||
/* summary map: 1 bit per inode extent */
|
||||
s32 inosmap[SMAPSZ]; /* 16: sum map of mapwords w/ free inodes;
|
||||
* note: this indicates free and backed
|
||||
* inodes, if the extent is not backed the
|
||||
* value will be 1. if the extent is
|
||||
* backed but all inodes are being used the
|
||||
* value will be 1. if the extent is
|
||||
* backed but at least one of the inodes is
|
||||
* free the value will be 0.
|
||||
*/
|
||||
s32 extsmap[SMAPSZ]; /* 16: sum map of mapwords w/ free extents */
|
||||
s32 nfreeinos; /* 4: number of free inodes */
|
||||
s32 nfreeexts; /* 4: number of free extents */
|
||||
/* (72) */
|
||||
u8 pad[1976]; /* 1976: pad to 2048 bytes */
|
||||
/* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
|
||||
u32 wmap[EXTSPERIAG]; /* 512: working allocation map */
|
||||
u32 pmap[EXTSPERIAG]; /* 512: persistent allocation map */
|
||||
pxd_t inoext[EXTSPERIAG]; /* 1024: inode extent addresses */
|
||||
} iag_t; /* (4096) */
|
||||
|
||||
#endif /* _JFS_H_ */
|
|
@ -1 +0,0 @@
|
|||
/* Sorry, nothing is shared here ;) Just for GRUB compatibility. */
|
|
@ -1,193 +0,0 @@
|
|||
/* Interface between GRUB's fs drivers and application code */
|
||||
#include <lib.h>
|
||||
|
||||
#include "filesys.h"
|
||||
#include <fs.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_VFS
|
||||
#include <debug.h>
|
||||
|
||||
int filepos;
|
||||
int filemax;
|
||||
grub_error_t errnum;
|
||||
void (*disk_read_hook) (int, int, int);
|
||||
void (*disk_read_func) (int, int, int);
|
||||
char FSYS_BUF[FSYS_BUFLEN];
|
||||
int fsmax;
|
||||
|
||||
struct fsys_entry {
|
||||
char *name;
|
||||
int (*mount_func) (void);
|
||||
int (*read_func) (char *buf, int len);
|
||||
int (*dir_func) (char *dirname);
|
||||
void (*close_func) (void);
|
||||
int (*embed_func) (int *start_sector, int needed_sectors);
|
||||
};
|
||||
|
||||
struct fsys_entry fsys_table[] = {
|
||||
# ifdef FSYS_FAT
|
||||
{"fat", fat_mount, fat_read, fat_dir, 0, 0},
|
||||
# endif
|
||||
# ifdef FSYS_EXT2FS
|
||||
{"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
|
||||
# endif
|
||||
# ifdef FSYS_MINIX
|
||||
{"minix", minix_mount, minix_read, minix_dir, 0, 0},
|
||||
# endif
|
||||
# ifdef FSYS_REISERFS
|
||||
{"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0,
|
||||
reiserfs_embed},
|
||||
# endif
|
||||
# ifdef FSYS_JFS
|
||||
{"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
|
||||
# endif
|
||||
# ifdef FSYS_XFS
|
||||
{"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
|
||||
# endif
|
||||
# ifdef FSYS_ISO9660
|
||||
{"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
|
||||
# endif
|
||||
};
|
||||
|
||||
/* NULLFS is used to read images from raw device */
|
||||
static int nullfs_dir(char *name)
|
||||
{
|
||||
uint64_t dev_size;
|
||||
|
||||
if (name) {
|
||||
debug("can't have a named file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_size = (uint64_t) part_length << 9;
|
||||
/* GRUB code doesn't like 2GB or bigger files */
|
||||
if (dev_size > 0x7fffffff)
|
||||
dev_size = 0x7fffffff;
|
||||
filemax = dev_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nullfs_read(char *buf, int len)
|
||||
{
|
||||
if (devread(filepos>>9, filepos&0x1ff, len, buf)) {
|
||||
filepos += len;
|
||||
return len;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fsys_entry nullfs =
|
||||
{"nullfs", 0, nullfs_read, nullfs_dir, 0, 0};
|
||||
|
||||
static struct fsys_entry *fsys;
|
||||
|
||||
int mount_fs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
|
||||
if (fsys_table[i].mount_func()) {
|
||||
fsys = &fsys_table[i];
|
||||
printf("Mounted %s\n", fsys->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
fsys = 0;
|
||||
printf("Unknown filesystem type\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int file_open(const char *filename)
|
||||
{
|
||||
|
||||
char dev[32];
|
||||
// char *dev=0;
|
||||
const char *path;
|
||||
int len;
|
||||
int retval = 0;
|
||||
int reopen;
|
||||
|
||||
path = strchr(filename, ':');
|
||||
if (path) {
|
||||
len = path - filename;
|
||||
path++;
|
||||
//dev = malloc(len + 1);
|
||||
memcpy(dev, filename, len);
|
||||
dev[len] = '\0';
|
||||
} else {
|
||||
/* No colon is given. Is this device or filename? */
|
||||
if (filename[0] == '/') {
|
||||
/* Anything starts with '/' must be a filename */
|
||||
// dev = 0;
|
||||
dev[0]=0;
|
||||
|
||||
path = filename;
|
||||
} else {
|
||||
memcpy(dev, filename, 32);
|
||||
// dev = strdup(filename);
|
||||
path = 0;
|
||||
}
|
||||
}
|
||||
debug("dev=%s, path=%s\n", dev, path);
|
||||
|
||||
if (dev && dev[0]) {
|
||||
if (!devopen(dev, &reopen)) {
|
||||
fsys = 0;
|
||||
goto out;
|
||||
}
|
||||
if (!reopen)
|
||||
fsys = 0;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
if (!fsys || fsys==&nullfs) {
|
||||
if (!mount_fs())
|
||||
goto out;
|
||||
}
|
||||
using_devsize = 0;
|
||||
if (!path[0]) {
|
||||
printf("No filename is given\n");
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
fsys = &nullfs;
|
||||
|
||||
filepos = 0;
|
||||
errnum = 0;
|
||||
if (!fsys->dir_func((char *) path)) {
|
||||
printf("errnum=%d\n",errnum);
|
||||
// printf("File not found\n");
|
||||
goto out;
|
||||
}
|
||||
retval = 1;
|
||||
out:
|
||||
// if (dev)
|
||||
// free(dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int file_read(void *buf, unsigned long len)
|
||||
{
|
||||
if (filepos < 0 || filepos > filemax)
|
||||
filepos = filemax;
|
||||
if (len < 0 || len > filemax-filepos)
|
||||
len = filemax - filepos;
|
||||
errnum = 0;
|
||||
return fsys->read_func(buf, len);
|
||||
}
|
||||
|
||||
int file_seek(unsigned long offset)
|
||||
{
|
||||
filepos = offset;
|
||||
return filepos;
|
||||
}
|
||||
|
||||
unsigned long file_size(void)
|
||||
{
|
||||
return filemax;
|
||||
}
|
||||
|
||||
void file_close(void)
|
||||
{
|
||||
}
|
||||
|
|
@ -1,546 +0,0 @@
|
|||
/* xfs.h - an extraction from xfsprogs-1.3.5/include/xfs* into one file */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Further, this software is distributed without any warranty that it is
|
||||
* free of the rightful claim of any third person regarding infringement
|
||||
* or the like. Any license provided herein, whether implied or
|
||||
* otherwise, applies only to this software file. Patent licenses, if
|
||||
* any, provided herein do not apply to combinations of this program with
|
||||
* other software, or any other product whatsoever.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
||||
* Mountain View, CA 94043, or:
|
||||
*
|
||||
* http://www.sgi.com
|
||||
*
|
||||
* For further information regarding this notice, see:
|
||||
*
|
||||
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
|
||||
*/
|
||||
|
||||
#ifndef _BITS_TYPES_H
|
||||
typedef signed char __int8_t;
|
||||
typedef unsigned char __uint8_t;
|
||||
typedef short __int16_t;
|
||||
typedef unsigned short __uint16_t;
|
||||
typedef int __int32_t;
|
||||
typedef unsigned int __uint32_t;
|
||||
typedef long long __int64_t;
|
||||
typedef unsigned long long __uint64_t;
|
||||
#endif
|
||||
|
||||
typedef __uint64_t xfs_ino_t;
|
||||
typedef __uint32_t xfs_agino_t;
|
||||
typedef __int64_t xfs_daddr_t;
|
||||
typedef __int64_t xfs_off_t;
|
||||
typedef __uint8_t uuid_t[16];
|
||||
|
||||
|
||||
/* those are from xfs_types.h */
|
||||
|
||||
typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */
|
||||
typedef __uint32_t xfs_extlen_t; /* extent length in blocks */
|
||||
typedef __uint32_t xfs_agnumber_t; /* allocation group number */
|
||||
typedef __int32_t xfs_extnum_t; /* # of extents in a file */
|
||||
typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */
|
||||
typedef __int64_t xfs_fsize_t; /* bytes in a file */
|
||||
|
||||
typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
|
||||
typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */
|
||||
|
||||
/*
|
||||
* Disk based types:
|
||||
*/
|
||||
typedef __uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
|
||||
typedef __uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
|
||||
typedef __uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
|
||||
typedef __uint64_t xfs_dfiloff_t; /* block number in a file */
|
||||
|
||||
typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
|
||||
typedef __uint64_t xfs_fileoff_t; /* block number in a file */
|
||||
typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */
|
||||
|
||||
|
||||
/* those are from xfs_sb.h */
|
||||
|
||||
#define XFS_SB_MAGIC 0x58465342 /* 'XFSB'*/
|
||||
#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
|
||||
#define XFS_SB_VERSION_NUMBITS 0x000f
|
||||
|
||||
typedef struct xfs_sb
|
||||
{
|
||||
__uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
|
||||
__uint32_t sb_blocksize; /* logical block size, bytes */
|
||||
xfs_drfsbno_t sb_dblocks; /* number of data blocks */
|
||||
xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
|
||||
xfs_drtbno_t sb_rextents; /* number of realtime extents */
|
||||
uuid_t sb_uuid; /* file system unique id */
|
||||
xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
|
||||
xfs_ino_t sb_rootino; /* root inode number */
|
||||
xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
|
||||
xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
|
||||
xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
|
||||
xfs_agblock_t sb_agblocks; /* size of an allocation group */
|
||||
xfs_agnumber_t sb_agcount; /* number of allocation groups */
|
||||
xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
|
||||
xfs_extlen_t sb_logblocks; /* number of log blocks */
|
||||
__uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
|
||||
__uint16_t sb_sectsize; /* volume sector size, bytes */
|
||||
__uint16_t sb_inodesize; /* inode size, bytes */
|
||||
__uint16_t sb_inopblock; /* inodes per block */
|
||||
char sb_fname[12]; /* file system name */
|
||||
__uint8_t sb_blocklog; /* log2 of sb_blocksize */
|
||||
__uint8_t sb_sectlog; /* log2 of sb_sectsize */
|
||||
__uint8_t sb_inodelog; /* log2 of sb_inodesize */
|
||||
__uint8_t sb_inopblog; /* log2 of sb_inopblock */
|
||||
__uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
|
||||
__uint8_t sb_rextslog; /* log2 of sb_rextents */
|
||||
__uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
|
||||
__uint8_t sb_imax_pct; /* max % of fs for inode space */
|
||||
/* statistics */
|
||||
/*
|
||||
* These fields must remain contiguous. If you really
|
||||
* want to change their layout, make sure you fix the
|
||||
* code in xfs_trans_apply_sb_deltas().
|
||||
*/
|
||||
__uint64_t sb_icount; /* allocated inodes */
|
||||
__uint64_t sb_ifree; /* free inodes */
|
||||
__uint64_t sb_fdblocks; /* free data blocks */
|
||||
__uint64_t sb_frextents; /* free realtime extents */
|
||||
/*
|
||||
* End contiguous fields.
|
||||
*/
|
||||
xfs_ino_t sb_uquotino; /* user quota inode */
|
||||
xfs_ino_t sb_gquotino; /* group quota inode */
|
||||
__uint16_t sb_qflags; /* quota flags */
|
||||
__uint8_t sb_flags; /* misc. flags */
|
||||
__uint8_t sb_shared_vn; /* shared version number */
|
||||
xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
|
||||
__uint32_t sb_unit; /* stripe or raid unit */
|
||||
__uint32_t sb_width; /* stripe or raid width */
|
||||
__uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
|
||||
__uint8_t sb_dummy[7]; /* padding */
|
||||
} xfs_sb_t;
|
||||
|
||||
|
||||
/* those are from xfs_btree.h */
|
||||
|
||||
/*
|
||||
* Long form header: bmap btrees.
|
||||
*/
|
||||
typedef struct xfs_btree_lblock
|
||||
{
|
||||
__uint32_t bb_magic; /* magic number for block type */
|
||||
__uint16_t bb_level; /* 0 is a leaf */
|
||||
__uint16_t bb_numrecs; /* current # of data records */
|
||||
xfs_dfsbno_t bb_leftsib; /* left sibling block or NULLDFSBNO */
|
||||
xfs_dfsbno_t bb_rightsib; /* right sibling block or NULLDFSBNO */
|
||||
} xfs_btree_lblock_t;
|
||||
|
||||
/*
|
||||
* Combined header and structure, used by common code.
|
||||
*/
|
||||
typedef struct xfs_btree_hdr
|
||||
{
|
||||
__uint32_t bb_magic; /* magic number for block type */
|
||||
__uint16_t bb_level; /* 0 is a leaf */
|
||||
__uint16_t bb_numrecs; /* current # of data records */
|
||||
} xfs_btree_hdr_t;
|
||||
|
||||
typedef struct xfs_btree_block
|
||||
{
|
||||
xfs_btree_hdr_t bb_h; /* header */
|
||||
union {
|
||||
struct {
|
||||
xfs_agblock_t bb_leftsib;
|
||||
xfs_agblock_t bb_rightsib;
|
||||
} s; /* short form pointers */
|
||||
struct {
|
||||
xfs_dfsbno_t bb_leftsib;
|
||||
xfs_dfsbno_t bb_rightsib;
|
||||
} l; /* long form pointers */
|
||||
} bb_u; /* rest */
|
||||
} xfs_btree_block_t;
|
||||
|
||||
/* those are from xfs_bmap_btree.h */
|
||||
|
||||
/*
|
||||
* Bmap root header, on-disk form only.
|
||||
*/
|
||||
typedef struct xfs_bmdr_block
|
||||
{
|
||||
__uint16_t bb_level; /* 0 is a leaf */
|
||||
__uint16_t bb_numrecs; /* current # of data records */
|
||||
} xfs_bmdr_block_t;
|
||||
|
||||
/*
|
||||
* Bmap btree record and extent descriptor.
|
||||
* For 32-bit kernels,
|
||||
* l0:31 is an extent flag (value 1 indicates non-normal).
|
||||
* l0:0-30 and l1:9-31 are startoff.
|
||||
* l1:0-8, l2:0-31, and l3:21-31 are startblock.
|
||||
* l3:0-20 are blockcount.
|
||||
* For 64-bit kernels,
|
||||
* l0:63 is an extent flag (value 1 indicates non-normal).
|
||||
* l0:9-62 are startoff.
|
||||
* l0:0-8 and l1:21-63 are startblock.
|
||||
* l1:0-20 are blockcount.
|
||||
*/
|
||||
|
||||
#define BMBT_USE_64 1
|
||||
|
||||
typedef struct xfs_bmbt_rec_32
|
||||
{
|
||||
__uint32_t l0, l1, l2, l3;
|
||||
} xfs_bmbt_rec_32_t;
|
||||
typedef struct xfs_bmbt_rec_64
|
||||
{
|
||||
__uint64_t l0, l1;
|
||||
} xfs_bmbt_rec_64_t;
|
||||
|
||||
#if BMBT_USE_64
|
||||
typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */
|
||||
typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
|
||||
#else /* !BMBT_USE_64 */
|
||||
typedef __uint32_t xfs_bmbt_rec_base_t; /* use this for casts */
|
||||
typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t;
|
||||
#endif /* BMBT_USE_64 */
|
||||
|
||||
/*
|
||||
* Key structure for non-leaf levels of the tree.
|
||||
*/
|
||||
typedef struct xfs_bmbt_key
|
||||
{
|
||||
xfs_dfiloff_t br_startoff; /* starting file offset */
|
||||
} xfs_bmbt_key_t, xfs_bmdr_key_t;
|
||||
|
||||
typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */
|
||||
/* btree block header type */
|
||||
typedef struct xfs_btree_lblock xfs_bmbt_block_t;
|
||||
|
||||
|
||||
/* those are from xfs_dir2.h */
|
||||
/*
|
||||
* Directory version 2.
|
||||
* There are 4 possible formats:
|
||||
* shortform
|
||||
* single block - data with embedded leaf at the end
|
||||
* multiple data blocks, single leaf+freeindex block
|
||||
* data blocks, node&leaf blocks (btree), freeindex blocks
|
||||
*
|
||||
* The shortform format is in xfs_dir2_sf.h.
|
||||
* The single block format is in xfs_dir2_block.h.
|
||||
* The data block format is in xfs_dir2_data.h.
|
||||
* The leaf and freeindex block formats are in xfs_dir2_leaf.h.
|
||||
* Node blocks are the same as the other version, in xfs_da_btree.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Byte offset in data block and shortform entry.
|
||||
*/
|
||||
typedef __uint16_t xfs_dir2_data_off_t;
|
||||
|
||||
/*
|
||||
* Byte offset in a directory.
|
||||
*/
|
||||
typedef xfs_off_t xfs_dir2_off_t;
|
||||
|
||||
/* those are from xfs_da_btree.h */
|
||||
/*========================================================================
|
||||
* Directory Structure when greater than XFS_LBSIZE(mp) bytes.
|
||||
*========================================================================*/
|
||||
|
||||
/*
|
||||
* This structure is common to both leaf nodes and non-leaf nodes in the Btree.
|
||||
*
|
||||
* Is is used to manage a doubly linked list of all blocks at the same
|
||||
* level in the Btree, and to identify which type of block this is.
|
||||
*/
|
||||
#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */
|
||||
#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */
|
||||
|
||||
typedef struct xfs_da_blkinfo {
|
||||
xfs_dablk_t forw; /* previous block in list */
|
||||
xfs_dablk_t back; /* following block in list */
|
||||
__uint16_t magic; /* validity check on block */
|
||||
__uint16_t pad; /* unused */
|
||||
} xfs_da_blkinfo_t;
|
||||
|
||||
/*
|
||||
* This is the structure of the root and intermediate nodes in the Btree.
|
||||
* The leaf nodes are defined above.
|
||||
*
|
||||
* Entries are not packed.
|
||||
*
|
||||
* Since we have duplicate keys, use a binary search but always follow
|
||||
* all match in the block, not just the first match found.
|
||||
*/
|
||||
|
||||
typedef struct xfs_da_intnode {
|
||||
struct xfs_da_node_hdr { /* constant-structure header block */
|
||||
xfs_da_blkinfo_t info; /* block type, links, etc. */
|
||||
__uint16_t count; /* count of active entries */
|
||||
__uint16_t level; /* level above leaves (leaf == 0) */
|
||||
} hdr;
|
||||
struct xfs_da_node_entry {
|
||||
xfs_dahash_t hashval; /* hash value for this descendant */
|
||||
xfs_dablk_t before; /* Btree block before this key */
|
||||
} btree[1]; /* variable sized array of keys */
|
||||
} xfs_da_intnode_t;
|
||||
|
||||
|
||||
/* those are from xfs_dir2_data.h */
|
||||
/*
|
||||
* Directory format 2, data block structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
#define XFS_DIR2_DATA_FREE_TAG 0xffff
|
||||
#define XFS_DIR2_DATA_FD_COUNT 3
|
||||
|
||||
/*
|
||||
* Structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Describe a free area in the data block.
|
||||
* The freespace will be formatted as a xfs_dir2_data_unused_t.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_free {
|
||||
xfs_dir2_data_off_t offset; /* start of freespace */
|
||||
xfs_dir2_data_off_t length; /* length of freespace */
|
||||
} xfs_dir2_data_free_t;
|
||||
|
||||
/*
|
||||
* Header for the data blocks.
|
||||
* Always at the beginning of a directory-sized block.
|
||||
* The code knows that XFS_DIR2_DATA_FD_COUNT is 3.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_hdr {
|
||||
__uint32_t magic; /* XFS_DIR2_DATA_MAGIC */
|
||||
/* or XFS_DIR2_BLOCK_MAGIC */
|
||||
xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
|
||||
} xfs_dir2_data_hdr_t;
|
||||
|
||||
/*
|
||||
* Active entry in a data block. Aligned to 8 bytes.
|
||||
* Tag appears as the last 2 bytes.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_entry {
|
||||
xfs_ino_t inumber; /* inode number */
|
||||
__uint8_t namelen; /* name length */
|
||||
__uint8_t name[1]; /* name bytes, no null */
|
||||
/* variable offset */
|
||||
xfs_dir2_data_off_t tag; /* starting offset of us */
|
||||
} xfs_dir2_data_entry_t;
|
||||
|
||||
/*
|
||||
* Unused entry in a data block. Aligned to 8 bytes.
|
||||
* Tag appears as the last 2 bytes.
|
||||
*/
|
||||
typedef struct xfs_dir2_data_unused {
|
||||
__uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */
|
||||
xfs_dir2_data_off_t length; /* total free length */
|
||||
/* variable offset */
|
||||
xfs_dir2_data_off_t tag; /* starting offset of us */
|
||||
} xfs_dir2_data_unused_t;
|
||||
|
||||
typedef union {
|
||||
xfs_dir2_data_entry_t entry;
|
||||
xfs_dir2_data_unused_t unused;
|
||||
} xfs_dir2_data_union_t;
|
||||
|
||||
|
||||
/* those are from xfs_dir2_leaf.h */
|
||||
/*
|
||||
* Directory version 2, leaf block structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Leaf block header.
|
||||
*/
|
||||
typedef struct xfs_dir2_leaf_hdr {
|
||||
xfs_da_blkinfo_t info; /* header for da routines */
|
||||
__uint16_t count; /* count of entries */
|
||||
__uint16_t stale; /* count of stale entries */
|
||||
} xfs_dir2_leaf_hdr_t;
|
||||
|
||||
|
||||
/* those are from xfs_dir2_block.h */
|
||||
/*
|
||||
* xfs_dir2_block.h
|
||||
* Directory version 2, single block format structures
|
||||
*/
|
||||
|
||||
/*
|
||||
* The single block format is as follows:
|
||||
* xfs_dir2_data_hdr_t structure
|
||||
* xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures
|
||||
* xfs_dir2_leaf_entry_t structures
|
||||
* xfs_dir2_block_tail_t structure
|
||||
*/
|
||||
|
||||
#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */
|
||||
|
||||
typedef struct xfs_dir2_block_tail {
|
||||
__uint32_t count; /* count of leaf entries */
|
||||
__uint32_t stale; /* count of stale lf entries */
|
||||
} xfs_dir2_block_tail_t;
|
||||
|
||||
|
||||
/* those are from xfs_dir2_sf.h */
|
||||
|
||||
/*
|
||||
* Directory layout when stored internal to an inode.
|
||||
*
|
||||
* Small directories are packed as tightly as possible so as to
|
||||
* fit into the literal area of the inode.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inode number stored as 8 8-bit values.
|
||||
*/
|
||||
typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t;
|
||||
|
||||
/*
|
||||
* Inode number stored as 4 8-bit values.
|
||||
* Works a lot of the time, when all the inode numbers in a directory
|
||||
* fit in 32 bits.
|
||||
*/
|
||||
typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t;
|
||||
|
||||
typedef union {
|
||||
xfs_dir2_ino8_t i8;
|
||||
xfs_dir2_ino4_t i4;
|
||||
} xfs_dir2_inou_t;
|
||||
|
||||
/*
|
||||
* Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t.
|
||||
* Only need 16 bits, this is the byte offset into the single block form.
|
||||
*/
|
||||
typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t;
|
||||
|
||||
/*
|
||||
* The parent directory has a dedicated field, and the self-pointer must
|
||||
* be calculated on the fly.
|
||||
*
|
||||
* Entries are packed toward the top as tightly as possible. The header
|
||||
* and the elements must be bcopy()'d out into a work area to get correct
|
||||
* alignment for the inode number fields.
|
||||
*/
|
||||
typedef struct xfs_dir2_sf_hdr {
|
||||
__uint8_t count; /* count of entries */
|
||||
__uint8_t i8count; /* count of 8-byte inode #s */
|
||||
xfs_dir2_inou_t parent; /* parent dir inode number */
|
||||
} xfs_dir2_sf_hdr_t;
|
||||
|
||||
typedef struct xfs_dir2_sf_entry {
|
||||
__uint8_t namelen; /* actual name length */
|
||||
xfs_dir2_sf_off_t offset; /* saved offset */
|
||||
__uint8_t name[1]; /* name, variable size */
|
||||
xfs_dir2_inou_t inumber; /* inode number, var. offset */
|
||||
} xfs_dir2_sf_entry_t;
|
||||
|
||||
typedef struct xfs_dir2_sf {
|
||||
xfs_dir2_sf_hdr_t hdr; /* shortform header */
|
||||
xfs_dir2_sf_entry_t list[1]; /* shortform entries */
|
||||
} xfs_dir2_sf_t;
|
||||
|
||||
/* those are from xfs_dinode.h */
|
||||
|
||||
#define XFS_DINODE_VERSION_1 1
|
||||
#define XFS_DINODE_VERSION_2 2
|
||||
#define XFS_DINODE_MAGIC 0x494e /* 'IN' */
|
||||
|
||||
/*
|
||||
* Disk inode structure.
|
||||
* This is just the header; the inode is expanded to fill a variable size
|
||||
* with the last field expanding. It is split into the core and "other"
|
||||
* because we only need the core part in the in-core inode.
|
||||
*/
|
||||
typedef struct xfs_timestamp {
|
||||
__int32_t t_sec; /* timestamp seconds */
|
||||
__int32_t t_nsec; /* timestamp nanoseconds */
|
||||
} xfs_timestamp_t;
|
||||
|
||||
/*
|
||||
* Note: Coordinate changes to this structure with the XFS_DI_* #defines
|
||||
* below and the offsets table in xfs_ialloc_log_di().
|
||||
*/
|
||||
typedef struct xfs_dinode_core
|
||||
{
|
||||
__uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
|
||||
__uint16_t di_mode; /* mode and type of file */
|
||||
__int8_t di_version; /* inode version */
|
||||
__int8_t di_format; /* format of di_c data */
|
||||
__uint16_t di_onlink; /* old number of links to file */
|
||||
__uint32_t di_uid; /* owner's user id */
|
||||
__uint32_t di_gid; /* owner's group id */
|
||||
__uint32_t di_nlink; /* number of links to file */
|
||||
__uint16_t di_projid; /* owner's project id */
|
||||
__uint8_t di_pad[10]; /* unused, zeroed space */
|
||||
xfs_timestamp_t di_atime; /* time last accessed */
|
||||
xfs_timestamp_t di_mtime; /* time last modified */
|
||||
xfs_timestamp_t di_ctime; /* time created/inode modified */
|
||||
xfs_fsize_t di_size; /* number of bytes in file */
|
||||
xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */
|
||||
xfs_extlen_t di_extsize; /* basic/minimum extent size for file */
|
||||
xfs_extnum_t di_nextents; /* number of extents in data fork */
|
||||
xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/
|
||||
__uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
|
||||
__int8_t di_aformat; /* format of attr fork's data */
|
||||
__uint32_t di_dmevmask; /* DMIG event mask */
|
||||
__uint16_t di_dmstate; /* DMIG state info */
|
||||
__uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
|
||||
__uint32_t di_gen; /* generation number */
|
||||
} xfs_dinode_core_t;
|
||||
|
||||
typedef struct xfs_dinode
|
||||
{
|
||||
xfs_dinode_core_t di_core;
|
||||
xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */
|
||||
union {
|
||||
xfs_bmdr_block_t di_bmbt; /* btree root block */
|
||||
xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */
|
||||
xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */
|
||||
char di_c[1]; /* local contents */
|
||||
} di_u;
|
||||
} xfs_dinode_t;
|
||||
|
||||
/*
|
||||
* Values for di_format
|
||||
*/
|
||||
typedef enum xfs_dinode_fmt
|
||||
{
|
||||
XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */
|
||||
XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */
|
||||
/* LNK: di_symlink */
|
||||
XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */
|
||||
XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */
|
||||
XFS_DINODE_FMT_UUID /* MNT: di_uuid */
|
||||
} xfs_dinode_fmt_t;
|
||||
|
||||
/*
|
||||
* File types (mode field)
|
||||
*/
|
||||
#define IFMT 0170000 /* type of file */
|
||||
#define IFDIR 0040000 /* directory */
|
||||
#define IFREG 0100000 /* regular */
|
||||
#define IFLNK 0120000 /* symbolic link */
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* context switching
|
||||
* 2003-10 by SONE Takeshi
|
||||
*/
|
||||
#include <etherboot.h>
|
||||
|
||||
#include "segment.h"
|
||||
#include "context.h"
|
||||
|
||||
#define MAIN_STACK_SIZE 16384
|
||||
#define IMAGE_STACK_SIZE 4096
|
||||
|
||||
static void start_main(void); /* forward decl. */
|
||||
void __exit_context(void); /* assembly routine */
|
||||
|
||||
/*
|
||||
* Main context structure
|
||||
* It is placed at the bottom of our stack, and loaded by assembly routine
|
||||
* to start us up.
|
||||
*/
|
||||
struct context main_ctx __attribute__((section (".initctx"))) = {
|
||||
.gdt_base = (uint32_t) gdt,
|
||||
.gdt_limit = GDT_LIMIT,
|
||||
.cs = FLAT_CS,
|
||||
.ds = FLAT_DS,
|
||||
.es = FLAT_DS,
|
||||
.fs = FLAT_DS,
|
||||
.gs = FLAT_DS,
|
||||
.ss = FLAT_DS,
|
||||
.esp = (uint32_t) ESP_LOC(&main_ctx),
|
||||
.eip = (uint32_t) start_main,
|
||||
.return_addr = (uint32_t) __exit_context,
|
||||
};
|
||||
|
||||
/* This is used by assembly routine to load/store the context which
|
||||
* it is to switch/switched. */
|
||||
struct context *__context = &main_ctx;
|
||||
|
||||
#if 0
|
||||
/* Stack for loaded ELF image */
|
||||
static uint8_t image_stack[IMAGE_STACK_SIZE];
|
||||
#endif
|
||||
|
||||
/* Pointer to startup context (physical address) */
|
||||
unsigned long __boot_ctx;
|
||||
|
||||
/*
|
||||
* Main starter
|
||||
* This is the C function that runs first.
|
||||
*/
|
||||
static void start_main(void)
|
||||
{
|
||||
int retval;
|
||||
extern int filo(void);
|
||||
|
||||
/* Save startup context, so we can refer to it later.
|
||||
* We have to keep it in physical address since we will relocate. */
|
||||
__boot_ctx = virt_to_phys(__context);
|
||||
|
||||
/* Start the real fun */
|
||||
retval = filo();
|
||||
|
||||
/* Pass return value to startup context. Bootloader may see it. */
|
||||
boot_ctx->eax = retval;
|
||||
|
||||
/* Returning from here should jump to __exit_context */
|
||||
__context = boot_ctx;
|
||||
}
|
||||
|
||||
/* Setup a new context using the given stack.
|
||||
*/
|
||||
struct context *
|
||||
init_context(uint8_t *stack, uint32_t stack_size, int num_params)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
ctx = (struct context *)
|
||||
(stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t)));
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
/* Fill in reasonable default for flat memory model */
|
||||
ctx->gdt_base = virt_to_phys(gdt);
|
||||
ctx->gdt_limit = GDT_LIMIT;
|
||||
ctx->cs = FLAT_CS;
|
||||
ctx->ds = FLAT_DS;
|
||||
ctx->es = FLAT_DS;
|
||||
ctx->fs = FLAT_DS;
|
||||
ctx->gs = FLAT_DS;
|
||||
ctx->ss = FLAT_DS;
|
||||
ctx->esp = virt_to_phys(ESP_LOC(ctx));
|
||||
ctx->return_addr = virt_to_phys(__exit_context);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* Switch to another context. */
|
||||
struct context *switch_to(struct context *ctx)
|
||||
{
|
||||
struct context *save, *ret;
|
||||
|
||||
save = __context;
|
||||
__context = ctx;
|
||||
asm ("pushl %cs; call __switch_context");
|
||||
ret = __context;
|
||||
__context = save;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//We will use elf_start in Etherboot
|
||||
/* Start ELF Boot image */
|
||||
uint32_t start_elf(uint32_t entry_point, uint32_t param)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
ctx = init_context(image_stack, sizeof image_stack, 1);
|
||||
ctx->eip = entry_point;
|
||||
ctx->param[0] = param;
|
||||
ctx->eax = 0xe1fb007;
|
||||
ctx->ebx = param;
|
||||
|
||||
ctx = switch_to(ctx);
|
||||
return ctx->eax;
|
||||
}
|
||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef i386_CONTEXT_H
|
||||
#define i386_CONTEXT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct context {
|
||||
/* Stack Segment, placed here because of the alignment issue... */
|
||||
uint16_t ss;
|
||||
/* Used with sgdt/lgdt */
|
||||
uint16_t gdt_limit;
|
||||
uint32_t gdt_base;
|
||||
/* General registers, accessed with pushal/popal */
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
uint32_t esp; /* points just below eax */
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
#define ESP_LOC(ctx) (&(ctx)->gs)
|
||||
/* Segment registers */
|
||||
uint32_t gs;
|
||||
uint32_t fs;
|
||||
uint32_t es;
|
||||
uint32_t ds;
|
||||
/* Flags */
|
||||
uint32_t eflags;
|
||||
/* Code segment:offset */
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
/* Optional stack contents */
|
||||
uint32_t return_addr;
|
||||
uint32_t param[0];
|
||||
};
|
||||
|
||||
/* Create a new context in the given stack */
|
||||
struct context *
|
||||
init_context(uint8_t *stack, uint32_t stack_size, int num_param);
|
||||
|
||||
/* Switch context */
|
||||
struct context *switch_to(struct context *);
|
||||
|
||||
/* Holds physical address of boot context */
|
||||
extern unsigned long __boot_ctx;
|
||||
|
||||
/* This can always be safely used to refer to the boot context */
|
||||
#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx))
|
||||
|
||||
#endif /* i386_CONTEXT_H */
|
|
@ -1,629 +0,0 @@
|
|||
/*
|
||||
* Linux/i386 loader
|
||||
* Supports bzImage, zImage and Image format.
|
||||
*
|
||||
* Based on work by Steve Gehlbach.
|
||||
* Portions are taken from mkelfImage.
|
||||
*
|
||||
* 2003-09 by SONE Takeshi
|
||||
*/
|
||||
#include <etherboot.h>
|
||||
|
||||
#include <lib.h>
|
||||
|
||||
#include <fs.h>
|
||||
#include <sys_info.h>
|
||||
|
||||
#include "context.h"
|
||||
#include "segment.h"
|
||||
|
||||
#define DEBUG_THIS DEBUG_LINUXLOAD
|
||||
#include <debug.h>
|
||||
|
||||
#define LINUX_PARAM_LOC 0x90000
|
||||
#define COMMAND_LINE_LOC 0x91000
|
||||
#define GDT_LOC 0x92000
|
||||
#define STACK_LOC 0x93000
|
||||
|
||||
/* The header of Linux/i386 kernel */
|
||||
struct linux_header {
|
||||
uint8_t reserved1[0x1f1]; /* 0x000 */
|
||||
uint8_t setup_sects; /* 0x1f1 */
|
||||
uint16_t root_flags; /* 0x1f2 */
|
||||
uint8_t reserved2[6]; /* 0x1f4 */
|
||||
uint16_t vid_mode; /* 0x1fa */
|
||||
uint16_t root_dev; /* 0x1fc */
|
||||
uint16_t boot_sector_magic; /* 0x1fe */
|
||||
/* 2.00+ */
|
||||
uint8_t reserved3[2]; /* 0x200 */
|
||||
uint8_t header_magic[4]; /* 0x202 */
|
||||
uint16_t protocol_version; /* 0x206 */
|
||||
uint32_t realmode_swtch; /* 0x208 */
|
||||
uint16_t start_sys; /* 0x20c */
|
||||
uint16_t kver_addr; /* 0x20e */
|
||||
uint8_t type_of_loader; /* 0x210 */
|
||||
uint8_t loadflags; /* 0x211 */
|
||||
uint16_t setup_move_size; /* 0x212 */
|
||||
uint32_t code32_start; /* 0x214 */
|
||||
uint32_t ramdisk_image; /* 0x218 */
|
||||
uint32_t ramdisk_size; /* 0x21c */
|
||||
uint8_t reserved4[4]; /* 0x220 */
|
||||
/* 2.01+ */
|
||||
uint16_t heap_end_ptr; /* 0x224 */
|
||||
uint8_t reserved5[2]; /* 0x226 */
|
||||
/* 2.02+ */
|
||||
uint32_t cmd_line_ptr; /* 0x228 */
|
||||
/* 2.03+ */
|
||||
uint32_t initrd_addr_max; /* 0x22c */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* Paramters passed to 32-bit part of Linux
|
||||
* This is another view of the structure above.. */
|
||||
struct linux_params {
|
||||
uint8_t orig_x; /* 0x00 */
|
||||
uint8_t orig_y; /* 0x01 */
|
||||
uint16_t ext_mem_k; /* 0x02 -- EXT_MEM_K sits here */
|
||||
uint16_t orig_video_page; /* 0x04 */
|
||||
uint8_t orig_video_mode; /* 0x06 */
|
||||
uint8_t orig_video_cols; /* 0x07 */
|
||||
uint16_t unused2; /* 0x08 */
|
||||
uint16_t orig_video_ega_bx; /* 0x0a */
|
||||
uint16_t unused3; /* 0x0c */
|
||||
uint8_t orig_video_lines; /* 0x0e */
|
||||
uint8_t orig_video_isVGA; /* 0x0f */
|
||||
uint16_t orig_video_points; /* 0x10 */
|
||||
|
||||
/* VESA graphic mode -- linear frame buffer */
|
||||
uint16_t lfb_width; /* 0x12 */
|
||||
uint16_t lfb_height; /* 0x14 */
|
||||
uint16_t lfb_depth; /* 0x16 */
|
||||
uint32_t lfb_base; /* 0x18 */
|
||||
uint32_t lfb_size; /* 0x1c */
|
||||
uint16_t cl_magic; /* 0x20 */
|
||||
#define CL_MAGIC_VALUE 0xA33F
|
||||
uint16_t cl_offset; /* 0x22 */
|
||||
uint16_t lfb_linelength; /* 0x24 */
|
||||
uint8_t red_size; /* 0x26 */
|
||||
uint8_t red_pos; /* 0x27 */
|
||||
uint8_t green_size; /* 0x28 */
|
||||
uint8_t green_pos; /* 0x29 */
|
||||
uint8_t blue_size; /* 0x2a */
|
||||
uint8_t blue_pos; /* 0x2b */
|
||||
uint8_t rsvd_size; /* 0x2c */
|
||||
uint8_t rsvd_pos; /* 0x2d */
|
||||
uint16_t vesapm_seg; /* 0x2e */
|
||||
uint16_t vesapm_off; /* 0x30 */
|
||||
uint16_t pages; /* 0x32 */
|
||||
uint8_t reserved4[12]; /* 0x34 -- 0x3f reserved for future expansion */
|
||||
|
||||
//struct apm_bios_info apm_bios_info; /* 0x40 */
|
||||
uint8_t apm_bios_info[0x40];
|
||||
//struct drive_info_struct drive_info; /* 0x80 */
|
||||
uint8_t drive_info[0x20];
|
||||
//struct sys_desc_table sys_desc_table; /* 0xa0 */
|
||||
uint8_t sys_desc_table[0x140];
|
||||
uint32_t alt_mem_k; /* 0x1e0 */
|
||||
uint8_t reserved5[4]; /* 0x1e4 */
|
||||
uint8_t e820_map_nr; /* 0x1e8 */
|
||||
uint8_t reserved6[9]; /* 0x1e9 */
|
||||
uint16_t mount_root_rdonly; /* 0x1f2 */
|
||||
uint8_t reserved7[4]; /* 0x1f4 */
|
||||
uint16_t ramdisk_flags; /* 0x1f8 */
|
||||
#define RAMDISK_IMAGE_START_MASK 0x07FF
|
||||
#define RAMDISK_PROMPT_FLAG 0x8000
|
||||
#define RAMDISK_LOAD_FLAG 0x4000
|
||||
uint8_t reserved8[2]; /* 0x1fa */
|
||||
uint16_t orig_root_dev; /* 0x1fc */
|
||||
uint8_t reserved9[1]; /* 0x1fe */
|
||||
uint8_t aux_device_info; /* 0x1ff */
|
||||
uint8_t reserved10[2]; /* 0x200 */
|
||||
uint8_t param_block_signature[4]; /* 0x202 */
|
||||
uint16_t param_block_version; /* 0x206 */
|
||||
uint8_t reserved11[8]; /* 0x208 */
|
||||
uint8_t loader_type; /* 0x210 */
|
||||
#define LOADER_TYPE_LOADLIN 1
|
||||
#define LOADER_TYPE_BOOTSECT_LOADER 2
|
||||
#define LOADER_TYPE_SYSLINUX 3
|
||||
#define LOADER_TYPE_ETHERBOOT 4
|
||||
#define LOADER_TYPE_KERNEL 5
|
||||
uint8_t loader_flags; /* 0x211 */
|
||||
uint8_t reserved12[2]; /* 0x212 */
|
||||
uint32_t kernel_start; /* 0x214 */
|
||||
uint32_t initrd_start; /* 0x218 */
|
||||
uint32_t initrd_size; /* 0x21c */
|
||||
uint8_t reserved12_5[8]; /* 0x220 */
|
||||
uint32_t cmd_line_ptr; /* 0x228 */
|
||||
uint8_t reserved13[164]; /* 0x22c */
|
||||
struct e820entry e820_map[E820MAX]; /* 0x2d0 */
|
||||
uint8_t reserved16[688]; /* 0x550 */
|
||||
#define COMMAND_LINE_SIZE 256
|
||||
/* Command line is copied here by 32-bit i386/kernel/head.S.
|
||||
* So I will follow the boot protocol, rather than putting it
|
||||
* directly here. --ts1 */
|
||||
uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */
|
||||
uint8_t reserved17[1792]; /* 0x900 - 0x1000 */
|
||||
};
|
||||
|
||||
uint64_t forced_memsize;
|
||||
|
||||
/* Load the first part the file and check if it's Linux */
|
||||
static uint32_t load_linux_header(struct linux_header *hdr)
|
||||
{
|
||||
int load_high;
|
||||
uint32_t kern_addr;
|
||||
|
||||
if (file_read(hdr, sizeof *hdr) != sizeof *hdr) {
|
||||
debug("Can't read Linux header\n");
|
||||
return 0;
|
||||
}
|
||||
if (hdr->boot_sector_magic != 0xaa55) {
|
||||
debug("Not a Linux kernel image\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Linux is found. Print some information */
|
||||
if (memcmp(hdr->header_magic, "HdrS", 4) != 0) {
|
||||
/* This may be floppy disk image or something.
|
||||
* Perform a simple (incomplete) sanity check. */
|
||||
if (hdr->setup_sects >= 16
|
||||
|| file_size() - (hdr->setup_sects<<9) >= 512<<10) {
|
||||
debug("This looks like a bootdisk image but not like Linux...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
debugx("Possible very old Linux");
|
||||
/* This kernel does not even have a protocol version.
|
||||
* Force the value. */
|
||||
hdr->protocol_version = 0; /* pre-2.00 */
|
||||
} else
|
||||
printf("Found Linux");
|
||||
if (hdr->protocol_version >= 0x200 && hdr->kver_addr) {
|
||||
char kver[256];
|
||||
file_seek(hdr->kver_addr + 0x200);
|
||||
if (file_read(kver, sizeof kver) != 0) {
|
||||
kver[255] = 0;
|
||||
printf(" version %s", kver);
|
||||
}
|
||||
}
|
||||
debug(" (protocol %#x)", hdr->protocol_version);
|
||||
load_high = 0;
|
||||
if (hdr->protocol_version >= 0x200) {
|
||||
debug(" (loadflags %#x)", hdr->loadflags);
|
||||
load_high = hdr->loadflags & 1;
|
||||
}
|
||||
if (load_high) {
|
||||
printf(" bzImage");
|
||||
kern_addr = 0x100000;
|
||||
} else {
|
||||
printf(" zImage or Image");
|
||||
kern_addr = 0x1000;
|
||||
}
|
||||
printf(".\n");
|
||||
|
||||
return kern_addr;
|
||||
}
|
||||
|
||||
/* Set up parameters for 32-bit kernel */
|
||||
static void
|
||||
init_linux_params(struct linux_params *params, struct linux_header *hdr)
|
||||
{
|
||||
debug("Setting up paramters at %#lx\n", virt_to_phys(params));
|
||||
memset(params, 0, sizeof *params);
|
||||
|
||||
/* Copy some useful values from header */
|
||||
params->mount_root_rdonly = hdr->root_flags;
|
||||
params->orig_root_dev = hdr->root_dev;
|
||||
|
||||
/* Video parameters.
|
||||
* This assumes we have VGA in standard 80x25 text mode,
|
||||
* just like our vga.c does.
|
||||
* Cursor position is filled later to allow some more printf's. */
|
||||
params->orig_video_mode = 3;
|
||||
params->orig_video_cols = 80;
|
||||
params->orig_video_lines = 25;
|
||||
params->orig_video_isVGA = 1;
|
||||
params->orig_video_points = 16;
|
||||
|
||||
params->loader_type = 0xff; /* Unregistered Linux loader */
|
||||
}
|
||||
|
||||
/* Memory map */
|
||||
static void
|
||||
set_memory_size(struct linux_params *params, struct sys_info *info)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t ramtop = 0;
|
||||
struct e820entry *linux_map;
|
||||
struct e820entry *filo_map;
|
||||
|
||||
linux_map = params->e820_map;
|
||||
|
||||
filo_map = meminfo.map;
|
||||
for (i = 0; i < meminfo.map_count; i++, linux_map++, filo_map++) {
|
||||
if (i < E820MAX) {
|
||||
/* Convert to BIOS e820 style */
|
||||
linux_map->addr = filo_map->addr;
|
||||
linux_map->size = filo_map->size;
|
||||
linux_map->type = filo_map->type;
|
||||
// debug("%016Lx - %016Lx\n", linux_map->addr,linux_map->addr + linux_map->size);
|
||||
params->e820_map_nr = i+1;
|
||||
}
|
||||
|
||||
}
|
||||
ramtop = meminfo.memsize;
|
||||
debug("ramtop=%#xk\n", ramtop);
|
||||
/* Size of memory above 1MB in KB */
|
||||
params->alt_mem_k = ramtop;
|
||||
/* old style, 64MB max */
|
||||
if (ramtop >= (64<<10))
|
||||
params->ext_mem_k = (63<<10);
|
||||
else
|
||||
params->ext_mem_k = params->alt_mem_k;
|
||||
|
||||
debug("ext_mem_k=%d, alt_mem_k=%d\n", params->ext_mem_k, params->alt_mem_k);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse command line
|
||||
* Some parameters, like initrd=<file>, are not passed to kernel,
|
||||
* we are responsible to process them.
|
||||
* Parameters for kernel are copied to kern_cmdline. Returns name of initrd.
|
||||
*/
|
||||
static char *parse_command_line(const char *orig_cmdline, char *kern_cmdline)
|
||||
{
|
||||
const char *start, *sep, *end, *val;
|
||||
char name[64];
|
||||
int len;
|
||||
int k_len;
|
||||
int to_kern;
|
||||
char *initrd = 0;
|
||||
int toolong = 0;
|
||||
|
||||
forced_memsize = 0;
|
||||
|
||||
if (!orig_cmdline) {
|
||||
*kern_cmdline = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_len = 0;
|
||||
debug("original command line: \"%s\"\n", orig_cmdline);
|
||||
debug("kernel command line at %#lx\n", virt_to_phys(kern_cmdline));
|
||||
|
||||
start = orig_cmdline;
|
||||
while (*start == ' ')
|
||||
start++;
|
||||
while (*start) {
|
||||
end = strchr(start, ' ');
|
||||
if (!end)
|
||||
end = start + strlen(start);
|
||||
sep = strchr(start, '=');
|
||||
if (!sep || sep > end)
|
||||
sep = end;
|
||||
len = sep - start;
|
||||
if (len >= sizeof(name))
|
||||
len = sizeof(name) - 1;
|
||||
memcpy(name, start, len);
|
||||
name[len] = 0;
|
||||
|
||||
if (*sep == '=') {
|
||||
val = sep + 1;
|
||||
len = end - val;
|
||||
} else {
|
||||
val = 0;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Only initrd= and mem= are handled here. vga= is not,
|
||||
* which I believe is a paramter to the realmode part of Linux,
|
||||
* which we don't execute. */
|
||||
if (strcmp(name, "initrd") == 0) {
|
||||
if (!val)
|
||||
printf("Missing filename to initrd parameter\n");
|
||||
else {
|
||||
initrd = allot(len + 1);
|
||||
memcpy(initrd, val, len);
|
||||
initrd[len] = 0;
|
||||
debug("initrd=%s\n", initrd);
|
||||
}
|
||||
/* Don't pass this to kernel */
|
||||
to_kern = 0;
|
||||
} else if (strcmp(name, "mem") == 0) {
|
||||
if (!val)
|
||||
printf("Missing value for mem parameter\n");
|
||||
else {
|
||||
forced_memsize = strtoull_with_suffix(val, (char**)&val, 0);
|
||||
if (forced_memsize == 0)
|
||||
printf("Invalid mem option, ignored\n");
|
||||
if (val != end) {
|
||||
printf("Garbage after mem=<size>, ignored\n");
|
||||
forced_memsize = 0;
|
||||
}
|
||||
// debug("mem=%Lu\n", forced_memsize);
|
||||
}
|
||||
/* mem= is for both loader and kernel */
|
||||
to_kern = 1;
|
||||
} else
|
||||
to_kern = 1;
|
||||
|
||||
if (to_kern) {
|
||||
/* Copy to kernel command line buffer */
|
||||
if (k_len != 0)
|
||||
kern_cmdline[k_len++] = ' '; /* put separator */
|
||||
len = end - start;
|
||||
if (k_len + len >= COMMAND_LINE_SIZE) {
|
||||
len = COMMAND_LINE_SIZE - k_len - 1;
|
||||
if (!toolong) {
|
||||
printf("Kernel command line is too long; truncated to "
|
||||
"%d bytes\n", COMMAND_LINE_SIZE-1);
|
||||
toolong = 1;
|
||||
}
|
||||
}
|
||||
memcpy(kern_cmdline + k_len, start, len);
|
||||
k_len += len;
|
||||
}
|
||||
|
||||
start = end;
|
||||
while (*start == ' ')
|
||||
start++;
|
||||
}
|
||||
kern_cmdline[k_len] = 0;
|
||||
debug("kernel command line (%d bytes): \"%s\"\n", k_len, kern_cmdline);
|
||||
|
||||
return initrd;
|
||||
}
|
||||
|
||||
/* Set command line location */
|
||||
static void set_command_line_loc(struct linux_params *params,
|
||||
struct linux_header *hdr)
|
||||
{
|
||||
if (hdr->protocol_version >= 0x202) {
|
||||
/* new style */
|
||||
params->cmd_line_ptr = COMMAND_LINE_LOC;
|
||||
} else {
|
||||
/* old style */
|
||||
params->cl_magic = CL_MAGIC_VALUE;
|
||||
params->cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load 32-bit part of kernel */
|
||||
static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr)
|
||||
{
|
||||
uint32_t kern_offset, kern_size;
|
||||
|
||||
if (hdr->setup_sects == 0)
|
||||
hdr->setup_sects = 4;
|
||||
kern_offset = (hdr->setup_sects + 1) * 512;
|
||||
file_seek(kern_offset);
|
||||
kern_size = file_size() - kern_offset;
|
||||
debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size);
|
||||
|
||||
if (using_devsize) {
|
||||
printf("Attempt to load up to end of device as kernel; "
|
||||
"specify the image size\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Loading kernel... ");
|
||||
if (file_read(phys_to_virt(kern_addr), kern_size) != kern_size) {
|
||||
printf("Can't read kernel\n");
|
||||
return 0;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
return kern_size;
|
||||
}
|
||||
|
||||
static int load_initrd(struct linux_header *hdr, struct sys_info *info,
|
||||
uint32_t kern_end, struct linux_params *params, const char *initrd_file)
|
||||
{
|
||||
uint32_t max;
|
||||
uint32_t start, end, size;
|
||||
uint64_t forced;
|
||||
extern char _virt_start[], _end[];
|
||||
|
||||
if (!file_open(initrd_file)) {
|
||||
printf("Can't open initrd: %s\n", initrd_file);
|
||||
return -1;
|
||||
}
|
||||
if (using_devsize) {
|
||||
printf("Attempt to load up to end of device as initrd; "
|
||||
"specify the image size\n");
|
||||
return -1;
|
||||
}
|
||||
size = file_size();
|
||||
|
||||
|
||||
/* Find out the kernel's restriction on how high the initrd can be
|
||||
* placed */
|
||||
if (hdr->protocol_version >= 0x203)
|
||||
max = hdr->initrd_addr_max;
|
||||
else
|
||||
max = 0x38000000; /* Hardcoded value for older kernels */
|
||||
|
||||
/* FILO itself is at the top of RAM. (relocated)
|
||||
* So, try putting initrd just below us. */
|
||||
end = virt_to_phys(_virt_start);
|
||||
if (end > max)
|
||||
end = max;
|
||||
|
||||
/* If "mem=" option is given, we have to put the initrd within
|
||||
* the specified range. */
|
||||
if (forced_memsize) {
|
||||
forced = forced_memsize;
|
||||
if (forced > max)
|
||||
forced = max;
|
||||
/* If the "mem=" is lower, it's easy */
|
||||
if (forced <= end)
|
||||
end = forced;
|
||||
else {
|
||||
/* Otherwise, see if we can put it above us */
|
||||
if (virt_to_phys(_end) + size <= forced)
|
||||
end = forced; /* Ok */
|
||||
}
|
||||
}
|
||||
|
||||
start = end - size;
|
||||
start &= ~0xfff; /* page align */
|
||||
end = start + size;
|
||||
|
||||
debug("start=%#x end=%#x\n", start, end);
|
||||
|
||||
if (start < kern_end) {
|
||||
printf("Initrd is too big\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Loading initrd... ");
|
||||
if (file_read(phys_to_virt(start), size) != size) {
|
||||
printf("Can't read initrd\n");
|
||||
return -1;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
params->initrd_start = start;
|
||||
params->initrd_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hardware_setup(void)
|
||||
{
|
||||
/* Disable nmi */
|
||||
outb(0x80, 0x70);
|
||||
|
||||
/* Make sure any coprocessor is properly reset.. */
|
||||
outb(0, 0xf0);
|
||||
outb(0, 0xf1);
|
||||
|
||||
/* we're getting screwed again and again by this problem of the 8259.
|
||||
* so we're going to leave this lying around for inclusion into
|
||||
* crt0.S on an as-needed basis.
|
||||
*
|
||||
* well, that went ok, I hope. Now we have to reprogram the interrupts :-(
|
||||
* we put them right after the intel-reserved hardware interrupts, at
|
||||
* int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
|
||||
* messed this up with the original PC, and they haven't been able to
|
||||
* rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
|
||||
* which is used for the internal hardware interrupts as well. We just
|
||||
* have to reprogram the 8259's, and it isn't fun.
|
||||
*/
|
||||
|
||||
outb(0x11, 0x20); /* initialization sequence to 8259A-1 */
|
||||
outb(0x11, 0xA0); /* and to 8259A-2 */
|
||||
|
||||
outb(0x20, 0x21); /* start of hardware int's (0x20) */
|
||||
outb(0x28, 0xA1); /* start of hardware int's 2 (0x28) */
|
||||
|
||||
outb(0x04, 0x21); /* 8259-1 is master */
|
||||
outb(0x02, 0xA1); /* 8259-2 is slave */
|
||||
|
||||
outb(0x01, 0x21); /* 8086 mode for both */
|
||||
outb(0x01, 0xA1);
|
||||
|
||||
outb(0xFF, 0xA1); /* mask off all interrupts for now */
|
||||
outb(0xFB, 0x21); /* mask all irq's but irq2 which is cascaded */
|
||||
}
|
||||
|
||||
/* Start Linux */
|
||||
static int start_linux(uint32_t kern_addr, struct linux_params *params)
|
||||
{
|
||||
struct segment_desc *linux_gdt;
|
||||
struct context *ctx;
|
||||
#if 0
|
||||
extern int cursor_x, cursor_y;
|
||||
#endif
|
||||
|
||||
ctx = init_context(phys_to_virt(STACK_LOC), 4096, 0);
|
||||
|
||||
/* Linux expects GDT being in low memory */
|
||||
linux_gdt = phys_to_virt(GDT_LOC);
|
||||
memset(linux_gdt, 0, 13*sizeof(struct segment_desc));
|
||||
/* Normal kernel code/data segments */
|
||||
linux_gdt[2] = gdt[FLAT_CODE];
|
||||
linux_gdt[3] = gdt[FLAT_DATA];
|
||||
/* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible
|
||||
* segments (2 and 3), so it SHOULD not be a problem.
|
||||
* However, some distro kernels (eg. RH9) with backported threading
|
||||
* patch use 12 and 13 also when booting... */
|
||||
linux_gdt[12] = gdt[FLAT_CODE];
|
||||
linux_gdt[13] = gdt[FLAT_DATA];
|
||||
ctx->gdt_base = GDT_LOC;
|
||||
ctx->gdt_limit = 14*8-1;
|
||||
ctx->cs = 0x10;
|
||||
ctx->ds = 0x18;
|
||||
ctx->es = 0x18;
|
||||
ctx->fs = 0x18;
|
||||
ctx->gs = 0x18;
|
||||
ctx->ss = 0x18;
|
||||
|
||||
/* Parameter location */
|
||||
ctx->esi = virt_to_phys(params);
|
||||
|
||||
/* Entry point */
|
||||
ctx->eip = kern_addr;
|
||||
|
||||
debug("eip=%#x\n", kern_addr);
|
||||
printf("Jumping to entry point...\n");
|
||||
|
||||
#ifdef VGA_CONSOLE
|
||||
/* Update VGA cursor position.
|
||||
* This must be here because the printf changes the value! */
|
||||
#if 0
|
||||
params->orig_x = cursor_x;
|
||||
params->orig_y = cursor_y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Go... */
|
||||
ctx = switch_to(ctx);
|
||||
|
||||
/* It's impossible but... */
|
||||
printf("Returned with eax=%#x\n", ctx->eax);
|
||||
|
||||
return ctx->eax;
|
||||
}
|
||||
|
||||
int linux_load(struct sys_info *info, const char *file, const char *cmdline)
|
||||
{
|
||||
struct linux_header hdr;
|
||||
struct linux_params *params;
|
||||
uint32_t kern_addr, kern_size;
|
||||
char *initrd_file = 0;
|
||||
|
||||
if (!file_open(file))
|
||||
return -1;
|
||||
|
||||
kern_addr = load_linux_header(&hdr);
|
||||
if (kern_addr == 0)
|
||||
return LOADER_NOT_SUPPORT;
|
||||
|
||||
params = phys_to_virt(LINUX_PARAM_LOC);
|
||||
init_linux_params(params, &hdr);
|
||||
set_memory_size(params, info);
|
||||
initrd_file = parse_command_line(cmdline, phys_to_virt(COMMAND_LINE_LOC));
|
||||
set_command_line_loc(params, &hdr);
|
||||
|
||||
kern_size = load_linux_kernel(&hdr, kern_addr);
|
||||
if (kern_size == 0) {
|
||||
if (initrd_file)
|
||||
forget(initrd_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (initrd_file) {
|
||||
if (load_initrd(&hdr, info, kern_addr+kern_size, params, initrd_file)
|
||||
!= 0) {
|
||||
forget(initrd_file);
|
||||
return -1;
|
||||
}
|
||||
forget(initrd_file);
|
||||
}
|
||||
|
||||
hardware_setup();
|
||||
|
||||
start_linux(kern_addr, params);
|
||||
return 0;
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/* Support for Multiboot */
|
||||
#include <etherboot.h>
|
||||
|
||||
#include <lib.h>
|
||||
#include <sys_info.h>
|
||||
#include <arch/io.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_MULTIBOOT
|
||||
#include <debug.h>
|
||||
|
||||
/* Multiboot header, gives information to loader */
|
||||
|
||||
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||
#define MULTIBOOT_HEADER_FLAGS 0x00000003
|
||||
|
||||
struct mbheader {
|
||||
unsigned int magic, flags, checksum;
|
||||
};
|
||||
const struct mbheader multiboot_header
|
||||
__attribute__((section (".hdr"))) =
|
||||
{
|
||||
MULTIBOOT_HEADER_MAGIC,
|
||||
MULTIBOOT_HEADER_FLAGS,
|
||||
-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
|
||||
};
|
||||
|
||||
/* Multiboot information structure, provided by loader to us */
|
||||
|
||||
struct multiboot_mmap {
|
||||
unsigned entry_size;
|
||||
unsigned base_lo, base_hi;
|
||||
unsigned size_lo, size_hi;
|
||||
unsigned type;
|
||||
};
|
||||
|
||||
struct multiboot_info {
|
||||
unsigned flags;
|
||||
#define MULTIBOOT_MEM_VALID 0x01
|
||||
#define MULTIBOOT_BOOT_DEV_VALID 0x02
|
||||
#define MULTIBOOT_CMDLINE_VALID 0x04
|
||||
#define MULTIBOOT_MODS_VALID 0x08
|
||||
#define MULTIBOOT_AOUT_SYMS_VALID 0x10
|
||||
#define MULTIBOOT_ELF_SYMS_VALID 0x20
|
||||
#define MULTIBOOT_MMAP_VALID 0x40
|
||||
unsigned mem_lower;
|
||||
unsigned mem_upper;
|
||||
unsigned char boot_device[4];
|
||||
unsigned command_line;
|
||||
unsigned mods_count;
|
||||
unsigned mods_addr;
|
||||
unsigned syms_num;
|
||||
unsigned syms_size;
|
||||
unsigned syms_addr;
|
||||
unsigned syms_shndx;
|
||||
unsigned mmap_length;
|
||||
unsigned mmap_addr;
|
||||
};
|
||||
|
||||
void collect_multiboot_info(struct sys_info *info)
|
||||
{
|
||||
struct multiboot_info *mbinfo;
|
||||
struct multiboot_mmap *mbmem;
|
||||
unsigned mbcount, mbaddr;
|
||||
int i;
|
||||
struct memrange *mmap;
|
||||
int mmap_count;
|
||||
|
||||
if (info->boot_type != 0x2BADB002)
|
||||
return;
|
||||
|
||||
debug("Using Multiboot information at %#lx\n", info->boot_data);
|
||||
|
||||
mbinfo = phys_to_virt(info->boot_data);
|
||||
|
||||
if (mbinfo->flags & MULTIBOOT_MMAP_VALID) {
|
||||
/* convert mmap records */
|
||||
mbmem = phys_to_virt(mbinfo->mmap_addr);
|
||||
mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4);
|
||||
mmap = malloc(mbcount * sizeof *mmap);
|
||||
mmap_count = 0;
|
||||
mbaddr = mbinfo->mmap_addr;
|
||||
for (i = 0; i < mbcount; i++) {
|
||||
mbmem = phys_to_virt(mbaddr);
|
||||
debug("%08x%08x %08x%08x (%d)\n",
|
||||
mbmem->base_hi,
|
||||
mbmem->base_lo,
|
||||
mbmem->size_hi,
|
||||
mbmem->size_lo,
|
||||
mbmem->type);
|
||||
if (mbmem->type == 1) { /* Only normal RAM */
|
||||
mmap[mmap_count].base = mbmem->base_lo
|
||||
+ (((unsigned long long) mbmem->base_hi) << 32);
|
||||
mmap[mmap_count].size = mbmem->size_lo
|
||||
+ (((unsigned long long) mbmem->size_hi) << 32);
|
||||
mmap_count++;
|
||||
}
|
||||
mbaddr += mbmem->entry_size + 4;
|
||||
if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length)
|
||||
break;
|
||||
}
|
||||
/* simple sanity check - there should be at least 2 RAM segments
|
||||
* (base 640k and extended) */
|
||||
if (mmap_count >= 2)
|
||||
goto got_it;
|
||||
|
||||
printf("Multiboot mmap is broken\n");
|
||||
free(mmap);
|
||||
/* fall back to mem_lower/mem_upper */
|
||||
}
|
||||
|
||||
if (mbinfo->flags & MULTIBOOT_MEM_VALID) {
|
||||
/* use mem_lower and mem_upper */
|
||||
mmap_count = 2;
|
||||
mmap = malloc(2 * sizeof(*mmap));
|
||||
mmap[0].base = 0;
|
||||
mmap[0].size = mbinfo->mem_lower << 10;
|
||||
mmap[1].base = 1 << 20; /* 1MB */
|
||||
mmap[1].size = mbinfo->mem_upper << 10;
|
||||
goto got_it;
|
||||
}
|
||||
|
||||
printf("Can't get memory information from Multiboot\n");
|
||||
return;
|
||||
|
||||
got_it:
|
||||
info->memrange = mmap;
|
||||
info->n_memranges = mmap_count;
|
||||
return;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/* Segmentation of the i386 architecture.
|
||||
*
|
||||
* 2003-07 by SONE Takeshi
|
||||
*/
|
||||
#include <etherboot.h>
|
||||
|
||||
//#include <lib.h>
|
||||
#include <sys_info.h>
|
||||
#include "segment.h"
|
||||
|
||||
#define DEBUG_THIS DEBUG_SEGMENT
|
||||
#include <debug.h>
|
||||
|
||||
/* i386 lgdt argument */
|
||||
struct gdtarg {
|
||||
unsigned short limit;
|
||||
unsigned int base;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* GDT, the global descriptor table */
|
||||
struct segment_desc gdt[NUM_SEG] = {
|
||||
/* 0x00: null segment */
|
||||
{0, 0, 0, 0, 0, 0},
|
||||
/* 0x08: flat code segment */
|
||||
{0xffff, 0, 0, 0x9f, 0xcf, 0},
|
||||
/* 0x10: flat data segment */
|
||||
{0xffff, 0, 0, 0x93, 0xcf, 0},
|
||||
/* 0x18: code segment for relocated execution */
|
||||
{0xffff, 0, 0, 0x9f, 0xcf, 0},
|
||||
/* 0x20: data segment for relocated execution */
|
||||
{0xffff, 0, 0, 0x93, 0xcf, 0},
|
||||
};
|
||||
|
||||
/* Copy GDT to new location and reload it */
|
||||
void move_gdt(unsigned long newgdt)
|
||||
{
|
||||
struct gdtarg gdtarg;
|
||||
|
||||
debug("Moving GDT to %#lx...", newgdt);
|
||||
memcpy(phys_to_virt(newgdt), gdt, sizeof gdt);
|
||||
gdtarg.base = newgdt;
|
||||
gdtarg.limit = GDT_LIMIT;
|
||||
debug("reloading GDT...");
|
||||
__asm__ __volatile__ ("lgdt %0\n\t" : : "m" (gdtarg));
|
||||
debug("reloading CS for fun...");
|
||||
__asm__ __volatile__ ("ljmp %0, $1f\n1:" : : "n" (RELOC_CS));
|
||||
debug("ok\n");
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* Segment indexes. Must match the gdt definition in segment.c. */
|
||||
enum {
|
||||
NULL_SEG,
|
||||
FLAT_CODE,
|
||||
FLAT_DATA,
|
||||
RELOC_CODE,
|
||||
RELOC_DATA,
|
||||
NUM_SEG,
|
||||
};
|
||||
|
||||
/* Values for segment selector register */
|
||||
#define FLAT_CS (FLAT_CODE << 3)
|
||||
#define FLAT_DS (FLAT_DATA << 3)
|
||||
#define RELOC_CS (RELOC_CODE << 3)
|
||||
#define RELOC_DS (RELOC_DATA << 3)
|
||||
|
||||
/* i386 segment descriptor */
|
||||
struct segment_desc {
|
||||
unsigned short limit_0;
|
||||
unsigned short base_0;
|
||||
unsigned char base_16;
|
||||
unsigned char types;
|
||||
unsigned char flags;
|
||||
unsigned char base_24;
|
||||
};
|
||||
|
||||
extern struct segment_desc gdt[NUM_SEG];
|
||||
|
||||
#define GDT_LIMIT ((NUM_SEG << 3) - 1)
|
|
@ -1,116 +0,0 @@
|
|||
.globl entry, __switch_context, __exit_context, halt
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
/*
|
||||
* Entry point
|
||||
* We start execution from here.
|
||||
* It is assumed that CPU is in 32-bit protected mode and
|
||||
* all segments are 4GB and base zero (flat model).
|
||||
*/
|
||||
entry:
|
||||
/* Save boot context and switch to our main context.
|
||||
* Main context is statically defined in C.
|
||||
*/
|
||||
pushl %cs
|
||||
call __switch_context
|
||||
|
||||
/* We get here when the main context switches back to
|
||||
* the boot context.
|
||||
* Return to previous bootloader.
|
||||
*/
|
||||
ret
|
||||
|
||||
/*
|
||||
* Switch execution context
|
||||
* This saves registers, segments, and GDT in the stack, then
|
||||
* switches the stack, and restores everything from the new stack.
|
||||
* This function takes no argument. New stack pointer is
|
||||
* taken from global variable __context, and old stack pointer
|
||||
* is also saved to __context. This way we can just jump to
|
||||
* this routine to get back to the original context.
|
||||
*
|
||||
* Call this routine with lcall or pushl %cs; call.
|
||||
*/
|
||||
__switch_context:
|
||||
/* Save everything in current stack */
|
||||
pushfl /* 56 */
|
||||
pushl %ds /* 52 */
|
||||
pushl %es /* 48 */
|
||||
pushl %fs /* 44 */
|
||||
pushl %gs /* 40 */
|
||||
pushal /* 8 */
|
||||
subl $8, %esp
|
||||
movw %ss, (%esp) /* 0 */
|
||||
sgdt 2(%esp) /* 2 */
|
||||
|
||||
#if 0
|
||||
/* Swap %cs and %eip on the stack, so lret will work */
|
||||
movl 60(%esp), %eax
|
||||
xchgl %eax, 64(%esp)
|
||||
movl %eax, 60(%esp)
|
||||
#endif
|
||||
|
||||
/* At this point we don't know if we are on flat segment
|
||||
* or relocated. So compute the address offset from %eip.
|
||||
* Assuming CS.base==DS.base==SS.base.
|
||||
*/
|
||||
call 1f
|
||||
1: popl %ebx
|
||||
subl $1b, %ebx
|
||||
|
||||
/* Interrupts are not allowed... */
|
||||
cli
|
||||
|
||||
/* Current context pointer is our stack pointer */
|
||||
movl %esp, %esi
|
||||
|
||||
/* Normalize the ctx pointer */
|
||||
subl %ebx, %esi
|
||||
|
||||
/* Swap it with new value */
|
||||
xchgl %esi, __context(%ebx)
|
||||
|
||||
/* Adjust new ctx pointer for current address offset */
|
||||
addl %ebx, %esi
|
||||
|
||||
/* Load new %ss and %esp to temporary */
|
||||
movzwl (%esi), %edx
|
||||
movl 20(%esi), %eax
|
||||
|
||||
/* Load new GDT */
|
||||
lgdt 2(%esi)
|
||||
|
||||
/* Load new stack segment with new GDT */
|
||||
movl %edx, %ss
|
||||
|
||||
/* Set new stack pointer, but we have to adjust it because
|
||||
* pushal saves %esp value before pushal, and we want the value
|
||||
* after pushal.
|
||||
*/
|
||||
leal -32(%eax), %esp
|
||||
|
||||
/* Load the rest from new stack */
|
||||
popal
|
||||
popl %gs
|
||||
popl %fs
|
||||
popl %es
|
||||
popl %ds
|
||||
popfl
|
||||
|
||||
/* Finally, load new %cs and %eip */
|
||||
lret
|
||||
|
||||
__exit_context:
|
||||
/* Get back to the original context */
|
||||
pushl %cs
|
||||
call __switch_context
|
||||
|
||||
/* We get here if the other context attempt to switch to this
|
||||
* dead context. This should not happen. */
|
||||
|
||||
halt:
|
||||
cli
|
||||
hlt
|
||||
jmp halt
|
|
@ -1,29 +0,0 @@
|
|||
#include <etherboot.h>
|
||||
#include <sys_info.h>
|
||||
#include "context.h"
|
||||
#define DEBUG_THIS DEBUG_SYS_INFO
|
||||
#include <debug.h>
|
||||
|
||||
void collect_multiboot_info(struct sys_info *);
|
||||
|
||||
void collect_sys_info(struct sys_info *info)
|
||||
{
|
||||
|
||||
/* Pick up paramters given by bootloader to us */
|
||||
info->boot_type = boot_ctx->eax;
|
||||
info->boot_data = boot_ctx->ebx;
|
||||
info->boot_arg = boot_ctx->param[0];
|
||||
debug("boot eax = %#lx\n", info->boot_type);
|
||||
debug("boot ebx = %#lx\n", info->boot_data);
|
||||
debug("boot arg = %#lx\n", info->boot_arg);
|
||||
|
||||
collect_elfboot_info(info);
|
||||
collect_linuxbios_info(info);
|
||||
#ifdef MULTIBOOT_IMAGE
|
||||
collect_multiboot_info(info);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
debug("RAM %Ld MB\n", (meminfo.memsize + 512*1024) >> 20);
|
||||
#endif
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
|
||||
#include "etherboot.h"
|
||||
|
||||
#include <lib.h>
|
||||
|
||||
int getline(char *buf, int max)
|
||||
{
|
||||
int cur, ch, nonspace_seen;
|
||||
|
||||
cur = 0;
|
||||
while (buf[cur]) {
|
||||
putchar(buf[cur]);
|
||||
cur++;
|
||||
}
|
||||
for (;;) {
|
||||
ch = getchar();
|
||||
switch (ch) {
|
||||
/* end of line */
|
||||
case '\r':
|
||||
case '\n':
|
||||
putchar('\n');
|
||||
goto out;
|
||||
/* backspace */
|
||||
case '\b':
|
||||
case '\x7f':
|
||||
if (cur > 0) {
|
||||
cur--;
|
||||
putchar('\b');
|
||||
putchar(' ');
|
||||
putchar('\b');
|
||||
}
|
||||
break;
|
||||
/* word erase */
|
||||
case 'W' & 0x1f: /* ^W */
|
||||
nonspace_seen = 0;
|
||||
while (cur) {
|
||||
if (buf[cur-1] != ' ')
|
||||
nonspace_seen = 1;
|
||||
putchar('\b');
|
||||
putchar(' ');
|
||||
putchar('\b');
|
||||
cur--;
|
||||
if (nonspace_seen && cur < max-1 && cur > 0 && buf[cur-1]==' ')
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* line erase */
|
||||
case 'U' & 0x1f: /* ^U */
|
||||
while (cur) {
|
||||
putchar('\b');
|
||||
putchar(' ');
|
||||
putchar('\b');
|
||||
cur--;
|
||||
}
|
||||
cur = 0;
|
||||
break;
|
||||
default:
|
||||
if (ch < 0x20)
|
||||
break; /* ignore control char */
|
||||
if (ch >= 0x7f)
|
||||
break;
|
||||
if (cur + 1 < max) {
|
||||
putchar(ch); /* echo back */
|
||||
buf[cur] = ch;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (cur >= max)
|
||||
cur = max - 1;
|
||||
buf[cur] = '\0';
|
||||
return cur;
|
||||
}
|
|
@ -1,398 +0,0 @@
|
|||
/* ELF Boot loader
|
||||
* As we have seek, this implementation can be straightforward.
|
||||
* 2003-07 by SONE Takeshi
|
||||
*/
|
||||
#include <etherboot.h>
|
||||
#include <elf.h>
|
||||
#include <bits/elf_x.h>
|
||||
#include <elf_boot.h>
|
||||
#include <lib.h>
|
||||
#include <sys_info.h>
|
||||
|
||||
#include <fs.h>
|
||||
#define DEBUG_THIS DEBUG_ELFBOOT
|
||||
#include <debug.h>
|
||||
|
||||
#if 1
|
||||
//Use that in Etherboot
|
||||
extern int elf_start(unsigned long __unused_i386, unsigned long entry, unsigned long param);
|
||||
#define start_elf(x,y) elf_start(0, x, y)
|
||||
#else
|
||||
// original in filo
|
||||
extern unsigned int start_elf(unsigned long entry_point, unsigned long param);
|
||||
#endif
|
||||
|
||||
extern char _virt_start[], _end[];
|
||||
|
||||
static char *image_name, *image_version;
|
||||
|
||||
static int check_mem_ranges(struct sys_info *info,
|
||||
Elf_phdr *phdr, int phnum)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long start, end;
|
||||
unsigned long prog_start, prog_end;
|
||||
#if 0
|
||||
struct memrange *mem;
|
||||
#else
|
||||
struct e820entry *mem;
|
||||
#endif
|
||||
|
||||
prog_start = virt_to_phys(&_virt_start);
|
||||
prog_end = virt_to_phys(&_end);
|
||||
|
||||
for (i = 0; i < phnum; i++) {
|
||||
if (phdr[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
start = phdr[i].p_paddr;
|
||||
end = start + phdr[i].p_memsz;
|
||||
if (start < prog_start && end > prog_start)
|
||||
goto conflict;
|
||||
if (start < prog_end && end > prog_end)
|
||||
goto conflict;
|
||||
#if 0
|
||||
for (j = 0; j < info->n_memranges; j++) {
|
||||
mem = &info->memrange[j];
|
||||
if (mem->base <= start && mem->base + mem->size >= end)
|
||||
break;
|
||||
}
|
||||
if (j >= info->n_memranges)
|
||||
goto badseg;
|
||||
#else
|
||||
#define LB_MEM_RAM 1
|
||||
for (j = 0; j < meminfo.map_count; j++) {
|
||||
mem = &meminfo.map[j];
|
||||
if (mem->type!=LB_MEM_RAM) continue;
|
||||
if (mem->addr <= start && mem->addr + mem->size >= end)
|
||||
break;
|
||||
}
|
||||
if (j >= meminfo.map_count)
|
||||
goto badseg;
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
|
||||
conflict:
|
||||
printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
|
||||
|
||||
badseg:
|
||||
printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
|
||||
unsigned short *sum_ptr)
|
||||
{
|
||||
int i;
|
||||
char *buf = NULL;
|
||||
int retval = 0;
|
||||
unsigned long addr, end;
|
||||
Elf_Nhdr *nhdr;
|
||||
const char *name;
|
||||
void *desc;
|
||||
|
||||
for (i = 0; i < phnum; i++) {
|
||||
if (phdr[i].p_type != PT_NOTE)
|
||||
continue;
|
||||
buf = allot(phdr[i].p_filesz);
|
||||
file_seek(phdr[i].p_offset);
|
||||
if (file_read(buf, phdr[i].p_filesz) != phdr[i].p_filesz) {
|
||||
printf("Can't read note segment\n");
|
||||
goto out;
|
||||
}
|
||||
addr = (unsigned long) buf;
|
||||
end = addr + phdr[i].p_filesz;
|
||||
while (addr < end) {
|
||||
nhdr = (Elf_Nhdr *) addr;
|
||||
addr += sizeof(Elf_Nhdr);
|
||||
name = (const char *) addr;
|
||||
addr += (nhdr->n_namesz+3) & ~3;
|
||||
desc = (void *) addr;
|
||||
addr += (nhdr->n_descsz+3) & ~3;
|
||||
|
||||
if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT)
|
||||
&& memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) {
|
||||
if (nhdr->n_type == EIN_PROGRAM_NAME) {
|
||||
image_name = calloc(1, nhdr->n_descsz + 1);
|
||||
memcpy(image_name, desc, nhdr->n_descsz);
|
||||
}
|
||||
if (nhdr->n_type == EIN_PROGRAM_VERSION) {
|
||||
image_version = calloc(1, nhdr->n_descsz + 1);
|
||||
memcpy(image_version, desc, nhdr->n_descsz);
|
||||
}
|
||||
if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) {
|
||||
*sum_ptr = *(unsigned short *) desc;
|
||||
debug("Image checksum: %04x\n", *sum_ptr);
|
||||
/* Where in the file */
|
||||
retval = phdr[i].p_offset
|
||||
+ (unsigned long) desc - (unsigned long) buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (buf)
|
||||
forget(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int load_segments(Elf_phdr *phdr, int phnum,
|
||||
unsigned long checksum_offset)
|
||||
{
|
||||
unsigned long bytes;
|
||||
unsigned int start_time, time;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
bytes = 0;
|
||||
start_time = currticks();
|
||||
#if 0
|
||||
for (j = 0; j < phnum; j++) {
|
||||
if (phdr[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
debug("0 segment %d addr:%#x file:%#x mem:%#x, phdr%#x\n",
|
||||
j, phdr[j].p_paddr, phdr[j].p_filesz, phdr[j].p_memsz, virt_to_phys(&phdr[j]));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < phnum; i++) {
|
||||
if (phdr[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
debug("segment %d addr:%#x file:%#x mem:%#x phdr:%#x ",
|
||||
i, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz, virt_to_phys(&phdr[i]));
|
||||
file_seek(phdr[i].p_offset);
|
||||
debug("loading... ");
|
||||
if (file_read(phys_to_virt(phdr[i].p_paddr), phdr[i].p_filesz)
|
||||
!= phdr[i].p_filesz) {
|
||||
printf("Can't read program segment %d\n", i);
|
||||
return 0;
|
||||
}
|
||||
bytes += phdr[i].p_filesz;
|
||||
debug("clearing... ");
|
||||
memset(phys_to_virt(phdr[i].p_paddr + phdr[i].p_filesz), 0,
|
||||
phdr[i].p_memsz - phdr[i].p_filesz);
|
||||
if (phdr[i].p_offset <= checksum_offset
|
||||
&& phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) {
|
||||
debug("clearing checksum... ");
|
||||
memset(phys_to_virt(phdr[i].p_paddr + checksum_offset
|
||||
- phdr[i].p_offset), 0, 2);
|
||||
}
|
||||
debug("ok\n");
|
||||
|
||||
}
|
||||
time = (currticks() - start_time)*1000/18;
|
||||
printf("Loaded %d bytes in %dms (%dKB/s)\n", bytes, time,
|
||||
time? bytes/time : 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum,
|
||||
unsigned short image_sum)
|
||||
{
|
||||
unsigned short sum, part_sum;
|
||||
unsigned long offset;
|
||||
int i;
|
||||
|
||||
sum = 0;
|
||||
offset = 0;
|
||||
|
||||
part_sum = ipchksum(ehdr, sizeof *ehdr);
|
||||
sum = add_ipchksums(offset, sum, part_sum);
|
||||
offset += sizeof *ehdr;
|
||||
|
||||
part_sum = ipchksum(phdr, phnum * sizeof(*phdr));
|
||||
sum = add_ipchksums(offset, sum, part_sum);
|
||||
offset += phnum * sizeof(*phdr);
|
||||
|
||||
for (i = 0; i < phnum; i++) {
|
||||
if (phdr[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
part_sum = ipchksum(phys_to_virt(phdr[i].p_paddr), phdr[i].p_memsz);
|
||||
sum = add_ipchksums(offset, sum, part_sum);
|
||||
offset += phdr[i].p_memsz;
|
||||
}
|
||||
|
||||
if (sum != image_sum) {
|
||||
printf("Verify FAILED (image:%04x vs computed:%04x)\n",
|
||||
image_sum, sum);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline unsigned const padded(unsigned s)
|
||||
{
|
||||
return (s + 3) & ~3;
|
||||
}
|
||||
|
||||
static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
|
||||
unsigned type, const char *desc, unsigned descsz)
|
||||
{
|
||||
Elf_Nhdr nhdr;
|
||||
unsigned ent_size, new_size, pad;
|
||||
char *addr;
|
||||
|
||||
if (!bhdr)
|
||||
return NULL;
|
||||
|
||||
nhdr.n_namesz = name? strlen(name)+1 : 0;
|
||||
nhdr.n_descsz = descsz;
|
||||
nhdr.n_type = type;
|
||||
ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz);
|
||||
if (bhdr->b_size + ent_size > 0xffff) {
|
||||
printf("Boot notes too big\n");
|
||||
forget(bhdr);
|
||||
return NULL;
|
||||
}
|
||||
if (bhdr->b_size + ent_size > bhdr->b_checksum) {
|
||||
do {
|
||||
new_size = bhdr->b_checksum * 2;
|
||||
} while (new_size < bhdr->b_size + ent_size);
|
||||
if (new_size > 0xffff)
|
||||
new_size = 0xffff;
|
||||
debug("expanding boot note size to %u\n", new_size);
|
||||
bhdr = realloc(bhdr, new_size);
|
||||
bhdr->b_checksum = new_size;
|
||||
}
|
||||
|
||||
addr = (char *) bhdr;
|
||||
addr += bhdr->b_size;
|
||||
memcpy(addr, &nhdr, sizeof(nhdr));
|
||||
addr += sizeof(nhdr);
|
||||
|
||||
memcpy(addr, name, nhdr.n_namesz);
|
||||
addr += nhdr.n_namesz;
|
||||
pad = padded(nhdr.n_namesz) - nhdr.n_namesz;
|
||||
memset(addr, 0, pad);
|
||||
addr += pad;
|
||||
|
||||
memcpy(addr, desc, nhdr.n_descsz);
|
||||
addr += nhdr.n_descsz;
|
||||
pad = padded(nhdr.n_descsz) - nhdr.n_descsz;
|
||||
memset(addr, 0, pad);
|
||||
addr += pad;
|
||||
|
||||
bhdr->b_size += ent_size;
|
||||
bhdr->b_records++;
|
||||
return bhdr;
|
||||
}
|
||||
|
||||
static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name,
|
||||
unsigned type, const char *desc)
|
||||
{
|
||||
return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1);
|
||||
}
|
||||
|
||||
static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline)
|
||||
{
|
||||
Elf_Bhdr *bhdr;
|
||||
|
||||
bhdr = allot(256);
|
||||
bhdr->b_signature = ELF_BHDR_MAGIC;
|
||||
bhdr->b_size = sizeof *bhdr;
|
||||
bhdr->b_checksum = 256; /* XXX cache the current buffer size here */
|
||||
bhdr->b_records = 0;
|
||||
|
||||
if (info->firmware)
|
||||
bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware);
|
||||
bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name);
|
||||
bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version);
|
||||
if (cmdline)
|
||||
bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline);
|
||||
if (!bhdr)
|
||||
return bhdr;
|
||||
bhdr->b_checksum = 0;
|
||||
bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size);
|
||||
return bhdr;
|
||||
}
|
||||
|
||||
int elf_load(struct sys_info *info, const char *filename, const char *cmdline)
|
||||
{
|
||||
Elf_ehdr ehdr;
|
||||
Elf_phdr *phdr = NULL;
|
||||
unsigned long phdr_size;
|
||||
unsigned long checksum_offset;
|
||||
unsigned short checksum;
|
||||
Elf_Bhdr *boot_notes = NULL;
|
||||
int retval = -1;
|
||||
int image_retval;
|
||||
|
||||
image_name = image_version = 0;
|
||||
|
||||
if (!file_open(filename))
|
||||
goto out;
|
||||
|
||||
if (file_read(&ehdr, sizeof ehdr) != sizeof ehdr) {
|
||||
debug("Can't read ELF header\n");
|
||||
retval = LOADER_NOT_SUPPORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ehdr.e_ident[EI_MAG0] != ELFMAG0
|
||||
|| ehdr.e_ident[EI_MAG1] != ELFMAG1
|
||||
|| ehdr.e_ident[EI_MAG2] != ELFMAG2
|
||||
|| ehdr.e_ident[EI_MAG3] != ELFMAG3
|
||||
|| ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS
|
||||
|| ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA
|
||||
|| ehdr.e_ident[EI_VERSION] != EV_CURRENT
|
||||
|| ehdr.e_type != ET_EXEC
|
||||
|| !ARCH_ELF_MACHINE_OK(ehdr.e_machine)
|
||||
|| ehdr.e_version != EV_CURRENT
|
||||
|| ehdr.e_phentsize != sizeof(Elf_phdr)) {
|
||||
debug("Not a bootable ELF image\n");
|
||||
retval = LOADER_NOT_SUPPORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
phdr_size = ehdr.e_phnum * sizeof *phdr;
|
||||
phdr = allot(phdr_size);//hack LYH otherwise some one clear the last entry
|
||||
file_seek(ehdr.e_phoff);
|
||||
if (file_read(phdr, phdr_size) != phdr_size) {
|
||||
printf("Can't read program header\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!check_mem_ranges(info, phdr, ehdr.e_phnum))
|
||||
goto out;
|
||||
|
||||
checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum);
|
||||
|
||||
printf("Loading %s", image_name ? image_name : "image");
|
||||
if (image_version)
|
||||
printf(" version %s", image_version);
|
||||
printf("...\n");
|
||||
|
||||
if (!load_segments(phdr, ehdr.e_phnum, checksum_offset))
|
||||
goto out;
|
||||
|
||||
if (checksum_offset) {
|
||||
if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
|
||||
goto out;
|
||||
}
|
||||
|
||||
boot_notes = build_boot_notes(info, cmdline);
|
||||
|
||||
debug("current time: %x\n", currticks());
|
||||
|
||||
debug("entry point is %#x\n", ehdr.e_entry);
|
||||
printf("Jumping to entry point...\n");
|
||||
|
||||
image_retval = start_elf(ehdr.e_entry, virt_to_phys(boot_notes));
|
||||
#if 0
|
||||
console_init();
|
||||
#endif
|
||||
|
||||
printf("Image returned with return value %#x\n", image_retval);
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
if (phdr)
|
||||
forget(phdr);
|
||||
if (boot_notes)
|
||||
forget(boot_notes);
|
||||
if (image_name)
|
||||
forget(image_name);
|
||||
if (image_version)
|
||||
forget(image_version);
|
||||
return retval;
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
/* Support for ELF Boot Proposal as a boot image */
|
||||
|
||||
#include <etherboot.h>
|
||||
#include <elf_boot.h>
|
||||
#include <sys_info.h>
|
||||
#include <lib.h>
|
||||
|
||||
#include "version.h"
|
||||
#define DEBUG_THIS DEBUG_ELFNOTE
|
||||
#include <debug.h>
|
||||
|
||||
/* ELF image notes provide information to the loader who boots us */
|
||||
|
||||
/* This compiles and generates correct PT_NOTE segment for me.
|
||||
* If it doesn't, use assembly version below. */
|
||||
|
||||
struct elf_image_note {
|
||||
Elf_Nhdr hdr0;
|
||||
char name0[sizeof(ELF_NOTE_BOOT)];
|
||||
char prog_name[sizeof(PROGRAM_NAME)];
|
||||
|
||||
Elf_Nhdr hdr1;
|
||||
char name1[sizeof(ELF_NOTE_BOOT)];
|
||||
char version[sizeof(PROGRAM_VERSION)];
|
||||
|
||||
Elf_Nhdr hdr2;
|
||||
char name2[sizeof(ELF_NOTE_BOOT)];
|
||||
unsigned short checksum;
|
||||
};
|
||||
|
||||
const struct elf_image_note elf_image_notes
|
||||
__attribute__ ((section (".note.ELFBoot"))) =
|
||||
{
|
||||
.hdr0 = {
|
||||
.n_namesz = sizeof(ELF_NOTE_BOOT),
|
||||
.n_descsz = sizeof(PROGRAM_NAME),
|
||||
.n_type = EIN_PROGRAM_NAME,
|
||||
},
|
||||
.name0 = ELF_NOTE_BOOT,
|
||||
.prog_name = PROGRAM_NAME,
|
||||
|
||||
.hdr1 = {
|
||||
.n_namesz = sizeof(ELF_NOTE_BOOT),
|
||||
.n_descsz = sizeof(PROGRAM_VERSION),
|
||||
.n_type = EIN_PROGRAM_VERSION,
|
||||
},
|
||||
.name1 = ELF_NOTE_BOOT,
|
||||
.version = PROGRAM_VERSION,
|
||||
|
||||
.hdr2 = {
|
||||
.n_namesz = sizeof(ELF_NOTE_BOOT),
|
||||
.n_descsz = sizeof(unsigned short),
|
||||
.n_type = EIN_PROGRAM_CHECKSUM,
|
||||
},
|
||||
.name2 = ELF_NOTE_BOOT,
|
||||
.checksum = 0, /* to be computed by external tool */
|
||||
};
|
||||
|
||||
/* This is refered by other files */
|
||||
const char *program_name = elf_image_notes.prog_name;
|
||||
const char *program_version = elf_image_notes.version;
|
||||
|
||||
#if 0
|
||||
|
||||
/* This tells the linker to make a PT_NOTE segment.
|
||||
* If the section is named just ".note", it will be
|
||||
* mixed up with useless .version notes generated by GCC.
|
||||
*/
|
||||
.section ".note.ELFBoot", "a"
|
||||
|
||||
.align 4
|
||||
.int 2f - 1f
|
||||
.int 4f - 3f
|
||||
.int EIN_PROGRAM_NAME
|
||||
1: .asciz "ELFBoot"
|
||||
2: .align 4
|
||||
3: .asciz PROGRAM_NAME
|
||||
4:
|
||||
|
||||
.align 4
|
||||
.int 2f - 1f
|
||||
.int 4f - 3f
|
||||
.int EIN_PROGRAM_VERSION
|
||||
1: .asciz "ELFBoot"
|
||||
2: .align 4
|
||||
3: .asciz PROGRAM_VERSION
|
||||
4:
|
||||
|
||||
.align 4
|
||||
.int 2f - 1f
|
||||
.int 4f - 3f
|
||||
.int EIN_PROGRAM_CHECKSUM
|
||||
1: .asciz "ELFBoot"
|
||||
2: .align 4
|
||||
3: .short 0
|
||||
4:
|
||||
#endif
|
||||
|
||||
/* Collect information from the ELF bootloader
|
||||
* Note that we have to copy them to our own memory,
|
||||
* otherwise they might be overwritten afterward. */
|
||||
void collect_elfboot_info(struct sys_info *info)
|
||||
{
|
||||
Elf_Bhdr *hdr = 0;
|
||||
char *addr, *end;
|
||||
Elf_Nhdr *nhdr;
|
||||
char *name, *desc;
|
||||
|
||||
if (info->boot_type == ELF_BHDR_MAGIC)
|
||||
hdr = phys_to_virt(info->boot_data);
|
||||
else
|
||||
hdr = phys_to_virt(info->boot_arg);
|
||||
|
||||
if (hdr->b_signature != ELF_BHDR_MAGIC)
|
||||
return;
|
||||
|
||||
if (ipchksum(hdr, hdr->b_size) != 0) {
|
||||
printf("Broken ELF boot notes\n");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = (char *) (hdr + 1);
|
||||
end = addr + hdr->b_size;
|
||||
while (addr < end) {
|
||||
nhdr = (Elf_Nhdr *) addr;
|
||||
addr += sizeof(Elf_Nhdr);
|
||||
name = addr;
|
||||
addr += (nhdr->n_namesz + 3) & ~3;
|
||||
desc = addr;
|
||||
addr += (nhdr->n_descsz + 3) & ~3;
|
||||
|
||||
if (nhdr->n_namesz == 0) {
|
||||
/* Standard notes */
|
||||
switch (nhdr->n_type) {
|
||||
case EBN_FIRMWARE_TYPE:
|
||||
info->firmware = strdup(desc);
|
||||
break;
|
||||
case EBN_BOOTLOADER_NAME:
|
||||
debug("Bootloader: %s\n", desc);
|
||||
break;
|
||||
case EBN_BOOTLOADER_VERSION:
|
||||
debug("Version: %s\n", desc);
|
||||
break;
|
||||
case EBN_COMMAND_LINE:
|
||||
info->command_line = strdup(desc);
|
||||
break;
|
||||
case EBN_LOADED_IMAGE:
|
||||
debug("Image name: %s\n", desc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
#include <etherboot.h>
|
||||
|
||||
#include <fs.h>
|
||||
#include <lib.h>
|
||||
#include <sys_info.h>
|
||||
|
||||
#define ENTER '\r'
|
||||
#define ESCAPE '\x1b'
|
||||
|
||||
#ifndef AUTOBOOT_FILE
|
||||
#define autoboot() ((void) 0) /* nop */
|
||||
#endif
|
||||
|
||||
#ifndef AUTOBOOT_DELAY
|
||||
#define autoboot_delay() 0 /* success */
|
||||
#endif
|
||||
|
||||
struct sys_info sys_info;
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
collect_sys_info(&sys_info);
|
||||
|
||||
printf("%s version %s\n", program_name, program_version);
|
||||
|
||||
}
|
||||
|
||||
static void boot(const char *line)
|
||||
{
|
||||
char file[256], *param;
|
||||
|
||||
/* Split filename and parameter */
|
||||
memcpy(file, line,256);
|
||||
// file = strdup(line);
|
||||
param = strchr(file, ' ');
|
||||
if (param) {
|
||||
*param = '\0';
|
||||
param++;
|
||||
}
|
||||
if (elf_load(&sys_info, file, param) == LOADER_NOT_SUPPORT){
|
||||
if (linux_load(&sys_info, file, param) == LOADER_NOT_SUPPORT)
|
||||
printf("Unsupported image format\n");
|
||||
}
|
||||
// free(file);
|
||||
}
|
||||
|
||||
#ifdef AUTOBOOT_FILE
|
||||
#if AUTOBOOT_DELAY
|
||||
|
||||
static inline int autoboot_delay(void)
|
||||
{
|
||||
unsigned int timeout;
|
||||
int sec, tmp;
|
||||
int key;
|
||||
|
||||
key = 0;
|
||||
|
||||
printf("Press <Enter> for default boot, or <Esc> for boot prompt... ");
|
||||
for (sec = AUTOBOOT_DELAY; sec>0 && key==0; sec--) {
|
||||
printf("%d", sec);
|
||||
timeout = currticks() + TICKS_PER_SEC;
|
||||
while (currticks() < timeout) {
|
||||
if (iskey()) {
|
||||
key = getchar();
|
||||
if (key==ENTER || key==ESCAPE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (tmp = sec; tmp; tmp /= 10)
|
||||
printf("\b \b");
|
||||
}
|
||||
if (key == 0) {
|
||||
printf("timed out\n");
|
||||
return 0; /* success */
|
||||
} else {
|
||||
putchar('\n');
|
||||
if (key == ESCAPE)
|
||||
return -1; /* canceled */
|
||||
else
|
||||
return 0; /* default accepted */
|
||||
}
|
||||
}
|
||||
#endif /* AUTOBOOT_DELAY */
|
||||
|
||||
static void autoboot(void)
|
||||
{
|
||||
/* If Escape key is pressed already, skip autoboot */
|
||||
if (iskey() && getchar()==ESCAPE)
|
||||
return;
|
||||
|
||||
if (autoboot_delay()==0) {
|
||||
printf("boot: %s\n", AUTOBOOT_FILE);
|
||||
boot(AUTOBOOT_FILE);
|
||||
}
|
||||
}
|
||||
#endif /* AUTOBOOT_FILE */
|
||||
|
||||
/* The main routine */
|
||||
int filo(void)
|
||||
{
|
||||
char line[256];
|
||||
|
||||
/* Initialize */
|
||||
|
||||
init();
|
||||
|
||||
/* Try default image */
|
||||
autoboot();
|
||||
|
||||
/* The above didn't work, ask user */
|
||||
while (iskey())
|
||||
getchar();
|
||||
#ifdef AUTOBOOT_FILE
|
||||
strncpy(line, AUTOBOOT_FILE, sizeof(line)-1);
|
||||
line[sizeof(line)-1] = '\0';
|
||||
#else
|
||||
line[0] = '\0';
|
||||
#endif
|
||||
for (;;) {
|
||||
printf("boot: ");
|
||||
getline(line, sizeof line);
|
||||
// BY LYH add "quit" to exit filo
|
||||
if (strcmp(line,"quit")==0) break;
|
||||
// if (memcmp(line,"quit",4)==0) break;
|
||||
if (line[0])
|
||||
boot(line);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
|
||||
#include <etherboot.h>
|
||||
#include <lib.h>
|
||||
|
||||
char *strdup(const char *s)
|
||||
{
|
||||
size_t sz = strlen(s) + 1;
|
||||
char *d = allot(sz);
|
||||
memcpy(d, s, sz);
|
||||
return d;
|
||||
}
|
||||
|
||||
int isspace(int c)
|
||||
{
|
||||
switch (c) {
|
||||
case ' ': case '\f': case '\n':
|
||||
case '\r': case '\t': case '\v':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int get_le32(const unsigned char *p)
|
||||
{
|
||||
return ((unsigned int) p[0] << 0)
|
||||
| ((unsigned int) p[1] << 8)
|
||||
| ((unsigned int) p[2] << 16)
|
||||
| ((unsigned int) p[3] << 24);
|
||||
}
|
||||
|
||||
unsigned int get_le16(const unsigned char *p)
|
||||
{
|
||||
return ((unsigned int) p[0] << 0)
|
||||
| ((unsigned int) p[1] << 8);
|
||||
}
|
||||
#if (DEBUG_ALL || DEBUG_ELFBOOT || DEBUG_ELFNOTE || DEBUG_LINUXBIOS || \
|
||||
DEBUG_MALLOC || DEBUG_MULTIBOOT || DEBUG_SEGMENT || DEBUG_SYS_INFO ||\
|
||||
DEBUG_TIMER || DEBUG_BLOCKDEV || DEBUG_PCI || DEBUG_LINUXLOAD ||\
|
||||
DEBUG_IDE || DEBUG_ELTORITO)
|
||||
|
||||
// It is needed by debug for filo
|
||||
void hexdump(const void *p, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
const unsigned char *q = p;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i%16==0)
|
||||
printf("%04x: ", i);
|
||||
printf("%02x%c", q[i], i%16==15 ? '\n' : i%8==7 ? '-' : ' ');
|
||||
}
|
||||
if (i%16 != 0)
|
||||
putchar('\n');
|
||||
}
|
||||
#endif
|
|
@ -1,124 +0,0 @@
|
|||
/* Adapted from Etherboot 5.1.8 */
|
||||
#include <sys_info.h>
|
||||
#define DEBUG_THIS DEBUG_LINUXBIOS
|
||||
#include <debug.h>
|
||||
|
||||
#if 0
|
||||
|
||||
#define for_each_lbrec(head, rec) \
|
||||
for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
|
||||
(((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \
|
||||
(rec->size >= 1) && \
|
||||
((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
|
||||
rec = (struct lb_record *)(((char *)rec) + rec->size))
|
||||
|
||||
static void convert_memmap(struct lb_memory *lbmem, struct sys_info *info)
|
||||
{
|
||||
int lbcount;
|
||||
int i;
|
||||
|
||||
lbcount = lbmem->size / sizeof(struct lb_memory_range);
|
||||
info->memrange = malloc(lbcount * sizeof(struct memrange));
|
||||
info->n_memranges = 0;
|
||||
for (i = 0; i < lbcount; i++) {
|
||||
debug("%#016Lx %#016Lx %d\n",
|
||||
lbmem->map[i].start, lbmem->map[i].size,
|
||||
(int) lbmem->map[i].type);
|
||||
if (lbmem->map[i].type != LB_MEM_RAM)
|
||||
continue;
|
||||
info->memrange[info->n_memranges].base = lbmem->map[i].start;
|
||||
info->memrange[info->n_memranges].size = lbmem->map[i].size;
|
||||
info->n_memranges++;
|
||||
}
|
||||
}
|
||||
static int read_lbtable(struct lb_header *head, struct sys_info *info)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
/* Read linuxbios tables... */
|
||||
struct lb_record *rec;
|
||||
|
||||
for_each_lbrec(head, rec) {
|
||||
switch(rec->tag) {
|
||||
case LB_TAG_MEMORY:
|
||||
convert_memmap((struct lb_memory *) rec, info);
|
||||
retval = 1;
|
||||
break;
|
||||
};
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
//Use func in Etherboot
|
||||
static unsigned long count_lb_records(void *start, unsigned long length)
|
||||
{
|
||||
struct lb_record *rec;
|
||||
void *end;
|
||||
unsigned long count;
|
||||
count = 0;
|
||||
end = ((char *)start) + length;
|
||||
for(rec = start; ((void *)rec < end) &&
|
||||
((signed long)rec->size <= (end - (void *)rec));
|
||||
rec = (void *)(((char *)rec) + rec->size)) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
static int find_lb_table(void *start, void *end, struct lb_header **result)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
/* For now be stupid.... */
|
||||
for(ptr = start; (void *)ptr < end; ptr += 16) {
|
||||
struct lb_header *head = (struct lb_header *)ptr;
|
||||
if ( (head->signature[0] != 'L') ||
|
||||
(head->signature[1] != 'B') ||
|
||||
(head->signature[2] != 'I') ||
|
||||
(head->signature[3] != 'O')) {
|
||||
continue;
|
||||
}
|
||||
if (head->header_bytes != sizeof(*head))
|
||||
continue;
|
||||
debug("Found canidate at: %p\n", head);
|
||||
if (ipchksum((uint16_t *)head, sizeof(*head)) != 0)
|
||||
continue;
|
||||
debug("header checksum o.k.\n");
|
||||
if (ipchksum((uint16_t *)(ptr + sizeof(*head)), head->table_bytes) !=
|
||||
head->table_checksum) {
|
||||
continue;
|
||||
}
|
||||
debug("table checksum o.k.\n");
|
||||
if (count_lb_records(ptr + sizeof(*head), head->table_bytes) !=
|
||||
head->table_entries) {
|
||||
continue;
|
||||
}
|
||||
debug("record count o.k.\n");
|
||||
*result = head;
|
||||
return 1;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
void collect_linuxbios_info(struct sys_info *info)
|
||||
{
|
||||
#if 0
|
||||
struct lb_header *lb_table;
|
||||
int found;
|
||||
debug("Searching for LinuxBIOS tables...\n");
|
||||
found = 0;
|
||||
if (!found) {
|
||||
found = find_lb_table(phys_to_virt(0x00000), phys_to_virt(0x01000), &lb_table);
|
||||
}
|
||||
if (!found) {
|
||||
found = find_lb_table(phys_to_virt(0xf0000), phys_to_virt(0x100000), &lb_table);
|
||||
}
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
debug("Found LinuxBIOS table at: %p\n", lb_table);
|
||||
#endif
|
||||
info->firmware = "LinuxBIOS";
|
||||
#if 0
|
||||
read_lbtable(lb_table, info);
|
||||
#endif
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#include <etherboot.h>
|
||||
|
||||
#include <lib.h>
|
||||
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t alloc_size = nmemb * size;
|
||||
void *mem;
|
||||
|
||||
if (alloc_size < nmemb || alloc_size < size) {
|
||||
printf("calloc overflow: %u, %u\n", nmemb, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem = allot(alloc_size);
|
||||
memset(mem, 0, alloc_size);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void *realloc(void *mem, size_t size)
|
||||
{
|
||||
size_t copy_size;
|
||||
void *new_mem;
|
||||
size_t *mark, addr;
|
||||
|
||||
if (mem == 0)
|
||||
return allot(size);
|
||||
if (size == 0) {
|
||||
forget(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr = virt_to_phys(mem);
|
||||
mark = phys_to_virt(addr - sizeof(size_t));
|
||||
copy_size = *mark;
|
||||
|
||||
if (size < copy_size)
|
||||
copy_size = size;
|
||||
/* XXX should optimze this */
|
||||
new_mem = allot(size);
|
||||
memcpy(new_mem, mem, copy_size);
|
||||
forget(mem);
|
||||
return new_mem;
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
#ifdef CONFIG_PCI
|
||||
|
||||
/*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <etherboot.h>
|
||||
#include <pci.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_PCI
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
struct pci_device *dev_list;
|
||||
int n_devs;
|
||||
|
||||
static void pci_scan_bus(void)
|
||||
{
|
||||
|
||||
unsigned int first_bus, first_devfn;
|
||||
unsigned int devfn, bus, buses;
|
||||
|
||||
uint32_t class;
|
||||
uint16_t vendor, dev_id;
|
||||
uint8_t hdr_type;
|
||||
|
||||
|
||||
first_bus = 0;
|
||||
first_devfn = 0;
|
||||
|
||||
buses=256;
|
||||
for (bus = first_bus; bus < buses; ++bus) {
|
||||
for (devfn = first_devfn; devfn < 0xff; ++devfn) {
|
||||
|
||||
#if 1
|
||||
if (PCI_FUNC(devfn) == 0)
|
||||
pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
|
||||
else if (!(hdr_type & 0x80)) /* not a multi-function device */
|
||||
continue;
|
||||
#endif
|
||||
|
||||
pcibios_read_config_word(bus,devfn, PCI_VENDOR_ID, &vendor);
|
||||
if (vendor==0xffff || vendor==0)
|
||||
continue;
|
||||
|
||||
if (dev_list) {
|
||||
dev_list[n_devs].bus = bus;
|
||||
dev_list[n_devs].devfn = devfn;
|
||||
dev_list[n_devs].vendor = vendor;
|
||||
|
||||
pcibios_read_config_word(bus,devfn, PCI_DEVICE_ID, &dev_id);
|
||||
dev_list[n_devs].dev_id = dev_id;
|
||||
|
||||
pcibios_read_config_dword(bus,devfn, PCI_CLASS_REVISION, &class);
|
||||
dev_list[n_devs].class = class;
|
||||
|
||||
}
|
||||
n_devs++;
|
||||
}
|
||||
first_devfn = 0;
|
||||
}
|
||||
first_bus = 0;
|
||||
|
||||
}
|
||||
#define DEBUG 0
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
/* Count devices */
|
||||
dev_list = 0;
|
||||
n_devs = 0;
|
||||
debug("Scanning PCI: ");
|
||||
pci_scan_bus();
|
||||
debug("found %d devices\n", n_devs);
|
||||
|
||||
/* Make the list */
|
||||
dev_list = allot(n_devs * sizeof(struct pci_device));
|
||||
n_devs = 0;
|
||||
pci_scan_bus();
|
||||
#if DEBUG
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_devs; i++) {
|
||||
printf("%02x:%02x.%x %04x:%04x %04x %02x\n",
|
||||
dev_list[i].bus,
|
||||
PCI_SLOT(dev_list[i].devfn),
|
||||
PCI_FUNC(dev_list[i].devfn),
|
||||
dev_list[i].vendor,
|
||||
dev_list[i].dev_id,((dev_list[i].class)>>16),
|
||||
((dev_list[i].class)>>8 & 0xff));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct pci_device *pci_find_device_2(int vendor, int device, int devclass, int devclass2, int prog_if, int index)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<n_devs; i++) {
|
||||
if (vendor < 0 || vendor==dev_list[i].vendor)
|
||||
if (device < 0 || device==dev_list[i].dev_id)
|
||||
if (devclass < 0 || devclass==((dev_list[i].class)>>16) || devclass2==((dev_list[i].class)>>16))
|
||||
if (prog_if < 0 || prog_if==((dev_list[i].class)>>8 & 0xff)) {
|
||||
if (index == 0)
|
||||
return &dev_list[i];
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct pci_device *pci_find_device(int vendor, int device, int devclass, int prog_if, int index)
|
||||
{
|
||||
return pci_find_device_2(vendor, device, devclass, devclass, prog_if, index);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,400 +0,0 @@
|
|||
/* Adapted from LinuxBIOS */
|
||||
|
||||
/*
|
||||
*
|
||||
* linux/lib/vsprintf.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
*/
|
||||
|
||||
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
|
||||
/*
|
||||
* Wirzenius wrote this portably, Torvalds fucked it up :-)
|
||||
*/
|
||||
|
||||
#include "etherboot.h"
|
||||
#include <stdarg.h>
|
||||
#include <lib.h>
|
||||
|
||||
/* haha, don't need ctype.c */
|
||||
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
#define is_digit isdigit
|
||||
#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
|
||||
#define islower(c) ((c) >= 'a' && (c) <= 'z')
|
||||
#define toupper(c) __toupper(c)
|
||||
|
||||
static inline unsigned char __toupper(unsigned char c)
|
||||
{
|
||||
if (islower(c))
|
||||
c -= 'a'-'A';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
|
||||
{
|
||||
unsigned long long result = 0,value;
|
||||
|
||||
if (!base) {
|
||||
base = 10;
|
||||
if (*cp == '0') {
|
||||
base = 8;
|
||||
cp++;
|
||||
if ((*cp == 'x') && isxdigit(cp[1])) {
|
||||
cp++;
|
||||
base = 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
|
||||
? toupper(*cp) : *cp)-'A'+10) < base) {
|
||||
result = result*base + value;
|
||||
cp++;
|
||||
}
|
||||
if (endp)
|
||||
*endp = (char *)cp;
|
||||
return result;
|
||||
}
|
||||
|
||||
long long simple_strtoll(const char *cp,char **endp,unsigned int base)
|
||||
{
|
||||
if(*cp=='-')
|
||||
return -simple_strtoull(cp+1,endp,base);
|
||||
return simple_strtoull(cp,endp,base);
|
||||
}
|
||||
|
||||
unsigned long long strtoull_with_suffix(const char *cp,char **endp,unsigned int base)
|
||||
{
|
||||
unsigned long long result;
|
||||
|
||||
if (!endp) {
|
||||
printf("%s must be called with endp\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
result = simple_strtoull(cp, endp, base);
|
||||
switch (toupper(**endp)) {
|
||||
case 'K':
|
||||
result <<= 10;
|
||||
++*endp;
|
||||
break;
|
||||
case 'M':
|
||||
result <<= 20;
|
||||
++*endp;
|
||||
break;
|
||||
case 'G':
|
||||
result <<= 30;
|
||||
++*endp;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// it can be used to substitute the vsprintf.c in etherboot. And it has better
|
||||
// support in numeric output suppot
|
||||
//When you want to debug filo, you need to enable it and disable vsprintf.c
|
||||
// to get output from filo
|
||||
// BY LYH
|
||||
|
||||
static int skip_atoi(const char **s)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while (is_digit(**s))
|
||||
i = i*10 + *((*s)++) - '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
#define ZEROPAD 1 /* pad with zero */
|
||||
#define SIGN 2 /* unsigned/signed long */
|
||||
#define PLUS 4 /* show plus */
|
||||
#define SPACE 8 /* space if plus */
|
||||
#define LEFT 16 /* left justified */
|
||||
#define SPECIAL 32 /* 0x */
|
||||
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
||||
|
||||
#define do_div(n,base) ({ \
|
||||
int __res; \
|
||||
__res = ((unsigned long) n) % (unsigned) base; \
|
||||
n = ((unsigned long) n) / (unsigned) base; \
|
||||
__res; })
|
||||
|
||||
static int number(int (*tx_byte)(int byte), long num, int base, int size, int precision
|
||||
,int type)
|
||||
{
|
||||
char c,sign,tmp[66];
|
||||
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
if (type & LARGE)
|
||||
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
if (type & LEFT)
|
||||
type &= ~ZEROPAD;
|
||||
if (base < 2 || base > 36)
|
||||
return 0;
|
||||
c = (type & ZEROPAD) ? '0' : ' ';
|
||||
sign = 0;
|
||||
if (type & SIGN) {
|
||||
if (num < 0) {
|
||||
sign = '-';
|
||||
num = -num;
|
||||
size--;
|
||||
} else if (type & PLUS) {
|
||||
sign = '+';
|
||||
size--;
|
||||
} else if (type & SPACE) {
|
||||
sign = ' ';
|
||||
size--;
|
||||
}
|
||||
}
|
||||
if (type & SPECIAL) {
|
||||
if (base == 16)
|
||||
size -= 2;
|
||||
else if (base == 8)
|
||||
size--;
|
||||
}
|
||||
i = 0;
|
||||
if (num == 0)
|
||||
tmp[i++]='0';
|
||||
else while (num != 0)
|
||||
tmp[i++] = digits[do_div(num,base)];
|
||||
if (i > precision)
|
||||
precision = i;
|
||||
size -= precision;
|
||||
if (!(type&(ZEROPAD+LEFT)))
|
||||
while(size-->0)
|
||||
tx_byte(' '), count++;
|
||||
if (sign)
|
||||
tx_byte(sign), count++;
|
||||
if (type & SPECIAL) {
|
||||
if (base==8)
|
||||
tx_byte('0'), count++;
|
||||
else if (base==16) {
|
||||
tx_byte('0'), count++;
|
||||
tx_byte(digits[33]), count++;
|
||||
}
|
||||
}
|
||||
if (!(type & LEFT))
|
||||
while (size-- > 0)
|
||||
tx_byte(c), count++;
|
||||
while (i < precision--)
|
||||
tx_byte('0'), count++;
|
||||
while (i-- > 0)
|
||||
tx_byte(tmp[i]), count++;
|
||||
while (size-- > 0)
|
||||
tx_byte(' '), count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int vtxprintf(int (*tx_byte)(int byte), const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
unsigned long num;
|
||||
int i, base;
|
||||
const char *s;
|
||||
|
||||
int flags; /* flags to number() */
|
||||
|
||||
int field_width; /* width of output field */
|
||||
int precision; /* min. # of digits for integers; max
|
||||
number of chars for from string */
|
||||
int qualifier; /* 'h', 'l', or 'L' for integer fields */
|
||||
|
||||
int count;
|
||||
|
||||
for (count=0; *fmt ; ++fmt) {
|
||||
if (*fmt != '%') {
|
||||
tx_byte(*fmt), count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process flags */
|
||||
flags = 0;
|
||||
repeat:
|
||||
++fmt; /* this also skips first '%' */
|
||||
switch (*fmt) {
|
||||
case '-': flags |= LEFT; goto repeat;
|
||||
case '+': flags |= PLUS; goto repeat;
|
||||
case ' ': flags |= SPACE; goto repeat;
|
||||
case '#': flags |= SPECIAL; goto repeat;
|
||||
case '0': flags |= ZEROPAD; goto repeat;
|
||||
}
|
||||
|
||||
/* get field width */
|
||||
field_width = -1;
|
||||
if (is_digit(*fmt))
|
||||
field_width = skip_atoi(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
++fmt;
|
||||
/* it's the next argument */
|
||||
field_width = va_arg(args, int);
|
||||
if (field_width < 0) {
|
||||
field_width = -field_width;
|
||||
flags |= LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the precision */
|
||||
precision = -1;
|
||||
if (*fmt == '.') {
|
||||
++fmt;
|
||||
if (is_digit(*fmt))
|
||||
precision = skip_atoi(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
++fmt;
|
||||
/* it's the next argument */
|
||||
precision = va_arg(args, int);
|
||||
}
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
}
|
||||
|
||||
/* get the conversion qualifier */
|
||||
qualifier = -1;
|
||||
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
|
||||
qualifier = *fmt;
|
||||
++fmt;
|
||||
}
|
||||
|
||||
/* default base */
|
||||
base = 10;
|
||||
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
if (!(flags & LEFT))
|
||||
while (--field_width > 0)
|
||||
tx_byte(' '), count++;
|
||||
tx_byte((unsigned char) va_arg(args, int)), count++;
|
||||
while (--field_width > 0)
|
||||
tx_byte(' '), count++;
|
||||
continue;
|
||||
|
||||
case 's':
|
||||
s = va_arg(args, char *);
|
||||
if (!s)
|
||||
s = "<NULL>";
|
||||
|
||||
len = strnlen(s, precision);
|
||||
|
||||
if (!(flags & LEFT))
|
||||
while (len < field_width--)
|
||||
tx_byte(' '), count++;
|
||||
for (i = 0; i < len; ++i)
|
||||
tx_byte(*s++), count++;
|
||||
while (len < field_width--)
|
||||
tx_byte(' '), count++;
|
||||
continue;
|
||||
|
||||
case 'p':
|
||||
if (field_width == -1) {
|
||||
field_width = 2*sizeof(void *);
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
count += number(tx_byte,
|
||||
(unsigned long) va_arg(args, void *), 16,
|
||||
field_width, precision, flags);
|
||||
continue;
|
||||
|
||||
|
||||
case 'n':
|
||||
if (qualifier == 'l') {
|
||||
long * ip = va_arg(args, long *);
|
||||
*ip = count;
|
||||
} else {
|
||||
int * ip = va_arg(args, int *);
|
||||
*ip = count;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '%':
|
||||
tx_byte('%'), count++;
|
||||
continue;
|
||||
|
||||
/* integer number formats - set up the flags and "break" */
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
flags |= LARGE;
|
||||
case 'x':
|
||||
base = 16;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
case 'u':
|
||||
break;
|
||||
|
||||
default:
|
||||
tx_byte('%'), count++;
|
||||
if (*fmt)
|
||||
tx_byte(*fmt), count++;
|
||||
else
|
||||
--fmt;
|
||||
continue;
|
||||
}
|
||||
if (qualifier == 'L')
|
||||
num = va_arg(args, unsigned long long);
|
||||
else if (qualifier == 'l')
|
||||
num = va_arg(args, unsigned long);
|
||||
else if (qualifier == 'h') {
|
||||
num = (unsigned short) va_arg(args, int);
|
||||
if (flags & SIGN)
|
||||
num = (short) num;
|
||||
} else if (flags & SIGN)
|
||||
num = va_arg(args, int);
|
||||
else
|
||||
num = va_arg(args, unsigned int);
|
||||
count += number(tx_byte, num, base, field_width, precision, flags);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* FIXME this global makes vsprintf non-reentrant
|
||||
*/
|
||||
static char *str_buf;
|
||||
static int str_tx_byte(int byte)
|
||||
{
|
||||
*str_buf = byte;
|
||||
str_buf++;
|
||||
return byte;
|
||||
}
|
||||
|
||||
int vsprintf(char * buf, const char *fmt, va_list args)
|
||||
{
|
||||
int i;
|
||||
str_buf = buf;
|
||||
i = vtxprintf(str_tx_byte, fmt, args);
|
||||
/* maeder/Ispiri -- The null termination was missing a deference */
|
||||
/* and was just zeroing out the pointer instead */
|
||||
*str_buf = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
int sprintf(char * buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i=vsprintf(buf,fmt,args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
||||
void printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vtxprintf(putchar, fmt, args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
||||
#endif
|
|
@ -1,433 +0,0 @@
|
|||
#ifdef USB_DISK
|
||||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <etherboot.h>
|
||||
#include <pci.h>
|
||||
#include <timer.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_USB
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTF debug
|
||||
|
||||
#include "usb.h"
|
||||
#include "uhci.h"
|
||||
#include "debug_x.h"
|
||||
|
||||
//#include <string.h>
|
||||
|
||||
|
||||
void dump_link( link_pointer_t *link, char *prefix)
|
||||
{
|
||||
DPRINTF("%saddr: %08x\n", prefix, MEM_ADDR(link->link) );
|
||||
DPRINTF("%s raw addr: %04x\n", prefix, (link->link) <<4 );
|
||||
DPRINTF("%sterminate: %x\n", prefix, link->terminate);
|
||||
DPRINTF("%squeue: %x\n", prefix, link->queue);
|
||||
DPRINTF("%sdepth: %x\n", prefix, link->depth);
|
||||
}
|
||||
|
||||
void dump_frame_list( link_pointer_t *addr, char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF("%sFRAMELIST:\n",prefix);
|
||||
|
||||
for(i=0;i<10; i++) {
|
||||
dump_link(addr+i, prefix);
|
||||
if(addr[i].queue)
|
||||
dump_queue_head( MEM_ADDR(addr[i].link), "");
|
||||
else
|
||||
dump_td( MEM_ADDR(addr[i].link), "");
|
||||
}
|
||||
}
|
||||
|
||||
void dump_hex(uchar *data, int len, char *prefix)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
while(i<len) {
|
||||
if(!i%16) {
|
||||
DPRINTF("\n%s %04x: ", prefix, i);
|
||||
}
|
||||
else {
|
||||
DPRINTF(": ");
|
||||
}
|
||||
|
||||
DPRINTF("%02x", data[i++]);
|
||||
}
|
||||
|
||||
DPRINTF("\n");
|
||||
}
|
||||
|
||||
void dump_uhci(uint32_t port)
|
||||
{
|
||||
#if 0
|
||||
unsigned long value;
|
||||
#endif
|
||||
|
||||
DPRINTF("HCI at %08x\n", port);
|
||||
#if 0
|
||||
value = inw(port);
|
||||
DPRINTF("Command: %04x\n", value);
|
||||
|
||||
value = inw(port+2);
|
||||
DPRINTF("USBSTS: %04x\n", value);
|
||||
|
||||
value = inw(port+4);
|
||||
DPRINTF("USBINTR: %04x\n", value);
|
||||
|
||||
value = inw(port+6);
|
||||
DPRINTF("FRNUM: %04x\n", value);
|
||||
|
||||
value = inl(port+8);
|
||||
DPRINTF("FLBASEADD: %08x\n", value);
|
||||
|
||||
value = inb(port+0x0c);
|
||||
DPRINTF("SOFMOD: %02x\n", value);
|
||||
|
||||
value = inw(port+0x10);
|
||||
DPRINTF("PORTSTS1: %04x\n", value);
|
||||
|
||||
value = inw(port+0x12);
|
||||
DPRINTF("PORTSTS2: %04x\n", value);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void dump_td( td_t *td, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
|
||||
newpre[0]='\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
DPRINTF("%sTD(%08x):\n", prefix, td);
|
||||
|
||||
switch(td->packet_type) {
|
||||
case SETUP_TOKEN:
|
||||
DPRINTF("%stype: SETUP\n", prefix);
|
||||
break;
|
||||
case OUT_TOKEN:
|
||||
DPRINTF("%stype: OUT\n", prefix);
|
||||
break;
|
||||
case IN_TOKEN:
|
||||
DPRINTF("%stype: IN\n", prefix);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%stype: INVALID (%02x)\n", prefix, td->packet_type);
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("%sretries: %x\n", prefix, td->retrys);
|
||||
|
||||
if(td->isochronous) {
|
||||
DPRINTF("%sisochronous\n", prefix);
|
||||
}
|
||||
|
||||
if(td->interrupt) {
|
||||
DPRINTF("%sIOC\n", prefix);
|
||||
}
|
||||
|
||||
if(td->lowspeed) {
|
||||
DPRINTF("%slowspeed\n", prefix);
|
||||
}
|
||||
|
||||
if(td->detect_short) {
|
||||
DPRINTF("%sDETECT_SHORT\n", prefix);
|
||||
}
|
||||
|
||||
DPRINTF("%sactive: %04x\n", prefix, td->active);
|
||||
DPRINTF("%sdevice_addr: %02x\n", prefix, td->device_addr);
|
||||
DPRINTF("%sendpoint: %1x\n", prefix, td->endpoint);
|
||||
DPRINTF("%sdata_toggle: %1x\n", prefix, td->data_toggle);
|
||||
DPRINTF("%smax_transfer: %x\n", prefix, td->max_transfer);
|
||||
DPRINTF("%sactual: %x\n", prefix, td->actual);
|
||||
DPRINTF("%slink:\n", prefix);
|
||||
|
||||
if(td->stall) {
|
||||
DPRINTF("%sSTALL\n", prefix);
|
||||
}
|
||||
|
||||
if(td->bitstuff) {
|
||||
DPRINTF("%sBITSTUFF ERROR\n", prefix);
|
||||
}
|
||||
|
||||
if(td->crc) {
|
||||
DPRINTF("%sCRC ERROR\n", prefix);
|
||||
}
|
||||
|
||||
if(td->nak) {
|
||||
DPRINTF("%sNAK ERROR\n", prefix);
|
||||
}
|
||||
|
||||
if(td->babble) {
|
||||
DPRINTF("%sBABBLE ERROR\n", prefix);
|
||||
}
|
||||
|
||||
if(td->buffer_error) {
|
||||
DPRINTF("%sBUFFER ERROR\n", prefix);
|
||||
}
|
||||
|
||||
if(MEM_ADDR(td->link.link) == td) {
|
||||
DPRINTF("link loops back to me!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dump_link(&(td->link), newpre);
|
||||
if(!td->link.terminate) {
|
||||
if(td->link.queue)
|
||||
dump_queue_head(MEM_ADDR(td->link.link), prefix );
|
||||
else
|
||||
dump_td(MEM_ADDR(td->link.link), prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_queue_head( queue_head_t *qh, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
DPRINTF("%sQUEUE HEAD(%x):\n", prefix, qh);
|
||||
DPRINTF("%sdepth:\n", prefix);
|
||||
dump_link( &(qh->depth), newpre);
|
||||
|
||||
if(!qh->depth.terminate) {
|
||||
if(qh->depth.queue) {
|
||||
dump_queue_head(MEM_ADDR(qh->depth.link), newpre);
|
||||
}
|
||||
else {
|
||||
dump_td( MEM_ADDR(qh->depth.link), newpre);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DPRINTF("%sbredth:\n", prefix);
|
||||
dump_link( &(qh->bredth), newpre);
|
||||
if(!qh->bredth.terminate) {
|
||||
if(qh->bredth.queue) {
|
||||
dump_queue_head(MEM_ADDR(qh->bredth.link), newpre);
|
||||
}
|
||||
else {
|
||||
dump_td( MEM_ADDR(qh->bredth.link), newpre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_transaction( transaction_t *trans, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
|
||||
DPRINTF("%s TRANSACTION(%x):\n", prefix, trans);
|
||||
dump_queue_head( trans->qh, newpre);
|
||||
|
||||
DPRINTF("%s TDs:\n", prefix);
|
||||
dump_td( trans->td_list, newpre);
|
||||
|
||||
DPRINTF("\n");
|
||||
if(trans->next)
|
||||
dump_transaction(trans->next, prefix);
|
||||
}
|
||||
|
||||
void dump_usbdev( usbdev_t *dev, char *prefix)
|
||||
{
|
||||
char newpre[64];
|
||||
int i;
|
||||
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
DPRINTF("%saddress: %x\n", prefix, dev->address);
|
||||
DPRINTF("%sclass: %x\n", prefix, dev->class);
|
||||
DPRINTF("%ssubclass: %x\n", prefix, dev->subclass);
|
||||
DPRINTF("%sbulk_in: %x\n", prefix, dev->bulk_in);
|
||||
DPRINTF("%sbulk_out: %x\n", prefix, dev->bulk_out);
|
||||
DPRINTF("%sinterrupt: %x\n", prefix, dev->interrupt);
|
||||
|
||||
DPRINTF("%sep toggle:\n", prefix);
|
||||
for(i=0;i<MAX_EP;i++) {
|
||||
DPRINTF("%s%x\n", newpre, dev->toggle[i]);
|
||||
}
|
||||
|
||||
DPRINTF("%sep max_packet:\n", prefix);
|
||||
for(i=0;i<MAX_EP;i++) {
|
||||
DPRINTF("%s%x\n", newpre, dev->max_packet[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_all_usbdev(char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<MAX_USB_DEV;i++) {
|
||||
if(usb_device[i].address) {
|
||||
DPRINTF("%sDEVICE: %x\n", prefix, i);
|
||||
dump_usbdev( usb_device +i, prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_device_descriptor( device_descriptor_t *des, char *prefix)
|
||||
{
|
||||
DPRINTF("%sbLength: %02x\n", prefix, des->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, des->type);
|
||||
DPRINTF("%sbcdVersion: %1x%1x\n", prefix, des->bcdVersion[1], des->bcdVersion[0]);
|
||||
DPRINTF("%sClass: %02x\n",prefix, des->Class);
|
||||
DPRINTF("%sSubClass: %02x\n",prefix, des->SubClass);
|
||||
DPRINTF("%sprotocol: %02x\n",prefix, des->protocol);
|
||||
DPRINTF("%smax_packet: %x\n",prefix, des->max_packet);
|
||||
DPRINTF("%sidVendor: %04x\n", prefix, des->idVendor);
|
||||
DPRINTF("%sidProduct: %04x\n", prefix, des->idProduct);
|
||||
DPRINTF("%sbcdDeviceVersion: %1x%1x\n", prefix, des->bcdDevice[1], des->bcdDevice[0]);
|
||||
DPRINTF("%siManufacturor: %02x\n", prefix, des->iManufacturor);
|
||||
DPRINTF("%siProduct: %02x\n", prefix, des->iProduct);
|
||||
DPRINTF("%siSerial: %02x\n", prefix, des->iSerial);
|
||||
DPRINTF("%sbNumConfig: %02x\n", prefix, des->bNumConfig);
|
||||
|
||||
}
|
||||
|
||||
void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix)
|
||||
{
|
||||
|
||||
DPRINTF("%sbLength: %02x\n", prefix, iface->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, iface->type);
|
||||
DPRINTF("%sbInterfaceNumber: %02x\n", prefix, iface->bInterfaceNumber);
|
||||
DPRINTF("%sbAlternateSetting: %02x\n", prefix, iface->bAlternateSetting);
|
||||
DPRINTF("%sbNumEndpoints: %02x\n", prefix, iface->bNumEndpoints);
|
||||
DPRINTF("%sbInterfaceClass: %02x\n", prefix, iface->bInterfaceClass);
|
||||
DPRINTF("%sbInterfaceSubClass: %02x\n", prefix, iface->bInterfaceSubClass);
|
||||
DPRINTF("%sbInterfaceProtocol: %02x\n", prefix, iface->bInterfaceProtocol);
|
||||
DPRINTF("%siInterface: %02x\n", prefix, iface->iInterface);
|
||||
}
|
||||
|
||||
void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix)
|
||||
{
|
||||
|
||||
DPRINTF("%sbLength: %02x\n", prefix, ep->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, ep->type);
|
||||
DPRINTF("%sbEndpointAddress: %02x\n", prefix, ep->bEndpointAddress);
|
||||
DPRINTF("%sbmAttributes: %02x\n", prefix, ep->bmAttributes);
|
||||
DPRINTF("%swMaxPacketSize: %02x\n", prefix, ep->wMaxPacketSize);
|
||||
DPRINTF("%sbInterval: %02x\n", prefix, ep->bInterval);
|
||||
}
|
||||
|
||||
void dump_config_descriptor( uchar *des, char *prefix) // YES uchar *
|
||||
{
|
||||
config_descriptor_t *config;
|
||||
interface_descriptor_t *iface;
|
||||
endpoint_descriptor_t *ep;
|
||||
char newpre[64];
|
||||
int i;
|
||||
|
||||
memset(newpre,0,sizeof(newpre));
|
||||
newpre[0] = '\t';
|
||||
strcpy(newpre+1, prefix);
|
||||
|
||||
config = (config_descriptor_t *) des;
|
||||
iface = (interface_descriptor_t *) (des + config->bLength);
|
||||
ep = (endpoint_descriptor_t *) (des + config->bLength + iface->bLength);
|
||||
|
||||
// now, the config itself
|
||||
DPRINTF("%sbLength: %02x\n", prefix, config->bLength);
|
||||
DPRINTF("%stype: %02x\n", prefix, config->type);
|
||||
DPRINTF("%swTotalLength: %04x\n", prefix, config->wTotalLength);
|
||||
DPRINTF("%sbNumInterfaces: %02x\n", prefix, config->bNumInterfaces);
|
||||
DPRINTF("%sbConfigurationValue: %02x\n", prefix, config->bConfigurationValue);
|
||||
DPRINTF("%siConfiguration: %02x\n", prefix, config->iConfiguration);
|
||||
DPRINTF("%sbmAttributes: %02x\n", prefix, config->bmAttributes);
|
||||
|
||||
DPRINTF("%sbMaxPower: %02x\n", prefix, config->bMaxPower);
|
||||
|
||||
DPRINTF("\n%sInterface(%x):\n", prefix, iface);
|
||||
dump_interface_descriptor(iface, newpre);
|
||||
|
||||
newpre[1] = '\t';
|
||||
strcpy(newpre+2, prefix);
|
||||
|
||||
for(i=0; i<iface->bNumEndpoints; i++) {
|
||||
DPRINTF("\n%sEndpoint (%x):\n", newpre+1, ep+i);
|
||||
dump_endpoint_descriptor( ep+i, newpre);
|
||||
}
|
||||
}
|
||||
|
||||
// Some control message bmRequestType defines
|
||||
#define CTRL_DEVICE 0
|
||||
#define CONTROL_INTERFACE 1
|
||||
#define CONTROL_ENDPOINT 2
|
||||
#define CONTROL_OTHER 3
|
||||
#define CONTROL_RECIPIENT_MASK 0x1f
|
||||
|
||||
#define CONTROL_TYPE_STD 0
|
||||
#define CONTROL_TYPE_CLASS 0x20
|
||||
#define CONTROL_CLASS_VENDOR 0x40
|
||||
#define CONTROL_CLASS_MASK 0x60
|
||||
|
||||
#define CONTROL_OUT 0
|
||||
#define CONTROL_IN 0x80
|
||||
#define CONTROL_DIR_MASK 0x80
|
||||
|
||||
// bRequest values
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
#define SYNC_FRAME 12
|
||||
|
||||
// descriptor types
|
||||
#define DEVICE_DESC 1
|
||||
#define CONFIGURATION_DESC 2
|
||||
#define STRING_DESC 3
|
||||
#define INTERFACE_DESC 4
|
||||
#define ENDPOINT_DESC 5
|
||||
#define OTHERSPEED_DESC 7
|
||||
#define POWER_DESC 8
|
||||
|
||||
// features
|
||||
#define FEATURE_HALT 0
|
||||
void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix)
|
||||
{
|
||||
DPRINTF("%sbmRequestType: %02x\n", prefix, msg->bmRequestType);
|
||||
DPRINTF("%sbRequest: %02x\n", prefix, msg->bRequest);
|
||||
DPRINTF("%swValue: %04x\n", prefix, msg->wValue);
|
||||
DPRINTF("%swIndex: %04x\n", prefix, msg->wIndex);
|
||||
DPRINTF("%swLength: %04x\n", prefix, msg->wLength);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef _DEBUG_X_H
|
||||
#define _DEBUG_X_H
|
||||
|
||||
void dump_hex(uchar *data, int len, char *prefix);
|
||||
void dump_link( link_pointer_t *link, char *prefix);
|
||||
void dump_td( td_t *td, char *prefix);
|
||||
void dump_queue_head( queue_head_t *qh, char *prefix);
|
||||
void dump_transaction( transaction_t *trans, char *prefix);
|
||||
void dump_usbdev( usbdev_t *dev, char *prefix);
|
||||
void dump_uhci(uint32_t port);
|
||||
//void dump_all_usbdev(char *prefix);
|
||||
void dump_device_descriptor( device_descriptor_t *des, char *prefix);
|
||||
void dump_interface_descriptor( interface_descriptor_t *iface, char *prefix);
|
||||
void dump_endpoint_descriptor( endpoint_descriptor_t *ep, char *prefix);
|
||||
void dump_config_descriptor( uchar *des, char *prefix);
|
||||
void dump_ctrlmsg( ctrl_msg_t *msg, char *prefix);
|
||||
|
||||
#endif
|
1437
src/filo/usb/ohci.c
1437
src/filo/usb/ohci.c
File diff suppressed because it is too large
Load Diff
|
@ -1,316 +0,0 @@
|
|||
#ifdef USB_DISK
|
||||
|
||||
#ifndef _OHCI_H
|
||||
#define _OHCI_H
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
// for OHCI
|
||||
|
||||
/* ED States */
|
||||
|
||||
#define ED_NEW 0x00
|
||||
#define ED_UNLINK 0x01
|
||||
#define ED_OPER 0x02
|
||||
#define ED_DEL 0x04
|
||||
#define ED_URB_DEL 0x08
|
||||
|
||||
/* usb_ohci_ed */
|
||||
struct ed {
|
||||
u32 hwINFO;
|
||||
u32 hwTailP;
|
||||
u32 hwHeadP;
|
||||
u32 hwNextED;
|
||||
|
||||
struct ed * ed_prev;
|
||||
u8 int_period; // No use just for aligned
|
||||
u8 int_branch; // No use just for aligned
|
||||
u8 int_load; // No uae just for aligned
|
||||
u8 int_interval; // No use just for aligned
|
||||
u8 state;
|
||||
u8 type;
|
||||
u16 last_iso; // no use just for aligned
|
||||
struct ed * ed_rm_list; // No use just for aligned
|
||||
|
||||
void * dma;
|
||||
|
||||
u32 unused[3];
|
||||
};
|
||||
// __attribute((aligned(16)));
|
||||
typedef struct ed ed_t;
|
||||
|
||||
/* TD info field */
|
||||
#define TD_CC 0xf0000000
|
||||
#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
|
||||
#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
|
||||
#define TD_EC 0x0C000000
|
||||
#define TD_T 0x03000000
|
||||
#define TD_T_DATA0 0x02000000
|
||||
#define TD_T_DATA1 0x03000000
|
||||
#define TD_T_TOGGLE 0x00000000
|
||||
#define TD_R 0x00040000
|
||||
#define TD_DI 0x00E00000
|
||||
#define TD_DI_SET(X) (((X) & 0x07)<< 21)
|
||||
#define TD_DP 0x00180000
|
||||
#define TD_DP_SETUP 0x00000000
|
||||
#define TD_DP_IN 0x00100000
|
||||
#define TD_DP_OUT 0x00080000
|
||||
|
||||
#define TD_ISO 0x00010000
|
||||
#define TD_DEL 0x00020000
|
||||
|
||||
/* CC Codes */
|
||||
#define TD_CC_NOERROR 0x00
|
||||
#define TD_CC_CRC 0x01
|
||||
#define TD_CC_BITSTUFFING 0x02
|
||||
#define TD_CC_DATATOGGLEM 0x03
|
||||
#define TD_CC_STALL 0x04
|
||||
#define TD_DEVNOTRESP 0x05
|
||||
#define TD_PIDCHECKFAIL 0x06
|
||||
#define TD_UNEXPECTEDPID 0x07
|
||||
#define TD_DATAOVERRUN 0x08
|
||||
#define TD_DATAUNDERRUN 0x09
|
||||
#define TD_BUFFEROVERRUN 0x0C
|
||||
#define TD_BUFFERUNDERRUN 0x0D
|
||||
#define TD_NOTACCESSED 0x0F
|
||||
|
||||
|
||||
#define MAXPSW 1
|
||||
|
||||
struct ohci_td {
|
||||
u32 hwINFO;
|
||||
u32 hwCBP; /* Current Buffer Pointer */
|
||||
u32 hwNextTD; /* Next TD Pointer */
|
||||
u32 hwBE; /* Memory Buffer End Pointer */
|
||||
u16 hwPSW[MAXPSW];
|
||||
u8 unused;
|
||||
u8 index;
|
||||
struct ed * ed;
|
||||
struct ohci_td * next_dl_td;
|
||||
struct urb * urb; //defined in usb.h
|
||||
void * td_dma;
|
||||
void * data_dma;
|
||||
u32 unused2[2];
|
||||
};
|
||||
//__attribute((aligned(32))); /* normally 16, iso needs 32 */
|
||||
typedef struct ohci_td ohci_td_t;
|
||||
|
||||
#define OHCI_ED_SKIP (1 << 14)
|
||||
|
||||
/*
|
||||
* The HCCA (Host Controller Communications Area) is a 256 byte
|
||||
* structure defined in the OHCI spec. that the host controller is
|
||||
* told the base address of. It must be 256-byte aligned.
|
||||
*/
|
||||
|
||||
#define NUM_INTS 32 /* part of the OHCI standard */
|
||||
struct ohci_hcca {
|
||||
u32 int_table[NUM_INTS]; /* Interrupt ED table */
|
||||
u16 frame_no; /* current frame number */
|
||||
u16 pad1; /* set to 0 on each frame_no change */
|
||||
u32 done_head; /* info returned for an interrupt */
|
||||
u8 reserved_for_hc[116];
|
||||
} __attribute((aligned(256)));
|
||||
|
||||
|
||||
#define MAX_ROOT_PORTS 15
|
||||
|
||||
struct ohci_regs {
|
||||
/* control and status registers */
|
||||
u32 revision;
|
||||
u32 control;
|
||||
u32 cmdstatus;
|
||||
u32 intrstatus;
|
||||
u32 intrenable;
|
||||
u32 intrdisable;
|
||||
/* memory pointers */
|
||||
u32 hcca;
|
||||
u32 ed_periodcurrent;
|
||||
u32 ed_controlhead;
|
||||
u32 ed_controlcurrent;
|
||||
u32 ed_bulkhead;
|
||||
u32 ed_bulkcurrent;
|
||||
u32 donehead;
|
||||
/* frame counters */
|
||||
u32 fminterval;
|
||||
u32 fmremaining;
|
||||
u32 fmnumber;
|
||||
u32 periodicstart;
|
||||
u32 lsthresh;
|
||||
/* Root hub ports */
|
||||
struct ohci_roothub_regs {
|
||||
u32 a;
|
||||
u32 b;
|
||||
u32 status;
|
||||
u32 portstatus[MAX_ROOT_PORTS];
|
||||
} roothub;
|
||||
} __attribute((aligned(32)));
|
||||
typedef struct ohci_regs ohci_regs_t;
|
||||
|
||||
|
||||
/* OHCI CONTROL AND STATUS REGISTER MASKS */
|
||||
|
||||
/*
|
||||
* HcControl (control) register masks
|
||||
*/
|
||||
#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
|
||||
#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
|
||||
#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
|
||||
#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
|
||||
#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
|
||||
#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
|
||||
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
|
||||
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
|
||||
#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
|
||||
|
||||
/* pre-shifted values for HCFS */
|
||||
# define OHCI_USB_RESET (0 << 6)
|
||||
# define OHCI_USB_RESUME (1 << 6)
|
||||
# define OHCI_USB_OPER (2 << 6)
|
||||
# define OHCI_USB_SUSPEND (3 << 6)
|
||||
|
||||
/*
|
||||
* HcCommandStatus (cmdstatus) register masks
|
||||
*/
|
||||
#define OHCI_HCR (1 << 0) /* host controller reset */
|
||||
#define OHCI_CLF (1 << 1) /* control list filled */
|
||||
#define OHCI_BLF (1 << 2) /* bulk list filled */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_SOC (3 << 16) /* scheduling overrun count */
|
||||
|
||||
/*
|
||||
* masks used with interrupt registers:
|
||||
* HcInterruptStatus (intrstatus)
|
||||
* HcInterruptEnable (intrenable)
|
||||
* HcInterruptDisable (intrdisable)
|
||||
*/
|
||||
#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
|
||||
#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
|
||||
#define OHCI_INTR_SF (1 << 2) /* start frame */
|
||||
#define OHCI_INTR_RD (1 << 3) /* resume detect */
|
||||
#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
|
||||
#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
|
||||
#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
|
||||
#define OHCI_INTR_OC (1 << 30) /* ownership change */
|
||||
#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
|
||||
|
||||
|
||||
/* For initializing controller (mask in an HCFS mode too) */
|
||||
#define OHCI_CONTROL_INIT \
|
||||
(OHCI_CTRL_CBSR & 0x3)
|
||||
//| OHCI_CTRL_IE | OHCI_CTRL_PLE
|
||||
|
||||
/* OHCI ROOT HUB REGISTER MASKS */
|
||||
|
||||
/* roothub.portstatus [i] bits */
|
||||
#define RH_PS_CCS 0x00000001 /* current connect status */
|
||||
#define RH_PS_PES 0x00000002 /* port enable status*/
|
||||
#define RH_PS_PSS 0x00000004 /* port suspend status */
|
||||
#define RH_PS_POCI 0x00000008 /* port over current indicator */
|
||||
#define RH_PS_PRS 0x00000010 /* port reset status */
|
||||
#define RH_PS_PPS 0x00000100 /* port power status */
|
||||
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
|
||||
#define RH_PS_CSC 0x00010000 /* connect status change */
|
||||
#define RH_PS_PESC 0x00020000 /* port enable status change */
|
||||
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
|
||||
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
|
||||
#define RH_PS_PRSC 0x00100000 /* port reset status change */
|
||||
|
||||
/* roothub.status bits */
|
||||
#define RH_HS_LPS 0x00000001 /* local power status */
|
||||
#define RH_HS_OCI 0x00000002 /* over current indicator */
|
||||
#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
|
||||
#define RH_HS_LPSC 0x00010000 /* local power status change */
|
||||
#define RH_HS_OCIC 0x00020000 /* over current indicator change */
|
||||
#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
|
||||
|
||||
/* roothub.b masks */
|
||||
#define RH_B_DR 0x0000ffff /* device removable flags */
|
||||
#define RH_B_PPCM 0xffff0000 /* port power control mask */
|
||||
|
||||
/* roothub.a masks */
|
||||
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
|
||||
#define RH_A_PSM (1 << 8) /* power switching mode */
|
||||
#define RH_A_NPS (1 << 9) /* no power switching */
|
||||
#define RH_A_DT (1 << 10) /* device type (mbz) */
|
||||
#define RH_A_OCPM (1 << 11) /* over current protection mode */
|
||||
#define RH_A_NOCP (1 << 12) /* no over current protection */
|
||||
#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ed_t * ed;
|
||||
u16 length; // number of tds associated with this request
|
||||
u16 td_cnt; // number of tds already serviced
|
||||
int state;
|
||||
#if 0
|
||||
wait_queue_head_t * wait;
|
||||
#endif
|
||||
ohci_td_t * td[0]; // list pointer to all corresponding TDs associated with this request
|
||||
|
||||
} urb_priv_t;
|
||||
|
||||
#define NUM_EDS 32 /* num of preallocated endpoint descriptors */
|
||||
|
||||
typedef struct ohci {
|
||||
struct ohci_hcca *hcca; /* hcca */
|
||||
void * hcca_dma;
|
||||
|
||||
ohci_regs_t * regs; /* OHCI controller's memory */
|
||||
|
||||
ed_t * ed_bulktail; /* last endpoint of bulk list */
|
||||
ed_t * ed_controltail; /* last endpoint of control list */
|
||||
|
||||
int intrstatus;
|
||||
u32 hc_control; /* copy of the hc control reg */
|
||||
|
||||
uint32_t ed_cnt;
|
||||
ed_t *ed; // Allocate that from ed_buffer in ohc_init
|
||||
usbdev_t *dev[NUM_EDS];
|
||||
urb_t *urb; // one ohci one urb
|
||||
urb_priv_t *urb_priv;
|
||||
struct usb_ctrlrequest *dr;
|
||||
} ohci_t;
|
||||
|
||||
|
||||
extern ohci_t _ohci_x[MAX_CONTROLLERS];
|
||||
|
||||
#define usb_to_ohci(usb_dev) (&_ohci_x[(usb_dev)->controller])
|
||||
|
||||
extern ohci_regs_t *ohci_regs;
|
||||
|
||||
void clear_oport_stat(uint32_t port);
|
||||
int ohc_init(struct pci_device *dev);
|
||||
int poll_o_root_hub(uint32_t port, uchar controller);
|
||||
|
||||
int ohci_bulk_transfer( uchar devnum, uchar ep, unsigned int data_len, uchar *data);
|
||||
int ohci_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short
|
||||
wLength, void *data);
|
||||
void ohci_wait_urb_done(struct urb *urb, int timeout);
|
||||
|
||||
void ohci_init(void);
|
||||
int ohc_init(struct pci_device *dev);
|
||||
int ohci_submit_urb (struct urb * urb);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,226 +0,0 @@
|
|||
/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
/*
|
||||
* This header file contains public constants and structures used by
|
||||
* the scsi code for linux.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_H
|
||||
#define _SCSI_SCSI_H 1
|
||||
|
||||
//#include <features.h>
|
||||
|
||||
/*
|
||||
* SCSI opcodes
|
||||
*/
|
||||
|
||||
#define TEST_UNIT_READY 0x00
|
||||
#define REZERO_UNIT 0x01
|
||||
#define REQUEST_SENSE 0x03
|
||||
#define FORMAT_UNIT 0x04
|
||||
#define READ_BLOCK_LIMITS 0x05
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define READ_6 0x08
|
||||
#define WRITE_6 0x0a
|
||||
#define SEEK_6 0x0b
|
||||
#define READ_REVERSE 0x0f
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
#define INQUIRY 0x12
|
||||
#define RECOVER_BUFFERED_DATA 0x14
|
||||
#define MODE_SELECT 0x15
|
||||
#define RESERVE 0x16
|
||||
#define RELEASE 0x17
|
||||
#define COPY 0x18
|
||||
#define ERASE 0x19
|
||||
#define MODE_SENSE 0x1a
|
||||
#define START_STOP 0x1b
|
||||
#define RECEIVE_DIAGNOSTIC 0x1c
|
||||
#define SEND_DIAGNOSTIC 0x1d
|
||||
#define ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
|
||||
#define SET_WINDOW 0x24
|
||||
#define READ_CAPACITY 0x25
|
||||
#define READ_10 0x28
|
||||
#define WRITE_10 0x2a
|
||||
#define SEEK_10 0x2b
|
||||
#define WRITE_VERIFY 0x2e
|
||||
#define VERIFY 0x2f
|
||||
#define SEARCH_HIGH 0x30
|
||||
#define SEARCH_EQUAL 0x31
|
||||
#define SEARCH_LOW 0x32
|
||||
#define SET_LIMITS 0x33
|
||||
#define PRE_FETCH 0x34
|
||||
#define READ_POSITION 0x34
|
||||
#define SYNCHRONIZE_CACHE 0x35
|
||||
#define LOCK_UNLOCK_CACHE 0x36
|
||||
#define READ_DEFECT_DATA 0x37
|
||||
#define MEDIUM_SCAN 0x38
|
||||
#define COMPARE 0x39
|
||||
#define COPY_VERIFY 0x3a
|
||||
#define WRITE_BUFFER 0x3b
|
||||
#define READ_BUFFER 0x3c
|
||||
#define UPDATE_BLOCK 0x3d
|
||||
#define READ_LONG 0x3e
|
||||
#define WRITE_LONG 0x3f
|
||||
#define CHANGE_DEFINITION 0x40
|
||||
#define WRITE_SAME 0x41
|
||||
#define READ_TOC 0x43
|
||||
#define LOG_SELECT 0x4c
|
||||
#define LOG_SENSE 0x4d
|
||||
#define MODE_SELECT_10 0x55
|
||||
#define RESERVE_10 0x56
|
||||
#define RELEASE_10 0x57
|
||||
#define MODE_SENSE_10 0x5a
|
||||
#define PERSISTENT_RESERVE_IN 0x5e
|
||||
#define PERSISTENT_RESERVE_OUT 0x5f
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
#define READ_12 0xa8
|
||||
#define WRITE_12 0xaa
|
||||
#define WRITE_VERIFY_12 0xae
|
||||
#define SEARCH_HIGH_12 0xb0
|
||||
#define SEARCH_EQUAL_12 0xb1
|
||||
#define SEARCH_LOW_12 0xb2
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
#define SEND_VOLUME_TAG 0xb6
|
||||
#define WRITE_LONG_2 0xea
|
||||
|
||||
/*
|
||||
* Status codes
|
||||
*/
|
||||
|
||||
#define GOOD 0x00
|
||||
#define CHECK_CONDITION 0x01
|
||||
#define CONDITION_GOOD 0x02
|
||||
#define BUSY 0x04
|
||||
#define INTERMEDIATE_GOOD 0x08
|
||||
#define INTERMEDIATE_C_GOOD 0x0a
|
||||
#define RESERVATION_CONFLICT 0x0c
|
||||
#define COMMAND_TERMINATED 0x11
|
||||
#define QUEUE_FULL 0x14
|
||||
|
||||
#define STATUS_MASK 0x3e
|
||||
|
||||
/*
|
||||
* SENSE KEYS
|
||||
*/
|
||||
|
||||
#define NO_SENSE 0x00
|
||||
#define RECOVERED_ERROR 0x01
|
||||
#define NOT_READY 0x02
|
||||
#define MEDIUM_ERROR 0x03
|
||||
#define HARDWARE_ERROR 0x04
|
||||
#define ILLEGAL_REQUEST 0x05
|
||||
#define UNIT_ATTENTION 0x06
|
||||
#define DATA_PROTECT 0x07
|
||||
#define BLANK_CHECK 0x08
|
||||
#define COPY_ABORTED 0x0a
|
||||
#define ABORTED_COMMAND 0x0b
|
||||
#define VOLUME_OVERFLOW 0x0d
|
||||
#define MISCOMPARE 0x0e
|
||||
|
||||
|
||||
/*
|
||||
* DEVICE TYPES
|
||||
*/
|
||||
|
||||
#define TYPE_DISK 0x00
|
||||
#define TYPE_TAPE 0x01
|
||||
#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
|
||||
#define TYPE_WORM 0x04 /* Treated as ROM by our system */
|
||||
#define TYPE_ROM 0x05
|
||||
#define TYPE_SCANNER 0x06
|
||||
#define TYPE_MOD 0x07 /* Magneto-optical disk -
|
||||
* - treated as TYPE_DISK */
|
||||
#define TYPE_MEDIUM_CHANGER 0x08
|
||||
#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
|
||||
#define TYPE_NO_LUN 0x7f
|
||||
|
||||
/*
|
||||
* standard mode-select header prepended to all mode-select commands
|
||||
*
|
||||
* moved here from cdrom.h -- kraxel
|
||||
*/
|
||||
|
||||
struct ccs_modesel_head
|
||||
{
|
||||
unsigned char _r1; /* reserved. */
|
||||
unsigned char medium; /* device-specific medium type. */
|
||||
unsigned char _r2; /* reserved. */
|
||||
unsigned char block_desc_length; /* block descriptor length. */
|
||||
unsigned char density; /* device-specific density code. */
|
||||
unsigned char number_blocks_hi; /* number of blocks in this block
|
||||
desc. */
|
||||
unsigned char number_blocks_med;
|
||||
unsigned char number_blocks_lo;
|
||||
unsigned char _r3;
|
||||
unsigned char block_length_hi; /* block length for blocks in this
|
||||
desc. */
|
||||
unsigned char block_length_med;
|
||||
unsigned char block_length_lo;
|
||||
};
|
||||
|
||||
/*
|
||||
* MESSAGE CODES
|
||||
*/
|
||||
|
||||
#define COMMAND_COMPLETE 0x00
|
||||
#define EXTENDED_MESSAGE 0x01
|
||||
#define EXTENDED_MODIFY_DATA_POINTER 0x00
|
||||
#define EXTENDED_SDTR 0x01
|
||||
#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */
|
||||
#define EXTENDED_WDTR 0x03
|
||||
#define SAVE_POINTERS 0x02
|
||||
#define RESTORE_POINTERS 0x03
|
||||
#define DISCONNECT 0x04
|
||||
#define INITIATOR_ERROR 0x05
|
||||
#define ABORT 0x06
|
||||
#define MESSAGE_REJECT 0x07
|
||||
#define NOP 0x08
|
||||
#define MSG_PARITY_ERROR 0x09
|
||||
#define LINKED_CMD_COMPLETE 0x0a
|
||||
#define LINKED_FLG_CMD_COMPLETE 0x0b
|
||||
#define BUS_DEVICE_RESET 0x0c
|
||||
|
||||
#define INITIATE_RECOVERY 0x0f /* SCSI-II only */
|
||||
#define RELEASE_RECOVERY 0x10 /* SCSI-II only */
|
||||
|
||||
#define SIMPLE_QUEUE_TAG 0x20
|
||||
#define HEAD_OF_QUEUE_TAG 0x21
|
||||
#define ORDERED_QUEUE_TAG 0x22
|
||||
|
||||
/*
|
||||
* Here are some scsi specific ioctl commands which are sometimes useful.
|
||||
*/
|
||||
/* These are a few other constants only used by scsi devices. */
|
||||
|
||||
#define SCSI_IOCTL_GET_IDLUN 0x5382
|
||||
|
||||
/* Used to turn on and off tagged queuing for scsi devices. */
|
||||
|
||||
#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
|
||||
#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
|
||||
|
||||
/* Used to obtain the host number of a device. */
|
||||
#define SCSI_IOCTL_PROBE_HOST 0x5385
|
||||
|
||||
/* Used to get the bus number for a device. */
|
||||
#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
|
||||
|
||||
#endif /* scsi/scsi.h */
|
|
@ -1,512 +0,0 @@
|
|||
#ifdef USB_DISK
|
||||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <etherboot.h>
|
||||
#include <pci.h>
|
||||
#include <timer.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_USB
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTF debug
|
||||
|
||||
|
||||
#include "scsi.h"
|
||||
|
||||
|
||||
#include "usb_scsi_low.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *) 0x0
|
||||
#endif
|
||||
|
||||
#include "scsi_cmds.h"
|
||||
|
||||
devhandle sgh;
|
||||
|
||||
typedef struct sense_data {
|
||||
uchar code;
|
||||
|
||||
uchar sense_key:4;
|
||||
uchar res1:4;
|
||||
|
||||
uchar additional_code;
|
||||
uchar qualifier;
|
||||
|
||||
uchar res2[3];
|
||||
|
||||
uchar length;
|
||||
} __attribute__ ((packed)) sense_data_t;
|
||||
|
||||
typedef struct fixed_sense_data {
|
||||
uchar code:7;
|
||||
uchar valid:1;
|
||||
|
||||
uchar obs1;
|
||||
|
||||
uchar sense_key:4;
|
||||
uchar res1:1;
|
||||
uchar ili:1;
|
||||
uchar eom:1;
|
||||
uchar mark:1;
|
||||
|
||||
unsigned int info;
|
||||
|
||||
uchar add_len;
|
||||
} __attribute__ ((packed)) fixed_sense_data_t;
|
||||
|
||||
typedef struct additional_fixed_data {
|
||||
unsigned int info;
|
||||
|
||||
uchar code;
|
||||
uchar qualifier;
|
||||
uchar fru;
|
||||
|
||||
uchar specific[3];
|
||||
} __attribute__ ((packed)) additional_fixed_data_t;
|
||||
|
||||
|
||||
void PrintSense(uchar *sense, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINTF( "sense data ");
|
||||
for(i=0;i<len; i++) {
|
||||
DPRINTF( ":%02x", sense[i]);
|
||||
}
|
||||
DPRINTF("\n\n");
|
||||
|
||||
if( (sense[0] & 0x7f) >=0x72) {
|
||||
sense_data_t *sd = (sense_data_t *) sense;
|
||||
uchar *pos = sense+sizeof(sense_data_t);
|
||||
uchar remaining = sd->length;
|
||||
int dlen;
|
||||
|
||||
DPRINTF("code = %02x, key = %1x, additional = %02x, qual = %02x\n", sd->code, sd->sense_key, sd->additional_code, sd->qualifier);
|
||||
|
||||
while(remaining) {
|
||||
DPRINTF("type = %02x", pos[0]);
|
||||
dlen = pos[1];
|
||||
pos+=2;
|
||||
remaining -=2;
|
||||
|
||||
for(i=0; i<dlen; i++)
|
||||
DPRINTF( ": %02x", pos[i]);
|
||||
|
||||
DPRINTF("\n");
|
||||
pos+=i;
|
||||
remaining -=i;
|
||||
}
|
||||
|
||||
} else {
|
||||
fixed_sense_data_t *fd = (fixed_sense_data_t *) sense;
|
||||
uchar remaining = fd->add_len;
|
||||
additional_fixed_data_t *afd;
|
||||
|
||||
|
||||
DPRINTF("code = %02x key = %1x\n", fd->code, fd->sense_key);
|
||||
if(fd->mark) {
|
||||
DPRINTF("filemark ");
|
||||
}
|
||||
|
||||
if(fd->eom) {
|
||||
DPRINTF(" End Of Media ");
|
||||
}
|
||||
|
||||
if(fd->ili) {
|
||||
DPRINTF("Illegal instruction");
|
||||
}
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
if(fd->valid) {
|
||||
DPRINTF( "(valid) ");
|
||||
}
|
||||
|
||||
DPRINTF( "Info: %08x\n", ntohl(fd->info));
|
||||
|
||||
afd = (additional_fixed_data_t *) (sense + 8);
|
||||
|
||||
// while(remaining) {
|
||||
if(remaining) {
|
||||
DPRINTF("command info = %08x\n", ntohl(afd->info));
|
||||
DPRINTF("code = %02x, qual = %02x, fru = %02x\n", afd->code, afd->qualifier, afd->fru);
|
||||
DPRINTF("sense key data = %02x:%02x:%02x\n\n", afd->specific[2], afd->specific[1], afd->specific[0]);
|
||||
|
||||
afd++;
|
||||
remaining -= sizeof(additional_fixed_data_t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef struct query_response {
|
||||
uchar type:5;
|
||||
uchar qualifier:3;
|
||||
|
||||
uchar reserved1:7;
|
||||
uchar removable:1;
|
||||
|
||||
uchar version;
|
||||
|
||||
uchar ResponseDataFormat:4; // should == 2
|
||||
uchar HiSup:1; // report luns cmd supported
|
||||
uchar NormACA:1;
|
||||
uchar obsolete:1;
|
||||
uchar aerc:1;
|
||||
|
||||
uchar AdditionalLength; // length of vendor specific data (beyond 96 bytes)
|
||||
|
||||
uchar reserved2:7;
|
||||
uchar sccs:1; // have raid controller
|
||||
|
||||
uchar addr16:1; //
|
||||
uchar obsolete2:2;
|
||||
uchar MChnger:1; // media changer
|
||||
uchar MultiP:1; // multi port
|
||||
uchar vs:1; // ???
|
||||
uchar EncServ:1; // enclosure service
|
||||
uchar BQue:1; // basic command queueing
|
||||
|
||||
uchar vs2:1;
|
||||
uchar CmdQue:1; // full command queueing
|
||||
uchar obsolete4:1;
|
||||
uchar linked:1;
|
||||
uchar sync:1;
|
||||
uchar wbus16:1; //
|
||||
uchar obsolete3:1;
|
||||
uchar RelAddr:1; // treletive addressing
|
||||
|
||||
char vendor[8];
|
||||
char product[16];
|
||||
char revision[4];
|
||||
char vendor_data[20];
|
||||
|
||||
uchar ius:1;
|
||||
uchar qas:1;
|
||||
uchar clocking:2; //
|
||||
uchar reserved3:4;
|
||||
|
||||
unsigned short version_desc[8];
|
||||
|
||||
char reserved4[21];
|
||||
} query_response_t;
|
||||
|
||||
typedef struct ReadBlockCMD {
|
||||
uchar cmd;
|
||||
|
||||
uchar reladdr:1;
|
||||
uchar reserved:2;
|
||||
uchar fua:1; // force unit access flush to media
|
||||
uchar dpo:1; // direct page out, do not cache
|
||||
uchar reserved2:3;
|
||||
|
||||
unsigned int block_address;
|
||||
uchar reserved3;
|
||||
|
||||
unsigned short block_count;
|
||||
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadBlockCMD_t ;
|
||||
|
||||
int ll_read_block(devhandle sgd, char *buffer, int blocknum, int count)
|
||||
{
|
||||
int ret;
|
||||
ReadBlockCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = READ_10;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.block_count = htons(count);
|
||||
|
||||
ret = scsi_command( sgd, (uint8_t *)&rb, sizeof(rb), SG_DXFER_FROM_DEV, buffer, count * 512, sensedat, sizeof(sensedat));
|
||||
|
||||
if(ret<0) {
|
||||
DPRINTF("ERROR: ll_read_block( %x, %x, %x, %x) = %d\n", sgd, buffer, blocknum, count, ret);
|
||||
PrintSense(sensedat, 32);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
|
||||
}
|
||||
|
||||
int ll_write_block(devhandle sgd, char *buffer, int blocknum, int count)
|
||||
{
|
||||
int ret;
|
||||
ReadBlockCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = WRITE_10;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.block_count = htons(count);
|
||||
|
||||
ret = scsi_command( sgd, (uint8_t *)&rb, sizeof(rb), SG_DXFER_TO_DEV, buffer, count * 512, sensedat, sizeof(sensedat));
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct ReadLongCMD {
|
||||
uchar cmd;
|
||||
|
||||
uchar reladdr:1;
|
||||
uchar correct:1;
|
||||
uchar reserved:5;
|
||||
|
||||
unsigned int block_address;
|
||||
uchar reserved3;
|
||||
|
||||
unsigned short length;
|
||||
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadLongCMD_t ;
|
||||
|
||||
int ll_read_long(devhandle sgd, char *buffer, int blocknum, int size)
|
||||
{
|
||||
int ret;
|
||||
ReadLongCMD_t rb;
|
||||
char sensedat[32];
|
||||
|
||||
memset(&rb,0,sizeof(rb));
|
||||
rb.cmd = READ_LONG;
|
||||
rb.block_address = htonl(blocknum);
|
||||
rb.length = htons(size);
|
||||
|
||||
ret = scsi_command( sgd, (uint8_t *)&rb, sizeof(rb), SG_DXFER_FROM_DEV, buffer, size, sensedat, sizeof(sensedat));
|
||||
return(ret);
|
||||
}
|
||||
|
||||
unsigned char ReadCapacityCMD[10] = { READ_CAPACITY, 0, 0,0,0,0, 0,0,0, 0};
|
||||
|
||||
struct ReadCapacityResponse {
|
||||
unsigned int block_address;
|
||||
unsigned int block_length;
|
||||
};
|
||||
|
||||
int get_capacity(devhandle sgd, unsigned long *block_count, unsigned int *blk_len)
|
||||
{
|
||||
int ret;
|
||||
struct ReadCapacityResponse response;
|
||||
char sensedat[32];
|
||||
|
||||
ret = scsi_command(sgd, ReadCapacityCMD, sizeof(ReadCapacityCMD), SG_DXFER_FROM_DEV, (uint8_t *)&response, sizeof(response), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("ERROR:get capacity: %d\n", ret);
|
||||
PrintSense(sensedat,32);
|
||||
}
|
||||
|
||||
|
||||
*block_count = ntohl(response.block_address) +1;
|
||||
*blk_len = ntohl(response.block_length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#define INQ_REP_LEN 96
|
||||
unsigned char InquiryCMD[6] = { INQUIRY, 0, 0, 0, INQ_REP_LEN, 0};
|
||||
|
||||
int query(devhandle sgd, query_response_t *qr)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
|
||||
ret = scsi_command(sgd, InquiryCMD, sizeof(InquiryCMD), SG_DXFER_FROM_DEV, (uint8_t *)qr, sizeof(query_response_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0){
|
||||
DPRINTF("query: IOCTL");
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct lun_list {
|
||||
unsigned int list_length;
|
||||
unsigned int reserved;
|
||||
unsigned long long lun[16];
|
||||
} lun_list_t;
|
||||
|
||||
#define REPORT_LUNS 0xa0
|
||||
unsigned char ReportLunsCMD[12] = { REPORT_LUNS, 0, 2, 0, 0, 0, 0, 0, 0, 128, 0, 0 };
|
||||
|
||||
int ReportLUNS(devhandle sgd, lun_list_t *list)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
|
||||
memset (list, 0, sizeof(lun_list_t));
|
||||
ret = scsi_command(sgd, ReportLunsCMD, sizeof(ReportLunsCMD), SG_DXFER_FROM_DEV, (uint8_t *)list, sizeof(lun_list_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0) {
|
||||
DPRINTF("Report Luns: IOCTL");
|
||||
}
|
||||
|
||||
list->list_length = ntohl(list->list_length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
typedef struct command_descriptor {
|
||||
uchar opcode;
|
||||
uchar reserved;
|
||||
unsigned short service_action;
|
||||
uchar reserved2;
|
||||
|
||||
uchar action_valid:1;
|
||||
uchar reserved3:7;
|
||||
|
||||
unsigned short cdb_len;
|
||||
} __attribute__ ((packed)) command_descriptor_t;
|
||||
|
||||
typedef struct report_opcodes_result {
|
||||
unsigned long length;
|
||||
|
||||
command_descriptor_t command[256];
|
||||
} __attribute__ ((packed)) report_opcode_result_t;
|
||||
|
||||
|
||||
#define REPORT_OPCODES 0xa3
|
||||
|
||||
typedef struct report_opcodes_cmd {
|
||||
uchar cmd;
|
||||
uchar reserved[5];
|
||||
unsigned int reply_len;
|
||||
uchar reserved2;
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReportOpcodesCMD_t;
|
||||
|
||||
//ReportOpcodesCMD_t ReportOpcodesCMD = { cmd : REPORT_OPCODES, reply_len: htonl(sizeof(report_opcode_result_t)) };
|
||||
|
||||
int ReportOpCodes(devhandle sgd, report_opcode_result_t *list)
|
||||
{
|
||||
int ret;
|
||||
char sensedat[32];
|
||||
ReportOpcodesCMD_t ReportOpcodesCMD;
|
||||
|
||||
memset (list, 0, sizeof(report_opcode_result_t));
|
||||
ReportOpcodesCMD.cmd = REPORT_OPCODES;
|
||||
ReportOpcodesCMD.reply_len = htonl( sizeof(report_opcode_result_t));
|
||||
|
||||
ret = scsi_command(sgd, (uint8_t *)&ReportOpcodesCMD, sizeof(ReportOpcodesCMD_t), SG_DXFER_FROM_DEV, (uint8_t *)list, sizeof(report_opcode_result_t), sensedat, sizeof(sensedat) );
|
||||
|
||||
if(ret<0) {
|
||||
DPRINTF("Report Luns: IOCTL");
|
||||
}
|
||||
|
||||
list->length = ntohl(list->length);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
#define READ_ATTRIBUTE 0x8c
|
||||
#define VOLUME_LIST 2
|
||||
#define PARTITION_LIST 3
|
||||
|
||||
typedef struct read_attribute_cmd {
|
||||
uchar cmd;
|
||||
|
||||
uchar action:5;
|
||||
uchar res:3;
|
||||
|
||||
uchar restricted[3];
|
||||
|
||||
uchar volume;
|
||||
uchar res2;
|
||||
uchar partition;
|
||||
|
||||
ushort attribute;
|
||||
unsigned int reply_len;
|
||||
uchar res3;
|
||||
uchar control;
|
||||
} __attribute__ ((packed)) ReadAttributeCMD_t;
|
||||
|
||||
int CheckVolumes(devhandle sgd)
|
||||
{
|
||||
int ret;
|
||||
uchar reply[4];
|
||||
uchar sensedat[32];
|
||||
ReadAttributeCMD_t cmd;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
|
||||
cmd.cmd=READ_ATTRIBUTE;
|
||||
cmd.action = VOLUME_LIST;
|
||||
cmd.reply_len = htonl(4);
|
||||
|
||||
ret = scsi_command(sgd, (uint8_t *)&cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("Report Volumes: IOCTL");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(! reply[0] && !reply[1])
|
||||
return(0);
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
int CheckPartitions(devhandle sgd)
|
||||
{
|
||||
int ret;
|
||||
uchar reply[4];
|
||||
uchar sensedat[32];
|
||||
ReadAttributeCMD_t cmd;
|
||||
|
||||
memset(&cmd,0,sizeof(cmd));
|
||||
|
||||
cmd.cmd=READ_ATTRIBUTE;
|
||||
cmd.action = PARTITION_LIST;
|
||||
cmd.reply_len = htonl(4);
|
||||
|
||||
ret = scsi_command(sgd, (uint8_t *)&cmd, sizeof(cmd), SG_DXFER_FROM_DEV, reply, sizeof(reply), sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("Report PARTITIONVolumes: IOCTL");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(! reply[0] && !reply[1])
|
||||
return(0);
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
int UnitReady(devhandle sgd)
|
||||
{
|
||||
uchar cmd[6];
|
||||
uchar sensedat[32];
|
||||
int ret;
|
||||
|
||||
memset(cmd,0,sizeof(cmd));
|
||||
|
||||
ret = scsi_command(sgd, &cmd, sizeof(cmd), SG_DXFER_FROM_DEV, NULL, 0, sensedat, sizeof(sensedat) );
|
||||
if(ret<0) {
|
||||
DPRINTF("UnitReady :");
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef _SCSI_CMDS_H
|
||||
#define _SCSI_CMDS_H
|
||||
|
||||
#define devhandle uint8_t
|
||||
|
||||
#define uchar uint8_t
|
||||
#define ushort uint16_t
|
||||
|
||||
void PrintSense(uchar *sense, int len);
|
||||
int ll_read_block(devhandle sgd, char *buffer, int blocknum, int count);
|
||||
|
||||
int get_capacity(devhandle sgd, unsigned long *block_count, unsigned int *blk_len);
|
||||
int UnitReady(uchar sgd);
|
||||
#endif
|
1143
src/filo/usb/uhci.c
1143
src/filo/usb/uhci.c
File diff suppressed because it is too large
Load Diff
|
@ -1,175 +0,0 @@
|
|||
#ifndef _UHCI_H
|
||||
#define _UHCI_H
|
||||
|
||||
/*
|
||||
* The link pointer is multi use. Some fields are valid only for some uses.
|
||||
* In other cases, they must be 0
|
||||
*
|
||||
*/
|
||||
|
||||
#define MAX_POLLDEV 10
|
||||
|
||||
#define MAX_TRANSACTIONS 10
|
||||
#define MAX_QUEUEHEAD 255
|
||||
#define MAX_TD 1024
|
||||
|
||||
|
||||
typedef struct link_pointer {
|
||||
unsigned long terminate:1;
|
||||
unsigned long queue:1;
|
||||
unsigned long depth:1;
|
||||
unsigned long reserved:1;
|
||||
unsigned long link:28;
|
||||
} __attribute__((packed)) link_pointer_t;
|
||||
|
||||
extern link_pointer_t *frame_list[];
|
||||
|
||||
void init_framelist(uchar dev);
|
||||
|
||||
|
||||
#define SETUP_TOKEN 0x2d
|
||||
#define IN_TOKEN 0x69
|
||||
#define OUT_TOKEN 0xe1
|
||||
|
||||
#define CTRL_RETRIES 3
|
||||
#define CONTROL_STS_RETRIES 0
|
||||
|
||||
|
||||
// some port features
|
||||
#define PORT_CONNECTION 0
|
||||
#define PORT_ENABLE 1
|
||||
#define PORT_SUSPEND 2
|
||||
#define PORT_OVER_CURRENT 3
|
||||
#define PORT_RESET 4
|
||||
#define PORT_POWER 8
|
||||
#define PORT_LOW_SPEED 9
|
||||
#define C_PORT_CONNECTION 16
|
||||
#define C_PORT_ENABLE 17
|
||||
#define C_PORT_SUSPEND 18
|
||||
#define C_PORT_OVER_CURRENT 19
|
||||
#define C_PORT_RESET 20
|
||||
|
||||
// features
|
||||
#define FEATURE_HALT 0
|
||||
|
||||
typedef struct td {
|
||||
|
||||
link_pointer_t link;
|
||||
|
||||
unsigned long actual:11; // actual length
|
||||
unsigned long reserved2:5;
|
||||
|
||||
// status/error flags
|
||||
unsigned long res1:1;
|
||||
unsigned long bitstuff:1;
|
||||
unsigned long crc:1;
|
||||
unsigned long nak:1;
|
||||
unsigned long babble:1;
|
||||
unsigned long buffer_error:1;
|
||||
unsigned long stall:1;
|
||||
unsigned long active:1;
|
||||
|
||||
unsigned long interrupt:1; // interrupt on complete
|
||||
unsigned long isochronous:1;
|
||||
unsigned long lowspeed:1;
|
||||
unsigned long retrys:2;
|
||||
unsigned long detect_short:1;
|
||||
unsigned long reserved3:2;
|
||||
|
||||
unsigned long packet_type:8; // one of in (0x69), out (0xe1) or setup (0x2d)
|
||||
unsigned long device_addr:7;
|
||||
unsigned long endpoint:4;
|
||||
unsigned long data_toggle:1;
|
||||
unsigned long reserved:1;
|
||||
unsigned long max_transfer:11; // misnamed. Desired length might be better
|
||||
|
||||
void *buffer;
|
||||
unsigned long data[4]; // free use by driver
|
||||
} __attribute__((packed)) td_t;
|
||||
|
||||
typedef struct queue_head {
|
||||
link_pointer_t bredth; // depth must = 0
|
||||
link_pointer_t depth; // depth may vary randomly, ignore
|
||||
unsigned long int udata[2];
|
||||
} __attribute__((packed)) queue_head_t;
|
||||
|
||||
typedef struct transaction {
|
||||
queue_head_t *qh;
|
||||
td_t *td_list;
|
||||
struct transaction *next;
|
||||
} transaction_t;
|
||||
|
||||
//#####################################################
|
||||
int wait_head( queue_head_t *head, int count);
|
||||
|
||||
extern queue_head_t *free_qh;
|
||||
extern queue_head_t *queue_heads;
|
||||
|
||||
queue_head_t *new_queue_head(void);
|
||||
void free_queue_head( queue_head_t *qh);
|
||||
void init_qh(void);
|
||||
|
||||
extern td_t *free_td_list;
|
||||
extern td_t *tds;
|
||||
|
||||
void init_td(void);
|
||||
td_t *new_td(void);
|
||||
td_t *find_last_td(td_t *td);
|
||||
void free_td( td_t *td);
|
||||
link_pointer_t *queue_end( queue_head_t *queue);
|
||||
void add_td( queue_head_t *head, td_t *td);
|
||||
|
||||
extern transaction_t transactions[MAX_TRANSACTIONS];
|
||||
extern transaction_t *free_transactions;
|
||||
|
||||
void init_transactions(void);
|
||||
void free_transaction( transaction_t *trans );
|
||||
transaction_t *new_transaction(td_t *td);
|
||||
transaction_t *add_transaction( transaction_t *trans, td_t *td);
|
||||
|
||||
|
||||
#define USBCMD(x) hc_base[x]
|
||||
#define USBSTS(x) (hc_base[x] + 0x02)
|
||||
#define USBINTR(x) (hc_base[x] + 0x04)
|
||||
#define FRNUM(x) ( hc_base[x] + 0x06)
|
||||
#define FLBASE(x) ( hc_base[x] + 0x08)
|
||||
#define SOFMOD(x) ( hc_base[x] + 0x0c)
|
||||
#define PORTSC1(x) ( hc_base[x] + 0x10)
|
||||
#define PORTSC2(x) ( hc_base[x] + 0x12)
|
||||
|
||||
#define USBCMDRUN 0x01
|
||||
#define USBCMD_DEBUG 0x20
|
||||
|
||||
#define USBSTSHALTED 0x20
|
||||
|
||||
|
||||
void hc_reset(uchar dev);
|
||||
int hc_stop(void);
|
||||
int hc_start(uchar dev);
|
||||
|
||||
extern queue_head_t *sched_queue[];
|
||||
|
||||
void init_sched(uchar dev);
|
||||
int poll_queue_head( queue_head_t *qh);
|
||||
int wait_queue_complete( queue_head_t *qh);
|
||||
|
||||
extern int num_polls;
|
||||
extern int (*devpoll[MAX_POLLDEV])(uchar);
|
||||
extern uchar parm[MAX_POLLDEV];
|
||||
|
||||
transaction_t *_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
|
||||
transaction_t *ctrl_msg(uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, uchar *data);
|
||||
int schedule_transaction( uchar dev, transaction_t *trans);
|
||||
int wait_transaction( transaction_t *trans);
|
||||
void unlink_transaction( uchar dev, transaction_t *trans);
|
||||
int uhci_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
|
||||
int uhci_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex, unsigned short wLength, void *data);
|
||||
|
||||
|
||||
// defined in uhci.c
|
||||
int uhc_init(struct pci_device *dev);
|
||||
void uhci_init(void);
|
||||
void clear_uport_stat(unsigned short port);
|
||||
int poll_u_root_hub(unsigned short port, uchar controller);
|
||||
|
||||
#endif
|
|
@ -1,803 +0,0 @@
|
|||
#ifdef USB_DISK
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <etherboot.h>
|
||||
#include <pci.h>
|
||||
#include <timer.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_USB
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTF debug
|
||||
|
||||
|
||||
#include "usb.h"
|
||||
#include "uhci.h"
|
||||
#include "ohci.h"
|
||||
#include "debug_x.h"
|
||||
|
||||
|
||||
#define ALLOCATE 1
|
||||
|
||||
int usec_offset=0;
|
||||
|
||||
int num_controllers=0;
|
||||
|
||||
uint32_t hc_base[MAX_CONTROLLERS];
|
||||
uint8_t hc_type[MAX_CONTROLLERS];
|
||||
|
||||
|
||||
void hci_init(void)
|
||||
{
|
||||
int i;
|
||||
struct pci_device *dev;
|
||||
uint8_t prog_if;
|
||||
|
||||
|
||||
for(i=0;i<MAX_CONTROLLERS; i++) {
|
||||
hc_type[i] = 0xff;
|
||||
}
|
||||
|
||||
/* Find a PCI_SERIAL_USB class device */
|
||||
i=0;
|
||||
num_controllers = 0;
|
||||
while(num_controllers<MAX_CONTROLLERS) {
|
||||
dev = pci_find_device(-1, -1, 0x0c03, -1, i);
|
||||
if(!dev) break;
|
||||
|
||||
prog_if = ((dev->class>>8) & 0xff);
|
||||
if(prog_if == 0x00 ) { // UHCI
|
||||
hc_type[num_controllers] = prog_if;
|
||||
uhc_init(dev);
|
||||
}
|
||||
else if(prog_if == 0x10) { // OHCI
|
||||
hc_type[num_controllers] = prog_if;
|
||||
ohc_init(dev);
|
||||
}
|
||||
#if 0
|
||||
else if(prog_if == 0x20) { // EHCI
|
||||
hc_type[num_controllers] = prog_if;
|
||||
ehc_init(dev);
|
||||
}
|
||||
#endif
|
||||
i++;
|
||||
}
|
||||
// From now should not change num_controllers any more
|
||||
|
||||
uhci_init();
|
||||
ohci_init();
|
||||
}
|
||||
|
||||
|
||||
int next_usb_dev;
|
||||
usbdev_t usb_device[MAX_USB_DEV];
|
||||
|
||||
void init_devices(void)
|
||||
{
|
||||
|
||||
memset(usb_device,0,sizeof(usb_device));
|
||||
usb_device[0].max_packet[0] = 8;
|
||||
next_usb_dev=2; // 0 for all controller root hub, use MAX_CONTROLLERS instead???
|
||||
// do we need have one for every controller ?? or just use hc_base and hc_type instead
|
||||
// For example 0 --> controller 1 root hub
|
||||
// 1 --> controller 2 root hub
|
||||
// 2 --> controller 3 root hub....
|
||||
}
|
||||
|
||||
|
||||
inline int set_address( uchar address)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(0, 0, SET_ADDRESS, address, 0, 0, NULL);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
inline int clear_stall(uchar device, uchar endpoint)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(device, CONTROL_ENDPOINT, CLEAR_FEATURE, FEATURE_HALT, endpoint, 0, NULL);
|
||||
if(hc_type[device]==0x00) {
|
||||
usb_device[device].toggle[endpoint]=0;
|
||||
}
|
||||
else if(hc_type[device]==0x10) {
|
||||
usb_settoggle(&usb_device[device], endpoint & 0xf, ((endpoint & 0x80)>>7)^1, 0);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
inline int device_reset(uchar device) {
|
||||
return usb_control_msg(device, 0x21, 0xff, 0, 0, 0, NULL);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Descriptors
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define STRING_DESCRIPTOR 0x0300
|
||||
|
||||
int get_string( uchar addr, uchar string, int len, uchar *buffer)
|
||||
{
|
||||
int ret;
|
||||
int i,j;
|
||||
int real_len;
|
||||
ushort lang;
|
||||
|
||||
if(!string) {
|
||||
strcpy(buffer, "unknown");
|
||||
return(0);
|
||||
}
|
||||
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, 0, 4, buffer);
|
||||
real_len = buffer[0];
|
||||
if(real_len>len)
|
||||
real_len = len;
|
||||
|
||||
lang = buffer[2] | buffer[3]<<8;
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, lang, real_len, buffer);
|
||||
|
||||
// de-unicode it!
|
||||
for(i=0, j=2; j<real_len; i++, j+=2)
|
||||
buffer[i] = buffer[j];
|
||||
|
||||
buffer[i]=0;
|
||||
real_len/=2;
|
||||
|
||||
return(real_len);
|
||||
}
|
||||
|
||||
int get_string2( uchar addr, uchar string, ushort lang, int len, uchar *buffer)
|
||||
{
|
||||
int ret;
|
||||
int i,j;
|
||||
int real_len;
|
||||
|
||||
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, lang, len, buffer);
|
||||
|
||||
real_len = buffer[0];
|
||||
if(real_len>len)
|
||||
real_len = len;
|
||||
|
||||
if(real_len<=4) {
|
||||
strcpy(buffer, "USB");
|
||||
real_len = 3;
|
||||
buffer[real_len] = 0;
|
||||
} else {
|
||||
// de-unicode it!
|
||||
for(i=0, j=2; j<real_len; i++, j+=2)
|
||||
buffer[i] = buffer[j];
|
||||
|
||||
buffer[i]=0;
|
||||
real_len/=2;
|
||||
}
|
||||
|
||||
return(real_len);
|
||||
}
|
||||
ushort get_lang( uchar addr, uchar string, int len, uchar *buffer)
|
||||
{
|
||||
int ret;
|
||||
int i,j;
|
||||
int real_len;
|
||||
ushort lang;
|
||||
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, STRING_DESCRIPTOR | string, 0, 4, buffer);
|
||||
lang = buffer[2] | buffer[3]<<8;
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HUB functions. This will be moved to it's own module soonishly
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct port_charge {
|
||||
ushort c_port_connection:1;
|
||||
ushort c_port_enable:1;
|
||||
ushort c_port_suspend:1;
|
||||
ushort c_port_over_current:1;
|
||||
ushort c_port_reset:1;
|
||||
ushort reserved:11;
|
||||
} port_change_t;
|
||||
|
||||
typedef struct port_status {
|
||||
ushort port_connection:1;
|
||||
ushort port_enable:1;
|
||||
ushort port_suspend:1;
|
||||
ushort port_over_current:1;
|
||||
ushort port_reset:1;
|
||||
ushort reserved:3;
|
||||
ushort port_power:1;
|
||||
ushort port_lowspeed:1;
|
||||
ushort port_highspeed:1;
|
||||
ushort port_test:1;
|
||||
ushort port_indicator:1;
|
||||
} __attribute__ ((packed)) portstatus_t;
|
||||
|
||||
|
||||
typedef struct portstat {
|
||||
portstatus_t stat;
|
||||
port_change_t change;
|
||||
} __attribute__ ((packed)) portstat_t;
|
||||
|
||||
int hub_port_reset( uchar addr, uchar port)
|
||||
{
|
||||
int ret;
|
||||
int tries=100;
|
||||
portstat_t status;
|
||||
|
||||
ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_RESET, port, 0, NULL); // reset port
|
||||
|
||||
while(tries--) {
|
||||
udelay(10000);
|
||||
ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, port, 4, &status);
|
||||
if(!status.change.c_port_reset)
|
||||
continue;
|
||||
|
||||
ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, C_PORT_RESET, port, 0, NULL); // clear status
|
||||
return(0);
|
||||
}
|
||||
|
||||
DPRINTF("hub_port_reset(%x, %x) failed,\n", addr, port);
|
||||
dump_hex((uint8_t *)&status, 4, "status=");
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int hub_port_resume( uchar addr, uchar port)
|
||||
{
|
||||
int ret;
|
||||
int tries=100;
|
||||
portstat_t status;
|
||||
|
||||
ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, PORT_SUSPEND, port, 0, NULL); // reset port
|
||||
|
||||
while(tries--) {
|
||||
udelay(10000);
|
||||
ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, port, 4, &status);
|
||||
if(!status.change.c_port_suspend)
|
||||
continue;
|
||||
|
||||
ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, C_PORT_SUSPEND, port, 0, NULL); // clear status
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int poll_hub(uchar addr)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
uchar devaddr=0;
|
||||
hub_descriptor_t *desc;
|
||||
portstat_t status;
|
||||
|
||||
DPRINTF("Poll hub (%x)\n", addr);
|
||||
desc = usb_device[addr].private;
|
||||
|
||||
for(i=1; i<= desc->bNbrPorts; i++) {
|
||||
ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, i, 4, &status);
|
||||
// DPRINTF("Get status for port %u returns: %d\n", i, ret);
|
||||
// dump_hex(&status, 4, "status=");
|
||||
|
||||
if(status.change.c_port_connection) {
|
||||
ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, C_PORT_CONNECTION, i, 0, NULL); // clear status
|
||||
|
||||
if(status.stat.port_connection) {
|
||||
udelay(desc->bPwrOn2PwrGood * 20000);
|
||||
|
||||
hub_port_resume(addr, i);
|
||||
|
||||
ret = hub_port_reset(addr,i);
|
||||
udelay(10);
|
||||
ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_ENABLE, i, 0, NULL); // enable port
|
||||
|
||||
// ret = usb_control_msg(addr, 0xa3, GET_STATUS, 0x0, i, 4, &status);
|
||||
// DPRINTF("*****Get status again for port %u returns: %d\n", i, ret);
|
||||
// dump_hex(&status, 4, "status=");
|
||||
|
||||
devaddr = configure_device(i, usb_device[addr].controller, status.stat.port_lowspeed);
|
||||
|
||||
// configure
|
||||
} else {
|
||||
ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_SUSPEND, i, 0, NULL); // suspend port
|
||||
ret = usb_control_msg(addr, 0x23, CLEAR_FEATURE, PORT_ENABLE, i, 0, NULL); // disable port
|
||||
DPRINTF("Hub %d, Port %04x disconnected\n", addr, i);
|
||||
// deconfigure
|
||||
}
|
||||
}
|
||||
}
|
||||
return(devaddr);
|
||||
|
||||
}
|
||||
|
||||
int usb_hub_init( uchar addr)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
hub_descriptor_t *desc;
|
||||
|
||||
desc = allot(sizeof(hub_descriptor_t));
|
||||
|
||||
memset(desc, 0 , sizeof(hub_descriptor_t));
|
||||
|
||||
DPRINTF("hub init (%d)\n", addr);
|
||||
|
||||
ret = usb_control_msg(addr, 0xa0, GET_DESCRIPTOR, 0x2900, 0, 8, desc);
|
||||
ret = usb_control_msg(addr, 0xa0, GET_DESCRIPTOR, 0x2900, 0, desc->bLength, desc);
|
||||
|
||||
usb_device[addr].private = desc;
|
||||
|
||||
for(i=1; i<=desc->bNbrPorts; i++)
|
||||
ret = usb_control_msg(addr, 0x23, SET_FEATURE, PORT_POWER, i, 0, NULL); // power port
|
||||
|
||||
|
||||
// register hub to be polled
|
||||
|
||||
devpoll[num_polls] = poll_hub;
|
||||
parm[num_polls++] = addr;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
extern void ohci_dump_x(uchar controller);
|
||||
|
||||
// will set up whatever device is answering at address 0.
|
||||
int configure_device(uint32_t port, uchar controller, unsigned int lowspeed)
|
||||
{
|
||||
device_descriptor_t *desc;
|
||||
config_descriptor_t *conf;
|
||||
interface_descriptor_t *iface;
|
||||
endpoint_descriptor_t *epd;
|
||||
int ret;
|
||||
int i;
|
||||
int addr = next_usb_dev++;
|
||||
uchar buffer[512];
|
||||
uchar string[255];
|
||||
ushort lang;
|
||||
uchar x[2];
|
||||
|
||||
desc = (device_descriptor_t *) buffer;
|
||||
|
||||
memset( &usb_device[addr], 0, sizeof(usbdev_t));
|
||||
|
||||
printf("New USB device, setting address %d\n", addr);
|
||||
if(lowspeed) {
|
||||
usb_device[addr].lowspeed = usb_device[0].lowspeed = 1;
|
||||
DPRINTF("LOWSPEED\n");
|
||||
} else
|
||||
usb_device[addr].lowspeed = usb_device[0].lowspeed = 0;
|
||||
|
||||
usb_device[0].port = usb_device[addr].port = port;
|
||||
usb_device[0].controller = usb_device[addr].controller = controller;
|
||||
usb_device[addr].toggle2[0]=0;
|
||||
usb_device[addr].toggle2[1]=0;
|
||||
|
||||
// hc_clear_stat();
|
||||
|
||||
ret = set_address(addr);
|
||||
if(ret<0) {
|
||||
DPRINTF("configure_device: set_address failed!\n");
|
||||
next_usb_dev--;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
mdelay(10); /* Let the SET_ADDRESS settle */
|
||||
|
||||
usb_device[addr].max_packet[0] = 8;
|
||||
|
||||
|
||||
DPRINTF("Fetching device descriptor length\n");
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x100, 0, 8, desc);
|
||||
|
||||
usb_device[addr].max_packet[0] = desc->max_packet;
|
||||
|
||||
DPRINTF("Fetching device descriptor\n");
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x100, 0, desc->bLength, desc);
|
||||
if(ret < desc->bLength)
|
||||
return(-1);
|
||||
|
||||
DPRINTF("Fetching config descriptor length\n");
|
||||
conf = (config_descriptor_t *) (buffer + sizeof(device_descriptor_t));
|
||||
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x200, 0, 8, conf);
|
||||
|
||||
DPRINTF("Fetching config descriptor\n");
|
||||
ret = usb_control_msg(addr, 0x80, GET_DESCRIPTOR, 0x200, 0, conf->wTotalLength, conf);
|
||||
if(ret < conf->wTotalLength)
|
||||
return(-1);
|
||||
|
||||
iface = (interface_descriptor_t *) (buffer + sizeof(device_descriptor_t) + conf->bLength);
|
||||
epd = (endpoint_descriptor_t *) (buffer + conf->bLength + iface->bLength + sizeof(device_descriptor_t));
|
||||
|
||||
DPRINTF("device:\n");
|
||||
dump_device_descriptor( desc, "");
|
||||
DPRINTF("config:\n");
|
||||
dump_config_descriptor( (uchar *)conf, "");
|
||||
|
||||
DPRINTF("Selecting Configuration number %x:\n", conf->bConfigurationValue);
|
||||
ret = usb_control_msg(addr, 0, SET_CONFIGURATION, conf->bConfigurationValue, 0, 0, NULL);
|
||||
|
||||
// mdelay(20);
|
||||
|
||||
#if 0
|
||||
usb_control_msg(addr, 0x80, GET_CONFIGURATION, 0, 0, 1 , x);
|
||||
DPRINTF("Configuration number = %x\n", x[0]);
|
||||
|
||||
usb_control_msg(addr, 0x80, GET_STATUS, 0, addr, 2, x);
|
||||
DPRINTF("status = %x %x\n", x[0], x[1]);
|
||||
|
||||
usb_control_msg(addr, 0x81, GET_STATUS, 0, 0, 2, x);
|
||||
DPRINTF("status = %x %x\n", x[0], x[1]);
|
||||
#endif
|
||||
|
||||
for(i=0; i<iface->bNumEndpoints;i++) {
|
||||
if(!epd[i].bEndpointAddress) {
|
||||
usb_device[addr].max_packet[ 1 ] = epd[i].wMaxPacketSize & 0x3ff;
|
||||
} else {
|
||||
usb_device[addr].max_packet[ epd[i].bEndpointAddress & 0x7f ] = epd[i].wMaxPacketSize & 0x3ff;
|
||||
}
|
||||
|
||||
if( (epd[i].bmAttributes & 0x03) == 0x01) // interrupt
|
||||
usb_device[addr].interrupt = epd[i].bEndpointAddress;
|
||||
|
||||
if( (epd[i].bmAttributes & 0x03) == 0x02) { // bulk
|
||||
#if 0
|
||||
DPRINTF("clear stall on ep=%x\n", epd[i].bEndpointAddress);
|
||||
clear_stall(addr, epd[i].bEndpointAddress); // to reset data toggle
|
||||
udelay(10);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
usb_control_msg(addr, 0x82, GET_STATUS, 0, epd[i].bEndpointAddress, 2, x);
|
||||
DPRINTF("status = %x %x\n", x[0], x[1]);
|
||||
#endif
|
||||
|
||||
if(epd[i].bEndpointAddress & 0x80){ //in
|
||||
usb_device[addr].bulk_in = epd[i].bEndpointAddress;
|
||||
}
|
||||
else { //out
|
||||
usb_device[addr].bulk_out = epd[i].bEndpointAddress;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// determine device class
|
||||
if(desc->Class) {
|
||||
usb_device[addr].class = desc->Class;
|
||||
usb_device[addr].subclass = desc->SubClass;
|
||||
usb_device[addr].protocol = desc->protocol;
|
||||
} else {
|
||||
usb_device[addr].class = iface->bInterfaceClass;
|
||||
usb_device[addr].subclass = iface->bInterfaceSubClass;
|
||||
usb_device[addr].protocol = iface->bInterfaceProtocol;
|
||||
}
|
||||
|
||||
printf("%02x:%02x:%02x\n", usb_device[addr].class, usb_device[addr].subclass, usb_device[addr].protocol);
|
||||
#if 0
|
||||
get_string(addr, desc->iManufacturor, sizeof(string), string);
|
||||
printf("Manufacturor: %s\n", string);
|
||||
|
||||
get_string(addr, desc->iProduct, sizeof(string), string);
|
||||
printf("Product: %s\n", string);
|
||||
|
||||
get_string(addr, desc->iSerial, sizeof(string), string);
|
||||
printf("Serial: %s\n", string);
|
||||
#else
|
||||
lang = get_lang(addr, 0, sizeof(string), string);
|
||||
|
||||
get_string2(addr, desc->iManufacturor, lang, sizeof(string), string);
|
||||
printf("Manufacturor: %s\n", string);
|
||||
|
||||
get_string2(addr, desc->iProduct, lang,sizeof(string), string);
|
||||
printf("Product: %s\n", string);
|
||||
|
||||
get_string2(addr, desc->iSerial, lang, sizeof(string), string);
|
||||
printf("Serial: %s\n", string);
|
||||
#endif
|
||||
|
||||
switch( usb_device[addr].class) {
|
||||
case 0x09: // hub
|
||||
usb_hub_init(addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
DPRINTF("DEVICE CONFIGURED\n");
|
||||
|
||||
return(addr);
|
||||
}
|
||||
|
||||
int num_polls=0;
|
||||
int (*devpoll[MAX_POLLDEV])(uchar);
|
||||
uchar parm[MAX_POLLDEV];
|
||||
|
||||
int poll_usb()
|
||||
{
|
||||
int addr;
|
||||
int found=0;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for(i=0; i<num_controllers; i++) {
|
||||
debug("poll_usb1 i=%d\t", i);
|
||||
// if addr >0, should probably see what was attached!
|
||||
if(hc_type[i]==0x00) {
|
||||
addr = poll_u_root_hub(PORTSC1(i), i);
|
||||
if(addr && !found)
|
||||
found=addr;
|
||||
|
||||
addr = poll_u_root_hub(PORTSC2(i), i);
|
||||
if(addr && !found)
|
||||
found=addr;
|
||||
}
|
||||
|
||||
else if(hc_type[i]==0x10) {
|
||||
int NDP;
|
||||
NDP = readl(&ohci_regs->roothub.a) & 0xff;
|
||||
ohci_regs = (ohci_regs_t *)hc_base[i];
|
||||
for(j=0;j<NDP;j++) {
|
||||
addr = poll_o_root_hub((uint32_t)&ohci_regs->roothub.portstatus[j], i);
|
||||
if(addr && !found)
|
||||
found=addr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// now poll registered drivers (such as the hub driver
|
||||
for(i=0;i<num_polls; i++) {
|
||||
debug("poll_usb2 i=%d\t", i);
|
||||
addr = devpoll[i](parm[i]);
|
||||
if(addr && !found)
|
||||
found=addr;
|
||||
}
|
||||
|
||||
return(found);
|
||||
}
|
||||
|
||||
|
||||
int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data)
|
||||
{
|
||||
uint8_t hc_num = usb_device[devnum].controller;
|
||||
if(ep&0x80) {
|
||||
ep = usb_device[devnum].bulk_in;
|
||||
} else {
|
||||
ep = usb_device[devnum].bulk_out;
|
||||
}
|
||||
|
||||
if(hc_type[hc_num] == 0x00) { //UHCI
|
||||
return uhci_bulk_transfer(devnum, ep, len, data);
|
||||
}
|
||||
else if( hc_type[hc_num] == 0x10 ) { //OHCI
|
||||
return ohci_bulk_transfer(devnum, ep, len, data);
|
||||
}
|
||||
#if 0
|
||||
else if (hc_type[hc_num] == 0x20 ) { //EHCI
|
||||
return ehci_bulk_transfer(devnum, ep, len, data);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
int usb_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex,
|
||||
unsigned short wLength, void *data)
|
||||
{
|
||||
|
||||
uint8_t hc_num = usb_device[devnum].controller;
|
||||
|
||||
if(hc_type[hc_num] == 0x00) { //UHCI
|
||||
return uhci_control_msg(devnum, request_type, request, wValue, wIndex, wLength, data);
|
||||
}
|
||||
else if( hc_type[hc_num] == 0x10 ) { //OHCI
|
||||
return ohci_control_msg(devnum, request_type, request, wValue, wIndex, wLength, data);
|
||||
}
|
||||
#if 0
|
||||
else if (hc_type[hc_num] == 0x20 ) { //EHCI
|
||||
return ehci_control_msg(devnum, request_type, request, wValue, wIndex, wLength, data);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct urb *usb_alloc_urb(int controller)
|
||||
{
|
||||
struct urb *urb;
|
||||
ohci_t *ohci = NULL;
|
||||
#if URB_PRE_ALLOCATE!=1
|
||||
urb = (struct urb *)allot2(sizeof(struct urb),0xff);
|
||||
if (!urb) {
|
||||
printf("usb_alloc_urb: allot2 failed");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if(hc_type[controller] == 0x10) { //OHCI
|
||||
ohci = &_ohci_x[controller];
|
||||
urb = ohci->urb;
|
||||
} else {
|
||||
urb = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(urb, 0, sizeof(*urb));
|
||||
|
||||
return urb;
|
||||
}
|
||||
/**
|
||||
* usb_free_urb - frees the memory used by a urb
|
||||
* @urb: pointer to the urb to free
|
||||
*
|
||||
* If an urb is created with a call to usb_create_urb() it should be
|
||||
* cleaned up with a call to usb_free_urb() when the driver is finished
|
||||
* with it.
|
||||
*/
|
||||
void usb_free_urb(struct urb* urb)
|
||||
{
|
||||
#if URB_PRE_ALLOCATE!=1
|
||||
if (urb)
|
||||
forget2(urb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usb_wait_urb_done(struct urb* urb, int timeout)
|
||||
{
|
||||
usbdev_t *usb_dev = urb->dev;
|
||||
if(hc_type[usb_dev->controller]==0x10) {
|
||||
ohci_wait_urb_done(urb, timeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int usb_submit_urb(struct urb *urb)
|
||||
{
|
||||
if (urb && urb->dev) {
|
||||
#if 0
|
||||
if(hc_type[urb->dev->controller] == 0x00) {
|
||||
return uhci_submit_urb(urb);
|
||||
} else
|
||||
#endif
|
||||
if(hc_type[urb->dev->controller] == 0x10) {
|
||||
return ohci_submit_urb(urb);
|
||||
}
|
||||
#if 0
|
||||
else if(hc_type[urb->dev->controller] == 0x20) {
|
||||
return ohci_submit_urb(urb);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
// Starts urb and waits for completion or timeout
|
||||
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
|
||||
{
|
||||
int status;
|
||||
status = usb_submit_urb(urb);
|
||||
|
||||
//for OHCI We will check the BLF and CLF, because HC after processing all td list, it will clear the BLF and CLF
|
||||
usb_wait_urb_done(urb, timeout);
|
||||
//Add by LYH to call complete function
|
||||
if(urb->complete!=0) urb->complete(urb);
|
||||
|
||||
if (actual_length)
|
||||
*actual_length = urb->actual_length;
|
||||
|
||||
usb_free_urb(urb);
|
||||
return status;
|
||||
}
|
||||
// returns status (negative) or length (positive)
|
||||
int usb_internal_control_msg(struct usbdev *usb_dev, unsigned int pipe,
|
||||
struct usb_ctrlrequest *cmd, void *data, int len, int timeout, usb_complete_t complete)
|
||||
{
|
||||
struct urb *urb;
|
||||
int retv;
|
||||
int length;
|
||||
|
||||
urb = usb_alloc_urb(usb_dev->controller);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
|
||||
complete,0);
|
||||
|
||||
retv = usb_start_wait_urb(urb, timeout, &length);
|
||||
if (retv < 0)
|
||||
return retv;
|
||||
else
|
||||
return length;
|
||||
}
|
||||
int usb_control_msg_x(struct usbdev *dev, unsigned int pipe, u8 request, u8 requesttype,
|
||||
u16 value, u16 index, void *data, u16 size, int timeout, usb_complete_t complete)
|
||||
{
|
||||
struct usb_ctrlrequest *dr;
|
||||
int ret;
|
||||
int controller = dev->controller;
|
||||
ohci_t *ohci;
|
||||
|
||||
#if URB_PRE_ALLOCATE!=1
|
||||
dr = allot2(sizeof(struct usb_ctrlrequest), 0xf);
|
||||
if (!dr) {
|
||||
printf("usb_control_msg_x: dr allocate no MEM\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else
|
||||
if(hc_type[controller] == 0x10) { //OHCI
|
||||
ohci = &_ohci_x[controller];
|
||||
dr = ohci->dr;
|
||||
} else {
|
||||
dr = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
dr->bRequestType = requesttype;
|
||||
dr->bRequest = request;
|
||||
dr->wValue = cpu_to_le16p(&value);
|
||||
dr->wIndex = cpu_to_le16p(&index);
|
||||
dr->wLength = cpu_to_le16p(&size);
|
||||
|
||||
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout, complete);
|
||||
|
||||
#if URB_PRE_ALLOCATE!=1
|
||||
forget2(dr);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
int usb_bulk_msg_x(struct usbdev *usb_dev, unsigned int pipe,
|
||||
void *data, int len, int *actual_length, int timeout, usb_complete_t complete)
|
||||
{
|
||||
struct urb *urb;
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
urb=usb_alloc_urb(usb_dev->controller);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
|
||||
FILL_BULK_URB(urb, usb_dev, pipe, data, len,
|
||||
complete, 0);
|
||||
|
||||
return usb_start_wait_urb(urb,timeout,actual_length);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,435 +0,0 @@
|
|||
#ifndef _USB_H
|
||||
#define _USB_H
|
||||
|
||||
#define URB_PRE_ALLOCATE 1
|
||||
|
||||
#define u32 uint32_t
|
||||
#define u16 uint16_t
|
||||
#define u8 uint8_t
|
||||
|
||||
#define uchar uint8_t
|
||||
#define ushort uint16_t
|
||||
#define EBUSY 1
|
||||
#define ENOMEM 12
|
||||
#define ENODEV 19
|
||||
#define EINVAL 22
|
||||
#define EINPROGRESS 115
|
||||
|
||||
#define LINK_ADDR(x) ( virt_to_bus(x) >> 4)
|
||||
#define MEM_ADDR(x) (void *) ( bus_to_virt( ((unsigned int) (x)) <<4) )
|
||||
|
||||
#define MAX_CONTROLLERS 4
|
||||
|
||||
extern int num_controllers;
|
||||
|
||||
extern uint32_t hc_base[];
|
||||
extern uint8_t hc_type[];
|
||||
|
||||
// Some control message bmRequestType defines
|
||||
#define CTRL_DEVICE 0
|
||||
#define CONTROL_INTERFACE 1
|
||||
#define CONTROL_ENDPOINT 2
|
||||
#define CONTROL_OTHER 3
|
||||
#define CONTROL_RECIPIENT_MASK 0x1f
|
||||
|
||||
#define CONTROL_TYPE_STD 0
|
||||
#define CONTROL_TYPE_CLASS 0x20
|
||||
#define CONTROL_CLASS_VENDOR 0x40
|
||||
#define CONTROL_CLASS_MASK 0x60
|
||||
|
||||
#define CONTROL_OUT 0
|
||||
#define CONTROL_IN 0x80
|
||||
#define CONTROL_DIR_MASK 0x80
|
||||
|
||||
// bRequest values
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
#define SYNC_FRAME 12
|
||||
|
||||
// descriptor types
|
||||
#define DEVICE_DESC 1
|
||||
#define CONFIGURATION_DESC 2
|
||||
#define STRING_DESC 3
|
||||
#define INTERFACE_DESC 4
|
||||
#define ENDPOINT_DESC 5
|
||||
#define OTHERSPEED_DESC 7
|
||||
#define POWER_DESC 8
|
||||
|
||||
|
||||
typedef struct device_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bcdVersion[2];
|
||||
uchar Class;
|
||||
uchar SubClass;
|
||||
uchar protocol;
|
||||
uchar max_packet;
|
||||
|
||||
unsigned short idVendor;
|
||||
unsigned short idProduct;
|
||||
|
||||
uchar bcdDevice[2];
|
||||
uchar iManufacturor;
|
||||
uchar iProduct;
|
||||
uchar iSerial;
|
||||
uchar bNumConfig;
|
||||
} __attribute__((packed)) device_descriptor_t;
|
||||
|
||||
#define GET_DESCRIPTOR 6
|
||||
|
||||
typedef struct config_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
unsigned short wTotalLength;
|
||||
uchar bNumInterfaces;
|
||||
uchar bConfigurationValue;
|
||||
uchar iConfiguration;
|
||||
|
||||
uchar bmAttributes;
|
||||
uchar bMaxPower;
|
||||
} __attribute__((packed)) config_descriptor_t;
|
||||
|
||||
typedef struct interface_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bInterfaceNumber;
|
||||
uchar bAlternateSetting;
|
||||
|
||||
uchar bNumEndpoints;
|
||||
uchar bInterfaceClass;
|
||||
uchar bInterfaceSubClass;
|
||||
uchar bInterfaceProtocol;
|
||||
uchar iInterface;
|
||||
} __attribute__((packed)) interface_descriptor_t;
|
||||
|
||||
typedef struct endpoint_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bEndpointAddress;
|
||||
uchar bmAttributes;
|
||||
unsigned short wMaxPacketSize;
|
||||
uchar bInterval;
|
||||
} __attribute__((packed)) endpoint_descriptor_t;
|
||||
|
||||
typedef struct ctrl_msg {
|
||||
uchar bmRequestType;
|
||||
uchar bRequest;
|
||||
unsigned short wValue;
|
||||
unsigned short wIndex;
|
||||
unsigned short wLength;
|
||||
} __attribute__((packed)) ctrl_msg_t;
|
||||
|
||||
// Some descriptors for hubs, will be moved later
|
||||
typedef struct hub_descriptor {
|
||||
uchar bLength;
|
||||
uchar type;
|
||||
|
||||
uchar bNbrPorts;
|
||||
ushort wHubCharacteristics;
|
||||
uchar bPwrOn2PwrGood;
|
||||
uchar bHubCntrCurrent;
|
||||
|
||||
uchar DeviceRemovable; // assume bNbrPorts <=8
|
||||
uchar PortPwrCntrMask;
|
||||
} __attribute__((packed)) hub_descriptor_t;
|
||||
|
||||
#define MAX_USB_DEV 127
|
||||
#define MAX_EP 8
|
||||
|
||||
typedef struct usbdev {
|
||||
uint32_t port;
|
||||
uchar address;
|
||||
uchar controller;
|
||||
uchar class;
|
||||
uchar subclass;
|
||||
uchar protocol;
|
||||
uchar bulk_in;
|
||||
uchar bulk_out;
|
||||
uchar interrupt;
|
||||
uchar lowspeed;
|
||||
uint32_t toggle2[2]; //For OHCI
|
||||
uint32_t halted[2];
|
||||
uchar toggle[MAX_EP]; //for UHCI
|
||||
unsigned short max_packet[MAX_EP];
|
||||
void *private;
|
||||
} usbdev_t;
|
||||
|
||||
// I will use urb as transaction for OHCI to remember the td and ed
|
||||
|
||||
struct urb;
|
||||
typedef void (*usb_complete_t)(struct urb *);
|
||||
|
||||
struct urb
|
||||
{
|
||||
#if 0
|
||||
spinlock_t lock; // lock for the URB
|
||||
#endif
|
||||
void *hcpriv; // private data for host controller
|
||||
#if 0
|
||||
struct list_head urb_list; // list pointer to all active urbs
|
||||
struct urb *next; // pointer to next URB
|
||||
#endif
|
||||
struct usbdev *dev; // pointer to associated USB device
|
||||
unsigned int pipe; // pipe information
|
||||
int status; // returned status
|
||||
unsigned int transfer_flags; // USB_DISABLE_SPD | USB_ISO_ASAP | etc.
|
||||
void *transfer_buffer; // associated data buffer
|
||||
void *transfer_dma; // dma addr for transfer_buffer
|
||||
int transfer_buffer_length; // data buffer length
|
||||
int actual_length; // actual data buffer length
|
||||
int bandwidth; // bandwidth for this transfer request (INT or ISO)
|
||||
unsigned char *setup_packet; // setup packet (control only)
|
||||
void * setup_dma; // dma addr for setup_packet
|
||||
//
|
||||
int start_frame; // start frame (iso/irq only)
|
||||
int number_of_packets; // number of packets in this request (iso)
|
||||
int interval; // polling interval (irq only)
|
||||
int error_count; // number of errors in this transfer (iso only)
|
||||
int timeout; // timeout (in jiffies)
|
||||
//
|
||||
void *context; // context for completion routine
|
||||
usb_complete_t complete; // pointer to completion routine
|
||||
//
|
||||
#if 0
|
||||
struct iso_packet_descriptor iso_frame_desc[0];
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct urb urb_t;
|
||||
|
||||
/*
|
||||
* urb->transfer_flags:
|
||||
*/
|
||||
#define USB_DISABLE_SPD 0x0001
|
||||
#define URB_SHORT_NOT_OK USB_DISABLE_SPD
|
||||
#define USB_ISO_ASAP 0x0002
|
||||
#define USB_ASYNC_UNLINK 0x0008
|
||||
#define USB_QUEUE_BULK 0x0010
|
||||
#define USB_NO_FSBR 0x0020
|
||||
#define USB_ZERO_PACKET 0x0040 // Finish bulk OUTs always with zero length packet
|
||||
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
|
||||
/* ... less overhead for QUEUE_BULK */
|
||||
#define USB_TIMEOUT_KILLED 0x1000 // only set by HCD!
|
||||
|
||||
|
||||
struct usb_ctrlrequest {
|
||||
u8 bRequestType;
|
||||
u8 bRequest;
|
||||
u16 wValue;
|
||||
u16 wIndex;
|
||||
u16 wLength;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* USB-status codes:
|
||||
* USB_ST* maps to -E* and should go away in the future
|
||||
*/
|
||||
|
||||
#define USB_ST_NOERROR 0
|
||||
#define USB_ST_CRC (-EILSEQ)
|
||||
#define USB_ST_BITSTUFF (-EPROTO)
|
||||
#define USB_ST_NORESPONSE (-ETIMEDOUT) /* device not responding/handshaking */
|
||||
#define USB_ST_DATAOVERRUN (-EOVERFLOW)
|
||||
#define USB_ST_DATAUNDERRUN (-EREMOTEIO)
|
||||
#define USB_ST_BUFFEROVERRUN (-ECOMM)
|
||||
#define USB_ST_BUFFERUNDERRUN (-ENOSR)
|
||||
#define USB_ST_INTERNALERROR (-EPROTO) /* unknown error */
|
||||
#define USB_ST_SHORT_PACKET (-EREMOTEIO)
|
||||
#define USB_ST_PARTIAL_ERROR (-EXDEV) /* ISO transfer only partially completed */
|
||||
#define USB_ST_URB_KILLED (-ENOENT) /* URB canceled by user */
|
||||
#define USB_ST_URB_PENDING (-EINPROGRESS)
|
||||
#define USB_ST_REMOVED (-ENODEV) /* device not existing or removed */
|
||||
#define USB_ST_TIMEOUT (-ETIMEDOUT) /* communication timed out, also in urb->status**/
|
||||
#define USB_ST_NOTSUPPORTED (-ENOSYS)
|
||||
#define USB_ST_BANDWIDTH_ERROR (-ENOSPC) /* too much bandwidth used */
|
||||
#define USB_ST_URB_INVALID_ERROR (-EINVAL) /* invalid value/transfer type */
|
||||
#define USB_ST_URB_REQUEST_ERROR (-ENXIO) /* invalid endpoint */
|
||||
#define USB_ST_STALL (-EPIPE) /* pipe stalled, also in urb->status*/
|
||||
|
||||
/**
|
||||
* FILL_CONTROL_URB - macro to help initialize a control urb
|
||||
* @URB: pointer to the urb to initialize.
|
||||
* @DEV: pointer to the struct usb_device for this urb.
|
||||
* @PIPE: the endpoint pipe
|
||||
* @SETUP_PACKET: pointer to the setup_packet buffer
|
||||
* @TRANSFER_BUFFER: pointer to the transfer buffer
|
||||
* @BUFFER_LENGTH: length of the transfer buffer
|
||||
* @COMPLETE: pointer to the usb_complete_t function
|
||||
* @CONTEXT: what to set the urb context to.
|
||||
*
|
||||
* Initializes a control urb with the proper information needed to submit
|
||||
* it to a device. This macro is depreciated, the usb_fill_control_urb()
|
||||
* function should be used instead.
|
||||
*/
|
||||
#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
|
||||
do {\
|
||||
(URB)->dev=DEV;\
|
||||
(URB)->pipe=PIPE;\
|
||||
(URB)->setup_packet=SETUP_PACKET;\
|
||||
(URB)->transfer_buffer=TRANSFER_BUFFER;\
|
||||
(URB)->transfer_buffer_length=BUFFER_LENGTH;\
|
||||
(URB)->complete=COMPLETE;\
|
||||
(URB)->context=CONTEXT;\
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* FILL_BULK_URB - macro to help initialize a bulk urb
|
||||
* @URB: pointer to the urb to initialize.
|
||||
* @DEV: pointer to the struct usb_device for this urb.
|
||||
* @PIPE: the endpoint pipe
|
||||
* @TRANSFER_BUFFER: pointer to the transfer buffer
|
||||
* @BUFFER_LENGTH: length of the transfer buffer
|
||||
* @COMPLETE: pointer to the usb_complete_t function
|
||||
* @CONTEXT: what to set the urb context to.
|
||||
*
|
||||
* Initializes a bulk urb with the proper information needed to submit it
|
||||
* to a device. This macro is depreciated, the usb_fill_bulk_urb()
|
||||
* function should be used instead.
|
||||
*/
|
||||
#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
|
||||
do {\
|
||||
(URB)->dev=DEV;\
|
||||
(URB)->pipe=PIPE;\
|
||||
(URB)->transfer_buffer=TRANSFER_BUFFER;\
|
||||
(URB)->transfer_buffer_length=BUFFER_LENGTH;\
|
||||
(URB)->complete=COMPLETE;\
|
||||
(URB)->context=CONTEXT;\
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* USB directions
|
||||
*/
|
||||
#define USB_DIR_OUT 0 /* to device */
|
||||
#define USB_DIR_IN 0x80 /* to host */
|
||||
|
||||
/*
|
||||
* USB Packet IDs (PIDs)
|
||||
*/
|
||||
#define USB_PID_UNDEF_0 0xf0
|
||||
#define USB_PID_OUT 0xe1
|
||||
#define USB_PID_ACK 0xd2
|
||||
#define USB_PID_DATA0 0xc3
|
||||
#define USB_PID_PING 0xb4 /* USB 2.0 */
|
||||
#define USB_PID_SOF 0xa5
|
||||
#define USB_PID_NYET 0x96 /* USB 2.0 */
|
||||
#define USB_PID_DATA2 0x87 /* USB 2.0 */
|
||||
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
|
||||
#define USB_PID_IN 0x69
|
||||
#define USB_PID_NAK 0x5a
|
||||
#define USB_PID_DATA1 0x4b
|
||||
#define USB_PID_PREAMBLE 0x3c /* Token mode */
|
||||
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
|
||||
#define USB_PID_SETUP 0x2d
|
||||
#define USB_PID_STALL 0x1e
|
||||
#define USB_PID_MDATA 0x0f /* USB 2.0 */
|
||||
|
||||
#define PIPE_ISOCHRONOUS 0
|
||||
#define PIPE_INTERRUPT 1
|
||||
#define PIPE_CONTROL 2
|
||||
#define PIPE_BULK 3
|
||||
|
||||
#define usb_maxpacket(dev, pipe, out) ((dev)->max_packet[usb_pipeendpoint(pipe)])
|
||||
#define usb_packetid(pipe) (((pipe) & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT)
|
||||
|
||||
#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1)
|
||||
#define usb_pipein(pipe) (((pipe) >> 7) & 1)
|
||||
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
|
||||
#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
|
||||
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
|
||||
#define usb_pipedata(pipe) (((pipe) >> 19) & 1)
|
||||
#define usb_pipeslow(pipe) (((pipe) >> 26) & 1)
|
||||
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
|
||||
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
|
||||
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
|
||||
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL)
|
||||
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK)
|
||||
|
||||
#define PIPE_DEVEP_MASK 0x0007ff00
|
||||
|
||||
|
||||
/* The D0/D1 toggle bits */
|
||||
#define usb_gettoggle(dev, ep, out) (((dev)->toggle2[out] >> (ep)) & 1)
|
||||
#define usb_dotoggle(dev, ep, out) ((dev)->toggle2[out] ^= (1 << (ep)))
|
||||
static inline void usb_settoggle(struct usbdev *dev,
|
||||
unsigned int ep,
|
||||
unsigned int out,
|
||||
int bit)
|
||||
{
|
||||
dev->toggle2[out] &= ~(1 << ep);
|
||||
dev->toggle2[out] |= bit << ep;
|
||||
}
|
||||
|
||||
|
||||
/* Endpoint halt control/status */
|
||||
#define usb_endpoint_out(ep_dir) (((ep_dir >> 7) & 1) ^ 1)
|
||||
#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
|
||||
#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
|
||||
#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
|
||||
|
||||
|
||||
static inline unsigned int __create_pipe(usbdev_t *dev, unsigned int endpoint)
|
||||
{
|
||||
return (dev->address << 8) | (endpoint << 15) |
|
||||
((dev->lowspeed == 1) << 26);
|
||||
}
|
||||
|
||||
static inline unsigned int __default_pipe(struct usbdev *dev)
|
||||
{
|
||||
return ((dev->lowspeed == 1) << 26);
|
||||
}
|
||||
|
||||
/* Create various pipes... */
|
||||
#define usb_sndctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
|
||||
#define usb_rcvctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
|
||||
#if 0
|
||||
#define usb_sndisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
|
||||
#define usb_rcvisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
|
||||
#endif
|
||||
#define usb_sndbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
|
||||
#define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
|
||||
#if 0
|
||||
#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
|
||||
#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
|
||||
#endif
|
||||
#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30) | __default_pipe(dev))
|
||||
#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | __default_pipe(dev) | USB_DIR_IN)
|
||||
|
||||
|
||||
extern int next_usb_dev;
|
||||
usbdev_t usb_device[MAX_USB_DEV];
|
||||
|
||||
void init_devices(void);
|
||||
void hci_init(void);
|
||||
int hc_init(struct pci_device *dev);
|
||||
inline int set_address(uchar address);
|
||||
inline int clear_stall(uchar device, uchar endpoint);
|
||||
int poll_usb();
|
||||
int configure_device(uint32_t port, uchar controller, unsigned int lowspeed);
|
||||
int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
|
||||
int usb_control_msg( uchar devnum, uchar request_type, uchar request, unsigned short wValue, unsigned short wIndex,
|
||||
unsigned short wLength, void *data);
|
||||
|
||||
int usb_control_msg_x(struct usbdev *dev, unsigned int pipe, u8 request, u8 requesttype,
|
||||
u16 value, u16 index, void *data, u16 size, int timeout, usb_complete_t complete);
|
||||
int usb_bulk_msg_x(struct usbdev *usb_dev, unsigned int pipe,
|
||||
void *data, int len, int *actual_length, int timeout, usb_complete_t complete);
|
||||
|
||||
#endif
|
|
@ -1,172 +0,0 @@
|
|||
#ifdef USB_DISK
|
||||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <etherboot.h>
|
||||
#include <pci.h>
|
||||
#include <timer.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_USB
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTF debug
|
||||
|
||||
#define uchar uint8_t
|
||||
|
||||
//#include "debug_x.h"
|
||||
#include "usb_scsi_low.h"
|
||||
|
||||
int usb_bulk_transfer( uchar devnum, uchar ep, unsigned int len, uchar *data);
|
||||
|
||||
#define SG_DXFER_FROM_DEV -3
|
||||
#define SG_DXFER_TO_DEV -2
|
||||
|
||||
#define REQUEST_SENSE 0x03
|
||||
|
||||
#define CBW_SIG 0x43425355
|
||||
|
||||
typedef struct usb_cbw {
|
||||
unsigned int signature;
|
||||
unsigned int tag;
|
||||
unsigned int transfer_len; // this is exclusive of cbw and csw
|
||||
|
||||
uchar res1:7;
|
||||
uchar direction:1; // 1 = device to host (read)
|
||||
|
||||
uchar lun:4;
|
||||
uchar res:4;
|
||||
|
||||
uchar cbw_len:5; // the length of the SCSI command
|
||||
uchar res3:3;
|
||||
|
||||
uchar scsi_cmd[16];
|
||||
} __attribute__ ((packed)) usb_cbw_t;
|
||||
|
||||
#define CSW_SIG 0x53425355
|
||||
|
||||
typedef struct usb_csw {
|
||||
unsigned int signature;
|
||||
unsigned int tag;
|
||||
unsigned int residue;
|
||||
uchar status;
|
||||
} __attribute__ ((packed)) usb_csw_t;
|
||||
|
||||
|
||||
int scsi_command( uchar device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, char *sense_data, int sense_len)
|
||||
{
|
||||
usb_cbw_t cbw;
|
||||
usb_csw_t csw;
|
||||
int ret;
|
||||
|
||||
memset(&cbw,0,sizeof(usb_cbw_t));
|
||||
memset(&csw,0,sizeof(usb_csw_t));
|
||||
|
||||
cbw.signature = CBW_SIG;
|
||||
cbw.tag = 777;
|
||||
|
||||
memcpy(cbw.scsi_cmd, cmd, cmd_len);
|
||||
cbw.cbw_len = cmd_len;
|
||||
|
||||
if(direction == SG_DXFER_FROM_DEV)
|
||||
cbw.direction=1;
|
||||
|
||||
cbw.transfer_len = data_len;
|
||||
|
||||
ret = usb_bulk_transfer(device, 2, sizeof(cbw), (uchar *) &cbw);
|
||||
if(ret<0){
|
||||
DPRINTF("ERROR:Bulk write:\n");
|
||||
}
|
||||
|
||||
if(data_len) {
|
||||
if(cbw.direction) {
|
||||
DPRINTF("scsi_command reading %d bytes\n", data_len);
|
||||
ret = usb_bulk_transfer(device, 0x81, data_len, data);
|
||||
DPRINTF("scsi_command read %d bytes\n", ret);
|
||||
if(ret<0 || ret <data_len) {
|
||||
DPRINTF("ERROR:Bulk read data ret = %d\n", ret);
|
||||
}
|
||||
} else {
|
||||
// DPRINTF("scsi_command writing %u bytes\n", data_len);
|
||||
ret = usb_bulk_transfer(device, 0x2, data_len, data);
|
||||
// DPRINTF("scsi_command wrote %u bytes\n", ret);
|
||||
if(ret<0) {
|
||||
DPRINTF("ERROR:Bulk write data\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DPRINTF("scsi_command fetching csw\n");
|
||||
ret = usb_bulk_transfer(device, 0x81, sizeof(csw), (uchar *) &csw);
|
||||
// DPRINTF("scsi_command csw is %d bytes\n", ret);
|
||||
if(ret<0 || ret < sizeof(csw)) {
|
||||
DPRINTF("ERROR: Bulk read CSW ret = %d\n", ret);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(csw.status) {
|
||||
DPRINTF("CSW: residue = %08x, status = %02x\n", csw.residue, csw.status);
|
||||
DPRINTF("Getting sense data\n");
|
||||
request_sense( device, sense_data, sense_len);
|
||||
return(-csw.status);
|
||||
}
|
||||
|
||||
return(data_len - csw.residue);
|
||||
}
|
||||
|
||||
int request_sense( uchar device, char *sense_data, int len)
|
||||
{
|
||||
usb_cbw_t cbw;
|
||||
usb_csw_t csw;
|
||||
int ret;
|
||||
|
||||
memset(&cbw,0,sizeof(usb_cbw_t));
|
||||
memset(&csw,0,sizeof(usb_csw_t));
|
||||
|
||||
cbw.signature = CBW_SIG;
|
||||
cbw.tag = 666;
|
||||
|
||||
cbw.scsi_cmd[0] = REQUEST_SENSE;
|
||||
cbw.scsi_cmd[4] = len;
|
||||
cbw.cbw_len = 6;
|
||||
cbw.direction=1;
|
||||
cbw.transfer_len = len;
|
||||
|
||||
ret = usb_bulk_transfer(device, 2, sizeof(usb_cbw_t), (uchar *) &cbw);
|
||||
if(ret<0 || ret < sizeof(usb_cbw_t)) {
|
||||
DPRINTF("ERROR: sense Bulk write ret = %d\n", ret);
|
||||
}
|
||||
|
||||
ret = usb_bulk_transfer(device, 0x81, len, sense_data);
|
||||
if(ret<0 || ret < len) {
|
||||
DPRINTF("ERROR: sense Bulk read data ret = %d\n", ret);
|
||||
}
|
||||
|
||||
ret = usb_bulk_transfer(device, 0x81, sizeof(usb_csw_t), (uchar *) &csw);
|
||||
if(ret<0 || ret < sizeof(usb_csw_t)) {
|
||||
DPRINTF("ERROR: sense Bulk read CSW ret = %d\n", ret);
|
||||
}
|
||||
|
||||
return(-csw.status);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef _USB_SCSI_LOW_H
|
||||
#define _USB_SCSI_LOW_H
|
||||
|
||||
#define SG_DXFER_FROM_DEV -3
|
||||
#define SG_DXFER_TO_DEV -2
|
||||
|
||||
int scsi_command( unsigned char device, unsigned char *cmd, int cmd_len, int direction, unsigned char *data, int data_len, char *sense_data, int sense_len);
|
||||
int request_sense( unsigned char device, char *sense_data, int len);
|
||||
|
||||
#endif
|
|
@ -1,163 +0,0 @@
|
|||
#ifdef USB_DISK
|
||||
/*******************************************************************************
|
||||
*
|
||||
*
|
||||
* Copyright 2003 Steven James <pyro@linuxlabs.com> and
|
||||
* LinuxLabs http://www.linuxlabs.com
|
||||
*
|
||||
* This program 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <etherboot.h>
|
||||
#include <pci.h>
|
||||
#include <timer.h>
|
||||
#include <lib.h>
|
||||
|
||||
#define DEBUG_THIS DEBUG_USB
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTF debug
|
||||
|
||||
#include "usb.h"
|
||||
#include "scsi_cmds.h"
|
||||
|
||||
struct usbdisk_info_t {
|
||||
struct controller *ctrl;
|
||||
uint16_t heads;
|
||||
uint16_t cylinders;
|
||||
uint16_t sectors_per_track;
|
||||
uint8_t model_number[41];
|
||||
uint8_t slave;
|
||||
sector_t sectors;
|
||||
int address_mode;
|
||||
#define ADDRESS_MODE_CHS 0
|
||||
#define ADDRESS_MODE_LBA 1
|
||||
#define ADDRESS_MODE_LBA48 2
|
||||
#define ADDRESS_MODE_PACKET 3
|
||||
uint32_t hw_sector_size;
|
||||
unsigned drive_exists : 1;
|
||||
unsigned slave_absent : 1;
|
||||
unsigned removable : 1;
|
||||
|
||||
unsigned char usb_device_address;
|
||||
};
|
||||
|
||||
struct usbdisk_info_t usbdisk_info;
|
||||
|
||||
#define TEST 0
|
||||
|
||||
#if TEST==1
|
||||
#include "usb_scsi_low.h"
|
||||
typedef struct partition_entry {
|
||||
uchar boot_flag;
|
||||
|
||||
uchar chs[7];
|
||||
|
||||
unsigned int lba_start;
|
||||
unsigned int lba_len;
|
||||
} __attribute__ ((packed)) partition_entry_t;
|
||||
|
||||
typedef struct partition {
|
||||
char loader[446];
|
||||
partition_entry_t entry[4];
|
||||
char sig[2];
|
||||
} __attribute__ ((packed)) partition_t;
|
||||
#endif
|
||||
|
||||
int usb_probe(int drive)
|
||||
{
|
||||
struct usbdisk_info_t *info = &usbdisk_info;
|
||||
#if TEST==1
|
||||
partition_t part;
|
||||
unsigned char sense_data[32];
|
||||
#endif
|
||||
int i,res;
|
||||
int error_count=100;
|
||||
|
||||
printf("LinuxLabs USB bootloader\n");
|
||||
|
||||
// outb( 0x30, 0x70); // reset primary boot
|
||||
// outb( 0xff, 0x71);
|
||||
init_devices();
|
||||
hci_init();
|
||||
|
||||
info->usb_device_address = 0;
|
||||
// find first usb device
|
||||
|
||||
while(error_count && (res = poll_usb())) // keep polling usb until no more devices are enumerated
|
||||
if(res<0)
|
||||
if(!--error_count)
|
||||
printf("There is a USB device, but it won't init! This is a bad thing.\n");
|
||||
|
||||
for(i=0; i< next_usb_dev ; i++) {
|
||||
if(usb_device[i].class == 0x08 && usb_device[i].subclass == 0x06 && usb_device[i].protocol == 0x50) {
|
||||
printf("Found USB block device %d\n", i);
|
||||
if(drive==0) {
|
||||
info->usb_device_address = i;
|
||||
break;
|
||||
}
|
||||
drive--;
|
||||
}
|
||||
}
|
||||
|
||||
if(info->usb_device_address == 0) return -1;
|
||||
|
||||
UnitReady(info->usb_device_address);
|
||||
|
||||
#if TEST==1
|
||||
//Test
|
||||
printf("Requesting initial sense data\n");
|
||||
request_sense( info->usb_device_address, sense_data, 32);
|
||||
PrintSense(sense_data, 32);
|
||||
|
||||
res = ll_read_block(info->usb_device_address, (uint8_t *)&part, 0, 1);
|
||||
|
||||
printf("ll_read_block returns %d\n", res);
|
||||
|
||||
res=-1;
|
||||
|
||||
debug("part address (phy) = %x, (virt) = %x\n", (uint32_t) virt_to_phys(&part), (uint32_t)&part);
|
||||
|
||||
for(i=0; i<4; i++) {
|
||||
printf("%d: boot=%02x, start=%08x length=%08x\n",i, part.entry[i].boot_flag, part.entry[i].lba_start, part.entry[i]
|
||||
.lba_len);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int usb_read(int drive, sector_t sector, void *buffer)
|
||||
{
|
||||
struct usbdisk_info_t *info = &usbdisk_info;
|
||||
int result;
|
||||
int blocknum = sector;
|
||||
int i;
|
||||
// printf("sector= %d\t", blocknum);
|
||||
result = ll_read_block(info->usb_device_address, buffer,blocknum, 1);
|
||||
#if 0
|
||||
for(i=0;i<128;i++) {
|
||||
if((i%4)==0) printf("\n %08x:",i*4);
|
||||
printf(" %08x ",(uint32_t)*((uint32_t *)buffer+i));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(result!=512) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue