📄 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_STRINGS
static BYTE *dskRcsId =
"$Id: initdisk.c,v 1.33 2004/05/25 19:24:55 bartoldeman Exp $";
#endif
UBYTE 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));
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -