From 4ddb0942741dd826d553653b3addd78e101dd6d5 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Thu, 26 May 2022 16:59:54 +0100
Subject: [PATCH] Add variants of _swi and _swix that take a va_list

These are typically useful for wrapper functions that want to do something
before and/or after a SWI call, and which therefore need to pass a pointer
to their own variadic arguments into the guts of _swi or _swix.

The pairs of functions _swi and _vswi, and _swix and _vswix, are almost
identical, differing only in argument marshalling.

There being only two additional entries, I didn't think it was worth
introducing a whole new library chunk. Instead, I've tacked them onto the
end of chunk 2 (the basic clib functions).

Note that this means that any applications that use these new entries will
need to take responsibility for RMEnsuring this version of the
SharedCLibrary module and softloading a newer one if necessary.
---
 clib/s/cl_entries |  2 ++
 h/swisheader      | 17 +++++++++++++++--
 kernel/s/swiv     | 29 +++++++++++++++++++++++------
 3 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/clib/s/cl_entries b/clib/s/cl_entries
index 170dd4a..dafc55d 100644
--- a/clib/s/cl_entries
+++ b/clib/s/cl_entries
@@ -213,6 +213,8 @@
 
         Entry   _swi, imported, , unveneered
         Entry   _swix, imported, , unveneered
+        Entry   _vswi, imported, , unveneered
+        Entry   _vswix, imported, , unveneered
 
 ; __va_illegal_arg 0
         END
diff --git a/h/swisheader b/h/swisheader
index 39dd223..d8e08be 100644
--- a/h/swisheader
+++ b/h/swisheader
@@ -34,12 +34,18 @@ extern "C"
 {
 #endif
 
+typedef char *__va_list[1];       /* keep in step with <stdarg.h> */
+
 #pragma -v4
 extern int _swi (int swi_no, unsigned int, ...);
 
 extern _kernel_oserror *_swix (int swi_no, unsigned int, ...);
 #pragma -v0
 
+extern int _vswi (int swi_no, unsigned int, __va_list);
+
+extern _kernel_oserror *_vswix (int swi_no, unsigned int, __va_list);
+
 #ifdef __cplusplus
 }
 #endif
@@ -61,9 +67,11 @@ extern _kernel_oserror *_swix (int swi_no, unsigned int, ...);
  * These functions provide a generic method of calling RISC OS SWIs from C or
  * C++.
  *
- * Two functions are provided:
+ * Four functions are provided:
  *     _swi for calling SWIs without setting the X bit
- *     _swix which sets the X bit before calling the SWI.
+ *     _swix which sets the X bit before calling the SWI
+ *     _vswi, like _swi but using a va_list instead of variadic arguments
+ *     _vswix, like _swix but using a va_list instead of variadic arguments.
  *
  * swi_no is the number of the SWI to be called. This should never have the
  * X bit set.
@@ -142,5 +150,10 @@ extern _kernel_oserror *_swix (int swi_no, unsigned int, ...);
  *               &workspace_end, &next);
  *
  *     e = _swix(Wimp_SetExtent, _IN(0)|_BLOCK(1), w, minx, miny, maxx, maxy);
+ *
+ *     va_list ap;
+ *     va_start(ap, flags);
+ *     e = _vswix(swi_no, flags, ap);
+ *     va_end(ap);
  */
 
diff --git a/kernel/s/swiv b/kernel/s/swiv
index ac03fcb..c99ef95 100644
--- a/kernel/s/swiv
+++ b/kernel/s/swiv
@@ -39,10 +39,29 @@ $name   MRS     lr, CPSR
 
         EXPORT  |_swix|
         EXPORT  |_swi|
+        EXPORT  |_vswix|
+        EXPORT  |_vswi|
 
     ; tedious static _swi(x) entry handling, to avoid generating dynamic code, and
     ; requiring an expensive XOS_SynchroniseCodeAreas
 
+|_vswix|
+        ORR     r0, r0, #&20000
+        TST     r1, #&FF0                 ; check for use of input regs. 4 to 9, or of block param
+        BNE     vswix_even_more_tedious   ; if so, do full stuff
+
+        SUB     sp, sp, #2*4              ; leave a gap so we can use common bottom half
+        STMDB   sp!, {r1, r4-r9, lr}      ; save stuff
+        LDR     r14, [r2]                 ; r14 -> input args
+        B       swix_vswix_common
+
+vswix_even_more_tedious
+|_vswi|
+        SUB     sp, sp, #2*4              ; leave a gap so we can use common bottom half
+        STMDB   sp!, {r1, r4-r9, lr}      ; save stuff
+        LDR     r14, [r2]                 ; r14 -> input args
+        B       swi_vswi_common
+
 |_swix|
         ORR     r0, r0, #&20000
         TST     r1, #&FF0                 ; check for use of input regs. 4 to 9, or of block param
@@ -50,10 +69,9 @@ $name   MRS     lr, CPSR
 
         STMFD   sp!, {r2, r3}             ; put 1st two variadic args on stack
         STMDB   sp!, {r1, r4-r9, lr}      ; save stuff
-
+        ADD     r14, sp, #8*4             ; r14 -> input args
+swix_vswix_common
         SUB     sp, sp, #5*4              ; so we can use tail code common with dynamic version (and room for regs stash)
-
-        ADD     r14, sp, #(5+8)*4         ; r14 -> input args
         MOV     r12, r0                   ; target SWI code
         STR     fp, [sp]                  ; stash fp
 
@@ -78,10 +96,9 @@ swix_even_more_tedious
 |_swi|
         STMFD   sp!, {r2, r3}             ; put 1st two variadic args on stack
         STMDB   sp!, {r1, r4-r9, lr}      ; save stuff
-
+        ADD     r14, sp, #8*4             ; r14 -> input args
+swi_vswi_common
         SUB     sp, sp, #5*4              ; so we can use tail code common with dynamic version (and room for regs stash)
-
-        ADD     r14, sp, #(5+8)*4         ; r14 -> input args
         MOV     r12, r0                   ; target SWI code
         STR     fp, [sp]                  ; stash fp
 
-- 
GitLab