|
发表于 2021-9-13 18:00:24
|
显示全部楼层
不对,就算是使用中断的方式读取硬盘数据
也是在硬盘准备数据的这段时间可以切换到其他程序去执行
等硬盘准备好了,处理器需要切回来,从硬盘的 io 端口两个字节两个字节的读取 256 次数据到内存
然后再切去别的程序,等下一个中断到来了,还要切回来,循环 256 次读取硬盘 io 端口
就是说,如果不使用 dma,处理器就需要从硬盘 io 端口,两个字节两个字节的读取数据到内存
这几天我找了好多相关的资料,自己也写程序验证了
之前回复你的,有一些是错误的,^_^
还有,书上,百度上说的,PC/AT 机器,dma 通道只有一个 SDLC 通信适配器(通道1) 和 一个 软盘驱动器(通道2),没有硬盘的
我在 bochs 上找到的是软盘的和 sb16(Sound Blaster 16)的,没有硬盘的
我在百度上找到了一个使用 PCI-IDE控制器 的
使用 dma 要枚举 pci 配置空间
或者改用 软盘
两个的代码量都有点多,而且考虑到要用汇编语言,我实在写不下去了,^_^
未来有机会的话,可以考虑用 C语言
学习这些东西之前要先学汇编语言,学了汇编语言你就可以使用汇编语言验证你的猜想
- .code16
- .globl _start
- _start:
- ljmpw $0x07c0, $1f
- 1: xorw %ax, %ax
- movw %ax, %ss
- movw $0x7c00, %sp
- callw interrupt_init
- callw register_disk_interrupt
- callw enable_disk_interrupt
- # 全局变量初始化
- # flag = 0;
- movb $0, %cs:0 # 就把它放在这里,这不会有任何问题
- # 读取从扇区 0 开始的 8 个扇区到 ds:si 指定的位置
- movw $0x07e0, %ax
- movw %ax, %ds
- xorw %si, %si
- movw $8, %cx
- xorw %bx, %bx
- callw read_sect
- movw $0xb800, %ax
- movw %ax, %ds
- movb o', 0x06e0
- movb k', 0x06e2
- movb $0x04, 0x06e1
- movb $0x04, 0x06e3
- cli
- hlt
- 3: jmp 3b
- # void read_sect(uint8_t *buff, size_t start_sect, size_t count);
- # buff -> ds:si
- # start_sect -> bx
- # count -> cx
- read_sect:
- pushw %ax
- pushw %cx
- pushw %dx
- pushw %si
- pushw %bx
- # 读取 count 个扇区
- movb %cl, %al
- movw $0x01f2, %dx
- outb %al, (%dx)
- # 发送逻辑扇区号
- movb %bl, %al
- movw $0x01f3, %dx
- outb %al, (%dx)
- movb %bh, %al
- movw $0x01f4, %dx
- outb %al, (%dx)
- movb $0, %al
- movw $0x01f5, %dx
- outb %al, (%dx)
- movb $0xe0, %al # 主盘,LBA 模式
- movw $0x01f6, %dx
- outb %al, (%dx)
- # 发送读命令
- movb $0x20, %al
- movw $0x01f7, %dx
- outb %al, (%dx)
- movw %cx, %bx
- # 等待硬盘准备好
- 1: movb %cs:0, %al
- cmpb $1, %al
- jne 1b
- movb $0, %cs:0
- # 从硬盘读取数据
- xorw %cx, %cx
- movw $0x01f0, %dx
- 2: inw (%dx), %ax
- movw %ax, (%si)
- addw $2, %si
- incw %cx
- cmpw $256, %cx # 512 字节,256 个字
- jb 2b
- decw %bx
- cmpw $0, %bx
- jne 1b
- popw %bx
- popw %si
- popw %dx
- popw %cx
- popw %ax
- retw
- # void interrupt_init(void);
- interrupt_init:
- cli
- pushw %ax
- pushw %cx
- pushw %dx
- pushw %si
- pushw %ds
- # ICW1: 边沿触发/级联方式
- movb $0x11, %al
- movw $0x20, %dx
- outb %al, (%dx)
- # ICW2: 起始中断向量
- movb $0x20, %al
- movw $0x21, %dx
- outb %al, (%dx)
- # ICW3: 从片级联到IR2
- movb $0x04, %al
- movw $0x21, %dx
- outb %al, (%dx)
- # ICW4: 非总线缓存/特殊全嵌套/非自动结束
- movb $0x11, %al
- movw $0x21, %dx
- outb %al, (%dx)
- # ICW1: 边沿触发/级联方式
- movb $0x11, %al
- movw $0xa0, %dx
- outb %al, (%dx)
- # ICW2: 起始中断向量
- movb $0x28, %al
- movw $0xa1, %dx
- outb %al, (%dx)
- # ICW3: 从片级联到IR2
- movb $0x02, %al
- movw $0xa1, %dx
- outb %al, (%dx)
- # ICW4: 非总线缓存/普通全嵌套/非自动结束
- movb $0x01, %al
- movw $0xa1, %dx
- outb %al, (%dx)
- # 设置默认中断
- xorw %cx, %cx
- movw %cx, %ds
- movw $0x20 * 4, %si
- movw $ignore_interrupt, %ax
- movw %cs, %dx
- 1: movw %ax, (%si)
- movw %dx, 2(%si)
- addw $4, %si
- incw %cx
- cmpw $16, %cx
- jb 1b
- popw %ds
- popw %si
- popw %dx
- popw %cx
- popw %ax
- sti
- retw
- # void ignore_interrupt(void);
- ignore_interrupt:
- pushw %ax
- pushw %dx
- # 发送 OCW2
- movb $0x20, %al
- movw $0xa0, %dx
- outb %al, (%dx)
- movb $0x20, %al
- movw $0x20, %dx
- outb %al, (%dx)
- popw %dx
- popw %ax
- iretw
- # void register_disk_interrupt(void);
- register_disk_interrupt:
- cli
- pushw %ax
- pushw %dx
- pushw %ds
- xorw %ax, %ax
- movw %ax, %ds
- movw $disk_interrupt, %ax
- movw %cs, %dx
- # IRQ14
- movw %ax, 0xb8
- movw %dx, 0xba
- popw %ds
- popw %dx
- popw %ax
- sti
- retw
- # void disk_interrupt(void);
- disk_interrupt:
- pushw %ax
- pushw %dx
- # 读取硬盘状态
- movw $0x01f7, %dx
- inb (%dx), %al
- andb $0x88, %al
- cmpb $0x08, %al
- jne 1f
- # 硬盘数据准备好了
- # flag = 1;
- movb $1, %cs:0
- 1:
- # 发送 OCW2
- movb $0x20, %al
- movw $0xa0, %dx
- outb %al, (%dx)
- movb $0x20, %al
- movw $0x20, %dx
- outb %al, (%dx)
- popw %dx
- popw %ax
- iretw
- # void enable_disk_interrupt(void);
- enable_disk_interrupt:
- pushw %ax
- pushw %dx
- movb $0x00, %al
- movw $0x03f6, %dx
- outb %al, (%dx)
- popw %dx
- popw %ax
- retw
复制代码 |
|