中断上下文

master
阳光少年 1 year ago
parent 0ec631a645
commit 71e3d80ed9

@ -8,7 +8,7 @@
; c语言整理的其实也是下面的 handler_entry_table
extern handler_table
; 中断发生时栈的布局为: 低地址(栈顶) %1(中断向量号) gp错误码(如果有) ip cs eflags 高地址(栈底)
; 中断发生时栈的布局为: 低地址(栈顶) %1(中断向量号) gp错误码(如果有) ip cs eflags 高地址(栈底)
section .text
; ## gp错误码
@ -20,15 +20,19 @@ section .text
; 由于0x80 我们没有中断处理函数, 手动软中断出发之后, 又会立即硬中断所以会又触发0x0d一般性保护异常, 把异常压入栈
; 在80286中 gp错误码是16个bit, 现在为了兼容 扩充到了32位
; ## eflag ; sti打开中断这个指令会把 if位 置为1,
; ## eflag ; sti打开中断这个指令会把 if位 置为1, 如果是0表示中断时禁用状态
; 如果使用sti指令 后压入栈的 eflags就是 0x212, 如果关闭中断则压入栈的eflags就变成了0x012, 0x212或者0x012 这俩数, 他们的bit位的第九位存在差别
; 此时压入栈的是0x212, 而eflag寄存器则是0x12, 因为我们初始化中断描述符的时候, 设置的是中断门 所以第九位被置为了0保存在了eflag寄存器中
; 所以, 在中断的时候 eflag中的 if位又被设置成了0(关闭中断状态), 如果我们想在中断处理函数内调度用户任务, 需要打开中断, 让用户任务执行的时候可以触发中断
; 此时压入栈的是0x212, 而eflag寄存器则是0x12(是为了防止在处理中断的时候又被触发中断), 因为我们初始化中断描述符的时候, 设置的是中断门 所以第九位被置为了0保存在了eflag寄存器中
; 所以, 在中断的时候 eflag中的 if位又被设置成了0(关闭中断状态),
; 如果我们想在中断处理函数内调度用户任务, 且由中断调用的schdule切换到用户任务执行中又可以被中断 需要打开中断, 让用户任务执行的时候可以触发中断
; 注意在 schdule函数体内, 中断是关闭状态, 只有tash_switch 切换完之后ret, 再到外面iret完成之后, 恢复到用户任务执行的时候才会回复用户任务eflag状态
; 用户的任务因为是在中断内进行的调度, 而进入中断 if标志位又被置为0, 所以由中断函数进入到当前任务中时, 需要把任务的eflag置为1(打开中断)
; 这样中断在调用完中断处理函数之后, 会pop保存的寄存器状态, 我们这个函数一进来就把 if标志位置 设置为1了, 也就跟着恢复了
; 时钟中断时 0x20 这个也没有错误码
%macro INTERRUPT_HANDLER 2
interrupt_handler_%1:
xchg bx, bx ; 这时候观察栈, 如果有状态码
; xchg bx, bx ; 这时候观察栈, 如果有状态码
%ifn %2
push 0x20222202 ; 这个是给没有错误码的调用添加一个自己定义的魔数
%endif
@ -38,11 +42,29 @@ interrupt_handler_%1:
interrupt_entry:
mov eax, [esp]
; 进入中断, 保存寄存器上下文信息, 一共保存了 12个
push ds
push es
push fs
push gs
pusha ; 8个寄存器
mov eax, [esp + 12 * 4] ; 找到%1 压入的中断向量
; 调用中断处理函数 handler_table 中存储了中断处理函数的指针, 并把 上方push %1 中断号传入中断处理函数的指针(所以这里 *4)
push eax
call [handler_table + eax * 4]
; 弹栈, 弹出 %1, 弹出0x20222202, 后面调用iret
add esp, 4 ; 弹出调用中断处理函数之前push 的 eax
; 弹出12个寄存器
popa
pop gs
pop fs
pop es
pop ds
; 弹栈, 弹出 宏里面的生成的 %1, 弹出0x20222202, 后面调用iret
add esp, 8
iret

@ -13,15 +13,33 @@ u8* handler_table[IDT_SIZE];
// 为了让我们从c语言加载 idt表, 中断时 会先进入这个指针所在函数内, 然后继续跳入到 handler_table中
extern handler_entry_table[ENTRY_SIZE];
// 导入调度函数
extern void schdule();
// 异常 中断处理函数默认函数
void exception_handle(u8 handle_num){
void exception_handle(u8 handle_num,
u32 edi, u32 esi, u32 ebp, u32 esp,
u32 ebx, u32 edx, u32 ecx, u32 eax,
u32 gs, u32 fs, u32 es, u32 ds,
u32 vector0, u32 error, u32 eip, u32 cs, u32 eflags){
char *msg;
if (handle_num < 22) {
msg = messages[handle_num];
} else{
msg = messages[15];
}
printk("Exception as [0x%02X] %s\n", handle_num, msg);
// 打印异常发生时, 一些寄存器的状态
printk("\nEXCEPTION : %s \n", msg);
printk(" VECTOR : 0x%02X\n", handle_num);
printk(" ERROR : 0x%08X\n", error);
printk(" EFLAGS : 0x%08X\n", eflags);
printk(" CS : 0x%02X\n", cs);
printk(" EIP : 0x%08X\n", eip);
printk(" ESP : 0x%08X\n", esp);
hang();
}
@ -39,13 +57,11 @@ void send_eoi(u8 handle_num)
}
}
u32 counter = 0;
// 外中断 中断处理函数默认函数
void default_handler(u8 handle_num)
{
void default_handler(u8 handle_num){
send_eoi(handle_num);
counter += 1;
DEBUGK("[%x] default interrupt called... %d", handle_num, counter);
// 外中断发生就立即调度
schdule();
}

@ -11,24 +11,18 @@ void kernel_init(){
// 初始化全局描述符
gdt_init();
// 初始化任务
// task_init();
// 初始化中断
interrupt_init();
asm volatile(
"sti\n" // 打开cpu的中断中断
"movl %eax, %eax\n"
);
// u32 counter = 0;
// while(true){
// counter += 1;
// DEBUGK("looping in kernel init %d", counter);
// delay(10000000);
// int cnt = 0;
// while (true){
// cnt += 1;
// printk("%d", 123);
// }
// 初始化任务
task_init();
}

@ -6,6 +6,7 @@
static u8* buf[1024];
u32 printk(const u8 *fmt, ...){
va_list args;
u32 i;
@ -13,6 +14,9 @@ u32 printk(const u8 *fmt, ...){
i = vsprintf(buf, fmt, args);
va_end(args);
asm volatile("cli\n");
console_write(buf, i);
asm volatile("sti\n");
return i;
}

@ -25,6 +25,7 @@ task_switch:
; next的 的栈顶指针
mov esp, [eax]
; 在任务第一次进入到这里的时候会把我们设置的寄存器的默认值 pop 到指定寄存器中
pop edi
pop esi
pop ebx

@ -9,7 +9,7 @@ global _start
_start:
call kernel_init
; int 0x0d
; int 0x08
; mov bx, 0
; div bx

@ -1,4 +1,5 @@
#include <onix/task.h>
#include <onix/debug.h>
#include <onix/printk.h>
extern void task_switch(task_t* next);
@ -33,7 +34,7 @@ task_t* running_task(){
}
void schdule(){
void _ofp schdule(){
task_t* current = running_task();
// 这里实验的, 如果当前是任务a 就切换到任务b, 如果是任务b 就切换到任务a
task_t* next;
@ -46,22 +47,26 @@ void schdule(){
}
void thread_a(){
void _ofp thread_a(){
asm volatile("sti\n");
int c = 0;
while(true){
printk("A");
schdule();
printk("A~");
}
}
void thread_b(){
void _ofp thread_b(){
// 因为是在中断内进行的调度, 而进入中断 if标志位又被置为0, 所以由中断函数进入到当前任务中时, 需要把任务的eflag置为1(打开中断)
// , 这样中断在调用完中断处理函数之后, 会pop保存的寄存器状态, 我们这个函数一进来就把 if标志位置 设置为1了, 也就跟着恢复了
asm volatile("sti\n");
int c = 0;
while(true){
printk("B");
schdule();
printk("B~");
}
}
void task_init(){
// test();
test();
}
@ -70,7 +75,6 @@ void test(){
task_create(task_a_stack, thread_a);
task_create(task_b_stack, thread_b);
schdule();
}
/*

@ -324,3 +324,217 @@ test_console(){
// console_write(message2, strlen(message2));
// console_write(message2, strlen(message2));
}
// #include <onix/console.h>
// #include <onix/io.h>
// #include <onix/string.h>
// #define CRT_ADDR_REG 0x3D4 // CRT(6845)索引寄存器
// #define CRT_DATA_REG 0x3D5 // CRT(6845)数据寄存器
// #define CRT_START_ADDR_H 0xC // 显示内存起始位置 - 高位
// #define CRT_START_ADDR_L 0xD // 显示内存起始位置 - 低位
// #define CRT_CURSOR_H 0xE // 光标位置 - 高位
// #define CRT_CURSOR_L 0xF // 光标位置 - 低位
// #define MEM_BASE 0xB8000 // 显卡内存起始位置
// #define MEM_SIZE 0x4000 // 显卡内存大小
// #define MEM_END (MEM_BASE + MEM_SIZE) // 显卡内存结束位置
// #define WIDTH 80 // 屏幕文本列数
// #define HEIGHT 25 // 屏幕文本行数
// #define ROW_SIZE (WIDTH * 2) // 每行字节数
// #define SCR_SIZE (ROW_SIZE * HEIGHT) // 屏幕字节数
// #define ASCII_NUL 0x00
// #define ASCII_ENQ 0x05
// #define ASCII_BEL 0x07 // \a
// #define ASCII_BS 0x08 // \b
// #define ASCII_HT 0x09 // \t
// #define ASCII_LF 0x0A // \n
// #define ASCII_VT 0x0B // \v
// #define ASCII_FF 0x0C // \f
// #define ASCII_CR 0x0D // \r
// #define ASCII_DEL 0x7F
// static u32 screen; // 当前显示器开始的内存位置
// static u32 pos; // 记录当前光标的内存位置
// static u32 x, y; // 当前光标的坐标
// static u8 attr = 7; // 字符样式
// static u16 erase = 0x0720; // 空格
// // 获得当前显示器的开始位置
// static void get_screen()
// {
// out_8(CRT_ADDR_REG, CRT_START_ADDR_H); // 开始位置高地址
// screen = in_8(CRT_DATA_REG) << 8; // 开始位置高八位
// out_8(CRT_ADDR_REG, CRT_START_ADDR_L);
// screen |= in_8(CRT_DATA_REG);
// screen <<= 1; // screen *= 2
// screen += MEM_BASE;
// }
// // 设置当前显示器开始的位置
// static void set_screen()
// {
// out_8(CRT_ADDR_REG, CRT_START_ADDR_H); // 开始位置高地址
// out_8(CRT_DATA_REG, ((screen - MEM_BASE) >> 9) & 0xff);
// out_8(CRT_ADDR_REG, CRT_START_ADDR_L);
// out_8(CRT_DATA_REG, ((screen - MEM_BASE) >> 1) & 0xff);
// }
// // 获得当前光标位置
// static void get_cursor()
// {
// out_8(CRT_ADDR_REG, CRT_CURSOR_H); // 高地址
// pos = in_8(CRT_DATA_REG) << 8; // 高八位
// out_8(CRT_ADDR_REG, CRT_CURSOR_L);
// pos |= in_8(CRT_DATA_REG);
// get_screen();
// pos <<= 1; // pos *= 2
// pos += MEM_BASE;
// u32 delta = (pos - screen) >> 1;
// x = delta % WIDTH;
// y = delta / WIDTH;
// }
// static void set_cursor()
// {
// out_8(CRT_ADDR_REG, CRT_CURSOR_H); // 光标高地址
// out_8(CRT_DATA_REG, ((pos - MEM_BASE) >> 9) & 0xff);
// out_8(CRT_ADDR_REG, CRT_CURSOR_L);
// out_8(CRT_DATA_REG, ((pos - MEM_BASE) >> 1) & 0xff);
// }
// console_clear()
// {
// screen = MEM_BASE;
// pos = MEM_BASE;
// x = y = 0;
// set_cursor();
// set_screen();
// u16 *ptr = (u16 *)MEM_BASE;
// while (ptr < (u16 *)MEM_END)
// {
// *ptr++ = erase;
// }
// }
// // 向上滚屏
// static void scroll_up()
// {
// if (screen + SCR_SIZE + ROW_SIZE >= MEM_END)
// {
// memcpy((void *)MEM_BASE, (void *)screen, SCR_SIZE);
// pos -= (screen - MEM_BASE);
// screen = MEM_BASE;
// }
// u32 *ptr = (u32 *)(screen + SCR_SIZE);
// for (usize i = 0; i < WIDTH; i++)
// {
// *ptr++ = erase;
// }
// screen += ROW_SIZE;
// pos += ROW_SIZE;
// set_screen();
// }
// static void command_lf()
// {
// if (y + 1 < HEIGHT)
// {
// y++;
// pos += ROW_SIZE;
// return;
// }
// scroll_up();
// }
// static void command_cr()
// {
// pos -= (x << 1);
// x = 0;
// }
// static void command_bs()
// {
// if (x)
// {
// x--;
// pos -= 2;
// *(u16 *)pos = erase;
// }
// }
// static void command_del()
// {
// *(u16 *)pos = erase;
// }
// console_write(u8 *buf, u32 count)
// {
// char ch;
// while (count--)
// {
// ch = *buf++;
// switch (ch)
// {
// case ASCII_NUL:
// break;
// case ASCII_BEL:
// // todo \a
// break;
// case ASCII_BS:
// command_bs();
// break;
// case ASCII_HT:
// break;
// case ASCII_LF:
// command_lf();
// command_cr();
// break;
// case ASCII_VT:
// break;
// case ASCII_FF:
// command_lf();
// break;
// case ASCII_CR:
// command_cr();
// break;
// case ASCII_DEL:
// command_del();
// break;
// default:
// if (x >= WIDTH)
// {
// x -= WIDTH;
// pos -= ROW_SIZE;
// command_lf();
// }
// *((char *)pos) = ch;
// pos++;
// *((char *)pos) = attr;
// pos++;
// x++;
// break;
// }
// }
// set_cursor();
// }
// console_init()
// {
// console_clear();
// }
Loading…
Cancel
Save