Commit 350370aa authored by Kevin Bracey's avatar Kevin Bracey
Browse files

Abort and error handling massively overhauled:

  Aborts now give standard error messages (Abort on Data Transfer at... etc)
  *ShowRegs now filled in after aborts
  assert(), abort(), "free failed" and standard signal handlers now use Wimp
    error boxes if in the desktop
  Postmortem button on error boxes to view the postmortem

Also, x$multiply, x$divide, __rt_sdiv, x$remainder, x$udivide, __rt_udiv and
x$uremainder optimised.

Version 5.35. Tagged as 'RISC_OSLib-5_35'
parent b89f78c3
R0 -> error, R1-R9 as returned from SWI, R10-R12, SWI addr on stack, R14=SPSR
On entry to error handler, for SWI errors:
User mode - IRQs on
R0 -> error handler's buffer (containing PC error occured at (address of instr after SWI),
and a copy of the error)
R1-R9 as returned from the SWI
R10-R12 recovered from stack (may be wrong if SWI wasn't top level - bad person)
User R13,R14 as it was when SWI called
Default abort handler:
Register block filled in with registers for current mode at time of abort.
Stacks flattened
R10-R12, PC from dump placed in SVC stack
OS_Generate error called.
End result: R0-> error
R1-R9 corrupt
R10-R12 = registers at instant of abort (from mode in which abort happened)
R13,R14 = USR registers at instant of abort
Register block contains registers for current mode at time of abort.
C abort handler should note USR mode registers (only) then pass it on.
C error handler should note that it is an abort, and not touch the register dump.
Error numbers:
&800000XX - machine exceptions: 00=Undef, 01=PAbort, 02=DAbort, 03=AddrEx, 04=Unknown IRQ?
05=BThru0
&800002XX - FP exceptions: 00=IVO, 01=OFL, 02=DVZ, 03=UFL, 04=INX, 05=Faulty
FP exceptions:
User mode registers go into integer register dump.
FP registers go into FP register dump
OS_GenerateError from inside FPEm - error handler called with all except R1 intact.
;
; This file is automatically maintained by srccommit, do not edit manually.
; Last processed by srccommit version: 1.62.
;
GBLS Module_MajorVersion
GBLA Module_Version
......@@ -11,14 +12,14 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.34"
Module_Version SETA 534
Module_MajorVersion SETS "5.35"
Module_Version SETA 535
Module_MinorVersion SETS ""
Module_Date SETS "23 Aug 2001"
Module_ApplicationDate2 SETS "23-Aug-01"
Module_ApplicationDate4 SETS "23-Aug-2001"
Module_Date SETS "29 Jan 2002"
Module_ApplicationDate2 SETS "29-Jan-02"
Module_ApplicationDate4 SETS "29-Jan-2002"
Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.34"
Module_HelpVersion SETS "5.34 (23 Aug 2001)"
Module_FullVersion SETS "5.35"
Module_HelpVersion SETS "5.35 (29 Jan 2002)"
END
/* (5.34)
/* (5.35)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.62.
*
*/
#define Module_MajorVersion_CMHG 5.34
#define Module_MajorVersion_CMHG 5.35
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 23 Aug 2001
#define Module_Date_CMHG 29 Jan 2002
#define Module_MajorVersion "5.34"
#define Module_Version 534
#define Module_MajorVersion "5.35"
#define Module_Version 535
#define Module_MinorVersion ""
#define Module_Date "23 Aug 2001"
#define Module_Date "29 Jan 2002"
#define Module_ApplicationDate2 "23-Aug-01"
#define Module_ApplicationDate4 "23-Aug-2001"
#define Module_ApplicationDate2 "29-Jan-02"
#define Module_ApplicationDate4 "29-Jan-2002"
#define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.34"
#define Module_HelpVersion "5.34 (23 Aug 2001)"
#define Module_FullVersion "5.35"
#define Module_HelpVersion "5.35 (29 Jan 2002)"
#define Module_LibraryVersionInfo "5:35"
......@@ -33,6 +33,7 @@
#include <string.h> /* for strlen() */
#include <time.h> /* for clock */
#include <errno.h>
#include <stdbool.h>
/* IMPORTS */
extern int main(int argc, char **argv); /* the point of it all */
......@@ -40,11 +41,14 @@ extern FILEHANDLE __dup(int new, int old);
extern void _ctype_init(void);
extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
extern int _sprintf_lf(char *buff, const char *fmt, ...);
extern _kernel_oserror *_kernel_peek_last_oserror(void);
/* HIDDEN EXPORTS */
void _main(char *s, int (*main)(int, char **));
void _backtrace(int why, int *address, _kernel_unwindblock *uwb);
const char *_clib_version(void);
int _sys_msg_1(const char *s, const char *but);
int _desktop_task(void);
#define str(x) #x
#define xstr(x) str(x)
......@@ -149,9 +153,118 @@ time_t time(time_t *timer)
#define istty(fh) ((fh) == TTYHANDLE)
/*
* We're a desktop task if we're in user mode, TaskWindow_TaskInfo 0 returns 0 (or an error),
* and Wimp_ReadSysInfo 3 says we're in the desktop, and Wimp_ReadSysInfo 5 gives us a
* task handle.
*/
int _desktop_task()
{
int h = 0;
if (_kernel_processor_mode() & 0xF) return 0;
_swix(TaskWindow_TaskInfo, _IN(0)|_OUT(0), 0, &h);
if (h) return 0;
_swix(Wimp_ReadSysInfo, _IN(0)|_OUT(0), 3, &h);
if (h == 0) return 0;
_swix(Wimp_ReadSysInfo, _IN(0)|_OUT(0), 5, &h);
return h;
}
static int _desktop_report(const char *s, const char *but)
{
_kernel_oserror err, *e;
const char *n = NULL;
char *p, *end;
int flags, r, h = _desktop_task();
if (h == 0) return 0;
flags = 0x102; /* New error, cancel button */
if ((e = _kernel_last_oserror()) != NULL && s == e->errmess)
{
flags |= 2 << 9;
}
else
{
while (*s == ' ')
s++;
if (s[0] == '*') /* If leading '*'s then make it a serious one */
{
while (*s == '*' || *s == ' ') /* Strip off the '*'s */
s++;
flags |= 3 << 9;
err.errnum = 0x1B << 24;
}
else
{
flags |= 2 << 9;
err.errnum = 0;
}
for (p = err.errmess, end = err.errmess + sizeof err.errmess - 1; p < end && *s >= ' '; )
*p++ = *s++;
*p = '\0';
err.errmess[0] = toupper(err.errmess[0]);
e = &err;
}
_swix(TaskManager_TaskNameFromHandle, _IN(0)|_OUT(0), h, &n);
r = 0;
_swix(Wimp_ReportError, _INR(0,5)|_OUT(1), e, flags, n, NULL, 1, but, &r);
return r;
}
bool _sys__assert(const char *s, const char *expr, const char *file, int line)
{
char buffer[252];
int len, exprlen, filelen;
if (!istty(stderr->__file)) return false;
if (!_desktop_task()) return false;
if (strlen(s) > 200) return false; /* Be safe */
len = sprintf(buffer, s, "", "", line);
exprlen = strlen(expr);
filelen = strlen(file);
if (len + exprlen + filelen < 251)
{
sprintf(buffer, s, expr, file, line);
}
else
{
char expr2[200];
char file2[100];
#define min(a,b) a<b?a:b
exprlen = min(exprlen, 199);
filelen = min(filelen, 99);
filelen = min(filelen, 251-len-exprlen);
if (filelen < 0) filelen = 0;
exprlen = min(exprlen, 251-len-filelen);
memcpy(expr2, expr, exprlen);
memcpy(file2, file, filelen);
expr2[exprlen]='\0';
file2[filelen]='\0';
sprintf(buffer, s, expr2, file2, line);
}
return _desktop_report(buffer, NULL);
}
static int _error_recursion;
void _sys_msg(const char *s)
{ /* write out s carefully for intimate system use. */
int _sys_msg_1(const char *s, const char *but)
{
if (istty(stderr->__file))
{
int r = _desktop_report(s, but);
if (r) return r;
}
/* write out s carefully for intimate system use. */
if ((stderr->__flag & _IOWRITE) && !_error_recursion)
{
_error_recursion = 1;
......@@ -166,6 +279,13 @@ void _sys_msg(const char *s)
_ttywrite((unsigned char *)s, strlen(s), 0);
_ttywrite((unsigned char *)"\n", 1, 0);
}
return 0;
}
void _sys_msg(const char *s)
{
_sys_msg_1(s, NULL);
}
#define LF '\n'
......@@ -195,9 +315,8 @@ FILEHANDLE _sys_open(const char *filename, int openmode)
(openmode & OPEN_W) ||
(openmode & ~OPEN_B) == OPEN_A) /* or mode = w, w+, or a */
{ if (_kernel_osfile(9, name, &fb) == _kernel_ERROR)
{ if (_kernel_last_oserror()->errnum == 0x108c9)
{ (void)_kernel_osfile(9, name, &fb); /* to restore the error */
errno = -1;
{ if (_kernel_peek_last_oserror()->errnum == 0x108c9)
{ errno = -1;
return NONHANDLE; /* (Protected disc) */
}
}
......
......@@ -49,9 +49,11 @@ void _sysdie(const char *s)
/* from <assert.h> */
void __assert(char *expr, char *file, int line)
{
_fprintf_lf(stderr,
_kernel_getmessage("*** assertion failed: %s, file %s, line %d", "C34"),
expr, file, line);
const char *s;
s = _kernel_getmessage("*** assertion failed: %s, file %s, line %d", "C34");
if (!_sys__assert(s, expr, file, line))
_fprintf_lf(stderr, s, expr, file, line);
fputc('\n', stderr);
abort();
}
......
......@@ -29,6 +29,9 @@
extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
extern int _sprintf_lf(char *buff, const char *fmt, ...);
extern int _SignalNumber(int errnum);
extern _kernel_oserror *_kernel_peek_last_oserror(void);
#define SIGLAST 11 /* one after highest signal number (see <signal.h>) */
static void (*_signalvector[SIGLAST+1])(int);
......@@ -47,6 +50,14 @@ extern void __ignore_signal_handler(int sig)
static void _real_default_signal_handler(int sig)
{
char *s, v[128];
_kernel_oserror *e = _kernel_peek_last_oserror();
if (((sig == SIGSEGV || sig == SIGILL) && _SignalNumber(e->errnum) == sig) ||
sig == SIGFPE || sig == SIGOSERROR)
{
_postmortem(e->errmess, *((int *)"mesg"));
return;
}
switch (sig)
{
......@@ -56,10 +67,6 @@ case SIGABRT:
#endif
s = _kernel_getmessage(s, "C39");
break;
case SIGFPE:
case SIGOSERROR:
s = &(_kernel_last_oserror()->errmess[0]);
break;
case SIGILL:
#ifdef DEFAULT_TEXT
#ifdef __arm
......
......@@ -68,6 +68,7 @@ $Label RFS r1
IMPORT |_signal_real_handler|
IMPORT |_armsys_lib_init|
IMPORT |_sys_msg|
IMPORT |_sys_msg_1|
IMPORT |_kernel_fpavailable|
IMPORT |_kernel_exittraphandler|
......@@ -103,11 +104,7 @@ $Label RFS r1
EXPORT |x$stack_overflow|
EXPORT |x$stack_overflow_1|
EXPORT |_raise_stacked_interrupts|
EXPORT |x$udivide|
EXPORT |x$uremainder|
EXPORT |x$divide|
EXPORT |x$divtest|
EXPORT |x$remainder|
EXPORT |x$multiply|
EXPORT |_rd1chk|
EXPORT |_rd2chk|
......@@ -137,14 +134,13 @@ $Label RFS r1
EXPORT |_count|
EXPORT |_count1|
EXPORT |_default_sigstak_handler|
EXPORT |_SignalNumber|
EXPORT |_ldfp|
EXPORT |_stfp|
EXPORT |__rt_stkovf_split_small|
EXPORT |__rt_stkovf_split_big|
EXPORT |__rt_udiv|
EXPORT |__rt_sdiv|
EXPORT |__rt_divtest|
EXPORT |__rt_rd1chk|
EXPORT |__rt_rd2chk|
......@@ -242,6 +238,7 @@ UnhandledEventHandler Keep
02 MOV a1, #1 ; we wish to handle it, but not just yet
Return ,LinkNotStacked
|_SignalNumber|
SignalNumber Keep
; nb required not to disturb a4
MOV a2, #SIGOSERROR
......@@ -316,39 +313,21 @@ Raised
|x$multiply|
; a1 := a2 * a1.
; sets a2 to 0 and a3 to a copy of the product.
MOV a3, #0
m0loop MOVS a2, a2, LSR #1
ADDCS a3, a3, a1
ADD a1, a1, a1
BNE m0loop
MOV a1, a3
; a2, a3 can be scrambled.
MUL a1, a2, a1
Return ,LinkNotStacked
|x$remainder|
B |_kernel_srem|
IMPORT |_kernel_copyerror|
IMPORT |_kernel_fault|
|__rt_divtest|
|x$divtest|
; test for division by zero (used when division is voided)
CMPS a1, #0
TEQS a1, #0
Return ,LinkNotStacked, NE
STMFD sp!, {r0}
ADR r0, E_DivideByZero
B |_kernel_fault|
|__rt_sdiv|
|x$divide|
B |_kernel_sdiv|
|__rt_udiv|
|x$udivide|
B |_kernel_udiv|
|x$uremainder|
B |_kernel_urem|
|__rt_rd1chk|
|_rd1chk|
......@@ -492,10 +471,6 @@ readfail
Return
mesg DCB "mesg"
wimp_title
DCB "WindowManager", 0
utility_title
DCB "UtilityModule", 0
[ :DEF:DEFAULT_TEXT
postmortem_title
DCB "Postmortem", 0
......@@ -504,70 +479,13 @@ postmortem_tag
DCB "C65", 0
ALIGN
n_module_lookup EQU 18
wimp_preinitflag EQU &80000000
zp_wimpdomain EQU &ff8
IMPORT |_desktop_task|
IMPORT |_kernel_unwind|
IMPORT exit
|_postmortem|
; Prepare window manager for output
; First check this is a wimp task
STMFD sp!, {r0-r5, r14}
MOV r0, #n_module_lookup
ADR r1, utility_title
SWI XOS_Module
BVS postmortem2
LDR r0, [r3, #5 * 4]
MOV r1, #0
ADD r0, r0, r3
postmortem3
LDRB r2, [r0], #1
CMP r2, #9
ORREQ r1, r1, #7
ADD r1, r1, #1
CMP r1, #16
BCC postmortem3
LDRB r1, [r0]
SUB r1, r1, #'0'
LDRB r2, [r0, #2]
SUB r2, r2, #'0'
ADD r1, r1, r1, LSL #2
ADD r1, r2, r1, LSL #1
LDRB r2, [r0, #3]
SUB r2, r2, #'0'
ADD r1, r1, r1, LSL #2
ADD r1, r2, r1, LSL #1
CMP r1, #202
BCC postmortem2
MOV r0, #0
SWI XTaskWindow_TaskInfo
MOVVS r0, #0
CMP r0, #0
BNE postmortem0
MOV r0, #3
SWI XWimp_ReadSysInfo
BVS postmortem0
CMP r0, #0
BEQ postmortem0
B postmortem4
postmortem2
MOV r0, #0
SWI XWimp_ReadSysInfo
BVS postmortem0
CMP r0, #0
BEQ postmortem0
; In desktop, now check Wimp_Initialise has been called
MOV r0, #n_module_lookup
ADR r1, wimp_title
SWI XOS_Module
BVS postmortem0
MOV r0, #0
LDR r0, [r0, #zp_wimpdomain]
LDR r0, [r4, r0]
TST r0, #wimp_preinitflag
BNE postmortem0
; If so reopen command window
postmortem4
[ :DEF:DEFAULT_TEXT
ADR r0, postmortem_title
ADR r1, postmortem_tag
......@@ -575,13 +493,32 @@ postmortem4
ADR r0, postmortem_tag
]
BL |_kernel_getmessage|
SWI XWimp_CommandWindow
MOV r5, r0
postmortem0
LDMFD sp!, {r0-r5}
LDR a3, mesg
CMP a2, a3
BLEQ |_sys_msg| ; BL<cond> 32-bit OK
LDMFD sp, {a1-a2}
LDR a3, mesg ; if magic arg2 != "mesg"
CMP a2, a3 ; then go straight onto postmortem
BNE postmortem1
MOV a2, r5 ; if so, offer postmortem
BL |_sys_msg_1|
TEQ r4, #1
TEQ a1, #0 ; if didn't display the button
TEQNE a1, #3 ; or if he selected it, then carry on with postmortem
MOVNE a1, #1 ; otherwise exit(EXIT_FAILURE)
BNE exit
postmortem1
BL _desktop_task
TEQ a1, #0
BEQ postmortem2
LoadStaticAddress __iob + 2 * 40, a2, a3 ; a2 -> stderr
LDR r4, [a2, #20] ; a2 = stderr->__file
TEQ r4, #0 ; istty(stderr->__file)?
BNE postmortem2
MOV r0, r5 ; if desktop, and stderr = tty
SWI XWimp_CommandWindow ; then open command window,
SWI XOS_WriteI + 14 ; page mode on
postmortem2
LDMFD sp!, {r0-r5}
BL |_kernel_fpavailable|
LDMFD sp!, {r14}
CMP a1, #0
......@@ -645,6 +582,28 @@ postmortem_nofp
ADD sp, sp, #22*4
MOV a3, sp
B |_backtrace|
;MOV a1, #&4000
;MOV a2, #&4000
;MOV a3, #&20
;MOV a4, #&FF
;SWI XOS_ReadLine
;MOVCS a1, #124
;SWICS XOS_Byte
;SWI XWimp_CloseDown
;ADR a1, debug_cmd
;SWI XOS_CLI
;MOVVC a1, #0
;LDRVS a1, [a1]
;TEQ a1, #0
;TEQNE a1, #&11
;MOVEQ a1, #-1
;SWIEQ XWimp_CommandWindow
;MOV a1, #1
;B exit
debug_cmd
DCB "Debug", 0
ALIGN
|__rt_stkovf_split_small|
|x$stack_overflow|
......
......@@ -23,6 +23,7 @@
#define __hostsys_h
#include <stdio.h>
#include <stdbool.h>
#undef MACHINE
#ifdef __arm
......@@ -99,6 +100,8 @@ extern void *_sys_alloc(size_t n);
extern void _init_user_alloc(void);
extern void _terminate_user_alloc(void);
extern void _sys_msg(const char *);
extern bool _sys__assert(const char *fmt,
const char *expr, const char *file, int line);
extern void _exit(int n);
extern void _terminate_getenv(void);
......
......@@ -47,6 +47,7 @@
EXPORT |_kernel_osargs|
EXPORT |_kernel_oscli|
EXPORT |_kernel_last_oserror|
EXPORT |_kernel_peek_last_oserror|
EXPORT |_kernel_system|
EXPORT |_kernel_getenv|
EXPORT |_kernel_setenv|
......@@ -88,9 +89,16 @@
EXPORT |_kernel_call_client|
EXPORT |_kernel_raise_error|
EXPORT |__rt_sdiv|
EXPORT |__rt_udiv|
EXPORT |__rt_udiv10|
EXPORT |__rt_sdiv10|
EXPORT |x$divide|
EXPORT |x$udivide|
EXPORT |x$remainder|
EXPORT |x$uremainder|
EXPORT |__counter|
PSRBits * &FC000003
......@@ -719,7 +727,7 @@ ABEXString
; tacked on the end.
IIHandlerInDataInitValue
STMFD r13!, {r0, r12}
STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_IIHandlerInData+12
; Now the bits of the abort handlers which get executed from the code.
......@@ -728,81 +736,88 @@ IIHandlerInDataInitValue
IIHandler Keep
SUB r14, r14, #4
ADR r0, E_IllegalInstruction
STR r14, [r12, #O_registerDump + 15 * 4]
LDR r14, [r12, #O_oldAbortHandlers + 0]
STR r14, [r13, #28]
B Aborted
PAHandlerInDataInitValue
STMFD r13!, {r0, r12}
STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_PAHandlerInData+12
PAHandler Keep
SUB r14, r14, #4
ADR r0, E_PrefetchAbort
STR r14, [r12, #O_registerDump + 15 * 4]
LDR r14, [r12, #O_oldAbortHandlers + 4]
STR r14, [r13, #28]
B Aborted
DAHandlerInDataInitValue
STMFD r13!, {r0, r12}
STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_DAHandlerInData+12
DAHandler Keep
SUB r14, r14, #8
ADR r0, E_DataAbort
STR r14, [r12, #O_registerDump + 15 * 4]
LDR r14, [r12, #O_oldAbortHandlers + 8]
STR r14, [r13, #28]
B Aborted2
AEHandlerInDataInitValue
STMFD r13!, {r0, r12}
STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_AEHandlerInData+12
AEHandler Keep
SUB r14, r14, #8
ADR r0, E_AddressException
STR r14, [r12, #O_registerDump + 15 * 4]
LDR r14, [r12, #O_oldAbortHandlers + 12]
STR r14, [r13, #28]
; B Aborted2
Aborted2 Keep
; Abort which may be in the FP emulator, and if so should be reported
; as occurring at the instruction being emulated.
; Try the FPEmulator_Abort SWI
STMFD sp!, {r0-r2, r14}
LDR r2, [sp, #24]
[ {CONFIG}=26
BIC r14, r14, #PSRBits
BIC r2, r2, #PSRBits
|
MOV r0, #0
MRS r0, CPSR
TST r0, #2_11100
BICEQ r14, r14, #PSRBits
TEQ pc, pc
BICNE r2, r2, #PSRBits
]
MOV r0, #-2 ; current context
LDR r1, [sp, #20] ; original r12
ADD r2, r14, #8 ; original r14
ADD r2, r2, #8 ; original r14
SWI XFPEmulator_Abort
BVS NoFPEAbortSWI
TEQ r0, #0
LDMEQFD sp!, {r0-r2, r14}
LDMEQFD sp, {r0-r2}
BEQ Aborted ; not in FPEmulator
STR r0, [sp, #20] ; update r12 in stack
LDMFD sp!, {r0-r2, r14}
B FPEFault
NoFPEAbortSWI
; If in user mode, can't be in FPE
[ {CONFIG}=26
LDR r1, [sp, #12]
LDR r1, [sp, #24]
TST r1, #PSRPrivileged
|
MOV r2, #0
MRS r2, CPSR
TST r2, #2_11100
LDREQ r1, [sp, #12]
ANDEQ r1, r1, #3 ; obtain aborter's mode from R14
MRSNE r1, SPSR ; obtain aborter's mode from SPSR
TEQ pc, pc
LDRNE r1, [sp, #24]
ANDNE r1, r1, #PSRMode ; obtain aborter's mode from R14
MRSEQ r1, SPSR ; obtain aborter's mode from SPSR
TST r1, #PSR32Privileged
]
LDMEQFD sp!, {r0-r2, r14}
LDMEQFD sp, {r0-r4}
BEQ Aborted
; Otherwise, find out where the FPE module is
[ {CONFIG} <> 26
TST r2, #2_11100
]
LDMFD sp!, {r0-r2, r14}
STMFD sp!, {r0 - r6, r14}
STMFD sp!, {r0 - r6}
[ {CONFIG} = 26
BIC r6, r14, #PSRBits
|
......@@ -812,65 +827,60 @@ NoFPEAbortSWI
MOV r0, #18
ADR r1, FPEName
SWI Module
LDMVSFD sp!, {r0 - r6, r14}
LDMVSFD sp!, {r0 - r6}
BVS Aborted
; (r3 = code base of FPE; word before is length of FPE code)
CMP r6, r3
LDRGE r4, [r3, #-4]
ADDGE r3, r3, r4
CMPGE r3, r6
LDMFD sp!, {r0 - r6, r14}
LDMFD sp!, {r0 - r6}
BLT Aborted
; It was a storage fault in the FP emulator.
; We assume FPEmulator 4.00 or later - r12 in the register dump
; We assume FPEmulator 4.00 or later - r0
; will point to a full register save. The format differs slightly
; depending on whether the FPEmulator is 32-bit or not. If we're
; in a 32-bit mode, we know the FPEmulator will be. If not, check
; to see if the saved r12 is in the UND stack.
FPEFault
LDR r1, [r13, #4] ; r1 -> FPE stack frame
ADD r13, r13, #8 ; pop the saved values of r0 and r12
ADD r14, r12, #O_registerDump
LDMIA r1!, {r2-r9} ; copy R0-R15
STMIA r14!, {r2-r9}
LDMIA r1!, {r2-r9}
SUB r9, r9, #4
STMIA r14!, {r2-r9}
LDMIA r0!, {r1-r4} ; copy R0-R15
STMIA r14!, {r1-r4}
LDMIA r0!, {r1-r4}
STMIA r14!, {r1-r4}
LDMIA r0!, {r1-r4}
STMIA r14!, {r1-r4}
LDMIA r0!, {r1-r4}
SUB r4, r4, #4 ; adjust PC back 4
STMIA r14!, {r1-r4}
[ {CONFIG}<>26
MOV r2, #0
MRS r2, CPSR
TST r2, #2_11100
BNE FPEFault_32on32
TEQ pc, pc
BEQ FPEFault_32on32
]
LDR r3, [r12, #O_undStack]
MOV r2, r1, LSR #20 ; we're on a 26-bit system
TEQ r2, r3, LSR #20 ; is the stack frame in the UND stack?
BEQ FPEFault_32on26
FPEFault_26on26
MOV sp, r1 ; pull the SVC stack up
B AbortFindHandler
B FPEFault_Continue
FPEFault_32on26
LDR r2, [r1, #-72] ; get the SPSR
LDR r2, [r0, #-72] ; get the SPSR
AND r2, r2, #PSRBits
BIC r9, r9, #PSRBits
ORR r9, r9, r2
STR r9, [r14, #-4] ; merge it with pc in register dump
B FPEFault_32
BIC r4, r4, #PSRBits
ORR r4, r4, r2
STR r4, [r14, #-4] ; merge it with pc in register dump
[ {CONFIG}<>26
B FPEFault_Continue
FPEFault_32on32
LDR r2, [r1, #-72] ; get the SPSR
STR r2, [r14] ; store it in the register dump
]
FPEFault_32
MRS r2, CPSR
BIC r3, r2, #PSR32Mode
ORR r3, r3, #PSR32IBit + PSR32UNDMode
MSR CPSR_c, r3
MOV sp, r1 ; pull the UND stack up
MSR CPSR_c, r2
B AbortFindHandler
FPEFault_Continue
LDMFD r13!, {r0-r4, r12, r14, pc}
ErrorBlock PrefetchAbort, "Prefetch Abort", C60
ErrorBlock DataAbort, "Data Abort", C61
......@@ -880,59 +890,49 @@ FPEName = "FPEmulator",0
ALIGN
Aborted Keep
; entry here in SVC26, SVC32, ABT32 or UND32 mode
; r0 a pointer to an error block describing the abort.
; all user registers except r0, r12 are as at the time of the abort.
; r0 & r12 are on the stack.
; First, save all user registers in registerDump.
STMFD r13!, {r14} ; remember the abort pc
BL |_kernel_copyerror|
ADD r14, r12, #O_registerDump
[ SASTMhatbroken
STMIB r14!, {r1-r12}
STMIB r14, {r13,r14}^
NOP
SUB r14, r14, #12*4
STMIA r14!, {r0-r12}
STMIA r14, {r13,r14}^
NOP
SUB r14, r14, #13*4
|
STMIB r14, {r1-r14}^
STMIA r14, {r0-r14}^
NOP
]
LDMFD r13!, {r1, r2, r3} ; abort PC, R0, R12
MOV r6, r14 ; switch it to a non-banked register
MOV r4, #0
MRS r4, CPSR
TST r4, #2_11100
ANDEQ r5, r1, #3 ; obtain aborter's mode from R14
MRSNE r5, SPSR ; obtain aborter's mode from SPSR
STRNE r5, [r14, #16*4] ; store aborter's SPSR if in 32-bit mode
BICNE r4, r4, #PSR32Mode
ORRNE r4, r4, #PSR32SVCMode
MSRNE CPSR_c, r4 ; switch to SVC32 (already in SVC26 if 26bit)
TST r5, #PSR32Privileged
LDRNE r1, [r6, #lr*4] ; if aborted in a privileged mode, save
STR r1, [r6, #pc*4] ; PC as user R14
STR r2, [r6, #r0*4]
STREQ r3, [r6, #r12*4]
BEQ AbortFlattenStacks
LDR r4, [r12, #O_svcStack]
SUB r1, r4, sp
CMP r1, #3 * 4
BCC AbortFlattenStacks
LDMEA r4, {r1, r2, r3}
ADD r4, r6, #10 * 4
STMIA r4, {r1, r2, r3}
; should really fall through to error handler and let the OS clean up,
; but this is a lot better than it was!
AbortFlattenStacks
MRS r4, CPSR ; MRS and MSR here will be NOPs on
ORR r1, r4, #PSR32UNDMode ; ARM2/3, so we'll end up setting
MSR CPSR_c, r1 ; R13_svc twice; just make sure
LDR sp, [r12, #O_undStack] ; we set the real value last.
MSR CPSR_c, r4
LDR sp, [r12, #O_svcStack]
LDR r0, [r13, #20]
STR r0, [r14, #r12*4]
MOV r3, pc
AND r3, r3, #PSRBits
MRS r3, CPSR
TST r3, #2_11100
LDREQ r0, [sp, #24]
ANDEQ r0, r0, #PSRMode ; obtain aborter's mode from R14
MRSNE r0, SPSR ; obtain aborter's mode from SPSR
STRNE r0, [r14, #16*4] ; store aborter's SPSR if in 32-bit mode
TST r0, #PSR32Privileged
BEQ NotPrivileged
LDR r0, [r14, #r14*4] ; if abort in a privileged mode, save
STR r0, [r14, #pc*4] ; PC as user R14
LDR r0, [r12, #O_svcStack] ; switch to SVC mode and look at R13_svc
TEQ pc, pc
MSREQ CPSR_c, #PSR32SVCMode
TEQNEP pc, #PSRSVCMode
NOP
SUB r12, r0, sp
CMP r12, #3 * 4
BLT NotPrivileged
LDMDB r0, {r0-r2} ; Pull R10-R12 off of top of SVC stack
ADD r4, r14, #10 * 4 ; if there were at least 3 words on it
STMIA r4, {r0-r2}
TEQ pc, pc
MSREQ CPSR_cxs, r3
TEQNEP pc, r3
NOP
NotPrivileged
LDMFD r13!, {r0-r4, r12, r14, pc}
AbortFindHandler Keep
; We can only call an abort handler if we had a stack at the
......@@ -1493,19 +1493,26 @@ ErrorHandler Keep
; Since it would be nice to preserve as much as possible for the FP fault case
; we switch back to SWI mode to save the registers.
SWI EnterSVC
ADD r14, r0, #O_registerDump
LDR r14, [r0, #O_errorNumber]
TEQ r14, #Error_IllegalInstruction
TEQNE r14, #Error_PrefetchAbort
TEQNE r14, #Error_DataAbort
TEQNE r14, #Error_AddressException
[ SASTMhatbroken
STMIA r14!, {r0-r12}
STMIA r14, {r13,r14}^
NOP
SUB r14, r14, #13*4
ADDNE r14, r0, #O_registerDump
STMNEIA r14!, {r0-r12}
STMNEIA r14, {r13,r14}^
NOP
SUBNE r14, r14, #13*4
|
STMIA r14, {r0-r14}^
STMNEIA r14, {r0-r14}^
]
MOV r12, r0
ADD r0, r0, #O_errorNumber
BEQ AbortFindHandler
LDMDA r0, {r1, r2} ; r1 is error pc, r2 error number
MOV r14, #0
STR r14, [r12, #O_registerDump+16*4] ; zero PSR
......@@ -1582,13 +1589,20 @@ EndFastEventHandlers
EscapeHandler Keep
TSTS r11, #&40
MOVEQ pc, r14 ; ignore flag going away
BNE haveEscape
STMFD r13!, {r0}
MOV r0, #0
STRB r0, [r12, #O_hadEscape]
LDMFD r13!, {r0}
MOV pc, r14 ; ignore flag going away
haveEscape
; In Arthur, it is NEVER safe to call a handler now: we always have to
; wait for CallBack.
STMFD r13!, {r0}
MOV r0, #-1
STRB r0, [r12, #O_hadEscape]
LDRB r0, [r12, #O_eventCode]
STRB r0, [r12, #O_escapeSeen]
STR r0, [r12, #O_eventCode]
LDRB r11, [r12, #O_callbackInactive]
......@@ -1652,9 +1666,12 @@ Event_NoStackForHandler
MOV r1, #0
STRB r1, [v6, #O_hadEscape]
LDR v1, [v6, #O_eventCode]
TEQ r0, #0 ; if hadEscape = 0
CMPEQ v1, #-1 ; and it's an escape event
BEQ %FT02 ; then the escape's gone.
CMP r0, #0
BEQ %FT01
MOV r0, #&7e
MOV r0, #126 ; acknowledge escape
SWI Byte
MOV v1, #-1 ; escape overrides everything else
01
......@@ -1667,7 +1684,7 @@ Event_NoStackForHandler
CMP r12, #0
BGE CallEventHandlers
02
ADD r0, v6, #O_registerDump
B ReloadUserState
......@@ -2116,6 +2133,13 @@ ErrorExitV6Stacked
STRNE a2, [ip, #O_errorBuffer]
Return ,LinkNotStacked
|_kernel_peek_last_oserror|
LoadStaticBase ip, a1
LDR a1, [ip, #O_errorBuffer]
TEQ a1, #0
ADDNE a1, ip, #O_errorNumber
Return ,LinkNotStacked
|_kernel_system|
; Execute the string a1 as a command; if a2 is zero, as a subprogram,
; otherwise a replacement.
......@@ -2853,7 +2877,9 @@ StackOverflowFault Keep
;* Arithmetic *
;*-------------------------------------------------------------------*
|__rt_udiv|
|_kernel_udiv|
|x$udivide|
; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
; Destroys a3 and ip
......@@ -2913,6 +2939,7 @@ u_sh0 RSBS ip, a1, a2
; codegenerator will call udiv directly and use the result in a2
|_kernel_urem|
|x$uremainder|
FunctionEntry
BL |_kernel_udiv|
MOV a1, a2
......@@ -2936,7 +2963,9 @@ u_sh0 RSBS ip, a1, a2
Return ,LinkNotStacked
|__rt_sdiv|
|_kernel_sdiv|
|x$divide|
; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
; Quotient is truncated (rounded towards zero).
; Sign of remainder = sign of dividend.
......@@ -3001,6 +3030,7 @@ s_sh0 RSBS ip, a1, a2
; Signed remainder of a2 by a1: returns remainder in a1
|_kernel_srem|
|x$remainder|
FunctionEntry
BL |_kernel_sdiv|
MOV a1, a2
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment