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.


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