📄 inthndlr.c
字号:
/****************************************************************/
/* */
/* inthndlr.c */
/* */
/* Interrupt Handler and Function dispatcher for Kernel */
/* */
/* Copyright (c) 1995 */
/* Pasquale J. Villani */
/* All Rights Reserved */
/* */
/* This file is part of DOS-C. */
/* */
/* DOS-C is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License */
/* as published by the Free Software Foundation; either version */
/* 2, or (at your option) any later version. */
/* */
/* DOS-C is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
/* the GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public */
/* License along with DOS-C; see the file COPYING. If not, */
/* write to the Free Software Foundation, 675 Mass Ave, */
/* Cambridge, MA 02139, USA. */
/* */
/****************************************************************/
#define MAIN
#include "portab.h"
#include "globals.h"
#include "nls.h"
#ifdef VERSION_STRINGS
BYTE *RcsId =
"$Id: inthndlr.c,v 1.87 2004/05/30 19:31:07 bartoldeman Exp $";
#endif
#ifdef TSC
STATIC VOID StartTrace(VOID);
static bTraceNext = FALSE;
#endif
#if 0 /* Very suspicious, passing structure by value??
Deactivated -- 2000/06/16 ska */
/* Special entry for far call into the kernel */
#pragma argsused
VOID FAR int21_entry(iregs UserRegs)
{
int21_handler(UserRegs);
}
#endif
/* Structures needed for int 25 / int 26 */
struct HugeSectorBlock {
ULONG blkno;
WORD nblks;
BYTE FAR *buf;
};
/* Normal entry. This minimizes user stack usage by avoiding local */
/* variables needed for the rest of the handler. */
/* this here works on the users stack !! and only very few functions
are allowed */
VOID ASMCFUNC int21_syscall(iregs FAR * irp)
{
Int21AX = irp->AX;
switch (irp->AH)
{
/* Set Interrupt Vector */
case 0x25:
setvec(irp->AL, (intvec)MK_FP(irp->DS, irp->DX));
break;
/* DosVars - get/set dos variables */
case 0x33:
switch (irp->AL)
{
/* Get Ctrl-C flag */
case 0x00:
irp->DL = break_ena;
break;
/* Set Ctrl-C flag */
case 0x01:
break_ena = irp->DL & 1;
break;
case 0x02: /* andrew schulman: get/set extended control break */
{
UBYTE tmp = break_ena;
break_ena = irp->DL & 1;
irp->DL = tmp;
}
break;
/* Get Boot Drive */
case 0x05:
irp->DL = BootDrive;
break;
/* Get (real) DOS-C version */
case 0x06:
irp->BL = os_major;
irp->BH = os_minor;
irp->DL = rev_number;
irp->DH = version_flags; /* bit3:runs in ROM,bit 4: runs in HMA */
break;
case 0x03: /* DOS 7 does not set AL */
case 0x07: /* neither here */
default: /* set AL=0xFF as error, NOT carry */
irp->AL = 0xff;
break;
/* set FreeDOS returned version for int 21.30 from BX */
case 0xfc: /* 0xfc ... 0xff are FreeDOS extensions */
os_setver_major = irp->BL;
os_setver_minor = irp->BH;
break;
/* Toggle DOS-C rdwrblock trace dump */
#ifdef DEBUG
case 0xfd:
bDumpRdWrParms = !bDumpRdWrParms;
break;
#endif
/* Toggle DOS-C syscall trace dump */
#ifdef DEBUG
case 0xfe:
bDumpRegs = !bDumpRegs;
break;
#endif
/* Get DOS-C release string pointer */
case 0xff:
irp->DX = FP_SEG(os_release);
irp->AX = FP_OFF(os_release);
}
break;
/* Get Interrupt Vector */
case 0x35:
{
intvec p = getvec(irp->AL);
irp->ES = FP_SEG(p);
irp->BX = FP_OFF(p);
break;
}
/* Set PSP */
case 0x50:
cu_psp = irp->BX;
break;
/* Get PSP */
case 0x51:
/* UNDOCUMENTED: return current psp */
case 0x62:
irp->BX = cu_psp;
/* Normal DOS function - DO NOT ARRIVE HERE */
/* default: */
}
}
#ifdef WITHFAT32
/* DOS 7.0+ FAT32 extended functions */
int int21_fat32(lregs *r)
{
COUNT rc;
switch (r->AL)
{
/* Get extended drive parameter block */
case 0x02:
{
struct dpb FAR *dpb;
struct xdpbdata FAR *xddp;
if (r->CX < sizeof(struct xdpbdata))
return DE_INVLDBUF;
dpb = GetDriveDPB(r->DL, &rc);
if (rc != SUCCESS)
return rc;
/* hazard: no error checking! */
flush_buffers(dpb->dpb_unit);
dpb->dpb_flags = M_CHANGED; /* force reread of drive BPB/DPB */
if (media_check(dpb) < 0)
return DE_INVLDDRV;
xddp = MK_FP(r->ES, r->DI);
fmemcpy(&xddp->xdd_dpb, dpb, sizeof(struct dpb));
xddp->xdd_dpbsize = sizeof(struct dpb);
break;
}
/* Get extended free drive space */
case 0x03:
{
struct xfreespace FAR *xfsp = MK_FP(r->ES, r->DI);
if (r->CX < sizeof(struct xfreespace))
return DE_INVLDBUF;
rc = DosGetExtFree(MK_FP(r->DS, r->DX), xfsp);
if (rc != SUCCESS)
return rc;
xfsp->xfs_datasize = sizeof(struct xfreespace);
xfsp->xfs_version.actual = 0;
break;
}
/* Set DPB to use for formatting */
case 0x04:
{
struct xdpbforformat FAR *xdffp = MK_FP(r->ES, r->DI);
struct dpb FAR *dpb;
if (r->CX < sizeof(struct xdpbforformat))
{
return DE_INVLDBUF;
}
dpb = GetDriveDPB(r->DL, &rc);
if (rc != SUCCESS)
return rc;
xdffp->xdff_datasize = sizeof(struct xdpbforformat);
xdffp->xdff_version.actual = 0;
switch ((UWORD) xdffp->xdff_function)
{
case 0x00:
{
ULONG nfreeclst = xdffp->xdff_f.setdpbcounts.nfreeclst;
ULONG cluster = xdffp->xdff_f.setdpbcounts.cluster;
if (ISFAT32(dpb))
{
if ((dpb->dpb_xfsinfosec == 0xffff
&& (nfreeclst != 0 || cluster != 0))
|| nfreeclst == 1 || nfreeclst > dpb->dpb_xsize
|| cluster == 1 || cluster > dpb->dpb_xsize)
{
return DE_INVLDPARM;
}
dpb->dpb_xnfreeclst = nfreeclst;
dpb->dpb_xcluster = cluster;
write_fsinfo(dpb);
}
else
{
if ((unsigned)nfreeclst == 1 || (unsigned)nfreeclst > dpb->dpb_size ||
(unsigned)cluster == 1 || (unsigned)cluster > dpb->dpb_size)
{
return DE_INVLDPARM;
}
dpb->dpb_nfreeclst = (UWORD)nfreeclst;
dpb->dpb_cluster = (UWORD)cluster;
}
break;
}
case 0x01:
{
ddt *pddt = getddt(r->DL);
fmemcpy(&pddt->ddt_bpb, xdffp->xdff_f.rebuilddpb.bpbp,
sizeof(bpb));
}
case 0x02:
{
rebuild_dpb:
/* hazard: no error checking! */
flush_buffers(dpb->dpb_unit);
dpb->dpb_flags = M_CHANGED;
if (media_check(dpb) < 0)
return DE_INVLDDRV;
break;
}
case 0x03:
{
struct buffer FAR *bp;
bpb FAR *bpbp;
DWORD newmirroring =
xdffp->xdff_f.setmirroring.newmirroring;
if (newmirroring != -1
&& (ISFAT32(dpb)
&& (newmirroring & ~(0xf | 0x80))))
{
return DE_INVLDPARM;
}
xdffp->xdff_f.setmirroring.oldmirroring =
(ISFAT32(dpb) ? dpb->dpb_xflags : 0);
if (newmirroring != -1 && ISFAT32(dpb))
{
bp = getblock(1, dpb->dpb_unit);
bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT);
bp->b_flag |= BFR_VALID | BFR_DIRTY;
bpbp = (bpb FAR *) & bp->b_buffer[BT_BPB];
bpbp->bpb_xflags = (UWORD)newmirroring;
}
goto rebuild_dpb;
}
case 0x04:
{
struct buffer FAR *bp;
bpb FAR *bpbp;
DWORD rootclst = xdffp->xdff_f.setroot.newrootclst;
if (!ISFAT32(dpb)
|| (rootclst != -1
&& (rootclst == 1
|| (ULONG)rootclst > dpb->dpb_xsize)))
{
return DE_INVLDPARM;
}
xdffp->xdff_f.setroot.oldrootclst = dpb->dpb_xrootclst;
if (rootclst != -1)
{
bp = getblock(1, dpb->dpb_unit);
bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT);
bp->b_flag |= BFR_VALID | BFR_DIRTY;
bpbp = (bpb FAR *) & bp->b_buffer[BT_BPB];
bpbp->bpb_xrootclst = rootclst;
}
goto rebuild_dpb;
}
}
break;
}
/* Extended absolute disk read/write */
/* TODO(vlp) consider using of the 13-14th bits of SI */
case 0x05:
{
struct HugeSectorBlock FAR *SectorBlock =
(struct HugeSectorBlock FAR *)MK_FP(r->DS, r->BX);
UBYTE mode;
if (r->CX != 0xffff || ((r->SI & 1) == 0 && r->SI != 0)
|| (r->SI & ~0x6001))
{
return DE_INVLDPARM;
}
if (r->DL > lastdrive || r->DL == 0)
return -0x207;
if (r->SI == 0)
mode = DSKREADINT25;
else
mode = DSKWRITEINT26;
r->AX =
dskxfer(r->DL - 1, SectorBlock->blkno, SectorBlock->buf,
SectorBlock->nblks, mode);
if (mode == DSKWRITEINT26)
if (r->AX <= 0)
setinvld(r->DL - 1);
if (r->AX > 0)
return -0x20c;
break;
}
default:
return DE_INVLDFUNC;
}
return SUCCESS;
}
#endif
VOID ASMCFUNC int21_service(iregs FAR * r)
{
COUNT rc;
long lrc;
lregs lr; /* 8 local registers (ax, bx, cx, dx, si, di, ds, es) */
#define FP_DS_DX (MK_FP(lr.DS, lr.DX))
#define FP_ES_DI (MK_FP(lr.ES, lr.DI))
#define CLEAR_CARRY_FLAG() r->FLAGS &= ~FLG_CARRY
#define SET_CARRY_FLAG() r->FLAGS |= FLG_CARRY
((psp FAR *) MK_FP(cu_psp, 0))->ps_stack = (BYTE FAR *) r;
fmemcpy(&lr, r, sizeof(lregs) - 4);
lr.DS = r->DS;
lr.ES = r->ES;
dispatch:
#ifdef DEBUG
if (bDumpRegs)
{
fmemcpy(&error_regs, user_r, sizeof(iregs));
printf("System call (21h): %02x\n", user_r->AX);
dump_regs = TRUE;
dump();
}
#endif
if ((lr.AH >= 0x38 && lr.AH <= 0x4F) || (lr.AH >= 0x56 && lr.AH <= 0x5c) ||
(lr.AH >= 0x5e && lr.AH <= 0x60) || (lr.AH >= 0x65 && lr.AH <= 0x6a) ||
lr.AH == 0x6c)
{
CLEAR_CARRY_FLAG();
if (lr.AH != 0x59)
CritErrCode = SUCCESS;
}
/* Clear carry by default for these functions */
/* Check for Ctrl-Break */
if (break_ena || (lr.AH >= 1 && lr.AH <= 5) || (lr.AH >= 8 && lr.AH <= 0x0b))
check_handle_break(&syscon);
/* The dispatch handler */
switch (lr.AH)
{
/* int 21h common error handler */
case 0x64:
goto error_invalid;
/* case 0x00: --> Simulate a DOS-4C-00 */
/* Read Keyboard with Echo */
case 0x01:
DOS_01:
lr.AL = read_char_stdin(TRUE);
write_char_stdout(lr.AL);
break;
/* Display Character */
case 0x02:
DOS_02:
lr.AL = lr.DL;
write_char_stdout(lr.AL);
break;
/* Auxiliary Input */
case 0x03:
{
int sft_idx = get_sft_idx(STDAUX);
lr.AL = read_char(sft_idx, sft_idx, TRUE);
break;
}
/* Auxiliary Output */
case 0x04:
write_char(lr.DL, get_sft_idx(STDAUX));
break;
/* Print Character */
case 0x05:
write_char(lr.DL, get_sft_idx(STDPRN));
break;
/* Direct Console I/O */
case 0x06:
DOS_06:
if (lr.DL != 0xff)
goto DOS_02;
lr.AL = 0x00;
r->FLAGS |= FLG_ZERO;
if (StdinBusy())
break;
r->FLAGS &= ~FLG_ZERO;
/* fall through */
/* Direct Console Input */
case 0x07:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -