相关查阅博客链接
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 .
最终实现效果
不知道是不是因为字符串的原因 动不动就会直接报错 感觉可能就是因为同步的问题 最后这里直接会卡死 希望应该后面一章的锁给做了 这里就不会报错了 如果不是的话 我脆弱的心脏哪天出事的话 我都不会感觉到意外 做操作系统心脏真的得好啊 先写到这里 吃晚饭去了 咕~
|