📄 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_STRINGSBYTE *RcsId = "$Id: inthndlr.c,v 1.96 2006/05/20 20:50:44 mceric Exp $";#endif#ifdef TSCSTATIC 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 argsusedVOID 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); /* if it doesn't look like an extended DPB, fill in those fields */ if (!ISFAT32(dpb) && dpb->dpb_xsize != dpb->dpb_size) { xddp->xdd_dpb.dpb_nfreeclst_un.dpb_nfreeclst_st.dpb_nfreeclst_hi = (dpb->dpb_nfreeclst == 0xFFFF ? 0xFFFF : 0); dpb16to32(&xddp->xdd_dpb); xddp->xdd_dpb.dpb_xfatsize = dpb->dpb_fatsize; xddp->xdd_dpb.dpb_xcluster = (dpb->dpb_cluster == 0xFFFF ? 0xFFFFFFFFuL : dpb->dpb_cluster); } 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;}#endifVOID 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()) { DosIdle_int(); break; } r->FLAGS &= ~FLG_ZERO; /* fall through */ /* Direct Console Input */ case 0x07: DOS_07: lr.AL = read_char_stdin(FALSE); break; /* Read Keyboard Without Echo */ case 0x08: DOS_08: lr.AL = read_char_stdin(TRUE); break; /* Display String */ case 0x09: { unsigned char c; unsigned char FAR *bp = FP_DS_DX; while ((c = *bp++) != '$')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -