Add support for thunking cdecl/stdcall-style real-mode code
authorH. Peter Anvin <hpa@zytor.com>
Wed, 21 Nov 2007 02:51:54 +0000 (18:51 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Wed, 21 Nov 2007 02:51:54 +0000 (18:51 -0800)
Add support for thunking cdecl/stdcall-style 16-bit functions which
pass parameters on the stack.  This is necessary in order to be able
to call PnPBIOS functions without using the (rather scary) PM
interface.

com32.inc
com32/include/com32.h
com32/lib/Makefile
com32/lib/sys/entry.S
comboot.doc

index c4a1faa..47f104b 100644 (file)
--- a/com32.inc
+++ b/com32.inc
@@ -1,6 +1,6 @@
 ;; -----------------------------------------------------------------------
 ;;
-;;   Copyright 1994-2006 H. Peter Anvin - All Rights Reserved
+;;   Copyright 1994-2007 H. Peter Anvin - All Rights Reserved
 ;;
 ;;   This program is free software; you can redistribute it and/or modify
 ;;   it under the terms of the GNU General Public License as published by
@@ -164,12 +164,13 @@ com32_call_start:
 
                ; Now everything is set up for interrupts...
 
+               push dword com32_cfarcall       ; Cfarcall entry point
                push dword com32_farcall        ; Farcall entry point
                push dword (1 << 16)            ; 64K bounce buffer
                push dword (comboot_seg << 4)   ; Bounce buffer address
                push dword com32_intcall        ; Intcall entry point
                push dword command_line         ; Command line pointer
-               push dword 5                    ; Argument count
+               push dword 6                    ; Argument count
                sti                             ; Interrupts OK now
                call pm_entry                   ; Run the program...
                ; ... on return, fall through to com32_exit ...
@@ -232,7 +233,7 @@ com32_int_rm:
                jmp com32_enter_pm              ; Go back to PM
 
 ;
-; 16-bit system call handling code
+; 16-bit intcall/farcall handling code
 ;
 com32_sys_rm:
                pop gs
@@ -253,7 +254,18 @@ com32_sys_rm:
                push es
                push fs
                push gs
-               mov ebx,com32_sys_resume
+               mov ebx,com32_syscall.resume
+               jmp com32_enter_pm
+
+;
+; 16-bit cfarcall handing code
+;
+com32_cfar_rm:
+               retf
+.return:
+               mov sp,[cs:Com32SysSP]
+               mov [cs:RealModeEAX],eax
+               mov ebx,com32_cfarcall.resume
                jmp com32_enter_pm
 
 ;
@@ -335,7 +347,7 @@ com32_syscall:
                ; On return, the 44-byte return structure is on the
                ; real-mode stack, plus the 10 additional bytes used
                ; by the target address (see above.)
-com32_sys_resume:
+.resume:
                movzx esi,word [word RealModeSSSP]
                movzx eax,word [word RealModeSSSP+2]
                mov edi,[esp+12*4]      ; Dest regs
@@ -354,11 +366,53 @@ com32_sys_resume:
                popfd
                ret                     ; Return to 32-bit program
 
+;
+; Cfarcall invocation.  We copy the stack frame to the real-mode stack,
+; followed by the return CS:IP and the CS:IP of the target function.
+;
+com32_cfarcall:
+               pushfd
+               pushad
+
+               cld
+               mov ecx,[esp+12*4]              ; Size of stack frame
+
+               movzx edi,word [word RealModeSSSP]
+               movzx ebx,word [word RealModeSSSP+2]
+               mov [word Com32SysSP],di
+               sub edi,ecx             ; Allocate space for stack frame
+               and edi,~3              ; Round
+               sub edi,4*2             ; Return pointer, return value
+               mov [word RealModeSSSP],di
+               shl ebx,4
+               add edi,ebx             ; Create linear address
+
+               mov eax,[esp+10*4]      ; CS:IP
+               stosd                   ; Save to stack frame
+               mov eax,com32_cfar_rm.return    ; Return seg:off
+               stosd
+               mov esi,[esp+11*4]      ; Stack frame
+               mov eax,ecx             ; Copy the stack frame
+               rep movsd
+               mov ecx,eax
+               and ecx,3
+               rep movsb
+
+               mov bx,com32_cfar_rm
+               jmp com32_enter_rm
+
+.resume:
+               popad
+               mov eax,[word RealModeEAX]
+               popfd
+               ret
+
                bits 16
 
                section .bss1
                alignb 4
 RealModeSSSP   resd 1                  ; Real-mode SS:SP
+RealModeEAX    resd 1                  ; Real mode EAX
 PMESP          resd 1                  ; Protected-mode ESP
 Com32SysSP     resw 1                  ; SP saved during COM32 syscall
 
index 264f609..7e61897 100644 (file)
@@ -74,14 +74,17 @@ extern struct com32_sys_args {
   void *cs_bounce;
   uint32_t cs_bounce_size;
   void __cdecl (*cs_farcall)(uint32_t, const com32sys_t *, com32sys_t *);
+  int __cdecl (*cs_cfarcall)(uint32_t, const void *, uint32_t);
 } __com32;
 
 /*
  * System call wrapper functions
  */
 void __intcall(uint8_t __i, const com32sys_t *__sr, com32sys_t *__dr);
-void __farcall(uint16_t __es, uint16_t __eo,
+void __farcall(uint16_t __cs, uint16_t __ip,
               const com32sys_t *__sr, com32sys_t *__dr);
+int __cfarcall(uint16_t __cs, uint16_t __ip,
+              const void *__stack, uint32_t __stack_size);
 extern const com32sys_t __com32_zero_regs;
 
 /*
index 991d588..1cde067 100644 (file)
@@ -24,7 +24,7 @@ LIBOBJS = \
        libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o      \
        libgcc/__divdi3.o libgcc/__moddi3.o                             \
        \
-       sys/intcall.o sys/farcall.o sys/zeroregs.o                      \
+       sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o       \
        sys/entry.o sys/exit.o sys/argv.o sys/times.o                   \
        sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
        sys/close.o sys/open.o sys/fileread.o sys/fileclose.o           \
index be42c8b..c959c09 100644 (file)
@@ -1,6 +1,6 @@
 # -----------------------------------------------------------------------
 #
-#   Copyright 2003-2004 H. Peter Anvin - All Rights Reserved
+#   Copyright 2003-2007 H. Peter Anvin - All Rights Reserved
 #
 #   Permission is hereby granted, free of charge, to any person
 #   obtaining a copy of this software and associated documentation
@@ -27,7 +27,9 @@
 
 # COM32 start up code - must be linked first in the binary
 
-
+/* Number of arguments in our version of the entry structure */
+#define COM32_ARGS 6
+       
                .section ".init","ax"
                .globl _start
                .type _start, @function
@@ -49,7 +51,7 @@ _start:
                # Copy COM32 invocation parameters
                leal 4(%esp),%esi               # Argument list
                movl $__com32,%edi
-               movl $5,%ecx
+               movl $COM32_ARGS,%ecx
                movl %esp,-4(%edi)              # Save the initial stack ptr
                cmpl (%esi),%ecx
                jbe 1f
@@ -87,4 +89,4 @@ _start:
                .globl __entry_esp
 __entry_esp:   .space 4
                .globl __com32
-__com32:       .space 4*6
+__com32:       .space 4*(COM32_ARGS+1)
index 3c806c3..2939f9b 100644 (file)
@@ -85,6 +85,7 @@ The following arguments are passed to the program on the stack:
  [ESP+16] dword Pointer to low memory bounce buffer
  [ESP+20] dword Size of low memory bounce buffer
  [ESP+24] dword Pointer to FAR call helper function (new in 2.05)
+ [ESP+28] dword Pointer to CDECL helper function (new in 3.xx)
 
 This corresponds to the following C prototype, available in the file
 com32/include/com32.h:
@@ -95,7 +96,9 @@ int _start(unsigned int __nargs,
           void (*__intcall)(uint8_t, com32sys_t *, com32sys_t *),
           void *__bounce_ptr,
           unsigned int __bounce_len,
-          void (*__farcall)(uint32_t, uint16_t, com32sys_t *, com32sys_t *));
+          void (*__farcall)(uint32_t, com32sys_t *, com32sys_t *),
+          int (*__cfarcall)(uint32_t, void *, size_t)
+          );
 
 The intcall helper function can be used to issue BIOS or SYSLINUX API
 calls, and takes the interrupt number as first argument.  The second
@@ -138,6 +141,10 @@ The farcall helper function behaves similarly, but takes as its first
 argument the CS:IP (in the form (CS << 16) + IP) of procedure to be
 invoked via a FAR CALL.
 
+The cfarcall helper function takes (CS << 16)+IP, a pointer to a stack
+frame, a size of that stack frame, and returns the return value of EAX
+(which may need to be appropriate truncated by the user.)
+
 
        ++++ SYSLINUX API CALLS +++