diff options
Diffstat (limited to 'arch/x86/machine/cpu_i.h')
-rw-r--r-- | arch/x86/machine/cpu_i.h | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/arch/x86/machine/cpu_i.h b/arch/x86/machine/cpu_i.h new file mode 100644 index 00000000..2c28573e --- /dev/null +++ b/arch/x86/machine/cpu_i.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef X86_CPU_I_H +#define X86_CPU_I_H + +/* + * EFLAGS register flags. + */ +#define CPU_EFL_ONE 0x00000002 /* Reserved, must be set */ +#define CPU_EFL_IF 0x00000200 + +/* + * GDT segment selectors. + * + * Keep in mind that, on amd64, the size of a GDT entry referred to + * by a selector depends on the descriptor type. + */ +#define CPU_GDT_SEL_NULL 0 +#define CPU_GDT_SEL_CODE 8 +#define CPU_GDT_SEL_DATA 16 +#define CPU_GDT_SEL_TSS 24 + +#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__ */ + +#ifndef __ASSEMBLER__ + +#include <stdalign.h> +#include <stdint.h> + +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; + +/* + * LDT or TSS system segment descriptor. + */ +struct cpu_sysseg_desc { + uint32_t word1; + uint32_t word2; +#ifdef __LP64__ + uint32_t word3; + uint32_t word4; +#endif /* __LP64__ */ +}; + +struct cpu_gdt { + alignas(CPU_L1_SIZE) char descs[CPU_GDT_SIZE]; +}; + +#define CPU_VENDOR_ID_SIZE 13 +#define CPU_MODEL_NAME_SIZE 49 + +/* + * CPU states. + * TODO Boolean. + */ +#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; // TODO Use a struct bitmap + unsigned int features2; + unsigned int features3; + unsigned int features4; + unsigned short phys_addr_width; + unsigned short virt_addr_width; + + struct cpu_gdt gdt; + + /* + * TSS segments, one set per CPU. + * + * One TSS at least is required per processor to provide the following : + * - stacks for double fault handlers, implemented with task switching + * on i386, interrupt stack tables on amd64 + * - stacks for each privilege level + * - I/O permission bitmaps + * + * See Intel 64 and IA-32 Architecture Software Developer's Manual, + * Volume 3 System Programming Guide : + * - 6.12.2 Interrupt tasks + * - 7.3 Task switching + */ + struct cpu_tss tss; +#ifndef __LP64__ + struct cpu_tss df_tss; +#endif /* __LP64__ */ + + volatile int state; // TODO Atomic accessors + void *boot_stack; + + alignas(CPU_DATA_ALIGN) char intr_stack[CPU_INTR_STACK_SIZE]; + alignas(CPU_DATA_ALIGN) char df_stack[CPU_INTR_STACK_SIZE]; +}; + +/* + * 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; + +/* + * Return the content of the EFLAGS register. + * + * Implies a compiler barrier. + * + * TODO Add cpu_flags_t type. + */ +static __always_inline unsigned long +cpu_get_eflags(void) +{ + unsigned long eflags; + + asm volatile("pushf\n" + "pop %0\n" + : "=r" (eflags) + : : "memory"); + + return eflags; +} + +#endif /* __ASSEMBLER__ */ + +#endif /* X86_CPU_I_H */ |