mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Enable CPU exception handling w/ IDT & TSS (#640)
This commit is contained in:
parent
09811e739f
commit
bc8532688b
7 changed files with 231 additions and 7 deletions
25
ape/ape.S
25
ape/ape.S
|
@ -1137,12 +1137,17 @@ sconf: .short 1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
|
||||||
.endobj sconf,global,hidden
|
.endobj sconf,global,hidden
|
||||||
|
|
||||||
// Global Descriptor Table
|
// Global Descriptor Table
|
||||||
//
|
|
||||||
// @note address portion only concern legacy modes
|
|
||||||
.align 8
|
.align 8
|
||||||
gdt: .short 2f-1f # table byte length
|
_gdtrphy:
|
||||||
.long REAL(1f),0 # table address
|
.short 2f-1f-1 # table byte length
|
||||||
.zero 2
|
.long REAL(1f) # table address (physical space)
|
||||||
|
.endobj _gdtrphy,global,hidden
|
||||||
|
_gdtr:
|
||||||
|
.short 2f-1f-1 # table byte length
|
||||||
|
.quad 1f # table address (final virtual space)
|
||||||
|
.endobj _gdtr,global,hidden
|
||||||
|
.align 8
|
||||||
|
_gdt:
|
||||||
1:
|
1:
|
||||||
// ┌G:granularity (1 → limit *= 0x1000)
|
// ┌G:granularity (1 → limit *= 0x1000)
|
||||||
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
||||||
|
@ -1172,7 +1177,9 @@ gdt: .short 2f-1f # table byte length
|
||||||
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
||||||
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
||||||
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
||||||
2: .endobj gdt,global,hidden
|
.tssdescstub _tss #56,64
|
||||||
|
2:
|
||||||
|
.endobj _gdt,global,hidden
|
||||||
|
|
||||||
/*─────────────────────────────────────────────────────────────────────────────╗
|
/*─────────────────────────────────────────────────────────────────────────────╗
|
||||||
│ αcτµαlly pδrταblε εxεcµταblε § real mode │
|
│ αcτµαlly pδrταblε εxεcµταblε § real mode │
|
||||||
|
@ -1433,7 +1440,7 @@ golong: cli
|
||||||
rdmsr
|
rdmsr
|
||||||
or $EFER_LME|EFER_SCE,%eax
|
or $EFER_LME|EFER_SCE,%eax
|
||||||
wrmsr
|
wrmsr
|
||||||
lgdt REAL(gdt)
|
lgdt REAL(_gdtrphy)
|
||||||
mov %cr0,%eax
|
mov %cr0,%eax
|
||||||
or $CR0_PE|CR0_PG|CR0_MP,%eax
|
or $CR0_PE|CR0_PG|CR0_MP,%eax
|
||||||
and $~CR0_EM,%eax
|
and $~CR0_EM,%eax
|
||||||
|
@ -1451,6 +1458,8 @@ long: xor %eax,%eax
|
||||||
mov %eax,%fs
|
mov %eax,%fs
|
||||||
mov %eax,%gs
|
mov %eax,%gs
|
||||||
mov $0x80000,%esp
|
mov $0x80000,%esp
|
||||||
|
mov $GDT_LONG_TSS,%al
|
||||||
|
ltr %ax
|
||||||
xor %r12d,%r12d
|
xor %r12d,%r12d
|
||||||
xor %r13d,%r13d
|
xor %r13d,%r13d
|
||||||
xor %r14d,%r14d
|
xor %r14d,%r14d
|
||||||
|
@ -1464,6 +1473,8 @@ long: xor %eax,%eax
|
||||||
call __map_phdrs
|
call __map_phdrs
|
||||||
push $0x037f
|
push $0x037f
|
||||||
fldcw (%rsp)
|
fldcw (%rsp)
|
||||||
|
lgdt _gdtr # reload GDTR for
|
||||||
|
# virtual memory space
|
||||||
movabs $kernel,%rax
|
movabs $kernel,%rax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
.endfn long
|
.endfn long
|
||||||
|
|
|
@ -572,6 +572,9 @@ HIDDEN(v_ape_realslacksectors =
|
||||||
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
||||||
HIDDEN(v_ape_highsectors =
|
HIDDEN(v_ape_highsectors =
|
||||||
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
||||||
|
PROVIDE_HIDDEN(_tss = 0);
|
||||||
|
PROVIDE_HIDDEN(_tss_end = 0);
|
||||||
|
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ZIP End of Central Directory header */
|
/* ZIP End of Central Directory header */
|
||||||
|
|
|
@ -180,6 +180,12 @@
|
||||||
.stub \name\()_bcs\n,long
|
.stub \name\()_bcs\n,long
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
// Task State Segment Descriptor Entries.
|
||||||
|
.macro .tssdescstub name:req
|
||||||
|
.stub \name\()_desc_ent0,quad
|
||||||
|
.stub \name\()_desc_ent1,quad
|
||||||
|
.endm
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
#elif defined(__LINKER__)
|
#elif defined(__LINKER__)
|
||||||
|
|
||||||
|
@ -257,5 +263,22 @@
|
||||||
(X) % 10 * 0x1000000 \
|
(X) % 10 * 0x1000000 \
|
||||||
: 0xffffffffffffffff)
|
: 0xffffffffffffffff)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||||
|
*/
|
||||||
|
#define TSSDESCSTUB2(SYM, BASE, LIM) \
|
||||||
|
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||||
|
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||||
|
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||||
|
#define TSSDESC_ENT0(BASE, LIM) \
|
||||||
|
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||||
|
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||||
|
0x89 << 40 | \
|
||||||
|
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||||
|
0x2 << 52 | \
|
||||||
|
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||||
|
#define TSSDESC_ENT1(BASE) \
|
||||||
|
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
#endif /* APE_MACROS_H_ */
|
#endif /* APE_MACROS_H_ */
|
||||||
|
|
173
libc/intrin/interrupts.S
Normal file
173
libc/intrin/interrupts.S
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=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/macros.internal.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 0—31.
|
||||||
|
i = 31
|
||||||
|
.rept 30
|
||||||
|
push %rsi # preserve rsi
|
||||||
|
mov $i,%sil # rsi = exception number
|
||||||
|
1: jmp 1f # 🦘
|
||||||
|
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
|
||||||
|
mov 40(%rsp),%rcx # edx:rcx = "caller" cs:rip
|
||||||
|
mov 48(%rsp),%edx
|
||||||
|
mov 32(%rsp),%r8 # r8 = error code
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
call kprintf # print error message
|
||||||
|
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; we already loaded
|
||||||
|
# task register in ape/ape.S
|
||||||
|
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
|
||||||
|
9: ret
|
||||||
|
|
||||||
|
// String constants.
|
||||||
|
.rodata.str1.1
|
||||||
|
.excep_msg:
|
||||||
|
.asciz "CPU exception %d @ %#llx:%#llx err code %#llx\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
|
|
@ -28,6 +28,10 @@
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
#if SupportsMetal()
|
||||||
|
STATIC_YOINK("_idt");
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts process after printing a backtrace.
|
* Aborts process after printing a backtrace.
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,9 +16,18 @@
|
||||||
#define IS2POW(X) (!((X) & ((X)-1)))
|
#define IS2POW(X) (!((X) & ((X)-1)))
|
||||||
#define ROUNDUP(X, K) (((X) + (K)-1) & -(K))
|
#define ROUNDUP(X, K) (((X) + (K)-1) & -(K))
|
||||||
#define ROUNDDOWN(X, K) ((X) & -(K))
|
#define ROUNDDOWN(X, K) ((X) & -(K))
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
#define ABS(X) ((X) >= 0 ? (X) : -(X))
|
#define ABS(X) ((X) >= 0 ? (X) : -(X))
|
||||||
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
|
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
|
||||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||||
|
#else
|
||||||
|
// The GNU assembler does not grok the ?: ternary operator; furthermore,
|
||||||
|
// boolean expressions yield -1 and 0 for "true" and "false", not 1 and 0.
|
||||||
|
#define __MAPBOOL(P) (!!(P) / (!!(P) + !(P)))
|
||||||
|
#define __IFELSE(P, X, Y) (__MAPBOOL(P) * (X) + __MAPBOOL(!(P)) * (Y))
|
||||||
|
#define MIN(X, Y) (__IFELSE((Y) > (X), (X), (Y)))
|
||||||
|
#define MAX(X, Y) (__IFELSE((Y) < (X), (X), (Y)))
|
||||||
|
#endif
|
||||||
#define PASTE(A, B) __PASTE(A, B)
|
#define PASTE(A, B) __PASTE(A, B)
|
||||||
#define STRINGIFY(A) __STRINGIFY(A)
|
#define STRINGIFY(A) __STRINGIFY(A)
|
||||||
#define EQUIVALENT(X, Y) (__builtin_constant_p((X) == (Y)) && ((X) == (Y)))
|
#define EQUIVALENT(X, Y) (__builtin_constant_p((X) == (Y)) && ((X) == (Y)))
|
||||||
|
|
|
@ -120,6 +120,7 @@
|
||||||
#define GDT_LEGACY_DATA 32
|
#define GDT_LEGACY_DATA 32
|
||||||
#define GDT_LONG_CODE 40
|
#define GDT_LONG_CODE 40
|
||||||
#define GDT_LONG_DATA 48
|
#define GDT_LONG_DATA 48
|
||||||
|
#define GDT_LONG_TSS 56
|
||||||
|
|
||||||
#define PIC1 0x20 /* IO base address for master PIC */
|
#define PIC1 0x20 /* IO base address for master PIC */
|
||||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
#define PIC2 0xA0 /* IO base address for slave PIC */
|
||||||
|
|
Loading…
Reference in a new issue