1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#pragma once 8 9#include <model/statedata.h> 10#include <arch/machine/cpu_registers.h> 11#include <arch/model/smp.h> 12#include <arch/machine.h> 13 14/* Address space control */ 15static inline paddr_t getCurrentPD(void) 16{ 17 return MODE_NODE_STATE(ia32KSCurrentPD); 18} 19 20static inline void setCurrentPD(paddr_t addr) 21{ 22 MODE_NODE_STATE(ia32KSCurrentPD) = addr; 23 write_cr3(addr); 24} 25 26static inline void setCurrentVSpaceRoot(paddr_t addr, word_t pcid) 27{ 28 /* pcid is not supported on ia32 and so we should always be passed zero */ 29 assert(pcid == 0); 30 setCurrentPD(addr); 31} 32 33static inline cr3_t getCurrentCR3(void) 34{ 35 /* on ia32 the PD is the full value of CR3, so we can just return that */ 36 return cr3_new(getCurrentPD()); 37} 38 39static inline void invalidateLocalTLBEntry(vptr_t vptr) 40{ 41 asm volatile("invlpg (%[vptr])" :: [vptr] "r"(vptr)); 42} 43 44/* Invalidates page structures cache */ 45static inline void invalidateLocalPageStructureCache(void) 46{ 47 /* invalidate an arbitrary line to invalidate the page structure cache */ 48 invalidateLocalTLBEntry(0); 49} 50 51static inline void invalidateLocalPageStructureCacheASID(paddr_t root, asid_t asid) 52{ 53 /* ignore asid */ 54 invalidateLocalPageStructureCache(); 55} 56 57static inline void invalidateLocalTLB(void) 58{ 59 /* rewrite the current page directory */ 60 write_cr3(MODE_NODE_STATE(ia32KSCurrentPD)); 61} 62 63static inline void invalidateLocalTranslationSingle(vptr_t vptr) 64{ 65 /* Just invalidate a single entry in the TLB */ 66 invalidateLocalTLBEntry(vptr); 67} 68 69static inline void invalidateLocalTranslationSingleASID(vptr_t vptr, asid_t asid) 70{ 71 /* no asid support in 32-bit, just invalidate TLB */ 72 invalidateLocalTLBEntry(vptr); 73} 74 75static inline void invalidateLocalTranslationAll(void) 76{ 77 invalidateLocalTLB(); 78 invalidateLocalPageStructureCache(); 79} 80 81static inline rdmsr_safe_result_t x86_rdmsr_safe(const uint32_t reg) 82{ 83 uint32_t low; 84 uint32_t high; 85 word_t returnto; 86 rdmsr_safe_result_t result; 87 asm volatile( 88 "movl $1f, (%[returnto_addr]) \n\ 89 rdmsr \n\ 90 1: \n\ 91 movl (%[returnto_addr]), %[returnto] \n\ 92 movl $0, (%[returnto_addr])" 93 : [returnto] "=&r"(returnto), 94 [high] "=&d"(high), 95 [low] "=&a"(low) 96 : [returnto_addr] "r"(&ARCH_NODE_STATE(x86KSGPExceptReturnTo)), 97 [reg] "c"(reg) 98 : "memory" 99 ); 100 result.success = returnto != 0; 101 result.value = ((uint64_t)high << 32) | (uint64_t)low; 102 return result; 103} 104 105/* GDT installation */ 106void ia32_install_gdt(gdt_idt_ptr_t *gdt_idt_ptr); 107 108/* IDT installation */ 109void ia32_install_idt(gdt_idt_ptr_t *gdt_idt_ptr); 110 111/* LDT installation */ 112void ia32_install_ldt(uint32_t ldt_sel); 113 114/* TSS installation */ 115void ia32_install_tss(uint32_t tss_sel); 116 117void ia32_load_fs(word_t selector); 118void ia32_load_gs(word_t selector); 119 120#if defined(CONFIG_FSGSBASE_GDT) || !defined(CONFIG_FSGSBASE_MSR) 121 122static inline void FORCE_INLINE x86_write_fs_base_impl(word_t base) 123{ 124 gdt_entry_gdt_data_ptr_set_base_low(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_FS], base & 0xFFFF); 125 gdt_entry_gdt_data_ptr_set_base_mid(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_FS], (base >> 16) & 0xFF); 126 gdt_entry_gdt_data_ptr_set_base_high(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_FS], (base >> 24) & 0xFF); 127 asm volatile( 128 "movw %0, %%ax\n" 129 "movw %%ax, %%fs\n" 130 : 131 : "i"(SEL_FS) 132 : "ax" 133 ); 134} 135 136static inline void FORCE_INLINE x86_write_gs_base_impl(word_t base) 137{ 138 gdt_entry_gdt_data_ptr_set_base_low(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_GS], base & 0xFFFF); 139 gdt_entry_gdt_data_ptr_set_base_mid(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_GS], (base >> 16) & 0xFF); 140 gdt_entry_gdt_data_ptr_set_base_high(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_GS], (base >> 24) & 0xFF); 141 asm volatile( 142 "movw %0, %%ax\n" 143 "movw %%ax, %%gs\n" 144 : 145 : "i"(SEL_GS) 146 : "ax" 147 ); 148} 149 150static inline word_t FORCE_INLINE x86_read_fs_base_impl(void) 151{ 152 word_t base = 0; 153 base &= gdt_entry_gdt_data_ptr_get_base_low(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_FS]) & 0xFFFF; 154 base &= (gdt_entry_gdt_data_ptr_get_base_mid(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_FS]) & 0xFF) << 16; 155 base &= (gdt_entry_gdt_data_ptr_get_base_high(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_FS]) & 0xFF) << 24; 156 return base; 157} 158 159static inline word_t FORCE_INLINE x86_read_gs_base_impl(void) 160{ 161 word_t base = 0; 162 base &= gdt_entry_gdt_data_ptr_get_base_low(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_GS]) & 0xFFFF; 163 base &= (gdt_entry_gdt_data_ptr_get_base_mid(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_GS]) & 0xFF) << 16; 164 base &= (gdt_entry_gdt_data_ptr_get_base_high(&x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt[GDT_GS]) & 0xFF) << 24; 165 return base; 166} 167 168#elif defined(CONFIG_FSGSBASE_MSR) 169 170static inline void x86_write_gs_base_impl(word_t base) 171{ 172 x86_wrmsr(IA32_GS_BASE_MSR, base); 173} 174 175static inline word_t x86_read_gs_base_impl(void) 176{ 177 return x86_rdmsr(IA32_GS_BASE_MSR); 178} 179 180#endif 181 182static inline void x86_set_tls_segment_base(word_t tls_base) 183{ 184 x86_write_gs_base(tls_base, SMP_TERNARY(getCurrentCPUIndex(), 0)); 185} 186 187static inline void init_syscall_msrs(void) 188{ 189 fail("syscall not supported on ia32"); 190} 191 192