github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/kernel/trap.go (about)

     1  package kernel
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	"github.com/icexin/eggos/drivers/pic"
     7  	"github.com/icexin/eggos/kernel/isyscall"
     8  	"github.com/icexin/eggos/kernel/sys"
     9  	"github.com/icexin/eggos/kernel/trap"
    10  	"github.com/icexin/eggos/log"
    11  )
    12  
    13  var (
    14  	trapnum = [...]string{
    15  		"#DE(0) Divide by zero",
    16  		"#DB(1) Debug exception",
    17  		"#NMI(2) Non maskable interrupt exception",
    18  		"#BP(3) Breakpoint exception",
    19  		"#OF(4) Overflow exception",
    20  		"#BR(5) Bound range exception",
    21  		"#UD(6) Invalid opcode exception",
    22  		"#NM(7) Device not avaiable exception",
    23  		"#DF(8) Double fault exception",
    24  		"(9)Coprocessor segment overrun exception",
    25  		"#TS(10) Invalid TSS exception",
    26  		"#NP(11) Segment not present exception",
    27  		"#SS(12) Stack exception",
    28  		"#GP(13) General protection exception",
    29  		"#PF(14) Page fault exception",
    30  		"#MF(15) x87 floating point exception",
    31  		"#AC(16) Alignment check exception",
    32  		"#MC(17) Machine check exception",
    33  		"#XF(18) SIMD floating point exception",
    34  		"#HV(19) Hypervisor injection exception",
    35  		"#VC(20) VMM communication exception",
    36  		"#SX(21) Security Exception",
    37  	}
    38  )
    39  
    40  //go:notinheap
    41  type trapFrame struct {
    42  	AX, BX, CX, DX    uintptr
    43  	BP, SI, DI, R8    uintptr
    44  	R9, R10, R11, R12 uintptr
    45  	R13, R14, R15     uintptr
    46  
    47  	Trapno, Err uintptr
    48  
    49  	// pushed by hardware
    50  	IP, CS, FLAGS, SP, SS uintptr
    51  }
    52  
    53  func (t *trapFrame) SyscallRequest() isyscall.Request {
    54  	return isyscall.NewRequest(uintptr(unsafe.Pointer(t)))
    55  }
    56  
    57  //go:nosplit
    58  func trapret()
    59  
    60  //go:nosplit
    61  func trapPanic() {
    62  	tf := Mythread().tf
    63  	log.PrintStr("trap panic: ")
    64  	if tf.Trapno < uintptr(len(trapnum)) {
    65  		log.PrintStr(trapnum[tf.Trapno])
    66  	}
    67  	log.PrintStr("\n")
    68  	throwtf(tf, "stack trace:")
    69  }
    70  
    71  //go:nosplit
    72  func pageFaultPanic() {
    73  	panic("nil pointer or invalid memory access")
    74  }
    75  
    76  //go:nosplit
    77  func ignoreHandler() {
    78  }
    79  
    80  //go:nosplit
    81  func pageFaultHandler() {
    82  	t := Mythread()
    83  	checkKernelPanic(t)
    84  	changeReturnPC(t.tf, sys.FuncPC(pageFaultPanic))
    85  }
    86  
    87  //go:nosplit
    88  func faultHandler() {
    89  	trapPanic()
    90  }
    91  
    92  //go:nosplit
    93  func printReg(name string, reg uintptr) {
    94  	log.PrintStr(name)
    95  	log.PrintStr("=")
    96  	log.PrintHex(reg)
    97  	log.PrintStr("\n")
    98  }
    99  
   100  //go:nosplit
   101  func checkKernelPanic(t *Thread) {
   102  	tf := t.tf
   103  	if tf.CS != _KCODE_IDX<<3 {
   104  		return
   105  	}
   106  	printReg("tid", uintptr(t.id))
   107  	printReg("no", tf.Trapno)
   108  	printReg("err", tf.Err)
   109  	printReg("cr2", sys.Cr2())
   110  	printReg("ip", tf.IP)
   111  	printReg("sp", tf.SP)
   112  	printReg("ax", tf.AX)
   113  	printReg("bx", tf.BX)
   114  	printReg("cx", tf.CX)
   115  	printReg("dx", tf.CX)
   116  	printReg("cs", tf.CS)
   117  	throw("trap fault in kernel\n")
   118  }
   119  
   120  //go:nosplit
   121  func preparePanic(tf *trapFrame) {
   122  	changeReturnPC(tf, sys.FuncPC(trapPanic))
   123  }
   124  
   125  // ChangeReturnPC change the return pc of a trap
   126  // must be called in trap handler
   127  //go:nosplit
   128  func changeReturnPC(tf *trapFrame, pc uintptr) {
   129  	// tf.Err, tf.IP, tf.CS, tf.FLAGS = pc, tf.CS, tf.FLAGS, tf.IP
   130  	sp := tf.SP
   131  	sp -= sys.PtrSize
   132  	*(*uintptr)(unsafe.Pointer(sp)) = tf.IP
   133  	tf.SP = sp
   134  	tf.IP = pc
   135  }
   136  
   137  //go:nosplit
   138  func dotrap(tf *trapFrame) {
   139  	if sys.Flags()&_FLAGS_IF != 0 {
   140  		throw("IF should clear")
   141  	}
   142  	my := Mythread()
   143  	// ugly as it is, avoid writeBarrier
   144  	// my.tf = tf
   145  	*(*uintptr)(unsafe.Pointer(&my.tf)) = uintptr(unsafe.Pointer(tf))
   146  
   147  	handler := trap.Handler(int(tf.Trapno))
   148  	if handler == nil {
   149  		faultHandler()
   150  		return
   151  	}
   152  	// timer and syscall interrupts are processed synchronously
   153  	if tf.Trapno > 32 && tf.Trapno != 0x80 {
   154  		// pci using level trigger irq, cause dead lock on trap handler
   155  		// FIXME: hard code network irq line
   156  		if tf.Trapno == 43 {
   157  			pic.DisableIRQ(43 - pic.IRQ_BASE)
   158  		}
   159  		wakeIRQ(tf.Trapno)
   160  		return
   161  	}
   162  	handler()
   163  }
   164  
   165  //go:nosplit
   166  func trapInit() {
   167  	trap.Register(14, pageFaultHandler)
   168  	trap.Register(39, ignoreHandler)
   169  	trap.Register(47, ignoreHandler)
   170  }