/* * cpu.h * * Copyright (C) 2016 Aleksandar Andrejevic * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef _CPU_H_ #define _CPU_H_ #include #include #define CPU_CONTROL_FLAG_PE (1 << 0) #define CPU_CONTROL_FLAG_MP (1 << 1) #define CPU_CONTROL_FLAG_EM (1 << 2) #define CPU_CONTROL_FLAG_TS (1 << 3) #define CPU_CONTROL_FLAG_ET (1 << 4) #define CPU_CONTROL_FLAG_NE (1 << 5) #define CPU_CONTROL_FLAG_WP (1 << 16) #define CPU_CONTROL_FLAG_AM (1 << 18) #define CPU_CONTROL_FLAG_NW (1 << 29) #define CPU_CONTROL_FLAG_CD (1 << 30) #define CPU_CONTROL_FLAG_PG (1 << 31) #define CPU_FEATURE_FLAG_VME (1 << 0) #define CPU_FEATURE_FLAG_PVI (1 << 1) #define CPU_FEATURE_FLAG_TSD (1 << 2) #define CPU_FEATURE_FLAG_DE (1 << 3) #define CPU_FEATURE_FLAG_PSE (1 << 4) #define CPU_FEATURE_FLAG_PAE (1 << 5) #define CPU_FEATURE_FLAG_MCE (1 << 6) #define CPU_FEATURE_FLAG_PGE (1 << 7) #define CPU_FEATURE_FLAG_PCE (1 << 8) #define CPU_FEATURE_FLAG_OSXFSR (1 << 9) #define CPU_FEATURE_FLAG_OSXMMEXCPT (1 << 10) #define CPU_FEATURE_FLAG_UMIP (1 << 11) #define CPU_FEATURE_FLAG_LA57 (1 << 12) #define CPU_FEATURE_FLAG_VMXE (1 << 13) #define CPU_FEATURE_FLAG_SMXE (1 << 14) #define CPU_FEATURE_FLAG_FSGSBASE (1 << 16) #define CPU_FEATURE_FLAG_PCIDE (1 << 17) #define CPU_FEATURE_FLAG_OSXSAVE (1 << 18) #define CPU_FEATURE_FLAG_SMEP (1 << 20) #define CPU_FEATURE_FLAG_SMAP (1 << 21) #define CPU_FEATURE_FLAG_PKE (1 << 22) enum { FPU_NOT_PRESENT = 0, FPU_LEGACY, FPU_XFSR, }; typedef word_t port_t; #define IO_PORT_FUNCTIONS(type, prefix) \ static inline type##_t cpu_read_port_##type(port_t port) \ { \ type##_t value; \ __asm__ volatile ("in %1, %0\n" : "=a"(value) : "Nd"(port)); \ return value; \ } \ \ static inline void cpu_write_port_##type(port_t port, type##_t value) \ { \ __asm__ volatile ("out %0, %1\n" :: "a"(value), "Nd"(port)); \ } \ \ static inline void cpu_read_port_buffer_##type(port_t port, type##_t *buffer, size_t size) \ { \ __asm__ volatile("cld\n" \ "rep; ins" prefix "\n" \ :"+D"(buffer), "+c"(size) \ : "d"(port) \ : "cc"); \ } \ \ static inline void cpu_write_port_buffer_##type(port_t port, const type##_t *buffer, size_t size) \ { \ __asm__ volatile("cld\n" \ "rep; outs " prefix "\n" \ : "+S"(buffer), "+c"(size) \ : "d"(port) \ : "cc"); \ } IO_PORT_FUNCTIONS(byte, "b") IO_PORT_FUNCTIONS(word, "w") IO_PORT_FUNCTIONS(dword, "l") static inline uintptr_t cpu_read_master_control_register(void) { uintptr_t value; __asm__ volatile ("movl %%cr0, %0" : "=r"((dword_t)value) /* output */ : /* input */ : /* clobber */); return value; } static inline void cpu_write_master_control_register(uintptr_t value) { __asm__ volatile ("movl %0, %%cr0" : /* output */ : "r"((dword_t)value) /* input */ : /* clobber */); } static inline uintptr_t cpu_read_faulting_address(void) { uintptr_t value; __asm__ volatile ("movl %%cr2, %0" : "=r"((dword_t)value) /* output */ : /* input */ : /* clobber */); return value; } static inline uintptr_t cpu_read_page_table_register(void) { uintptr_t value; __asm__ volatile ("movl %%cr3, %0" : "=r"((dword_t)value) /* output */ : /* input */ : /* clobber */); return value; } static inline void cpu_write_page_table_register(uintptr_t value) { __asm__ volatile ("movl %0, %%cr3" : /* output */ : "r"((dword_t)value) /* input */ : /* clobber */); } static inline uintptr_t cpu_read_feature_register(void) { uintptr_t value; __asm__ volatile ("movl %%cr4, %0" : "=r"((dword_t)value) /* output */ : /* input */ : /* clobber */); return value; } static inline void cpu_write_feature_register(uintptr_t value) { __asm__ volatile ("movl %0, %%cr4" : /* output */ : "r"((dword_t)value) /* input */ : /* clobber */); } static inline bool_t cpu_enable_interrupts(void) { dword_t flags; __asm__ volatile ("pushf\n" "sti\n" "pop %0" : "=g"(flags) /* output */ : /* input */ : /* clobber */); return !!(flags & CPU_STATUS_FLAG_IF); } static inline bool_t cpu_disable_interrupts(void) { dword_t flags; __asm__ volatile ("pushf\n" "cli\n" "pop %0" : "=g"(flags) /* output */ : /* input */ : /* clobber */); return !!(flags & CPU_STATUS_FLAG_IF); } static inline void cpu_set_interrupt_table(void *base, word_t size) { struct { word_t length; void *base; } __attribute__((__packed__)) idtr = { size - 1, base }; __asm__ volatile ("lidt %0" : /* output */ : "m"(idtr) /* input */ : /* clobber */); } static inline void cpu_invalidate_tlb(void *address) { __asm__ volatile ("invlpg (%0)" : /* output */ : "r"(address) /* input */ : "memory" /* clobber */); } static inline void cpu_halt(void) { __asm__ volatile ("hlt"); } extern int cpu_fpu_present; extern byte_t cpu_max_physical_bits; static inline void cpu_save_fpu_state(void *state) { switch (cpu_fpu_present) { case FPU_LEGACY: asm volatile ("fsave %0" : "=m"(*(byte_t*)state) /* output */ : /* input */ : /* clobber */); break; case FPU_XFSR: asm volatile ("fxsave %0" : "=m"(*(byte_t*)state) /* output */ : /* input */ : /* clobber */); break; } } static inline void cpu_restore_fpu_state(void *state) { switch (cpu_fpu_present) { case FPU_LEGACY: asm volatile ("frstor %0" : /* output */ : "m"(*(byte_t*)state) /* input */ : /* clobber */); break; case FPU_XFSR: asm volatile ("fxrstor %0" : /* output */ : "m"(*(byte_t*)state) /* input */ : /* clobber */); break; } } void cpu_init(void); #endif