相关查阅博客链接
linux 中“.”和“…”代表什么意思 C语言中extern的用法
本书中错误勘误
闲聊时刻
各位看官 又来到了每章必到的闲聊时刻了哈 哈哈 这次我想想又想聊点什么呢 感觉刚刚有很多话想说 自己编辑的时候的又写不出来什么
就是聊一下最近写这个《操作系统真象还原》相关的章节博客嘛 其实说实话 因为每一章其实我都是自己定了时间大概多久就必须完成 但其实往往每一章花的时间要比我预计的时间还是要多个一天多
除此之外呢 其实我真的觉得写这个还是相当的不轻松的 当然书籍作者是最不轻松的 不仅要把代码写完 还要以各种方式把整个实现给呈现出来 不轻松的原因就是 我还是特别希望整个操作系统十五章 每一章的博客我都尽量写的细致一点 当然最主要的原因是 写操作系统的代码确实太不好写了
细节多 而且我是属于全部都自己能思考清楚之后 我再大部分看了代码 自己再写一遍 而不是属于很纯粹的copy 你让那些copy 代码的人来说一下 各种地方的实现原理 我相信是根本说不出来的 而且这个写操作系统纯copy 代码的人而言 是真的我不相信有几个能写下来 哈哈
为什么我会这样说呢 因为我自己的情况就是 比如写一章花的时间是12小时 3-5小时敲代码 + 6-7小时调试各种问题 + 2-3个小时写博客 这里当然是抛开了思考时间 看书的时间 不清楚思路 不清楚代码为什么这样写的人 写出来的代码出现了问题 你让他去debug 哈哈 根本就是痴人说梦了 而且书中时不时的还会出现一些错误 不带着思考审视的眼光去看 去写代码 很多地方就会被卡死
现在也来到了倒数第二章了 我看了看内容 这十四章的实现思路总的来说呢 还是挺清晰的 后面我应该会先写思路写出来 再给代码
写了那么多 其实我当时就想说 写这个操作系统 真的得连续花时间一鼓作气写下去 如果心里面不沉淀下来 很多人中途就会放弃 而且其实写这个的这段时间 我总是感觉有一个沉沉的担子在身上 就是感觉心里面装了事情 一点都不轻松 可能到最后操作系统写完的那一天 我把最后的博客发了 并且把代码先全贴出来 看能不能放到github 上面 最后再贴个链接 可能要给自己放个一天的假了 哈哈哈哈 到时候再说吧 先一步步做着走 那下面再见
部分缩写熟知
fs file system 文件系统 ft file type 文件类型
由于我没怎么用过. .. 经常用 所以下面提一嘴 在Linux 中 . 是当前目录 .. 是到上一级目录
实现文件系统的原理
这个的话 还是内容挺多的 刚刚和我的好homie聊了会天 聊了个把小时 一直没心思写这部分的内容 现在静下来了 我就来写一下
我们话说在前面 我们不聊FAT 文件系统 FAT 文件系统不好的地方 就在于每个文件节点的末尾都用链表链接 每次寻找文件的话都只能通过链表遍历一遍才能找到
好了 说了不聊还是聊了一下 哈哈 回到我们的重点
inode构建原理
我们采用Linux 文件系统的思路 什么是核心呢 inode 对 inode 起到什么作用呢 inode 基本上可以代表着文件 这个话说的有点武断 但是我们可以通过inode 寻找到文件所在的磁盘位置 这是怎么寻找到的呢 我们先介绍这个 待会在介绍上一层的目录
我们对硬盘进行了分区 当然可以不分 先不聊分区 linux 中的inode 有多少inode 就有多少文件 inode 中有个15 的整型数组 其中0-12 是直接的lba 块所在直接编号 这够直接吧 对的 我们通过访问inode 中的数组就能直接找到文件所在的块位置 那一个块大小挺小的 15 个整型数组怎么存放的到那么多块呢 比如一个文件2GB 我们怎么存放呢 对了 可能有聪明的hxd就想到了 我们的第13号可以指定一个区域的块 里面存放着块信息 这样是不是就扩大了呢 哈哈 那怎么扩的更大呢 我们第14号就指定的那个区域 里面的区域全是存放着另一个区域的块号 而那个另一个区域里面再负责指定精准块号不就行了吗 哈哈 这样其实就相当多了 依次类推即可
对了 再额外提一嘴 inode 里面除了存放文件具体存储在哪些块 还存放着 文件日期 访问权限 大小 当然还有编号 除了大小 编号 其他的都是比较成熟的文件系统构建的 我们的小型系统就不构建这些啦 哈哈
inode 文件并不关心里面装的是什么类型 并且里面也没有说明 但是这和我们平时的认识就冲突了 我们的文件有各种类型 比如在windos下的 mp4 jpg docx 那我们访问的时候怎么知道文件是什么类型呢 哈哈 而且我们平时访问文件的时候也根本没有出现inode 我们又是怎么访问到的呢 这又要引出下面一个概念了 目录 各位看官往下看
目录构建原理
站在inode 的上一层 我的理解就是目录 比如我们的windows 我们与文件的交互 都是利用图标与文件名 对吧 不存在什么inode 编号 如果我们访问每个文件都是采用输入inode 编号来访问的 那也是真的太烦人了吧 哈哈
目录是干什么的呢 我们与文件交互都是利用文件名 而且我们也会给文件命名 文件系统是以一种树的类型建立起来的 我们访问一个文件 如果目录项里面的文件名和我们的文件名匹配 并且目录项里面存放着的有该文件的inode 编号 以及文件类型 我们不是可以把相关文件交给相关文件处理文件处理啦 那我们上面的问题不是迎刃而解了 是吧
注意 inode 可不管你文件类型是什么 这叫给目录项来管理 但是我们访问目录找到指定的文件 是一级一级的寻找 我们是不是必须要把根目录给固定下来 找inode 首先需要先找目录 找到对应的inode 编号 再通过inode 编号找到具体的inode 再通过具体的inode 访问到对应的块
那找目录 我们从哪里开始找呢 对了 就是根目录 我们必须要把根目录固定下来 不然每次我们都不知道在哪里找目录 而目录文件也是文件类型的一种 找文件的话又要通过inode 找 找inode 又要通过目录项来找 这样的话进入死循环了 怎么办
就如我说的那样 固定 固定下来 我们必须要把最底层的东西固定下来 我们的第一个inode 固定成根目录的专属inode 每一次找根目录 直接找固定下来的根目录位置 那我们怎么找固定根目录位置呢 哈哈 这又要引入一个下面的一个概念了 超级块
超级块构建思路
书上我记得有一句话说的特别好 就是其实很多在上面的东西 都必须要依靠最底层最固定的东西 仔细想了一想是这个样子的 都写到接近尾声了 我现在都还能记得 我们第一步写mbr 的时候 cpu 读入的时候 不都是确定了必须是硬盘的第一块扇区吗 就像mbr 也必须是确定要512字节的 很多东西都是必须要确定下来 后面的东西才能依次开展
超级块 是干什么的呢 我们既然要分区 那我们很多地方的起始位置 或者 存放位置是不是得固定下来 比如inode数组 的位置 inode数组 由位图来管理 空闲块也由位图来管理 这些位图位置是不是得放好了之后得存在超级块里面呢
那当然 超级块的位置肯定是确定好了 我们放在哪里呢 哈哈 这又得说 我们的引导块是放在除去第一个扇区后面的 我把书上的原图拍下来是给弄在这里 方便各位学习
哈哈 是不是特别贴心
然后超级块里面 也是存放着该分区的各种信息 很多很多 这里也可以贴一下 我就懒得说那么多了 哈哈 当然这是我们的小型操作系统所要用的 其他的都很少
总得来说就是那么多了 代码里面我可是满满的注释 超级详细 哈哈 直接上代码咯
创建文件系统
编写完的super_block.h
路径fs/super_block.h
#ifndef __FS_SUPER_BLOCK_H
#define __FS_SUPER_BLOCK_H
struct super_block
{
uint32_t magic;
uint32_t sec_cnt;
uint32_t inode_cnt;
uint32_t part_lba_base;
uint32_t block_bitmap_lba;
uint32_t block_bitmap_sects;
uint32_t inode_bitmap_lba;
uint32_t inode_bitmap_sects;
uint32_t inode_table_lba;
uint32_t inode_table_sects;
uint32_t data_start_lba;
uint32_t root_inode_no;
uint32_t dir_entry_size;
uint8_t pad[460];
}; __attribute__ ((packed));
#endif
编写完的inode.h
路径fs/inode.h
#ifndef __FS_INODE_H
#define __FS_INODE_H
#include "list.h"
struct inode
{
uint32_t i_no;
uint32_t i_size;
uint32_t i_open_cnts;
bool write_deny;
uint32_t i_sectors[13];
struct list_elem inode_tag;
};
#endif
编写完的dir.h
#ifndef __FS_DIR_H
#define __FS_DIR_H
#define MAX_FILE_NAME_LEN 16
struct dir
{
struct inode* inode;
uint32_t dir_pos;
uint8_t dir_buf[512];
};
struct dir_entry
{
char filename[MAX_FILE_NAME_LEN];
uint32_t i_no;
enum file_types f_type;
};
#endif
编写完的fs.h
路径fs/fs.h
#ifndef __FS_FS_H
#define __FS_FS_H
#include "ide.h"
#define MAX_FILES_PER_PART 4096
#define BITS_PER_SECTOR 4096
#define SECTOR_SIZE 512
#define BLOCK_SIZE SECTOR_SIZE
enum file_types
{
FT_UNKNOWN,
FT_REGULAR,
FT_DIRECTORY
};
void partition_format(struct disk* hd,struct partition* part);
bool mount_partition(struct list_elem* pelem,int arg);
void filesys_init(void);
#endif
编写完的fs.c
#include "fs.h"
#include "stdint.h"
#include "global.h"
#include "../device/ide.h"
#include "inode.h"
#include "dir.h"
#include "super_block.h"
#include "stdio-kernel.h"
#include "string.h"
#include "debug.h"
#include "list.h"
struct partition* cur_part;
void partition_format(struct disk* hd,struct partition* part)
{
uint32_t boot_sector_sects = 1;
uint32_t super_block_sects = 1;
uint32_t inode_bitmap_sects = DIV_ROUND_UP(MAX_FILES_PER_PART,BITS_PER_SECTOR);
uint32_t inode_table_sects = DIV_ROUND_UP((sizeof(struct inode) * MAX_FILES_PER_PART),SECTOR_SIZE);
uint32_t used_sects = boot_sector_sects + super_block_sects + inode_bitmap_sects + inode_table_sects;
uint32_t free_sects = part->sec_cnt - used_sects;
uint32_t block_bitmap_sects = DIV_ROUND_UP(free_sects,BITS_PER_SECTOR);
uint32_t block_bitmap_bit_len = free_sects - block_bitmap_sects;
block_bitmap_sects = DIV_ROUND_UP(block_bitmap_bit_len,BITS_PER_SECTOR);
struct super_block sb;
sb.magic = 0x23333333;
sb.sec_cnt = part->sec_cnt;
sb.inode_cnt = MAX_FILES_PER_PART;
sb.part_lba_base = part->start_lba;
sb.block_bitmap_lba = part->start_lba + boot_sector_sects + super_block_sects;
sb.block_bitmap_sects = block_bitmap_sects;
sb.inode_bitmap_lba = sb.block_bitmap_lba + block_bitmap_sects;
sb.inode_bitmap_sects = inode_bitmap_sects;
sb.inode_table_lba = sb.inode_bitmap_lba + inode_bitmap_sects;
sb.inode_table_sects = inode_table_sects;
sb.data_start_lba = sb.inode_table_lba + inode_table_sects;
sb.root_inode_no = 0;
sb.dir_entry_size = sizeof(struct dir_entry);
printk("%s info:\n",part->name);
printk(" magic:0x%x\n part_lba_base:0x%x\n all_sectors:0x%x\n \
inode_cnt:0x%x\n block_bitmap_lba:0x%x\n block_bitmap_sectors:0x%x\n \
inode_bitmap_lba:0x%x\n inode_bitmap_sectors:0x%x\n \
inode_table_lba:0x%x\n inode_table_sectors:0x%x\n \
data_start_lba:0x%x\n", \
sb.magic,sb.part_lba_base,sb.sec_cnt,sb.inode_cnt,sb.block_bitmap_lba,sb.block_bitmap_sects,\
sb.inode_bitmap_lba,sb.inode_bitmap_sects,sb.inode_table_lba,\
sb.inode_table_sects,sb.data_start_lba);
ide_write(hd,part->start_lba + boot_sector_sects,&sb,super_block_sects);
printk(" super_block_lba:0x%x\n",part->start_lba + 1);
uint32_t buf_size = (sb.block_bitmap_sects >= sb.inode_bitmap_sects) ? sb.block_bitmap_sects : sb.inode_bitmap_sects;
buf_size = ((buf_size >= inode_table_sects) ? buf_size : inode_table_sects) * SECTOR_SIZE;
uint8_t* buf = (uint8_t*)sys_malloc(buf_size);
buf[0] |= 0;
uint8_t block_bitmap_last_byte = block_bitmap_bit_len / 8;
uint8_t block_bitmap_last_bit = block_bitmap_bit_len % 8;
uint32_t last_size = SECTOR_SIZE - (block_bitmap_last_byte % SECTOR_SIZE);
memset(&buf[block_bitmap_last_byte],0xff,last_size);
uint8_t bit_idx = 0;
while(bit_idx <= block_bitmap_last_bit)
buf[block_bitmap_last_byte] &= ~(1 << (bit_idx++));
ide_write(hd,sb.block_bitmap_lba,buf,sb.block_bitmap_sects);
memset(buf,0,buf_size);
buf[0] |= 0x1;
ide_write(hd,sb.inode_bitmap_lba,buf,sb.inode_bitmap_sects);
memset(buf,0,buf_size);
struct inode* i = (struct inode*)buf;
i->i_size = sb.dir_entry_size * 2;
i->i_no = 0;
i->i_sectors[0] = sb.data_start_lba;
ide_write(hd,sb.inode_table_lba,buf,sb.inode_table_sects);
memset(buf,0,buf_size);
struct dir_entry* p_de = (struct dir_entry*)buf;
memcpy(p_de->filename,",",1);
p_de->i_no = 0;
p_de->f_type = FT_DIRECTORY;
p_de++;
p_de->i_no = 0;
p_de->f_type = FT_DIRECTORY;
ide_write(hd,sb.data_start_lba,buf,1);
printk(" root_dir_lba:0x%x\n",sb.data_start_lba);
printk("%s format done\n",part->name);
sys_free(buf);
}
bool mount_partition(struct list_elem* pelem,int arg)
{
char* part_name = (char*)arg;
struct partition* part = elem2entry(struct partition,part_tag,pelem);
if(!strcmp(part->name,part_name))
{
cur_part = part;
struct disk* hd = cur_part->my_disk;
struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);
if(sb_buf == NULL)
PANIC("alloc memory failed!");
memset(sb_buf,0,SECTOR_SIZE);
ide_read(hd,cur_part->start_lba + 1,sb_buf,1);
cur_part->sb = sb_buf;
cur_part->block_bitmap.bits = (uint8_t*)sys_malloc(sb_buf->block_bitmap_sects * SECTOR_SIZE);
if(cur_part->block_bitmap.bits == NULL)
PANIC("alloc memory failed!");
cur_part->block_bitmap.btmp_bytes_len = sb_buf->block_bitmap_sects * SECTOR_SIZE;
ide_read(hd,sb_buf->block_bitmap_lba,cur_part->block_bitmap.bits,sb_buf->block_bitmap_sects);
cur_part->inode_bitmap.bits = (uint8_t*)sys_malloc(sb_buf->inode_bitmap_sects * SECTOR_SIZE);
if(cur_part->inode_bitmap.bits == NULL)
PANIC("alloc memory failed!");
cur_part->inode_bitmap.btmp_bytes_len = sb_buf->inode_bitmap_sects * SECTOR_SIZE;
ide_read(hd,sb_buf->inode_bitmap_lba,cur_part->inode_bitmap.bits,sb_buf->inode_bitmap_sects);
list_init(&cur_part->open_inodes);
printk("mount %s done!\n",part->name);
return true;
}
return false;
}
void filesys_init(void)
{
uint8_t channel_no = 0,dev_no,part_idx = 0;
struct super_block* sb_buf = (struct super_block*)sys_malloc(SECTOR_SIZE);
if(sb_buf == NULL) PANIC("alloc memory failed!");
printk("searching filesysteam......\n");
while(channel_no < channel_cnt)
{
dev_no = 1;
while(dev_no < 2)
{
if(!dev_no)
{
++dev_no;
continue;
}
struct disk* hd = &channels[0].devices[1];
struct partition* part = hd->prim_parts;
while(part_idx < 12)
{
if(part_idx == 4)
part = hd->logic_parts;
if(part->sec_cnt != 0)
{
memset(sb_buf,0,SECTOR_SIZE);
ide_read(hd,part->start_lba +1,sb_buf,1);
if(sb_buf->magic != 0x23333333)
{
printk("formatting %s's partition %s......\n",\
hd->name,part->name);
partition_format(hd,part);
}
else
printk("%s has filesystem\n",part->name);
}
++part_idx;
++part;
}
++dev_no;
}
++channel_no;
}
sys_free(sb_buf);
char default_part[8] = "sdb1";
list_traversal(&partition_list,mount_partition,(int)default_part);
}
修改后的ide.h
增加下面三条
extern uint8_t channel_cnt;
extern struct ide_channel channels[2];
extern struct list partition_list;
修改后的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 \
$(BUILD_DIR)/stdio-kernel.o $(BUILD_DIR)/ide.o $(BUILD_DIR)/fs.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 \
lib/kernel/stdio-kernel.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 device/ide.h fs/fs.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 kernel/global.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 \
kernel/memory.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)/stdio-kernel.o: lib/kernel/stdio-kernel.c lib/kernel/stdio-kernel.h \
lib/stdio.h device/console.h
$(CC) $(CFLAGS) $< -o $@
$(BUILD_DIR)/ide.o: device/ide.c device/ide.h lib/stdint.h kernel/debug.h \
lib/kernel/stdio-kernel.h lib/stdio.h kernel/global.h thread/sync.h \
lib/kernel/io.h device/timer.h kernel/interrupt.h lib/kernel/list.h fs/fs.h
$(CC) $(CFLAGS) $< -o $@
$(BUILD_DIR)/fs.o: fs/fs.c fs/fs.h lib/stdint.h kernel/global.h device/ide.h fs/inode.h fs/dir.h \
fs/super_block.h lib/kernel/stdio-kernel.h lib/string.h kernel/debug.h lib/kernel/list.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 .
修改后的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"
#include "../device/ide.h"
#include "../fs/fs.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();
ide_init();
filesys_init();
}
make all 验证成果
这里分两个个阶段 因为写入硬盘就直接写入了 和内存不一样 所以的话 最后一次重复的时候我们的文件系统已经创建完成 所以就直接出现sda1 has filesystem sda5 has filesystem sda6 has filesystem sda7 has filesystem sda8 has filesystem sda9 has filesystem
第一个make all阶段(第一次给分区装载文件系统)
这里的话 我当时把filesys_init 放到了ide_init的最后了 就导致最后一句是ide_init done 后面就单独弄出来了
第二个make all阶段(第二次给分区装载文件系统+挂载)
第二次的时候不仅装好了文件系统 还弄好了挂载 如下图所示
创建文件系统的debug心路历程
这部分与其说是创建文件系统的debug心路历程 还不如说是悲惨史 哈哈 真的还是挺惨的 感觉表面上我博客代码写的那么多 内容写的那么充实 其实背后我写代码 make all 编译不知道实现一部分功能我就需要调试编译几十次 如果出现大功能 整体做完出错了 我可能需要纠错 编译上百次 + 修改一些最基本的语法错误 总之还是真的很累人的
这次在创建文件系统最后的读取超级块的时候发生了错误 当时的时候 我心里面还没什么感觉 就觉得哪里肯定写了一点错误 但在排查了一个小时 用while(1); 断点尝试之后 发现就是在ide_read() 函数出了错
我之后仔细思考了一下 如果到后面的filesys_init 才出错的话 前面的ide_init 也是用了函数filesys_init 但我们的读取的内容都是对的 怎么到filesys_init 就出错了 此时我在想是不是线程切换出了错 此时我就倒吸了一口冷气 线程切换这个出了错那是相当不好调试的 啊 怎么办
没办法 只能一行一行尝试 断点尝试while(1) 并尝试printk 一些数据 看一下是不是哪里访问出错了 在从上午的11点到下午的2点 终于有了突破 发现错误在于ide_read函数 中的read_from_sector(); 函数
我刚开始认为是不是中断在那几次读过了之后就被屏蔽了 但在尝试了几次后 就发现没有问题 之后又想了想 不会是内存分配的问题吧 毕竟我们的内存都是malloc 出来的 我一直觉得malloc 那个地方细节太多了 真的调试起来难度相当相当大 最后在尝试了几次malloc 都发现挺合情合理的
那问题在哪里呢 在我摸不着头脑时 我就把ide_read 函数放在了sema_down 的前面 结果就发现不出错了 我当时冷汗更是直冒 问题出在sema_down 啊 但我事后仔细想了想 sema_down 的核心就在于阻塞 而核心应该是schedule 调度函数 一次偶然的尝试下 我看了看我们ide_read 前我们的页表 竟然发现我们的页表 我们分配的虚拟地址竟然不在页表中 我真的服了
之后又想了想 在schedule 前后 schedule 前可以ide_read schedule 后出错 后面进行了两次断点 发现如下图的页表 我们分配的虚拟地址是在0xc0101c0c 分配了512字节 最高地址在0xc0101e0c 还没有到0xc0101ffff
没有schedule 前的页表 schedule 后的页表
厚米 我是相当无语 我想了想schedule 唯一和页表有关系的 只有page_dir_activate 函数中的 asm volatile ("movl %0,%%cr3" : : "r"(pagedir_phy_addr) : "memory");
我之后仔细想了哈 不对啊 我们的初始化都在内核啊 只是重新装载了相同的物理地址 页表应该是相同的啊 怎么会出现不一样的页表 而且内核区域的页表一直都是相同的物理地址0x100000
之后我就很明确感觉到 问题肯定在memory.c 中的sys_malloc 和sys_free 因为那里面的函数 很多涉及页表位置的修改 页表项的移除与还原 于是在我一行一行的代码的对比纠察下 功夫不负有心人 终于找到了凶手 就是在sys_free 的最后两行代码 少写了两行代码 其中的赋值后面还画蛇添足的加了个++ 在修改后 终于一切都正常的运转起来了 这就是一次 我debug 的全程的想法和心路历程 相当的折磨
其实之前写的每一章博客 基本上每一章都有这样类似的bug出现 每一次我都是心力劳损的一点点慢慢的修改 这样类似的情况还有很多很多次 只是这次我想着已经快接近尾声了 还是写点有意思的东西吧 不然表面上看上去写操作系统很简单的样子 哈哈 其实真的挺难的 各种问题和意想不到的事情发生 都需要耐住性子一点点去解决 一点点去磨
哈哈 这部分就先写到这里 毕竟是事后了 现在的心情肯定是舒畅的 那个时候肯定是比较难受的 哈哈
|