何德海的博客资料

本文主要介绍何德海的博客资料 方法和在新技术下所面对的“挑战”,方便大家深入理解何德海的博客资料 过程。本文也将分享何德海的博客资料 所遇到的问题和应对策略,怎么解决怎么做的问题。
通过深入本文可以理解代码原理,进行代码文档的下载,也可以查看相应 Demo 部署效果。

1 任务

  为了学习计算机底层和os,我给自己布置了一个任务:在x86硬件上,使用c和nasm来显示一张bmp图片。完成这个任务,前后估计花了2个月的业余时间。

  这个任务涉及了很多知识点,包括:启动区、保护模式、nasm汇编、c和nasm汇编互调、ld链接、硬盘io读取、显卡调色板模式、bmp图片格式、bios中断指令、c指针操作内存、borch虚拟机、binutils工具集、makefile等。

2 环境

ubuntu

borchs

nasm和 c

PS:c代码遵循google的C++ 风格指南,使用gnu99标准

3步骤

3.1 生成一个10M的硬盘镜像

  bximage是borchs软件包的一个小工具,可以用于生成硬盘或软盘镜像。打开终端,输入:bximage。按照如下图所示的,一步一步地操作。

何德海的博客

最终会在当前目录下,生成一个名为10M.img的文件。

3.2 准备一张320*200的bmp图片

  为简单起见,屏幕的分辨率使用320*200。因此我们的bmp图片的大小320*200。我准备了一张图片,如下,这是我家主子的靓照。

何德海的博客 

  将文件命名为cat-666.bmp,然后写入到#201扇区

dd if=src/cat-ham.bmp of=10M.img bs=512 seek=201 conv=notrunc

3.3 引导区

  引导区位于启动盘的#0扇区,为计算机启动后首次执行的代码。为简单起见,我们的引导区仅完成以下功能:

  • 设置vga模式设置显示模式为320*200。
  • 配置了配置了5个gdt表项,用作程序运行的内存空间。
  • 跳入32位保护模式。
  • 读取内核至内存0x100000
  • 跳至内核入口。

 

具体代码如下:boot.asm

  1 ;设置堆栈段和栈指针    2     mov    eax, cs   3     mov     ss, eax   4     mov     sp, 0x7c00   5             6    7 set_vga:   8     mov    ax, 0x0013              ;;0x0013为 320*200*8bit   9     int    0x10                ;int 0x10  10   11 set_gdt:  12     ;GDT 开始于 0x7e00  13     mov     ax, 0x7e00  14     mov     bx, ax;  15   16     ; null_descriptor,这是处理器的要求  17     mov     dword [bx + 0x00], 0x00000000  18     mov     dword [bx + 0x04], 0x00000000  19   20     ; code 启动区  21     mov     dword [bx + 0x08], 0x7c0001ff    ;base:0x7c00,limit: 1ff,512B  22     mov     dword [bx + 0x0c], 0x00409A00    ;粒度为1B,  23   24     ; code kernel  25     mov     dword [bx + 0x10], 0x000000ff    ; base: 0x10_0000, limit:0xff,1MB  26     mov     dword [bx + 0x14], 0x00c09a10    ; 粒度为4KB,  27   28     ; data  29     mov     dword [bx + 0x18], 0x0000ffff    ;base: 0, limit:0xf_ffff, 4GB  30     mov     dword [bx + 0x1c], 0x00cf9200    ;粒度为4KB,  31   32     ; stack  33     mov     dword [bx + 0x20], 0x7a00fffe    ; base: 0x7a00, limit:0xfffe  34     mov     dword [bx + 0x24], 0x00cf9600    ; 粒度为4KB,  35            36     ;初始化描述符表寄存器 GDTR  37     mov     word [cs: gdt_desc + 0x7c00], 39    ;描述符表的界限  38     lgdt     [cs: gdt_desc + 0x7c00]  39         40     in    al, 0x92            ;南桥芯片内的端口  41     or     al, 0000_0010B  42     out    0x92, al                        ;打开A20  43   44     cli                    ;中断机制尚未工作  45   46     mov    eax, cr0  47     or     eax, 1  48     mov     cr0, eax                        ;设置PE位  49         50     ;以下进入保护模式 ...  51     jmp     dword 0x0008: mode32_start    ;16位的描述符选择子:32位偏移  52                53                54                55     [bits 32]  56 mode32_start:   57     mov     eax, 0x0018            ;加载数据段选择子  58     mov     es, eax;  59     mov     ds, eax;  60   61   62 ; 读取内核,并且跳入。读取200个扇区至 0x10_0000  63 read_kernel:  64     mov    dx, 0x1f2;  65     mov     al, 200                ; 200个扇区  66     out     dx, al                ;  67       68     mov     dx, 0x1f3            ;  69     mov    al ,0x01            ; 1号扇区(第2个扇区), zero-based  70     out     dx, al;  71       72     mov    dx, 0x1f4            ;  73     mov    al, 0x00            ;  74     out    dx, al                ;  75       76     mov     dx, 0x1f5            ;  77     mov     al, 0x00;  78     out     dx, al;  79       80     mov     dx, 0x1f6            ;  81     mov    al, 0xe0            ;  82     out    dx, al                ;  83       84     ; ask for read  85     mov    dx, 0x1f7            ;  86     mov    al, 0x20            ;  87     out    dx, al                ;  88       89     ; wait for finish  90     mov    dx, 0x1f7            ;  91 _rk_wait:  92     in     al,dx                ;  93     and     al, 0x88            ;  94     cmp     al, 0x08            ;  95     jnz     _rk_wait            ;  96   97     ;read data to bx  98     mov     ebx, 0x10_0000            ;  99     mov     cx, 256 *  200            ;  n * 256; 100     mov     dx, 0x1f0            ; 101  102 _rk_read_loop: 103     in     ax, dx; 104     mov     word[ebx], ax;            ; 每次读2个字节 105     add     ebx, 2; 106     loop     _rk_read_loop            ; 107  108     ; jump to kernel, 段选择子 109     jmp     dword 0x0010:0 110  111            112     hlt; 113        114           115 ;------------------------------------------------------------------------------- 116 gdt_desc:    dw 0 117         dd 0x00007e00              ; GDT的物理地址,刚好在启动区之后 118 ;-------------------------------------------------------------------------------                              119 times     510-($-$$) db 0 120 db    0x55, 0xaa

 

编译

nasm boot.asm -f bin -o boot.bin

 

写入到硬盘镜像(写入到#0扇区)

dd if=boot.bin of=10M.img bs=512 count=1 conv=notrunc

 

3.4 bmp文件的结构

  BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广泛使用的图像文件格式。其结构如下图所示:

何德海的博客

  参考:https://www.cnblogs.com/kingmoon/archive/2011/04/18/2020097.html

  参考bmp的结构定义,编写如下头文件:bmp.h

  1 #ifndef _OS_BMP_H_   2 #define _OS_BMP_H_   3    4 #include <stdint.h>   5    6 typedef struct {   7   /**   8    * 文件类型,   9    */  10   char type[2];  11   12   /**  13    * 位图大小  14    */  15   uint32_t size;  16   17   /**  18    * 保留位  19    */  20   uint16_t reserved1;  21   22   /**  23   * 保留位  24   */  25   uint16_t reserved2;  26   27   /**  28    * 图像数据偏移量  29    */  30   uint32_t off_bits;  31   32 } __attribute__ ((packed)) BitMapFileHeader;  33   34 /**  35  * 信息头  36  */  37 typedef struct {  38   /**  39    * BitMapFileHeader 字节数  40    */  41   uint32_t size;  42   43   /**  44    * 位图宽度  45    */  46   uint32_t width;  47   48   /**  49    * 位图高度,正位正向,反之为倒图  50    */  51   uint32_t height;  52   53   /**  54    * 为目标设备说明位面数,其值将总是被设为1  55    */  56   uint16_t planes;  57   58   /**  59    * 说明比特数/象素,为1、4、8、16、24、或32。  60    */  61   uint16_t bit_count;  62   63   /**  64    * 图象数据压缩的类型没有压缩的类型:BI_RGB  65    */  66   uint32_t compression;  67   68   /**  69    * 图像数据区大小,以字节为单位  70    */  71   uint32_t image_size;  72   73   /**  74    * 水平分辨率  75    */  76   uint32_t x_pixel_per_meter;  77   78   /**  79    * 垂直分辨率  80    */  81   uint32_t y_pixel_per_meter;  82   83   /**  84    * 位图实际使用的彩色表中的颜色索引数  85    */  86   uint32_t color_used;  87   88   /**  89    * 对图象显示有重要影响的索引数,0都重要。  90    */  91   uint32_t color_important;  92 } __attribute__ ((packed)) BitMapInfoHeader;  93   94 /*  95  * 颜色结构体  96  */  97 typedef struct {  98   /**  99    * 100    */ 101   uint8_t blue; 102  103   /** 104    * 105    */ 106   uint8_t green; 107  108   /** 109    * 110    */ 111   uint8_t red; 112  113   /** 114    * 保留值 115    */ 116   uint8_t reserved; 117  118 } __attribute__ ((packed)) RGB; 119  120 #endif //_OS_BMP_H_

 

代码说明:

  • 定义了3个结构体BitMapFileHeader(文件头)、 BitMapInfoHeader(位图信息头)、RGB(颜色)
  • 需要特别注意的是,在类型定义中加入了__attribute__ ((packed))修饰。它的作用就是告诉编译器取消结构体在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。不加入这个的话,会导致程序在读取bmp数据时发生错位。

 

3.5 io操作

  在这个任务中需要直接操作硬件,比如读取硬盘扇区、端口读写、打开中断、读取eflags标志等,这部分功能的代码将使用nasm来编写,然后导出相应的方法让c来调用。

      nasm代码如下:x86.asm

;数据区 [section .data] ;  ;代码区 [section .text] ;  global read_sector; global io_hlt ; ; global io_in8; global io_in16; global io_in32; global io_out8; global io_out16; global io_out32; ; global io_read_eflags; global io_write_eflags; ; global io_cli; global io_sti;   ; ;功能    : 读取一个扇区 ;入口    : 无 ;出口    : 无 ;堆栈使用: 无 ;全局变量: ;函数签名:void read_sector(int sector, int dst); read_sector:     mov    ecx, [esp + 4]            ;参数1:sector     mov    ebx, [esp + 8]            ;参数2:dst      mov    dx, 0x1f2            ;     mov     al, 0x01            ;1 sector     out     dx, al                ;     mov    dx, 0x1f3            ;     mov    al, cl                ;0-7     out    dx, al                ;          mov     dx, 0x1f4            ;     mov     al, ch                ;8-15     out    dx, al          mov    dx, 0x1f5            ;     mov    al, 0x00            ;16-23     out     dx, al                ;          mov     dx, 0x1f6            ;     mov     al, 0xe0            ;     out     dx, al                ;          ; ask for read      mov     dx, 0x1f7            ;     mov     al, 0x20            ;     out     dx, al                ;          ; wait for finish     mov     dx, 0x1f7            ; _rs_wait:     in      al, dx                ;     and     al, 0x88            ;     cmp     al, 0x08            ;     jnz     _rs_wait            ;      ;read data to bx     mov     cx, 256                ;     mov     dx, 0x1f0            ;  _rs_read_loop:     in      ax, dx                ;     mov     word[ebx], ax            ;     add     ebx, 2                ;     loop    _rs_read_loop            ;      ret                    ;    ;功能    :  挂起 ;入口    : 无 ;出口    : 无 ;堆栈使用: 无 ;全局变量: ;函数签名:void io_hlt(void); io_hlt:     hlt                    ;     ret;    ;功能    : 读取 eflags ;函数签名: int read_eflags(void); io_read_eflags:     pushfd                    ;将 eflags 压入栈     pop    eax                ;将 eflags 弹出并保存至eax     ret  ;功能    : 往端口写入1个字节 ;函数签名: void io_out8(int port, int value); io_out8:     mov     edx, [esp + 4]            ;参数1: port     mov     al, [esp + 8]            ;参数2:value     out     dx, al     ret    ;功能    : 从端口读取1个字节 ;函数签名:uint8_t io_in8(int port); io_in8:     mov    edx, [esp + 4]            ;参数1: port     mov    eax, 0                ;将数据置为0,防止干扰     in    al, dx                ;     ret   ;功能    : 从端口读取2个字节 ;函数签名:uint16_t io_in16(int port); io_in16:     mov    edx, [esp + 4]            ;参数1: port     mov    eax, 0                ;将数据置为0,防止干扰     in    ax, dx                ;     ret   ;功能    : 从端口读取4个字节 ;函数签名:uint32_t io_in32(int port); io_in32:     mov    edx, [esp + 4]            ;参数1: port     mov    eax, 0                ;将数据置为0,防止干扰     in    eax, dx                ;     ret    ;功能    : 往端口写入2个字节 ;函数签名: void io_out16(int port, int value); io_out16:     mov     edx, [esp + 4]            ;参数1: port     mov     al, [esp + 8]            ;参数2:value     out     dx, ax     ret   ;功能    : 往端口写入4个字节 ;函数签名: void io_out32(int port, int value); io_out32:     mov     edx, [esp + 4]            ;参数1: port     mov     al, [esp + 8]            ;参数2:value     out     dx, eax     ret   ;功能    : 关闭中断 ;函数签名: void io_cli(void); io_cli:     cli                    ; clean interrupt flag     ret   ;功能    : 打开中断 ;函数签名: void io_sti(void); io_sti:     sti                    ; set interrupt flag     ret   ;功能    : 写入 eflags ;函数签名: void write_eflags(int flags); io_write_eflags:     mov     eax, [esp + 4]            ;参数1:eflags     push     eax                ;将参数 eflags压入栈中     popfd                    ;从栈中弹出eflags的值并将之写入到 EFLAGS 寄存器     ret

代码说明:

  • 导出函数使用global关键字。比如global read_sector,将导出read_sector函数。
  • 函数的参数使用栈来存储,次序为从右到左,使用esp栈指针来访问。
  • 所有的函数都放在section  .text 中。
  • 整型类型的返回值可以放在eax/ax/dx寄存中进行返回。

 

编译

nasm -f elf -o x86.o x86.asm

 

  为了便于c代码调用上面的代码,我们还需要创建一个头文件:x86.h:

#ifndef _OS_X86_H_ #define _OS_X86_H_  #include <stdint.h>  /**  * 读取扇区的数据  * @param sector 扇区号。  * @param dst 目标地址  */ void read_sector(int sector, uint8_t *dst);  /**  * 挂起  */ void io_hlt();   /**  * 读取 eflags  * @return  */ uint32_t io_read_eflags();  /**  * 写入 eflags  * @param flags  */ void io_write_eflags(uint32_t flags);    /**  * 从端口读取1个字节  * @param port 端口号  * @return 端口上的数据  */ uint8_t io_in8(uint16_t port);  /**  * 从端口读取2个字节  * @param port 端口号  * @return 端口上的数据  */ uint16_t io_in16(uint16_t port);  /**  * 从端口读取4个字节  * @param port 端口号  * @return 端口上的数据  */ uint32_t io_in32(uint16_t port);  /**  * 往端口写入1个字节  * @param port 端口号  * @param value 要写入的值  * @return  */ void io_out8(uint16_t port, uint8_t value);  /**  * 往端口写入2个字节  * @param port 端口号  * @param value 要写入的值  * @return  */ void io_out16(uint16_t port, uint16_t value);  /**  * 往端口写入4个字节  * @param port 端口号  * @param value 要写入的值  * @return  */ void io_out32(uint16_t port, uint32_t value);  /**  * 关闭中断  */ void io_cli();  /**  * 打开中断  */ void io_sti();  #endif //_OS_X86_H_

 

代码说明:

  • 函数的签名要跟nasm文件中的保持一致,包括函数名,参数个数、参数类型。
  • 在调用的时候跟普通的头文件一样,先引入x86.h,然后调用相应的方法。

 

3.6 内核代码

  在内核代码中,执行以下操作:

  • 读取bmp文件所在的起始个扇区。从该扇区数据中取出文件大小,决定要还要继续读几个扇区,接着读完所有扇区。
  • 从bmp数据中取出调色板数据,然后用它来更改显卡的调色板。
  • 从bmp数据中取出图像数据,写入到图像缓冲区。

  代码如下:kernel.c

 1 #include <stdint.h>  2 #include "x86.h"  3 #include "bmp.h"  4   5 // 视频缓冲区的内存位置  6 #define VIDEO_BUFFER_MEMORY_LOC 0x0a0000  7 // bmp文件的内存位置  8 #define BMP_FILE_MEMORY_LOC 0x200000  9 // bmp文件所在的起始扇区 10 #define BMP_FILE_SECTOR 201 11  12 int main(void) { 13   // 读扇区的索引, 14   uint32_t sector_read_index = BMP_FILE_SECTOR; 15   // 读文件的索引 16   uint8_t *file_read_index = (uint8_t *) BMP_FILE_MEMORY_LOC; 17  18   // 读取bmp文件所在的第1个扇区 19   read_sector(sector_read_index, file_read_index); 20   file_read_index = file_read_index + 512; 21   sector_read_index++; 22  23   // 文件头 24   BitMapFileHeader *bmp_header = (BitMapFileHeader *) BMP_FILE_MEMORY_LOC; 25   uint32_t file_size = bmp_header->size; 26  27   // 图像数据偏移 28   uint32_t off_bits = bmp_header->off_bits; 29  30   // 需要再读取几个扇区? 31   int more_sectors = (file_size / 512) - 1; 32   if (file_size % 512 != 0) { 33     more_sectors++; 34   } 35  36   // 读取更多扇区 37   for (int i = 0; i < more_sectors; i++) { 38     read_sector(sector_read_index, file_read_index); 39     sector_read_index++; 40     file_read_index += 512; 41   } 42  43   //*********************调色板设置 ************* 44   // 读取调色板数据 45   // 调色板数据开始于文件偏移 54 46   RGB *palette_index = (RGB *) (BMP_FILE_MEMORY_LOC + 54); 47   // 48   uint32_t eflags = io_read_eflags(); 49   io_cli(); 50  51   // 写入0号调色板 52   io_out8(0x03c8, 0); 53  54   // 写入调色板数据 55   for (int i = 0; i < 256; ++i) { 56     RGB rgb = *palette_index; 57     // 必须除以4,因为 vga 只能显示64色 58     io_out8(0x03c9, rgb.red / 4); 59     io_out8(0x03c9, rgb.green / 4); 60     io_out8(0x03c9, rgb.blue / 4); 61     palette_index++; 62   } 63  64   io_write_eflags(eflags); 65  66   // 位图信息头 67   BitMapInfoHeader *info_header = (BitMapInfoHeader *) (BMP_FILE_MEMORY_LOC + 14); 68   // 数据位数组 69   uint8_t *file_bits = (uint8_t *) (BMP_FILE_MEMORY_LOC + off_bits); 70   // 坐标点的内存地址 71   uint8_t *p = 0; 72   // 73   for (int i = 0; i < info_header->image_size; i++) { 74     // x 坐标 75     int x = i % info_header->width; 76     // y 坐标 77     int y = (info_header->height - 1) - (i / info_header->width); 78     // 点(x,y)的内存地址 79     p = (uint8_t *) (VIDEO_BUFFER_MEMORY_LOC + x + y * info_header->width); 80     *p = *file_bits; 81     file_bits++; 82   } 83  84   // use this to avoid to reset 85   while (1) { 86     io_hlt(); 87   } 88   return 0; 89 }

 

 关键代码说明:

  • 在写入调色板之前,eflags要先暂存,然后再回写。
  • bmp的数据是从下往上,从左往右存储的,所以显示的时候要反过来。
  • 对视频缓冲区内存区域的读写用到了指针。定义一个指针uint8_t *p, p为坐标点的内存地址,然后使用*p = *file_bits来修改该内存的值。

 

编译

gcc -c-std=gnu99  -fno-stack-protector  -m32 -Wall -o kernel.o kernel.c

 

3.7 链接

链接脚本如下:kernel.ld

  1 OUTPUT_FORMAT("elf32-i386")   2 OUTPUT_ARCH(i386)   3 ENTRY(main)   4    5 SECTIONS   6 {   7 	. = 0x040000;   8 	.text :  {   9 		*(.text)  10 	}  11 	.data : {  12 		*(.data)  13 	}  14 	.bss : {  15 		*(.bss)  16 	}  17 	/DISCARD/ : {  18 		*(.eh_frame .note.GNU-stack)  19 	}  20 }  21   22 

 

脚本说明:

  • OUTPUT_FORMAT(“elf32-i386”) 表示输出格式为efl32 32位格式。
  • ENTRY(main) 表示入口函数为main
  • /DISCARD/表示忽略.eh_frame段和.note.GNU-stack

 

链接

ld -s -T kernel.ld -o kernel.out kernel.o x86.o 注意,对象文件(*.o)的次序要正确,否则运行的时候会出错。次序的原则是被依赖的放在后面。

 

3.8 .text段提取

  链接后的文件kernel.out是一个elf类型的文件,它包含了elf头信息、.text、.data等。通过readelf命令可以查看efl文件的结构。

readelf -a kernel.out

命令结果如下:

 何德海的博客

我们仅需要 .text段 。这个时候通过objcopy来提取kernel.out中的.text段,如下:

objcopy -S -O binary -j .text kernel.out kernel.bin

  

将kernel.bin写入到硬盘镜像(从#1扇区开始)

dd if=target/kernel.bin of=10M.img bs=512 seek=1 count=200 conv=notrunc

 

3.9 放入borch虚拟机中运行

     配置一个虚拟机,配置如下,bochsrc :

  1 ###############################################################   2 # Configuration file for Bochs   3 ###############################################################   4    5 # how much memory the emulated machine will have   6 megs: 32   7    8 # filename of ROM images   9 romimage: file=/usr/local/share/bochs/BIOS-bochs-latest  10 vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest  11   12 # what disk images will be used  13 #floppya: 1_44=a.img, status=inserted  14 ata0-master: type=disk, mode=flat, path="10M.img", cylinders=20, heads=16, spt=63  15   16 # choose the boot disk.  17 #boot: floppy  18 boot: disk  19   20   21 # where do we send log messages?  22 # log: bochsout.txt  23 # disable the mouse  24 mouse: enabled=0  25   26 # enable key mapping, using US layout as default.  27 keyboard_mapping: enabled=1, map=/usr/local/share/bochs/keymaps/x11-pc-us.map  28   29 

 

关键配置说明:

  • megs: 32 表示内存为32M
  • boot: disk 表示从硬盘启动
  • ata0-master: path=”10M.img”, 设置了硬盘镜像的路径
  • vgaromimage: file=VGABIOS-lgpl-latest 表示显卡的rom镜像为VGABIOS-lgpl-latest,如果设置错误,显示就会不正常。
  • keyboard_mapping: enabled=1, 用于设置键盘布局,这里采用美式键盘布局。

 

启动虚拟机

bochs -q

 

效果如下:

何德海的博客

 

3.10  makefile

  用makefile将上面零散的命令整合一下。脚本如下,Makefile: 

  1 .PHONY : all clean run install   2    3 CFLAGS = -std=gnu99  -fno-stack-protector  -m32 -Wall   4    5 all: target/boot.bin target/kernel.bin install   6    7 target/boot.bin : src/boot.asm   8 	nasm src/boot.asm -f bin -o target/boot.bin   9   10 target/kernel.bin : target/kernel.out  11 	objcopy -S -O binary -j .text  target/kernel.out target/kernel.bin  12   13 target/x86.o :  src/x86.asm  14 	nasm -f elf -o target/x86.o src/x86.asm  15   16 target/kernel.o : src/kernel.c  17 	gcc -c $(CFLAGS)  -o target/kernel.o src/kernel.c  18   19 # x86.o要放到最后,否则会无法运行  20 target/kernel.out : target/kernel.o target/x86.o  21 	ld -s -T kernel.ld -o target/kernel.out target/kernel.o  target/x86.o  22   23   24   25 install :  26 	# #0扇区  27 	dd if=target/boot.bin of=10M.img bs=512 count=1 conv=notrunc  28 	# #1 ~ #200 扇区  29 	dd if=target/kernel.bin of=10M.img bs=512 seek=1 count=200 conv=notrunc  30 	# #201扇区开始  31 	dd if=src/cat-666.bmp of=10M.img bs=512 seek=201  conv=notrunc  32   33   34 run :  35 	make all  36 	bochs -q  37   38   39 clean :  40 	-rm target/*.bin  41 	-rm target/*.o  42 	-rm target/*.out  43   44   45   46 

脚本说明:

  • 将源文件放到src目录下,将目标文件放到target目录下。
  • make run 为运行。 
  • make install 为安装。
  • make clean 为清理。

3.11 内存和硬盘布局 

内存布局

物理地址

内容

0x7c00 ~ 0x7dff

启动区

0x7e00~ 0x7eff

gdt

0x100000~0x1fffff

内核,大小1M。

0x200000开始

图片。

0x0a0000-0xaf9ff

图像缓冲区

硬盘布局

扇区

内容

#0

boot.bin

#1 ~ #200

kernel.bin

#201

cat-6666.bmp

 

4 参考资料

  • 《x86汇编语言 从实模式到保护模式》
  • 《Linux0.11内核完全注释》
  • 《30天自制操作系统》
  • 《一步一步学习linux汇编语言程序设计》
  • 《xv6》

何德海的博客资料部分资料来自网络,侵权毕设源码联系删除

区块链毕设网(www.qklbishe.com)全网最靠谱的原创区块链毕设代做网站
部分资料来自网络,侵权联系删除!
资源收费仅为搬运整理打赏费用,用户自愿支付 !
qklbishe.com区块链毕设代做网专注|以太坊fabric-计算机|java|毕业设计|代做平台 » 何德海的博客资料

提供最优质的资源集合

立即查看 了解详情