Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update boot.s #9

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions boot/x86/boot.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
2 changes: 2 additions & 0 deletions boot/x86/config.h
Original file line number Diff line number Diff line change
@@ -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
72 changes: 61 additions & 11 deletions boot/x86/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
********************************************************************/
#include "init.h"

// 标识16位代码
asm(".code16gcc\n");
asm("cli\n");
#if defined(__WIN32__)
Expand All @@ -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));
}
Expand All @@ -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;
Expand All @@ -65,6 +72,7 @@ void itoa(char* buf, int base, int d) {
*p = 0;

/* Reverse BUF. */
// 字符顺序调整
p1 = buf;
p2 = p - 1;
while (p1 < p2) {
Expand All @@ -77,15 +85,18 @@ void itoa(char* buf, int base, int d) {
}

void printf(const char* format, ...) {
// 取得参数列表基址
char** arg = (char**)&format;
int c;
char buf[20];

arg++;

while ((c = *format++) != 0) {
// 为可输出字符
if (c != '%')
print_char(c);
// 分析格式
else {
char* p;

Expand Down Expand Up @@ -115,6 +126,7 @@ void printf(const char* format, ...) {
}
}

// 初始化boot_info信息
void init_boot_info() {
boot_info = &boot_data;
boot_info->version = BOOT_VERSION;
Expand All @@ -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
}

Expand Down Expand Up @@ -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"
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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++) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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++) {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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);
}
}
9 changes: 7 additions & 2 deletions boot/x86/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -29,4 +34,4 @@ void* load_kernel();
void init_memory();
void init_kernel();

#endif
#endif
Loading