Linux0.11版源代码分析——boot/setup.s
Linux0.11版源码分析第二篇,setup.s注释分析。
! ! setup.s (C) 1991 Linus Torvalds ! ! setup.s is responsible for getting the system data from the BIOS, ! and putting them into the appropriate places in system memory. ! both setup.s and system has been loaded by the bootblock. ! ! This code asks the bios for memory/disk/other parameters, and ! puts them in a "safe" place: 0x90000-0x901FF, ie where the ! boot-block used to be. It is then up to the protected mode ! system to read them from there before the area is overwritten ! for buffer-blocks. ! ! ! setup.s (C) 1991 Linus Torvalds版权所有 ! ! setup负责从BIOS获取系统数据,并存储在适当的内存位置, ! setup和system都已经被引导程序bootsect加载到内存了 ! ! ! 这个代码向bios询问内存/硬盘和其它参数,然后将这些参数放置到安全的地方: 0x90000-0x901FF ! 也就是原来bootsect呆的地方。在该缓冲区被覆盖前,由保护模式的system读取 ! !注意!以下参数最好和bootsect中的相同 ! INITSEG = 0x9000 ! we move boot here - out of the way !boots所在位置 SYSSEG = 0x1000 ! system loaded at 0x10000 (65536). !system所在位置 SETUPSEG = 0x9020 ! this is the current segment !setup所在位置 .globl begtext, begdata, begbss, endtext, enddata, endbss !定义全局标识符 .text begtext: .data begdata: .bss begbss: .text entry start !入口地址,跳转至标号start处 start: ! start标号 ! ok, the read went well so we get current cursor position and save it for !ok,读取磁盘过程很成功,我们获取当前光标位置并保存 ! posterity. ! mov ax,#INITSEG ! this is done in bootsect already, but... !ds指向0x9000位置 mov ds,ax ! mov ah,#0x03 ! read cursor pos !利用中断0x10读取光标位置 xor bh,bh ! int 0x10 ! save it in known place, con_init fetches !执行中断 mov [0],dx ! it from 0x90000. !将该位置保存到ds:[0]处即0x90000 ! Get memory size (extended mem, kB) !获取内存大小 mov ah,#0x88 !功能号 int 0x15 !执行中断0x15 mov [2],ax !将内存大小保存到0x90002处 ! Get video-card data: !获取显卡数据 mov ah,#0x0f !中断功能号 int 0x10 !执行中断0x10 mov [4],bx ! bh = display page !保存显示页 mov [6],ax ! al = video mode, ah = window width !保存显示模式、字符列数 ! check for EGA/VGA and some config parameters !检测EGA/VGA和一些配置参数 mov ah,#0x12 !功能号 mov bl,#0x10 !功能号 int 0x10 !执行中断 mov [8],ax !保存不知道放了什么东西??? mov [10],bx !保存显存和显示模式 mov [12],cx !保存显卡特性参数 ! Get hd0 data !获取hd0的参数,第一个硬盘参数表的首地址是向量0x41的向量值 !为加载该向量 mov ax,#0x0000 mov ds,ax lds si,[4*0x41] !取出参数 mov ax,#INITSEG mov es,ax mov di,#0x0080 mov cx,#0x10 rep movsb !放置到指定位置 ! Get hd1 data !获取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 ! Check that there IS a hd1 :-) !检测是否有第二块硬盘 mov ax,#0x01500 !驱动器号 mov dl,#0x81 !功能号 int 0x13 !执行中断查询 jc no_disk1 !flags中标记,判断是否存在第二个硬盘 cmp ah,#3 !比较ah中的返回值 je is_disk1 !有第二个硬盘 no_disk1: !没有第二个硬盘,参数清零,就是前面保存的值清零 mov ax,#INITSEG mov es,ax mov di,#0x0090 mov cx,#0x10 mov ax,#0x00 rep stosb is_disk1: !如果有第二个硬盘,准备进入保护模式 ! now we want to move to protected mode ... !准备进入保护模式 cli ! no interrupts allowed ! !关中断 ! first we move the system to it's rightful place mov ax,#0x0000 ! cld ! 'direction'=0, movs moves forward !清方向位 do_move: !移动system mov es,ax ! destination segment add ax,#0x1000 cmp ax,#0x9000 jz end_move mov ds,ax ! source segment sub di,di sub si,si mov cx,#0x8000 rep movsw jmp do_move ! then we load the segment descriptors !加载描述符表 end_move: mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) !设置ds指向 mov ds,ax lidt idt_48 ! load idt with 0,0 !加载中断描述符寄存器 lgdt gdt_48 ! load gdt with whatever appropriate !加载全局描述符寄存器 ! that was painless, now we enable A20 !打开A20地址 call empty_8042 !检测是否为空可写 mov al,#0xD1 ! command write !命令字 out #0x64,al !写命令 call empty_8042 !检测是否为空可写 mov al,#0xDF ! A20 on !命令字 out #0x60,al !写命令,使A20打开 call empty_8042 !检查是否为空,如果为空,则可打开a20 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-( !希望可以很好的运行,现在我们不得不去进行中断编程设置 ! we put them right after the intel-reserved hardware interrupts, at !我们将它放置在intel保留中断的后面,即int 0x20-0x2F ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really !在那里放置不会引起混乱,很不幸的是ibm在原来的pc机中 ! messed this up with the original PC, and they haven't been able to !搞混乱了再也没有改过来。bios设置中断在0x08-0x0f,所以我们 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, !需要重新对8259A重新编程控制,这一点也不好玩。 ! which is used for the internal hardware interrupts as well. We just ! ! have to reprogram the 8259's, and it isn't fun. ! mov al,#0x11 ! initialization sequence !初始化 out #0x20,al ! send it to 8259A-1 ! .word 0x00eb,0x00eb ! jmp $+2, jmp $+2 ! out #0xA0,al ! and to 8259A-2 ! .word 0x00eb,0x00eb ! mov al,#0x20 ! start of hardware int's (0x20) !开始中断port out #0x21,al ! .word 0x00eb,0x00eb ! mov al,#0x28 ! start of hardware int's 2 (0x28) !开始中断port out #0xA1,al .word 0x00eb,0x00eb mov al,#0x04 ! 8259-1 is master !设置为主芯片 out #0x21,al .word 0x00eb,0x00eb mov al,#0x02 ! 8259-2 is slave !设置为从芯片 out #0xA1,al .word 0x00eb,0x00eb mov al,#0x01 ! 8086 mode for both !设置主从芯片8086模式 out #0x21,al .word 0x00eb,0x00eb !延时 out #0xA1,al .word 0x00eb,0x00eb !跳转延时 mov al,#0xFF ! mask off all interrupts for now !屏蔽主从芯片中断请求 out #0x21,al .word 0x00eb,0x00eb !延时 out #0xA1,al ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't ! need no steenking BIOS anyway (except for the initial loading :-). ! The BIOS-routine wants lots of unnecessary data, and it's less ! "interesting" anyway. This is how REAL programmers do it. ! ! Well, now's the time to actually move into protected mode. To make ! things as simple as possible, we do no register set-up or anything, ! we let the gnu-compiled 32-bit programs do that. We just jump to ! absolute address 0x00000, in 32-bit protected mode. mov ax,#0x0001 ! protected mode (PE) bit !保护模式 lmsw ax ! This is it! !加载状态字 jmpi 0,8 ! jmp offset 0 of segment 8 (cs) !跳转到system处执行,8是段选择子 ! This routine checks that the keyboard command queue is empty !这个程序检测键盘命令队列是否为空。这里不是用超时检测方法, ! No timeout is used - if this hangs there is something wrong with !(.word 0x00eb,0x00eb跳转)是因为如果出问题,就是pc机问题 ! the machine, and we probably couldn't proceed anyway. !我们没办法再进行下去了 empty_8042: !检测8042控制器 .word 0x00eb,0x00eb !不用超时的方法,而是采用跳转的方法延时0x00eb其实就是jump in al,#0x64 ! 8042 status port !读控制器的的状态控制器 test al,#2 ! is input buffer full? !通过返回值检测输入控制器是否已满 jnz empty_8042 ! yes - loop !如果满,则继续检测,直至该缓冲器为空,为写命令字提供条件 ret gdt: .word 0,0,0,0 ! dummy .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) .word 0x0000 ! base address=0 .word 0x9A00 ! code read/exec .word 0x00C0 ! granularity=4096, 386 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) .word 0x0000 ! base address=0 .word 0x9200 ! data read/write .word 0x00C0 ! granularity=4096, 386 idt_48: .word 0 ! idt limit=0 .word 0,0 ! idt base=0L gdt_48: .word 0x800 ! gdt limit=2048, 256 GDT entries .word 512+gdt,0x9 ! gdt base = 0X9xxxx .text endtext: .data enddata: .bss endbss: