simon 10 hónapja
szülő
commit
60baa84302
7 módosított fájl, 156 hozzáadás és 11 törlés
  1. 2 0
      kernel/init.c
  2. 1 1
      kernel/main.c
  3. 106 0
      kernel/memory.c
  4. 29 0
      kernel/memory.h
  5. 1 1
      lib/kernel/bitmap.h
  6. 1 0
      lib/stdint.h
  7. 16 9
      makefile

+ 2 - 0
kernel/init.c

@@ -2,10 +2,12 @@
 #include "../lib/kernel/print.h"
 #include "interrupt.h"
 #include "../device/timer.h"
+#include "memory.h"
 
 void init_all(void)
 {
     put_str("init_all\n");
     itd_init();   // 初始化中断
     timer_init(); // 初始化定时器
+    mem_init();   // 初始化内存管理系统
 }

+ 1 - 1
kernel/main.c

@@ -7,7 +7,7 @@ int main(void)
     put_str("I am kernel\n");
     init_all();
     // asm volatile("sti"); // 使能中断
-    ASSERT(1 == 2);
+    // ASSERT(1 == 2);
 
     while (1)
         ;

+ 106 - 0
kernel/memory.c

@@ -0,0 +1,106 @@
+#include "memory.h"
+#include "../lib/kernel/print.h"
+
+#define PG_SIZE 4096 // 1 页 = 4KB = 4096 字节
+/************************ 位图地址 ****************************************
+ * 0xc009f000 是内核主线程栈顶,0xc009e000 是内核主线程的pcb
+ * 一个页框大小的位图可表示128MB内存,位图位置安排在地址0xc009a000
+ * 0xc009e000 - 0x4000 = 0xc009a000
+ */
+#define MEM_BITMAP_BASE 0xc009a000
+/***********************************************************************/
+/*0xc0000000 是内核从虚拟地址 3G 起,0xc0100000 指跨过低端 1MB 内存,使虚拟地址在逻辑上连续 */
+#define K_HEAP_START 0xc0100000
+
+/* 内存池结构,生成两个实例用于管理内核内存池和用户内存池 */
+struct pool
+{
+    struct bitmap pool_bitmap; // 本内存池用到的位图结构,用于管理物理内存
+    uint32_t phy_addr_start;   // 本内存池所管理物理内存的起始地址
+    uint32_t pool_size;        // 本内存池字节容量
+};
+
+struct pool kernel_pool, user_pool; // 生成内核内存池和用户内存池
+struct virtual_addr kernel_vaddr;   // 此结构是用来给内核分配虚拟地址
+
+/* 初始化内存池 */
+static void mem_pool_init(uint32_t all_mem)
+{
+    put_str("    mem_pool_init start\n");
+    // 页表大小 = 页目录项数 * 每个页目录项占用的字节数
+    // 页目录项数 = 1 页的页目录表 + 第 0 和第 768(内核页目录项)个页目录项指向同一个页表 +
+    // 第 769 ~ 1022 个页目录项指向 254 个页表 = 256 个页目录项
+    //! 最后 1 个页目录项(第 1023 个 pde)指向页目录表自身
+    uint32_t page_table_size = PG_SIZE * 256; // 256 个页目录项 * 4KB = 1MB
+
+    // 1024(0x400) * 1024 =  0x100000  是低端 1MB 内存
+    uint32_t used_mem = page_table_size + 0x100000;
+    uint32_t free_mem = all_mem - used_mem;
+    uint16_t all_free_pages = free_mem / PG_SIZE; // 1 页 = 4KB = 4096 字节
+
+    uint16_t kernel_free_pages = all_free_pages / 2;
+    uint16_t user_free_pages = all_free_pages - kernel_free_pages;
+
+    /* 为了简化操作,余数不处理,坏处是这样做会丢失内存,好像是不用做内存的越界检查,因为位图表的内存少于实际物理内存 */
+    uint32_t kbm_length = kernel_free_pages / 8; // Kernel BitMap 长度,位图中的一位表示一页,以字节为单位
+    uint32_t ubm_length = user_free_pages / 8;   // User BitMap 长度
+
+    uint32_t kp_start = used_mem;                               // Kernel Pool 起始地址,内核内存池的起始地址
+    uint32_t up_start = kp_start + kernel_free_pages * PG_SIZE; // User Pool 起始地址,用户内存池的起始地址
+
+    kernel_pool.phy_addr_start = kp_start;
+    user_pool.phy_addr_start = up_start;
+
+    kernel_pool.pool_size = kernel_free_pages * PG_SIZE;
+    user_pool.pool_size = user_free_pages * PG_SIZE;
+
+    kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
+    user_pool.pool_bitmap.btmp_bytes_len = ubm_length;
+
+    /********* 内核内存池和用户内存池的位图 ****************
+     * 位图是全局的数据,长度不固定
+     * 全局或静态的数组需要在编译时知道其长度
+     * 而我们需要根据总内存大小算出需要多少字节
+     * 所以改为指定一块内存来生成位图
+     ************************************************/
+    // 内核使用的最高地址是 0xc009f000,这是主线程的栈地址
+    // 内核的大小预计为 70KB 左右
+    // (32MB = 32 * 1024 * 1024 字节)内存占位图是 1KB
+    // 内核内存池位图的位置安排在地址 0xc009a000
+    kernel_pool.pool_bitmap.bits = (void *)MEM_BITMAP_BASE;
+    // 用户内存池的位图紧跟在内核内存池位图之后
+    user_pool.pool_bitmap.bits = (void *)((uintptr_t)MEM_BITMAP_BASE + kbm_length);
+
+    /********************** 输出内存池信息 ******************************/
+    put_str("    kernel_pool_bitmap_start: ");
+    put_int((uintptr_t)kernel_pool.pool_bitmap.bits);
+    put_str(", kernel_pool_phy_addr_start: ");
+    put_int(kernel_pool.phy_addr_start);
+    put_str("\n");
+    put_str("    user_pool_bitmap_start: ");
+    put_int((uintptr_t)user_pool.pool_bitmap.bits);
+    put_str(", user_pool_phy_addr_start: ");
+    put_int(user_pool.phy_addr_start);
+    put_str("\n");
+
+    bitmap_init(&kernel_pool.pool_bitmap);
+    bitmap_init(&user_pool.pool_bitmap);
+
+    /*********************** 初始化虚拟内存池 ********************************/
+    kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length; // 虚拟地址位图的长度,按实际物理内存大小生成数组
+    /*位图的数组指向一块未使用的内存,目前定位在内核内存池和用户内存池之后*/
+    kernel_vaddr.vaddr_bitmap.bits = (void *)((uintptr_t)MEM_BITMAP_BASE + kbm_length + ubm_length);
+    kernel_vaddr.vaddr_start = K_HEAP_START;
+    bitmap_init(&kernel_vaddr.vaddr_bitmap);
+
+    put_str("    mem_pool_init end\n");
+}
+
+// 内存管理初始化
+void mem_init(void)
+{
+    put_str("mem_init start\n");
+    uint32_t mem_bytes_total = (*(uint32_t *)(0xb00)); // 从地址 0xb00 处取出总内存数
+    mem_pool_init(mem_bytes_total);                    // 初始化内存池
+    put_str("mem_init done\n");
+}

+ 29 - 0
kernel/memory.h

@@ -0,0 +1,29 @@
+/************************************************************************
+ * 0xc0000000 是内核从虚拟地址3G起
+ * 0x100000 是内核从物理地址1M起
+ *
+ * 低端1MB内存中,0x00000000~0x00a0000 是低端640K内存
+ * 0x00a0000~0x00f0000 是显存
+ * 0x00f0000~0x0100000 是BIOS数据区
+ *
+ * 0xc0000000~0xc0100000 是映射到物理地址的前1MB内存
+ * 0xc0100000~0xf0000000 是内核地址空间,共503MB
+ * 0xf0000000~ 是保留给用户的地址空间
+ ************************************************************************/
+#ifndef __KERNEL_MEMORY_H
+#define __KERNEL_MEMORY_H
+
+#include "../lib/stdint.h"
+#include "../lib/kernel/bitmap.h"
+
+// 虚拟地址池,用于虚拟地址管理
+struct virtual_addr
+{
+    Bitmap vaddr_bitmap;  // 虚拟地址用到的位图结构
+    uint32_t vaddr_start; // 虚拟地址起始地址
+};
+
+extern struct pool kernel_pool, user_pool; // 内核内存池和用户内存池
+void mem_init(void);                       // 内存管理初始化
+
+#endif // __KERNEL_MEMORY_H

+ 1 - 1
lib/kernel/bitmap.h

@@ -3,7 +3,7 @@
 #include "../../kernel/global.h"
 
 #define BITMAP_MASK 1
-typedef struct
+typedef struct bitmap
 {
     uint32_t btmp_bytes_len; // 位图字节长度
     uint8_t *bits;           // 位图的指针

+ 1 - 0
lib/stdint.h

@@ -16,5 +16,6 @@ typedef unsigned int uint32_t;
 typedef unsigned long long uint64_t;
 
 typedef uint8_t bool;
+typedef unsigned long uintptr_t;
 
 #endif // __LIB_STDINT_H

+ 16 - 9
makefile

@@ -12,7 +12,8 @@ CFLAGS = -Wall $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototype
 LDFLAGS = -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_BIN_DIR)/kernel.map
 OBJS = $(BUID_O_DIR)/main.o $(BUID_O_DIR)/init.o $(BUID_O_DIR)/interrupt.o  \
 	$(BUID_O_DIR)/timer.o $(BUID_O_DIR)/kernel.o $(BUID_O_DIR)/print.o   \
-	$(BUID_O_DIR)/debug.o $(BUID_O_DIR)/string.o $(BUID_O_DIR)/bitmap.o
+	$(BUID_O_DIR)/debug.o $(BUID_O_DIR)/string.o $(BUID_O_DIR)/bitmap.o  \
+	$(BUID_O_DIR)/memory.o
 
 ################################ C 代码编译 ################################
 $(BUID_O_DIR)/main.o: kernel/main.c lib/kernel/print.h lib/stdint.h kernel/init.h
@@ -36,6 +37,9 @@ $(BUID_O_DIR)/string.o: lib/string.c lib/string.h lib/stdint.h
 $(BUID_O_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h lib/stdint.h lib/string.h
 	$(CC) $(CFLAGS) $< -o $@
 
+$(BUID_O_DIR)/memory.o: kernel/memory.c kernel/memory.h lib/stdint.h lib/kernel/bitmap.h lib/string.h lib/kernel/print.h
+	$(CC) $(CFLAGS) $< -o $@
+
 ################################ 汇编代码编译 ################################
 $(BUID_O_DIR)/kernel.o: kernel/kernel.S
 	$(AS) $(ASFLAGS) $< -o $@
@@ -54,7 +58,7 @@ $(BUILD_BIN_DIR)/kernel.bin: $(OBJS)
 	$(LD) $(LDFLAGS) $^ -o $@
 
 
-.PHONY:clean mk_dir mbr loader K create_img hd run all
+.PHONY:clean mk_dir mbr loader K create_img hd run build all
 
 mk_dir:
 	@if [ ! -d $(BUID_O_DIR) ]; then mkdir $(BUID_O_DIR); fi
@@ -62,27 +66,30 @@ mk_dir:
 
 ################################ 创建 DIS_IMG ################################
 create_img:
-	bximage -q -func=create -hd=30M $(DIS_IMG)
+	@if [ ! -f $(DIS_IMG) ]; then bximage -q -func=create -hd=30M $(DIS_IMG); fi
 	@echo "创建 $(DIS_IMG) 成功"
 
-hd:
+hd: mbr loader K create_img
 	dd if=$(BUILD_BIN_DIR)/mbr.bin of=$(DIS_IMG) bs=512 count=1 conv=notrunc
 	dd if=$(BUILD_BIN_DIR)/loader.bin of=$(DIS_IMG) bs=512 count=4 seek=2 conv=notrunc
 	dd if=$(BUILD_BIN_DIR)/kernel.bin of=$(DIS_IMG) bs=512 count=200 seek=9 conv=notrunc
 
-clean:
+clean: mk_dir
 	cd $(BUID_O_DIR) && rm -rf ./*
 	rm -rf $(BUID_O_DIR)
 	rm -rf $(DIS_IMG)
 	rm -rf bochs_log.txt
 
-K: $(BUILD_BIN_DIR)/kernel.bin
+K: mk_dir $(BUILD_BIN_DIR)/kernel.bin 
 
-mbr: $(BUILD_BIN_DIR)/mbr.bin
+mbr: mk_dir $(BUILD_BIN_DIR)/mbr.bin
 
-loader: $(BUILD_BIN_DIR)/loader.bin
+loader: mk_dir $(BUILD_BIN_DIR)/loader.bin 
 
-run:
+run: hd
 	bochs -f bochsrc -q
 
+build: mk_dir mbr loader K mk_dir
+	@echo "编译完成"
+
 all: mk_dir create_img mbr loader K hd