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.


7170ecc2d7edd525de7d9f2c7a30c2c577ee4820
[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.ack_irq = &ack_irq;
217     os_hooks.get_cpu_khz = &get_cpu_khz;
218
219     Init_VMM(&os_hooks, &vmm_ops);
220   
221
222     /* MOVE THIS TO AN INIT GUEST ROUTINE */
223    
224     
225     v3_init_time(&(vm_info.time_state));
226     init_shadow_map(&(vm_info.mem_map));
227
228     if ((vmm_ops).has_nested_paging()) {
229       vm_info.shdw_pg_mode = NESTED_PAGING;
230     } else {
231       init_shadow_page_state(&(vm_info.shdw_pg_state));
232       vm_info.shdw_pg_mode = SHADOW_PAGING;
233     }
234
235     vm_info.cpu_mode = REAL;
236     vm_info.mem_mode = PHYSICAL_MEM;
237
238     //init_irq_map(&(vm_info.irq_map));
239     init_vmm_io_map(&(vm_info.io_map));
240     init_interrupt_state(&vm_info);
241
242     dev_mgr_init(&(vm_info.dev_mgr));
243     /* ** */
244     
245     if (0) {
246       
247       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x800000, 0x10000);    
248       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x1000000, 0);
249       
250       rip = (ulong_t)(void*)&BuzzVM;
251       //  rip -= 0x10000;
252       //    rip = (addr_t)(void*)&exit_test;
253       //  rip -= 0x2000;
254       vm_info.rip = rip;
255       rsp = (addr_t)Alloc_Page();
256       
257       vm_info.vm_regs.rsp = (rsp +4092 );// - 0x2000;
258       
259             
260     } else if (0) {
261       //add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x1000, 0x100000);
262       //      add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x100000, 0x0);
263       
264       /*
265         shadow_region_t *ent = Malloc(sizeof(shadow_region_t));;
266         init_shadow_region_physical(ent,0,0x100000,GUEST_REGION_PHYSICAL_MEMORY,
267         0x100000, HOST_REGION_PHYSICAL_MEMORY);
268         add_shadow_region(&(vm_info.mem_map),ent);
269       */
270
271       add_shadow_region_passthrough(&vm_info, 0x0, 0x100000, 0x100000);
272
273       hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
274       hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
275       
276       /*
277         vm_info.cr0 = 0;
278         vm_info.cs.base=0xf000;
279         vm_info.cs.limit=0xffff;
280       */
281       //vm_info.rip = 0xfff0;
282
283       vm_info.rip = 0;
284       vm_info.vm_regs.rsp = 0x0;
285     } else {
286       int i;
287       void * region_start;
288
289       extern char _binary_vm_kernel_start;
290       PrintBoth(" Guest Load Addr: 0x%x\n", &_binary_vm_kernel_start);
291
292       struct guest_mem_layout * layout = (struct guest_mem_layout *)&_binary_vm_kernel_start;
293
294       //     SerialPrint("Guest Mem Dump at 0x%x\n", 0x100000);
295       //SerialMemDump((unsigned char *)(0x100000), 261 * 1024);
296       if (layout->magic != MAGIC_CODE) {
297         
298         PrintBoth("Layout Magic Mismatch (0x%x)\n", layout->magic);
299         return -1;
300       }
301
302       PrintBoth("%d layout regions\n", layout->num_regions);
303
304       region_start = (void *)&(layout->regions[layout->num_regions]);
305
306       PrintBoth("region start = 0x%x\n", region_start);
307
308       for (i = 0; i < layout->num_regions; i++) {
309         struct layout_region * reg = &(layout->regions[i]);
310         uint_t num_pages = (reg->length / PAGE_SIZE) + ((reg->length % PAGE_SIZE) ? 1 : 0);
311         void * guest_mem = Allocate_VMM_Pages(num_pages);
312
313         PrintBoth("Layout Region %d bytes\n", reg->length);
314         memcpy(guest_mem, region_start, reg->length);
315         
316         SerialMemDump((unsigned char *)(guest_mem), 16);
317
318         add_shadow_region_passthrough(&vm_info, reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
319
320         PrintBoth("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
321
322         region_start += reg->length;
323       }
324       
325       //     
326       add_shadow_region_passthrough(&vm_info, 0x0, 0xa0000, (addr_t)Allocate_VMM_Pages(160));
327       
328       add_shadow_region_passthrough(&vm_info, 0xa0000, 0xc0000, 0xa0000); 
329       //hook_guest_mem(&vm_info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL);
330
331
332       // TEMP
333       //add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
334
335       if (1) {
336         add_shadow_region_passthrough(&vm_info, 0xc7000, 0xc8000, (addr_t)Allocate_VMM_Pages(1));
337         if (add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, (addr_t)Allocate_VMM_Pages(40)) == -1) {
338           PrintBoth("Error adding shadow region\n");
339         }
340       } else {
341         add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
342         add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, 0xc8000);
343       }
344
345
346       //add_shadow_region_passthrough(&vm_info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
347       add_shadow_region_passthrough(&vm_info, 0x100000, 0x1000000, (addr_t)Allocate_VMM_Pages(4096));
348
349       // test - give linux accesss to PCI space - PAD
350       add_shadow_region_passthrough(&vm_info, 0xc0000000,0xffffffff,0xc0000000);
351
352
353       print_shadow_map(&(vm_info.mem_map));
354
355       hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
356       //hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
357
358
359       hook_io_port(&(vm_info.io_map), 0x400, &IO_Read, &IO_Write_to_Serial, NULL);
360       hook_io_port(&(vm_info.io_map), 0x401, &IO_Read, &IO_Write_to_Serial, NULL);
361       hook_io_port(&(vm_info.io_map), 0x402, &IO_Read, &IO_BOCHS_info, NULL);
362       hook_io_port(&(vm_info.io_map), 0x403, &IO_Read, &IO_BOCHS_debug, NULL);
363
364       {
365         
366         struct vm_device * nvram = create_nvram();
367         //struct vm_device * timer = create_timer();
368         struct vm_device * pic = create_pic();
369         struct vm_device * keyboard = create_keyboard();
370         struct vm_device * pit = create_pit(); 
371         //struct vm_device * serial = create_serial();
372
373
374 #define GENERIC 1
375
376 #if GENERIC
377         generic_port_range_type range[] = {
378 #if 0
379           {0x00, 0x07, GENERIC_PRINT_AND_IGNORE},   // DMA 1 channels 0,1,2,3 (address, counter)
380           {0xc0, 0xc7, GENERIC_PRINT_AND_
381 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(&vm_info, 6);
453 #endif
454
455       //primary ide
456       hook_irq(&vm_info, 14);
457
458       // secondary ide
459       hook_irq(&vm_info, 15);
460
461
462
463       vm_info.rip = 0xfff0;
464       vm_info.vm_regs.rsp = 0x0;
465     }
466
467
468     PrintBoth("Initializing Guest (eip=0x%.8x) (esp=0x%.8x)\n", (uint_t)vm_info.rip,(uint_t)vm_info.vm_regs.rsp);
469     (vmm_ops).init_guest(&vm_info);
470     PrintBoth("Starting Guest\n");
471     //Clear_Screen();
472     (vmm_ops).start_guest(&vm_info);
473
474     return 0;
475 }