test: rename kvm/user/test to kvm/user
[qemu-kvm/amd-iommu.git] / kvm / user / x86 / vm.c
blobec9c1458ad3beb7aa8f649d386f2afef02a489ad
2 #include "vm.h"
4 void print(const char *s);
6 #define PAGE_SIZE 4096ul
7 #define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
9 static void *free = 0;
10 static void *vfree_top = 0;
12 static unsigned long virt_to_phys(const void *virt)
14 return (unsigned long)virt;
17 static void *phys_to_virt(unsigned long phys)
19 return (void *)phys;
22 void *memset(void *data, int c, unsigned long len)
24 char *s = data;
26 while (len--)
27 *s++ = c;
29 return data;
32 static void free_memory(void *mem, unsigned long size)
34 while (size >= PAGE_SIZE) {
35 *(void **)mem = free;
36 free = mem;
37 mem += PAGE_SIZE;
38 size -= PAGE_SIZE;
42 void *alloc_page()
44 void *p;
46 if (!free)
47 return 0;
49 p = free;
50 free = *(void **)free;
52 return p;
55 void free_page(void *page)
57 *(void **)page = free;
58 free = page;
61 extern char edata;
62 static unsigned long end_of_memory;
64 #define PTE_PRESENT (1ull << 0)
65 #define PTE_PSE (1ull << 7)
66 #define PTE_WRITE (1ull << 1)
67 #define PTE_ADDR (0xffffffffff000ull)
69 static void install_pte(unsigned long *cr3,
70 int pte_level,
71 void *virt,
72 unsigned long pte)
74 int level;
75 unsigned long *pt = cr3;
76 unsigned offset;
78 for (level = 4; level > pte_level; --level) {
79 offset = ((unsigned long)virt >> ((level-1) * 9 + 12)) & 511;
80 if (!(pt[offset] & PTE_PRESENT)) {
81 unsigned long *new_pt = alloc_page();
82 memset(new_pt, 0, PAGE_SIZE);
83 pt[offset] = virt_to_phys(new_pt) | PTE_PRESENT | PTE_WRITE;
85 pt = phys_to_virt(pt[offset] & 0xffffffffff000ull);
87 offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
88 pt[offset] = pte;
91 static unsigned long get_pte(unsigned long *cr3, void *virt)
93 int level;
94 unsigned long *pt = cr3, pte;
95 unsigned offset;
97 for (level = 4; level > 1; --level) {
98 offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
99 pte = pt[offset];
100 if (!(pte & PTE_PRESENT))
101 return 0;
102 if (level == 2 && (pte & PTE_PSE))
103 return pte;
104 pt = phys_to_virt(pte & 0xffffffffff000ull);
106 offset = ((unsigned long)virt >> (((level-1) * 9) + 12)) & 511;
107 pte = pt[offset];
108 return pte;
111 static void install_large_page(unsigned long *cr3,
112 unsigned long phys,
113 void *virt)
115 install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_PSE);
118 static void install_page(unsigned long *cr3,
119 unsigned long phys,
120 void *virt)
122 install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE);
125 static inline void load_cr3(unsigned long cr3)
127 asm ( "mov %0, %%cr3" : : "r"(cr3) );
130 static inline unsigned long read_cr3()
132 unsigned long cr3;
134 asm volatile ( "mov %%cr3, %0" : "=r"(cr3) );
135 return cr3;
138 static inline void load_cr0(unsigned long cr0)
140 asm volatile ( "mov %0, %%cr0" : : "r"(cr0) );
143 static inline unsigned long read_cr0()
145 unsigned long cr0;
147 asm volatile ( "mov %%cr0, %0" : "=r"(cr0) );
148 return cr0;
151 static inline void load_cr4(unsigned long cr4)
153 asm volatile ( "mov %0, %%cr4" : : "r"(cr4) );
156 static inline unsigned long read_cr4()
158 unsigned long cr4;
160 asm volatile ( "mov %%cr4, %0" : "=r"(cr4) );
161 return cr4;
164 struct gdt_table_descr
166 unsigned short len;
167 unsigned long *table;
168 } __attribute__((packed));
170 static inline void load_gdt(unsigned long *table, int nent)
172 struct gdt_table_descr descr;
174 descr.len = nent * 8 - 1;
175 descr.table = table;
176 asm volatile ( "lgdt %0" : : "m"(descr) );
179 #define SEG_CS_32 8
180 #define SEG_CS_64 16
182 struct ljmp {
183 void *ofs;
184 unsigned short seg;
187 static void setup_mmu(unsigned long len)
189 unsigned long *cr3 = alloc_page();
190 unsigned long phys = 0;
192 if (len < (1ul << 32))
193 len = 1ul << 32; /* map mmio 1:1 */
195 memset(cr3, 0, PAGE_SIZE);
196 while (phys + LARGE_PAGE_SIZE <= len) {
197 install_large_page(cr3, phys, (void *)phys);
198 phys += LARGE_PAGE_SIZE;
200 while (phys + PAGE_SIZE <= len) {
201 install_page(cr3, phys, (void *)phys);
202 phys += PAGE_SIZE;
205 load_cr3(virt_to_phys(cr3));
206 print("paging enabled\n");
209 static unsigned int inl(unsigned short port)
211 unsigned int val;
212 asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
213 return val;
216 void setup_vm()
218 end_of_memory = inl(0xd1);
219 free_memory(&edata, end_of_memory - (unsigned long)&edata);
220 setup_mmu(end_of_memory);
223 void *vmalloc(unsigned long size)
225 void *mem, *p;
226 unsigned pages;
228 size += sizeof(unsigned long);
230 size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
231 vfree_top -= size;
232 mem = p = vfree_top;
233 pages = size / PAGE_SIZE;
234 while (pages--) {
235 install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p);
236 p += PAGE_SIZE;
238 *(unsigned long *)mem = size;
239 mem += sizeof(unsigned long);
240 return mem;
243 void vfree(void *mem)
245 unsigned long size = ((unsigned long *)mem)[-1];
247 while (size) {
248 free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
249 mem += PAGE_SIZE;
250 size -= PAGE_SIZE;
254 void *vmap(unsigned long long phys, unsigned long size)
256 void *mem, *p;
257 unsigned pages;
259 size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
260 vfree_top -= size;
261 phys &= ~(unsigned long long)(PAGE_SIZE - 1);
263 mem = p = vfree_top;
264 pages = size / PAGE_SIZE;
265 while (pages--) {
266 install_page(phys_to_virt(read_cr3()), phys, p);
267 phys += PAGE_SIZE;
268 p += PAGE_SIZE;
270 return mem;