import "io" manifest { iv_none = 0, iv_memory = 1, iv_pagefault = 2, iv_unimpop = 3, iv_halt = 4, iv_divzero = 5, iv_unwrop = 6, iv_timer = 7, iv_privop = 8, iv_keybd = 9, iv_badcall = 10, iv_pagepriv = 11, iv_debug = 12, iv_intrfault = 13 } manifest { free_page_list = 0xC0400000, page_dir = 0xC0000000, pe_map_page_1 = 0xC0980002, map_page_1 = 0xC0001000, p_free_page_ptr = 0xC0000800, intvec = 0xC0000810, cgbase = 0xC0000830, next_free_in_attic = 0xC0000930, p_phys_addr_attic = 0xC0000801 } let get_page() be { let r = free_page_list ! (! p_free_page_ptr); ! p_free_page_ptr +:= 1; resultis r; } let pfhandler(a, addr, c) be { let ptn = addr >> 22; let pn = (addr >> 11) bitand 0x7FF; let offs = addr bitand 0x7FF; let npte = get_page() bitor 1; out("PAGE FAULT! addr = %x, %x/%x/%x\n", addr, ptn, pn, offs); if ptn /= 0x1FF then { outs("Bad memory access\n"); finish } 0xC08FF800 ! pn := npte; ireturn } let thandler() be { out("TIMER!\n"); ireturn } let halthandler() be { out("Process wants to exit\n"); finish; } let sc1(code, regn, regv, pc, fp, sp, r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0) be { out("sc1(%d) %d %d %d %d\n", code, r1, r2, r3, r4); // flags is before code ireturn } let sc2(code, regn, regv, pc, fp, sp) be { let nargs = (fp ! 2) / 2; out("sc2(%d, %d, %d, %d)\n", fp!3, fp!4, fp!5, fp!6); ireturn } let syscall_exit() be { out("Process wants to exit\n"); ireturn; } let print_mem_map() be { let pdbr; assembly { getsr r1, $pdbr store r1, [] } out("00000000 to FFFFFFFF: PDBR = p%x, v%x\n", pdbr, page_dir); for ptn = 1023 to 0 by -1 do // page table number { let pde = page_dir ! ptn; // page directory entry let pt = pde >> 11 << 11; // page table's address let ptrange = ptn << 22; // beginning of PT's VA range if pde = 0 then loop; out(" %08x to %08x: ", ptrange, ptrange + 0x3FFFFF); if (pde bitand 1) = 0 then { out("%08x - invalid\n", pde); loop } out("pp %d at %x\n", pde >> 11, pde >> 11 << 11); ! pe_map_page_1 := pde; for pn = 2047 to 0 by -1 do // page number in table { let pte = map_page_1 ! pn; // page table entry let range = ptrange + (pn << 11); // beginning of page's VA range if pte = 0 then loop; out(" %08x to %08x: ", range, range + 0x7FF); if (pte bitand 1) = 0 then { out("%08x - invalid\n", pte); loop } out("pp %d at %x\n", pte >> 11, pte >> 11 << 11) } } } let inlast = '\n'; let newinput() be { outs("> "); inlast := 0; } let inchar() be { if inlast <> 0 then { let r = inlast; inlast := 0; resultis r; } resultis inch(); } let inpart(s, max) be { let c = inchar(), n = 0; while true do { if c = '\n' then { inlast := '\n'; resultis nil; } if c > ' ' then break; c := inchar(); } while true do { if n < max then { byte n of s := c; n +:= 1 } c := inchar(); if c <= ' ' then { inlast := c; break } } byte n of s := 0; resultis s } let streq(a, b) be { let i = 0; while true do { let ca = byte i of a, cb = byte i of b; if ca <> cb then resultis false; if ca = 0 then resultis true; i +:= 1 } } let start() be { let x = 12; let y = x*x; let stack_ptr = 0x7FFFFFFF; intvec ! iv_pagefault := pfhandler; intvec ! iv_timer := thandler; intvec ! iv_halt := halthandler; cgbase ! 1 := sc1; cgbase ! 2 := sc2; cgbase ! 3 := syscall_exit; out("I'm the operating system!\n"); out(" start = %x\n", start); out(" @x = %x\n", @x); out(" y = %d\n", y); print_mem_map(); assembly { loadh r1, 200 setsr r1, $timer load r1, 0 setfl r1, $ip } while true do { let s = vec(30); newinput(); s := inpart(s, 119); if s = nil then loop; if streq(s, "exit") then break; if streq(s, "run") then { assembly { load r2, [] load r1, 0 setfl r1, $ip setfl r1, $sys store r2, sp store r1, fp jump 0 } } out("bad command '%s'\n", s) } outs("all done\n") }