Browse Source

:wrench: 使cpu支持SSE(目前会出现#GP)

fslongjin 3 years ago
parent
commit
40a551d154
9 changed files with 198 additions and 16 deletions
  1. 10 0
      bootloader/loader.asm
  2. 12 6
      kernel/Makefile
  3. 9 2
      kernel/common/glib.h
  4. 104 2
      kernel/common/printk.c
  5. 3 0
      kernel/common/printk.h
  6. 1 1
      kernel/exception/trap.c
  7. 9 5
      kernel/main.c
  8. 29 0
      kernel/mm/mm.c
  9. 21 0
      kernel/mm/mm.h

+ 10 - 0
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模式
 

+ 12 - 6
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)

+ 9 - 2
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
 {

+ 104 - 2
kernel/common/printk.c

@@ -2,7 +2,6 @@
 // Created by longjin on 2022/1/22.
 //
 #include "printk.h"
-#include <math.h>
 //#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++ = ' ';

+ 3 - 0
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 在屏幕上指定位置打印字符
  * 

+ 1 - 1
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)
         ;
 }

+ 9 - 5
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)
         ;

+ 29 - 0
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);
+}

+ 21 - 0
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();