| /* Copyright (c) 2016 Google Inc. |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. |
| * |
| * Getters and setters for FS Base and GS base. */ |
| |
| #pragma once |
| |
| #include <cpu_feat.h> |
| #include <arch/x86.h> |
| |
| static inline uintptr_t read_fsbase(void) |
| { |
| uintptr_t base; |
| |
| if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) |
| return read_msr(MSR_FS_BASE); |
| asm volatile ("rdfsbase %0" : "=r"(base)); |
| return base; |
| } |
| |
| static inline void write_fsbase(uintptr_t base) |
| { |
| if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) { |
| write_msr(MSR_FS_BASE, base); |
| return; |
| } |
| asm volatile ("wrfsbase %0" : : "r"(base)); |
| } |
| |
| static inline uintptr_t read_gsbase(void) |
| { |
| uintptr_t base; |
| |
| if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) |
| return read_msr(MSR_GS_BASE); |
| asm volatile ("rdgsbase %0" : "=r"(base)); |
| return base; |
| } |
| |
| static inline void write_gsbase(uintptr_t base) |
| { |
| if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) { |
| write_msr(MSR_GS_BASE, base); |
| return; |
| } |
| asm volatile ("wrgsbase %0" : : "r"(base)); |
| } |
| |
| /* If we have fast FS/GS access, we can use swapgs to quickly access |
| * kern_gsbase. */ |
| static inline uintptr_t read_kern_gsbase(void) |
| { |
| uintptr_t base; |
| int8_t irq_state = 0; |
| |
| if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) |
| return read_msr(MSR_KERNEL_GS_BASE); |
| disable_irqsave(&irq_state); |
| swap_gs(); |
| base = read_gsbase(); |
| swap_gs(); |
| enable_irqsave(&irq_state); |
| return base; |
| } |
| |
| static inline void write_kern_gsbase(uintptr_t base) |
| { |
| int8_t irq_state = 0; |
| |
| if (!cpu_has_feat(CPU_FEAT_X86_FSGSBASE)) { |
| write_msr(MSR_KERNEL_GS_BASE, base); |
| return; |
| } |
| disable_irqsave(&irq_state); |
| swap_gs(); |
| write_gsbase(base); |
| swap_gs(); |
| enable_irqsave(&irq_state); |
| } |