这次操作系统会对内存布局做最后一次大调整
这张图是上次学习时的内存布局
进入setup.s文件
现在程序跳转到了0x90200这个位置开始执行,这个位置的代码就位于setup.s的开头
start:
mov ax,#0x9000 ; this is done in bootsect already, but...
mov ds,ax
mov ah,#0x03 ; read cursor pos
xor bh,bh
int 0x10 ; save it in known place, con_init fetches
mov [0],dx ; it from 0x90000.
这里又出现的int指令时触发BIOS提供的中断服务,就是调用显示服务相关的中断处理程序
代码中ah寄存器被赋值为0x13表示显示服务里具体的读取光标位置功能这个子服务
int 0x10执行完中断处理后返回时,会在dx寄存器中存储好光标的位置,高八位行号,低八位列号
计算机加电自检后会自动初始化到文字模式,在这种模式下,一屏幕可以显示25行×80列
mov [0],dx 就是把这个光标位置存储在 [0] 这个内存地址处
这里需要注意,前面学过这个内存地址是偏移地址,最终的物理地址是要加上ds寄存器里存储的段基址
这里就可以知道,0x90000处存着光标位置,这在之后初始化控制台的时候会用到
操作系统最开始的时候会多次调用BIOS提供的现成程序
接下来的代码也是调用一个BIOS中断获取断点信息,然后存储在内存中的某个位置
代码放在下面了,逻辑和前面那段是一样的,注释里写得很清楚
比如获取内存信息。
; Get memory size (extended mem, kB)
mov ah,#0x88
int 0x15
mov [2],ax
获取显卡显示模式。
; Get video-card data:
mov ah,#0x0f
int 0x10
mov [4],bx ; bh = display page
mov [6],ax ; al = video mode, ah = window width
检查显示方式并取参数
; check for EGA/VGA and some config parameters
mov ah,#0x12
mov bl,#0x10
int 0x10
mov [8],ax
mov [10],bx
mov [12],cx
获取第一块硬盘的信息。
; Get hd0 data
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
mov ax,#0x0000
mov ds,ax
lds si,[4*0x46]
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
rep
movsb
这些代码执行完后,内存地址及其对应存储的信息就整理在下面的表格中
保存好这些信息后,操作系统会执行cli命令关闭中断
cli ; no interrupts allowed ;
因为后面要覆盖掉原本bios写好的中断向量表
即后面我们会破坏掉原有的中断向量表,写上自己的中断向量表。所以这个时候是不允许中断进来
接下来的代码:
; first we move the system to it's rightful place
mov ax,#0x0000
cld ; 'direction'=0, movs moves forward
do_move:
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:
...
这里又有了熟悉的rep指令,又是搬运内存中的内容
最终的结果是,把内存地址 0x10000 处开始往后一直到 0x90000 的内容,统统复制到内存的最开始的 0 位置
如下图所示
现在的内存布局就变成了这样
极客时间《Linux0.11源码趣读》学习笔记day7