当前位置: 首页 > news >正文

MyOS第三天——进入32位模式并导入C语言

MyOS 进入32位模式并导入C语言

在ubuntu下编译第三天的代码

修改Makefile

  1. 重新定义工具和参数
# 定义工具和参数
# Ubuntu下使用系统自带的工具,无需再指定z_tools路径
MAKE     = make
NASM     = nasm
GCC      = gcc
LD       = ld
OBJCOPY  = objcopy
QEMU     = qemu-system-i386
RM       = rm -f
CP       = cp# GCC编译选项:
# -m32: 生成32位代码 (Haribote运行在32位保护模式)
# -nostdlib: 不使用标准库 (我们是在写操作系统内核)
# -fno-pie: 关闭位置无关可执行文件 (内核需要固定地址)
# -I. : 头文件路径
CFLAGS   = -m32 -nostdlib -fno-pie -I. -Os -Wall -Wextra# 链接选项:
# -m elf_i386: 指定生成32位的 elf 格式 (配合 -m32 使用)
# -Ttext 0xc200: 将代码段起始地址指定为0xc200,对应haribote的bootpack装载地址
LDFLAGS  = -m elf_i386 -Ttext 0xc200# 默认动作
default :$(MAKE) img# 1. 编译IPL (启动区)
ipl10.bin : ipl10.nas$(NASM) ipl10.nas -o ipl10.bin -l ipl10.lst# 2. 编译汇编启动头 (asmhead)
asmhead.bin : asmhead.nas$(NASM) asmhead.nas -o asmhead.bin -l asmhead.lst# 3. 编译C语言内核文件 (bootpack)
#   将 .c 文件直接编译为 32位 的 .o 对象文件
bootpack.o : bootpack.c Makefile$(GCC) $(CFLAGS) -c bootpack.c -o bootpack.o# 4. 编译汇编函数文件
naskfunc.o : naskfunc.nas Makefile$(NASM) -f elf32 naskfunc.nas -o naskfunc.o -l naskfunc.lst# 5. 链接生成内核二进制文件
#   链接所有 .o 文件,并输出为 elf 格式,再用 objcopy 转为纯二进制
bootpack.bin : bootpack.o naskfunc.o Makefile$(LD) $(LDFLAGS) bootpack.o naskfunc.o -o bootpack.elf$(OBJCOPY) -O binary bootpack.elf bootpack.bin# 6. 合并启动头与内核,生成最终系统文件
haribote.sys : asmhead.bin bootpack.bincat asmhead.bin bootpack.bin > haribote.sys# 7. 制作磁盘镜像 (使用dd命令创建软盘镜像并写入文件)
haribote.img : ipl10.bin haribote.sys# 创建一个空的1440KB软盘镜像dd if=/dev/zero of=haribote.img bs=512 count=2880 2>/dev/null# 将ipl10.bin写入第一个扇区dd if=ipl10.bin of=haribote.img bs=512 count=1 conv=notrunc 2>/dev/null# 拷贝系统文件到镜像中 (这里借助mcopy工具,如果没有请先安装: sudo apt install mtools)# 或者你也可以利用后续的run指令直接通过QEMU挂载文件夹,不一定要打包进imgmcopy -i haribote.img haribote.sys ::# 8. 运行 (通过QEMU直接启动)
run : haribote.sys$(QEMU) -drive file=haribote.sys,format=raw,if=floppy -boot a# 9. 完整制作镜像
img :$(MAKE) haribote.img# 10. 清理临时文件
clean :$(RM) *.bin *.lst *.o *.elf *.sys *.img# 11. 彻底清理(包括镜像)
src_only :$(MAKE) clean$(RM) haribote.img

修改nas文件

  1. 修改 RESB 关键字
; ipl10.nas
; haribote-ipl
; TAB=4CYLS	EQU		10				; 声明CYLS=10ORG		0x7c00			; 指明程序装载地址; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy codeJMP		entryDB		0x90DB		"HARIBOTE"		; 启动扇区名称(8字节)DW		512				; 每个扇区(sector)大小(必须512字节)DB		1				; 簇(cluster)大小(必须为1个扇区)DW		1				; FAT起始位置(一般为第一个扇区)DB		2				; FAT个数(必须为2)DW		224				; 根目录大小(一般为224项)DW		2880			; 该磁盘大小(必须为2880扇区1440*1024/512)DB		0xf0			; 磁盘类型(必须为0xf0)DW		9				; FAT的长度(必??9扇区)DW		18				; 一个磁道(track)有几个扇区(必须为18)DW		2				; 磁头数(必??2)DD		0				; 不使用分区,必须是0DD		2880			; 重写一次磁盘大小DB		0,0,0x29		; 意义不明(固定)DD		0xffffffff		; (可能是)卷标号码DB		"HARIBOTEOS "	; 磁盘的名称(必须为11字?,不足填空格)DB		"FAT12   "		; 磁盘格式名称(必??8字?,不足填空格)RESB	18				; 先空出18字节; 程序主体entry:MOV		AX,0			; 初始化寄存器MOV		SS,AXMOV		SP,0x7c00MOV		DS,AX; 读取磁盘MOV		AX,0x0820MOV		ES,AXMOV		CH,0			; 柱面0MOV		DH,0			; 磁头0MOV		CL,2			; 扇区2readloop:MOV		SI,0			; 记录失败次数寄存器retry:MOV		AH,0x02			; AH=0x02 : 读入磁盘MOV		AL,1			; 1个扇区MOV		BX,0MOV		DL,0x00			; A驱动器INT		0x13			; 调用磁盘BIOSJNC		next			; 没出错则跳转到finADD		SI,1			; 往SI加1CMP		SI,5			; 比较SI与5JAE		error			; SI >= 5 跳转到errorMOV		AH,0x00MOV		DL,0x00			; A驱动器INT		0x13			; 重置驱动器JMP		retry
next:MOV		AX,ES			; 把内存地址后移0x200(512/16十六进制转换)ADD		AX,0x0020MOV		ES,AX			; ADD ES,0x020因为没有ADD ES,只能通过AX进行ADD		CL,1			; 往CL里面加1CMP		CL,18			; 比较CL与18JBE		readloop		; CL <= 18 跳转到readloopMOV		CL,1ADD		DH,1CMP		DH,2JB		readloop		; DH < 2 跳转到readloopMOV		DH,0ADD		CH,1CMP		CH,CYLSJB		readloop		; CH < CYLS 跳转到readloop; 读取完毕,跳转到haribote.sys执行!MOV		[0x0ff0],CH		; IPLがどこまで読んだのかをメモJMP		0xc200error:MOV		SI,msgputloop:MOV		AL,[SI]ADD		SI,1			; 给SI加1CMP		AL,0JE		finMOV		AH,0x0e			; 显示一个文字MOV		BX,15			; 指定字符颜色INT		0x10			; 调用显卡BIOSJMP		putloopfin:HLT						; 让CPU停止,等待指令JMP		fin				; 无限循环msg:DB		0x0a, 0x0a		; 换行两次DB		"load error"DB		0x0a			; 换行DB		0;		RESB	0x7dfe-$		; 填写0x00直到0x001fetimes 0x1fe-($-$$) db 0DB		0x55, 0xaa
  1. 修改 asmhead.nas 文件
; haribote-os boot asm
; TAB=4BOTPAK	EQU		0x00280000		; 加载bootpack
DSKCAC	EQU		0x00100000		; 磁盘缓存的位置
DSKCAC0	EQU		0x00008000		; 磁盘缓存的位置(实模式); 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显卡,320x200x8bitMOV		AH,0x00INT		0x10MOV		BYTE [VMODE],8	; 屏幕的模式(参考C语言的引用)MOV		WORD [SCRNX],320MOV		WORD [SCRNY],200MOV		DWORD [VRAM],0x000a0000; 通过BIOS获取指示灯状态MOV		AH,0x02INT		0x16 			; keyboard BIOSMOV		[LEDS],AL; 防止PIC接受所有中断
;	AT兼容机的规范、PIC初始化
;	然后之前在CLI不做任何事就挂起
;	PIC在同意后初始化MOV		AL,0xffOUT		0x21,ALNOP						; 不断执行OUT指令OUT		0xa1,ALCLI						; 进一步中断CPU; 让CPU支持1M以上内存、设置A20GATECALL	waitkbdoutMOV		AL,0xd1OUT		0x64,ALCALL	waitkbdoutMOV		AL,0xdf			; enable A20OUT		0x60,ALCALL	waitkbdout; 保护模式转换;[INSTRSET "i486p"]				; 说明使用486指令LGDT	[GDTR0]			; 设置临时GDTMOV		EAX,CR0AND		EAX,0x7fffffff	; 使用bit31(禁用分页)OR		EAX,0x00000001	; bit0到1转换(保护模式过渡)MOV		CR0,EAXJMP		pipelineflush
pipelineflush:MOV		AX,1*8			;  写32bit的段MOV		DS,AXMOV		ES,AXMOV		FS,AXMOV		GS,AXMOV		SS,AX; bootpack传递MOV		ESI,bootpack	; 源MOV		EDI,BOTPAK		; 目标MOV		ECX,512*1024/4CALL	memcpy; 传输磁盘数据; 从引导区开始MOV		ESI,0x7c00		; 源MOV		EDI,DSKCAC		; 目标MOV		ECX,512/4CALL	memcpy; 剩余的全部MOV		ESI,DSKCAC0+512	; 源MOV		EDI,DSKCAC+512	; 目标MOV		ECX,0MOV		CL,BYTE [CYLS]IMUL	ECX,512*18*2/4	; 除以4得到字节数SUB		ECX,512/4		; IPL偏移量CALL	memcpy; 由于还需要asmhead才能完成
; 完成其余的bootpack任务; bootpack启动MOV		EBX,BOTPAKMOV		ECX,[EBX+16]ADD		ECX,3			; ECX += 3;SHR		ECX,2			; ECX /= 4;JZ		skip			; 传输完成MOV		ESI,[EBX+20]	; 源ADD		ESI,EBXMOV		EDI,[EBX+12]	; 目标CALL	memcpy
skip:MOV		ESP,[EBX+12]	; 堆栈的初始化JMP		DWORD 2*8:0x0000001bwaitkbdout:IN		 AL,0x64AND		 AL,0x02JNZ		waitkbdout		; AND结果不为0跳转到waitkbdoutRETmemcpy:MOV		EAX,[ESI]ADD		ESI,4MOV		[EDI],EAXADD		EDI,4SUB		ECX,1JNZ		memcpy			; 运算结果不为0跳转到memcpyRET
; memcpy地址前缀大小ALIGNB	16
GDT0:
;		RESB	8				; 初始值times 8 db 0DW		0xffff,0x0000,0x9200,0x00cf	; 写32bit位段寄存器DW		0xffff,0x0000,0x9a28,0x0047	; 可执行的文件的32bit寄存器(bootpack用)DW		0
GDTR0:DW		8*3-1DD		GDT0align	16
bootpack:
  1. 修改nasfunc.nas文件
; [FORMAT "WCOFF"]		; ← 删除或注释掉,nasm不需要
; [BITS 32]			; ← 这个可以保留,但nasm会通过命令行参数指定
[BITS 32]				; 制作32位模式用的机器语言; 制作目标文件的信息
; [FILE "naskfunc.nas"]	; ← 删除或注释掉,nasm不需要GLOBAL	_io_hlt		; 程序中包含的函数名; 以下是实际的函数实现
_io_hlt:	; void io_hlt(void);HLTRET

nasm支持以上内容,无需特意声明

详解 ipl.nas 文件

; haribote-ipl
; TAB=4CYLS	EQU		10				; 声明CYLS=10ORG		0x7c00			; 指明程序装载地址; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy codeJMP		entryDB		0x90DB		"HARIBOTE"		; 启动扇区名称(8字节)DW		512				; 每个扇区(sector)大小(必须512字节)DB		1				; 簇(cluster)大小(必须为1个扇区)DW		1				; FAT起始位置(一般为第一个扇区)DB		2				; FAT个数(必须为2)DW		224				; 根目录大小(一般为224项)DW		2880			; 该磁盘大小(必须为2880扇区1440*1024/512)DB		0xf0			; 磁盘类型(必须为0xf0)DW		9				; FAT的长度(必??9扇区)DW		18				; 一个磁道(track)有几个扇区(必须为18)DW		2				; 磁头数(必??2)DD		0				; 不使用分区,必须是0DD		2880			; 重写一次磁盘大小DB		0,0,0x29		; 意义不明(固定)DD		0xffffffff		; (可能是)卷标号码DB		"HARIBOTEOS "	; 磁盘的名称(必须为11字?,不足填空格)DB		"FAT12   "		; 磁盘格式名称(必??8字?,不足填空格)RESB	18				; 先空出18字节; 程序主体entry:MOV		AX,0			; 初始化寄存器MOV		SS,AXMOV		SP,0x7c00MOV		DS,AX; 读取磁盘MOV		AX,0x0820MOV		ES,AXMOV		CH,0			; 柱面0MOV		DH,0			; 磁头0MOV		CL,2			; 扇区2readloop:MOV		SI,0			; 记录失败次数寄存器retry:MOV		AH,0x02			; AH=0x02 : 读入磁盘MOV		AL,1			; 1个扇区MOV		BX,0MOV		DL,0x00			; A驱动器INT		0x13			; 调用磁盘BIOSJNC		next			; 没出错则跳转到finADD		SI,1			; 往SI加1CMP		SI,5			; 比较SI与5JAE		error			; SI >= 5 跳转到errorMOV		AH,0x00MOV		DL,0x00			; A驱动器INT		0x13			; 重置驱动器JMP		retry
next:MOV		AX,ES			; 把内存地址后移0x200(512/16十六进制转换)ADD		AX,0x0020MOV		ES,AX			; ADD ES,0x020因为没有ADD ES,只能通过AX进行ADD		CL,1			; 往CL里面加1CMP		CL,18			; 比较CL与18JBE		readloop		; CL <= 18 跳转到readloopMOV		CL,1ADD		DH,1CMP		DH,2JB		readloop		; DH < 2 跳转到readloopMOV		DH,0ADD		CH,1CMP		CH,CYLSJB		readloop		; CH < CYLS 跳转到readloop; 读取完毕,跳转到haribote.sys执行!MOV		[0x0ff0],CH		; IPLがどこまで読んだのかをメモJMP		0xc200error:MOV		SI,msgputloop:MOV		AL,[SI]ADD		SI,1			; 给SI加1CMP		AL,0JE		finMOV		AH,0x0e			; 显示一个文字MOV		BX,15			; 指定字符颜色INT		0x10			; 调用显卡BIOSJMP		putloopfin:HLT						; 让CPU停止,等待指令JMP		fin				; 无限循环msg:DB		0x0a, 0x0a		; 换行两次DB		"load error"DB		0x0a			; 换行DB		0;		RESB	0x7dfe-$		; 填写0x00直到0x001fetimes 0x1fe-($-$$) db 0DB		0x55, 0xaa
http://www.rkmt.cn/news/1407389.html

相关文章:

  • ComfyUI跨系统移植实战:从Windows到Ubuntu 26.04的深度兼容性破解
  • Agent 框架最全解析与实战攻略:LangChain / LangGraph、AutoGen、CrewAI... 到底怎么选?
  • 免费解锁AMD Ryzen隐藏性能:终极硬件调试工具完全指南
  • 天龙八部单机版GM工具终极指南:免费开源的游戏数据管理神器
  • 免费获取macOS风格鼠标指针的终极指南:让你的Windows和Linux桌面焕然一新
  • 2026年三亚汽车贴膜合规资质横向深度测评:4家官方授权门店实测对比 - GrowthUME
  • OpenAI 兼容客户端通用教程:API 地址、密钥与模型名
  • 人机协同进化:从指令执行到互补共创的三种模式与实战
  • 不止甘特图!6个项目管理核心工具,搞定进度、分工与风险管控
  • ChatGPT的替代威胁有多强?供应商议价力、买方议价力、新进入者、替代品、同业竞争——五维压力值全测算,附可落地的防御策略
  • 树莓派部署YOLO+量化LLM:本地化多模态AI流水线实践
  • Windows风扇控制终极指南:用FanControl实现完美静音与散热平衡
  • DataAgent实战指南:从架构设计到工程实现,小白也能轻松掌握大模型落地(收藏版)
  • AI编程助手成本审计:半年投入1.3万美元的真实回报与优化策略
  • 3分钟生成合规高转化产品描述,ChatGPT+人工校验双模工作流(含GDPR/广告法风险扫描表)
  • 告别RealVNC:在Ubuntu 20.04/22.04上快速搭建TigerVNC或x11vnc服务端(附防火墙配置)
  • 3A,60VIN,XZ6925,降压恒流LED驱动芯片
  • 工业增强现实在智能船厂的应用实践:雾计算架构与AR性能评估
  • 2026年科里奥利质量流量计国产品牌排名:五家优选深度解析 - 科技焦点
  • 上百台服务器手动装Nginx?用Ansible Playbook一条命令搞定批量部署
  • EM68C16CWQG-25H DDR2 SDRAM芯片功能描述与操作逻辑
  • py每日spider案例之某pan资源搜索接口(无加密)
  • 田利健导演团队倾力护航《沿着边境看中国》第三季:融合真人秀元素,以匠心铸就边境新篇章
  • RH850 SPI实战:从FIFO模式到异步中断,如何让你的嵌入式通信又快又省CPU
  • ChatGPT导出Word怎么做?Chat2File 安装与使用教程
  • 从人工每天 120 通,到 AI 每天 5000 通!外呼系统如何重塑电销效率(附真实品牌实测)
  • 2026年广州钢结构开顶柜出口,这三点让你少走弯路
  • Debug:查看样品
  • 杭州企业招人,别再忽略背调这道关
  • 阿里 Qwen3.7-Max 冲上编程榜前列:国产 AI Coding 真追上来了?