ucore是清华大学提供的一个学习操作系统的平台。ucore有完整的mooc视频与说明文档。

https://objectkuan.gitbooks.io/ucore-docs/content/#

本文将主要记录在完成ucore平台的实验时,个人认为ucore内核及Result中的存在的问题,以及部分挑战练习内容。由于个人水平有限,可能理解有误,欢迎前来讨论。

本文主要内容:

  • Lab2 物理内存管理 练习一 Result代码错误
  • Lab3 虚拟内存管理 挑战练习 Clock算法实现
  • Lab8 文件系统 内核错误 用户程序ls错误

Lab2 练习一 Result代码错误

在实现first fit 内存分配算法的回收函数时,要考虑地址连续的空闲块之间的合并操作。提示:在建立空闲页块链表时,需要按照空闲页块起始地址来排序,形成一个有序的链表。

ans中思路是把所有的空闲页都加入空闲列表,这样效率非常低,且其中有很多标志位置位错误。我选择使用类似于实验指导书上的思路,将一个空闲块中的一个空闲页加入到空闲列表中。所有的操作只是对空闲段里面的第一个空闲页的操作。

代码中详细的注释,这里不做过多的说明。

/*
* Details of FFMA
* Prepare: In order to implement the First-Fit Mem Alloc (FFMA), we should manage the free mem block use some list.
* 为了能够接入FFMA我们要先建立空闲列表
* The struct free_area_t is used for the management of free mem blocks.
* free_area_t是空闲列表的中的结构体
* At first you should be familiar to the struct list in list.h.
* struct list is a simple doubly linked list implementation.
* 首先要在list.h找到list结构体
* list是一个双向链表
* You should know howto USE: list_init, list_add(list_add_after), list_add_before, list_del, list_next, list_prev
* 嗨呀就是简单的链表操作
* Another tricky method is to transform a general list struct to a special struct (such as struct page):
* you can find some MACRO: le2page (in memlayout.h), (in future labs: le2vma (in vmm.h), le2proc (in proc.h),etc.)
* 可以吧list的结构体转为page|proc的结构体
**/
free_area_t free_area; #define free_list (free_area.free_list)
#define nr_free (free_area.nr_free)
/**
* default_init:
* you can reuse the demo default_init fun to
* init the free_list and set nr_free to 0.
* 代码已经实现了 init freelist 然后设置nr_free 为0
* free_list : is used to record the free mem blocks.
* nr_free : is the total number for free mem blocks.
*/
static void default_init(void) {
list_init(&free_list);
nr_free = 0;
} /**
* default_init_memmap:
* 调用顺序: kern_init --> pmm_init-->page_init-->init_memmap--> pmm_manager->init_memmap
* This fun is used to init a free block (with parameter: addr_base, page_number).
* 这个函数是用来初始化一个free block 参数有base和page_number
* 若本页是空的 且不是第一页,flag中的property位设置为0
* 若本页是空的 且是第一页,flag中的property位设置为1 说明其有效
* 若本页空 且是第一页 property就是总共的空block数
* reference 引用的count清0 也就是有没有对应咯
**/
static void default_init_memmap(struct Page *base, size_t n) {
//assert用来检查一个判断是否为真
assert(n > 0);
struct Page *p = base;
for (; p != base + n; p++) {
p->flags = 0;
//若本页空&&不是第一页,property就是总共的空block数
p->property = 0;
//reference引用的count清0
p->ref = 0;
ClearPageReserved(p);
// from memlayout
// if this bit=1:
// the Page is reserved for kernel,
// cannot be used in alloc/free_pages;
// otherwise, this bit=0
}
//跟新一共有多少个free page
nr_free += n;
//first block
SetPageProperty(base);
//若本页空&&第一页,property就是总共的空block数
base->property = n;
list_add(&free_list, &(base->page_link));
} /**
* default_alloc_pages:
* search find a first free block (block size >=n)
* in free list and reszie the free block,
* return the addr of malloced block.
**/
static struct Page *
default_alloc_pages(size_t n) {
list_entry_t *list_iterator, *nxtptr;
struct Page *first_fit_page;
assert(n > 0);
//要分配的页数大于剩余的free数
if (n > nr_free) {
return NULL;
}
list_iterator = &free_list;
//循环访问一次free list
while ((list_iterator = list_next(list_iterator)) != &free_list) {
//从link回去找到page的base addr
first_fit_page = le2page(list_iterator, page_link);
//若当前的page可用大于需要的size
//注意这个地方,只有一个空闲区域里面的first page才会有property的data
if (first_fit_page->property >= n) {
//将这片空闲区域中的n个block分配出去
//检查这n个block能否分配
struct Page *alloc = first_fit_page;
for (; alloc != first_fit_page + n; alloc++) {
//若Reserved位为1 不能alloc和free
assert(!PageReserved(alloc));
}
//若这个空闲区域里面空闲的数量比我需要的数量还要多
if (first_fit_page->property > n) {
//原来空闲的空间这样子 H是空闲区域里面first page
//||H1....................x..................||
//现在这个空闲的区域变成了这样子
//.......n.......||H2........x-n.............||
//设置其property为剩下的x-n个block
//向后找n个page后的page
struct Page *new_head = first_fit_page + n;
new_head->property = first_fit_page->property - n;
SetPageProperty(new_head);
//因为按照addr的order 则直接添加到first fit page的后面就好了
list_add(&(first_fit_page->page_link), &(new_head->page_link));
}
//从free list 中删除分配走的page的link
list_del(&(first_fit_page->page_link));
ClearPageProperty(first_fit_page);
nr_free -= n;
return first_fit_page;
}
}
return NULL;
} /**
* default_free_pages
* free掉分配了的页
* base:为free的页的first page的基地址
* n :为free掉多少页
*/
static void default_free_pages(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
//将n这么多空间释放
for (; p != base + n; p++) {
//检查要free的n个size时候合法
//不能被标记Reserved和Property
assert(!PageReserved(p) && !PageProperty(p));
//初始化flags位
p->flags = 0;
//清空页面访问counter
set_page_ref(p, 0);
}
//更新新的base
base->property = n;
SetPageProperty(base); //下面开始找能否合并到其他的已有的区域
list_entry_t *le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
le = list_next(le);
//若base后面接着了p
if (base + base->property == p) {
base->property += p->property;
p->property = 0;
ClearPageProperty(p);
list_del(&(p->page_link));
}
//若p后面接着了base
else if (p + p->property == base) {
p->property += base->property;
ClearPageProperty(base);
base->property = 0;
base = p;
list_del(&(p->page_link));
}
}
// 按照地址顺序插入这个新的base节点
nr_free += n;
le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
if (p > base)
break;
le = list_next(le);
}
//插入到list中去
list_add_before(le, &(base->page_link));
} static size_t default_nr_free_pages(void) {
return nr_free;
}

Lab3 挑战练习 Clock算法实现

设定swap策略为Clock算法

/*
* 设定swap策略
*/
struct swap_manager swap_manager_clock = {
.name = "clock clock manager",
.init = &_clock_init,
.init_mm = &_clock_init_mm,
.tick_event = &_clock_tick_event,
.map_swappable = &_clock_map_swappable,
.set_unswappable = &_clock_set_unswappable,
.swap_out_victim = &_clock_swap_out_victim,
.check_clock_swap = &_clock_check_swap,
};

选择调用clock算法

#ifdef CLOCK
sm = &swap_manager_clock;
#else
sm = &swap_manager_fifo;
#endif

由于每次我们访问一个地址时,要对物理页做标记,所以要用到mm中的pd的基地址,从而获取pte,获取page对象,再对dirty位做标记,这里在抽象类中添加一个方法(mm是拥有相同PDT)

int (*check_clock_swap)(struct mm_struct *mm);

在接入该接口时添加调用的mm参数

static inline int check_content_access(struct mm_struct *mm){
#ifdef CLOCK
int ret = sm->check_clock_swap(mm);
return ret;
#else
int ret = sm->check_swap();
return ret;
#endif
}

在page的结构体中flag标志位加入dirtybit

#define PG_dirtybit                 2       // Used for clock pra

#define SetDirtyBit(page)           set_bit(PG_dirtybit, &((page)->flags))
#define ClearDirtyBit(page) clear_bit(PG_dirtybit, &((page)->flags))
#define PageDirty(page) test_bit(PG_dirtybit,&((page)->flags))

CLOCK实现

#include <defs.h>
#include <x86.h>
#include <stdio.h>
#include <string.h>
#include <swap.h>
#include <swap_clock.h>
#include <list.h> list_entry_t pra_list_head; static int _clock_init_mm(struct mm_struct *mm) {
list_init(&pra_list_head);
mm->sm_priv = &pra_list_head;
return 0;
} static int _clock_map_swappable(struct mm_struct *mm, uintptr_t addr,
struct Page *page, int swap_in) {
list_entry_t *head = (list_entry_t*) mm->sm_priv;
list_entry_t *entry = &(page->pra_page_link);
assert(entry != NULL && head != NULL);
//将entry加入到list的头
list_add(head->prev, entry);
//page->has_used = 1;
SetDirtyBit(page);
//init present_ptr
if(mm->present_ptr == NULL){
//cprintf("INIT\n\n\n\n");
mm->present_ptr = entry;
}
return 0;
} static int _clock_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page,
int in_tick) {
list_entry_t *head = (list_entry_t*) mm->sm_priv;
list_entry_t *tmp;
struct Page *iter;
assert(head != NULL);
assert(in_tick == 0);
//cprintf("Present PTR %x\n", mm->present_ptr);
cprintf("\nLet's find victim!!!\n");
//list empty
assert(head -> next != head);
while(1){
//若转了一圈回到了head 跳过head
if(mm->present_ptr == head) {
cprintf("Hit head!\n");
mm->present_ptr = mm->present_ptr->next;
}
iter = le2page(mm->present_ptr,pra_page_link);
//若标记dirtybit为0就替换走
if(!PageDirty(iter)) {
cprintf("Find it!!!\n\n");
tmp = mm->present_ptr;
mm->present_ptr = mm->present_ptr->next;
*ptr_page = iter;
list_del(tmp);
return 0;
}
cprintf("Not good\n");
ClearDirtyBit(iter);
mm->present_ptr = mm->present_ptr->next;
}
return 1;
} static void visit(struct mm_struct *mm,uintptr_t addr,int value){
*(unsigned char*) addr = value;
//从虚拟地址获取pte
uintptr_t *tmp = get_pte(mm->pgdir,addr,0);
//从pte获取page
struct Page *page = pte2page(*tmp);
//设置dirty_bit
SetDirtyBit(page);
} /*
* _clock_init
*/
static int _clock_init(void) {
return 0;
} /*
* _clock_set_unswappable
* 设置addr为不可被换出的
*/
static int _clock_set_unswappable(struct mm_struct *mm, uintptr_t addr) {
list_entry_t *head = (list_entry_t*) mm->sm_priv;
list_entry_t *iter = head->next;
//从虚拟地址获取pte
uintptr_t *tmp = get_pte(mm->pgdir,addr,0);
//从pte获取page
struct Page *page = pte2page(*tmp);
while(iter != head){
if(iter == &(page->pra_page_link)){
list_del(iter);
return 0;
}
iter = iter->next;
}
cprintf("Cannot find addr in list");
assert(0);
return 1;
} static int _clock_tick_event(struct mm_struct *mm) {
return 0;
}

测试函数

static int _clock_check_swap(struct mm_struct *mm) {
cprintf("write Virt Page c in clock_check_swap\n");
visit(mm,0x3000,0x0c);
cprintf("PGFAULT_NUM:%d\n",pgfault_num); cprintf("write Virt Page a in clock_check_swap\n");
visit(mm,0x1000,0x0a);
//assert(pgfault_num == 4);
cprintf("PGFAULT_NUM:%d\n",pgfault_num); cprintf("write Virt Page d in clock_check_swap\n");
visit(mm,0x4000, 0x0d);
//assert(pgfault_num == 4);
cprintf("PGFAULT_NUM:%d\n",pgfault_num); cprintf("write Virt Page b in clock_check_swap\n");
visit(mm,0x2000 ,0x0b);
//assert(pgfault_num == 4);
cprintf("PGFAULT_NUM:%d\n",pgfault_num); cprintf("write Virt Page e in clock_check_swap\n");
visit(mm,0x5000 , 0x0e);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 5); cprintf("write Virt Page b in clock_check_swap\n");
visit(mm,0x2000, 0x0b);
//assert(pgfault_num == 5);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num); cprintf("write Virt Page a in clock_check_swap\n");
visit(mm, 0x1000 , 0x0a);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 6); cprintf("write Virt Page b in clock_check_swap\n");
visit(mm, 0x2000 , 0x0b);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 7); cprintf("write Virt Page c in clock_check_swap\n");
visit(mm, 0x3000 , 0x0c);
//assert(pgfault_num == 8);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num); cprintf("write Virt Page d in clock_check_swap\n");
visit(mm, 0x4000 , 0x0d);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 9);
return 0;
}

其中由于每次访问时需要吧dirty bit置为1,而直接等号赋值不能实现该功能,故将访问打包到visit函数内

输出分析

  • 前四次是冷启动,必然会出现四次miss

    set up init env for check_swap begin!
    page fault at 0x00001000: K/W [no page found].
    page fault at 0x00002000: K/W [no page found].
    page fault at 0x00003000: K/W [no page found].
    page fault at 0x00004000: K/W [no page found].
    set up init env for check_swap over!
  • 后面的输出分析见下表格

    set up init env for check_swap over!
    write Virt Page c in clock_check_swap
    PGFAULT_NUM:4
    write Virt Page a in clock_check_swap
    PGFAULT_NUM:4
    write Virt Page d in clock_check_swap
    PGFAULT_NUM:4
    write Virt Page b in clock_check_swap
    PGFAULT_NUM:4
    write Virt Page e in clock_check_swap
    page fault at 0x00005000: K/W [no page found]. Let's find victim!!!
    Not good
    Not good
    Not good
    Not good
    Hit head!
    Find it!!! swap_out: i 0, store page in vaddr 0x1000 to disk swap entry 2
    PGFAULT_NUM:5 write Virt Page b in clock_check_swap
    PGFAULT_NUM:5 write Virt Page a in clock_check_swap
    page fault at 0x00001000: K/W [no page found]. Let's find victim!!!
    Not good
    Find it!!! swap_out: i 0, store page in vaddr 0x3000 to disk swap entry 4
    swap_in: load disk swap entry 2 with swap_page in vadr 0x1000
    PGFAULT_NUM:6 write Virt Page b in clock_check_swap
    PGFAULT_NUM:6 write Virt Page c in clock_check_swap
    page fault at 0x00003000: K/W [no page found]. Let's find victim!!!
    Find it!!! swap_out: i 0, store page in vaddr 0x4000 to disk swap entry 5
    swap_in: load disk swap entry 4 with swap_page in vadr 0x3000
    PGFAULT_NUM:7 write Virt Page d in clock_check_swap
    page fault at 0x00004000: K/W [no page found]. Let's find victim!!!
    Not good
    Not good
    Not good
    Hit head!
    Not good
    Find it!!! swap_out: i 0, store page in vaddr 0x5000 to disk swap entry 6
    swap_in: load disk swap entry 5 with swap_page in vadr 0x4000
    PGFAULT_NUM:8 count is 0, total is 7
    check_swap() succeeded!

    实际情况分析如图:

Lab8 内核错误 用户程序ls错误

利用Lab8练习2写好的程序,测试ls(ls也写错了,下面为修改过的ls)

查看内核代码,发现sfs_lookup()写错了,下面是修改过的sfs_lookup()

这里只是随手改的,没有管协定文件目录长度,最大设置为40

暴力遍历分解子目录

/*
* sfs_lookup - Parse path relative to the passed directory
* DIR, and hand back the inode for the file it
* refers to.
*/
static int
sfs_lookup(struct inode *node, char *path, struct inode **node_store) {
struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
assert(*path != '\0' && *path != '/');
vop_ref_inc(node);
struct sfs_inode *sin = vop_info(node, sfs_inode);
if (sin->din->type != SFS_TYPE_DIR) {
vop_ref_dec(node);
return -E_NOTDIR;
}
struct inode *subnode;
struct sfs_inode *cur_node = sin;
// cprintf("Show Path:%s\n",path);
//开始拆分
char tmp[40];
int i = 0,j = 0,ret = 0;
for(j = 0;;j++){
//末尾
if(path[j]=='\0'){
tmp[i] = '\0';
i = 0;
// cprintf("Find: %s\n",tmp);
ret = sfs_lookup_once(sfs, cur_node, tmp, &subnode, NULL);
break;
}
//遇到/
if(path[j]=='/'){
tmp[i] = '\0';
i = 0;
// cprintf("Find: %s\n",tmp);
if((ret = sfs_lookup_once(sfs, cur_node, tmp, &subnode, NULL))!=0) break;
//cur_node为当前目录inode
cur_node = vop_info(subnode, sfs_inode);
}
//正常
else{
tmp[i]=path[j];
i++;
}
} vop_ref_dec(node);
if (ret != 0) {
return ret;
}
*node_store = subnode;
return 0;
}

修改ls里面的bug:

int lsdir(const char *path) {
struct stat __stat, *stat = &__stat;
int ret;
DIR *dirp = opendir(path); if (dirp == NULL) {
return -1;
}
struct dirent *direntp;
char tmppath[40]; while ((direntp = readdir(dirp)) != NULL) {
strcpy(tmppath,path);
strcat(tmppath,"/");
strcat(tmppath,direntp->name);
// printf("File has %s\n",tmppath); if ((ret = getstat(tmppath, stat)) != 0) {
goto failed;
}
lsstat(stat, direntp->name);
}
printf("lsdir: step 4\n");
closedir(dirp);
return 0;
failed:
closedir(dirp);
return ret;
}

修改disk0的文件系统如图,测试ls正常:

操作系统:ucore的部分Bug&挑战练习的更多相关文章

  1. 关于ucore实验一的资料查找

    任务:阅读实验一makefile 搞清楚ucore.img是如何构建的 $@  $<  $^  这三个变量分别是什么意思 https://blog.csdn.net/YEYUANGEN/arti ...

  2. 【测试基础第六篇】bug定义及生命周期

    bug定义 狭义:软件程序的漏洞或缺陷 广义:测试工程师或用户所发现和提出的软件可改进的细节(增强型.建议性)或需求文档存在差异的功能实现 职责:发现bug,提给开发,让其修改 bug类型--了解 代 ...

  3. 如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?

    一.我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用.积木化.功能重组的智能硬件模块构想 二.别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的! ...

  4. Linux(9.14-9.20)学习笔记

    实验一 Linux系统简介 一.Linux 为何物 Linux 就是一个操作系统,Linux 也就是系统调用和内核那两层. 二.Linux 历史简介 操作系统始于二十世纪 50 年代,当时的操作系统能 ...

  5. Linux 读书笔记 一

    一.Linux 简介 实验介绍 本节主要介绍 Linux 的历史,Linux 与 Windows 的区别等入门知识.如果你已经有过充分的了解,可以跳过本节,直接进入下一个实验. 一.Linux 为何物 ...

  6. 1.1Linux 系统简介(学习过程)

    =====课程笔记===== 一.Linux 为何物 Linux 是一个操作系统,就像你多少已经了解的 Windows(xp,7,8)和 Max OS . Linux 也就是系统调用和内核两层,我们使 ...

  7. iOS 黑屏

    1. 首先看操作系统是否有很多Bug 9.0.2 的系统不稳定. http://tech.163.com/15/1020/05/B6BL6PML000915BD.html

  8. SQLite在多线程环境下的应用

    文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...

  9. iOS sqlite3数据库解析

    看来从版本3.3.1基本上已经支持线程句柄的传递功能.具体限制我标记了一下.(6) Is SQLite threadsafe?SQLite is threadsafe. We make this co ...

随机推荐

  1. error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    一.情形描述 下载了一个VS的源码,不知道此源码的版本.使用VS2010编译时出现如下报错: error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 二.解决方法 在VS2010界 ...

  2. 设置webstorm缩写代码

    文件 ->设置->编辑器->活动模板->找到需要设置的文件类型(比如JavaScript)-->添加-(右上角)->设置模板之后,注意最后需要defind才能生效

  3. C#使用HttpClient获取Location

    之前使用HttpWebRequest的时候,只需要设置HttpWebRequest对象的AllowAutoRedirect属性值为false即可在Respomse的Header中获取Location: ...

  4. 处理Oracle数据中的无效对象

    今天还原了一份数据库(在服务器上没有无效对象),还原在本地之后有三十几个无效对象,当时很是郁闷,然后我发现还原之后的数据库中缺少表! 开始我怀疑Oracle数据库的还原功能,但是在我创建表的时候发现, ...

  5. mongodb分片部署

    Mongodb 分片部署 配置mongodb集群,比如 在3个server上配置 3 shard的Mongodb集群: 架构: 1.每片数据需要3个mongod server,2个为主从数据节点:1个 ...

  6. NYOJ--102--次方求模(快速求幂取模)

    次方求模 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 求a的b次方对c取余的值   输入 第一行输入一个整数n表示测试数据的组数(n<100)每组测试只有一 ...

  7. VS2013+MFC串口控件的简单上位机

    因为做东西,正好用到这里.所以就上传了文件分享一下. 利用VS带的MFC库,用起来还是比较方便的.空间的程序构架都是自动生成的,具体的程序自己加进去就行. 里面有整个的工程 还带有一个生成的EXE文件 ...

  8. 为什么要学习Java EE

    Java EE学习之路 学习了Java SE,还只是完成“万里长征”的第一步. 接下来选择学习Java EE或是Java ME(或者你还想不断深入学习Java SE,只要你喜欢,你可以一直深入下去,就 ...

  9. 使用DbFunctions来解决EF按照日期分组数据

    如下一张表 要进行MyDate的date部分进行分组,我们会发现如下写法会报异常 那么如何才能使linq正确转化为sql语句呢,这就要使用到了DbFunctions这个工具类 转到定义可以看到此类在e ...

  10. Gitlab CI 自动部署 asp.net core web api 到Docker容器

    为什么要写这个? 在一个系统长大的过程中会经历不断重构升级来满足商业的需求,而一个严谨的商业系统需要高效.稳定.可扩展,有时候还不得不考虑成本的问题.我希望能找到比较完整的开源解决方案来解决持续集成. ...