jehanne/sys/src/kern/amd64/l64idt.S

411 lines
11 KiB
ArmAsm

/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
* See /doc/license/gpl-2.0.txt for details about the licensing.
*/
/*
* Interrupt/exception handling.
*/
#include "amd64.h"
#include "mem.h"
.code64
/* Interrupts.
*
* Let's just talk about hardware interrupts.
* What has to happen is that we save enough state to
* return to where we were, and that's all we do. Hardware needs a stack,
* so it pushes SS and %rsp. Hardware has to
* clear If, which means we have to save the flags. We might be
* in user mode, so we need to change CS, so we need to save
* CS. Finally, we have to know where we were, so we need to save
* the RIP. And that's all get saved.
* Further, if you look at idthandlers below, you see a call to intrp.
* So on entry to intrp, the stack looks like this:
* EFLAGS 24(%rsp)
* CS 16(%rsp)
* EIP of interrupted code 8(%rsp)
* EIP from the call from the idthandlers. (%rsp)
* We, finally, need to push the error code and type.,
* then the registers.
* Why the call from IDThandlers? So we can get a way to point
* to the type. We don't need to save 0(%rsp), we just need
* it to get the type. We can pop it and throw it away when
* needed.
* What does the C level function need?
* It needs a pointer to the Uregs, as defined in ureg.h
* The other problem: all the regs have to be saved, so
* Plan 9 code can see them all.
* Finally, if it's a nested interrupt, we need to know that
* so we don't swapgs at the wrong time.
* Finally, this is utterly different from how Plan 9 does it, because
* all args are on the stack in Plan 9. We need %rdi for the pointer.
* And, the final x86 mess: for some things, the error code pointer
* is on the stack. For others, it's not. To make the stacks
* look identical for the common code and exit we save %rax and line things up.
*/
// When we enter:
// registers are NOT saved. We need to save them all.
// return PC is on the stat8(%rsp). It should be left there.
// @ (%rsp) is the PC from the vector table.
// So indirecting on that will get us the interrupt #.
// We need to get what the return PC is pointing to into %rdi.
// We no longer need to make the stack look the same as in Plan 9
// because the arg is in %rdi
.globl _intrp
_intrp:
pushq %rax // bogus error code. Makes stack look like intre.
// Except in this case, bogus error code is at 0(%rsp)
// vno pointer is at 8(%rsp)
movq 8(%rsp), %rax
// Now %rax points to the vector number.
jmp _intrcommon
// For intre, error is at top of stack on trap. But then we call here
// from the interrupt vectors so error is at 8(%rsp).
// I just realized I think intre means interrupt exception, e.g. page fault.
.globl _intre
_intre:
///jmp _intre
// The error code has been pushed. How I love the x86.
// So the error code is ABOVE the pointer to the vector #.
xchgq %rax, (%rsp)
// Now %rax points to the vector number.
// When we get here:
// %RAX points to our vector number, i.e. "return" pc from calls below.
// For intrp, (%rsp) is bogus code, 8(%rsp) is pointer to vno
// for intre, (%rsp) is pointer to vno, 8(%rsp) is error code.
// The rest of the stack is the same.
_intrcommon:
// Get the vector number into %al
MOVb (%rax), %al
andq $0xff, %rax
// Put that at TOS (this is plan 9 argument style)
xchgq %rax, 0(%rsp)
// 0(%rsp) now has the vno
subq $16, %rsp /* R1[45] */
cmpw $KESEL, 40(%rsp) /* old CS */
je _intrnested
movq %r14, 0(%rsp)
movq %r15, 8(%rsp)
swapgs
movq %gs:0, %r15 /* m-> (movq GS:0x0, R15) */
movq 16(%r15), %r14 /* m->proc (set up->) */
_intrnested:
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rbp
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx
pushq %rbx
pushq %rax
movq %rsp, %rdi // it's ok, we saved %rdi.
xorq %rax, %rax
/* if we came from user, stack traces end here */
cmpw $SSEL(SiCS, SsTIGDT|SsRPL0), 144(%rsp)
cmovneq %rax, %rbp
pushq %rax
popfq /* clear all flags. is there something else we should clear too? */
call trap
.globl _intrr
_intrr:
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rsi
popq %rdi
popq %rbp
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
cmpw $KESEL, 40(%rsp) /* old CS */
je _iretnested
swapgs
movq 8(%rsp), %r15
movq 0(%rsp), %r14
_iretnested:
// Throw away:
// The %rax you pushed (error code)
// EIP from the vector table.
addq $32, %rsp
iretq
.globl idthandlers
idthandlers:
call _intrp; .byte IdtDE /* #DE Divide-by-Zero Error */
call _intrp; .byte IdtDB /* #DB Debug */
call _intrp; .byte IdtNMI /* #NMI Borked */
call _intrp; .byte IdtBP /* #BP Breakpoint */
call _intrp; .byte IdtOF /* #OF Overflow */
call _intrp; .byte IdtBR /* #BR Bound-Range */
call _intrp; .byte IdtUD /* #UD Invalid-Opcode */
call _intrp; .byte IdtNM /* #NM Device-Not-Available */
call _intre; .byte IdtDF /* #DF Double-Fault */
call _intrp; .byte Idt09 /* reserved */
call _intre; .byte IdtTS /* #TS Invalid-TSS */
call _intre; .byte IdtNP /* #NP Segment-Not-Present */
call _intre; .byte IdtSS /* #SS Stack */
call _intre; .byte IdtGP /* #GP General-Protection */
call _intre; .byte IdtPF /* #PF Page-Fault */
call _intrp; .byte Idt0F /* reserved */
call _intrp; .byte IdtMF /* #MF x87 FPE-Pending */
call _intre; .byte IdtAC /* #AC Alignment-Check */
call _intrp; .byte IdtMC /* #MC Machine-Check */
call _intrp; .byte IdtXF /* #XF SIMD Floating-Point */
call _intrp; .byte 0x14 /* reserved */
call _intrp; .byte 0x15 /* reserved */
call _intrp; .byte 0x16 /* reserved */
call _intrp; .byte 0x17 /* reserved */
call _intrp; .byte 0x18 /* reserved */
call _intrp; .byte 0x19 /* reserved */
call _intrp; .byte 0x1a /* reserved */
call _intrp; .byte 0x1b /* reserved */
call _intrp; .byte 0x1c /* reserved */
call _intrp; .byte 0x1d /* reserved */
call _intrp; .byte 0x1e /* reserved */
call _intrp; .byte 0x1f /* reserved */
call _intrp; .byte 0x20
call _intrp; .byte 0x21
call _intrp; .byte 0x22
call _intrp; .byte 0x23
call _intrp; .byte 0x24
call _intrp; .byte 0x25
call _intrp; .byte 0x26
call _intrp; .byte 0x27
call _intrp; .byte 0x28
call _intrp; .byte 0x29
call _intrp; .byte 0x2a
call _intrp; .byte 0x2b
call _intrp; .byte 0x2c
call _intrp; .byte 0x2d
call _intrp; .byte 0x2e
call _intrp; .byte 0x2f
call _intrp; .byte 0x30
call _intrp; .byte 0x31
call _intrp; .byte 0x32
call _intrp; .byte 0x33
call _intrp; .byte 0x34
call _intrp; .byte 0x35
call _intrp; .byte 0x36
call _intrp; .byte 0x37
call _intrp; .byte 0x38
call _intrp; .byte 0x39
call _intrp; .byte 0x3a
call _intrp; .byte 0x3b
call _intrp; .byte 0x3c
call _intrp; .byte 0x3d
call _intrp; .byte 0x3e
call _intrp; .byte 0x3f
call _intrp; .byte 0x40
call _intrp; .byte 0x41
call _intrp; .byte 0x42
call _intrp; .byte 0x43
call _intrp; .byte 0x44
call _intrp; .byte 0x45
call _intrp; .byte 0x46
call _intrp; .byte 0x47
call _intrp; .byte 0x48
call _intrp; .byte 0x49
call _intrp; .byte 0x4a
call _intrp; .byte 0x4b
call _intrp; .byte 0x4c
call _intrp; .byte 0x4d
call _intrp; .byte 0x4e
call _intrp; .byte 0x4f
call _intrp; .byte 0x50
call _intrp; .byte 0x51
call _intrp; .byte 0x52
call _intrp; .byte 0x53
call _intrp; .byte 0x54
call _intrp; .byte 0x55
call _intrp; .byte 0x56
call _intrp; .byte 0x57
call _intrp; .byte 0x58
call _intrp; .byte 0x59
call _intrp; .byte 0x5a
call _intrp; .byte 0x5b
call _intrp; .byte 0x5c
call _intrp; .byte 0x5d
call _intrp; .byte 0x5e
call _intrp; .byte 0x5f
call _intrp; .byte 0x60
call _intrp; .byte 0x61
call _intrp; .byte 0x62
call _intrp; .byte 0x63
call _intrp; .byte 0x64
call _intrp; .byte 0x65
call _intrp; .byte 0x66
call _intrp; .byte 0x67
call _intrp; .byte 0x68
call _intrp; .byte 0x69
call _intrp; .byte 0x6a
call _intrp; .byte 0x6b
call _intrp; .byte 0x6c
call _intrp; .byte 0x6d
call _intrp; .byte 0x6e
call _intrp; .byte 0x6f
call _intrp; .byte 0x70
call _intrp; .byte 0x71
call _intrp; .byte 0x72
call _intrp; .byte 0x73
call _intrp; .byte 0x74
call _intrp; .byte 0x75
call _intrp; .byte 0x76
call _intrp; .byte 0x77
call _intrp; .byte 0x78
call _intrp; .byte 0x79
call _intrp; .byte 0x7a
call _intrp; .byte 0x7b
call _intrp; .byte 0x7c
call _intrp; .byte 0x7d
call _intrp; .byte 0x7e
call _intrp; .byte 0x7f
call _intrp; .byte 0x80
call _intrp; .byte 0x81
call _intrp; .byte 0x82
call _intrp; .byte 0x83
call _intrp; .byte 0x84
call _intrp; .byte 0x85
call _intrp; .byte 0x86
call _intrp; .byte 0x87
call _intrp; .byte 0x88
call _intrp; .byte 0x89
call _intrp; .byte 0x8a
call _intrp; .byte 0x8b
call _intrp; .byte 0x8c
call _intrp; .byte 0x8d
call _intrp; .byte 0x8e
call _intrp; .byte 0x8f
call _intrp; .byte 0x90
call _intrp; .byte 0x91
call _intrp; .byte 0x92
call _intrp; .byte 0x93
call _intrp; .byte 0x94
call _intrp; .byte 0x95
call _intrp; .byte 0x96
call _intrp; .byte 0x97
call _intrp; .byte 0x98
call _intrp; .byte 0x99
call _intrp; .byte 0x9a
call _intrp; .byte 0x9b
call _intrp; .byte 0x9c
call _intrp; .byte 0x9d
call _intrp; .byte 0x9e
call _intrp; .byte 0x9f
call _intrp; .byte 0xa0
call _intrp; .byte 0xa1
call _intrp; .byte 0xa2
call _intrp; .byte 0xa3
call _intrp; .byte 0xa4
call _intrp; .byte 0xa5
call _intrp; .byte 0xa6
call _intrp; .byte 0xa7
call _intrp; .byte 0xa8
call _intrp; .byte 0xa9
call _intrp; .byte 0xaa
call _intrp; .byte 0xab
call _intrp; .byte 0xac
call _intrp; .byte 0xad
call _intrp; .byte 0xae
call _intrp; .byte 0xaf
call _intrp; .byte 0xb0
call _intrp; .byte 0xb1
call _intrp; .byte 0xb2
call _intrp; .byte 0xb3
call _intrp; .byte 0xb4
call _intrp; .byte 0xb5
call _intrp; .byte 0xb6
call _intrp; .byte 0xb7
call _intrp; .byte 0xb8
call _intrp; .byte 0xb9
call _intrp; .byte 0xba
call _intrp; .byte 0xbb
call _intrp; .byte 0xbc
call _intrp; .byte 0xbd
call _intrp; .byte 0xbe
call _intrp; .byte 0xbf
call _intrp; .byte 0xc0
call _intrp; .byte 0xc1
call _intrp; .byte 0xc2
call _intrp; .byte 0xc3
call _intrp; .byte 0xc4
call _intrp; .byte 0xc5
call _intrp; .byte 0xc6
call _intrp; .byte 0xc7
call _intrp; .byte 0xc8
call _intrp; .byte 0xc9
call _intrp; .byte 0xca
call _intrp; .byte 0xcb
call _intrp; .byte 0xcc
call _intrp; .byte 0xce
call _intrp; .byte 0xce
call _intrp; .byte 0xcf
call _intrp; .byte 0xd0
call _intrp; .byte 0xd1
call _intrp; .byte 0xd2
call _intrp; .byte 0xd3
call _intrp; .byte 0xd4
call _intrp; .byte 0xd5
call _intrp; .byte 0xd6
call _intrp; .byte 0xd7
call _intrp; .byte 0xd8
call _intrp; .byte 0xd9
call _intrp; .byte 0xda
call _intrp; .byte 0xdb
call _intrp; .byte 0xdc
call _intrp; .byte 0xdd
call _intrp; .byte 0xde
call _intrp; .byte 0xdf
call _intrp; .byte 0xe0
call _intrp; .byte 0xe1
call _intrp; .byte 0xe2
call _intrp; .byte 0xe3
call _intrp; .byte 0xe4
call _intrp; .byte 0xe5
call _intrp; .byte 0xe6
call _intrp; .byte 0xe7
call _intrp; .byte 0xe8
call _intrp; .byte 0xe9
call _intrp; .byte 0xea
call _intrp; .byte 0xeb
call _intrp; .byte 0xec
call _intrp; .byte 0xed
call _intrp; .byte 0xee
call _intrp; .byte 0xef
call _intrp; .byte 0xf0
call _intrp; .byte 0xf1
call _intrp; .byte 0xf2
call _intrp; .byte 0xf3
call _intrp; .byte 0xf4
call _intrp; .byte 0xf5
call _intrp; .byte 0xf6
call _intrp; .byte 0xf7
call _intrp; .byte 0xf8
call _intrp; .byte 0xf9
call _intrp; .byte 0xfa
call _intrp; .byte 0xfb
call _intrp; .byte 0xfc
call _intrp; .byte 0xfd
call _intrp; .byte 0xfe
call _intrp; .byte 0xff