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.


92d61f1e8e567fcffbc1e746793450305707adea
[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.page_mode = SHADOW_PAGING;
207
208     vm_info.cpu_mode = REAL;
209
210     //init_irq_map(&(vm_info.irq_map));
211     init_vmm_io_map(&(vm_info.io_map));
212     init_interrupt_state(&vm_info);
213
214     dev_mgr_init(&(vm_info.dev_mgr));
215     /* ** */
216     
217     if (0) {
218       
219       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x800000, 0x10000);    
220       //    add_shared_mem_range(&(vm_info.mem_layout), 0, 0x1000000, 0);
221       
222       rip = (ulong_t)(void*)&BuzzVM;
223       //  rip -= 0x10000;
224       //    rip = (addr_t)(void*)&exit_test;
225       //  rip -= 0x2000;
226       vm_info.rip = rip;
227       rsp = (addr_t)Alloc_Page();
228       
229       vm_info.vm_regs.rsp = (rsp +4092 );// - 0x2000;
230       
231             
232     } else if (0) {
233       //add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x1000, 0x100000);
234       //      add_shared_mem_range(&(vm_info.mem_layout), 0x0, 0x100000, 0x0);
235       
236       /*
237         shadow_region_t *ent = Malloc(sizeof(shadow_region_t));;
238         init_shadow_region_physical(ent,0,0x100000,GUEST_REGION_PHYSICAL_MEMORY,
239         0x100000, HOST_REGION_PHYSICAL_MEMORY);
240         add_shadow_region(&(vm_info.mem_map),ent);
241       */
242
243       add_shadow_region_passthrough(&vm_info, 0x0, 0x100000, 0x100000);
244
245       hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
246       hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
247       
248       /*
249         vm_info.cr0 = 0;
250         vm_info.cs.base=0xf000;
251         vm_info.cs.limit=0xffff;
252       */
253       //vm_info.rip = 0xfff0;
254
255       vm_info.rip = 0;
256       vm_info.vm_regs.rsp = 0x0;
257     } else {
258       int i;
259       void * region_start;
260
261  
262       PrintBoth("Guest Size: %lu\n", bootInfo->guest_size);
263
264       struct guest_mem_layout * layout = (struct guest_mem_layout *)0x100000;
265
266       if (layout->magic != MAGIC_CODE) {
267         PrintBoth("Layout Magic Mismatch (0x%x)\n", layout->magic);
268       }
269
270       PrintBoth("%d layout regions\n", layout->num_regions);
271
272       region_start = (void *)&(layout->regions[layout->num_regions]);
273
274       PrintBoth("region start = 0x%x\n", region_start);
275
276       for (i = 0; i < layout->num_regions; i++) {
277         struct layout_region * reg = &(layout->regions[i]);
278         uint_t num_pages = (reg->length / PAGE_SIZE) + ((reg->length % PAGE_SIZE) ? 1 : 0);
279         void * guest_mem = Allocate_VMM_Pages(num_pages);
280
281         PrintBoth("Layout Region %d bytes\n", reg->length);
282         memcpy(guest_mem, region_start, reg->length);
283         
284         SerialMemDump((unsigned char *)(guest_mem), 16);
285
286         add_shadow_region_passthrough(&vm_info, reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
287
288         PrintBoth("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
289
290         region_start += reg->length;
291       }
292       
293       //     
294       add_shadow_region_passthrough(&vm_info, 0x0, 0xa0000, (addr_t)Allocate_VMM_Pages(160));
295       
296       add_shadow_region_passthrough(&vm_info, 0xa0000, 0xc0000, 0xa0000); 
297       //hook_guest_mem(&vm_info, 0xa0000, 0xc0000, passthrough_mem_read, passthrough_mem_write, NULL);
298
299
300       // TEMP
301       //add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
302
303       if (1) {
304         add_shadow_region_passthrough(&vm_info, 0xc7000, 0xc8000, (addr_t)Allocate_VMM_Pages(1));
305         if (add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, (addr_t)Allocate_VMM_Pages(40)) == -1) {
306           PrintBoth("Error adding shadow region\n");
307         }
308       } else {
309         add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
310         add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, 0xc8000);
311       }
312
313
314       //add_shadow_region_passthrough(&vm_info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
315       add_shadow_region_passthrough(&vm_info, 0x100000, 0x1000000, (addr_t)Allocate_VMM_Pages(4096));
316
317
318       print_shadow_map(&(vm_info.mem_map));
319
320       hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
321       //hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
322
323
324       hook_io_port(&(vm_info.io_map), 0x400, &IO_Read, &IO_Write_to_Serial, NULL);
325       hook_io_port(&(vm_info.io_map), 0x401, &IO_Read, &IO_Write_to_Serial, NULL);
326       hook_io_port(&(vm_info.io_map), 0x402, &IO_Read, &IO_BOCHS_debug, NULL);
327       hook_io_port(&(vm_info.io_map), 0x403, &IO_Read, &IO_Write_to_Serial, NULL);
328
329       {
330         
331         struct vm_device * nvram = create_nvram();
332         //struct vm_device * timer = create_timer();
333         struct vm_device * pic = create_pic();
334         struct vm_device * keyboard = create_keyboard();
335         struct vm_device * pit = create_pit();
336
337         //generic_port_range_type range = {0,1024} ; // hook first 1024 ports if not already hooked
338
339         //struct vm_device * generic = create_generic(&range, 1, NULL, 0, NULL, 0);
340         
341
342         attach_device(&(vm_info), nvram);
343         //attach_device(&(vm_info), timer);
344         attach_device(&(vm_info), pic);
345         attach_device(&(vm_info), pit);
346         attach_device(&(vm_info), keyboard);
347
348         // Important that this be attached last!
349         //attach_device(&(vm_info), generic);
350
351         PrintDebugDevMgr(&(vm_info.dev_mgr));
352       }
353
354       // give keyboard interrupts to vm
355       //hook_irq(&vm_info, 1);
356       
357       // give floppy controller to vm
358       //hook_irq(&vm_info, 6);
359
360       // primary ide
361       //hook_irq(&vm_info, 14);
362
363       // secondary ide
364       //hook_irq(&vm_info, 15);
365
366
367       vm_info.rip = 0xfff0;
368       vm_info.vm_regs.rsp = 0x0;
369     }
370
371     PrintBoth("Initializing Guest (eip=0x%.8x) (esp=0x%.8x)\n", (uint_t)vm_info.rip,(uint_t)vm_info.vm_regs.rsp);
372     (vmm_ops).init_guest(&vm_info);
373     PrintBoth("Starting Guest\n");
374     //Clear_Screen();
375     (vmm_ops).start_guest(&vm_info);
376
377     return 0;
378 }