ref: 3aeca15d3c8647db5e7c76dadbc62cf3067791f4
parent: 26a8accad26267678c240e48a8544a208d9ba571
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Mar 10 19:16:47 EDT 2014
5e: trap unaligned memory access
--- a/sys/src/cmd/5e/arm.c
+++ b/sys/src/cmd/5e/arm.c
@@ -25,6 +25,15 @@
suicide("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
}
+u32int
+evenaddr(u32int addr, u32int mask)
+{
+ if((addr & mask) == 0)
+ return addr;
+ suicide("unaligned access %8ux @ %8ux\n", addr, P->R[15] - 4);
+ return addr & ~mask;
+}
+
static u32int
doshift(u32int instr)
{
@@ -81,6 +90,8 @@
addr = *Rn;
if(instr & fP)
addr += offset;
+ if((instr & fB) == 0)
+ addr = evenaddr(addr, 3);
targ = vaddr(addr, 4, &seg);
switch(instr & (fB | fL)) {
case 0:
@@ -112,7 +123,7 @@
static void
swap(u32int instr)
{
- u32int *Rm, *Rn, *Rd, *targ, tmp;
+ u32int *Rm, *Rn, *Rd, *targ, addr, tmp;
Segment *seg;
Rm = P->R + (instr & 15);
@@ -120,7 +131,10 @@
Rn = P->R + ((instr >> 16) & 15);
if(Rm == P->R + 15 || Rd == P->R + 15 || Rn == P->R + 15)
invalid(instr);
- targ = (u32int *) vaddr(*Rn, 4, &seg);
+ addr = *Rn;
+ if((instr & fB) == 0)
+ addr = evenaddr(addr, 3);
+ targ = (u32int *) vaddr(addr, 4, &seg);
lock(&seg->lock);
if(instr & fB) {
tmp = *(u8int*) targ;
@@ -255,6 +269,8 @@
target = *Rn;
if(instr & fP)
target += offset;
+ if(instr & fH)
+ target = evenaddr(target, 1);
switch(instr & (fSg | fH | fL)) {
case fSg: *(u8int*) vaddr(target, 1, &seg) = *Rd; break;
case fSg | fL: *Rd = (long) *(char*) vaddr(target, 1, &seg); break;
@@ -281,7 +297,7 @@
Rn = P->R + ((instr >> 16) & 15);
if(Rn == P->R + 15 || instr & (1<<15))
sysfatal("R15 block");
- targ = *Rn;
+ targ = evenaddr(*Rn, 3);
if(instr & fU) {
for(i = 0; i < 16; i++) {
if(!(instr & (1<<i)))
@@ -374,7 +390,7 @@
static void
singleex(u32int instr)
{
- u32int *Rn, *Rd, *Rm, *targ;
+ u32int *Rn, *Rd, *Rm, *targ, addr;
Segment *seg;
Rd = P->R + ((instr >> 12) & 15);
@@ -381,8 +397,9 @@
Rn = P->R + ((instr >> 16) & 15);
if(Rd == P->R + 15 || Rn == P->R + 15)
invalid(instr);
+ addr = evenaddr(*Rn, 3);
if(instr & fS) {
- targ = vaddr(*Rn, 4, &seg);
+ targ = vaddr(addr, 4, &seg);
lock(&seg->lock);
*Rd = *targ;
segunlock(seg);
@@ -390,7 +407,7 @@
Rm = P->R + (instr & 15);
if(Rm == P->R + 15)
invalid(instr);
- targ = vaddr(*Rn, 4, &seg);
+ targ = vaddr(addr, 4, &seg);
if(canlock(&seg->lock)) {
*Rd = 1;
} else {
--- a/sys/src/cmd/5e/fns.h
+++ b/sys/src/cmd/5e/fns.h
@@ -32,6 +32,7 @@
void dump(void);
void resetfpa(void);
void invalid(u32int);
+u32int evenaddr(u32int,u32int);
void fpatransfer(u32int);
void fpaoperation(u32int);
void fparegtransfer(u32int);
--- a/sys/src/cmd/5e/proc.c
+++ b/sys/src/cmd/5e/proc.c
@@ -107,7 +107,7 @@
{
ulong tos, sp, ap, size, i, len;
- tos = mach->utop - sizeof(Tos) * 2;
+ tos = (mach->utop & ~7) - sizeof(Tos) * 2;
sp = tos;
size = 8;
@@ -139,7 +139,7 @@
{
ulong tos;
- tos = mach->utop - sizeof(Tos) * 2;
+ tos = (mach->utop & ~7) - sizeof(Tos) * 2;
((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = P->pid;
}
--- a/sys/src/cmd/5e/vfp.c
+++ b/sys/src/cmd/5e/vfp.c
@@ -55,8 +55,7 @@
sz = instr & (1<<8);
if((instr & (1<<23)) == 0)
off = -off;
- ea = vaddr(P->R[n] + off, 8, &seg);
-
+ ea = vaddr(evenaddr(P->R[n] + off, sz ? 7 : 3), 8, &seg);
switch((instr>>20)&0x3){
case 0:
if(sz)