相关查阅博客链接
C语言static 关键字总结
本书中错误勘误
1、这个地方我认为是书上没有写到的地方 就是kernel.S 里面的syscall_handler() 需要头文件单独引出来 不然编译器找不到函数
闲聊时刻
今天已经是 8月2日了 距离暑假结束仅有33天了 细细回忆 我们军训结束就已经7月18日了 原本其实我在军训还没开始的时候我就觉得暑假应该去完成很多很多事情 但是可惜 军训的15天把我的很多计划与斗志全部化为了灰烬
7/19-7/22 在寝室昏耍了4天之后 潘然不想再继续玩下去了 因为没有什么好玩的了 毅然决然决定去图书馆重新整顿整顿 恢复原来的状态 7/22-7/30 可能还是连续去了很几天 然后室友就全部搬出去了 那个时候因为很久很久没有开始编程了 进度相对会稍微慢一些 但是之后室友搬出来之后就没有再去图书馆了 去图书馆的原因只是我做事情的时候比较喜欢独处 不喜欢有人在旁边
细细想来 复工到现在已经有12天了 操作系统播客也陆陆续续发了5篇了 为什么会来这里写点闲聊 是因为昨天一天上午把前天的博客写了发出去了 下午写了三道力扣之后就开始彻底歇下来了 开始看视频 玩小游戏 导致昨天晚上的晚饭也没有吃
其实我很清楚 暑假一个人在寝室也是一个挺大的考验 身边太多事情自己容易被分心 我觉得很多事情自己还是得做的毅然决然一点 话就不写那么多了 今天一天先把第十二章给结束了 之后的事情还得一点点慢慢做
实现系统调用
实现系统调用的思路
这里还是说一下大概的思路 因为之前哈工大操作系统Lab中 我们就自己实现过系统调用 当然 那个时候只是人家把框架写好 我们往里面套函数罢了 但是多多少少还是对这部分挺熟悉的
1、例如进程调用getpid() 后
2、调用getpid() 的函数 == 调用_syscall0宏函数 函数号放入了eax
3、_syscall0 中 int 0x80 引发中断 eax 此时已经是函数号了
4、int 0x80 的中断处理函数就是syscall_handler syscall_handler 的核心在call [syscall_table+eax*4] 我们的syscall_table 是提前准备好的 就是我们各种系统调用的函数指针表 根据我们输入的函数号即可定位到对应的处理函数
5、之后再进入intr_exit 还原上下文 中断退出 完整的系统调用结束 程序照常进行
也没什么好说的 翻来覆去就那么点内容 哈哈 不说了 看下面代码吧
修改后的kernel.S
这里就是多了一个syscall_handler 还有多了下面的填位置的中断序列 改一下即可
[bits 32]
%define ERROR_CODE nop ; 若在相关的异常中cpu已经自动压入了错误码,为保持栈中格式统一,这里不做操作.
%define ZERO push 0 ; 若在相关的异常中cpu没有压入错误码,为了统一栈中格式,就手工压入一个0
extern put_str;
extern idt_table;
extern syscall_table;
section .data
global intr_entry_table
intr_entry_table:
%macro VECTOR 2
section .text
intr%1entry: ; 每个中断处理程序都要压入中断向量号,所以一个中断类型一个中断处理程序,自己知道自己的中断向量号是多少
%2 ; 中断若有错误码会压在eip后面
; 以下是保存上下文环境
push ds
push es
push fs
push gs
pushad ; PUSHAD指令压入32位寄存器,其入栈顺序是: EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
; 如果是从片上进入的中断,除了往从片上发送EOI外,还要往主片上发送EOI
mov al,0x20 ; 中断结束命令EOI
out 0xa0,al ; 向从片发送
out 0x20,al ; 向主片发送
push %1 ; 不管idt_table中的目标程序是否需要参数,都一律压入中断向量号,调试时很方便
call [idt_table + %1*4] ; 调用idt_table中的C版本中断处理函数
jmp intr_exit
section .data
dd intr%1entry ; 存储各个中断入口程序的地址,形成intr_entry_table数组
%endmacro
section .text
global intr_exit
intr_exit:
; 以下是恢复上下文环境
add esp, 4 ; 跳过中断号
popad
pop gs
pop fs
pop es
pop ds
add esp, 4 ; 跳过error_code
iretd
section .text
global syscall_handler
syscall_handler:
push 0
push ds
push es
push fs
push gs
pushad
push 0x80 ; 不管是否需要参数,都一律压入中断向量号,调试时很方便
push edx ;第三个参数
push ecx ;第二个参数
push ebx ;第一个参数
call [syscall_table + eax*4]
add esp,12
mov [esp + 8*4],eax ;返回值给放到eax中 eax前面有 中断号+EDI+ESI+EBP+ESP+EBX+EDX+ECX
jmp intr_exit
VECTOR 0x0 ,ZERO
VECTOR 0X1 ,ZERO
VECTOR 0X2 ,ZERO
VECTOR 0x3 ,ZERO
VECTOR 0X4 ,ZERO
VECTOR 0X5 ,ZERO
VECTOR 0x6 ,ZERO
VECTOR 0X7 ,ZERO
VECTOR 0X8 ,ERROR_CODE
VECTOR 0x9 ,ZERO
VECTOR 0XA ,ERROR_CODE
VECTOR 0XB ,ERROR_CODE
VECTOR 0XC ,ERROR_CODE
VECTOR 0XD ,ERROR_CODE
VECTOR 0XE ,ERROR_CODE
VECTOR 0XF ,ZERO
VECTOR 0X10 ,ZERO
VECTOR 0X11 ,ERROR_CODE
VECTOR 0x12 ,ZERO
VECTOR 0X13 ,ZERO
VECTOR 0X14 ,ZERO
VECTOR 0x15 ,ZERO
VECTOR 0X16 ,ZERO
VECTOR 0X17 ,ZERO
VECTOR 0X18 ,ZERO
VECTOR 0X19 ,ZERO
VECTOR 0X1A ,ZERO
VECTOR 0X1B ,ZERO
VECTOR 0X1C ,ZERO
VECTOR 0X1D ,ZERO
VECTOR 0X1E ,ERROR_CODE ;处理器自动推错误码
VECTOR 0X1F ,ZERO
VECTOR 0X20 ,ZERO ;时钟中断
VECTOR 0X21 ,ZERO ;键盘中断
VECTOR 0X22 ,ZERO ;级联
VECTOR 0X23 ,ZERO ;串口2
VECTOR 0X24 ,ZERO ;串口1
VECTOR 0X25 ,ZERO ;并口2
VECTOR 0X26 ,ZERO ;软盘
VECTOR 0X27 ,ZERO ;并口1
VECTOR 0X28 ,ZERO ;实时时钟
VECTOR 0X29 ,ZERO ;重定向
VECTOR 0X2A ,ZERO ;保留
VECTOR 0x2B ,ZERO ;保留
VECTOR 0x2C ,ZERO ;ps/2 鼠标
VECTOR 0x2D ,ZERO ;fpu 浮点单元异常
VECTOR 0x2E ,ZERO ;硬盘
VECTOR 0x2F ,ZERO ;保留
VECTOR 0x30 ,ZERO
VECTOR 0x31 ,ZERO
VECTOR 0x32 ,ZERO
VECTOR 0x33 ,ZERO
VECTOR 0x34 ,ZERO
VECTOR 0x35 ,ZERO
VECTOR 0x36 ,ZERO
VECTOR 0x37 ,ZERO
VECTOR 0x38 ,ZERO
VECTOR 0x39 ,ZERO
VECTOR 0x3A ,ZERO
VECTOR 0x3B ,ZERO
VECTOR 0x3C ,ZERO
VECTOR 0x3D ,ZERO
VECTOR 0x3E ,ZERO
VECTOR 0x3F ,ZERO
VECTOR 0x40 ,ZERO
VECTOR 0x41 ,ZERO
VECTOR 0x42 ,ZERO
VECTOR 0x43 ,ZERO
VECTOR 0x44 ,ZERO
VECTOR 0x45 ,ZERO
VECTOR 0x46 ,ZERO
VECTOR 0x47 ,ZERO
VECTOR 0x48 ,ZERO
VECTOR 0x49 ,ZERO
VECTOR 0x4A ,ZERO
VECTOR 0x4B ,ZERO
VECTOR 0x4C ,ZERO
VECTOR 0x4D ,ZERO
VECTOR 0x4E ,ZERO
VECTOR 0x4F ,ZERO
VECTOR 0x50 ,ZERO
VECTOR 0x51 ,ZERO
VECTOR 0x52 ,ZERO
VECTOR 0x53 ,ZERO
VECTOR 0x54 ,ZERO
VECTOR 0x55 ,ZERO
VECTOR 0x56 ,ZERO
VECTOR 0x57 ,ZERO
VECTOR 0x58 ,ZERO
VECTOR 0x59 ,ZERO
VECTOR 0x5A ,ZERO
VECTOR 0x5B ,ZERO
VECTOR 0x5C ,ZERO
VECTOR 0x5D ,ZERO
VECTOR 0x5E ,ZERO
VECTOR 0x5F ,ZERO
VECTOR 0x61 ,ZERO
VECTOR 0x62 ,ZERO
VECTOR 0x63 ,ZERO
VECTOR 0x64 ,ZERO
VECTOR 0x65 ,ZERO
VECTOR 0x66 ,ZERO
VECTOR 0x67 ,ZERO
VECTOR 0x68 ,ZERO
VECTOR 0x69 ,ZERO
VECTOR 0x6A ,ZERO
VECTOR 0x6B ,ZERO
VECTOR 0x6C ,ZERO
VECTOR 0x6D ,ZERO
VECTOR 0x6E ,ZERO
VECTOR 0x6F ,ZERO
VECTOR 0x70 ,ZERO
VECTOR 0x71 ,ZERO
VECTOR 0x72 ,ZERO
VECTOR 0x73 ,ZERO
VECTOR 0x74 ,ZERO
VECTOR 0x75 ,ZERO
VECTOR 0x76 ,ZERO
VECTOR 0x77 ,ZERO
VECTOR 0x78 ,ZERO
VECTOR 0x79 ,ZERO
VECTOR 0x7A ,ZERO
VECTOR 0x7B ,ZERO
VECTOR 0x7C ,ZERO
VECTOR 0x7D ,ZERO
VECTOR 0x7E ,ZERO
VECTOR 0x7F ,ZERO
VECTOR 0x80 ,ZERO
修改后的interrupt.c
这里修改主要修改支持中断数到0x81 因为最后的中断是int 0x80 还有把int 0x80 的中断函数地址赋值给 syscall_handler 直接给代码咯
注意注意注意 这里包含的kernel.h 是为了把syscall_handler 给引出来 不加这个我这里显示没办法找到kernel.S 里面的函数
这里先给kernel.h 的代码 再下面就是interrupt.c
kernel.h
#ifndef __KERNEL_KERNEL_H
#define __KERNEL_KERNEL_H
void syscall_handler(void);
#endif
interrupt.c
#include "interrupt.h"
#include "stdint.h"
#include "global.h"
#include "io.h"
#include "print.h"
#include "kernel.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 0x81
#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);
static struct gate_desc idt[IDT_DESC_CNT];
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, 0xfc);
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]);
}
make_idt_desc(&idt[lastindex],IDT_DESC_ATTR_DPL3,syscall_handler);
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;
}
编写完的syscall.c
路径lib/user/syscall.c 宏函数定义在此
#include "syscall.h"
#define _syscall0(NUMBER) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) : "memory"); retval; \
})
#define _syscall1(NUMBER, ARG1) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) : "memory"); retval; \
})
#define _syscall2(NUMBER, ARG1, ARG2) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2): "memory"); retval; \
})
#define _syscall3(NUMBER, ARG1, ARG2, ARG3) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2), "d"(ARG3): "memory"); retval; \
})
uint32_t getpid(void)
{
return _syscall0(SYS_GETPID);
}
编写完的syscall.h
路径lib/user/syscall.h
#ifndef __LIB_USER_SCSCALL_H
#define __LIB_USER_SCSCALL_H
#include "stdint.h"
enum SYSCALL_NR
{
SYS_GETPID
};
uint32_t getpid(void);
#endif
编写完的syscall-init.c
这里主要就是把syscall_table 初始化了 还有函数定义了
#include "syscall-init.h"
#include "../lib/user/syscall.h"
#include "stdint.h"
#include "print.h"
#include "interrupt.h"
#include "../thread/thread.h"
#define syscall_nr 32
typedef void* syscall;
syscall syscall_table[syscall_nr];
uint32_t sys_getpid(void)
{
return running_thread()->pid;
}
void syscall_init(void)
{
put_str("syscall_init start\n");
syscall_table[SYS_GETPID] = sys_getpid;
put_str("syscall_init done\n");
}
编写后的syscall-init.h
#ifndef __USERPROG_SYSCALL_INIT_H
#define __USERPROG_SYSCALL_INIT_H
#include "stdint.h"
uint32_t sys_getpid(void);
void syscall_init(void);
#endif
修改后的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"
#include "../userprog/process.h"
#include "../thread/sync.h"
struct task_struct* main_thread;
struct list thread_ready_list;
struct list thread_all_list;
struct lock pid_lock;
extern void switch_to(struct task_struct* cur,struct task_struct* next);
pid_t allocate_pid(void)
{
static pid_t next_pid = 0;
lock_acquire(&pid_lock);
++next_pid;
lock_release(&pid_lock);
return next_pid;
}
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_stack);
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->pid = allocate_pid();
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;
process_activate(next);
switch_to(cur,next);
}
void thread_init(void)
{
put_str("thread_init start!\n");
list_init(&thread_ready_list);
list_init(&thread_all_list);
lock_init(&pid_lock);
make_main_thread();
put_str("thread_init done!\n");
}
void thread_block(enum task_status stat)
{
ASSERT(((stat == TASK_BLOCKED) || (stat == TASK_WAITING) || stat == TASK_HANGING));
enum intr_status old_status = intr_disable();
struct task_struct* cur_thread = running_thread();
cur_thread->status = stat;
schedule();
intr_set_status(old_status);
}
void thread_unblock(struct task_struct* pthread)
{
enum intr_status old_status = intr_disable();
ASSERT(((pthread->status == TASK_BLOCKED) || (pthread->status == TASK_WAITING) || (pthread->status == TASK_HANGING)));
if(pthread->status != TASK_READY)
{
ASSERT(!elem_find(&thread_ready_list,&pthread->general_tag));
if(elem_find(&thread_ready_list,&pthread->general_tag))
PANIC("thread_unblock: blocked thread in ready_list\n");
list_push(&thread_ready_list,&pthread->general_tag);
pthread->status = TASK_READY;
}
intr_set_status(old_status);
}
修改后的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"
void init_all() {
put_str("init_all\n");
idt_init();
mem_init();
timer_init();
thread_init();
console_init();
keyboard_init();
tss_init();
syscall_init();
}
修改后的Main.c
#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
int a=0,b=0;
void test_thread1(void* arg);
void test_thread2(void* arg);
void u_prog_a(void);
void u_prog_b(void);
int main(void) {
put_str("I am kernel\n");
init_all();
process_execute(u_prog_a,"user_prog_a");
process_execute(u_prog_b,"user_prog_b");
intr_enable();
console_put_str(" main_pid:0x");
console_put_int(sys_getpid());
console_put_char('\n');
thread_start("kernel_thread_a",31,test_thread1," thread_A:0x");
thread_start("kernel_thread_b",31,test_thread2," thread_B:0x");
while(1);
return 0;
}
void test_thread1(void* arg)
{
console_put_str((char*)arg);
console_put_int(getpid());
console_put_char('\n');
console_put_str(" u_prog_a:0x");
console_put_int(a);
console_put_char('\n');
while(1);
}
void test_thread2(void* arg)
{
console_put_str((char*)arg);
console_put_int(getpid());
console_put_char('\n');
console_put_str(" u_prog_b:0x");
console_put_int(b);
console_put_char('\n');
while(1);
}
void u_prog_a(void)
{
a = getpid();
while(1);
}
void u_prog_b(void)
{
b = getpid();
while(1);
}
修改后的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
############## 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
$(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
$(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
$(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 \
thread/sync.h thread/thread.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
$(CC) $(CFLAGS) $< -o $@
$(BUILD_DIR)/syscall.o: lib/user/syscall.c lib/user/syscall.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 .
make all 验收成果
哈哈 每次验收成果的时候 都是这个小标题 当然每次都不知道调试过多少次了 再来写这个博客
后面会留下一个小问题 哈哈 当时人几乎要崩溃了 发现有问题 后面才醒悟过来 后面再写 看下面的效果应该是ok了 后面会有一个小问题
为什么进程里面不允许console_put_str
这个问题其实当时几乎让我崩溃 哈哈哈 如果进程里面放了console_put_str 的话 可以试一下 一定会报错 例如下面的 我就加了一句
void u_prog_a(void)
{
a = getpid();
console_put_str("go!\n");
while(1);
}
最后的运行效果 其实没什么好神秘 如果你还不知道答案的话 说明可能之前做进程部分有点点水 哈哈 就是那个时候 我们设置了gs == 0 相当于进程是不允许访问显存的 还记得吗 哈哈 就是这个样子 一切都make sense 了
实现简易write
哈哈 超级简易 没有什么好说的 直接给代码吧
修改后的syscall-init.c
#include "syscall-init.h"
#include "../lib/user/syscall.h"
#include "stdint.h"
#include "print.h"
#include "interrupt.h"
#include "../thread/thread.h"
#define syscall_nr 32
typedef void* syscall;
syscall syscall_table[syscall_nr];
uint32_t sys_getpid(void)
{
return running_thread()->pid;
}
void sys_write(char* str)
{
console_put_str(str);
}
void syscall_init(void)
{
put_str("syscall_init start\n");
syscall_table[SYS_GETPID] = sys_getpid;
syscall_table[SYS_WRITE] = sys_write;
put_str("syscall_init done\n");
}
修改后的syscall-init.h
#ifndef __USERPROG_SYSCALL_INIT_H
#define __USERPROG_SYSCALL_INIT_H
#include "stdint.h"
uint32_t sys_getpid(void);
void sys_write(char* str);
void syscall_init(void);
#endif
修改后的syscall.c
#include "syscall.h"
#define _syscall0(NUMBER) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) : "memory"); retval; \
})
#define _syscall1(NUMBER, ARG1) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) : "memory"); retval; \
})
#define _syscall2(NUMBER, ARG1, ARG2) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2): "memory"); retval; \
})
#define _syscall3(NUMBER, ARG1, ARG2, ARG3) ({ \
int retval; \
asm volatile ("int $0x80" : "=a"(retval) : "a"(NUMBER) , "b"(ARG1) , "c"(ARG2), "d"(ARG3): "memory"); retval; \
})
uint32_t getpid(void)
{
return _syscall0(SYS_GETPID);
}
void write(char* str)
{
return _syscall1(SYS_WRITE,str);
}
修改后的syscall.h
#ifndef __LIB_USER_SCSCALL_H
#define __LIB_USER_SCSCALL_H
#include "stdint.h"
enum SYSCALL_NR
{
SYS_GETPID,
SYS_WRITE
};
uint32_t getpid(void);
void write(char* str);
#endif
实现printf
哈哈 这部分挺有趣的 只是因为下午自己懒了一下 跟别人聊了一个小时的天 然后跟同学语音打了两个小时 导致今日份的任务没做完 晚饭还没吃 晕 待会把这部分博客写了 下楼买泡面了 看一下还开没开门
对于这部分的指针问题 我也已经很详细的写了注释了 看不懂为什么有的时候要取& 我只能说 比如int a = 8 为了在其他函数改变a 的值 不改变形参 我们都会用int* 传导 然后通过*a = 6 来改变 很多地方就是同理 ok
编写后的stdio.c
路径lib/stdio.c
#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "syscall.h"
#define va_start(ap,v) ap = (va_list)&v
#define va_arg(ap,t) *((t*)(ap +=4))
#define va_end(ap) ap = NULL
void itoa(uint32_t value,char** buf_ptr_addr,uint8_t base)
{
uint32_t m = value % base;
uint32_t i = value / base;
if(i)
itoa(i,buf_ptr_addr,base);
if(m < 10)
*((*buf_ptr_addr)++) = m + '0';
else
*((*buf_ptr_addr)++) = m + 'A' - 10;
}
uint32_t vsprintf(char* str,const char* format,va_list ap)
{
char* buf_ptr = str;
const char* index_ptr = format;
char index_char = *index_ptr;
int32_t arg_int;
char* arg_str;
while(index_char)
{
if(index_char != '%')
{
*(buf_ptr++) = index_char;
index_char = *(++index_ptr);
continue;
}
index_char = *(++index_ptr);
switch(index_char)
{
case 's':
arg_str = va_arg(ap,char*);
strcpy(buf_ptr,arg_str);
buf_ptr += strlen(arg_str);
index_char = *(++index_ptr);
break;
case 'x':
arg_int = va_arg(ap,int);
itoa(arg_int,&buf_ptr,16);
index_char = *(++index_ptr);
break;
case 'd':
arg_int = va_arg(ap,int);
if(arg_int < 0)
{
arg_int = 0 - arg_int;
*(buf_ptr++) = '-';
}
itoa(arg_int,&buf_ptr,10);
index_char = *(++index_ptr);
break;
case 'c':
*(buf_ptr++) = va_arg(ap,char);
index_char = *(++index_ptr);
}
}
return strlen(str);
}
uint32_t printf(const char* format, ...)
{
va_list args;
uint32_t retval;
va_start(args,format);
char buf[1024] = {0};
retval = vsprintf(buf,format,args);
va_end(args);
write(buf);
return retval;
}
编写后的stdio.h
#ifndef __LIB__STDIO_H
#define __LIB__STDIO_H
#include "stdint.h"
typedef void* va_list;
void itoa(uint32_t value,char** buf_ptr_addr,uint8_t base);
uint32_t vsprintf(char* str,const char* format,va_list ap);
uint32_t printf(const char* format, ...);
#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)/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
############## 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
$(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
$(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
$(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 \
thread/sync.h thread/thread.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
$(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)/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 .
修改后的main.c
#include "print.h"
#include "init.h"
#include "debug.h"
#include "string.h"
#include "memory.h"
#include "../thread/thread.h"
#include "interrupt.h"
#include "../device/console.h"
#include "../device/ioqueue.h"
#include "../device/keyboard.h"
#include "../userprog/process.h"
#include "../lib/user/syscall.h"
#include "../userprog/syscall-init.h"
#include "../lib/stdio.h"
int a=0,b=0;
void test_thread1(void* arg);
void test_thread2(void* arg);
void u_prog_a(void);
void u_prog_b(void);
int main(void) {
put_str("I am kernel\n");
init_all();
process_execute(u_prog_a,"user_prog_a");
process_execute(u_prog_b,"user_prog_b");
intr_enable();
console_put_str(" i am main:0x");
printf("%x",getpid());
console_put_char('\n');
thread_start("kernel_thread_a",31,test_thread1," i am thread_A:0x");
thread_start("kernel_thread_b",31,test_thread2," i am thread_B:0x");
while(1);
return 0;
}
void test_thread1(void* arg)
{
console_put_str((char*)arg);
printf("%x",getpid());
console_put_char('\n');
while(1);
}
void test_thread2(void* arg)
{
console_put_str((char*)arg);
printf("%x",getpid());
console_put_char('\n');
while(1);
}
void u_prog_a(void)
{
printf(" i am %s prog_a_pid:%d%c","prog_a",getpid(),'\n');
while(1);
}
void u_prog_b(void)
{
printf(" i am %s prog_b_pid:%d%c","prog_b",getpid(),'\n');
while(1);
}
make all 验收成果
老套路了哈 这里ok了 家人们 此时心里面有没有疑惑 为什么上面说 线程不能输出字符 现在可以了哈哈 因为这里是调用的write 中断 进入了中断之后才行的 之后进入内核空间再调用的 console_put_str ok 下楼买泡面去了
晚餐时间
晒点晚餐 哈哈 买完回来之后吃了桶泡面就匆匆上床了 之后的内容只能明天再做了
结束语(上)
下面的内容就留到下篇再写了 今天晚上吃完好次的晚饭发现太晚了 只能留到明天辣 下篇再见~
|