Skip to content
Permalink
Browse files
NEC98: Fix for supporting PC-98 (mainly to handle SIGFPE correctly)
  • Loading branch information
lpproj committed Jul 31, 2020
1 parent 9f82373 commit ff819a64c2265ea45675489b18d4cecd91b28e4b
Showing with 272 additions and 2 deletions.
  1. +50 −0 include/libc/_machine.h
  2. +79 −0 src/libc/crt0/crt1.c
  3. +102 −2 src/libc/go32/dpmiexcp.c
  4. +11 −0 src/libc/go32/exceptn.S
  5. +19 −0 src/makefile.cfg
  6. +11 −0 src/makefile.tgt
@@ -0,0 +1,50 @@
#ifndef __dj_include_libc__machine_h_
#define __dj_include_libc__machine_h_

#ifndef __dj_ENFORCE_ANSI_FREESTANDING

#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \
|| !defined(__STRICT_ANSI__) || defined(__cplusplus)

#endif /* (__STDC_VERSION__ >= 199901L) || !__STRICT_ANSI__ */

#ifndef __STRICT_ANSI__

#ifndef _POSIX_SOURCE

#define __crt0_mtype_PCAT 0x00
#define __crt0_mtype_DOSV 0x01
#define __crt0_mtype_PC98 0x10
#define __crt0_mtype_PC98H 0x11

#define MACHINE_TYPE_IBMPC 0
#define MACHINE_TYPE_NEC98 1
#define MACHINE_TYPE_FMR 2 /* reserved (not supported, for now) */

#define MACHINE_SUBTYPE_NEC98_NORMAL 0
#define MACHINE_SUBTYPE_NEC98_HIRES 1

#define MACHINE_SUBTYPE_IBMPC 0x00
#define MACHINE_SUBTYPE_IBMPC_TOPVIEW 0x10
#define MACHINE_SUBTYPE_IBMPC_DOSV (MACHINE_SUBTYPE_IBMPC_TOPVIEW | 0x01)


#ifdef __cplusplus
extern "C" {
#endif

extern unsigned char __crt0_machine_type;
extern unsigned char __crt0_machine_subtype;

#ifdef __cplusplus
}
#endif


#endif /* !_POSIX_SOURCE */
#endif /* !__STRICT_ANSI__ */
#endif /* !__dj_ENFORCE_ANSI_FREESTANDING */


#endif /* !__dj_include_libc__machine_h_ */

@@ -37,6 +37,13 @@
the static storage. */
int __bss_count = 1;

#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
# include <libc/_machine.h>
int __crt0_mtype = 0;
unsigned char __crt0_machine_type = 0;
unsigned char __crt0_machine_subtype = 0;
#endif

extern char **_environ;

int __crt0_argc;
@@ -87,10 +94,24 @@ setup_core_selector(void)
static void
setup_screens(void)
{
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
/* todo: FMR */
if (__crt0_machine_type == MACHINE_TYPE_NEC98) {
unsigned s = (unsigned)(_farpeekw(_dos_ds, 0x600 + 0x32)) * 16U;
if (s == 0) {
s = __crt0_machine_subtype == MACHINE_SUBTYPE_NEC98_HIRES ? 0xe0000 : 0xa0000;
}
ScreenPrimary = ScreenSecondary = s;
}
else if (__crt0_machine_type == MACHINE_TYPE_IBMPC && (__crt0_machine_subtype & 0xf0) == MACHINE_SUBTYPE_IBMPC_TOPVIEW) {
ScreenSecondary = ScreenPrimary;
}
#else
if(_farpeekw(_dos_ds, 0xffff3) == 0xfd80) /* NEC PC98 ? */
{
ScreenPrimary = ScreenSecondary = 0xa0000;
}
#endif
else if (_farpeekb(_dos_ds, 0x449) == 7)
{
ScreenPrimary = 0xb0000;
@@ -208,6 +229,61 @@ setup_os_version(void)
_osminor = v & 0xff;
}

#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
static void
setup_machine_type(void)
{
__dpmi_regs regs;

/* todo: check FMR at first (for MACHINE_TYPE_FMR */
if (_farpeekw(_dos_ds, 0xffff3) == 0xfd80) {
__crt0_machine_type = MACHINE_TYPE_NEC98;
/* __crt0_machine_subtype = MACHINE_SUBTYPE_NEC98_NORMAL */
}
else {
regs.x.ax = 0x0f07;
__dpmi_int(0x10, &regs);
if (regs.h.ah == 0x0f) __crt0_machine_type = MACHINE_TYPE_NEC98;
else __crt0_machine_type = MACHINE_TYPE_IBMPC;
}

switch(__crt0_machine_type) {
case MACHINE_TYPE_IBMPC: {
regs.h.ah = 0xfe;
regs.x.di = 0;
regs.x.es = 0xb800;
__dpmi_int(0x10, &regs);
if (regs.x.di == 0 || regs.x.es == 0xb800) {
__crt0_machine_subtype = MACHINE_SUBTYPE_IBMPC;
}
else {
__crt0_machine_subtype = MACHINE_SUBTYPE_IBMPC_TOPVIEW;
ScreenPrimary = (unsigned)(regs.x.es) * 16U + regs.x.di;
regs.x.ax = 0x4900;
regs.x.bx = 0;
__dpmi_int(0x15, &regs);
if (regs.h.ah == 0 && regs.h.bl < 15) {
__crt0_machine_subtype += (regs.h.bl + 1);
__crt0_mtype = __crt0_mtype_DOSV;
}
}
break;
}
case MACHINE_TYPE_NEC98: {
if ((_farpeekb(_dos_ds, 0x501) & 0x08) == 0x08) {
__crt0_machine_subtype = MACHINE_SUBTYPE_NEC98_HIRES;
__crt0_mtype = __crt0_mtype_PC98H;
}
else {
__crt0_machine_subtype = MACHINE_SUBTYPE_NEC98_NORMAL;
__crt0_mtype = __crt0_mtype_PC98;
}
break;
}
}
}
#endif /* SUPPORT_NEC98 || SUPPORT_FMR */


void
__crt1_startup(void)
@@ -216,6 +292,9 @@ __crt1_startup(void)
__crt0_argv = 0;
setup_os_version();
setup_core_selector();
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
setup_machine_type();
#endif
setup_screens();
setup_go32_info_block();
__djgpp_exception_setup();
@@ -22,6 +22,9 @@
#include <sys/nearptr.h> /* For DS base/limit info */
#include <libc/internal.h>
#include <stubinfo.h>
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
# include <libc/_machine.h>
#endif

#define err(x) _write(STDERR_FILENO, x, sizeof(x)-1)

@@ -35,6 +38,9 @@ extern unsigned __djgpp_stack_top;
/* These are all defined in exceptn.S and only used here */
extern int __djgpp_exception_table;
extern int __djgpp_npx_hdlr;
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
extern int __djgpp_npx_hdlr_native_mode_swint;
#endif
extern int __djgpp_kbd_hdlr;
extern int __djgpp_kbd_hdlr_pc98;
extern short __excep_ds_alias;
@@ -86,6 +92,15 @@ except_to_sig(int excep)
case 7:
return SIGNOFP;
default:
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if (__crt0_machine_type == MACHINE_TYPE_NEC98) {
return SIGILL;
}
else if (__crt0_machine_type == MACHINE_TYPE_NEC98) {
return SIGILL;
}
/* fallthrough (for IBMPC) */
#endif
if(excep == 0x75) /* HW int to fake exception values hardcoded in exceptn.S */
return SIGFPE;
else if(excep == 0x78)
@@ -108,7 +123,20 @@ show_call_frame(void)

if (isatty(STDERR_FILENO))
{
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
max = 25;
switch (__crt0_machine_type) {
case MACHINE_TYPE_IBMPC:
max =_farpeekb(_dos_ds, 0x484) + 1;
if (max <= 1) max = 25; /* old CGA/MDA */
break;
case MACHINE_TYPE_NEC98:
max = _farpeekb(_dos_ds, 0x600 + 0x112) + 1;
break;
}
#else
max =_farpeekb(_dos_ds, 0x484) + 1; /* number of screen lines */
#endif
if (max < 10 || max > 75) /* sanity check */
max = 10; /* 10 worked for v2.0 and v2.01 */
else
@@ -196,7 +224,11 @@ do_faulting_finish_message(int fake_exception)
const char *prog_name;

/* check video mode for original here and reset (not if PC98) */
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if(__crt0_machine_type == MACHINE_TYPE_IBMPC && ScreenPrimary != 0xa0000 && _farpeekb(_dos_ds, 0x449) != old_video_mode) {
#else
if(ScreenPrimary != 0xa0000 && _farpeekb(_dos_ds, 0x449) != old_video_mode) {
#endif
asm volatile ("pusha;movzbl _old_video_mode,%eax; int $0x10;popa;nop");
}
en = (signum >= EXCEPTION_COUNT) ? 0 :
@@ -235,7 +267,11 @@ do_faulting_finish_message(int fake_exception)
else
itox(__djgpp_exception_state->__eip, 8);

#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if (__crt0_machine_type == MACHINE_TYPE_IBMPC && signum == 0x79)
#else
if (signum == 0x79)
#endif
{
err("\r\n");
exit(-1); /* note: `exit', not `_exit' as for the rest of signals! */
@@ -250,7 +286,20 @@ do_faulting_finish_message(int fake_exception)
}
if (except_to_sig(signum) == SIGFPE)
{
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
unsigned sw, cw;

/* NEC98: avoid re-raising SIGFPE at _status87() */
asm volatile ("fnstsw %0; fnstcw %1" : "=m"(sw), "=m"(cw));
if (__crt0_machine_type != MACHINE_TYPE_IBMPC)
{
asm volatile ("fnclex");
}
err(", x87 status="); itox((sw & 0xffffU), 4);
err(" control="); itox((cw & 0xffffU), 4);
#else
err(", x87 status="); itox(_status87(), 4);
#endif
}
err("\r\neax="); itox(__djgpp_exception_state->__eax, 8);
err(" ebx="); itox(__djgpp_exception_state->__ebx, 8);
@@ -382,7 +431,13 @@ __djgpp_exception_processor(void)

sig = except_to_sig(__djgpp_exception_state->__signum);
raise(sig);
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if(__djgpp_exception_state->__signum >= EXCEPTION_COUNT /* Not exception so continue OK */
|| (__crt0_machine_type != MACHINE_TYPE_IBMPC && __djgpp_exception_state->__signum == 16) /* NEC98 (and FMR?): Floating point exception (native mode) */
)
#else
if(__djgpp_exception_state->__signum >= EXCEPTION_COUNT) /* Not exception so continue OK */
#endif
longjmp(__djgpp_exception_state, __djgpp_exception_state->__eax);
/* User handler did not exit or longjmp, we must exit */
err("Cannot continue from exception, ");
@@ -403,6 +458,12 @@ static __dpmi_regs cbrk_regs;
void
__djgpp_exception_toggle(void)
{
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
/* NEC98: For Microsoft's DPMI server (DPMI.EXE in NEC DOS 5.0 or "MS-DOS Prompt" in Win3.x/9x), seems to be needed to hook 0x10 as software intrrupt */
const int npx_int = __crt0_machine_type == MACHINE_TYPE_IBMPC ? 0x75 : 0x10;
#else
const int npx_int = 0x75;
#endif
__dpmi_paddr except;
size_t i;

@@ -413,8 +474,8 @@ __djgpp_exception_toggle(void)
__dpmi_set_processor_exception_handler_vector(i, &except_ori[i]);
except_ori[i] = except;
}
__dpmi_get_protected_mode_interrupt_vector(0x75, &except);
__dpmi_set_protected_mode_interrupt_vector(0x75, &npx_ori);
__dpmi_get_protected_mode_interrupt_vector(npx_int, &except);
__dpmi_set_protected_mode_interrupt_vector(npx_int, &npx_ori);
npx_ori = except;
__dpmi_get_protected_mode_interrupt_vector(9, &except);
__dpmi_set_protected_mode_interrupt_vector(9, &kbd_ori);
@@ -432,7 +493,11 @@ __djgpp_exception_toggle(void)
/* If the timer interrupt is hooked, toggle it as well. This is so
programs which use SIGALRM or itimer, and don't unhook the timer before
they exit, won't leave the system with timer pointing into the void. */
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if (__crt0_machine_type == MACHINE_TYPE_IBMPC && __djgpp_old_timer.selector != 0 && __djgpp_old_timer.offset32 != 0)
#else
if (__djgpp_old_timer.selector != 0 && __djgpp_old_timer.offset32 != 0)
#endif
{
if (timer_ori.selector == __djgpp_old_timer.selector
&& timer_ori.offset32 == __djgpp_old_timer.offset32)
@@ -522,6 +587,22 @@ __djgpp_exception_setup(void)
size_t i;

__excep_ds_alias = __djgpp_ds_alias;
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if (__crt0_machine_type == MACHINE_TYPE_IBMPC)
{ /* for IBMPC */
__djgpp_set_sigint_key(DEFAULT_SIGINT);
__djgpp_set_sigquit_key(DEFAULT_SIGQUIT);
}
else if (__crt0_machine_type == MACHINE_TYPE_NEC98)
{ /* for PC98 */
__djgpp_set_sigint_key(DEFAULT_SIGINT_98);
__djgpp_set_sigquit_key(DEFAULT_SIGQUIT_98);
}
else if (__crt0_machine_type == MACHINE_TYPE_FMR)
{
/* todo: for FMR */
}
#else
if (ScreenPrimary != 0xa0000)
{
__djgpp_set_sigint_key(DEFAULT_SIGINT);
@@ -532,6 +613,7 @@ __djgpp_exception_setup(void)
__djgpp_set_sigint_key(DEFAULT_SIGINT_98);
__djgpp_set_sigquit_key(DEFAULT_SIGQUIT_98);
}
#endif

for (i = 0; i < SIGMAX; i++)
signal_list[i] = (SignalHandler)SIG_DFL;
@@ -556,6 +638,23 @@ __djgpp_exception_setup(void)
}
kbd_ori.selector = npx_ori.selector = except.selector;
npx_ori.offset32 = (unsigned) &__djgpp_npx_hdlr;
#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
if (__crt0_machine_type == MACHINE_TYPE_IBMPC)
kbd_ori.offset32 = (unsigned) &__djgpp_kbd_hdlr;
else if (__crt0_machine_type == MACHINE_TYPE_NEC98)
{
npx_ori.offset32 = (unsigned) &__djgpp_npx_hdlr_native_mode_swint;
kbd_ori.offset32 = (unsigned) &__djgpp_kbd_hdlr_pc98;
cbrk_vect = 0x06;
except.offset32 = (unsigned) &__djgpp_iret; /* TDPMI98 bug */
__dpmi_set_protected_mode_interrupt_vector(0x23, &except);
}
else if (__crt0_machine_type == MACHINE_TYPE_FMR)
{
/* todo: for FMR */
npx_ori.offset32 = (unsigned) &__djgpp_npx_hdlr_native_mode_swint;
}
#else
if(ScreenPrimary != 0xa0000)
kbd_ori.offset32 = (unsigned) &__djgpp_kbd_hdlr;
else
@@ -565,6 +664,7 @@ __djgpp_exception_setup(void)
except.offset32 = (unsigned) &__djgpp_iret; /* TDPMI98 bug */
__dpmi_set_protected_mode_interrupt_vector(0x23, &except);
}
#endif
except.offset32 = (unsigned) &__djgpp_i24;
__dpmi_set_protected_mode_interrupt_vector(0x24, &except);

@@ -304,6 +304,17 @@ exception_state: .space 64
.global ___excep_ds_alias
___excep_ds_alias: .word 0 /* private locked __djgpp_ds_alias */

#if defined SUPPORT_NEC98 || defined SUPPORT_FMR
.balign 16,,7
.global ___djgpp_npx_hdlr_native_mode_swint
___djgpp_npx_hdlr_native_mode_swint:
pushl %eax
movl $0x10,%eax
call ___djgpp_hw_exception
popl %eax
iret
#endif

.balign 16,,7
.global ___djgpp_npx_hdlr
___djgpp_npx_hdlr:

0 comments on commit ff819a6

Please sign in to comment.