From 40a551d15411d49a01a1435b9bd63b0868659708 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Thu, 27 Jan 2022 14:58:14 +0800 Subject: [PATCH] =?UTF-8?q?:wrench:=20=E4=BD=BFcpu=E6=94=AF=E6=8C=81SSE?= =?UTF-8?q?=EF=BC=88=E7=9B=AE=E5=89=8D=E4=BC=9A=E5=87=BA=E7=8E=B0#GP?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bootloader/loader.asm | 10 ++++ kernel/Makefile | 18 ++++--- kernel/common/glib.h | 11 ++++- kernel/common/printk.c | 106 +++++++++++++++++++++++++++++++++++++++- kernel/common/printk.h | 3 ++ kernel/exception/trap.c | 2 +- kernel/main.c | 14 ++++-- kernel/mm/mm.c | 29 +++++++++++ kernel/mm/mm.h | 21 ++++++++ 9 files changed, 198 insertions(+), 16 deletions(-) create mode 100644 kernel/mm/mm.c create mode 100644 kernel/mm/mm.h diff --git a/bootloader/loader.asm b/bootloader/loader.asm index aeb0c1c8..be7e5984 100644 --- a/bootloader/loader.asm +++ b/bootloader/loader.asm @@ -545,6 +545,7 @@ Label_Set_SVGA_Mode: mov eax, cr0 or eax, 1 ; 启用保护模式 + or eax, 0x22 ; 启用x87浮点运算单元 mov cr0, eax ; 跳转到保护模式下的第一个程序 @@ -632,6 +633,15 @@ GO_TO_TMP_Protect: bts eax, 31 ; 开启分页管理机制 mov cr0, eax + ;now enable SSE and the like + mov eax, cr0 + and ax, 0xFFFB ;clear coprocessor emulation CR0.EM + or ax, 0x2 ;set coprocessor monitoring CR0.MP + mov cr0, eax + mov eax, cr4 + or ax, 3 << 9 ;set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time + mov cr4, eax + ; === 通过此条远跳转指令,处理器跳转到内核文件进行执行,正式进入IA-32e模式 diff --git a/kernel/Makefile b/kernel/Makefile index 16cb308b..cd720750 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,14 +1,17 @@ SUBDIR_ROOTS := . common DIRS := . $(shell find $(SUBDIR_ROOTS) -type d) -GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ kernel *.a +GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ kernel GARBAGE := $(foreach DIR,$(DIRS),$(addprefix $(DIR)/,$(GARBAGE_PATTERNS))) +DIR_LIB=lib +lib_patterns := *.a +LIB_FILES := $(foreach DIR,$(DIR_LIB),$(addprefix $(DIR)/,$(lib_patterns))) all: kernel objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary kernel ../bin/kernel/kernel.bin -kernel: head.o entry.o main.o printk.o trap.o - ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o -T link.lds +kernel: head.o entry.o main.o printk.o trap.o mm.o + ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o mm/mm.o -T link.lds head.o: head.S gcc -E head.S > head.s # 预处理 @@ -21,14 +24,17 @@ entry.o: exception/entry.S main.o: main.c # -fno-builtin: 不使用C语言内建函数 # The -m64 option sets int to 32bits and long and pointer to 64 bits and generates code for AMD’s x86-64 architecture. - gcc -mcmodel=large -fno-builtin -m64 -c main.c -o main.o -fno-stack-protector + gcc -mcmodel=large -fno-builtin -m64 -c main.c -o main.o printk.o: common/printk.c - gcc -mcmodel=large -fno-builtin -m64 -c common/printk.c -o common/printk.o -fno-stack-protector + gcc -mcmodel=large -fno-builtin -m64 -c common/printk.c -o common/printk.o trap.o: exception/trap.c - gcc -mcmodel=large -fno-builtin -m64 -c exception/trap.c -o exception/trap.o -fno-stack-protector + gcc -mcmodel=large -fno-builtin -m64 -c exception/trap.c -o exception/trap.o + +mm.o: mm/mm.c + gcc -mcmodel=large -fno-builtin -m64 -c mm/mm.c -o mm/mm.o clean: rm -rf $(GARBAGE) \ No newline at end of file diff --git a/kernel/common/glib.h b/kernel/common/glib.h index f70c9a2a..ed4b522d 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -24,13 +24,20 @@ #define io_lfence() __asm__ __volatile__("lfence\n\t" :: \ : "memory") // 在lfence指令前的读操作当必须在lfence指令后的读操作前完成。 -#define ABS(x) ((x) > 0 ? (x) : -(x)) // 绝对值 - // 定义类型的缩写 typedef unsigned long ul; typedef unsigned long long ull; typedef long long ll; +#define ABS(x) ((x) > 0 ? (x) : -(x)) // 绝对值 + +// 四舍五入成整数 +ul round(double x) +{ + return (ul)(x+0.5); +} + + //链表数据结构 struct List { diff --git a/kernel/common/printk.c b/kernel/common/printk.c index d6daa42b..4accf7c9 100644 --- a/kernel/common/printk.c +++ b/kernel/common/printk.c @@ -2,7 +2,6 @@ // Created by longjin on 2022/1/22. // #include "printk.h" -#include //#include "linkage.h" struct screen_info pos; @@ -351,6 +350,18 @@ static int vsprintf(char *buf, const char *fmt, va_list args) *ip = str - buf; break; + case 'f': + // 默认精度为3 + //printk("1111\n"); + //va_arg(args, double); + //printk("222\n"); + + if (precision < 0) + precision = 3; + str = write_float_point_num(str, va_arg(args, double), field_width, precision, flags); + + + break; //对于不识别的控制符,直接输出 default: @@ -460,7 +471,98 @@ static char *write_num(char *str, long long num, int base, int field_width, int while (js_num-- > 0) *str++ = tmp_num[js_num]; - + + while (field_width-- > 0) + *str++ = ' '; + + return str; +} + +static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags) +{ + /** + * @brief 将浮点数按照指定的要求转换成对应的字符串 + * + * @param str 要返回的字符串 + * @param num 要打印的数值 + * @param field_width 区域宽度 + * @param precision 精度 + * @param flags 标志位 + */ + + char pad, sign, tmp_num_z[100], tmp_num_d[350]; + + const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + // 显示小写字母 + if (flags & SMALL) + digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + + // 设置填充元素 + pad = (flags & PAD_ZERO) ? '0' : ' '; + + sign = 0; + if (flags & SIGN && num < 0) + { + sign = '-'; + num = -num; + } + else + { + // 设置符号 + sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0); + } + + // sign占用了一个宽度 + if (sign) + --field_width; + + int js_num_z = 0, js_num_d = 0; // 临时数字字符串tmp_num_z tmp_num_d的长度 + ul num_z = (ul)(num); // 获取整数部分 + ul num_decimal = (ul)(round((num - num_z) * precision)); // 获取小数部分 + + if (num == 0) + tmp_num_z[js_num_z++] = '0'; + else + { + //存储整数部分 + while (num_z > 0) + { + tmp_num_z[js_num_z++] = digits[num_z % 10]; // 注意这里,输出的数字,是小端对齐的。低位存低位 + num_z /= 10; + } + } + + while (num_decimal > 0) + { + tmp_num_d[js_num_d++] = digits[num_decimal % 10]; + num_decimal /= 10; + } + + field_width -= (precision + 1 + js_num_z); + + // 靠右对齐 + if (!(flags & LEFT)) + while (field_width-- > 0) + *str++ = pad; + + if (sign) + *str++ = sign; + + // 输出整数部分 + while (js_num_z-- > 0) + *str++ = tmp_num_z[js_num_z]; + + *str++ = '.'; + + // 输出小数部分 + while (js_num_d-- > 0) + *str++ = tmp_num_d[js_num_d]; + + while (js_num_d < precision) + { + --precision; + *str++ = '0'; + } while (field_width-- > 0) *str++ = ' '; diff --git a/kernel/common/printk.h b/kernel/common/printk.h index 50acbacc..0a8818ef 100644 --- a/kernel/common/printk.h +++ b/kernel/common/printk.h @@ -94,6 +94,9 @@ static int vsprintf(char *buf, const char *fmt, va_list args); */ static char* write_num(char *str, long long num, int base, int field_width, int precision, int flags); + +static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags); + /** * @brief 在屏幕上指定位置打印字符 * diff --git a/kernel/exception/trap.c b/kernel/exception/trap.c index 978c22ac..011b1434 100644 --- a/kernel/exception/trap.c +++ b/kernel/exception/trap.c @@ -211,7 +211,7 @@ void do_general_protection(unsigned long rsp, unsigned long error_code) printk("[ "); printk_color(RED, BLACK, "ERROR"); printk(" ] do_general_protection(13),\tError Code:%#18lx,\tRSP:%#18lx,\tRIP:%#18lx\n", error_code, rsp, *rip); - + return; while (1) ; } diff --git a/kernel/main.c b/kernel/main.c index cc34a007..5d5382a1 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -6,8 +6,10 @@ #include "common/printk.h" #include "exception/gate.h" #include "exception/trap.h" +#include "mm/mm.h" int *FR_address = (int *)0xffff800000a00000; //帧缓存区的地址 +char fxsave_region[512] __attribute__((aligned(16))); void show_welcome() { @@ -67,11 +69,16 @@ void init() // 初始化任务状态段表 ul tss_item_addr = 0xffff800000007c00; set_TSS64(tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, - tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr); + tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr); // 初始化中断描述符表 init_sys_vector(); + + asm volatile(" fxsave %0 " ::"m"(fxsave_region)); + // 初始化内存管理单元 + printk("[ DragonOS ] Initializing memory manage unit...\n"); + mm_init(); } //操作系统内核从这里开始执行 void Start_Kernel(void) @@ -80,13 +87,10 @@ void Start_Kernel(void) init(); show_welcome(); - - //test_printk(); //int t = 1 / 0; // 测试异常处理模块能否正常工作 触发除法错误 - int t = *(int*) 0xffff80000aa00000; // 触发页故障 - + // int t = *(int *)0xffff80000aa00000; // 触发页故障 while (1) ; diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c new file mode 100644 index 00000000..a2c3f5d3 --- /dev/null +++ b/kernel/mm/mm.c @@ -0,0 +1,29 @@ +#include "mm.h" +#include "../common/printk.h" + +ul Total_Memory = 0; +void mm_init() +{ + // 实模式下获取到的信息的起始地址,转换为ARDS指针 + struct ARDS *ards_ptr = (struct ARDS *)0xffff800000007e00; + + for (int i = 0; i < 32; ++i) + { + printk("Addr = %#10lx,%8lx\tLength = %#10lx,%8lx\tType = %#10lx\n", + ards_ptr->BaseAddrH, ards_ptr->BaseAddrL, ards_ptr->LengthH, ards_ptr->LengthL, ards_ptr->type); + + //可用的内存 + if (ards_ptr->type == 1) + { + Total_Memory += ards_ptr->LengthL; + Total_Memory += ((ul)(ards_ptr->LengthH)) << 32; + } + + ++ards_ptr; + + // 脏数据 + if (ards_ptr->type > 4) + break; + } + printk_color(ORANGE, BLACK, "Total amount of RAM DragonOS can use: %ld bytes\n", Total_Memory); +} \ No newline at end of file diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h new file mode 100644 index 00000000..0411eaed --- /dev/null +++ b/kernel/mm/mm.h @@ -0,0 +1,21 @@ +#pragma once + +#include"../common/glib.h" + +// Address Range Descriptor Structure 地址范围描述符 +struct ARDS +{ + unsigned int BaseAddrL; // 基地址低32位 + unsigned int BaseAddrH; // 基地址高32位 + unsigned int LengthL; // 内存长度低32位 以字节为单位 + unsigned int LengthH; // 内存长度高32位 + unsigned int type; // 本段内存的类型 + // type=1 表示可以被操作系统使用 + // type=2 ARR - 内存使用中或被保留,操作系统不能使用 + // 其他 未定义,操作系统需要将其视为ARR +}; + + + + +void mm_init(); \ No newline at end of file