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.


initial SVM guest running
[palacios.git] / palacios / src / geekos / svm.c
1 #include <geekos/svm.h>
2 #include <geekos/vmm.h>
3
4 #include <geekos/vmcb.h>
5
6 extern struct vmm_os_hooks * os_hooks;
7
8 extern uint_t cpuid_ecx(uint_t op);
9 extern uint_t cpuid_edx(uint_t op);
10 extern void Get_MSR(uint_t MSR, uint_t * high_byte, uint_t * low_byte); 
11 extern void Set_MSR(uint_t MSR, uint_t high_byte, uint_t low_byte);
12 extern uint_t launch_svm(vmcb_t * vmcb_addr);
13
14
15 /* Checks machine SVM capability */
16 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
17 int is_svm_capable() {
18   uint_t ret =  cpuid_ecx(CPUID_FEATURE_IDS);
19   uint_t vm_cr_low = 0, vm_cr_high = 0;
20
21
22   return 1;
23   if ((ret & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) {
24     PrintDebug("SVM Not Available\n");
25     return 0;
26   } 
27
28   Get_MSR(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
29
30   if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 0) {
31     return 1;
32   }
33
34   ret = cpuid_edx(CPUID_SVM_REV_AND_FEATURE_IDS);
35   
36   if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
37     PrintDebug("SVM BIOS Disabled, not unlockable\n");
38   } else {
39     PrintDebug("SVM is locked with a key\n");
40   }
41
42   return 0;
43 }
44
45
46
47 void Init_SVM() {
48   reg_ex_t msr;
49   void * host_state;
50
51
52   // setup 
53   Get_MSR(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
54   msr.e_reg.low |= EFER_MSR_svm_enable;
55   Set_MSR(EFER_MSR, 0, msr.e_reg.low);
56   
57   PrintDebug("SVM Enabled\n");
58
59
60   // Setup the host state save area
61   host_state = os_hooks->Allocate_Pages(1);
62   
63   msr.e_reg.high = 0;
64   msr.e_reg.low = (uint_t)host_state;
65
66
67   PrintDebug("Host State being saved at %x\n", (uint_t)host_state);
68   Set_MSR(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
69
70
71   return;
72 }
73
74
75 int init_svm_guest(struct guest_info *info) {
76   PrintDebug("Allocating VMCB\n");
77   info->vmm_data = (void*)Allocate_VMCB();
78
79   PrintDebug("Initializing VMCB (addr=%x)\n", info->vmm_data);
80   Init_VMCB((vmcb_t*)(info->vmm_data), *info);
81
82   return 0;
83 }
84
85
86 // can we start a kernel thread here...
87 int start_svm_guest(struct guest_info *info) {
88   vmcb_ctrl_t * guest_ctrl = 0;
89
90   ulong_t exit_code = 0;
91
92   PrintDebug("Launching SVM VM (vmcb=%x)\n", info->vmm_data);
93
94   launch_svm((vmcb_t*)(info->vmm_data));
95
96   guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
97
98
99   PrintDebug("SVM Returned: (Exit Code=%x) (VMCB=%x)\n",&(guest_ctrl->exit_code), info->vmm_data); 
100
101
102   exit_code = guest_ctrl->exit_code;
103
104   PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
105
106   return 0;
107 }
108
109
110
111 vmcb_t * Allocate_VMCB() {
112   vmcb_t * vmcb_page = (vmcb_t*)os_hooks->Allocate_Pages(1);
113
114
115   memset(vmcb_page, 0, 4096);
116
117   return vmcb_page;
118 }
119
120
121
122 void Init_VMCB(vmcb_t *vmcb, guest_info_t vm_info) {
123   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
124   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
125   uint_t i = 0;
126
127
128   guest_state->rsp = vm_info.rsp;
129   guest_state->rip = vm_info.rip;
130
131
132   /* I pretty much just gutted this from TVMM */
133   /* Note: That means its probably wrong */
134
135   // set the segment registers to mirror ours
136   guest_state->cs.selector = 0;
137   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
138   guest_state->cs.attrib.fields.S = 1;
139   guest_state->cs.attrib.fields.P = 1;
140   guest_state->cs.attrib.fields.db = 1;
141   guest_state->cs.limit = 0xffffffff;
142   guest_state->cs.base = 0;
143   
144   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
145   for ( i = 0; segregs[i] != NULL; i++) {
146     struct vmcb_selector * seg = segregs[i];
147     
148     seg->selector = 0;
149     seg->attrib.fields.type = 0x2; // Data Segment+read/write
150     seg->attrib.fields.S = 1;
151     seg->attrib.fields.P = 1;
152     seg->attrib.fields.db = 1;
153     seg->limit = 0xffffffff;
154     seg->base = 0;
155   }
156
157
158   guest_state->efer |= EFER_MSR_svm_enable;
159   guest_state->cr0 = 0x00000001;    // PE 
160   guest_state->rflags = 0x00000002; // The reserved bit is always 1
161   ctrl_area->svm_instrs.instrs.VMRUN = 1;
162   ctrl_area->guest_ASID = 1;
163
164
165
166   /* ** */
167
168 }