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.


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