cosmopolitan/libc/intrin/interrupts.S
Jōshin 2fc507c98f
Fix more vi modelines (#1006)
* modelines: tw -> sw

shiftwidth, not textwidth.

* space-surround modelines

* fix irregular modelines

* Fix modeline in titlegen.c
2023-12-13 02:28:11 -05:00

185 lines
6.2 KiB
ArmAsm

/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/pc.internal.h"
// Code and data structures for bare metal interrupt handling.
#define ISR_STK_SZ 0x10000
#define ISR_STK_ALIGN 0x10
// Interrupt stack to use for IRQs. TODO.
#define IRQ_IST 1
// Interrupt stack to use for CPU exceptions.
#define EXCEP_IST 2
// Interrupt numbers to use for IRQs 0 & 8. TODO: implement these!
#define IRQ0 0x20
#define IRQ8 0x28
.init.start 100,_init_isr
push %rdi
call isr_init
pop %rdi
.init.end 100,_init_isr
// Interrupt service routines for CPU exceptions 031.
i = 31
.rept 30
push %rsi # preserve rsi
mov $i,%sil # rsi = exception number
1: jmp 1f # kangeroo
i = i - 1
.endr
__excep1_isr:
push %rsi
mov $1,%sil
1: jmp 1f
__excep0_isr:
push %rsi
xor %esi,%esi
1: test $8,%esp # if no error code was pushed,
jnz 2f # stuff our own
pushq (%rsp)
orq $-1,8(%rsp)
2: movzbq %sil,%rsi # zero-extend the exception number
push %rcx # preserve registers which we will
push %rdx # use to call kprintf
push %r8
push %r9
mov 48(%rsp),%rcx # edx:rcx = 'caller' cs:rip
mov 56(%rsp),%edx
mov 40(%rsp),%r8 # r8 = error code
mov %cr2,%r9 # r9 = cr2, in case it is useful
push %rax # preserve other call-used registers
push %rdi
push %r9
push %r10
push %r11
mov %ss,%eax # preserve ds, es, ss
push %rax
mov %ds,%eax
push %rax
mov %es,%eax
push %rax
mov $GDT_LONG_DATA,%eax # ...& load ds, es, ss correctly
mov %eax,%ss
mov %eax,%ds
mov %eax,%es
cld # make sure DF is reset, for C code
ezlea .excep_msg,di # stack should be 16-byte aligned now
xor %eax,%eax # kprintf is variadic, remember to
# pass no. of vector regs. used (= 0)
.weak kprintf # weakly link kprintf() because we
ezlea kprintf,bx # want to keep life.com tiny
test %ebx,%ebx
jz 8f
call *%rbx # print error message
8: cli
9: hlt
jmp 9b
/* TODO: link up with sigaction etc. */
// Initialization code for setting up a Task State Segment (TSS) &
// Interrupt Descriptor Table (IDT) in bare metal mode, to start
// processing exceptions & asynchronous IRQs.
isr_init:
testb IsMetal()
jz 9f
ezlea _tss+0x24,di # fill up TSS
ezlea _isr_stk_1+ISR_STK_SZ,ax
and $-ISR_STK_ALIGN,%al # be paranoid & enforce correct
stosq # alignment of stack pointers
ezlea _isr_stk_2+ISR_STK_SZ,ax
and $-ISR_STK_ALIGN,%al
stosq
add $0x66-0x34,%rdi
movw $_tss_iopb-_tss,%ax
stosw
lidt _idtr # load IDTR
ezlea _idt,di
pushpop 32,%rcx # fill IDT entries for CPU exceptions
ezlea __excep0_isr,dx
1: mov %edx,%eax
stosw
mov %cs,%eax
stosw
mov %rdx,%rax
// P:present
// DPL:privilege
// system segment (0)
// gate type (interrupt gate, i.e. disable IRQs)
// reserved
// IST:interrupt stack table
//
mov $0b1000111000000000|EXCEP_IST,%ax
stosl
shr $32,%rax
stosq
add $__excep1_isr-__excep0_isr,%rdx
loop 1b
mov $GDT_LONG_TSS,%cl # load task register (cx = 0 here)
ltr %cx
9: ret
// String constants.
.rodata.str1.1
.excep_msg:
.ascii "\033[1;31mCPU exception %d @ %#llx:%#llx err code %#llx "
.asciz "cr2 %#llx\33[0m\n"
.previous
// IDTR value.
.rodata
_idtr: .short _idt_end-_idt-1
.quad _idt
.endobj _idtr,globl,hidden
.balign 8
.previous
.bss
// Space for the Task State Segment.
_tss:
.space 0x68
_tss_iopb:
_tss_end:
.endobj _tss,globl,hidden
.endobj _tss_end,globl,hidden
// Space for the Interrupt Descriptor Table.
_idt: .space (MAX(IRQ0,IRQ8)+8)*0x10
_idt_end:
.endobj _idt,globl,hidden
.previous
// Interrupt stacks.
.lcomm _isr_stk_1,ISR_STK_SZ
.lcomm _isr_stk_2,ISR_STK_SZ