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. ; This file is automatically maintained by srccommit, do not edit manually.
; Last processed by srccommit version: 1.62.
; ;
GBLS Module_MajorVersion GBLS Module_MajorVersion
GBLA Module_Version GBLA Module_Version
...@@ -11,14 +12,14 @@ ...@@ -11,14 +12,14 @@
GBLS Module_HelpVersion GBLS Module_HelpVersion
GBLS Module_ComponentName GBLS Module_ComponentName
GBLS Module_ComponentPath GBLS Module_ComponentPath
Module_MajorVersion SETS "5.34" Module_MajorVersion SETS "5.35"
Module_Version SETA 534 Module_Version SETA 535
Module_MinorVersion SETS "" Module_MinorVersion SETS ""
Module_Date SETS "23 Aug 2001" Module_Date SETS "29 Jan 2002"
Module_ApplicationDate2 SETS "23-Aug-01" Module_ApplicationDate2 SETS "29-Jan-02"
Module_ApplicationDate4 SETS "23-Aug-2001" Module_ApplicationDate4 SETS "29-Jan-2002"
Module_ComponentName SETS "RISC_OSLib" Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "RiscOS/Sources/Lib/RISC_OSLib" Module_ComponentPath SETS "RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.34" Module_FullVersion SETS "5.35"
Module_HelpVersion SETS "5.34 (23 Aug 2001)" Module_HelpVersion SETS "5.35 (29 Jan 2002)"
END END
/* (5.34) /* (5.35)
* *
* This file is automatically maintained by srccommit, do not edit manually. * 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_MinorVersion_CMHG
#define Module_Date_CMHG 23 Aug 2001 #define Module_Date_CMHG 29 Jan 2002
#define Module_MajorVersion "5.34" #define Module_MajorVersion "5.35"
#define Module_Version 534 #define Module_Version 535
#define Module_MinorVersion "" #define Module_MinorVersion ""
#define Module_Date "23 Aug 2001" #define Module_Date "29 Jan 2002"
#define Module_ApplicationDate2 "23-Aug-01" #define Module_ApplicationDate2 "29-Jan-02"
#define Module_ApplicationDate4 "23-Aug-2001" #define Module_ApplicationDate4 "29-Jan-2002"
#define Module_ComponentName "RISC_OSLib" #define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "RiscOS/Sources/Lib/RISC_OSLib" #define Module_ComponentPath "RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.34" #define Module_FullVersion "5.35"
#define Module_HelpVersion "5.34 (23 Aug 2001)" #define Module_HelpVersion "5.35 (29 Jan 2002)"
#define Module_LibraryVersionInfo "5:35"
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <string.h> /* for strlen() */ #include <string.h> /* for strlen() */
#include <time.h> /* for clock */ #include <time.h> /* for clock */
#include <errno.h> #include <errno.h>
#include <stdbool.h>
/* IMPORTS */ /* IMPORTS */
extern int main(int argc, char **argv); /* the point of it all */ extern int main(int argc, char **argv); /* the point of it all */
...@@ -40,11 +41,14 @@ extern FILEHANDLE __dup(int new, int old); ...@@ -40,11 +41,14 @@ extern FILEHANDLE __dup(int new, int old);
extern void _ctype_init(void); extern void _ctype_init(void);
extern int _fprintf_lf(FILE *fp, const char *fmt, ...); extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
extern int _sprintf_lf(char *buff, const char *fmt, ...); extern int _sprintf_lf(char *buff, const char *fmt, ...);
extern _kernel_oserror *_kernel_peek_last_oserror(void);
/* HIDDEN EXPORTS */ /* HIDDEN EXPORTS */
void _main(char *s, int (*main)(int, char **)); void _main(char *s, int (*main)(int, char **));
void _backtrace(int why, int *address, _kernel_unwindblock *uwb); void _backtrace(int why, int *address, _kernel_unwindblock *uwb);
const char *_clib_version(void); const char *_clib_version(void);
int _sys_msg_1(const char *s, const char *but);
int _desktop_task(void);
#define str(x) #x #define str(x) #x
#define xstr(x) str(x) #define xstr(x) str(x)
...@@ -149,9 +153,118 @@ time_t time(time_t *timer) ...@@ -149,9 +153,118 @@ time_t time(time_t *timer)
#define istty(fh) ((fh) == TTYHANDLE) #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; static int _error_recursion;
void _sys_msg(const char *s) int _sys_msg_1(const char *s, const char *but)
{ /* write out s carefully for intimate system use. */ {
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) if ((stderr->__flag & _IOWRITE) && !_error_recursion)
{ {
_error_recursion = 1; _error_recursion = 1;
...@@ -166,6 +279,13 @@ void _sys_msg(const char *s) ...@@ -166,6 +279,13 @@ void _sys_msg(const char *s)
_ttywrite((unsigned char *)s, strlen(s), 0); _ttywrite((unsigned char *)s, strlen(s), 0);
_ttywrite((unsigned char *)"\n", 1, 0); _ttywrite((unsigned char *)"\n", 1, 0);
} }
return 0;
}
void _sys_msg(const char *s)
{
_sys_msg_1(s, NULL);
} }
#define LF '\n' #define LF '\n'
...@@ -195,9 +315,8 @@ FILEHANDLE _sys_open(const char *filename, int openmode) ...@@ -195,9 +315,8 @@ FILEHANDLE _sys_open(const char *filename, int openmode)
(openmode & OPEN_W) || (openmode & OPEN_W) ||
(openmode & ~OPEN_B) == OPEN_A) /* or mode = w, w+, or a */ (openmode & ~OPEN_B) == OPEN_A) /* or mode = w, w+, or a */
{ if (_kernel_osfile(9, name, &fb) == _kernel_ERROR) { if (_kernel_osfile(9, name, &fb) == _kernel_ERROR)
{ if (_kernel_last_oserror()->errnum == 0x108c9) { if (_kernel_peek_last_oserror()->errnum == 0x108c9)
{ (void)_kernel_osfile(9, name, &fb); /* to restore the error */ { errno = -1;
errno = -1;
return NONHANDLE; /* (Protected disc) */ return NONHANDLE; /* (Protected disc) */
} }
} }
......
...@@ -49,9 +49,11 @@ void _sysdie(const char *s) ...@@ -49,9 +49,11 @@ void _sysdie(const char *s)
/* from <assert.h> */ /* from <assert.h> */
void __assert(char *expr, char *file, int line) void __assert(char *expr, char *file, int line)
{ {
_fprintf_lf(stderr, const char *s;
_kernel_getmessage("*** assertion failed: %s, file %s, line %d", "C34"), s = _kernel_getmessage("*** assertion failed: %s, file %s, line %d", "C34");
expr, file, line);
if (!_sys__assert(s, expr, file, line))
_fprintf_lf(stderr, s, expr, file, line);
fputc('\n', stderr); fputc('\n', stderr);
abort(); abort();
} }
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
extern int _fprintf_lf(FILE *fp, const char *fmt, ...); extern int _fprintf_lf(FILE *fp, const char *fmt, ...);
extern int _sprintf_lf(char *buff, 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>) */ #define SIGLAST 11 /* one after highest signal number (see <signal.h>) */
static void (*_signalvector[SIGLAST+1])(int); static void (*_signalvector[SIGLAST+1])(int);
...@@ -47,6 +50,14 @@ extern void __ignore_signal_handler(int sig) ...@@ -47,6 +50,14 @@ extern void __ignore_signal_handler(int sig)
static void _real_default_signal_handler(int sig) static void _real_default_signal_handler(int sig)
{ {
char *s, v[128]; 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) switch (sig)
{ {
...@@ -56,10 +67,6 @@ case SIGABRT: ...@@ -56,10 +67,6 @@ case SIGABRT:
#endif #endif
s = _kernel_getmessage(s, "C39"); s = _kernel_getmessage(s, "C39");
break; break;
case SIGFPE:
case SIGOSERROR:
s = &(_kernel_last_oserror()->errmess[0]);
break;
case SIGILL: case SIGILL:
#ifdef DEFAULT_TEXT #ifdef DEFAULT_TEXT
#ifdef __arm #ifdef __arm
......
...@@ -68,6 +68,7 @@ $Label RFS r1 ...@@ -68,6 +68,7 @@ $Label RFS r1
IMPORT |_signal_real_handler| IMPORT |_signal_real_handler|
IMPORT |_armsys_lib_init| IMPORT |_armsys_lib_init|
IMPORT |_sys_msg| IMPORT |_sys_msg|
IMPORT |_sys_msg_1|
IMPORT |_kernel_fpavailable| IMPORT |_kernel_fpavailable|
IMPORT |_kernel_exittraphandler| IMPORT |_kernel_exittraphandler|
...@@ -103,11 +104,7 @@ $Label RFS r1 ...@@ -103,11 +104,7 @@ $Label RFS r1
EXPORT |x$stack_overflow| EXPORT |x$stack_overflow|
EXPORT |x$stack_overflow_1| EXPORT |x$stack_overflow_1|
EXPORT |_raise_stacked_interrupts| EXPORT |_raise_stacked_interrupts|
EXPORT |x$udivide|
EXPORT |x$uremainder|
EXPORT |x$divide|
EXPORT |x$divtest| EXPORT |x$divtest|
EXPORT |x$remainder|
EXPORT |x$multiply| EXPORT |x$multiply|
EXPORT |_rd1chk| EXPORT |_rd1chk|
EXPORT |_rd2chk| EXPORT |_rd2chk|
...@@ -137,14 +134,13 @@ $Label RFS r1 ...@@ -137,14 +134,13 @@ $Label RFS r1
EXPORT |_count| EXPORT |_count|
EXPORT |_count1| EXPORT |_count1|
EXPORT |_default_sigstak_handler| EXPORT |_default_sigstak_handler|
EXPORT |_SignalNumber|
EXPORT |_ldfp| EXPORT |_ldfp|
EXPORT |_stfp| EXPORT |_stfp|
EXPORT |__rt_stkovf_split_small| EXPORT |__rt_stkovf_split_small|
EXPORT |__rt_stkovf_split_big| EXPORT |__rt_stkovf_split_big|
EXPORT |__rt_udiv|
EXPORT |__rt_sdiv|
EXPORT |__rt_divtest| EXPORT |__rt_divtest|
EXPORT |__rt_rd1chk| EXPORT |__rt_rd1chk|
EXPORT |__rt_rd2chk| EXPORT |__rt_rd2chk|
...@@ -242,6 +238,7 @@ UnhandledEventHandler Keep ...@@ -242,6 +238,7 @@ UnhandledEventHandler Keep
02 MOV a1, #1 ; we wish to handle it, but not just yet 02 MOV a1, #1 ; we wish to handle it, but not just yet
Return ,LinkNotStacked Return ,LinkNotStacked
|_SignalNumber|
SignalNumber Keep SignalNumber Keep
; nb required not to disturb a4 ; nb required not to disturb a4
MOV a2, #SIGOSERROR MOV a2, #SIGOSERROR
...@@ -316,39 +313,21 @@ Raised ...@@ -316,39 +313,21 @@ Raised
|x$multiply| |x$multiply|
; a1 := a2 * a1. ; a1 := a2 * a1.
; sets a2 to 0 and a3 to a copy of the product. ; a2, a3 can be scrambled.
MOV a3, #0 MUL a1, a2, a1
m0loop MOVS a2, a2, LSR #1
ADDCS a3, a3, a1
ADD a1, a1, a1
BNE m0loop
MOV a1, a3
Return ,LinkNotStacked Return ,LinkNotStacked
|x$remainder|
B |_kernel_srem|
IMPORT |_kernel_copyerror| IMPORT |_kernel_copyerror|
IMPORT |_kernel_fault| IMPORT |_kernel_fault|
|__rt_divtest| |__rt_divtest|
|x$divtest| |x$divtest|
; test for division by zero (used when division is voided) ; test for division by zero (used when division is voided)
CMPS a1, #0 TEQS a1, #0
Return ,LinkNotStacked, NE Return ,LinkNotStacked, NE
STMFD sp!, {r0} STMFD sp!, {r0}
ADR r0, E_DivideByZero ADR r0, E_DivideByZero
B |_kernel_fault| B |_kernel_fault|
|__rt_sdiv|
|x$divide|
B |_kernel_sdiv|
|__rt_udiv|
|x$udivide|
B |_kernel_udiv|
|x$uremainder|
B |_kernel_urem|
|__rt_rd1chk| |__rt_rd1chk|
|_rd1chk| |_rd1chk|
...@@ -492,10 +471,6 @@ readfail ...@@ -492,10 +471,6 @@ readfail
Return Return
mesg DCB "mesg" mesg DCB "mesg"
wimp_title
DCB "WindowManager", 0
utility_title
DCB "UtilityModule", 0
[ :DEF:DEFAULT_TEXT [ :DEF:DEFAULT_TEXT
postmortem_title postmortem_title
DCB "Postmortem", 0 DCB "Postmortem", 0
...@@ -504,70 +479,13 @@ postmortem_tag ...@@ -504,70 +479,13 @@ postmortem_tag
DCB "C65", 0 DCB "C65", 0
ALIGN ALIGN
n_module_lookup EQU 18 IMPORT |_desktop_task|
wimp_preinitflag EQU &80000000
zp_wimpdomain EQU &ff8
IMPORT |_kernel_unwind| IMPORT |_kernel_unwind|
IMPORT exit
|_postmortem| |_postmortem|
; Prepare window manager for output ; Prepare window manager for output
; First check this is a wimp task ; First check this is a wimp task
STMFD sp!, {r0-r5, r14} 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 [ :DEF:DEFAULT_TEXT
ADR r0, postmortem_title ADR r0, postmortem_title
ADR r1, postmortem_tag ADR r1, postmortem_tag
...@@ -575,13 +493,32 @@ postmortem4 ...@@ -575,13 +493,32 @@ postmortem4
ADR r0, postmortem_tag ADR r0, postmortem_tag
] ]
BL |_kernel_getmessage| BL |_kernel_getmessage|
SWI XWimp_CommandWindow MOV r5, r0
postmortem0 postmortem0
LDMFD sp!, {r0-r5} LDMFD sp, {a1-a2}
LDR a3, mesg LDR a3, mesg ; if magic arg2 != "mesg"
CMP a2, a3 CMP a2, a3 ; then go straight onto postmortem
BLEQ |_sys_msg| ; BL<cond> 32-bit OK 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 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| BL |_kernel_fpavailable|
LDMFD sp!, {r14} LDMFD sp!, {r14}
CMP a1, #0 CMP a1, #0
...@@ -645,6 +582,28 @@ postmortem_nofp ...@@ -645,6 +582,28 @@ postmortem_nofp
ADD sp, sp, #22*4 ADD sp, sp, #22*4
MOV a3, sp MOV a3, sp
B |_backtrace| 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| |__rt_stkovf_split_small|
|x$stack_overflow| |x$stack_overflow|
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define __hostsys_h #define __hostsys_h
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#undef MACHINE #undef MACHINE
#ifdef __arm #ifdef __arm
...@@ -99,6 +100,8 @@ extern void *_sys_alloc(size_t n); ...@@ -99,6 +100,8 @@ extern void *_sys_alloc(size_t n);
extern void _init_user_alloc(void); extern void _init_user_alloc(void);
extern void _terminate_user_alloc(void); extern void _terminate_user_alloc(void);
extern void _sys_msg(const char *); 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 _exit(int n);
extern void _terminate_getenv(void); extern void _terminate_getenv(void);
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
EXPORT |_kernel_osargs| EXPORT |_kernel_osargs|
EXPORT |_kernel_oscli| EXPORT |_kernel_oscli|
EXPORT |_kernel_last_oserror| EXPORT |_kernel_last_oserror|
EXPORT |_kernel_peek_last_oserror|
EXPORT |_kernel_system| EXPORT |_kernel_system|
EXPORT |_kernel_getenv| EXPORT |_kernel_getenv|
EXPORT |_kernel_setenv| EXPORT |_kernel_setenv|
...@@ -88,9 +89,16 @@ ...@@ -88,9 +89,16 @@
EXPORT |_kernel_call_client| EXPORT |_kernel_call_client|
EXPORT |_kernel_raise_error| EXPORT |_kernel_raise_error|
EXPORT |__rt_sdiv|
EXPORT |__rt_udiv|
EXPORT |__rt_udiv10| EXPORT |__rt_udiv10|
EXPORT |__rt_sdiv10| EXPORT |__rt_sdiv10|
EXPORT |x$divide|
EXPORT |x$udivide|
EXPORT |x$remainder|
EXPORT |x$uremainder|
EXPORT |__counter| EXPORT |__counter|
PSRBits * &FC000003 PSRBits * &FC000003
...@@ -719,7 +727,7 @@ ABEXString ...@@ -719,7 +727,7 @@ ABEXString
; tacked on the end. ; tacked on the end.
IIHandlerInDataInitValue IIHandlerInDataInitValue
STMFD r13!, {r0, r12} STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_IIHandlerInData+12 SUB r12, pc, #O_IIHandlerInData+12
; Now the bits of the abort handlers which get executed from the code. ; Now the bits of the abort handlers which get executed from the code.
...@@ -728,81 +736,88 @@ IIHandlerInDataInitValue ...@@ -728,81 +736,88 @@ IIHandlerInDataInitValue
IIHandler Keep IIHandler Keep
SUB r14, r14, #4 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 B Aborted
PAHandlerInDataInitValue PAHandlerInDataInitValue
STMFD r13!, {r0, r12} STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_PAHandlerInData+12 SUB r12, pc, #O_PAHandlerInData+12
PAHandler Keep PAHandler Keep
SUB r14, r14, #4 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 B Aborted
DAHandlerInDataInitValue DAHandlerInDataInitValue
STMFD r13!, {r0, r12} STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_DAHandlerInData+12 SUB r12, pc, #O_DAHandlerInData+12
DAHandler Keep DAHandler Keep
SUB r14, r14, #8 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 B Aborted2
AEHandlerInDataInitValue AEHandlerInDataInitValue
STMFD r13!, {r0, r12} STMFD r13!, {r0-r4, r12, r14, pc}
SUB r12, pc, #O_AEHandlerInData+12 SUB r12, pc, #O_AEHandlerInData+12
AEHandler Keep AEHandler Keep
SUB r14, r14, #8 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 ; B Aborted2
Aborted2 Keep Aborted2 Keep
; Abort which may be in the FP emulator, and if so should be reported ; Abort which may be in the FP emulator, and if so should be reported
; as occurring at the instruction being emulated. ; as occurring at the instruction being emulated.
; Try the FPEmulator_Abort SWI ; Try the FPEmulator_Abort SWI
STMFD sp!, {r0-r2, r14}
LDR r2, [sp, #24]
[ {CONFIG}=26 [ {CONFIG}=26
BIC r14, r14, #PSRBits BIC r2, r2, #PSRBits
| |
MOV r0, #0 TEQ pc, pc
MRS r0, CPSR BICNE r2, r2, #PSRBits
TST r0, #2_11100
BICEQ r14, r14, #PSRBits
] ]
MOV r0, #-2 ; current context MOV r0, #-2 ; current context
LDR r1, [sp, #20] ; original r12 LDR r1, [sp, #20] ; original r12
ADD r2, r14, #8 ; original r14 ADD r2, r2, #8 ; original r14
SWI XFPEmulator_Abort SWI XFPEmulator_Abort
BVS NoFPEAbortSWI BVS NoFPEAbortSWI
TEQ r0, #0 TEQ r0, #0
LDMEQFD sp!, {r0-r2, r14} LDMEQFD sp, {r0-r2}
BEQ Aborted ; not in FPEmulator BEQ Aborted ; not in FPEmulator
STR r0, [sp, #20] ; update r12 in stack
LDMFD sp!, {r0-r2, r14}
B FPEFault B FPEFault
NoFPEAbortSWI NoFPEAbortSWI
; If in user mode, can't be in FPE ; If in user mode, can't be in FPE
[ {CONFIG}=26 [ {CONFIG}=26
LDR r1, [sp, #12] LDR r1, [sp, #24]
TST r1, #PSRPrivileged TST r1, #PSRPrivileged
| |
MOV r2, #0 TEQ pc, pc
MRS r2, CPSR LDRNE r1, [sp, #24]
TST r2, #2_11100 ANDNE r1, r1, #PSRMode ; obtain aborter's mode from R14
LDREQ r1, [sp, #12] MRSEQ r1, SPSR ; obtain aborter's mode from SPSR
ANDEQ r1, r1, #3 ; obtain aborter's mode from R14
MRSNE r1, SPSR ; obtain aborter's mode from SPSR
TST r1, #PSR32Privileged TST r1, #PSR32Privileged
] ]
LDMEQFD sp!, {r0-r2, r14} LDMEQFD sp, {r0-r4}
BEQ Aborted BEQ Aborted
; Otherwise, find out where the FPE module is ; Otherwise, find out where the FPE module is
[ {CONFIG} <> 26 [ {CONFIG} <> 26
TST r2, #2_11100 TST r2, #2_11100
] ]
LDMFD sp!, {r0-r2, r14} STMFD sp!, {r0 - r6}
STMFD sp!, {r0 - r6, r14}
[ {CONFIG} = 26 [ {CONFIG} = 26
BIC r6, r14, #PSRBits BIC r6, r14, #PSRBits
| |
...@@ -812,65 +827,60 @@ NoFPEAbortSWI ...@@ -812,65 +827,60 @@ NoFPEAbortSWI
MOV r0, #18 MOV r0, #18
ADR r1, FPEName ADR r1, FPEName
SWI Module SWI Module
LDMVSFD sp!, {r0 - r6, r14} LDMVSFD sp!, {r0 - r6}
BVS Aborted BVS Aborted
; (r3 = code base of FPE; word before is length of FPE code) ; (r3 = code base of FPE; word before is length of FPE code)
CMP r6, r3 CMP r6, r3
LDRGE r4, [r3, #-4] LDRGE r4, [r3, #-4]
ADDGE r3, r3, r4 ADDGE r3, r3, r4
CMPGE r3, r6 CMPGE r3, r6
LDMFD sp!, {r0 - r6, r14} LDMFD sp!, {r0 - r6}
BLT Aborted BLT Aborted
; It was a storage fault in the FP emulator. ; 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 ; will point to a full register save. The format differs slightly
; depending on whether the FPEmulator is 32-bit or not. If we're ; 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 ; 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. ; to see if the saved r12 is in the UND stack.
FPEFault 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 ADD r14, r12, #O_registerDump
LDMIA r1!, {r2-r9} ; copy R0-R15 LDMIA r0!, {r1-r4} ; copy R0-R15
STMIA r14!, {r2-r9} STMIA r14!, {r1-r4}
LDMIA r1!, {r2-r9} LDMIA r0!, {r1-r4}
SUB r9, r9, #4 STMIA r14!, {r1-r4}
STMIA r14!, {r2-r9} 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 [ {CONFIG}<>26
MOV r2, #0 TEQ pc, pc
MRS r2, CPSR BEQ FPEFault_32on32
TST r2, #2_11100
BNE FPEFault_32on32
] ]
LDR r3, [r12, #O_undStack] LDR r3, [r12, #O_undStack]
MOV r2, r1, LSR #20 ; we're on a 26-bit system 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? TEQ r2, r3, LSR #20 ; is the stack frame in the UND stack?
BEQ FPEFault_32on26 BEQ FPEFault_32on26
FPEFault_26on26 FPEFault_26on26
MOV sp, r1 ; pull the SVC stack up B FPEFault_Continue
B AbortFindHandler
FPEFault_32on26 FPEFault_32on26
LDR r2, [r1, #-72] ; get the SPSR LDR r2, [r0, #-72] ; get the SPSR
AND r2, r2, #PSRBits AND r2, r2, #PSRBits
BIC r9, r9, #PSRBits BIC r4, r4, #PSRBits
ORR r9, r9, r2 ORR r4, r4, r2
STR r9, [r14, #-4] ; merge it with pc in register dump STR r4, [r14, #-4] ; merge it with pc in register dump
B FPEFault_32 [ {CONFIG}<>26
B FPEFault_Continue
FPEFault_32on32 FPEFault_32on32
LDR r2, [r1, #-72] ; get the SPSR LDR r2, [r1, #-72] ; get the SPSR
STR r2, [r14] ; store it in the register dump STR r2, [r14] ; store it in the register dump
]
FPEFault_32 FPEFault_Continue
MRS r2, CPSR LDMFD r13!, {r0-r4, r12, r14, pc}
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
ErrorBlock PrefetchAbort, "Prefetch Abort", C60 ErrorBlock PrefetchAbort, "Prefetch Abort", C60
ErrorBlock DataAbort, "Data Abort", C61 ErrorBlock DataAbort, "Data Abort", C61
...@@ -880,59 +890,49 @@ FPEName = "FPEmulator",0 ...@@ -880,59 +890,49 @@ FPEName = "FPEmulator",0
ALIGN ALIGN
Aborted Keep 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 ADD r14, r12, #O_registerDump
[ SASTMhatbroken [ SASTMhatbroken
STMIB r14!, {r1-r12} STMIA r14!, {r0-r12}
STMIB r14, {r13,r14}^ STMIA r14, {r13,r14}^
NOP NOP
SUB r14, r14, #12*4 SUB r14, r14, #13*4
| |
STMIB r14, {r1-r14}^ STMIA r14, {r0-r14}^
NOP
] ]
LDMFD r13!, {r1, r2, r3} ; abort PC, R0, R12 LDR r0, [r13, #20]
STR r0, [r14, #r12*4]
MOV r6, r14 ; switch it to a non-banked register
MOV r4, #0 MOV r3, pc
MRS r4, CPSR AND r3, r3, #PSRBits
TST r4, #2_11100 MRS r3, CPSR
ANDEQ r5, r1, #3 ; obtain aborter's mode from R14 TST r3, #2_11100
MRSNE r5, SPSR ; obtain aborter's mode from SPSR LDREQ r0, [sp, #24]
STRNE r5, [r14, #16*4] ; store aborter's SPSR if in 32-bit mode ANDEQ r0, r0, #PSRMode ; obtain aborter's mode from R14
BICNE r4, r4, #PSR32Mode MRSNE r0, SPSR ; obtain aborter's mode from SPSR
ORRNE r4, r4, #PSR32SVCMode STRNE r0, [r14, #16*4] ; store aborter's SPSR if in 32-bit mode
MSRNE CPSR_c, r4 ; switch to SVC32 (already in SVC26 if 26bit) TST r0, #PSR32Privileged
TST r5, #PSR32Privileged BEQ NotPrivileged
LDRNE r1, [r6, #lr*4] ; if aborted in a privileged mode, save LDR r0, [r14, #r14*4] ; if abort in a privileged mode, save
STR r1, [r6, #pc*4] ; PC as user R14 STR r0, [r14, #pc*4] ; PC as user R14
STR r2, [r6, #r0*4] LDR r0, [r12, #O_svcStack] ; switch to SVC mode and look at R13_svc
STREQ r3, [r6, #r12*4] TEQ pc, pc
BEQ AbortFlattenStacks MSREQ CPSR_c, #PSR32SVCMode
LDR r4, [r12, #O_svcStack] TEQNEP pc, #PSRSVCMode
SUB r1, r4, sp NOP
CMP r1, #3 * 4 SUB r12, r0, sp
BCC AbortFlattenStacks CMP r12, #3 * 4
LDMEA r4, {r1, r2, r3} BLT NotPrivileged
ADD r4, r6, #10 * 4 LDMDB r0, {r0-r2} ; Pull R10-R12 off of top of SVC stack
STMIA r4, {r1, r2, r3} ADD r4, r14, #10 * 4 ; if there were at least 3 words on it
STMIA r4, {r0-r2}
; should really fall through to error handler and let the OS clean up, TEQ pc, pc
; but this is a lot better than it was! MSREQ CPSR_cxs, r3
AbortFlattenStacks TEQNEP pc, r3
MRS r4, CPSR ; MRS and MSR here will be NOPs on NOP
ORR r1, r4, #PSR32UNDMode ; ARM2/3, so we'll end up setting NotPrivileged
MSR CPSR_c, r1 ; R13_svc twice; just make sure LDMFD r13!, {r0-r4, r12, r14, pc}
LDR sp, [r12, #O_undStack] ; we set the real value last.
MSR CPSR_c, r4
LDR sp, [r12, #O_svcStack]
AbortFindHandler Keep AbortFindHandler Keep
; We can only call an abort handler if we had a stack at the ; We can only call an abort handler if we had a stack at the
...@@ -1493,19 +1493,26 @@ ErrorHandler Keep ...@@ -1493,19 +1493,26 @@ ErrorHandler Keep
; Since it would be nice to preserve as much as possible for the FP fault case ; 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. ; we switch back to SWI mode to save the registers.
SWI EnterSVC 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 [ SASTMhatbroken
STMIA r14!, {r0-r12} ADDNE r14, r0, #O_registerDump
STMIA r14, {r13,r14}^ STMNEIA r14!, {r0-r12}
STMNEIA r14, {r13,r14}^
NOP NOP
SUB r14, r14, #13*4 SUBNE r14, r14, #13*4
| |
STMIA r14, {r0-r14}^ STMNEIA r14, {r0-r14}^
] ]
MOV r12, r0 MOV r12, r0
ADD r0, r0, #O_errorNumber ADD r0, r0, #O_errorNumber
BEQ AbortFindHandler
LDMDA r0, {r1, r2} ; r1 is error pc, r2 error number LDMDA r0, {r1, r2} ; r1 is error pc, r2 error number
MOV r14, #0 MOV r14, #0
STR r14, [r12, #O_registerDump+16*4] ; zero PSR STR r14, [r12, #O_registerDump+16*4] ; zero PSR
...@@ -1582,13 +1589,20 @@ EndFastEventHandlers ...@@ -1582,13 +1589,20 @@ EndFastEventHandlers
EscapeHandler Keep EscapeHandler Keep
TSTS r11, #&40 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 ; In Arthur, it is NEVER safe to call a handler now: we always have to
; wait for CallBack. ; wait for CallBack.
STMFD r13!, {r0} STMFD r13!, {r0}
MOV r0, #-1 MOV r0, #-1
STRB r0, [r12, #O_hadEscape] STRB r0, [r12, #O_hadEscape]
LDRB r0, [r12, #O_eventCode]
STRB r0, [r12, #O_escapeSeen] STRB r0, [r12, #O_escapeSeen]
STR r0, [r12, #O_eventCode] STR r0, [r12, #O_eventCode]
LDRB r11, [r12, #O_callbackInactive] LDRB r11, [r12, #O_callbackInactive]
...@@ -1652,9 +1666,12 @@ Event_NoStackForHandler ...@@ -1652,9 +1666,12 @@ Event_NoStackForHandler
MOV r1, #0 MOV r1, #0
STRB r1, [v6, #O_hadEscape] STRB r1, [v6, #O_hadEscape]
LDR v1, [v6, #O_eventCode] 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 CMP r0, #0
BEQ %FT01 BEQ %FT01
MOV r0, #&7e MOV r0, #126 ; acknowledge escape
SWI Byte SWI Byte
MOV v1, #-1 ; escape overrides everything else MOV v1, #-1 ; escape overrides everything else
01 01
...@@ -1667,7 +1684,7 @@ Event_NoStackForHandler ...@@ -1667,7 +1684,7 @@ Event_NoStackForHandler
CMP r12, #0 CMP r12, #0
BGE CallEventHandlers BGE CallEventHandlers
02
ADD r0, v6, #O_registerDump ADD r0, v6, #O_registerDump
B ReloadUserState B ReloadUserState
...@@ -2116,6 +2133,13 @@ ErrorExitV6Stacked ...@@ -2116,6 +2133,13 @@ ErrorExitV6Stacked
STRNE a2, [ip, #O_errorBuffer] STRNE a2, [ip, #O_errorBuffer]
Return ,LinkNotStacked 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| |_kernel_system|
; Execute the string a1 as a command; if a2 is zero, as a subprogram, ; Execute the string a1 as a command; if a2 is zero, as a subprogram,
; otherwise a replacement. ; otherwise a replacement.
...@@ -2853,7 +2877,9 @@ StackOverflowFault Keep ...@@ -2853,7 +2877,9 @@ StackOverflowFault Keep
;* Arithmetic * ;* Arithmetic *
;*-------------------------------------------------------------------* ;*-------------------------------------------------------------------*
|__rt_udiv|
|_kernel_udiv| |_kernel_udiv|
|x$udivide|
; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2 ; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
; Destroys a3 and ip ; Destroys a3 and ip
...@@ -2913,6 +2939,7 @@ u_sh0 RSBS ip, a1, a2 ...@@ -2913,6 +2939,7 @@ u_sh0 RSBS ip, a1, a2
; codegenerator will call udiv directly and use the result in a2 ; codegenerator will call udiv directly and use the result in a2
|_kernel_urem| |_kernel_urem|
|x$uremainder|
FunctionEntry FunctionEntry
BL |_kernel_udiv| BL |_kernel_udiv|
MOV a1, a2 MOV a1, a2
...@@ -2936,7 +2963,9 @@ u_sh0 RSBS ip, a1, a2 ...@@ -2936,7 +2963,9 @@ u_sh0 RSBS ip, a1, a2
Return ,LinkNotStacked Return ,LinkNotStacked
|__rt_sdiv|
|_kernel_sdiv| |_kernel_sdiv|
|x$divide|
; Signed divide of a2 by a1: returns quotient in a1, remainder in a2 ; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
; Quotient is truncated (rounded towards zero). ; Quotient is truncated (rounded towards zero).
; Sign of remainder = sign of dividend. ; Sign of remainder = sign of dividend.
...@@ -3001,6 +3030,7 @@ s_sh0 RSBS ip, a1, a2 ...@@ -3001,6 +3030,7 @@ s_sh0 RSBS ip, a1, a2
; Signed remainder of a2 by a1: returns remainder in a1 ; Signed remainder of a2 by a1: returns remainder in a1
|_kernel_srem| |_kernel_srem|
|x$remainder|
FunctionEntry FunctionEntry
BL |_kernel_sdiv| BL |_kernel_sdiv|
MOV a1, a2 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