跟我一起写操作系统

    返回首页    发表留言
本文作者:李德强
          第四节 制作启动光盘
 
 

        光盘启动与软盘启动的方式有很大不同,主要在于光盘容量要远远大于软盘的容量。一张74分钟的标准CD包含333000个扇区。每个扇区为2352字节,模式1型的CD-ROM包含2048字节计算机数据,模式2型的CD-ROM包含2336字节PSX/VCD数据,音频包含2352字节信息。扇区容量的差异来自头信息和纠错编码,计算机数据对精度要求最高,这类信息最多,VCD对精度要求不高,这类信息稍小,音频CD没有这类信息。如果用RAW格式从盘片中读取数据,无论是什么数据类型,每个扇区都能够读出2352字节信息。在一张74分钟的CD上,能够用RAW方式刻录更多的信息,这样做容量可以达到333000 * 2352 = 783216000 字节(大约747MB)。这是74分钟650MB的CD的容量的上限。容量增加了14.8%,但是,这样做将失去纠错数据。

        首先,我们来来看一下一个可引导光盘的文件结构。这种光盘遵从EL TORITO和ISO 9660规范。每个扇区大小为2048个字节,1至16个扇区为保留扇区,从第17个扇区开始正式的数据存储。我们使用二进制查看工具打开一个可引导的iso文件,来查看它的二进制内容,如下:

vim -b boot.iso
:%!xxd
        使用vim命令并采用二进制方式打开boot.iso这个文件,打开之后在vim中执行“:%!xxd”来进入二进制显示模式,iso光盘镜像文件的第17个扇区的位置为2048 * 17 = 34816(0x8800),我们这个iso文件的内容如下:
0008800: 0043 4430 3031 0145 4c20 544f 5249 544f .CD001.EL TORITO
0008810: 2053 5045 4349 4649 4341 5449 4f4e 0000 SPECIFICATION..
0008820: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0008830: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0008840: 0000 0000 0000 0013 0000 0000 0000 0000 ................
0008850: 0000 0000 0000 0000 0000 0000 0000 0000 ................
        我们来看一下这个扇区的每一个字节所代表的意思:

偏移地址

数据类型

说明

0x0

Byte

启动标识,必须是0

0

0x1 - 0x5

Byte

ISO-9600定义,必须是CD001

CD001

0x6

Byte

版本描述符,必须是1

1

0x7 - 0x26

Byte

引导系统标识符,必须是EL TORITO SPECIFICATION并以0填充未使用的字节

EL TORITO SPECIFICATION

0x27 - 0x46

Byte

保留,必须是0

0

0x47 - 0x4A

Dword

引导目录的第一个扇区号

0x00000013

0x4A - 0x7FF

Byte

保留,必须是0

0

 

        值得注意的是,这个扇区的内容只是标识出这张光盘是可引导的,它的开始引导目录的第一个扇区号是0x00000013。所以,我们还要看一下0x00000013这个扇区的内容(位置在0x13 * 0x800 = 0x9800):

0009800: 0100 0000 0000 0000 0000 0000 0000 0000 ................
0009810: 0000 0000 0000 0000 0000 0000 aa55 55aa .............UU.
0009820: 8800 0000 0000 0402 2501 0000 0000 0000 ........%.......
0009830: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0009840: 0000 0000 0000 0000 0000 0000 0000 0000 ................

        我们再来看一下这个扇区的每一个字节所代表的意思:

偏移地址

数据类型

说明

0x0

Byte

引导目录标识,必须是01

01

0x1

Byte

平台ID

0 (80x86 platform id)

1 (Power PC platform id)

2 (Mac platform id)

0x2 - 0x3

Byte

保留,必须是0

0

0x4 - 0x1B

Byte

生产厂商

0

0x1C - 0x1D

Byte

校验码,0

0

0x1E

Byte

结束标识55

55

0x1F

Byte

结束标识AA

AA

0x20

Byte

启动标识符

0 (not bootable)

88 (bootable)

0x21

Byte

启动媒体类型

0 (no emulation)

1 (1.2mb disk)

2 (1.44mb disk)

3 (2.88mb disk)

4 (hard drive)

0x22 - 0x23

Word

将引导扇区数据载入内存的段地址,如果 是0则代表载入到默认段地址为0x7c0处

0

0x24

Byte

系统分区类型,必须是0

0

0x25

Byte

保留,必须是0

0

0x26 - 0x27

Word

载入扇区数

0x0400

0x28 – 0x2B

Dword

正式载入引导程序的开始扇区号

0x00000125

0x2C - 0x3F

Byte

保留,必须是0

0

        了解了光盘的头格式,下一步我们就可以制作一张可引导的光盘镜像,并将前面使用汇编编写的引导程序烧录到我们的光盘镜像中。首先创建一个名为mkiso的Makefile新工程,并创建一个mkiso.c的C语言源代码文件,并在里面编写下面的代码。我们先要定义一些常用的类型:

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;

      无符号单字节、无符号双字节、无符号4字节和无符号8字节类型。下面是第17扇区头内容,按字节大小和类型进行相关定义:

typedef struct iso_struct
{
    u8 boot_record_indicator;
    char iso_9660_identifier[5];
    u8 version_of_this_descriptor;
    char boot_system_identifier[23];
    u8 pad0;
    u8 pad1;
    u8 pad2[32];
    u8 pad3[7];
    u8 first_sector0;
    u8 first_sector1;
    u8 first_sector2;
    u8 first_sector3;
    u8 pad4[1973];
} iso_struct;

        再下面是第19扇区的头格式内容:

typedef struct iso_boot_catalog
{
    u8 boot_indicator;
    u8 platform_id;
    u8 reserved0;
    u8 reserved1;
    u8 pad0[26];
    u8 end_55;
    u8 end_AA;
    u8 bootable;
    u8 boot_media_type;
    u8 load_segment_for_image0;
    u8 load_segment_for_image1;
    u8 system_type;
    u8 pad1;
    u8 sector_count0;
    u8 sector_count1;
    u32 start_address_of_the_virtual_disk;
    u8 pad2[20];
    u8 pad3[1984];
} iso_boot_catalog;

        再定义两个类型,也就是上面两个结构体类型,这样定义是为了使用方便:

typedef iso_struct iso;
typedef iso_boot_catalog iso_boot;

        这样定义的好处是以后想要定义一个struct iso_struct类型和struct iso_boot_catalog 的变量只需要这样定义:

iso i;
iso_boot b;

        而不再需要再使用结构体名称来定义,比如这样:

struct iso_struct i;
struct iso_boot_catalog b;
        这样就大大简化了代码,也提高了编程的效率。

        再下面就是定义两个光盘头格式的变量,并将其内容写如bin文件中:

iso iso_m;
//为iso_n赋值,设置17扇区内容
...
iso_boot iso_b;
//为iso_b赋值,设置19扇区内容
...
        创建一个bin文件,这个文件的路径来自于args[1],也就是说我们编写的mkiso程序在执行时需要给它传入参数,参数的内容即是要生成的bin文件目录及文件名。并写入iso_m扇区内容:
FILE *p = fopen(args[1], "wb");
fwrite((char*) &iso_m, sizeof(char), sizeof(iso_m), p);
fclose(p);
        创建一个bin文件,并写入iso_b扇区内容:
FILE *p2 = fopen(args[2], "wb");
fwrite((char*) &iso_b, sizeof(char), sizeof(iso_b), p2);
fclose(p2);
        再为mkiso工程编写一个Makefile文件,加入以下内容:
BUILD = build
all:
mkdir -p $(BUILD)
#编译mkiso.c文件,生成mkiso可执行文件。
gcc -m32 mkiso.c -o $(BUILD)/mkiso
#执行mkiso程序,生成第17扇区的iso_header.bin文件和第19扇区的iso_bootable.bin文件。
$(BUILD)/mkiso $(BUILD)/iso_header.bin $(BUILD)/iso_bootable.bin

clean:
rm -rvf $(BUILD)
        编译并运行,可以看到在mkiso工程下生成了build目录,里面有mkiso、iso_header.bin和iso_bootable.bin三个文件,如下图:


        看到程序执行的正确结果之后,我们就可以将这个工具工程的源代码加入到lidqos主工程的Makefile文件中,并执行dd命令将iso_header.bin、iso_bootable.bin和boot.bin烧录到我们的iso光盘镜像文件中。在lidqos的Makefile文件中修改代码为:

BUILD = build
all:
    mkdir -p $(BUILD)
    gcc boot.S -c -m32 -std=c99 -o $(BUILD)/boot.o
    ld -m elf_i386 -Ttext 0x0 -e _start $(BUILD)/boot.o -o $(BUILD)/boot
    objcopy -O binary $(BUILD)/boot $(BUILD)/boot.bin
    gcc -m32 ../tool/mkiso/mkiso.c -o $(BUILD)/mkiso
    
    #编译并执行mkiso,生成iso_header.bin、iso_bootable.bin文件。
    $(BUILD)/mkiso $(BUILD)/iso_header.bin $(BUILD)/iso_bootable.bin
    
    #将iso_header.bin烧录到第17扇区。
    dd bs=2048 seek=17 count=1 conv=notrunc if=$(BUILD)/iso_header.bin of=$(BUILD)/boot.iso
    
    #将iso_bootable.bin烧录到第19扇区。
    dd bs=2048 seek=19 count=1 conv=notrunc if=$(BUILD)/iso_bootable.bin of=$(BUILD)/boot.iso
    
    #将boot.iso引导程序烧录到293(0x0125)扇区。
    dd bs=2048 seek=293 count=1 conv=notrunc if=$(BUILD)/boot.bin of=$(BUILD)/boot.iso
    
    #补齐扇区。
    dd bs=2048 seek=4096 count=1 conv=notrunc if=/dev/zero of=$(BUILD)/boot.iso


clean:
    rm -rvf $(BUILD)

        执行make all编译,就会在lidqos/build目录下生成相关文件,这里我们关心的是boot.iso光盘镜像文件,如下图:



        成功生成了boot.iso文件之后,就可以在VirtualBox中使用这个文件来引导我们的系统了,在VirtualBox中修改lidqos虚拟机的设置,删除软驱控制器,并在CD/DVD Drive中选中我们上面生成的boot.iso文件。如下图:


        点击OK按钮,并启动虚拟机,运行成功:



        源代码的下载地址为:

https            https://github.com/magicworldos/lidqos.git
git              git@github.com:magicworldos/lidqos.git
subverion        https://github.com/magicworldos/lidqos
branch           v0.2
    返回首页    返回顶部
  看不清?点击刷新

 

  Copyright © 2015-2023 问渠网 辽ICP备15013245号