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.


a6f5bb08c3bbd4343a88bc3dd76e057619060fac
[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 = &geekos_hook_interrupt_new;
223     os_hooks.ack_irq = &ack_irq;
224     os_hooks.get_cpu_khz = &get_cpu_khz;
225
226
227
228     Init_V3(&os_hooks, &vmm_ops);
229
230     //test decoder
231     PrintBoth("testing decoder\n");
232     parse();
233     PrintBoth("testing decoder done\n");
234   
235
236     /* MOVE THIS TO AN INIT GUEST ROUTINE */
237    
238     
239     v3_init_time(&(vm_info.time_state));
240     init_shadow_map(&(vm_info.mem_map));
241
242     if ((vmm_ops).has_nested_paging()) {
243       vm_info.shdw_pg_mode = NESTED_PAGING;
244     } else {
245       init_shadow_page_state(&(vm_info.shdw_pg_state));
246       vm_info.shdw_pg_mode = SHADOW_PAGING;
247     }
248
249     vm_info.cpu_mode = REAL;
250     vm_info.mem_mode = PHYSICAL_MEM;
251
252     //init_irq_map(&(vm_info.irq_map));
253     init_vmm_io_map(&(vm_info.io_map));
254     init_interrupt_state(&vm_info);
255
256     dev_mgr_init(&(vm_info.dev_mgr));
257     /* ** */
258     
259     if (0) {
260       
261       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x800000, 0x10000);    
262       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x1000000, 0);
263       
264       rip = (ulong_t)(void*)&BuzzVM;
265       //  rip -= 0x10000;
266       //    rip = (addr_t)(void*)&exit_test;
267       //  rip -= 0x2000;
268       vm_info.rip = rip;
269       rsp = (addr_t)Alloc_Page();
270       
271       vm_info.vm_regs.rsp = (rsp +4092 );// - 0x2000;
272       
273             
274     } else if (0) {
275       //add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x1000, 0x100000);
276       //      add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x100000, 0x0);
277       
278       /*
279         shadow_region_t *ent = Malloc(sizeof(shadow_region_t));;
280         init_shadow_region_physical(ent,0,0x100000,GUEST_REGION_PHYSICAL_MEMORY,
281         0x100000, HOST_REGION_PHYSICAL_MEMORY);
282         add_shadow_region(&(vm_info.mem_map),ent);
283       */
284
285       add_shadow_region_passthrough(&vm_info, 0x0, 0x100000, 0x100000);
286
287       v3_hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
288       v3_hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
289       
290       /*
291         vm_info.cr0 = 0;
292         vm_info.cs.base=0xf000;
293         vm_info.cs.limit=0xffff;
294       */
295       //vm_info.rip = 0xfff0;
296
297       vm_info.rip = 0;
298       vm_info.vm_regs.rsp = 0x0;
299     } else {
300       int i;
301       void * region_start;
302
303       extern char _binary_vm_kernel_start;
304       PrintBoth(" Guest Load Addr: 0x%x\n", &_binary_vm_kernel_start);
305
306       struct guest_mem_layout * layout = (struct guest_mem_layout *)&_binary_vm_kernel_start;
307
308       //     SerialPrint("Guest Mem Dump at 0x%x\n", 0x100000);
309       //SerialMemDump((unsigned char *)(0x100000), 261 * 1024);
310       if (layout->magic != MAGIC_CODE) {
311         
312         PrintBoth("Layout Magic Mismatch (0x%x)\n", layout->magic);
313         return -1;
314       }
315
316       PrintBoth("%d layout regions\n", layout->num_regions);
317
318       region_start = (void *)&(layout->regions[layout->num_regions]);
319
320       PrintBoth("region start = 0x%x\n", region_start);
321
322       for (i = 0; i < layout->num_regions; i++) {
323         struct layout_region * reg = &(layout->regions[i]);
324         uint_t num_pages = (reg->length / PAGE_SIZE) + ((reg->length % PAGE_SIZE) ? 1 : 0);
325         void * guest_mem = Allocate_VMM_Pages(num_pages);
326
327         PrintBoth("Layout Region %d bytes\n", reg->length);
328         memcpy(guest_mem, region_start, reg->length);
329         
330         SerialMemDump((unsigned char *)(guest_mem), 16);
331
332         add_shadow_region_passthrough(&vm_info, reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
333
334         PrintBoth("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
335
336         region_start += reg->length;
337       }
338       
339       //     
340       add_shadow_region_passthrough(&vm_info, 0x0, 0xa0000, (addr_t)Allocate_VMM_Pages(160));
341       
342       add_shadow_region_passthrough(&vm_info, 0xa0000, 0xc0000, 0xa0000); 
343       //hook_guest_mem(&vm_info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL);
344
345
346       // TEMP
347       //add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
348
349       if (1) {
350         add_shadow_region_passthrough(&vm_info, 0xc7000, 0xc8000, (addr_t)Allocate_VMM_Pages(1));
351         if (add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, (addr_t)Allocate_VMM_Pages(40)) == -1) {
352           PrintBoth("Error adding shadow region\n");
353         }
354       } else {
355         add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
356         add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, 0xc8000);
357       }
358
359
360       //add_shadow_region_passthrough(&vm_info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
361       add_shadow_region_passthrough(&vm_info, 0x100000, 0x1000000, (addr_t)Allocate_VMM_Pages(4096));
362
363       add_shadow_region_passthrough(&vm_info, 0x1000000, 0x8000000, (addr_t)Allocate_VMM_Pages(32768));
364
365       // test - give linux accesss to PCI space - PAD
366       add_shadow_region_passthrough(&vm_info, 0xc0000000,0xffffffff,0xc0000000);
367
368
369       print_shadow_map(&(vm_info.mem_map));
370
371       v3_hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
372       //v3_hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
373
374
375       v3_hook_io_port(&(vm_info.io_map), 0x400, &IO_Read, &IO_Write_to_Serial, NULL);
376       v3_hook_io_port(&(vm_info.io_map), 0x401, &IO_Read, &IO_Write_to_Serial, NULL);
377       v3_hook_io_port(&(vm_info.io_map), 0x402, &IO_Read, &IO_BOCHS_info, NULL);
378       v3_hook_io_port(&(vm_info.io_map), 0x403, &IO_Read, &IO_BOCHS_debug, NULL);
379
380       {
381         
382         struct vm_device * nvram = create_nvram();
383         //struct vm_device * timer = create_timer();
384         struct vm_device * pic = create_pic();
385         struct vm_device * keyboard = create_keyboard();
386         struct vm_device * pit = create_pit(); 
387         //struct vm_device * serial = create_serial();
388
389
390 #define GENERIC 1
391
392 #if GENERIC
393         generic_port_range_type range[] = {
394 #if 1
395           {0x00, 0x07, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channels 0,1,2,3 (address, counter)
396           {0xc0, 0xc7, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channels 4,5,6,7 (address, counter)
397           {0x87, 0x87, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 0 page register
398           {0x83, 0x83, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 1 page register
399           {0x81, 0x81, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 2 page register
400           {0x82, 0x82, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channel 3 page register
401           {0x8f, 0x8f, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 4 page register
402           {0x8b, 0x8b, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 5 page register
403           {0x89, 0x89, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 6 page register
404           {0x8a, 0x8a, GENERIC_PRINT_AND_IGNORE},   // DMA 2 channel 7 page register
405           {0x08, 0x0f, GENERIC_PRINT_AND_IGNORE},   // DMA 1 misc registers (csr, req, smask,mode,clearff,reset,enable,mmask)
406           {0xd0, 0xde, GENERIC_PRINT_AND_IGNORE},   // DMA 2 misc registers
407 #endif
408
409           
410           {0x3f8, 0x3f8+7, GENERIC_PRINT_AND_IGNORE},      // COM 1
411           {0x2f8, 0x2f8+7, GENERIC_PRINT_AND_IGNORE},      // COM 2
412           {0x3e8, 0x3e8+7, GENERIC_PRINT_AND_IGNORE},      // COM 3
413           {0x2e8, 0x2e8+7, GENERIC_PRINT_AND_IGNORE},      // COM 4
414           
415 #if 0
416             {0x170, 0x178, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 1
417             {0x376, 0x377, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 1
418             {0x1f0, 0x1f8, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 0
419             {0x3f6, 0x3f7, GENERIC_PRINT_AND_PASSTHROUGH}, // IDE 0
420 #endif
421
422
423 #if 0
424           {0x3f0, 0x3f2, GENERIC_PRINT_AND_IGNORE}, // Primary floppy controller (base,statusa/statusb,DOR)
425           {0x3f4, 0x3f5, GENERIC_PRINT_AND_IGNORE}, // Primary floppy controller (mainstat/datarate,data)
426           {0x3f7, 0x3f7, GENERIC_PRINT_AND_IGNORE}, // Primary floppy controller (DIR)
427           {0x370, 0x372, GENERIC_PRINT_AND_IGNORE}, // Secondary floppy controller (base,statusa/statusb,DOR)
428           {0x374, 0x375, GENERIC_PRINT_AND_IGNORE}, // Secondary floppy controller (mainstat/datarate,data)
429           {0x377, 0x377, GENERIC_PRINT_AND_IGNORE}, // Secondary floppy controller (DIR)
430
431 #endif
432
433           //      {0x378, 0x400, GENERIC_PRINT_AND_IGNORE}
434
435           {0,0,0},  // sentinal - must be last
436
437         };
438
439
440         struct vm_device * generic = create_generic(range, NULL, NULL);
441
442 #endif
443
444         v3_attach_device(&(vm_info), nvram);
445         //v3_attach_device(&(vm_info), timer);
446         v3_attach_device(&(vm_info), pic);
447         v3_attach_device(&(vm_info), pit);
448         v3_attach_device(&(vm_info), keyboard);
449         // v3_attach_device(&(vm_info), serial);
450
451
452 #if GENERIC
453         // Important that this be attached last!
454         v3_attach_device(&(vm_info), generic);
455
456 #endif
457
458         PrintDebugDevMgr(&(vm_info.dev_mgr));
459       }
460
461       // give keyboard interrupts to vm
462       // no longer needed since we have a keyboard device
463       //hook_irq(&vm_info, 1);
464       
465 #if 1
466       // give floppy controller to vm
467       v3_hook_irq_for_guest_injection(&vm_info, 6);
468 #endif
469
470 #if 1
471       //primary ide
472       v3_hook_irq_for_guest_injection(&vm_info, 14);
473
474       // secondary ide
475       v3_hook_irq_for_guest_injection(&vm_info, 15);
476 #endif
477
478
479       vm_info.rip = 0xfff0;
480       vm_info.vm_regs.rsp = 0x0;
481     }
482
483
484     PrintBoth("Initializing Guest (eip=0x%.8x) (esp=0x%.8x)\n", (uint_t)vm_info.rip,(uint_t)vm_info.vm_regs.rsp);
485     (vmm_ops).init_guest(&vm_info);
486     PrintBoth("Starting Guest\n");
487     //Clear_Screen();
488     (vmm_ops).start_guest(&vm_info);
489
490     return 0;
491 }