哈工大操作系统学习L2 之 揭开钢琴的盖子
Open the OS
从打开电源开始
打开电源à计算机要开始工作了,计算机怎么工作? 这是我们最最基本, 也最最重要的常识…
从白纸到图灵机
计算机怎么工作? 说到底就是一个计算模型,下图为由图灵提出的模型:
一台图灵机是如何实现加法的呢?通过控制器在纸带上读入3;在纸带上读入2;在纸带上读入+;控制器查表知道是5;在纸带上写下5。以上就是整个过程。那么如果有其它的运算呢?除了加法我们还能做什么?
从图灵机到通用图灵机
图灵机就好像一个只会做一道菜的厨师,而通用图灵机则是一个能看懂菜谱的厨师。通用图灵机通过修改控制器,并且设置控制器的动作,进行工作。而这一系列的控制器动作也就是我们今天所说的程序。
从通用图灵机到计算机
1946年 冯·诺依曼提出存储程序思想,将程序和数据存放到计算机内部的存储器中,计算机在程序 的控制下一步一步进行处理。这是这一伟大思想奠定了今天的计算机基础。
计算机由五大部件组成:输入设备、输出设备、存储器、运算器、控制器
举个例子:
打开电源,计算机执行的第 一句指令什么?
指针IP及其指向的内容
计算机刚打开电源时,IP=? 是由硬件设计者决定。
对于X86PC机而言:
(1)x86 PC刚开机时CPU处于实模式
(2)开机时,CS=0xFFFF; IP=0x0000
(3)寻址0xFFFF0(ROM BIOS映射区)
(4)检查RAM,键盘,显示器,软硬磁盘
(5)将磁盘0磁道0扇区读入0x7c00处
(6)设置cs=0x07c0,ip=0x0000
注意:实模式和保护模式对应,实模式的寻址CS:IP(CS左移4位+IP), 和保护模式不一样!
0x7c00处存放的代码
就是从磁盘引导扇区读入的那512个字节:
- 引导扇区就是启动设备的第一个扇区(开机时按住del键可进入 启动设备设置界面,可 以设置为光盘启动!)
- 启动设备信息被设置在CMOS中…(CMOS: 互补金属氧化物半导 体(64B-128B)。用来存储实 时钟和硬件配置信息。)
- 因此,硬盘的第一个扇区上存放着开机 后执行的第一段我们可以控制的程序。
操作系统的故事从这里开始…
引导扇区代码: bootsect.s
.s 表明是汇编语言的代码。
globl begtext,begdata,begbss,endtext,enddata,endbss
.text //文本段
begtext:
.data //数据段
begdata:
.bss //未初始化数据段
begbss:
entry start //关键字entry告诉链接器“程序入口”
start:
mov ax, #BOOTSEG mov ds, ax //此条语句就是0x7c00 ;ds=7c0,es=9000
处存放的语句!
mov ax, #INITSEG mov es, ax // ;es=9000
mov cx, #256
sub si, si sub di,di //连接
rep movw //将0x07c0:0x0000处的256个 字移动到0x9000:0x0000处
jmpi go, INITSEG //cs=go,ip=INITSEC
BOOTSEG=0x07c0
INITSEG=0x9000
SETUPSEG=0x9020
(1).text等是伪操作符,告诉编译器产生 文本段,.text用于标识文本段的开始 位置。 此处的.text、.data、.bss表明这3个 段重叠,不分段!
jmpi go, INITSEG
jmpi (jump intersegment段间跳转): cs=INITSEG, ip=go
go: mov ax,cs //cs=0x9000
mov ds,ax mov es,ax mov ss,ax mov sp,#0xff00
load_setup: //载入setup模块
mov dx,#0x0000 mov cx,#0x0002 mov bx,#0x0200
mov ax,#0x0200+SETUPLEN int 0x13 //BIOS中断
jnc ok_load_setup
mov dx,#0x0000
mov ax,#0x0000 //复位
int 0x13
j load_setup //重读
其中:0x13是BIOS读磁盘扇区的 中断: ah=0x02-读磁盘,al=扇区数量(SETUPLEN=4),
ch=柱面号,cl=开始扇区,dh=磁头号,dl=驱动器号,es:bx=内存地址(即0x90200)
读入setup模块后: ok_load_setup
Ok_load_setup: //载入setup模块
mov dl,#0x00 mov ax,#0x0800 //ah=8获得磁盘参数
int 0x13 mov ch,#0x00 mov sectors,cx
mov ah,#0x03 xor bh,bh int 0x10 //读光标
mov cx,#24 mov bx,#0x0007 //7是显示属性! //修改开机logo时候需修改这24个字符
mov bp,#msg1 mov ax,#1301 int 0x10 //显示字符
mov ax,#SYSSEG //SYSSEG=0x1000
mov es,ax
call read_it //读入system模块,此处也是利用0x13 的BIOS中断
jmpi 0,SETUPSEG //转入0x9020:0x0000 执行setup.s
bootsect.s中的数据 //在文件末尾
sectors: .word 0 //磁道扇区数
msg1:.byte 13,10
.ascii “Loading system...” //开机时候的logo
.byte 13,10,13,10
read_it //读入system模块
为什么读入 system模块还需要定义一个函数?
因为system模块可能很大, 要跨越磁道
read_it: mov ax,es cmp ax,#ENDSEG jb ok1_read
ret
ok1_read:
mov ax,sectors
sub ax,sread //sread是当前磁道已读扇区数,ax未读扇区数
call read_track //读磁道...
对于 jb ok1_read :
ENDSEG=SYSSEG+SYSSIZE
SYSSIZE=0x8000 //该变量可根据
Image大小设定(编译操作系统时
引导扇区的末尾 //BIOS用以识别引导扇区
.org 510
.word 0xAA55 //扇区的最后两个字节
否则会打出非引导设备。
接下来可以转入setup执行了,jmpi 0, SETUPSEG 继续将控制权交给setup,(通过CS,IP)