From b4d8701d5cb9bb9a97aec6f59bb19b4e4958f290 Mon Sep 17 00:00:00 2001 From: Kenneth J Davis Date: Sun, 20 Nov 2005 16:52:45 +0000 Subject: [PATCH] initial BIOS disk int 13h wrapper, only passively detects and notes floppy disk change git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/branches/UNSTABLE@1154 6ac86273-5f31-0410-b378-82cca8765d1b --- kernel/int2f.asm | 2 + kernel/inthndlr.c | 106 ++++++++++++++++++++++++++++++++++++++++++++-- kernel/kernel.asm | 28 ++++++++++++ kernel/main.c | 81 +++++++++++++++++++++++++++++------ 4 files changed, 199 insertions(+), 18 deletions(-) diff --git a/kernel/int2f.asm b/kernel/int2f.asm index 465a5cb..75b3333 100644 --- a/kernel/int2f.asm +++ b/kernel/int2f.asm @@ -56,6 +56,8 @@ FarTabRetn: Int2f3: cmp ah,12h je IntDosCal ; Dos Internal calls + cmp ah,13h + je IntDosCal ; Install Int13h Hook cmp ah,16h je IntDosCal ; Win (Multitasking) Hook cmp ah,46h diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c index 8f23df3..02cf373 100644 --- a/kernel/inthndlr.c +++ b/kernel/inthndlr.c @@ -41,7 +41,7 @@ BYTE *RcsId = #ifdef TSC STATIC VOID StartTrace(VOID); -static bTraceNext = FALSE; +STATIC bTraceNext = FALSE; #endif #if 0 /* Very suspicious, passing structure by value?? @@ -1703,6 +1703,9 @@ struct int2f12regs { xreg callerARG1; /* used if called from INT2F/12 */ }; +extern intvec BIOSInt13, UserInt13, BIOSInt19; + + /* WARNING: modifications in `r' are used outside of int2F_12_handler() * On input r.AX==0x12xx, 0x4A01 or 0x4A02 * also handle Windows' DOS notification hooks, r.AH==0x16 @@ -1733,6 +1736,17 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs r) r.BX = size; return; } + else if (r.AH == 0x13) /* set disk interrupt (13h) handler */ + { + /* set new values for int13h calls, and must return old values */ + register intvec tmp = UserInt13; + UserInt13 = MK_FP(r.ds, r.DX); /* int13h handler to use */ + r.ds = FP_SEG(tmp); r.DX = FP_OFF(tmp); + tmp = BIOSInt13; + BIOSInt13 = MK_FP(r.es, r.BX); /* int13h handler to restore on reboot */ + r.es = FP_SEG(tmp); r.BX = FP_OFF(tmp); + return; + } else if (r.AH == 0x16) /* Window/Multitasking hooks */ { #ifdef WIN31SUPPORT /* See "DOS Internals" or RBIL under DOSMGR for details */ @@ -1915,9 +1929,8 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs r) case 0x80: /* Win Release Time-slice */ { /* This function is generally only called in idle loops */ - enable; /* enable interrupts */ - // __emit__(0xf4); /* halt */ - asm hlt; + __emit__(0xfb); /* sti; enable interrupts */ + __emit__(0xf4); /* hlt; halt until interrupt */ r.AX = 0; /* DebugPrintf(("Release Time Slice\n")); */ break; @@ -2259,6 +2272,91 @@ error_exit: r.FLAGS |= FLG_CARRY; } + +/* how registers pushed on stack prior to calling int wrapper function, + when returns these are then popped off, so any changes to these + will effectively set the returned value in these registers + */ +struct intXXregs { +#ifdef I386 + /* preserved 386+ only registers, compiler specific */ +#endif + UWORD es, ds; + UWORD di, si, bp; + xreg b, d, c, a; + UWORD intreq; /* which interrupt filter request for */ + UWORD flags; /* flags duplicated, one pushed by int call ignored */ + xreg param; + UWORD ip, cs , oflags; + /* top item of int caller's stack, possibly additional params */ +}; + + +/* additional processing for various wrapped/filtered interrupts + WARNING: this function also called during kernel init phase + -- int 13h + filter for BIOS int13h support, only called on int13h error + for ms-dos compatibility this should at minimal + watch for disk-change notification and set internal status + (may be called multiple times in row when BIOS reports same + change multiple times, ie delays clearing disk change status) + TODO: move DMA bounday check from int25/26 to here + Note: use stored user (usually BIOS) hooked int13 handler + -- int 19h + clean up prior to a warm reboot + for ms compatibility this should at a minimal + restore original (or indicated as original) BIOS int13h handler + and any others that may be hooked (including this one) + if himem loaded clear high memory area (clear vdisk signature so himem loads) + */ +VOID ASMCFUNC intXX_filter(struct intXXregs r) +{ + DebugPrintf(("int %02xh filter\n", r.intreq)); + switch(r.intreq) + { + case 0x19: /* reboot via bootstrap */ + { + setvec(0x13, BIOSInt13); + setvec(0x19, BIOSInt19); + + /* clear vdisk signature if kernel loaded in hma */ + if (version_flags & 0x10) + fmemset(MK_FP(0xffff, 0x0010),0,512); + break; + } + case 0x13: /* error with disk handler */ + { + DebugPrintf(("disk error %i [ah=%x] (drive %x)\n", r.a.b.h, r.param.b.h, r.param.b.l)); + DebugPrintf(("bx==(%x) cx==(%x) dx==(%x)\n", r.BX, r.CX, r.DX)); + /* currently just marks floppy as changed on disk change error */ + if ((r.a.b.h == 0x06) && (r.param.b.l < 0x80)) /* diskchange and is it a floppy? */ + { + register int i; + + /* mark floppy as changed */ + for(i=0; i < blk_dev.dh_name[0]; i++) + { + ddt *pddt = getddt(i); + if (pddt->ddt_driveno == r.param.b.l) + { + DebugPrintf(("ddt[%i] match, flags=%04x\n", i, pddt->ddt_descflags)); + if ((pddt->ddt_descflags & DF_CHANGELINE) && /* drive must have changeline support */ + (pddt->ddt_descflags & DF_CURBPBLOCK)) /* and BPB not currently locked (in-use) */ + pddt->ddt_descflags |= DF_DISKCHANGE; + /* or get dpb pointer from ddt and set dpbp->dpb_flags = M_CHANGED; */ + } + } + } + break; + } + default: + DebugPrintf(("INT_ERROR!\n")); + break; + } +} + + + /* * 2000/09/04 Brian Reifsnyder * Modified interrupts 0x25 & 0x26 to return more accurate error codes. diff --git a/kernel/kernel.asm b/kernel/kernel.asm index 19fe35c..b95cf78 100644 --- a/kernel/kernel.asm +++ b/kernel/kernel.asm @@ -652,6 +652,22 @@ _ext_open_action dw 0 ;2DD - extended open action _ext_open_attrib dw 0 ;2DF - extended open attrib _ext_open_mode dw 0 ;2E1 - extended open mode + + +; these 3 placed here so init code and int wrapper can easily access +; holds pointers to actual disk handler routines and interrupt +; vectors that we try to restore before a warm reboot + global _SAVEDIVLST +_SAVEDIVLST: + ; used by int13 handler and get/set via int 2f/13h + global _BIOSInt13 + global _UserInt13 +_BIOSInt13 dd 0 ; used to restore int13 on reboot (see int19 wrapper) +_UserInt13 dd 0 ; actual disk handler used by kernel + global _BIOSInt19 +_BIOSInt19 dd 0 ; original int19 + + ; Pad to 0620h times (300h - ($ - _internal_data)) db 0 global _szNames @@ -846,6 +862,18 @@ initforceEnableA20: global __HMARelocationTableStart __HMARelocationTableStart: + global _int13_handler + extern reloc_call_int13_handler +_int13_handler: jmp 0:reloc_call_int13_handler + call near forceEnableA20 + +#if 0 + global _int19_handler + extern reloc_call_int19_handler +_int19_handler: jmp 0:reloc_call_int19_handler + call near forceEnableA20 +#endif + global _int2f_handler extern reloc_call_int2f_handler _int2f_handler: jmp 0:reloc_call_int2f_handler diff --git a/kernel/main.c b/kernel/main.c index bff2b2f..b61a0d8 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -30,6 +30,7 @@ #include "portab.h" #include "init-mod.h" #include "dyndata.h" +#include "debug.h" #ifdef VERSION_STRINGS static BYTE *mainRcsId = @@ -48,6 +49,7 @@ STATIC VOID init_internal_devices(void); STATIC VOID update_dcb(struct dhdr FAR *); STATIC VOID init_kernel(VOID); +STATIC VOID do_fixup(VOID); STATIC VOID signon(VOID); STATIC VOID init_shell(VOID); STATIC VOID FsConfig(VOID); @@ -55,6 +57,11 @@ STATIC VOID InitPrinters(VOID); STATIC VOID InitSerialPorts(VOID); STATIC void CheckContinueBootFromHarddisk(void); STATIC void setup_int_vectors(void); +#define setup_fastprint_hook() setvec(0x29, int29_handler) /* required for printf! */ + + +void setvec(unsigned char intno, intvec vector); + #ifdef _MSC_VER BYTE _acrtused = 0; @@ -67,6 +74,7 @@ __segment DosTextSeg = 0; #endif struct lol FAR * const LoL = &DATASTART; +intvec FAR * const savedIVs = &SAVEDIVLST; void ASMCFUNC FreeDOSmain(void) { @@ -120,14 +128,25 @@ void ASMCFUNC FreeDOSmain(void) fmemcpy(&InitKernelConfig, p, sizeof InitKernelConfig); } - setup_int_vectors(); + /* printfs won't work until int29, fast console output hook is installed */ + setup_fastprint_hook(); + /* check if booting from CD before we hook too many interrupts */ CheckContinueBootFromHarddisk(); + /* display copyright info and kernel emulation status */ signon(); - init_kernel(); - init_shell(); + /* finish initial HMA segment relocation (move up until DOS=HIGH known) */ + do_fixup(); + + /* install DOS API and other interrupt service routines, basic kernel functionality works */ + setup_int_vectors(); + + /* initialize all internal variables, process CONFIG.SYS, load drivers, etc */ + init_kernel(); + + init_shell(); init_call_p_0(&Config); /* execute process 0 (the shell) */ } @@ -195,6 +214,30 @@ void setvec(unsigned char intno, intvec vector) } #endif + +/* ensures int vectors we may need to restore are saved */ +STATIC VOID save_int_vectors(VOID) +{ + /* we create far pointers otherwise compiler sets value + in initial data segment (IDATA) which does us no good. + */ + extern intvec BIOSInt13, UserInt13, BIOSInt19; /* in kernel.asm */ + intvec FAR *pBIOSInt13, FAR *pUserInt13, FAR *pBIOSInt19; + + pBIOSInt13 = MK_FP(FP_SEG(savedIVs), FP_OFF(savedIVs)); + pUserInt13 = pBIOSInt13 + 1; + pBIOSInt19 = pBIOSInt13 + 2; + + /* store for later use by our replacement int13handler */ + *pBIOSInt13 = getvec(0x13); /* save original BIOS int 0x13 handler */ + *pUserInt13 = *pBIOSInt13; /* default to it for user int 0x13 handler */ + *pBIOSInt19 = getvec(0x19); /* save reboot handler so we can clean up a little */ + + DDebugPrintf(("\n")); /* force anything printed to start on next line after BS */ + DDebugPrintf(("BIOSInt13(at %p) is %p\n", pBIOSInt13, *pBIOSInt13)); + DDebugPrintf(("BIOSInt19(at %p) is %p\n", pBIOSInt19, *pBIOSInt19)); +} + STATIC void setup_int_vectors(void) { static struct vec @@ -208,20 +251,27 @@ STATIC void setup_int_vectors(void) { 0x1, FP_OFF(empty_handler) }, /* single step */ { 0x3, FP_OFF(empty_handler) }, /* debug breakpoint */ { 0x6, FP_OFF(int6_handler) }, /* invalid opcode */ + { 0x13, FP_OFF(int13_handler) }, /* BIOS disk filter */ +#if 0 + { 0x19, FP_OFF(int19_handler) }, /* BIOS bootstrap loader, vdisk */ +#endif { 0x20, FP_OFF(int20_handler) }, - { 0x21, FP_OFF(int21_handler) }, + { 0x21, FP_OFF(int21_handler) }, /* primary DOS API */ { 0x22, FP_OFF(int22_handler) }, { 0x24, FP_OFF(int24_handler) }, - { 0x25, FP_OFF(low_int25_handler) }, + { 0x25, FP_OFF(low_int25_handler) }, /* DOS abs read/write calls */ { 0x26, FP_OFF(low_int26_handler) }, { 0x27, FP_OFF(int27_handler) }, { 0x28, FP_OFF(int28_handler) }, { 0x2a, FP_OFF(int2a_handler) }, - { 0x2f, FP_OFF(int2f_handler) } + { 0x2f, FP_OFF(int2f_handler) } /* multiplex int */ }; struct vec *pvec; int i; + save_int_vectors(); + + /* install default handlers */ for (i = 0x23; i <= 0x3f; i++) setvec(i, empty_handler); for (pvec = vectors; pvec < ENDOF(vectors); pvec++) @@ -229,7 +279,7 @@ STATIC void setup_int_vectors(void) pokeb(0, 0x30 * 4, 0xea); pokel(0, 0x30 * 4 + 1, (ULONG)cpm_entry); - /* these two are in the device driver area LOWTEXT (0x70) */ + /* handlers for int 0x1b and 0x29 are in the device driver area LOWTEXT (0x70) */ setvec(0x1b, got_cbreak); setvec(0x29, int29_handler); /* required for printf! */ } @@ -251,14 +301,8 @@ STATIC void printIRQvectors(void) } #endif -STATIC void init_kernel(void) +STATIC void do_fixup(void) { - COUNT i; - - LoL->os_setver_major = LoL->os_major = MAJOR_RELEASE; - LoL->os_setver_minor = LoL->os_minor = MINOR_RELEASE; - LoL->rev_number = REVISION_SEQ; - /* move kernel to high conventional RAM, just below the init code */ /* Note: kernel.asm actually moves and jumps here, but MoveKernel must still be called to do the necessary segment fixups */ @@ -275,6 +319,15 @@ STATIC void init_kernel(void) chunk allocated, lpTop. I.e. lpTop is top of free conv memory */ lpTop = MK_FP(FP_SEG(lpTop) - 0xfff, 0xfff0); +} + +STATIC void init_kernel(void) +{ + COUNT i; + + LoL->os_setver_major = LoL->os_major = MAJOR_RELEASE; + LoL->os_setver_minor = LoL->os_minor = MINOR_RELEASE; + LoL->rev_number = REVISION_SEQ; /* Initialize IO subsystem */ init_internal_devices();