Initial import of ViperOS
This commit is contained in:
4
VKernel/Kernel/platform/pch/__init__.py
Normal file
4
VKernel/Kernel/platform/pch/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from . import pic
|
||||
from . import pit
|
||||
from . import timer
|
||||
from . import rtc
|
||||
120
VKernel/Kernel/platform/pch/pic.py
Normal file
120
VKernel/Kernel/platform/pch/pic.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
|
||||
# PIC端口定义
|
||||
PIC1_COMMAND: t.CDefine = 0x20
|
||||
PIC1_DATA: t.CDefine = 0x21
|
||||
PIC2_COMMAND: t.CDefine = 0xA0
|
||||
PIC2_DATA: t.CDefine = 0xA1
|
||||
|
||||
# ICW1 - 初始化命令字1
|
||||
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
|
||||
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
|
||||
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
|
||||
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
|
||||
ICW1_INIT: t.CDefine = 0x10 # 初始化
|
||||
|
||||
# ICW4 - 初始化命令字4
|
||||
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
|
||||
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
|
||||
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
|
||||
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
|
||||
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
|
||||
|
||||
# OCW2 - 操作命令字2
|
||||
OCW2_EOI: t.CDefine = 0x20 # 结束中断
|
||||
|
||||
# OCW3 - 操作命令字3
|
||||
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
|
||||
|
||||
# 初始化PIC
|
||||
def init():
|
||||
# 发送ICW1:开始初始化,需要ICW4
|
||||
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW2:中断向量偏移
|
||||
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW3:级联信息
|
||||
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW4:8086模式
|
||||
asm.outb(PIC1_DATA, ICW4_8086)
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, ICW4_8086)
|
||||
asm.io_wait()
|
||||
|
||||
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
|
||||
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
|
||||
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
|
||||
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
|
||||
asm.io_wait()
|
||||
|
||||
# 发送EOI信号
|
||||
def eoi(irq: t.CUInt8T):
|
||||
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
|
||||
asm.outb(PIC1_COMMAND, OCW2_EOI)
|
||||
|
||||
|
||||
# 检查是否是虚假中断(spurious interrupt)
|
||||
# 返回 1 表示是虚假中断,0 表示是真实中断
|
||||
def isSpurious(irq: t.CInt) -> t.CInt:
|
||||
# 边界检查
|
||||
if irq < 0 or irq > 15: return 0
|
||||
isr: t.CUInt8T
|
||||
if irq < 8:
|
||||
# 发送OCW3,读取ISR(Interrupt Service Register)
|
||||
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
|
||||
asm.io_wait()
|
||||
isr = asm.inb(PIC1_COMMAND)
|
||||
# 如果ISR中对应位为0,说明是虚假中断
|
||||
return not (isr & (1 << irq))
|
||||
else:
|
||||
# 发送OCW3,读取从PIC的ISR
|
||||
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
|
||||
asm.io_wait()
|
||||
isr = asm.inb(PIC2_COMMAND)
|
||||
# 如果ISR中对应位为0,说明是虚假中断
|
||||
return not (isr & (1 << (irq - 8)))
|
||||
|
||||
# 设置IRQ屏蔽
|
||||
def setMask(irq: t.CUInt8T):
|
||||
# 边界检查
|
||||
if irq > 15: return
|
||||
port: t.CUInt16T
|
||||
value: t.CUInt8T
|
||||
if irq < 8:
|
||||
port = PIC1_DATA
|
||||
else:
|
||||
port = PIC2_DATA
|
||||
irq -= 8
|
||||
value = asm.inb(port) | (1 << irq)
|
||||
asm.outb(port, value)
|
||||
asm.io_wait() # 确保命令生效
|
||||
|
||||
# 清除IRQ屏蔽
|
||||
def clearMask(irq: t.CUInt8T):
|
||||
# 边界检查
|
||||
if irq > 15: return
|
||||
port: t.CUInt16T
|
||||
value: t.CUInt8T
|
||||
if irq < 8:
|
||||
port = PIC1_DATA
|
||||
else:
|
||||
port = PIC2_DATA
|
||||
irq -= 8
|
||||
value = asm.inb(port) & ~(1 << irq)
|
||||
asm.outb(port, value)
|
||||
asm.io_wait() # 确保命令生效
|
||||
26
VKernel/Kernel/platform/pch/pit.py
Normal file
26
VKernel/Kernel/platform/pch/pit.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
PIT_CHANNEL0: t.CDefine = 0x40
|
||||
PIT_CHANNEL1: t.CDefine = 0x41
|
||||
PIT_CHANNEL2: t.CDefine = 0x42
|
||||
PIT_COMMAND: t.CDefine = 0x43
|
||||
|
||||
def pit_init(frequency: t.CInt):
|
||||
# 参数验证:确保频率为正数
|
||||
if frequency <= 0: return
|
||||
|
||||
# 计算除数,使用16位无符号整数
|
||||
divisor: t.CUInt32T = 1193180 / frequency
|
||||
|
||||
# 发送命令字:通道0,先低后高,模式3(方波),二进制计数
|
||||
asm.outb(PIT_COMMAND, 0x36)
|
||||
asm.io_wait()
|
||||
|
||||
# 写入低字节
|
||||
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
|
||||
asm.io_wait()
|
||||
|
||||
# 写入高字节
|
||||
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
|
||||
asm.io_wait()
|
||||
97
VKernel/Kernel/platform/pch/rtc.py
Normal file
97
VKernel/Kernel/platform/pch/rtc.py
Normal file
@@ -0,0 +1,97 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
|
||||
RTC_CMOS_ADDR: t.CUInt16T = 0x70
|
||||
RTC_CMOS_DATA: t.CUInt16T = 0x71
|
||||
|
||||
RTC_REG_SECONDS: t.CDefine = 0x00
|
||||
RTC_REG_MINUTES: t.CDefine = 0x02
|
||||
RTC_REG_HOURS: t.CDefine = 0x04
|
||||
RTC_REG_DAY: t.CDefine = 0x07
|
||||
RTC_REG_MONTH: t.CDefine = 0x08
|
||||
RTC_REG_YEAR: t.CDefine = 0x09
|
||||
RTC_REG_STATUS_A: t.CDefine = 0x0A
|
||||
RTC_REG_STATUS_B: t.CDefine = 0x0B
|
||||
|
||||
RTC_TZ_OFFSET: t.CDefine = 8
|
||||
|
||||
rtc_seconds: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_minutes: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_hours: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_day: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_month: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_year: t.CStatic | t.CVolatile | t.CUInt16T = 0
|
||||
|
||||
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
|
||||
asm.outb(RTC_CMOS_ADDR, reg)
|
||||
return asm.inb(RTC_CMOS_DATA)
|
||||
|
||||
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
|
||||
return (bcd >> 4) * 10 + (bcd & 0x0F)
|
||||
|
||||
def rtc_read_time():
|
||||
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
|
||||
sec: t.CUInt8T = cmos_read(RTC_REG_SECONDS)
|
||||
min_: t.CUInt8T = cmos_read(RTC_REG_MINUTES)
|
||||
hour: t.CUInt8T = cmos_read(RTC_REG_HOURS)
|
||||
day: t.CUInt8T = cmos_read(RTC_REG_DAY)
|
||||
mon: t.CUInt8T = cmos_read(RTC_REG_MONTH)
|
||||
year: t.CUInt8T = cmos_read(RTC_REG_YEAR)
|
||||
reg_b: t.CUInt8T = cmos_read(RTC_REG_STATUS_B)
|
||||
if not (reg_b & 0x04):
|
||||
sec = bcd_to_bin(sec)
|
||||
min_ = bcd_to_bin(min_)
|
||||
hour = bcd_to_bin(hour)
|
||||
day = bcd_to_bin(day)
|
||||
mon = bcd_to_bin(mon)
|
||||
year = bcd_to_bin(year)
|
||||
if not (reg_b & 0x02) and (hour & 0x80):
|
||||
hour = ((hour & 0x7F) + 12) % 24
|
||||
hour = hour + RTC_TZ_OFFSET
|
||||
if hour >= 24:
|
||||
hour = hour - 24
|
||||
day = day + 1
|
||||
max_day: t.CUInt8T = 31
|
||||
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
|
||||
max_day = 30
|
||||
elif mon == 2:
|
||||
max_day = 28
|
||||
y4: t.CUInt16T = t.CUInt16T(year) + 2000
|
||||
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
|
||||
max_day = 29
|
||||
if day > max_day:
|
||||
day = 1
|
||||
mon = mon + 1
|
||||
if mon > 12:
|
||||
mon = 1
|
||||
year = year + 1
|
||||
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
|
||||
rtc_seconds = sec
|
||||
rtc_minutes = min_
|
||||
rtc_hours = hour
|
||||
rtc_day = day
|
||||
rtc_month = mon
|
||||
rtc_year = t.CUInt16T(year) + 2000
|
||||
|
||||
def rtc_init():
|
||||
rtc_read_time()
|
||||
|
||||
def rtc_get_hours() -> t.CUInt8T:
|
||||
return rtc_hours
|
||||
|
||||
def rtc_get_minutes() -> t.CUInt8T:
|
||||
return rtc_minutes
|
||||
|
||||
def rtc_get_seconds() -> t.CUInt8T:
|
||||
return rtc_seconds
|
||||
|
||||
def rtc_get_day() -> t.CUInt8T:
|
||||
return rtc_day
|
||||
|
||||
def rtc_get_month() -> t.CUInt8T:
|
||||
return rtc_month
|
||||
|
||||
def rtc_get_year() -> t.CUInt16T:
|
||||
return rtc_year
|
||||
102
VKernel/Kernel/platform/pch/timer.py
Normal file
102
VKernel/Kernel/platform/pch/timer.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import platform.pch.pic as pic
|
||||
import platform.pch.pit as pit
|
||||
import sched.sched as sched
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
TIMER_FREQUENCY: t.CDefine = 1000
|
||||
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
|
||||
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
|
||||
|
||||
ticks: t.CStatic | t.CVolatile | t.CUInt64T = 0
|
||||
seconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
|
||||
milliseconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
|
||||
timer_running: t.CStatic | t.CVolatile | bool = False
|
||||
|
||||
def timer_init():
|
||||
global ticks, seconds, milliseconds, timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = 0
|
||||
seconds = 0
|
||||
milliseconds = 0
|
||||
timer_running = True
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
pit.pit_init(TIMER_FREQUENCY)
|
||||
|
||||
def timer_handler():
|
||||
global ticks, seconds, milliseconds, timer_running
|
||||
if not timer_running:
|
||||
pic.eoi(0)
|
||||
return
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = ticks + 1
|
||||
milliseconds = milliseconds + MILLISECONDS_PER_TICK
|
||||
if milliseconds >= 1000:
|
||||
seconds = seconds + 1
|
||||
milliseconds = milliseconds - 1000
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
sched.Scheduler.sched_tick()
|
||||
pic.eoi(0)
|
||||
|
||||
def timer_start():
|
||||
global timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
timer_running = True
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_stop():
|
||||
global timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
timer_running = False
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_reset():
|
||||
global ticks, seconds, milliseconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = 0
|
||||
seconds = 0
|
||||
milliseconds = 0
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_get_ticks() -> t.CUInt64T:
|
||||
current_ticks: t.CUInt64T
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_ticks = ticks
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_ticks
|
||||
|
||||
def timer_get_seconds() -> t.CUInt32T:
|
||||
current_seconds: t.CUInt32T
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_seconds = seconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_seconds
|
||||
|
||||
def timer_get_milliseconds() -> t.CUInt32T:
|
||||
current_milliseconds: t.CUInt32T
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_milliseconds = milliseconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_milliseconds
|
||||
|
||||
def timer_get_time(out_seconds: t.CUInt32T | t.CPtr, out_milliseconds: t.CUInt32T | t.CPtr):
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
if out_seconds:
|
||||
c.Set(c.Deref(out_seconds), seconds)
|
||||
if out_milliseconds:
|
||||
c.Set(c.Deref(out_milliseconds), milliseconds)
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_msleep(ms: t.CUInt32T):
|
||||
target: t.CUInt64T = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
|
||||
while ticks < target:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
sched.Scheduler._yield()
|
||||
|
||||
def timer_sleep(sec: t.CUInt32T):
|
||||
target: t.CUInt64T = ticks + sec * TICKS_PER_SECOND
|
||||
while ticks < target:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
sched.Scheduler._yield()
|
||||
Reference in New Issue
Block a user