Files
2ine-tms34010/native/os2native16.h
T
Ryan C. Gordon 3e83a67d48 Let OS2APIINFO optionally take key/value pairs, use it for export names.
This lets me remove my tcpip32 hack, and will let me export old symbols
as all caps for OS/2's use and something more sane for regular use
(like VioGetCurPos() in modern times is VIOGETCURPOS in viocalls.dll, etc).
2018-06-17 22:21:52 -04:00

274 lines
9.8 KiB
C

/**
* 2ine; an OS/2 emulator for Linux.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#ifndef _INCL_OS2NATIVE16_H_
#define _INCL_OS2NATIVE16_H_
#include "os2native.h"
// !!! FIXME: _lots_ of macro salsa in here.
#define LX_NATIVE_MODULE_16BIT_SUPPORT() \
static LxMmaps obj16;
// These are the 16-bit entry points, which are exported to the LX loader
// (not when linking directly to this shared library).
#define LX_NATIVE_MODULE_16BIT_API(fn) \
static void *fn##16 = NULL;
#define LX_NATIVE_MODULE_16BIT_SUPPORT_END()
#define LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT() \
if (obj16.alias != 0xFFFF) { \
GLoaderState.freeSelector(obj16.alias); \
} \
if (obj16.mapped != NULL) { \
munmap(obj16.mapped, obj16.size); \
} \
obj16.mapped = obj16.addr = NULL; \
obj16.size = 0; \
obj16.alias = 0xFFFF; \
#define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() \
obj16.mapped = obj16.addr = NULL; \
obj16.size = 0; \
obj16.alias = 0xFFFF; \
\
const size_t vsize = 0x10000 * 2; \
void *mmapaddr = mmap(NULL, vsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); \
if (mmapaddr == ((void *) MAP_FAILED)) { \
fprintf(stderr, "mmap(NULL, 0x20000, RW-, ANON|PRIVATE, -1, 0) failed (%d): %s\n", errno, strerror(errno)); \
return 0; \
} \
\
obj16.mapped = mmapaddr; \
obj16.size = vsize; \
\
/* force objects with a 16:16 alias to a 64k boundary. */ \
size_t adjust = (size_t) mmapaddr; \
if ((adjust % 0x10000) != 0) { \
const size_t diff = 0x10000 - (adjust % 0x10000); \
adjust += diff; \
mmapaddr = (void *) adjust; \
} \
obj16.addr = mmapaddr; \
\
uint16 offset = 0; \
if (!GLoaderState.findSelector((uint32) obj16.addr, &obj16.alias, &offset, 1)) { \
fprintf(stderr, "couldn't find a selector for 16-bit entry points!\n"); \
munmap(obj16.mapped, vsize); \
obj16.mapped = obj16.addr = NULL; \
obj16.size = 0; \
obj16.alias = 0xFFFF; \
return 0; \
} \
assert(offset == 0); \
\
uint8 *ptr = (uint8 *) mmapaddr;
/* This is the original assembly code, for use with NASM.
USE16 ; start in 16-bit code where our 16-bit caller lands.
PUSH BX ; this might be overkill, but save off everything you can, just in case.
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
MOV CX, SP ; save off sp
JMP DWORD 0x7788:0x33332222 ; jmp into the 32-bit code segment (the next instruction!).
USE32
MOV BX, SS ; save off ss
SHL EBX, 16 ; scootch over!
MOV BX, CX ; %ebx now has 16-bit ss:sp
; our stack is tiled, so we can easily find the linear address of it.
MOV AX, SS ; move the stack segment into the low word.
SHR AX, 3 ; shift out the control bits from the segment.
SHL EAX, 16 ; move the remaining selector bits to the high word of %eax
MOV AX, CX ; move the stack offset into the low word. Now %eax has the linear stack pointer.
MOV CX, 0xABCD ; original linear stack segment from lx_loader's main().
MOV SS, CX
MOV ESP, EAX ; and the same stack pointer, but linear.
ADD EAX, 16 ; %eax now points to original function arguments on the stack.
PUSH EBX ; save original ss:sp to stack.
PUSH DS ; save off the caller's data segment.
PUSH ES ; save off the caller's %es register.
MOV CX, 0x8888 ; restore our linear data segment.
MOV DS, CX
MOV CX, 0x9999 ; restore %es register.
MOV ES, CX
PUSH EAX ; make this the sole argument to the bridge function.
MOV EAX, 0x55555555 ; absolute address of our 32-bit bridging function in C.
CALL [EAX] ; call our 32-bit bridging function in C.
; don't touch EAX anymore, it has the return value now!
ADD ESP, 4 ; dump our function argument.
POP ES ; get back caller's %es register.
POP DS ; get back our 16-bit data segment.
; Restore 16:16 stack. !!! FIXME: can use LSS if we figure out prefix and DS politics.
POP BX ; Get our original sp back.
POP CX ; Get our original ss back.
JMP WORD 0xAAAA:0xBBBB ; back into 16-bit land (the next instruction!).
USE16
MOV SS, CX
MOV SP, BX
POP BP ; restore all our overkill registers
POP DI
POP SI
POP DX
POP CX
POP BX
RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling convention!) with retval in AX.
*/
#define LX_NATIVE_INIT_16BIT_BRIDGE(fn, argbytes) { \
fn##16 = ptr; \
\
/* instructions are in Intel syntax here, not AT&T. */ \
/* USE16 */ \
*(ptr++) = 0x53; /* push bx */ \
*(ptr++) = 0x51; /* push cx */ \
*(ptr++) = 0x52; /* push dx */ \
*(ptr++) = 0x56; /* push si */ \
*(ptr++) = 0x57; /* push di */ \
*(ptr++) = 0x55; /* push bp */ \
*(ptr++) = 0x89; /* mov cx,sp... */ \
*(ptr++) = 0xE1; /* ...mov cx,sp */ \
*(ptr++) = 0x66; /* jmp dword 0x7788:0x33332222... */ \
*(ptr++) = 0xEA; /* ...jmp dword 0x7788:0x33332222 */ \
const uint32 jmp32addr = (uint32) (ptr + 6); \
memcpy(ptr, &jmp32addr, 4); ptr += 4; \
memcpy(ptr, &GLoaderState.original_cs, 2); ptr += 2; \
\
/* USE32 */ \
*(ptr++) = 0x66; /* mov bx,ss... */ \
*(ptr++) = 0x8C; /* ...mov bx,ss */ \
*(ptr++) = 0xD3; /* ...mov bx,ss */ \
*(ptr++) = 0xC1; /* shl ebx,byte 0x10... */ \
*(ptr++) = 0xE3; /* ...shl ebx,byte 0x10 */ \
*(ptr++) = 0x10; /* ...shl ebx,byte 0x10 */ \
*(ptr++) = 0x66; /* mov bx,cx... */ \
*(ptr++) = 0x89; /* ...mov bx,cx */ \
*(ptr++) = 0xCB; /* ...mov bx,cx */ \
*(ptr++) = 0x66; /* mov ax,ss... */ \
*(ptr++) = 0x8C; /* ...mov ax,ss */ \
*(ptr++) = 0xD0; /* ...mov ax,ss */ \
*(ptr++) = 0x66; /* shr ax,byte 0x3... */ \
*(ptr++) = 0xC1; /* ...shr ax,byte 0x3 */ \
*(ptr++) = 0xE8; /* ...shr ax,byte 0x3 */ \
*(ptr++) = 0x03; /* ...shr ax,byte 0x3 */ \
*(ptr++) = 0xC1; /* shl eax,byte 0x10... */ \
*(ptr++) = 0xE0; /* ...shl eax,byte 0x10 */ \
*(ptr++) = 0x10; /* ...shl eax,byte 0x10 */ \
*(ptr++) = 0x66; /* mov ax,cx... */ \
*(ptr++) = 0x89; /* ...mov ax,cx */ \
*(ptr++) = 0xC8; /* ...mov ax,cx */ \
*(ptr++) = 0x66; /* mov cx,0xabcd... */ \
*(ptr++) = 0xB9; /* ...mov cx,0xabcd */ \
memcpy(ptr, &GLoaderState.original_ss, 2); ptr += 2; \
*(ptr++) = 0x8E; /* mov ss,ecx... */ \
*(ptr++) = 0xD1; /* ...mov ss,ecx */ \
*(ptr++) = 0x89; /* mov esp,eax... */ \
*(ptr++) = 0xC4; /* ...mov esp,eax */ \
*(ptr++) = 0x83; /* add eax,byte +0x10... */ \
*(ptr++) = 0xC0; /* ...add eax,byte +0x10 */ \
*(ptr++) = 0x10; /* ...add eax,byte +0x10 */ \
*(ptr++) = 0x53; /* push ebx */ \
*(ptr++) = 0x1E; /* push ds */ \
*(ptr++) = 0x06; /* push es */ \
if (GLoaderState.original_ss != GLoaderState.original_ds) { \
*(ptr++) = 0x66; /* mov cx,0x8888... */ \
*(ptr++) = 0xB9; /* ...mov cx,0x8888 */ \
memcpy(ptr, &GLoaderState.original_ds, 2); ptr += 2; \
} \
*(ptr++) = 0x8E; /* mov ds,ecx... */ \
*(ptr++) = 0xD9; /* ...mov ds,ecx */ \
if (GLoaderState.original_ds != GLoaderState.original_es) { \
*(ptr++) = 0x66; /* mov cx,0x9999... */ \
*(ptr++) = 0xB9; /* ...mov cx,0x9999 */ \
memcpy(ptr, &GLoaderState.original_es, 2); ptr += 2; \
} \
*(ptr++) = 0x8E; /* mov es,ecx... */ \
*(ptr++) = 0xC1; /* ...mov es,ecx */ \
*(ptr++) = 0x50; /* push eax */ \
*(ptr++) = 0xB8; /* mov eax,0x55555555... */ \
const uint32 callbridgeaddr = (uint32) bridge16to32_##fn; \
memcpy(ptr, &callbridgeaddr, 4); ptr += 4; \
*(ptr++) = 0xFF; /* call dword [eax]... */ \
*(ptr++) = 0xD0; /* ...call dword [eax] */ \
*(ptr++) = 0x83; /* add esp,byte +0x4... */ \
*(ptr++) = 0xC4; /* ...add esp,byte +0x4 */ \
*(ptr++) = 0x04; /* ...add esp,byte +0x4 */ \
*(ptr++) = 0x07; /* pop es */ \
*(ptr++) = 0x1F; /* pop ds */ \
*(ptr++) = 0x66; /* pop bx... */ \
*(ptr++) = 0x5B; /* ...pop bx */ \
*(ptr++) = 0x66; /* pop cx... */ \
*(ptr++) = 0x59; /* ...pop cx */ \
*(ptr++) = 0x66; /* jmp word 0xaaaa:0xbbbb... */ \
*(ptr++) = 0xEA; /* ...jmp word 0xaaaa:0xbbbb */ \
const uint16 jmp16offset = (uint16) ((((uint32)ptr) - ((uint32)mmapaddr))+4); \
memcpy(ptr, &jmp16offset, 2); ptr += 2; \
const uint16 jmp16segment = (obj16.alias << 3) | 7; \
memcpy(ptr, &jmp16segment, 2); ptr += 2; \
\
/* USE16 */ \
*(ptr++) = 0x8E; /* mov ss,cx... */ \
*(ptr++) = 0xD1; /* ...mov ss,cx */ \
*(ptr++) = 0x89; /* mov sp,bx... */ \
*(ptr++) = 0xDC; /* ...mov sp,bx */ \
*(ptr++) = 0x5D; /* pop bp */ \
*(ptr++) = 0x5F; /* pop di */ \
*(ptr++) = 0x5E; /* pop si */ \
*(ptr++) = 0x5A; /* pop dx */ \
*(ptr++) = 0x59; /* pop cx */ \
*(ptr++) = 0x5B; /* pop bx */ \
*(ptr++) = 0xCA; /* retf 0x22... */ \
const uint16 argbytecount = argbytes; \
memcpy(ptr, &argbytecount, 2); ptr += 2; \
}
#define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() { \
assert((((uint32)ptr) - ((uint32)mmapaddr)) < 0x10000); /* don't be more than 64k. */ \
if (mprotect(obj16.mapped, vsize, PROT_READ | PROT_EXEC) == -1) { \
fprintf(stderr, "mprotect() failed for 16-bit bridge code!\n"); \
munmap(obj16.mapped, vsize); \
GLoaderState.freeSelector(obj16.alias); \
obj16.mapped = obj16.addr = NULL; \
obj16.size = 0; \
obj16.alias = 0xFFFF; \
return 0; \
} \
}
#define LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(typ, var) \
const typ var = *((typ *) args); args += sizeof (typ)
#define LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(typ, var) \
typ var = (typ) GLoaderState.convert1616to32(*((uint32 *) args)); args += sizeof (uint32)
#define LX_NATIVE_EXPORT16(fn, ord) { ord, #fn, &fn##16, &obj16 }
#define LX_NATIVE_EXPORT16_DIFFERENT_NAME(fn, fnname, ord) { ord, fnname, &fn##16, &obj16 }
#endif
// end of os2native16.h ...