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.


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