diff --git a/.vscode/settings.json b/.vscode/settings.json index c8dca873..05f9ef64 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "stdarg.h": "c", "font.h": "c", "trap.h": "c", - "gate.h": "c" + "gate.h": "c", + "process.h": "c" } } \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index 1f376bf5..edac1278 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,8 +10,8 @@ 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 mm.o irq.o 8259A.o - ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o exception/8259A.o mm/mm.o -T link.lds +kernel: head.o entry.o main.o printk.o trap.o mm.o irq.o 8259A.o process.o + ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o main.o common/printk.o exception/trap.o exception/irq.o exception/8259A.o mm/mm.o process/process.o -T link.lds head.o: head.S gcc -E head.S > head.s # 预处理 @@ -44,5 +44,8 @@ irq.o: exception/irq.c mm.o: mm/mm.c gcc -mcmodel=large -fno-builtin -m64 -c mm/mm.c -o mm/mm.o +process.o: process/process.c + gcc -mcmodel=large -fno-builtin -m64 -c process/process.c -o process/process.o + clean: rm -rf $(GARBAGE) \ No newline at end of file diff --git a/kernel/common/cpu.h b/kernel/common/cpu.h new file mode 100644 index 00000000..ace43937 --- /dev/null +++ b/kernel/common/cpu.h @@ -0,0 +1,3 @@ +#pragma once + +#define CPU_NUM 8 \ No newline at end of file diff --git a/kernel/common/glib.h b/kernel/common/glib.h index 51d7e0b2..27c6a9cc 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -23,6 +23,19 @@ : "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成 #define io_lfence() __asm__ __volatile__("lfence\n\t" :: \ : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。 +/** + * @brief 根据结构体变量内某个成员变量member的基地址,计算出该结构体变量的基地址 + * @param ptr 指向结构体变量内的成员变量member的指针 + * @param type 成员变量所在的结构体 + * @param member 成员变量名 + * + * 方法:使用ptr减去结构体内的偏移,得到结构体变量的基地址 + */ +#define container_of(ptr, type, member) \ + ({ \ + typeof(((type *)0)->member) *p = (ptr); \ + (type *)((unsigned long)p - (unsigned long)&(((type *)0)->member)); \ + }) // 定义类型的缩写 typedef unsigned long ul; @@ -100,6 +113,32 @@ static inline bool list_empty(struct List *entry) return false; } +/** + * @brief 获取链表的上一个元素 + * + * @param entry + * @return 链表的上一个元素 + */ +static inline struct List* list_prev(struct List *entry) +{ + if(entry->prev!=NULL) + return entry->prev; + else return NULL; +} + +/** + * @brief 获取链表的下一个元素 + * + * @param entry + * @return 链表的下一个元素 + */ +static inline struct List* list_next(struct List *entry) +{ + if(entry->next!=NULL) + return entry->next; + else return NULL; +} + //计算字符串的长度(经过测试,该版本比采用repne/scasb汇编的运行速度快16.8%左右) static inline int strlen(char *s) { @@ -137,33 +176,32 @@ void *memset(void *dst, unsigned char C, ul Count) /** * @brief 内存拷贝函数 - * + * * @param dst 目标数组 * @param src 源数组 * @param Num 字节数 - * @return void* + * @return void* */ -void * memcpy(void *dst,void * src,long Num) +void *memcpy(void *dst, void *src, long Num) { - int d0,d1,d2; - __asm__ __volatile__ ( "cld \n\t" - "rep \n\t" - "movsq \n\t" - "testb $4,%b4 \n\t" - "je 1f \n\t" - "movsl \n\t" - "1:\ttestb $2,%b4 \n\t" - "je 2f \n\t" - "movsw \n\t" - "2:\ttestb $1,%b4 \n\t" - "je 3f \n\t" - "movsb \n\t" - "3: \n\t" - :"=&c"(d0),"=&D"(d1),"=&S"(d2) - :"0"(Num/8),"q"(Num),"1"(src),"2"(dst) - :"memory" - ); - return dst; + int d0, d1, d2; + __asm__ __volatile__("cld \n\t" + "rep \n\t" + "movsq \n\t" + "testb $4,%b4 \n\t" + "je 1f \n\t" + "movsl \n\t" + "1:\ttestb $2,%b4 \n\t" + "je 2f \n\t" + "movsw \n\t" + "2:\ttestb $1,%b4 \n\t" + "je 3f \n\t" + "movsb \n\t" + "3: \n\t" + : "=&c"(d0), "=&D"(d1), "=&S"(d2) + : "0"(Num / 8), "q"(Num), "1"(src), "2"(dst) + : "memory"); + return dst; } void *memset_c(void *dst, unsigned char c, ul n) { @@ -176,44 +214,43 @@ void *memset_c(void *dst, unsigned char c, ul n) // 从io口读入8个bit unsigned char io_in8(unsigned short port) { - unsigned char ret = 0; - __asm__ __volatile__( "inb %%dx, %0 \n\t" - "mfence \n\t" - :"=a"(ret) - :"d"(port) - :"memory"); - return ret; + unsigned char ret = 0; + __asm__ __volatile__("inb %%dx, %0 \n\t" + "mfence \n\t" + : "=a"(ret) + : "d"(port) + : "memory"); + return ret; } // 从io口读入32个bit unsigned int io_in32(unsigned short port) { - unsigned int ret = 0; - __asm__ __volatile__( "inl %%dx, %0 \n\t" - "mfence \n\t" - :"=a"(ret) - :"d"(port) - :"memory"); - return ret; + unsigned int ret = 0; + __asm__ __volatile__("inl %%dx, %0 \n\t" + "mfence \n\t" + : "=a"(ret) + : "d"(port) + : "memory"); + return ret; } // 输出8个bit到输出端口 -void io_out8(unsigned short port,unsigned char value) +void io_out8(unsigned short port, unsigned char value) { - __asm__ __volatile__( "outb %0, %%dx \n\t" - "mfence \n\t" - : - :"a"(value),"d"(port) - :"memory"); + __asm__ __volatile__("outb %0, %%dx \n\t" + "mfence \n\t" + : + : "a"(value), "d"(port) + : "memory"); } // 输出32个bit到输出端口 -void io_out32(unsigned short port,unsigned int value) +void io_out32(unsigned short port, unsigned int value) { - __asm__ __volatile__( "outl %0, %%dx \n\t" - "mfence \n\t" - : - :"a"(value),"d"(port) - :"memory"); + __asm__ __volatile__("outl %0, %%dx \n\t" + "mfence \n\t" + : + : "a"(value), "d"(port) + : "memory"); } - diff --git a/kernel/head.S b/kernel/head.S index 03ed9b53..bb803473 100644 --- a/kernel/head.S +++ b/kernel/head.S @@ -2,6 +2,8 @@ // Created by longjin. // 2022/01/20 +#include "common/asm.h" + .section .text .global _start @@ -140,6 +142,11 @@ m_ignore_int: go_to_ignore_int: .quad ignore_int + +ENTRY(_stack_start) + .quad initial_proc_union + 32768 + + // 初始化页表 .align 8 //设置为8byte对齐 .org 0x1000 //设置页表位置为内核执行头程序的0x1000处 diff --git a/kernel/link.lds b/kernel/link.lds index beebd82d..1328b9bb 100644 --- a/kernel/link.lds +++ b/kernel/link.lds @@ -21,6 +21,15 @@ SECTIONS _edata = .; } + .rodata : + { + _rodata = .; + *(.rodata) + _erodata = .; + } + + . = ALIGN(32768); + .data.init_proc : { *(.data.init_proc) } .bss : { _bss = .; diff --git a/kernel/main.c b/kernel/main.c index 7535a09c..b7479ae4 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -4,11 +4,12 @@ #include "common/glib.h" #include "common/printk.h" +#include "common/kprint.h" #include "exception/gate.h" #include "exception/trap.h" #include "exception/irq.h" #include "mm/mm.h" -#include "common/kprint.h" +#include "process/process.h" int *FR_address = (int *)0xffff800000a00000; //帧缓存区的地址 //char fxsave_region[512] __attribute__((aligned(16))); @@ -64,7 +65,7 @@ void test_printk() } // 测试内存管理单元 -void test_mm() +void test_mmm() { kinfo("Testing memory management unit..."); //printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *memory_management_struct.bmp, *(memory_management_struct.bmp + 1)); @@ -80,7 +81,7 @@ void test_mm() } */ - //printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *(memory_management_struct.bmp), *(memory_management_struct.bmp + 1)); + printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *(memory_management_struct.bmp), *(memory_management_struct.bmp + 1)); } void init() @@ -104,6 +105,7 @@ void init() // 初始化中断模块 init_irq(); + process_init(); } @@ -113,7 +115,8 @@ void Start_Kernel(void) init(); //show_welcome(); - test_mm(); + //test_mm(); + //test_printk(); //int t = 1 / 0; // 测试异常处理模块能否正常工作 触发除法错误 diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 4cad517b..2c67c2f2 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -159,7 +159,7 @@ void mm_init() { struct Zone *z = memory_management_struct.zones_struct + i; //printk_color(ORANGE, BLACK, "zone_addr_start:%#18lx, zone_addr_end:%#18lx, zone_length:%#18lx, pages_group:%#18lx, count_pages:%#18lx\n", - // z->zone_addr_start, z->zone_addr_end, z->zone_length, z->pages_group, z->count_pages); + // z->zone_addr_start, z->zone_addr_end, z->zone_length, z->pages_group, z->count_pages); // 1GB以上的内存空间不做映射 if (z->zone_addr_start == 0x100000000) @@ -180,7 +180,7 @@ void mm_init() page_init(memory_management_struct.pages_struct + j, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT | PAGE_ACTIVE); } - ul *cr3 = get_CR3(); + global_CR3 = get_CR3(); /* printk_color(INDIGO, BLACK, "cr3:\t%#018lx\n", cr3); @@ -188,9 +188,11 @@ void mm_init() printk_color(INDIGO, BLACK, "**cr3:\t%#018lx\n", *phys_2_virt(*(phys_2_virt(cr3)) & (~0xff)) & (~0xff)); */ + /* // 消除一致性页表映射,将页目录(PML4E)的前10项清空 for (int i = 0; i < 10; ++i) - *(phys_2_virt(cr3) + i) = 0UL; + *(phys_2_virt(global_CR3) + i) = 0UL; + */ flush_tlb(); @@ -241,7 +243,7 @@ unsigned long page_init(struct Page *page, ul flags) /** * @brief 从已初始化的页结构中搜索符合申请条件的、连续num个struct page * - * @param zone_select 选择内存区域, 可选项:dma, mapped in pgt, unmapped in pgt + * @param zone_select 选择内存区域, 可选项:dma, mapped in pgt(normal), unmapped in pgt * @param num 需要申请的连续内存页的数量 num<=64 * @param flags 将页面属性设置成flag * @return struct Page* @@ -310,4 +312,36 @@ struct Page *alloc_pages(unsigned int zone_select, int num, ul flags) } } } + return NULL; +} + +unsigned long page_clean(struct Page *p) +{ + if (!p->attr) + p->attr = 0; + else if ((p->attr & PAGE_REFERENCED) || (p->attr & PAGE_K_SHARE_TO_U)) + { + // 被引用的页或内核共享给用户态的页 + --p->ref_counts; + --p->zone->total_pages_link; + + // 当引用为0时 + if (!p->ref_counts) + { + p->attr = 0; + --p->zone->count_pages_using; + ++p->zone->count_pages_free; + } + } + else + { + // 将bmp复位 + *(memory_management_struct.bmp + ((p->addr_phys >> PAGE_2M_SHIFT) >> 6)) &= ~(1UL << ((p->addr_phys >> PAGE_2M_SHIFT) % 64)); + + p->attr = 0; + p->ref_counts = 0; + --p->zone->count_pages_using; + ++p->zone->count_pages_free; + --p->zone->total_pages_link; + } } \ No newline at end of file diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index 6632ec84..aef438ec 100644 --- a/kernel/mm/mm.h +++ b/kernel/mm/mm.h @@ -7,7 +7,7 @@ #define PTRS_PER_PGT 512 // 内核层的起始地址 -#define KERNEL_BASE_ADDR 0xffff800000000000 +#define KERNEL_BASE_ADDR ((unsigned long)0xffff800000000000) #define PAGE_4K_SHIFT 12 #define PAGE_2M_SHIFT 21 @@ -29,14 +29,18 @@ // 虚拟地址与物理地址转换 #define virt_2_phys(addr) ((unsigned long)(addr)-KERNEL_BASE_ADDR) #define phys_2_virt(addr) ((unsigned long *)((unsigned long)(addr) + KERNEL_BASE_ADDR)) +#define Phy_To_Virt(addr) ((unsigned long *)((unsigned long)(addr) + KERNEL_BASE_ADDR)) + +#define Virt_To_2M_Page(kaddr) (memory_management_struct.pages_struct + (virt_2_phys(kaddr) >> PAGE_2M_SHIFT)) +#define Phy_to_2M_Page(kaddr) (memory_management_struct.pages_struct + ((unsigned long)(kaddr) >> PAGE_2M_SHIFT)) // ===== 内存区域属性 ===== // DMA区域 -#define ZONE_DMA (1<<0) +#define ZONE_DMA (1 << 0) // 已在页表中映射的区域 -#define ZONE_NORMAL (1<<1) +#define ZONE_NORMAL (1 << 1) // 未在页表中映射的区域 -#define ZONE_UNMAPPED_IN_PGT (1<<2) +#define ZONE_UNMAPPED_IN_PGT (1 << 2) // ===== 页面属性 ===== // 页面在页表中已被映射 @@ -60,23 +64,21 @@ // slab内存分配器的页 #define PAGE_SLAB (1 << 9) - /** * @brief 刷新TLB的宏定义 * 由于任何写入cr3的操作都会刷新TLB,因此这个宏定义可以刷新TLB */ -#define flush_tlb() \ - do \ - { \ - ul tmp; \ - __asm__ __volatile__( \ - "movq %%cr3, %0\n\t" \ - "movq %0, %%cr3\n\t" \ +#define flush_tlb() \ + do \ + { \ + ul tmp; \ + __asm__ __volatile__( \ + "movq %%cr3, %0\n\t" \ + "movq %0, %%cr3\n\t" \ : "=r"(tmp)::"memory"); \ - \ + \ } while (0); - // Address Range Descriptor Structure 地址范围描述符 struct ARDS { @@ -155,32 +157,39 @@ extern struct memory_desc memory_management_struct; // 导出内核程序的几个段的起止地址 extern char _text; extern char _etext; +extern char _data; extern char _edata; +extern char _rodata; +extern char _erodata; +extern char _bss; +extern char _ebss; extern char _end; // 每个区域的索引 int ZONE_DMA_INDEX = 0; -int ZONE_NORMAL_INDEX = 0; //low 1GB RAM ,was mapped in pagetable -int ZONE_UNMAPED_INDEX = 0; //above 1GB RAM,unmapped in pagetable +int ZONE_NORMAL_INDEX = 0; // low 1GB RAM ,was mapped in pagetable +int ZONE_UNMAPED_INDEX = 0; // above 1GB RAM,unmapped in pagetable + +ul *global_CR3 = NULL; // 初始化内存管理单元 void mm_init(); /** * @brief 初始化内存页 - * + * * @param page 内存页结构体 * @param flags 标志位 * 对于新页面: 初始化struct page * 对于当前页面属性/flags中含有引用属性或共享属性时,则只增加struct page和struct zone的被引用计数。否则就只是添加页表属性,并置位bmp的相应位。 - * @return unsigned long + * @return unsigned long */ unsigned long page_init(struct Page *page, ul flags); /** * @brief 读取CR3寄存器的值(存储了页目录的基地址) - * + * * @return unsigned* cr3的值的指针 */ unsigned long *get_CR3() @@ -194,10 +203,27 @@ unsigned long *get_CR3() /** * @brief 从已初始化的页结构中搜索符合申请条件的、连续num个struct page - * - * @param zone_select 选择内存区域, 可选项:dma, mapped in pgt, unmapped in pgt + * + * @param zone_select 选择内存区域, 可选项:dma, mapped in pgt(normal), unmapped in pgt * @param num 需要申请的内存页的数量 num<=64 * @param flags 将页面属性设置成flag - * @return struct Page* + * @return struct Page* */ -struct Page* alloc_pages(unsigned int zone_select, int num, ul flags); \ No newline at end of file +struct Page *alloc_pages(unsigned int zone_select, int num, ul flags); + +/** + * @brief 释放内存页 + * + * @param page 内存页结构体 + * @return unsigned long + */ +unsigned long page_clean(struct Page *page); + +/** + * @brief 内存页表结构体 + * + */ +typedef struct +{ + unsigned long pml4t; +} pml4t_t; \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c new file mode 100644 index 00000000..0bda7a02 --- /dev/null +++ b/kernel/process/process.c @@ -0,0 +1,246 @@ +#include "process.h" + + +#include "../exception/gate.h" +#include "../common/printk.h" +#include "../common/kprint.h" + + +void test_mm() +{ + kinfo("Testing memory management unit..."); + //printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *memory_management_struct.bmp, *(memory_management_struct.bmp + 1)); + kinfo("Try to allocate 64 memory pages."); + struct Page *page = alloc_pages(ZONE_NORMAL, 64, PAGE_PGT_MAPPED | PAGE_ACTIVE | PAGE_KERNEL); + + for (int i = 0; i <= 65; ++i) + { + printk("page%d\tattr:%#018lx\tphys_addr:%#018lx\t", i, page->attr, page->addr_phys); + ++page; + if (((i + 1) % 2) == 0) + printk("\n"); + } + + + printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *(memory_management_struct.bmp), *(memory_management_struct.bmp + 1)); +} + +/** + * @brief 切换进程 + * + * @param prev 上一个进程的pcb + * @param next 将要切换到的进程的pcb + * 由于程序在进入内核的时候已经保存了寄存器,因此这里不需要保存寄存器。 + * 这里切换fs和gs寄存器 + */ +void __switch_to(struct process_control_block *prev, struct process_control_block *next) +{ + initial_tss[0].rsp0 = next->thread->rbp; + set_TSS64(initial_tss[0].rsp0, initial_tss[0].rsp1, initial_tss[0].rsp2, initial_tss[0].ist1, + initial_tss[0].ist2, initial_tss[0].ist3, initial_tss[0].ist4, initial_tss[0].ist5, initial_tss[0].ist6, initial_tss[0].ist7); + + __asm__ __volatile__("movq %%fs, %0 \n\t" + : "=a"(prev->thread->fs)); + __asm__ __volatile__("movq %%gs, %0 \n\t" + : "=a"(prev->thread->gs)); + + __asm__ __volatile__("movq %0, %%fs \n\t" ::"a"(next->thread->fs)); + __asm__ __volatile__("movq %0, %%gs \n\t" ::"a"(next->thread->gs)); + + printk("prev->thread->rbp=%#018lx\n", prev->thread->rbp); + printk("next->thread->rbp=%#018lx\n", next->thread->rbp); +} + +/** + * @brief 内核init进程 + * + * @param arg + * @return ul 参数 + */ +ul init(ul arg) +{ + printk("initial proc running...\targ:%#018lx\n", arg); + return 1; +} + +/** + * @brief 进程退出时执行的函数 + * + * @param code 返回码 + * @return ul + */ +ul do_exit(ul code) +{ + kinfo("thread_exiting..., code is %#018lx.", code); + while (1) + ; +} + +/** + * @brief 导出内核线程的执行引导程序 + * 目的是还原执行现场(在kernel_thread中伪造的) + * 执行到这里时,rsp位于栈顶,然后弹出寄存器值 + * 弹出之后还要向上移动7个unsigned long的大小,从而弹出额外的信息(详见pt_regs) + */ +extern void kernel_thread_func(void); + +__asm__( + "kernel_thread_func: \n\t" + " popq %r15 \n\t" + " popq %r14 \n\t" + " popq %r13 \n\t" + " popq %r12 \n\t" + " popq %r11 \n\t" + " popq %r10 \n\t" + " popq %r9 \n\t" + " popq %r8 \n\t" + " popq %rbx \n\t" // 在kernel_thread中,将程序执行地址保存在了rbx + " popq %rcx \n\t" + " popq %rdx \n\t" + " popq %rsi \n\t" + " popq %rdi \n\t" + " popq %rbp \n\t" + " popq %rax \n\t" + " movq %rax, %ds\n\t" + " popq %rax \n\t" + " movq %rax, %es\n\t" + " popq %rax \n\t" + " addq $0x38, %rsp \n\t" + // ======================= // + " movq %rdx, %rdi \n\t" + " callq *%rbx \n\t" + " movq %rax, %rdi \n\t" + " callq do_exit \n\t"); + +/** + * @brief 初始化内核进程 + * + * @param fn 目标程序的地址 + * @param arg 向目标程序传入的参数 + * @param flags + * @return int + */ +int kernel_thread(unsigned long (* fn)(unsigned long), unsigned long arg, unsigned long flags) +{ + //struct Page *page = alloc_pages(ZONE_NORMAL, 2, PAGE_PGT_MAPPED | PAGE_ACTIVE | PAGE_KERNEL); + struct pt_regs regs; + memset(®s, 0, sizeof(regs)); + + // 在rbx寄存器中保存进程的入口地址 + regs.rbx = (ul)fn; + // 在rdx寄存器中保存传入的参数 + regs.rdx = (ul)arg; + + regs.ds = KERNEL_DS; + regs.es = KERNEL_DS; + regs.cs = KERNEL_CS; + regs.ss = KERNEL_DS; + + // 置位中断使能标志位 + regs.rflags = (1 << 9); + + // rip寄存器指向内核线程的引导程序 + regs.rip = (ul)kernel_thread_func; + + return (int)do_fork(®s, flags, 0, 0); +} + +void process_init() +{ + + initial_mm.pgd = (pml4t_t *)global_CR3; + + initial_mm.code_addr_start = memory_management_struct.kernel_code_start; + initial_mm.code_addr_end = memory_management_struct.kernel_code_end; + + initial_mm.data_addr_start = (ul)&_data; + initial_mm.data_addr_end = memory_management_struct.kernel_data_end; + + initial_mm.rodata_addr_start = (ul)&_rodata; + initial_mm.rodata_addr_end = (ul)&_erodata; + + initial_mm.brk_start = 0; + initial_mm.brk_end = memory_management_struct.kernel_end; + + initial_mm.stack_start = _stack_start; + + + // 初始化进程和tss + set_TSS64(initial_thread.rbp, initial_tss[0].rsp1, initial_tss[0].rsp2, initial_tss[0].ist1, initial_tss[0].ist2, initial_tss[0].ist3, initial_tss[0].ist4, initial_tss[0].ist5, initial_tss[0].ist6, initial_tss[0].ist7); + + + + initial_tss[0].rsp0 = initial_thread.rbp; + + // 初始化进程的循环链表 + list_init(&initial_proc_union.pcb.list); + + test_mm(); + kernel_thread(init, 10, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); // 初始化内核进程 + initial_proc_union.pcb.state = PROC_RUNNING; + + // 获取新的进程的pcb + struct process_control_block *p = container_of(list_next(¤t_pcb->list), struct process_control_block, list); + switch_proc(current_pcb, p); +} + +/** + * @brief fork当前进程 + * + * @param regs 新的寄存器值 + * @param clone_flags 克隆标志 + * @param stack_start 堆栈开始地址 + * @param stack_size 堆栈大小 + * @return unsigned long + */ +unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size) +{ + //printk("bmp[0]:%#018x\tbmp[1]%#018lx\n", *(memory_management_struct.bmp), *(memory_management_struct.bmp + 1)); + struct process_control_block *tsk = NULL; + + //printk("alloc_pages,bmp %#018lx\n", *(memory_management_struct.bmp)); + + // 获取一个物理页并在这个物理页内初始化pcb + struct Page *p = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED | PAGE_ACTIVE | PAGE_KERNEL); + printk("22\n"); + + //kinfo("alloc_pages,bmp:%#018lx", *(memory_management_struct.bmp)); + tsk = (struct process_control_block *)((unsigned long)(p->addr_phys) + (0xffff800000000000UL)); + + //printk("phys_addr\t%#018lx\n",p->addr_phys); + printk("virt_addr\t%#018lx\n",(unsigned long)(p->addr_phys) + (0xffff800000000000UL)); + //kinfo("pcb addr:%#018lx", (ul)tsk); + + memset(tsk, 0, sizeof(*tsk)); + printk("33\n"); + // 将当前进程的pcb复制到新的pcb内 + *tsk = *current_pcb; + + // 将进程加入循环链表 + list_init(&tsk->list); + printk("44\n"); + list_append(&initial_proc_union.pcb.list, &tsk->list); + printk("5\n"); + + ++(tsk->pid); + tsk->state = PROC_UNINTERRUPTIBLE; + + // 将线程结构体放置在pcb的后面 + struct thread_struct *thd = (struct thread_struct *)(tsk + 1); + tsk->thread = thd; + + // 将寄存器信息存储到进程的内核栈空间的顶部 + memcpy((void *)((ul)tsk + STACK_SIZE - sizeof(struct pt_regs)), regs, sizeof(struct pt_regs)); + // 设置进程的内核栈 + thd->rbp = (ul)tsk + STACK_SIZE; + thd->rip = regs->rip; + thd->rsp = (ul)tsk + STACK_SIZE - sizeof(struct pt_regs); + + // 若进程不是内核层的进程,则跳转到ret from intr + if (!(tsk->flags & PF_KTHREAD)) + thd->rip = regs->rip = (ul)ret_from_intr; + + tsk->state = PROC_RUNNING; + printk("1111\n"); + return 0; +} \ No newline at end of file diff --git a/kernel/process/process.h b/kernel/process/process.h new file mode 100644 index 00000000..7761af64 --- /dev/null +++ b/kernel/process/process.h @@ -0,0 +1,270 @@ +/** + * @file process.h + * @author longjin + * @brief 进程 + * @date 2022-01-29 + * + * @copyright Copyright (c) 2022 + * + */ + +#pragma once + +#include "../common/cpu.h" +#include "../common/glib.h" +#include "../mm/mm.h" +#include "ptrace.h" + +extern unsigned long _stack_start; // 导出内核层栈基地址(定义在head.S) +extern void ret_from_intr(); // 导出从中断返回的函数(定义在entry.S) + +// 进程的内核栈大小 32K +#define STACK_SIZE 32768 + +// 进程的运行状态 +// 正在运行 +#define PROC_RUNNING (1 << 0) +// 可被中断 +#define PROC_INTERRUPTIBLE (1 << 1) +// 不可被中断 +#define PROC_UNINTERRUPTIBLE (1 << 2) +// 挂起 +#define PROC_ZOMBIE (1 << 3) +// 已停止 +#define PROC_STOPPED (1 << 4) + +// 内核代码段基地址 +#define KERNEL_CS (0x08) +// 内核数据段基地址 +#define KERNEL_DS (0x10) +// 用户代码段基地址 +#define USER_CS (0x28) +// 用户数据段基地址 +#define USER_DS (0x30) + +// 进程初始化时的数据拷贝标志位 +#define CLONE_FS (1 << 0) +#define CLONE_FILES (1 << 1) +#define CLONE_SIGNAL (1 << 2) + +/** + * @brief 内存空间分布结构体 + * 包含了进程内存空间分布的信息 + */ +struct mm_struct +{ + pml4t_t *pgd; // 内存页表指针 + // 代码段空间 + ul code_addr_start, code_addr_end; + // 数据段空间 + ul data_addr_start, data_addr_end; + // 只读数据段空间 + ul rodata_addr_start, rodata_addr_end; + // 动态内存分配区(堆区域) + ul brk_start, brk_end; + // 应用层栈基地址 + ul stack_start; +}; + +struct thread_struct +{ + // 内核层栈基指针 + ul rbp; // in tss rsp0 + // 内核层代码指针 + ul rip; + // 内核层栈指针 + ul rsp; + + ul fs, gs; + + ul cr2; + // 异常号 + ul trap_num; + // 错误码 + ul err_code; +}; + +// 进程标志位 +#define PF_KTHREAD (1 << 0) + +/** + * @brief 进程控制块 + * + */ +struct process_control_block +{ + // 连接各个pcb的双向链表 + struct List list; + + // 进程的状态 + volatile long state; + // 进程标志:进程、线程、内核线程 + unsigned long flags; + + // 内存空间分布结构体, 记录内存页表和程序段信息 + struct mm_struct *mm; + + // 进程切换时保存的状态信息 + struct thread_struct *thread; + + // 地址空间范围 + // 用户空间: 0x0000 0000 0000 0000 ~ 0x0000 7fff ffff ffff + // 内核空间: 0xffff 8000 0000 0000 ~ 0xffff ffff ffff ffff + ul addr_limit; + + // 进程id + long pid; + + // 可用时间片 + long counter; + + // 信号 + long signal; + + // 优先级 + long priority; +}; + +// 将进程的pcb和内核栈融合到一起,8字节对齐 +union proc_union +{ + struct process_control_block pcb; + ul stack[STACK_SIZE / sizeof(ul)]; +} __attribute__((aligned(8))); + +struct mm_struct initial_mm; +struct thread_struct initial_thread; + +// 设置初始进程的PCB +#define INITIAL_PROC(proc) \ + { \ + .state = PROC_UNINTERRUPTIBLE, \ + .flags = PF_KTHREAD, \ + .mm = &initial_mm, \ + .thread = &initial_thread, \ + .addr_limit = 0xffff800000000000, \ + .pid = 0, \ + .counter = 1, \ + .signal = 0, \ + .priority = 0 \ + } + +// 初始化 初始进程的union ,并将其链接到.data.init_proc段内 +union proc_union initial_proc_union __attribute__((__section__(".data.init_proc"))) = {INITIAL_PROC(initial_proc_union.pcb)}; + +struct process_control_block *initial_proc[CPU_NUM] = {&initial_proc_union.pcb, 0}; + +struct mm_struct initial_mm = {0}; +struct thread_struct initial_thread = + { + .rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), + .rsp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), + .fs = KERNEL_DS, + .gs = KERNEL_DS, + .cr2 = 0, + .trap_num = 0, + .err_code = 0}; + +/** + * @brief 任务状态段结构体 + * + */ +struct tss_struct +{ + unsigned int reserved0; + ul rsp0; + ul rsp1; + ul rsp2; + ul reserved1; + ul ist1; + ul ist2; + ul ist3; + ul ist4; + ul ist5; + ul ist6; + ul ist7; + ul reserved2; + unsigned short reserved3; + // io位图基地址 + unsigned short io_map_base_addr; +} __attribute__((packed)); // 使用packed表明是紧凑结构,编译器不会对成员变量进行字节对齐。 + +// 设置初始进程的tss +#define INITIAL_TSS \ + { \ + .reserved0 = 0, \ + .rsp0 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), \ + .rsp1 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), \ + .rsp2 = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), \ + .reserved1 = 0, \ + .ist1 = 0xffff800000007c00, \ + .ist2 = 0xffff800000007c00, \ + .ist3 = 0xffff800000007c00, \ + .ist4 = 0xffff800000007c00, \ + .ist5 = 0xffff800000007c00, \ + .ist6 = 0xffff800000007c00, \ + .ist7 = 0xffff800000007c00, \ + .reserved2 = 0, \ + .reserved3 = 0, \ + .io_map_base_addr = 0 \ + } +// 为每个核心初始化初始进程的tss +struct tss_struct initial_tss[CPU_NUM] = {[0 ... CPU_NUM - 1] = INITIAL_TSS}; + +// 获取当前的pcb +struct process_control_block *get_current_pcb() +{ + struct process_control_block *current = NULL; + // 利用了当前pcb和栈空间总大小为32k大小对齐,将rsp低15位清空,即可获得pcb的起始地址 + __asm__ __volatile__("andq %%rsp, %0 \n\t" + : "=r"(current) + : "0"(~32767UL)); + return current; +} + +#define current_pcb get_current_pcb() + +#define GET_CURRENT_PCB \ + "movq %rsp, %rbx \n\t" \ + "andq $-32768, %rbx\n\t" + +/** + * @brief 切换进程上下文 + * 先把rbp和rax保存到栈中,然后将rsp和rip保存到prev的thread结构体中 + * 然后调用__switch_to切换栈,配置其他信息,最后恢复下一个进程的rax rbp。 + */ +#define switch_proc(prev, next) \ + do \ + { \ + __asm__ __volatile__("pushq %%rbp \n\t" \ + "pushq %%rax \n\t" \ + "movq %%rsp, %0 \n\t" \ + "movq %2, %%rax \n\t" \ + "leaq 1f(%%rip), %%rax \n\t" \ + "movq %%rax, %1 \n\t" \ + "pushq %3 \n\t" \ + "jmp __switch_to \n\t" \ + "1: \n\t" \ + "popq %%rax \n\t" \ + "popq %%rbp \n\t" \ + : "=m"(prev->thread->rsp), "=m"(prev->thread->rip) \ + : "m"(next->thread->rsp), "m"(next->thread->rip), "D"(prev), "S"(next) \ + : "memory"); \ + } while (0) + +/** + * @brief 初始化系统的第一个进程 + * + */ +void process_init(); + +/** + * @brief fork当前进程 + * + * @param regs 新的寄存器值 + * @param clone_flags 克隆标志 + * @param stack_start 堆栈开始地址 + * @param stack_size 堆栈大小 + * @return unsigned long + */ +unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size); \ No newline at end of file diff --git a/kernel/process/ptrace.h b/kernel/process/ptrace.h new file mode 100644 index 00000000..baedb247 --- /dev/null +++ b/kernel/process/ptrace.h @@ -0,0 +1,30 @@ +#pragma once +#include "../common/glib.h" +// 进程执行现场的寄存器状态 +struct pt_regs +{ + ul r15; + ul r14; + ul r13; + ul r12; + ul r11; + ul r10; + ul r9; + ul r8; + ul rbx; + ul rcx; + ul rdx; + ul rsi; + ul rdi; + ul rbp; + ul ds; + ul es; + ul rax; + ul func; + ul err_code; + ul rip; + ul cs; + ul rflags; + ul rsp; + ul ss; +}; \ No newline at end of file