From 44118c4a81f03a3a88b17955ee4da3f260525d79 Mon Sep 17 00:00:00 2001
From: lirong <lirongleiyan@163.com>
Date: Tue, 9 May 2023 16:43:02 +0000
Subject: [PATCH] alloc_PCB

---
 kernel.c    |  3 +-
 memlayout.h | 14 ++++++---
 memory.c    | 28 ++++++++++++++++--
 memory.h    |  2 +-
 process.c   | 83 +++++++++++++++++++++++++++++++++++++++++------------
 process.h   |  9 +++---
 riscv.h     |  3 +-
 trap.c      |  1 +
 vm.c        |  3 +-
 vm.h        |  4 +++
 10 files changed, 116 insertions(+), 34 deletions(-)

diff --git a/kernel.c b/kernel.c
index 446fd06..8ae7c15 100644
--- a/kernel.c
+++ b/kernel.c
@@ -35,7 +35,8 @@ void Kernel_Init(uint64_t hartid)
         boot_flag = true;
         wake_other_hart(hartid);
         printf("hartid:%d, pid:%d, this is idle\n", hartid, myPCB()->pid);
-        //printf("clock init\n");
+        struct PCB *p = alloc_PCB();
+        printf("pid of alloc_PCB:%d\n", p->pid);
         clock_init();       // 这块以后集成一个trap_init()
         //Test
         panic("Test");
diff --git a/memlayout.h b/memlayout.h
index f6e3498..dab8de7 100644
--- a/memlayout.h
+++ b/memlayout.h
@@ -7,12 +7,18 @@
 #define MEM_MAX_SIZE 128                                // 128M ram
 #define PA_MAX (SBI_ENRTY+ 128*1024*1024)   
 #define KERNEL_ENTRY 0X80200000L                         // 内核入口
-#define KERNEL_STACK_SIZE (1<<13)                       // 每个hart分配8kb的内核栈
-#define KERNEL_STACK_SIZE_SHIFT 13                      // 1<<13 同上    
+#define KERNEL_STACK_SIZE (1<<12)                       // 每个hart分配4kb的内核栈
+#define KERNEL_STACK_SIZE_SHIFT 12                      // 1<<12 同上    
 #define PYHSTOP (SBI_ENRTY+MEM_MAX_SIZE*1024*1024)      // dram上限
 
-#define PAGE_SIZE   (1<<12)                             //一页的大小 4K
-#define PAGE_SIZE_SHIFT 12          
+#define PGSIZE   (1<<12)                             //一页的大小 4K
+#define PGSIZE_SHIFT 12          
+
+#define TRAMPOLINE (MAXVA - PGSIZE)                     // 蹦床 用于用户态进程陷入内核态
+
+// map kernel stacks beneath the trampoline,
+// each surrounded by invalid guard pages.
+#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
 
 // 使用了 xv6 kernel/memlayout.h
 // qemu -machine virt
diff --git a/memory.c b/memory.c
index be74a78..46374fc 100644
--- a/memory.c
+++ b/memory.c
@@ -19,7 +19,8 @@ struct{
 }kmem;
 
 /*
- * @brief 
+ * @brief 将物理页释放
+ * @param pa 物理地址,必须页对齐
 */
 void memfree(uint64_t pa){
 	struct run *r;
@@ -54,7 +55,7 @@ void init_mem(){
 }
 
 /*
- * @brief 分配页,返回的实际地址
+ * @brief 分配实页,返回其物理地址
  * @retval return pyshical address of page or 0 if failed
 */
 void* alloc_page(){
@@ -66,7 +67,28 @@ void* alloc_page(){
 		// panic()  mark
 		return 0;
 	}
-	kmem.freelist = r ->next;
+	kmem.freelist = r->next;
 	release_lock(&kmem.mem_lock);
 	return (void*)r;
 }
+
+/*
+ * @brief 分配连续的n页内存
+*/
+void* alloc_npages(int32_t n){
+	if(n < 1)	return NULL;
+	struct run *last, *start;
+	int i;
+	acquire_lock(&kmem.mem_lock);
+	start = last = kmem.freelist;
+	for(i = 0; i < n; i++){
+		if(last == NULL){
+			printf("error: no free memory!\n");
+			return 0;
+		}
+		last = last->next;
+	}
+	kmem.freelist = last;
+	release_lock(&kmem.mem_lock);
+	return (void*)start;
+}
diff --git a/memory.h b/memory.h
index 910a2b0..20c6041 100644
--- a/memory.h
+++ b/memory.h
@@ -5,5 +5,5 @@
 void init_mem();
 void* alloc_page();
 void memfree(uint64_t pa);
-
+void* alloc_npages(int32_t n);
 #endif
\ No newline at end of file
diff --git a/process.c b/process.c
index b7cd246..52131e8 100644
--- a/process.c
+++ b/process.c
@@ -5,9 +5,16 @@
 #include "register.h"
 #include "stdio.h"
 #include "hart.h"
+#include "memory.h"
+#include "memlayout.h"
+#include "string.h"
 
 extern uint64_t KernelStack_start;          //定义在
 struct PCB PCBs[MAX_PROC_NUM];
+struct spinlock pid_lock;
+int32_t next_pid = 1;
+
+pgtable_t alloc_pgtable();
 
 /*
  * @brief 将所有pcb初始化
@@ -19,6 +26,7 @@ void init_proc(){
         init_lock(&(p->lock), "pcb_lock");
         PCBs[i].state = UNUSED;
     }
+    init_lock(&pid_lock, "pid_lock");
 }
 
 /*
@@ -34,13 +42,15 @@ void init_hart_idle(uint64_t hartid){
     p->parent = NULL;
     p->pagetable = (pte_t*)r_satp();      // 这个感觉好像不需要
     p->state = RUNNABLE;
-    p->kstack = (void*)(KernelStack_start + hartid*KERNEL_STACK_SIZE);   //guard page以后再加吧 mark
+    p->kstack = (KernelStack_start + hartid*KERNEL_STACK_SIZE);   //guard page以后再加吧 mark
     
     // 将pcb信息写入到当前hart上
     push_interrupt();
     myhart()->proc = p;
     pop_interrupt();
 
+    // 修改sp寄存器等 mark process_running();
+
     printf("hartid %d :init_hart_idle\n", hartid);
 }
 
@@ -49,24 +59,47 @@ void init_hart_idle(uint64_t hartid){
  * @retval 如果失败,返回0,否则返回PCB指针
  * @note 前KERNEL_MAX_NUM个PCB始终被idle占用
 */
+struct PCB* alloc_PCB(void){
+    struct PCB *p;
+    for(int i = KERNEL_MAX_NUM; i < MAX_PROC_NUM; i++){
+        p = &PCBs[i];
+        if(p->state == UNUSED){
+            if(init_PCB(p) == false)    return NULL;
+            return p;
+        }
+    }
+    return NULL;
+}
+
+bool init_PCB(struct PCB* p ){
+    acquire_lock(&p->lock);
+    p->state = SLEEPING;
+    if((p->pid = alloc_pid()) < 1){
+        return false;
+    }
+    p->parent = NULL;
+    p->runtime = 0;
+    p->size_of_memory = 0;
+    p->pagetable = alloc_pgtable();
+    p->kstack = KSTACK((int) (p - PCBs));
+    p->name = NULL;
 
-// static struct PCB* alloc_PCB(void){
-//     struct PCB *p;
-//     for(int i = KERNEL_MAX_NUM; i < MAX_PROC_NUM; i++){
-//         p = &PCBs[i];
-//         if(p->state == UNUSED){
-//             acquire_lock(&p->lock);
-//             p->state = SLEEPING;
-//             p->pid = -1;
-//             p->parent = NULL;
-//             p->runtime = 0;
-//             p->size_of_memory = 0;
-//             p->pagetable = NULL;
-//             p->kstack = NULL;
-//             p->name = NULL;
-//         }
-//     }
-// }
+    // p->trapframe.ra mark
+    p->trapframe.sp = p->kstack + PGSIZE;
+    return true;
+}
+
+/*
+ * @brief 分配一个pid
+*/
+int32_t alloc_pid(){
+    int32_t pid;
+    acquire_lock(&pid_lock);
+    pid = next_pid;
+    next_pid++;
+    release_lock(&pid_lock);
+    return pid;
+}
 
 struct PCB* myPCB(){
     push_interrupt();
@@ -74,4 +107,18 @@ struct PCB* myPCB(){
     pop_interrupt();
     return p;
 }
+/*
+ * @brief 为进程分配一张页表
+*/
+pgtable_t alloc_pgtable(){
+    pgtable_t pg;
+    pg = (pgtable_t)alloc_page();
+    if(pg == 0) return 0;
+    memset(pg, 0, PGSIZE);
+
+    // if(map_pages(pg, TRAMPOLINE, PGSIZE, trampoline, PTE_R | PTE_X) == false){
+    //     return 0;
+    // } mark 将蹦床映射
+    return pg;
+}
 
diff --git a/process.h b/process.h
index 25f8460..468cd68 100644
--- a/process.h
+++ b/process.h
@@ -78,7 +78,7 @@ enum process_state{
 struct PCB{
     uint32_t pid;
     uint32_t priority;              //进程优先级
-    struct trapframe *trapframe;     //trap帧    用于陷入内核态
+    struct trapframe trapframe;     //trap帧    用于陷入内核态
     struct context context;         //上下文
     struct spinlock lock;   
     enum process_state state;       //进程状态
@@ -86,14 +86,15 @@ struct PCB{
     uint64_t runtime;               //运行时间
     uint64_t size_of_memory;        //内存空间大小
     pgtable_t pagetable;            //用户态下的进程页表,进程陷入内核态后异常处理等可能需要使用
-    void* kstack;                   //内核栈
+    uint64_t kstack;                   //内核栈
     char* name;                     //debug用
 };
 
 void init_proc();
 void init_hart_idle(uint64_t hartid);
-struct PCB* alloc_proc();
+struct PCB* alloc_PCB(void);
 void free_proc(struct PCB *pro);
 struct PCB* myPCB();
-
+bool init_PCB(struct PCB* p );
+int32_t alloc_pid();
 #endif
\ No newline at end of file
diff --git a/riscv.h b/riscv.h
index 7893dbc..083a01f 100644
--- a/riscv.h
+++ b/riscv.h
@@ -12,8 +12,7 @@
 #define SSTATUS_UIE (1L << 0)       // User Interrupt Enable
 #define SIE_STIE    (1L << 5)       // SIE 寄存器 timer
 
-#define PGSIZE 4096                 // 页表长度
-#define PGSHIFT 12  
+#define MAXVA (1L << 38)            // 最大虚拟地址
 
 #define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))
 #define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))
diff --git a/trap.c b/trap.c
index 687ea7f..9d12b6e 100644
--- a/trap.c
+++ b/trap.c
@@ -114,6 +114,7 @@ void exception_handler(){
         case Load_page_fault:
             // mark 加载页错误
             printf("Load page fault\n");
+            panic("1");
             break;
         case Store_or_AMO_page_fault:
             printf("Store/AMO page fault\n");
diff --git a/vm.c b/vm.c
index 4753c11..7b2561c 100644
--- a/vm.c
+++ b/vm.c
@@ -16,7 +16,7 @@ void init_kernelvm(){
     if(kernel_pagetable == 0){
         panic("init_kernelvm failed");
     }
-    memset(kernel_pagetable, 0, PAGE_SIZE);
+    memset(kernel_pagetable, 0, PGSIZE);
 
 /*
     // uart registers
@@ -55,6 +55,7 @@ void init_hart_vm(){
  * @param size 大小 
  * @param pa 物理地址
  * @param perm pte的标志位   
+ * @retval flase or true 
 */
 bool map_pages(pgtable_t pagetable, uint64_t va, uint64_t size, uint64_t pa, int perm){
     if(size == 0)
diff --git a/vm.h b/vm.h
index 08a3fe4..8cc16b1 100644
--- a/vm.h
+++ b/vm.h
@@ -15,4 +15,8 @@ static inline void sfence_vma(){
     asm volatile("sfence.vma zero, zero");
 }
 void init_hart_vm();
+
+pgtable_t alloc_user_pgtable();
+pgtable_t alloc_kernel_pgtable();
+// pgtable_t alloc_pgtable();
 #endif
\ No newline at end of file
-- 
GitLab