首先,非常感谢《30天自制操作系统》这本书,为我解决了非常多的困惑并提供了一些工具的源码,以便于我用来修改并兼容中文汇编。
因此这篇文章用中文汇编的方式展示书上32位保护模式和C语言的导入(后面开发可能不这样写)。下面直接贴上源码:
柱面数 等 10
装载 0x7c00
跳 主体
字 0x90
字 "NAJCNAJC"
双字 512
字 1
双字 1
字 2
双字 224
双字 2880
字 0xf0
双字 9
双字 18
双字 2
四字 0
四字 2880
字 0,0,0x29
四字 0xffffffff
字 "JC-OS--NAJC"
字 "FAT12 "
补字 18
主体:
移 寄加,0
移 段堆,寄加
移 栈指,0x7c00
移 段数,寄加
移 寄加,0x0820
移 段附,寄加
移 寄计高,0
移 寄数高,0
移 寄计低,2
循环读:
移 变源,0
重试:
移 寄加高,0x02
移 寄加低,1
移 寄基,0
移 寄数低,0
中断 0x13
不错跳 下一遍
加 变源,1
比 变源,5
高等跳 错误
移 寄加高,0
移 寄数低,0
中断 0x13
跳 重试
下一遍:
移 寄加,段附
加 寄加,0x0020
移 段附,寄加
加 寄计低,1
比 寄计低,18
低等跳 循环读
移 寄计低,1
加 寄数高,1
比 寄数高,2
低跳 循环读
移 寄数高,0
加 寄计高,1
比 寄计高,柱面数
低跳 循环读
移 [0x0ff0],寄计高
跳 0xc200
错误:
移 变源,消息
循环输出:
移 寄加低,[变源]
加 变源,1
比 寄加低,0
等跳 最后
移 寄加高,0x0e
移 寄基,15
中断 0x10
跳 循环输出
最后:
休
跳 最后
消息:
字 0x0a, 0x0a
字 "load error"
字 0x0a
字 0
补字 0x1fe-($-$$)
字 0x55, 0xaa
上面是系统的启动引导,该引导写入在磁盘的第0柱面第0号磁头第1扇区。启动时把该引导装载到0x7c00。引导的源码实现了从第0柱面第0号磁头第2扇区读取软盘的10个柱面一共180KB写入到内存0x8200地址(段附x16+寄基)。写入完成后跳转到0xc200(下面系统文件在0x4200,而上面读取从0x200开始,因此0x8200+0x4200-0x200=0xc200)进行执行。
接下来就是加载到0xc200处的系统源码:
BOTPAK 等 0x00280000
DSKCAC 等 0x00100000
DSKCAC0 等 0x00008000
启动区 等 0x0ff0
键盘灯 等 0x0ff1
模式 等 0x0ff2
宽 等 0x0ff4
高 等 0x0ff6
缓冲区 等 0x0ff8
装载 0xc200
移 寄加低,0x13
移 寄加高,0x00
中断 0x10
移 转字 [模式],8
移 转双字 [宽],320
移 转双字 [高],200
移 转四字 [缓冲区],0x000a0000
移 寄加高,0x02
中断 0x16
移 [键盘灯],寄加低
移 寄加低,0xff
出 0x21,寄加低
空
出 0xa1,寄加低
禁中断
调 waitkbdout
移 寄加低,0xd1
出 0x64,寄加低
调 waitkbdout
移 寄加低,0xdf
出 0x60,寄加低
调 waitkbdout
全描 [GDTR0]
移 高寄加,寄控0
和 高寄加,0x7fffffff
或 高寄加,0x00000001
移 寄控0,高寄加
跳 pipelineflush
pipelineflush:
移 寄加,8
移 段数,寄加
移 段附,寄加
移 段附f,寄加
移 段附g,寄加
移 段堆,寄加
移 高变源,bootpack
移 高变目,BOTPAK
移 高寄计,512*1024/4
调 memcpy
移 高变源,0x7c00
移 高变目,DSKCAC
移 高寄计,512/4
调 memcpy
移 高变源,DSKCAC0+512
移 高变目,DSKCAC+512
移 高寄计,0
移 寄计低,转字 [启动区]
符乘 高寄计,512*18*2/4
减 高寄计,512/4
调 memcpy
移 高寄基,BOTPAK
移 高寄计,[高寄基+16]
加 高寄计,3
逻右移 高寄计,2
零跳 skip
移 高变源,[高寄基+20]
加 高变源,高寄基
移 高变目,[高寄基+12]
调 memcpy
skip:
移 高栈指,[高寄基+12]
跳 转四字 2*8:0x0000001b
waitkbdout:
入 寄加低,0x64
和 寄加低,0x02
非零跳 waitkbdout
返
memcpy:
移 高寄加,[高变源]
加 高变源,4
移 [高变目],高寄加
加 高变目,4
减 高寄计,1
非零跳 memcpy
返
section align=16
GDT0:
补字 8
双字 0xffff,0x0000,0x9200,0x00cf
双字 0xffff,0x0000,0x9a28,0x0047
双字 0
GDTR0:
双字 8*3-1
四字 GDT0
section align=16
bootpack:
以上代码是进入32位保护模式的代码,这些先不做介绍,“移 高变源,bootpack
移 高变目,BOTPAK
移 高寄计,512*1024/4
调 memcpy”这段代码是把bootpack以下的部分复制到0x00280000,由于每次复制4个字节所以除于4。最后跳转到0x28001b开始执行下面代码:
void io_hlt();
void write_mem8(int addr, int data);
void JCMain()
{
int i;
char *p;
p = 0xa0000;
for (i = 0;i<=0xffff;i++)
{
p[i] = i &0x0f;
}
for(;;)
{
io_hlt();
}
}
通过编译并通过gas2najc.exe转码后:
[BITS 32]
EXTERN _io_hlt
[SECTION .text]
全局 _JCMain
_JCMain:
入栈 高基指
异或 高寄数,高寄数
移 高基指,高栈指
L6:
移 寄加低,寄数低
和 高寄加,15
移 转字 [655360+高寄数],寄加低
自增 高寄数
比 高寄数,65535
小等跳 L6
L7:
调 _io_hlt
跳 L7
可以看出C语言的函数在汇编里面是标签,我们这里定义了全局的_JCMain,经过最终链接后会变成地址。JCMain是我们的main函数,启动时调用。Main里面就是对0xa000到0xffff进行赋值,通过makefile生成img格式,可以在vmware虚拟机加载,结果显示条纹。
后续有时间时,我会按照linux启动的模式用中文汇编再次写一个系统加载。
CSDN源码:https://download.csdn.net/download/u011736517/12142310