⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 initdisk.c

📁 GNU FreeDOS兼容MS DOS很好的东东.
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************//*                                                              *//*                            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, &regs) 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, &regs);  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, &regs);  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 + -