IOMAllMMIO.cpp revision 389b9f89a42b9efcb0d843a6a45c54418dd02e11
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync/* $Id$ */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @file
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync * IOM - Input / Output Monitor - Guest Context.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 innotek GmbH
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * available from http://www.virtualbox.org. This file is free software;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License as published by the Free Software Foundation,
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Header Files *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define LOG_GROUP LOG_GROUP_IOM
cd6f71bc352f550074f1ba2c830a2cf2f0b3dd46vboxsync#include <VBox/iom.h>
da957c069c2a3c582fe265ff88170ce4c42b499dvboxsync#include <VBox/cpum.h>
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#include <VBox/pgm.h>
009d45aa55691312278d41edb20154dc208d9cd8vboxsync#include <VBox/selm.h>
16a9adc14900ca18e6909679a579f6833425e030vboxsync#include <VBox/mm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/em.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/pgm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/trpm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include "IOMInternal.h"
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/vm.h>
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#include <VBox/dis.h>
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync#include <VBox/disopcode.h>
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#include <VBox/param.h>
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#include <VBox/err.h>
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#include <iprt/assert.h>
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#include <VBox/log.h>
efff36b306e370346025647a158689021df2e1d1vboxsync#include <iprt/asm.h>
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#include <iprt/string.h>
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/*******************************************************************************
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync* Internal Functions *
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync*******************************************************************************/
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncstatic bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize);
efff36b306e370346025647a158689021df2e1d1vboxsyncstatic bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t u32Data);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
efff36b306e370346025647a158689021df2e1d1vboxsync* Global Variables *
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync*******************************************************************************/
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/**
efff36b306e370346025647a158689021df2e1d1vboxsync * Array for accessing 32-bit general registers in VMMREGFRAME structure
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * by register's index from disasm.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic unsigned g_aReg32Index[] =
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_EAX */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_ECX */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_EDX */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_EBX */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_ESP */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_EBP */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_ESI */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_EDI */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync};
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure.
0abd77741a608f6c41c8dfcd4781b8b84adf1044vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define ACCESS_REG32(p, idx) (*((uint32_t *)((char *)(p) + g_aReg32Index[idx])))
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Array for accessing 16-bit general registers in CPUMCTXCORE structure
9496f2d398b49813176939d7a339ae513d5175efvboxsync * by register's index from disasm.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncstatic unsigned g_aReg16Index[] =
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync{
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AX */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CX */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DX */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BX */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_SP */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_BP */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_SI */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_DI */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync};
c0a370e600bb60153a269fb32b5f709347c35768vboxsync
c0a370e600bb60153a269fb32b5f709347c35768vboxsync/**
c0a370e600bb60153a269fb32b5f709347c35768vboxsync * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure.
c0a370e600bb60153a269fb32b5f709347c35768vboxsync */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#define ACCESS_REG16(p, idx) (*((uint16_t *)((char *)(p) + g_aReg16Index[idx])))
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync/**
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Array for accessing 8-bit general registers in CPUMCTXCORE structure
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * by register's index from disasm.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic unsigned g_aReg8Index[] =
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AL */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CL */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DL */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BL */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, eax) + 1, /* USE_REG_AH */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, ecx) + 1, /* USE_REG_CH */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync RT_OFFSETOF(CPUMCTXCORE, edx) + 1, /* USE_REG_DH */
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync RT_OFFSETOF(CPUMCTXCORE, ebx) + 1 /* USE_REG_BH */
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync};
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync/**
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define ACCESS_REG8(p, idx) (*((uint8_t *)((char *)(p) + g_aReg8Index[idx])))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Array for accessing segment registers in CPUMCTXCORE structure
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * by register's index from disasm.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic unsigned g_aRegSegIndex[] =
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync{
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync RT_OFFSETOF(CPUMCTXCORE, es), /* USE_REG_ES */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, cs), /* USE_REG_CS */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, ss), /* USE_REG_SS */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, ds), /* USE_REG_DS */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_OFFSETOF(CPUMCTXCORE, fs), /* USE_REG_FS */
9496f2d398b49813176939d7a339ae513d5175efvboxsync RT_OFFSETOF(CPUMCTXCORE, gs) /* USE_REG_GS */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync};
9496f2d398b49813176939d7a339ae513d5175efvboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Macro for accessing segment registers in CPUMCTXCORE structure.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync#define ACCESS_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])))
21029597fc4b76d0db0c9542daee201447281781vboxsync
21029597fc4b76d0db0c9542daee201447281781vboxsync/**
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * Array for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic const unsigned g_aSize2Shift[] =
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync ~0, /* 0 - invalid */
9496f2d398b49813176939d7a339ae513d5175efvboxsync 0, /* *1 == 2^0 */
16a9adc14900ca18e6909679a579f6833425e030vboxsync 1, /* *2 == 2^1 */
16a9adc14900ca18e6909679a579f6833425e030vboxsync ~0, /* 3 - invalid */
16a9adc14900ca18e6909679a579f6833425e030vboxsync 2, /* *4 == 2^2 */
16a9adc14900ca18e6909679a579f6833425e030vboxsync ~0, /* 5 - invalid */
c0a370e600bb60153a269fb32b5f709347c35768vboxsync ~0, /* 6 - invalid */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync ~0, /* 7 - invalid */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync 3 /* *8 == 2^3 */
c0a370e600bb60153a269fb32b5f709347c35768vboxsync};
c0a370e600bb60153a269fb32b5f709347c35768vboxsync
c0a370e600bb60153a269fb32b5f709347c35768vboxsync/**
c0a370e600bb60153a269fb32b5f709347c35768vboxsync * Macro for fast recode of the operand size (1/2/4/8 bytes) to bit shift value.
c0a370e600bb60153a269fb32b5f709347c35768vboxsync */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync#define SIZE2SHIFT(cb) (g_aSize2Shift[cb])
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Wrapper which does the write and updates range statistics when such are enabled.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @warning VBOX_SUCCESS(rc=VINF_IOM_HC_MMIO_WRITE) is TRUE!
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncinline int iomGCMMIODoWrite(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, const void *pvData, unsigned cbSize)
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync{
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync#ifdef VBOX_WITH_STATISTICS
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pRange->cbSize <= PAGE_SIZE)
16a9adc14900ca18e6909679a579f6833425e030vboxsync {
16a9adc14900ca18e6909679a579f6833425e030vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!pStats)
16a9adc14900ca18e6909679a579f6833425e030vboxsync return VINF_IOM_HC_MMIO_WRITE;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cbSize); /* @todo fix const!! */
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (rc != VINF_IOM_HC_MMIO_WRITE)
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_COUNTER_INC(&pStats->WriteGC);
16a9adc14900ca18e6909679a579f6833425e030vboxsync return rc;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync }
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync#endif
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync return pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, (void *)pvData, cbSize);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync}
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync/**
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Wrapper which does the read and updates range statistics when such are enabled.
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync */
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsyncinline int iomGCMMIODoRead(PVM pVM, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault, void *pvData, unsigned cbSize)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync{
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync#ifdef VBOX_WITH_STATISTICS
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (pRange->cbSize <= PAGE_SIZE)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync {
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (!pStats)
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync return VINF_IOM_HC_MMIO_READ;
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cbSize);
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync if (rc != VINF_IOM_HC_MMIO_READ)
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync STAM_COUNTER_INC(&pStats->ReadGC);
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync return rc;
681fd85cc7cd49e9cf66a917d6ae9ff36eb7d9e9vboxsync }
009d45aa55691312278d41edb20154dc208d9cd8vboxsync#endif
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhysFault, pvData, cbSize);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Returns the contents of register or immediate data of instruction's parameter.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns true on success.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pCpu Pointer to current disassembler context.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pParam Pointer to parameter of instruction to proccess.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pu32Data Where to store retrieved data.
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync * @param pcbSize Where to store the size of data (1, 2, 4).
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncstatic bool iomGCGetRegImmData(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, uint32_t *pu32Data, unsigned *pcbSize)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync{
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32))
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pcbSize = 0;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = 0;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return false;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync }
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync if (pParam->flags & USE_REG_GEN32)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pcbSize = 4;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = ACCESS_REG32(pRegFrame, pParam->base.reg_gen32);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return true;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync }
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync if (pParam->flags & USE_REG_GEN16)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pcbSize = 2;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = ACCESS_REG16(pRegFrame, pParam->base.reg_gen16);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return true;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync }
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync if (pParam->flags & USE_REG_GEN8)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pcbSize = 1;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync *pu32Data = ACCESS_REG8(pRegFrame, pParam->base.reg_gen8);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_SX8))
16a9adc14900ca18e6909679a579f6833425e030vboxsync {
16a9adc14900ca18e6909679a579f6833425e030vboxsync *pcbSize = 4;
16a9adc14900ca18e6909679a579f6833425e030vboxsync *pu32Data = (uint32_t)pParam->parval;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_SX8))
16a9adc14900ca18e6909679a579f6833425e030vboxsync {
16a9adc14900ca18e6909679a579f6833425e030vboxsync *pcbSize = 2;
16a9adc14900ca18e6909679a579f6833425e030vboxsync *pu32Data = (uint16_t)pParam->parval;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pParam->flags & USE_IMMEDIATE8)
16a9adc14900ca18e6909679a579f6833425e030vboxsync {
16a9adc14900ca18e6909679a579f6833425e030vboxsync *pcbSize = 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync *pu32Data = (uint8_t)pParam->parval;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return true;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (pParam->flags & USE_REG_SEG)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *pcbSize = 2;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *pu32Data = ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return true;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync } /* Else - error. */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *pcbSize = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *pu32Data = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return false;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync/**
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * Saves data to 8/16/32 general purpose or segment register defined by
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * instruction's parameter.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @returns true on success.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pCpu Pointer to current disassembler context.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pParam Pointer to parameter of instruction to proccess.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest structure.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param u32Data 8/16/32 bit data to store.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncstatic bool iomGCSaveDataToReg(PDISCPUSTATE pCpu, PCOP_PARAMETER pParam, PCPUMCTXCORE pRegFrame, unsigned u32Data)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (pParam->flags & (USE_BASE | USE_INDEX | USE_SCALE | USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE32_SX8 | USE_IMMEDIATE16_SX8))
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return false;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (pParam->flags & USE_REG_GEN32)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ACCESS_REG32(pRegFrame, pParam->base.reg_gen32) = u32Data;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return true;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (pParam->flags & USE_REG_GEN16)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ACCESS_REG16(pRegFrame, pParam->base.reg_gen16) = (uint16_t)u32Data;
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync return true;
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync if (pParam->flags & USE_REG_GEN8)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ACCESS_REG8(pRegFrame, pParam->base.reg_gen8) = (uint8_t)u32Data;
9496f2d398b49813176939d7a339ae513d5175efvboxsync return true;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (pParam->flags & USE_REG_SEG)
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync {
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync ACCESS_REGSEG(pRegFrame, pParam->base.reg_seg) = (uint16_t)u32Data;
22ec733a5e041fcdfe02fce2eafc9faf8b0077ddvboxsync return true;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* Else - error. */
9496f2d398b49813176939d7a339ae513d5175efvboxsync return false;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync/*
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Internal - statistics only.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsyncinline void iomGCMMIOStatLength(PVM pVM, unsigned cb)
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#ifdef VBOX_WITH_STATISTICS
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync switch (cb)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync case 1:
d5ea45cc92d7f1d3ade8189944531f665bfe8ed5vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO1Byte);
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync break;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync case 2:
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO2Bytes);
d5ea45cc92d7f1d3ade8189944531f665bfe8ed5vboxsync break;
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync case 4:
d5ea45cc92d7f1d3ade8189944531f665bfe8ed5vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIO4Bytes);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync break;
9496f2d398b49813176939d7a339ae513d5175efvboxsync default:
9496f2d398b49813176939d7a339ae513d5175efvboxsync /* No way. */
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync AssertMsgFailed(("Invalid data length %d\n", cb));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync break;
468c2bcb36eb9a032f5dd0fcb34db10bd58e9996vboxsync }
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync#else
9496f2d398b49813176939d7a339ae513d5175efvboxsync NOREF(pVM); NOREF(cb);
16a9adc14900ca18e6909679a579f6833425e030vboxsync#endif
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync/**
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * MOV reg, mem (read)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * MOVZX reg, mem (read)
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync * MOVSX reg, mem (read)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @returns VBox status code.
ffbe6daf773e38167f3cabaf1f063d84ecd063e9vboxsync *
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pVM The virtual machine (GC pointer ofcourse).
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync * @param pCpu Disassembler CPU state.
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync * @param pRange Pointer MMIO range.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsyncstatic int iomGCInterpretMOVxXRead(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync{
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync /*
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync * If no read handler then go to ring-3 and handle it there.
ba74637cb4d2e749337d51ccbfb1038bdd3e2092vboxsync */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync if (!pRange->pfnReadCallback)
ba74637cb4d2e749337d51ccbfb1038bdd3e2092vboxsync return VINF_IOM_HC_MMIO_READ;
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync
ba74637cb4d2e749337d51ccbfb1038bdd3e2092vboxsync /*
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync * Get the data size from parameter 2,
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync * and call the handler function to get the data.
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync */
61d064a54f03596920c3918f58ecc7764074a5d8vboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync AssertMsg(cbSize > 0 && cbSize <= sizeof(uint32_t), ("cbSize=%d\n", cbSize));
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync uint32_t u32Data = 0;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &u32Data, cbSize);
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync if (rc == VINF_SUCCESS)
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync {
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync /*
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync * Do sign extension for MOVSX.
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync */
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync /** @todo checkup MOVSX implementation! */
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync if (pCpu->pCurInstr->opcode == OP_MOVSX)
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync {
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync if (cbSize == 1)
b5ad839a3757b305d4e98d7264da2b53c9cd27f0vboxsync {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* DWORD <- BYTE */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int32_t iData = (int8_t)u32Data;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync u32Data = (uint32_t)iData;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync else
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* DWORD <- WORD */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int32_t iData = (int16_t)u32Data;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync u32Data = (uint32_t)iData;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Store the result to register (parameter 1).
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, u32Data);
16a9adc14900ca18e6909679a579f6833425e030vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (rc == VINF_SUCCESS)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync iomGCMMIOStatLength(pVM, cbSize);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return rc;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * MOV mem, reg|imm (write)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @returns VBox status code.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
16a9adc14900ca18e6909679a579f6833425e030vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * @param pCpu Disassembler CPU state.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRange Pointer MMIO range.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncstatic int iomGCInterpretMOVxXWrite(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange, RTGCPHYS GCPhysFault)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * If no write handler then go to ring-3 and handle it there.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!pRange->pfnWriteCallback)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return VINF_IOM_HC_MMIO_WRITE;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync /*
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync * Get data to write from second parameter,
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync * and call the callback to write it.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync */
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync unsigned cbSize = 0;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync uint32_t u32Data = 0;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &u32Data, &cbSize);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &u32Data, cbSize);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (rc == VINF_SUCCESS)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync iomGCMMIOStatLength(pVM, cbSize);
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync return rc;
9496f2d398b49813176939d7a339ae513d5175efvboxsync}
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync/** @todo All the string MMIO stuff can do terrible things since physical contiguous mappings are
9496f2d398b49813176939d7a339ae513d5175efvboxsync * assumed all over the place! This must be addressed in a general way, like for example let EM do
16a9adc14900ca18e6909679a579f6833425e030vboxsync * all the interpretation and checking of selectors and addresses.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * -> I don't see the problem here. MMIO ranges are by definition linear ranges. The virtual source or destination is read/written properly.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncDECLINLINE(int) iomRamRead(PVM pVM, void *pDest, RTGCPTR GCSrc, uint32_t cb)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#ifdef IN_GC
9496f2d398b49813176939d7a339ae513d5175efvboxsync return MMGCRamReadNoTrapHandler(pDest, GCSrc, cb);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#else
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return PGMPhysReadGCPtrSafe(pVM, pDest, GCSrc, cb);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#endif
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncDECLINLINE(int) iomRamWrite(PVM pVM, RTGCPTR GCDest, void *pSrc, uint32_t cb)
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync{
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync#ifdef IN_GC
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync return MMGCRamWriteNoTrapHandler(GCDest, pSrc, cb);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync#else
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync return PGMPhysWriteGCPtrSafe(pVM, GCDest, pSrc, cb);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync#endif
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync/**
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * [REP] MOVSB
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync * [REP] MOVSW
9496f2d398b49813176939d7a339ae513d5175efvboxsync * [REP] MOVSD
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Restricted implementation.
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
16a9adc14900ca18e6909679a579f6833425e030vboxsync *
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @returns VBox status code.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param uErrorCode CPU Error code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync * @param pCpu Disassembler CPU state.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * @param pRange Pointer MMIO range.
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#ifdef IOMGC_MOVS_SUPPORT
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic int iomGCInterpretMOVS(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovs, a);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * We do not support segment prefixes or REPNE.
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync */
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync if (pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE))
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync return VINF_IOM_HC_MMIO_READ_WRITE;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
7766bf675357fd940d8c49e69a5d72dc6eaa6be4vboxsync * Get bytes/words/dwords count to copy.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync uint32_t cTransfers = 1;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (pCpu->prefix & PREFIX_REP)
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync cTransfers = pRegFrame->ecx;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
9496f2d398b49813176939d7a339ae513d5175efvboxsync cTransfers &= 0xffff;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!cTransfers)
9496f2d398b49813176939d7a339ae513d5175efvboxsync return VINF_SUCCESS;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync }
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /* Get the current privilege level. */
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /*
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Get data size.
9496f2d398b49813176939d7a339ae513d5175efvboxsync */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync Assert(cbSize);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#ifdef VBOX_WITH_STATISTICS
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pVM->iom.s.cMovsMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync pVM->iom.s.cMovsMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync RTGCPHYS Phys = GCPhysFault;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync int rc;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync if (uErrorCode & X86_TRAP_PF_RW)
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync {
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /*
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * Write operation: [Mem] -> [MMIO]
9496f2d398b49813176939d7a339ae513d5175efvboxsync * ds:esi (Virt Src) -> es:edi (Phys Dst)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Check callback. */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!pRange->pfnWriteCallback)
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync return VINF_IOM_HC_MMIO_WRITE;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync }
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /* Convert source address ds:esi. */
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync RTGCUINTPTR pu8Virt;
9496f2d398b49813176939d7a339ae513d5175efvboxsync rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
9496f2d398b49813176939d7a339ae513d5175efvboxsync SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync (PRTGCPTR)&pu8Virt, NULL);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync if (VBOX_SUCCESS(rc))
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync {
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync /* Access verification first; we currently can't recover properly from traps inside this instruction */
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync rc = PGMVerifyAccess(pVM, pu8Virt, cTransfers * cbSize, (cpl == 3) ? X86_PTE_US : 0);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync if (rc != VINF_SUCCESS)
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync {
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync return VINF_EM_RAW_EMULATE_INSTR;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync }
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync#ifdef IN_GC
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync MMGCRamRegisterTrapHandler(pVM);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync#endif
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync /* copy loop. */
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync while (cTransfers)
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync {
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync uint32_t u32Data = 0;
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync rc = iomRamRead(pVM, &u32Data, (RTGCPTR)pu8Virt, cbSize);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (rc != VINF_SUCCESS)
16a9adc14900ca18e6909679a579f6833425e030vboxsync break;
16a9adc14900ca18e6909679a579f6833425e030vboxsync rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (rc != VINF_SUCCESS)
16a9adc14900ca18e6909679a579f6833425e030vboxsync break;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync pu8Virt += offIncrement;
16a9adc14900ca18e6909679a579f6833425e030vboxsync Phys += offIncrement;
16a9adc14900ca18e6909679a579f6833425e030vboxsync pRegFrame->esi += offIncrement;
16a9adc14900ca18e6909679a579f6833425e030vboxsync pRegFrame->edi += offIncrement;
16a9adc14900ca18e6909679a579f6833425e030vboxsync cTransfers--;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync#ifdef IN_GC
16a9adc14900ca18e6909679a579f6833425e030vboxsync MMGCRamDeregisterTrapHandler(pVM);
16a9adc14900ca18e6909679a579f6833425e030vboxsync#endif
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Update ecx. */
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pCpu->prefix & PREFIX_REP)
16a9adc14900ca18e6909679a579f6833425e030vboxsync pRegFrame->ecx = cTransfers;
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsToMMIO, a2);
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync else
16a9adc14900ca18e6909679a579f6833425e030vboxsync rc = VINF_IOM_HC_MMIO_READ_WRITE;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync else
16a9adc14900ca18e6909679a579f6833425e030vboxsync {
16a9adc14900ca18e6909679a579f6833425e030vboxsync /*
16a9adc14900ca18e6909679a579f6833425e030vboxsync * Read operation: [MMIO] -> [mem] or [MMIO] -> [MMIO]
16a9adc14900ca18e6909679a579f6833425e030vboxsync * ds:[eSI] (Phys Src) -> es:[eDI] (Virt Dst)
16a9adc14900ca18e6909679a579f6833425e030vboxsync */
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Check callback. */
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!pRange->pfnReadCallback)
16a9adc14900ca18e6909679a579f6833425e030vboxsync return VINF_IOM_HC_MMIO_READ;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync /* Convert destination address. */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync RTGCUINTPTR pu8Virt;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync (RTGCPTR *)&pu8Virt, NULL);
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync if (VBOX_FAILURE(rc))
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync return VINF_EM_RAW_GUEST_TRAP;
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /* Check if destination address is MMIO. */
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync RTGCPHYS PhysDst;
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync rc = PGMGstGetPage(pVM, (RTGCPTR)pu8Virt, NULL, &PhysDst);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync if ( VBOX_SUCCESS(rc)
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync && iomMMIOGetRangeHC(&pVM->iom.s, PhysDst))
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync {
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync /*
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync * Extra: [MMIO] -> [MMIO]
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync */
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsMMIO, d);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync PhysDst |= (RTGCUINTPTR)pu8Virt & PAGE_OFFSET_MASK;
efff36b306e370346025647a158689021df2e1d1vboxsync CTXALLSUFF(PIOMMMIORANGE) pMMIODst = iomMMIOGetRange(&pVM->iom.s, PhysDst);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if ( !pMMIODst
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync || !pMMIODst->pfnWriteCallback)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync return VINF_IOM_HC_MMIO_READ_WRITE;
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync }
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync /* copy loop. */
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync while (cTransfers)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t u32Data;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc != VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync break;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoWrite(pVM, pMMIODst, PhysDst, &u32Data, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc != VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync break;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Phys += offIncrement;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync PhysDst += offIncrement;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->esi += offIncrement;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->edi += offIncrement;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync cTransfers--;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsMMIO, d);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Normal: [MMIO] -> [Mem]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Access verification first; we currently can't recover properly from traps inside this instruction */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = PGMVerifyAccess(pVM, pu8Virt, cTransfers * cbSize, X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc != VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Log(("MOVS will generate a trap -> recompiler, rc=%d\n", rc));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VINF_EM_RAW_EMULATE_INSTR;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* copy loop. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#ifdef IN_GC
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync MMGCRamRegisterTrapHandler(pVM);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#endif
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync while (cTransfers)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t u32Data;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = iomGCMMIODoRead(pVM, pRange, Phys, &u32Data, cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (rc != VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync break;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomRamWrite(pVM, (RTGCPTR)pu8Virt, &u32Data, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc != VINF_SUCCESS)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync Log(("iomRamWrite %08X size=%d failed with %d\n", pu8Virt, cbSize, rc));
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pu8Virt += offIncrement;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync Phys += offIncrement;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->esi += offIncrement;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->edi += offIncrement;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cTransfers--;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#ifdef IN_GC
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync MMGCRamDeregisterTrapHandler(pVM);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#endif
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovsFromMMIO, c);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update ecx on exit. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pCpu->prefix & PREFIX_REP)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->ecx = cTransfers;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* work statistics. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMovs, a);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync iomGCMMIOStatLength(pVM, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync return rc;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#endif
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/**
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * [REP] STOSB
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * [REP] STOSW
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * [REP] STOSD
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync *
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @returns VBox status code.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncstatic int iomGCInterpretSTOS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstStos, a);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * We do not support segment prefixes or REPNE..
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pCpu->prefix & (PREFIX_SEG | PREFIX_REPNE))
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync return VINF_IOM_HC_MMIO_READ_WRITE;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /*
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Get bytes/words/dwords count to copy.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t cTransfers = 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pCpu->prefix & PREFIX_REP)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cTransfers = pRegFrame->ecx;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cTransfers &= 0xffff;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (!cTransfers)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync return VINF_SUCCESS;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /*
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Get data size.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param1);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync Assert(cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#ifdef VBOX_WITH_STATISTICS
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pVM->iom.s.cStosMaxBytes < (cTransfers << SIZE2SHIFT(cbSize)))
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pVM->iom.s.cStosMaxBytes = cTransfers << SIZE2SHIFT(cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#endif
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync RTGCPHYS Phys = GCPhysFault;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync uint32_t u32Data = pRegFrame->eax;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int rc;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pRange->pfnFillCallback)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /*
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Use the fill callback.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /** @todo pfnFillCallback must return number of bytes successfully written!!! */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (offIncrement > 0)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* addr++ variant. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, Phys, u32Data, cbSize, cTransfers);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update registers. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->edi += cTransfers << SIZE2SHIFT(cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pCpu->prefix & PREFIX_REP)
59a2c1c0a4a0762b46bc5ff056f5705ec9c0a660vboxsync pRegFrame->ecx = 0;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync else
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* addr-- variant. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = pRange->pfnFillCallback(pRange->pDevIns, pRange->pvUser, (Phys - (cTransfers - 1)) << SIZE2SHIFT(cbSize), u32Data, cbSize, cTransfers);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (rc == VINF_SUCCESS)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update registers. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->edi -= cTransfers << SIZE2SHIFT(cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pCpu->prefix & PREFIX_REP)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->ecx = 0;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync else
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /*
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Use the write callback.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Check write callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (!pRange->pfnWriteCallback)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync return VINF_IOM_HC_MMIO_WRITE;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* fill loop. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync do
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rc = iomGCMMIODoWrite(pVM, pRange, Phys, &u32Data, cbSize);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (rc != VINF_SUCCESS)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Phys += offIncrement;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->edi += offIncrement;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cTransfers--;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync } while (cTransfers);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /* Update ecx on exit. */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (pCpu->prefix & PREFIX_REP)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync pRegFrame->ecx = cTransfers;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync /*
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Work statistics and return.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstStos, a);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync iomGCMMIOStatLength(pVM, cbSize);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync }
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync return rc;
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync}
4bd3e7685494afe7c303fc131c66e685023b6b4avboxsync
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync
4bd3e7685494afe7c303fc131c66e685023b6b4avboxsync/**
4bd3e7685494afe7c303fc131c66e685023b6b4avboxsync * [REP] LODSB
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * [REP] LODSW
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * [REP] LODSD
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync *
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * Restricted implementation.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync *
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync *
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @returns VBox status code.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync *
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @param pVM The virtual machine (GC pointer ofcourse).
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic int iomGCInterpretLODS(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstLods, a1);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /*
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * We do not support segment prefixes or REP*.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync */
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync if (pCpu->prefix & (PREFIX_SEG | PREFIX_REP | PREFIX_REPNE))
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync return VINF_IOM_HC_MMIO_READ_WRITE;
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check that we can handle it. */
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync if (!pRange->pfnReadCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VINF_IOM_HC_MMIO_READ;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Get data size.
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync unsigned cbSize = DISGetParamSize(pCpu, &pCpu->param2);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync Assert(cbSize);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync int offIncrement = pRegFrame->eflags.Bits.u1DF ? -(signed)cbSize : (signed)cbSize;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /*
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Perform read.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync int rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &pRegFrame->eax, cbSize);
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync if (rc == VINF_SUCCESS)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync pRegFrame->esi += offIncrement;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /*
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Work statistics and return.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (rc == VINF_SUCCESS)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstLods, a1);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync iomGCMMIOStatLength(pVM, cbSize);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync }
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync return rc;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync}
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync/**
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * CMP [MMIO], reg|imm
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * CMP reg|imm, [MMIO]
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync *
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Restricted implementation.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync *
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync *
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
8dbf70ba2345e69b0b6d45c38cf1add0ef10591cvboxsync * @param pCpu Disassembler CPU state.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsyncstatic int iomGCInterpretCMP(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync{
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstCmp, a1);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /* Check read callback. */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (!pRange->pfnReadCallback)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync return VINF_EM_RAW_GUEST_TRAP;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /*
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync * Get the operands.
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync unsigned cbSize = 0;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync uint32_t uData1;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync uint32_t uData2;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync int rc;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /* cmp reg, [MMIO]. */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* cmp [MMIO], reg|imm. */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Disassember CMP problem..\n"));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Emulate CMP and update guest flags. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t eflags = EMEmulateCmp(uData1, uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
efff36b306e370346025647a158689021df2e1d1vboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstCmp, a1);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync iomGCMMIOStatLength(pVM, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync/**
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * AND [MMIO], reg|imm
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * AND reg, [MMIO]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
51a01524909c95ee04b636218b6a89b29fb81825vboxsyncstatic int iomGCInterpretAND(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
51a01524909c95ee04b636218b6a89b29fb81825vboxsync{
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstAnd, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check read callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbSize = 0;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t uData1;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t uData2;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync bool fAndWrite;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* and reg, [MMIO]. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync fAndWrite = false;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pRange->pfnReadCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = VINF_IOM_HC_MMIO_READ;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* and [MMIO], reg|imm. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync fAndWrite = true;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pRange->pfnReadCallback && pRange->pfnWriteCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = VINF_IOM_HC_MMIO_READ_WRITE;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Disassember AND problem..\n"));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Emulate AND and update guest flags. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (fAndWrite)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to MMIO. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to register. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Update guest's eflags and finish. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstAnd, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync iomGCMMIOStatLength(pVM, cbSize);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync return rc;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync/**
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * TEST [MMIO], reg|imm
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * TEST reg, [MMIO]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
b0b15690f00527424b2d5fb88456d747252322f7vboxsyncstatic int iomGCInterpretTEST(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync{
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check read callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbSize = 0;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t uData1;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t uData2;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
a2f96875f61628e5a5fd33785f8c0bbb310f981fvboxsync /* and test, [MMIO]. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pRange->pfnReadCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = VINF_IOM_HC_MMIO_READ;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* test [MMIO], reg|imm. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pRange->pfnReadCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = VINF_IOM_HC_MMIO_READ;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Disassember TEST problem..\n"));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
51a01524909c95ee04b636218b6a89b29fb81825vboxsync
51a01524909c95ee04b636218b6a89b29fb81825vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /* Emulate TEST (=AND without write back) and update guest EFLAGS. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t eflags = EMEmulateAnd(&uData1, uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync pRegFrame->eflags.u32 = (pRegFrame->eflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF))
b0b15690f00527424b2d5fb88456d747252322f7vboxsync | (eflags & (X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF));
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync iomGCMMIOStatLength(pVM, cbSize);
a2f96875f61628e5a5fd33785f8c0bbb310f981fvboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync/**
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * XCHG [MMIO], reg
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * XCHG reg, [MMIO]
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Restricted implementation.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pRegFrame Trap register frame.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pCpu Disassembler CPU state.
a2f96875f61628e5a5fd33785f8c0bbb310f981fvboxsync * @param pRange Pointer MMIO range.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncstatic int iomGCInterpretXCHG(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, PDISCPUSTATE pCpu, CTXALLSUFF(PIOMMMIORANGE) pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync{
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstTest, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Check read callback. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbSize = 0;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t uData1;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync uint32_t uData2;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (!pRange->pfnReadCallback || !pRange->pfnWriteCallback)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = VINF_IOM_HC_MMIO_READ;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync goto end;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uData1, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* xchg reg, [MMIO]. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData2, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to MMIO. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* Store result to register. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param1, pRegFrame, uData2);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (iomGCGetRegImmData(pCpu, &pCpu->param2, pRegFrame, &uData2, &cbSize))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /* xchg [MMIO], reg. */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync rc = iomGCMMIODoRead(pVM, pRange, GCPhysFault, &uData1, cbSize);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (rc == VINF_SUCCESS)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /* Store result to MMIO. */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync rc = iomGCMMIODoWrite(pVM, pRange, GCPhysFault, &uData2, cbSize);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync
51a01524909c95ee04b636218b6a89b29fb81825vboxsync if (rc == VINF_SUCCESS)
51a01524909c95ee04b636218b6a89b29fb81825vboxsync {
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /* Store result to register. */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync bool fRc = iomGCSaveDataToReg(pCpu, &pCpu->param2, pRegFrame, uData1);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync AssertMsg(fRc, ("Failed to store register value!\n")); NOREF(fRc);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync }
51a01524909c95ee04b636218b6a89b29fb81825vboxsync else
51a01524909c95ee04b636218b6a89b29fb81825vboxsync Assert(rc == VINF_IOM_HC_MMIO_WRITE || rc == VINF_PATM_HC_MMIO_PATCH_WRITE);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync }
51a01524909c95ee04b636218b6a89b29fb81825vboxsync else
51a01524909c95ee04b636218b6a89b29fb81825vboxsync Assert(rc == VINF_IOM_HC_MMIO_READ || rc == VINF_PATM_HC_MMIO_PATCH_READ);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync }
51a01524909c95ee04b636218b6a89b29fb81825vboxsync else
51a01524909c95ee04b636218b6a89b29fb81825vboxsync {
51a01524909c95ee04b636218b6a89b29fb81825vboxsync AssertMsgFailed(("Disassember XCHG problem..\n"));
51a01524909c95ee04b636218b6a89b29fb81825vboxsync rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
51a01524909c95ee04b636218b6a89b29fb81825vboxsync goto end;
51a01524909c95ee04b636218b6a89b29fb81825vboxsync }
51a01524909c95ee04b636218b6a89b29fb81825vboxsync
51a01524909c95ee04b636218b6a89b29fb81825vboxsyncend:
51a01524909c95ee04b636218b6a89b29fb81825vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstTest, a1);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#ifdef IN_RING0
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync/**
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Read callback for disassembly function; supports reading bytes that cross a page boundary
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @returns VBox status code.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pSrc GC source pointer
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pDest HC destination pointer
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param size Number of bytes to read
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * @param pvUserdata Callback specific user data (pCpu)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncDECLCALLBACK(int) iomReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, unsigned size, void *pvUserdata)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync{
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync DISCPUSTATE *pCpu = (DISCPUSTATE *)pvUserdata;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync PVM pVM = (PVM)pCpu->apvUserData[0];
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc = PGMPhysReadGCPtr(pVM, pDest, pSrc, size);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertRC(rc);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return rc;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncinline int iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync{
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VBOX_SUCCESS(DISCoreOneEx(InstrGC, pCpu->mode, iomReadBytes, pVM, pCpu, pOpsize));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsyncinline int iomDisCoreOne(PVM pVM, DISCPUSTATE *pCpu, RTGCUINTPTR InstrGC, uint32_t *pOpsize)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync{
b0b15690f00527424b2d5fb88456d747252322f7vboxsync return VBOX_SUCCESS(DISCoreOne(pCpu, InstrGC, pOpsize));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync}
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#endif
51a01524909c95ee04b636218b6a89b29fb81825vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync/**
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * \#PF Handler callback for MMIO ranges.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Note: we are on ring0 in Hypervisor and interrupts are disabled.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync *
217fa436516d137a409bb493cb7d350898f64666vboxsync * @returns VBox status code (appropriate for GC return).
217fa436516d137a409bb493cb7d350898f64666vboxsync * @param pVM VM Handle.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param uErrorCode CPU Error code.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param pRegFrame Trap register frame.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param pvFault The fault address (cr2).
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * @param pvUser Pointer to the MMIO ring-3 range entry.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync */
51a01524909c95ee04b636218b6a89b29fb81825vboxsyncIOMDECL(int) IOMMMIOHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, RTGCPHYS GCPhysFault, void *pvUser)
51a01524909c95ee04b636218b6a89b29fb81825vboxsync{
51a01524909c95ee04b636218b6a89b29fb81825vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync NOREF(pvUser); /** @todo implement pvUser usage! */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync Log3(("IOMMMIOHandler: GCPhys=%RGp uErr=%#x pvFault=%p eip=%RGv\n",
51a01524909c95ee04b636218b6a89b29fb81825vboxsync GCPhysFault, uErrorCode, pvFault, pRegFrame->eip));
51a01524909c95ee04b636218b6a89b29fb81825vboxsync
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /*
51a01524909c95ee04b636218b6a89b29fb81825vboxsync * Find the corresponding MMIO range.
51a01524909c95ee04b636218b6a89b29fb81825vboxsync */
51a01524909c95ee04b636218b6a89b29fb81825vboxsync CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhysFault);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (!pRange)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#ifdef VBOX_WITH_STATISTICS
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pStats)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (uErrorCode & X86_TRAP_PF_RW)
51a01524909c95ee04b636218b6a89b29fb81825vboxsync STAM_COUNTER_INC(&pStats->WriteGCToR3);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync else
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_COUNTER_INC(&pStats->ReadGCToR3);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#endif
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhysFault);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pRangeR3)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCMMIOHandler, a);
51a01524909c95ee04b636218b6a89b29fb81825vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
51a01524909c95ee04b636218b6a89b29fb81825vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
51a01524909c95ee04b636218b6a89b29fb81825vboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Now, why are we here...
51a01524909c95ee04b636218b6a89b29fb81825vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Internal error! GCPhysFault=%x\n", GCPhysFault));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Convert CS:EIP to linear address and initialize the disassembler.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
217fa436516d137a409bb493cb7d350898f64666vboxsync DISCPUSTATE cpu;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync cpu.mode = SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid) ? CPUMODE_32BIT : CPUMODE_16BIT;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync RTGCPTR pvCode;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)(cpu.mode == CPUMODE_32BIT ? pRegFrame->eip : pRegFrame->eip & 0xffff), &pvCode);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (VBOX_FAILURE(rc))
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync AssertMsgFailed(("Internal error! cs:eip=%04x:%08x rc=%Vrc\n", pRegFrame->cs, pRegFrame->eip, rc));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return VERR_IOM_MMIO_HANDLER_BOGUS_CALL;
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync }
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Disassemble the instruction and interprete it.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync unsigned cbOp;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (iomDisCoreOne(pVM, &cpu, (RTGCUINTPTR)pvCode, &cbOp))
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync switch (cpu.pCurInstr->opcode)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_MOV:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_MOVZX:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_MOVSX:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_PROFILE_START(&pVM->iom.s.StatGCInstMov, b);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (uErrorCode & X86_TRAP_PF_RW)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretMOVxXWrite(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync else
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretMOVxXRead(pVM, pRegFrame, &cpu, pRange, GCPhysFault);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (rc == VINF_SUCCESS)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCInstMov, b);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#ifdef IOMGC_MOVS_SUPPORT
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_MOVSB:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_MOVSWD:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretMOVS(pVM, uErrorCode, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#endif
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_STOSB:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_STOSWD:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync Assert(uErrorCode & X86_TRAP_PF_RW);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretSTOS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_LODSB:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_LODSWD:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync Assert(!(uErrorCode & X86_TRAP_PF_RW));
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretLODS(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_CMP:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync Assert(!(uErrorCode & X86_TRAP_PF_RW));
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretCMP(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_AND:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretAND(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_TEST:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync Assert(!(uErrorCode & X86_TRAP_PF_RW));
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretTEST(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case OP_XCHG:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = iomGCInterpretXCHG(pVM, pRegFrame, GCPhysFault, &cpu, pRange);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync /*
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * The instruction isn't supported. Hand it on to ring-3.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync default:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOther);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = (uErrorCode & X86_TRAP_PF_RW) ? VINF_IOM_HC_MMIO_WRITE : VINF_IOM_HC_MMIO_READ;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync else
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync AssertMsgFailed(("Disassembler freaked out!\n"));
b0b15690f00527424b2d5fb88456d747252322f7vboxsync rc = VERR_IOM_MMIO_HANDLER_DISASM_ERROR;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync /*
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * On success advance EIP.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (rc == VINF_SUCCESS)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync pRegFrame->eip += cbOp;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync else
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCMMIOFailures);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#ifdef VBOX_WITH_STATISTICS
b0b15690f00527424b2d5fb88456d747252322f7vboxsync switch (rc)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case VINF_IOM_HC_MMIO_READ:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case VINF_IOM_HC_MMIO_WRITE:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync case VINF_IOM_HC_MMIO_READ_WRITE:
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhysFault);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (pStats)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (uErrorCode & X86_TRAP_PF_RW)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_COUNTER_INC(&pStats->WriteGCToR3);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync else
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_COUNTER_INC(&pStats->ReadGCToR3);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync break;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#endif
b0b15690f00527424b2d5fb88456d747252322f7vboxsync }
b0b15690f00527424b2d5fb88456d747252322f7vboxsync STAM_PROFILE_STOP(&pVM->iom.s.StatGCMMIOHandler, a);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync return rc;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync}
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync/**
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * Reads a MMIO register.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync *
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @returns VBox status code.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync *
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param pVM VM handle.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param GCPhys The physical address to read.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param pu32Value Where to store the value read.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync */
b0b15690f00527424b2d5fb88456d747252322f7vboxsyncIOMDECL(int) IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value, size_t cbValue)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync{
b0b15690f00527424b2d5fb88456d747252322f7vboxsync/** @todo add return to ring-3 statistics when this function is used in GC! */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync
b0b15690f00527424b2d5fb88456d747252322f7vboxsync /*
b0b15690f00527424b2d5fb88456d747252322f7vboxsync * Lookup the current context range node and statistics.
b0b15690f00527424b2d5fb88456d747252322f7vboxsync */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#ifdef VBOX_WITH_STATISTICS
b0b15690f00527424b2d5fb88456d747252322f7vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
b0b15690f00527424b2d5fb88456d747252322f7vboxsync# ifdef IN_RING3
b0b15690f00527424b2d5fb88456d747252322f7vboxsync pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
b0b15690f00527424b2d5fb88456d747252322f7vboxsync# else
b0b15690f00527424b2d5fb88456d747252322f7vboxsync return VINF_IOM_HC_MMIO_READ;
b0b15690f00527424b2d5fb88456d747252322f7vboxsync# endif
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#endif /* VBOX_WITH_STATISTICS */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#ifdef IN_RING3
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (pRange)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#else /* !IN_RING3 */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync if (pRange && pRange->pfnReadCallback)
b0b15690f00527424b2d5fb88456d747252322f7vboxsync#endif /* !IN_RING3 */
b0b15690f00527424b2d5fb88456d747252322f7vboxsync {
b0b15690f00527424b2d5fb88456d747252322f7vboxsync /*
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync * Perform the read and deal with the result.
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync */
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#ifdef VBOX_WITH_STATISTICS
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pStats)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfRead), a);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#endif
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync int rc = pRange->pfnReadCallback(pRange->pDevIns, pRange->pvUser, GCPhys, pu32Value, cbValue);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#ifdef VBOX_WITH_STATISTICS
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pStats)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfRead), a);
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync if (pStats && rc != VINF_IOM_HC_MMIO_READ)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync#endif
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync switch (rc)
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync {
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync case VINF_SUCCESS:
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync default:
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
cc15c3fa4bb2d3fb91e4d0cd15a73133963f86b0vboxsync return rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case VINF_IOM_MMIO_UNUSED_00:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync switch (cbValue)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync case 1: *(uint8_t *)pu32Value = 0x00; break;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync case 2: *(uint16_t *)pu32Value = 0x0000; break;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync case 4: *(uint32_t *)pu32Value = 0x00000000; break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync }
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync return VINF_SUCCESS;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync case VINF_IOM_MMIO_UNUSED_FF:
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync switch (cbValue)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync {
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync case 1: *(uint8_t *)pu32Value = 0xff; break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync case 2: *(uint16_t *)pu32Value = 0xffff; break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync case 4: *(uint32_t *)pu32Value = 0xffffffff; break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync default: AssertReleaseMsgFailed(("cbValue=%d GCPhys=%VGp\n", cbValue, GCPhys)); break;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync }
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, *pu32Value, cbValue, rc));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync return VINF_SUCCESS;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync }
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync }
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync#ifndef IN_RING3
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync /*
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Lookup the ring-3 range.
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync */
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (pRangeR3)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync {
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (pRangeR3->pfnReadCallback)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync return VINF_IOM_HC_MMIO_READ;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync# ifdef VBOX_WITH_STATISTICS
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (pStats)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync STAM_COUNTER_INC(&pStats->CTXALLSUFF(Read));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync# endif
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync *pu32Value = 0;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync Log4(("IOMMMIORead: GCPhys=%RGp *pu32=%08RX32 cb=%d rc=VINF_SUCCESS\n", GCPhys, *pu32Value, cbValue));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync return VINF_SUCCESS;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync }
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync#endif
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync return VERR_INTERNAL_ERROR;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync}
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync
ff88d4153cd65650577e8c2d1a5a3fdfa0404a80vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * Writes to a MMIO register.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status code.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pVM VM handle.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param GCPhys The physical address to write to.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param u32Value The value to write.
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsyncIOMDECL(int) IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync{
ff88d4153cd65650577e8c2d1a5a3fdfa0404a80vboxsync/** @todo add return to ring-3 statistics when this function is used in GC! */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * Lookup the current context range node.
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync */
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync CTXALLSUFF(PIOMMMIORANGE) pRange = iomMMIOGetRange(&pVM->iom.s, GCPhys);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync#ifdef VBOX_WITH_STATISTICS
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync PIOMMMIOSTATS pStats = iomMMIOGetStats(&pVM->iom.s, GCPhys);
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (!pStats && (!pRange || pRange->cbSize <= PAGE_SIZE))
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync# ifdef IN_RING3
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync pStats = iomR3MMIOStatsCreate(pVM, GCPhys, pRange ? pRange->pszDesc : NULL);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync# else
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync return VINF_IOM_HC_MMIO_WRITE;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync# endif
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif /* VBOX_WITH_STATISTICS */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /*
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * Perform the write if we found a range.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync#ifdef IN_RING3
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (pRange)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync#else /* !IN_RING3 */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync if (pRange && pRange->pfnWriteCallback)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif /* !IN_RING3 */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef VBOX_WITH_STATISTICS
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pStats)
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_PROFILE_ADV_START(&pStats->CTXALLSUFF(ProfWrite), a);
16a9adc14900ca18e6909679a579f6833425e030vboxsync#endif
16a9adc14900ca18e6909679a579f6833425e030vboxsync int rc = pRange->pfnWriteCallback(pRange->pDevIns, pRange->pvUser, GCPhys, &u32Value, cbValue);
16a9adc14900ca18e6909679a579f6833425e030vboxsync#ifdef VBOX_WITH_STATISTICS
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync if (pStats)
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_PROFILE_ADV_STOP(&pStats->CTXALLSUFF(ProfWrite), a);
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pStats && rc != VINF_IOM_HC_MMIO_WRITE)
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
16a9adc14900ca18e6909679a579f6833425e030vboxsync#endif
16a9adc14900ca18e6909679a579f6833425e030vboxsync Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue, rc));
16a9adc14900ca18e6909679a579f6833425e030vboxsync return rc;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync#ifndef IN_RING3
16a9adc14900ca18e6909679a579f6833425e030vboxsync /*
16a9adc14900ca18e6909679a579f6833425e030vboxsync * Lookup the ring-3 range.
16a9adc14900ca18e6909679a579f6833425e030vboxsync */
16a9adc14900ca18e6909679a579f6833425e030vboxsync PIOMMMIORANGER3 pRangeR3 = iomMMIOGetRangeHC(&pVM->iom.s, GCPhys);
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pRangeR3)
16a9adc14900ca18e6909679a579f6833425e030vboxsync {
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pRangeR3->pfnWriteCallback)
16a9adc14900ca18e6909679a579f6833425e030vboxsync return VINF_IOM_HC_MMIO_WRITE;
16a9adc14900ca18e6909679a579f6833425e030vboxsync# ifdef VBOX_WITH_STATISTICS
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (pStats)
16a9adc14900ca18e6909679a579f6833425e030vboxsync STAM_COUNTER_INC(&pStats->CTXALLSUFF(Write));
16a9adc14900ca18e6909679a579f6833425e030vboxsync# endif
16a9adc14900ca18e6909679a579f6833425e030vboxsync Log4(("IOMMMIOWrite: GCPhys=%RGp u32=%08RX32 cb=%d rc=%Vrc\n", GCPhys, u32Value, cbValue));
16a9adc14900ca18e6909679a579f6833425e030vboxsync return VINF_SUCCESS;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync#endif
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync AssertMsgFailed(("Handlers and page tables are out of sync or something! GCPhys=%VGp cbValue=%d\n", GCPhys, cbValue));
16a9adc14900ca18e6909679a579f6833425e030vboxsync return VERR_INTERNAL_ERROR;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * [REP*] INSB/INSW/INSD
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * ES:EDI,DX[,ECX]
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @remark Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync *
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_SUCCESS Success.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * status code must be passed on to EM.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync *
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param uPort IO Port
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param uPrefix IO instruction prefix
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * @param cbTransfer Size of transfer unit
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsyncIOMDECL(int) IOMInterpretINSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync#ifdef VBOX_WITH_STATISTICS
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCInstIns);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync#endif
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync /*
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * We do not support REPNE or decrementing destination
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * pointer. Segment prefixes are deliberately ignored, as per the instruction specification.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync if ( (uPrefix & PREFIX_REPNE)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync || pRegFrame->eflags.Bits.u1DF)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync return VINF_EM_RAW_EMULATE_INSTR;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync /*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Get bytes/words/dwords count to transfer.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync RTGCUINTREG cTransfers = 1;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync if (uPrefix & PREFIX_REP)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync cTransfers = pRegFrame->ecx;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync cTransfers &= 0xffff;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (!cTransfers)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync return VINF_SUCCESS;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync /* Convert destination address es:edi. */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync RTGCPTR GCPtrDst;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync int rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->es, (RTGCPTR)pRegFrame->edi, &pRegFrame->esHid,
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync &GCPtrDst, NULL);
594521f7faf13f7a88f31e6cd76629bd67340229vboxsync if (VBOX_FAILURE(rc))
e04eeee1b306d610b0441cee9bf1c750100254d5vboxsync {
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Log(("INS destination address conversion failed -> fallback, rc=%d\n", rc));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return VINF_EM_RAW_EMULATE_INSTR;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync /* Access verification first; we can't recover from traps inside this instruction, as the port read cannot be repeated. */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrDst, cTransfers * cbTransfer,
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync X86_PTE_RW | ((cpl == 3) ? X86_PTE_US : 0));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (rc != VINF_SUCCESS)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync {
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Log(("INS will generate a trap -> fallback, rc=%d\n", rc));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync return VINF_EM_RAW_EMULATE_INSTR;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync }
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Log(("IOM: rep ins%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync if (cTransfers > 1)
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync {
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync /* If the device supports string transfers, ask it to do as
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync * much as it wants. The rest is done with single-word transfers. */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync const RTGCUINTREG cTransfersOrg = cTransfers;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync rc = IOMIOPortReadString(pVM, uPort, &GCPtrDst, &cTransfers, cbTransfer);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync pRegFrame->edi += (cTransfersOrg - cTransfers) * cbTransfer;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef IN_GC
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync MMGCRamRegisterTrapHandler(pVM);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync#endif
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync while (cTransfers && rc == VINF_SUCCESS)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync uint32_t u32Value;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync rc = IOMIOPortRead(pVM, uPort, &u32Value, cbTransfer);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!IOM_SUCCESS(rc))
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync break;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync int rc2 = iomRamWrite(pVM, GCPtrDst, &u32Value, cbTransfer);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync Assert(rc2 == VINF_SUCCESS); NOREF(rc2);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbTransfer);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync pRegFrame->edi += cbTransfer;
594521f7faf13f7a88f31e6cd76629bd67340229vboxsync cTransfers--;
e04eeee1b306d610b0441cee9bf1c750100254d5vboxsync }
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync#ifdef IN_GC
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync MMGCRamDeregisterTrapHandler(pVM);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* Update ecx on exit. */
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (uPrefix & PREFIX_REP)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pRegFrame->ecx = cTransfers;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertMsg(rc == VINF_SUCCESS || rc == VINF_IOM_HC_IOPORT_READ || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) || VBOX_FAILURE(rc), ("%Vrc\n", rc));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return rc;
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/**
9496f2d398b49813176939d7a339ae513d5175efvboxsync * [REP*] INSB/INSW/INSD
9496f2d398b49813176939d7a339ae513d5175efvboxsync * ES:EDI,DX[,ECX]
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync * @retval VINF_SUCCESS Success.
7a3f491705173bc08122f2c7d26d48a8b4c5ceecvboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync * status code must be passed on to EM.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_IOM_HC_IOPORT_READ Defer the read to ring-3. (R0/GC only)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_EM_RAW_EMULATE_INSTR Defer the read to the REM.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync *
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync * @param pCpu Disassembler CPU state.
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync */
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsyncIOMDECL(int) IOMInterpretINS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync /*
9496f2d398b49813176939d7a339ae513d5175efvboxsync * Get port number directly from the register (no need to bother the
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * disassembler). And get the I/O register size from the opcode / prefix.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync */
009d45aa55691312278d41edb20154dc208d9cd8vboxsync uint32_t uPort = pRegFrame->edx & 0xffff;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync unsigned cbSize = 0;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync if (pCpu->pCurInstr->opcode == OP_INSB)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync cbSize = 1;
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync else
19badc2a6bdaeb1208f71b7de06feec1aa7c59c9vboxsync cbSize = pCpu->opmode == CPUMODE_32BIT ? 4 : 2;
19badc2a6bdaeb1208f71b7de06feec1aa7c59c9vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (RT_UNLIKELY(rc != VINF_SUCCESS))
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync {
009d45aa55691312278d41edb20154dc208d9cd8vboxsync AssertMsg(rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED || rc == VINF_TRPM_XCPT_DISPATCHED || VBOX_FAILURE(rc), ("%Vrc\n", rc));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return rc;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync }
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return IOMInterpretINSEx(pVM, pRegFrame, uPort, pCpu->prefix, cbSize);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync}
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync/**
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * [REP*] OUTSB/OUTSW/OUTSD
9496f2d398b49813176939d7a339ae513d5175efvboxsync * DS:ESI,DX[,ECX]
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @remark Assumes caller checked the access privileges (IOMInterpretCheckPortIOAccess)
9496f2d398b49813176939d7a339ae513d5175efvboxsync *
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
9496f2d398b49813176939d7a339ae513d5175efvboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
9496f2d398b49813176939d7a339ae513d5175efvboxsync * @retval VINF_SUCCESS Success.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * status code must be passed on to EM.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
63c12491acc2b8b95c8ac454f1c48b98eec8f7d8vboxsync *
19badc2a6bdaeb1208f71b7de06feec1aa7c59c9vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
19badc2a6bdaeb1208f71b7de06feec1aa7c59c9vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param uPort IO Port
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param uPrefix IO instruction prefix
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * @param cbTransfer Size of transfer unit
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync */
009d45aa55691312278d41edb20154dc208d9cd8vboxsyncIOMDECL(int) IOMInterpretOUTSEx(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uPort, uint32_t uPrefix, uint32_t cbTransfer)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync{
009d45aa55691312278d41edb20154dc208d9cd8vboxsync#ifdef VBOX_WITH_STATISTICS
009d45aa55691312278d41edb20154dc208d9cd8vboxsync STAM_COUNTER_INC(&pVM->iom.s.StatGCInstOuts);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync#endif
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync /*
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * We do not support segment prefixes, REPNE or
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * decrementing source pointer.
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync */
9496f2d398b49813176939d7a339ae513d5175efvboxsync if ( (uPrefix & (PREFIX_SEG | PREFIX_REPNE))
9496f2d398b49813176939d7a339ae513d5175efvboxsync || pRegFrame->eflags.Bits.u1DF)
9496f2d398b49813176939d7a339ae513d5175efvboxsync return VINF_EM_RAW_EMULATE_INSTR;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync /*
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync * Get bytes/words/dwords count to transfer.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync */
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync RTGCUINTREG cTransfers = 1;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (uPrefix & PREFIX_REP)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync {
009d45aa55691312278d41edb20154dc208d9cd8vboxsync cTransfers = pRegFrame->ecx;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (!SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
009d45aa55691312278d41edb20154dc208d9cd8vboxsync cTransfers &= 0xffff;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
bdaae7f756db4f5cf2d62f495a2a80acaf581a0cvboxsync if (!cTransfers)
bdaae7f756db4f5cf2d62f495a2a80acaf581a0cvboxsync return VINF_SUCCESS;
bdaae7f756db4f5cf2d62f495a2a80acaf581a0cvboxsync }
bdaae7f756db4f5cf2d62f495a2a80acaf581a0cvboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync /* Convert source address ds:esi. */
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync RTGCPTR GCPtrSrc;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync int rc = SELMToFlatEx(pVM, pRegFrame->eflags, pRegFrame->ds, (RTGCPTR)pRegFrame->esi, &pRegFrame->dsHid,
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync SELMTOFLAT_FLAGS_HYPER | SELMTOFLAT_FLAGS_NO_PL,
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync &GCPtrSrc, NULL);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (VBOX_FAILURE(rc))
009d45aa55691312278d41edb20154dc208d9cd8vboxsync {
009d45aa55691312278d41edb20154dc208d9cd8vboxsync Log(("OUTS source address conversion failed -> fallback, rc=%Vrc\n", rc));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return VINF_EM_RAW_EMULATE_INSTR;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync }
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync /* Access verification first; we currently can't recover properly from traps inside this instruction */
009d45aa55691312278d41edb20154dc208d9cd8vboxsync uint32_t cpl = CPUMGetGuestCPL(pVM, pRegFrame);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = PGMVerifyAccess(pVM, (RTGCUINTPTR)GCPtrSrc, cTransfers * cbTransfer,
009d45aa55691312278d41edb20154dc208d9cd8vboxsync (cpl == 3) ? X86_PTE_US : 0);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (rc != VINF_SUCCESS)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync {
009d45aa55691312278d41edb20154dc208d9cd8vboxsync Log(("OUTS will generate a trap -> fallback, rc=%Vrc\n", rc));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync return VINF_EM_RAW_EMULATE_INSTR;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync }
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync Log(("IOM: rep outs%d port %#x count %d\n", cbTransfer * 8, uPort, cTransfers));
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (cTransfers > 1)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync {
009d45aa55691312278d41edb20154dc208d9cd8vboxsync /*
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * If the device supports string transfers, ask it to do as
009d45aa55691312278d41edb20154dc208d9cd8vboxsync * much as it wants. The rest is done with single-word transfers.
009d45aa55691312278d41edb20154dc208d9cd8vboxsync */
009d45aa55691312278d41edb20154dc208d9cd8vboxsync const RTGCUINTREG cTransfersOrg = cTransfers;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = IOMIOPortWriteString(pVM, uPort, &GCPtrSrc, &cTransfers, cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync AssertRC(rc); Assert(cTransfers <= cTransfersOrg);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync pRegFrame->esi += (cTransfersOrg - cTransfers) * cbTransfer;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync }
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync#ifdef IN_GC
009d45aa55691312278d41edb20154dc208d9cd8vboxsync MMGCRamRegisterTrapHandler(pVM);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync#endif
009d45aa55691312278d41edb20154dc208d9cd8vboxsync
009d45aa55691312278d41edb20154dc208d9cd8vboxsync while (cTransfers && rc == VINF_SUCCESS)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync {
009d45aa55691312278d41edb20154dc208d9cd8vboxsync uint32_t u32Value;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = iomRamRead(pVM, &u32Value, GCPtrSrc, cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (rc != VINF_SUCCESS)
009d45aa55691312278d41edb20154dc208d9cd8vboxsync break;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync rc = IOMIOPortWrite(pVM, uPort, u32Value, cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync if (!IOM_SUCCESS(rc))
009d45aa55691312278d41edb20154dc208d9cd8vboxsync break;
009d45aa55691312278d41edb20154dc208d9cd8vboxsync GCPtrSrc = (RTGCPTR)((RTUINTPTR)GCPtrSrc + cbTransfer);
009d45aa55691312278d41edb20154dc208d9cd8vboxsync pRegFrame->esi += cbTransfer;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync cTransfers--;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef IN_GC
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync MMGCRamDeregisterTrapHandler(pVM);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#endif
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /* Update ecx on exit. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync if (uPrefix & PREFIX_REP)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pRegFrame->ecx = cTransfers;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync AssertMsg(rc == VINF_SUCCESS || rc == VINF_IOM_HC_IOPORT_WRITE || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) || VBOX_FAILURE(rc), ("%Vrc\n", rc));
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return rc;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync}
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * [REP*] OUTSB/OUTSW/OUTSD
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * DS:ESI,DX[,ECX]
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @returns Strict VBox status code. Informational status codes other than the one documented
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_SUCCESS Success.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * status code must be passed on to EM.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_IOM_HC_IOPORT_WRITE Defer the write to ring-3. (R0/GC only)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_RAW_EMULATE_INSTR Defer the write to the REM.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_RAW_GUEST_TRAP The exception was left pending. (TRPMRaiseXcptErr)
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @retval VINF_TRPM_XCPT_DISPATCHED The exception was raised and dispatched for raw-mode execution. (TRPMRaiseXcptErr)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @retval VINF_EM_RESCHEDULE_REM The exception was dispatched and cannot be executed in raw-mode. (TRPMRaiseXcptErr)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync *
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pVM The virtual machine (GC pointer ofcourse).
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pRegFrame Pointer to CPUMCTXCORE guest registers structure.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * @param pCpu Disassembler CPU state.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncIOMDECL(int) IOMInterpretOUTS(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync /*
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * Get port number from the first parameter.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync * And get the I/O register size from the opcode / prefix.
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync uint32_t uPort = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync unsigned cbSize = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync bool fRc = iomGCGetRegImmData(pCpu, &pCpu->param1, pRegFrame, &uPort, &cbSize);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync AssertMsg(fRc, ("Failed to get reg/imm port number!\n")); NOREF(fRc);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (pCpu->pCurInstr->opcode == OP_OUTSB)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync cbSize = 1;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync else
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync cbSize = (pCpu->opmode == CPUMODE_32BIT) ? 4 : 2;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int rc = IOMInterpretCheckPortIOAccess(pVM, pRegFrame, uPort, cbSize);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (RT_UNLIKELY(rc != VINF_SUCCESS))
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AssertMsg(rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED || rc == VINF_TRPM_XCPT_DISPATCHED || VBOX_FAILURE(rc), ("%Vrc\n", rc));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return rc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return IOMInterpretOUTSEx(pVM, pRegFrame, uPort, pCpu->prefix, cbSize);
1189c7dde5d7f6c26f338ced3d40fc830b822e68vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync