Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


*** empty log message ***
[palacios.git] / palacios / src / geekos / vm.c
1 #include <geekos/vmm_stubs.h>
2 #include <palacios/vmm.h>
3 #include <geekos/debug.h>
4 #include <geekos/serial.h>
5 #include <geekos/vm.h>
6 #include <geekos/screen.h>
7
8 #include <devices/generic.h>
9 #include <devices/nvram.h>
10 #include <devices/timer.h>
11 #include <devices/simple_pic.h>
12 #include <devices/8259a.h>
13 #include <devices/8254.h>
14 #include <devices/keyboard.h>
15
16 #include <palacios/vmm_intr.h>
17 #include <palacios/vmm_dev_mgr.h>
18 #include <palacios/vmm_time.h>
19
20 #define SPEAKER_PORT 0x61
21
22 static inline void VM_Out_Byte(ushort_t port, uchar_t value)
23 {
24     __asm__ __volatile__ (
25         "outb %b0, %w1"
26         :
27         : "a" (value), "Nd" (port)
28     );
29 }
30
31 /*
32  * Read a byte from an I/O port.
33  */
34 static inline uchar_t VM_In_Byte(ushort_t port)
35 {
36     uchar_t value;
37
38     __asm__ __volatile__ (
39         "inb %w1, %b0"
40         : "=a" (value)
41         : "Nd" (port)
42     );
43
44     return value;
45 }
46
47
48
49
50 int IO_Read(ushort_t port, void * dst, uint_t length, void * priv_data) {
51
52   if (length != 1) {
53     return 0;
54   }
55
56   *(uchar_t*)dst = VM_In_Byte(port);    
57   return 1;
58 }
59
60
61
62 int IO_Write(ushort_t port, void * src, uint_t length, void * priv_data) {
63
64   if (length != 1) {
65     return 0;
66   }
67
68   VM_Out_Byte(port, *(uchar_t *)src);    
69
70   return 1;
71 }
72
73
74 int IO_Read_to_Serial(ushort_t port, void * dst, uint_t length, void * priv_data) {
75   PrintBoth("Input from Guest on port %d (0x%x) Length=%d\n", port, port, length);
76   
77   return 0;
78 }
79
80
81 char * bochs_debug_buf = NULL;
82 int bochs_debug_offset = 0;
83
84
85 int IO_BOCHS_debug(ushort_t port, void * src, uint_t length, void * priv_data) {
86   if (!bochs_debug_buf) {
87     bochs_debug_buf = (char*)Malloc(1024);
88   }
89
90   bochs_debug_buf[bochs_debug_offset++] = *(char*)src;
91
92   if ((*(char*)src == 0xa) ||  (bochs_debug_offset == 1023)) {
93     SerialPrint("BOCHS>%s", bochs_debug_buf);
94     memset(bochs_debug_buf, 0, 1024);
95     bochs_debug_offset = 0;
96   }
97
98   return length;
99 }
100
101
102 int IO_Write_to_Serial(ushort_t port, void * src, uint_t length, void * priv_data) {
103  SerialPrint("Output from Guest on port %d (0x%x) Length=%d\n", port, port, length);
104   switch (length) {
105
106   case 1:
107     SerialPrint(">0x%.2x\n", *(char*)src);
108     break;
109   case 2:
110     SerialPrint(">0x%.4x\n", *(ushort_t*)src);
111     break;
112   case 4:
113     SerialPrint(">0x%.8x\n", *(uint_t*)src);
114     break;
115   default:
116     break;
117   }
118
119   //  SerialMemDump(src, length);
120   return length;
121 }
122
123
124
125 void BuzzVM()
126 {
127   int x;
128   int j;
129   unsigned char init;
130
131 #if 0  
132   __asm__ __volatile__ (
133     "popf"
134     );
135     
136 #endif
137     
138   PrintBoth("Starting To Buzz\n");
139
140   init=VM_In_Byte(SPEAKER_PORT);
141
142   while (1) {
143     VM_Out_Byte(SPEAKER_PORT, init|0x2);
144     for (j=0;j<1000000;j++) { 
145       x+=j;
146     }
147     VM_Out_Byte(SPEAKER_PORT, init);
148     for (j=0;j<1000000;j++) { 
149       x+=j;
150     }
151   }
152 }
153
154
155
156 int passthrough_mem_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
157   memcpy(dst, (void*)guest_addr, length);
158   return length;
159 }
160
161 int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
162   memcpy((void*)guest_addr, src, length);
163   return length;
164 }
165
166
167
168 /* We need a configuration mechanism, so we can wrap this completely inside the VMM code, 
169  * with no pollution into the HOST OS
170  */
171
172 int RunVMM(struct Boot_Info * bootInfo) {
173
174     struct vmm_os_hooks os_hooks;
175     struct vmm_ctrl_ops vmm_ops;
176     struct guest_info vm_info;
177     addr_t rsp;
178     addr_t rip;
179
180
181
182     memset(&os_hooks, 0, sizeof(struct vmm_os_hooks));
183     memset(&vmm_ops, 0, sizeof(struct vmm_ctrl_ops));
184     memset(&vm_info, 0, sizeof(struct guest_info));
185
186     os_hooks.print_debug = &SerialPrint;
187     os_hooks.print_info = &Print;
188     os_hooks.print_trace = &SerialPrint;
189     os_hooks.allocate_pages = &Allocate_VMM_Pages;
190     os_hooks.free_page = &Free_VMM_Page;
191     os_hooks.malloc = &VMM_Malloc;
192     os_hooks.free = &VMM_Free;
193     os_hooks.vaddr_to_paddr = &Identity;
194     os_hooks.paddr_to_vaddr = &Identity;
195     os_hooks.hook_interrupt = &hook_irq_stub;
196     os_hooks.ack_irq = &ack_irq;
197     os_hooks.get_cpu_khz = &get_cpu_khz;
198
199     Init_VMM(&os_hooks, &vmm_ops);
200   
201
202     /* MOVE THIS TO AN INIT GUEST ROUTINE */
203    
204     
205     v3_init_time(&(vm_info.time_state));
206     init_shadow_map(&(vm_info.mem_map));
207
208     if ((vmm_ops).has_nested_paging()) {
209       vm_info.shdw_pg_mode = NESTED_PAGING;
210     } else {
211       init_shadow_page_state(&(vm_info.shdw_pg_state));
212       vm_info.shdw_pg_mode = SHADOW_PAGING;
213     }
214
215     vm_info.cpu_mode = REAL;
216     vm_info.mem_mode = PHYSICAL_MEM;
217
218     //init_irq_map(&(vm_info.irq_map));
219     init_vmm_io_map(&(vm_info.io_map));
220     init_interrupt_state(&vm_info);
221
222     dev_mgr_init(&(vm_info.dev_mgr));
223     /* ** */
224     
225     if (0) {
226       
227       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x800000, 0x10000);    
228       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x1000000, 0);
229       
230       rip = (ulong_t)(void*)&BuzzVM;
231       //  rip -= 0x10000;
232       //    rip = (addr_t)(void*)&exit_test;
233       //  rip -= 0x2000;
234       vm_info.rip = rip;
235       rsp = (addr_t)Alloc_Page();
236       
237       vm_info.vm_regs.rsp = (rsp +4092 );// - 0x2000;
238       
239             
240     } else if (0) {
241       //add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x1000, 0x100000);
242       //      add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x100000, 0x0);
243       
244       /*
245         shadow_region_t *ent = Malloc(sizeof(shadow_region_t));;
246         init_shadow_region_physical(ent,0,0x100000,GUEST_REGION_PHYSICAL_MEMORY,
247         0x100000, HOST_REGION_PHYSICAL_MEMORY);
248         add_shadow_region(&(vm_info.mem_map),ent);
249       */
250
251       add_shadow_region_passthrough(&vm_info, 0x0, 0x100000, 0x100000);
252
253       hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
254       hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
255       
256       /*
257         vm_info.cr0 = 0;
258         vm_info.cs.base=0xf000;
259         vm_info.cs.limit=0xffff;
260       */
261       //vm_info.rip = 0xfff0;
262
263       vm_info.rip = 0;
264       vm_info.vm_regs.rsp = 0x0;
265     } else {
266       int i;
267       void * region_start;
268
269  
270       PrintBoth("Guest Size: %lu\n", bootInfo->guest_size);
271
272       struct guest_mem_layout * layout = (struct guest_mem_layout *)0x100000;
273
274       if (layout->magic != MAGIC_CODE) {
275         PrintBoth("Layout Magic Mismatch (0x%x)\n", layout->magic);
276       }
277
278       PrintBoth("%d layout regions\n", layout->num_regions);
279
280       region_start = (void *)&(layout->regions[layout->num_regions]);
281
282       PrintBoth("region start = 0x%x\n", region_start);
283
284       for (i = 0; i < layout->num_regions; i++) {
285         struct layout_region * reg = &(layout->regions[i]);
286         uint_t num_pages = (reg->length / PAGE_SIZE) + ((reg->length % PAGE_SIZE) ? 1 : 0);
287         void * guest_mem = Allocate_VMM_Pages(num_pages);
288
289         PrintBoth("Layout Region %d bytes\n", reg->length);
290         memcpy(guest_mem, region_start, reg->length);
291         
292         SerialMemDump((unsigned char *)(guest_mem), 16);
293
294         add_shadow_region_passthrough(&vm_info, reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
295
296         PrintBoth("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
297
298         region_start += reg->length;
299       }
300       
301       //     
302       add_shadow_region_passthrough(&vm_info, 0x0, 0xa0000, (addr_t)Allocate_VMM_Pages(160));
303       
304       add_shadow_region_passthrough(&vm_info, 0xa0000, 0xc0000, 0xa0000); 
305       //hook_guest_mem(&vm_info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL);
306
307
308       // TEMP
309       //add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
310
311       if (1) {
312         add_shadow_region_passthrough(&vm_info, 0xc7000, 0xc8000, (addr_t)Allocate_VMM_Pages(1));
313         if (add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, (addr_t)Allocate_VMM_Pages(40)) == -1) {
314           PrintBoth("Error adding shadow region\n");
315         }
316       } else {
317         add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
318         add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, 0xc8000);
319       }
320
321
322       //add_shadow_region_passthrough(&vm_info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
323       add_shadow_region_passthrough(&vm_info, 0x100000, 0x1000000, (addr_t)Allocate_VMM_Pages(4096));
324
325       // test - give linux accesss to PCI space - PAD
326       add_shadow_region_passthrough(&vm_info, 0xc0000000,0xffffffff,0xc0000000);
327
328
329       print_shadow_map(&(vm_info.mem_map));
330
331       hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
332       //hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
333
334
335       hook_io_port(&(vm_info.io_map), 0x400, &IO_Read, &IO_Write_to_Serial, NULL);
336       hook_io_port(&(vm_info.io_map), 0x401, &IO_Read, &IO_Write_to_Serial, NULL);
337       hook_io_port(&(vm_info.io_map), 0x402, &IO_Read, &IO_BOCHS_debug, NULL);
338       hook_io_port(&(vm_info.io_map), 0x403, &IO_Read, &IO_Write_to_Serial, NULL);
339
340       {
341         
342         struct vm_device * nvram = create_nvram();
343         //struct vm_device * timer = create_timer();
344         struct vm_device * pic = create_pic();
345         struct vm_device * keyboard = create_keyboard();
346         struct vm_device * pit = create_pit(); 
347
348
349 #define GENERIC 1
350
351 #if GENERIC
352         generic_port_range_type range[] = {
353 #if 0
354           {0x00, 0x07, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channels 0,1,2,3 (address, counter)
355           {0xc0, 0xc7, GENERIC_PRINT_AND_
356 IGNORE},   // DMA 2 channels 4,5,6,7 (address, counter)
357           {0x87, 0x87, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 0 page register
358           {0x83, 0x83, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 1 page register
359           {0x81, 0x81, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 2 page register
360           {0x82, 0x82, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 3 page register
361           {0x8f, 0x8f, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 4 page register
362           {0x8b, 0x8b, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 5 page register
363           {0x89, 0x89, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 6 page register
364           {0x8a, 0x8a, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 7 page register
365           {0x08, 0x0f, GENERIC_PRINT_AND_IGNORE},   // DMA 1 misc registers (csr, req, smask,mode,clearff,reset,enable,mmask)
366           {0xd0, 0xde, GENERIC_PRINT_AND_IGNORE},   // DMA 2 misc registers
367 #endif
368
369           {0x3f8, 0x3f8+7, GENERIC_PRINT_AND_IGNORE},      // COM 1
370           {0x2f8, 0x2f8+7, GENERIC_PRINT_AND_IGNORE},      // COM 2
371           {0x3e8, 0x3e8+7, GENERIC_PRINT_AND_IGNORE},      // COM 2
372           {0x2e8, 0x2e8+7, GENERIC_PRINT_AND_IGNORE},      // COM 2
373           /*
374             {0x170, 0x178, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 1
375             {0x376, 0x377, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 1
376             {0x1f0, 0x1f8, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 0
377             {0x3f6, 0x3f7, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 0
378           */
379           {0x3f0, 0x3f2, GENERIC_PRINT_AND_IGNORE}, // Primary floppy controller (base,statusa/statusb,DOR)
380           {0x3f4, 0x3f5, GENERIC_PRINT_AND_IGNORE}, // Primary floppy controller (mainstat/datarate,data)
381           {0x3f7, 0x3f7, GENERIC_PRINT_AND_IGNORE}, // Primary floppy controller (DIR)
382           {0x370, 0x372, GENERIC_PRINT_AND_IGNORE}, // Secondary floppy controller (base,statusa/statusb,DOR)
383           {0x374, 0x375, GENERIC_PRINT_AND_IGNORE}, // Secondary floppy controller (mainstat/datarate,data)
384           {0x377, 0x377, GENERIC_PRINT_AND_IGNORE}, // Secondary floppy controller (DIR)
385
386           //      {0x378, 0x400, GENERIC_PRINT_AND_IGNORE}
387
388         };
389
390         struct vm_device * generic = create_generic(range,10,  // THIS NUMBER IS CRITICAL
391
392                                                     NULL,0,NULL,0);
393 #endif
394
395         attach_device(&(vm_info), nvram);
396         //attach_device(&(vm_info), timer);
397         attach_device(&(vm_info), pic);
398         attach_device(&(vm_info), pit);
399         attach_device(&(vm_info), keyboard);
400
401
402 #if GENERIC
403         // Important that this be attached last!
404         attach_device(&(vm_info), generic);
405
406 #endif
407
408         PrintDebugDevMgr(&(vm_info.dev_mgr));
409       }
410
411       // give keyboard interrupts to vm
412       // no longer needed since we have a keyboard device
413       //hook_irq(&vm_info, 1);
414       
415 #if 0
416       // give floppy controller to vm
417       hook_irq(&vm_info, 6);
418 #endif
419
420       //primary ide
421       hook_irq(&vm_info, 14);
422
423       // secondary ide
424       hook_irq(&vm_info, 15);
425
426
427
428       vm_info.rip = 0xfff0;
429       vm_info.vm_regs.rsp = 0x0;
430     }
431
432
433     PrintBoth("Initializing Guest (eip=0x%.8x) (esp=0x%.8x)\n", (uint_t)vm_info.rip,(uint_t)vm_info.vm_regs.rsp);
434     (vmm_ops).init_guest(&vm_info);
435     PrintBoth("Starting Guest\n");
436     //Clear_Screen();
437     (vmm_ops).start_guest(&vm_info);
438
439     return 0;
440 }