mirror of https://github.com/xemu-project/xemu.git
s390x/mmu: Add function for accessing guest memory
According to the POP specification, the parameter blocks of various functions like the IO instructions are accessed with logical addresses. Thus we need a function that can read or write a buffer from/to the guest's logical address space. This patch now provides a function that can be used to access virtual guest memory by using the mmu_translate function of QEMU to convert the virtual addresses to physical. Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com> Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
This commit is contained in:
parent
801cdd355f
commit
c3edd62851
|
@ -287,6 +287,7 @@ typedef struct CPUS390XState {
|
||||||
#define FLAG_MASK_32 0x00001000
|
#define FLAG_MASK_32 0x00001000
|
||||||
|
|
||||||
/* Control register 0 bits */
|
/* Control register 0 bits */
|
||||||
|
#define CR0_LOWPROT 0x0000000010000000ULL
|
||||||
#define CR0_EDAT 0x0000000000800000ULL
|
#define CR0_EDAT 0x0000000000800000ULL
|
||||||
|
|
||||||
static inline int cpu_mmu_index (CPUS390XState *env)
|
static inline int cpu_mmu_index (CPUS390XState *env)
|
||||||
|
@ -897,6 +898,16 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
|
||||||
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
|
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
|
||||||
uint64_t vr);
|
uint64_t vr);
|
||||||
|
|
||||||
|
int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, void *hostbuf, int len,
|
||||||
|
bool is_write);
|
||||||
|
|
||||||
|
#define s390_cpu_virt_mem_read(cpu, laddr, dest, len) \
|
||||||
|
s390_cpu_virt_mem_rw(cpu, laddr, dest, len, false)
|
||||||
|
#define s390_cpu_virt_mem_write(cpu, laddr, dest, len) \
|
||||||
|
s390_cpu_virt_mem_rw(cpu, laddr, dest, len, true)
|
||||||
|
#define s390_cpu_virt_mem_check_write(cpu, laddr, len) \
|
||||||
|
s390_cpu_virt_mem_rw(cpu, laddr, NULL, len, true)
|
||||||
|
|
||||||
/* The value of the TOD clock for 1.1.1970. */
|
/* The value of the TOD clock for 1.1.1970. */
|
||||||
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
|
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "exec/address-spaces.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
/* #define DEBUG_S390 */
|
/* #define DEBUG_S390 */
|
||||||
|
@ -368,3 +371,102 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lowprot_enabled: Check whether low-address protection is enabled
|
||||||
|
*/
|
||||||
|
static bool lowprot_enabled(const CPUS390XState *env)
|
||||||
|
{
|
||||||
|
if (!(env->cregs[0] & CR0_LOWPROT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(env->psw.mask & PSW_MASK_DAT)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the private-space control bit */
|
||||||
|
switch (env->psw.mask & PSW_MASK_ASC) {
|
||||||
|
case PSW_ASC_PRIMARY:
|
||||||
|
return !(env->cregs[1] & _ASCE_PRIVATE_SPACE);
|
||||||
|
case PSW_ASC_SECONDARY:
|
||||||
|
return !(env->cregs[7] & _ASCE_PRIVATE_SPACE);
|
||||||
|
case PSW_ASC_HOME:
|
||||||
|
return !(env->cregs[13] & _ASCE_PRIVATE_SPACE);
|
||||||
|
default:
|
||||||
|
/* We don't support access register mode */
|
||||||
|
error_report("unsupported addressing mode");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translate_pages: Translate a set of consecutive logical page addresses
|
||||||
|
* to absolute addresses
|
||||||
|
*/
|
||||||
|
static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
|
||||||
|
target_ulong *pages, bool is_write)
|
||||||
|
{
|
||||||
|
bool lowprot = is_write && lowprot_enabled(&cpu->env);
|
||||||
|
uint64_t asc = cpu->env.psw.mask & PSW_MASK_ASC;
|
||||||
|
CPUS390XState *env = &cpu->env;
|
||||||
|
int ret, i, pflags;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_pages; i++) {
|
||||||
|
/* Low-address protection? */
|
||||||
|
if (lowprot && (addr < 512 || (addr >= 4096 && addr < 4096 + 512))) {
|
||||||
|
trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, 0);
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, true);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!address_space_access_valid(&address_space_memory, pages[i],
|
||||||
|
TARGET_PAGE_SIZE, is_write)) {
|
||||||
|
program_interrupt(env, PGM_ADDRESSING, 0);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
addr += TARGET_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* s390_cpu_virt_mem_rw:
|
||||||
|
* @laddr: the logical start address
|
||||||
|
* @hostbuf: buffer in host memory. NULL = do only checks w/o copying
|
||||||
|
* @len: length that should be transfered
|
||||||
|
* @is_write: true = write, false = read
|
||||||
|
* Returns: 0 on success, non-zero if an exception occured
|
||||||
|
*
|
||||||
|
* Copy from/to guest memory using logical addresses. Note that we inject a
|
||||||
|
* program interrupt in case there is an error while accessing the memory.
|
||||||
|
*/
|
||||||
|
int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, void *hostbuf,
|
||||||
|
int len, bool is_write)
|
||||||
|
{
|
||||||
|
int currlen, nr_pages, i;
|
||||||
|
target_ulong *pages;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nr_pages = (((laddr & ~TARGET_PAGE_MASK) + len - 1) >> TARGET_PAGE_BITS)
|
||||||
|
+ 1;
|
||||||
|
pages = g_malloc(nr_pages * sizeof(*pages));
|
||||||
|
|
||||||
|
ret = translate_pages(cpu, laddr, nr_pages, pages, is_write);
|
||||||
|
if (ret == 0 && hostbuf != NULL) {
|
||||||
|
/* Copy data by stepping through the area page by page */
|
||||||
|
for (i = 0; i < nr_pages; i++) {
|
||||||
|
currlen = MIN(len, TARGET_PAGE_SIZE - (laddr % TARGET_PAGE_SIZE));
|
||||||
|
cpu_physical_memory_rw(pages[i] | (laddr & ~TARGET_PAGE_MASK),
|
||||||
|
hostbuf, currlen, is_write);
|
||||||
|
laddr += currlen;
|
||||||
|
hostbuf += currlen;
|
||||||
|
len -= currlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(pages);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue