blob: c51f76768659ec4345dd959fe8baf87d64fe8239 [file] [log] [blame]
Kevin O'Connorb9c6a962013-09-14 13:01:30 -04001// Basic x86 asm functions.
2#ifndef __X86_H
3#define __X86_H
4
5// CPU flag bitdefs
6#define F_CF (1<<0)
7#define F_ZF (1<<6)
8#define F_IF (1<<9)
9#define F_ID (1<<21)
10
11// CR0 flags
12#define CR0_PG (1<<31) // Paging
13#define CR0_CD (1<<30) // Cache disable
14#define CR0_NW (1<<29) // Not Write-through
15#define CR0_PE (1<<0) // Protection enable
16
17#ifndef __ASSEMBLY__
18
19#include "types.h" // u32
20
21static inline void irq_disable(void)
22{
23 asm volatile("cli": : :"memory");
24}
25
26static inline void irq_enable(void)
27{
28 asm volatile("sti": : :"memory");
29}
30
31static inline u32 save_flags(void)
32{
33 u32 flags;
34 asm volatile("pushfl ; popl %0" : "=rm" (flags));
35 return flags;
36}
37
38static inline void restore_flags(u32 flags)
39{
40 asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
41}
42
43static inline void cpu_relax(void)
44{
45 asm volatile("rep ; nop": : :"memory");
46}
47
48static inline void nop(void)
49{
50 asm volatile("nop");
51}
52
53static inline void hlt(void)
54{
55 asm volatile("hlt": : :"memory");
56}
57
58static inline void wbinvd(void)
59{
60 asm volatile("wbinvd": : :"memory");
61}
62
63#define CPUID_TSC (1 << 4)
64#define CPUID_MSR (1 << 5)
65#define CPUID_APIC (1 << 9)
66#define CPUID_MTRR (1 << 12)
67static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
68{
69 asm("cpuid"
70 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
71 : "0" (index));
72}
73
74static inline u32 getcr0(void) {
75 u32 cr0;
76 asm("movl %%cr0, %0" : "=r"(cr0));
77 return cr0;
78}
79static inline void setcr0(u32 cr0) {
80 asm("movl %0, %%cr0" : : "r"(cr0));
81}
82
83static inline u64 rdmsr(u32 index)
84{
85 u64 ret;
86 asm ("rdmsr" : "=A"(ret) : "c"(index));
87 return ret;
88}
89
90static inline void wrmsr(u32 index, u64 val)
91{
92 asm volatile ("wrmsr" : : "c"(index), "A"(val));
93}
94
95static inline u64 rdtscll(void)
96{
97 u64 val;
98 asm volatile("rdtsc" : "=A" (val));
99 return val;
100}
101
102static inline u32 __ffs(u32 word)
103{
104 asm("bsf %1,%0"
105 : "=r" (word)
106 : "rm" (word));
107 return word;
108}
109static inline u32 __fls(u32 word)
110{
111 asm("bsr %1,%0"
112 : "=r" (word)
113 : "rm" (word));
114 return word;
115}
116
117static inline u32 getesp(void) {
118 u32 esp;
119 asm("movl %%esp, %0" : "=rm"(esp));
120 return esp;
121}
122
Kevin O'Connor4ade5232013-09-18 21:41:48 -0400123static inline void outb(u8 value, u16 port) {
124 __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
125}
126static inline void outw(u16 value, u16 port) {
127 __asm__ __volatile__("outw %w0, %w1" : : "a"(value), "Nd"(port));
128}
129static inline void outl(u32 value, u16 port) {
130 __asm__ __volatile__("outl %0, %w1" : : "a"(value), "Nd"(port));
131}
132static inline u8 inb(u16 port) {
133 u8 value;
134 __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
135 return value;
136}
137static inline u16 inw(u16 port) {
138 u16 value;
139 __asm__ __volatile__("inw %w1, %w0" : "=a"(value) : "Nd"(port));
140 return value;
141}
142static inline u32 inl(u16 port) {
143 u32 value;
144 __asm__ __volatile__("inl %w1, %0" : "=a"(value) : "Nd"(port));
145 return value;
146}
147
148static inline void insb(u16 port, u8 *data, u32 count) {
149 asm volatile("rep insb (%%dx), %%es:(%%edi)"
150 : "+c"(count), "+D"(data) : "d"(port) : "memory");
151}
152static inline void insw(u16 port, u16 *data, u32 count) {
153 asm volatile("rep insw (%%dx), %%es:(%%edi)"
154 : "+c"(count), "+D"(data) : "d"(port) : "memory");
155}
156static inline void insl(u16 port, u32 *data, u32 count) {
157 asm volatile("rep insl (%%dx), %%es:(%%edi)"
158 : "+c"(count), "+D"(data) : "d"(port) : "memory");
159}
160// XXX - outs not limited to es segment
161static inline void outsb(u16 port, u8 *data, u32 count) {
162 asm volatile("rep outsb %%es:(%%esi), (%%dx)"
163 : "+c"(count), "+S"(data) : "d"(port) : "memory");
164}
165static inline void outsw(u16 port, u16 *data, u32 count) {
166 asm volatile("rep outsw %%es:(%%esi), (%%dx)"
167 : "+c"(count), "+S"(data) : "d"(port) : "memory");
168}
169static inline void outsl(u16 port, u32 *data, u32 count) {
170 asm volatile("rep outsl %%es:(%%esi), (%%dx)"
171 : "+c"(count), "+S"(data) : "d"(port) : "memory");
172}
173
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400174static inline void writel(void *addr, u32 val) {
175 *(volatile u32 *)addr = val;
176}
177static inline void writew(void *addr, u16 val) {
178 *(volatile u16 *)addr = val;
179}
180static inline void writeb(void *addr, u8 val) {
181 *(volatile u8 *)addr = val;
182}
183static inline u32 readl(const void *addr) {
184 return *(volatile const u32 *)addr;
185}
186static inline u16 readw(const void *addr) {
187 return *(volatile const u16 *)addr;
188}
189static inline u8 readb(const void *addr) {
190 return *(volatile const u8 *)addr;
191}
192
193// GDT bits
194#define GDT_CODE (0x9bULL << 40) // Code segment - P,R,A bits also set
195#define GDT_DATA (0x93ULL << 40) // Data segment - W,A bits also set
196#define GDT_B (0x1ULL << 54) // Big flag
197#define GDT_G (0x1ULL << 55) // Granularity flag
198// GDT bits for segment base
199#define GDT_BASE(v) ((((u64)(v) & 0xff000000) << 32) \
200 | (((u64)(v) & 0x00ffffff) << 16))
201// GDT bits for segment limit (0-1Meg)
202#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32) \
203 | (((u64)(v) & 0x0000ffff) << 0))
204// GDT bits for segment limit (0-4Gig in 4K chunks)
205#define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12))
206
207struct descloc_s {
208 u16 length;
209 u32 addr;
210} PACKED;
211
212
213// x86.c
214void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
215
216
217#endif // !__ASSEMBLY__
218
219#endif // x86.h