From 80320033a3e24c95f0b941842504a231c419cd24 Mon Sep 17 00:00:00 2001 From: yanguangshaonian Date: Wed, 12 Apr 2023 14:07:44 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A1=E6=95=B0=E5=99=A8=E5=92=8C=E6=97=B6?= =?UTF-8?q?=E9=92=9F=E4=B8=AD=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 5 ++++- src/Makefile | 1 + src/include/onix/clock.h | 19 +++++++++++++++++++ src/include/onix/interrupt.h | 25 +++++++++++++++++++++++++ src/include/onix/onix.h | 1 + src/kernel/clock.c | 31 +++++++++++++++++++++++++++++++ src/kernel/interrupt.c | 34 ++++++++++++++++++++++++++++------ src/kernel/main.c | 14 ++++++-------- src/kernel/printk.c | 4 ++-- 9 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 src/include/onix/clock.h create mode 100644 src/kernel/clock.c diff --git a/.vscode/settings.json b/.vscode/settings.json index 598d26c..6c72fc9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,6 +22,9 @@ "task.h": "c", "interrupt.h": "c", "vector": "c", - "stdlib.h": "c" + "stdlib.h": "c", + "cassert": "c", + "*.inc": "c", + "clock.h": "c" } } \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index 936ea63..3c3b481 100644 --- a/src/Makefile +++ b/src/Makefile @@ -52,6 +52,7 @@ $(BUILD_PATH)/kernel.bin:$(BUILD_PATH)/kernel/start.o \ $(BUILD_PATH)/kernel/handle.o\ $(BUILD_PATH)/kernel/interrupt.o\ $(BUILD_PATH)/lib/stdlib.o\ + $(BUILD_PATH)/kernel/clock.o\ $(shell mkdir -p $(dir $@)) ld -m elf_i386 -static $^ -o $@ -Ttext $(KERNEL_ENTRY_POINT) diff --git a/src/include/onix/clock.h b/src/include/onix/clock.h new file mode 100644 index 0000000..79baeff --- /dev/null +++ b/src/include/onix/clock.h @@ -0,0 +1,19 @@ + +#ifndef ONIX_CLOCK_H +#define ONIX_CLOCK_H + + +#define PIT_CHAN0_REG 0X40 // 设置计数器 0 +#define PIT_CHAN2_REG 0X42 // 设置计数器 2 我们用不到 +#define PIT_CTRL_REG 0X43 // 控制字, 端口号是0x43, 8位寄存器, 控制字寄存器也是模式控制寄存器, 用于指定计数器的工作方式, 读写格式, 以及数字制式 + + +#define HITS 100 // 我们设置的 每秒钟想要发生中断的次数, 当然也不能太低或者太高, 因为要在计数器寄存器(16)位存放 +#define OSCILLATOR 1193182 // 每秒钟时钟震荡次数 +#define CLOCK_COUNTER (OSCILLATOR / HITS) // 如果想每秒钟 发生 HITS 次中断, 需要给计数器设置为 总震荡次数/我们想要发生的次数 得到每次发生中断需要计算的计数器 +#define HIT_GAP (1000 / HITS) // 1秒有1000ms, 算出来每次 中断的间隔时间, 也就是 每个时间片 大概10ms + + +void clock_init(); + +#endif \ No newline at end of file diff --git a/src/include/onix/interrupt.h b/src/include/onix/interrupt.h index 0d89c12..82e5126 100644 --- a/src/include/onix/interrupt.h +++ b/src/include/onix/interrupt.h @@ -17,6 +17,24 @@ #define PIC_S_DATA 0xa1 // 从片的数据端口 #define PIC_EOI 0x20 // 通知中断控制器中断结束 +#define IRQ_CLOCK 0 // 时钟 +#define IRQ_KEYBOARD 1 // 键盘 +#define IRQ_CASCADE 2 // 8259 从片控制器 +#define IRQ_SERIAL_2 3 // 串口 2 +#define IRQ_SERIAL_1 4 // 串口 1 +#define IRQ_PARALLEL_2 5 // 并口 2 +#define IRQ_FLOPPY 6 // 软盘控制器 +#define IRQ_PARALLEL_1 7 // 并口 1 +#define IRQ_RTC 8 // 实时时钟 +#define IRQ_REDIRECT 9 // 重定向 IRQ2 +#define IRQ_MOUSE 12 // 鼠标 +#define IRQ_MATH 13 // 协处理器 x87 +#define IRQ_HARDDISK 14 // ATA 硬盘第一通道 +#define IRQ_HARDDISK2 15 // ATA 硬盘第二通道 + +#define IRQ_MASTER_NR 0x20 // 主片起始向量号 +#define IRQ_SLAVE_NR 0x28 // 从片起始向量号 + typedef struct gate_t{ u16 offset0; // 段内偏移 0 ~ 15 位 @@ -33,6 +51,13 @@ typedef struct gate_t{ // 初始化保护模式的中断向量表 void interrupt_init(); +// 通知中断控制器,中断处理结束 +void send_eoi(u8 handle_num); + +// 设置中断处理函数 +void set_interrupt_handler(u8 irq, usize handler); // 修改handler_table设置的默认处理函数为我们自己定义的 +void set_interrupt_mask(u8 irq, bool enable); // 设置某个外中断是否打开 + static char *messages[] = { "#DE Divide Error\0", diff --git a/src/include/onix/onix.h b/src/include/onix/onix.h index cab035e..312819f 100644 --- a/src/include/onix/onix.h +++ b/src/include/onix/onix.h @@ -11,6 +11,7 @@ #include > #include > #include > +#include > void kernel_init(); diff --git a/src/kernel/clock.c b/src/kernel/clock.c new file mode 100644 index 0000000..e90e2b3 --- /dev/null +++ b/src/kernel/clock.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + + + +usize counter = 0; +// 时钟中断的处理函数, 等下就替换掉默认的外中断处理函数 +void clock_handler(u8 handle_num){ + assert(handle_num == 0x20); // 只允许时钟中断调用这个 + send_eoi(handle_num); // 通知中断控制器, cpu正在处理这个中断了 + counter += 1; + DEBUGK("clock handler %d", counter); +} + +void pit_init(){ + // 配置计数器 0 时钟 + out_8(PIT_CTRL_REG, 0b00110100); // 第0号计数器, 计数器先读写低字节, 再读写高字节, 模式2, 使用二进制编码的计数器 + out_8(PIT_CHAN0_REG, CLOCK_COUNTER & 0xff); // 先设置低字节 + out_8(PIT_CHAN0_REG, (CLOCK_COUNTER >> 8) & 0xff); // 再设置高字节 +} + +void clock_init(){ + pit_init(); + // 设置中断处理函数 + set_interrupt_handler(IRQ_CLOCK, clock_handler); + // 打开中断 + set_interrupt_mask(IRQ_CLOCK, true); +} + diff --git a/src/kernel/interrupt.c b/src/kernel/interrupt.c index 0da9681..06cfae9 100644 --- a/src/kernel/interrupt.c +++ b/src/kernel/interrupt.c @@ -13,9 +13,6 @@ u8* handler_table[IDT_SIZE]; // 为了让我们从c语言加载 idt表, 中断时 会先进入这个指针所在函数内, 然后继续跳入到 handler_table中 extern handler_entry_table[ENTRY_SIZE]; -// 导入调度函数 -extern void schdule(); - // 异常 中断处理函数默认函数 void exception_handle(u8 handle_num, u32 edi, u32 esi, u32 ebp, u32 esp, @@ -57,11 +54,36 @@ void send_eoi(u8 handle_num) } } + // 外中断 中断处理函数默认函数 void default_handler(u8 handle_num){ send_eoi(handle_num); - // 外中断发生就立即调度 - schdule(); + DEBUGK("[0x%x] default interrupt called...\n", handle_num); +} + + +// 修改handler_table设置的默认处理函数为我们自己定义的 +// 主要针对外中断 +void set_interrupt_handler(u8 irq, usize handler) { + assert(irq >= 0 && irq < 16); // 中断处理函数需要大于0, 且小于16, 因为外中断就是只有16个, 0x20到0x2f + handler_table[IRQ_MASTER_NR + irq] = handler; +} + +// 设置某个外中断的状态是否打开和关闭 +void set_interrupt_mask(u8 irq, bool enable){ + assert(irq >= 0 && irq < 16); + u16 port; + if (irq < 8) { // 说明是一个主片 + port = PIC_M_DATA; + } else { // 从片 + port = PIC_S_DATA; + irq -= 8; + } + if (enable){ + out_8(port, in_8(port) & ~(1 << irq)); + } else { + out_8(port, in_8(port) & (1 << irq)); + } } @@ -109,7 +131,7 @@ void pic_init(){ out_8(PIC_S_DATA, 2); // ICW3: 设置从片连接到主片的 IR2 引脚 out_8(PIC_S_DATA, 0b00000001); // ICW4: 8086模式, 正常EOI - out_8(PIC_M_DATA, 0b11111110); // 只打开主片的第0个中断也就是 的主片的0x20时钟中断 + out_8(PIC_M_DATA, 0b11111111); // 关闭所有主片pic中断 out_8(PIC_S_DATA, 0b11111111); // 关闭从片所有pic中断 } diff --git a/src/kernel/main.c b/src/kernel/main.c index 3609b98..bff2e7b 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -1,4 +1,3 @@ - #include @@ -14,14 +13,13 @@ void kernel_init(){ // 初始化中断 interrupt_init(); - // int cnt = 0; - // while (true){ - // cnt += 1; - // printk("%d", 123); - // } - // 初始化任务 - task_init(); + // task_init(); + + clock_init(); + + asm volatile("sti\n"); + hang(); } diff --git a/src/kernel/printk.c b/src/kernel/printk.c index fbbd3de..e63612d 100644 --- a/src/kernel/printk.c +++ b/src/kernel/printk.c @@ -15,8 +15,8 @@ u32 printk(const u8 *fmt, ...){ i = vsprintf(buf, fmt, args); va_end(args); - asm volatile("cli\n"); + // asm volatile("cli\n"); console_write(buf, i); - asm volatile("sti\n"); + // asm volatile("sti\n"); return i; } \ No newline at end of file