implemented safe stack for access exception handler
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
* Author: Markus Fröschle
|
* Author: Markus Fröschle
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SYSCLK 132000
|
#define SYSCLK 132000 /* NOTE: 132 _is_ correct. 133 _is_ wrong. Do not change! */
|
||||||
|
|
||||||
#define BOOTFLASH_BASE_ADDRESS 0xE0000000
|
#define BOOTFLASH_BASE_ADDRESS 0xE0000000
|
||||||
#define BOOTFLASH_SIZE 0x800000 /* FireBee has 8 MByte Flash */
|
#define BOOTFLASH_SIZE 0x800000 /* FireBee has 8 MByte Flash */
|
||||||
|
|||||||
@@ -35,6 +35,6 @@ extern long video_tlb;
|
|||||||
extern long video_sbt;
|
extern long video_sbt;
|
||||||
|
|
||||||
extern void mmu_init(void);
|
extern void mmu_init(void);
|
||||||
extern void mmutr_miss(uint32_t addresss);
|
extern void mmutr_miss(uint32_t address);
|
||||||
|
|
||||||
#endif /* _MMU_H_ */
|
#endif /* _MMU_H_ */
|
||||||
|
|||||||
@@ -93,8 +93,11 @@ int am79c874_init(uint8_t fec_ch, uint8_t phy_addr, uint8_t speed, uint8_t duple
|
|||||||
|
|
||||||
/* Set the default mode (Full duplex, 100 Mbps) */
|
/* Set the default mode (Full duplex, 100 Mbps) */
|
||||||
if (!fec_mii_write(fec_ch, phy_addr, MII_AM79C874_CR, MII_AM79C874_CR_100MB | MII_AM79C874_CR_DPLX))
|
if (!fec_mii_write(fec_ch, phy_addr, MII_AM79C874_CR, MII_AM79C874_CR_100MB | MII_AM79C874_CR_DPLX))
|
||||||
|
{
|
||||||
|
dbg("%s: forced setting 100Mbps/full failed.\r\n", __FUNCTION__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DBG_AM79
|
#ifdef DBG_AM79
|
||||||
settings = 0;
|
settings = 0;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "bas_string.h"
|
#include "bas_string.h"
|
||||||
#include "bas_printf.h"
|
#include "bas_printf.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "wait.h"
|
||||||
#include "am79c874.h"
|
#include "am79c874.h"
|
||||||
//#include "bcm5222.h"
|
//#include "bcm5222.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -91,6 +92,7 @@ int fec_mii_write(uint8_t ch, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
|
|||||||
*/
|
*/
|
||||||
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
||||||
{
|
{
|
||||||
|
wait(1);
|
||||||
if (MCF_FEC_EIR(ch) & MCF_FEC_EIR_MII)
|
if (MCF_FEC_EIR(ch) & MCF_FEC_EIR_MII)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -156,6 +158,7 @@ int fec_mii_read(uint8_t ch, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
|
|||||||
*/
|
*/
|
||||||
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
||||||
{
|
{
|
||||||
|
wait(1);
|
||||||
if (MCF_FEC_EIR(ch) & MCF_FEC_EIR_MII)
|
if (MCF_FEC_EIR(ch) & MCF_FEC_EIR_MII)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -481,9 +484,7 @@ void fec_init(uint8_t ch, uint8_t mode, const uint8_t *pa)
|
|||||||
*/
|
*/
|
||||||
MCF_FEC_RCR(ch) = 0
|
MCF_FEC_RCR(ch) = 0
|
||||||
| MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM)
|
| MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM)
|
||||||
//#ifdef FEC_PROMISCUOUS
|
|
||||||
| MCF_FEC_RCR_PROM
|
| MCF_FEC_RCR_PROM
|
||||||
//#endif
|
|
||||||
| MCF_FEC_RCR_FCE;
|
| MCF_FEC_RCR_FCE;
|
||||||
|
|
||||||
if (mode == FEC_MODE_MII)
|
if (mode == FEC_MODE_MII)
|
||||||
|
|||||||
@@ -391,28 +391,34 @@ reset_vector:
|
|||||||
// cannot use the supervisor stack in here. Therefore we first switch to a safe stack
|
// cannot use the supervisor stack in here. Therefore we first switch to a safe stack
|
||||||
// (RAMBAR0, the processor internal SRAM)
|
// (RAMBAR0, the processor internal SRAM)
|
||||||
access_exception:
|
access_exception:
|
||||||
move.w #0x2700,sr // disable interrupt
|
// no point in disabling interrupts within an exception handler
|
||||||
|
// move.w #0x2700,sr // disable interrupt
|
||||||
|
|
||||||
|
|
||||||
// save current SSP
|
// save current SSP
|
||||||
|
|
||||||
move.l sp,__SUP_SP // defined in linker script: top of SRAM0
|
move.l sp,__SUP_SP // defined in linker script: top of SRAM0
|
||||||
lea __SUP_SP - 4,sp // now we can savely use the stack
|
lea __SUP_SP - 4,sp // now we can savely use the stack
|
||||||
|
|
||||||
move.l d0,-(sp) // ++ vr
|
// save gcc scratch registers, others will be handled by called function
|
||||||
move.l a0,-(sp)
|
lea -4*4(sp),sp
|
||||||
|
movem.l d0-d1/a0-a1,(sp)
|
||||||
|
|
||||||
move.l __SUP_SP,a0 // original stack frame
|
|
||||||
move.w (a0),d0 // get format_status word from stack
|
|
||||||
andi.l #0x0c03,d0 // mask out fault status bits
|
|
||||||
cmpi.l #0x0401,d0 // TLB miss on opword of instruction fetch?
|
|
||||||
beq access_exception_mmu // yes
|
|
||||||
cmpi.l #0x0402,d0 // TLB miss on extension word of instruction fetch?
|
|
||||||
beq access_exception_mmu // yes
|
|
||||||
cmpi.l #0x0802,d0 // TLB miss on data write?
|
|
||||||
beq access_exception_mmu // yes
|
|
||||||
cmpi.l #0x0c02,d0 // TLB miss on data read, or read-modify-write?
|
|
||||||
beq access_exception_mmu // yes
|
|
||||||
|
|
||||||
// revert stack trickery
|
move.l __SUP_SP,a0 // original stack pointer
|
||||||
|
|
||||||
|
move.l 4(a0),-(sp) // format status word
|
||||||
|
move.l (a0),-(sp) // program counter at access error
|
||||||
|
|
||||||
|
jsr _access_exception
|
||||||
|
lea 2*4(sp),sp // adjust stack
|
||||||
|
|
||||||
|
tst.l d0 // handled?
|
||||||
|
bne bus_error
|
||||||
|
|
||||||
|
movem.l (sp),d0-d1/a0-a1 // restore scratch registers
|
||||||
|
lea 4*4(sp),sp
|
||||||
|
|
||||||
|
|
||||||
move.l (sp)+,a0
|
move.l (sp)+,a0
|
||||||
move.l (sp)+,d0
|
move.l (sp)+,d0
|
||||||
@@ -420,22 +426,6 @@ access_exception:
|
|||||||
|
|
||||||
bra bus_error // everything else is a classic bus error
|
bra bus_error // everything else is a classic bus error
|
||||||
|
|
||||||
access_exception_mmu:
|
|
||||||
move.l MCF_MMU_MMUSR,d0 // did the last fault hit in TLB?
|
|
||||||
btst #1,d0 // yes, it did. So we already mapped that page
|
|
||||||
bne bus_error // and this must be a real bus error
|
|
||||||
|
|
||||||
move.l MCF_MMU_MMUAR,d0
|
|
||||||
cmp.l #__FASTRAM_END,d0 // above max User RAM area?
|
|
||||||
bge bus_error // -> bus error
|
|
||||||
|
|
||||||
lea -5*4(sp),sp // save gcc scratch registers
|
|
||||||
movem.l d0-d1/a0-a2,(sp)
|
|
||||||
|
|
||||||
move.l d0,-(sp) // fault address
|
|
||||||
jsr _mmutr_miss // else we have an MMU TLB miss
|
|
||||||
addq.l #4,sp
|
|
||||||
|
|
||||||
movem.l (sp),d0-d1/a0-a2 // restore gcc scratch registers
|
movem.l (sp),d0-d1/a0-a2 // restore gcc scratch registers
|
||||||
lea 5*4(sp),sp
|
lea 5*4(sp),sp
|
||||||
|
|
||||||
@@ -449,11 +439,16 @@ access_exception_mmu:
|
|||||||
rte
|
rte
|
||||||
|
|
||||||
bus_error:
|
bus_error:
|
||||||
|
|
||||||
|
// revert stack trickery
|
||||||
|
|
||||||
|
move.l (sp)+,a0
|
||||||
move.l (sp)+,d0 // restore register
|
move.l (sp)+,d0 // restore register
|
||||||
|
move.l __SUP_SP,sp // restore original stack
|
||||||
|
|
||||||
bra std_exc_vec
|
bra std_exc_vec
|
||||||
|
|
||||||
zero_divide:
|
zero_divide:
|
||||||
move.w #0x2700,sr // disable interrupt
|
|
||||||
move.l a0,-(a7)
|
move.l a0,-(a7)
|
||||||
move.l d0,-(a7)
|
move.l d0,-(a7)
|
||||||
move.l 12(a7),a0 // pc
|
move.l 12(a7),a0 // pc
|
||||||
|
|||||||
@@ -394,26 +394,70 @@ void mmu_init(void)
|
|||||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handle an access error
|
||||||
|
* upper level routine called from access_exception inside exceptions.S
|
||||||
|
*/
|
||||||
|
bool access_exception(uint32_t pc, uint32_t format_status)
|
||||||
|
{
|
||||||
|
int fault_status;
|
||||||
|
uint32_t fault_address;
|
||||||
|
bool is_tlb_miss = false; /* assume access error is not a TLB miss */
|
||||||
|
extern uint8_t __FASTRAM_END[];
|
||||||
|
uint32_t FASTRAM_END = (uint32_t) &__FASTRAM_END[0];
|
||||||
|
|
||||||
|
fault_status = (((format_status & 0xc000000) >> 26) |
|
||||||
|
((format_status & 0x30000) >> 16));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* determine if access fault was caused by a TLB miss
|
||||||
|
*/
|
||||||
|
switch (fault_status)
|
||||||
|
{
|
||||||
|
case 0x5: /* TLB miss on opword of instruction fetch */
|
||||||
|
case 0x6: /* TLB miss on extension word of instruction fetch */
|
||||||
|
case 0xa: /* TLB miss on data write */
|
||||||
|
case 0xe: /* TLB miss on data read or read-modify-write */
|
||||||
|
is_tlb_miss = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_tlb_miss)
|
||||||
|
{
|
||||||
|
if (MCF_MMU_MMUSR & 1) /* did the last fault hit in TLB? */
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* if yes, then we already mapped that page during a previous turn and this is in fact a bus error
|
||||||
|
*/
|
||||||
|
is_tlb_miss = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fault_address = MCF_MMU_MMUAR; /* retrieve fault access address from MMU */
|
||||||
|
if (fault_address > FASTRAM_END)
|
||||||
|
{
|
||||||
|
is_tlb_miss = false; /* this is a bus error */
|
||||||
|
}
|
||||||
|
else /* map this page */
|
||||||
|
{
|
||||||
|
mmutr_miss(fault_address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return is_tlb_miss;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void mmutr_miss(uint32_t address)
|
void mmutr_miss(uint32_t address)
|
||||||
{
|
{
|
||||||
dbg("MMU TLB MISS at 0x%08x\r\n", address);
|
dbg("MMU TLB MISS at 0x%08x\r\n", address);
|
||||||
flush_and_invalidate_caches();
|
flush_and_invalidate_caches();
|
||||||
|
|
||||||
switch (address)
|
|
||||||
{
|
|
||||||
case keyctl:
|
|
||||||
case keybd:
|
|
||||||
/* do something to emulate the IKBD access */
|
|
||||||
dbg("IKBD access\r\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case midictl:
|
|
||||||
case midi:
|
|
||||||
/* do something to emulate MIDI access */
|
|
||||||
dbg("MIDI ACIA access\r\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* add missed page to TLB */
|
/* add missed page to TLB */
|
||||||
MCF_MMU_MMUTR = (address & 0xfff00000) | /* virtual aligned to 1M */
|
MCF_MMU_MMUTR = (address & 0xfff00000) | /* virtual aligned to 1M */
|
||||||
MCF_MMU_MMUTR_SG | /* shared global */
|
MCF_MMU_MMUTR_SG | /* shared global */
|
||||||
@@ -433,7 +477,6 @@ void mmutr_miss(uint32_t address)
|
|||||||
MCF_MMU_MMUOR_ACC | /* access TLB */
|
MCF_MMU_MMUOR_ACC | /* access TLB */
|
||||||
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
MCF_MMU_MMUOR_UAA; /* update allocation address field */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user