mirror of https://gitee.com/openkylin/qemu.git
Properly implement non-execute bit on PowerPC segments and PTEs.
Fix page protection bits for PowerPC 64 MMU. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3395 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
dbdd25065e
commit
b227a8e9aa
|
@ -596,6 +596,7 @@ struct mmu_ctx_t {
|
||||||
target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
|
target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
|
||||||
target_ulong ptem; /* Virtual segment ID | API */
|
target_ulong ptem; /* Virtual segment ID | API */
|
||||||
int key; /* Access key */
|
int key; /* Access key */
|
||||||
|
int nx; /* Non-execute area */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -96,12 +96,76 @@ static always_inline void pte64_invalidate (target_ulong *pte0)
|
||||||
#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
|
#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static always_inline int pp_check (int key, int pp, int nx)
|
||||||
|
{
|
||||||
|
int access;
|
||||||
|
|
||||||
|
/* Compute access rights */
|
||||||
|
/* When pp is 3/7, the result is undefined. Set it to noaccess */
|
||||||
|
access = 0;
|
||||||
|
if (key == 0) {
|
||||||
|
switch (pp) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x1:
|
||||||
|
case 0x2:
|
||||||
|
access |= PAGE_WRITE;
|
||||||
|
/* No break here */
|
||||||
|
case 0x3:
|
||||||
|
case 0x6:
|
||||||
|
access |= PAGE_READ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (pp) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x6:
|
||||||
|
access = 0;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
case 0x3:
|
||||||
|
access = PAGE_READ;
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
access = PAGE_READ | PAGE_WRITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nx == 0)
|
||||||
|
access |= PAGE_EXEC;
|
||||||
|
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
|
static always_inline int check_prot (int prot, int rw, int access_type)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (access_type == ACCESS_CODE) {
|
||||||
|
if (prot & PAGE_EXEC)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = -2;
|
||||||
|
} else if (rw) {
|
||||||
|
if (prot & PAGE_WRITE)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = -2;
|
||||||
|
} else {
|
||||||
|
if (prot & PAGE_READ)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
|
static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
|
||||||
target_ulong pte0, target_ulong pte1,
|
target_ulong pte0, target_ulong pte1,
|
||||||
int h, int rw)
|
int h, int rw, int type)
|
||||||
{
|
{
|
||||||
target_ulong ptem, mmask;
|
target_ulong ptem, mmask;
|
||||||
int access, ret, pteh, ptev;
|
int access, ret, pteh, ptev, pp;
|
||||||
|
|
||||||
access = 0;
|
access = 0;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
@ -122,11 +186,15 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
|
||||||
if (is_64b) {
|
if (is_64b) {
|
||||||
ptem = pte0 & PTE64_PTEM_MASK;
|
ptem = pte0 & PTE64_PTEM_MASK;
|
||||||
mmask = PTE64_CHECK_MASK;
|
mmask = PTE64_CHECK_MASK;
|
||||||
|
pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
|
||||||
|
ctx->nx |= (pte1 >> 2) & 1; /* No execute bit */
|
||||||
|
ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ptem = pte0 & PTE_PTEM_MASK;
|
ptem = pte0 & PTE_PTEM_MASK;
|
||||||
mmask = PTE_CHECK_MASK;
|
mmask = PTE_CHECK_MASK;
|
||||||
|
pp = pte1 & 0x00000003;
|
||||||
}
|
}
|
||||||
if (ptem == ctx->ptem) {
|
if (ptem == ctx->ptem) {
|
||||||
if (ctx->raddr != (target_ulong)-1) {
|
if (ctx->raddr != (target_ulong)-1) {
|
||||||
|
@ -138,42 +206,23 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Compute access rights */
|
/* Compute access rights */
|
||||||
if (ctx->key == 0) {
|
access = pp_check(ctx->key, pp, ctx->nx);
|
||||||
access = PAGE_READ;
|
|
||||||
if ((pte1 & 0x00000003) != 0x3)
|
|
||||||
access |= PAGE_WRITE;
|
|
||||||
} else {
|
|
||||||
switch (pte1 & 0x00000003) {
|
|
||||||
case 0x0:
|
|
||||||
access = 0;
|
|
||||||
break;
|
|
||||||
case 0x1:
|
|
||||||
case 0x3:
|
|
||||||
access = PAGE_READ;
|
|
||||||
break;
|
|
||||||
case 0x2:
|
|
||||||
access = PAGE_READ | PAGE_WRITE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Keep the matching PTE informations */
|
/* Keep the matching PTE informations */
|
||||||
ctx->raddr = pte1;
|
ctx->raddr = pte1;
|
||||||
ctx->prot = access;
|
ctx->prot = access;
|
||||||
if ((rw == 0 && (access & PAGE_READ)) ||
|
ret = check_prot(ctx->prot, rw, type);
|
||||||
(rw == 1 && (access & PAGE_WRITE))) {
|
if (ret == 0) {
|
||||||
/* Access granted */
|
/* Access granted */
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
if (loglevel != 0)
|
if (loglevel != 0)
|
||||||
fprintf(logfile, "PTE access granted !\n");
|
fprintf(logfile, "PTE access granted !\n");
|
||||||
#endif
|
#endif
|
||||||
ret = 0;
|
|
||||||
} else {
|
} else {
|
||||||
/* Access right violation */
|
/* Access right violation */
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
if (loglevel != 0)
|
if (loglevel != 0)
|
||||||
fprintf(logfile, "PTE access rejected\n");
|
fprintf(logfile, "PTE access rejected\n");
|
||||||
#endif
|
#endif
|
||||||
ret = -2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,17 +230,17 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pte32_check (mmu_ctx_t *ctx,
|
static int pte32_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1,
|
||||||
target_ulong pte0, target_ulong pte1, int h, int rw)
|
int h, int rw, int type)
|
||||||
{
|
{
|
||||||
return _pte_check(ctx, 0, pte0, pte1, h, rw);
|
return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
static int pte64_check (mmu_ctx_t *ctx,
|
static int pte64_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1,
|
||||||
target_ulong pte0, target_ulong pte1, int h, int rw)
|
int h, int rw, int type)
|
||||||
{
|
{
|
||||||
return _pte_check(ctx, 1, pte0, pte1, h, rw);
|
return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -353,7 +402,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
|
||||||
rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
|
rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) {
|
switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
|
||||||
case -3:
|
case -3:
|
||||||
/* TLB inconsistency */
|
/* TLB inconsistency */
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -398,7 +447,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
|
||||||
{
|
{
|
||||||
target_ulong *BATlt, *BATut, *BATu, *BATl;
|
target_ulong *BATlt, *BATut, *BATu, *BATl;
|
||||||
target_ulong base, BEPIl, BEPIu, bl;
|
target_ulong base, BEPIl, BEPIu, bl;
|
||||||
int i;
|
int i, pp;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
#if defined (DEBUG_BATS)
|
#if defined (DEBUG_BATS)
|
||||||
|
@ -447,19 +496,23 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
|
||||||
ctx->raddr = (*BATl & 0xF0000000) |
|
ctx->raddr = (*BATl & 0xF0000000) |
|
||||||
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
|
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
|
||||||
(virtual & 0x0001F000);
|
(virtual & 0x0001F000);
|
||||||
if (*BATl & 0x00000001)
|
/* Compute access rights */
|
||||||
ctx->prot = PAGE_READ;
|
pp = *BATl & 0x00000003;
|
||||||
if (*BATl & 0x00000002)
|
ctx->prot = 0;
|
||||||
ctx->prot = PAGE_WRITE | PAGE_READ;
|
if (pp != 0) {
|
||||||
|
ctx->prot = PAGE_READ | PAGE_EXEC;
|
||||||
|
if (pp == 0x2)
|
||||||
|
ctx->prot |= PAGE_WRITE;
|
||||||
|
}
|
||||||
|
ret = check_prot(ctx->prot, rw, type);
|
||||||
#if defined (DEBUG_BATS)
|
#if defined (DEBUG_BATS)
|
||||||
if (loglevel != 0) {
|
if (ret == 0 && loglevel != 0) {
|
||||||
fprintf(logfile, "BAT %d match: r 0x" PADDRX
|
fprintf(logfile, "BAT %d match: r 0x" PADDRX
|
||||||
" prot=%c%c\n",
|
" prot=%c%c\n",
|
||||||
i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
|
i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
|
||||||
ctx->prot & PAGE_WRITE ? 'W' : '-');
|
ctx->prot & PAGE_WRITE ? 'W' : '-');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,12 +536,14 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No hit */
|
/* No hit */
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PTE table lookup */
|
/* PTE table lookup */
|
||||||
static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw)
|
static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h,
|
||||||
|
int rw, int type)
|
||||||
{
|
{
|
||||||
target_ulong base, pte0, pte1;
|
target_ulong base, pte0, pte1;
|
||||||
int i, good = -1;
|
int i, good = -1;
|
||||||
|
@ -501,7 +556,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw)
|
||||||
if (is_64b) {
|
if (is_64b) {
|
||||||
pte0 = ldq_phys(base + (i * 16));
|
pte0 = ldq_phys(base + (i * 16));
|
||||||
pte1 = ldq_phys(base + (i * 16) + 8);
|
pte1 = ldq_phys(base + (i * 16) + 8);
|
||||||
r = pte64_check(ctx, pte0, pte1, h, rw);
|
r = pte64_check(ctx, pte0, pte1, h, rw, type);
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
if (loglevel != 0) {
|
if (loglevel != 0) {
|
||||||
fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
|
fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
|
||||||
|
@ -516,7 +571,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw)
|
||||||
{
|
{
|
||||||
pte0 = ldl_phys(base + (i * 8));
|
pte0 = ldl_phys(base + (i * 8));
|
||||||
pte1 = ldl_phys(base + (i * 8) + 4);
|
pte1 = ldl_phys(base + (i * 8) + 4);
|
||||||
r = pte32_check(ctx, pte0, pte1, h, rw);
|
r = pte32_check(ctx, pte0, pte1, h, rw, type);
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
if (loglevel != 0) {
|
if (loglevel != 0) {
|
||||||
fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
|
fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
|
||||||
|
@ -577,27 +632,27 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_pte32 (mmu_ctx_t *ctx, int h, int rw)
|
static int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type)
|
||||||
{
|
{
|
||||||
return _find_pte(ctx, 0, h, rw);
|
return _find_pte(ctx, 0, h, rw, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
static int find_pte64 (mmu_ctx_t *ctx, int h, int rw)
|
static int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type)
|
||||||
{
|
{
|
||||||
return _find_pte(ctx, 1, h, rw);
|
return _find_pte(ctx, 1, h, rw, type);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
|
static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
|
||||||
int h, int rw)
|
int h, int rw, int type)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
if (env->mmu_model == POWERPC_MMU_64B)
|
if (env->mmu_model == POWERPC_MMU_64B)
|
||||||
return find_pte64(ctx, h, rw);
|
return find_pte64(ctx, h, rw, type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return find_pte32(ctx, h, rw);
|
return find_pte32(ctx, h, rw, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
|
@ -796,7 +851,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
int attr;
|
int attr;
|
||||||
#endif
|
#endif
|
||||||
int ds, nx, vsid_sh, sdr_sh;
|
int ds, vsid_sh, sdr_sh;
|
||||||
int ret, ret2;
|
int ret, ret2;
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
|
@ -812,7 +867,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||||
ctx->key = ((attr & 0x40) && msr_pr == 1) ||
|
ctx->key = ((attr & 0x40) && msr_pr == 1) ||
|
||||||
((attr & 0x80) && msr_pr == 0) ? 1 : 0;
|
((attr & 0x80) && msr_pr == 0) ? 1 : 0;
|
||||||
ds = 0;
|
ds = 0;
|
||||||
nx = attr & 0x20 ? 1 : 0;
|
ctx->nx = attr & 0x20 ? 1 : 0;
|
||||||
vsid_mask = 0x00003FFFFFFFFF80ULL;
|
vsid_mask = 0x00003FFFFFFFFF80ULL;
|
||||||
vsid_sh = 7;
|
vsid_sh = 7;
|
||||||
sdr_sh = 18;
|
sdr_sh = 18;
|
||||||
|
@ -825,7 +880,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||||
ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
|
ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
|
||||||
((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
|
((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
|
||||||
ds = sr & 0x80000000 ? 1 : 0;
|
ds = sr & 0x80000000 ? 1 : 0;
|
||||||
nx = sr & 0x10000000 ? 1 : 0;
|
ctx->nx = sr & 0x10000000 ? 1 : 0;
|
||||||
vsid = sr & 0x00FFFFFF;
|
vsid = sr & 0x00FFFFFF;
|
||||||
vsid_mask = 0x01FFFFC0;
|
vsid_mask = 0x01FFFFC0;
|
||||||
vsid_sh = 6;
|
vsid_sh = 6;
|
||||||
|
@ -844,13 +899,13 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
if (loglevel != 0) {
|
if (loglevel != 0) {
|
||||||
fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n",
|
fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n",
|
||||||
ctx->key, ds, nx, vsid);
|
ctx->key, ds, ctx->nx, vsid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ret = -1;
|
ret = -1;
|
||||||
if (!ds) {
|
if (!ds) {
|
||||||
/* Check if instruction fetch is allowed, if needed */
|
/* Check if instruction fetch is allowed, if needed */
|
||||||
if (type != ACCESS_CODE || nx == 0) {
|
if (type != ACCESS_CODE || ctx->nx == 0) {
|
||||||
/* Page address translation */
|
/* Page address translation */
|
||||||
/* Primary table address */
|
/* Primary table address */
|
||||||
sdr = env->sdr1;
|
sdr = env->sdr1;
|
||||||
|
@ -909,7 +964,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Primary table lookup */
|
/* Primary table lookup */
|
||||||
ret = find_pte(env, ctx, 0, rw);
|
ret = find_pte(env, ctx, 0, rw, type);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* Secondary table lookup */
|
/* Secondary table lookup */
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
|
@ -921,7 +976,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||||
(uint32_t)hash, ctx->pg_addr[1]);
|
(uint32_t)hash, ctx->pg_addr[1]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ret2 = find_pte(env, ctx, 1, rw);
|
ret2 = find_pte(env, ctx, 1, rw, type);
|
||||||
if (ret2 != -1)
|
if (ret2 != -1)
|
||||||
ret = ret2;
|
ret = ret2;
|
||||||
}
|
}
|
||||||
|
@ -1119,76 +1174,32 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||||
__func__, i, zsel, zpr, rw, tlb->attr);
|
__func__, i, zsel, zpr, rw, tlb->attr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (access_type == ACCESS_CODE) {
|
/* Check execute enable bit */
|
||||||
/* Check execute enable bit */
|
switch (zpr) {
|
||||||
switch (zpr) {
|
case 0x2:
|
||||||
case 0x2:
|
if (msr_pr)
|
||||||
if (msr_pr)
|
goto check_perms;
|
||||||
goto check_exec_perm;
|
/* No break here */
|
||||||
goto exec_granted;
|
case 0x3:
|
||||||
case 0x0:
|
/* All accesses granted */
|
||||||
if (msr_pr) {
|
ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||||
ctx->prot = 0;
|
ret = 0;
|
||||||
ret = -3;
|
break;
|
||||||
break;
|
case 0x0:
|
||||||
}
|
if (msr_pr) {
|
||||||
/* No break here */
|
ctx->prot = 0;
|
||||||
case 0x1:
|
ret = -2;
|
||||||
check_exec_perm:
|
|
||||||
/* Check from TLB entry */
|
|
||||||
if (!(tlb->prot & PAGE_EXEC)) {
|
|
||||||
ret = -3;
|
|
||||||
} else {
|
|
||||||
if (tlb->prot & PAGE_WRITE) {
|
|
||||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
|
||||||
} else {
|
|
||||||
ctx->prot = PAGE_READ;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x3:
|
|
||||||
exec_granted:
|
|
||||||
/* All accesses granted */
|
|
||||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (zpr) {
|
|
||||||
case 0x2:
|
|
||||||
if (msr_pr)
|
|
||||||
goto check_rw_perm;
|
|
||||||
goto rw_granted;
|
|
||||||
case 0x0:
|
|
||||||
if (msr_pr) {
|
|
||||||
ctx->prot = 0;
|
|
||||||
ret = -2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* No break here */
|
|
||||||
case 0x1:
|
|
||||||
check_rw_perm:
|
|
||||||
/* Check from TLB entry */
|
|
||||||
/* Check write protection bit */
|
|
||||||
if (tlb->prot & PAGE_WRITE) {
|
|
||||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
ctx->prot = PAGE_READ;
|
|
||||||
if (rw)
|
|
||||||
ret = -2;
|
|
||||||
else
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x3:
|
|
||||||
rw_granted:
|
|
||||||
/* All accesses granted */
|
|
||||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* No break here */
|
||||||
|
case 0x1:
|
||||||
|
check_perms:
|
||||||
|
/* Check from TLB entry */
|
||||||
|
/* XXX: there is a problem here or in the TLB fill code... */
|
||||||
|
ctx->prot = tlb->prot;
|
||||||
|
ctx->prot |= PAGE_EXEC;
|
||||||
|
ret = check_prot(ctx->prot, rw, access_type);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
ctx->raddr = raddr;
|
ctx->raddr = raddr;
|
||||||
|
@ -1274,7 +1285,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
|
||||||
int in_plb, ret;
|
int in_plb, ret;
|
||||||
|
|
||||||
ctx->raddr = eaddr;
|
ctx->raddr = eaddr;
|
||||||
ctx->prot = PAGE_READ;
|
ctx->prot = PAGE_READ | PAGE_EXEC;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
switch (env->mmu_model) {
|
switch (env->mmu_model) {
|
||||||
case POWERPC_MMU_32B:
|
case POWERPC_MMU_32B:
|
||||||
|
@ -1421,9 +1432,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||||
}
|
}
|
||||||
ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
|
ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
|
ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK,
|
||||||
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
|
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
|
||||||
mmu_idx, is_softmmu);
|
mmu_idx, is_softmmu);
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
#if defined (DEBUG_MMU)
|
#if defined (DEBUG_MMU)
|
||||||
if (loglevel != 0)
|
if (loglevel != 0)
|
||||||
|
|
Loading…
Reference in New Issue