| git.druid.rocks | index | druid520 | kaboom | src/ | kernel/ | idt.nsc |
src/kernel/idt.nsc
/*
* idt: 32 cpu exception vectors, 16 remapped pic irq vectors (masked
* for now -- no device driver hooks them up yet), one syscall gate at
* 0x80. every vector's dispatch funnels through isr_dispatch below,
* called by the single shared trampoline in idt_asm.s.
*
* same packing constraint as gdt.nsc: an idt entry can't be a nsc
* struct (fields are word-addressed, not byte-packed), so each 16-byte
* entry is built as two hand-packed u64 words.
*/
include "klog.nsh";
include "../fs/kfs.nsh";
include "exec.nsh";
include "alloc.nsh";
global struct arena heap_colosseum;
void outb(u16 port, u8 val);
u8 inb(u16 port);
void load_idt(ptr idtr_addr);
void serial_puts(ptr str);
void vga_puts(ptr str);
global i8 idt_table[4096]; /* 256 entries * 16 bytes */
global i8 idtr[10];
void
idt_set_entry(i32 idx, ptr handler, u16 selector, u8 type_attr)
{
ptr lo_slot;
ptr hi_slot;
u64 addr;
u64 lo;
u64 hi;
addr = (u64)handler;
lo = addr & (u64)0xffff;
lo = lo | ((u64)selector << (u64)16);
lo = lo | ((u64)type_attr << (u64)40);
lo = lo | (((addr >> (u64)16) & (u64)0xffff) << (u64)48);
hi = addr >> (u64)32; /* right shift on a u64 already zero-fills the top bits */
lo_slot = &idt_table[0] + idx * 16;
hi_slot = lo_slot + 8;
*lo_slot = (i64)lo;
*hi_slot = (i64)hi;
}
/* one extern per address-getter, generated in idt_asm.s (see the
* comment there for why this has to work through a getter function
* instead of nsc just taking each stub's address directly). */
ptr get_isr0_addr(void);
ptr get_isr1_addr(void);
ptr get_isr2_addr(void);
ptr get_isr3_addr(void);
ptr get_isr4_addr(void);
ptr get_isr5_addr(void);
ptr get_isr6_addr(void);
ptr get_isr7_addr(void);
ptr get_isr8_addr(void);
ptr get_isr9_addr(void);
ptr get_isr10_addr(void);
ptr get_isr11_addr(void);
ptr get_isr12_addr(void);
ptr get_isr13_addr(void);
ptr get_isr14_addr(void);
ptr get_isr15_addr(void);
ptr get_isr16_addr(void);
ptr get_isr17_addr(void);
ptr get_isr18_addr(void);
ptr get_isr19_addr(void);
ptr get_isr20_addr(void);
ptr get_isr21_addr(void);
ptr get_isr22_addr(void);
ptr get_isr23_addr(void);
ptr get_isr24_addr(void);
ptr get_isr25_addr(void);
ptr get_isr26_addr(void);
ptr get_isr27_addr(void);
ptr get_isr28_addr(void);
ptr get_isr29_addr(void);
ptr get_isr30_addr(void);
ptr get_isr31_addr(void);
ptr get_isr32_addr(void);
ptr get_isr33_addr(void);
ptr get_isr34_addr(void);
ptr get_isr35_addr(void);
ptr get_isr36_addr(void);
ptr get_isr37_addr(void);
ptr get_isr38_addr(void);
ptr get_isr39_addr(void);
ptr get_isr40_addr(void);
ptr get_isr41_addr(void);
ptr get_isr42_addr(void);
ptr get_isr43_addr(void);
ptr get_isr44_addr(void);
ptr get_isr45_addr(void);
ptr get_isr46_addr(void);
ptr get_isr47_addr(void);
ptr get_isr128_addr(void);
void
idt_install(void)
{
idt_set_entry(0, get_isr0_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(1, get_isr1_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(2, get_isr2_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(3, get_isr3_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(4, get_isr4_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(5, get_isr5_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(6, get_isr6_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(7, get_isr7_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(8, get_isr8_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(9, get_isr9_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(10, get_isr10_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(11, get_isr11_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(12, get_isr12_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(13, get_isr13_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(14, get_isr14_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(15, get_isr15_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(16, get_isr16_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(17, get_isr17_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(18, get_isr18_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(19, get_isr19_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(20, get_isr20_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(21, get_isr21_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(22, get_isr22_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(23, get_isr23_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(24, get_isr24_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(25, get_isr25_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(26, get_isr26_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(27, get_isr27_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(28, get_isr28_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(29, get_isr29_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(30, get_isr30_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(31, get_isr31_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(32, get_isr32_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(33, get_isr33_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(34, get_isr34_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(35, get_isr35_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(36, get_isr36_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(37, get_isr37_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(38, get_isr38_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(39, get_isr39_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(40, get_isr40_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(41, get_isr41_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(42, get_isr42_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(43, get_isr43_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(44, get_isr44_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(45, get_isr45_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(46, get_isr46_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(47, get_isr47_addr(), (u16)0x08, (u8)0x8e);
idt_set_entry(128, get_isr128_addr(), (u16)0x08, (u8)0xee); /* syscall gate: dpl=3 so user mode can int $0x80 later */
}
void io_wait(void);
void halt(void);
void kbd_handle_irq(void);
void serial_handle_irq(void);
void
pic_remap(void)
{
outb((u16)0x20, (u8)0x11);
io_wait();
outb((u16)0xa0, (u8)0x11);
io_wait();
outb((u16)0x21, (u8)0x20); /* master irq0-7 -> vectors 32-39 */
io_wait();
outb((u16)0xa1, (u8)0x28); /* slave irq8-15 -> vectors 40-47 */
io_wait();
outb((u16)0x21, (u8)0x04);
io_wait();
outb((u16)0xa1, (u8)0x02);
io_wait();
outb((u16)0x21, (u8)0x01);
io_wait();
outb((u16)0xa1, (u8)0x01);
io_wait();
/* mask every irq except irq1 (keyboard) and irq4 (com1, bits 1
* and 4 of the master mask): 0xff with both cleared = 0xed. com1
* unmasked so a byte arriving over serial -- the ONLY input path
* that exists at all under -nographic, where there's no separate
* ps/2-backed keyboard focus -- actually wakes up a halted cpu
* (see serial.nsc's own note on why this was missing entirely
* until someone tried typing into a real -nographic session).
* remapping matters even for the still-masked ones -- it's what
* keeps a spurious/late irq from ever landing on a cpu exception
* vector by accident. */
outb((u16)0x21, (u8)0xed);
outb((u16)0xa1, (u8)0xff);
}
void
pic_send_eoi(u64 vector)
{
if(vector >= (u64)40)
{
outb((u16)0xa0, (u8)0x20); /* slave-handled irq: eoi both */
}
outb((u16)0x20, (u8)0x20);
}
/* saved-register block layout, from isr_common_stub's push order
* (last pushed = lowest address = offset 0): r15,r14,r13,r12,r11,r10,
* r9,r8,rbp,rdi,rsi,rdx,rcx,rbx,rax. rax (first pushed, so highest
* offset among the 15) lands at 14*8=112; rdi (arg1 in sysv, our
* syscall convention's arg1 too) at 9*8=72. */
u64
regs_get_rax(ptr regs)
{
ptr slot;
slot = regs + 112;
return (u64)*slot;
}
void
regs_set_rax(ptr regs, u64 val)
{
ptr slot;
slot = regs + 112;
*slot = (i64)val;
}
u64
regs_get_rdi(ptr regs)
{
ptr slot;
slot = regs + 72;
return (u64)*slot;
}
u64
regs_get_rsi(ptr regs)
{
ptr slot;
slot = regs + 80;
return (u64)*slot;
}
u64
regs_get_rdx(ptr regs)
{
ptr slot;
slot = regs + 88;
return (u64)*slot;
}
u64
regs_get_r10(ptr regs)
{
ptr slot;
slot = regs + 40;
return (u64)*slot;
}
void
print_udec(u64 val)
{
i8 buf[21];
i32 i;
u64 v;
i = 20;
buf[20] = 0;
v = val;
if(v == (u64)0)
{
i = i - 1;
buf[i] = (i8)48;
}
while(v > (u64)0)
{
i = i - 1;
buf[i] = (i8)(48 + (i32)(v % (u64)10));
v = v / (u64)10;
}
serial_puts(&buf[i]);
vga_puts(&buf[i]);
}
/* same digit-extraction as print_udec, but into the kernel log
* instead of the live console -- sys_doerror's own pid number. kept
* as its own tiny copy rather than reusing print_udec directly: this
* one specifically must NOT also write to serial/vga (an error log
* line isn't the same thing as a boot/panic message the user is
* meant to see immediately on the console). */
void
klog_write_udec(u64 val)
{
i8 buf[21];
i32 i;
u64 v;
i = 20;
buf[20] = 0;
v = val;
if(v == (u64)0)
{
i = i - 1;
buf[i] = (i8)48;
}
while(v > (u64)0)
{
i = i - 1;
buf[i] = (i8)(48 + (i32)(v % (u64)10));
v = v / (u64)10;
}
klog_write(&buf[i]);
}
/* the shared error path every permission-checked syscall branch below
* calls instead of hand-rolling its own "log it, then set rax"
* boilerplate. is_error is the CALLER's own already-correct "did this
* fail" test -- the failure convention genuinely differs per syscall
* (some return a negative value, some a plain 0/1 boolean, see the
* syscall table's own comment), so this never tries to guess it from
* result alone. op_name is a short label for the log line.
*
* logs "pid <N>: <op_name>: permission denied" specifically when
* kaboom_errno says that's really why (kfs_check_perm, kfs.nsc, is
* the one place that ever sets it -- see its own comment), or a
* plainer "<op_name>: failed" otherwise (not found, already exists,
* a directory that isn't empty, ...) -- then always sets rax to
* result, exactly like every syscall branch already did by hand. */
void
sys_doerror(ptr regs, i64 result, i32 is_error, ptr op_name)
{
if(is_error == 1)
{
klog_write("pid ");
klog_write_udec(kaboom_current_pid());
klog_write(": ");
klog_write(op_name);
if(kaboom_errno == (i32)1)
{
klog_write(": permission denied\n");
}
else
{
klog_write(": failed\n");
}
}
regs_set_rax(regs, (u64)result);
}
i64 fd_read(i32 fd, ptr buf, u64 maxlen);
i64 fd_write(i32 fd, ptr buf, u64 len);
i32 fd_open(ptr path, u64 path_len);
i32 fd_close(i32 fd);
i64 fd_fsize(i32 fd);
u64 klog_read(ptr buf, u64 maxlen);
void vga_clear(void);
void serial_clear(void);
void rtc_read_datetime(ptr buf);
/* syscall table: number in rax (also where the return value goes),
* args in rdi/rsi/rdx -- same register order/positions as the real
* x86-64 sysv/syscall convention, kept for familiarity even though
* the actual entry mechanism here is the classic int-gate, not the
* syscall instruction.
*
* every syscall below that can genuinely fail routes its result
* through sys_doerror (this file, right above syscall_dispatch)
* instead of setting rax by hand -- the return VALUE and its meaning
* per syscall are unchanged (still exactly what's documented below),
* sys_doerror only adds a kernel-log line, "pid <N>: <name>:
* permission denied" or "<name>: failed", whenever the call actually
* failed. it distinguishes the two using kaboom_errno (kfs.nsc),
* which kfs_check_perm is the one and only place that ever sets --
* every other failure reason (not found, already exists, a directory
* that isn't empty, ...) logs as a plain "failed" instead. `klogs`
* shows these lines like any other kernel log entry.
* 1 = debug print a nul-terminated string (rdi) -- the original
* proof-of-mechanism syscall, kept for back-compat.
* 2 = write(fd, buf, len) -> bytes written, or -1
* 3 = read(fd, buf, maxlen) -> bytes read, or -1
* 4 = open(path, path_len) -> fd, or -1
* 5 = close(fd) -> 0, or -1
* 6 = listdir(names_out, max) -> count of entries written
* 7 = exec(path, path_len, argc, argv) -> the child's exit code
* (whatever it left in rax when it ret'd), or -1
* 8 = klog_read(buf, maxlen) -> bytes copied from the kernel log
* 9 = mkdir(name, name_len, perm) -> new inode number, or -1
* 10 = rmdir(name, name_len) -> 1, or 0
* 11 = rm(name, name_len) -> 1, or 0
* 12 = cd(name, name_len) -> 1, or 0
* 13 = pwd(buf) -> path length
* 14 = info(buf) -> fills buf (room for 4 u64s) with total_blocks,
* blocks_used, inode_count, inodes_used; always returns 0
* 15 = writefile(name, name_len, data, len) -> 1, or 0 -- finds or
* creates name in the current directory and overwrites its
* entire content; 4 args, same r10-for-the-4th-arg convention
* as exec (7)
* 16 = vga_clear() -> void, no args
* 17 = chmod(name, name_len, perm) -> 1, or 0
* 18 = alloc(size) -> ptr, or (ptr)0 if the heap arena is exhausted
* -- userspace's way to get memory dynamically instead of
* declaring a huge fixed-size global/stack buffer; wraps the
* same arena_alloc every kernel-side subsystem uses
* 19 = free(ptr) -> void, no args used beyond the pointer, always a
* no-op -- kaboom's arena allocator never frees (see
* alloc.nsc's own note); this exists as real api surface (so a
* program can call free without knowing that) not because it
* does anything yet
* 20 = stat(path, path_len) -> -1 not found, 1 a file, 2 a directory
* 21 = listdir_path(path, path_len, names_out, max) -> count, or -1
* if path doesn't resolve to a directory; 4 args, same
* r10-for-the-4th-arg convention as exec (7)
* 22 = date(buf) -> void, fills buf (room for 6 u64s) with second,
* minute, hour, day, month, year (full) from the cmos rtc
* 23 = errno(void) -> kaboom_errno (0 generic, 1 EPERM) as left by
* the most recent syscall THIS process made -- check it right
* after a failing call, before making another one
* 24 = getperm(path, path_len) -> the resolved inode's permission
* bitmask (r=1 w=2 x=4), or -1 if path doesn't resolve --
* chmod's read-back counterpart, for a `perms` command to show
* what's actually set
* 25 = fsize(fd) -> the open file's full content size in bytes, or
* -1 if fd isn't an open file -- lets a program size one buffer
* to the whole file before a single read, instead of assuming a
* fixed maximum
* 26 = ino(path, path_len) -> the inode number path resolves to, or
* -1 if it doesn't resolve -- file identity, so a program can
* tell two different path spellings of the same file apart
* from two different files (mv's same-file check)
* grows further once real coreutils show what else they need. */
void
syscall_dispatch(ptr regs)
{
u64 num;
u64 arg1;
u64 arg2;
u64 arg3;
i64 result;
num = regs_get_rax(regs);
if(num == (u64)1)
{
arg1 = regs_get_rdi(regs);
serial_puts((ptr)arg1);
vga_puts((ptr)arg1);
regs_set_rax(regs, (u64)0);
return;
}
if(num == (u64)2)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = fd_write((i32)arg1, (ptr)arg2, arg3);
sys_doerror(regs, result, (i32)(result < (i64)0), "write");
return;
}
if(num == (u64)3)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = fd_read((i32)arg1, (ptr)arg2, arg3);
sys_doerror(regs, result, (i32)(result < (i64)0), "read");
return;
}
if(num == (u64)4)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)fd_open((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result < (i64)0), "open");
return;
}
if(num == (u64)5)
{
arg1 = regs_get_rdi(regs);
result = (i64)fd_close((i32)arg1);
sys_doerror(regs, result, (i32)(result < (i64)0), "close");
return;
}
if(num == (u64)6)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)kfs_dir_list((ptr)arg1, (i32)arg2);
sys_doerror(regs, result, (i32)(result < (i64)0), "listdir");
return;
}
if(num == (u64)7)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = sys_exec((ptr)arg1, arg2, (i64)arg3, (ptr)regs_get_r10(regs));
/* -1 is ambiguous here (exec itself failing vs. the child's
* own legitimate exit code happening to BE -1) -- a
* pre-existing wart (sh.nsc already treats any -1 as "command
* not found" the same way), not something this makes worse. */
sys_doerror(regs, result, (i32)(result == (i64)(-1)), "exec");
return;
}
if(num == (u64)8)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)klog_read((ptr)arg1, arg2);
regs_set_rax(regs, (u64)result);
return;
}
if(num == (u64)9)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = (i64)kfs_mkdir((ptr)arg1, arg2, arg3);
sys_doerror(regs, result, (i32)(result < (i64)0), "mkdir");
return;
}
if(num == (u64)10)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)kfs_rmdir((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result == (i64)0), "rmdir");
return;
}
if(num == (u64)11)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)kfs_rm((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result == (i64)0), "rm");
return;
}
if(num == (u64)12)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)kfs_cd((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result == (i64)0), "cd");
return;
}
if(num == (u64)13)
{
arg1 = regs_get_rdi(regs);
result = (i64)kfs_pwd((ptr)arg1);
regs_set_rax(regs, (u64)result);
return;
}
if(num == (u64)14)
{
arg1 = regs_get_rdi(regs);
kfs_info((ptr)arg1);
regs_set_rax(regs, (u64)0);
return;
}
if(num == (u64)15)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = (i64)kfs_save((ptr)arg1, arg2, (ptr)arg3, regs_get_r10(regs));
sys_doerror(regs, result, (i32)(result == (i64)0), "writefile");
return;
}
if(num == (u64)16)
{
vga_clear();
serial_clear();
regs_set_rax(regs, (u64)0);
return;
}
if(num == (u64)17)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = (i64)kfs_chmod((ptr)arg1, arg2, arg3);
sys_doerror(regs, result, (i32)(result == (i64)0), "chmod");
return;
}
if(num == (u64)18)
{
arg1 = regs_get_rdi(regs);
regs_set_rax(regs, (u64)arena_alloc(&heap_colosseum, arg1));
return;
}
if(num == (u64)19)
{
regs_set_rax(regs, (u64)0);
return;
}
if(num == (u64)20)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = kfs_stat((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result == (i64)(-1)), "stat");
return;
}
if(num == (u64)21)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
arg3 = regs_get_rdx(regs);
result = (i64)kfs_dir_list_path((ptr)arg1, arg2, (ptr)arg3, (i32)regs_get_r10(regs));
sys_doerror(regs, result, (i32)(result < (i64)0), "listdir_path");
return;
}
if(num == (u64)22)
{
arg1 = regs_get_rdi(regs);
rtc_read_datetime((ptr)arg1);
regs_set_rax(regs, (u64)0);
return;
}
if(num == (u64)23)
{
/* the userspace half of kaboom_errno/sys_doerror: klogs
* already gets the real reason a syscall failed, but a
* command's OWN user-visible error message had no way to ask
* "was that permission denied, or something else" until now.
* no args -- reads whatever kaboom_errno was left at by the
* MOST RECENT syscall this same process made, so a caller
* needs to check it right after a failing call, before making
* another one. */
regs_set_rax(regs, (u64)kaboom_errno);
return;
}
if(num == (u64)24)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)kfs_getperm((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result < (i64)0), "getperm");
return;
}
if(num == (u64)25)
{
arg1 = regs_get_rdi(regs);
result = fd_fsize((i32)arg1);
sys_doerror(regs, result, (i32)(result < (i64)0), "fsize");
return;
}
if(num == (u64)26)
{
arg1 = regs_get_rdi(regs);
arg2 = regs_get_rsi(regs);
result = (i64)kfs_resolve((ptr)arg1, arg2);
sys_doerror(regs, result, (i32)(result < (i64)0), "ino");
return;
}
regs_set_rax(regs, ~(u64)0);
}
global void
isr_dispatch(u64 vector, u64 error_code, ptr regs)
{
if(vector == (u64)128)
{
syscall_dispatch(regs);
return;
}
if(vector < (u64)32)
{
klog_write("kaboom: PANIC: exception, see serial for vector/error code\n");
serial_puts("\nkaboom: PANIC: exception vector ");
print_udec(vector);
serial_puts(", error code ");
print_udec(error_code);
serial_puts("\n");
while(1)
{
halt();
}
}
/* remapped hardware irq (32-47). every one needs an eoi sent back
* to the pic regardless of whether anything actually handles it,
* or the pic stops delivering further interrupts entirely -- easy
* to lose track of since nothing breaks until the SECOND
* keypress, not the first. */
pic_send_eoi(vector);
if(vector == (u64)33)
{
kbd_handle_irq();
}
if(vector == (u64)36)
{
serial_handle_irq();
}
}
global void
idt_init(void)
{
i32 limit;
u64 addr;
i32 i;
idt_install();
pic_remap();
limit = 4095;
idtr[0] = (i8)(limit & 0xff);
idtr[1] = (i8)((limit >> 8) & 0xff);
addr = (u64)&idt_table[0];
i = 0;
while(i < 8)
{
idtr[2 + i] = (i8)((addr >> (u64)(i * 8)) & (u64)0xff);
i = i + 1;
}
load_idt(&idtr[0]);
}