Mail Archives: djgpp/2019/06/22/02:49:08
On Fri, 21 Jun 2019 09:44:34 +0200
"Gisle Vanem (gisle DOT vanem AT gmail DOT com) [via djgpp AT delorie DOT com]"
<djgpp AT delorie DOT com> wrote:
> Rod Pemberton wrote:
> > Of course, not saving/restoring C/C++ code's in-use registers does
> > much the same thing. Certain registers must be preserved and can't
> > be clobbered. These can also be referred to as callee-savee or
> > caller-saved registers. For DJGPP, my notes say that EBX, EDI, ESI,
> > EBP, DS, ES, SS registers must preserved. I.e., check your inlined
> > assembly's clobber list.
>
> And the GS, FS registers too. These are *not* preserved in a
> real-mode callback (RMCB) like
> '_go32_dpmi_allocate_real_mode_callback_retf()' Not sure about
> '_dpmi_allocate_real_mode_callback()'
>
> Ref: <djgpp_root>/src/LIBC/GO32/gormcb.c
>
> I figured this after similar bugs in the network-driver
> call-back in Watt-32 tcp/ip stack.
Thank you.
I made some notes on what each does and when to use them, e.g.,
(some lines wrapped, so double spaced ...)
__dpmi_int() preferred method in DJGPP for calling ints (vs. int86)
__dpmi_int calls Int in RM by using the DPMI host
__dpmi_allocate_real_mode_callback (for assembly code in PM)
_go32_dpmi_allocate_real_mode_callback_iret (for C code on RM int)
_go32_dpmi_allocate_real_mode_callback_retf (for C code on RM far jump)
_go32_dpmi_allocate_iret_wrapper (for C code on PM int)
_go32_dpmi_chain_protected_mode_interrupt_vector (for C code on PM int
which chains to old PM int)
Also other interrupt calling functions,
int86() via _int86() calls Int in PM which is then reflected to RM by
DPMI host - except for a few Int 0x21 functions (extended) which call
__dpmi_int()
int86x() calls Int in PM
_int86() calls Int in PM
int386() same as int86() - dos.h
int386x() same as int86x() - dos.h
intdos() same as int86() for Int 0x21 - dos.h
intdosx() same as int86x() for int 0x21 - dos.h - intdosx.c
bdosptr() same as bdos() - dos.h - bdosptr.S
bdos() - bdos.c - calls Int 0x21 with func=AH, AL, DX - bdosptr uses DX
as pointer to buffer - calls int86() with 0x21
__dpmi_int() - d0300_z.S - calls DPMI via PM Int 0x31 which calls RM
Int - ss, e sp, flags are 'automatically' taken care of - certain Int
0x21 int_86() calls redirected to __dpmi_int() by int_86()
__dpmi_simulate_real_mode_interrupt() - d0300.S - calls DPMI via PM Int
0x31 which calls RM Int - same as __dpmi_int() without saving/restoring
ss,sp,flags
Also, some go32 to DPMI mappings,
__go32_dpmi_simulate_int -> ___dpmi_simulate_real_mode_interrupt in
godefv1.S
__go32_dpmi_simulate_fcall -> ___dpmi_simulate_real_mode_procedure_retf
in godefv1.S
__go32_dpmi_simulate_fcall_iret ->
___dpmi_simulate_real_mode_procedure_iret in godefv1.S
_go32_dpmi_simulate_int -> __dpmi_simulate_real_mode_interrupt in dpmi.h
_go32_dpmi_simulate_fcall -> __dpmi_simulate_real_mode_procedure_retf
in dpmi.h
_go32_dpmi_simulate_fcall_iret ->
__dpmi_simulate_real_mode_procedure_iret in dpmi.h
> I'm not sure how/where FS/GS are used; I suspect a modern gcc uses
> those in e.g. built-in functions etc.
>
DJGPP uses fs for far pointers (farpeek, farpoke)
DJGPP uses gs for dos segment via _dos_ds and within libc
For reference on DJGPP's various selectors, some info I extracted:
(some lines wrapped, so double spaced ... from v2.03)
cs selector for code segment, _my_cs(), _go32_my_cs()
ds data for cs selector for data segment used by gcc, _my_ds(),
_go32_my_ds()
ss same as ds selector for stack segment, _my_ss(), _go32_my_ss()
es same as ds selector for psp segment used by gcc
fs selector unused, but used for farptrs (farpeek,farpoke)
gs selector for dos segment (1M+64k), and used by libc
dsa alias for ds __djgpp_ds_alias, mirrors ds, used for rmcb's
dsl is gs __djgpp_dos_sel
dds is gs _dos_ds, _go32_info_ block+26,
_go32_info_block.selector_for_linear_memory
cms is gs _go32_conventional_mem_selector()
_my_cs() - returns cs
_my_ds() - returns ds (and also ss, es, dsa)
_my_ss() - returns ss (and also ds, es, dsa)
_dos_ds - is gs (and also dsl, cms)
_farsetsel - set fs to another selector e.g., _dos_ds, _my_ds() for use
with farpeek, farpoke etc.
For adjusting segment limit's,
__djgpp_nearptr_enable() can be used to boost the segment limit to 4Gb
for cs, ds, es, ss, and dsa
__dpmi_set_segment_limit(_selector_, 0xFFFFFFFFU) can be used to boost
the segment limit to 4Gb for _dos_ds, etc.
For wrapped memory addressing,
DJGPP defines two offsets in <sys\nearptr.h>:
__djgpp_conventional_base (which is a #define)
__djgpp_base_address (which is an int)
They are related by the following define:
#define __djgpp_conventional_base (-__djgpp_base_address)
For DJGPP's transfer buffer, i.e., calling RM DOS or BIOS functions,
__tb is a linear address:
for RM, segment:offset is __tb>>4:0
for RM, segment:offset is __tb_segment:__tb_offset
for PM, selector:offset is _dos_ds:__tb
for PM to RM, segment:offset is __tb>>4:0
(tb is paragraph aligned for PM)
__tb is _go32_info_block+12,
_go32_info_block.linear_address_of_transfer_buffer
__tb is _stubinfo->ds_segment * 16
__tb_segment is __tb >> 4
__tb_offset is 0
__tb size is
_go32_info_block.size_of_transfer_buffer,_go32_info_block+16
__tb size is _stubinfo->minkeep
__tb size is 04000h (16384 bytes)
HTH,
Rod Pemberton
--
Once upon a time, many decades ago in a place far away, humble people
sought their freedom, and lost. "Ideas are bulletproof."
- Raw text -