mirror of
https://github.com/open-goal/jak-project
synced 2026-08-06 09:54:10 -04:00
333 lines
13 KiB
Common Lisp
333 lines
13 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
(bundles "KERNEL.CGO")
|
|
(require "kernel/gcommon.gc")
|
|
|
|
;; Debug-handler support for the EE kernel. These routines depend on the exact
|
|
;; memory layout of the supported BIOS and verify every hardwired address before
|
|
;; installing handlers. Syscall 102 is temporarily repurposed to enter the small
|
|
;; copy/read/write routines stored in low kernel memory.
|
|
;;
|
|
;; The PC port keeps the public entry points as explicit stubs.
|
|
|
|
;; Scratch layout beginning at #x80000. The kernel syscall dispatcher reads the
|
|
;; three function slots installed below; the remaining fields hold interrupt and
|
|
;; DMA bookkeeping shared with the exception handlers.
|
|
(deftype lowmemmap (structure)
|
|
((irq-info-stack uint32)
|
|
(irq2-info-stack uint32)
|
|
(kernel-copy-fn uint32)
|
|
(kernel-write-fn uint32)
|
|
(r1-save uint128)
|
|
(last-time uint32)
|
|
(high-time uint32)
|
|
(dma-status uint32)
|
|
(dma-qnext uint32)
|
|
(dma-qwc uint32)
|
|
(dma-tnext uint32)
|
|
(dma-stack0 uint32)
|
|
(dma-stack1 uint32)
|
|
(kernel-read-fn uint32)))
|
|
|
|
(defmacro nyi-break (name)
|
|
`(begin
|
|
(format 0 "~A is not implemented!~%" (quote ,name))
|
|
(break)
|
|
(none)))
|
|
|
|
(defun kernel-copy-function ((unused object) (source pointer) (dest pointer) (word-count int))
|
|
"Copy a positive number of 32-bit words for the private kernel syscall. The first ABI argument is unused."
|
|
(#unless PC_PORT
|
|
(rlet ((source-reg :reg a1)
|
|
(dest-reg :reg a2)
|
|
(remaining :reg a3)
|
|
(word))
|
|
copy-word
|
|
(l.w word source-reg)
|
|
(s.w word dest-reg)
|
|
(&+! source-reg 4)
|
|
(&+! dest-reg 4)
|
|
(-! remaining 1)
|
|
(b.nz remaining copy-word :delay (nop!))
|
|
(j ra :delay (nop!))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-copy-function)))
|
|
|
|
;; The syscall dispatcher reads these entry points directly from low memory.
|
|
(#unless PC_PORT
|
|
(set! (-> (the lowmemmap #x80000) kernel-copy-fn) (the uint32 kernel-copy-function)))
|
|
|
|
(defun kernel-copy-to-kernel-ram ((unused object) (source pointer) (dest pointer) (word-count int))
|
|
"Invoke the private syscall-102 kernel copy service."
|
|
(#unless PC_PORT
|
|
(rlet ((selector :reg a0)
|
|
(syscall-id :reg v1))
|
|
(m! selector #xe001fd5a)
|
|
(m! syscall-id 102)
|
|
(syscall 0)
|
|
(return (none))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-copy-to-kernel-ram)))
|
|
|
|
(defun kernel-write-function ((unused object) (dest pointer) (value uint32))
|
|
"Write one 32-bit word for the private kernel syscall. The first ABI argument is unused."
|
|
(#unless PC_PORT
|
|
(rlet ((dest-reg :reg a1)
|
|
(value-reg :reg a2))
|
|
(j ra :delay (s.w value-reg dest-reg))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-write-function)))
|
|
|
|
(#unless PC_PORT
|
|
(set! (-> (the lowmemmap #x80000) kernel-write-fn) (the uint32 kernel-write-function)))
|
|
|
|
(defun kernel-write ((unused object) (dest pointer) (value uint32))
|
|
"Invoke the private syscall-102 kernel word-write service."
|
|
(#unless PC_PORT
|
|
(rlet ((selector :reg a0)
|
|
(syscall-id :reg v1))
|
|
(m! selector #xe001fd5b)
|
|
(m! syscall-id 102)
|
|
(syscall 0)
|
|
(return (none))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-write)))
|
|
|
|
(defun kernel-read-function ((unused object) (source pointer))
|
|
"Read one signed 32-bit word for the private kernel syscall. The first ABI argument is unused."
|
|
(#unless PC_PORT
|
|
(rlet ((source-reg :reg a1)
|
|
(result :reg v0))
|
|
(j ra :delay (l.w result source-reg))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-read-function)))
|
|
|
|
(#unless PC_PORT
|
|
(set! (-> (the lowmemmap #x80000) kernel-read-fn) (the uint32 kernel-read-function)))
|
|
|
|
(defun kernel-read ((unused object) (source pointer))
|
|
"Invoke the private syscall-102 kernel word-read service."
|
|
(#unless PC_PORT
|
|
(rlet ((selector :reg a0)
|
|
(syscall-id :reg v1)
|
|
(result :reg v0))
|
|
(m! selector #xe001fd68)
|
|
(m! syscall-id 102)
|
|
(syscall 0)
|
|
(return (the int result))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-read)))
|
|
|
|
(defun kernel-check-hardwired-addresses ()
|
|
"Verify that the running PS2 kernel matches the hardwired debug-monitor memory layout."
|
|
(#unless PC_PORT
|
|
(let* ((irq-table (+ #x80010000 (logand (kernel-read 0 (the pointer #x80000248)) #xffff)))
|
|
(handler-2 (kernel-read 0 (the pointer (+ irq-table 8))))
|
|
(handler-3 (kernel-read 0 (the pointer (+ irq-table 12))))
|
|
(handler-7 (kernel-read 0 (the pointer (+ irq-table 28))))
|
|
(exception-table (+ #x80010000 (logand (kernel-read 0 (the pointer #x800001a0)) #xffff)))
|
|
(exception-handler (kernel-read 0 (the pointer exception-table)))
|
|
(level2-vector-1 (+ #x80000000 (* (logand (kernel-read 0 (the pointer #x80000088)) #xffff) 4)))
|
|
(level2-vector-2 (+ #x80000000 (* (logand (kernel-read 0 (the pointer #x80000108)) #xffff) 4)))
|
|
(syscall-table (+ #x80010000 (logand (kernel-read 0 (the pointer #x800002f8)) #xffff)))
|
|
(syscall-102-handler (kernel-read 0 (the pointer (+ syscall-table 408))))
|
|
(syscall-102-data
|
|
(logior (shl (logand (kernel-read 0 (the pointer syscall-102-handler)) #xffff) 16)
|
|
(logand (kernel-read 0 (the pointer (+ syscall-102-handler 16))) #xffff)))
|
|
(valid? #t))
|
|
(format 0 "Read data from kernel~%")
|
|
(format 0 "IRQ table at ~8X~%" irq-table)
|
|
(format 0 " Handler 2 ~8X~%" handler-2)
|
|
(format 0 " Handler 3 ~8X~%" handler-3)
|
|
(format 0 " Handler 7 ~8X~%" handler-7)
|
|
(format 0 "Exception table at ~8X~%" exception-table)
|
|
(format 0 " Handler ~8X~%" exception-handler)
|
|
(format 0 "L2 exception #1 ~8X~%" level2-vector-1)
|
|
(format 0 "L2 exception #2 ~8X~%" level2-vector-2)
|
|
(format 0 "SYSCALL table at ~8X~%" syscall-table)
|
|
(format 0 " SYSCALL 102 ~8X~%" syscall-102-handler)
|
|
(format 0 " SYSCALL 102 data ~8X~%" syscall-102-data)
|
|
(unless (= irq-table #x80014180) (set! valid? #f))
|
|
(unless (= handler-2 #x80000380) (set! valid? #f))
|
|
(unless (= handler-3 #x800004c0) (set! valid? #f))
|
|
(unless (= handler-7 #x80000600) (set! valid? #f))
|
|
(unless (= exception-table #x80014140) (set! valid? #f))
|
|
(unless (= exception-handler #x80012ec8) (set! valid? #f))
|
|
(unless (= level2-vector-1 #x80012f64) (set! valid? #f))
|
|
(unless (= level2-vector-2 #x80012f64) (set! valid? #f))
|
|
(unless (= syscall-table #x80013d40) (set! valid? #f))
|
|
(unless (= syscall-102-handler #x80000a80) (set! valid? #f))
|
|
(unless (= syscall-102-data #x80000aa0) (set! valid? #f))
|
|
(unless valid?
|
|
(format 0 "======================================================================~%")
|
|
(format 0 "I CANNOT CONTINUE TO LOAD GOAL, BECAUSE THE KERNEL VERSION HAS CHANGED~%")
|
|
(format 0 "======================================================================~%")
|
|
(format 0 "~%Alternatively, try removing pskernel.gc and debug-handlers.gc from project.cl, do an (lg) and then (:r) again~%")
|
|
;; Stop immediately: using these addresses with another kernel would corrupt kernel memory.
|
|
(s.l r0 r0 2))
|
|
(dotimes (i 128)
|
|
(unless (zero? (kernel-read 0 (the pointer (+ #x80030000 (* i 4)))))
|
|
(set! valid? #f)))
|
|
(unless valid?
|
|
(format 0 "======================================================================~%")
|
|
(format 0 "I CANNOT CONTINUE TO LOAD GOAL, BECAUSE THE KERNEL VERSION HAS CHANGED~%")
|
|
(format 0 " (Previously unused area now has data) ~%")
|
|
(format 0 "======================================================================~%")
|
|
(format 0 "~%Alternatively, try removing pskernel.gc and debug-handlers.gc from project.cl, do an (lg) and then (:r) again~%")
|
|
(s.l r0 r0 2))
|
|
(format 0 "Unused area OK~%")
|
|
(return (none))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-check-hardwired-addresses)))
|
|
|
|
(defun install-default-debug-handler ((handler object))
|
|
"Install one debug handler for the supported EE exception classes."
|
|
(#unless PC_PORT
|
|
(install-debug-handler 1 handler)
|
|
(install-debug-handler 2 handler)
|
|
(install-debug-handler 3 handler)
|
|
(install-debug-handler 4 handler)
|
|
(install-debug-handler 5 handler)
|
|
(install-debug-handler 6 handler)
|
|
(install-debug-handler 7 handler)
|
|
(install-debug-handler 10 handler)
|
|
(install-debug-handler 11 handler)
|
|
(install-debug-handler 12 handler)
|
|
(install-debug-handler 13 handler)
|
|
(return (none)))
|
|
(#when PC_PORT
|
|
(nyi-break install-default-debug-handler)))
|
|
|
|
(defun return-from-exception ((regs (pointer uint128)))
|
|
"Restore an EE register image and return from the exception with eret."
|
|
(#unless PC_PORT
|
|
(rlet ((regs-base :reg a0))
|
|
(l.q r0 regs-base 0)
|
|
(l.q at regs-base 16)
|
|
(l.q v0 regs-base 32)
|
|
(l.q v1 regs-base 48)
|
|
(l.q a1 regs-base 80)
|
|
(l.q a2 regs-base 96)
|
|
(l.q a3 regs-base 112)
|
|
(l.q t0 regs-base 128)
|
|
(l.q t1 regs-base 144)
|
|
(l.q t2 regs-base 160)
|
|
(l.q t3 regs-base 176)
|
|
(l.q t4 regs-base 192)
|
|
(l.q t5 regs-base 208)
|
|
(l.q t6 regs-base 224)
|
|
(l.q t7 regs-base 240)
|
|
(l.q s0 regs-base 256)
|
|
(l.q s1 regs-base 272)
|
|
(l.q s2 regs-base 288)
|
|
(l.q s3 regs-base 304)
|
|
(l.q s4 regs-base 320)
|
|
(l.q s5 regs-base 336)
|
|
(l.q s6 regs-base 352)
|
|
(l.q s7 regs-base 368)
|
|
(l.q t8 regs-base 384)
|
|
(l.q t9 regs-base 400)
|
|
(l.q gp regs-base 448)
|
|
(l.q sp regs-base 464)
|
|
(l.q fp regs-base 480)
|
|
(l.q ra regs-base 496)
|
|
;; a0 is restored last because it holds the register-image base.
|
|
(l.q a0 regs-base 64)
|
|
(sync.l)
|
|
(sync.p)
|
|
(eret :delay (nop!))
|
|
(nop!)
|
|
(nop!)))
|
|
(#when PC_PORT
|
|
(nyi-break return-from-exception)))
|
|
|
|
(defun kernel-set-exception-vector ((exception int) (handler object))
|
|
"Install a handler for an EE exception class."
|
|
(#unless PC_PORT
|
|
(rlet ((exception-reg :reg a0)
|
|
(syscall-id :reg v1)
|
|
(result :reg v0))
|
|
(b.geu exception-reg 4 common-handler :delay (nop!))
|
|
(m! syscall-id 13)
|
|
(syscall 0)
|
|
(m! result 0)
|
|
(b vector-done :delay (nop!))
|
|
common-handler
|
|
(m! syscall-id 14)
|
|
(syscall 0)
|
|
(m! result 0)
|
|
vector-done
|
|
(return (none))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-set-exception-vector)))
|
|
|
|
(defun kernel-set-interrupt-vector ((interrupt int) (handler object))
|
|
"Install an EE interrupt handler through syscall 15."
|
|
(#unless PC_PORT
|
|
(rlet ((syscall-id :reg v1)
|
|
(result :reg v0))
|
|
(m! syscall-id 15)
|
|
(syscall 0)
|
|
(m! result 0)
|
|
(return (none))))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-set-interrupt-vector)))
|
|
|
|
(defun kernel-set-level2-vector ((vector-number int) (handler uint))
|
|
"Install a KSEG0 handler for one of the two level-two vectors."
|
|
(#unless PC_PORT
|
|
(when (!= (logand (shl #xf000 16) handler) (shl #x8000 16))
|
|
(format 0 "CANNOT SET LEVEL2 HANDLER IF IT IS NOT IN KSEG0 MEMORY (#x8xxxxxxx)~%")
|
|
(return #f))
|
|
(if (= vector-number 1)
|
|
(kernel-write 0
|
|
(the-as pointer (the-as uint #x80000088))
|
|
(the-as uint32 (logior #x8000000 (shr (logand #xfffffff handler) 2)))))
|
|
(if (= vector-number 2)
|
|
(kernel-write 0
|
|
(the-as pointer (the-as uint #x80000108))
|
|
(the-as uint32 (logior #x8000000 (shr (logand #xfffffff handler) 2)))))
|
|
(return #t))
|
|
(#when PC_PORT
|
|
(nyi-break kernel-set-level2-vector)))
|
|
|
|
(defun deinstall-debug-handler ((exception int))
|
|
"Restore the default kernel handler for one exception class."
|
|
(#unless PC_PORT
|
|
(kernel-set-exception-vector exception (the-as uint #x80012ec8))
|
|
(return (none)))
|
|
(#when PC_PORT
|
|
(nyi-break deinstall-debug-handler)))
|
|
|
|
(defun deinstall-debug-handlers ()
|
|
"Restore the default kernel handler for every exception class used by the debug monitor."
|
|
(#unless PC_PORT
|
|
(kernel-set-exception-vector 1 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 2 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 3 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 4 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 5 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 6 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 7 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 10 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 11 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 12 (the-as uint #x80012ec8))
|
|
(kernel-set-exception-vector 13 (the-as uint #x80012ec8))
|
|
(return (none)))
|
|
(#when PC_PORT
|
|
(nyi-break deinstall-debug-handlers)))
|
|
|
|
(defun resend-exception ((status uint) (cause uint) (epc uint) (bad-vaddr uint) (bad-paddr uint) (regs (pointer uint128)))
|
|
"Remove the debug handlers, restore the saved COP0 exception state, and resume through the supplied register image."
|
|
(#unless PC_PORT
|
|
(deinstall-debug-handlers)
|
|
(m Status status)
|
|
(m Cause cause)
|
|
(m EPC epc)
|
|
(m BadVAddr bad-vaddr)
|
|
(m BadPAddr bad-paddr)
|
|
(return-from-exception regs)
|
|
(return (none)))
|
|
(#when PC_PORT
|
|
(nyi-break resend-exception)))
|