From 350370aa3fee849c6f821bc69235d854a0ed2f26 Mon Sep 17 00:00:00 2001 From: Kevin Bracey <kbracey@gitlab.riscosopen.org> Date: Tue, 29 Jan 2002 16:03:36 +0000 Subject: [PATCH] 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' --- Doc/AbortNotes | 40 ++++++++ VersionASM | 15 +-- VersionNum | 22 +++-- c/armsys | 129 +++++++++++++++++++++++- c/error | 8 +- c/signal | 15 ++- clib/s/cl_body | 149 ++++++++++------------------ h/hostsys | 3 + kernel/s/k_body | 258 +++++++++++++++++++++++++++--------------------- 9 files changed, 401 insertions(+), 238 deletions(-) create mode 100644 Doc/AbortNotes diff --git a/Doc/AbortNotes b/Doc/AbortNotes new file mode 100644 index 0000000..8981a6d --- /dev/null +++ b/Doc/AbortNotes @@ -0,0 +1,40 @@ +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. + diff --git a/VersionASM b/VersionASM index 91da504..c28713d 100644 --- a/VersionASM +++ b/VersionASM @@ -1,5 +1,6 @@ ; ; 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 diff --git a/VersionNum b/VersionNum index 4894d1e..6989597 100644 --- a/VersionNum +++ b/VersionNum @@ -1,22 +1,24 @@ -/* (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" diff --git a/c/armsys b/c/armsys index 4b270b6..21723b2 100644 --- a/c/armsys +++ b/c/armsys @@ -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) */ } } diff --git a/c/error b/c/error index d6fdcfc..00c3eac 100644 --- a/c/error +++ b/c/error @@ -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(); } diff --git a/c/signal b/c/signal index 1186109..fb4417e 100644 --- a/c/signal +++ b/c/signal @@ -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 diff --git a/clib/s/cl_body b/clib/s/cl_body index 5a0f957..e4272d6 100644 --- a/clib/s/cl_body +++ b/clib/s/cl_body @@ -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| diff --git a/h/hostsys b/h/hostsys index a51bf5b..d0cf537 100644 --- a/h/hostsys +++ b/h/hostsys @@ -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); diff --git a/kernel/s/k_body b/kernel/s/k_body index 8e2f5c1..87badcd 100644 --- a/kernel/s/k_body +++ b/kernel/s/k_body @@ -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 -- GitLab