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