diff options
Diffstat (limited to 'arch/x86/machine/cpu.h')
-rw-r--r-- | arch/x86/machine/cpu.h | 373 |
1 files changed, 146 insertions, 227 deletions
diff --git a/arch/x86/machine/cpu.h b/arch/x86/machine/cpu.h index 0c4e6e1d..78857cdc 100644 --- a/arch/x86/machine/cpu.h +++ b/arch/x86/machine/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Richard Braun. + * Copyright (c) 2010-2018 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,60 @@ #include <limits.h> +#include <machine/page.h> + +/* + * Architecture defined exception vectors. + */ +#define CPU_EXC_DE 0 /* Divide Error */ +#define CPU_EXC_DB 1 /* Debug */ +#define CPU_EXC_NMI 2 /* NMI Interrupt */ +#define CPU_EXC_BP 3 /* Breakpoint */ +#define CPU_EXC_OF 4 /* Overflow */ +#define CPU_EXC_BR 5 /* BOUND Range Exceeded */ +#define CPU_EXC_UD 6 /* Undefined Opcode */ +#define CPU_EXC_NM 7 /* No Math Coprocessor */ +#define CPU_EXC_DF 8 /* Double Fault */ +#define CPU_EXC_TS 10 /* Invalid TSS */ +#define CPU_EXC_NP 11 /* Segment Not Present */ +#define CPU_EXC_SS 12 /* Stack-Segment Fault */ +#define CPU_EXC_GP 13 /* General Protection */ +#define CPU_EXC_PF 14 /* Page Fault */ +#define CPU_EXC_MF 16 /* Math Fault */ +#define CPU_EXC_AC 17 /* Alignment Check */ +#define CPU_EXC_MC 18 /* Machine Check */ +#define CPU_EXC_XM 19 /* SIMD Floating-Point Exception */ + +/* + * Exception vectors used for external interrupts. + */ +#define CPU_EXC_INTR_FIRST 32 +#define CPU_EXC_INTR_LAST 223 + +/* + * System defined exception vectors. + * + * The local APIC assigns one priority every 16 vectors. + */ +#define CPU_EXC_XCALL 238 +#define CPU_EXC_THREAD_SCHEDULE 239 +#define CPU_EXC_HALT 240 +#define CPU_EXC_LAPIC_PMC_OF 252 +#define CPU_EXC_LAPIC_TIMER 253 +#define CPU_EXC_LAPIC_ERROR 254 +#define CPU_EXC_LAPIC_SPURIOUS 255 + +#define CPU_NR_EXC_VECTORS 256 + +#define CPU_INTR_STACK_SIZE PAGE_SIZE + +#define CPU_VENDOR_STR_SIZE 13 +#define CPU_MODEL_NAME_SIZE 49 + +#define CPU_VENDOR_UNKNOWN 0 +#define CPU_VENDOR_INTEL 1 +#define CPU_VENDOR_AMD 2 + /* * L1 cache line size. * @@ -49,80 +103,57 @@ /* * Processor privilege levels. */ -#define CPU_PL_KERNEL 0 -#define CPU_PL_USER 3 +#define CPU_PL_KERNEL 0 +#define CPU_PL_USER 3 /* * Control register 0 flags. */ -#define CPU_CR0_PE 0x00000001 -#define CPU_CR0_MP 0x00000002 -#define CPU_CR0_TS 0x00000008 -#define CPU_CR0_ET 0x00000010 -#define CPU_CR0_NE 0x00000020 -#define CPU_CR0_WP 0x00010000 -#define CPU_CR0_AM 0x00040000 -#define CPU_CR0_PG 0x80000000 +#define CPU_CR0_PE 0x00000001 +#define CPU_CR0_MP 0x00000002 +#define CPU_CR0_TS 0x00000008 +#define CPU_CR0_ET 0x00000010 +#define CPU_CR0_NE 0x00000020 +#define CPU_CR0_WP 0x00010000 +#define CPU_CR0_AM 0x00040000 +#define CPU_CR0_PG 0x80000000 /* * Control register 4 flags. */ -#define CPU_CR4_PSE 0x00000010 -#define CPU_CR4_PAE 0x00000020 -#define CPU_CR4_PGE 0x00000080 - -/* - * EFLAGS register flags. - */ -#define CPU_EFL_ONE 0x00000002 /* Reserved, must be one */ -#define CPU_EFL_IF 0x00000200 +#define CPU_CR4_PSE 0x00000010 +#define CPU_CR4_PAE 0x00000020 +#define CPU_CR4_PGE 0x00000080 /* * Model specific registers. */ -#define CPU_MSR_EFER 0xc0000080 -#define CPU_MSR_FSBASE 0xc0000100 -#define CPU_MSR_GSBASE 0xc0000101 +#define CPU_MSR_EFER 0xc0000080 +#define CPU_MSR_FSBASE 0xc0000100 +#define CPU_MSR_GSBASE 0xc0000101 /* * EFER MSR flags. */ -#define CPU_EFER_LME 0x00000100 +#define CPU_EFER_LME 0x00000100 /* * Feature2 flags. * * TODO Better names. */ -#define CPU_FEATURE2_FPU 0x00000001 -#define CPU_FEATURE2_PSE 0x00000008 -#define CPU_FEATURE2_PAE 0x00000040 -#define CPU_FEATURE2_MSR 0x00000020 -#define CPU_FEATURE2_CX8 0x00000100 -#define CPU_FEATURE2_APIC 0x00000200 -#define CPU_FEATURE2_PGE 0x00002000 - -#define CPU_FEATURE4_1GP 0x04000000 -#define CPU_FEATURE4_LM 0x20000000 - -/* - * GDT segment selectors. - */ -#define CPU_GDT_SEL_NULL 0 -#define CPU_GDT_SEL_CODE 8 -#define CPU_GDT_SEL_DATA 16 -#define CPU_GDT_SEL_TSS 24 +#define CPU_FEATURE2_FPU 0x00000001 +#define CPU_FEATURE2_PSE 0x00000008 +#define CPU_FEATURE2_PAE 0x00000040 +#define CPU_FEATURE2_MSR 0x00000020 +#define CPU_FEATURE2_CX8 0x00000100 +#define CPU_FEATURE2_APIC 0x00000200 +#define CPU_FEATURE2_PGE 0x00002000 -#ifdef __LP64__ -#define CPU_GDT_SIZE 40 -#else /* __LP64__ */ -#define CPU_GDT_SEL_DF_TSS 32 -#define CPU_GDT_SEL_PERCPU 40 -#define CPU_GDT_SEL_TLS 48 -#define CPU_GDT_SIZE 56 -#endif /* __LP64__ */ +#define CPU_FEATURE4_1GP 0x04000000 +#define CPU_FEATURE4_LM 0x20000000 -#define CPU_IDT_SIZE 256 +#include <machine/cpu_i.h> #ifndef __ASSEMBLER__ @@ -137,137 +168,65 @@ #include <machine/pit.h> #include <machine/ssp.h> +#define CPU_INTR_TABLE_SIZE (CPU_EXC_INTR_LAST - CPU_EXC_INTR_FIRST) + /* * Gate/segment descriptor bits and masks. */ -#define CPU_DESC_TYPE_DATA 0x00000200 -#define CPU_DESC_TYPE_CODE 0x00000a00 -#define CPU_DESC_TYPE_TSS 0x00000900 -#define CPU_DESC_TYPE_GATE_INTR 0x00000e00 -#define CPU_DESC_TYPE_GATE_TASK 0x00000500 -#define CPU_DESC_S 0x00001000 -#define CPU_DESC_PRESENT 0x00008000 -#define CPU_DESC_LONG 0x00200000 -#define CPU_DESC_DB 0x00400000 -#define CPU_DESC_GRAN_4KB 0x00800000 - -#define CPU_DESC_GATE_OFFSET_LOW_MASK 0x0000ffff -#define CPU_DESC_GATE_OFFSET_HIGH_MASK 0xffff0000 -#define CPU_DESC_SEG_IST_MASK 0x00000007 -#define CPU_DESC_SEG_BASE_LOW_MASK 0x0000ffff -#define CPU_DESC_SEG_BASE_MID_MASK 0x00ff0000 -#define CPU_DESC_SEG_BASE_HIGH_MASK 0xff000000 -#define CPU_DESC_SEG_LIMIT_LOW_MASK 0x0000ffff -#define CPU_DESC_SEG_LIMIT_HIGH_MASK 0x000f0000 +#define CPU_DESC_TYPE_DATA 0x00000200 +#define CPU_DESC_TYPE_CODE 0x00000a00 +#define CPU_DESC_TYPE_TSS 0x00000900 +#define CPU_DESC_TYPE_GATE_INTR 0x00000e00 +#define CPU_DESC_TYPE_GATE_TASK 0x00000500 +#define CPU_DESC_S 0x00001000 +#define CPU_DESC_PRESENT 0x00008000 +#define CPU_DESC_LONG 0x00200000 +#define CPU_DESC_DB 0x00400000 +#define CPU_DESC_GRAN_4KB 0x00800000 -/* - * Code or data segment descriptor. - */ -struct cpu_seg_desc { - uint32_t low; - uint32_t high; -}; +#define CPU_DESC_GATE_OFFSET_LOW_MASK 0x0000ffff +#define CPU_DESC_GATE_OFFSET_HIGH_MASK 0xffff0000 +#define CPU_DESC_SEG_IST_MASK 0x00000007 +#define CPU_DESC_SEG_BASE_LOW_MASK 0x0000ffff +#define CPU_DESC_SEG_BASE_MID_MASK 0x00ff0000 +#define CPU_DESC_SEG_BASE_HIGH_MASK 0xff000000 +#define CPU_DESC_SEG_LIMIT_LOW_MASK 0x0000ffff +#define CPU_DESC_SEG_LIMIT_HIGH_MASK 0x000f0000 /* - * Forward declaration. - */ -struct trap_frame; - -/* - * IST indexes (0 is reserved). - */ -#define CPU_TSS_IST_DF 1 - -struct cpu_tss { -#ifdef __LP64__ - uint32_t reserved0; - uint64_t rsp0; - uint64_t rsp1; - uint64_t rsp2; - uint64_t ist[8]; - uint64_t reserved1; - uint16_t reserved2; -#else /* __LP64__ */ - uint32_t link; - uint32_t esp0; - uint32_t ss0; - uint32_t esp1; - uint32_t ss1; - uint32_t esp2; - uint32_t ss2; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t es; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t fs; - uint32_t gs; - uint32_t ldt; - uint16_t trap_bit; -#endif /* __LP64__ */ - uint16_t iobp_base; -} __packed; - -#define CPU_VENDOR_STR_SIZE 13 -#define CPU_MODEL_NAME_SIZE 49 - -#define CPU_VENDOR_UNKNOWN 0 -#define CPU_VENDOR_INTEL 1 -#define CPU_VENDOR_AMD 2 + * Type for interrupt handler functions. + */ +typedef void (*cpu_intr_handler_fn_t)(unsigned int vector); /* - * CPU states. - */ -#define CPU_STATE_OFF 0 -#define CPU_STATE_ON 1 - -struct cpu { - unsigned int id; - unsigned int apic_id; - char vendor_str[CPU_VENDOR_STR_SIZE]; - char model_name[CPU_MODEL_NAME_SIZE]; - unsigned int cpuid_max_basic; - unsigned int cpuid_max_extended; - unsigned int vendor_id; - unsigned int type; - unsigned int family; - unsigned int model; - unsigned int stepping; - unsigned int clflush_size; - unsigned int initial_apic_id; - unsigned int features1; - unsigned int features2; - unsigned int features3; - unsigned int features4; - unsigned short phys_addr_width; - unsigned short virt_addr_width; - alignas(8) char gdt[CPU_GDT_SIZE]; - struct cpu_tss tss; -#ifndef __LP64__ - struct cpu_tss double_fault_tss; -#endif /* __LP64__ */ - volatile int state; - void *boot_stack; - void *double_fault_stack; -}; - + * TLS segment, as expected by the compiler. + * + * TLS isn't actually used inside the kernel. The current purpose of this + * segment is to implement stack protection. + * + * This is a public structure, made available to the boot module so that + * C code that runs early correctly works when built with stack protection. + */ struct cpu_tls_seg { uintptr_t unused[SSP_WORD_TLS_OFFSET]; uintptr_t ssp_guard_word; }; /* + * Code or data segment descriptor. + * + * See Intel 64 and IA-32 Architecture Software Developer's Manual, + * Volume 3 System Programming Guide, 3.4.5 Segment Descriptors. + */ +struct cpu_seg_desc { + uint32_t low; + uint32_t high; +}; + +/* * Macro to create functions that read/write control registers. + * + * TODO Break down. */ #define CPU_DECL_GETSET_CR(name) \ static __always_inline unsigned long \ @@ -300,24 +259,6 @@ CPU_DECL_GETSET_CR(cr3) CPU_DECL_GETSET_CR(cr4) /* - * Return the content of the EFLAGS register. - * - * Implies a compiler barrier. - */ -static __always_inline unsigned long -cpu_get_eflags(void) -{ - unsigned long eflags; - - asm volatile("pushf\n" - "pop %0\n" - : "=r" (eflags) - : : "memory"); - - return eflags; -} - -/* * Enable local interrupts. * * Implies a compiler barrier. @@ -428,17 +369,7 @@ cpu_halt(void) */ void cpu_halt_broadcast(void); -/* - * Interrupt handler for inter-processor halt requests. - */ -void cpu_halt_intr(struct trap_frame *frame); - -/* - * This percpu variable contains the address of the percpu area for the local - * processor. This is normally the same value stored in the percpu module, but - * it can be directly accessed through a segment register. - */ -extern void *cpu_local_area; +/* Generic percpu accessors */ #define cpu_local_ptr(var) \ MACRO_BEGIN \ @@ -453,7 +384,7 @@ MACRO_END #define cpu_local_var(var) (*cpu_local_ptr(var)) -/* Interrupt-safe percpu accessors for basic types */ +/* Generic interrupt-safe percpu accessors */ #define cpu_local_assign(var, val) \ asm("mov %0, %%fs:%1" \ @@ -523,6 +454,7 @@ cpu_has_global_pages(void) * pages were previously disabled. * * Implies a full memory barrier. + * TODO Update barrier description. */ static __always_inline void cpu_enable_global_pages(void) @@ -533,8 +465,7 @@ cpu_enable_global_pages(void) /* * CPUID instruction wrapper. * - * The CPUID instruction is a serializing instruction, implying a full - * memory barrier. + * The CPUID instruction is a serializing instruction. */ static __always_inline void cpu_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, @@ -581,19 +512,11 @@ cpu_set_msr64(uint32_t msr, uint64_t value) cpu_set_msr(msr, high, low); } -static __always_inline uint64_t -cpu_get_tsc(void) -{ - uint32_t high, low; - - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - return ((uint64_t)high << 32) | low; -} - /* * Flush non-global TLB entries. * * Implies a full memory barrier. + * TODO Update barrier description. */ static __always_inline void cpu_tlb_flush(void) @@ -605,6 +528,7 @@ cpu_tlb_flush(void) * Flush all TLB entries, including global ones. * * Implies a full memory barrier. + * TODO Update barrier description. */ static __always_inline void cpu_tlb_flush_all(void) @@ -631,6 +555,7 @@ cpu_tlb_flush_all(void) * Flush a single page table entry in the TLB. * * Implies a full memory barrier. + * TODO Update barrier description. */ static __always_inline void cpu_tlb_flush_va(unsigned long va) @@ -678,22 +603,14 @@ void cpu_delay(unsigned long usecs); void * cpu_get_boot_stack(void); /* - * Install an interrupt handler in the IDT. - * - * These functions may be called before the cpu module is initialized. - */ -void cpu_idt_set_gate(unsigned int vector, void (*isr)(void)); -void cpu_idt_set_double_fault(void (*isr)(void)); - -/* * Log processor information. */ void cpu_log_info(const struct cpu *cpu); /* - * Register the presence of a local APIC. + * Register a local APIC. */ -void cpu_mp_register_lapic(unsigned int apic_id, int is_bsp); +void cpu_mp_register_lapic(unsigned int apic_id, bool is_bsp); /* * Start application processors. @@ -724,27 +641,29 @@ cpu_apic_id(unsigned int cpu) static inline void cpu_send_xcall(unsigned int cpu) { - lapic_ipi_send(cpu_apic_id(cpu), TRAP_XCALL); + lapic_ipi_send(cpu_apic_id(cpu), CPU_EXC_XCALL); } /* - * Interrupt handler for cross-calls. - */ -void cpu_xcall_intr(struct trap_frame *frame); - -/* * Send a scheduling interrupt to a remote processor. */ static inline void cpu_send_thread_schedule(unsigned int cpu) { - lapic_ipi_send(cpu_apic_id(cpu), TRAP_THREAD_SCHEDULE); + lapic_ipi_send(cpu_apic_id(cpu), CPU_EXC_THREAD_SCHEDULE); } /* - * Interrupt handler for scheduling requests. + * Register an interrupt handler. + * + * This function is only available during system initialization, before the + * scheduler is started. It is meant for architectural interrupts, including + * interrupt controllers, and not directly for drivers, which should use + * the machine-independent intr module instead. + * + * Registration is system-wide. */ -void cpu_thread_schedule_intr(struct trap_frame *frame); +void cpu_register_intr(unsigned int vector, cpu_intr_handler_fn_t fn); /* * This init operation provides : |