From 56d4ab31217c4b76f12b8efb1975901d95a261de Mon Sep 17 00:00:00 2001 From: pointer-to-bios Date: Wed, 13 Dec 2023 02:24:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=86=85=E5=AD=98=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Makefile | 4 +- src/include/kernel/arch/x86_64/kernel.h | 7 + src/include/kernel/arch/x86_64/memm.h | 110 +++++++++++ src/include/kernel/kernel.h | 9 +- src/include/kernel/memm.h | 150 +++++++++++++++ src/include/kernel/memm/allocator/raw.h | 31 +++ src/include/kernel/tty.h | 11 +- src/include/libk/bits.h | 28 +++ src/include/libk/lst.h | 44 +++++ src/include/libk/math.h | 7 + src/kernel/Makefile | 15 +- src/kernel/arch/x86_64/entry32.s | 2 +- src/kernel/arch/x86_64/memm_x86_64.c | 134 +++++++++++++ src/kernel/arch/x86_64/memm_x86_64_s.s | 11 ++ src/kernel/main.c | 24 +-- src/kernel/memm/allocator/raw.c | 69 +++++++ src/kernel/memm/memm.c | 240 ++++++++++++++++++++++++ src/kernel/tty/tty.c | 18 +- src/libk/Makefile | 11 +- src/libk/lst.c | 183 ++++++++++++++++++ src/metaverse.lds | 1 - 21 files changed, 1069 insertions(+), 40 deletions(-) create mode 100644 src/include/kernel/arch/x86_64/kernel.h create mode 100644 src/include/kernel/arch/x86_64/memm.h create mode 100644 src/include/kernel/memm.h create mode 100644 src/include/kernel/memm/allocator/raw.h create mode 100644 src/include/libk/bits.h create mode 100644 src/include/libk/lst.h create mode 100644 src/include/libk/math.h create mode 100644 src/kernel/arch/x86_64/memm_x86_64.c create mode 100644 src/kernel/arch/x86_64/memm_x86_64_s.s create mode 100644 src/kernel/memm/allocator/raw.c create mode 100644 src/kernel/memm/memm.c create mode 100644 src/libk/lst.c diff --git a/src/Makefile b/src/Makefile index 1b92967..39da335 100644 --- a/src/Makefile +++ b/src/Makefile @@ -44,6 +44,6 @@ libk: @echo -e "\e[33m-------------------------\e[0m" clear: - @make -C kernel clear --no-print-directory - @make -C libk clear --no-print-directory + @make -C kernel clear --no-print-directory ${DEFINES} + @make -C libk clear --no-print-directory ${DEFINES} @-rm metaverse.elf metaverse.map diff --git a/src/include/kernel/arch/x86_64/kernel.h b/src/include/kernel/arch/x86_64/kernel.h new file mode 100644 index 0000000..450c290 --- /dev/null +++ b/src/include/kernel/arch/x86_64/kernel.h @@ -0,0 +1,7 @@ +#ifndef X86_64_KERNEL_H +#define X86_64_KERNEL_H 1 + +#include + + +#endif diff --git a/src/include/kernel/arch/x86_64/memm.h b/src/include/kernel/arch/x86_64/memm.h new file mode 100644 index 0000000..a8594ee --- /dev/null +++ b/src/include/kernel/arch/x86_64/memm.h @@ -0,0 +1,110 @@ +#ifndef X86_64_MEMM_H +#define X86_64_MEMM_H 1 + +#include +#include + +/* 页大小,以MEMM_PAGE_SIZE为单位 */ +#define MEMM_PAGE_SIZE 4096 +typedef enum __memm_page_size +{ + MEMM_PAGE_SIZE_4K = 1, // 1个4KB页大小 + MEMM_PAGE_SIZE_2M = 512, // 512个4KB页大小 + MEMM_PAGE_SIZE_1G = 262144, // 262144个4KB页大小 +} memm_page_size; + +extern u64 PML4[512]; + +#define MEMM_PAGE_TABLE_FLAGS_AREA ((u64)0xfff) + +/* 页对齐掩码 */ +#define MEMM_4K_ALIGN_MASK ((u64)0xfff) +#define MEMM_2M_ALIGN_MASK ((u64)0x1fffff) +#define MEMM_1G_ALIGN_MASK ((u64)0x3fffffff) + +/* 页表项属性FLAGS */ +#define MEMM_ENTRY_FLAG_PRESENT ((u64)1) +#define MEMM_ENTRY_FLAG_WRITE ((u64)1 << 1) +#define MEMM_ENTRY_FLAG_USER ((u64)1 << 2) +#define MEMM_ENTRY_FLAG_PWT ((u64)1 << 3) +#define MEMM_ENTRY_FLAG_PCD ((u64)1 << 4) +#define MEMM_ENTRY_FLAG_ACCECED ((u64)1 << 5) +#define MEMM_ENTRY_FLAG_DIRTY ((u64)1 << 6) +#define MEMM_ENTRY_FLAG_PS ((u64)1 << 7) +#define MEMM_ENTRY_FLAG_GLOBAL ((u64)1 << 8) +#define MEMM_ENTRY_FLAG_PAT ((u64)1 << 12) +#define MEMM_PTE_ENTRY_FLAG_PAT ((u64)1 << 7) +#define MEMM_ENTRY_FLAG_XD ((u64)1 << 63) +#define memm_entry_flag_get(entry, flag) \ + ((entry & flag) ? true : false) + +/* 页表(大型页)项地址域掩码 */ +#define MEMM_ENTRY_ADDRESS_MASK ((u64)0x000ffffffffff000) +#define MEMM_BP_ENTRY_ADDRESS_MASK ((u64)0x000fffffffffe000) +#define memm_entry_get_address(entry) \ + ((entry) & (memm_entry_flag_get(entry, MEMM_ENTRY_FLAG_PS) \ + ? MEMM_BP_ENTRY_ADDRESS_MASK \ + : MEMM_ENTRY_ADDRESS_MASK)) + +/* 线性地址表项索引或页内偏移掩码 */ +#define MEMM_LA_PML4EI_MASK ((u64)0x0000ff8000000000) +#define MEMM_LA_PDPTEI_MASK ((u64)0x0000007fc0000000) +#define MEMM_LA_PDEI_MASK ((u64)0x000000003fe00000) +#define MEMM_LA_PEI_MASK ((u64)0x00000000001ff000) + +#define MEMM_LA_1GB_PAGE_OFFSET_MASK ((u64)0x000000003fffffff) +#define MEMM_LA_2MB_PAGE_OFFSET_MASK ((u64)0x00000000001fffff) +#define MEMM_LA_4KB_PAGE_OFFSET_MASK ((u64)0x0000000000000fff) + +/* 线性地址表项索引偏移位数 */ +#define MEMM_LA_PML4EI_OFFSET (39) +#define MEMM_LA_PDPTEI_OFFSET (30) +#define MEMM_LA_PDEI_OFFSET (21) +#define MEMM_LA_PEI_OFFSET (12) + +/* 获取线性地址中某个表项索引以及获取页内偏移 */ +#define MEMM_LA_PML4EI +#define MEMM_LA_PDPTEI +#define MEMM_LA_PDEI +#define MEMM_LA_PEI +#define memm_la_get_entry_index(addr, entry) \ + (((addr) & (entry##_MASK)) >> (entry##_OFFSET)) + +#define MEMM_LA_1GB_PAGE_OFFSET +#define MEMM_LA_2MB_PAGE_OFFSET +#define MEMM_LA_4KB_PAGE_OFFSET +#define memm_la_get_offset(addr, page_type) \ + ((addr) & (page_type##_MASK)) + +/* +仅支持canonical型地址 + +target与physical至少都是以MEMM_PAGE_SIZE对齐的 + +没有MEMM_PAGE_SIZE对齐的,和非canonical型地址都会返回false + +当剩余长度超过1GB的一半且地址1GB对齐,则会映射一个1GB页; +当剩余长度超过2MB的一半且地址2MB对齐,则会映射一个2MB页; +否则映射4KB页。 + */ +bool memm_map_pageframes_to( + u64 target, u64 physical, + usize size, + bool user, bool write); + +extern void reload_pml4(); + +#define is_user_address(addr) \ + (((addr) > 0xffff7fffffffffff) ? true : false) + +#define is_cannonical(addr) \ + (((addr) < 0x0000800000000000 || (addr) > 0xffff7fffffffffff) ? true : false) + +#define memm_get_page_align(addr) \ + (is_aligned(addr, MEMM_PAGE_SIZE_1G) \ + ? MEMM_PAGE_SIZE_1G \ + : (is_aligned(addr, MEMM_PAGE_SIZE_2M) \ + ? MEMM_PAGE_SIZE_2M \ + : MEMM_PAGE_SIZE_4K)) + +#endif diff --git a/src/include/kernel/kernel.h b/src/include/kernel/kernel.h index bd1b137..5ed0bda 100644 --- a/src/include/kernel/kernel.h +++ b/src/include/kernel/kernel.h @@ -2,7 +2,14 @@ #define KERNEL_H 1 #include -#include + +#ifdef __x86_64__ + +#include + +#define ISA_STRING "x86_64" + +#endif #define KERNEL_TODO() \ while (true) \ diff --git a/src/include/kernel/memm.h b/src/include/kernel/memm.h new file mode 100644 index 0000000..8890d08 --- /dev/null +++ b/src/include/kernel/memm.h @@ -0,0 +1,150 @@ +#ifndef MEMM_H +#define MEMM_H 1 + +#ifdef __x86_64__ +#include +#endif + +#include + +/** + * @brief 内存管理模块 + * + * TODO 还没设计页回收算法 + */ + +/* 最大支持1TB内存 */ +#define MEMM_MAX_SUPPORTED_MEMORY (1024 * (1024 * (1024 * (usize)1024))) + +/* 最大支持的分页数量 */ +// 这里的页均以最小的页大小计算 +#define MEMM_MAX_SUPPORTED_PAGES (MEMM_MAX_SUPPORTED_MEMORY / MEMM_PAGE_SIZE) + +/* 只分配不映射空间 */ +#define MEMM_ALLOC_ONLY_MEMORY (128 * 1024 * 1024) + +/* +内存分配器 +分配器对象的首地址永远是MEMM_PAGE_SIZE对齐的 + */ +typedef struct __allocator_t +{ + bool initialized; + + // 在本分配器中调用allocate返回nullptr后为true + // 调用free后为false + bool full; + + // 进程id,当pid=0时代表内核 + usize pid; + // 分配器类型 + usize type; + usize size; + + // 分配器实例的allocate函数 + // 无法分配空间返回nullptr + // 在size参数为0时,保证不可以分配空间,但是如果空间已满依然返回nullptr + // 当参数align=0时表示不需要对齐 + void *(*allocate)(void *allocator, usize size, usize align); + + // 分配器实例的free函数 + // 若不是allocate得到的地址则什么都不做 + void (*free)(void *allocator, void *mem); + + // 分配器实例 + // 对应`type`类型使用 + // 在kernel/memm/allocator/中是所有的内存分配器 + u64 allocator_instance[0]; +} allocator_t; + +typedef struct __allocator_iterator_t +{ + allocator_t *allocator; + struct __allocator_iterator_t *left, *right; + + // 这个节点的内存空间处于的那个分配器 + allocator_t *owned_allocator; +} allocator_iterator_t; + +/* +内存管理器 +内存分配分成两个阶段:映射和分配 +映射后的页进入allocator记录中,具体的分配工作由allocator完成 + +在page_map中置位、在map_with_allocator中复位、在map_with_destructed_allocator中复位 +且不在available_pages_table中的页,是页表、程序代码段、内核代码等使用的页 +*/ +typedef struct __mem_manager_t +{ + usize memory_size; + usize page_amount; + + // 这里记录的数量为最小的页的数量 + usize mapped_page_amount; + + // 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被 + // 页表映射,这部分内存不可以再映射到物理页框 + usize alloc_only_memory; +#ifdef __x86_64__ + // 在这里三种页的数量分别记录 + usize mapped_4k_page; + usize mapped_2m_page; + usize mapped_1g_page; +#endif + // 页地图 + // 每个bit都表示这个页是否被映射 + u8 *page_map; + // 分配器页地图 + // 每个bit表示这个页是否被内存分配器控制 + // (不代表每个页都包含完整的分配器) + u8 *map_with_allocator; + // 分配器释放页地图 + // 每个bit表示这个页是否曾经被内存分配器控制且现在被释放 + // 需要取消映射 + u8 *map_with_destructed_allocator; + + // 空闲页线段搜索表 + lst_iterator_t *available_pages_table; + + // 分配器树 + // 为方便查找,以二叉树的形式存储 + // index=0为无效项 + allocator_iterator_t *allocators; +} mem_manager_t; + +mem_manager_t *memm_new(usize mem_size); + +/* +在`start`处创建一个长度为`length`的内存分配器 +当`pid`为0时,表示这个分配器只给内核使用 + */ +allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid); + +/* +释放分配器对象 + +只能被内存回收模块调用 + */ +void memm_allocator_destruct(allocator_t *allocator); + +/* +申请内存 +第三个参数也是返回值,表示申请内存使用的分配器 +pid=0时为内核分配 +所有内存在内核空间都有对物理内存空间的直接映射,也就是线性地址与物理地址相同,称为内核地址 + +allocator对象在进程与内核之间传递时一律使用内核空间的映射地址 + */ +void *memm_allocate(usize size, usize pid, allocator_t **allocator); + +/* +释放内存 + */ +void memm_free(allocator_t *allocator, void *mem); + +/* +寻找大小合适的一组页 + */ +usize find_fitable_pages(usize page_count); + +#endif diff --git a/src/include/kernel/memm/allocator/raw.h b/src/include/kernel/memm/allocator/raw.h new file mode 100644 index 0000000..8f84c09 --- /dev/null +++ b/src/include/kernel/memm/allocator/raw.h @@ -0,0 +1,31 @@ +#ifndef RAW_H +#define RAW_H 1 + +#include + +#define MEMM_RAW_ALLOCATOR 1 + +typedef struct __raw_allocator_cell +{ + usize capacity; // 是content的长度 + usize length; // 是实际使用的长度 + u8 content[0]; +} raw_allocator_cell; + +// 原始分配器 +// 包括至少一个cell,分配时像cell的分裂一样将空白的一段分成两段 +// 释放时,只把length归零,并不将cell合并 +// length=0的cell称为空cell +// 在分配时遇到第一个空cell时将紧随其后的空cell都合并掉 +typedef struct __raw_allocator_t +{ + usize size, reserved; + raw_allocator_cell cells[0]; +} raw_allocator_t; + +void raw_allocator_new(raw_allocator_t *allocator, usize size); + +void *raw_allocator_allocate(raw_allocator_t *allocator, usize size, usize align); +void raw_allocator_free(raw_allocator_t *allocator, void *mem); + +#endif diff --git a/src/include/kernel/tty.h b/src/include/kernel/tty.h index fd2c517..54c00fd 100644 --- a/src/include/kernel/tty.h +++ b/src/include/kernel/tty.h @@ -2,6 +2,7 @@ #define TTY_H #include +#include typedef enum __tty_type { @@ -58,21 +59,23 @@ typedef struct __tty tty_typeinfo typeinfo; tty_mode mode; tty_text_state text; + + allocator_t *allocator; } tty; // tty控制器 -typedef struct __tty_controller +typedef struct __tty_controller_t { #define TTY_MAX_NUM 128 tty *ttys[TTY_MAX_NUM]; bool map[TTY_MAX_NUM]; -} tty_controller; +} tty_controller_t; /** * @brief 初始化tty控制器 * */ -void tty_controller_init(); +tty_controller_t *tty_controller_new(); /** * @brief 创建tty @@ -82,7 +85,7 @@ void tty_controller_init(); * @return tty* 返回tty对象的地址,如果tty数量超过TTY_MAX_NUM返回nullptr, * 无论传入的__tty是否是nullptr */ -tty *tty_new(tty *__tty, tty_type type, tty_mode mode); +tty *tty_new(tty_type type, tty_mode mode); /** * @brief 通过tty id获取一个tty diff --git a/src/include/libk/bits.h b/src/include/libk/bits.h new file mode 100644 index 0000000..01c41f3 --- /dev/null +++ b/src/include/libk/bits.h @@ -0,0 +1,28 @@ +#ifndef BITS_H +#define BITS_H 1 + +#include + +#define bit_set(byte, n) (byte) |= (1 << (n)); +#define bit_reset(byte, n) (byte) &= ~(1 << (n)); +#define bit_get(byte, n) (((byte) & (1 << (n))) >> (n)) + +#define bitmap_set(map, n) bit_set(((u8 *)(map))[(n) / 8], (n) % 8); +#define bitmap_reset(map, n) bit_reset(((u8 *)(map))[(n) / 8], (n) % 8); +#define bitmap_get(map, n) bit_get(map[(n) / 8], (n) % 8) + +// 向后对齐 +#define align_to(addr, align) \ + if ((usize)(addr) % (align) != 0) \ + { \ + usize __align_to_tmp_addr = (usize)(addr); \ + __align_to_tmp_addr /= (align); \ + __align_to_tmp_addr++; \ + __align_to_tmp_addr *= (align); \ + addr = __align_to_tmp_addr; \ + } + +#define is_aligned(addr, align) \ + (addr % align == 0) + +#endif diff --git a/src/include/libk/lst.h b/src/include/libk/lst.h new file mode 100644 index 0000000..b57a9df --- /dev/null +++ b/src/include/libk/lst.h @@ -0,0 +1,44 @@ +#ifndef LST_H +#define LST_H 1 + +/* +Line Search Table +线段搜索表 + */ + +#include + +typedef struct __lst_line_t +{ + usize left, right; +} lst_line_t; + +typedef struct __lst_iterator_t +{ + lst_line_t line; + // 这个指针是kernel/memm.h中的allocator_t * + // 代表当前lst_line_index_t对象在allocate时使用的allocator + // 用的话会造成递归include + void *allocator; + struct __lst_iterator_t *next; +} lst_iterator_t; + +lst_iterator_t *lst_new(usize start, usize end); + +lst_iterator_t *lst_next(lst_iterator_t *iterator); + +/* +在`lst`中移除一个线段[left,right) +force=true时忽略不存在于`lst`中的线段 +force=false时若有不存在于`lst`中的线段,不移除任何线段,返回false,否则返回true + */ +bool lst_remove(lst_iterator_t *lst, usize left, usize right, bool force); + +/* +在`lst`中添加一个线段[left,right) +force=true时忽略已经存在于`lst`中的线段 +force=false时若有存在于`lst`中的线段,只添加这些部分之外的线段,返回false,否则返回true + */ +bool lst_add(lst_iterator_t *lst, usize left, usize right, bool force); + +#endif diff --git a/src/include/libk/math.h b/src/include/libk/math.h new file mode 100644 index 0000000..3b35894 --- /dev/null +++ b/src/include/libk/math.h @@ -0,0 +1,7 @@ +#ifndef MATH_H +#define MATH_H 1 + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +#endif diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 635448e..ced90a5 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -9,7 +9,7 @@ ifdef release CCFLAGS := ${CCFLAGS} -O2 endif -C_SRCS = main.c tty.c klog.c font.c +C_SRCS = main.c tty.c klog.c font.c memm.c memm_${ARCH}.c raw.c C_OBJS = ${C_SRCS:.c=.o} ################################ @@ -33,7 +33,7 @@ endif ASMFLAGS := ${ASMFLAGS} ASMFLAGS32 = -f elf32 -S_OBJS = entry32.32.o entry.o +S_OBJS = entry32.32.o entry.o memm_${ARCH}_s.o ################################ @@ -44,7 +44,7 @@ STRIP_SECS = -R .comment -R .note.GNU-stack OBJCOPY_FLAGS = ${STRIP_SECS} # 子目录 -VPATH = mm/ tty/ klog/ +VPATH = memm/ memm/allocator tty/ klog/ arch/${ARCH} %.o: %.c @echo -e "\e[1m\e[33m${CC}\e[0m \e[32m$<\e[0m \e[34m-->\e[0m \e[1m\e[32m$@\e[0m" @@ -56,16 +56,17 @@ VPATH = mm/ tty/ klog/ %.32.o: arch/${ARCH}/%.s @echo -e "\e[1m\e[33m${ASM}\e[0m \e[32m$<\e[0m \e[34m-->\e[0m \e[1m\e[32m$@\e[0m" - @${ASM} ${ASMFLAGS32} -o $@ $< 2>&1 | "${SOURCE}/colorize" "warning:=yellow" "error:=red" - @objcopy -I elf32-i386 -O elf64-x86-64 $@ $@ 2>&1 | "${SOURCE}/colorize" "warning:=yellow" "error:=red" "objcopy=lyellow" + @${ASM} ${ASMFLAGS32} -o $@ $< 2>&1 | "${SOURCE}/colorize" "warning:=pink" "error:=red" + @objcopy -I elf32-i386 -O elf64-x86-64 $@ $@ 2>&1 | "${SOURCE}/colorize" "warning:=pink" "error:=red" "objcopy=lyellow" %.o: arch/${ARCH}/%.s @echo -e "\e[1m\e[33m${ASM}\e[0m \e[32m$<\e[0m \e[34m-->\e[0m \e[1m\e[32m$@\e[0m" - @${ASM} ${ASMFLAGS} -o $@ $< 2>&1 | "${SOURCE}/colorize" "warning:=yellow" "error:=red" + @${ASM} ${ASMFLAGS} -o $@ $< 2>&1 | "${SOURCE}/colorize" "warning:=pink" "error:=red" kernel.o: ${OBJS} @echo -e "\e[1m\e[33mld\e[0m \e[1m\e[32mkernel.o\e[0m \e[34m<--\e[0m \e[32m${OBJS}\e[0m" - @ld -r ${OBJS} -o kernel.o -Map=kernel.map -unresolved-symbols=ignore-all 2>&1 | "${SOURCE}/colorize" "warning:=yellow" "error:=red" "ld=lyellow" + @ld -r ${OBJS} -o kernel.o -Map=kernel.map -unresolved-symbols=ignore-all 2>&1 \ + | "${SOURCE}/colorize" "warning:=pink" "error:=red" "ld=lyellow" @objcopy ${OBJCOPY_FLAGS} kernel.o kernel.o .PHONY: all clear diff --git a/src/kernel/arch/x86_64/entry32.s b/src/kernel/arch/x86_64/entry32.s index 4042185..57d618b 100644 --- a/src/kernel/arch/x86_64/entry32.s +++ b/src/kernel/arch/x86_64/entry32.s @@ -75,7 +75,7 @@ init32: jmp 0x8:init64 section .cpumeta align=4096 - + global PML4 ; 分页 ; 链接器会把这些数据替换掉所以要在代码中重新设置 PML4: diff --git a/src/kernel/arch/x86_64/memm_x86_64.c b/src/kernel/arch/x86_64/memm_x86_64.c new file mode 100644 index 0000000..2eeec75 --- /dev/null +++ b/src/kernel/arch/x86_64/memm_x86_64.c @@ -0,0 +1,134 @@ +#include + +#include + +#include +#include + +#define map_pagemap(addr) \ + map_pageframe_to((u64)addr, (u64)addr, false, true, MEMM_PAGE_SIZE_4K); + +// 这里的physical必须保证根据ps对齐 +static void map_pageframe_to(u64 target, u64 physical, + bool user, bool write, memm_page_size ps) +{ + if (!is_cannonical(target)) + return; + + usize pml4ei = memm_la_get_entry_index(target, MEMM_LA_PML4EI); + usize pml4e = PML4[pml4ei]; + u64 *PDPT; + if (memm_entry_flag_get(pml4e, MEMM_ENTRY_FLAG_PRESENT) == true) + PDPT = (u64 *)memm_entry_get_address(pml4e); + else + { + PDPT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); + map_pagemap(PDPT); + memset(PDPT, 0, MEMM_PAGE_SIZE); + + PML4[pml4ei] = + MEMM_ENTRY_FLAG_PRESENT | + MEMM_ENTRY_FLAG_WRITE | + (u64)PDPT; + } + + usize pdptei = memm_la_get_entry_index(target, MEMM_LA_PDPTEI); + if (ps == MEMM_PAGE_SIZE_1G) + { + PDPT[pdptei] = + MEMM_ENTRY_FLAG_PRESENT | + (write ? MEMM_ENTRY_FLAG_WRITE : 0) | + (is_user_address(target) ? MEMM_ENTRY_FLAG_USER : 0) | + MEMM_ENTRY_FLAG_PS | + (is_user_address(target) ? 0 : MEMM_ENTRY_FLAG_GLOBAL) | + physical; + return; + } + usize pdpte = PDPT[pdptei]; + u64 *PDT; + if (memm_entry_flag_get(pdpte, MEMM_ENTRY_FLAG_PRESENT) == true) + PDT = (u64 *)memm_entry_get_address(pdpte); + else + { + PDT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); + map_pagemap(PDT); + memset(PDT, 0, MEMM_PAGE_SIZE); + + PDPT[pdptei] = + MEMM_ENTRY_FLAG_PRESENT | + MEMM_ENTRY_FLAG_WRITE | + (u64)PDT; + } + + usize pdei = memm_la_get_entry_index(target, MEMM_LA_PDEI); + if (ps == MEMM_PAGE_SIZE_2M) + { + PDT[pdei] = + MEMM_ENTRY_FLAG_PRESENT | + (write ? MEMM_ENTRY_FLAG_WRITE : 0) | + (is_user_address(target) ? MEMM_ENTRY_FLAG_USER : 0) | + MEMM_ENTRY_FLAG_PS | + (is_user_address(target) ? 0 : MEMM_ENTRY_FLAG_GLOBAL) | + physical; + return; + } + usize pde = PDT[pdei]; + u64 *PT; + if (memm_entry_flag_get(pde, MEMM_ENTRY_FLAG_PRESENT) == true) + PT = (u64 *)memm_entry_get_address(pde); + else + { + PT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); + map_pagemap(PT); + memset(PT, 0, MEMM_PAGE_SIZE); + + PDT[pdei] = + MEMM_ENTRY_FLAG_PRESENT | + MEMM_ENTRY_FLAG_WRITE | + (u64)PT; + } + + usize pei = memm_la_get_entry_index(target, MEMM_LA_PEI); + PT[pei] = + MEMM_ENTRY_FLAG_PRESENT | + (write ? MEMM_ENTRY_FLAG_WRITE : 0) | + (is_user_address(target) ? MEMM_ENTRY_FLAG_USER : 0) | + MEMM_ENTRY_FLAG_PS | + (is_user_address(target) ? 0 : MEMM_ENTRY_FLAG_GLOBAL) | + physical; + return; +} + +bool memm_map_pageframes_to( + u64 target, u64 physical, + usize size, + bool user, bool write) +{ + if (!is_cannonical(target) || !is_cannonical(physical)) + return false; + if (!is_aligned(target, MEMM_PAGE_SIZE) || !is_aligned(physical, MEMM_PAGE_SIZE)) + return false; + while (size != 0) + { + memm_page_size align = memm_get_page_align(physical); + if (align == MEMM_PAGE_SIZE_1G) + { + if (size < (usize)align * MEMM_PAGE_SIZE / 2) + align = MEMM_2M_ALIGN_MASK; + } + if (align == MEMM_PAGE_SIZE_2M) + { + if (size < (usize)align * MEMM_PAGE_SIZE / 2) + align = MEMM_4K_ALIGN_MASK; + } + + map_pageframe_to(target, physical, user, write, align); + usize step = min(size, (usize)align * MEMM_PAGE_SIZE); + + size -= step; + target += step; + physical += step; + } + reload_pml4(); + return true; +} diff --git a/src/kernel/arch/x86_64/memm_x86_64_s.s b/src/kernel/arch/x86_64/memm_x86_64_s.s new file mode 100644 index 0000000..8f7c139 --- /dev/null +++ b/src/kernel/arch/x86_64/memm_x86_64_s.s @@ -0,0 +1,11 @@ + section .text + global reload_pml4 +reload_pml4: + push rax + + mov rax, cr3 + mov cr3, rax + + pop rax + + ret diff --git a/src/kernel/main.c b/src/kernel/main.c index 802a81f..973df5e 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -16,7 +16,7 @@ void kmain(void *mb2_bootinfo) // 获取内存信息 void **tags; usize tags_amount; - if ((tags_amount = bootinfo_get_tag(bootinfo, BOOTINFO_BASIC_MEMORY_INFO_TYPE, &tags)) == 0) + if ((tags_amount = bootinfo_get_tag(&bootinfo, BOOTINFO_BASIC_MEMORY_INFO_TYPE, &tags)) == 0) { KERNEL_TODO(); } @@ -26,15 +26,17 @@ void kmain(void *mb2_bootinfo) // 初始化内存管理模块 mem_manager_t *memm = memm_new(mem_size); - tty_controller_init(); + // 初始化tty模块 + tty_controller_t *tty_controler = tty_controller_new(); framebuffer fb; get_frame_buffer_with_bootinfo(&fb, &bootinfo); - tty tty0; - tty_new(&tty0, tty_type_raw_framebuffer, tty_mode_text); + tty *tty0 = tty_new(tty_type_raw_framebuffer, tty_mode_text); tty_set_framebuffer(&tty0, &fb); - tty_text_print(&tty0, "Hello Metaverse!\n", gen_color(0xbb, 0xbb, 0xbb), gen_color(0, 0, 0)); + tty_text_print(&tty0, "Hello Metaverse!\n", gen_color(0xee, 0xee, 0xee), gen_color(0, 0, 0)); + + // 初始化内核日志模块 while (true) { @@ -54,11 +56,9 @@ void get_frame_buffer_with_bootinfo(framebuffer *fb, bootinfo_t *bootinfo) fb->width = fbinfo->framebuffer_width; fb->height = fbinfo->framebuffer_height; fb->pixsize = fbinfo->framebuffer_bpp / 8; - // TODO 对应内存空间还没有分页 - KERNEL_TODO(); - for (usize i = 0; i < 10000; i++) - { - ((u8 *)fb->pointer)[i] = 0xff; - } - KERNEL_TODO(); + memm_map_pageframes_to( + (u64)fb->pointer, (u64)fb->pointer, + fb->width * fb->height * fb->pixsize, + false, true); + // TODO fb->type需要确定 } diff --git a/src/kernel/memm/allocator/raw.c b/src/kernel/memm/allocator/raw.c new file mode 100644 index 0000000..5264025 --- /dev/null +++ b/src/kernel/memm/allocator/raw.c @@ -0,0 +1,69 @@ +#include + +#include + +#include + +void raw_allocator_new(raw_allocator_t *allocator, usize size) +{ + allocator->size = size - sizeof(allocator->size); + allocator->cells[0].capacity = size - sizeof(raw_allocator_t); + allocator->cells[0].length = 0; +} + +void *raw_allocator_allocate(raw_allocator_t *allocator, usize size, usize align) +{ + // 搜索 + raw_allocator_cell *cell = allocator->cells; + while ((void *)cell < (void *)allocator + allocator->size && + cell->length != 0 && cell->capacity >= size) + { + cell = (void *)cell + sizeof(raw_allocator_cell) + cell->capacity; + } + if ((void *)cell >= (void *)allocator + allocator->size) + return nullptr; + + // 合并 + raw_allocator_cell *next_cell = (void *)cell + sizeof(raw_allocator_cell) + cell->capacity; + while ((void *)next_cell < (void *)allocator + allocator->size && + next_cell->length == 0) + { + cell->capacity += sizeof(raw_allocator_cell) + next_cell->capacity; + next_cell = (void *)next_cell + sizeof(raw_allocator_cell) + next_cell->capacity; + } + + // 分割 + usize allsize = sizeof(raw_allocator_cell) + size; + align_to(allsize, 16); + next_cell = (void *)cell + allsize; + if (allsize + sizeof(raw_allocator_cell) < sizeof(raw_allocator_cell) + cell->capacity) + { + usize nextsize = sizeof(raw_allocator_cell) + cell->capacity - allsize; + next_cell->capacity = nextsize - sizeof(raw_allocator_cell); + next_cell->length = 0; + } + else + { + allsize += 16; + } + + // 分配 + cell->capacity = allsize - sizeof(raw_allocator_cell); + cell->length = size; + + return &cell->content; +} + +void raw_allocator_free(raw_allocator_t *allocator, void *mem) +{ + raw_allocator_cell *cell = allocator->cells; + while ((void *)cell < (void *)allocator + allocator->size) + { + if (mem == cell->content) + { + cell->length = 0; + break; + } + cell = (void *)cell + sizeof(raw_allocator_cell) + cell->capacity; + } +} diff --git a/src/kernel/memm/memm.c b/src/kernel/memm/memm.c new file mode 100644 index 0000000..13b3cb0 --- /dev/null +++ b/src/kernel/memm/memm.c @@ -0,0 +1,240 @@ +#include +#include +#include + +#include +#include + +mem_manager_t memory_manager; + +mem_manager_t *memm_new(usize mem_size) +{ + memset(&memory_manager, 0, sizeof(memory_manager)); + memory_manager.memory_size = mem_size; + memory_manager.page_amount = mem_size / MEMM_PAGE_SIZE; + + usize kernel_initial_size = (usize)&kend; + align_to(kernel_initial_size, MEMM_PAGE_SIZE); + memory_manager.alloc_only_memory = MEMM_ALLOC_ONLY_MEMORY; + + // 配置分配器树 + allocator_t *allocator0 = memm_allocator_new( + (void *)kernel_initial_size, + memory_manager.alloc_only_memory - kernel_initial_size, + MEMM_RAW_ALLOCATOR, 0); + + allocator_iterator_t *alcatr_ind = allocator0->allocate( + &allocator0->allocator_instance, sizeof(allocator_iterator_t), 0); + + alcatr_ind->allocator = allocator0; + alcatr_ind->left = nullptr; + alcatr_ind->right = nullptr; + + memory_manager.allocators = alcatr_ind; + + // 配置页映射地图 + usize pmc_size = memory_manager.page_amount; + align_to(pmc_size, 8); + pmc_size /= 8; + + memory_manager.page_map = allocator0->allocate(&allocator0->allocator_instance, pmc_size, 0); + memset(memory_manager.page_map, 0, pmc_size); + memset(memory_manager.page_map, 0xff, MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE / 8); + for (usize i = (MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE / 8) * (u8)8; + i < MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE % 8; i++) + { + bitmap_set(memory_manager.page_map, i); + } + + // 配置分配器页地图 + memory_manager.map_with_allocator = + allocator0->allocate(&allocator0->allocator_instance, pmc_size, 0); + memset(memory_manager.map_with_allocator, 0, pmc_size); + for (usize i = kernel_initial_size / MEMM_PAGE_SIZE; + i < MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE; + i += MEMM_PAGE_SIZE) + { + bitmap_set(memory_manager.map_with_allocator, i); + } + + // 分配器释放页地图 + memory_manager.map_with_destructed_allocator = + allocator0->allocate(&allocator0->allocator_instance, pmc_size, 0); + memset(memory_manager.map_with_destructed_allocator, 0, pmc_size); + + // 配置空闲页线段搜索表 + memory_manager.available_pages_table = lst_new(0, memory_manager.page_amount); + lst_remove(memory_manager.available_pages_table, 0, MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE, false); + + return &memory_manager; +} + +allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid) +{ + allocator_t *allocator = start; + allocator->initialized = true; + allocator->full = false; + allocator->pid = 0; + allocator->size = length; + allocator->type = type; + switch (type) + { + case MEMM_RAW_ALLOCATOR: + raw_allocator_new((void *)allocator->allocator_instance, length - sizeof(allocator_t)); + allocator->allocate = &raw_allocator_allocate; + allocator->free = &raw_allocator_free; + break; + default: + allocator->initialized = false; + break; + } +} + +void memm_allocator_destruct(allocator_t *allocator) +{ + allocator->initialized = false; + // TODO 从分配器树中删除这个分配器 + KERNEL_TODO(); +} + +void *memm_find_and_allocate(allocator_iterator_t *allocator_ind, usize size, usize pid, allocator_t **writeback) +{ + void *ptr; + allocator_t *allocator = allocator_ind->allocator; + if (allocator->pid == pid && allocator->full == false) + { // 尝试用本节点分配 + if ((ptr = allocator->allocate(&allocator->allocator_instance, size, 0)) != nullptr) + { + *writeback = allocator; + return ptr; + } + else + { + if ((ptr = allocator->allocate(&allocator->allocator_instance, 0, 0)) == nullptr) + allocator->full = true; + } + } + if (allocator_ind->left != nullptr) + { // 尝试用左子树分配 + ptr = memm_find_and_allocate(allocator_ind->left, size, pid, writeback); + if (ptr != nullptr) + return ptr; + } + if (allocator_ind->right != nullptr) + { // 尝试用右子树分配 + ptr = memm_find_and_allocate(allocator_ind->right, size, pid, writeback); + if (ptr != nullptr) + return ptr; + } + // 都不行就只能返回nullptr + return nullptr; +} + +static void insert_allocator(allocator_iterator_t *iter, allocator_iterator_t *inserter) +{ + if (inserter->allocator < iter->allocator) + { + if (iter->left == nullptr) + { + iter->left = inserter; + return; + } + else + { + insert_allocator(iter->left, inserter); + } + } + else if (inserter->allocator > iter->allocator) + { + if (iter->right == nullptr) + { + iter->right = inserter; + return; + } + else + { + insert_allocator(iter->right, inserter); + } + } +} + +void *memm_allocate(usize size, usize pid, allocator_t **allocator) +{ + usize orgsize = size; + // 从分配器树中分配内存 + void *ptr = memm_find_and_allocate(memory_manager.allocators, size, pid, allocator); + if (ptr != nullptr) + goto after_allocation; + + // 分配器树中没有可分配的内存 + size += sizeof(allocator_t) + MEMM_PAGE_SIZE; + align_to(size, MEMM_PAGE_SIZE); + size /= MEMM_PAGE_SIZE; + usize allocator_start = find_fitable_pages(size); + for (usize i = allocator_start; i < allocator_start + size; i++) + { + bitmap_set(memory_manager.map_with_allocator, i); + } + if (allocator_start == 0) + return nullptr; // 内存中已经没有可分配的页了 + memm_map_pageframes_to(allocator_start * MEMM_PAGE_SIZE, allocator_start * MEMM_PAGE_SIZE, + size * MEMM_PAGE_SIZE, + false, // 用户空间标志 + true // 写权限 + ); + + // 在新映射的页中创建一个分配器 + // TODO 在用户态可能需要实现一个效率更高的分配器 + allocator_t *new_allocator = + memm_allocator_new((void *)(allocator_start * MEMM_PAGE_SIZE), size * MEMM_PAGE_SIZE, + MEMM_RAW_ALLOCATOR, pid); + *allocator = new_allocator; + + allocator_t *all; + allocator_iterator_t *allind = memm_allocate(sizeof(allocator_iterator_t), 0, &all); + allind->owned_allocator = all; + allind->allocator = new_allocator; + allind->left = nullptr; + allind->right = nullptr; + insert_allocator(memory_manager.allocators, allind); + ptr = new_allocator->allocate(&new_allocator->allocator_instance, orgsize, 0); + +after_allocation: + if (pid != 0) + { // TODO 进程管理中应该有一个用户地址-内核地址映射表 + // 在进程分配时将页映射到用户空间中,并将这个映射关系记录进这个表中 + // 需要返回的是用户空间的地址 + } + return ptr; +} + +void memm_free(allocator_t *allocator, void *mem) +{ + if (is_user_address((u64)mem)) + { // TODO 对于用户空间的地址需要先转换到内核地址后释放 + } + allocator->free(allocator->allocator_instance, mem); + if (allocator->full) + allocator->full = false; +} + +usize find_fitable_pages(usize page_count) +{ + usize res = 0; + lst_iterator_t *iter = memory_manager.available_pages_table; + do + { + if (iter->line.right - iter->line.left > page_count) + { + res = iter->line.left; + lst_remove(iter, res, res + page_count, false); + for (usize i = res; i < res + page_count; i++) + { + bitmap_set(memory_manager.page_map, i); + } + break; + } + } while ((iter = lst_next(iter)) != nullptr); + memory_manager.mapped_page_amount += page_count; + return res; +} diff --git a/src/kernel/tty/tty.c b/src/kernel/tty/tty.c index bfe234d..644c282 100644 --- a/src/kernel/tty/tty.c +++ b/src/kernel/tty/tty.c @@ -1,24 +1,26 @@ -#include #include + +#include + #include -tty_controller tty_ctrler; +tty_controller_t tty_ctrler; -void tty_controller_init() +tty_controller_t *tty_controller_new() { memset(tty_ctrler.ttys, 0, sizeof(tty_ctrler.ttys)); memset(tty_ctrler.map, 0, sizeof(tty_ctrler.map)); + return &tty_ctrler; } -tty *tty_new(tty *__tty, tty_type type, tty_mode mode) +tty *tty_new(tty_type type, tty_mode mode) { - if (__tty == nullptr) - { // TODO 实现内存管理功能后实现 - KERNEL_TODO(); - } + allocator_t *allocator; + tty *__tty = memm_allocate(sizeof(tty), 0, &allocator); memset(__tty, 0, sizeof(tty)); __tty->type = type; __tty->mode = mode; + __tty->allocator = allocator; tty *res = nullptr; for (usize i = 0; i < TTY_MAX_NUM; ++i) { diff --git a/src/libk/Makefile b/src/libk/Makefile index 847ff3a..3d987e9 100644 --- a/src/libk/Makefile +++ b/src/libk/Makefile @@ -7,12 +7,14 @@ endif # C语言环境变量 CC = gcc -CCFLAGS = -m64 -mcmodel=large -I ../include -fno-stack-protector -fno-exceptions -fno-builtin -nostdinc -nostdlib +CCFLAGS = -m64 -mcmodel=large -I ../include \ + -fno-stack-protector -fno-exceptions \ + -fno-builtin -nostdinc -nostdlib ifdef release CCFLAGS := ${CCFLAGS} -O2 endif -C_OBJS = bootinfo.o +C_OBJS = bootinfo.o lst.o ################################ @@ -57,11 +59,12 @@ VPATH = multiboot2/ string/ %.o: arch/${ARCH}/%.s @echo -e "\e[1m\e[33m${ASM}\e[0m \e[32m$<\e[0m \e[34m-->\e[0m \e[1m\e[32m$@\e[0m" - @${ASM} ${ASMFLAGS} -o $@ $< 2>&1 | "${SOURCE}/colorize" "warning:=yellow" "error:=red" + @${ASM} ${ASMFLAGS} -o $@ $< 2>&1 | "${SOURCE}/colorize" "warning:=pink" "error:=red" libk.o: ${OBJS} @echo -e "\e[1m\e[33mld\e[0m \e[1m\e[32mlibk.o\e[0m \e[34m<--\e[0m \e[32m${OBJS}\e[0m" - @ld -r ${OBJS} -o libk.o -Map=libk.map 2>&1 | "${SOURCE}/colorize" "warning:=yellow" "error:=red" "ld=lyellow" + @ld -r ${OBJS} -o libk.o -Map=libk.map -unresolved-symbols=ignore-all 2>&1 \ + | "${SOURCE}/colorize" "warning:=pink" "error:=red" "ld=lyellow" @objcopy ${OBJCOPY_FLAGS} libk.o libk.o .PHONY: all postproc postproc_x86_64 diff --git a/src/libk/lst.c b/src/libk/lst.c new file mode 100644 index 0000000..262ceb9 --- /dev/null +++ b/src/libk/lst.c @@ -0,0 +1,183 @@ +#include + +#include +#include + +#include + +lst_iterator_t *lst_new(usize start, usize end) +{ + allocator_t *allocator; + lst_iterator_t *lst = memm_allocate(sizeof(lst_iterator_t), 0, &allocator); + lst->line.left = start; + lst->line.right = end; + lst->allocator = allocator; + lst->next = nullptr; + return lst; +} + +lst_iterator_t *lst_next(lst_iterator_t *iterator) +{ + return iterator->next; +} + +static lst_line_t get_overlap(lst_line_t *l1, lst_line_t *l2) +{ + lst_line_t l; + if (l1->right < l2->left || l2->right < l1->left) + { + l.left = l.right = 0; + return l; + } + if (l1->left < l2->left) + { + if (l1->right < l2->right) + { + l.left = l2->left; + l.right = l1->right; + return l; + } + else + { + l.left = l2->left; + l.right = l2->right; + return l; + } + } + else + { + if (l1->right < l2->right) + { + l.left = l1->left; + l.right = l1->right; + return l; + } + else + { + l.left = l1->left; + l.right = l2->right; + return l; + } + } +} + +/* +线的减法 + +只处理有一条边重合的情况 + */ +static void substract_line(lst_line_t *line, lst_line_t *substractor) +{ + if (line->left == substractor->left && line->right > substractor->right) + { + line->left = substractor->right; + } + else if (line->right == substractor->right && line->left < substractor->left) + { + line->right = substractor->left; + } +} + +#define line_is_equal(a, b) ((a).left == (b).left && (a).right == (b).right) +#define line_is_zero(l) ((l).left == (l).right) + +bool lst_remove(lst_iterator_t *lst, usize left, usize right, bool force) +{ + while (lst != nullptr) + { + if (left > lst->line.left && right < lst->line.right) + { + lst_iterator_t *new_node = lst_new(right, lst->line.right); + lst->line.right = left; + + new_node->next = lst->next; + lst->next = new_node; + return true; + } + else + { + lst_line_t line = { + .left = left, + .right = right, + }; + lst_line_t ol = get_overlap(&line, &lst->line); + substract_line(&line, &ol); + if (!line_is_zero(line) && !force) + return false; + substract_line(&lst->line, &ol); + return true; + } + lst = lst_next(lst); + } + return force; +} + +bool lst_add(lst_iterator_t *lst, usize left, usize right, bool force) +{ + lst_iterator_t *last = nullptr; + while (lst != nullptr) + { + if (left < lst->line.left) + { + lst_line_t line = { + .left = left, + .right = right, + }; + lst_line_t ol = get_overlap(&line, &lst->line); + if (!force && !line_is_zero(ol)) + return false; + if (right >= lst->line.right) + lst->line.left = left; + else + { + allocator_t *alloctr; + lst_iterator_t *new_node = memm_allocate(sizeof(lst_iterator_t), 0, &alloctr); + new_node->allocator = alloctr; + new_node->line = line; + new_node->next = lst; + if (last != nullptr) + last->next = new_node; + return true; + } + } + else if (left <= lst->line.right) + { + if (!force && left < lst->line.right) + return false; + if (right <= lst->line.right) + { + return true; + } + else if (right < lst->next->line.left) + { + lst->line.right = right; + return true; + } + else + { + if (!force && right >= lst->next->line.left) + return false; + lst_iterator_t *tmpnode = lst->next; + lst_iterator_t tmplast = *lst; + while (tmpnode != nullptr) + { + if (right < tmpnode->line.left) + { + lst->line.right = tmplast.line.right; + lst->next = tmpnode; + return true; + } + tmplast = *tmpnode; + lst_iterator_t *t = lst_next(tmpnode); + memm_free(tmpnode->allocator, tmpnode); + tmpnode = t; + } + lst->line.right = max(tmplast.line.right, right); + lst->next = nullptr; + return true; + } + } + last = lst; + lst = lst_next(lst); + } +} diff --git a/src/metaverse.lds b/src/metaverse.lds index c038e87..c5296d2 100644 --- a/src/metaverse.lds +++ b/src/metaverse.lds @@ -26,7 +26,6 @@ SECTIONS { . = 16M; .text : { - kmain = .; *(.text) } .data :