blob: 53378e9ed55de67ee82c0cdbf131d9eca7cfc4cc [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
Kevin O'Connor341f8d92014-10-11 13:16:12 -040017// PORT_A20 bitdefs
18#define PORT_A20 0x0092
19#define A20_ENABLE_BIT 0x02
20
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040021#ifndef __ASSEMBLY__
22
23#include "types.h" // u32
24
25static inline void irq_disable(void)
26{
27 asm volatile("cli": : :"memory");
28}
29
30static inline void irq_enable(void)
31{
32 asm volatile("sti": : :"memory");
33}
34
35static inline u32 save_flags(void)
36{
37 u32 flags;
38 asm volatile("pushfl ; popl %0" : "=rm" (flags));
39 return flags;
40}
41
42static inline void restore_flags(u32 flags)
43{
44 asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
45}
46
47static inline void cpu_relax(void)
48{
49 asm volatile("rep ; nop": : :"memory");
50}
51
52static inline void nop(void)
53{
54 asm volatile("nop");
55}
56
57static inline void hlt(void)
58{
59 asm volatile("hlt": : :"memory");
60}
61
62static inline void wbinvd(void)
63{
64 asm volatile("wbinvd": : :"memory");
65}
66
67#define CPUID_TSC (1 << 4)
68#define CPUID_MSR (1 << 5)
69#define CPUID_APIC (1 << 9)
70#define CPUID_MTRR (1 << 12)
71static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
72{
73 asm("cpuid"
74 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
75 : "0" (index));
76}
77
Kevin O'Connor62de31b2015-09-22 12:35:00 -040078static inline u32 cr0_read(void) {
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040079 u32 cr0;
80 asm("movl %%cr0, %0" : "=r"(cr0));
81 return cr0;
82}
Kevin O'Connor62de31b2015-09-22 12:35:00 -040083static inline void cr0_write(u32 cr0) {
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040084 asm("movl %0, %%cr0" : : "r"(cr0));
85}
Kevin O'Connor62de31b2015-09-22 12:35:00 -040086static inline void cr0_mask(u32 off, u32 on) {
87 cr0_write((cr0_read() & ~off) | on);
88}
89static inline u16 cr0_vm86_read(void) {
Kevin O'Connor251e2632015-03-17 11:37:25 -040090 u16 cr0;
91 asm("smsww %0" : "=r"(cr0));
92 return cr0;
93}
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040094
95static inline u64 rdmsr(u32 index)
96{
97 u64 ret;
98 asm ("rdmsr" : "=A"(ret) : "c"(index));
99 return ret;
100}
101
102static inline void wrmsr(u32 index, u64 val)
103{
104 asm volatile ("wrmsr" : : "c"(index), "A"(val));
105}
106
107static inline u64 rdtscll(void)
108{
109 u64 val;
110 asm volatile("rdtsc" : "=A" (val));
111 return val;
112}
113
114static inline u32 __ffs(u32 word)
115{
116 asm("bsf %1,%0"
117 : "=r" (word)
118 : "rm" (word));
119 return word;
120}
121static inline u32 __fls(u32 word)
122{
123 asm("bsr %1,%0"
124 : "=r" (word)
125 : "rm" (word));
126 return word;
127}
128
129static inline u32 getesp(void) {
130 u32 esp;
131 asm("movl %%esp, %0" : "=rm"(esp));
132 return esp;
133}
134
Stefan Berger5aa2a752015-03-23 14:22:17 -0400135static inline u32 rol(u32 val, u16 rol) {
136 u32 res;
137 asm volatile("roll %%cl, %%eax"
138 : "=a" (res) : "a" (val), "c" (rol));
139 return res;
140}
141
Kevin O'Connor4ade5232013-09-18 21:41:48 -0400142static inline void outb(u8 value, u16 port) {
143 __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
144}
145static inline void outw(u16 value, u16 port) {
146 __asm__ __volatile__("outw %w0, %w1" : : "a"(value), "Nd"(port));
147}
148static inline void outl(u32 value, u16 port) {
149 __asm__ __volatile__("outl %0, %w1" : : "a"(value), "Nd"(port));
150}
151static inline u8 inb(u16 port) {
152 u8 value;
153 __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
154 return value;
155}
156static inline u16 inw(u16 port) {
157 u16 value;
158 __asm__ __volatile__("inw %w1, %w0" : "=a"(value) : "Nd"(port));
159 return value;
160}
161static inline u32 inl(u16 port) {
162 u32 value;
163 __asm__ __volatile__("inl %w1, %0" : "=a"(value) : "Nd"(port));
164 return value;
165}
166
167static inline void insb(u16 port, u8 *data, u32 count) {
168 asm volatile("rep insb (%%dx), %%es:(%%edi)"
169 : "+c"(count), "+D"(data) : "d"(port) : "memory");
170}
171static inline void insw(u16 port, u16 *data, u32 count) {
172 asm volatile("rep insw (%%dx), %%es:(%%edi)"
173 : "+c"(count), "+D"(data) : "d"(port) : "memory");
174}
175static inline void insl(u16 port, u32 *data, u32 count) {
176 asm volatile("rep insl (%%dx), %%es:(%%edi)"
177 : "+c"(count), "+D"(data) : "d"(port) : "memory");
178}
179// XXX - outs not limited to es segment
180static inline void outsb(u16 port, u8 *data, u32 count) {
181 asm volatile("rep outsb %%es:(%%esi), (%%dx)"
182 : "+c"(count), "+S"(data) : "d"(port) : "memory");
183}
184static inline void outsw(u16 port, u16 *data, u32 count) {
185 asm volatile("rep outsw %%es:(%%esi), (%%dx)"
186 : "+c"(count), "+S"(data) : "d"(port) : "memory");
187}
188static inline void outsl(u16 port, u32 *data, u32 count) {
189 asm volatile("rep outsl %%es:(%%esi), (%%dx)"
190 : "+c"(count), "+S"(data) : "d"(port) : "memory");
191}
192
Kevin O'Connoreee06e02015-09-29 10:14:58 -0400193/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
194static inline void smp_rmb(void) {
195 barrier();
196}
197static inline void smp_wmb(void) {
198 barrier();
199}
200
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400201static inline void writel(void *addr, u32 val) {
Ameya Palandebc82fa42015-02-17 14:00:49 -0800202 barrier();
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400203 *(volatile u32 *)addr = val;
204}
205static inline void writew(void *addr, u16 val) {
Ameya Palandebc82fa42015-02-17 14:00:49 -0800206 barrier();
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400207 *(volatile u16 *)addr = val;
208}
209static inline void writeb(void *addr, u8 val) {
Ameya Palandebc82fa42015-02-17 14:00:49 -0800210 barrier();
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400211 *(volatile u8 *)addr = val;
212}
213static inline u32 readl(const void *addr) {
Ameya Palandebc82fa42015-02-17 14:00:49 -0800214 u32 val = *(volatile const u32 *)addr;
215 barrier();
216 return val;
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400217}
218static inline u16 readw(const void *addr) {
Ameya Palandebc82fa42015-02-17 14:00:49 -0800219 u16 val = *(volatile const u16 *)addr;
220 barrier();
221 return val;
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400222}
223static inline u8 readb(const void *addr) {
Ameya Palandebc82fa42015-02-17 14:00:49 -0800224 u8 val = *(volatile const u8 *)addr;
225 barrier();
226 return val;
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400227}
228
229// GDT bits
230#define GDT_CODE (0x9bULL << 40) // Code segment - P,R,A bits also set
231#define GDT_DATA (0x93ULL << 40) // Data segment - W,A bits also set
232#define GDT_B (0x1ULL << 54) // Big flag
233#define GDT_G (0x1ULL << 55) // Granularity flag
234// GDT bits for segment base
235#define GDT_BASE(v) ((((u64)(v) & 0xff000000) << 32) \
236 | (((u64)(v) & 0x00ffffff) << 16))
237// GDT bits for segment limit (0-1Meg)
238#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32) \
239 | (((u64)(v) & 0x0000ffff) << 0))
240// GDT bits for segment limit (0-4Gig in 4K chunks)
241#define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12))
242
243struct descloc_s {
244 u16 length;
245 u32 addr;
246} PACKED;
247
Kevin O'Connor0f0612e2013-12-04 11:48:05 -0500248static inline void sgdt(struct descloc_s *desc) {
249 asm("sgdtl %0" : "=m"(*desc));
250}
251static inline void lgdt(struct descloc_s *desc) {
252 asm("lgdtl %0" : : "m"(*desc) : "memory");
253}
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400254
Kevin O'Connor341f8d92014-10-11 13:16:12 -0400255static inline u8 get_a20(void) {
256 return (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
257}
258
259static inline u8 set_a20(u8 cond) {
260 u8 val = inb(PORT_A20);
261 outb((val & ~A20_ENABLE_BIT) | (cond ? A20_ENABLE_BIT : 0), PORT_A20);
262 return (val & A20_ENABLE_BIT) != 0;
263}
264
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400265// x86.c
266void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
267
Kevin O'Connorb9c6a962013-09-14 13:01:30 -0400268#endif // !__ASSEMBLY__
269
270#endif // x86.h