如何所有的磁盘扇区组装迭代? [英] How are all disk sectors iterated in assembly?
问题描述
在学习汇编的过程中,我写的操作系统。我已经成功写入必要的code对追加第二个512字节扇区最初的512字节的引导程序:
%定义KBDINT 0x16
%定义VIDINT为0x10
%定义DISKINT 0x13
%定义TTYOUT为0x0E
%定义为0x0000 vidmode运行
%定义NUL为0x00
%定义CR 0X0D
%定义LF的0x0A
%定义开始0x7C00%宏PRINT 1
MOV SI,1%
调用打印
%endmacro 位16; 16位实模式
组织START;在内存中加载程序启动
启动:JMP主打印:JMP .init
.loop:MOV BX,vidmode运行
MOV啊,TTYOUT
INT VIDINT
INC SI
.init:MOV人,[SI]
CMP人,NUL
JNE .loop
RET主:CLI
异斧,斧
MOV DS,AX
MOV ES,AX
STI
PRINT欢迎 MOV啊,NUL
INT DISKINT
MOV等,为0x01;扇区计数
MOV啊,0X02;读取功能
MOV BX,内核
MOV CL,0X02
MOV CH,0×00;柱面号
MOV DH,0×00;头数
INT DISKINT
JC失败
JMP内核失败:PRINT失败
; JMP叫停暂停:暂停打印
CLI
HLT
PRINT imprbbl
JMP叫停 欢迎DB驼鹿OS,CR,LF NUL
失败分贝故障磁盘负荷,CR,LF NUL
暂停DB停止,CR,LF NUL
imprbbl分贝,但是这是不可能的!,CR,LF NUL次0x0200 - ($ - $$) - 2分贝为0x00
结束DW 0xAA55将内核:PRINT耶
耶DB内核,CR,LF NUL
JMP叫停次0xFFFF的分贝为0x00
我编译的文件: NASM -f斌-o BOOT.BIN boot.asm&放大器;&安培; QEMU BOOT.BIN
:
我很好奇,怎么头和气瓶使用:
- 如何在部门通过迭代?
- 仿真和直接执行之间如何迭代有什么不同?
•如何在部门通过迭代?
块引用>要使用的 CHS CylinderHeadSector符号迭代许多部门,我们
首先必须检索这些参数的实际限制。 BIOS中有功能
08H在INT 13H
,让我们在最大值,以及一些额外的
信息,我们不需要现在。在CL的扇区数为1至63结果
在DH头数的取值范围为0〜255,虽然255是很少使用。结果
在CL气缸数目的范围从0到1023由于这不能在举行
一个字节,该10比特数的2的最高位存储在第6位
和CL的7注册!的迭代是如何工作的
想想CHS表示法,就好像它是某种多项,其中的 C 是
最显著的部分和取值是最显著的部分。结果
要到磁盘上的下一个扇区,我们开始我们的这个增量
号的在其至少显著结束。结果
如果通过增加在取值的一部分,我们溢出其范围,我们把它重置为
最小值(1),并开始递增下一更显著一部分
是的 ^ h 在这种情况下。结果
如果通过增加在 ^ h 的一部分,我们溢出其范围,我们把它重置为
最小值(0),并开始递增的最显著一部分
是的 C 在这种情况下。结果
如果通过增加在 C 的一部分,我们溢出其范围,我们把它重置为
最小值(0)。这将使该磁盘上的存储空间。如果输入
正确的SectorCount在这一点上读数被赋予那么通常会有
停了下来。; INPUT:DL =驱动器
; CH =汽缸
; DH =头
; CL =部门
; AX = SectorCount
; ES:BX =缓冲区
;输出:CF = 0 AH = 0
; CH,DH,CL =以下部门CHS
; CF = 1 AH =错误状态
; CH,DH,CL =问题部门CHS
ReadDiskSectors:
ES推
推迪
推基点
MOV BP,SP;局部变量:
推斧[BP-2] = SectorCount
推CX; [BP-4] = MaxSector
推DX; [BP-6] = MaxHead
推BX; [BP-8] = MaxCylinder ES推
MOV啊,08H
INT 13H; ReturnDiskDriveParameters
流行ES
JC NOK
MOV BX,CX; 10位缸信息 - > BX
XCHG BL,BH
SHR BH,6
XCHG [BP-8],BX;存储MaxCylinder并获得输入BX回来
MOVZX DX,DH 8位头信息 - > DX
XCHG [BP-6,DX;存储MaxHead并获得输入DX回来
和CX,003FH; 6位的行业资讯 - > CX
XCHG [BP-4],CX;存储MaxSector并获得输入CX回来ReadNext:
MOV DI,5;最大5试图每个扇区
ReadAgain:
MOV AX,0201H;读取扇区
INT 13H; ReadDiskSectors
JNC OK
推斧;在AH保存错误状态字节
MOV啊,00H
诠释13H; ResetDiskSystem
流行斧
十二月二
JNZ ReadAgain
STC
JMP NOK
好:
癸字PTR [BP-2]; SectorCount
JZ就绪
电话NextCHS
MOV AX,ES;移动缓冲512字节起来
加斧,十六分之五百十二
MOV ES,AX
JMP ReadNext准备:
调用NextCHS;返回有用的CHS值支持读取
XOR啊,啊; - > CF = 0 ...是不是内存不再
NOK:
MOV SP,BP
流行基点
流行迪
流行ES
RETNextCHS:
MOV人,CL;计算6比特扇区号
和人,00111111b
CMP人,[BP-4]; MaxSector
JB NextSector
CMP DH,[BP-6]; MaxHead
JB NextHead
MOV AX,CX;计算的10位柱面数
XCHG人啊
SHR啊,6
CMP AX,[BP-8]; MaxCylinder
JB NextCylinder
DiskWrap:
MOV CX,1;环绕式在磁盘上的第一个扇区
MOV DH,0
RET
NextCylinder:
INC斧
SHL啊,6;在CL和CH斯普利特10位柱面数
XCHG人啊
MOV CX,AX
MOV DH,0
INC CL
RET
NextHead:
INC DH
和Cl,11000000b
NextSector:
INC CL
RET上的扇区大小的说明
虽然这是完全正常的,以具有不在512字节扇区
长度,这是一个假设保存,他们将是大小。
的经过几十年的节目我从来没有见过那些没有512字节的任何磁盘
部门。的结果
如果你坚持要支持不同的尺寸,你可以看看第4个字节
从DI:在DisketteParameterTable为您收到的ES指针
BIOS的功能ReturnDiskDriveParameters。
•仿真和直接执行之间如何迭代有什么不同?
块引用>我想通过的直接执行的你了解真实的硬件。结果
对于真正的硬件BIOS将返回的几何CHS符号和部门存在的...好只是因为他们是真实的!结果
在仿真模拟器会尽力还为您提供将这些几何值,但是这将是由你来确保有关驱动器上存在足够的部门。这正是@Jester说,当他问你:你甚至有图像文件中的行业通过使用放大图像文件来解决这个问题倍0xFFFF的分贝为0x00
一些额外的建议
您没有设置堆栈。既然你在加载的7C00h处上面的启动扇区你的内核,我建议你初始化SS:SP到0000h:7C00h处的启动扇区下一个堆栈
。主:
CLI
异斧,斧
MOV DS,AX
MOV ES,AX
MOV SS,AX
MOV SP,7C00h处
STI
PRINT欢迎由于@Fifoernik评论你最好把
JMP停止
的耶DB仁之前,CR,LF NUL
至prevent该数据的执行力!内核:
PRINT耶
JMP叫停
耶DB内核,CR,LF NULIn the process of learning assembly, I am writing an OS. I have successfully written the code necessary for appending a second 512 byte sector to the initial 512 byte bootloader:
%define KBDINT 0x16 %define VIDINT 0x10 %define DISKINT 0x13 %define TTYOUT 0x0E %define VIDMODE 0x0000 %define NUL 0x00 %define CR 0x0D %define LF 0x0A %define START 0x7C00 %macro PRINT 1 mov si, %1 call print %endmacro bits 16 ; 16 bit real mode org START ; loader start in memory start: jmp main print: jmp .init .loop: mov bx, VIDMODE mov ah, TTYOUT int VIDINT inc si .init: mov al, [si] cmp al, NUL jne .loop ret main: cli xor ax, ax mov ds, ax mov es, ax sti PRINT welcome mov ah, NUL int DISKINT mov al, 0x01 ; sector count mov ah, 0x02 ; read function mov bx, kernel mov cl, 0x02 mov ch, 0x00 ; cylinder number mov dh, 0x00 ; head number int DISKINT jc fail jmp kernel fail: PRINT failure ; jmp halt halt: PRINT halting cli hlt PRINT imprbbl jmp halt welcome db "moose os", CR, LF, NUL failure db "failed disk load", CR, LF, NUL halting db "halting", CR, LF, NUL imprbbl db "but that's impossible!", CR, LF, NUL times 0x0200 - ($ - $$) - 2 db 0x00 end dw 0xAA55 kernel: PRINT yay yay db "kernel", CR, LF, NUL jmp halt times 0xFFFF db 0x00
I compile the file with:
nasm -f bin -o boot.bin boot.asm && qemu boot.bin
:I am curious how heads and cylinders are used:
- How are the sectors iterated through?
- How does iteration differ between emulation and direct execution?
解决方案•How are the sectors iterated through?
To iterate over many sectors using CHS CylinderHeadSector notation, we first have to retrieve the actual limits on these parameters. BIOS has function 08h on
int 13h
that gives us the maximum values as well as some extra info that we don't need for now.The sector number in CL ranges from 1 to 63.
The head number in DH ranges from 0 to 255, although 255 is seldom used.
The cylinder number in CL ranges from 0 to 1023. Since this cannot be held in a single byte, the 2 highest bits of this 10-bit number are stored in bits 6 and 7 of the CL register!How the iteration works
Think of the CHS notation as if it were some kind of number where C is the most significant part and S is the least significant part.
To get to the next sector on the disk we start our incrementation of this number at its least significant end.
If by incrementing the S part we overflow its range, we reset it to its smallest value (1) and start incrementing the next more significant part which is H in this case.
If by incrementing the H part we overflow its range, we reset it to its smallest value (0) and start incrementing the most significant part which is C in this case.
If by incrementing the C part we overflow its range, we reset it to its smallest value (0). This will make for a wraparound on the disk. If on input a correct SectorCount was given then normally at this point reading will have stopped.; INPUT: DL=Drive ; CH=Cylinder ; DH=Head ; CL=Sector ; AX=SectorCount ; ES:BX=Buffer ; OUTPUT: CF=0 AH = 0 ; CH,DH,CL = CHS of following sector ; CF=1 AH = Error status ; CH,DH,CL = CHS of problem sector ReadDiskSectors: push es push di push bp mov bp,sp ;Local variables: push ax ;[bp-2]=SectorCount push cx ;[bp-4]=MaxSector push dx ;[bp-6]=MaxHead push bx ;[bp-8]=MaxCylinder push es mov ah,08h int 13h ;ReturnDiskDriveParameters pop es jc NOK mov bx,cx ;10-bit cylinder info -> BX xchg bl,bh shr bh,6 xchg [bp-8],bx ;Store MaxCylinder and get input BX back movzx dx,dh ;8-bit head info -> DX xchg [bp-6],dx ;Store MaxHead and get input DX back and cx,003Fh ;6-bit sector info -> CX xchg [bp-4],cx ;Store MaxSector and get input CX back ReadNext: mov di,5 ;Max 5 tries per sector ReadAgain: mov ax,0201h ;Read 1 sector int 13h ;ReadDiskSectors jnc OK push ax ;Save error status byte in AH mov ah,00h int 13h ;ResetDiskSystem pop ax dec di jnz ReadAgain stc jmp NOK OK: dec word ptr [bp-2] ;SectorCount jz Ready call NextCHS mov ax,es ;Move buffer 512 bytes up add ax,512/16 mov es,ax jmp ReadNext Ready: call NextCHS ;Return useful CHS values to support reads xor ah,ah ; -> CF=0 ... that are longer than memory NOK: mov sp,bp pop bp pop di pop es ret NextCHS: mov al,cl ;Calculate the 6-bit sector number and al,00111111b cmp al,[bp-4] ;MaxSector jb NextSector cmp dh,[bp-6] ;MaxHead jb NextHead mov ax,cx ;Calculate the 10-bit cylinder number xchg al,ah shr ah,6 cmp ax,[bp-8] ;MaxCylinder jb NextCylinder DiskWrap: mov cx,1 ;Wraparound to very first sector on disk mov dh,0 ret NextCylinder: inc ax shl ah,6 ;Split 10-bit cylinder number over CL and CH xchg al,ah mov cx,ax mov dh,0 inc cl ret NextHead: inc dh and cl,11000000b NextSector: inc cl ret
A note on sector size
Although it's perfectly alright to have sectors that are not 512 bytes in length, it's a save assumption that they will be that size. After decades of programming I've never seen any disk that hadn't 512-byte sectors.
If you insisted on supporting different sizes, you can look at the 4th byte of the DisketteParameterTable for which you recieved a pointer in ES:DI from the BIOS function ReturnDiskDriveParameters.•How does iteration differ between emulation and direct execution?
I suppose that by direct execution you understand real hardware.
For real hardware BIOS will return you the geometry in CHS notation and the sectors exist ... well just because they are real!
Under emulation the emulator will do its best to also provide you will these geometry values but it will be up to you to make sure that enough sectors exist on the concerned drive. This is exactly what @Jester said when he asked you: "Do you even have that sector in the image file?" You resolved this issue by enlarging the image file usingtimes 0xFFFF db 0x00
Some extra advice
You didn't setup the stack. Since you load your kernel above the bootsector at 7C00h, I suggest you initialize SS:SP to 0000h:7C00h for a stack beneath the bootsector.
main: cli xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, 7C00h sti PRINT welcome
As @Fifoernik commented you would better put the
jmp halt
before theyay db "kernel", CR, LF, NUL
to prevent the execution of this data!kernel: PRINT yay jmp halt yay db "kernel", CR, LF, NUL
这篇关于如何所有的磁盘扇区组装迭代?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!