章节 – 8
磁盘 BIOS 功能和使用 C 处理的中断
简介
在本章中,我们将讨论重要的 Disk-BIOS 功能和其他重要的功能,这些功能使我们可以在 C 程序中自由使用和处理中断,方法简单而简短。这些功能是后面的–数据恢复和磁盘故障排除编程的骨干。这些是使 C 语言成为“高级”的功能。级汇编语言”.
biosdisk 和 _bios_disk 函数
这两个功能对于我们的数据恢复和磁盘故障排除编程来说是最重要的功能。我们大部分时间都会使用这些功能。
这两个是 BIOS 磁盘驱动器服务,已在 bios.h 中定义,其中 biosdisk 在原始扇区上的文件级别以下运行。如果稍微不小心使用这些功能,它可能会破坏硬盘上的文件内容和目录。 biosdisk 和 _bios_disk 函数都使用中断 0x13 直接向 BIOS 发出磁盘操作。 _bios_disk 函数在程序中的声明方式如下:
unsigned _bios_disk(unsigned cmd, struct diskinfo_t *dinfo);
And the declaration for the bios disk function is as follows:
int biosdisk(int cmd, int drive, int head, int track,
int sector, int nsects, void *buffer);
这些参数的含义已在下表中描述:
Parameter |
Function |
What It Is or what it does |
cmd |
Both |
Indicates the operation to perform such as read, write, verify etc.(See the description of cmd, given next) |
dinfo |
_bios_disk |
Points to a diskinfo_t structure that contains the remaining Parameters required by the operation.(see the description of diskinfo_t structure, given next) |
drive |
biosdisk |
Specifies which disk drive is to be used(0 for a:, 1for b: and 0x80 for first physical hard disk, 0x81 for second and so on.) |
head
track
sector |
biosdisk |
These specify the starting sector location from which the Operation is to be started. |
nsects |
biosdisk |
Number of sectors to read, write, verify etc. |
buffer |
biosdisk |
Memory address where data is to be read or written |
在这两个函数中,数据以每个扇区 512 字节的速度从缓冲区读取和写入,这是硬盘扇区的逻辑大小,两个函数返回的值都是 INT 0x13H 设置的 AX 寄存器的值BIOS 调用。
如果函数成功,高字节= 0,表示成功完成,低字节包含读取、写入或验证的扇区数等。
但是如果有任何错误并且功能不成功,高字节的值将是下表中描述的以下错误代码之一:
Value |
Description |
0x00 |
Successful completion (Not an Error!!) |
0x01 |
Bad command |
0x02 |
Address mark not found |
0x03 |
Attempt to write to write-protected disk |
0x04 |
Sector not found |
0x05 |
Reset failed (hard disk) |
0x06 |
Disk changed since last operation |
0x07 |
Drive parameter activity failed |
0x08 |
Direct memory access (DMA) overrun |
0x09 |
Attempt to perform DMA across 64K boundary
(data Boundary error or >80H sectors) |
0x0A |
Bad sector detected |
0x0B |
Bad track detected |
0x0C |
Unsupported track |
0x0D |
Invalid number of sectors on format (PS/2 hard disk) |
0x0E |
Control data address mark detected (hard disk) |
0x0F |
DMA arbitration level out of range (hard disk) |
0x10 |
Bad CRC/ECC on disk read |
0x11 |
CRC/ECC corrected data error (Not an error actually) |
0x20 |
Controller has failed |
0x31 |
No media in drive (IBM/MS INT 13 extensions) |
0x32 |
Incorrect drive type stored in CMOS (Compaq) |
0x40 |
Seek operation failed |
0x80 |
Attachment failed to respond |
0xAA |
Drive not ready (hard disk only) |
0xB0 |
Volume not locked in drive (INT 13 extensions) |
0xB1 |
Volume locked in drive (INT 13 extensions) |
0xB2 |
Volume not removable (INT 13 extensions) |
0xB3 |
Volume in use (INT 13 extensions) |
0xB4 |
Lock count exceeded (INT 13 extensions) |
0xB5 |
Valid eject request failed (INT 13 extensions) |
0xBB |
Undefined error occurred (hard disk only) |
0xCC |
Write fault occurred |
0xE0 |
Status register error |
0xFF |
Sense operation failed |
下面给出的表格代表了 cmd 参数要执行的操作命令。首先,我们将看到这两个函数的共同操作。
biosdisk |
_bios_disk |
What it does |
0 |
_DISK_RESET |
Resets disk system, forcing the drive controller to do a hard reset. Ignore all other parameters |
1 |
_DISK_STATUS |
Returns the status of the last disk operation. Ignores all other parameters |
2 |
_DISK_READ |
Reads one or more disk sectors into memory |
3 |
_DISK_WRITE |
Writes one or more disk sectors from memory |
4 |
_DISK_VERIFY |
Verifies one or more sectors |
5 |
_DISK_FORMAT |
Formats a track |
尽管您可以随意使用 cmd = 0, 1, 2, 3, 4,5 或 cmd = _DISK_RESET, _DISK_STATUS, _DISK_READ, _DISK_WRITE, _DISK_VARIFY, _DISK_FORMAT 并且这两个选项具有相同的效果,但建议您应该习惯使用诸如 cmd = _DISK_FORMAT 之类的单词选项而不是 cmd = 5,因为它可以帮助您避免在 cmd 输入错误命令号时可能发生的错误。
在 biosdisk 或 _bios_disk 函数的声明中,如果我们给 cmd = _DISK_RESET 该函数通过忽略所有其他参数来重置磁盘系统,_DISK_STATUS 返回最后一次磁盘操作的状态,忽略所有其他参数
对于 cmd =_DISK_READ、_DISK_WRITE 或 _DISK_VERIFY(2、3 或 4),biosdisk 和 _bios_disk 函数也使用如下所示的其他参数:
Parameter |
What It Does |
head
track
sector |
These three specify the location of starting sector for the specified operation. (minimum possible values may be head = 0, track = 0 and sector =1) |
nsectors |
This specifies the number of sectors to read or write |
buffer |
It points to the buffer where data is to be read and written |
如果 cmd 的值为 = 5 (_DISK_FORMAT),则 biosdisk 和 _bios_disk 按照表中的说明使用以下参数。始终建议您在使用 _DISK_FORMAT 时要小心,并且您应该知道要使用什么。缺乏知识甚至是一个小错误都可能使您面临大量数据丢失。
Parameter |
What It Does |
head
track |
These specify the location of the track to format |
buffer |
It points to a table of sector headers to be written on the named track |
cmd 的一些附加值仅由 biosdisk 函数使用。这些 cmd 值仅适用于 XT、AT、PS/2 和兼容设备。下表中描述了值:
cmd |
What it does |
6 |
Formats a track and sets bad sector flags |
7 |
Formats the drive beginning at a specific track |
8 |
Returns the current drive parameters in first 4 bytes of buffer |
9 |
Initializes drive-pair characteristics |
10 |
Does a long read (512 plus 4 extra bytes per sector) |
11 |
Does a long write (512 plus 4 extra bytes per sector) |
12 |
Does a disk seek |
13 |
Alternates disk reset |
14 |
Reads sector buffer |
15 |
Writes sector buffer |
16 |
Tests whether the named drive is ready |
17 |
Recalibrates the drive |
18 |
Controller RAM diagnostic |
19 |
Drive diagnostic |
20 |
Controller internal diagnostic |
diskinfo_t 结构
diskinfo_t 结构由_bios_disk 函数使用。结构描述如下:
struct diskinfo_t {
unsigned drive, head, track, sector, nsectors;
void far *buffer;
};
其中 drive 指定要使用的磁盘驱动器。永远记住,对于硬盘,指定的是物理驱动器,而不是磁盘分区。如果要操作分区,应用程序还必须解释该磁盘本身的分区表信息。
head、track和sector的值指定了操作的起始扇区的位置。 nsectors 指定要读取或写入的扇区数,缓冲区指向读取和写入数据的缓冲区。根据 cmd 的值,可能需要也可能不需要 diskinfo_t 结构中的其他参数。
在 biosdisk 和 _bios_disk 函数中使用的磁盘驱动器规格的值已在下表中给出:
drive Value |
Disk drive to use |
0 |
First floppy-disk drive |
1 |
Second floppy-disk drive |
2 |
Third floppy-disk drive |
.... |
(and so on) |
0x80 |
First hard-disk drive |
0x81 |
Second hard-disk drive |
0x82 |
Third hard-disk drive |
.... |
(and so on) |
理论够了!现在让我们看看一些实际的东西和这些功能的一些例子。下面的例子读取软盘的四个磁道两侧的扇区,并将内容存储到用户指定的文件中。没关系,如果您因为程序直接读取磁盘表面而从磁盘中删除了文件。
要查看已删除的数据,最好是拿一张完全格式化的软盘并复制一些文本文件,例如.c程序编码或其他文本文件(以便您了解文件的内容)占用约73KB(数据存储在四个磁道,两侧,每个磁道18个扇区。每个扇区为512字节)。已开发该程序来演示该示例。但是,您可以更改和开发它以准备恢复数据。
/* 程序读取软盘的 4 个磁道(0、1、2 和 3)并将内容写入指定文件 */
#include <bios.h>
#include <stdio.h>
#include<conio.h>
void main(void)
{
int head,track;
int result,i,sector;
char filename[80];
char *buffer;
struct diskinfo_t dinfo;
static char dbuf[512];
FILE *tt;
clrscr();
/// 检查驱动器是否就绪 \\\
if(!(biosdisk(4,0,0,0,0,1,buffer) & 0x02))
{
printf(" Drive A: Not Ready:\n Insert disk into Drive A:
and press any key\n");
getch();
}
/* 获取文件名来存储Sectors的数据
磁盘 */
printf("\nEnter the Destination File name with full Path
to store the data \n\n >");
gets(filename);
if((tt= fopen(filename, "wb"))==NULL)
{
printf("Could not open the File!!!");
getch();
}
for(track=0;track<4;track++)
{
for(head=0; head<=1;head++)
{
for(sector=1;sector<=18;sector++)
{
dinfo.drive = 0; /* drive number for A: */
dinfo.head = head; /* disk head number */
dinfo.track = track; /* track number */
dinfo.sector = sector; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
/// 显示状态 \\\
gotoxy(10,10); printf("Reading Data from: Head=%d
Track=%d Sector=%d",
head, track, sector);
fprintf(tt,"\n Data read from: Head=%d Track=%d Sector=%d\n",
head, track, sector);
/// 阅读指定部门 \\\
result = _bios_disk(_DISK_READ, &dinfo);
/// 将内容存储在指定文件中 \\\
if ((result & 0xff00) == 0)
{
for(i=0;i<512;i++)
fprintf(tt,"%c",dbuf[i] & 0xff);
}
/* 在读取扇区时在屏幕上和文件中打印错误消息 */
else
{
printf("\n Can not read at Head= %d Track= %d
Sector= %d\n",head,track,sector);
fprintf(tt,"\n Can not read at Head= %d Track= %d
Sector =%d\n",head,track,sector);
}
}
}
}
fclose(tt);
}
该示例显示了函数 biosdisk 和 _bios_disk 的使用。 biosdisk 功能检查磁盘是否准备好并找到地址标记。 _bios_disk 函数读取双方最多四个磁道的扇区。
磁盘表面的读(或写)顺序应该如下:
absread 和 abswrite 函数
这些函数已在 Dos.h 中定义。 absread 函数读取绝对磁盘扇区,abswrite 函数写入绝对磁盘扇区。函数 absread 使用 DOS 中断 0x25 读取特定磁盘扇区,函数 abswrite 使用 DOS 中断 0x26 写入特定磁盘扇区。
绝对读取或写入操作通过逐步递增扇区以顺序方式进行,并且完全没有磁头和磁道编号等。计算机的 BIOS 的工作是将绝对扇区转换为相应的扇区轨道、头和扇区号。
在我们要对整个磁盘执行读/写操作的程序中建议使用绝对读写操作,并且我们希望避免在程序中进行额外的编码和循环,以将程序的速度提高到最快。
absread 和 abswrite 这两个函数都忽略了磁盘的逻辑结构,不关注文件、FAT 或目录。这些函数直接对磁盘表面进行绝对读写操作,这就是abswrite如果使用不当可以覆盖文件、目录和FAT的原因。
absread函数的声明如下:
int absread(int drive, int nsects, long lsect,
void *buffer);
and the abswrite function is declared as follows:
int abswrite(int drive, int nsects, long lsect,
void *buffer);
其中参数含义如下:
Param. |
What It Is/Does |
drive |
Drive number to read (or write): 0 = A, 1 = B, etc. |
nsects |
Number of sectors to read (or write) |
lsect |
Beginning logical sector number |
buffer |
Memory address where the data is to be read (or written) |
成功时,这两个函数都返回 0。当有任何错误时,都返回 -1 并设置错误号。系统调用返回的 AX 寄存器的值。
读写操作的扇区数限制为 64K 或缓冲区大小,以较小者为准。但是我们将在接下来的章节中学习如何使用超大内存来超过内存限制 64K,以开发一个非常快速的程序。
|
用 C 处理中断
C 有时被称为高级汇编语言,因为它可以使用一些已定义的函数来调用不同的中断。一些重要的功能如下:
- int86: 调用 MS-DOS 中断。
- int86x: 使用段寄存器值调用 MS-DOS 中断。
- intdos: 使用 DX 和 AL 以外的寄存器调用 MS-DOS 服务
- intdosx: 使用段寄存器值调用 MS-DOS 服务。
- segread: 读取段寄存器
我们将详细讨论这些功能。首先,我们讨论一些经常或必须与这些函数一起使用的预定义结构和联合。
SREGS 结构
此结构已在 dos.h 中定义,它是传递给函数 int86x、intdosx 和 segread 并由函数填充的段寄存器的结构。结构的声明如下:
struct SREGS {
unsigned int es;
unsigned int cs;
unsigned int ss;
unsigned int ds;
};
REGS 联盟
REGS 是两个结构的并集。联合 REGS 已在 dos.h 中定义,用于在函数 int86、int86x、intdos 和 intdosx 之间传递信息。工会宣言如下:
union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};
BYTEREGS 和 WORDREGS 结构
BYTEREGES 和 WORDREGS 结构已在 dos.h 中定义,它们用于存储字节和字寄存器。 WORGREGS 结构允许用户以 16 位数量访问 CPU 的寄存器,其中 BYTEREGES 结构提供对各个 8 位寄存器的访问。
BITREGS 结构声明如下:
struct BYTEREGS {
unsigned char al, ah, bl, bh;
unsigned char cl, ch, dl, dh;
};
WORDREGS 结构声明如下:
struct WORDREGS {
unsigned int ax, bx, cx, dx;
unsigned int si, di, cflag, flags;
};
int86 和 int86x 函数
这些函数是dos.h中定义的通用8086软件中断接口。寄存器设置为所需的值,并调用这些函数来调用 MS-DOS 中断。 int86函数的声明如下:
int int86(int intno, union REGS *inregs,
union REGS *outregs);
int86x 是 int86 函数的变体。声明如下:
int int86x(int intno, union REGS *inregs,
union REGS *outregs, struct SREGS *segregs);
int86 和 int86x 函数都执行由参数 intno 指定的 8086 软件中断,或者我们可以说要生成的中断由 intno 指定。
使用 int86x 函数只能访问 ES 和 DS 而不能访问 CS 和 SS,因此您可以调用 8086 软件中断,该中断采用不同于默认数据段的 DS 值和/或采用 ES 中的参数。
这些函数在执行软件中断之前将寄存器值从 inregs 复制到寄存器中。函数 int86x 还在执行软件中断之前将 segregs->ds 和 segregs->es 的值复制到相应的寄存器中。此功能允许使用远指针或大数据内存模型的程序指定将哪个段用于软件中断。
在软件中断返回后,函数将当前寄存器值复制到 outregs,将进位标志的状态复制到 outregs 中的 x.cflag 字段,并将 8086 标志寄存器的值复制到 outregs 中的 x.flags 字段。函数 int86x 还恢复 DS 并将 segregs->es 和 segregs->ds 字段设置为相应段寄存器的值。
在这两个函数中, inregs 和 outregs 可以指向相同的结构,并且两个函数都在软件中断完成后返回 AX 的值。如果设置了进位标志,通常表示发生了错误。
C 中使用的 REGS 联合元素,相当于汇编语言,如下表所示:
16-bit |
8-bit |
C language |
Assembly language |
C language |
Assembly language |
inregs.x.ax |
AX |
inregs.h.al |
AL |
|
|
inregs.h.ah |
AH |
inregs.x.bx |
BX |
inregs.h.bl |
BL |
|
|
inregs.h.bh |
BH |
inregs.x.cx |
CX |
inregs.h.cl |
CL |
|
|
inregs.h.ch |
CH |
inregs.x.dx |
DX |
inregs.h.dl |
DL |
|
|
inregs.h.dh |
DH |
inregs.x.si |
SI |
|
|
inregs.x.di |
DI |
|
|
inregs.x.cflag |
CF |
|
|
让我们看一下 int86 和 int86x 函数的示例。以下程序扫描软盘的每个扇区并在屏幕上打印每个扇区的状态。
/* 程序扫描软盘的每个扇区并打印状态 */
#include<dos.h>
#include<conio.h>
void main()
{
int head,track,sector,i;
char *buf;
union REGS inregs, outregs;
struct SREGS sregs;
clrscr();
/// 通过重置磁盘系统初始化磁盘 \\\
gotoxy(10,2); printf("Initializing The Disk...");
for(i=0;i<3;i++)
{
inregs.h.ah=0x00; // Function Number
inregs.h.dl=0x00; // Floppy Disk
int86(0x13,&inregs,&outregs);
}
gotoxy(10,2); printf("The Status of the Disk is as....\n");
/* 从 0 到 79 磁道扫描软盘(共 80 磁道) */
for(track=0;track<=79;track++)
for(head=0;head<=1;head++)
for(sector=1;sector<=18;sector++)
{
inregs.h.ah = 0x04; /// function Number
inregs.h.al = 1; /// Number of sectors
inregs.h.dl = 0x00; /// Floppy Disk
inregs.h.ch = track;
inregs.h.dh = head;
inregs.h.cl = sector;
inregs.x.bx = FP_OFF(buf);
sregs.es = FP_SEG(buf);
int86x(0x13,&inregs,&outregs,&sregs);
//// 打印扫描扇区的状态 \\\\
switch(outregs.h.ah)
{
case 0x00:
cprintf("STATUS: No Error!!");
break;
case 0x01:
cprintf("STATUS: Bad command");
break;
case 0x02:
cprintf("STATUS: Address mark not found");
break;
case 0x03:
cprintf("STATUS: Attempt to write to
write-protected disk");
break;
case 0x04:
cprintf("STATUS: Sector not found");
break;
case 0x05:
cprintf("STATUS: Reset failed (hard disk)");
break;
case 0x06:
cprintf("STATUS: Disk changed since last
operation");
break;
case 0x07:
cprintf("STATUS: Drive parameter activity
failed");
break;
case 0x08:
cprintf("STATUS: Direct memory access (DMA)
overrun");
break;
case 0x09:
cprintf("STATUS: Attempt to perform DMA across
64K boundary");
break;
case 0x0A:
cprintf("STATUS: Bad sector detected");
break;
case 0x0B:
cprintf("STATUS: Bad track detected");
break;
case 0x0C:
cprintf("STATUS: Media type not found");
break;
case 0x0D:
cprintf("STATUS: Invalid number of sectors on
format (hard disk)");
break;
case 0x0E:
cprintf("STATUS: Control data address mark
detected (hard disk)");
break;
case 0x0F:
cprintf("STATUS: DMA arbitration level out of
range (hard disk)");
break;
case 0x10:
cprintf("STATUS: Bad CRC/ECC on disk read");
break;
case 0x11:
cprintf("STATUS: CRC/ECC corrected data error");
break;
case 0x20:
cprintf("STATUS: Controller has failed");
break;
case 0x31:
cprintf("STATUS: No media in drive (IBM/MS INT 13H
extensions)");
break;
case 0x32:
cprintf("STATUS: Incorrect drive type stored in
CMOS (Compaq)");
break;
case 0x40:
cprintf("STATUS: Seek operation failed");
break;
case 0x80:
cprintf("STATUS: Attachment failed to respond
(Disk Timed-out)");
break;
case 0xAA:
cprintf("STATUS: Drive not ready (hard disk
only)");
break;
case 0xB0:
cprintf("STATUS: Volume not locked in drive (INT
13H extensions)");
break;
case 0xB1:
cprintf("STATUS: Volume locked in drive (INT 13H extensions)");
break;
case 0xB2:
cprintf("STATUS: Volume not removable (INT 13H
extensions)");
break;
case 0xB3:
cprintf("STATUS: Volume in use (INT 13H
extensions)");
break;
case 0xB4:
cprintf("STATUS: Lock count exceeded (INT 13H
extensions)");
break;
case 0xB5:
cprintf("STATUS: Valid eject request failed (INT
13H extensions)");
break;
case 0xBB:
cprintf("STATUS: Undefined error occurred (hard
disk only)");
break;
case 0xCC:
cprintf("STATUS: Write fault occurred");
break;
case 0xE0:
cprintf("STATUS: Status register error");
break;
case 0xFF:
cprintf("STATUS: Sense operation failed");
break;
default: cprintf("STATUS: UNKNOWN Status CODE");
}
printf("\nCurrent position= Track:%d Head:%d Sector:%d \n",
track,head,sector);
}
gotoxy(10,24);printf("Scanning Completed!! Press Any Key TO
Exit..");
getch();
}
该程序显示了函数 int86 和 int86x 函数的使用示例。在本程序中,int86 函数是通过使用 INT 13H 的函数 00H 通过重置磁盘系统来初始化磁盘。 int86x 函数是使用 INT 13H 的 04H 函数从两侧验证软盘(1.44Mb,3½ 软盘)的每个扇区,最多 0 到 79 个磁道(共 80 个磁道)。
segread函数
此函数已在 dos.h 中定义。该函数读取段寄存器。函数声明如下:
void segread(struct SREGS *segp);
其中 segread 将段寄存器的当前值放入结构 *segp。该函数不返回任何内容,并且该调用旨在与 intdosx 和 int86x 一起使用。让我们看一个例子
#include <stdio.h>
#include <dos.h>
void main()
{
struct SREGS segs;
segread(&segs);
printf("Current segment register settings\n\n");
printf("CS: %X DS: %X\n", segs.cs, segs.ds);
printf("ES: %X SS: %X\n", segs.es, segs.ss);
getch();
}
程序的输出将是这样的:
Current segment register settings
CS: EED DS: 10BA
ES: 10BA SS: 10BA
intdos 和 intdosx 函数
这些函数已在 dos.h 中定义。这些是通用的 DOS 中断接口。函数 intdos 调用 MS-DOS 服务寄存器,然后调用 DX 和 AL,其中函数 intdosx 使用段寄存器值调用 MS-DOS 服务。
intdos函数的声明如下:
int intdos(union REGS *inregs, union REGS *outregs);
intdosx 函数的声明如下:
int intdosx(union REGS *inregs, union REGS *outregs,
struct SREGS *segregs);
intdos 和 intdosx 函数执行 DOS 中断 0x21 以调用指定的 DOS 函数。 inregs->h.ah 的值指定要调用的 DOS 函数。 函数 intdosx 在调用 DOS 函数之前还将 segregs ->ds 和 segregs ->es 值复制到相应的寄存器中,然后恢复 DS。
函数的这一特性允许使用远指针或大数据内存模型的程序指定要用于函数执行的段。使用 intdosx 函数,您可以调用一个 DOS 函数,该函数采用不同于默认数据段的 DS 值和/或采用 ES 中的参数。
这两个函数都在完成 DOS 函数调用后返回 AX 的值,如果设置了进位标志 (outregs -> x.cflag != 0),则表明发生了错误。
在中断 0x21 返回函数后,将当前寄存器值复制到 outregs,将进位标志的状态复制到 outregs 中的 x.cflag 字段,并将 8086 标志寄存器的值复制到 outregs 中的 x.flags 字段。 inregs 和 outregs 都可以指向同一个结构。让我们看看这些函数的例子。
intdos函数的使用示例如下。该程序获取有关软盘(1.44Mb,3½ 英寸软盘)磁盘驱动器的选定信息。本程序提供软盘的分配信息。
/* 获取磁盘使用的驱动器分配信息 */
#include <dos.h> /* for intdos() and union REGS */
#include <stdio.h> /* for printf() */
union REGS inregs, outregs;
void main()
{
inregs.h.ah = 0x36; /* get disk free space
function number */
inregs.h.dl = 0x01; /* drive A: */
intdos(&inregs, &outregs);
printf("%d sectors/cluster,\n%d clusters,\n%d bytes/sector,
\n%d total clusters",
outregs.x.ax,outregs.x.bx,
outregs.x.cx, outregs.x.dx);
getch();
}
程序的输出将是这样的:
1 sectors/cluster,
1933 clusters,
512 bytes/sector,
2843 total clusters
现在让我们看一个函数intdosx的例子。以下示例显示了 intdosx 函数 的使用。程序将一个字符串输出到标准输出。
/* 将“字符串”输出到标准的程序
输出。 */
#include <dos.h>
union REGS inregs, outregs;
struct SREGS segregs;
char far *string = "this string is not in the
default data segment$";
void main()
{
inregs.h.ah = 0x09; /* function number */
inregs.x.dx = FP_OFF(string);/*DS:DX is far
address of 'string */
segregs.ds = FP_SEG(string);
intdosx(&inregs, &outregs, &segregs);
getch();
}
程序的输出如下:
this string is not in the default data segment |
在这里,我们使用函数 intdosx 打印给定的字符串,通过 INT 21H 的函数 09H。应始终牢记,给定的字符串应始终以字符 “$” 结尾。
如何知道物理硬盘号
物理硬盘编号是一个非常重要的东西,应该写的准确。非法的驱动器规格可能会导致重大数据丢失。在数据恢复或磁盘故障排除编程期间,我们必须对驱动器号充满信心。如何知道不同磁盘排列的磁盘的驱动器号可以通过下面给出的例子来估计。
根据最普遍的神话,物理驱动器编号是根据磁盘的连接状态提供的,但在某些或特殊情况下,它可能取决于您的操作系统的引导过程或开机设置。
这里给出了 BIOS 提供的 物理驱动器号 最通用的概念,但即便如此,您也必须借助任何磁盘编辑工具或下一章节中给出的程序来确认,关于磁盘的配置。在确定您应该对运行此类程序做出任何决定后,如果这些程序被非法使用或缺乏知识,可能会损坏或损害数据。
一般情况下,如果两个磁盘都连接到系统,一个是主主,另一个是辅助主,第一优先级将被赋予主主(如果可用,然后是主从),然后是辅助主(如果有的话,然后到次要奴隶等等),物理编号将根据他们的喜好给出。
让我们假设您的系统一次最多支持四个硬盘。所有四个硬盘都可以按照给定的方式连接 Next:
Primary Master |
Primary Slave |
Secondary Master |
Secondary Slave |
现在让我们考虑一些物理驱动器数量的情况。在这里,我假设您已按照磁盘制造商的说明使用正确的跳线设置连接了磁盘,并且在正确的主从设置中:
- 如果所有四个硬盘都连接到系统:如果所有四个磁盘都连接到系统,则物理驱动器编号如下:
Primary/Secondary (Master/Slave) |
Status |
Physical Drive Number and Description |
Primary Master |
Disk is Present |
Physical Drive Number will be 80H. In this case the Hard Disk is called the First Hard Disk. |
Primary Slave |
Disk is Present |
Physical Drive Number will be 81H. In this case the Hard Disk is called the Second Hard Disk. |
Secondary Master |
Disk is Present |
Physical Drive Number will be 82H. In this case the Hard Disk is called the Third Hard Disk. |
Secondary Slave |
Disk is Present |
Physical Drive Number will be 83H. In this case the Hard Disk is called the Fourth Hard Disk. |
- 如果三个硬盘连接到系统:如果三个硬盘连接到系统,物理驱动器号将根据其附件首选项。以下示例代表了一些安排:
Primary/Secondary (Master/Slave) |
Status |
Physical Drive Number and Description |
Primary Master |
Disk is Present |
Physical Drive Number will be 80H. In this case the Hard Disk is called the First Hard Disk. |
Primary Slave |
Disk is Present |
Physical Drive Number will be 81H. In this case the Hard Disk is called the Second Hard Disk. |
Secondary Master |
Disk is Present |
Physical Drive Number will be 82H. In this case the Hard Disk is called the Third Hard Disk. |
Secondary Slave |
Disk Not Present |
------------------- |
Primary/Secondary (Master/Slave) |
Status |
Physical Drive Number and Description |
Primary Master |
Disk Not Present |
------------------- |
Primary Slave |
Disk is Present |
Physical Drive Number will be 80H. In this case the Hard Disk is called the First Hard Disk. |
Secondary Master |
Disk is Present |
Physical Drive Number will be 81H. In this case the Hard Disk is called the Second Hard Disk. |
Secondary Slave |
Disk is Present |
Physical Drive Number will be 82H. In this case the Hard Disk is called the Third Hard Disk. |
Primary/Secondary (Master/Slave) |
Status |
Physical Drive Number and Description |
Primary Master |
Disk is Present |
Physical Drive Number will be 80H. In this case the Hard Disk is called the First Hard Disk. |
Primary Slave |
Disk Not Present |
------------------- |
Secondary Master |
Disk is Present |
Physical Drive Number will be 81H. In this case the Hard Disk is called the Second Hard Disk. |
Secondary Slave |
Disk is Present |
Physical Drive Number will be 82H. In this case the Hard Disk is called the Third Hard Disk. |
Primary/Secondary (Master/Slave) |
Status |
Physical Drive Number and Description |
Primary Master |
Disk is Present |
Physical Drive Number will be 80H. In this case the Hard Disk is called the First Hard Disk. |
Primary Slave |
Disk is Present |
Physical Drive Number will be 81H. In this case the Hard Disk is called the Second Hard Disk. |
Secondary Master |
Disk Not Present |
------------------- |
Secondary Slave |
Disk is Present |
Physical Drive Number will be 82H. In this case the Hard Disk is called the Third Hard Disk. |
- 如果两个硬盘连接到系统:同样,如果两个硬盘连接到系统,物理驱动器号将根据它们的附件偏好。下面的例子说明了它:
Primary/Secondary (Master/Slave) |
Status |
Physical Drive Number and Description |
Primary Master |
Disk is Present |
Physical Drive Number will be 80H. In this case the Hard Disk is called the First Hard Disk. |
Primary Slave |
Disk Not Present |
------------------- |
Secondary Master |
Disk Not Present |
------------------- |
Secondary Slave |
Disk is Present |
Physical Drive Number will be 81H. In this case the Hard Disk is called the Second Hard Disk. |
- 如果单硬盘连接到系统:不用想,如果只有一个磁盘可用,物理驱动器号将是 80H。
中断 13H (INT 13H),ROM BIOS 磁盘驱动功能
这里已经给出了 INT 13H 函数的描述。这些功能应该谨慎学习,因为这些功能的滥用或使用不小心或缺乏知识,可能会导致大量数据丢失或其他许多问题。但是,如果以适当和适当的方式使用这些功能,则有助于最大限度地减少程序的编码,并使您的编程变得简单易行。
INT 13H (0x13)
Function 00H (0x00) Reset disk system
Call with AH = 00H
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
Returns: If function is successful
Carry flag = clear
AH = 00H
If function is unsuccessful
Carry flag = set
AH = status
评论:
重置磁盘控制器,重新校准其连接的驱动器。读/写臂移动到柱面 0 并为磁盘 I/O 做准备。
此函数应在软盘读取、写入、验证或格式化请求失败后调用,然后重试操作。如果使用固定磁盘驱动器调用该函数(即选择 DL>=80H),则重置软盘控制器,然后重置固定磁盘控制器。
INT 13H (0x13)
Function 01H (0x01) Get disk system status
Call with: AH = 01H
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
Returns: AH = 00H
AL = status of previous disk operation
(See the table given before for error
and status codes description).
评论:
返回最近磁盘操作的状态
INT 13H (0x13)
Function 02H (0x02) Read sector
Call with: AH = 02H
AL = number of sectors
CH = cylinder
CL = sector
DH = head
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
ES:BX = segment: offset of buffer
Returns: If function successful
Carry flag = clear
AH = 00H
AL = number of sectors transferred
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数从磁盘读取一个或多个扇区到内存中。在固定磁盘上,10 位柱面号的高 2 位放在寄存器 CL 的高 2 位中。
INT 13H (0x13)
Function 03H (0x03) Write sector
Call with: AH = 03H
AL = number of sectors
CH = cylinder
CL = sector
DH = head
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
ES: BX = segment: offset of buffer
Returns: If function successful
Carry flag = clear
AH = 00H
AL = number of sector transferred
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数将一个或多个扇区从内存写入磁盘。在固定磁盘上,10 位柱面号的高 2 位放在寄存器 CL 的高 2 位中。
INT 13H (0x13)
Function 04H (0x04) >> Verify sector
Call with: AH = 04H
AL = number of sectors
CH = cylinder
CL = sector
DH = drive
00H-7FH floppy disk
80H-FFH fixed drive
ES: BX = segment: offset of buffer
Returns: If function is successful
Carry flag = clear
AH = 00H
AL = number of sectors verified
If function is unsuccessful
Carry flag = set
AH = status
评论:
该函数验证一个或多个扇区的地址字段。此操作不会将任何数据传入或传出内存。在固定磁盘上,10 位柱面号的高 2 位被放在寄存器 CL 的高 2 位中。
此功能可用于测试可读媒体是否在软盘驱动器中。请求程序应重置软盘系统(INT 13H 功能 00H)并重试该操作 3 次,然后再假定不存在可读取的软盘。推荐在大多数软盘初始化操作中使用。
INT 13H (0x13)
Function 05H (0x05) >> Format track
Call with: AH = 05H
AL = interleave (PC/XT fixed disks)
CH = cylinder
DH = head
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
ES: BX = segment: offset of address field list
(Except PC/XT fixed disk)
Returns: If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status (see the status table given
earlier)
评论:
初始化指定磁道上的磁盘扇区和磁道地址字段。在软盘上,地址字段列表由一系列 4 字节条目组成,每个扇区一个条目。格式已在下表中给出。
在固定磁盘上,10 位柱面编号的高 2 位放在寄存器 CL 的高 2 位中。
Byte |
Contents |
0 |
Cylinder |
1 |
Head |
2 |
Sector |
3
|
Sector-size code
Value |
Description |
00H |
128 Byte per sector |
01H |
256 Byte per sector |
02H |
512 Byte per sector |
03H |
1024 Byte per sector |
|
INT 13H (0x13)
Function 06H (0x06) >> Format bad track
Call with: AH = 06H
AL = interleave
CH = cylinder
DH = head
DL = drive
80H-FFH fixed disk
Returns:If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此功能仅适用于 PC/XT 固定磁盘驱动器。它初始化一个磁道,写入磁盘地址字段和数据扇区并设置坏扇区标志。
INT 13H (0x13)
Function 07H (0x07) >> Format drive
Call with: AH = 07H
AL = interleave
CH = cylinder
DL = drive
80H-FFH fixed disk
Returns: If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status (see the status table given
earlier)
评论:
此功能仅针对 PC/XT 固定磁盘驱动器定义。它格式化整个驱动器,从指定的柱面开始写入磁盘地址字段和数据扇区。
INT 13H (0x13)
Function 08H (0x08) >> Get drive parameters
Call with: AH = 08H
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
Returns: If function successful
Carry flag = clear
BL = drive type (PC/AT and PS/2 floppy
disk)
Value |
Description |
01H |
360KB, 40 track, 5.25” |
02H |
1.2MB, 80 track, 5.25” |
03H |
720KB, 80 track, 3.5” |
04H |
1.44MB, 80 track, 3.5” |
CH = low 8 bits of maximum cylinder
number
CL = bits 6-7 high order 2 bits of maximum
cylinder number bits 0-5 maximum
sector number
DH = maximum head number
DL = number of drives
ES: DI = segment: offset of disk drive
parameter table
If function unsuccessful
Carry flag = set
AH = status
评论:
该函数返回指定驱动器的各种参数。寄存器 DL 中返回的值反映了连接到所请求驱动器的适配器的物理驱动器的真实数量。
INT 13H (0x13)
Function 09H (0x09) >> Initialize fixed disk characteristics
Call with: AH = 09H
DL = drive
80H-FFH fixed disk
On the PC/XT Vector for INT 41H
must point to disk parameter block or, on the PC/AT and PS/2
Vector for INT 41H must point to disk
parameter block for drive 0
Vector for INT 46H must point to disk
parameter block for drive 1
Returns: If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数使用 ROM BIOS 磁盘参数块中的值初始化固定磁盘控制器以进行后续 I/O 操作。该功能仅在固定磁盘上支持。 PC 和 PC/XT 硬盘的参数块格式如下:
Byte(s) |
Contents |
00H-01H |
Maximum number of cylinders |
02H |
Maximum number of heads |
03H-04H |
Starting reduced write current cylinder |
05H-06H |
Starting write pre compensation cylinder |
07H |
Maximum ECC burst length |
08H
|
Drive option
Bit(s) |
Significance (if set) |
0 – 2 |
drive option |
3 – 5 |
reserved (0) |
6 |
disable ECC entries |
7 |
disable disk-access retries |
|
09H |
Standard time-out value |
0AH |
Time-out value for format drive |
0BH |
Time-out value for check drive |
0CH-0FH |
Reserved |
PC/AT 和 PS/2 硬盘的参数块格式如下:
Byte(s) |
Contents |
00H_01H |
maximum number of cylinders |
02H |
maximum number of heads |
03H-04H |
Reserved |
05H-06H |
starting write pre compensation cylinder |
07H |
maximum ECC burst length |
08H |
Drive options
Bit(s) |
Significance (if set) |
0 – 2 |
not used |
3 |
more than 8 heads |
4 |
not used |
5 |
manufacturer’s defect map present at
maximum cylinder +1 |
6 – 8 |
nonzero (10, 01,or 11) if retries disabled |
|
09H-0BH |
Reserved |
0CH-0DH |
landing zone cylinder |
0EH |
sector per track |
0FH |
Reserved |
INT 13H (0x13)
Function 0A H (0x0A or 10) >> Read sector long
Call with: AH = 0AH
AL = number of sectors
CH = cylinder
CL = sector
DH = head
DL = drive
80H-FFH fixed disk
ES: BX = segment: offset of buffer
Returns:If function successful
Carry flag = clear
AH = 00H
AL = number of sectors transferred
If function unsuccessful
Carry flag = set
AH = status
评论:
该函数将一个或多个扇区从磁盘读取到内存中,并为每个扇区读取一个 4 字节的纠错码 (ECC) 代码。与正常的读取扇区功能(INT 13H (0x13) 功能 02H)不同,ECC 错误不会自动更正。多扇区传输在任何扇区出现读取错误后终止。
此功能仅在固定磁盘上受支持。 10 位柱面编号的高 2 位放在寄存器 CL 的高 2 位中。
INT 13H (0x13)
Function 0BH (0x0B or 11) >> Write sector long
Call with:AH = 0BH
AL = number of sectors
CH = cylinder
CL = sector
DH = head
DL = drive
80H-FFH fixed disk
ES: BX = segment: offset of buffer
Returns:If function successful
Carry flag = clear
AH = 00H
AL = number of sectors transferred
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数将一个或多个扇区从内存写入磁盘。每个扇区的数据价值必须跟在它的 4 字节 ECC 代码之后。 10 位柱面编号的高 2 位放在寄存器 CL 的高 2 位中。仅在固定磁盘上支持此功能。
INT 13H (0x13)
Function 0CH (0x0C or 12) >> Seek
Call with:AH = 0CH
CH = lower 8 bits of cylinder
CL = upper 2 bits of cylinder in bits 6-7
DH = head
DL = drive
80H-FFH fixed disk
Returns:If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数将磁盘读/写磁头定位到指定的柱面而不传输任何数据。柱面号的高 2 位存放在寄存器 CL 的高 2 位中。仅在固定磁盘上支持此功能。
INT 13H (0x13)
Function 0DH (0x0D or 13) >> Reset fixed disk system
Call with:AH = 0DH
DL = drive
80H-FFH fixed disk
Returns:If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status (see INT 13H Function 01H)
评论:
此函数重置固定磁盘控制器,重新校准连接的驱动器,将读/写臂移动到柱面 0,并为后续磁盘 I/O 做准备。
INT 13H (0x13)
Function 0EH (0x0E or 14) >> Read sector buffer
Call with:AH = 0EH
ES: BX = segment: offset of buffer
Returns:If function successful
Carry flag = clear
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数将固定磁盘适配器内部扇区缓冲区的内容传输到系统内存。没有从物理磁盘驱动器读取数据。
INT 13H (0x13)
Function 0FH (0x0F or 15) >> Write sector buffer
Call with:AH = 0FH
ES: BX = segment: offset of buffer
Returns:If function successful
Carry flag = clear
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数将数据从系统内存传输到固定适配器的内部扇区缓冲区。没有数据写入物理磁盘驱动器。在使用 INT 13H 功能 05H 格式化驱动器之前,应调用此函数来初始化扇区缓冲区的内容。
INT 13H (0x13)
Function 10H (0x10 or 16) >> Get drive status
Call with:AH = 10H
DL = drive
80H-FFH fixed disk
Returns:If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数测试指定的固定磁盘驱动器是否可以运行并返回驱动器的状态。仅在固定磁盘上支持此功能。
INT 13H (0x13)
Function 11H (0x11 or 17) >> Recalibrate drive
Call with:AH =11H
DL = drive
80H-FFH fixed disk
Returns:If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数使固定磁盘适配器为指定的驱动器重新校准自身,将读/写臂定位到柱面 0,并返回驱动器的状态。仅在固定磁盘上支持此功能。
INT 13H (0x13)
Function 12H (0x12 or 18) >> Controller RAM
diagnostic
Call with:AH = 12H
Returns:If function successful
Carry flag = clear
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数使固定磁盘适配器对其内部扇区缓冲区执行内置诊断测试,通过返回的状态指示测试是否通过。
INT 13H (0x13)
Function 13H (0x13 or 19) >> Controller drive diagnostic
Call with:AH = 13H
Returns:If function successful
Carry flag = clear
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数使固定适配器运行连接驱动器的内部诊断测试,通过返回的状态指示测试是否通过。
INT 13H (0x13)
Function 14H (0x14 or 20) >> Controller internal
diagnostic
Call with:AH = 14H
Returns:If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数使固定磁盘适配器执行内置诊断自检,通过返回状态指示测试是否通过。
INT 13H (0x13)
Function 15H (0x15 or 21) >> Get disk type
Call with:AH = 15H
DL = drive
00H-7FH floppy disk
80H-FFH fixed disk
Returns:If function successful
Carry flag = clear
AH = drive type code
00H if no drive present
01H if floppy disk drive without change-line support
02H if floppy disk drive with change-line support
03H if fixed disk
|
And, if fixed disk (AH =03H)
CX: DX = number of 512-byte sectors
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数返回一个代码,指示指定驱动器代码引用的软盘或固定磁盘的类型。
INT 13H (0x13)
Function 16H (0x16 or 22) >> Get disk change
status
Call with: AH = 16H
DL = drive
00H-7FH floppy disk
Returns:If change line inactive and disk has not been changed
Carry flag = clear
AH = 00H
If change line active and disk may have been changed
Carry flag = set
AH = 06H
评论:
此函数返回更改行的状态,指示驱动器中的磁盘自上次访问磁盘后是否已被替换。如果此函数返回并设置进位标志,则磁盘不一定被更换,更换线可以通过简单地解锁和锁定磁盘驱动器门来激活,而无需取出软盘。
INT 13H (0x13)
Function 17H (0x17 or 23) >> Set disk type
Call with: AH = 17H
AL = floppy disk type code
Value |
Description |
00H |
Not used |
01H |
320/360 KB floppy disk in 360 KB drive |
02H |
320/360 KB floppy disk in 1.2 MB drive |
03H |
1.2 MB floppy disk in 1.2 MB drive |
04H |
720 KB floppy disk in 720 KB drive |
SL = drive
00H-7FH floppy disk
Returns: If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数为指定驱动器选择软盘类型。
INT 13H (0x13)
Function 18H (0x18 or 24) >> Set media type for format
Call with: AH = 18H
CH = number of cylinders
CL = sector per track
DL = drive
00H-7FH floppy disk
Returns: If function successful
Carry flag = clear
AH = 00H
ES: DI = segment: offset of disk
parameter table for media type
If function unsuccessful
Carry flag = set
AH = status
评论:
此函数选择指定驱动器的介质特性,因此驱动器中必须存在软盘。
INT 13H (0x13)
Function 19H (0x19 or 25) >> Park heads
Call with: AH = 19H
DL = drive
80H-FFH fixed disk
Returns: If function successful
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status
评论:
该功能将读/写臂移动到不用于数据存储的磁道上,这样驱动器关闭时数据不会被损坏。
INT 13H (0x13)
Function 1AH (0x1A or 26) >> Format ESDI drive
Call with: AH = 1AH
AL = Relative Block Address (RBA)
defect table count
0, if no RBA table
>0, if RBA table used
CL = format modifier bits
Bit(s) |
Significance (if set) |
0 |
Ignore primary defect map |
1 |
Ignore secondary defect map |
2 |
Update secondary defect map |
3 |
Perform extended surface analysis |
4 |
Generate periodic interrupt |
5-7 |
Reserved (must be 0) |
DL = drive
80H-FFH fixed disk
ES: BX = segment: offset of RBA table
Returns: If function successfu
Carry flag = clear
AH = 00H
If function unsuccessful
Carry flag = set
AH = status (see INT 13H Function 01H)
评论:
此函数初始化连接到 ESDI 固定磁盘驱动器适配器的驱动器上的磁盘扇区和轨道地址字段。
此函数的操作称为低级格式化,并为扇区级别的物理读/写操作准备磁盘。随后必须使用 FDISK 命令对驱动器进行分区,然后使用 FORMAT 命令进行高级格式化以安装文件系统。