1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#ifndef __MODE_MACHINE_H
12#define __MODE_MACHINE_H
13
14#include <model/statedata.h>
15#include <arch/machine/cpu_registers.h>
16#include <arch/model/smp.h>
17
18/* Address space control */
19static inline paddr_t getCurrentPD(void)
20{
21    return MODE_NODE_STATE(ia32KSCurrentPD);
22}
23
24static inline void setCurrentPD(paddr_t addr)
25{
26    MODE_NODE_STATE(ia32KSCurrentPD) = addr;
27    write_cr3(addr);
28}
29
30static inline void setCurrentVSpaceRoot(paddr_t addr, word_t pcid)
31{
32    /* pcid is not supported on ia32 and so we should always be passed zero */
33    assert(pcid == 0);
34    setCurrentPD(addr);
35}
36
37static inline cr3_t getCurrentCR3(void)
38{
39    /* on ia32 the PD is the full value of CR3, so we can just return that */
40    return cr3_new(getCurrentPD());
41}
42
43static inline void invalidateLocalTLBEntry(vptr_t vptr)
44{
45    asm volatile("invlpg (%[vptr])" :: [vptr] "r"(vptr));
46}
47
48/* Invalidates page structures cache */
49static inline void invalidateLocalPageStructureCache(void)
50{
51    /* invalidate an arbitrary line to invalidate the page structure cache */
52    invalidateLocalTLBEntry(0);
53}
54
55static inline void invalidateLocalPageStructureCacheASID(paddr_t root, asid_t asid)
56{
57    /* ignore asid */
58    invalidateLocalPageStructureCache();
59}
60
61static inline void invalidateLocalTLB(void)
62{
63    /* rewrite the current page directory */
64    write_cr3(MODE_NODE_STATE(ia32KSCurrentPD));
65}
66
67static inline void invalidateLocalTranslationSingle(vptr_t vptr)
68{
69    /* Just invalidate a single entry in the TLB */
70    invalidateLocalTLBEntry(vptr);
71}
72
73static inline void invalidateLocalTranslationSingleASID(vptr_t vptr, asid_t asid)
74{
75    /* no asid support in 32-bit, just invalidate TLB */
76    invalidateLocalTLBEntry(vptr);
77}
78
79static inline void invalidateLocalTranslationAll(void)
80{
81    invalidateLocalTLB();
82    invalidateLocalPageStructureCache();
83}
84
85static inline rdmsr_safe_result_t x86_rdmsr_safe(const uint32_t reg)
86{
87    uint32_t low;
88    uint32_t high;
89    word_t returnto;
90    rdmsr_safe_result_t result;
91    asm volatile(
92        "movl $1f, (%[returnto_addr]) \n\
93         rdmsr \n\
94         1: \n\
95         movl (%[returnto_addr]), %[returnto] \n\
96         movl $0, (%[returnto_addr])"
97        : [returnto] "=&r" (returnto),
98        [high] "=&d" (high),
99        [low] "=&a" (low)
100        : [returnto_addr] "r" (&ARCH_NODE_STATE(x86KSGPExceptReturnTo)),
101        [reg] "c" (reg)
102        : "memory"
103    );
104    result.success = returnto != 0;
105    result.value = ((uint64_t)high << 32) | (uint64_t)low;
106    return result;
107}
108
109/* GDT installation */
110void ia32_install_gdt(gdt_idt_ptr_t* gdt_idt_ptr);
111
112/* IDT installation */
113void ia32_install_idt(gdt_idt_ptr_t* gdt_idt_ptr);
114
115/* LDT installation */
116void ia32_install_ldt(uint32_t ldt_sel);
117
118/* TSS installation */
119void ia32_install_tss(uint32_t tss_sel);
120
121#if defined(CONFIG_FSGSBASE_GDT) || !defined(CONFIG_FSGSBASE_MSR)
122
123static inline void FORCE_INLINE x86_write_fs_base_impl(word_t base)
124{
125    gdt_entry_gdt_data_ptr_set_base_low(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt + GDT_IPCBUF, base);
126    gdt_entry_gdt_data_ptr_set_base_mid(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt + GDT_IPCBUF,  (base >> 16) & 0xFF);
127    gdt_entry_gdt_data_ptr_set_base_high(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt + GDT_IPCBUF, (base >> 24) & 0xFF);
128}
129
130static inline void FORCE_INLINE x86_write_gs_base_impl(word_t base)
131{
132    gdt_entry_gdt_data_ptr_set_base_low(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt + GDT_TLS, base);
133    gdt_entry_gdt_data_ptr_set_base_mid(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt + GDT_TLS,  (base >> 16) & 0xFF);
134    gdt_entry_gdt_data_ptr_set_base_high(x86KSGlobalState[CURRENT_CPU_INDEX()].x86KSgdt + GDT_TLS, (base >> 24) & 0xFF);
135}
136
137#endif
138
139void ia32_load_fs(word_t selector);
140void ia32_load_gs(word_t selector);
141
142static inline void init_syscall_msrs(void)
143{
144    fail("syscall not supported on ia32");
145}
146
147#endif
148