因为闹钟中断无法开启, 未知bug, 所以用周期中断实现了一个伪闹钟中断

master
阳光少年 1 year ago
parent 422fd35aac
commit 976d3a4017

@ -26,6 +26,7 @@
"cassert": "c",
"*.inc": "c",
"clock.h": "c",
"time.h": "c"
"time.h": "c",
"rtc.h": "c"
}
}

@ -41,7 +41,7 @@ debugger_log: -
magic_break: enabled=1
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
clock: sync=realtime, time0=local, rtc_sync=1
# no cmosimage
log: -
logprefix: %t%e%d

@ -36,7 +36,7 @@ print_timestamps: enabled=0
gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
clock: sync=realtime, time0=local, rtc_sync=1
# no cmosimage
log: -
logprefix: %t%e%d

@ -54,6 +54,7 @@ $(BUILD_PATH)/kernel.bin:$(BUILD_PATH)/kernel/start.o \
$(BUILD_PATH)/lib/stdlib.o\
$(BUILD_PATH)/kernel/clock.o\
$(BUILD_PATH)/kernel/time.o\
$(BUILD_PATH)/kernel/rtc.o\
$(shell mkdir -p $(dir $@))
ld -m elf_i386 -static $^ -o $@ -Ttext $(KERNEL_ENTRY_POINT)

@ -9,7 +9,7 @@
#define IDT_SIZE 256
#define ENTRY_SIZE 0x30 // 我们实现的中断数量
#define LOGK(fmt, args...) DEBUGK(fmt, ##args)
// #define LOGK(fmt, args...) DEBUGK(fmt, ##args)
#define PIC_M_CTRL 0x20 // 主片的控制端口
#define PIC_M_DATA 0x21 // 主片的数据端口

@ -13,6 +13,7 @@
#include <onix/stdlib.h>>
#include <onix/clock.h>>
#include <onix/time.h>>
#include <onix/rtc.h>>
void kernel_init();

@ -2,11 +2,39 @@
#define ONIX_RTC_H
#include <onix/types.h>
#include <onix/debug.h>
#include <onix/assert.h>
#include <onix/time.h>
#include <onix/interrupt.h>
#include <onix/printk.h>
#define CMOS_ADDR 0x70 // CMOS 地址寄存器
#define CMOS_DATA 0x71 // CMOS 数据寄存器
// 下面是 CMOS 信息的寄存器索引
#define CMOS_SECOND 0x00 // (0 ~ 59)
#define CMOS_MINUTE 0x02 // (0 ~ 59)
#define CMOS_HOUR 0x04 // (0 ~ 23)
#define CMOS_WEEKDAY 0x06 // (1 ~ 7) 星期天 = 1星期六 = 7
#define CMOS_DAY 0x07 // (1 ~ 31)
#define CMOS_MONTH 0x08 // (1 ~ 12)
#define CMOS_YEAR 0x09 // (0 ~ 99)
#define CMOS_CENTURY 0x32 // 可能不存在
#define CMOS_NMI 0x80
#define CMOS_A 0x0a
#define CMOS_B 0x0b
#define CMOS_C 0x0c
#define CMOS_D 0x0d
u8 cmos_read(u8 addr);
void cmos_write(u8 addr, u8 value);
void rtc_init();
#endif

@ -2,20 +2,10 @@
#define ONIX_TIME_H
#include <onix/types.h>
#include <onix/debug.h>
#include <onix/rtc.h>
#define CMOS_ADDR 0x70 // CMOS 地址寄存器
#define CMOS_DATA 0x71 // CMOS 数据寄存器
// 下面是 CMOS 信息的寄存器索引
#define CMOS_SECOND 0x00 // (0 ~ 59)
#define CMOS_MINUTE 0x02 // (0 ~ 59)
#define CMOS_HOUR 0x04 // (0 ~ 23)
#define CMOS_WEEKDAY 0x06 // (1 ~ 7) 星期天 = 1星期六 = 7
#define CMOS_DAY 0x07 // (1 ~ 31)
#define CMOS_MONTH 0x08 // (1 ~ 12)
#define CMOS_YEAR 0x09 // (0 ~ 99)
#define CMOS_CENTURY 0x32 // 可能不存在
#define CMOS_NMI 0x80
#define MINUTE 60 // 每分钟的秒数
#define HOUR (60 * MINUTE) // 每小时的秒数

@ -22,6 +22,9 @@ void kernel_init(){
// 初始化时间
// time_init();
// 闹钟中断
rtc_init();
asm volatile("sti\n");
hang();

@ -0,0 +1,97 @@
#include <onix/rtc.h>
// 从cmos芯片中读取到时间
u8 cmos_read(u8 addr){
out_8(CMOS_ADDR, CMOS_NMI | addr);
return in_8(CMOS_DATA);
}
// 写 cmos 寄存器的值
void cmos_write(u8 addr, u8 value)
{
out_8(CMOS_ADDR, CMOS_NMI | addr);
out_8(CMOS_DATA, value);
}
int counter = 0;
static u32 next_time = 0xffffffff;
// 实时时钟中断处理函数
void rtc_handler(int handle_num)
{
// 实时时钟中断向量号
assert(handle_num == 0x28);
// 向中断控制器发送中断处理完成的信号
send_eoi(handle_num);
// 读 CMOS 寄存器 C允许 CMOS 继续产生中断
cmos_read(CMOS_C);
tm time;
time_read(&time);
u32 now_time = mktime(&time);
if (next_time <= mktime(&time)) {
DEBUGK("rtc handler %d... %d %d \n", counter++, now_time, next_time);
next_time = 0xffffffff;
set_alarm(1);
}
}
// 设置 secs 秒后发生实时时钟中断
void set_alarm(u32 secs)
{
tm time;
time_read(&time);
u8 sec = secs % 60;
secs /= 60;
u8 min = secs % 60;
secs /= 60;
u32 hour = secs;
time.tm_sec += sec;
if (time.tm_sec >= 60)
{
time.tm_sec %= 60;
time.tm_min += 1;
}
time.tm_min += min;
if (time.tm_min >= 60)
{
time.tm_min %= 60;
time.tm_hour += 1;
}
time.tm_hour += hour;
if (time.tm_hour >= 24)
{
time.tm_hour %= 24;
}
next_time = mktime(&time);
}
void rtc_init()
{
cmos_write(CMOS_B, 0b01000010); // 打开周期中断
// cmos_write(CMOS_B, 0b00100010); // 打开闹钟中断
cmos_read(CMOS_C); // 读 C 寄存器,以允许 CMOS 中断
// 设置中断频率
out_8(CMOS_A, (in_8(CMOS_A) & 0xf) | 0b1110);
set_alarm(3);
// 设置自定义中断处理函数
set_interrupt_handler(IRQ_RTC, rtc_handler);
// 打开从片上的实时时钟中断控制器
set_interrupt_mask(IRQ_RTC, true);
// 从片和主片和这个接口相连接
set_interrupt_mask(IRQ_CASCADE, true);
}

@ -31,5 +31,5 @@ task_switch:
pop ebx
pop ebp
; 此时 栈顶是 call task_switch 的下一行代码的位置, ret即可
; 此时 栈顶是 call task_switch 的下一行代码的位置(如果是第一次调用则是函数指针的位置), ret即可
ret

@ -136,12 +136,6 @@ u32 get_yday(tm *time)
return res;
}
// 从cmos芯片中读取到时间
u8 cmos_read(u8 addr)
{
out_8(CMOS_ADDR, CMOS_NMI | addr);
return in_8(CMOS_DATA);
};
void time_read_bcd(tm *time)
{
@ -192,6 +186,6 @@ void time_init()
// 计算得到时间戳
startup_time = mktime(&time);
DEBUGK("时间戳 time: %d", startup_time);
DEBUGK("now time: %d", startup_time);
}
Loading…
Cancel
Save