文章目录
专栏博客链接
相关查阅博客链接
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了下来
但总的来说 自从上午做了几道很简单的力扣之后
我感觉原来的感觉已经回来了一点了 也很明白 编程中间只要彻底放空一段时间意味着什么 我还是对后面的章节 比较期待吧 这两章博客写的质量稍微差了一点 写操作系统最好还是抽的是连续的时间写 效果是最好的…
就写到这里 去吃晚饭回寝室了