进入32位模式并导入c语言

bochs 安装

  1. 首先在bochs官网中找到bochs的最新版本的下载地址
    https://bochs.sourceforge.io/getcurrent.html
    img
    img
    img
    我这里是Windows的,直接下载Windows msi,一直点下一步就行了。
  2. 修改配置文件
    在bochs安装目录下有个bochsrc-sample.txt,这个文件bochs配置文件的实例,复制一份修改文件名称为bochsrc
    img
    打开配置文件,我们只需要修改配置文件的几项
    boot: floppy
    将引导设置成软盘引导,将之前的硬盘引导注释掉。
    img
    floppya: type=1_44, 1_44="D:\os\Lyra-os-branch\build\lyra-os.img", status=inserted, write_protected=0
    设置插入软盘大小为1.44M软盘,镜像文件为D:\os\Lyra-os-branch\build\lyra-os.img,状态是已插入,镜像保护已关闭。
    megs: 512
    设置内存大小为512M

启动报错ata0-0: could not open hard drive image file '30M.sample'
需要将#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17注释掉。
非debug模式启动则是bochs -f bochs配置文件
debug模式启动则是bochsdbg -q -f bochs配置文件

  1. 开启bochs gui debug
    文档: https://bochs.sourceforge.io/doc/docbook/user/bochsrc.html#BOCHSOPT-DISPLAYLIBRARY
    添加display_library: win32, options="gui_debug"
    根据操作系统的不同,libary库支持的也不同,bochs默认支持以下gui库:
    img

制作真正的IPL

在电脑启动的时候,BIOS会将0面0道1扇区的数据结尾是不是aa55,如果是则将该硬盘的一个扇区也就是512字节加载到0x7c00-0x7eff处。如果一个操作系统仅仅一种这512字节肯定是什么都干不了的,所以我们需要在这512字节执行的过程中,将我们的操作系统从硬盘中找出来,并加载到内存中。

    mov AX, 0x0820
    MOV ES, AX
    MOV CH, 0
    MOV DH, 0
    MOV CL, 2

    MOV AH, 0x02
    MOV AL, 1
    MOV BX, 0
    MOV DL, 0x00
    INT 0x13
    JC error

JC指令也是跳转指令,如果进位标志位为1才会进行跳转。

INT 0x13为低级磁盘服务,可以直接调用INT 0x13来对磁盘进行读写。
AH = 实现功能。
AL = 处理对象的扇区数。(1 - 128)
CH = 柱面号 (0 - 1023)
CL = 扇区号 (1 - 17)
DH = 磁头号 (0-15 dec.)
DL = 驱动器号 (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
DL = 驱动器号 (0=A:, 1=2nd floppy, 80h=C:, 81h=D:)
ES:BX = 缓冲地址

AH取值:
0x00: 磁盘复位。
0x01: 获取磁盘状态,在返回中具体有些各状态操作码的含义是什么。
0x0x: 读取磁盘。
0x03: 写入磁盘
0x04: 校验磁盘
0x0c: 寻到
除此之外还有很多很多功能,实在懒得写了,具体请看: https://stanislavs.org/helppc/int_13.html
返回:
CF = 0 读取成功
= 1 读取失败
AH = 操作状态码
00 没有错误
01 将错误的命令传递给设备
02 地址标记未找到或坏扇区
03 磁盘写保护错误
04 扇区未找到
05 固定磁盘重置失败
06 磁盘已更改或已删除
07 坏的固定磁盘参数表
08 DMA 超限
09 DMA 跨过64K边界访问
0A 固定磁盘扇区标致错误
0B 坏的磁盘柱面
0C 不支持 track/invalid 媒体
0D 在固定磁盘格式上扇区数目无效
0E 检测到固定磁盘控制的数据地址标记
0F 固定磁盘DMA仲裁水平超出范围
10 磁盘读取时出现ECC/CRC错误
11 可恢复的固定磁盘数据错误,数据被ECC修复
20 控制器错误(软盘的NEC)。
40 搜索失败
80 超时,驱动器未准备好
AA 固定磁盘驱动器未准备好
BB 固定磁盘未定义错误
CC 固定磁盘在所选驱动器上的写入故障
E0 固定磁盘状态错误/错误寄存器=0
FF 感应操作失败

我们要使用的是AH = 0x02读取磁盘的功能,我们要读取的是0柱面、0磁头、2扇区、0磁盘,分别对应这寄存器CH、CL、DH、DL。
img
圆盘中的每一个圆圈都是一个柱面 ,从外到里,柱面0、柱面1、柱面2等等。
磁头则是用于读取柱面上的数据的,磁头有两个一个用于读取正面柱面,一个则是用于读取反面的柱面。
由于单个柱面为单位继续读写的话,读写的数据较大,所以我们需要将它们拼接分割成几个相同大小的空间。软盘将它们平均分为18份,也就是说一个柱面有18各扇区。
软盘柱面正反都有写数据的,一个磁头是读取正面柱面的,一个磁头用于读取反面柱面的,所以需要 * 2 才能算出柱面的真实大小
一个软盘有80个柱面、2个磁头、18个扇区、每个扇区有512B,那么这个磁盘大小空间为:80 * 2 * 18 * 512 = 1440KB

我们需要将从软盘中读取的地方加载到内存一个位置中,在实模式中,CPU的寻址方式是ES:BX,表示ES * 16 + BX来表示内存地址,在最初设计CPU时,8086中ES存储最大为0xffff,BX存储最大为0xffff,那么根据ES * 16 + BX表示最大寻址空间为 0xffff * 0x10 + 0xffff = 0x10FFEF,也就是1,114,095字节,并不到64MB,但这个空间再当时是够用,谁也没办法想到计算机发展速度那么快,到现在内存64GB也是很常见的了。
根据公式 ES = 0x0820, AX = 0,我们将数据存储到的地址是0x8200,由于0x8000 - 0x81ff是留给启动区的,所以我们要使用之后的内存空间来加载数据。

由于读取磁盘可能会出现错误,我们要为系统添加容错,当读取磁盘失败时,那么就进行重试,如果五次都失败则直接打印错误信息。在读取磁盘时先将si初始化为0,每读取失败一次,si + 1,如果si >= 5则直接跳转到error中。如果 < 5则将磁盘复位,被那个跳转到retry中重写读取一下磁盘数据。

readloop: 
    mov si, 0

retry:
    mov ah, 0x02
    mov al, 1
    mov bx, 0
    mov dl, 0x00
    int 0x13
    jnc next
    add si, 1
    cmp si, 5
    jae error
    mov ah, 0x00
    mov dl, 0x00
    int 0x13
    jmp retry

读完一个扇区还不算完,一个柱面共有18个扇区,我们将磁盘柱面的18个扇区一起全部读完,jnc next就是做这个事情的,当读取扇区时没有发生错误时,那么就跳转到next下读取下一个扇区,一个扇区等于512个字节,每读取完毕一个扇区后,需要将缓冲地址往后移动512个字节来保存下一个扇区的内容,下方代码前两天语句就是做这个事情的,由于没有 add es, 0x0020这个指令,所以我们需要先将读取es的地址保存到ax中,在将ax 0x0020,之后再将ax的值保存到ex中。
再然后读取扇区数 + 1, 直到18个扇区全部读完跳出循环为止。

next:
    mov ax, es
    add ax, 0x0020
    mov es, ax
    add cl, 1
    cmp cl, 18
    jbe readloop

之后读完一个柱面之后还不算完,还得将10个柱面全部读到内存中来,由于盘片分为正反两面,没读取完一次柱面都需要切换一下磁头以便于读取另一面。
下面的代码是先将读取扇区初始化为1,并将柱面 + 1,磁头设置为1,然后进行读取磁盘,读取完毕后判断磁盘编号是否为2,如果是2则初始化为0,直到10个柱面全部读取完毕。

    mov cl, 1
    add dh, 1
    cmp dh, 2
    jb readloop
    mov dh, 0
    add ch, 1
    cmp ch, 10
    jb readloop

之后我们新建一个lyra-os.nsm用于编写我们操作系统的内核,代码如下,没什么好说的,就是想程序加载到内存为0xc200地址上,之后在控制台上打印一句话而已。

org 0xc200

fin:
    mov ax, 0
    mov ss, ax
    mov ds, ax
    mov es, ax
    mov si, msg
    jmp putloop

putloop: 
    mov al, [si]
    add si, 1
    cmp al, 0
    je stop
    mov ah, 0x0e
    mov bx, 15
    int 0x10
    jmp putloop
 

stop:
    HLT


msg:
    DB "Hello Lyra OS"
    DB 0x0a
    DB 0

之后将lyra-os.nas编译成lyra-os.sys,创建磁盘映像,将ipl写入到磁盘映像中,将lyra-os.sys保存到磁盘映像中,读取软盘数据完毕后跳转到lyra-os.sys内存位置执行系统功能。

  1. 使用bochs自带的bximage创建硬盘镜像文件
bximage -q -fd=1.44M -func=create -sectsize=512 -imgmode=flat lyra-os.img

以上命令为创建一个类型为fd也就是软盘的磁盘,空间为1.44M,扇区大小为512字节,硬盘格式为flat,因为ipl大小就是512字节,直接将512字节全部覆盖到软盘中即可
2. 利用dd将ipl写入到软盘中
dd for windows: http://www.chrysocome.net/dd

dd if=ipl.bin of=lyra-os.img seek=0 count=1 conv=notrunc

if表示输入
of表示输出
seek表示跳过单元数,单位为512字节
count是写单元数
conv文件转换方式,由以下几种转换方式
conversion:用指定的参数转换文件。
ascii:转换ebcdic为ascii
ebcdic:转换ascii为ebcdic
ibm:转换ascii为alternate ebcdic
block:把每一行转换为长度为cbs,不足部分用空格填充
unblock:使每一行的长度都为cbs,不足部分用空格填充
lcase:把大写字符转换为小写字符
ucase:把小写字符转换为大写字符
swap:交换输入的每对字节
noerror:出错时不停止
notrunc:不截短输出文件
sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。

  1. 将系统镜像保存到磁盘映像中,将lyra-os.sys保存到磁盘映像中即可
    winImage: https://www.winimage.com/download.htm
winimage lyra-os.img  /i lyra-os.sys /f /q /h

/F : 从命令行写入软盘时格式化
/Q :命令行运行后总是退出
/H :隐藏 WinImage 主窗口
/I xxx :将文件保存到磁盘映像中

32为模式前准备

由于16位访问内存较少且没办法使用例如EAX EBX之类的32位寄存器且还有CPU自我保护功能,所以我们需要将16位切换为32位。
需要注意的是,由于BIOS是用16位机器码写的,切换到32位就没办法使用BIOS中断了。
我们需要将一些画面的配置信息写入到指定内存中,便于以后使用,调用int16h终端向量表可以获取到shift按键状态

; BOOT_INFO相关
CYLS	EQU		0x0ff0			; 引导扇区设置
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 关于颜色的信息
SCRNX	EQU		0x0ff4			; 分辨率X
SCRNY	EQU		0x0ff6			; 分辨率Y
VRAM	EQU		0x0ff8			; 图像缓冲区的起始地址

		ORG		0xc200			;  这个的程序要被装载的内存地址

; 画面设置 

		MOV		AL,0x13			; VGA显卡,320x200x8bit
		MOV		AH,0x00
		INT		0x10
		MOV		BYTE [VMODE],8	; 屏幕的模式(参考C语言的引用)
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000

; 通过BIOS获取指示灯状态

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

VRAM中保存的地址是0x00a0000,这是根据int10h显示模式不同,显卡内部内存分配也不同,ah=0x00 al=0x13的内存分配则是0xa0000-0xaffff,320*200 8位。
其他的显示模式:http://www.columbia.edu/~em36/wpdos/videomodes.txt
地址是A000,在实模式中寻址是0xA000 * 16 + bx = 0xa0000,所以varam=0x0000
img
0xa000-0xaffff是用来显示画面的内存,检测现存,通过给这段地址分配不同的值来展示不同的画面。

开始导入c语言

之后去03_day下的harib00i中的asmhead.nask赋值到项目中,系统内核前部分是用汇编写的,后部分是用c语言写的,为了c语言调用汇编,所以在asmhead.nask中添加了100多行的代码,这些代码的含义先条共,后面几章会有讲解。
c语言代码如下:
HariMain是main函数,这个不符合我项目,后期应该可以改吧。。大概,这里的作用是一个死循环。

void HariMain(void) {
    fin:

    goto fin;
}

c语言调用汇编或者汇编调用c语言需要以下几个步骤:

  1. ccl基于gcc而gcc又基于gas汇编,所以我们首先需要将c语言程序编译为gas汇编程序。
    -o:输出
cc1 -o bootpack.gas .\bootpack.c
  1. nask不支持gas语法,所以还需要将gas转换为nask语法。
gas2nask .\bootpack.gas bootpack.nas
  1. 编译nask源代码为obj文件,也就是目标文件,这个目标文件就是二进制文件。
nask .\bootpack.nas .\bootpack.obj bootpack.lst
  1. 单单编译目标文件还没办法直接运行,还需要与其他的二进制文件进行链接才能够使用,所以还需要进行链接操作。有些c语言需要调用汇编语言的命令,在c语言中编写函数体,在汇编语言中编写相应的汇编语句,经过链接就能实现c语言调用汇编语言的操作了。
    根据光盘目录下的haribote.rul规则配置文件进行连接,可以看到该配置文件中依赖了harilibc.lib与golibc.lib文件。
    out: 输出
    map: 输出map文件(可选) 然后开始输出.map文件,输出三种段的大小以及处理过的全局的符号表,也不知道这个的作用是什么。
    stack: 在makefile中写的是MB+64KB=3136KB,不知道这个东西作用的是什么。
 obj2bim @光盘目录\z_tools\haribote\haribote.rul out:bootpack.bim stack:3136k map:bootpack.map .\bootpack.obj 
  1. 加工操作,加上识别专用的文件头、压缩等。
    0:堆不知道为什么会设置成0,后面应该后讲吧。
bim2hrb bootpack.bim bootpack.hrb 0
  1. 将二进制文件进行拼接保存为.sys文件
copy /B asmhead.bin+bootpack.hrb lyra-os.sys

实现hit

[FORMAT "WCOFF"]
[BITS 32]
[FILE "naskfun.nas"]

GLOBAL _io_hlt

[SECTION .text]
_io_hlt:
    hlt
    ret
  • FORMAT定义了目标文件格式,COFF表示通用对象文件格式,COFF: https://wiki.osdev.org/COFF。
  • BITS定义了编译为32位机器码模式。
  • FILE定义了源文件名称,在目标模式下,必须指定源文件名称。
  • GLOBAL定义了一个全局的暴漏给c语言调用的函数名称,函数名称必须是以_前缀才能与c语言进行了链接。
  • [SECTION .text]保存代码段,是只读可执行的。
  • 之后就是_io_hlt的函数体实现了

前三行定义了源文件的基本信息,后四行为函数的定义与实现。

之后在c语言中定义函数,调用即可

void io_hlt(void);

void HariMain(void) {
    fin:
    io_hlt();

    goto fin;
}

链接时将c语言与汇编语言进行链接,就行了

	cc1 -o bootpack.gas .\bootpack.c
	gas2nask .\bootpack.gas bootpack.nas
	nask .\bootpack.nas .\bootpack.obj bootpack.lst
	obj2bim @D:\os\os\tolset\z_tools\haribote\haribote.rul out:bootpack.bim stack:3136k map:bootpack.map .\bootpack.obj naskfun.obj
	bim2hrb bootpack.bim bootpack.hrb 0
	copy /B asmhead.bin+bootpack.hrb lyra-os.sys
posted @ 2023-04-25 10:53  RainbowMagic  阅读(97)  评论(0编辑  收藏  举报