欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > 《操作系统真象还原》第八章(2)——内存管理系统

《操作系统真象还原》第八章(2)——内存管理系统

2025/5/18 12:52:33 来源:https://blog.csdn.net/2301_79535379/article/details/147285987  浏览:    关键词:《操作系统真象还原》第八章(2)——内存管理系统

文章目录

    • 前言
    • 位图bitmap及其函数的实现
      • bitmap.h
      • bitmap.c
    • 内存管理系统
      • 内存池规划
        • memery.h
        • memry.c
        • 运行结果截图
      • 按页分配内存
        • memery.h
        • memery.c
        • main.c
        • makefile
        • 运行结果
    • 结语

前言

本篇博客是第八章第二部分,主要完成位图相关实现和完整的内存管理系统。

第一部分博客:《操作系统真象还原》第八章(1)——内存管理系统-CSDN博客

本章参考博客:《操作系统真象还原》第八章 ---- 初入内存管理系统 涉足MakeFile 了解摸谈一二_makefile内存管理-CSDN博客


位图bitmap及其函数的实现

位图,也就是bitmap,广泛用于资源管理,是一种管理资源的方式、手段。“资源”包括很多,比如内存或硬盘,对于此类大容量资源的管理一般都会采用位图的方式。

简单来说,我们用一个字符数组来保存一个二进制位串,用这个二进制串来映射内存。一个位由0/1两种状态,代表一个内存页4kb的空间是否被使用。放一张书上的截图辅助理解。

本节又新增两个文件bitmap.c和bitmap.h,它们位于lib/kernel/下。

bitmap.h

//这个头文件定义了位图的结构体和函数
//位图是一个用来表示某些资源是否被占用的结构体
#ifndef __LIB_KERNEL_BITMAP_H
#define __LIB_KERNEL_BITMAP_H
#include "stdint.h"
#define BITMAP_MASK 1 //掩码
struct bitmap{uint32_t btmp_bytes_len; //位图的长度/*关于位图指针,遍历位图时,整体以字节为单位,细节上以位为单位,所以位图指针还是从单字节类型*/uint8_t *btmp_bits; //位图的指针
};void bitmap_init(struct bitmap *btmp); //初始化位图为0
bool bitmap_scan_test(struct bitmap *btmp, uint32_t bit_idx); //测试位图的某一位是0还是1
int bitmap_scan(struct bitmap *btmp, uint32_t cnt); //申请连续的cnt个位
void bitmap_set(struct bitmap *btmp, uint32_t bit_idx, int8_t value); //设置位图的某一位为0或1
#endif

bitmap.c

//实现位图相关操作函数
#include "bitmap.h"
#include "debug.h"
#include "string.h"
#include "stdint.h"
#include "print.h"
#include "interrupt.h"/* 将位图bitmap初始化为0 */
void bitmap_init(struct bitmap *btmp) {ASSERT(btmp != NULL);memset(btmp->btmp_bits, 0, btmp->btmp_bytes_len);
}/* 判断bit_idx位是否是1,为1返回true,否则返回false */
bool bitmap_scan_test(struct bitmap *btmp, uint32_t bit_idx) {ASSERT(btmp != NULL);ASSERT(bit_idx < btmp->btmp_bytes_len * 8);uint32_t byte_idx = bit_idx / 8; //字节索引uint32_t bit_odd = bit_idx % 8; //位索引return (btmp->btmp_bits[byte_idx] & (BITMAP_MASK << bit_odd)) != 0;
}/* 在位图中申请连续的cnt个位,若成功,返回起始下标,失败返回-1 */
int bitmap_scan(struct bitmap *btmp, uint32_t cnt) {ASSERT(btmp != NULL);uint32_t idx_byte = 0; //字节索引//先找到对应的字节,如果这个字节的值是0xff,说明这个字节的所有位都被占用//如果这个字节的值不是0xff,说明这个字节中有空闲位while ((idx_byte < btmp->btmp_bytes_len) && (btmp->btmp_bits[idx_byte] == 0xff)) {idx_byte++;}ASSERT(idx_byte < btmp->btmp_bytes_len);//如果idx_byte == btmp->btmp_bytes_len,说明没有找到空闲位if(idx_byte == btmp->btmp_bytes_len) {return -1; //没有找到空闲位}//如果idx_byte < btmp->btmp_bytes_len,说明找到了空闲位//找到空闲位后,找到这个字节中第一个空闲位int idx_bit = 0;while ((idx_bit < 8) && ((btmp->btmp_bits[idx_byte] & (BITMAP_MASK << idx_bit)) != 0)) {idx_bit++;}int bit_idx_start = idx_byte * 8 + idx_bit; //起始位索引if (cnt == 1) {return bit_idx_start;}uint32_t bit_left = (btmp->btmp_bytes_len * 8 - bit_idx_start); //剩余位数uint32_t next_bit = bit_idx_start + 1;uint32_t count = 1; //计数器bit_idx_start = -1; //初始化为-1while (bit_left-- > 0) {if(bitmap_scan_test(btmp, next_bit) == 0) {count++;}else {count = 0; //重置计数器}if (count == cnt) {bit_idx_start = next_bit - cnt + 1; //起始位索引break;}next_bit++;}return bit_idx_start; //返回起始位索引
}/* 将位图的bit_idx位设置为value */
void bitmap_set(struct bitmap *btmp, uint32_t bit_idx, int8_t value) {ASSERT(btmp != NULL);ASSERT(bit_idx < btmp->btmp_bytes_len * 8);ASSERT(value == 0 || value == 1);//ASSERT(value == 0 || value == 1); //value只能是0或1uint32_t byte_idx = bit_idx / 8; //字节索引uint32_t bit_odd = bit_idx % 8; //位索引if (value) {btmp->btmp_bits[byte_idx] |= (BITMAP_MASK << bit_odd); //设置为1}else {btmp->btmp_bits[byte_idx] &= ~(BITMAP_MASK << bit_odd); //设置为0}
}

内存管理系统

内存池规划

先说物理内存池,目前规划是内核和用户进程各占一半,用户进程申请内存的单位是标准页4kb。

再说虚拟地址。内核为完成某项工作,也需要申请内存,我们让内核也通过内存管理系统申请内存,为此,它也要有个虚拟地址池,当它申请内存时,从内核自己的虚拟地址池中分配虚拟地址,再从内核物理内存池(内核专用)中分配物理内存,然后在内核自己的页表将这两种地址建立好 映射关系。

对用户进程来说,它向内存管理系统,即操作系统,申请内存时,操作系统先从用户进程自己的虚拟 地址池中分配空闲虚拟地址,然后再从用户物理内存池(所有用户进程共享)中分配空闲的物理内存,然 后在该用户进程自己的页表将这两种地址建立好映射关系。

memery.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;       //虚拟地址起始位置
};extern struct pool kernel_pool; //内核内存池
extern struct pool user_pool;   //用户内存池
void mem_pool_init(uint32_t all_mem); //内存池初始化
void mem_init(void); //内存管理初始化
#endif
memry.c
//实现memery.h中的函数
#include "memery.h"
#include "print.h"
#include "stdint.h"#define PAGE_SIZE 4096 //定义页面大小为4KB
//关于位图地址,安排在0xc009a000,我的整个系统支持4个4kb位图,共管理512MB的内存
#define MEM_BITMAP_BASE 0xc009a000 //内核内存池位图基地址#define K_HEAP_START 0xc0100000 //内核堆起始地址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 mem_pool_init(uint32_t all_mem){put_str("  mem_pool_init start\n");uint32_t page_table_size = 256 * PAGE_SIZE; //计算页表使用的内存的大小uint32_t used_mem = page_table_size + 0x100000; //计算已用内存uint32_t free_mem = all_mem - used_mem; //计算总可用内存uint16_t all_free_pages = free_mem / PAGE_SIZE; //计算总可用页数uint16_t kernel_free_pages = all_free_pages / 2; //内核可用页数uint16_t user_free_pages = all_free_pages - kernel_free_pages; //用户可用页数uint32_t kbm_len = kernel_free_pages / 8; //内核位图长度uint32_t ubm_len = user_free_pages / 8; //用户位图长度uint32_t kp_start = used_mem; //内核内存池起始地址uint32_t up_start = kp_start + kernel_free_pages * PAGE_SIZE; //用户内存池起始地址kernel_pool.phy_addr_start = kp_start; //设置内核内存池起始地址user_pool.phy_addr_start = up_start; //设置用户内存池起始地址kernel_pool.pool_size = kernel_free_pages * PAGE_SIZE; //设置内核内存池大小user_pool.pool_size = user_free_pages * PAGE_SIZE; //设置用户内存池大小kernel_pool.pool_bitmap.btmp_bytes_len = kbm_len; //设置内核位图长度user_pool.pool_bitmap.btmp_bytes_len = ubm_len; //设置用户位图长度kernel_pool.pool_bitmap.btmp_bits = (void *)MEM_BITMAP_BASE; //设置内核位图地址user_pool.pool_bitmap.btmp_bits = (void *)(MEM_BITMAP_BASE + kbm_len); //设置用户位图地址/* 输出内存池信息 */put_str("    kernel_pool_bitmap_start: ");put_int((int)kernel_pool.pool_bitmap.btmp_bits);put_char('\n');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.btmp_bits);put_char('\n');put_str("    user_pool_phy_addr_start: ");put_int(user_pool.phy_addr_start);put_char('\n');/* 将池内位图置0 */bitmap_init(&kernel_pool.pool_bitmap); //初始化内核位图bitmap_init(&user_pool.pool_bitmap); //初始化用户位图/* 初始化内核虚拟地址的位图 */kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_len; //设置内核虚拟地址位图长度kernel_vaddr.vaddr_bitmap.btmp_bits = \(void *)(MEM_BITMAP_BASE + kbm_len + ubm_len); //设置内核虚拟地址位图地址kernel_vaddr.vaddr_start = K_HEAP_START; //设置内核虚拟地址起始位置bitmap_init(&kernel_vaddr.vaddr_bitmap); //初始化内核虚拟地址位图put_str("  mem_pool_init done\n");
}/* 内存管理初始化入口 */
void mem_init(void){put_str("mem_init start\n");uint32_t mem_bytes_total = (*(uint32_t *)(0xb00)); //获取内存总大小mem_pool_init(mem_bytes_total); //初始化内存池put_str("mem_init done\n");
}
运行结果截图

按页分配内存

复习下32位虚拟地址的转换过程。

  1. 高10位是页目录项pde的索引,用于在页目录表中定位pde,细节是处理器获取高10位后自动 将其乘以4,再加上页目录表的物理地址,这样便得到了pde索引对应的pde所在的物理地址,然后自动在该物理地址中,即该pde中,获取保存的页表物理地址。
  2. 中间10位是页表项pte的索引,用于在页表中定位pte。细节是处理器获取中间10位后自动将 其乘以4,再加上第一步中得到的页表的物理地址,这样便得到了pte索引对应的pte所在的物理地址, 然后自动在该物理地址(该pte)中获取保存的普通物理页的物理地址。
  3. 低 12位是物理页内的偏移量,页大小是4KB,12位可寻址的范围正好是4KB,因此处理器便直 接把低12位作为第二步中获取的物理页的偏移量,无需乘以4。用物理页的物理地址加上这低12位的和 便是这32位虚拟地址最终落向的物理地址。 32 位地址经过以上三步拆分,地址最终落在某个物理页内
memery.h
//声明了虚拟将地址池结构体
#ifndef __KERNEL_MEMORY_H
#define __KERNEL_MEMORY_H
#include "stdint.h"
#include "bitmap.h"/* 内存池标记 */
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 //用户特权级struct virtual_addr
{struct bitmap vaddr_bitmap; //虚拟地址位图uint32_t vaddr_start;       //虚拟地址起始位置
};extern struct pool kernel_pool; //内核内存池
extern struct pool user_pool;   //用户内存池
void mem_pool_init(uint32_t all_mem); //内存池初始化
void mem_init(void); //内存管理初始化
#endif
memery.c
//实现memery.h中的函数
#include "memery.h"
#include "bitmap.h"
#include "stdint.h"
#include "global.h"
#include "debug.h"
#include "print.h"
#include "string.h"#define PAGE_SIZE 4096 //定义页面大小为4KB
//关于位图地址,安排在0xc009a000,我的整个系统支持4个4kb位图,共管理512MB的内存
#define MEM_BITMAP_BASE 0xc009a000 //内核内存池位图基地址
#define K_HEAP_START 0xc0100000 //内核堆起始地址#define PDE_INDEX(addr) ((addr & 0xffc00000) >> 22) //获取页目录项索引
#define PTE_INDEX(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 mem_pool_init(uint32_t all_mem){put_str("  mem_pool_init start\n");uint32_t page_table_size = 256 * PAGE_SIZE; //计算页表使用的内存的大小uint32_t used_mem = page_table_size + 0x100000; //计算已用内存uint32_t free_mem = all_mem - used_mem; //计算总可用内存uint16_t all_free_pages = free_mem / PAGE_SIZE; //计算总可用页数uint16_t kernel_free_pages = all_free_pages / 2; //内核可用页数uint16_t user_free_pages = all_free_pages - kernel_free_pages; //用户可用页数uint32_t kbm_len = kernel_free_pages / 8; //内核位图长度uint32_t ubm_len = user_free_pages / 8; //用户位图长度uint32_t kp_start = used_mem; //内核内存池起始地址uint32_t up_start = kp_start + kernel_free_pages * PAGE_SIZE; //用户内存池起始地址kernel_pool.phy_addr_start = kp_start; //设置内核内存池起始地址user_pool.phy_addr_start = up_start; //设置用户内存池起始地址kernel_pool.pool_size = kernel_free_pages * PAGE_SIZE; //设置内核内存池大小user_pool.pool_size = user_free_pages * PAGE_SIZE; //设置用户内存池大小kernel_pool.pool_bitmap.btmp_bytes_len = kbm_len; //设置内核位图长度user_pool.pool_bitmap.btmp_bytes_len = ubm_len; //设置用户位图长度kernel_pool.pool_bitmap.btmp_bits = (void *)MEM_BITMAP_BASE; //设置内核位图地址user_pool.pool_bitmap.btmp_bits = (void *)(MEM_BITMAP_BASE + kbm_len); //设置用户位图地址/* 输出内存池信息 */put_str("    kernel_pool_bitmap_start: ");put_int((int)kernel_pool.pool_bitmap.btmp_bits);put_char('\n');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.btmp_bits);put_char('\n');put_str("    user_pool_phy_addr_start: ");put_int(user_pool.phy_addr_start);put_char('\n');/* 将池内位图置0 */bitmap_init(&kernel_pool.pool_bitmap); //初始化内核位图bitmap_init(&user_pool.pool_bitmap); //初始化用户位图/* 初始化内核虚拟地址的位图 */kernel_vaddr.vaddr_bitmap.btmp_bytes_len = kbm_len; //设置内核虚拟地址位图长度kernel_vaddr.vaddr_bitmap.btmp_bits = \(void *)(MEM_BITMAP_BASE + kbm_len + ubm_len); //设置内核虚拟地址位图地址kernel_vaddr.vaddr_start = K_HEAP_START; //设置内核虚拟地址起始位置bitmap_init(&kernel_vaddr.vaddr_bitmap); //初始化内核虚拟地址位图put_str("  mem_pool_init done\n");
}/* 内存管理初始化入口 */
void mem_init(void){put_str("mem_init start\n");uint32_t mem_bytes_total = (*(uint32_t *)(0xb00)); //获取内存总大小mem_pool_init(mem_bytes_total); //初始化内存池put_str("mem_init done\n");
}/* 在pf表示的虚拟内存池中申请pg_cnt个虚拟页,成功则返回虚拟页的起始地址,失败则返回NULL */
static void *vaddr_get(enum pool_flags pf, uint32_t pg_cnt){int bit_idx_start = -1; //位图索引uint32_t vaddr_start = 0; //虚拟地址uint32_t cnt = 0; //计数器if (pf == PF_KERNEL){ //内核内存池//扫描位图,找到空余的pg_cnt个位,对应相等的页bit_idx_start = bitmap_scan(&kernel_vaddr.vaddr_bitmap, pg_cnt); if (bit_idx_start == -1){ //没有找到合适的位置return NULL;}//找到后把位图中pg_cnt个位置设置为1,表示这些页已分配while(cnt < pg_cnt){ bitmap_set(&kernel_vaddr.vaddr_bitmap, bit_idx_start + cnt++, 1); //设置位图}vaddr_start = kernel_vaddr.vaddr_start + bit_idx_start * PAGE_SIZE; //计算虚拟地址}else { //用户内存池//整体和内核内存池类似,只是这里的位图是用户内存池的位图/*bit_idx_start = bitmap_scan(&user_pool.pool_bitmap, pg_cnt); //扫描位图if (bit_idx_start == -1){ //没有找到合适的地址return NULL;}while(cnt < pg_cnt){ bitmap_set(&user_pool.pool_bitmap, bit_idx_start + cnt++, 1); //设置位图}vaddr_start = user_pool.phy_addr_start + bit_idx_start * PAGE_SIZE; //计算虚拟地址*/}return (void *)vaddr_start; //返回虚拟地址
}/* 得到虚拟地址vaddr对应的pte的指针 */
uint32_t *pte_ptr(uint32_t vaddr){uint32_t *pte= (uint32_t *)(0xffc00000 + \((vaddr & 0xffc00000) >> 10) + \PTE_INDEX(vaddr) * 4); //计算页表项地址return pte; //返回页表项地址
}/* 得到虚拟地址vaddr对应的pde的指针 */
uint32_t *pde_ptr(uint32_t vaddr){uint32_t *pde = (uint32_t *)(0xfffff000 + \PDE_INDEX(vaddr) * 4); //计算页目录项地址return pde; //返回页目录项地址
}/* 在m_pool 指向的物理内存池中分配一个物理页,成功返回页物理地址,失败返回NULL */
static 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 = m_pool->phy_addr_start + bit_idx * PAGE_SIZE; //计算物理地址return (void *)page_phyaddr; //返回物理地址
}/* 页表中添加虚拟地址_vaddr与物理地址_page_phyaddr的映射 */ 
static void page_table_add(void *_vaddr, void *_page_phyaddr){uint32_t vaddr = (uint32_t)_vaddr; //虚拟地址uint32_t 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("page_table_add: 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 *)((uint32_t)pte & 0xfffff000), 0, PAGE_SIZE); //清空页表ASSERT(!(*pte & 0x00000001));*pte = page_phyaddr | PG_US_U | PG_RW_W | PG_P_1; //设置页表项}
}/* 分配pg_cnt个页空间,成功则返回起始虚拟地址,失败时返回NULL */ 
/* 上面三个函数的合成 */
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; //虚拟地址起始位置uint32_t 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 += PAGE_SIZE; //移动到下一个页}return vaddr_start; //返回虚拟地址
}/* 从内核物理内存池中申请pg_cnt页内存,成功则返回其虚拟地址,失败则返回NULL */
void *get_kernel_pages(uint32_t pg_cnt){void *vaddr = malloc_page(PF_KERNEL, pg_cnt); //申请内存if (vaddr != NULL){ //申请成功memset(vaddr, 0, pg_cnt * PAGE_SIZE); //清空内存}return vaddr; //返回虚拟地址
}
main.c
//内核的入口函数
#include "print.h"
#include "init.h"
#include "debug.h"
#include "memery.h"
int main(void){put_str("HongBai's OS\n");init_all();//初始化所有模块//中断测试,目前只完成了响应时钟中断//asm volatile("sti");//打开中断//asm volatile("cli");//关闭中断//断言测试//ASSERT(1 == 2); // 断言失败,会调用panic_spin函数//申请内存测试void *addr = get_kernel_pages(3); //申请3页内存put_str("get_kernel_pages start vaddr is: ");put_int((uint32_t)addr); //输出虚拟地址put_str("\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)/memery.o \$(BUILD_DIR)/bitmap.o##############     c代码编译     			###############
$(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \lib/kernel/stdint.h kernel/init.h lib/string.h kernel/memery.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \lib/kernel/stdint.h kernel/interrupt.h device/timer.h kernel/memery.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \lib/kernel/stdint.h kernel/global.h kernel/io.h lib/kernel/print.h$(CC) $(CFLAGS) $< -o $@$(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/stdint.h\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/kernel/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)/memery.o: kernel/memery.c kernel/memery.h \lib/kernel/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 allmk_dir:if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fihd:dd if=$(BUILD_DIR)/kernel.bin \of=/home/hongbai/bochs/bin/c.img \bs=512 count=200 seek=10 conv=notruncclean:cd $(BUILD_DIR) && rm -f  ./*build: $(BUILD_DIR)/kernel.binall: mk_dir build hd
运行结果


结语

这章到这里也就结束了,总的来说第7第8章真正自己写的代码不多,cv和代码补全的不少,最后结果还有一点点和书上不同,需要后续改进。

贴一下目前的目录:

可以看到经过这两章节的实现,新的文件越来越多,文件关系越来越复杂,我们的操作系统也越来越完善,离最终的完成又近了很多。

目前的目录还需要进一步梳理,我博客中贴出的代码可能也有一些小错误,还请大家酌情参考。等到最后操作系统完成后,我会在github上上传相关的makedown文档和所有源码。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词