📄 disk_io.c
字号:
/* disk_io.c - implement abstract BIOS disk input and output *//* * GRUB -- GRand Unified Bootloader * Copyright (C) 1999,2000,2001,2002,2003,2004 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 <shared.h>#include <filesys.h>#include <iso9660.h>#ifdef SUPPORT_NETBOOT# define GRUB 1# include <etherboot.h>#endif#ifdef GRUB_UTIL# include <device.h>#endif/* instrumentation variables */void (*disk_read_hook) (unsigned long, unsigned long, unsigned long) = NULL;void (*disk_read_func) (unsigned long, unsigned long, unsigned long) = NULL;/* Forward declarations. */static int next_bsd_partition (void);static int next_pc_slice (void);static char open_filename[512];static unsigned long relative_path;#ifndef STAGE1_5int print_possibilities;static int unique;static char *unique_string;static unsigned long cur_part_offset;static unsigned long cur_part_addr;static int do_completion;int dir (char *dirname);static int sane_partition (void);/* XX used for device completion in 'set_device' and 'print_completions' */static int incomplete, disk_choice;static enum{ PART_UNSPECIFIED = 0, PART_DISK, PART_CHOSEN,}part_choice;#endif /* ! STAGE1_5 */unsigned long i;#if !defined(STAGE1_5) && !defined(GRUB_UTIL)/* The first sector of stage2 can be reused as a tmp buffer. * Do NOT write more than 512 bytes to this buffer! * The stage2-body, i.e., the pre_stage2, starts at 0x8200! * Do NOT overwrite the pre_stage2 code at 0x8200! */char *mbr = (char *)0x8000; /* 512-byte buffer for any use. */#elsechar mbr[SECTOR_SIZE];#endifunsigned long next_partition_drive;unsigned long next_partition_dest;unsigned long *next_partition_partition;unsigned long *next_partition_type;unsigned long *next_partition_start;unsigned long *next_partition_len;unsigned long *next_partition_offset;unsigned long *next_partition_entry;unsigned long *next_partition_ext_offset;char *next_partition_buf;static unsigned long dest_partition;static unsigned long part_offset;static unsigned long entry;static unsigned long ext_offset;static unsigned long bsd_part_no;static unsigned long pc_slice_no;unsigned long fsmax;struct fsys_entry fsys_table[NUM_FSYS + 1] ={ /* TFTP should come first because others don't handle net device. */# ifdef FSYS_PXE {"pxe", pxe_mount, pxe_read, pxe_dir, pxe_close, 0},# endif# ifdef FSYS_TFTP {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},# endif# ifdef FSYS_EXT2FS {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},# endif# ifdef FSYS_FAT {"fat", fat_mount, fat_read, fat_dir, 0, 0},# endif# ifdef FSYS_NTFS {"ntfs", ntfs_mount, ntfs_read, ntfs_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_VSTAFS {"vstafs", vstafs_mount, vstafs_read, vstafs_dir, 0, 0},# 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_UFS2 {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed},# endif# ifdef FSYS_ISO9660 {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},# endif /* XX FFS should come last as it's superblock is commonly crossing tracks on floppies from track 1 to 2, while others only use 1. */# ifdef FSYS_FFS {"ffs", ffs_mount, ffs_read, ffs_dir, 0, ffs_embed},# endif {0, 0, 0, 0, 0, 0}};/* These have the same format as "boot_drive" and "install_partition", but are meant to be working values. */unsigned long current_drive = GRUB_INVALID_DRIVE;unsigned long current_partition;#ifndef STAGE1_5/* The register ESI should contain the address of the partition to be used for loading a chain-loader when chain-loading the loader. */unsigned long boot_part_addr = 0;#endif/* * Global variables describing details of the filesystem *//* FIXME: BSD evil hack */#include "freebsd.h"int bsd_evil_hack;/* filesystem type */int fsys_type = NUM_FSYS;/* these are the translated numbers for the open partition */unsigned long part_start;unsigned long part_length;unsigned long current_slice;/* disk buffer parameters */int buf_drive = -1;int buf_track = -1;struct geometry buf_geom;struct geometry tmp_geom; /* tmp variable used in many functions. */struct geometry fd_geom[4];struct geometry hd_geom[4];int rawread_ignore_memmove_overflow = 0;/* blocklist_func() set this to 1 *//* filesystem common variables */unsigned long filepos;unsigned long filemax;unsigned long emu_iso_sector_size_2048 = 0;inline unsigned longlog2_tmp (unsigned long word){ asm volatile ("bsfl %1,%0" : "=r" (word) : "r" (word)); return word;}/* Convert unicode filename to UTF-8 filename. N is the max characters to be * converted. The caller should asure there is enough room in the UTF8 buffer. * */voidunicode_to_utf8 (unsigned short *filename, unsigned char *utf8, unsigned long n){ unsigned short uni; unsigned long j, k; for (j = 0, k = 0; j < n && (uni = filename[j]); j++) { if (uni <= 0x007F) { if (uni != ' ') utf8[k++] = uni; else { /* quote the SPACE with a backslash */ utf8[k++] = '\\'; utf8[k++] = uni; } } else if (uni <= 0x07FF) { utf8[k++] = 0xC0 | (uni >> 6); utf8[k++] = 0x80 | (uni & 0x003F); } else { utf8[k++] = 0xE0 | (uni >> 12); utf8[k++] = 0x80 | ((uni >> 6) & 0x003F); utf8[k++] = 0x80 | (uni & 0x003F); } } utf8[k] = 0;}/* Read bytes from DRIVE to BUF. * * The bytes start at BYTE_OFFSET in absolute sector number SECTOR and with * BYTE_LEN bytes long. * */intrawread (unsigned long drive, unsigned long sector, unsigned long byte_offset, unsigned long byte_len, char *buf){ unsigned long slen, sectors_per_vtrack; unsigned long sector_size_bits = log2_tmp (buf_geom.sector_size);// if (byte_len == 0)// return 1; errnum = 0; while (byte_len > 0) { unsigned long soff, num_sect, track, size = byte_len; char *bufaddr; /* * Check track buffer. If it isn't valid or it is from the * wrong disk, then reset the disk geometry. */ if (buf_drive != drive) { if (get_diskinfo (drive, &buf_geom)) { errnum = ERR_NO_DISK; return 0; } buf_drive = drive; buf_track = -1; sector_size_bits = log2_tmp (buf_geom.sector_size); }#if 0 /* Make sure that SECTOR is valid. */ if (/* sector < 0 || */ sector >= buf_geom.total_sectors) { errnum = ERR_GEOM; /* Selected cylinder exceeds maximum supported by BIOS. This message is not proper. */ return 0; }#endif /* Sectors that need to read */ slen = ((byte_offset + byte_len + buf_geom.sector_size - 1) >> sector_size_bits); /* Eliminate a buffer overflow. */ if ((buf_geom.sectors << sector_size_bits) > BUFFERLEN) sectors_per_vtrack = (BUFFERLEN >> sector_size_bits); else sectors_per_vtrack = buf_geom.sectors; /* Get the first sector number in the track. */ soff = sector % sectors_per_vtrack; /* Get the starting sector number of the track. */ track = sector - soff; /* max number of sectors to read in the track. */ num_sect = sectors_per_vtrack - soff; /* Read data into the track buffer; Not all sectors in the track would be filled in. */ bufaddr = ((char *) BUFFERADDR + (soff << sector_size_bits) + byte_offset); if (track != buf_track) { unsigned long bios_err; unsigned long read_start = track; unsigned long read_len = sectors_per_vtrack; buf_track = track; /* * If there's more than one read in this entire loop, then * only make the earlier reads for the portion needed. This * saves filling the buffer with data that won't be used! */ if (slen > num_sect) { buf_track = -1; /* invalidate the buffer */ read_start = sector; read_len = num_sect; bufaddr = (char *) BUFFERADDR + byte_offset; } bios_err = biosdisk (BIOSDISK_READ, drive, &buf_geom, read_start, read_len, BUFFERSEG); if (bios_err) { buf_track = -1; /* invalidate the buffer */// if (bios_err == BIOSDISK_ERROR_GEOMETRY)// {// errnum = ERR_GEOM;// return 0;// }// else { /* Do not try again to read sectors near a bad track. * Reading these sectors may slow down the system. * This can also remind us potential problems with the disk. */#if 0 /* * If there was an error, try to load only the * required sector(s) rather than failing completely. */ if (slen > num_sect || biosdisk (BIOSDISK_READ, drive, &buf_geom, sector, slen, BUFFERSEG))#endif { errnum = ERR_READ; return 0; } //bufaddr = (char *) BUFFERADDR + byte_offset; } } } /* if (track != buf_track) */ if (size > (num_sect << sector_size_bits) - byte_offset) size = (num_sect << sector_size_bits) - byte_offset; /* * Instrumentation to tell which sectors were read and used. */ if (disk_read_func) { unsigned long sector_num = sector; unsigned long length = buf_geom.sector_size - byte_offset; if (length > size) length = size; (*disk_read_func) (sector_num++, byte_offset, length); length = size - length; if (length > 0) { while (length > buf_geom.sector_size) { (*disk_read_func) (sector_num++, 0, buf_geom.sector_size); length -= buf_geom.sector_size; } (*disk_read_func) (sector_num, 0, length); } } grub_memmove (buf, bufaddr, size); if (errnum == ERR_WONT_FIT) { if (! rawread_ignore_memmove_overflow) return 0; errnum = 0; buf = NULL; /* so that further memcheck() always fail */ } else buf += size; byte_len -= size; /* byte_len always >= size */ sector += num_sect; byte_offset = 0; } /* while (byte_len > 0 && !errnum) */ return 1;//(!errnum);}intdevread (unsigned long sector, unsigned long byte_offset, unsigned long byte_len, char *buf){ unsigned long sector_size_bits = log2_tmp(buf_geom.sector_size); if (emu_iso_sector_size_2048) { emu_iso_sector_size_2048 = 0; asm volatile ("shl%L0 %1,%0" : "=r"(sector) : "Ic"((int8_t)(ISO_SECTOR_BITS - sector_size_bits)), "0"(sector)); } /* * Check partition boundaries *///grub_printf ("sector=%x, byte_offset=%x, byte_len=%x, buf=%x, part_length=%x\n", sector, byte_offset, byte_len, buf, part_length); if (((unsigned long)(sector + ((byte_offset + byte_len - 1) >> sector_size_bits)) >= part_length) && part_start) { errnum = ERR_OUTSIDE_PART; return 0; }// if (byte_len <= 0)// return 1; /* * Get the read to the beginning of a partition. */ sector += byte_offset >> sector_size_bits; byte_offset &= buf_geom.sector_size - 1;#if !defined(STAGE1_5) if (disk_read_hook && (((unsigned long)debug) >= 0x7FFFFFFF)) printf ("<%d, %d, %d>", sector, byte_offset, byte_len);#endif /* !STAGE1_5 */ /* * Call RAWREAD, which is very similar, but: * * -- It takes an extra parameter, the drive number. * -- It requires that "sector" is relative to the beginning * of the disk. * -- It doesn't handle offsets across the sector boundary. */ return rawread (current_drive, part_start + sector, byte_offset, byte_len, buf);}#ifndef STAGE1_5/* Write 1 sector at BUF onto sector number SECTOR on drive DRIVE. * Only a 512-byte sector should be written with this function. * Return: * 1 success * 0 failure */intrawwrite (unsigned long drive, unsigned long sector, char *buf){ /* skip the write if possible. */ if (biosdisk (BIOSDISK_READ, drive, &buf_geom, sector, 1, SCRATCHSEG)) { errnum = ERR_READ; return 0; } if (! memcmp ((char *) SCRATCHADDR, buf, SECTOR_SIZE)) return 1; memmove ((char *) SCRATCHADDR, buf, SECTOR_SIZE); if (biosdisk (BIOSDISK_WRITE, drive, &buf_geom, sector, 1, SCRATCHSEG)) { errnum = ERR_WRITE; return 0; }#if 1 if (buf_drive == drive && sector - sector % buf_geom.sectors == buf_track) { /* Update the cache. */ memmove ((char *) BUFFERADDR + ((sector - buf_track) << SECTOR_BITS), buf, SECTOR_SIZE); }#else if (sector - sector % buf_geom.sectors == buf_track) /* Clear the cache. */ buf_track = -1;#endif return 1;}#endif /* ! STAGE1_5 */#ifndef STAGE1_5
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -