第三章 实验运行环境
实验结果的运行主要分为两种情况:软盘映像启动(floppy)和硬盘映像启动(hasr disk) ,
hard disk可以在U盘或者bochs启动,floppy可以在VMware和bochs上启动。
因此,书中有两种img文件,软盘映像demo.img和硬盘映像c.img。
软盘和硬盘的区别
软盘启动时,boot代码直接写在扇区0中,硬盘启动时,如果直接将boot代码写到扇区0.会导致一些机器启动不了。
软盘启动:boot代码直接写在MBR中,即扇区0,这样boot代码就是我们的MBR程序,BIOS将读软盘的扇区0(boot代码)到内存的7c00h的位置上。
硬盘启动:boot代码写入img文件或U盘的63扇区,BIOS会读取img文件或U盘的0扇区(FAT32格式启动盘生成的MBR代码)代码到7c00h,然后MBR到63扇区读取boot代码。
boot代码最终运行在7c00h的内存中,负责加载后续的模块(lib16、lib32、lib64、protected模式和long模式)。
环境搭建
编译器nasm,运行环境bochs
开始实验
1. 生成空白的映像文件
demo.img是软盘映像文件,大小1.44MB就足够了,用nasm来生成;c.img是硬盘映像文件,大小创建10MB,通过bochs在带的bximage来生成。
1.1软盘映像文件
汇编代码demo.asm生成demo,img
;demo.asm
;2021.9.25
;建立一个1.44MB的floppy映像文件,demo.img
;生成命令:nasm demo.asm -o demo.img
;用0填满1.44MB的floppy空间
times 0x168000-($-$$) db 0
nasm编译之后生成一个bin文件–demo.img,空白软盘映像文件。
1.2 硬盘映像文件
使用bochs自带的bximage,既可以制作软盘也可以制作硬盘,cmd运行bximage
E:\learn-file\5-X86\code\L03\first>bximage
========================================================================
bximage
Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
$Id: bximage.cc 13481 2018-03-30 21:04:04Z vruppert $
========================================================================
1. Create new floppy or hard disk image
2. Convert hard disk image to other format (mode)
3. Resize hard disk image
4. Commit 'undoable' redolog to base image
5. Disk image info
0. Quit
Please choose one [0] 1
Create image
Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] hd
What kind of image should I create?
Please type flat, sparse, growing, vpc or vmware4. [flat] flat
Choose the size of hard disk sectors.
Please type 512, 1024 or 4096. [512] 512
Enter the hard disk size in megabytes, between 10 and 8257535
[10] 10
What should be the name of the image?
[c.img] c.img
Creating hard disk image 'c.img' with CHS=20/16/63 (sector size = 512)
The following line should appear in your bochsrc:
ata0-master: type=disk, path="c.img", mode=flat
(The line is stored in your windows clipboard, use CTRL-V to paste)
Press any key to continue
到这里就已经将10MB的空白硬盘映像文件制作完成了。
2. 设置bochs配置文件
在Bochs的安装目录下找到bochsrc-sample.txt,拷贝到自己的工作目录,进行更改:
**megs:32
romimage:file=$BXSHARE/BIOS-bochs-latest
vgaromimage:file=$BXSHARE/VGABIOS-lgpl-latest
#floppya:1_44=demo.img,status=inserted
ata0-master: type=disk, path="c.img", mode=flat, cylinders=2, heads=16, spt=63
#boot:floppy
boot:disk
log:bochsout.txt
mouse:enabled=0
keyboard: keymap=$BXSHARE/keymaps/x11-pc-de.map**
上面的文件中,包含两种方式启动,因为软盘和硬盘都可以用bochs启动。
3. 编译源代码
源代码的结构树code/目录下包含所有的源代码以及所需要的库。
inc 定义所有源码的支持头文件,定义了一些常量和宏;
lib 库函数的实现代码,所有的源码都需要使用这些库;
common 通用代码,包括后面需要的boot.asm、setup.asm等;
L** 每章的代码。
源代码的编译
关于asm程序,全部使用nasm来编译,编译命令:
nasm setup.asm -o nasm.bin
//-o 指定输出的文件名
4. 映像文件中的组织结构
将源文件编译成bin文件之后,我们需要将这些bin文件写入到映像文件中,写入的先后顺序怎么确定,这就涉及到映像文件中bin文件是如何组织的。
软盘映像文件 demo.img
- boot:扇区0;
- setup:从扇区1开始;
- lib16:从扇区20开始;
- protected:从扇区64开始;
- long:从扇区128开始;
- lib32:从扇区192开始;
硬盘映像文件 c.img
硬盘和软盘的区就是,boot代码放到了扇区63,扇区0是FAT32格式文件的MBR,由MBR加载扇区63的boot代码到内存0x7c00,再由boot加载扇区20之后的内容,启动机器。
5. merge
知道了bin文件的组织顺序之后,需要一次将bin文件写入到映像文件中
- hex 使用hex软件诸葛将bin文件写入到映像文件中c.img;
-
dd dd可以进行磁盘/文件的复制/写入/合并等操作。
dd if=boot of=c.img count=2
if提供输入文件,of提供输出文件,count提供数量(以block为单位买12字节),这条命令就是将boot写入到c.img的0开始处(即映像文件的0扇区)。dd if=boot of=c.img count=1 seek=1
经boot写入到1扇区,seek可以跳过。 - merge 书中自带,皮偏高写入,读取当前目录下的配置文件config.txt来做相应的写入工作。
# 输入文件, 输入文件 offset, 输出文件, 输出文件 offset, 写入 block 数( 1 block = 512 bytes)
# ** 每一项用短号分隔 ****
# example:
#
#模块名 offset 输出文件名 offset count(1 count = 512 bytes)
#-------------------------------------------------
# boot, 0, demo.img, 0, 1
# setup, 0, demo.img, 1, 2
# init, 0, demo.img, 3, 5
#
# 意思是:
# boot 模块从 block 0 开始写入 demo.img 写入位置为 block 0, 写入 1 个 block
# setup 模块从 block 0 开始写入 demo.img 写入位置为 block 1, 写入 2 个 blocks
# init 模块从 block 0 开始写入 demo.img 写入位置为 block 3, 写入 5 个 blocks
7. boot代码
boot代码的主要功能是显示信息和从磁盘中读取扇区到内存中,主要代码:
; boot.asm
; 2021.9.25
; 软盘
; 编译命令是: nasm boot.asm -o boot
; 生成 boot 模块然后,写入 demo.img(磁盘映像)的第0扇区(MBR)
; 硬盘
; nasm boot.asm -o boot -d uboot
; 生成 uboot 模块然后,写入 c.img(磁盘映像)的第63扇区
%include "..\inc\support.inc"
%include "..\inc\ports.inc"
bits 16
;--------------------------------------
; now, the processor is real mode
;--------------------------------------
; Int 19h 加载 sector 0 (MBR) 进入 BOOT_SEG 段, BOOT_SEG 定义为 0x7c00
org BOOT_SEG
start:
cli
; enable a20 line
FAST_A20_ENABLE
sti
; set BOOT_SEG environment
mov ax, cs
mov ds, ax
mov ss, ax
mov es, ax
mov sp, BOOT_SEG ; 设 stack 底为 BOOT_SEG
call clear_screen
mov si, hello
call print_message
mov si, 20 ; setup 模块在第20号扇区里
mov di, SETUP_SEG - 2
call load_module ; 使用 load_module() 读多个扇区
mov si, SETUP_SEG
call print_message
mov si, word [load_message_table + eax * 2]
call print_message
next:
jmp $
上面的是boot的主题代码,其中会调用各种在boot.asm中定义的过程,其中包括:
- 首先,需要做出判断,BIOS是否支持
int 13h
功能,判断使用int 13h/ah=02h
还是int 13h/ah=42h
扩展功能读磁盘。 - 使用扩展的int 13h功能,
int 13h/ah=42h
,使用LBA的方式; - 使用旧的int 13h功能,
int 13h/ah=02h
,使用CHS的方式,需要将LBA转为CHS(LBA_to_CHS()完成转换)。
本文中所有的例子都是LBA方式,如果BIOS不支持int 13h的扩展功能,则需要将LBA转为CHS。
实验,使用软盘和硬盘启动
硬盘nasm -I..\ second\boot.asm -o second\boot -d UBOOT
软盘nasm -I..\ second\boot.asm
merge写入merge
E:\learn-file\5-X86\code\L03\second>merge
entry #0: uboot ---> c.img: success
entry #1: setup ---> c.img: success
entry #2: boot ---> demo.img: success
entry #3: setup ---> demo.img: success
启动命令 bochs -f bochsrc-sample.txt
软盘启动效果
硬盘启动效果
8. 总结
- boot.asm、boot、uboot boot源码
- setup.asm、setup setup源码
- bochsrc-sample.txt bochs启动配置文件
- conifg merge的配置文件
- demo.img 软盘映像文件
- c.img 硬盘映像文件