《操作系统真象还原》第八章 ---- 初入内存管理系统 涉足MakeFile 了解摸谈一二


专栏博客链接


《操作系统真象还原》从零开始自制操作系统 全章节博客链接


相关查阅博客链接


assert()函数用法总结
操作系统真象还原实验记录之实验十二:实现ASSERT
const char *和 char *const以及 char const * 的区别


部分缩写熟知


1、
src source
des destination目标

2、
顺带复习了一个地方就是
const char*char* const

const char*是表示这个指针指向的是一个常量
char* const是表示这个指针不能更改 但是指针中的地址指向的数可以更改

前者const 修饰的是*p,他是p所指向的内容为read-only;
而 后者 const 修饰的是p, 即指针变量p本身为 read-only;


本书中错误勘误


1、371页 代码8-4 其实应该是debug.c 书上写的是debug.h 哈哈哈 小问题
2、386页 32MB的内存占用位图应该是1kb 1kb*4kb*8 = 32MB


熟悉一下MakeFile(一笔带过)


这部分大家看一下就行了 因为之前做哈工大操作系统的时候
那个时候编辑很多文件都需要改MakeFile中的命令 我对这个还是有些许印象 但是还是不是很懂 如果后面要用到的话再说


设置哨兵ASSERT


对于ASSERT 实在惭愧 我的c语言看过哈工大的网课 看完就算学完了 但其实个人感觉c语言底层基础并不是很好 尽管平时的单元编程考试大概一道题2-3分钟就能完成满分 但是因为没有系统的看过C Prime 总归感觉还是差了点什么 对于ASSERT 不仅没用过 甚至感觉听都没怎么听过

但总归是做出来了
下面就一步一步的写一下


中断状态切换


俗话说的好 什么事情 磨刀不误砍柴工
我们做这个 我其实觉得还是很有必要的
因为在ASSERT中 如果出错 那个时候后面还有各种进程切换 或者 中断
有可能因为外面的中断cpu而切换走了 所以必须要关闭中断 故这里提前准备写好

这里感觉没什么好说的 把我自己写的给出来


路径kernel/interrupt.c
新增部分


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; 
}

路径kernel/interrupt.h

#ifndef __KERNEL_INTERRUPT_H
#define __KERNEL_INTERRUPT_H
#include "stdint.h"
typedef void* intr_handler;
void idt_init(void);

enum intr_status
{
    INTR_ON,
    INTR_OFF
};

enum intr_status intr_enable();
enum intr_status intr_disable();
enum intr_status intr_set_status(enum intr_status status);
enum intr_status intr_get_status();
#endif

debug.c debug.h编写


这部分就是仿照 ASSERT报错显示
对于debug.h中的三个__FILE__ __LINE__ __func__ 这三个其实我并不是很熟悉
但是最后调试的之后发现参数自动放进去了 所以我猜测这是宏编译器自动处理的 参数这样写就可以自动填充

这部分感觉也没什么好写的 直接给代码


debug.c
路径kernel/debug.c

#include "debug.h"
#include "print.h"
#include "interrupt.h"

void panic_spin(char* filename,int line,const char* func,const char* condition)
{
    intr_disable();                 //我的理解是中断关闭防止中断后cpu处理其他进程被调换
    put_str("\n\n\n\\**********ERROR\\**********\\\n");
    put_str("Filename: ");put_str(filename);put_char('\n');
    put_str("Line: "); put_int(line); put_char('\n');
    put_str("Func: ");put_str((char*)func);put_char('\n');
    put_str("Condition: ");put_str((char*)condition);put_char('\n');
    put_str("\\**********ERROR\\**********\\\n");
    while(1);
}

debug.h
路径kernel/debug.h

#ifndef __KERNEL_DEBUG_H
#define __KERNEL_DEBUG_H

void panic_spin(char* filename,int line,const char* func,const char* condition);

#define PANIC(...) panic_spin (__FILE__,__LINE__,__func__,__VA_ARGS__)

#ifdef NDEBUG 
#define ASSERT(CONDITION) ((void)0)
#else
#define ASSERT(CONDITION) \
   if(CONDITION){}        \
   else{ PANIC(#CONDITION); }

#endif
#endif


修改main.c 验证是否正确


稍加修改main.c 如果发现没有修改成功的话 先试一下去把
build 文件中的所有文件重新删除一次 再重新编译链接一下

修改的main.c代码如下

#include "print.h"
#include "init.h"
#include "debug.h"

int main(void) {
   put_str("I am kernel\n");
   init_all();
   ASSERT(2 == 3);
   while(1);
}

稍加修改 增加 编译 链接的命令 总命令如下

gcc -m32 -I lib/kernel -c -o build/timer.o device/timer.c
gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/init.o kernel/init.c
gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/debug.o kernel/debug.c
nasm -f elf -o build/print.o lib/kernel/print.S
nasm -f elf -o build/kernel.o kernel/kernel.S
ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o  \
build/print.o build/kernel.o build/timer.o build/debug.o
dd if=/home/cooiboi/bochs/build/kernel.bin of=/home/cooiboi/bochs/hd60M.img bs=512 count=200 seek=9 conv=notrunc
bin/bochs -f bochsrc.disk

运行命令 验证效果如下
成功

在这里插入图片描述


编译MakeFile make all一键完成编译


这里的话还是很感谢上面提供的博客链接 写的相关代码
Frankly Speaking 如果没有上面博客提供的代码
又不知道需要浪费多少时间在那里慢慢调试调试
MakeFile里面 因为一个空格或者Tab 不一样 就会导致出错 因为这个我找了很久的错误 本来MakeFile不是重心 但是因为这个而要改很久就算了

下面直接给出代码 感兴趣的hxd就自己手敲一下吧 我估计也会因为各种小地方出错 建议把除了路径以外的地方自己改一下 其他的地方cv即可

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)/debug.o 

##############     c代码编译     			###############
##############     后面的代码以后照本宣科即可		###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/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
	$(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
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/stdint.h\
        lib/kernel/io.h lib/kernel/print.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)/kernel.o: kernel/kernel.S
	$(AS) $(ASFLAGS) $< -o $@

$(BUILD_DIR)/print.o: lib/kernel/print.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
bin/bochs -f bochsrc.disk
这两行代码就成了我们的常客了 复制运行一下 看看效果 o

在这里插入图片描述


实现字符串操作函数


这个操作函数还是多有意思的
大家自己实现看看

我之后带入了main.c试了试效果 改了下makefile 发现成功实现
下面直接给出代码


编写string.c


路径lib/string.c

#include "string.h"
#include "debug.h"
#include "global.h"

void memset(void* dst_,uint8_t value,uint32_t size)
{
    ASSERT(dst_ != NULL);
    uint8_t* dst = (uint8_t*) dst_;
    while((size--) > 0)
    	*(dst++) = value;
    return;
}

void memcpy(void* dst_,const void* src_,uint32_t size)
{
    ASSERT(dst_ != NULL && src_ != NULL);
    uint8_t* dst = dst_;
    const uint8_t* src = src_;
    while((size--) > 0)
    	*(dst++) = *(src++);
    return;
}

int memcmp(const void* a_,const void* b_, uint32_t size)
{
    const char* a = a_;
    const char* b = b_;
    ASSERT(a != NULL || b != NULL);
    while((size--) > 0)
    {
    	if(*a != *b)	return (*a > *b) ? 1 : -1;
   	++a,++b;
    }
    return 0;
}

char* strcpy(char* dsc_,const char* src_)
{
    ASSERT(dsc_ != NULL && src_ != NULL);
    char* dsc = dsc_;
    while((*(dsc_++) = *(src_++) ));
    return dsc;     
}

uint32_t strlen(const char* str)
{
    ASSERT(str != NULL);
    const char* ptr = str;
    while(*(ptr++));
    return (ptr - str - 1);             //例如一个字 1 '\0' ptr会指向'\0'后面一位
}

int8_t strcmp(const char* a,const char* b)
{
    ASSERT(a != NULL && b != NULL);
    while(*a && *a == *b)
    {
    	a++,b++;
    }   
    return (*a < *b) ? -1 : (*a > *b) ; //这个表达式太猛了 用活了
}

char* strchr(const char* str,const char ch)
{
    ASSERT(str != NULL);
    while(*str)
    {
    	if(*str == ch)	return (char*)str;
    	++str;
    } 
    return NULL;
}

char* strrchr(const char* str,const uint8_t ch)
{
    ASSERT(str != NULL);
    char* last_chrptr = NULL;
    while(*str != 0)
    {
    	if(ch == *str)	last_chrptr = (char*)str;
    	str++;
    }
    return last_chrptr;   
}

char* strcat(char* dsc_,const char* src_)
{
    ASSERT(dsc_ != NULL && src_ != NULL);
    char* str = dsc_;
    while(*(str++));
    str--;
    while(*(str++) = *(src_++));
    return dsc_;
}

char* strchrs(const char* str,uint8_t ch)
{
    ASSERT(str != NULL);
    uint32_t ch_cnt = 0;
    while(*str)
    {
    	if(*str == ch) ++ch_cnt;
    	++str;
    }
    return ch_cnt;
}

编写string.h


路径 lib/string.h

#ifndef __LIB_STRING_H
#define __LIB_STRING_H

#include "stdint.h"
#define NULL 0

void memset(void* dst_,uint8_t value,uint32_t size);
void memcpy(void* dst_,const void* src_,uint32_t size);
int memcmp(const void* a_,const void* b_, uint32_t size);
char* strcpy(char* dsc_,const char* src_);
uint32_t strlen(const char* str);
int8_t strcmp(const char* a,const char* b);
char* strchr(const char* str,const char ch);
char* strrchr(const char* str,const uint8_t ch);
char* strcat(char* dsc_,const char* src_);
char* strchrs(const char* str,uint8_t ch);
#endif

修改makefile 和 main.c 验证效果


修改的makefile部分

OBJS部分增加$(BUILD_DIR)/string.o
main.o增加了lib/string.h
最下面部分直接增加即可

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)/debug.o $(BUILD_DIR)/string.o

$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
        lib/stdint.h kernel/init.h lib/string.h
	$(CC) $(CFLAGS) $< -o $@
$
(BUILD_DIR)/string.o: lib/string.c lib/string.h \
	kernel/debug.h kernel/global.h
	$(CC) $(CFLAGS) $< -o $@


稍加修改的main.c

#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"

int main(void) {
   put_str("I am kernel\n");
   init_all();
   ASSERT(strcmp("bbb","bbb"));
   while(1);
}

效果如下 只尝试了strcmp 感觉上面应该是正确的

在这里插入图片描述


Bitmap位图的函数 + 内存管理 代码实现


其实让我比较疑惑的是
我们的内核区 有个专门的内核虚拟空间分配区
那我们的用户区是怎么弄得呢 我们用户进程是怎么分配的
但我转念想了想 这个问题还是等我们后面把用户进程弄完了之后再来吧

书上既然还没写 我们就先当作一个疑问放着

这里面绝大部分的代码我都还是理解了的 有些还是自己靠理解写的
这里指理解了的是位图部分 和 大部分内存管理部分
最后页表的修改部分实在是绕的头晕 因为距离自己写页表相关的函数时已经是一个多月前了 当然印象就没有那么深了 这么绕的真的写不出来了 所以那部分就直接按照书上的一五一十的写了下来 没什么好说的

其实我更享受写操作系统的是 全靠自己的理解把一个部分写出来的
那样子我才有提升 我更期待的是后面的内容 其实这两章我感觉我的理解并没有提升多少 但是为了后面的内容完成这部分也必须要做 所以没办法

另外提一嘴 之前我把内存总量放在了0x800 而不是书上说的0xb00
那个时候我把内存总量设置成了 512MB 而不是32MB
现在我把内存总量改回来了 存放数据的地方没改 还是那个地方


bitmap.c


#include "bitmap.h"            //函数定义
#include "global.h"            //global.h 不清楚
#include "string.h"            //memset函数要用
#include "interrupt.h"         
#include "print.h"             
#include "debug.h"

#define BITMAP_MASK 1

void bitmap_init(struct bitmap* btmp)
{
    memset(btmp->bits,0,btmp->btmp_bytes_len);
    return;
}

bool bitmap_scan_test(struct bitmap* btmp,uint32_t bit_idx)  //一个8位的数 bit_idx/8 找数组下标 %得索引下的具体位置
{
    uint32_t byte_idx = bit_idx/8;
    uint32_t byte_pos = bit_idx%8;
    return (btmp->bits[byte_idx] & (BITMAP_MASK << byte_pos));
}

/*
   这个函数写很多的原因 是因为刚开始先用一个字节的快速扫描
   看是否每个字节中存在 位为0的位置 然后紧接着再看连续位 挺有意思 自己先写写看
*/

int bitmap_scan(struct bitmap* btmp,uint32_t cnt)
{
    ASSERT(cnt >= 1);
    uint32_t first_find_idx = 0;
    //解释一下0xff 一共8位 0xff = 11111111b
    while(first_find_idx < btmp->btmp_bytes_len && btmp->bits[first_find_idx] == 0xff)
    	++first_find_idx;
    if(first_find_idx == btmp->btmp_bytes_len)	return -1;
    
    uint32_t find_pos = 0;
    while((btmp->bits[first_find_idx] & (BITMAP_MASK << find_pos)))
    	++find_pos;
    if(cnt == 1)	return find_pos + 8*first_find_idx;
    
    uint32_t ret_pos = find_pos + 8*first_find_idx + 1,tempcnt = 1,endpos = (btmp->btmp_bytes_len)*8;
    while(ret_pos < endpos)
    {
    	if(!bitmap_scan_test(btmp,ret_pos))	++tempcnt;
    	else tempcnt = 0;
    	if(tempcnt == cnt)
    	    return ret_pos - tempcnt + 1;
    	++ret_pos;
    }    
    return -1;	
}

void bitmap_set(struct bitmap* btmp,uint32_t bit_idx,int8_t value)
{
    ASSERT(value == 1 || value == 0);
    uint32_t byte_idx = bit_idx/8;
    uint32_t byte_pos = bit_idx%8;
    if(value)	btmp->bits[byte_idx] |=  (BITMAP_MASK << byte_pos);
    else	btmp->bits[byte_idx] &= ~(BITMAP_MASK << byte_pos);
    return;
}

bitmap.h


#ifndef __LIB_KERNEL_BITMAP_H
#define __LIB_KERNEL_BITMAP_H
#include "global.h"
#include "stdint.h"
#define BITMAP_MASK 1
typedef int bool;

struct bitmap
{
    uint32_t btmp_bytes_len;
    uint8_t* bits;
};

void bitmap_init(struct bitmap* btmp);
bool bitmap_scan_test(struct bitmap* btmp,uint32_t bit_idx);
int  bitmap_scan(struct bitmap* btmp,uint32_t cnt);
void bitmap_set(struct bitmap* btmp,uint32_t bit_idx,int8_t value); 

#endif

memory.c


#include "memory.h"
#include "stdint.h"
#include "print.h"
#include "bitmap.h"
#include "debug.h"
#include "string.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 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
    {}
    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 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);
    put_str("    mem_pool_init done\n");
    return;
}

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);
    put_str("mem_init done!\n");
    return;
}


memory.h


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

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

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

#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

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 mem_pool_init(uint32_t all_mem);
void mem_init(void);
#endif

init.c


加了一个#include "memory.h" 和 一句 mem_init();


main.c


#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"


int main(void) {
   put_str("I am kernel\n");
   init_all();
   
   void* addr = get_kernel_pages(3);
   put_str("\n get_kernel_page start vaddr is ");
   put_int((uint32_t)addr);
   put_char('\n');
   
   while(1);
   return 0;
}

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)/debug.o $(BUILD_DIR)/string.o $(BUILD_DIR)/memory.o \
      $(BUILD_DIR)/bitmap.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
	$(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
	$(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
	$(CC) $(CFLAGS) $< -o $@

$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/stdint.h\
        lib/kernel/io.h lib/kernel/print.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
	$(CC) $(CFLAGS) $< -o $@
	
$(BUILD_DIR)/bitmap.o: lib/kernel/bitmap.c lib/kernel/bitmap.h \
	lib/string.h kernel/interrupt.h lib/kernel/print.h kernel/debug.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)/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
bin/bochs -f bochsrc.disk

在这里插入图片描述


第八章结束语


总得来说 这两章 第七章 第八章 是我接着第六章 40来天后继续做的
连贯性和很多地方相对原来做的就没有那么好了
对于一些很绕 很烧脑的地方 我也选择了选择性略过 直接把书上面的代码copy了下来

但总的来说 自从上午做了几道很简单的力扣之后
我感觉原来的感觉已经回来了一点了 也很明白 编程中间只要彻底放空一段时间意味着什么 我还是对后面的章节 比较期待吧 这两章博客写的质量稍微差了一点 写操作系统最好还是抽的是连续的时间写 效果是最好的…

就写到这里 去吃晚饭回寝室了

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Love 6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值