相关查阅博客链接
C语言结构体内存分布 C语言之typedef函数指针用法 c语言typedef怎么自定义函数,c语言中typedef的用法
本书中错误勘误
1、这个地方我认为是绝对错误的地方 就是关于我们的线程部分 书上写的是我们的main线程的pcb存放于位置应该是0xc009e00 但是按照书上loader.S既然mov esp,0xc009f000 那么肯定的是我们的main线程的pcb就是位于0xc009f000 而不会是0xc009e000 但是为什么这里没有出错呢 当然 把main的pcb放于这两个位置都没有问题 反正空余的空间是留够了的 放这两个地方都没有问题 个人认为这是作者思考写的思路的有的小问题
进程 线程的自我小理解
毕竟距离上次看 《现代操作系统》 已经时隔很久 很多很多原来记的很牢的东西也都还回去了 但是不重要 记忆过的东西拾起来都还是很快的
进程 = 资源 + 线程
线程这里面给我独特的记忆点在于 线程可以有属于自己的资源 是一个最小的执行单元 有寄存器 和 栈 线程也只不过是 借用了进程的资源来做事情罢了 一个个代码块而已 而一般我们常用的也只不过是 单线程进程 就是进程里面只有一个执行流 从上而下的执行 而多线程进程 则是我们显示的创造线程一般所用到的
线程 进程的状态
这个我记得在《现代操作系统》的那里我就谈到过 有几个状态 就绪态 阻塞态 运行态 这几个状态都是相互切换来的 阻塞态 例如等待I/O时 调度器就可以调度把那个进程设置为阻塞态 并把处理器分配给其他进程 之前做过哈工大操作系统Lab的hxd对这个肯定也是不陌生的
内核级线程 & 用户级线程
感觉这个也是老生常谈的事情了 我还是顺带也提一嘴我的理解 内核级线程 指的是操作系统支持线程 即提供了线程这个概念 程序员可以在操作系统的帮助下来进程创建线程操作 线程这个实物概念对于操作系统是可见的 而用户级线程 是指的是 操作系统不支持线程这个概念 用户 程序员在写进程程序的时候 自己写了调度器或者自己写了一个执行流 而线程的切换是通过进程本身来调节的
当然 有好处也有坏处 凡事都有一个两面性 用户级线程 好处是切换线程时 不需要陷入内核 切换线程的代价要小的多 速度非常快 因为毕竟是在用户级程序层面上而言 自己切换 但 坏处是 一旦发生阻塞 操作系统是不清楚有这个线程的存在 可能就直接把进程切换掉了 整个的进程就直接阻塞
初步实现内核级线程
xdm 编程完成了这个部分发生了一件十分痛苦的事情 具体是什么 待会在相关位置我会提一嘴 但是这给了我一个提示 就是做事情一定要小心谨慎一点 因为一点点偏差可能就会导致几个小时的浪费 对 没错 就是因为一个小问题 差点我愤怒的打算放弃编写操作系统 在折腾了两三个小时后 发现问题竟然是一个很小很小的问题 后面会讲
编写到这里我们来理一下思路 是怎么弄出来线程的 我们编写了thread.h 和 thread.c 目前只是把大概轮廓给弄了出来 我们通过创建了PCB 把我们线程所需要用到的相关内容全部放在了里面 PCB下端(我们申请的一页内存) 存放着的是我们的结构体task_struct 目前里面含有的东西不多 线程状态``特权级``边界魔数``还有我们的线程内核栈的地址
我们的 中断栈所在位置 位于一页内存的最顶点位置 我们上下文切换时 如果外面有中断 我们就把我们所有的上下文环境放在那里 我们的内核栈 所在位置 是位于中断栈的下方 那里我们放着的是我们的4个寄存器 和 我们的 某些需要的函数地址
浪费两三个小时调试的辛酸史
总得来说就是这样 看局部代码真不好分析出来 还是得总拉出来一起看 才看得懂代码是什么意思 这里我就要说一下 为什么这里我浪费了两三个小时调试半天 因为不是这里要测试一下 初步的线程创建切换吗
正确的主函数main.c本来应该是这样的
#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
void test_thread(void* arg);
int main(void) {
put_str("I am kernel\n");
init_all();
thread_start("kernel_thread_a",31,test_thread,"argA ");
while(1);
return 0;
}
void test_thread(void* arg)
{
while(1)
put_str((char*)arg);
}
我没找到问题前是这样写的
#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
void test_thread(void* arg);
void test_thread(void* arg)
{
while(1)
put_str((char*)arg);
}
int main(void) {
put_str("I am kernel\n");
init_all();
thread_start("kernel_thread_a",31,test_thread,"argA ");
while(1);
return 0;
}
这样写的话就导致 main.c编译的内存位置不再是0xc0001500了 而是其他位置了 哎 就这样我就发现原来可以运行的程序现在直接不能运行了 于是我还以为是昨晚的系统更新出错了 我就挨个挨个排查错误
从mar.S loader.S 一个板块一个板块排查 一点点排查 就这样我一点点摸到了Loader.S最后的历史使命 跳转到 0xc0001500 我就去看内存0xc0001500发生了什么 结果发现里面的内存全是默认的乱码 哎 给我整怒了
在调试良久之后 我那个时候都想放弃了 甚至想给书籍作者打电话问一下怎么解决 真的很无语 到最后才发现是这个问题 这里的辛酸史各位看客 且当一乐 希望各位不要这样去做 下面直接放出来thread.h thread.c的代码 里面有很多我写的注释
编写thread.h
目前的thread.h代码
#ifndef __THREAD_THREAD_H
#define __THREAD_THREAD_H
#include "stdint.h"
typedef void thread_func(void*);
enum task_status
{
TASK_RUNNING,
TASK_READY,
TASK_BLOCKED,
TASK_WAITING,
TASK_HANGING,
TASK_DIED
};
struct intr_struct
{
uint32_t vec_no;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp_dummy;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t gs;
uint32_t fs;
uint32_t es;
uint32_t ds;
uint32_t err_code;
void (*eip) (void);
uint32_t cs;
uint32_t eflags;
void* esp;
uint32_t ss;
};
struct thread_stack
{
uint32_t ebp;
uint32_t ebx;
uint32_t edi;
uint32_t esi;
void (*eip) (thread_func* func,void* func_arg);
void (*unused_retaddr);
thread_func* function;
void* func_arg;
};
struct task_struct
{
uint32_t* self_kstack;
enum task_status status;
uint8_t priority;
char name[16];
uint32_t stack_magic;
};
void kernel_thread(thread_func* function,void* func_arg);
void thread_create(struct task_struct* pthread,thread_func function,void* func_arg);
void init_thread(struct task_struct* pthread,char* name,int prio);
struct task_struct* thread_start(char* name,int prio,thread_func function,void* func_arg);
#endif
编写thread.c
#include "thread.h"
#include "stdint.h"
#include "string.h"
#include "global.h"
#include "memory.h"
#define PG_SIZE 4096
void kernel_thread(thread_func* function,void* func_arg)
{
function(func_arg);
}
void thread_create(struct task_struct* pthread,thread_func function,void* func_arg)
{
pthread->self_kstack -= sizeof(struct intr_struct);
pthread->self_kstack -= sizeof(struct thread_stack);
struct thread_stack* kthread_stack = (struct thread_stack*)pthread->self_kstack;
kthread_stack->eip = kernel_thread;
kthread_stack->function = function;
kthread_stack->func_arg = func_arg;
kthread_stack->ebp = kthread_stack->ebx = kthread_stack->ebx = kthread_stack->esi = 0;
return;
}
void init_thread(struct task_struct* pthread,char* name,int prio)
{
memset(pthread,0,sizeof(*pthread));
strcpy(pthread->name,name);
pthread->status = TASK_RUNNING;
pthread->priority = prio;
pthread->self_kstack = (uint32_t*)((uint32_t)pthread + PG_SIZE);
pthread->stack_magic = 0x23333333;
}
struct task_struct* thread_start(char* name,int prio,thread_func function,void* func_arg)
{
struct task_struct* thread = get_kernel_pages(1);
init_thread(thread,name,prio);
thread_create(thread,function,func_arg);
asm volatile("movl %0,%%esp; pop %%ebp; pop %%ebx; pop %%edi; pop %%esi; ret" : : "g"(thread->self_kstack) :"memory");
return thread;
}
修改MakeFile & main.c 验证结果
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 $(BUILD_DIR)/thread.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
$(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 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
$(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 .
main.c修改如下
#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
void test_thread(void* arg);
void test_thread(void* arg)
{
while(1)
put_str((char*)arg);
}
int main(void) {
put_str("I am kernel\n");
init_all();
thread_start("kernel_thread_a",31,test_thread,"argA ");
while(1);
return 0;
}
验证结果 从目前看应该是ok的

编写双向链表 基础数据结构
我觉得这个部分挺好的 之前虽然没怎么接触过双向链表 但是力扣刷题的时候做到过 这个时候来看一下原理发现还是多简单的 这个就不多解释了 下面直接先放代码
编写list.h
#ifndef __LIB_KERNEL_LIST_H
#define __LIB_KERNEL_LIST_H
#include "stdint.h"
#define offset(struct_type,member) (int) (&((struct_type*)0)->member)
#define elem2entry(struct_type,struct_member_name,elem_ptr) \
(struct_type*)((int)elem_ptr - offset(struct_type,struct_member_name))
struct list_elem
{
struct list_elem* prev;
struct list_elem* next;
};
struct list
{
struct list_elem head;
struct list_elem tail;
};
typedef bool (function) (struct list_elem*,int arg);
void list_init(struct list*);
void list_insert_before(struct list_elem* before,struct list_elem* elem);
void list_push(struct list* plist,struct list_elem* elem);
void list_append(struct list* plist,struct list_elem* elem);
void list_remove(struct list_elem* pelem);
struct list_elem* list_pop(struct list* plist);
bool list_empty(struct list* plist);
uint32_t list_len(struct list* plist);
struct list_elem* list_traversal(struct list* plist,function func,int arg);
bool elem_find(struct list* plist,struct list_elem* obj_elem);
#endif
编写list.c
#include "list.h"
#include "interrupt.h"
#include "stdint.h"
#include "debug.h"
#define NULL 0
void list_init(struct list* list)
{
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
void list_insert_before(struct list_elem* before,struct list_elem* elem)
{
enum intr_status old_status = intr_disable();
elem->next = before;
elem->prev = before->prev;
before->prev->next = elem;
before->prev = elem;
intr_set_status(old_status);
}
void list_push(struct list* plist,struct list_elem* elem)
{
list_insert_before(plist->head.next,elem);
}
void list_append(struct list* plist,struct list_elem* elem)
{
list_insert_before(&plist->tail,elem);
}
void list_remove(struct list_elem* pelem)
{
enum intr_status old_status = intr_disable();
pelem->prev->next = pelem->next;
pelem->next->prev = pelem->prev;
intr_set_status(old_status);
}
struct list_elem* list_pop(struct list* plist)
{
ASSERT(plist->head.next != &plist->tail);
struct list_elem* ret = plist->head.next;
list_remove(plist->head.next);
return ret;
}
bool list_empty(struct list* plist)
{
return (plist->head.next == &plist->tail ? true : false);
}
uint32_t list_len(struct list* plist)
{
uint32_t ret = 0;
struct list_elem* next = plist->head.next;
while(next != &plist->tail)
{
next = next->next;
++ret;
}
return ret;
}
struct list_elem* list_traversal(struct list* plist,function func,int arg)
{
struct list_elem* elem = plist->head.next;
if(list_empty(plist)) return NULL;
while(elem != &plist->tail)
{
if(func(elem,arg)) return elem;
elem = elem->next;
}
return NULL;
}
bool elem_find(struct list* plist,struct list_elem* obj_elem)
{
struct list_elem* ptr = plist->head.next;
while(ptr != &plist->tail)
{
if(ptr == obj_elem) return true;
ptr = ptr->next;
}
return false;
}
实现线程 编写修改相关文件
这部分确实太折磨了 细节确实很多 我调试也调试了很久 因为我写代码对于自己有思考的地方 我就会按照自己的思路来写 没有按照书上的一摸一样的去copy 所以就会导致很多地方出错 很多小细节出错
这章节至少最后实现效果看样子是正确的 而且我也修改了很多的文件 我还是写一下大概思路究竟是怎么切换线程的
1、先创建线程 2、打开中断 每个时钟中断调用中断函数 减去当前时间片 3、时间片为0 简称到期了 到期之后 调用schedule调度器 切换线程 4、schedule 把在最前面的准备队列的任务的pcb获取 把当前的放到最后 5、之后转到switch_to 保存寄存器 上下文环境 切换esp 即切换线程
在细节点 说一下pcb的存储 main主线程的本来pcb的内存空间就是留了的 这部分的问题在上面已经说过了 分配了一页内存后 pcb的核心部分在最低端的内存处 最高处是中断栈 就是存放各种寄存器的位置 最高处的下面就是内核栈 里面有四个我们相关的寄存器 还有一个esp的位置 剩下的就是第一次被切换所需要的内容了
感觉也没什么好说的了 整体理解还是我认为不是那么难 总览视角看起来还是比较容易的 拉一边即可 晚上朋友又不在 又没办法玩游戏 那这样的话 我就再多写一点博客吧 下面把我的代码贴出来
thread.c
#include "thread.h"
#include "stdint.h"
#include "string.h"
#include "global.h"
#include "memory.h"
#include "debug.h"
#include "interrupt.h"
#include "print.h"
#define PG_SIZE 4096
struct task_struct* main_thread;
struct list thread_ready_list;
struct list thread_all_list;
extern void switch_to(struct task_struct* cur,struct task_struct* next);
struct task_struct* running_thread(void)
{
uint32_t esp;
asm ("mov %%esp,%0" : "=g"(esp));
return (struct task_struct*)(esp & 0xfffff000);
}
void kernel_thread(thread_func* function,void* func_arg)
{
intr_enable();
function(func_arg);
}
void thread_create(struct task_struct* pthread,thread_func function,void* func_arg)
{
pthread->self_kstack -= sizeof(struct intr_struct);
pthread->self_kstack -= sizeof(struct thread_stack);
struct thread_stack* kthread_stack = (struct thread_stack*)pthread->self_kstack;
kthread_stack->eip = kernel_thread;
kthread_stack->function = function;
kthread_stack->func_arg = func_arg;
kthread_stack->ebp = kthread_stack->ebx = kthread_stack->ebx = kthread_stack->esi = 0;
return;
}
void init_thread(struct task_struct* pthread,char* name,int prio)
{
memset(pthread,0,sizeof(*pthread));
strcpy(pthread->name,name);
if(pthread == main_thread)
pthread->status = TASK_RUNNING;
else
pthread->status = TASK_READY;
pthread->self_kstack = (uint32_t*)((uint32_t)pthread + PG_SIZE);
pthread->priority = prio;
pthread->ticks = prio;
pthread->elapsed_ticks = 0;
pthread->pgdir = NULL;
pthread->stack_magic = 0x23333333;
}
struct task_struct* thread_start(char* name,int prio,thread_func function,void* func_arg)
{
struct task_struct* thread = get_kernel_pages(1);
init_thread(thread,name,prio);
thread_create(thread,function,func_arg);
ASSERT(!elem_find(&thread_ready_list,&thread->general_tag));
list_append(&thread_ready_list,&thread->general_tag);
ASSERT(!elem_find(&thread_all_list,&thread->all_list_tag));
list_append(&thread_all_list,&thread->all_list_tag);
return thread;
}
void make_main_thread(void)
{
main_thread = running_thread();
init_thread(main_thread,"main",31);
ASSERT(!elem_find(&thread_all_list,&main_thread->all_list_tag));
list_append(&thread_all_list,&main_thread->all_list_tag);
}
void schedule(void)
{
ASSERT(intr_get_status() == INTR_OFF);
struct task_struct* cur = running_thread();
if(cur->status == TASK_RUNNING)
{
ASSERT(!elem_find(&thread_ready_list,&cur->general_tag));
list_append(&thread_ready_list,&cur->general_tag);
cur->status = TASK_READY;
cur->ticks = cur->priority;
}
else
{}
ASSERT(!list_empty(&thread_ready_list));
struct task_struct* thread_tag = list_pop(&thread_ready_list);
struct task_struct* next = (struct task_struct*)((uint32_t)thread_tag & 0xfffff000);
next->status = TASK_RUNNING;
switch_to(cur,next);
}
void thread_init(void)
{
put_str("thread_init start!\n");
list_init(&thread_ready_list);
list_init(&thread_all_list);
make_main_thread();
put_str("thread_init done!\n");
}
thread.h
#ifndef __THREAD_THREAD_H
#define __THREAD_THREAD_H
#include "stdint.h"
#include "list.h"
typedef void thread_func(void*);
enum task_status
{
TASK_RUNNING,
TASK_READY,
TASK_BLOCKED,
TASK_WAITING,
TASK_HANGING,
TASK_DIED
};
struct intr_struct
{
uint32_t vec_no;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp_dummy;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t gs;
uint32_t fs;
uint32_t es;
uint32_t ds;
uint32_t err_code;
void (*eip) (void);
uint32_t cs;
uint32_t eflags;
void* esp;
uint32_t ss;
};
struct thread_stack
{
uint32_t ebp;
uint32_t ebx;
uint32_t edi;
uint32_t esi;
void (*eip) (thread_func* func,void* func_arg);
void (*unused_retaddr);
thread_func* function;
void* func_arg;
};
struct task_struct
{
uint32_t* self_kstack;
enum task_status status;
uint8_t priority;
uint8_t ticks;
uint32_t elapsed_ticks;
char name[16];
struct list_elem general_tag;
struct list_elem all_list_tag;
uint32_t* pgdir;
uint32_t stack_magic;
};
struct task_struct* running_thread(void);
void kernel_thread(thread_func* function,void* func_arg);
void thread_create(struct task_struct* pthread,thread_func function,void* func_arg);
void init_thread(struct task_struct* pthread,char* name,int prio);
struct task_struct* thread_start(char* name,int prio,thread_func function,void* func_arg);
void make_main_thread(void);
void schedule(void);
void thread_init(void);
#endif
interrupt.c
#include "interrupt.h"
#include "stdint.h"
#include "global.h"
#include "io.h"
#include "print.h"
#define PIC_M_CTRL 0x20
#define PIC_M_DATA 0x21
#define PIC_S_CTRL 0xa0
#define PIC_S_DATA 0xa1
#define IDT_DESC_CNT 0x21
#define EFLAGS_IF 0x00000200
#define GET_EFLAGS(EFLAG_VAR) asm volatile("pushfl; popl %0" : "=g" (EFLAG_VAR))
struct gate_desc {
uint16_t func_offset_low_word;
uint16_t selector;
uint8_t dcount;
uint8_t attribute;
uint16_t func_offset_high_word;
};
static void pic_init(void);
static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function);
static void general_intr_handler(uint8_t vec_nr);
static void exception_init(void);
void idt_init(void);
void register_handler(uint8_t vec_no,intr_handler function);
static struct gate_desc idt[IDT_DESC_CNT];
void register_handler(uint8_t vec_no,intr_handler function);
char* intr_name[IDT_DESC_CNT];
intr_handler idt_table[IDT_DESC_CNT];
extern intr_handler intr_entry_table[IDT_DESC_CNT];
static void pic_init(void) {
outb (PIC_M_CTRL, 0x11);
outb (PIC_M_DATA, 0x20);
outb (PIC_M_DATA, 0x04);
outb (PIC_M_DATA, 0x01);
outb (PIC_S_CTRL, 0x11);
outb (PIC_S_DATA, 0x28);
outb (PIC_S_DATA, 0x02);
outb (PIC_S_DATA, 0x01);
outb (PIC_M_DATA, 0xfe);
outb (PIC_S_DATA, 0xff);
put_str(" pic_init done\n");
}
static void make_idt_desc(struct gate_desc* p_gdesc, uint8_t attr, intr_handler function) {
p_gdesc->func_offset_low_word = (uint32_t)function & 0x0000FFFF;
p_gdesc->selector = SELECTOR_K_CODE;
p_gdesc->dcount = 0;
p_gdesc->attribute = attr;
p_gdesc->func_offset_high_word = ((uint32_t)function & 0xFFFF0000) >> 16;
}
static void idt_desc_init(void) {
int i, lastindex = IDT_DESC_CNT - 1;
for (i = 0; i < IDT_DESC_CNT; i++) {
make_idt_desc(&idt[i], IDT_DESC_ATTR_DPL0, intr_entry_table[i]);
}
put_str(" idt_desc_init done\n");
}
static void general_intr_handler(uint8_t vec_nr) {
if (vec_nr == 0x27 || vec_nr == 0x2f) {
return;
}
set_cursor(0);
int cursor_pos = 0;
while((cursor_pos++) < 320)
put_char(' ');
set_cursor(0);
put_str("!!!!!! excetion message begin !!!!!!\n");
set_cursor(88);
put_str(intr_name[vec_nr]);
if(vec_nr == 14)
{
int page_fault_vaddr = 0;
asm("movl %%cr2,%0" : "=r" (page_fault_vaddr));
put_str("\npage fault addr is ");
put_int(page_fault_vaddr);
}
put_str("!!!!!! excetion message end !!!!!!\n");
while(1);
}
static void exception_init(void) {
int i;
for (i = 0; i < IDT_DESC_CNT; i++) {
idt_table[i] = general_intr_handler;
intr_name[i] = "unknown";
}
intr_name[0] = "#DE Divide Error";
intr_name[1] = "#DB Debug Exception";
intr_name[2] = "NMI Interrupt";
intr_name[3] = "#BP Breakpoint Exception";
intr_name[4] = "#OF Overflow Exception";
intr_name[5] = "#BR BOUND Range Exceeded Exception";
intr_name[6] = "#UD Invalid Opcode Exception";
intr_name[7] = "#NM Device Not Available Exception";
intr_name[8] = "#DF Double Fault Exception";
intr_name[9] = "Coprocessor Segment Overrun";
intr_name[10] = "#TS Invalid TSS Exception";
intr_name[11] = "#NP Segment Not Present";
intr_name[12] = "#SS Stack Fault Exception";
intr_name[13] = "#GP General Protection Exception";
intr_name[14] = "#PF Page-Fault Exception";
intr_name[16] = "#MF x87 FPU Floating-Point Error";
intr_name[17] = "#AC Alignment Check Exception";
intr_name[18] = "#MC Machine-Check Exception";
intr_name[19] = "#XF SIMD Floating-Point Exception";
}
void idt_init() {
put_str("idt_init start\n");
idt_desc_init();
exception_init();
pic_init();
uint64_t idt_operand = ((sizeof(idt) - 1) | ((uint64_t)(uint32_t)idt << 16));
asm volatile("lidt %0" : : "m" (idt_operand));
put_str("idt_init done\n");
}
void register_handler(uint8_t vec_no,intr_handler function)
{
idt_table[vec_no] = function;
}
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;
}
switch.S
[bits 32]
section .text
global switch_to
switch_to:
push esi ;这里是根据ABI原则保护四个寄存器 放到栈里面
push edi
push ebx
push ebp
mov eax,[esp+20] ;esp+20的位置是cur cur的pcb赋值给eax
mov [eax],esp ;[eax]为pcb的内核栈指针变量 把当前环境的esp值记录下来
mov eax,[esp+24]
mov esp,[eax] ;把要切换的线程的pcb 内核栈esp取出来
pop ebp
pop ebx
pop edi
pop esi
ret ;这里的返回地址为 kernel_thread的地址
稍加修改过的print.S
为了用set_cursor 修改了一下 把set_cursor变成可以调用的函数了
[bits 32]
section .text
global switch_to
switch_to:
push esi ;这里是根据ABI原则保护四个寄存器 放到栈里面
push edi
push ebx
push ebp
mov eax,[esp+20] ;esp+20的位置是cur cur的pcb赋值给eax
mov [eax],esp ;[eax]为pcb的内核栈指针变量 把当前环境的esp值记录下来
mov eax,[esp+24]
mov esp,[eax] ;把要切换的线程的pcb 内核栈esp取出来
pop ebp
pop ebx
pop edi
pop esi
ret ;这里的返回地址为 kernel_thread的地址
稍微修改了一下的stdint.h
发现bool 经常会出错 而且true false报错 就这里加了一下
#ifndef __LIB_STDINT_H
#define __LIB_STDINT_H
#define true 1
#define false 0
typedef int bool;
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
#endif
timer.c
#include "timer.h"
#include "io.h"
#include "print.h"
#include "../kernel/interrupt.h"
#include "../thread/thread.h"
#include "debug.h"
#define IRQ0_FREQUENCY 100
#define INPUT_FREQUENCY 1193180
#define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY
#define COUNTER0_PORT 0X40
#define COUNTER0_NO 0
#define COUNTER_MODE 2
#define READ_WRITE_LATCH 3
#define PIT_COUNTROL_PORT 0x43
uint32_t ticks;
void frequency_set(uint8_t counter_port ,uint8_t counter_no,uint8_t rwl,uint8_t counter_mode,uint16_t counter_value)
{
outb(PIT_COUNTROL_PORT,(uint8_t) (counter_no << 6 | rwl << 4 | counter_mode << 1));
outb(counter_port,(uint8_t)counter_value);
outb(counter_port,(uint8_t)counter_value >> 8);
return;
}
void intr_timer_handler(void)
{
struct task_struct* cur_thread = running_thread();
ASSERT(cur_thread->stack_magic == 0x23333333);
++ticks;
++cur_thread->elapsed_ticks;
if(!cur_thread->ticks)
schedule();
else
--cur_thread->ticks;
return;
}
void timer_init(void)
{
put_str("timer_init start!\n");
frequency_set(COUNTER0_PORT,COUNTER0_NO,READ_WRITE_LATCH,COUNTER_MODE,COUNTER0_VALUE);
register_handler(0x20,intr_timer_handler);
put_str("timer_init done!\n");
return;
}
timer.h
#ifndef __DEVICE_TIME_H
#define __DEVICE_TIME_H
#include "stdint.h"
void frequency_set(uint8_t counter_port ,uint8_t counter_no,uint8_t rwl,uint8_t counter_mode,uint16_t counter_value);
void intr_timer_handler(void);
void timer_init(void);
void mtime_sleep(uint32_t m_seconds);
#endif
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 $(BUILD_DIR)/thread.o $(BUILD_DIR)/list.o $(BUILD_DIR)/switch.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
$(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
$(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/kernel/io.h lib/kernel/print.h \
kernel/interrupt.h thread/thread.h kernel/debug.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 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
$(CC) $(CFLAGS) $< -o $@
$(BUILD_DIR)/list.o: lib/kernel/list.c lib/kernel/list.o \
kernel/interrupt.h lib/stdint.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)/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 .
最终实现效果
不知道是不是因为字符串的原因 动不动就会直接报错 感觉可能就是因为同步的问题 最后这里直接会卡死 希望应该后面一章的锁给做了 这里就不会报错了 如果不是的话 我脆弱的心脏哪天出事的话 我都不会感觉到意外 做操作系统心脏真的得好啊 先写到这里 吃晚饭去了 咕~

|