📄 initdisk.c
字号:
/****************************************************************//* *//* initDISK.c *//* *//* Copyright (c) 2001 *//* tom ehlert *//* All Rights Reserved *//* *//* This file is part of DOS-C. *//* *//* DOS-C 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. *//* *//* DOS-C 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 DOS-C; see the file COPYING. If not, *//* write to the Free Software Foundation, 675 Mass Ave, *//* Cambridge, MA 02139, USA. *//****************************************************************/#include "portab.h"#include "init-mod.h"#include "dyndata.h"#ifdef VERSION_STRINGSstatic BYTE *dskRcsId = "$Id: initdisk.c,v 1.35 2005/03/06 16:12:34 perditionc Exp $";#endifUBYTE InitDiskTransferBuffer[SEC_SIZE] BSS_INIT({0});COUNT nUnits BSS_INIT(0);/* * Rev 1.0 13 May 2001 tom ehlert * Initial revision. * * this module implements the disk scanning for DOS accesible partitions * the drive letter ordering is somewhat chaotic, but like MSDOS does it. * * this module expects to run with CS = INIT_TEXT, like other init_code, * but SS = DS = DATA = DOS_DS, unlike other init_code. * * history: * 1.0 extracted the disk init code from DSK.C * added LBA support * moved code to INIT_TEXT * done the funny code segment stuff to switch between INIT_TEXT and TEXT * added a couple of snity checks for partitions * **************************************************************************** * * Implementation note: * this module needs some interfacing to INT 13 * how to implement them * * a) using inline assembly * _ASM mov ax,0x1314 * * b) using assembly routines in some external FLOPPY.ASM * * c) using the funny TURBO-C style * _AX = 0x1314 * * d) using intr(intno, ®s) method. * * whynot's * * a) this is my personal favorite, combining the best aof all worlds. * TURBO-C does support inline assembly, but only by using TASM, * which is not free. * so - unfortunately- its excluded. * * b) keeping funny memory model in sync with external assembly * routines is everything, but not fun * * c) you never know EXACT, what the compiler does, if its a bit * more complicated. does * _DL = drive & 0xff * _BL = driveParam.chs.Sector; * destroy any other register? sure? _really_ sure? * at least, it has it's surprises. * and - I found a couple of optimizer induced bugs (TC 2.01) * believe me. * it was coded - and operational that way. * but - there are many surprises waiting there. so I opted against. * * * d) this method is somewhat clumsy and certainly not the * fastest way to do things. * on the other hand, this is INIT code, executed once. * and scince it's the only portable method, I opted for it. * * e) and all this is my private opinion. tom ehlert. * * * Some thoughts about LBA vs. CHS. by Bart Oldeman 2001/Nov/11 * Matthias Paul writes in www.freedos.org/freedos/news/technote/113.html: * (...) MS-DOS 7.10+, which will always access logical drives in a type * 05h extended partition via CHS, even if the individual logical drives * in there are of LBA type, or go beyond 8 Gb... (Although this workaround * is sometimes used in conjunction with OS/2, using a 05h partition going * beyond 8 Gb may cause MS-DOS 7.10 to hang or corrupt your data...) (...) * * Also at http://www.win.tue.nl/~aeb/partitions/partition_types-1.html: * (...) 5 DOS 3.3+ Extended Partition * Supports at most 8.4 GB disks: with type 5 DOS/Windows will not use the * extended BIOS call, even if it is available. (...) * * So MS-DOS 7.10+ is brain-dead in this respect, but we knew that ;-) * However there is one reason to use old-style CHS calls: * some programs intercept int 13 and do not support LBA addressing. So * it is worth using CHS if possible, unless the user asks us not to, * either by specifying a 0x0c/0x0e/0x0f partition type or enabling * the ForceLBA setting in the fd kernel (sys) config. This will make * multi-sector reads and BIOS computations more efficient, at the cost * of some compatibility. * * However we need to be safe, and with varying CHS at different levels * that might be difficult. Hence we _only_ trust the LBA values in the * partition tables and the heads and sectors values the BIOS gives us. * After all these are the values the BIOS uses to process our CHS values. * So unless the BIOS is buggy, using CHS on one partition and LBA on another * should be safe. The CHS values in the partition table are NOT trusted. * We print a warning if there is a mismatch with the calculated values. * * The CHS values in the boot sector are used at a higher level. The CHS * that DOS uses in various INT21/AH=44 IOCTL calls are converted to LBA * using the boot sector values and then converted back to CHS using BIOS * values if necessary. Internally we do LBA as much as possible. * * However if the partition extends beyond cylinder 1023 and is not labelled * as one of the LBA types, we can't use CHS and print a warning, using LBA * instead if possible, and otherwise refuse to use it. * * As for EXTENDED_LBA vs. EXTENDED, FreeDOS makes no difference. This is * boot time - there is no reason not to use LBA for reading partition tables, * and the MSDOS 7.10 behaviour is not desirable. * * Note: for floppies we need the boot sector values though and the boot sector * code does not use LBA addressing yet. * * Conclusion: with all this implemented, FreeDOS should be able to gracefully * handle and read foreign hard disks moved across computers, whether using * CHS or LBA, strengthening its role as a rescue environment. *//* #define DEBUG */#define _BETA_ /* messages for initial phase only */#if defined(DEBUG)#define DebugPrintf(x) printf x#else#define DebugPrintf(x)#endif#if defined(_BETA_)#define BetaPrintf(x) printf x#else#define BetaPrintf(x)#endif#define LBA_to_CHS init_LBA_to_CHS/* interesting macros - used internally only*/#define SCAN_PRIMARYBOOT 0x00#define SCAN_PRIMARY 0x01#define SCAN_EXTENDED 0x02#define SCAN_PRIMARY2 0x03#define FAT12 0x01#define FAT16SMALL 0x04#define EXTENDED 0x05#define FAT16LARGE 0x06#define FAT32 0x0b /* FAT32 partition that ends before the 8.4 */ /* GB boundary */#define FAT32_LBA 0x0c /* FAT32 partition that ends after the 8.4GB */ /* boundary. LBA is needed to access this. */#define FAT16_LBA 0x0e /* like 0x06, but it is supposed to end past */ /* the 8.4GB boundary */#define FAT12_LBA 0xff /* fake FAT12 LBA entry for internal use */#define EXTENDED_LBA 0x0f /* like 0x05, but it is supposed to end past *//* Let's play it safe and do not allow partitions with clusters above * * or equal to 0xff0/0xfff0/0xffffff0 to be created * * the problem with fff0-fff6 is that they might be interpreted as BAD * * even though the standard BAD value is ...ff7 */#define FAT12MAX (FAT_MAGIC-6)#define FAT16MAX (FAT_MAGIC16-6)#define FAT32MAX (FAT_MAGIC32-6)#define IsExtPartition(parttyp) ((parttyp) == EXTENDED || \ (parttyp) == EXTENDED_LBA )#define IsLBAPartition(parttyp) ((parttyp) == FAT12_LBA || \ (parttyp) == FAT16_LBA || \ (parttyp) == FAT32_LBA)#ifdef WITHFAT32#define IsFATPartition(parttyp) ((parttyp) == FAT12 || \ (parttyp) == FAT16SMALL || \ (parttyp) == FAT16LARGE || \ (parttyp) == FAT16_LBA || \ (parttyp) == FAT32 || \ (parttyp) == FAT32_LBA)#else#define IsFATPartition(parttyp) ((parttyp) == FAT12 || \ (parttyp) == FAT16SMALL || \ (parttyp) == FAT16LARGE || \ (parttyp) == FAT16_LBA)#endif#define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */#define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */#define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */#define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature *//* local - returned and used for BIOS interface INT 13, AH=48*/struct _bios_LBA_disk_parameterS { UWORD size; UWORD information; ULONG cylinders; ULONG heads; ULONG sectors; ULONG totalSect; ULONG totalSectHigh; UWORD BytesPerSector; ULONG eddparameters;};/* physical characteristics of a drive */struct DriveParamS { UBYTE driveno; /* = 0x8x */ UWORD descflags; ULONG total_sectors; struct CHS chs; /* for normal INT 13 */};struct PartTableEntry /* INTERNAL representation of partition table entry */{ UBYTE Bootable; UBYTE FileSystem; struct CHS Begin; struct CHS End; ULONG RelSect; ULONG NumSect;};/* internal global data*/BOOL ExtLBAForce = FALSE;COUNT init_readdasd(UBYTE drive){ static iregs regs; regs.a.b.h = 0x15; regs.d.b.l = drive; init_call_intr(0x13, ®s); if ((regs.flags & 1) == 0) switch (regs.a.b.h) { case 2: return DF_CHANGELINE; case 3: return DF_FIXED; } return 0;}typedef struct { UWORD bpb_nbyte; /* Bytes per Sector */ UBYTE bpb_nsector; /* Sectors per Allocation Unit */ UWORD bpb_nreserved; /* # Reserved Sectors */ UBYTE bpb_nfat; /* # FAT's */ UWORD bpb_ndirent; /* # Root Directory entries */ UWORD bpb_nsize; /* Size in sectors */ UBYTE bpb_mdesc; /* MEDIA Descriptor Byte */ UWORD bpb_nfsect; /* FAT size in sectors */ UWORD bpb_nsecs; /* Sectors per track */ UWORD bpb_nheads; /* Number of heads */} floppy_bpb;floppy_bpb floppy_bpbs[5] = {/* copied from Brian Reifsnyder's FORMAT, bpb.h */ {SEC_SIZE, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2}, /* FD360 5.25 DS */ {SEC_SIZE, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2}, /* FD1200 5.25 HD */ {SEC_SIZE, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2}, /* FD720 3.5 LD */ {SEC_SIZE, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2}, /* FD1440 3.5 HD */ {SEC_SIZE, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2} /* FD2880 3.5 ED */};COUNT init_getdriveparm(UBYTE drive, bpb * pbpbarray){ static iregs regs; REG UBYTE type; if (drive & 0x80) return 5; regs.a.b.h = 0x08; regs.d.b.l = drive; init_call_intr(0x13, ®s); type = regs.b.b.l - 1; if (regs.flags & 1) type = 0; /* return 320-360 for XTs */ else if (type > 6) type = 8; /* any odd ball drives get 8&7=0: the 320-360 table */ else if (type == 5) type = 4; /* 5 and 4 are both 2.88 MB */ memcpy(pbpbarray, &floppy_bpbs[type & 7], sizeof(floppy_bpb)); ((bpb *)pbpbarray)->bpb_hidden = 0; /* very important to init to 0, see bug#1789 */ ((bpb *)pbpbarray)->bpb_huge = 0; if (type == 3) return 7; /* 1.44 MB */ if (type == 4) return 9; /* 2.88 almost forgot this one */ /* 0=320-360kB, 1=1.2MB, 2=720kB, 8=any odd ball drives */ return type;}/* translate LBA sectors into CHS addressing copied and pasted from dsk.c!*/void init_LBA_to_CHS(struct CHS *chs, ULONG LBA_address, struct DriveParamS *driveparam){ unsigned hs = driveparam->chs.Sector * driveparam->chs.Head; unsigned hsrem = (unsigned)(LBA_address % hs); LBA_address /= hs; chs->Cylinder = LBA_address >= 0x10000ul ? 0xffffu : (unsigned)LBA_address; chs->Head = hsrem / driveparam->chs.Sector; chs->Sector = hsrem % driveparam->chs.Sector + 1;}void printCHS(char *title, struct CHS *chs){ /* has no fixed size for head/sect: is often 1/1 in our context */ printf("%s%4u-%u-%u", title, chs->Cylinder, chs->Head, chs->Sector);}/* reason for this modules existence: we have found a partition, and add them to the global partition structure.*//* Compute ceil(a/b) */#define cdiv(a, b) (((a) + (b) - 1) / (b))/* calculates FAT data: code adapted by Bart Oldeman from mkdosfs from the Linux dosfstools: Author: Dave Hudson Updated by: Roman Hodek Portions copyright 1992, 1993 Remy Card and 1991 Linus Torvalds*/VOID CalculateFATData(ddt * pddt, ULONG NumSectors, UBYTE FileSystem){ UBYTE maxclustsize; ULONG fatdata; bpb *defbpb = &pddt->ddt_defbpb; /* FAT related items */ defbpb->bpb_nfat = 2; defbpb->bpb_ndirent = (FileSystem == FAT32 || FileSystem == FAT32_LBA) ? 0 : 512; /* normal value of number of entries in root dir */ defbpb->bpb_nreserved = (FileSystem == FAT32 || FileSystem == FAT32_LBA) ? 0x20 : 1; fatdata = NumSectors - cdiv(defbpb->bpb_ndirent * DIRENT_SIZE, defbpb->bpb_nbyte) - defbpb->bpb_nreserved; maxclustsize = 128;#ifdef DEBUG if (FileSystem != FAT12) DebugPrintf(("%ld sectors for FAT+data, starting with %d sectors/cluster\n", fatdata, defbpb->bpb_nsector));#endif switch (FileSystem) { case FAT12: case FAT12_LBA: { unsigned fatdat, fatlength, clust, maxclust; /* in DOS, FAT12 defaults to 4096kb (8 sector) - clusters. */ defbpb->bpb_nsector = 8; /* Force maximal fatdata=32696 sectors since with our only possible sector size (512 bytes) this is the maximum for 4k clusters. #clus*secperclus+#fats*fatlength= 4077 * 8 + 2 * 12 = 32640. max FAT12 size for FreeDOS = 16,728,064 bytes */ fatdat = (unsigned)fatdata; if (fatdata > 32640) fatdat = 32640; /* The "+2*defbpb->bpb_nsector" is for the reserved first two FAT entries */ fatlength = cdiv(fatdat + 2 * defbpb->bpb_nsector, defbpb->bpb_nbyte * 2 * defbpb->bpb_nsector / 3 + defbpb->bpb_nfat); /* Need to calculate number of clusters, since the unused parts of the * FATS and data area together could make up space for an additional, * not really present cluster. */ clust = (fatdat - defbpb->bpb_nfat * fatlength) / defbpb->bpb_nsector; maxclust = (fatlength * 2 * defbpb->bpb_nbyte) / 3; if (maxclust > FAT12MAX) maxclust = FAT12MAX; DebugPrintf(("FAT12: #clu=%u, fatlength=%u, maxclu=%u, limit=%u\n", clust, fatlength, maxclust, FAT12MAX)); if (clust > maxclust - 2) { clust = maxclust - 2; DebugPrintf(("FAT12: too many clusters: setting to maxclu-2\n")); } defbpb->bpb_nfsect = fatlength; memcpy(pddt->ddt_fstype, MSDOS_FAT12_SIGN, 8); break; } case FAT16SMALL: case FAT16LARGE: case FAT16_LBA: { unsigned fatlength; unsigned long clust, maxclust; /* FAT16: start at 4 sectors per cluster */ defbpb->bpb_nsector = 4; /* Force maximal fatdata=8387584 sectors (NumSectors=8387617) since with our only possible sectorsize (512 bytes) this is the maximum we can address with 64k clusters #clus*secperclus+#fats*fatlength=65517 * 128 + 2 * 256=8386688. max FAT16 size for FreeDOS = 4,293,984,256 bytes = 4GiB-983,040 */ if (fatdata > 8386688ul) fatdata = 8386688ul; do { DebugPrintf(("Trying with %d sectors/cluster:\n", defbpb->bpb_nsector)); fatlength = (unsigned)cdiv(fatdata + 2 * defbpb->bpb_nsector, (ULONG)defbpb->bpb_nbyte * defbpb->bpb_nsector / 2 + defbpb->bpb_nfat); /* Need to calculate number of clusters, since the unused parts of the * FATS and data area together could make up space for an additional, * not really present cluster. */ clust = (fatdata - defbpb->bpb_nfat * fatlength) / defbpb->bpb_nsector; maxclust = ((unsigned long)fatlength * defbpb->bpb_nbyte) / 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -