手写操作系统 - 操作系统内核突破512字节
2023-12-29 12:49:19
1. 如何让内核突破512字节?
boot.asm
和setup.asm
编译后生成对应的boot.o
和setup.o
文件,boot.o
由dd
命令写入硬盘的0磁道0柱面1扇区
,由BIOS例程
自动读入内存的0x7c00
处;setup.o
通过dd
命令写入硬盘的0磁道0柱面2扇区
,并且写两个扇区,然后由boot
读入内存。
2. 对 CMOS、BIOS、MBR、GPT、GRUB、UEFI基本认识。
总结:
- mbr是老版,gpt是新版
- mbr仅支持4个分区,gpt支持128个分区
- mbr支持最大2TB,gpt最大支持无限制
- 一般搭配:
bios
+mbr
、uefi
+gpt
3. 硬盘工作原理、汇编实现同步读写硬盘。
文件系统、OS如何操作硬盘,如下图:
- lba28以及lab48
LBA28 和 LBA48 是指逻辑块寻址(Logical Block Addressing, LBA)的两种模式,它们用于硬盘驱动器的数据寻址。这些模式定义了硬盘可以寻址的最大范围。- LBA28可以寻址的最大存储容量是 2^28×512 字节,即128GB。
- LBA28可以寻址的最大存储容量是 2^48×512 字节,即128PB(Petabytes,1PB 等于 1024 TB)。
- IO端口分配地址以及硬盘控制器
除了
0x1F0
为两个字节外,其余的都为一个字节,其中0x1F3 ~ 0x1F5
分别为lab28
低八位、中八位以及高八位,再加上0x1F6
的低四位,总共28位。
- 读写硬盘的一般流程
- 操作多少个扇区
- 往0x1f2写入操作的扇区数
- 从哪开始操作?
- 通过
0x1F3 ~ 0x1F6
四个寄存器拼起来的
- 通过
- 给硬盘发送读命令
- 读0x1F7,判断第4位和7位
- 读:获取硬盘的状态 0x20 读
写:给硬盘发命令 0x30 写
0xec 获取硬盘信息
- 读:获取硬盘的状态 0x20 读
- 读0x1F0端口,读256次,一次2个字节,总共512字节一个扇区。
- 操作多少个扇区
- 汇编实现同步写硬件
1)基本框架
;boot.asm
;0磁道0柱面1扇区
[ORG 0x7c00]
[SECTION .data]
BOOT_MAIN_ADDR equ 0x500
[SECTION .text]
[BITS 16]
global _start
_start:
;设置屏幕输出文本模式,清除屏幕
mov ax, 3
int 0x10
;跳过去
mov si, jmp_to_setup
call print
jmp $
;如何调用
;mov si, msg ;1.传入字符串
;call print ;2 调用
print:
mov ah, 0x0e
mov bh, 0
mov bl, 0x10
.loop:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .loop
.done:
ret
jmp_to_setup:
db "jump to setup...", 10, 13, 0
times 510 - ($ - $$) db 0
db 0x55, 0xaa
2)增加汇编代码实现对硬件的同步读
列出0x1F7寄存器图:
下图分析是对的
在基本框架基础上增加寄存器操作实现boot.asm:
;0磁道0柱面1扇区
[ORG 0x7c00]
[SECTION .data]
BOOT_MAIN_ADDR equ 0x500 ;BOOT_MAIN_ADDR值为0x500
[SECTION .text]
[BITS 16]
global _start
_start:
;设置屏幕输出文本模式,清除屏幕
mov ax, 3
int 0x10
mov ecx, 2 ; 从硬盘哪个扇区开始读
mov bl, 2 ;读取扇区的数量
; 0x1f2 8bit 指定读取或写入的扇区数
mov dx, 0x1f2
mov al, bl
out dx, al ;out指令仅能与累加寄存器使用al、ax、eax
; 0x1f3 8bit iba地址的第八位 0-7
inc dx ;增加DX寄存器的值(指向下一个端口0x1f3)
mov al, cl
out dx, al
; 0x1f4 8bit iba地址的中八位 8-15
inc dx
mov al, ch
out dx, al
; 0x1f5 8bit iba地址的高八位 16-23
inc dx
shr ecx, 16
mov al, cl
out dx, al
; 0x1f6 8bit
; 0-3 位iba地址的24-27
; 4 0表示主盘 1表示从盘
; 5、7位固定为1
; 6 0表示CHS模式,1表示LAB模式
inc dx
mov al, ch
and al, 0b1110_1111
out dx, al
; 0x1f7 8bit 命令或状态端口
inc dx
mov al, 0x20 ;读
out dx, al
; 验证状态
; 3 0表示硬盘未准备好与主机交换数据 1表示准备好了
; 7 0表示硬盘不忙 1表示硬盘忙
; 0 0表示前一条指令正常执行 1表示执行出错 出错信息通过0x1f1端口获得
.read_check:
mov dx, 0x1f7
in al,dx
and al, 0b1000_0100 ; 取硬盘状态的第3、7位
cmp al, 0b0000_0100 ;硬盘数据准备好了且不忙了
jnz .read_check
;读数据
mov dx, 0x1f0
mov cx, 256 ;loop次数
mov edi, BOOT_MAIN_ADDR ;将EDI寄存器设置为0x500
.read_data:
in ax, dx
mov [edi], ax ;把ax的值给edi所指向的内存地址
add edi, 2
loop .read_data
;跳过去
mov si, jmp_to_setup
call print
jmp BOOT_MAIN_ADDR
;如何调用
;mov si, msg ;1.传入字符串
;call print ;2 调用
print:
mov ah, 0x0e
mov bh, 0
mov bl, 0x10
.loop:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .loop
.done:
ret
jmp_to_setup:
db "jump to setup...", 10, 13, 0
times 510 - ($ - $$) db 0
db 0x55, 0xaa
setup.asm实现:
; 0柱面0磁道2扇區
[ORG 0x500]
[SECTION .text]
[BITS 16]
global _start
_start:
;寄存器初始化操作
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov si, ax
mov si, msg
call print
jmp $
; 如何调用
; mov si, msg ; 1 传入字符串
; call print ; 2 调用
print:
mov ah, 0x0e
mov bh, 0
mov bl, 0x01
.loop:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .loop
.done:
ret
msg:
db "hello", 10, 13, 0
3)运行成功效果图
运行完boot
后打印输出jump to setup...
,打印结束后通过jmp BOOT_MAIN_ADDR
跳到setup
执行。
文章来源:https://blog.csdn.net/weixin_53492721/article/details/134678547
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!