From 5e054c5c85ea746a01327982fc9553d284a68bf1 Mon Sep 17 00:00:00 2001 From: qingshu-yu <99584740+qingshu-yu@users.noreply.github.com> Date: Sun, 13 Feb 2022 16:44:13 +0800 Subject: [PATCH 1/5] Update boot.s --- boot/x86/boot.s | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/boot/x86/boot.s b/boot/x86/boot.s index d17c66b3..daaabb25 100644 --- a/boot/x86/boot.s +++ b/boot/x86/boot.s @@ -7,38 +7,48 @@ org 7c00h _start: %define init_base 0x0500 bits 16 - mov ax, cs - mov ds, ax - mov ss, ax - ; mov sp, 0 + ; 寄存器复位 + mov ax, cs + mov ds, ax + mov ss, ax + ; mov sp, 0 + + ; 屏蔽所有外部中断 cli + + ; 清除屏幕 call cls - + + ; 初始化光标 mov dx,0x0000 call set_cursor - + + ; 打印boot字符串 mov si,boot call print_string - + + ; 读取磁盘 mov bx,init_base call load_init - + + ; 读取成功 mov si,load_init_success call print_string - ;;跳转loader地址 + ; 跳转到loader jmp init_base jmp $ -;;磁盘读取到内存 es:bx 地址 +; int 13h ah=02h 读取磁盘扇区 al=读入的扇区数 ch=磁道号的低8位 cl=扇区号1~63(bit 0~5)磁道号,(柱面号)的高2位(bit 6~7,只对硬盘有效) dh=磁头号 dl=驱动器号 es:bx=>数据缓冲区 +; 根目录占用空间 = 14(详细请查看fat12相关信息) load_init: - mov ah,0x02 ;读取功能 - mov al,0x0e ;读取几个扇区 - mov cl,0x02 ;0x01 boot sector, 0x02 is first sector + mov ah,0x02 + mov al,0x0e + mov cl,0x02 mov ch,0x00 mov dh,0x00 - mov dl,0x00 ;软盘0 + mov dl,0x00 int 0x13 jc disk_error jmp dend @@ -50,9 +60,13 @@ dend: %include "boot/x86/util.s" +; 字符串定义(0x0a,0x0d,0表结束符) boot db "boot duck",0x0a,0x0d,0 disk_erro db "read boot disk erro",0x0a,0x0d,0 load_init_success db "load init success",0x0a,0x0d,0 +; 补齐至512 times 510-($-$$) db 0 + +; boot结束标志 dw 0xaa55 From 97d93d81ab3d58059f1f2c8b1a5465aede760147 Mon Sep 17 00:00:00 2001 From: qingshu-yu <99584740+qingshu-yu@users.noreply.github.com> Date: Sun, 13 Feb 2022 17:00:06 +0800 Subject: [PATCH 2/5] Update util.s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加注释 --- boot/x86/util.s | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/boot/x86/util.s b/boot/x86/util.s index 8c9dfbec..87579268 100644 --- a/boot/x86/util.s +++ b/boot/x86/util.s @@ -1,26 +1,30 @@ -;;设置光标位置 DH=列,DL=行 +; 设置光标位置 +; int 10h ah=02h表设定光标位置 dh=游标的列数 dl=游标的行数 bh=页码 set_cursor: - mov ah,0x02 ;光标位置初始化 + mov ah,0x02 mov bh,0 int 0x10 ret + reset: mov ah,0x00 mov al,0x01 int 0x10 ret -;;清除屏幕 +; 清除屏幕 +; int 10h ah=06h表滚动窗口 al=滚动的列数,若为0则实现清空屏幕功能 cls: - mov ah,0x06 ;清除屏幕 + mov ah,0x06 mov al,0 - mov cx,0 + mov cx,0 mov dx,0xffff - mov bh,0x0f ;属性为白字 + mov bh,0x0f int 0x10 ret -;;打印一个字符 al=ascii值 +; 打印一个字符 +; int 10h ah=0eh al=打印字符 bh=页码 bl=前景色 print_char: mov ah,0eh mov bx,0007h @@ -37,4 +41,4 @@ print_string: call print_char jmp ps pend: - ret \ No newline at end of file + ret From 87a970328c21927f20d63ca48d8699d2a19a5d77 Mon Sep 17 00:00:00 2001 From: qingshu-yu <99584740+qingshu-yu@users.noreply.github.com> Date: Sun, 13 Feb 2022 17:40:11 +0800 Subject: [PATCH 3/5] Update config.h --- boot/x86/config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boot/x86/config.h b/boot/x86/config.h index fe50be94..33f57fa5 100644 --- a/boot/x86/config.h +++ b/boot/x86/config.h @@ -1,5 +1,7 @@ #ifndef BOOT/X86/CONFIG_H #define BOOT/X86/CONFIG_H +// 内核块数(512) #define KERNEL_BLOCK_SIZE 93 +// 内核大小 #define KERNEL_SIZE 95064 #endif From 762330b445df7dba2c9fe1455b971b399f7bee27 Mon Sep 17 00:00:00 2001 From: qingshu-yu <99584740+qingshu-yu@users.noreply.github.com> Date: Sun, 13 Feb 2022 17:41:55 +0800 Subject: [PATCH 4/5] Update init.h --- boot/x86/init.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/boot/x86/init.h b/boot/x86/init.h index f9978a6e..1c87a8ab 100644 --- a/boot/x86/init.h +++ b/boot/x86/init.h @@ -10,11 +10,16 @@ #include "config.h" -#define KERNEL_MOVE +#define KERNEL_MOVE +// 扇区大小 #define READ_BLOCK_SIZE 512 +// 内核地址 #define KERNEL_BASE 0x100000 +// 内核原地址 #define KERNEL_ORIGIN_BASE 0x10000 +// 页表地址 #define PDT_BASE 0x9000 +// 版本 #define BOOT_VERSION 0x01 @@ -29,4 +34,4 @@ void* load_kernel(); void init_memory(); void init_kernel(); -#endif \ No newline at end of file +#endif From f14670832e1d9fa3dbb06907722b02734da83c1c Mon Sep 17 00:00:00 2001 From: qingshu-yu <99584740+qingshu-yu@users.noreply.github.com> Date: Sun, 13 Feb 2022 17:57:40 +0800 Subject: [PATCH 5/5] Update init.c --- boot/x86/init.c | 72 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/boot/x86/init.c b/boot/x86/init.c index 90a46de8..d8d1aeed 100644 --- a/boot/x86/init.c +++ b/boot/x86/init.c @@ -5,6 +5,7 @@ ********************************************************************/ #include "init.h" +// 标识16位代码 asm(".code16gcc\n"); asm("cli\n"); #if defined(__WIN32__) @@ -18,10 +19,13 @@ boot_info_t boot_data; u8 kernel_stack[1024]; // 1k u8 kernel_stack_top[0]; +// 清屏,设置光标 void cls() { // clear screen + // int 10h ah=06h表滚动窗口 AL=滚动的列数,若为0则实现清空屏幕功能 asm("int $0x10\n" : : "a"(0x0600)); // set cursor pos + // int 10h ah=02h表设定光标位置 DH=游标的列数 DL=游标的行数 BH=页码 asm("int $0x10\n" : : "a"(0x0200), "b"(0x0000), "d"(0x00)); // __asm__ __volatile__("int $0x10" : : "a"(0x0013)); } @@ -38,7 +42,10 @@ void getch() { "int $0x16\n"); } -void print_char(char s) { asm("int $0x10\n" : : "a"(s | 0x0e00), "b"(0x0007)); } +void print_char(char s) { + // int 10h ah=0eh al=打印字符 bh=页码 bl=前景色 + asm("int $0x10\n" : : "a"(s | 0x0e00), "b"(0x0007)); +} void itoa(char* buf, int base, int d) { char* p = buf; @@ -65,6 +72,7 @@ void itoa(char* buf, int base, int d) { *p = 0; /* Reverse BUF. */ + // 字符顺序调整 p1 = buf; p2 = p - 1; while (p1 < p2) { @@ -77,6 +85,7 @@ void itoa(char* buf, int base, int d) { } void printf(const char* format, ...) { + // 取得参数列表基址 char** arg = (char**)&format; int c; char buf[20]; @@ -84,8 +93,10 @@ void printf(const char* format, ...) { arg++; while ((c = *format++) != 0) { + // 为可输出字符 if (c != '%') print_char(c); + // 分析格式 else { char* p; @@ -115,6 +126,7 @@ void printf(const char* format, ...) { } } +// 初始化boot_info信息 void init_boot_info() { boot_info = &boot_data; boot_info->version = BOOT_VERSION; @@ -127,8 +139,11 @@ void init_boot_info() { } void init_disk() { + // 固定值 boot_info->disk.hpc = 2; + // 每柱面扇区数 boot_info->disk.spt = 18; + // 1.44m软盘 boot_info->disk.type = 1; // 1.44m floppy flat lba } @@ -165,6 +180,8 @@ u8 disk_read(u16 disk, u16 head, u16 cylinder, u16 sector, u16 number, u32 addr, u16 dx = (head << 8) | disk; u16 ax = (0x02 << 8) | number; u16 erro; + // int 13h ah=02h 读取磁盘扇区 al=读入的扇区数 ch=磁道号的低8位 cl=扇区号1~63(bit 0~5)磁道号,(柱面号)的高2位(bit 6~7,只对硬盘有效) dh=磁头号 dl=驱动器号 es:bx=>数据缓冲区 + // 调用结束 如果访问出错则CF被置1,AX存放错误信息 如果访问成功则CF被清零,AH存放状态,AL存放读入扇区数 asm volatile( "pushw %%es \n" "movw %w[seg], %%es \n" @@ -181,6 +198,7 @@ u8 disk_read(u16 disk, u16 head, u16 cylinder, u16 sector, u16 number, u32 addr, } u8 disk_read_lba(u32 lba, u32 addr, u8* status) { + // 将LBA格式转换为CHS格式(Cylinder/Head/Sector,柱面/磁头/扇区) u32 cylinder = lba / boot_info->disk.spt / boot_info->disk.hpc; u32 head = (lba / boot_info->disk.spt) % boot_info->disk.hpc; u32 sector = (lba % boot_info->disk.spt) + 1; @@ -200,9 +218,13 @@ u8 disk_read_lba(u32 lba, u32 addr, u8* status) { void read_kernel() { u8 status = 0; print_string(""); + // 柱面号 u32 cylinder = 0; + // 磁头号 u32 head = 0; + // 扇区号 u32 sector = 0xc; + // LBA(Logical Block Address,逻辑块寻址)格式磁盘扇区号 u32 lba = 0x00; u8 ret = 0; if (boot_info->disk.type == 1) { @@ -213,6 +235,7 @@ void read_kernel() { #ifdef KERNEL_MOVE u32 addr = boot_info->kernel_origin_base; #else + // 内核将要被读取到的位置 u32 addr = boot_info->kernel_base; #endif for (int i = 0; i < KERNEL_BLOCK_SIZE * 2; i++) { @@ -258,21 +281,26 @@ int memory_prob() { memory_info_t* ptr = boot_info->memory; boot_info->total_memory = 0; for (; count < MAX_MEMORY_BLOCK;) { + // int 15h ax=E820h表获取内存信息 ebx第一次调用必须为0 ecx表内存结构体的大小(字节) edx=0534D4150h es:di为内存信息结构体 + // 调用结束 eax=0534D4150h(如果不为0534D4150h,则硬件故障) ebx=无需关心值为什么,只需再次传入即可获取下一个内存信息描述符 ecx=被填充的字符数 asm("int $0x15" : "=a"(signature), "=c"(bytes), "=b"(id) : "a"(0xE820), "b"(id), "c"(24), "d"(0x534D4150), "D"(ptr)); + // 硬件故障 if (signature != 0x534D4150) { return -1; - } else if (bytes > 20 && (ptr->extended & 0x0001) == 0) { + } else if (bytes > 20 && (ptr->extended & 0x0001) == 0) { // 检查CF,是否发生错误 } else { boot_info->total_memory += ptr->length; ptr++; count++; } + // ebx为0表示为最后一个内存区域 if (id == 0) { break; } } + // 记录内存区域数量 boot_info->memory_number = count; return count; } @@ -332,28 +360,40 @@ void init_gdt() { void init_cpu() { // enable cr0 + // 置位CR0寄存器的第0位来开启保护模式 unsigned long cr0 = read_cr0(); write_cr0(cr0 | 1); } void init_boot() { + // 初始化boot_info信息 init_boot_info(); + + // 清屏,设置光标 cls(); printf("boot info addr %x\n\r", boot_info); - + + // 初始化gdt init_gdt(); - + + // 初始化显示模式信息 print_string("init display\n\r"); init_display(); - + + // 初始化内存信息 print_string("init memory\n\r"); init_memory(); - + + // 初始化软盘 init_disk(); - + + // 读取内核 read_kernel(); + + // 初始化cpu init_cpu(); - + + // 栈设置 asm volatile( "movl %0, %%esp\n" "mov %%esp,%%ebp\n" @@ -381,6 +421,7 @@ void* load_kernel() { #endif Elf32_Ehdr* elf_header = (Elf32_Ehdr*)elf; + // 判断魔数,如果是elf文件,则加载elf文件,找到内核程序入口 if (elf_header->e_ident[0] == ELFMAG0 || elf_header->e_ident[1] == ELFMAG1) { // printf("header: "); // for (int x = 0; x < 16; x++) { @@ -398,11 +439,12 @@ void* load_kernel() { load_elf(elf_header); return elf_header->e_entry; } else { - // printf("bin kernel\n\r"); - return boot_info->kernel_base; + // printf("bin kernel\n\r"); + return boot_info->kernel_base; // 如果不是elf文件,程序入口即内核地址 } } +// 从s2复制n个字符到s1 void* memmove32(void* s1, const void* s2, u32 n) { u32 *dest, *src; int i; @@ -413,6 +455,7 @@ void* memmove32(void* s1, const void* s2, u32 n) { } } +// 处理elf文件 void load_elf(Elf32_Ehdr* elf_header) { // printf("e_phnum:%d\n\r", elf_header->e_phnum); u16* elf = elf_header; @@ -427,6 +470,7 @@ void load_elf(Elf32_Ehdr* elf_header) { // phdr[i].p_vaddr, phdr[i].p_paddr, "", phdr[i].p_filesz, // phdr[i].p_memsz); break; + // 提取出来可加载程序段 case PT_LOAD: { // printf(" %s %x %x %x %s %x %x \r\n", "LOAD", phdr[i].p_offset, // phdr[i].p_vaddr, phdr[i].p_paddr, "", phdr[i].p_filesz, @@ -507,17 +551,23 @@ void load_elf(Elf32_Ehdr* elf_header) { // start kernel void start_kernel() { asm volatile("cli\n"); + // 寄存器置位 asm volatile("movl %0, %%ss" : : "r"(GDT_ENTRY_32BIT_DS * GDT_SIZE)); asm volatile("movl %0, %%ds" : : "r"(GDT_ENTRY_32BIT_DS * GDT_SIZE)); asm volatile("movl %0, %%es" : : "r"(GDT_ENTRY_32BIT_DS * GDT_SIZE)); asm volatile("movl %0, %%gs" : : "r"(GDT_ENTRY_32BIT_DS * GDT_SIZE)); asm volatile("movl %0, %%fs" : : "r"(GDT_ENTRY_32BIT_FS * GDT_SIZE)); // print_string("load kernel\n\r"); + // 获取内核入口 boot_info->kernel_entry = load_kernel(); entry start = boot_info->kernel_entry; + + // 参数 int argc = 0; char** argv = 0; char* envp[10]; envp[0] = boot_info; + + // 转至内核 start(argc, argv, envp); -} \ No newline at end of file +}