手机版 欢迎访问it开发者社区(www.mfbz.cn)网站

当前位置: > 开发

《操作系统真象还原》第十二章 ---- 实现系统调用深入浅出 进一步完善堆内存分配与Printf函数 让用户进程有话可说

时间:2021/8/3 14:28:01|来源:|点击: 次

文章目录

    • 相关查阅博客链接
    • 本书中错误勘误
    • 闲聊时刻
    • 实现系统调用
      • 实现系统调用的思路
      • 修改后的kernel.S
      • 修改后的interrupt.c
      • 编写完的syscall.c
      • 编写完的syscall.h
      • 编写完的syscall-init.c
      • 编写后的syscall-init.h
      • 修改后的thread.c
      • 修改后的init.c
      • 修改后的Main.c
      • 修改后的makefile
      • make all 验收成果
    • 为什么进程里面不允许console_put_str
    • 实现简易write
      • 修改后的syscall-init.c
      • 修改后的syscall-init.h
      • 修改后的syscall.c
      • 修改后的syscall.h
    • 实现printf
      • 编写后的stdio.c
      • 编写后的stdio.h
      • 修改后的makefile
      • 修改后的main.c
      • make all 验收成果
    • 晚餐时间
    • 实现堆内存管理(实现malloc部分)
      • 修改完的memory.h
      • 修改完的memory.c
      • 修改完的thread.c(task_struct部分)
      • 修改完的process.c(process_execute函数)
      • 修改完的memory.c
      • 修改完的makefile
      • 修改后的main.c
      • make all 验证成果
    • 实现free函数
      • 修改后的memory.c
      • 修改后的memory.h
      • 修改后的main.c
      • 发现用户进程的问题
      • make all 验收成果
    • 结束语


相关查阅博客链接


C语言static 关键字总结


本书中错误勘误


1、这个地方我认为是书上没有写到的地方 就是kernel.S里面的syscall_handler()需要头文件单独引出来 不然编译器找不到函数
2、


闲聊时刻


今天已经是 8月2日了 距离暑假结束仅有33天了
细细回忆 我们军训结束就已经7月18日了 原本其实我在军训还没开始的时候我就觉得暑假应该去完成很多很多事情 但是可惜 军训的15天把我的很多计划与斗志全部化为了灰烬

7/19-7/22 在寝室昏耍了4天之后 潘然不想再继续玩下去了 因为没有什么好玩的了 毅然决然决定去图书馆重新整顿整顿 恢复原来的状态
7/22-7/30 可能还是连续去了很几天 然后室友就全部搬出去了 那个时候因为很久很久没有开始编程了 进度相对会稍微慢一些 但是之后室友搬出来之后就没有再去图书馆了 去图书馆的原因只是我做事情的时候比较喜欢独处 不喜欢有人在旁边

细细想来 复工到现在已经有12天了 操作系统播客也陆陆续续发了5篇了 为什么会来这里写点闲聊 是因为昨天一天上午把前天的博客写了发出去了 下午写了三道力扣之后就开始彻底歇下来了 开始看视频 玩小游戏 导致昨天晚上的晚饭也没有吃

其实我很清楚 暑假一个人在寝室也是一个挺大的考验 身边太多事情自己容易被分心 我觉得很多事情自己还是得做的毅然决然一点 话就不写那么多了 今天一天先把第十二章给结束了 之后的事情还得一点点慢慢做


实现系统调用


实现系统调用的思路


这里还是说一下大概的思路 因为之前哈工大操作系统Lab中
我们就自己实现过系统调用 当然 那个时候只是人家把框架写好 我们往里面套函数罢了 但是多多少少还是对这部分挺熟悉的

1、例如进程调用getpid()

2、调用getpid()的函数 == 调用_syscall0宏函数 函数号放入了eax

3、_syscall0int 0x80 引发中断 eax此时已经是函数号了

4、int 0x80的中断处理函数就是syscall_handler syscall_handler的核心在call [syscall_table+eax*4] 我们的syscall_table是提前准备好的 就是我们各种系统调用的函数指针表 根据我们输入的函数号即可定位到对应的处理函数

5、之后再进入intr_exit 还原上下文 中断退出 完整的系统调用结束 程序照常进行

也没什么好说的 翻来覆去就那么点内容 哈哈 不说了 看下面代码吧


修改后的kernel.S


这里就是多了一个syscall_handler
还有多了下面的填位置的中断序列

改一下即可

[bits 32]
%define ERROR_CODE nop		 ; 若在相关的异常中cpu已经自动压入了错误码,为保持栈中格式统一,这里不做操作.
%define ZERO push 0		 ; 若在相关的异常中cpu没有压入错误码,为了统一栈中格式,就手工压入一个0

extern put_str;
extern idt_table;
extern syscall_table;

section .data
global intr_entry_table
intr_entry_table:

%macro VECTOR 2
section .text
intr%1entry:		 ; 每个中断处理程序都要压入中断向量号,所以一个中断类型一个中断处理程序,自己知道自己的中断向量号是多少

    %2				 ; 中断若有错误码会压在eip后面 
; 以下是保存上下文环境
    push ds
    push es
    push fs
    push gs
    pushad			 ; PUSHAD指令压入32位寄存器,其入栈顺序是: EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI

    ; 如果是从片上进入的中断,除了往从片上发送EOI外,还要往主片上发送EOI 
    mov al,0x20                   ; 中断结束命令EOI
    out 0xa0,al                   ; 向从片发送
    out 0x20,al                   ; 向主片发送

    push %1			   ; 不管idt_table中的目标程序是否需要参数,都一律压入中断向量号,调试时很方便
    call [idt_table + %1*4]       ; 调用idt_table中的C版本中断处理函数
    jmp intr_exit
	
section .data
    dd    intr%1entry	 ; 存储各个中断入口程序的地址,形成intr_entry_table数组
%endmacro

section .text
global intr_exit
intr_exit:	     
; 以下是恢复上下文环境
    add esp, 4			   ; 跳过中断号
    popad
    pop gs
    pop fs
    pop es
    pop ds
    add esp, 4			   ; 跳过error_code
    iretd

section .text   
global syscall_handler
syscall_handler:
    push 0
    
    push ds
    push es
    push fs
    push gs
    pushad
    
    push 0x80			     ; 不管是否需要参数,都一律压入中断向量号,调试时很方便
    push edx			     ;第三个参数
    push ecx			     ;第二个参数
    push ebx			     ;第一个参数
    
    call [syscall_table + eax*4]
    add  esp,12
    
    mov [esp + 8*4],eax	     ;返回值给放到eax中 eax前面有 中断号+EDI+ESI+EBP+ESP+EBX+EDX+ECX 
    jmp intr_exit
    

VECTOR 0x0 ,ZERO
VECTOR 0X1 ,ZERO
VECTOR 0X2 ,ZERO
VECTOR 0x3 ,ZERO
VECTOR 0X4 ,ZERO
VECTOR 0X5 ,ZERO
VECTOR 0x6 ,ZERO
VECTOR 0X7 ,ZERO
VECTOR 0X8 ,ERROR_CODE
VECTOR 0x9 ,ZERO
VECTOR 0XA ,ERROR_CODE
VECTOR 0XB ,ERROR_CODE
VECTOR 0XC ,ERROR_CODE
VECTOR 0XD ,ERROR_CODE
VECTOR 0XE ,ERROR_CODE
VECTOR 0XF ,ZERO
VECTOR 0X10 ,ZERO
VECTOR 0X11 ,ERROR_CODE
VECTOR 0x12 ,ZERO
VECTOR 0X13 ,ZERO
VECTOR 0X14 ,ZERO
VECTOR 0x15 ,ZERO
VECTOR 0X16 ,ZERO
VECTOR 0X17 ,ZERO
VECTOR 0X18 ,ZERO
VECTOR 0X19 ,ZERO
VECTOR 0X1A ,ZERO
VECTOR 0X1B ,ZERO
VECTOR 0X1C ,ZERO
VECTOR 0X1D ,ZERO
VECTOR 0X1E ,ERROR_CODE                               ;处理器自动推错误码
VECTOR 0X1F ,ZERO					
VECTOR 0X20 ,ZERO					;时钟中断
VECTOR 0X21 ,ZERO					;键盘中断
VECTOR 0X22 ,ZERO					;级联
VECTOR 0X23 ,ZERO					;串口2
VECTOR 0X24 ,ZERO					;串口1
VECTOR 0X25 ,ZERO					;并口2
VECTOR 0X26 ,ZERO					;软盘
VECTOR 0X27 ,ZERO					;并口1
VECTOR 0X28 ,ZERO					;实时时钟
VECTOR 0X29 ,ZERO					;重定向
VECTOR 0X2A ,ZERO					;保留
VECTOR 0x2B ,ZERO					;保留
VECTOR 0x2C ,ZERO					;ps/2 鼠标
VECTOR 0x2D ,ZERO					;fpu 浮点单元异常
VECTOR 0x2E ,ZERO					;硬盘
VECTOR 0x2F ,ZERO					;保留
VECTOR 0x30 ,ZERO
VECTOR 0x31 ,ZERO
VECTOR 0x32 ,ZERO
VECTOR 0x33 ,ZERO
VECTOR 0x34 ,ZERO
VECTOR 0x35 ,ZERO
VECTOR 0x36 ,ZERO
VECTOR 0x37 ,ZERO
VECTOR 0x38 ,ZERO
VECTOR 0x39 ,ZERO
VECTOR 0x3A ,ZERO
VECTOR 0x3B ,ZERO
VECTOR 0x3C ,ZERO
VECTOR 0x3D ,ZERO
VECTOR 0x3E ,ZERO
VECTOR 0x3F ,ZERO
VECTOR 0x40 ,ZERO
VECTOR 0x41 ,ZERO
VECTOR 0x42 ,ZERO
VECTOR 0x43 ,ZERO
VECTOR 0x44 ,ZERO
VECTOR 0x45 ,ZERO
VECTOR 0x46 ,ZERO
VECTOR 0x47 ,ZERO
VECTOR 0x48 ,ZERO
VECTOR 0x49 ,ZERO
VECTOR 0x4A ,ZERO
VECTOR 0x4B ,ZERO
VECTOR 0x4C ,ZERO
VECTOR 0x4D ,ZERO
VECTOR 0x4E ,ZERO
VECTOR 0x4F ,ZERO
VECTOR 0x50 ,ZERO
VECTOR 0x51 ,ZERO
VECTOR 0x52 ,ZERO
VECTOR 0x53 ,ZERO
VECTOR 0x54 ,ZERO
VECTOR 0x55 ,ZERO
VECTOR 0x56 ,ZERO
VECTOR 0x57 ,ZERO
VECTOR 0x58 ,ZERO
VECTOR 0x59 ,ZERO
VECTOR 0x5A ,ZERO
VECTOR 0x5B ,ZERO
VECTOR 0x5C ,ZERO
VECTOR 0x5D ,ZERO
VECTOR 0x5E ,ZERO
VECTOR 0x5F ,ZERO
VECTOR 0x61 ,ZERO
VECTOR 0x62 ,ZERO
VECTOR 0x63 ,ZERO
VECTOR 0x64 ,ZERO
VECTOR 0x65 ,ZERO
VECTOR 0x66 ,ZERO
VECTOR 0x67 ,ZERO
VECTOR 0x68 ,ZERO
VECTOR 0x69 ,ZERO
VECTOR 0x6A ,ZERO
VECTOR 0x6B ,ZERO
VECTOR 0x6C ,ZERO
VECTOR 0x6D ,ZERO
VECTOR 0x6E ,ZERO
VECTOR 0x6F ,ZERO
VECTOR 0x70 ,ZERO
VECTOR 0x71 ,ZERO
VECTOR 0x72 ,ZERO
VECTOR 0x73 ,ZERO
VECTOR 0x74 ,ZERO
VECTOR 0x75 ,ZERO
VECTOR 0x76 ,ZERO
VECTOR 0x77 ,ZERO
VECTOR 0x78 ,ZERO
VECTOR 0x79 ,ZERO
VECTOR 0x7A ,ZERO
VECTOR 0x7B ,ZERO
VECTOR 0x7C ,ZERO
VECTOR 0x7D ,ZERO
VECTOR 0x7E ,ZERO
VECTOR 0x7F ,ZERO
VECTOR 0x80 ,ZERO

修改后的interrupt.c


这里修改主要修改支持中断数到0x81 因为最后的中断是int 0x80
还有把int 0x80的中断函数地址赋值给 syscall_handler
直接给代码咯

注意注意注意
这里包含的kernel.h是为了把syscall_handler给引出来

不加这个我这里显示没办法找到kernel.S里面的函数

这里先给kernel.h的代码
再下面就是interrupt.c

kernel.h

#ifndef __KERNEL_KERNEL_H
#define __KERNEL_KERNEL_H

void syscall_handler(void);

#endif

interrupt.c

#include "interrupt.h"
#include "stdint.h"
#include "global.h"
#include "io.h"
#include "print.h"
#include "kernel.h"

#define PIC_M_CTRL 0x20	       // 这里用的可编程中断控制器是8259A,主片的控制端口是0x20
#define PIC_M_DATA 0x21	       // 主片的数据端口是0x21
#define PIC_S_CTRL 0xa0	       // 从片的控制端口是0xa0
#define PIC_S_DATA 0xa1	       // 从片的数据端口是0xa1

#define IDT_DESC_CNT 0x81	       // 目前总共支持的中断数

#define EFLAGS_IF   0x00000200        // eflags寄存器中的if位为1
#define GET_EFLAGS(EFLAG_VAR) asm volatile("pushfl; popl %0" : "=g" (EFLAG_VAR))



/*中断门描述符结构体*/
struct gate_desc {
   uint16_t    func_offset_low_word;
   uint16_t    selector;
   uint8_t     dcount;   //此项为双字计数字段,是门描述符中的第4字节。此项固定值,不用考虑
   uint8_t     attribute;
   uint16_t    func_offset_high_word;
};

// 静态函数声明,非必须
static void pic_init(void);
static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function);
static void general_intr_handler(uint8_t vec_nr);
static void exception_init(void);
static struct gate_desc idt[IDT_DESC_CNT];   	     // idt是中断描述符表,本质上就是个中断门描述符数组
char* intr_name[IDT_DESC_CNT];		     // 用于保存异常的名字   


/********    定义中断处理程序数组    ********
 * 在kernel.S中定义的intrXXentry只是中断处理程序的入口,
 * 最终调用的是ide_table中的处理程序*/
intr_handler idt_table[IDT_DESC_CNT];

/********************************************/
extern intr_handler intr_entry_table[IDT_DESC_CNT];	    // 声明引用定义在kernel.S中的中断处理函数入口数组





/* 初始化可编程中断控制器8259A */
static void pic_init(void) {

   /* 初始化主片 */
   outb (PIC_M_CTRL, 0x11);   // ICW1: 边沿触发,级联8259, 需要ICW4.
   outb (PIC_M_DATA, 0x20);   // ICW2: 起始中断向量号为0x20,也就是IR[0-7] 为 0x20 ~ 0x27.
   outb (PIC_M_DATA, 0x04);   // ICW3: IR2接从片. 
   outb (PIC_M_DATA, 0x01);   // ICW4: 8086模式, 正常EOI

   /* 初始化从片 */
   outb (PIC_S_CTRL, 0x11);    // ICW1: 边沿触发,级联8259, 需要ICW4.
   outb (PIC_S_DATA, 0x28);    // ICW2: 起始中断向量号为0x28,也就是IR[8-15] 为 0x28 ~ 0x2F.
   outb (PIC_S_DATA, 0x02);    // ICW3: 设置从片连接到主片的IR2引脚
   outb (PIC_S_DATA, 0x01);    // ICW4: 8086模式, 正常EOI
   
   outb (PIC_M_DATA, 0xfc);
   outb (PIC_S_DATA, 0xff);

   put_str("   pic_init done\n");
}

/* 创建中断门描述符 */
static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function) { 
   p_gdesc->func_offset_low_word = (uint32_t)function & 0x0000FFFF;
   p_gdesc->selector = SELECTOR_K_CODE;
   p_gdesc->dcount = 0;
   p_gdesc->attribute = attr;
   p_gdesc->func_offset_high_word = ((uint32_t)function & 0xFFFF0000) >> 16;
}

/*初始化中断描述符表*/
static void idt_desc_init(void) {
   int i, lastindex = IDT_DESC_CNT - 1;
   for (i = 0; i < IDT_DESC_CNT; i++) {
      make_idt_desc(&idt[i], IDT_DESC_ATTR_DPL0, intr_entry_table[i]); 
   }
   
   make_idt_desc(&idt[lastindex],IDT_DESC_ATTR_DPL3,syscall_handler);
/* 单独处理系统调用,系统调用对应的中断门dpl为3,
 * 中断处理程序为单独的syscall_handler */
   put_str("   idt_desc_init done\n");
}



/* 通用的中断处理函数,一般用在异常出现时的处理 */
static void general_intr_handler(uint8_t vec_nr) {
   if (vec_nr == 0x27 || vec_nr == 0x2f) {	// 0x2f是从片8259A上的最后一个irq引脚,保留
      return;		//IRQ7和IRQ15会产生伪中断(spurious interrupt),无须处理。
   }
   set_cursor(0);                                         //光标设置在0号位
   int cursor_pos = 0;
   while((cursor_pos++) < 320)			    //一行80字 4行空格
   	put_char(' ');			
   
   set_cursor(0);
   put_str("!!!!!!            excetion message begin            !!!!!!\n");
   set_cursor(88);					    //第二行第八个字开始打印
   put_str(intr_name[vec_nr]);                            //打印中断向量号
   if(vec_nr == 14)
   {
   	int page_fault_vaddr = 0;
   	asm("movl %%cr2,%0" : "=r" (page_fault_vaddr));   //把虚拟地址 出错的放到了这个变量里面
	put_str("\npage fault addr is ");
	put_int(page_fault_vaddr);
   }
   put_str("!!!!!!            excetion message end              !!!!!!\n");
   
   while(1);                                              //悬停
}


/* 完成一般中断处理函数注册及异常名称注册 */
static void exception_init(void) {			    // 完成一般中断处理函数注册及异常名称注册
   int i;
   for (i = 0; i < IDT_DESC_CNT; i++) {

/* idt_table数组中的函数是在进入中断后根据中断向量号调用的,
 * 见kernel/kernel.S的call [idt_table + %1*4] */
      idt_table[i] = general_intr_handler;		    // 默认为general_intr_handler。
							    // 以后会由register_handler来注册具体处理函数。
      intr_name[i] = "unknown";				    // 先统一赋值为unknown 
   }
   intr_name[0] = "#DE Divide Error";
   intr_name[1] = "#DB Debug Exception";
   intr_name[2] = "NMI Interrupt";
   intr_name[3] = "#BP Breakpoint Exception";
   intr_name[4] = "#OF Overflow Exception";
   intr_name[5] = "#BR BOUND Range Exceeded Exception";
   intr_name[6] = "#UD Invalid Opcode Exception";
   intr_name[7] = "#NM Device Not Available Exception";
   intr_name[8] = "#DF Double Fault Exception";
   intr_name[9] = "Coprocessor Segment Overrun";
   intr_name[10] = "#TS Invalid TSS Exception";
   intr_name[11] = "#NP Segment Not Present";
   intr_name[12] = "#SS Stack Fault Exception";
   intr_name[13] = "#GP General Protection Exception";
   intr_name[14] = "#PF Page-Fault Exception";
   // intr_name[15] 第15项是intel保留项,未使用
   intr_name[16] = "#MF x87 FPU Floating-Point Error";
   intr_name[17] = "#AC Alignment Check Exception";
   intr_name[18] = "#MC Machine-Check Exception";
   intr_name[19] = "#XF SIMD Floating-Point Exception";
   //intr_name[80] = "SYSCALL INTR";
}


/*完成有关中断的所有初始化工作*/
void idt_init() {
   put_str("idt_init start\n");
   idt_desc_init();	   // 初始化中断描述符表
   exception_init();	   // 异常名初始化并注册通常的中断处理函数
   pic_init();		   // 初始化8259A

   /* 加载idt */
   uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t)(uint32_t)idt << 16));
   asm volatile("lidt %0" : : "m" (idt_operand));
   put_str("idt_init done\n");
}

void register_handler(uint8_t vec_no,intr_handler function)
{
    //把相关向量号的注册函数指针放进去了
    idt_table[vec_no] = function;
}

enum intr_status intr_enable()
{
    if(intr_get_status() != INTR_ON)
    {
    	asm volatile("sti");
    	return INTR_OFF;
    }
    return INTR_ON;
}

enum intr_status intr_disable()
{
    if(intr_get_status() != INTR_OFF)
    {
   	asm volatile("cli");
   	return INTR_ON;
    }
    return INTR_OFF;
}

enum intr_status intr_set_status(enum intr_status status)
{
    return (status == INTR_ON) ? intr_enable() : intr_disable();
}

enum intr_status intr_get_status()
{
    uint32_t eflags = 0;
    GET_EFLAGS(eflags);
    return (eflags & EFLAGS_IF) ? INTR_ON : INTR_OFF; 
}

编写完的syscall.c


路径lib/user/syscall.c
宏函数定义在此

#include "syscall.h"

#define _syscall0(NUMBER) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) : "memory"); retval; \
    })

#define _syscall1(NUMBER, ARG1) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) : "memory"); retval; \
    })
    
#define _syscall2(NUMBER, ARG1, ARG2) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2): "memory"); retval; \
    })

#define _syscall3(NUMBER, ARG1, ARG2, ARG3) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2), "d"(ARG3): "memory"); retval; \
    })

uint32_t getpid(void)
{
    return _syscall0(SYS_GETPID);
}

编写完的syscall.h


路径lib/user/syscall.h

#ifndef __LIB_USER_SCSCALL_H
#define __LIB_USER_SCSCALL_H
#include "stdint.h"
enum SYSCALL_NR
{
    SYS_GETPID
};

uint32_t getpid(void);

#endif

编写完的syscall-init.c


这里主要就是把syscall_table初始化了
还有函数定义了

#include "syscall-init.h"
#include "../lib/user/syscall.h"
#include "stdint.h"
#include "print.h"
#include "interrupt.h"
#include "../thread/thread.h"

#define syscall_nr 32
typedef void* syscall;
syscall syscall_table[syscall_nr];

uint32_t sys_getpid(void)
{
    return running_thread()->pid;
}

void syscall_init(void)
{
    put_str("syscall_init start\n");
    syscall_table[SYS_GETPID] = sys_getpid;
    put_str("syscall_init done\n");
}

编写后的syscall-init.h


#ifndef __USERPROG_SYSCALL_INIT_H
#define __USERPROG_SYSCALL_INIT_H
#include "stdint.h"

uint32_t sys_getpid(void);
void syscall_init(void);

#endif

修改后的thread.c


#include "thread.h"   //函数声明 各种结构体
#include "stdint.h"   //前缀
#include "string.h"   //memset
#include "global.h"   //不清楚
#include "memory.h"   //分配页需要
#include "debug.h"
#include "interrupt.h"
#include "print.h"
#include "../userprog/process.h"
#include "../thread/sync.h"

struct task_struct* main_thread;                        //主线程main_thread的pcb
struct list thread_ready_list;			  //就绪队列
struct list thread_all_list;				  //总线程队列
struct lock pid_lock;

extern void switch_to(struct task_struct* cur,struct task_struct* next);

// 获取 pcb 指针
// 这部分我可以来稍微解释一下
// 我们线程所在的esp 肯定是在 我们get得到的那一页内存 pcb页上下浮动 但是我们的pcb的最起始位置是整数的 除去后面的12位
// 那么我们对前面的取 & 则可以得到 我们的地址所在地
pid_t allocate_pid(void)
{
    static pid_t next_pid = 0;			  //约等于全局变量 全局性+可修改性
    lock_acquire(&pid_lock);
    ++next_pid;
    lock_release(&pid_lock);
    return next_pid;
}

struct task_struct* running_thread(void)
{
    uint32_t esp;
    asm ("mov %%esp,%0" : "=g"(esp));
    return (struct task_struct*)(esp & 0xfffff000);
}


void kernel_thread(thread_func* function,void* func_arg)
{
    intr_enable();					    //开中断 防止后面的时间中断被屏蔽无法切换线程
    function(func_arg);
}

void thread_create(struct task_struct* pthread,thread_func function,void* func_arg)
{
    pthread->self_kstack -= sizeof(struct intr_stack);  //减去中断栈的空间
    pthread->self_kstack -= sizeof(struct thread_stack);
    struct thread_stack* kthread_stack = (struct thread_stack*)pthread->self_kstack; 
    kthread_stack->eip = kernel_thread;                 //地址为kernel_thread 由kernel_thread 执行function
    kthread_stack->function = function;
    kthread_stack->func_arg = func_arg;
    kthread_stack->ebp = kthread_stack->ebx = kthread_stack->ebx = kthread_stack->esi = 0; //初始化一下
    return;
}

void init_thread(struct task_struct* pthread,char* name,int prio)
{
    memset(pthread,0,sizeof(*pthread)); //pcb位置清0
    strcpy(pthread->name,name);
    
    if(pthread == main_thread)
    	pthread->status = TASK_RUNNING;                              //我们的主线程肯定是在运行的
    else
    	pthread->status = TASK_READY;					//放到就绪队列里面
    	
    pthread->self_kstack = (uint32_t*)((uint32_t)pthread + PG_SIZE); //刚开始的位置是最低位置 栈顶位置+一页得最顶部
                                                                     //后面还要对这个值进行修改
    pthread->pid = allocate_pid();                                   //提前分配pid                          
    pthread->priority = prio;                                        
    pthread->ticks = prio;                                           //和特权级 相同的时间片
    pthread->elapsed_ticks = 0;
    pthread->pgdir = NULL;                                           //线程没有单独的地址
    pthread->stack_magic = 0x23333333;                               //设置的魔数 检测是否越界限
}

struct task_struct* thread_start(char* name,int prio,thread_func function,void* func_arg)
{
    struct task_struct* thread = get_kernel_pages(1);
    init_thread(thread,name,prio);
    thread_create(thread,function,func_arg);
    ASSERT(!elem_find(&thread_ready_list,&thread->general_tag));     //之前不应该在就绪队列里面
    list_append(&thread_ready_list,&thread->general_tag);
    
    ASSERT(!elem_find(&thread_all_list,&thread->all_list_tag));
    list_append(&thread_all_list,&thread->all_list_tag);
     
    return thread;
}


//之前在loader.S的时候已经 mov esp,0xc0009f00
//现在的esp已经就在预留的pcb位置上了
void make_main_thread(void)
{		
    main_thread = running_thread();					//得到main_thread 的pcb指针
    init_thread(main_thread,"main",31);				
    
    ASSERT(!elem_find(&thread_all_list,&main_thread->all_list_tag));
    list_append(&thread_all_list,&main_thread->all_list_tag);
    
}

void schedule(void)
{
    ASSERT(intr_get_status() == INTR_OFF);
    
    struct task_struct* cur = running_thread();			//得到当前pcb的地址
    if(cur->status == TASK_RUNNING)
    {
    	ASSERT(!elem_find(&thread_ready_list,&cur->general_tag));     //目前在运行的肯定ready_list是不在的
    	list_append(&thread_ready_list,&cur->general_tag);            //加入尾部
    	
    	cur->status = TASK_READY;
    	cur->ticks = cur->priority;
    }
    else
    {}
    
    ASSERT(!list_empty(&thread_ready_list));
    struct task_struct* thread_tag = list_pop(&thread_ready_list);
    //书上面的有点难理解 代码我写了一个我能理解的
    struct task_struct* next = (struct task_struct*)((uint32_t)thread_tag & 0xfffff000);
    next->status = TASK_RUNNING;
    process_activate(next);
    switch_to(cur,next);                                              //esp头顶的是 返回地址 +12是next +8是cur
}

void thread_init(void)
{
    put_str("thread_init start!\n");
    list_init(&thread_ready_list);
    list_init(&thread_all_list);
    lock_init(&pid_lock);
    make_main_thread();
    put_str("thread_init done!\n");
}

void thread_block(enum task_status stat)
{
    //设置block状态的参数必须是下面三个以下的
    ASSERT(((stat == TASK_BLOCKED) || (stat == TASK_WAITING) || stat == TASK_HANGING));
    
    enum intr_status old_status = intr_disable();			 //关中断
    struct task_struct* cur_thread = running_thread();		 
    cur_thread->status = stat;					 //把状态重新设置
    
    //调度器切换其他进程了 而且由于status不是running 不会再被放到就绪队列中
    schedule();	
    				
    //被切换回来之后再进行的指令了
    intr_set_status(old_status);
}

//由锁拥有者来执行的 善良者把原来自我阻塞的线程重新放到队列中
void thread_unblock(struct task_struct* pthread)
{
    enum intr_status old_status = intr_disable();
    ASSERT(((pthread->status == TASK_BLOCKED) || (pthread->status == TASK_WAITING) || (pthread->status == TASK_HANGING)));
    if(pthread->status != TASK_READY)
    {
    	//被阻塞线程 不应该存在于就绪队列中)
    	ASSERT(!elem_find(&thread_ready_list,&pthread->general_tag));
    	if(elem_find(&thread_ready_list,&pthread->general_tag))
    	    PANIC("thread_unblock: blocked thread in ready_list\n"); //debug.h中定义过
    	
    	//让阻塞了很久的任务放在就绪队列最前面
    	list_push(&thread_ready_list,&pthread->general_tag);
    	
    	//状态改为就绪态
    	pthread->status = TASK_READY;
    }
    intr_set_status(old_status);
}


修改后的init.c


#include "init.h"
#include "print.h"
#include "interrupt.h"
#include "../device/timer.h"
#include "memory.h"
#include "../thread/thread.h"
#include "../device/console.h"
#include "../device/keyboard.h"
#include "../userprog/tss.h"
#include "../userprog/syscall-init.h"

/*负责初始化所有模块 */
void init_all() {
   put_str("init_all\n");
   idt_init();	     // 初始化中断
   mem_init();
   timer_init();
   thread_init();
   console_init();
   keyboard_init();
   tss_init();
   syscall_init();
}

修改后的Main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"

int a=0,b=0;
void test_thread1(void* arg);
void test_thread2(void* arg);
void u_prog_a(void);
void u_prog_b(void);

int main(void) {
   put_str("I am kernel\n");
   init_all();
   process_execute(u_prog_a,"user_prog_a");
   process_execute(u_prog_b,"user_prog_b");
   intr_enable();
   
   console_put_str(" main_pid:0x");
   console_put_int(sys_getpid());
   console_put_char('\n');
   
   thread_start("kernel_thread_a",31,test_thread1," thread_A:0x");
   thread_start("kernel_thread_b",31,test_thread2," thread_B:0x");
   
   while(1);
   return 0;
}

void test_thread1(void* arg)
{
    console_put_str((char*)arg);
    console_put_int(getpid());
    console_put_char('\n');
    console_put_str(" u_prog_a:0x");
    console_put_int(a);
    console_put_char('\n');
    while(1);
}

void test_thread2(void* arg)
{
    console_put_str((char*)arg);
    console_put_int(getpid());
    console_put_char('\n');
    console_put_str(" u_prog_b:0x");
    console_put_int(b);
    console_put_char('\n');
    while(1);
}

void u_prog_a(void)
{
    a = getpid();
    while(1);
}

void u_prog_b(void)
{
    b = getpid();
    while(1);
}

修改后的makefile


BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/ 
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
      $(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o \
      $(BUILD_DIR)/ioqueue.o $(BUILD_DIR)/tss.o $(BUILD_DIR)/process.o \
      $(BUILD_DIR)/syscall-init.o $(BUILD_DIR)/syscall.o
      
##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
        thread/thread.h kernel/interrupt.h device/console.h \
        device/keyboard.h device/ioqueue.h userprog/process.h \
        lib/user/syscall.h userprog/syscall-init.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
        lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
        thread/thread.h device/console.h device/keyboard.h userprog/tss.h \
        userprog/syscall-init.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
        lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h \
        kernel/kernel.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
        kernel/interrupt.h thread/thread.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
        lib/kernel/print.h lib/stdint.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
	lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h \
	thread/sync.h thread/thread.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
	lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
	kernel/debug.h kernel/interrupt.h lib/kernel/print.h \
	userprog/process.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
	kernel/interrupt.h lib/stdint.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
	lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/console.o: device/console.c device/console.h \
	lib/kernel/print.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \
	lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \
	kernel/global.h lib/stdint.h device/ioqueue.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h \
	kernel/interrupt.h kernel/global.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/tss.o: userprog/tss.c userprog/tss.h \
	kernel/global.h thread/thread.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/process.o: userprog/process.c userprog/process.h \
	lib/string.h kernel/global.h kernel/memory.h lib/kernel/print.h \
	thread/thread.h kernel/interrupt.h kernel/debug.h device/console.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/syscall-init.o: userprog/syscall-init.c userprog/syscall-init.h \
	lib/user/syscall.h lib/stdint.h lib/kernel/print.h kernel/interrupt.h thread/thread.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/syscall.o: lib/user/syscall.c lib/user/syscall.h 
	$(CC) $(CFLAGS) $< -o $@
	
##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
	$(AS) $(ASFLAGS) $< -o $@

##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
	$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
	dd if=$(BUILD_DIR)/kernel.bin \
           of=/home/cooiboi/bochs/hd60M.img \
           bs=512 count=200 seek=9 conv=notrunc

clean:
	cd $(BUILD_DIR) && rm -f  ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

make all 验收成果


哈哈 每次验收成果的时候 都是这个小标题
当然每次都不知道调试过多少次了 再来写这个博客

后面会留下一个小问题 哈哈 当时人几乎要崩溃了 发现有问题 后面才醒悟过来 后面再写
看下面的效果应该是ok了 后面会有一个小问题在这里插入图片描述


为什么进程里面不允许console_put_str


这个问题其实当时几乎让我崩溃
哈哈哈 如果进程里面放了console_put_str的话 可以试一下 一定会报错
例如下面的 我就加了一句

void u_prog_a(void)
{
    a = getpid();
    console_put_str("go!\n");
    while(1);
}

最后的运行效果
在这里插入图片描述
其实没什么好神秘 如果你还不知道答案的话 说明可能之前做进程部分有点点水 哈哈
就是那个时候 我们设置了gs == 0 相当于进程是不允许访问显存的 还记得吗 哈哈 就是这个样子 一切都make sense


实现简易write


哈哈 超级简易 没有什么好说的 直接给代码吧


修改后的syscall-init.c


#include "syscall-init.h"
#include "../lib/user/syscall.h"
#include "stdint.h"
#include "print.h"
#include "interrupt.h"
#include "../thread/thread.h"

#define syscall_nr 32
typedef void* syscall;
syscall syscall_table[syscall_nr];

uint32_t sys_getpid(void)
{
    return running_thread()->pid;
}

void sys_write(char* str)
{
    console_put_str(str);
}

void syscall_init(void)
{
    put_str("syscall_init start\n");
    syscall_table[SYS_GETPID] = sys_getpid;
    syscall_table[SYS_WRITE]  = sys_write;
    put_str("syscall_init done\n");
}

修改后的syscall-init.h


#ifndef __USERPROG_SYSCALL_INIT_H
#define __USERPROG_SYSCALL_INIT_H
#include "stdint.h"

uint32_t sys_getpid(void);
void sys_write(char* str);
void syscall_init(void);

#endif

修改后的syscall.c


#include "syscall.h"

#define _syscall0(NUMBER) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) : "memory"); retval; \
    })

#define _syscall1(NUMBER, ARG1) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) : "memory"); retval; \
    })
    
#define _syscall2(NUMBER, ARG1, ARG2) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2): "memory"); retval; \
    })

#define _syscall3(NUMBER, ARG1, ARG2, ARG3) ({ \
    int retval;		\
    asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2), "d"(ARG3): "memory"); retval; \
    })

uint32_t getpid(void)
{
    return _syscall0(SYS_GETPID);
}

void write(char* str)
{
    return _syscall1(SYS_WRITE,str);
}

修改后的syscall.h


#ifndef __LIB_USER_SCSCALL_H
#define __LIB_USER_SCSCALL_H
#include "stdint.h"
enum SYSCALL_NR
{
    SYS_GETPID,
    SYS_WRITE
};

uint32_t getpid(void);
void write(char* str);

#endif

实现printf


哈哈 这部分挺有趣的 只是因为下午自己懒了一下 跟别人聊了一个小时的天 然后跟同学语音打了两个小时 导致今日份的任务没做完 晚饭还没吃 晕 待会把这部分博客写了 下楼买泡面了 看一下还开没开门

对于这部分的指针问题 我也已经很详细的写了注释了 看不懂为什么有的时候要取& 我只能说 比如int a = 8 为了在其他函数改变a的值 不改变形参 我们都会用int*传导 然后通过*a = 6来改变 很多地方就是同理 ok


编写后的stdio.c


路径lib/stdio.c

#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "syscall.h"

#define va_start(ap,v) ap = (va_list)&v          //这里把第一个char*地址赋给ap 强制转换一下
#define va_arg(ap,t)   *((t*)(ap +=4))	   //强制类型转换 得到栈中参数
#define va_end(ap)	ap = NULL   

void itoa(uint32_t value,char** buf_ptr_addr,uint8_t base)//这里有理解的 为了修改一级指针的值 再取一次& 即可修改一级指针本身的值
{
    uint32_t m = value % base;
    uint32_t i = value / base;  //除数为0即最高位了 输出即可 没到零继续即可
    if(i)
    	itoa(i,buf_ptr_addr,base);
    if(m < 10)                  //m小于10的数
    	*((*buf_ptr_addr)++) = m + '0';
    else			 //m大于10的数
    	*((*buf_ptr_addr)++) = m + 'A' - 10;
}

uint32_t vsprintf(char* str,const char* format,va_list ap)
{
    char* buf_ptr = str;
    const char* index_ptr = format;
    char index_char = *index_ptr;
    int32_t arg_int;
    char* arg_str;
    while(index_char)		//挨个挨个字符来弄
    {
    	if(index_char != '%')
    	{
    	    *(buf_ptr++) = index_char;
    	    index_char = *(++index_ptr);
    	    continue;
    	}
    	index_char = *(++index_ptr);
    	switch(index_char)
    	{
    	    case 's':
    	    	arg_str = va_arg(ap,char*);
    	    	strcpy(buf_ptr,arg_str);
    	    	buf_ptr += strlen(arg_str);
    	    	index_char = *(++index_ptr);
    	    	break;
    	    case 'x':
    	    	arg_int = va_arg(ap,int);
    	    	itoa(arg_int,&buf_ptr,16);
    	    	index_char = *(++index_ptr);
    	    	break;
    	    case 'd':
    	    	arg_int = va_arg(ap,int);
    	    	if(arg_int < 0)
    	    	{
    	    	    arg_int = 0 - arg_int;
    	    	    *(buf_ptr++) = '-';
    	    	}
    	    	itoa(arg_int,&buf_ptr,10);
    	    	index_char = *(++index_ptr);
    	    	break;
    	    case 'c':
    	    	*(buf_ptr++) = va_arg(ap,char);
    	    	index_char = *(++index_ptr);
    	}
    }
    return strlen(str);
}

uint32_t printf(const char* format, ...)
{
    va_list args;
    uint32_t retval;
    va_start(args,format);		//args指向char* 的指针 方便指向下一个栈参数
    char buf[1024] = {0};
    retval = vsprintf(buf,format,args);
    va_end(args);
    write(buf);
    return retval;
}

编写后的stdio.h


#ifndef __LIB__STDIO_H
#define __LIB__STDIO_H
#include "stdint.h"

typedef void* va_list;
void itoa(uint32_t value,char** buf_ptr_addr,uint8_t base);
uint32_t vsprintf(char* str,const char* format,va_list ap);
uint32_t printf(const char* format, ...);

#endif

修改后的makefile


BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/ 
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
      $(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o \
      $(BUILD_DIR)/ioqueue.o $(BUILD_DIR)/tss.o $(BUILD_DIR)/process.o \
      $(BUILD_DIR)/syscall-init.o $(BUILD_DIR)/syscall.o $(BUILD_DIR)/stdio.o
      
##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
        thread/thread.h kernel/interrupt.h device/console.h \
        device/keyboard.h device/ioqueue.h userprog/process.h \
        lib/user/syscall.h userprog/syscall-init.h lib/stdio.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
        lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
        thread/thread.h device/console.h device/keyboard.h userprog/tss.h \
        userprog/syscall-init.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
        lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h \
        kernel/kernel.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
        kernel/interrupt.h thread/thread.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
        lib/kernel/print.h lib/stdint.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
	lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h \
	thread/sync.h thread/thread.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
	lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
	kernel/debug.h kernel/interrupt.h lib/kernel/print.h \
	userprog/process.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
	kernel/interrupt.h lib/stdint.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
	lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/console.o: device/console.c device/console.h \
	lib/kernel/print.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \
	lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \
	kernel/global.h lib/stdint.h device/ioqueue.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h \
	kernel/interrupt.h kernel/global.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/tss.o: userprog/tss.c userprog/tss.h \
	kernel/global.h thread/thread.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/process.o: userprog/process.c userprog/process.h \
	lib/string.h kernel/global.h kernel/memory.h lib/kernel/print.h \
	thread/thread.h kernel/interrupt.h kernel/debug.h device/console.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/syscall-init.o: userprog/syscall-init.c userprog/syscall-init.h \
	lib/user/syscall.h lib/stdint.h lib/kernel/print.h kernel/interrupt.h thread/thread.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/syscall.o: lib/user/syscall.c lib/user/syscall.h 
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/stdio.o: lib/stdio.c lib/stdio.h lib/stdint.h lib/string.h lib/user/syscall.h
	$(CC) $(CFLAGS) $< -o $@
	
##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
	$(AS) $(ASFLAGS) $< -o $@

##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
	$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
	dd if=$(BUILD_DIR)/kernel.bin \
           of=/home/cooiboi/bochs/hd60M.img \
           bs=512 count=200 seek=9 conv=notrunc

clean:
	cd $(BUILD_DIR) && rm -f  ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

修改后的main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"

int a=0,b=0;
void test_thread1(void* arg);
void test_thread2(void* arg);
void u_prog_a(void);
void u_prog_b(void);

int main(void) {
   put_str("I am kernel\n");
   init_all();
   process_execute(u_prog_a,"user_prog_a");
   process_execute(u_prog_b,"user_prog_b");
   intr_enable();
   console_put_str(" i am main:0x");
   printf("%x",getpid());
   console_put_char('\n');
   thread_start("kernel_thread_a",31,test_thread1," i am thread_A:0x");
   thread_start("kernel_thread_b",31,test_thread2," i am thread_B:0x");
   
   while(1);
   return 0;
}

void test_thread1(void* arg)
{
    console_put_str((char*)arg);
    printf("%x",getpid());
    console_put_char('\n');
    while(1);
}

void test_thread2(void* arg)
{
    console_put_str((char*)arg);
    printf("%x",getpid());
    console_put_char('\n');
    while(1);
}

void u_prog_a(void)
{
    printf(" i am %s prog_a_pid:%d%c","prog_a",getpid(),'\n');
    while(1);
}

void u_prog_b(void)
{
    printf(" i am %s prog_b_pid:%d%c","prog_b",getpid(),'\n');
    while(1);
}

make all 验收成果


老套路了哈 这里ok了 家人们
此时心里面有没有疑惑 为什么上面说 线程不能输出字符 现在可以了哈哈
因为这里是调用的write中断 进入了中断之后才行的 之后进入内核空间再调用的 console_put_str ok 下楼买泡面去了
在这里插入图片描述


晚餐时间


晒点晚餐 哈哈 买完回来之后吃了桶泡面就匆匆上床了 之后的内容只能明天再做了
在这里插入图片描述


实现堆内存管理(实现malloc部分)


这部分呢 哈哈 说实话 其实我觉得各位看官把代码看懂就行了
虽然我还是从上到下挨个代码一行行的看完理解完了 把malloc实现了再过来写的 但是呢 哈哈 这部分真从头让我写 确实写不出来

构局的缜密 而且各种小细节 哈哈 果然还是积聚了很多很多人的智慧写出来的操作系统 不容易啊 不容易 为了局部性和连贯性考虑 我还是一部分一部分的放 就先放实现malloc当前的代码吧 很多地方呢 我还是加了注释 那就走起


修改完的memory.h


#ifndef __KERNEL_MEMORY_H
#define __KERNEL_MEMORY_H
#include "stdint.h"
#include "bitmap.h"
#include "list.h"

struct virtual_addr
{
    struct bitmap vaddr_bitmap;
    uint32_t vaddr_start;
};

enum pool_flags
{
    PF_KERNEL = 1,
    PF_USER = 2
};

struct mem_block
{
    struct list_elem free_elem;
};

struct mem_block_desc
{
    uint32_t block_size;
    uint32_t block_per_arena;
    struct list free_list;	
};

struct arena
{
    struct mem_block_desc* desc;
    uint32_t cnt;
    bool large; 
};

#define PG_P_1 1
#define PG_P_0 0
#define PG_RW_R 0
#define PG_RW_W 2
#define PG_US_S 0
#define PG_US_U 4

#define DESC_CNT      7

extern struct pool kernel_pool,user_pool;
void* vaddr_get(enum pool_flags pf,uint32_t pg_cnt);
uint32_t* pte_ptr(uint32_t vaddr);
uint32_t* pde_ptr(uint32_t vaddr);
void* palloc(struct pool* m_pool);
void page_table_add(void* _vaddr,void* _page_phyaddr);
void* malloc_page(enum pool_flags pf,uint32_t pg_cnt);
void* get_kernel_pages(uint32_t pg_cnt);
void* get_user_pages(uint32_t pg_cnt);
void* get_a_page(enum pool_flags pf,uint32_t vaddr);
uint32_t addr_v2p(uint32_t vaddr);
void mem_pool_init(uint32_t all_mem);
void mem_init(void);
void block_desc_init(struct mem_block_desc* desc_array);
struct mem_block* arena2block(struct arena* a,uint32_t idx);
struct arena* block2arena(struct mem_block* b);
void* sys_malloc(uint32_t size);
#endif

修改完的memory.c


#include "memory.h"
#include "stdint.h"
#include "print.h"
#include "bitmap.h"
#include "debug.h"
#include "string.h"
#include "global.h"
#include "../thread/sync.h"
#include "../thread/thread.h"
#include "../lib/kernel/list.h"
#include "interrupt.h"

#define PG_SIZE 4096
#define MEM_BITMAP_BASE 0Xc009a000   //位图开始存放的位置
#define K_HEAP_START    0xc0100000   //内核栈起始位置
#define PDE_IDX(addr) ((addr & 0xffc00000) >> 22)
#define PTE_IDX(addr) ((addr & 0x003ff000) >> 12)

struct pool
{
    struct bitmap pool_bitmap; //位图来管理内存使用
    uint32_t phy_addr_start;   //内存池开始的起始地址
    uint32_t pool_size;	//池容量
    struct lock lock;
};
struct mem_block_desc k_block_descs[DESC_CNT]; //内核内存块描述符数组

struct pool kernel_pool ,user_pool; //生成内核内存池 和 用户内存池
struct virtual_addr kernel_vaddr;    //内核虚拟内存管理池

void* vaddr_get(enum pool_flags pf,uint32_t pg_cnt)
{
    int vaddr_start = 0,bit_idx_start = -1;
    uint32_t cnt = 0;
    if(pf == PF_KERNEL)
    {
    	bit_idx_start = bitmap_scan(&kernel_vaddr.vaddr_bitmap,pg_cnt);
    	if(bit_idx_start == -1)	return NULL;
    	while(cnt < pg_cnt)
    	    bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),1);
    	vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
    }
    else
    {
    	struct task_struct* cur = running_thread();
    	bit_idx_start = bitmap_scan(&cur->userprog_vaddr.vaddr_bitmap,pg_cnt);
    	if(bit_idx_start == -1)	return NULL;
    	
    	while(cnt < pg_cnt)
    	    bitmap_set(&cur->userprog_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),1);
    	vaddr_start = cur->userprog_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
    	ASSERT((uint32_t)vaddr_start < (0xc0000000 - PG_SIZE));
    }
    return (void*)vaddr_start;
}

uint32_t* pte_ptr(uint32_t vaddr)
{
    uint32_t* pte = (uint32_t*)(0xffc00000 + ((vaddr & 0xffc00000) >> 10) + PTE_IDX(vaddr) * 4);
    return pte;
}

uint32_t* pde_ptr(uint32_t vaddr)
{
    uint32_t* pde = (uint32_t*) ((0xfffff000) + PDE_IDX(vaddr) * 4);
    return pde;
}

void* palloc(struct pool* m_pool)
{
    int bit_idx = bitmap_scan(&m_pool->pool_bitmap,1);
    if(bit_idx == -1)	return NULL;
    bitmap_set(&m_pool->pool_bitmap,bit_idx,1);
    uint32_t page_phyaddr = ((bit_idx * PG_SIZE) + m_pool->phy_addr_start);
    return (void*)page_phyaddr;
}

void page_table_add(void* _vaddr,void* _page_phyaddr)
{
    uint32_t vaddr = (uint32_t)_vaddr,page_phyaddr = (uint32_t)_page_phyaddr;
    uint32_t* pde = pde_ptr(vaddr);
    uint32_t* pte = pte_ptr(vaddr);
    
    if(*pde & 0x00000001)
    {
    	ASSERT(!(*pte & 0x00000001));
    	if(!(*pte & 0x00000001))
    	    *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	else
    	{
    	    PANIC("pte repeat");
    	    *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	}
    } 
    else
    {
    	uint32_t pde_phyaddr = (uint32_t)palloc(&kernel_pool);
    	*pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	memset((void*)((int)pte & 0xfffff000),0,PG_SIZE);
    	ASSERT(!(*pte & 0x00000001));
    	*pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    }
    return;
}

void* malloc_page(enum pool_flags pf,uint32_t pg_cnt)
{
    ASSERT(pg_cnt > 0 && pg_cnt < 3840);
    
    void* vaddr_start = vaddr_get(pf,pg_cnt);
    if(vaddr_start == NULL)	return NULL;
    
    
    uint32_t vaddr = (uint32_t)vaddr_start,cnt = pg_cnt;
    struct pool* mem_pool = pf & PF_KERNEL ? &kernel_pool : &user_pool;
    
    while(cnt-- > 0)
    {
    	void* page_phyaddr = palloc(mem_pool);
    	if(page_phyaddr == NULL)	return NULL;
    	page_table_add((void*)vaddr,page_phyaddr);
    	vaddr += PG_SIZE;
    }
    return vaddr_start;
}

void* get_kernel_pages(uint32_t pg_cnt)
{
    void* vaddr = malloc_page(PF_KERNEL,pg_cnt);
    if(vaddr != NULL)	memset(vaddr,0,pg_cnt*PG_SIZE);
    return vaddr;
}

void* get_user_pages(uint32_t pg_cnt)
{
    lock_acquire(&user_pool.lock);	//用户进程可能会产生冲突 大部分时间都在用户进程 内核进程可以理解基本不会冲突
    void* vaddr = malloc_page(PF_USER,pg_cnt);
    if(vaddr != NULL)	memset(vaddr,0,pg_cnt*PG_SIZE);
    lock_release(&user_pool.lock);
    return vaddr;
}

void* get_a_page(enum pool_flags pf,uint32_t vaddr)
{
    struct pool* mem_pool = (pf == PF_KERNEL) ? &kernel_pool : &user_pool;
    lock_acquire(&mem_pool->lock);
    
    struct task_struct* cur = running_thread();
    int32_t bit_idx = -1;
    
    //虚拟地址位图置1
    if(cur->pgdir != NULL && pf == PF_USER)
    {
    	bit_idx = (vaddr - cur->userprog_vaddr.vaddr_start) / PG_SIZE;
    	ASSERT(bit_idx > 0);
    	bitmap_set(&cur->userprog_vaddr.vaddr_bitmap,bit_idx,1);
    }
    else if(cur->pgdir == NULL && pf == PF_KERNEL) 
    {
    	bit_idx = (vaddr - cur->userprog_vaddr.vaddr_start) / PG_SIZE;
    	ASSERT(bit_idx > 0);
    	bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx,1);
    }
    else
    	PANIC("get_a_page:not allow kernel alloc userspace or user alloc kernelspace by get_a_page");
    	
    void* page_phyaddr = palloc(mem_pool);
    if(page_phyaddr == NULL)
    	return NULL;
    page_table_add((void*)vaddr,page_phyaddr);
    lock_release(&mem_pool->lock);
    return (void*)vaddr;
}

/* 得到虚拟地址映射的物理地址 */
uint32_t addr_v2p(uint32_t vaddr)
{
    uint32_t* pte = pte_ptr(vaddr);
    return ((*pte & 0xfffff000) + (vaddr & 0x00000fff));
}

void mem_pool_init(uint32_t all_mem)
{
    put_str("    mem_pool_init start!\n");
    uint32_t page_table_size = PG_SIZE * 256;       //页表占用的大小
    uint32_t used_mem = page_table_size + 0x100000; //低端1MB的内存 + 页表所占用的大小
    uint32_t free_mem = all_mem - used_mem;
    
    uint16_t all_free_pages = free_mem / PG_SIZE;   //空余的页数 = 总空余内存 / 一页的大小
    
    uint16_t kernel_free_pages = all_free_pages /2; //内核 与 用户 各平分剩余内存
    uint16_t user_free_pages = all_free_pages - kernel_free_pages; //万一是奇数 就会少1 减去即可
    
    //kbm kernel_bitmap ubm user_bitmap
    uint32_t kbm_length = kernel_free_pages / 8;    //一位即可表示一页 8位一个数
    uint32_t ubm_length = user_free_pages / 8;
    
    //kp kernel_pool up user_pool
    uint32_t kp_start = used_mem;
    uint32_t up_start = kp_start + kernel_free_pages * PG_SIZE;
    
    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.bits = (void*)MEM_BITMAP_BASE;
    user_pool.pool_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length);
    
    kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
    user_pool.pool_bitmap.btmp_bytes_len = ubm_length; 
    
    put_str("        kernel_pool_bitmap_start:");
    put_int((int)kernel_pool.pool_bitmap.bits);
    put_str(" kernel_pool_phy_addr_start:");
    put_int(kernel_pool.phy_addr_start);
    put_char('\n');
    put_str("        user_pool_bitmap_start:");
    put_int((int)user_pool.pool_bitmap.bits);
    put_str(" user_pool_phy_addr_start:");
    put_int(user_pool.phy_addr_start);
    put_char('\n');
    
    bitmap_init(&kernel_pool.pool_bitmap);
    bitmap_init(&user_pool.pool_bitmap);
    
    kernel_vaddr.vaddr_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length + ubm_length);
    kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length;
    
    kernel_vaddr.vaddr_start = K_HEAP_START;
    bitmap_init(&kernel_vaddr.vaddr_bitmap);
    lock_init(&kernel_pool.lock);
    lock_init(&user_pool.lock);
    put_str("    mem_pool_init done\n");
    return;
}

void block_desc_init(struct mem_block_desc* desc_array)
{
    uint16_t desc_idx,block_size = 16;
    for(desc_idx = 0;desc_idx < DESC_CNT;desc_idx++)
    {
    	desc_array[desc_idx].block_size = block_size;
    	desc_array[desc_idx].block_per_arena = (PG_SIZE - sizeof(struct arena)) / block_size;
    	list_init(&desc_array[desc_idx].free_list);
    	block_size *= 2;
    }   
}

void mem_init()
{
    put_str("mem_init start!\n");
    uint32_t mem_bytes_total = (*(uint32_t*)(0x800)); //我们把总内存的值放在了0x800 我之前为了显示比较独特 放在了0x800处了
    mem_pool_init(mem_bytes_total);
    block_desc_init(k_block_descs);
    put_str("mem_init done!\n");
    return;
}

//返回idx个内存块的地址 空间布局为 arena元信息+n个内存块
struct mem_block* arena2block(struct arena* a,uint32_t idx)
{
    return (struct mem_block*)((uint32_t)a + sizeof(struct arena) + idx * a->desc->block_size);
}

//自然页框的最低点处
struct arena* block2arena(struct mem_block* b)
{
    return (struct arena*)((uint32_t)b & 0xfffff000);
}

void* sys_malloc(uint32_t size)
{
    enum pool_flags PF;
    struct pool* mem_pool;
    uint32_t pool_size;
    struct mem_block_desc* descs;
    struct task_struct* cur_thread = running_thread();
    
    if(cur_thread->pgdir == NULL)
    {
    	PF = PF_KERNEL;
    	pool_size = kernel_pool.pool_size;
    	mem_pool = &kernel_pool;
    	descs = k_block_descs;
    }
    else
    {
    	PF = PF_USER;
    	pool_size = user_pool.pool_size;
    	mem_pool = &user_pool;
    	descs = cur_thread->u_block_desc;
    }
    //size 超出空间大小或者为 0 负数
    if(!(size > 0 && size < pool_size))
    {
    	return NULL;
    }
    
    struct arena* a;
    struct mem_block* b;
    lock_acquire(&mem_pool->lock);
    
    //超过页框直接分配页框
    if(size > 1024)
    {
    	uint32_t page_cnt = DIV_ROUND_UP(size + sizeof(struct arena),PG_SIZE);
    	a = malloc_page(PF,page_cnt);
    	if(a != NULL)
    	{
    	    memset(a,0,page_cnt * PG_SIZE);
	    a->desc = NULL;
	    a->cnt  = page_cnt;
	    a->large = true;    
	    lock_release(&mem_pool->lock);
	    return (void*)(a+1); //返回地址 struct arena + sizeof(struct arena)
	}
	else
	{
	    lock_release(&mem_pool->lock);
	    return NULL;
	}
    }
    else
    {
    	uint8_t desc_idx;
    	for(desc_idx = 0;desc_idx < DESC_CNT;desc_idx++)
    	{
    	    if(size <= descs[desc_idx].block_size)
    	    {
    	    	break;
    	    }
    	}
    	
    	//已经空了
    	if(list_empty(&descs[desc_idx].free_list))
    	{
    	    a = malloc_page(PF,1);
    	    if(a == NULL)
    	    {
    	    	lock_release(&mem_pool->lock);
    	    	return NULL;
    	    }
    	    memset(a,0,PG_SIZE);
    	    
    	    a->desc = &descs[desc_idx];
    	    a->large = false;
    	    a->cnt = descs[desc_idx].block_per_arena;
    	    uint32_t block_idx;
    	    
    	    enum intr_status old_status = intr_disable();
    	    
    	    for(block_idx = 0;block_idx < descs[desc_idx].block_per_arena;++block_idx)
    	    {
    	    	b = arena2block(a,block_idx);
    	    	ASSERT(!elem_find(&a->desc->free_list,&b->free_elem));
    	    	list_append(&a->desc->free_list,&b->free_elem);
    	    }
    	    intr_set_status(old_status);
    	}
    	
    	b = (struct mem_block*)list_pop(&(descs[desc_idx].free_list));
    	memset(b,0,descs[desc_idx].block_size);
    	
    	a = block2arena(b);
    	--a->cnt;
    	lock_release(&mem_pool->lock);
    	return (void*)b;
    }
}

修改完的thread.c(task_struct部分)


struct task_struct
{
    uint32_t* self_kstack;                          //pcb中的 kernel_stack 内核栈
    pid_t pid;
    enum task_status status;                        //线程状态
    uint8_t priority;				      //特权级
    uint8_t ticks;				      //在cpu 运行的滴答数 看ticks 来判断是否用完了时间片
    uint32_t elapsed_ticks;                         //一共执行了多久
    char name[16];
    
    struct list_elem general_tag;                   //就绪队列中的连接节点
    struct list_elem all_list_tag;		      //总队列的连接节点
    
    uint32_t* pgdir;				      //进程自己页表的虚拟地址 线程没有   
    struct virtual_addr userprog_vaddr;	      //用户进程的虚拟空间               
    struct mem_block_desc u_block_desc[DESC_CNT];   //内存块描述符
    uint32_t stack_magic;			      //越界检查  因为我们pcb上面的就是我们要用的栈了 到时候还要越界检查
};

修改完的process.c(process_execute函数)


需要增加加头文件 我直接把头文件全放出来

#include "tss.h"
#include "process.h"
#include "string.h"
#include "global.h"
#include "memory.h"
#include "print.h"
#include "../thread/thread.h"
#include "../kernel/interrupt.h"
#include "debug.h"
#include "../device/console.h"
void process_execute(void* filename,char* name)
{
    struct task_struct* thread = get_kernel_pages(1);  //分配一页空间 得到pcb
    init_thread(thread,name,default_prio);		 //初始化pcb
    create_user_vaddr_bitmap(thread);			 //为虚拟地址位图初始化 分配空间
    thread_create(thread,start_process,filename);	 //创造线程 start_process 之后通过start_process intr_exit跳转到用户进程
    thread->pgdir = create_page_dir();		 //把页目录表的地址分配了 并且把内核的页目录都给复制过去 这样操作系统对每个进程都可见
    block_desc_init(thread->u_block_desc);
    
    enum intr_status old_status = intr_disable();     
    ASSERT(!elem_find(&thread_ready_list,&thread->general_tag));
    list_append(&thread_ready_list,&thread->general_tag);     //添加线程 start_process到就绪队列中
    
    ASSERT(!elem_find(&thread_all_list,&thread->all_list_tag));
    list_append(&thread_all_list,&thread->all_list_tag);
    intr_set_status(old_status);
}

修改完的memory.c


#include "memory.h"
#include "stdint.h"
#include "print.h"
#include "bitmap.h"
#include "debug.h"
#include "string.h"
#include "global.h"
#include "../thread/sync.h"
#include "../thread/thread.h"
#include "../lib/kernel/list.h"
#include "interrupt.h"

#define PG_SIZE 4096
#define MEM_BITMAP_BASE 0Xc009a000   //位图开始存放的位置
#define K_HEAP_START    0xc0100000   //内核栈起始位置
#define PDE_IDX(addr) ((addr & 0xffc00000) >> 22)
#define PTE_IDX(addr) ((addr & 0x003ff000) >> 12)

struct pool
{
    struct bitmap pool_bitmap; //位图来管理内存使用
    uint32_t phy_addr_start;   //内存池开始的起始地址
    uint32_t pool_size;	//池容量
    struct lock lock;
};
struct mem_block_desc k_block_descs[DESC_CNT]; //内核内存块描述符数组

struct pool kernel_pool ,user_pool; //生成内核内存池 和 用户内存池
struct virtual_addr kernel_vaddr;    //内核虚拟内存管理池

void* vaddr_get(enum pool_flags pf,uint32_t pg_cnt)
{
    int vaddr_start = 0,bit_idx_start = -1;
    uint32_t cnt = 0;
    if(pf == PF_KERNEL)
    {
    	bit_idx_start = bitmap_scan(&kernel_vaddr.vaddr_bitmap,pg_cnt);
    	if(bit_idx_start == -1)	return NULL;
    	while(cnt < pg_cnt)
    	    bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),1);
    	vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
    }
    else
    {
    	struct task_struct* cur = running_thread();
    	bit_idx_start = bitmap_scan(&cur->userprog_vaddr.vaddr_bitmap,pg_cnt);
    	if(bit_idx_start == -1)	return NULL;
    	
    	while(cnt < pg_cnt)
    	    bitmap_set(&cur->userprog_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),1);
    	vaddr_start = cur->userprog_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
    	ASSERT((uint32_t)vaddr_start < (0xc0000000 - PG_SIZE));
    }
    return (void*)vaddr_start;
}

uint32_t* pte_ptr(uint32_t vaddr)
{
    uint32_t* pte = (uint32_t*)(0xffc00000 + ((vaddr & 0xffc00000) >> 10) + PTE_IDX(vaddr) * 4);
    return pte;
}

uint32_t* pde_ptr(uint32_t vaddr)
{
    uint32_t* pde = (uint32_t*) ((0xfffff000) + PDE_IDX(vaddr) * 4);
    return pde;
}

void* palloc(struct pool* m_pool)
{
    int bit_idx = bitmap_scan(&m_pool->pool_bitmap,1);
    if(bit_idx == -1)	return NULL;
    bitmap_set(&m_pool->pool_bitmap,bit_idx,1);
    uint32_t page_phyaddr = ((bit_idx * PG_SIZE) + m_pool->phy_addr_start);
    return (void*)page_phyaddr;
}

void page_table_add(void* _vaddr,void* _page_phyaddr)
{
    uint32_t vaddr = (uint32_t)_vaddr,page_phyaddr = (uint32_t)_page_phyaddr;
    uint32_t* pde = pde_ptr(vaddr);
    uint32_t* pte = pte_ptr(vaddr);
    
    if(*pde & 0x00000001)
    {
    	ASSERT(!(*pte & 0x00000001));
    	if(!(*pte & 0x00000001))
    	    *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	else
    	{
    	    PANIC("pte repeat");
    	    *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	}
    } 
    else
    {
    	uint32_t pde_phyaddr = (uint32_t)palloc(&kernel_pool);
    	*pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	memset((void*)((int)pte & 0xfffff000),0,PG_SIZE);
    	ASSERT(!(*pte & 0x00000001));
    	*pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    }
    return;
}

void* malloc_page(enum pool_flags pf,uint32_t pg_cnt)
{
    ASSERT(pg_cnt > 0 && pg_cnt < 3840);
    
    void* vaddr_start = vaddr_get(pf,pg_cnt);
    if(vaddr_start == NULL)	return NULL;
    
    
    uint32_t vaddr = (uint32_t)vaddr_start,cnt = pg_cnt;
    struct pool* mem_pool = pf & PF_KERNEL ? &kernel_pool : &user_pool;
    
    while(cnt-- > 0)
    {
    	void* page_phyaddr = palloc(mem_pool);
    	if(page_phyaddr == NULL)	return NULL;
    	page_table_add((void*)vaddr,page_phyaddr);
    	vaddr += PG_SIZE;
    }
    return vaddr_start;
}

void* get_kernel_pages(uint32_t pg_cnt)
{
    void* vaddr = malloc_page(PF_KERNEL,pg_cnt);
    if(vaddr != NULL)	memset(vaddr,0,pg_cnt*PG_SIZE);
    return vaddr;
}

void* get_user_pages(uint32_t pg_cnt)
{
    lock_acquire(&user_pool.lock);	//用户进程可能会产生冲突 大部分时间都在用户进程 内核进程可以理解基本不会冲突
    void* vaddr = malloc_page(PF_USER,pg_cnt);
    if(vaddr != NULL)	memset(vaddr,0,pg_cnt*PG_SIZE);
    lock_release(&user_pool.lock);
    return vaddr;
}

void* get_a_page(enum pool_flags pf,uint32_t vaddr)
{
    struct pool* mem_pool = (pf == PF_KERNEL) ? &kernel_pool : &user_pool;
    lock_acquire(&mem_pool->lock);
    
    struct task_struct* cur = running_thread();
    int32_t bit_idx = -1;
    
    //虚拟地址位图置1
    if(cur->pgdir != NULL && pf == PF_USER)
    {
    	bit_idx = (vaddr - cur->userprog_vaddr.vaddr_start) / PG_SIZE;
    	ASSERT(bit_idx > 0);
    	bitmap_set(&cur->userprog_vaddr.vaddr_bitmap,bit_idx,1);
    }
    else if(cur->pgdir == NULL && pf == PF_KERNEL) 
    {
    	bit_idx = (vaddr - cur->userprog_vaddr.vaddr_start) / PG_SIZE;
    	ASSERT(bit_idx > 0);
    	bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx,1);
    }
    else
    	PANIC("get_a_page:not allow kernel alloc userspace or user alloc kernelspace by get_a_page");
    	
    void* page_phyaddr = palloc(mem_pool);
    if(page_phyaddr == NULL)
    	return NULL;
    page_table_add((void*)vaddr,page_phyaddr);
    lock_release(&mem_pool->lock);
    return (void*)vaddr;
}

/* 得到虚拟地址映射的物理地址 */
uint32_t addr_v2p(uint32_t vaddr)
{
    uint32_t* pte = pte_ptr(vaddr);
    return ((*pte & 0xfffff000) + (vaddr & 0x00000fff));
}

void mem_pool_init(uint32_t all_mem)
{
    put_str("    mem_pool_init start!\n");
    uint32_t page_table_size = PG_SIZE * 256;       //页表占用的大小
    uint32_t used_mem = page_table_size + 0x100000; //低端1MB的内存 + 页表所占用的大小
    uint32_t free_mem = all_mem - used_mem;
    
    uint16_t all_free_pages = free_mem / PG_SIZE;   //空余的页数 = 总空余内存 / 一页的大小
    
    uint16_t kernel_free_pages = all_free_pages /2; //内核 与 用户 各平分剩余内存
    uint16_t user_free_pages = all_free_pages - kernel_free_pages; //万一是奇数 就会少1 减去即可
    
    //kbm kernel_bitmap ubm user_bitmap
    uint32_t kbm_length = kernel_free_pages / 8;    //一位即可表示一页 8位一个数
    uint32_t ubm_length = user_free_pages / 8;
    
    //kp kernel_pool up user_pool
    uint32_t kp_start = used_mem;
    uint32_t up_start = kp_start + kernel_free_pages * PG_SIZE;
    
    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.bits = (void*)MEM_BITMAP_BASE;
    user_pool.pool_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length);
    
    kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
    user_pool.pool_bitmap.btmp_bytes_len = ubm_length; 
    
    put_str("        kernel_pool_bitmap_start:");
    put_int((int)kernel_pool.pool_bitmap.bits);
    put_str(" kernel_pool_phy_addr_start:");
    put_int(kernel_pool.phy_addr_start);
    put_char('\n');
    put_str("        user_pool_bitmap_start:");
    put_int((int)user_pool.pool_bitmap.bits);
    put_str(" user_pool_phy_addr_start:");
    put_int(user_pool.phy_addr_start);
    put_char('\n');
    
    bitmap_init(&kernel_pool.pool_bitmap);
    bitmap_init(&user_pool.pool_bitmap);
    
    kernel_vaddr.vaddr_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length + ubm_length);
    kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length;
    
    kernel_vaddr.vaddr_start = K_HEAP_START;
    bitmap_init(&kernel_vaddr.vaddr_bitmap);
    lock_init(&kernel_pool.lock);
    lock_init(&user_pool.lock);
    put_str("    mem_pool_init done\n");
    return;
}

void block_desc_init(struct mem_block_desc* desc_array)
{
    uint16_t desc_idx,block_size = 16;
    for(desc_idx = 0;desc_idx < DESC_CNT;desc_idx++)
    {
    	desc_array[desc_idx].block_size = block_size;
    	desc_array[desc_idx].block_per_arena = (PG_SIZE - sizeof(struct arena)) / block_size;
    	list_init(&desc_array[desc_idx].free_list);
    	block_size *= 2;
    }   
}

void mem_init()
{
    put_str("mem_init start!\n");
    uint32_t mem_bytes_total = (*(uint32_t*)(0x800)); //我们把总内存的值放在了0x800 我之前为了显示比较独特 放在了0x800处了
    mem_pool_init(mem_bytes_total);
    block_desc_init(k_block_descs);
    put_str("mem_init done!\n");
    return;
}

//返回idx个内存块的地址 空间布局为 arena元信息+n个内存块
struct mem_block* arena2block(struct arena* a,uint32_t idx)
{
    return (struct mem_block*)((uint32_t)a + sizeof(struct arena) + idx * a->desc->block_size);
}

//自然页框的最低点处
struct arena* block2arena(struct mem_block* b)
{
    return (struct arena*)((uint32_t)b & 0xfffff000);
}

void* sys_malloc(uint32_t size)
{
    enum pool_flags PF;
    struct pool* mem_pool;
    uint32_t pool_size;
    struct mem_block_desc* descs;
    struct task_struct* cur_thread = running_thread();
    
    if(cur_thread->pgdir == NULL)
    {
    	PF = PF_KERNEL;
    	pool_size = kernel_pool.pool_size;
    	mem_pool = &kernel_pool;
    	descs = k_block_descs;
    }
    else
    {
    	PF = PF_USER;
    	pool_size = user_pool.pool_size;
    	mem_pool = &user_pool;
    	descs = cur_thread->u_block_desc;
    }
    //size 超出空间大小或者为 0 负数
    if(!(size > 0 && size < pool_size))
    {
    	return NULL;
    }
    
    struct arena* a;
    struct mem_block* b;
    lock_acquire(&mem_pool->lock);
    
    //超过页框直接分配页框
    if(size > 1024)
    {
    	uint32_t page_cnt = DIV_ROUND_UP(size + sizeof(struct arena),PG_SIZE);
    	a = malloc_page(PF,page_cnt);
    	if(a != NULL)
    	{
    	    memset(a,0,page_cnt * PG_SIZE);
	    a->desc = NULL;
	    a->cnt  = page_cnt;
	    a->large = true;    
	    lock_release(&mem_pool->lock);
	    return (void*)(a+1); //返回地址 struct arena + sizeof(struct arena)
	}
	else
	{
	    lock_release(&mem_pool->lock);
	    return NULL;
	}
    }
    else
    {
    	uint8_t desc_idx;
    	for(desc_idx = 0;desc_idx < DESC_CNT;desc_idx++)
    	{
    	    if(size <= descs[desc_idx].block_size)
    	    {
    	    	break;
    	    }
    	}
    	
    	//已经空了
    	if(list_empty(&descs[desc_idx].free_list))
    	{
    	    a = malloc_page(PF,1);
    	    if(a == NULL)
    	    {
    	    	lock_release(&mem_pool->lock);
    	    	return NULL;
    	    }
    	    memset(a,0,PG_SIZE);
    	    
    	    a->desc = &descs[desc_idx];
    	    a->large = false;
    	    a->cnt = descs[desc_idx].block_per_arena;
    	    uint32_t block_idx;
    	    
    	    enum intr_status old_status = intr_disable();
    	    
    	    for(block_idx = 0;block_idx < descs[desc_idx].block_per_arena;++block_idx)
    	    {
    	    	b = arena2block(a,block_idx);
    	    	ASSERT(!elem_find(&a->desc->free_list,&b->free_elem));
    	    	list_append(&a->desc->free_list,&b->free_elem);
    	    }
    	    intr_set_status(old_status);
    	}
    	
    	b = (struct mem_block*)list_pop(&(descs[desc_idx].free_list));
    	memset(b,0,descs[desc_idx].block_size);
    	
    	a = block2arena(b);
    	--a->cnt;
    	lock_release(&mem_pool->lock);
    	return (void*)b;
    }
}

修改完的makefile


BUILD_DIR = ./build
ENTRY_POINT = 0xc0001500
AS = nasm
CC = gcc
LD = ld
LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/ 
ASFLAGS = -f elf
CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
      $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o $(BUILD_DIR)/switch.o \
      $(BUILD_DIR)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.o $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o \
      $(BUILD_DIR)/sync.o $(BUILD_DIR)/console.o $(BUILD_DIR)/keyboard.o \
      $(BUILD_DIR)/ioqueue.o $(BUILD_DIR)/tss.o $(BUILD_DIR)/process.o \
      $(BUILD_DIR)/syscall-init.o $(BUILD_DIR)/syscall.o $(BUILD_DIR)/stdio.o
      
##############     c代码编译     ###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h kernel/memory.h \
        thread/thread.h kernel/interrupt.h device/console.h \
        device/keyboard.h device/ioqueue.h userprog/process.h \
        lib/user/syscall.h userprog/syscall-init.h lib/stdio.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
        lib/stdint.h kernel/interrupt.h device/timer.h kernel/memory.h \
        thread/thread.h device/console.h device/keyboard.h userprog/tss.h \
        userprog/syscall-init.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
        lib/stdint.h kernel/global.h lib/kernel/io.h lib/kernel/print.h \
        kernel/kernel.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/io.h lib/kernel/print.h \
        kernel/interrupt.h thread/thread.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
        lib/kernel/print.h lib/stdint.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/memory.o: kernel/memory.c kernel/memory.h \
	lib/stdint.h lib/kernel/bitmap.h kernel/debug.h lib/string.h kernel/global.h \
	thread/sync.h thread/thread.h lib/kernel/list.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h kernel/global.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/thread.o: thread/thread.c thread/thread.h \
	lib/stdint.h lib/string.h kernel/global.h kernel/memory.h \
	kernel/debug.h kernel/interrupt.h lib/kernel/print.h \
	userprog/process.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h \
	kernel/interrupt.h lib/stdint.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/sync.o: thread/sync.c thread/sync.h \
	lib/stdint.h thread/thread.h kernel/debug.h kernel/interrupt.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/console.o: device/console.c device/console.h \
	lib/kernel/print.h thread/sync.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/keyboard.o: device/keyboard.c device/keyboard.h \
	lib/kernel/print.h lib/kernel/io.h kernel/interrupt.h \
	kernel/global.h lib/stdint.h device/ioqueue.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h \
	kernel/interrupt.h kernel/global.h kernel/debug.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/tss.o: userprog/tss.c userprog/tss.h \
	kernel/global.h thread/thread.h lib/kernel/print.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/process.o: userprog/process.c userprog/process.h \
	lib/string.h kernel/global.h kernel/memory.h lib/kernel/print.h \
	thread/thread.h kernel/interrupt.h kernel/debug.h device/console.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/syscall-init.o: userprog/syscall-init.c userprog/syscall-init.h \
	lib/user/syscall.h lib/stdint.h lib/kernel/print.h kernel/interrupt.h thread/thread.h
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/syscall.o: lib/user/syscall.c lib/user/syscall.h 
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/stdio.o: lib/stdio.c lib/stdio.h lib/stdint.h lib/string.h lib/user/syscall.h
	$(CC) $(CFLAGS) $< -o $@
	
##############    汇编代码编译    ###############
$(BUILD_DIR)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/switch.o: thread/switch.S
	$(AS) $(ASFLAGS) $< -o $@

##############    链接所有目标文件    #############
$(BUILD_DIR)/kernel.bin: $(OBJS)
	$(LD) $(LDFLAGS) $^ -o $@

.PHONY : mk_dir hd clean all

mk_dir:
	if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi

hd:
	dd if=$(BUILD_DIR)/kernel.bin \
           of=/home/cooiboi/bochs/hd60M.img \
           bs=512 count=200 seek=9 conv=notrunc

clean:
	cd $(BUILD_DIR) && rm -f  ./*

build: $(BUILD_DIR)/kernel.bin

all: mk_dir build hd

修改后的main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"

int a=0,b=0;
void test_thread1(void* arg);
void test_thread2(void* arg);
void u_prog_a(void);
void u_prog_b(void);

int main(void) {
   put_str("I am kernel\n");
   init_all();
   //process_execute(u_prog_a,"user_prog_a");
   //process_execute(u_prog_b,"user_prog_b");
   intr_enable();
   /*console_put_str(" i am main:0x");
   printf("%x",getpid());
   console_put_char('\n');*/
   thread_start("kernel_thread_a",31,test_thread1," i am thread_A:0x");
   thread_start("kernel_thread_b",31,test_thread2," i am thread_B:0x");
   
   while(1);
   return 0;
}

void test_thread1(void* arg)
{
    printf("i am thread_a sys_malloc(33) addr is 0x%x%c",sys_malloc(33),'\n');
    while(1);
}

void test_thread2(void* arg)
{
    printf("i am thread_b sys_malloc(63) addr is 0x%x%c",sys_malloc(63),'\n');
    while(1);
}

void u_prog_a(void)
{
    printf("i am thread_b sys_malloc(63) addr is 0x%x%c",sys_malloc(63),'\n');
    //printf("i am thread_b sys_malloc(63) addr is 0x%c",'\n');
    while(1);
}

void u_prog_b(void)
{
    printf("i am thread_b sys_malloc(63) addr is 0x%x%c",sys_malloc(63),'\n');
    //printf("i am thread_b sys_malloc(63) addr is 0x%c",'\n');
    while(1);
}

make all 验证成果


看成果应该是ok了 此时的网页已经超级卡了 后面还有些内容我就加到一起来写了


实现free函数


**实话实说 哈哈 里面的大部分内容我都是看了一眼就直接写上去了 没有多想 因为内存分配的那个地方我就是看懂了就直接写上去了 没有太多印象 而且今天人也比较困 理解一下老年人吧 只不过最后我调试了半小时 发现之前的用户进程的虚拟地址管理出现了点问题 这个在文末的时候会将 **

那代码就直接走起


修改后的memory.c


#include "memory.h"
#include "stdint.h"
#include "print.h"
#include "bitmap.h"
#include "debug.h"
#include "string.h"
#include "global.h"
#include "../thread/sync.h"
#include "../thread/thread.h"
#include "../lib/kernel/list.h"
#include "interrupt.h"

#define PG_SIZE 4096
#define MEM_BITMAP_BASE 0Xc009a000   //位图开始存放的位置
#define K_HEAP_START    0xc0100000   //内核栈起始位置
#define PDE_IDX(addr) ((addr & 0xffc00000) >> 22)
#define PTE_IDX(addr) ((addr & 0x003ff000) >> 12)

struct pool
{
    struct bitmap pool_bitmap; //位图来管理内存使用
    uint32_t phy_addr_start;   //内存池开始的起始地址
    uint32_t pool_size;	//池容量
    struct lock lock;
};
struct mem_block_desc k_block_descs[DESC_CNT]; //内核内存块描述符数组

struct pool kernel_pool ,user_pool; //生成内核内存池 和 用户内存池
struct virtual_addr kernel_vaddr;    //内核虚拟内存管理池

void* vaddr_get(enum pool_flags pf,uint32_t pg_cnt)
{
    int vaddr_start = 0,bit_idx_start = -1;
    uint32_t cnt = 0;
    if(pf == PF_KERNEL)
    {
    	bit_idx_start = bitmap_scan(&kernel_vaddr.vaddr_bitmap,pg_cnt);
    	if(bit_idx_start == -1)	return NULL;
    	while(cnt < pg_cnt)
    	    bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),1);
    	vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
    }
    else
    {
    	struct task_struct* cur = running_thread();
    	bit_idx_start = bitmap_scan(&cur->userprog_vaddr.vaddr_bitmap,pg_cnt);
    	if(bit_idx_start == -1)	return NULL;
    	
    	while(cnt < pg_cnt)
    	    bitmap_set(&cur->userprog_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),1);
    	vaddr_start = cur->userprog_vaddr.vaddr_start + bit_idx_start * PG_SIZE;
    	ASSERT((uint32_t)vaddr_start < (0xc0000000 - PG_SIZE));
    }
    return (void*)vaddr_start;
}

uint32_t* pte_ptr(uint32_t vaddr)
{
    uint32_t* pte = (uint32_t*)(0xffc00000 + ((vaddr & 0xffc00000) >> 10) + PTE_IDX(vaddr) * 4);
    return pte;
}

uint32_t* pde_ptr(uint32_t vaddr)
{
    uint32_t* pde = (uint32_t*) ((0xfffff000) + PDE_IDX(vaddr) * 4);
    return pde;
}

void* palloc(struct pool* m_pool)
{
    int bit_idx = bitmap_scan(&m_pool->pool_bitmap,1);
    if(bit_idx == -1)	return NULL;
    bitmap_set(&m_pool->pool_bitmap,bit_idx,1);
    uint32_t page_phyaddr = ((bit_idx * PG_SIZE) + m_pool->phy_addr_start);
    return (void*)page_phyaddr;
}

void page_table_add(void* _vaddr,void* _page_phyaddr)
{
    uint32_t vaddr = (uint32_t)_vaddr,page_phyaddr = (uint32_t)_page_phyaddr;
    uint32_t* pde = pde_ptr(vaddr);
    uint32_t* pte = pte_ptr(vaddr);
    
    if(*pde & 0x00000001)
    {
    	ASSERT(!(*pte & 0x00000001));
    	if(!(*pte & 0x00000001))
    	    *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	else
    	{
    	    PANIC("pte repeat");
    	    *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	}
    } 
    else
    {
    	uint32_t pde_phyaddr = (uint32_t)palloc(&kernel_pool);
    	*pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    	memset((void*)((int)pte & 0xfffff000),0,PG_SIZE);
    	ASSERT(!(*pte & 0x00000001));
    	*pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
    }
    return;
}

void* malloc_page(enum pool_flags pf,uint32_t pg_cnt)
{
    ASSERT(pg_cnt > 0 && pg_cnt < 3840);
    
    void* vaddr_start = vaddr_get(pf,pg_cnt);
    if(vaddr_start == NULL)	return NULL;
    
    
    uint32_t vaddr = (uint32_t)vaddr_start,cnt = pg_cnt;
    struct pool* mem_pool = pf & PF_KERNEL ? &kernel_pool : &user_pool;
    
    while(cnt-- > 0)
    {
    	void* page_phyaddr = palloc(mem_pool);
    	if(page_phyaddr == NULL)	return NULL;
    	page_table_add((void*)vaddr,page_phyaddr);
    	vaddr += PG_SIZE;
    }
    return vaddr_start;
}

void* get_kernel_pages(uint32_t pg_cnt)
{
    void* vaddr = malloc_page(PF_KERNEL,pg_cnt);
    if(vaddr != NULL)	memset(vaddr,0,pg_cnt*PG_SIZE);
    return vaddr;
}

void* get_user_pages(uint32_t pg_cnt)
{
    lock_acquire(&user_pool.lock);	//用户进程可能会产生冲突 大部分时间都在用户进程 内核进程可以理解基本不会冲突
    void* vaddr = malloc_page(PF_USER,pg_cnt);
    if(vaddr != NULL)	memset(vaddr,0,pg_cnt*PG_SIZE);
    lock_release(&user_pool.lock);
    return vaddr;
}

void* get_a_page(enum pool_flags pf,uint32_t vaddr)
{
    struct pool* mem_pool = (pf == PF_KERNEL) ? &kernel_pool : &user_pool;
    lock_acquire(&mem_pool->lock);
    
    struct task_struct* cur = running_thread();
    int32_t bit_idx = -1;
    
    //虚拟地址位图置1
    if(cur->pgdir != NULL && pf == PF_USER)
    {
    	bit_idx = (vaddr - cur->userprog_vaddr.vaddr_start) / PG_SIZE;
    	ASSERT(bit_idx > 0);
    	bitmap_set(&cur->userprog_vaddr.vaddr_bitmap,bit_idx,1);
    }
    else if(cur->pgdir == NULL && pf == PF_KERNEL) 
    {
    	bit_idx = (vaddr - cur->userprog_vaddr.vaddr_start) / PG_SIZE;
    	ASSERT(bit_idx > 0);
    	bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx,1);
    }
    else
    	PANIC("get_a_page:not allow kernel alloc userspace or user alloc kernelspace by get_a_page");
    	
    void* page_phyaddr = palloc(mem_pool);
    if(page_phyaddr == NULL)
    	return NULL;
    page_table_add((void*)vaddr,page_phyaddr);
    lock_release(&mem_pool->lock);
    return (void*)vaddr;
}

/* 得到虚拟地址映射的物理地址 */
uint32_t addr_v2p(uint32_t vaddr)
{
    uint32_t* pte = pte_ptr(vaddr);
    return ((*pte & 0xfffff000) + (vaddr & 0x00000fff));
}

void mem_pool_init(uint32_t all_mem)
{
    put_str("    mem_pool_init start!\n");
    uint32_t page_table_size = PG_SIZE * 256;       //页表占用的大小
    uint32_t used_mem = page_table_size + 0x100000; //低端1MB的内存 + 页表所占用的大小
    uint32_t free_mem = all_mem - used_mem;
    
    uint16_t all_free_pages = free_mem / PG_SIZE;   //空余的页数 = 总空余内存 / 一页的大小
    
    uint16_t kernel_free_pages = all_free_pages /2; //内核 与 用户 各平分剩余内存
    uint16_t user_free_pages = all_free_pages - kernel_free_pages; //万一是奇数 就会少1 减去即可
    
    //kbm kernel_bitmap ubm user_bitmap
    uint32_t kbm_length = kernel_free_pages / 8;    //一位即可表示一页 8位一个数
    uint32_t ubm_length = user_free_pages / 8;
    
    //kp kernel_pool up user_pool
    uint32_t kp_start = used_mem;
    uint32_t up_start = kp_start + kernel_free_pages * PG_SIZE;
    
    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.bits = (void*)MEM_BITMAP_BASE;
    user_pool.pool_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length);
    
    kernel_pool.pool_bitmap.btmp_bytes_len = kbm_length;
    user_pool.pool_bitmap.btmp_bytes_len = ubm_length; 
    
    put_str("        kernel_pool_bitmap_start:");
    put_int((int)kernel_pool.pool_bitmap.bits);
    put_str(" kernel_pool_phy_addr_start:");
    put_int(kernel_pool.phy_addr_start);
    put_char('\n');
    put_str("        user_pool_bitmap_start:");
    put_int((int)user_pool.pool_bitmap.bits);
    put_str(" user_pool_phy_addr_start:");
    put_int(user_pool.phy_addr_start);
    put_char('\n');
    
    bitmap_init(&kernel_pool.pool_bitmap);
    bitmap_init(&user_pool.pool_bitmap);
    
    kernel_vaddr.vaddr_bitmap.bits = (void*)(MEM_BITMAP_BASE + kbm_length + ubm_length);
    kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_length;
    
    kernel_vaddr.vaddr_start = K_HEAP_START;
    bitmap_init(&kernel_vaddr.vaddr_bitmap);
    lock_init(&kernel_pool.lock);
    lock_init(&user_pool.lock);
    put_str("    mem_pool_init done\n");
    return;
}

void block_desc_init(struct mem_block_desc* desc_array)
{
    uint16_t desc_idx,block_size = 16;
    for(desc_idx = 0;desc_idx < DESC_CNT;desc_idx++)
    {
    	desc_array[desc_idx].block_size = block_size;
    	desc_array[desc_idx].block_per_arena = (PG_SIZE - sizeof(struct arena)) / block_size;
    	list_init(&desc_array[desc_idx].free_list);
    	block_size *= 2;
    }   
}

void mem_init()
{
    put_str("mem_init start!\n");
    uint32_t mem_bytes_total = (*(uint32_t*)(0x800)); //我们把总内存的值放在了0x800 我之前为了显示比较独特 放在了0x800处了
    mem_pool_init(mem_bytes_total);
    block_desc_init(k_block_descs);
    put_str("mem_init done!\n");
    return;
}

//返回idx个内存块的地址 空间布局为 arena元信息+n个内存块
struct mem_block* arena2block(struct arena* a,uint32_t idx)
{
    return (struct mem_block*)((uint32_t)a + sizeof(struct arena) + idx * a->desc->block_size);
}

//自然页框的最低点处
struct arena* block2arena(struct mem_block* b)
{
    return (struct arena*)((uint32_t)b & 0xfffff000);
}

void* sys_malloc(uint32_t size)
{
    enum pool_flags PF;
    struct pool* mem_pool;
    uint32_t pool_size;
    struct mem_block_desc* descs;
    struct task_struct* cur_thread = running_thread();
    
    if(cur_thread->pgdir == NULL)
    {
    	PF = PF_KERNEL;
    	pool_size = kernel_pool.pool_size;
    	mem_pool = &kernel_pool;
    	descs = k_block_descs;
    }
    else
    {
    	PF = PF_USER;
    	pool_size = user_pool.pool_size;
    	mem_pool = &user_pool;
    	descs = cur_thread->u_block_desc;
    }
    //size 超出空间大小或者为 0 负数
    if(!(size > 0 && size < pool_size))
    {
    	return NULL;
    }
    
    struct arena* a;
    struct mem_block* b;
    lock_acquire(&mem_pool->lock);
    
    //超过页框直接分配页框
    if(size > 1024)
    {
    	uint32_t page_cnt = DIV_ROUND_UP(size + sizeof(struct arena),PG_SIZE);
    	a = malloc_page(PF,page_cnt);
    	if(a != NULL)
    	{
    	    memset(a,0,page_cnt * PG_SIZE);
	    a->desc = NULL;
	    a->cnt  = page_cnt;
	    a->large = true;    
	    lock_release(&mem_pool->lock);
	    return (void*)(a+1); //返回地址 struct arena + sizeof(struct arena)
	}
	else
	{
	    lock_release(&mem_pool->lock);
	    return NULL;
	}
    }
    else
    {
    	uint8_t desc_idx;
    	for(desc_idx = 0;desc_idx < DESC_CNT;desc_idx++)
    	{
    	    if(size <= descs[desc_idx].block_size)
    	    {
    	    	break;
    	    }
    	}
    	
    	//已经空了
    	if(list_empty(&descs[desc_idx].free_list))
    	{
    	    a = malloc_page(PF,1);
    	    if(a == NULL)
    	    {
    	    	lock_release(&mem_pool->lock);
    	    	return NULL;
    	    }
    	    memset(a,0,PG_SIZE);
    	    
    	    a->desc = &descs[desc_idx];
    	    a->large = false;
    	    a->cnt = descs[desc_idx].block_per_arena;
    	    uint32_t block_idx;
    	    
    	    enum intr_status old_status = intr_disable();
    	    
    	    for(block_idx = 0;block_idx < descs[desc_idx].block_per_arena;++block_idx)
    	    {
    	    	b = arena2block(a,block_idx);
    	    	ASSERT(!elem_find(&a->desc->free_list,&b->free_elem));
    	    	list_append(&a->desc->free_list,&b->free_elem);
    	    }
    	    intr_set_status(old_status);
    	}
    	b = (struct mem_block*)list_pop(&(descs[desc_idx].free_list));
    	memset(b,0,descs[desc_idx].block_size);
    	
    	a = block2arena(b);
    	--a->cnt;
    	lock_release(&mem_pool->lock);
    	return (void*)b;
    }
}

void pfree(uint32_t pg_phy_addr)
{
    struct pool* mem_pool;
    uint32_t bit_idx = 0;
    if(pg_phy_addr >= user_pool.phy_addr_start)
    {
    	mem_pool = &user_pool;
    	bit_idx = (pg_phy_addr - user_pool.phy_addr_start) / PG_SIZE;
    }
    else
    {
    	mem_pool = &kernel_pool;
    	bit_idx = (pg_phy_addr - kernel_pool.phy_addr_start) / PG_SIZE;
    }
    bitmap_set(&mem_pool->pool_bitmap,bit_idx,0);	//全部置0
}

void page_table_pte_remove(uint32_t vaddr)
{
    uint32_t* pte = pte_ptr(vaddr);
    *pte = ~PG_P_1;
    asm volatile("invlpg %0"::"m"(vaddr):"memory");	//更新tlb
}

void vaddr_remove(enum pool_flags pf,void* _vaddr,uint32_t pg_cnt)
{
    uint32_t bit_idx_start = 0,vaddr = (uint32_t)_vaddr,cnt = 0;
    
    if(pf == PF_KERNEL)
    {
    	bit_idx_start = (vaddr - kernel_vaddr.vaddr_start) / PG_SIZE;
    	while(cnt < pg_cnt)
    	{
    	    bitmap_set(&kernel_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),0);
    	}
    }
    else
    {
    	struct task_struct* cur_thread = running_thread();
    	bit_idx_start = (vaddr - cur_thread->userprog_vaddr.vaddr_start) / PG_SIZE;
    	while(cnt < pg_cnt)
    	{
    	    bitmap_set(&cur_thread->userprog_vaddr.vaddr_bitmap,bit_idx_start + (cnt++),0);
    	}
    }
}

void mfree_page(enum pool_flags pf,void* _vaddr,uint32_t pg_cnt)
{
    uint32_t pg_phy_addr;
    uint32_t vaddr = (int32_t)_vaddr,page_cnt = 0;
    ASSERT(pg_cnt >= 1 && vaddr % PG_SIZE == 0);
    pg_phy_addr = addr_v2p(vaddr);
    
    ASSERT((pg_phy_addr % PG_SIZE) == 0 && pg_phy_addr >= 0x102000);
    
    if(pg_phy_addr >= user_pool.phy_addr_start)
    {
    	vaddr -= PG_SIZE;
    	while(page_cnt < pg_cnt)
    	{
    	    vaddr += PG_SIZE;
    	    pg_phy_addr = addr_v2p(vaddr);
    	    ASSERT((pg_phy_addr % PG_SIZE) == 0 && pg_phy_addr >= user_pool.phy_addr_start);
    	    pfree(pg_phy_addr);
    	    page_table_pte_remove(vaddr);
    	    page_cnt++;
    	}
    	vaddr_remove(pf,_vaddr,pg_cnt);
   }
   else
   {
   	vaddr -= PG_SIZE;
   	while(page_cnt < pg_cnt)
   	{
   	    vaddr += PG_SIZE;
   	    pg_phy_addr = addr_v2p(vaddr);
   	    ASSERT((pg_phy_addr % PG_SIZE) == 0 && pg_phy_addr >= kernel_pool.phy_addr_start && pg_phy_addr < user_pool.phy_addr_start);
   	    pfree(pg_phy_addr);
   	    page_table_pte_remove(vaddr);
   	    page_cnt++;
   	}
   	vaddr_remove(pf,_vaddr,pg_cnt);
   }
}

void sys_free(void* ptr)
{
    ASSERT(ptr != NULL);
    if(ptr != NULL)
    {
    	enum pool_flags PF;
    	struct pool* mem_pool;
    	
    	if(running_thread()->pgdir == NULL)
    	{
    	    ASSERT((uint32_t)ptr >= K_HEAP_START);
    	    PF = PF_KERNEL;
    	    mem_pool = &kernel_pool;
    	}
    	else
    	{
    	    PF = PF_USER;
    	    mem_pool = &user_pool;
    	}
    	
    	lock_acquire(&mem_pool->lock);
    	struct mem_block* b = ptr;
    	struct arena* a = block2arena(b);
    	
    	ASSERT(a->large == 0 || a->large == 1);
    	if(a->desc == NULL && a->large == true)
    	{
    	    mfree_page(PF,a,a->cnt);
    	}
    	else
    	{
    	    list_append(&a->desc->free_list,&b->free_elem);
    	    if(++a->cnt == a->desc->block_per_arena)
    	    {
    	    	uint32_t block_idx;
    	    	for(block_idx = 0;block_idx < a->desc->block_per_arena;block_idx++)
    	    	{
    	    	    struct mem_block* b = arena2block(a,block_idx++);
    	    	    ASSERT(elem_find(&a->desc->free_list,&b->free_elem));
    	    	}
    	    	mfree_page(PF,a,1);
    	    }
    	}
    	lock_release(&mem_pool->lock);
    }
}

修改后的memory.h


#ifndef __KERNEL_MEMORY_H
#define __KERNEL_MEMORY_H
#include "stdint.h"
#include "bitmap.h"
#include "list.h"

struct virtual_addr
{
    struct bitmap vaddr_bitmap;
    uint32_t vaddr_start;
};

enum pool_flags
{
    PF_KERNEL = 1,
    PF_USER = 2
};

struct mem_block
{
    struct list_elem free_elem;
};

struct mem_block_desc
{
    uint32_t block_size;
    uint32_t block_per_arena;
    struct list free_list;	
};

struct arena
{
    struct mem_block_desc* desc;
    uint32_t cnt;
    bool large; 
};

#define PG_P_1 1
#define PG_P_0 0
#define PG_RW_R 0
#define PG_RW_W 2
#define PG_US_S 0
#define PG_US_U 4

#define DESC_CNT      7

extern struct pool kernel_pool,user_pool;
void* vaddr_get(enum pool_flags pf,uint32_t pg_cnt);
uint32_t* pte_ptr(uint32_t vaddr);
uint32_t* pde_ptr(uint32_t vaddr);
void* palloc(struct pool* m_pool);
void page_table_add(void* _vaddr,void* _page_phyaddr);
void* malloc_page(enum pool_flags pf,uint32_t pg_cnt);
void* get_kernel_pages(uint32_t pg_cnt);
void* get_user_pages(uint32_t pg_cnt);
void* get_a_page(enum pool_flags pf,uint32_t vaddr);
uint32_t addr_v2p(uint32_t vaddr);
void mem_pool_init(uint32_t all_mem);
void mem_init(void);
void block_desc_init(struct mem_block_desc* desc_array);
struct mem_block* arena2block(struct arena* a,uint32_t idx);
struct arena* block2arena(struct mem_block* b);
void* sys_malloc(uint32_t size);
void pfree(uint32_t pg_phy_addr);
void page_table_pte_remove(uint32_t vaddr);
void vaddr_remove(enum pool_flags pf,void* _vaddr,uint32_t pg_cnt);
void mfree_page(enum pool_flags pf,void* _vaddr,uint32_t pg_cnt);
void sys_free(void* ptr);

#endif

修改后的main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"

void k_thread_a(void* );
void k_thread_b(void* );
void u_prog_a (void);
void u_prog_b (void);

int main(void) {
   put_str("I am kernel\n");
   init_all();

   intr_enable();
   process_execute(u_prog_a, "u_prog_a");
   process_execute(u_prog_b, "u_prog_b"); 
   thread_start("k_thread_a", 31, k_thread_a, "argA ");
   thread_start("k_thread_b", 31, k_thread_b, "argB ");  
   while(1);
   return 0;
}

void k_thread_a(void* arg){

	void* addr1 = sys_malloc(256);
	void* addr2 = sys_malloc(255);
	void* addr3 = sys_malloc(254);
	console_put_str(" thread_a malloc addr:0x");
	console_put_int((int)addr1);
	console_put_char(',');
	console_put_int((int)addr2);
	console_put_char(',');
	console_put_int((int)addr3);
	console_put_char('\n');
	int cpu_delay = 100000;
	while(cpu_delay-->0);
	sys_free(addr1);
	sys_free(addr2);
	sys_free(addr3);
	while(1);
}

void k_thread_b(void* arg){
	void* addr1 = sys_malloc(256);
	void* addr2 = sys_malloc(255);
	void* addr3 = sys_malloc(254);
	console_put_str(" thread_b malloc addr:0x");
	console_put_int((int)addr1);
	console_put_char(',');
	console_put_int((int)addr2);
	console_put_char(',');
	console_put_int((int)addr3);
	console_put_char('\n');
	int cpu_delay = 100000;
	while(cpu_delay-->0);
	sys_free(addr1);
	sys_free(addr2);
	sys_free(addr3);
	while(1);
}

void u_prog_a(void) {
	void* addr1 = malloc(256);
	void* addr2 = malloc(255);
	void* addr3 = malloc(254);
	printf(" prog_a malloc addr:0x%x, 0x%x, 0x%x\n", (int)addr1,(int)addr2,(int)addr3);
	int cpu_delay = 100000;
	while(cpu_delay-->0);
	free(addr1);
	free(addr2);
	free(addr3);
	while(1);
}

void u_prog_b(void) {
	void* addr1 = malloc(256);
	void* addr2 = malloc(255);
	void* addr3 = malloc(254);
	printf(" prog_b malloc addr:0x%x, 0x%x, 0x%x\n", (int)addr1,(int)addr2,(int)addr3);
	int cpu_delay = 100000;
	while(cpu_delay-->0);
	free(addr1);
	free(addr2);
	free(addr3);
	while(1);
}

发现用户进程的问题


鉴于人懒 就算了 只写最后的那部分检验
但是在此之前 我做了很多次的检测 发现就会出现下面的问题
下面我放一下截图在这里插入图片描述


随后我去搜了一下 发现别人都没有我这个问题 但是我慢慢的发现 内核进程没有问题 用户进程出现了问题 之后我又一点点的调试跟踪 发现用户进程问题出现在memeset(a,0,PG_SIZE)
我就开始怀疑是不是memset出现了问题 但是自己检查了一下 发现怎么可能有问题 之后就猜测是不是进程创建的描述符出现了问题 之后又慢慢的去排查 发现也没有问题 那就奇怪了 问题出在哪里 之后一次偶然的调试 我先开始reg看了看寄存器 之后又看了看info tab 忽然就发现了问题 下面是问题所在地方

看看最上面一排0x8040000 根据推测应该是才分配出来的一页内存 而且之后我又去试了一下put_int 发现用户进程分配的虚拟内存刚好是0x804000 那这就可以解释了 0x804000+2000肯定是大于我们下面的0x804ffff的 说明问题出在虚拟内存超过页表匹配的范围了

在这里插入图片描述


之后我就去把用户的虚拟内存的起始地址改了一下 如下
毕竟要整数页嘛 起始地址应该最后三位就是0

在这里插入图片描述


make all 验收成果


ok了 homie 没问题了 那这一章就到此结束了! 感谢一直看到这里 哈哈
在这里插入图片描述

在这里插入图片描述


结束语


给大家看一个数据 哈哈 编辑到这已经73300多字了 话就不多说了 太卡了留在下一章说 终于结束了! 在这里插入图片描述

Copyright © 2002-2019 某某自媒体运营 版权所有