1 /////////////////////////////////////////////////////////////////////////
2 //// $Id: plex86-interface.cc,v 1.13 2008/05/23 17:49:43 sshwarts Exp $
3 ///////////////////////////////////////////////////////////////////////////
5 //// Copyright (C) 2002 Kevin P. Lawton
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.
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.
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
23 #include <sys/ioctl.h>
26 #include "plex86-interface.h"
28 #define LOG_THIS genlog->
30 unsigned plex86State
= 0;
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];
55 // This should be the first operation; no state should be set yet.
56 fprintf(stderr
, "plex86: openFD: plex86State = 0x%x\n", plex86State
);
61 fprintf(stderr
, "plex86: opening VM.\n");
62 fprintf(stderr
, "plex86: trying /dev/misc/plex86...");
63 plex86FD
= open("/dev/misc/plex86", O_RDWR
);
65 fprintf(stderr
, "failed.\n");
67 fprintf(stderr
, "plex86: trying /dev/plex86...");
68 plex86FD
= open("/dev/plex86", O_RDWR
);
70 fprintf(stderr
, "failed.\n");
71 fprintf(stderr
, "plex86: did you load the kernel module?"
72 " Read the toplevel README file!\n");
77 fprintf(stderr
, "OK.\n");
81 unsigned plex86CpuInfo(BX_CPU_C
*cpu
)
83 cpuid_info_t bochsCPUID
;
86 // If the plex86 File Descriptor has not been opened yet.
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: ");
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
++) {
114 fprintf(stderr
, "plex86: FC[%u] = %u\n", f
, faultCount
[f
]);
118 fprintf(stderr
, "plex86: plex86TearDown: FD not open.\n");
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.
155 unsigned plex86ExecuteInVM(BX_CPU_C
*cpu
)
157 plex86IoctlExecute_t executeMsg
;
160 if (plex86State
!= Plex86StateReady
) {
161 fprintf(stderr
, "plex86: plex86ExecuteInVM: not in ready state (0x%x)\n",
163 BX_PANIC(("plex86ExecuteInVM: bailing"));
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();
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
;
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
;
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
;
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
);
227 fprintf(stderr
, "plex86: ioctl(PLEX86_EXECUTE): ");
229 case Plex86NoExecute_Method
:
230 fprintf(stderr
, "bad execute method.\n");
232 case Plex86NoExecute_CR0
:
233 fprintf(stderr
, "bad CR0 value.\n");
235 case Plex86NoExecute_CR4
:
236 fprintf(stderr
, "bad CR4 value.\n");
238 case Plex86NoExecute_CS
:
239 fprintf(stderr
, "bad CS value.\n");
241 case Plex86NoExecute_A20
:
242 fprintf(stderr
, "bad A20 enable value.\n");
244 case Plex86NoExecute_Selector
:
245 fprintf(stderr
, "bad selector value.\n");
247 case Plex86NoExecute_DPL
:
248 fprintf(stderr
, "bad descriptor DPL.\n");
250 case Plex86NoExecute_EFlags
:
251 fprintf(stderr
, "bad EFlags.\n");
253 case Plex86NoExecute_Panic
:
254 fprintf(stderr
, "panic.\n");
256 case Plex86NoExecute_VMState
:
257 fprintf(stderr
, "bad VM state.\n");
260 fprintf(stderr
, "ret = %d\n", ret
);
264 switch (executeMsg
.monitorState
.request
) {
265 case MonReqFlushPrintBuf
:
266 fprintf(stderr
, "plex86: MonReqFlushPrintBuf:\n");
267 fprintf(stderr
, "::%s\n", plex86PrintBuffer
);
270 fprintf(stderr
, "plex86: MonReqPanic:\n");
271 fprintf(stderr
, "::%s\n", plex86PrintBuffer
);
274 // copyPlex86StateToBochs(cpu);
275 // return(0); /* All OK. */
276 case MonReqGuestFault
:
277 faultCount
[ executeMsg
.monitorState
.guestFaultNo
]++;
278 copyPlex86StateToBochs(cpu
);
279 return(0); /* All OK. */
281 fprintf(stderr
, "plex86: executeMsg.request = %u\n",
282 executeMsg
.monitorState
.request
);
288 BX_PANIC(("plex86ExecuteInVM: bailing"));
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
;
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) {
316 if (cpu
->sregs
[s
].cache
.valid
) {
318 BX_PANIC(("copyPlex86StateToBochs: null descriptor [%u] "
319 "with descriptor cache valid bit set.", s
));
321 /* valid bit == 0, invalidates a bochs descriptor cache. */
324 /* Non-null selector. */
325 if (cpu
->sregs
[s
].cache
.valid
==0) {
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
));
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
)
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;
381 plex86Desc
->g
= bochsDesc
->u
.system
.g
;
384 BX_PANIC(("copyBochsDescriptorToPlex86: desc type = %u.",
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
;
406 // If the plex86 File Descriptor has not been opened yet.
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
);
418 if (((unsigned)vector
) & 0xfff) {
419 // Memory vector must be page aligned.
420 fprintf(stderr
, "plex86: RegisterGuestMemory: vector not page aligned.");
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) {
430 plex86MemSize
= bytes
;
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",
444 unsigned plex86UnregisterGuestMemory(Bit8u
*vector
, unsigned bytes
)