用nasm语言重新实现linux-0.11 setup.s (博古以通今)

;文件名:followking/boot/setup.s
;本文件改写linux-0.11/boot/setup.s,目的是为了体验整个系统构建的过程。
;我是看着赵炯《Linux内核0.11完全注释》编写的。不过,我是编写代码,有疑问再看。
;我用的nasm的语法格式。我想写一个操作系统,现在觉得最简单的方式莫过于
;先把前辈的实现的东西重新实现一遍。等到对这个问题有更深刻认识的时候,
;再重新思考,写出有自己特色的系统。
;作者:hk0625
;开始时间: 2010年03月19号星期五 21:02 
;完成时间: 2010年03月20号星期六 20:49
;最后修改时间: 2010年04月08日星期四 09:05
;早上走了狗屎运了,终于把调试问题给解决了。起码调试一个系统对于我来说,
;已经没有太大挑战了。想一想,也挺不容易,从开始,到现在。这种准备已经两年多了。
;今天老乡聚会,喝了点酒,有点醉。状态不错,继续编吧。
;地点:北化1#宿舍楼426
;下面let's try

;setup.s负责从BIOS中获得系统数据,并将这些数据放到系统内存:0x90000 -0x901ff。
;此时setup.s和system已经由bootsect引导块加载到内存中。
;下面这些参数最好和bootsect.s中相同。
INITSEG  equ 0x9000 ;原来bootsect所处的段
SYSSEG  equ 0x1000 ;system在0x10000(64k)处
SETUPSEG equ 0x9020 ;本程序所在的段地址
;下面几个全局变量,我至今还不知道它们有什么作用。我为了避免可能因为它们引起的
;问题而采取保留它们的决策。O(∩_∩)O~,这一切都是暂时的。等到我弄明白主要的东东
;再回来处理这一些细节。不过作为一个展现一个系统实现的过程,我觉得把这种想法
;留下来是有它的价值的。这是一个处理你不熟悉问题的一个很好的思路。
global begtext, begdata, begbss, endtext, enddata, endbss
section .text
begtext:

start:
;保存光标位置以备后用。
 mov ax, INITSEG ;虽然这在bootsect已经设置过,但为了避免这里出错,
   ;还是重设吧。。。
 mov ds, ax
;读取光标的位置
 mov ah, 0x03
 xor bh, bh
 int 0x10
 mov [0], dx ;保存光标位置到ds:0即0x9000:0000处
 
;获得扩展内存的大小
 mov ah, 0x88
 int 0x15
 mov [2], ax

;获得视屏卡数据
 mov ah, 0x0f
 int 0x10
 mov [4], bx
 mov [6], ax

;检查显示方式(EGA/VGA)并取一些参数
 mov ah, 0x12
 mov bl, 0x10
 int 0x10
 mov [8], ax
 mov [10], bx
 mov [12], cx
;获取第一个硬盘分区的数据(即hd0)
 mov ax, 0x0000
 mov ds, ax
 lds si, [4*0x41] ;取中断向量0x41的值,也即hd0参数表的地址到ds:si
 mov ax, INITSEG
 mov es, ax
 mov di, 0x0080 ;目的地地址(es:di):0x9000:0x080
 mov cx, 0x10 ;共传输0x10字节。
 rep
 movsb

;获得hd1的数据
 mov ax, 0x0000
 mov ds, ax
 lds si, [4*0x46]
 mov ax, INITSEG
 mov es, ax
 mov di, 0x0090
 mov cx, 0x10
 rep
 movsb

;检查系统是否存在第2个硬盘,如果不存在则把第2个表清零。
 mov ax, 0x1500
 mov dl, 0x81
 int 0x13
 jc no_disk
 cmp ah, 3
 je is_disk1
no_disk:
 mov ax, INITSEG
 mov es, ax
 mov di, 0x0090
 mov cx, 0x10
 mov ax, 0x00
 rep
 stosb
is_disk1:
;注:上面BIOS调用,具体的参数设置我还不清楚,不过没有关系,让我们先进行下面的
;工作,等到出现问题再回过头来深究它。搞懂他们很简单,找一本中断大全即可。
;O(∩_∩)O~,听着迈克尔杰克逊的歌编程,很有劲。

;现在进入保护模式。。。。

 cli ;关掉中断,很多书上都这么说,我还是不太明白。。。
  ;也许以后会明白吧
;接下来,我们把system模块从0x10000(64k)移到0x00000处。这里有一个小问题,
;一定要注意,我们有两种方法来表示一块内存所处的位置
;比如说64k处我们可以这样表示0x10000,也可以这样0x1000:0000。
;这个问题对于初学者很容易困惑,很多困惑的根源在此。更详细的自己去查资料吧,
;推荐一本书吧王爽《汇编语言》不错,说得通俗易懂。呵呵,如果你理解这个问题,
 mov ax, 0x0000
 cld
do_move:
 mov es, ax ;目的地段,初始为0x0000然后依次递增0x1000, 0x2000
 add ax, 0x1000  ;0x3000 ...一直到0x9000 目的地:es:di
 cmp ax, 0x9000
 jz end_move
 mov ds, ax ;这里 ds被初始为0x1000  源地址ds:si
 sub di, di
 sub si, si
 mov cx, 0x8000 ;移动32k字(64k字节)O(∩_∩)O~,数学系出身还是有点用
   ;嘛,起码换算这个还是很拿手的。。。
   ;呵呵,just a kidding!
 rep
 movsw
 jmp do_move

;接下来我们开始加载段描述符。在这里推荐两本书吧。
;《80x86 80x87的结构与汇编语言程序设计》周明德 张淑玲编著清华大学出版社出版
;其中第六章80386的工作方式从124到156页值得一看。这段从理解实模式到保护模式
;应该有帮助(还有虚拟8086模式的切换)。呵呵
;另外一本不用说,于渊《自己动手编写操作系统》,可以当作实现时参考书。
 end_move:
 mov ax, SETUPSEG
 mov ds, ax
 lidt [idt_48] ;加载中断描述符表
 
 lgdt [gdt_48] ;加载全局描述符表

;现在我们可以打开A20
 call empty_8042
 
 mov al, 0xD1
 out 0x64, al
 
 call empty_8042
 mov al, 0xDF
 out 0x60, al
 call empty_8042
;注:上面这段程序,我得再找一些资料来看看。O(∩_∩)O~
;接下来重新对中断进行编程,这块很弱。先照猫画虎吧。
 mov al, 0x11
 out 0x20, al

 dw  0x00eb, 0x00eb ;作用延时
 out 0xA0, al
 dw 0x00eb, 0x00eb ;这个技巧之前在一本书看过,
 out 0x21, al ;没想到在这里看到它的应用
 dw 0x00eb, 0x00eb
 mov al, 0x28
 out  0xA1, al
 dw 0x00eb, 0x00eb
 mov al, 0x04
 out 0x21, al
 dw 0x00eb, 0x00eb
 mov al, 0x02
 out 0xA1, al
 
 dw 0x00eb, 0x00eb
 mov al, 0x01
 out 0x21, al
 
 dw 0x00eb, 0x00eb
 out 0xA1, al
 dw 0x00eb, 0x00eb
 mov al, 0xFF
 out 0x21, al
 dw 0x00eb, 0x00eb
 out 0xA1, al

;这里设置进入32位保护模式运行。首先加载机器状态字即控制寄存器CR0,然后将其第一个
;比特位改为1。具体的原理可以参考《80x86 80x87的结构与汇编语言程序设计》
;周明德 张淑玲编著清华大学出版社出版 其中第六章80386的工作方式
;有关编程方面也可以参考一下于渊的《自己动手编写操作系统》
 mov ax, 0x0001
 lmsw ax
; cli ;测试用
 jmp CodeSelector:0x0000
; jmp  $  ;这条指令是为了调试用的。
;下面这个子程序检查键盘命令队列是否为空。这里不使用超时方法 - 如果这里死机,
;则说明pc机有问题,我们就没有办法在处理下去了。
;只有当输入缓冲器为空时(状态寄存器2 = 0)才可以对其进行写命令。
empty_8042:
 dw 0x00eb, 0x00eb
 in al, 0x64
 test al, 2
 jnz empty_8042
 ret
;全局描述符表。
gdt:
 dw 0, 0, 0, 0 ;这个描述符表不用
;段代码寄存器  
CodeGdt:
 dw 0x07FF
 dw 0x0000
 dw 0x9A00
 dw 0x00C0

;数据段寄存器
DataGdt:
 dw 0x07FF
 dw 0x0000
 dw 0x9200
 dw 0x00C0
CodeSelector equ CodeGdt - gdt
DataSelector equ DataGdt - gdt
idt_48:
 dw 0
 dw 0, 0

gdt_48:
 dw 0x800
 dw 512+gdt, 0x9

endtext:
section .data
begdata:
enddata:
section .bss
begbss:
endbss:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值