- added instructions how to update the online documentation
[bochs-mirror.git] / plex86-interface.cc
blob135ecaa5e941f6b44f4b666d8c5ce0a20e2b476e
1 /////////////////////////////////////////////////////////////////////////
2 //// $Id: plex86-interface.cc,v 1.13 2008/05/23 17:49:43 sshwarts Exp $
3 ///////////////////////////////////////////////////////////////////////////
4 ////
5 //// Copyright (C) 2002 Kevin P. Lawton
6 ////
7 //// This library is free software; you can redistribute it and/or
8 //// modify it under the terms of the GNU Lesser General Public
9 //// License as published by the Free Software Foundation; either
10 //// version 2 of the License, or (at your option) any later version.
11 ////
12 //// This library is distributed in the hope that it will be useful,
13 //// but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 //// Lesser General Public License for more details.
16 ////
17 //// You should have received a copy of the GNU Lesser General Public
18 //// License along with this library; if not, write to the Free Software
19 //// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bochs.h"
23 #include <sys/ioctl.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include "plex86-interface.h"
28 #define LOG_THIS genlog->
30 unsigned plex86State = 0;
31 int plex86FD = -1;
33 asm (".comm plex86PrintBufferPage,4096,4096");
34 asm (".comm plex86GuestCPUPage,4096,4096");
35 extern Bit8u plex86PrintBufferPage[];
36 extern Bit8u plex86GuestCPUPage[];
38 static Bit8u *plex86MemPtr = 0;
39 static size_t plex86MemSize = 0;
40 static Bit8u *plex86PrintBuffer = plex86PrintBufferPage;
41 static guest_cpu_t *plex86GuestCPU = (guest_cpu_t *) plex86GuestCPUPage;
43 static void copyPlex86StateToBochs(BX_CPU_C *cpu);
44 static void copyBochsDescriptorToPlex86(descriptor_t *, bx_descriptor_t *);
45 static void copyPlex86DescriptorToBochs(BX_CPU_C *,
46 bx_descriptor_t *, descriptor_t *);
47 static int openFD(void);
49 static unsigned faultCount[32];
52 int openFD(void)
54 if (plex86State) {
55 // This should be the first operation; no state should be set yet.
56 fprintf(stderr, "plex86: openFD: plex86State = 0x%x\n", plex86State);
57 return(0); // Error.
60 // Open a new VM.
61 fprintf(stderr, "plex86: opening VM.\n");
62 fprintf(stderr, "plex86: trying /dev/misc/plex86...");
63 plex86FD = open("/dev/misc/plex86", O_RDWR);
64 if (plex86FD < 0) {
65 fprintf(stderr, "failed.\n");
66 // Try the old name.
67 fprintf(stderr, "plex86: trying /dev/plex86...");
68 plex86FD = open("/dev/plex86", O_RDWR);
69 if (plex86FD < 0) {
70 fprintf(stderr, "failed.\n");
71 fprintf(stderr, "plex86: did you load the kernel module?"
72 " Read the toplevel README file!\n");
73 perror ("open");
74 return(-1); // Error.
77 fprintf(stderr, "OK.\n");
78 return(1); // OK.
81 unsigned plex86CpuInfo(BX_CPU_C *cpu)
83 cpuid_info_t bochsCPUID;
85 if (plex86FD < 0) {
86 // If the plex86 File Descriptor has not been opened yet.
87 if (!openFD()) {
88 return(0); // Error.
92 bochsCPUID.vendorDWord0 = cpu->cpuidInfo.vendorDWord0;
93 bochsCPUID.vendorDWord1 = cpu->cpuidInfo.vendorDWord1;
94 bochsCPUID.vendorDWord2 = cpu->cpuidInfo.vendorDWord2;
95 bochsCPUID.procSignature.raw = cpu->cpuidInfo.procSignature;
96 bochsCPUID.featureFlags.raw = cpu->cpuidInfo.featureFlags;
98 fprintf(stderr, "plex86: passing guest CPUID to plex86.\n");
99 if (ioctl(plex86FD, PLEX86_CPUID, &bochsCPUID)) {
100 perror("ioctl CPUID: ");
101 return(0); // Error.
104 return(1); // OK.
107 unsigned plex86TearDown(void)
109 fprintf(stderr, "plex86: plex86TearDown called.\n");
111 fprintf(stderr, "plex86: guest Fault Count (FYI):\n");
112 for (unsigned f=0; f<32; f++) {
113 if (faultCount[f])
114 fprintf(stderr, "plex86: FC[%u] = %u\n", f, faultCount[f]);
117 if (plex86FD < 0) {
118 fprintf(stderr, "plex86: plex86TearDown: FD not open.\n");
119 return(0);
122 if (plex86State & Plex86StateMMapPhyMem) {
123 fprintf(stderr, "plex86: unmapping guest physical memory.\n");
125 plex86State &= ~Plex86StateMMapPhyMem;
127 if (plex86State & Plex86StateMMapPrintBuffer) {
129 plex86State &= ~Plex86StateMMapPrintBuffer;
131 if (plex86State & Plex86StateMMapGuestCPU) { }
132 plex86State &= ~Plex86StateMMapGuestCPU;
134 fprintf(stderr, "plex86: tearing down VM.\n");
135 if (ioctl(plex86FD, PLEX86_TEARDOWN, 0) == -1) {
136 perror("ioctl TEARDOWN: ");
137 return(0); // Failed.
139 plex86State &= ~Plex86StateMemAllocated;
141 // Close the connection to the kernel module.
142 fprintf(stderr, "plex86: closing VM device.\n");
143 if (close(plex86FD) == -1) {
144 perror("close of VM device\n");
145 return(0); // Failed.
148 plex86FD = -1; // File descriptor is now closed.
150 plex86State = 0; // For good measure.
152 return(1); // OK.
155 unsigned plex86ExecuteInVM(BX_CPU_C *cpu)
157 plex86IoctlExecute_t executeMsg;
158 int ret;
160 if (plex86State != Plex86StateReady) {
161 fprintf(stderr, "plex86: plex86ExecuteInVM: not in ready state (0x%x)\n",
162 plex86State);
163 BX_PANIC(("plex86ExecuteInVM: bailing"));
164 return(0);
167 executeMsg.executeMethod = Plex86ExecuteMethodNative;
168 plex86GuestCPU->edi = cpu->gen_reg[BX_32BIT_REG_EDI].dword.erx;
169 plex86GuestCPU->esi = cpu->gen_reg[BX_32BIT_REG_ESI].dword.erx;
170 plex86GuestCPU->ebp = cpu->gen_reg[BX_32BIT_REG_EBP].dword.erx;
171 plex86GuestCPU->esp = cpu->gen_reg[BX_32BIT_REG_ESP].dword.erx;
172 plex86GuestCPU->ebx = cpu->gen_reg[BX_32BIT_REG_EBX].dword.erx;
173 plex86GuestCPU->edx = cpu->gen_reg[BX_32BIT_REG_EDX].dword.erx;
174 plex86GuestCPU->ecx = cpu->gen_reg[BX_32BIT_REG_ECX].dword.erx;
175 plex86GuestCPU->eax = cpu->gen_reg[BX_32BIT_REG_EAX].dword.erx;
177 plex86GuestCPU->eflags = cpu->eflags.val32;
178 plex86GuestCPU->eip = cpu->get_eip();
180 // ES/CS/SS/DS/FS/GS
181 for (unsigned s=0; s<6; s++) {
182 plex86GuestCPU->sreg[s].sel.raw = cpu->sregs[s].selector.value;
183 copyBochsDescriptorToPlex86(&plex86GuestCPU->sreg[s].des,
184 &cpu->sregs[s].cache);
185 plex86GuestCPU->sreg[s].valid = cpu->sregs[s].cache.valid;
188 // LDTR
189 plex86GuestCPU->ldtr.sel.raw = cpu->ldtr.selector.value;
190 copyBochsDescriptorToPlex86(&plex86GuestCPU->ldtr.des, &cpu->ldtr.cache);
191 plex86GuestCPU->ldtr.valid = cpu->ldtr.cache.valid;
193 // TR
194 plex86GuestCPU->tr.sel.raw = cpu->tr.selector.value;
195 copyBochsDescriptorToPlex86(&plex86GuestCPU->tr.des, &cpu->tr.cache);
196 plex86GuestCPU->tr.valid = cpu->tr.cache.valid;
198 // GDTR/IDTR
199 plex86GuestCPU->gdtr.base = cpu->gdtr.base;
200 plex86GuestCPU->gdtr.limit = cpu->gdtr.limit;
201 plex86GuestCPU->idtr.base = cpu->idtr.base;
202 plex86GuestCPU->idtr.limit = cpu->idtr.limit;
204 plex86GuestCPU->dr[0] = cpu->dr[0];
205 plex86GuestCPU->dr[1] = cpu->dr[1];
206 plex86GuestCPU->dr[2] = cpu->dr[2];
207 plex86GuestCPU->dr[3] = cpu->dr[3];
208 plex86GuestCPU->dr6 = cpu->dr6;
209 plex86GuestCPU->dr7 = cpu->dr7;
211 plex86GuestCPU->tr3 = 0; // Unimplemented in bochs.
212 plex86GuestCPU->tr4 = 0; // Unimplemented in bochs.
213 plex86GuestCPU->tr5 = 0; // Unimplemented in bochs.
214 plex86GuestCPU->tr6 = 0; // Unimplemented in bochs.
215 plex86GuestCPU->tr7 = 0; // Unimplemented in bochs.
217 plex86GuestCPU->cr0.raw = cpu->cr0.val32;
218 plex86GuestCPU->cr1 = cpu->cr1;
219 plex86GuestCPU->cr2 = cpu->cr2;
220 plex86GuestCPU->cr3 = cpu->cr3;
221 plex86GuestCPU->cr4.raw = cpu->cr4.registerValue;
223 plex86GuestCPU->a20Enable = BX_GET_ENABLE_A20();
225 ret = ioctl(plex86FD, PLEX86_EXECUTE, &executeMsg);
226 if (ret != 0) {
227 fprintf(stderr, "plex86: ioctl(PLEX86_EXECUTE): ");
228 switch (ret) {
229 case Plex86NoExecute_Method:
230 fprintf(stderr, "bad execute method.\n");
231 break;
232 case Plex86NoExecute_CR0:
233 fprintf(stderr, "bad CR0 value.\n");
234 break;
235 case Plex86NoExecute_CR4:
236 fprintf(stderr, "bad CR4 value.\n");
237 break;
238 case Plex86NoExecute_CS:
239 fprintf(stderr, "bad CS value.\n");
240 break;
241 case Plex86NoExecute_A20:
242 fprintf(stderr, "bad A20 enable value.\n");
243 break;
244 case Plex86NoExecute_Selector:
245 fprintf(stderr, "bad selector value.\n");
246 break;
247 case Plex86NoExecute_DPL:
248 fprintf(stderr, "bad descriptor DPL.\n");
249 break;
250 case Plex86NoExecute_EFlags:
251 fprintf(stderr, "bad EFlags.\n");
252 break;
253 case Plex86NoExecute_Panic:
254 fprintf(stderr, "panic.\n");
255 break;
256 case Plex86NoExecute_VMState:
257 fprintf(stderr, "bad VM state.\n");
258 break;
259 default:
260 fprintf(stderr, "ret = %d\n", ret);
263 else {
264 switch (executeMsg.monitorState.request) {
265 case MonReqFlushPrintBuf:
266 fprintf(stderr, "plex86: MonReqFlushPrintBuf:\n");
267 fprintf(stderr, "::%s\n", plex86PrintBuffer);
268 break;
269 case MonReqPanic:
270 fprintf(stderr, "plex86: MonReqPanic:\n");
271 fprintf(stderr, "::%s\n", plex86PrintBuffer);
272 break;
273 //case MonReqNone:
274 // copyPlex86StateToBochs(cpu);
275 // return(0); /* All OK. */
276 case MonReqGuestFault:
277 faultCount[ executeMsg.monitorState.guestFaultNo ]++;
278 copyPlex86StateToBochs(cpu);
279 return(0); /* All OK. */
280 default:
281 fprintf(stderr, "plex86: executeMsg.request = %u\n",
282 executeMsg.monitorState.request);
283 break;
287 plex86TearDown();
288 BX_PANIC(("plex86ExecuteInVM: bailing"));
290 return(0);
293 void copyPlex86StateToBochs(BX_CPU_C *cpu)
295 cpu->gen_reg[BX_32BIT_REG_EDI].dword.erx = plex86GuestCPU->edi;
296 cpu->gen_reg[BX_32BIT_REG_ESI].dword.erx = plex86GuestCPU->esi;
297 cpu->gen_reg[BX_32BIT_REG_EBP].dword.erx = plex86GuestCPU->ebp;
298 cpu->gen_reg[BX_32BIT_REG_ESP].dword.erx = plex86GuestCPU->esp;
299 cpu->gen_reg[BX_32BIT_REG_EBX].dword.erx = plex86GuestCPU->ebx;
300 cpu->gen_reg[BX_32BIT_REG_EDX].dword.erx = plex86GuestCPU->edx;
301 cpu->gen_reg[BX_32BIT_REG_ECX].dword.erx = plex86GuestCPU->ecx;
302 cpu->gen_reg[BX_32BIT_REG_EAX].dword.erx = plex86GuestCPU->eax;
304 cpu->eflags.val32 = plex86GuestCPU->eflags;
305 cpu->gen_reg[BX_32BIT_REG_EIP].dword.erx = plex86GuestCPU->eip;
307 // Set fields used for exception processing.
308 cpu->prev_rip = plex86GuestCPU->eip;
310 // ES/CS/SS/DS/FS/GS
311 for (unsigned s=0; s<6; s++) {
312 cpu->sregs[s].selector.value = plex86GuestCPU->sreg[s].sel.raw;
313 cpu->sregs[s].cache.valid = plex86GuestCPU->sreg[s].valid;
314 if ((cpu->sregs[s].selector.value & 0xfffc) == 0) {
315 /* Null selector. */
316 if (cpu->sregs[s].cache.valid) {
317 plex86TearDown();
318 BX_PANIC(("copyPlex86StateToBochs: null descriptor [%u] "
319 "with descriptor cache valid bit set.", s));
321 /* valid bit == 0, invalidates a bochs descriptor cache. */
323 else {
324 /* Non-null selector. */
325 if (cpu->sregs[s].cache.valid==0) {
326 plex86TearDown();
327 BX_PANIC(("copyPlex86StateToBochs: non-null descriptor [%u] "
328 "with descriptor cache valid bit clear.", s));
330 copyPlex86DescriptorToBochs(cpu, &cpu->sregs[s].cache,
331 &plex86GuestCPU->sreg[s].des);
336 void copyBochsDescriptorToPlex86(descriptor_t *plex86Desc, bx_descriptor_t *bochsDesc)
338 // For now this function is a hack to convert from bochs descriptor
339 // cache fields which are parsed out into separate fields, to
340 // a packed descriptor format as stored in a real segment descriptor.
341 // This is user only for code/data segments and the LDTR/TR.
342 // Ideally, bochs would store the 64-bit segment descriptor when
343 // it loads segment registers.
345 if (bochsDesc->valid == 0) {
346 memset(plex86Desc, 0, sizeof(*plex86Desc));
347 return;
349 plex86Desc->p = bochsDesc->p;
350 plex86Desc->dpl = bochsDesc->dpl;
351 plex86Desc->type = (bochsDesc->segment<<4) | bochsDesc->type;
352 if (bochsDesc->segment) {
353 // Code/Data segment type.
354 Bit32u limit = bochsDesc->u.segment.limit;
355 plex86Desc->limit_low = limit; // Only lower 16-bits.
356 plex86Desc->limit_high = limit >> 16;
357 Bit32u base = bochsDesc->u.segment.base;
358 plex86Desc->base_low = base;
359 plex86Desc->base_med = base >> 16;
360 plex86Desc->base_high = base >> 24;
361 plex86Desc->avl = bochsDesc->u.segment.avl;
362 plex86Desc->reserved = 0;
363 plex86Desc->d_b = bochsDesc->u.segment.d_b;
364 plex86Desc->g = bochsDesc->u.segment.g;
366 else if (bochsDesc->type == BX_SYS_SEGMENT_AVAIL_286_TSS ||
367 bochsDesc->type == BX_SYS_SEGMENT_AVAIL_386_TSS ||
368 bochsDesc->type == BX_SYS_SEGMENT_LDT)
370 // LDT or TSS
371 Bit32u limit = bochsDesc->u.system.limit;
372 plex86Desc->limit_low = limit; // Only lower 16-bits.
373 plex86Desc->limit_high = limit >> 16;
374 Bit32u base = bochsDesc->u.system.base;
375 plex86Desc->base_low = base;
376 plex86Desc->base_med = base >> 16;
377 plex86Desc->base_high = base >> 24;
378 plex86Desc->avl = bochsDesc->u.system.avl;
379 plex86Desc->reserved = 0;
380 plex86Desc->d_b = 0;
381 plex86Desc->g = bochsDesc->u.system.g;
383 else {
384 BX_PANIC(("copyBochsDescriptorToPlex86: desc type = %u.",
385 bochsDesc->type));
389 void copyPlex86DescriptorToBochs(BX_CPU_C *cpu,
390 bx_descriptor_t *bochsDesc, descriptor_t *plex86Desc)
392 Bit32u dword1, dword2, *dwordPtr;
393 dwordPtr = (Bit32u *) plex86Desc;
395 /* We can assume little endian, since we're running an x86 VM. */
396 dword1 = dwordPtr[0];
397 dword2 = dwordPtr[1];
398 cpu->parse_descriptor(dword1, dword2, bochsDesc);
401 unsigned plex86RegisterGuestMemory(Bit8u *vector, unsigned bytes)
403 plex86IoctlRegisterMem_t ioctlMsg;
405 if (plex86FD < 0) {
406 // If the plex86 File Descriptor has not been opened yet.
407 if (!openFD()) {
408 return(0); // Error.
412 if (bytes & 0x3fffff) {
413 // Memory size must be multiple of 4Meg.
414 fprintf(stderr, "plex86: RegisterGuestMemory: memory size of %u bytes"
415 "is not a 4Meg increment.\n", bytes);
416 return(0); // Error.
418 if (((unsigned)vector) & 0xfff) {
419 // Memory vector must be page aligned.
420 fprintf(stderr, "plex86: RegisterGuestMemory: vector not page aligned.");
421 return(0); // Error.
423 ioctlMsg.nMegs = bytes >> 20;
424 ioctlMsg.guestPhyMemVector = (Bit32u) vector;
425 ioctlMsg.logBufferWindow = (Bit32u) plex86PrintBuffer;
426 ioctlMsg.guestCPUWindow = (Bit32u) plex86GuestCPU;
427 if (ioctl(plex86FD, PLEX86_REGISTER_MEMORY, &ioctlMsg) == -1) {
428 return(0); // Error.
430 plex86MemSize = bytes;
432 /* For now... */
433 plex86State |= Plex86StateMemAllocated;
434 plex86State |= Plex86StateMMapPhyMem;
435 plex86State |= Plex86StateMMapPrintBuffer;
436 plex86State |= Plex86StateMMapGuestCPU;
437 // Zero out printbuffer and guestcpu here?
439 fprintf(stderr, "plex86: RegisterGuestMemory: %uMB succeeded.\n",
440 ioctlMsg.nMegs);
441 return(1); // OK.
444 unsigned plex86UnregisterGuestMemory(Bit8u *vector, unsigned bytes)
446 return(1); // OK.