From c4311571563bad4496c994c108ae305b2548e000 Mon Sep 17 00:00:00 2001 From: KJD Date: Sun, 14 Oct 2012 20:08:06 -0400 Subject: [PATCH] FreeDOS kernel current - 2041+svn1709 --- RELEASE.BAT | 92 + bin/autoexec.bat | 3 + bin/config.sys | 5 + bin/install.bat | 36 + boot/boot.asm | 541 +++++ boot/boot32.asm | 392 +++ boot/boot32lb.asm | 403 ++++ boot/makefile | 33 + boot/oemboot.asm | 648 +++++ build.bat | 178 ++ buildall.bat | 110 + clean.bat | 37 + clobber.bat | 38 + config.b | 119 + config.m | 65 + default.bat | 82 + docs/bugs.txt | 8 + docs/build.txt | 120 + docs/config.txt | 480 ++++ docs/contrib.txt | 44 + docs/copying | 340 +++ docs/fdkernel.lsm | 13 + docs/history.txt | 3911 ++++++++++++++++++++++++++++++ docs/intfns.txt | 198 ++ docs/lfnapi.txt | 21 + docs/mkboot.txt | 11 + docs/nls.txt | 191 ++ docs/readme.cvs | 64 + docs/readme.txt | 38 + docs/sys.txt | 223 ++ drivers/floppy.asm | 229 ++ drivers/makefile | 49 + drivers/rdpcclk.asm | 53 + drivers/wratclk.asm | 63 + drivers/wrpcclk.asm | 49 + filelist | 153 ++ hdr/algnbyte.h | 13 + hdr/algndflt.h | 7 + hdr/buffer.h | 64 + hdr/cds.h | 91 + hdr/clock.h | 47 + hdr/date.h | 57 + hdr/dcb.h | 92 + hdr/debug.h | 145 ++ hdr/device.h | 506 ++++ hdr/dirmatch.h | 54 + hdr/dsk.h | 31 + hdr/error.h | 88 + hdr/exe.h | 57 + hdr/fat.h | 152 ++ hdr/fcb.h | 120 + hdr/file.h | 81 + hdr/fnode.h | 65 + hdr/kbd.h | 48 + hdr/kconfig.h | 36 + hdr/lol.h | 91 + hdr/mcb.h | 69 + hdr/network.h | 80 + hdr/nls.h | 628 +++++ hdr/pcb.h | 172 ++ hdr/portab.h | 325 +++ hdr/process.h | 110 + hdr/sft.h | 143 ++ hdr/stacks.inc | 198 ++ hdr/tail.h | 44 + hdr/time.h | 56 + hdr/version.h | 51 + hdr/win.h | 39 + hdr/xstructs.h | 83 + kernel/apisupt.asm | 130 + kernel/asmsupt.asm | 554 +++++ kernel/blockio.c | 517 ++++ kernel/break.c | 93 + kernel/chario.c | 548 +++++ kernel/config.c | 2568 ++++++++++++++++++++ kernel/config.h | 46 + kernel/console.asm | 254 ++ kernel/country.asm | 5108 ++++++++++++++++++++++++++++++++++++++++ kernel/cpu.asm | 74 + kernel/dosfns.c | 1377 +++++++++++ kernel/dosidle.asm | 96 + kernel/dsk.c | 1088 +++++++++ kernel/dyndata.h | 19 + kernel/dyninit.c | 98 + kernel/entry.asm | 671 ++++++ kernel/error.c | 95 + kernel/execrh.asm | 95 + kernel/fatdir.c | 482 ++++ kernel/fatfs.c | 1870 +++++++++++++++ kernel/fattab.c | 413 ++++ kernel/fcbfns.c | 713 ++++++ kernel/globals.h | 429 ++++ kernel/init-dat.h | 32 + kernel/init-mod.h | 336 +++ kernel/initclk.c | 74 + kernel/initdisk.c | 1401 +++++++++++ kernel/inithma.c | 410 ++++ kernel/initoem.c | 73 + kernel/int2f.asm | 539 +++++ kernel/inthndlr.c | 2086 ++++++++++++++++ kernel/intr.asm | 324 +++ kernel/io.asm | 593 +++++ kernel/io.inc | 60 + kernel/ioctl.c | 274 +++ kernel/iprf.c | 6 + kernel/irqstack.asm | 246 ++ kernel/kernel.asm | 1052 +++++++++ kernel/kernel.cfg | 14 + kernel/lfnapi.c | 364 +++ kernel/ludivmul.inc | 112 + kernel/main.c | 782 ++++++ kernel/makefile | 165 ++ kernel/memdisk.asm | 79 + kernel/memmgr.c | 495 ++++ kernel/misc.c | 79 + kernel/network.c | 63 + kernel/newstuff.c | 717 ++++++ kernel/nls.c | 718 ++++++ kernel/nls/001-437.hc | 111 + kernel/nls/001-437.unf | 130 + kernel/nls/001-437.up | Bin 0 -> 256 bytes kernel/nls/049-850.hc | 111 + kernel/nls/049-850.unf | 130 + kernel/nls/049-850.up | Bin 0 -> 256 bytes kernel/nls/files | 20 + kernel/nls_hc.asm | 127 + kernel/nls_load.c | 51 + kernel/nlssupt.asm | 73 + kernel/prf.c | 543 +++++ kernel/printer.asm | 244 ++ kernel/procsupt.asm | 300 +++ kernel/proto.h | 399 ++++ kernel/segs.inc | 99 + kernel/serial.asm | 182 ++ kernel/strings.c | 138 ++ kernel/sysclk.c | 173 ++ kernel/syspack.c | 123 + kernel/systime.c | 178 ++ kernel/task.c | 842 +++++++ kernel/turboc.cfg | 15 + lib/makefile | 24 + makefile | 104 + mkfiles/bc5.mak | 53 + mkfiles/generic.mak | 56 + mkfiles/mscl8.mak | 47 + mkfiles/owlinux.mak | 19 + mkfiles/tc2.mak | 53 + mkfiles/tc3.mak | 53 + mkfiles/turbocpp.mak | 53 + mkfiles/watcom.mak | 67 + share/makefile | 33 + share/share.c | 761 ++++++ share/share.hlp | 6 + sys/bin2c.c | 52 + sys/fdkrncfg.c | 482 ++++ sys/makefile | 66 + sys/sys.c | 1894 +++++++++++++++ sys/talloc.c | 225 ++ utils/echoto.bat | 12 + utils/exeflat.c | 464 ++++ utils/indent.ini | 18 + utils/makefile | 19 + utils/patchobj.c | 204 ++ utils/proto.bat | 1 + utils/relocinf.c | 162 ++ utils/rmfiles.bat | 10 + utils/wlinker.bat | 4 + 167 files changed, 50246 insertions(+) create mode 100644 RELEASE.BAT create mode 100644 bin/autoexec.bat create mode 100644 bin/config.sys create mode 100644 bin/install.bat create mode 100644 boot/boot.asm create mode 100644 boot/boot32.asm create mode 100644 boot/boot32lb.asm create mode 100644 boot/makefile create mode 100644 boot/oemboot.asm create mode 100644 build.bat create mode 100644 buildall.bat create mode 100644 clean.bat create mode 100644 clobber.bat create mode 100644 config.b create mode 100644 config.m create mode 100644 default.bat create mode 100644 docs/bugs.txt create mode 100644 docs/build.txt create mode 100644 docs/config.txt create mode 100644 docs/contrib.txt create mode 100644 docs/copying create mode 100644 docs/fdkernel.lsm create mode 100644 docs/history.txt create mode 100644 docs/intfns.txt create mode 100644 docs/lfnapi.txt create mode 100644 docs/mkboot.txt create mode 100644 docs/nls.txt create mode 100644 docs/readme.cvs create mode 100644 docs/readme.txt create mode 100644 docs/sys.txt create mode 100644 drivers/floppy.asm create mode 100644 drivers/makefile create mode 100644 drivers/rdpcclk.asm create mode 100644 drivers/wratclk.asm create mode 100644 drivers/wrpcclk.asm create mode 100644 filelist create mode 100644 hdr/algnbyte.h create mode 100644 hdr/algndflt.h create mode 100644 hdr/buffer.h create mode 100644 hdr/cds.h create mode 100644 hdr/clock.h create mode 100644 hdr/date.h create mode 100644 hdr/dcb.h create mode 100644 hdr/debug.h create mode 100644 hdr/device.h create mode 100644 hdr/dirmatch.h create mode 100644 hdr/dsk.h create mode 100644 hdr/error.h create mode 100644 hdr/exe.h create mode 100644 hdr/fat.h create mode 100644 hdr/fcb.h create mode 100644 hdr/file.h create mode 100644 hdr/fnode.h create mode 100644 hdr/kbd.h create mode 100644 hdr/kconfig.h create mode 100644 hdr/lol.h create mode 100644 hdr/mcb.h create mode 100644 hdr/network.h create mode 100644 hdr/nls.h create mode 100644 hdr/pcb.h create mode 100644 hdr/portab.h create mode 100644 hdr/process.h create mode 100644 hdr/sft.h create mode 100644 hdr/stacks.inc create mode 100644 hdr/tail.h create mode 100644 hdr/time.h create mode 100644 hdr/version.h create mode 100644 hdr/win.h create mode 100644 hdr/xstructs.h create mode 100644 kernel/apisupt.asm create mode 100644 kernel/asmsupt.asm create mode 100644 kernel/blockio.c create mode 100644 kernel/break.c create mode 100644 kernel/chario.c create mode 100644 kernel/config.c create mode 100644 kernel/config.h create mode 100644 kernel/console.asm create mode 100644 kernel/country.asm create mode 100644 kernel/cpu.asm create mode 100644 kernel/dosfns.c create mode 100644 kernel/dosidle.asm create mode 100644 kernel/dsk.c create mode 100644 kernel/dyndata.h create mode 100644 kernel/dyninit.c create mode 100644 kernel/entry.asm create mode 100644 kernel/error.c create mode 100644 kernel/execrh.asm create mode 100644 kernel/fatdir.c create mode 100644 kernel/fatfs.c create mode 100644 kernel/fattab.c create mode 100644 kernel/fcbfns.c create mode 100644 kernel/globals.h create mode 100644 kernel/init-dat.h create mode 100644 kernel/init-mod.h create mode 100644 kernel/initclk.c create mode 100644 kernel/initdisk.c create mode 100644 kernel/inithma.c create mode 100644 kernel/initoem.c create mode 100644 kernel/int2f.asm create mode 100644 kernel/inthndlr.c create mode 100644 kernel/intr.asm create mode 100644 kernel/io.asm create mode 100644 kernel/io.inc create mode 100644 kernel/ioctl.c create mode 100644 kernel/iprf.c create mode 100644 kernel/irqstack.asm create mode 100644 kernel/kernel.asm create mode 100644 kernel/kernel.cfg create mode 100644 kernel/lfnapi.c create mode 100644 kernel/ludivmul.inc create mode 100644 kernel/main.c create mode 100644 kernel/makefile create mode 100644 kernel/memdisk.asm create mode 100644 kernel/memmgr.c create mode 100644 kernel/misc.c create mode 100644 kernel/network.c create mode 100644 kernel/newstuff.c create mode 100644 kernel/nls.c create mode 100644 kernel/nls/001-437.hc create mode 100644 kernel/nls/001-437.unf create mode 100644 kernel/nls/001-437.up create mode 100644 kernel/nls/049-850.hc create mode 100644 kernel/nls/049-850.unf create mode 100644 kernel/nls/049-850.up create mode 100644 kernel/nls/files create mode 100644 kernel/nls_hc.asm create mode 100644 kernel/nls_load.c create mode 100644 kernel/nlssupt.asm create mode 100644 kernel/prf.c create mode 100644 kernel/printer.asm create mode 100644 kernel/procsupt.asm create mode 100644 kernel/proto.h create mode 100644 kernel/segs.inc create mode 100644 kernel/serial.asm create mode 100644 kernel/strings.c create mode 100644 kernel/sysclk.c create mode 100644 kernel/syspack.c create mode 100644 kernel/systime.c create mode 100644 kernel/task.c create mode 100644 kernel/turboc.cfg create mode 100644 lib/makefile create mode 100644 makefile create mode 100644 mkfiles/bc5.mak create mode 100644 mkfiles/generic.mak create mode 100644 mkfiles/mscl8.mak create mode 100644 mkfiles/owlinux.mak create mode 100644 mkfiles/tc2.mak create mode 100644 mkfiles/tc3.mak create mode 100644 mkfiles/turbocpp.mak create mode 100644 mkfiles/watcom.mak create mode 100644 share/makefile create mode 100644 share/share.c create mode 100644 share/share.hlp create mode 100644 sys/bin2c.c create mode 100644 sys/fdkrncfg.c create mode 100644 sys/makefile create mode 100644 sys/sys.c create mode 100644 sys/talloc.c create mode 100644 utils/echoto.bat create mode 100644 utils/exeflat.c create mode 100644 utils/indent.ini create mode 100644 utils/makefile create mode 100644 utils/patchobj.c create mode 100644 utils/proto.bat create mode 100644 utils/relocinf.c create mode 100644 utils/rmfiles.bat create mode 100644 utils/wlinker.bat diff --git a/RELEASE.BAT b/RELEASE.BAT new file mode 100644 index 0000000..1f15720 --- /dev/null +++ b/RELEASE.BAT @@ -0,0 +1,92 @@ +@ECHO OFF +IF "%1"=="" GOTO USAGE +REM goto to just below trunk and tags directory, assume ran in trunk directory +CD .. + +ECHO tag SVN with release version - svn copy trunk/ tags/ke%1 +svn copy https://freedos.svn.sourceforge.net/svnroot/freedos/kernel/trunk/ https://freedos.svn.sourceforge.net/svnroot/freedos/kernel/tags/ke%1 -m "Tag kernel release %1" +PAUSE +ECHO svn export to get clean tree +if EXIST SOURCE RMDIR /S /Q SOURCE > NUL +svn export https://freedos.svn.sourceforge.net/svnroot/freedos/kernel/tags/ke%1 SOURCE\ke%1 +REM svn export https://freedos.svn.sourceforge.net/svnroot/freedos/kernel/trunk SOURCE\ke%1 + +SET VERSION=%1 +SET LSMRET=SRC +SET LSMFILE=SOURCE\ke%1\docs\fdkernel.lsm +GOTO LSM +:SRC +ECHO zipping source +7z.exe a -tzip -mx9 -mpass15 -r ke%1s.zip SOURCE\* +ECHO creating APPINFO and expected packaging dir structure +ECHO using working configuration file +COPY trunk\CONFIG.BAT SOURCE\ke%1 > NUL +CD SOURCE\ke%1 + +ECHO build and packaging +SET VERSION=%1 (FAT12/FAT16) +SET FAT=16 +SET BZKRET=F16 +GOTO BZK +:F16 +SET VERSION=%1 (FAT12/FAT16/FAT32) +SET FAT=32 +SET BZKRET=F32 +GOTO BZK +:F32 +ECHO clean up +CD ..\.. +RMDIR /S /Q SOURCE > NUL +ECHO Done. +SET BZKRET= +GOTO DONE + + +:BZK +ECHO build kernel %VERSION% +CALL build.bat /D KERNEL_VERSION /V "%1 " 86 upx fat%FAT% +DEL BIN\K??86??.sys +SET LSMRET=BZK_2 +SET LSMFILE=docs\fdkernel.lsm +GOTO LSM +:BZK_2 +SET LSMRET= +ECHO zipping FAT%FAT% release version +7z.exe a -tzip -mx9 -mpass15 -r ..\..\ke%1_86f%FAT%.zip BIN\* DOCS\* +ECHO restructuring and zipping update package +DEL BIN\K??86??.* > NUL +MKDIR DOC +MKDIR DOC\KERNEL +COPY DOCS\* DOC\KERNEL\ +MKDIR APPINFO +MOVE DOC\KERNEL\*.lsm APPINFO\ +7z.exe a -tzip -mx9 -mpass15 -r ..\..\kernel%FAT%.zip APPINFO\* BIN\* DOC\* +ECHO cleaning up between builds +CALL clobber.bat +RMDIR /S /Q DOC +RMDIR /S /Q APPINFO +GOTO %BZKRET% + +:LSM +ECHO Begin3>%LSMFILE% +ECHO Title: The FreeDOS Kernel>>%LSMFILE% +ECHO Version: %VERSION%>>%LSMFILE% +ECHO Entered-date: %DATE%>>%LSMFILE% +ECHO Description: The FreeDOS Kernel>>%LSMFILE% +ECHO Keywords: kernel, FreeDOS, DOS, MSDOS>>%LSMFILE% +ECHO Author: (developers: can be reached on the freedos-kernel mailing list)>>%LSMFILE% +ECHO Maintained-by: freedos-kernel@lists.sourceforge.net>>%LSMFILE% +ECHO Primary-site: http://freedos.sourceforge.net/kernel/>>%LSMFILE% +ECHO Alternate-site: http://www.fdos.org/kernel/>>%LSMFILE% +ECHO Alternate-site: https://freedos.svn.sourceforge.net/svnroot/freedos>>%LSMFILE% +ECHO Original-site: http://www.gcfl.net/pub/FreeDOS/kernel>>%LSMFILE% +ECHO Platforms: DOS, FreeDOS, DOSEMU (OpenWatcom C or Turbo C, NASM, UPX)>>%LSMFILE% +ECHO Copying-policy: GPL2>>%LSMFILE% +ECHO End>>%LSMFILE% +SET LSMFILE= +SET VERSION= +GOTO %LSMRET% + +:USAGE +ECHO Tag and build release kernels - usage: RELEASE {VERSION} e.g. RELEASE 2039 +:DONE diff --git a/bin/autoexec.bat b/bin/autoexec.bat new file mode 100644 index 0000000..54f3e64 --- /dev/null +++ b/bin/autoexec.bat @@ -0,0 +1,3 @@ +@echo off +echo Welcome to FreeDOS (http://www.freedos.org)! +path=a:\ diff --git a/bin/config.sys b/bin/config.sys new file mode 100644 index 0000000..1810c89 --- /dev/null +++ b/bin/config.sys @@ -0,0 +1,5 @@ +rem dos=high +rem device=fdxms.sys (or himem.sys) +files=20 +buffers=20 +rem screen=0x12 diff --git a/bin/install.bat b/bin/install.bat new file mode 100644 index 0000000..259d09b --- /dev/null +++ b/bin/install.bat @@ -0,0 +1,36 @@ +@echo off +rem +rem Create a distribution floppy +rem +rem $Header$ + +set D=A: +if "%1" == "b:" set D=B: +if "%1" == "B:" set D=B: +if "%1" == "b" set D=B: +if "%1" == "B" set D=B: + +echo This utility will create a distribution floppy on the disk in drive %D% +pause + +rem try to transfer system files -- abort if it cannot. +sys %D% +if errorlevel 1 goto out + +rem copy remaining files +echo copying remaining files... +echo copying autoexec.bat... +copy autoexec.bat %D% +echo copying config.sys.. +copy config.sys %D% +echo copying sys.com.. +copy sys.com %D% +label %D% freedos + +rem exit methods +goto done +:out +echo Floppy creation aborted +:done +set D= + diff --git a/boot/boot.asm b/boot/boot.asm new file mode 100644 index 0000000..a7c88a6 --- /dev/null +++ b/boot/boot.asm @@ -0,0 +1,541 @@ +; +; File: +; boot.asm +; Description: +; DOS-C boot +; +; Copyright (c) 1997; +; Svante Frey +; 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. +; +; +; +--------+ 1FE0:7E00 +; |BOOT SEC| +; |RELOCATE| +; |--------| 1FE0:7C00 +; |LBA PKT | +; |--------| 1FE0:7BC0 +; |--------| 1FE0:7BA0 +; |BS STACK| +; |--------| +; |4KBRDBUF| used to avoid crossing 64KB DMA boundary +; |--------| 1FE0:63A0 +; | | +; |--------| 1FE0:3000 +; | CLUSTER| +; | LIST | +; |--------| 1FE0:2000 +; | | +; |--------| 0000:7E00 +; |BOOT SEC| overwritten by max 128k FAT buffer +; |ORIGIN | and later by max 134k loaded kernel +; |--------| 0000:7C00 +; | | +; |--------| +; |KERNEL | also used as max 128k FAT buffer +; |LOADED | before kernel loading starts +; |--------| 0060:0000 +; | | +; +--------+ + + +;%define ISFAT12 1 +;%define ISFAT16 1 + + +segment .text + +%define BASE 0x7c00 + + org BASE + +Entry: jmp short real_start + nop + +; bp is initialized to 7c00h +%define bsOemName bp+0x03 ; OEM label +%define bsBytesPerSec bp+0x0b ; bytes/sector +%define bsSecPerClust bp+0x0d ; sectors/allocation unit +%define bsResSectors bp+0x0e ; # reserved sectors +%define bsFATs bp+0x10 ; # of fats +%define bsRootDirEnts bp+0x11 ; # of root dir entries +%define bsSectors bp+0x13 ; # sectors total in image +%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc... +%define sectPerFat bp+0x16 ; # sectors in a fat +%define sectPerTrack bp+0x18 ; # sectors/track +%define nHeads bp+0x1a ; # heads +%define nHidden bp+0x1c ; # hidden sectors +%define nSectorHuge bp+0x20 ; # sectors if > 65536 +%define drive bp+0x24 ; drive number +%define extBoot bp+0x26 ; extended boot signature +%define volid bp+0x27 +%define vollabel bp+0x2b +%define filesys bp+0x36 + +%define LOADSEG 0x0060 + +%define FATBUF 0x2000 ; offset of temporary buffer for FAT + ; chain + +; Some extra variables + +;%define StoreSI bp+3h ;temp store + +;----------------------------------------------------------------------- + + times 0x3E-$+$$ db 0 + +; using bp-Entry+loadseg_xxx generates smaller code than using just +; loadseg_xxx, where bp is initialized to Entry, so bp-Entry equals 0 +%define loadsegoff_60 bp-Entry+loadseg_off +%define loadseg_60 bp-Entry+loadseg_seg + +%define LBA_PACKET bp-0x40 +%define LBA_SIZE word [LBA_PACKET] ; size of packet, should be 10h +%define LBA_SECNUM word [LBA_PACKET+2] ; number of sectors to read +%define LBA_OFF LBA_PACKET+4 ; buffer to read/write to +%define LBA_SEG LBA_PACKET+6 +%define LBA_SECTOR_0 word [LBA_PACKET+8 ] ; LBA starting sector # +%define LBA_SECTOR_16 word [LBA_PACKET+10] +%define LBA_SECTOR_32 word [LBA_PACKET+12] +%define LBA_SECTOR_48 word [LBA_PACKET+14] + +%define READBUF 0x63A0 ; max 4KB buffer (min 2KB stack), == stacktop-0x1800 +%define READADDR_OFF BP-0x60-0x1804 ; pointer within user buffer +%define READADDR_SEG BP-0x60-0x1802 + +%define PARAMS LBA_PACKET+0x10 +;%define RootDirSecs PARAMS+0x0 ; # of sectors root dir uses + +%define fat_start PARAMS+0x2 ; first FAT sector + +%define root_dir_start PARAMS+0x6 ; first root directory sector + +%define data_start PARAMS+0x0a ; first data sector + + +;----------------------------------------------------------------------- +; ENTRY +;----------------------------------------------------------------------- + +real_start: + cli + cld + xor ax, ax + mov ds, ax + mov bp, BASE + + + ; a reset should not be needed here +; int 0x13 ; reset drive + +; int 0x12 ; get memory available in AX +; mov ax, 0x01e0 +; mov cl, 6 ; move boot sector to higher memory +; shl ax, cl +; sub ax, 0x07e0 + + mov ax, 0x1FE0 + mov es, ax + mov si, bp + mov di, bp + mov cx, 0x0100 + rep movsw + jmp word 0x1FE0:cont + +loadseg_off dw 0 +loadseg_seg dw LOADSEG + +cont: + mov ds, ax + mov ss, ax + lea sp, [bp-0x60] + sti +; +; Note: some BIOS implementations may not correctly pass drive number +; in DL, however we work around this in SYS.COM by NOP'ing out the use of DL +; (formerly we checked for [drive]==0xff; update sys.c if code moves) +; + mov [drive], dl ; rely on BIOS drive number in DL + + mov LBA_SIZE, 10h + mov LBA_SECNUM,1 ; initialise LBA packet constants + mov word [LBA_SEG],ds + mov word [LBA_OFF],READBUF + + +; GETDRIVEPARMS: Calculate start of some disk areas. +; + mov si, word [nHidden] + mov di, word [nHidden+2] + add si, word [bsResSectors] + adc di, byte 0 ; DI:SI = first FAT sector + + mov word [fat_start], si + mov word [fat_start+2], di + + mov al, [bsFATs] + cbw + mul word [sectPerFat] ; DX:AX = total number of FAT sectors + + add si, ax + adc di, dx ; DI:SI = first root directory sector + mov word [root_dir_start], si + mov word [root_dir_start+2], di + + ; Calculate how many sectors the root directory occupies. + mov bx, [bsBytesPerSec] + mov cl, 5 ; divide BX by 32 + shr bx, cl ; BX = directory entries per sector + + mov ax, [bsRootDirEnts] + xor dx, dx + div bx + +; mov word [RootDirSecs], ax ; AX = sectors per root directory + push ax + + add si, ax + adc di, byte 0 ; DI:SI = first data sector + + mov [data_start], si + mov [data_start+2], di + + +; FINDFILE: Searches for the file in the root directory. +; +; Returns: +; AX = first cluster of file + + ; First, read the whole root directory + ; into the temporary buffer. + + mov ax, word [root_dir_start] + mov dx, word [root_dir_start+2] + pop di ; mov di, word [RootDirSecs] + les bx, [loadsegoff_60] ; es:bx = 60:0 + call readDisk + les di, [loadsegoff_60] ; es:di = 60:0 + + + ; Search for KERNEL.SYS file name, and find start cluster. + +next_entry: mov cx, 11 + mov si, filename + push di + repe cmpsb + pop di + mov ax, [es:di+0x1A]; get cluster number from directory entry + je ffDone + + add di, byte 0x20 ; go to next directory entry + cmp byte [es:di], 0 ; if the first byte of the name is 0, + jnz next_entry ; there is no more files in the directory + + jc boot_error ; fail if not found +ffDone: + push ax ; store first cluster number + + +; GETFATCHAIN: +; +; Reads the FAT chain and stores it in a temporary buffer in the first +; 64 kb. The FAT chain is stored an array of 16-bit cluster numbers, +; ending with 0. +; +; The file must fit in conventional memory, so it can't be larger than +; 640 kb. The sector size must be at least 512 bytes, so the FAT chain +; can't be larger than 2.5 KB (655360 / 512 * 2 = 2560). +; +; Call with: AX = first cluster in chain + + les bx, [loadsegoff_60] ; es:bx=60:0 + mov di, [sectPerFat] + mov ax, word [fat_start] + mov dx, word [fat_start+2] + call readDisk + pop ax ; restore first cluster number + + ; Set ES:DI to the temporary storage for the FAT chain. + push ds + pop es + mov ds, [loadseg_60] + mov di, FATBUF + +next_clust: stosw ; store cluster number + mov si, ax ; SI = cluster number + +%ifdef ISFAT12 + ; This is a FAT-12 disk. + +fat_12: add si, si ; multiply cluster number by 3... + add si, ax + shr si, 1 ; ...and divide by 2 + lodsw + + ; If the cluster number was even, the cluster value is now in + ; bits 0-11 of AX. If the cluster number was odd, the cluster + ; value is in bits 4-15, and must be shifted right 4 bits. If + ; the number was odd, CF was set in the last shift instruction. + + jnc fat_even + mov cl, 4 + shr ax, cl + +fat_even: and ah, 0x0f ; mask off the highest 4 bits + cmp ax, 0x0ff8 ; check for EOF + jb next_clust ; continue if not EOF + +%endif +%ifdef ISFAT16 + ; This is a FAT-16 disk. The maximal size of a 16-bit FAT + ; is 128 kb, so it may not fit within a single 64 kb segment. + +fat_16: mov dx, [loadseg_60] + add si, si ; multiply cluster number by two + jnc first_half ; if overflow... + add dh, 0x10 ; ...add 64 kb to segment value + +first_half: mov ds, dx ; DS:SI = pointer to next cluster + lodsw ; AX = next cluster + + cmp ax, 0xfff8 ; >= FFF8 = 16-bit EOF + jb next_clust ; continue if not EOF +%endif + +finished: ; Mark end of FAT chain with 0, so we have a single + ; EOF marker for both FAT-12 and FAT-16 systems. + + xor ax, ax + stosw + + push cs + pop ds + + +; loadFile: Loads the file into memory, one cluster at a time. + + les bx, [loadsegoff_60] ; set ES:BX to load address 60:0 + + mov si, FATBUF ; set DS:SI to the FAT chain + +cluster_next: lodsw ; AX = next cluster to read + or ax, ax ; EOF? + jne load_next ; no, continue + mov bl,dl ; drive (left from readDisk) + jmp far [loadsegoff_60] ; yes, pass control to kernel + +load_next: dec ax ; cluster numbers start with 2 + dec ax + + mov di, word [bsSecPerClust] + and di, 0xff ; DI = sectors per cluster + mul di + add ax, [data_start] + adc dx, [data_start+2] ; DX:AX = first sector to read + call readDisk + jmp short cluster_next + +; shows text after the call to this function. + +show: pop si + lodsb ; get character + push si ; stack up potential return address + mov ah,0x0E ; show character + int 0x10 ; via "TTY" mode + cmp al,'.' ; end of string? + jne show ; until done + ret + +boot_error: call show +; db "Error! Hit a key to reboot." + db "Error!." + + xor ah,ah + int 0x13 ; reset floppy + int 0x16 ; wait for a key + int 0x19 ; reboot the machine + + +; readDisk: Reads a number of sectors into memory. +; +; Call with: DX:AX = 32-bit DOS sector number +; DI = number of sectors to read +; ES:BX = destination buffer +; +; Returns: CF set on error +; ES:BX points one byte after the last byte read. + +readDisk: push si + + mov LBA_SECTOR_0,ax + mov LBA_SECTOR_16,dx + mov word [READADDR_SEG], es + mov word [READADDR_OFF], bx + + call show + db "." +read_next: + +;******************** LBA_READ ******************************* + + ; check for LBA support + + mov ah,041h ; + mov bx,055aah ; + mov dl, [drive] + + ; NOTE: sys must be updated if location changes!!! + test dl,dl ; don't use LBA addressing on A: + jz read_normal_BIOS ; might be a (buggy) + ; CDROM-BOOT floppy emulation + + int 0x13 + jc read_normal_BIOS + + shr cx,1 ; CX must have 1 bit set + + sbb bx,0aa55h - 1 ; tests for carry (from shr) too! + jne read_normal_BIOS + + + ; OK, drive seems to support LBA addressing + + lea si,[LBA_PACKET] + + ; setup LBA disk block + mov LBA_SECTOR_32,bx ; bx is 0 if extended 13h mode supported + mov LBA_SECTOR_48,bx + + mov ah,042h + jmp short do_int13_read + + + +read_normal_BIOS: + +;******************** END OF LBA_READ ************************ + mov cx,LBA_SECTOR_0 + mov dx,LBA_SECTOR_16 + + + ; + ; translate sector number to BIOS parameters + ; + + ; + ; abs = sector offset in track + ; + head * sectPerTrack offset in cylinder + ; + track * sectPerTrack * nHeads offset in platter + ; + mov al, [sectPerTrack] + mul byte [nHeads] + xchg ax, cx + ; cx = nHeads * sectPerTrack <= 255*63 + ; dx:ax = abs + div cx + ; ax = track, dx = sector + head * sectPertrack + xchg ax, dx + ; dx = track, ax = sector + head * sectPertrack + div byte [sectPerTrack] + ; dx = track, al = head, ah = sector + mov cx, dx + ; cx = track, al = head, ah = sector + + ; the following manipulations are necessary in order to + ; properly place parameters into registers. + ; ch = cylinder number low 8 bits + ; cl = 7-6: cylinder high two bits + ; 5-0: sector + mov dh, al ; save head into dh for bios + xchg ch, cl ; set cyl no low 8 bits + ror cl, 1 ; move track high bits into + ror cl, 1 ; bits 7-6 (assumes top = 0) + or cl, ah ; merge sector into cylinder + inc cx ; make sector 1-based (1-63) + + les bx,[LBA_OFF] + mov ax, 0x0201 +do_int13_read: + mov dl, [drive] + int 0x13 + jc boot_error ; exit on error + + mov ax, word [bsBytesPerSec] + + push di + mov si,READBUF ; copy read in sector data to + les di,[READADDR_OFF] ; user provided buffer + mov cx, ax +; shr cx, 1 ; convert bytes to word count +; rep movsw + rep movsb + pop di + +; div byte[LBA_PACKET] ; luckily 16 !! + mov cl, 4 + shr ax, cl ; adjust segment pointer by increasing + add word [READADDR_SEG], ax ; by paragraphs read in (per sector) + + add LBA_SECTOR_0, byte 1 + adc LBA_SECTOR_16, byte 0 ; DX:AX = next sector to read + dec di ; if there is anything left to read, + jnz read_next ; continue + + les bx, [READADDR_OFF] + ; clear carry: unnecessary since adc clears it + pop si + ret + + times 0x01f1-$+$$ db 0 + +filename db "KERNEL SYS",0,0 + +sign dw 0xAA55 + +%ifdef DBGPRNNUM +; DEBUG print hex digit routines +PrintLowNibble: ; Prints low nibble of AL, AX is destroyed + and AL, 0Fh ; ignore upper nibble + cmp AL, 09h ; if greater than 9, then don't base on '0', base on 'A' + jbe .printme + add AL, 7 ; convert to character A-F + .printme: + add AL, '0' ; convert to character 0-9 + mov AH,0x0E ; show character + int 0x10 ; via "TTY" mode + retn +PrintAL: ; Prints AL, AX is preserved + push AX ; store value so we can process a nibble at a time + shr AL, 4 ; move upper nibble into lower nibble + call PrintLowNibble + pop AX ; restore for other nibble + push AX ; but save so we can restore original AX + call PrintLowNibble + pop AX ; restore for other nibble + retn +PrintNumber: ; Prints (in Hex) value in AX, AX is preserved + xchg AH, AL ; high byte 1st + call PrintAL + xchg AH, AL ; now low byte + call PrintAL + retn +%endif + diff --git a/boot/boot32.asm b/boot/boot32.asm new file mode 100644 index 0000000..8ac4f3c --- /dev/null +++ b/boot/boot32.asm @@ -0,0 +1,392 @@ +; +--------+ +; | | +; | | +; |--------| 4000:0000 +; | | +; | FAT | +; | | +; |--------| 2000:0000 +; |BOOT SEC| +; |RELOCATE| +; |--------| 1FE0:0000 +; | | +; | | +; | | +; | | +; |--------| +; |BOOT SEC| +; |ORIGIN | 07C0:0000 +; |--------| +; | | +; | | +; | | +; |--------| +; |KERNEL | +; |LOADED | +; |--------| 0060:0000 +; | | +; +--------+ + +;%define MULTI_SEC_READ 1 + + +segment .text + +%define BASE 0x7c00 + + org BASE + +Entry: jmp short real_start + nop + +; bp is initialized to 7c00h +%define bsOemName bp+0x03 ; OEM label +%define bsBytesPerSec bp+0x0b ; bytes/sector +%define bsSecPerClust bp+0x0d ; sectors/allocation unit +%define bsResSectors bp+0x0e ; # reserved sectors +%define bsFATs bp+0x10 ; # of fats +%define bsRootDirEnts bp+0x11 ; # of root dir entries +%define bsSectors bp+0x13 ; # sectors total in image +%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc... +%define sectPerFat bp+0x16 ; # sectors in a fat +%define sectPerTrack bp+0x18 ; # sectors/track +%define nHeads bp+0x1a ; # heads +%define nHidden bp+0x1c ; # hidden sectors +%define nSectorHuge bp+0x20 ; # sectors if > 65536 +%define xsectPerFat bp+0x24 ; Sectors/Fat +%define xrootClst bp+0x2c ; Starting cluster of root directory +%define drive bp+0x40 ; Drive number + + times 0x5a-$+$$ db 0 + +%define LOADSEG 0x0060 + +%define FATSEG 0x2000 + +%define fat_sector bp+0x48 ; last accessed sector of the FAT + +%define loadsegoff_60 bp+loadseg_off-Entry ; FAR pointer = 60:0 +%define loadseg_60 bp+loadseg_seg-Entry + +%define fat_start bp+0x5e ; first FAT sector +%define data_start bp+0x62 ; first data sector +%define fat_secmask bp+0x66 ; number of clusters in a FAT sector - 1 +%define fat_secshift bp+0x68 ; fat_secmask+1 = 2^fat_secshift + +;----------------------------------------------------------------------- +; ENTRY +;----------------------------------------------------------------------- + +real_start: cld + cli + sub ax, ax + mov ds, ax + mov bp, 0x7c00 + + mov ax, 0x1FE0 + mov es, ax + mov si, bp + mov di, bp + mov cx, 0x0100 + rep movsw ; move boot code to the 0x1FE0:0x0000 + jmp word 0x1FE0:cont + +loadseg_off dw 0 +loadseg_seg dw LOADSEG + +cont: mov ds, ax + mov ss, ax + lea sp, [bp-0x20] + sti + mov [drive], dl ; BIOS passes drive number in DL + +; call print +; db "Loading ",0 + +; Calc Params +; Fat_Start + mov si, word [nHidden] + mov di, word [nHidden+2] + add si, word [bsResSectors] + adc di, byte 0 + + mov word [fat_start], si + mov word [fat_start+2], di + ; Data_Start + mov al, [bsFATs] + cbw + push ax + mul word [xsectPerFat+2] + add di, ax + pop ax + mul word [xsectPerFat] + add ax, si + adc dx, di + mov word[data_start], ax + mov word[data_start+2], dx +; fat_secmask + mov ax, word[bsBytesPerSec] + shr ax, 1 + shr ax, 1 + dec ax + mov word [fat_secmask], ax +; fat_secshift +; cx = temp +; ax = fat_secshift + xchg ax, cx ; cx = 0 after movsw + inc cx +secshift: inc ax + shr cx, 1 + cmp cx, 1 + jne secshift + mov byte [fat_secshift], al + dec cx + +; FINDFILE: Searches for the file in the root directory. +; +; Returns: +; DX:AX = first cluster of file + + mov word [fat_sector], cx ; CX is 0 after "dec" + mov word [fat_sector + 2], cx + + mov ax, word [xrootClst] + mov dx, word [xrootClst + 2] +ff_next_cluster: + push dx ; save cluster + push ax + call convert_cluster + jc boot_error ; EOC encountered + +ff_next_sector: + push bx ; save sector count + + les bx, [loadsegoff_60] + call readDisk + push dx ; save sector + push ax + + mov ax, [bsBytesPerSec] + + ; Search for KERNEL.SYS file name, and find start cluster. +ff_next_entry: mov cx, 11 + mov si, filename + mov di, ax + sub di, 0x20 + repe cmpsb + jz ff_done + + sub ax, 0x20 + jnz ff_next_entry + pop ax ; restore sector + pop dx + pop bx ; restore sector count + dec bx + jnz ff_next_sector +ff_find_next_cluster: + pop ax ; restore current cluster + pop dx + call next_cluster + jmp short ff_next_cluster +ff_done: + + mov ax, [es:di+0x1A-11] ; get cluster number + mov dx, [es:di+0x14-11] +c4: + sub bx, bx ; ES points to LOADSEG +c5: push dx + push ax + push bx + call convert_cluster + jc boot_success + mov di, bx + pop bx +c6: + call readDisk + dec di + jnz c6 + pop ax + pop dx + call next_cluster + jmp short c5 + +boot_error: + xor ah,ah + int 0x16 ; wait for a key + int 0x19 ; reboot the machine + +; input: +; DX:AX - cluster +; output: +; DX:AX - next cluster +; CX = 0 +; modify: +; DI +next_cluster: + push es + mov di, ax + and di, [fat_secmask] + + mov cx, [fat_secshift] +cn_loop: + shr dx,1 + rcr ax,1 + dec cx + jnz cn_loop ; DX:AX fat sector where our + ; cluster resides + ; DI - cluster index in this + ; sector + + shl di,1 ; DI - offset in the sector + shl di,1 + add ax, [fat_start] + adc dx, [fat_start+2] ; DX:AX absolute fat sector + + push bx + mov bx, FATSEG + mov es, bx + sub bx, bx + + cmp ax, [fat_sector] + jne cn1 ; if the last fat sector we + ; read was this, than skip + cmp dx,[fat_sector+2] + je cn_exit +cn1: + mov [fat_sector],ax ; save the fat sector number, + mov [fat_sector+2],dx ; we are going to read + call readDisk +cn_exit: + pop bx + mov ax, [es:di] ; DX:AX - next cluster + mov dx, [es:di + 2] ; + pop es + ret + + +boot_success: + mov bl, [drive] + jmp far [loadsegoff_60] + +; Convert cluster to the absolute sector +;input: +; DX:AX - target cluster +;output: +; DX:AX - absoulute sector +; BX - [bsSectPerClust] +;modify: +; CX +convert_cluster: + cmp dx,0x0fff + jne c3 + cmp ax,0xfff8 + jb c3 ; if cluster is EOC (carry is set), do ret + stc + ret +c3: + mov cx, dx ; sector = (cluster - 2)*clussize + + ; + data_start + sub ax, 2 + sbb cx, byte 0 ; CX:AX == cluster - 2 + mov bl, [bsSecPerClust] + sub bh, bh + xchg cx, ax ; AX:CX == cluster - 2 + mul bx ; first handle high word + ; DX must be 0 here + xchg ax, cx ; then low word + mul bx + add dx, cx ; DX:AX target sector + add ax, [data_start] + adc dx, [data_start + 2] + ret + +; prints text after call to this function. + +print_1char: + xor bx, bx ; video page 0 + mov ah, 0x0E ; else print it + int 0x10 ; via TTY mode +print: pop si ; this is the first character +print1: lodsb ; get token + push si ; stack up potential return address + cmp al, 0 ; end of string? + jne print_1char ; until done + ret ; and jump to it + +;input: +; DX:AX - 32-bit DOS sector number +; ES:BX - destination buffer +;output: +; ES:BX points one byte after the last byte read. +; DX:AX - next sector +;modify: +; ES if DI * bsBytesPerSec >= 65536, CX + +readDisk: +read_next: push dx + push ax + ; + ; translate sector number to BIOS parameters + ; + + ; + ; abs = sector offset in track + ; + head * sectPerTrack offset in cylinder + ; + track * sectPerTrack * nHeads offset in platter + ; + xchg ax, cx + mov al, [sectPerTrack] + mul byte [nHeads] + xchg ax, cx + ; cx = nHeads * sectPerTrack <= 255*63 + ; dx:ax = abs + div cx + ; ax = track, dx = sector + head * sectPertrack + xchg ax, dx + ; dx = track, ax = sector + head * sectPertrack + div byte [sectPerTrack] + ; dx = track, al = head, ah = sector + mov cx, dx + ; cx = track, al = head, ah = sector + + ; the following manipulations are necessary in order to + ; properly place parameters into registers. + ; ch = cylinder number low 8 bits + ; cl = 7-6: cylinder high two bits + ; 5-0: sector + mov dh, al ; save head into dh for bios + xchg ch, cl ; set cyl no low 8 bits + ror cl, 1 ; move track high bits into + ror cl, 1 ; bits 7-6 (assumes top = 0) + inc ah ; sector offset from 1 + or cl, ah ; merge sector into cylinder + + mov ax, 0x0201 + mov dl, [drive] + int 0x13 + + pop ax + pop dx + jnc read_ok ; jump if no error + xor ah, ah ; else, reset floppy + int 0x13 + jmp short read_next +read_ok: + add bx, word [bsBytesPerSec] + + jnc no_incr_es ; if overflow... + + mov cx, es + add ch, 0x10 ; ...add 1000h to ES + mov es, cx + +no_incr_es: + add ax,byte 1 + adc dx,byte 0 + ret + + times 0x01f1-$+$$ db 0 + +filename db "KERNEL SYS",0,0 + +sign dw 0xAA55 diff --git a/boot/boot32lb.asm b/boot/boot32lb.asm new file mode 100644 index 0000000..aa1631b --- /dev/null +++ b/boot/boot32lb.asm @@ -0,0 +1,403 @@ +; This is an LBA-enabled FreeDOS FAT32 boot sector (single sector!). +; You can use and copy source code and binaries under the terms of the +; GNU Public License (GPL), version 2 or newer. See www.gnu.org for more. + +; Based on earlier work by FreeDOS kernel hackers, modified heavily by +; Eric Auer and Jon Gentle in 7 / 2003. +; +; Features: Uses LBA and calculates all variables from BPB/EBPB data, +; thus making partition move / resize / image-restore easier. FreeDOS +; can boot from FAT32 partitions which start > 8 GB boundary with this +; boot sector. Disk geometry knowledge is not needed for booting. +; +; Windows uses 2-3 sectors for booting (sector stage, statistics sector, +; filesystem stage). Only using 1 sector for FreeDOS makes multi-booting +; of FreeDOS and Windows on the same filesystem easier. +; +; Requirements: LBA BIOS and 386 or better CPU. Use the older CHS-only +; boot sector if you want FAT32 on really old PCs (problems: you cannot +; boot from > 8 GB boundary, cannot move / resize / ... without applying +; SYS again if you use the CHS-only FAT32 boot sector). +; +; FAT12 / FAT16 hints: Use the older CHS-only boot sector unless you +; have to boot from > 8 GB. The LBA-and-CHS FAT12 / FAT16 boot sector +; needs applying SYS again after move / resize / ... a variant of that +; boot sector without CHS support but with better move / resize / ... +; support would be good for use on LBA harddisks. + + +; Memory layout for the FreeDOS FAT32 single stage boot process: + +; ... +; |-------| 1FE0:7E00 +; |BOOTSEC| +; |RELOC. | +; |-------| 1FE0:7C00 +; ... +; |-------| 2000:0200 +; | FAT | (only 1 sector buffered) +; |-------| 2000:0000 +; ... +; |-------| 0000:7E00 +; |BOOTSEC| overwritten by the kernel, so the +; |ORIGIN | bootsector relocates itself up... +; |-------| 0000:7C00 +; ... +; |-------| +; |KERNEL | maximum size 134k (overwrites bootsec origin) +; |LOADED | (holds 1 sector directory buffer before kernel load) +; |-------| 0060:0000 +; ... + +segment .text + + org 0x7c00 ; this is a boot sector + +Entry: jmp short real_start + nop + +; bp is initialized to 7c00h +; %define bsOemName bp+0x03 ; OEM label (8) +%define bsBytesPerSec bp+0x0b ; bytes/sector (dw) +%define bsSecPerClust bp+0x0d ; sectors/allocation unit (db) +%define bsResSectors bp+0x0e ; # reserved sectors (dw) +%define bsFATs bp+0x10 ; # of fats (db) +; %define bsRootDirEnts bp+0x11 ; # of root dir entries (dw, 0 for FAT32) + ; (FAT32 has root dir in a cluster chain) +; %define bsSectors bp+0x13 ; # sectors total in image (dw, 0 for FAT32) + ; (if 0 use nSectorHuge even if FAT16) +; %define bsMedia bp+0x15 ; media descriptor: fd=2side9sec, etc... (db) +; %define sectPerFat bp+0x16 ; # sectors in a fat (dw, 0 for FAT32) + ; (FAT32 always uses xsectPerFat) +%define sectPerTrack bp+0x18 ; # sectors/track +; %define nHeads bp+0x1a ; # heads (dw) +%define nHidden bp+0x1c ; # hidden sectors (dd) +; %define nSectorHuge bp+0x20 ; # sectors if > 65536 (dd) +%define xsectPerFat bp+0x24 ; Sectors/Fat (dd) + ; +0x28 dw flags (for fat mirroring) + ; +0x2a dw filesystem version (usually 0) +%define xrootClst bp+0x2c ; Starting cluster of root directory (dd) + ; +0x30 dw -1 or sector number of fs.-info sector + ; +0x32 dw -1 or sector number of boot sector backup + ; (+0x34 .. +0x3f reserved) +%define drive bp+0x40 ; Drive number +%define loadsegoff_60 bp+loadseg_off-Entry + +%define LOADSEG 0x0060 + +%define FATSEG 0x2000 + +%define fat_secshift fat_afterss-1 ; each fat sector describes 2^?? + ; clusters (db) (selfmodifying) +%define fat_sector bp+0x44 ; last accessed FAT sector (dd) + ; (overwriting unused bytes) +%define fat_start bp+0x48 ; first FAT sector (dd) + ; (overwriting unused bytes) +%define data_start bp+0x4c ; first data sector (dd) + ; (overwriting unused bytes) + + times 0x5a-$+$$ db 0 + ; not used: [0x42] = byte 0x29 (ext boot param flag) + ; [0x43] = dword serial + ; [0x47] = label (padded with 00, 11 bytes) + ; [0x52] = "FAT32",32,32,32 (not used by Windows) + ; ([0x5a] is where FreeDOS parts start) + +;----------------------------------------------------------------------- +; ENTRY +;----------------------------------------------------------------------- + +real_start: cld + cli + sub ax, ax + mov ds, ax + mov bp, 0x7c00 + + mov ax, 0x1FE0 + mov es, ax + mov si, bp + mov di, bp + mov cx, 0x0100 + rep movsw ; move boot code to the 0x1FE0:0x0000 + jmp word 0x1FE0:cont + +loadseg_off dw 0, LOADSEG + +; ------------- + +cont: mov ds, ax + mov ss, ax ; stack and BP-relative moves up, too + lea sp, [bp-0x20] + sti + mov [drive], dl ; BIOS passes drive number in DL + + mov si, msg_LoadFreeDOS + call print ; modifies AX BX SI + + +; ------------- + +; CALCPARAMS: figure out where FAT and DATA area starts +; (modifies EAX EDX, sets fat_start and data_start variables) + +calc_params: xor eax, eax + mov [fat_sector], eax ; init buffer status + + ; first, find fat_start: + mov ax, [bsResSectors] ; no movzx eax, word... needed + add eax, [nHidden] + mov [fat_start], eax ; first FAT sector + mov [data_start], eax ; (only first part of value) + + ; next, find data_start: + mov eax, [bsFATs] ; no movzx ... byte needed: + ; the 2 dw after the bsFATs db are 0 by FAT32 definition :-). + imul dword [xsectPerFat] ; (also changes edx) + add [data_start], eax ; first DATA sector + ; (adding in RAM is shorter!) + + ; finally, find fat_secshift: + mov ax, 512 ; default sector size (means default shift) + ; shift = log2(secSize) - log2(fatEntrySize) +;--- mov cl, 9-2 ; shift is 7 for 512 bytes per sector +fatss_scan: cmp ax, [bsBytesPerSec] + jz fatss_found + add ax,ax +;--- inc cx + inc word [fat_secshift] ;XXX ; initially 9-2 (byte!) + jmp short fatss_scan ; try other sector sizes +fatss_found: +;--- mov [fat_secshift], cl + +; ------------- + +; FINDFILE: Searches for the file in the root directory. +; Returns: EAX = first cluster of file + + mov eax, [xrootClst] ; root dir cluster + +ff_next_clust: push eax ; save cluster + call convert_cluster + jc boot_error ; EOC encountered + ; EDX is clust/sector, EAX is sector + +ff_next_sector: les bx, [loadsegoff_60] ; load to loadseg:0 + call readDisk +;--- push eax ; save sector + +;--- xor ax, ax ; first dir. entry in this sector + xor di, di ;XXX + + ; Search for KERNEL.SYS file name, and find start cluster. +ff_next_entry: mov cx, 11 + mov si, filename +;--- mov di, ax + repe cmpsb + jz ff_done ; note that di now is at dirent+11 + +;--- add ax, 0x20 ; next directory entry +;--- cmp ax, [bsBytesPerSec] ; end of sector reached? + add di, byte 0x20 ;XXX + and di, byte -0x20 ; 0xffe0 ;XXX + cmp di, [bsBytesPerSec] ;XXX + jnz ff_next_entry + +;--- pop eax ; restore sector + dec dx ; next sector in cluster + jnz ff_next_sector + +ff_walk_fat: pop eax ; restore current cluster + call next_cluster ; find next cluster + jmp ff_next_clust + +ff_done: push word [es:di+0x14-11] ; get cluster number HI + push word [es:di+0x1A-11] ; get cluster number LO + pop eax ; convert to 32bit + + sub bx, bx ; ES points to LOADSEG + ; (kernel -> ES:BX) + +; ------------- + +read_kernel: push eax + call convert_cluster + jc boot_success ; EOC encountered - done + ; EDX is sectors in cluster, EAX is sector + +rk_in_cluster: call readDisk + dec dx + jnz rk_in_cluster ; loop over sect. in cluster + +rk_walk_fat: pop eax + call next_cluster + jmp read_kernel + +;----------------------------------------------------------------------- + +boot_success: mov bl, [drive] + jmp far [loadsegoff_60] + +;----------------------------------------------------------------------- + +boot_error: mov si, msg_BootError + call print ; modifies AX BX SI + +wait_key: xor ah,ah + int 0x16 ; wait for a key +reboot: int 0x19 ; reboot the machine + +;----------------------------------------------------------------------- + +; given a cluster number, find the number of the next cluster in +; the FAT chain. Needs fat_secshift and fat_start. +; input: EAX - cluster +; output: EAX - next cluster + +next_cluster: push es + push di + push bx + + mov di, ax + shl di, 2 ; 32bit FAT + + push ax + mov ax, [bsBytesPerSec] + dec ax + and di, ax ; mask to sector size + pop ax + + shr eax, 7 ; e.g. 9-2 for 512 by/sect. +fat_afterss: ; selfmodifying code: previous byte is patched! + ; (to hold the fat_secshift value) + + add eax, [fat_start] ; absolute sector number now + + mov bx, FATSEG + mov es, bx + sub bx, bx + + cmp eax, [fat_sector] ; already buffered? + jz cn_buffered + mov [fat_sector],eax ; number of buffered sector + call readDisk + +cn_buffered: and byte [es:di+3],0x0f ; mask out top 4 bits + mov eax, [es:di] ; read next cluster number + + pop bx + pop di + pop es + ret + + +;----------------------------------------------------------------------- + +; Convert cluster number to the absolute sector number +; ... or return carry if EndOfChain! Needs data_start. +; input: EAX - target cluster +; output: EAX - absolute sector +; EDX - [bsSectPerClust] (byte) +; carry clear +; (if carry set, EAX/EDX unchanged, end of chain) + +convert_cluster: + cmp eax, 0x0ffffff8 ; if end of cluster chain... + jnb end_of_chain + + ; sector = (cluster-2) * clustersize + data_start + dec eax + dec eax + + movzx edx, byte [bsSecPerClust] + push edx + mul edx + pop edx + add eax, [data_start] + ; here, carry is unset (unless parameters are wrong) + ret + +end_of_chain: stc ; indicate EOC by carry + ret + +;----------------------------------------------------------------------- + +; PRINT - prints string DS:SI +; modifies AX BX SI + +printchar: xor bx, bx ; video page 0 + mov ah, 0x0e ; print it + int 0x10 ; via TTY mode +print: lodsb ; get token + cmp al, 0 ; end of string? + jne printchar ; until done + ret ; return to caller + +;----------------------------------------------------------------------- + +; Read a sector from disk, using LBA +; input: EAX - 32-bit DOS sector number +; ES:BX - destination buffer +; (will be filled with 1 sector of data) +; output: ES:BX points one byte after the last byte read. +; EAX - next sector + +readDisk: push dx + push si + push di + +read_next: push eax ; would ax be enough? + mov di, sp ; remember parameter block end + +;--- db 0x66 ; operand size override (push dword) + push byte 0 ;XXX ; other half of the 32 bits at [C] + ; (did not trust "o32 push byte 0" opcode) + push byte 0 ; [C] sector number high 32bit + push eax ; [8] sector number low 32bit + push es ; [6] buffer segment + push bx ; [4] buffer offset + push byte 1 ; [2] 1 sector (word) + push byte 16 ; [0] size of parameter block (word) + mov si, sp + mov dl, [drive] + mov ah, 42h ; disk read + int 0x13 + + mov sp, di ; remove parameter block from stack + ; (without changing flags!) + pop eax ; would ax be enough? + + jnc read_ok ; jump if no error + + push ax ; !! + xor ah, ah ; else, reset and retry + int 0x13 + pop ax ; !! + jmp read_next + +read_ok: inc eax ; next sector + add bx, word [bsBytesPerSec] + jnc no_incr_es ; if overflow... + + mov dx, es + add dh, 0x10 ; ...add 1000h to ES + mov es, dx + +no_incr_es: pop di + pop si + pop dx + ret + +;----------------------------------------------------------------------- + +msg_LoadFreeDOS db "Loading FreeDOS ",0 + + times 0x01ee-$+$$ db 0 + +msg_BootError db "No " + ; currently, only "kernel.sys not found" gives a message, + ; but read errors in data or root or fat sectors do not. + +filename db "KERNEL SYS" + +sign dw 0, 0xAA55 + ; Win9x uses all 4 bytes as magic value here. diff --git a/boot/makefile b/boot/makefile new file mode 100644 index 0000000..51c9107 --- /dev/null +++ b/boot/makefile @@ -0,0 +1,33 @@ +# +# makefile for DOS-C boot +# + + +!include "../mkfiles/generic.mak" + +production: fat12com.bin fat16com.bin fat32chs.bin fat32lba.bin oemfat12.bin oemfat16.bin + +fat12com.bin: boot.asm + $(NASM) -dISFAT12 boot.asm -l$*.lst -ofat12com.bin + +fat16com.bin: boot.asm + $(NASM) -dISFAT16 boot.asm -l$*.lst -ofat16com.bin + +fat32chs.bin: boot32.asm + $(NASM) boot32.asm -l$*.lst -ofat32chs.bin + +fat32lba.bin: boot32lb.asm + $(NASM) boot32lb.asm -l$*.lst -ofat32lba.bin + +oemfat12.bin: oemboot.asm + $(NASM) -dISFAT12 oemboot.asm -l$*.lst -ooemfat12.bin + +oemfat16.bin: oemboot.asm + $(NASM) -dISFAT16 oemboot.asm -l$*.lst -ooemfat16.bin + +clobber: clean + -$(RM) *.bin status.me + +clean: + -$(RM) *.lst *.map *.bak *.obj + diff --git a/boot/oemboot.asm b/boot/oemboot.asm new file mode 100644 index 0000000..a57bdbc --- /dev/null +++ b/boot/oemboot.asm @@ -0,0 +1,648 @@ +; +; File: +; oemboot.asm +; 2004, Kenneth J. Davis +; Copyright (c) 200?, +; Description: +; OEM boot sector for FreeDOS compatible with IBM's (R) PC-DOS, +; and Microsoft's (R) MS-DOS. It may work with older OpenDOS/DR-DOS, +; although the standard FreeDOS boot sector is needed with ver 7+ +; releases. May work with other versions of DOS that use +; IBMBIO.COM/IBMDOS.COM pair. This boot sector loads only up +; to 58 sectors (29KB) of the kernel (IBMBIO.COM) to 0x70:0 then +; jumps to it. As best I can tell, PC-DOS (and MS-DOS up to version +; 6.xx behaves similar) expects on entry for: +; ch = media id byte in the boot sector +; dl = BIOS drive booted from (0x00=A:, 0x80=C:, ...) +; ax:bx = the starting (LBA) sector of cluster 2 (ie the 1st +; data sector, which is 0x0000:0021 for FAT12) +; ?note? IBMBIO.COM/IO.SYS may use ax:bx and cluster # stored +; elsewhere (perhaps dir entry still at 0x50:0) to determine +; starting sector for full loading of kernel file. +; it also expects the boot sector (in particular the BPB) +; to still be at 0x0:7C00, the directory entry for IBMBIO.COM +; (generally first entry of first sector of the root directory) +; at 0x50:0 (DOS Data Area). The original boot sector may update +; the floppy disk parameter table (int 1Eh), but we don't so +; may fail for any systems where the changes (???) are needed. +; If the above conditions are not met, then IBMBIO.COM will +; print the not a bootable disk error message. +; +; For MS-DOS >= 7 (ie Win9x DOS) the following conditions +; must be met: +; bp = 0x7C00, ie offset boot sector loaded at +; [bp-4] = the starting (LBA) sector of cluster 2 (ie the 1st +; data sector [this is the same as ax:bx for earlier versions +; and dx:ax in Win9x boot sector] +; The starting cluster of the kernel file is stored in +; di for FAT 12/16 (where si is a don't care) and si:di +; for FAT 32. +; The values for ax,bx,cx,dx,ds and the stack do not +; seem to be important (used by IO.SYS) and so may be any value +; (though dx:ax=[data_start], cx=0, bx=0x0f00 on FAT12 or +; 0x0700 on FAT32, ds=0, ss:sp=0:7b??) + +; the boot time stack may store the original int1E floppy +; parameter table, otherwise nothing else important seems +; stored there and I am unsure if even this value is used +; beyond boot sector code. + +; +; This boot sector only supports FAT12/FAT16 as PC-DOS +; does not support FAT32 and newer FAT32 capable DOSes +; probably have different boot requirements; also do NOT +; use it to boot the FreeDOS kernel as it expects to be +; fully loaded by boot sector (> 29KB & usually to 0x60:0). +; +; WARNING: PC-DOS has additional requirements, in particular, +; it may expect that IBMBIO.COM and IBMDOS.COM be the 1st +; two entries in the root directory (even before the label) +; and that they occupy the 1st consecutive data sectors. +; Newer releases may support other positions, but still +; generally should occupy consecutive sectors. These conditions +; can usually be met by running sys on a freshly formatted +; and un-label'd disk. +; +; +; Derived From: +; boot.asm +; DOS-C boot +; +; Copyright (c) 1997, 2000-2004 +; Svante Frey, Jim Hall, Jim Tabor, Bart Oldeman, +; Tom Ehlert, Eric Auer, Luchezar Georgiev, Jon Gentle +; and Michal H. Tyc (DR-DOS adaptation, boot26dr.asm) +; All Rights Reserved +; +; This file is part of FreeDOS. +; +; 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. +; +; +; +--------+ +; | CLUSTER| +; | LIST | +; |--------| 0000:7F00 +; |LBA PKT | +; |--------| 0000:7E00 (0:BP+200) +; |BOOT SEC| contains BPB +; |ORIGIN | +; |--------| 0000:7C00 (0:BP) +; |VARS | only known is 1st data sector (start of cluster 2) +; |--------| 0000:7BFC (DS:[BP-4]) +; |STACK | minimal 256 bytes (1/2 sector) +; |- - - - | +; |KERNEL | kernel loaded here (max 58 sectors, 29KB) +; |LOADED | also used as FAT buffer +; |--------| 0070:0000 (0:0700) +; |DOS DA/ | DOS Data Area, +; |ROOT DIR| during boot contains directory entries +; |--------| 0000:0500 +; |BDA | BIOS Data Area +; +--------+ 0000:0400 +; |IVT | Interrupt Vector Table +; +--------+ 0000:0000 + +CPU 8086 ; enable assembler warnings to limit instruction set + +;%define ISFAT12 1 ; only 1 of these should be set, +;%define ISFAT16 1 ; defines which FAT is supported + +%define TRYLBAREAD 1 ; undefine to use only CHS int 13h +%define SETROOTDIR 1 ; if defined dir entry copied to 0:500 +%define LOOPONERR 1 ; if defined on error simply loop forever +;%define RETRYALWAYS 1 ; if defined retries read forever +;%define WINBOOT 1 ; use win9x kernel calling conventions (name & jmp addr) +;%define MSCOMPAT 1 ; sets default filename to MSDOS IO.SYS + +%ifdef WINBOOT ; if set also change from PC-DOS to +%ifndef MSCOMPAT ; kernel name to MS-DOS kernel name +%define MSCOMPAT +%endif +%endif + +segment .text + +%define BASE 0x7c00 ; boot sector originally at 0x0:BASE +%define LOADSEG 0x0070 ; segment to load kernel at LOADSEG:0 +%define LOADEND 0x07b0 ; limit reads to below this segment + ; LOADSEG+29KB, else data overwritten + +%define FATBUF bp-0x7500 ; offset of temporary buffer for FAT + ; chain 0:FATBUF = 0:0700 = LOADSEG:0 +%define ROOTDIR bp-0x7700 ; offset to buffer for root directory + ; entry of kernel 0:ROOTDIR +%define CLUSTLIST bp+0x0300 ; zero terminated list of clusters + ; that the kernel occupies + +; Some extra variables +; using bp-Entry+variable_name generates smaller code than using just +; variable_name, where bp is initialized to Entry, so bp-Entry equals 0 + +%define LBA_PACKET bp+0x0200 ; immediately after boot sector +%define LBA_SIZE word [LBA_PACKET] ; size of packet, should be 10h +%define LBA_SECNUM word [LBA_PACKET+2] ; number of sectors to read +%define LBA_OFF LBA_PACKET+4 ; buffer to read/write to +%define LBA_SEG LBA_PACKET+6 +%define LBA_SECTOR_0 word [LBA_PACKET+8 ] ; LBA starting sector # +%define LBA_SECTOR_16 word [LBA_PACKET+10] +%define LBA_SECTOR_32 word [LBA_PACKET+12] +%define LBA_SECTOR_48 word [LBA_PACKET+14] + +%define PARAMS LBA_PACKET+0x10 +;%define RootDirSecs PARAMS+0x0 ; # of sectors root dir uses +%define fat_start PARAMS+0x2 ; first FAT sector +;%define root_dir_start PARAMS+0x6 ; first root directory sector +%define first_cluster PARAMS+0x0a ; starting cluster of kernel file +%define data_start bp-4 ; first data sector (win9x expects here) + +;----------------------------------------------------------------------- + + + org BASE + +Entry: jmp short real_start + nop + +; bp is initialized to 7c00h +%define bsOemName bp+0x03 ; OEM label +%define bsBytesPerSec bp+0x0b ; bytes/sector +%define bsSecPerClust bp+0x0d ; sectors/allocation unit +%define bsResSectors bp+0x0e ; # reserved sectors +%define bsFATs bp+0x10 ; # of fats +%define bsRootDirEnts bp+0x11 ; # of root dir entries +%define bsSectors bp+0x13 ; # sectors total in image +%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc... +%define sectPerFat bp+0x16 ; # sectors in a fat +%define sectPerTrack bp+0x18 ; # sectors/track +%define nHeads bp+0x1a ; # heads +%define nHidden bp+0x1c ; # hidden sectors +%define nSectorHuge bp+0x20 ; # sectors if > 65536 +%define drive bp+0x24 ; drive number +%define extBoot bp+0x26 ; extended boot signature +%define volid bp+0x27 +%define vollabel bp+0x2b +%define filesys bp+0x36 + + +;----------------------------------------------------------------------- + +; times 0x3E-$+$$ db 0 +; +; Instead of zero-fill, +; initialize BPB with values suitable for a 1440 K floppy +; + db 'IBM 5.0' ; OEM label + dw 512 ; bytes per sector + db 1 ; sectors per cluster + dw 1 ; reserved sectors + db 2 ; number of FATs + dw 224 ; root directory entries + dw 80 * 36 ; total sectors on disk + db 0xF0 ; media descriptor + dw 9 ; sectors per 1 FAT copy + dw 18 ; sectors per track + dw 2 ; number of heads + dd 0 ; hidden sectors + dd 0 ; big total sectors + db 0 ; boot unit + db 0 ; reserved + db 0x29 ; extended boot record id + dd 0x12345678 ; volume serial number + db 'NO NAME '; volume label + db 'FAT12 ' ; filesystem id + +;----------------------------------------------------------------------- +; ENTRY +;----------------------------------------------------------------------- + +real_start: + cli ; disable interrupts until stack ready + cld ; all string operations increment + xor ax, ax ; ensure our segment registers ready + mov ds, ax ; cs=ds=es=ss=0x0000 + mov es, ax + mov ss, ax + mov bp, BASE + lea sp, [bp-4] ; for DOS <7 this may be [bp] + +; For compatibility, diskette parameter vector updated. +; lea di [bp+0x3E] ; use 7c3e([bp+3e]) for PC-DOS, +; ;lea di [bp] ; but 7c00([bp]) for DR-DOS 7 bug +; mov bx, 4 * 1eh ; stored at int 1E's vector +; lds si, [bx] ; fetch current int 1eh pointer +; push ds ; store original 1eh pointer at stack top +; push si ; so can restore later if needed +; +; Copy table to new location +; mov cl, 11 ; the parameter table is 11 bytes +; rep movsb ; and copy the parameter block +; mov ds, ax ; restore DS +; +; Note: make desired changes to table here +; +; Update int1E to new location +; mov [bx+2], 0 ; set to 0:bp or 0:bp+3e as appropriate +; mov word [bx], 0x7c3e ; (use 0x7c00 for DR-DOS) + + sti ; enable interrupts + +; If updated floppy parameter table then must notify BIOS +; Otherwise a reset should not be needed here. +; int 0x13 ; reset drive (AX=0) + +; +; Note: some BIOS implementations may not correctly pass drive number +; in DL, however we work around this in SYS.COM by NOP'ing out the use of DL +; (formerly we checked for [drive]==0xff; update sys.c if code moves) +; + mov [drive], dl ; rely on BIOS drive number in DL + + +; GETDRIVEPARMS: Calculate start of some disk areas. +; + mov si, word [nHidden] + mov di, word [nHidden+2] + add si, word [bsResSectors] + adc di, byte 0 ; DI:SI = first FAT sector + + mov word [fat_start], si + mov word [fat_start+2], di + + mov al, [bsFATs] + cbw + mul word [sectPerFat] ; DX:AX = total number of FAT sectors + + add si, ax + adc di, dx ; DI:SI = first root directory sector + push di ; mov word [root_dir_start+2], di + push si ; mov word [root_dir_start], si + + ; Calculate how many sectors the root directory occupies. + mov bx, [bsBytesPerSec] + mov cl, 5 ; divide BX by 32 + shr bx, cl ; BX = directory entries per sector + + mov ax, [bsRootDirEnts] + xor dx, dx + div bx ; set AX = sectors per root directory + push ax ; mov word [RootDirSecs], ax + + add si, ax + adc di, byte 0 ; DI:SI = first data sector + + mov [data_start], si + mov [data_start+2], di + + +; FINDFILE: Searches for the file in the root directory. +; +; Returns: +; AX = first cluster of file + + ; First, read the root directory into buffer. + ; into the temporary buffer. (max 29KB or overruns stuff) + + pop di ; mov di, word [RootDirSecs] + pop ax ; mov ax, word [root_dir_start] + pop dx ; mov dx, word [root_dir_start+2] + lea bx, [ROOTDIR] ; es:bx = 0:0500 + push es ; save pointer to ROOTDIR + call readDisk + pop es ; restore pointer to ROOTDIR + lea si, [ROOTDIR] ; ds:si = 0:0500 + + + ; Search for kernel file name, and find start cluster. + +next_entry: mov cx, 11 + mov di, filename + push si + repe cmpsb + pop si + mov ax, [si+0x1A]; get cluster number from directory entry + je ffDone + + add si, byte 0x20 ; go to next directory entry + jc boot_error ; fail if not found and si wraps + cmp byte [si], 0 ; if the first byte of the name is 0, + jnz next_entry ; there are no more files in the directory + +ffDone: + mov [first_cluster], ax ; store first cluster number + +%ifdef SETROOTDIR + ; copy over this portion of root dir to 0x0:500 for PC-DOS + ; (this may allow IBMBIO.COM to start in any directory entry) + lea di, [ROOTDIR] ; es:di = 0:0500 + mov cx, 32 ; limit to this 1 entry (rest don't matter) + rep movsw +%endif + +; GETFATCHAIN: +; +; Reads the FAT chain and stores it in a temporary buffer in the first +; 64 kb. The FAT chain is stored an array of 16-bit cluster numbers, +; ending with 0. +; +; The file must fit in conventional memory, so it can't be larger than +; 640 kb. The sector size must be at least 512 bytes, so the FAT chain +; can't be larger than 2.5 KB (655360 / 512 * 2 = 2560). +; +; Call with: AX = first cluster in chain + + ; Load the complete FAT into memory. The FAT can't be larger + ; than 128 kb + lea bx, [FATBUF] ; es:bx = 0:0700 + mov di, [sectPerFat] + mov ax, word [fat_start] + mov dx, word [fat_start+2] + call readDisk + + ; Set ES:DI to the temporary storage for the FAT chain. + push ds + pop es + lea di, [CLUSTLIST] + ; Set DS:0 to FAT data we loaded + mov ax, LOADSEG + mov ds, ax ; ds:0 = 0x70:0 = 0:FATBUF + + mov ax, [first_cluster] ; restore first cluster number + push ds ; store LOADSEG + +next_clust: stosw ; store cluster number + mov si, ax ; SI = cluster number + +%ifdef ISFAT12 + ; This is a FAT-12 disk. + +fat_12: add si, si ; multiply cluster number by 3... + add si, ax + shr si, 1 ; ...and divide by 2 + lodsw + + ; If the cluster number was even, the cluster value is now in + ; bits 0-11 of AX. If the cluster number was odd, the cluster + ; value is in bits 4-15, and must be shifted right 4 bits. If + ; the number was odd, CF was set in the last shift instruction. + + jnc fat_even + mov cl, 4 + shr ax, cl + +fat_even: and ah, 0x0f ; mask off the highest 4 bits + cmp ax, 0x0ff8 ; check for EOF + jb next_clust ; continue if not EOF + +%endif +%ifdef ISFAT16 + ; This is a FAT-16 disk. The maximal size of a 16-bit FAT + ; is 128 kb, so it may not fit within a single 64 kb segment. + +fat_16: mov dx, LOADSEG + add si, si ; multiply cluster number by two + jnc first_half ; if overflow... + add dh, 0x10 ; ...add 64 kb to segment value + +first_half: mov ds, dx ; DS:SI = pointer to next cluster + lodsw ; AX = next cluster + + cmp ax, 0xfff8 ; >= FFF8 = 16-bit EOF + jb next_clust ; continue if not EOF +%endif + +finished: ; Mark end of FAT chain with 0, so we have a single + ; EOF marker for both FAT-12 and FAT-16 systems. + + xor ax, ax + stosw + + push cs + pop ds + + +; loadFile: Loads the file into memory, one cluster at a time. + + pop es ; set ES:BX to load address 70:0 + xor bx, bx + + lea si, [CLUSTLIST] ; set DS:SI to the FAT chain + +cluster_next: lodsw ; AX = next cluster to read + or ax, ax ; EOF? + jne load_next ; no, continue + + ; dl set to drive by readDisk + mov ch, [bsMedia] ; ch set to media id + mov ax, [data_start+2] ; ax:bx set to 1st data sector + mov bx, [data_start] ; + mov di, [first_cluster] ; set di (si:di on FAT32) to starting cluster # +%ifdef WINBOOT + jmp LOADSEG:0x0200 ; yes, pass control to kernel +%else + jmp LOADSEG:0000 ; yes, pass control to kernel +%endif + + +; failed to boot +boot_error: +call show +; db "Error! Hit a key to reboot." + db "):." +%ifdef LOOPONERR +jmp $ +%else + + ; Note: should restore floppy paramater table address at int 0x1E + xor ah,ah + int 0x13 ; reset floppy + int 0x16 ; wait for a key + int 0x19 ; reboot the machine +%endif + + +load_next: dec ax ; cluster numbers start with 2 + dec ax + + mov di, word [bsSecPerClust] + and di, 0xff ; DI = sectors per cluster + mul di + add ax, [data_start] + adc dx, [data_start+2] ; DX:AX = first sector to read + call readDisk + jmp short cluster_next + + +; shows text after the call to this function. + +show: pop si + lodsb ; get character + push si ; stack up potential return address + mov ah,0x0E ; show character + int 0x10 ; via "TTY" mode + cmp al,'.' ; end of string? + jne show ; until done + ret + + +; readDisk: Reads a number of sectors into memory. +; +; Call with: DX:AX = 32-bit DOS sector number +; DI = number of sectors to read +; ES:BX = destination buffer +; +; Returns: CF set on error +; ES:BX points one byte after the last byte read. +; Exits early if LBA_SEG == LOADEND. + +readDisk: push si ; preserve cluster # + + mov LBA_SECTOR_0,ax + mov LBA_SECTOR_16,dx + mov word [LBA_SEG], es + mov word [LBA_OFF], bx + + call show + db "." +read_next: + +; initialize constants + mov LBA_SIZE, 10h ; LBA packet is 16 bytes + mov LBA_SECNUM,1 ; reset LBA count if error + +; limit kernel loading to 29KB, preventing stack & boot sector being overwritten + cmp word [LBA_SEG], LOADEND ; skip reading if past the end + je read_skip ; of kernel file buffer + +;******************** LBA_READ ******************************* + + ; check for LBA support + +%ifdef TRYLBAREAD + mov ah,041h ; + mov bx,055aah ; + mov dl, [drive] ; BIOS drive, 0=A:, 80=C: + test dl,dl ; don't use LBA addressing on A: + jz read_normal_BIOS ; might be a (buggy) + ; CDROM-BOOT floppy emulation + int 0x13 + jc read_normal_BIOS + + shr cx,1 ; CX must have 1 bit set + + sbb bx,0aa55h - 1 ; tests for carry (from shr) too! + jne read_normal_BIOS + ; OK, drive seems to support LBA addressing + lea si,[LBA_PACKET] + ; setup LBA disk block + mov LBA_SECTOR_32,bx ; bx is 0 if extended 13h mode supported + mov LBA_SECTOR_48,bx + + + mov ah,042h + jmp short do_int13_read +%endif + + + +read_normal_BIOS: + +;******************** END OF LBA_READ ************************ + mov cx, LBA_SECTOR_0 + mov dx, LBA_SECTOR_16 + + ; + ; translate sector number to BIOS parameters + ; + ; + ; abs = sector offset in track + ; + head * sectPerTrack offset in cylinder + ; + track * sectPerTrack * nHeads offset in platter + ; + mov al, [sectPerTrack] + mul byte [nHeads] + xchg ax, cx + ; cx = nHeads * sectPerTrack <= 255*63 + ; dx:ax = abs + div cx + ; ax = track, dx = sector + head * sectPertrack + xchg ax, dx + ; dx = track, ax = sector + head * sectPertrack + div byte [sectPerTrack] + ; dx = track, al = head, ah = sector + mov cx, dx + ; cx = track, al = head, ah = sector + + ; the following manipulations are necessary in order to + ; properly place parameters into registers. + ; ch = cylinder number low 8 bits + ; cl = 7-6: cylinder high two bits + ; 5-0: sector + mov dh, al ; save head into dh for bios + xchg ch, cl ; set cyl no low 8 bits + ror cl, 1 ; move track high bits into + ror cl, 1 ; bits 7-6 (assumes top = 0) + or cl, ah ; merge sector into cylinder + inc cx ; make sector 1-based (1-63) + + les bx,[LBA_OFF] + mov ax, 0x0201 +do_int13_read: + mov dl, [drive] + int 0x13 + +read_finished: +%ifdef RETRYALWAYS + jnc read_ok ; jump if no error + xor ah, ah ; else, reset floppy + int 0x13 +read_next_chained: + jmp short read_next ; read the same sector again +%else + jc boot_error ; exit on error +%endif + +read_ok: + mov ax, word [bsBytesPerSec] + mov cl, 4 ; adjust segment pointer by increasing + shr ax, cl + add word [LBA_SEG], ax ; by paragraphs read in (per sector) + + add LBA_SECTOR_0, byte 1 + adc LBA_SECTOR_16, byte 0 ; DX:AX = next sector to read + dec di ; if there is anything left to read, +%ifdef RETRYALWAYS + jnz read_next_chained ; continue +%else + jnz read_next ; continue +%endif + +read_skip: + mov es, word [LBA_SEG] ; load adjusted segment value + ; clear carry: unnecessary since adc clears it + pop si + ret + + times 0x01f1-$+$$ db 0 +%ifdef MSCOMPAT +filename db "IO SYS" +%else +filename db "IBMBIO COM" +%endif + db 0,0 + +sign dw 0xAA55 + diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..4c70db2 --- /dev/null +++ b/build.bat @@ -0,0 +1,178 @@ +@echo off +rem batch file to build everything +rem IF NOTHING COMPILES, CHECK IF YOUR CVS CHECKOUT USES CORRECT DOS LINEBREAKS + +if NOT "%1" == "/?" goto start +echo ":-----------------------------------------------------------------------" +echo ":- Syntax: BUILD [-r] [fat32|fat16] [msc|wc|tc|tcpp|bc] [86|186|386] " +echo ":- [debug] [lfnapi] [/L #] [/D value] [list] [upx] [win] " +echo ":- option case is significant !! " +echo ":- Note: Open Watcom (wc) is the preferred compiler " +echo ":-----------------------------------------------------------------------" +goto end + +:start + +:- assume an error until successful build +set XERROR=1 +if "%XERROR%" == "" goto noenv + +if "%1" == "-r" call clobber.bat +if "%1" == "-r" shift + +if not exist config.bat echo You must copy CONFIG.B to CONFIG.BAT and edit it to reflect your setup! +if not exist config.bat goto abort + +call config.bat +:-if "%LAST%" == "" goto noenv +set dos4g=quiet + +:----------------------------------------------------------------------- +:- following is command line handling +:- options on the commandline overwrite default settings +:----------------------------------------------------------------------- + +:loop_commandline + +if "%1" == "fat32" set XFAT=32 +if "%1" == "fat16" set XFAT=16 + +if "%1" == "msc" set COMPILER=MSCL8 +if "%1" == "wc" set COMPILER=WATCOM +if "%1" == "tc" set COMPILER=TC2 +if "%1" == "tcpp" set COMPILER=TURBOCPP +if "%1" == "bc" set COMPILER=BC + +if "%1" == "86" set XCPU=86 +if "%1" == "186" set XCPU=186 +if "%1" == "386" set XCPU=386 +if "%1" == "x86" goto setCPU + +if "%1" == "upx" set XUPX=upx --8086 --best + +if "%1" == "debug" set ALLCFLAGS=%ALLCFLAGS% -DDEBUG +if "%1" == "lfnapi" set ALLCFLAGS=%ALLCFLAGS% -DWITHLFNAPI + +if "%1" == "win" set ALLCFLAGS=%ALLCFLAGS% -DWIN31SUPPORT +if "%1" == "win" set NASMFLAGS=%NASMFLAGS% -DWIN31SUPPORT + +if "%1" == "list" set NASMFLAGS=%NASMFLAGS% -l$*.lst + +if "%1" == "/L" goto setLoadSeg +if "%1" == "/D" goto setDefine + +:nextOption +shift +if not "%1" == "" goto loop_commandline + +call default.bat +:-if "%LAST%" == "" goto noenv + +:----------------------------------------------------------------------- +:- finally - we are going to compile +:----------------------------------------------------------------------- + +echo USING OPTIONS of C=[%ALLCFLAGS%] ASM=[%NASMFLAGS%] + +echo. +echo Process UTILS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +echo. +cd utils +%MAKE% production +if errorlevel 1 goto abort-cd + +echo. +echo Process LIB ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +echo. +cd ..\lib +%MAKE% +if errorlevel 1 goto abort-cd + +echo. +echo Process DRIVERS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +echo. +cd ..\drivers +%MAKE% production +if errorlevel 1 goto abort-cd + +echo. +echo Process BOOT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +echo. +cd ..\boot +%MAKE% production +if errorlevel 1 goto abort-cd + +echo. +echo Process SYS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +echo. +cd ..\sys +%MAKE% production +if errorlevel 1 goto abort-cd +if NOT "%XUPX%" == "" %XUPX% ..\bin\sys.com + +echo. +echo Process KERNEL +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +echo. +cd ..\kernel +%MAKE% production +if errorlevel 1 goto abort-cd + +cd .. + +set XERROR= + +:- if you like, put finalizing commands (like copy to floppy) into build2.bat +if exist build2.bat call build2.bat + +echo. +echo Processing is done. +goto end + +:----------------------------------------------------------------------- + +:setLoadSeg +shift +if "%1" == "" echo you MUST specify load segment eg 0x60 with /L option +if "%1" == "" goto abort +set LOADSEG=%1 +goto nextOption + +:setCPU +shift +if "%1" == "" echo you MUST specify compiler's cpu cmd line argument, eg -5 +if "%1" == "" goto abort +set XCPU_EX=%1 +goto nextOption + +:setDefine +shift +:- Give extra compiler DEFINE flags here +if "%1" == "" echo you MUST specify value to define with /D option +if "%1" == "" echo such as /D DEBUG : extra DEBUG output +if "%1" == "" echo or /D DOSEMU : printf output goes to dosemu log +if "%1" == "" echo or /D WIN31SUPPORT : enable Win 3.x hooks +if "%1" == "" goto abort +if "%2" == "/V" goto :setDefineWithValue +set ALLCFLAGS=%ALLCFLAGS% -D%1 +set NASMFLAGS=%NASMFLAGS% -D%1 +goto nextOption + +:setDefineWithValue +set ALLCFLAGS=%ALLCFLAGS% -D%1=%3 +set NASMFLAGS=%NASMFLAGS% -D%1=%3 +shift +shift +goto nextOption + +:noenv +echo Unable to set necessary environment variables! +goto abort + +:abort-cd +cd .. + +:abort +echo Compilation was aborted! + +:end +call default.bat clearset diff --git a/buildall.bat b/buildall.bat new file mode 100644 index 0000000..088eae0 --- /dev/null +++ b/buildall.bat @@ -0,0 +1,110 @@ +@echo off +rem IF NOTHING COMPILES, CHECK IF YOUR CVS CHECKOUT USES CORRECT DOS LINEBREAKS + +:- $Id: buildall.bat 1305 2006-10-31 21:13:02Z bartoldeman $ + +:---------------------------------------------------------- +:- batch file to build _many_ KERNELS, hope build works. +:- takes 3 minutes on my(TE) Win2K/P700. your milage may vary :-) +:---------------------------------------------------------- + +if "%1" == "$SUMMARY" goto summary + +set onerror=if not "%XERROR%" == "" goto daswarwohlnix + +:***** MSCL kernels + +call config.bat +set dos4g=quiet + +if "%MS_BASE%" == "" goto no_ms +call build -r msc 386 fat16 +%ONERROR% +call build -r msc 186 fat16 +%ONERROR% +call build -r msc 86 fat16 +%ONERROR% +call build -r msc 386 fat32 +%ONERROR% +call build -r msc 186 fat32 +%ONERROR% +call build -r msc 86 fat32 +%ONERROR% +:no_ms + +:***** TC 2.01 kernels + +if "%TC2_BASE%" == "" goto no_tc +call build -r tc 186 fat16 +%ONERROR% +call build -r tc 86 fat16 +%ONERROR% +call build -r tc 186 fat32 +%ONERROR% +call build -r tc 86 fat32 +%ONERROR% +:no_tc + +:***** (Open) Watcom kernels + +if "%WATCOM%" == "" goto no_wc +call build -r wc 386 fat32 +%ONERROR% +call build -r wc 386 fat16 +%ONERROR% +call build -r wc 86 fat32 +%ONERROR% +call build -r wc 86 fat16 +%ONERROR% +:no_wc + +:***** now rebuild the default kernel + +call build -r + +:************************************************************** +:* now we build a summary of all kernels HMA size + total size +:* Yes, I know - "mit Linux waer das nicht passiert" :-) +:* at least, it's possible with standard DOS tools +:************************************************************** + +set Sumfile=bin\ksummary.txt +set TempSumfile=bin\tsummary.txt + +:****echo >%TempSumfile% Summary of all kernels build +:****echo.|date >>%TempSumfile% +:****echo.|time >>%TempSumfile% +:****for %%i in (bin\k*.map) do call %0 $SUMMARY %%i + +if exist %Sumfile% del %Sumfile% +if exist %TempSumfile% del %TempSumfile% +>ktemp.bat +for %%i in (bin\k*.map) do echo call %0 $SUMMARY %%i >>ktemp.bat +sort ktemps.bat +call ktemps.bat +del ktemp.bat +del ktemps.bat + +echo >>%Sumfile% Summary of all kernels build +echo.|date >>%Sumfile% +echo.|time >>%Sumfile% +find <%TempSumfile% "H" >>%Sumfile% +del %TempSumfile% + +set TempSumfile= +set Sumfile= +goto end + +:summary +echo H************************************************* %2 >>%TempSumfile% +find<%2 " HMA_TEXT"|find/V "HMA_TEXT_START"|find/V "HMA_TEXT_END">>%TempSumfile% +find<%2 " STACK">>%TempSumfile% +goto end + +:************* done with summary ********************************* + +:daswarwohlnix +echo Sorry, something didn't work as expected :-( +set ONERROR= + +:end diff --git a/clean.bat b/clean.bat new file mode 100644 index 0000000..d755585 --- /dev/null +++ b/clean.bat @@ -0,0 +1,37 @@ +@echo off + +:- batch file to clean everything +:- $Id: clean.bat 1181 2006-05-20 20:45:59Z mceric $ + +if not exist config.bat echo You must copy CONFIG.B to CONFIG.BAT and edit it to reflect your setup! +if not exist config.bat goto end + +call config.bat +call default.bat + +cd utils +%MAKE% clean + +cd ..\lib +%MAKE% clean + +cd ..\drivers +%MAKE% clean + +cd ..\boot +%MAKE% clean + +cd ..\sys +%MAKE% clean + +cd ..\kernel +%MAKE% clean + +cd ..\hdr +if exist *.bak del *.bak + +cd .. +if exist *.bak del *.bak + +:end +default.bat clearset diff --git a/clobber.bat b/clobber.bat new file mode 100644 index 0000000..7755e5d --- /dev/null +++ b/clobber.bat @@ -0,0 +1,38 @@ +@echo off + +:- batch file to clobber everything +:- $Id: clobber.bat 1181 2006-05-20 20:45:59Z mceric $ + +if not exist config.bat echo You must copy CONFIG.B to CONFIG.BAT and edit it to reflect your setup! +if not exist config.bat goto end + +call config.bat +call default.bat + +cd utils +%MAKE% clobber + +cd ..\lib +%MAKE% clobber + +cd ..\drivers +%MAKE% clobber + +cd ..\boot +%MAKE% clobber + +cd ..\sys +%MAKE% clobber + +cd ..\kernel +%MAKE% clobber + +cd ..\hdr +if exist *.bak del *.bak + +cd .. +if exist *.bak del *.bak +if exist status.me del status.me + +:end +default.bat clearset diff --git a/config.b b/config.b new file mode 100644 index 0000000..5fb77ee --- /dev/null +++ b/config.b @@ -0,0 +1,119 @@ +:- +:- batch file that is included in all other batch files for configuration +:- + +:-**************************************************************** +:- NOTICE! You must edit and rename this file to CONFIG.BAT! * +:-**************************************************************** + +:-********************************************************************* +:- determine your compiler settings +:- +:- you have to +:- search for XNASM - and set the path for NASM +:- search for COMPILER - and set your compiler +:- search for ??_BASE - and set the path to your compiler +:- +:-********************************************************************* + +:-********************************************************************** +:-- define NASM executable - remember - it should not be protected +:- mode DJGPP version if you're using Windows NT/2k/XP to compile +:- also: DJGPP-nasm crashes when using protected mode Borland's make +:-********************************************************************** + +set XNASM=c:\bin\nasm16 + +:********************************************************************** +:- define your COMPILER type here, pick one of them +:********************************************************************** + +:- Turbo C 2.01 +set COMPILER=TC2 +:- Turbo C++ 1.01 +:- set COMPILER=TURBOCPP +:- Turbo C 3.0 +:- set COMPILER=TC3 +:- Borland C +:- set COMPILER=BC5 +:- Microsoft C +:- set COMPILER=MSCL8 +:- Watcom C +:- set COMPILER=WATCOM + +:-********************************************************************** +:-- where is the BASE dir of your compiler(s) ?? +:-********************************************************************** + +set TC2_BASE=c:\tc201 +:- set TP1_BASE=c:\tcpp +:- set TC3_BASE=c:\tc3 +:- set BC5_BASE=c:\bc5 +:- set MS_BASE=c:\msvc + +:- if WATCOM maybe you need to set your WATCOM environment variables +:- and path +:- if not \%WATCOM% == \ goto watcom_defined +:- set WATCOM=c:\watcom +:- set PATH=%PATH%;%WATCOM%\binw +:watcom_defined + +:-********************************************************************** +:- where is UPX and which options to use? +:-********************************************************************** +set XUPX=upx --8086 --best +:- or use set XUPX= +:- if you don't want to use it + +:-********************************************************************** +:- (optionally) which linker to use: +:- (otherwise will be determined automatically) +:- +:- WARNING TLINK needs to be in your PATH! +:-********************************************************************** + +:- Turbo Link +:- set XLINK=tlink /m/c/s/l +:- Microsoft Link +:- set XLINK=d:\qb\link /ma +:- set XLINK=%MS_BASE%\bin\link /ONERROR:NOEXE /ma /nologo +:- WATCOM Link (wlinker is a batch file calling ms2wlink and wlink) +:- set XLINK=..\utils\wlinker /ma /nologo + +:- set path for Turbo Link - use OLDPATH to restore normal path +:- set OLDPATH=%PATH% +:- set PATH=%PATH%;%TC2_BASE% + +:********************************************************************** +:* optionally define your MAKE type here, if not then +:* it will be automatically determined, pick one of them +:* use MS nmake if you want to compile with MSCL +:********************************************************************** + +:- Borland MAKE +:- set MAKE=%TC2_BASE%\make +:- Watcom MAKE in MS mode +:- set MAKE=%WATCOM%\binw\wmake /ms +:- Microsoft MAKE +:- set MAKE=%MS_BASE%\bin\nmake /nologo + +:********************************************************************** +:* select your default target: required CPU and what FAT system to support +:********************************************************************** + +set XCPU=86 +:- set XCPU=186 +:- set XCPU=386 + +set XFAT=16 +:- set XFAT=32 + +:- Give extra compiler DEFINE flags here +:- such as -DDEBUG : extra DEBUG output +:- -DDOSEMU : printf output goes to dosemu log +:- set ALLCFLAGS=-DDEBUG + + +:- +:- $Id: config.b 864 2004-04-11 12:21:25Z bartoldeman $ +:- diff --git a/config.m b/config.m new file mode 100644 index 0000000..994a8ec --- /dev/null +++ b/config.m @@ -0,0 +1,65 @@ +# +# Linux cross compilation only! +# config file that is included in the main makefile for configuration +# + +#**************************************************************** +# NOTICE! If you edit you must rename this file to config.mak!* +#**************************************************************** + +#********************************************************************** +#- define NASM executable +#********************************************************************** +XNASM=nasm + +#********************************************************************** +#- where is the BASE dir of your compiler(s) ?? +#********************************************************************** + +# if WATCOM maybe you need to set your WATCOM environment variables +# and path +ifndef WATCOM + WATCOM=$(HOME)/watcom + PATH:=$(WATCOM)/binl:$(PATH) +endif + +#********************************************************************** +# where is UPX and which options to use? +#********************************************************************** +XUPX=upx --8086 --best + +# or use +#unexport XUPX +# without the # if you don't want to use it + +#********************************************************************** +# (optionally) which linker to use: +# (otherwise will be determined automatically) + +# WATCOM Link +#XLINK=wlink + +#********************************************************************* +# optionally define your MAKE type here, if not then +# it will be automatically determined, pick one of them +# use MS nmake if you want to compile with MSCL +#********************************************************************* + +# Watcom MAKE in MS mode +#MAKE=wmake -ms -h + +#********************************************************************* +# select your default target: required CPU and what FAT system to support +#********************************************************************* + +XCPU=86 +# XCPU=186 +# XCPU=386 + +XFAT=16 +# XFAT=32 + +# Give extra compiler DEFINE flags here +# such as -DDEBUG : extra DEBUG output +# -DDOSEMU : printf output goes to dosemu log +# set ALLCFLAGS=-DDEBUG diff --git a/default.bat b/default.bat new file mode 100644 index 0000000..d70dd32 --- /dev/null +++ b/default.bat @@ -0,0 +1,82 @@ +@echo off +:- $Id: default.bat 1482 2009-07-11 16:59:43Z perditionc $ + +:- with option clearset, clears all config.bat-made environment variables +:- without options, MAKE / LINK / ... are set to defaults based on COMPILER ... + +if "%1" == "clearset" goto clearset + +:----------------------------------------------------------------------- + +if not "%COMPILER%" == "" goto skip_cc + +set COMPILER=WATCOM + +echo No compiler specified, defaulting to Open Watcom + +:skip_cc + +:----------------------------------------------------------------------- + +if not "%MAKE%" == "" goto skip_make + +if "%COMPILER%" == "TC2" set MAKE=%TC2_BASE%\make +if "%COMPILER%" == "TURBOCPP" set MAKE=%TP1_BASE%\bin\make +if "%COMPILER%" == "TC3" set MAKE=%TC3_BASE%\bin\make +if "%COMPILER%" == "BC5" set MAKE=%BC5_BASE%\bin\make +if "%COMPILER%" == "WATCOM" set MAKE=wmake /ms /h +if "%COMPILER%" == "MSCL8" set MAKE=%MS_BASE%\bin\nmake /nologo + +echo Make is %MAKE%. + +:skip_make + +:----------------------------------------------------------------------- + +if not "%XLINK%" == "" goto skip_xlink + +if "%COMPILER%" == "TC2" set XLINK=%TC2_BASE%\tlink /m/c +if "%COMPILER%" == "TURBOCPP" set XLINK=%TP1_BASE%\bin\tlink /m/c +if "%COMPILER%" == "TC3" set XLINK=%TC3_BASE%\bin\tlink /m/c +if "%COMPILER%" == "BC5" set XLINK=%BC5_BASE%\bin\tlink /m/c +if "%COMPILER%" == "WATCOM" set XLINK=..\utils\wlinker /ma/nologo +if "%COMPILER%" == "MSCL8" set XLINK=%MS_BASE%\bin\link /ONERROR:NOEXE /ma /nologo + +echo Linker is %XLINK%. + +:skip_xlink + +:----------------------------------------------------------------------- + +if not "%XUPX%" == "" set UPXOPT=-U +if "%XUPX%" == "" set UPXOPT= + +goto end + +:----------------------------------------------------------------------- + +:clearset + +if not "%OLDPATH%" == "" set PATH=%OLDPATH% +if not "%OLDPATH%" == "" set OLDPATH= + +set MAKE= +set COMPILER= +set ALLCFLAGS= +set CFLAGS= +set XCPU= +set XCPU_EX= +set XFAT= +set XLINK= +set TC2_BASE= +set TP1_BASE= +set TC3_BASE= +set BC5_BASE= +set MS_BASE= +set XNASM= +set NASMFLAGS= +set XUPX= +set UPXOPT= +set LOADSEG= + +:end diff --git a/docs/bugs.txt b/docs/bugs.txt new file mode 100644 index 0000000..b28c100 --- /dev/null +++ b/docs/bugs.txt @@ -0,0 +1,8 @@ +The current bug database is available on the web at + + http://sourceforge.net/tracker/?group_id=5109&atid=105109 + +Please request an account if you want to report or +update bugs. Reading the database needs no login. + +Thanks! diff --git a/docs/build.txt b/docs/build.txt new file mode 100644 index 0000000..2b1dca3 --- /dev/null +++ b/docs/build.txt @@ -0,0 +1,120 @@ +Building on DOS or Windows: +=========================== + +To build the operating system a batch file (BUILD.BAT) is included +to make life easier. This file is in the FDKERNEL directory of the +distribution. In addition, there is a corresponding batch file +(CLEAN.BAT) to clean up the source directories. + +There is a CONFIG.B file that specifies all the paths and names of +the compiler, assembler, etc. that you want to use. You MUST copy +it to CONFIG.BAT first, then edit it to reflect your setup. + +The reason for this copying of files is that when new releases of the +kernel come out, you can extract them over your previous source, and +not have to worry about resetting up your configuration because your +CONFIG.BAT file will not get replaced! + +Building on Linux: +================== + +To cross compile on Linux you need to install Open Watcom 1.8 from +www.openwatcom.org and NASM which is probably included in your +distribution. You can then copy config.m to config.mak and adjust +for the same reasons mentioned above. + +Use the following commands: +- to build: +make all +- to build, overriding a config.mak setting, e.g.: +make all XCPU=386 +- to clean: +make clean +- to clobber (delete everything that was generated): +make clobber + +Notes: +====== +The recommended compiler and assembler at the time of writing (2009/05/19) +are OpenWatcom 1.8 and NASM 2.05.01. + +You may need to download the latest version of NASM and a C compiler +Be sure to edit the CONFIG.BAT file to reflect where you put the tools. + +You can find NASM at http://nasm.sourceforge.net. Version 0.98.36 or +later is strongly recommended. The older 0.98 will also work fine, but +any version in between is likely to fail. It's best to use a NASM +that is native to your host; that is, when compiling in Windows, use +the win32 version. The DJGPP version is less likely to run out of +memory than the DOS version. + +Optionally, the kernel can be compressed using UPX. You can find +UPX at http://upx.sourceforge.net. Simply adjust config.bat to +enable it. + +This kernel compiles with Turbo C 2.01, Turbo C++ 1.01 (now freely +available!), Turbo C 3.0, Borland C 4.51 & 5.01. It should work with +other Borland and Microsoft compilers and (Open)Watcom C. GCC can +compile the kernel but the result does *not* work (no 16-bit x86 support). + +The OpenWatcom 1.0 compiler (or later) for DOS can be downloaded at +www.openwatcom.org: you need at least the following zips from +ftp://ftp.openwatcom.org/watcom/zips/ +(see ftp://ftp.openwatcom.org/watcom/zips/layout.txt) + +cm_core_all - Core binaries (All hosts) +cm_core_dos - Core binaries (DOS host) +cm_core_doswin - Core binaries (DOS & Win hosts) +cm_clib_hdr - C runtime library header files +cm_clib_a16 - C runtime libraries (16-bit all targets) +cm_clib_d16 - C runtime libraries (16-bit DOS) +clib_a16 - C runtime libraries (16-bit all targets) +clib_d16 - C runtime libraries (16-bit DOS) +core_doswin - Core binaries (DOS & Win16 hosts) +c_doswin - C compiler (DOS & Win16 hosts) +ext_dos4gw - DOS/4GW DOS extender + +Replace "dos" by "nt" for an NT/Win9x host or "os2" for an OS/2 host. +The host needs to be a 386+ with at least 8MB of memory. + +If you feel hardy, read on to understand the directory structure. A +more complete description of the build environment is contained in a +companion book, "The FreeDOS Kernel" (ISBN: 0-87930-436-7) published +by R&D Books, an imprint of Miller Freeman of Lawrence, Kansas (USA) +and distributed in the USA and Canada by Publishers Group West. See +the file README.TXT for more details. + + +Directory Structure +------------------- + +fdkernel root directory + +-----bin holds image of distribution disk + +-----boot boot.bin (boot sector) + +-----docs documentation directory + +-----drivers DEVICE.LIB + +-----hdr common *.h files + +-----kernel The kernel itself + +-----lib LIBM.LIB and DEVICE.LIB + +-----sys SYS.COM and supporting programs + +-----utils Miscellaneous utilities + + +Organization in a nutshell +-------------------------- +Each component or group of utilities is segregated into its own +directory. In order to build that component or utility, a makefile +exists in the directory that bears the component's or utility's +basename. + +Each makefile has at least two targets, production and clean. The +target production builds the expected component or utility and the +component clean cleans up the directory for distribution. The +makefile may have at least one additional target that builds the +component. Study the makefile to better understand this. + +--------------------------------------------------------------------- + +$Id: build.txt 1387 2009-05-19 21:39:29Z bartoldeman $ + + diff --git a/docs/config.txt b/docs/config.txt new file mode 100644 index 0000000..87c525b --- /dev/null +++ b/docs/config.txt @@ -0,0 +1,480 @@ +Title: Config.sys Options + +Configuring your DOS system for use: +------------------------------------ + +When booting DOS, you will find it only supports a subset of +the devices available on many computers. To support additional +devices and advanced features, device specific driver and +memory resident software most be loaded. This allows the +kernel to be easily extended to support hardware not presently +available and take better advantage of installed hardware +without wasting resources on computers lacking it. This +software is generally loaded during the kernel initialization +phase, with details describing what to load expressed in the +file CONFIG.SYS. The FreeDOS kernel will first look for a +file named FDCONFIG.SYS, should it exist, it will will be used +instead of CONFIG.SYS; this allows the FreeDOS kernel to coexist +and be configured differently than another DOS kernel. There +are additional options available to adjust other aspects of the +kernel's behaviour. Note: some options listed below are FreeDOS +specific and will not work when using other/older DOS kernels. +Below is list of all documented FreeDOS config.sys supported +options; additional undocumented options may exist but are not +meant for normal usage. + + +BREAK +Usage: break=on|off +Set extended Control-C/Control-Break checking to on [default] or off. +When set to on, the kernel will perform the check (and invoke current +handler if pressed) prior to most int 21h calls. When set to off, +the kernel only performs the check on I/O calls using standard streams. +Example: break=off + +BUFFERS +BUFFERSHIGH +Usage: buffers=nn[,m] where nn is in range 1-99 & m is in range 1-8 +Memory buffers used by the kernel; primary[,secondary] +The secondary buffer option is available for compatibility with +other DOS kernels, but is ignored by the FreeDOS kernel. In MS DOS, +a secondary buffer can used to read-ahead data. FreeDOS does not do +this. Buffers are stored in HMA by FreeDOS, unless you select nn to +allocate more buffers than fit in HMA. If nn is smaller, unused HMA +space will be used for further buffers until something else allocates +the HMA space for something else. Even then, at least nn buffers will +always be available. You can set nn to a negative value to disable +the use of unused HMA space: BUFFERS=-10 only uses 10 buffers, further +free space in the HMA will just stay unused. Because the buffers can +use the HMA anyway, BUFFERSHIGH does the same as BUFFERS for now, but +shows a note about that to inform the user that it does not use UMB. +Example: buffers=20 + +COUNTRY +Usage: country=nnn[,[mmm][,[d:][path]file]] +Enables/sets international features of DOS by selecting a country +code and (only with the unstable / devel kernel) optionally also +a codepage and country file. The stable kernel only uses the nnn +value. For full support, use the unstable / devel kernel. You also +need a COUNTRY.SYS file for the latter, while the former ignores the +filename argument and only sets date/time/number formats, using values +compiled into the kernel for a few common countries. It does not set +sort order and upper/lower case translation tables. NLSFUNC can only +be used with the unstable kernel. +nnn is country code (001==US) +mmm is code page (437 is default, 850 is updated form, 1252 for Windows) +[drive][path]file specifies file with country specific data +Example: country=001,850,C:\FDOS\BIN\COUNTRY.SYS + +DEVICE +Usage: device=[d:][path]file [options] +Load the device driver specified by d:path\file (into conventional +[low 640KB] memory). The options are for the driver itself; refer +to documentation that came with your particular device for supported +options and their usage. +Example: device=himem.sys + +DEVICEHIGH +Usage: devicehigh=[d:][path]file [options] +This is just like device= statement, except it attempts to load +the device driver into high memory first (failing that it should +load it in conventional memory). +Note: The order you load devices may have a large impact on amount +of free memory available. In general try to load large (in memory +usage) programs into high memory first. +Important: You should have a high memory manager such as FDXMS or +HIMEM installed (prior device=FDXMS.SYS or device=HIMEM.SYS) before +using this option. +Example: devicehigh=xcdrom.sys /D:FDCD0001 + +DOS +Usage: dos=high|low,umb|noumb +Indicates whether the kernel should try to load itself into +high memory or only conventional (low), and whether to link +upper memory blocks in with normal memory or not. +Note: only one set need be given, ie dos=high and dos=noumb are ok. +Important: if you specify dos=high[,umb|noumb] then you must also +load a high memory manager (first), ie FDXMS or HIMEM +Example: dos=high,umb +Example: dos=low,noumb + +DOSDATA +Usage: dosdata=umb +Try to load kernel data into Upper Memory Blocks; effectively +same as using the [name]HIGH variant of kernel parameters, +such as fileshigh, lastdrivehigh, and stackshigh (does not +effect drivers loaded using device= or install=). +Example: dosdata=umb + +ECHO +Usage: ECHO Message to be displayed to user. +ECHO displays (echos) its arguments to the console during +config.sys processing when device drivers are loaded (when +DEVICE= lines are executed). +Example: + ECHO loading driver 1 + device=Driver1.sys + ECHO driver1 successfully loaded + +EECHO +Usage: EECHO Message with ANSI Escape Sequence +EECHO allows for echo-ing ANSI Escape Sequences +(redefines keyboard input for example). Use a dollar sign ($) +to represent the ANSI Escape character. Note: requires an +ANSI driver like NANSI loaded prior to use. +Example: EECHO feeling $[33;44;1m blue :-) + +FCBS +Usage: fcbs=nnn +where nnn is in range 1-255 +Sets the number of File Control Blocks to reserve room for. +As file control blocks have been replaced by file handles +(see files) and FreeDOS dynamically simulates FCBS from the +handle data as needed, nnn is simply ignored by FreeDOS. +Example: fcbs=4 + +FILES +FILESHIGH +Usage: files=nnn +where nnn is in range 8-255 (default 8) +Specifies how many files allowed open at once (reserves +memory necessary to support opening this many files). +Note: there are other restrictions, so a given program + may not be able to actually open this many +A good number is 20, though some programs suggest/require +30, 40, or even 255 +Example: files=20 + +IDLEHALT +Usage: idlehalt=n +where n can be -1, 0, 1 or higher (default 0) +Activates built-in kernel energy saving functionality if n is +not 0. Value -1 enables all hooks, 1 enables only "safe" hooks, +CPU halted only if kernel is waiting for CON char device input. +Further hooks for n=-1 and n>0 depend on the kernel version: +In addition to the safe hooks, other hooks can get activated, +for example one for int 0x2f, ax=0x1680 "release time slice". +Note: In rare cases, entering or leaving HLT mode (which causes + big changes in CPU power consumption) can cause crashes if + cheap power supplies or mainboards cannot properly filter + the transients. Underclocking the whole system may help. + Linux always does a few HLT at boot time, to force a hang + on buggy systems early (boot with no-hlt to disable HLT). +P90 may have buggy HLT? www.tavi.co.uk/ps2pages/ohland/halt.html + +INSTALL +INSTALLHIGH +Usage: install=[d:][path]file [options] +Load the program specified by d:path\file. Generally used to +load TSR (terminate and stay resident) programs with a minimal +environment block. The options are for the program itself; refer +to documentation that came with your particular software for +supported options and usage. +Example: install=nansi.com + +KEYBUF +Usage: keybuf=n[,m] +where n is in 0xac-0xde or 0x106-0x1de range and m is max 0x200 +Relocate keyboard buffer from the default location at +0x40:0x1e-0x3e to 0x40:n-m. The buffer must be more +than 32 bytes and must not touch offsets 0x100-0x105. +Default for m is "next multiple of 0x100 after n". +Note: Some BIOSes store data in the 0xac-0xff area. BASICA will + use the 0x106-0x120 area. Other hardware, drivers or apps + can collide with KEYBUF, too, so use it at your own risk. +A reasonably safe choice should be "keybuf=0x140,0x1c0". + +LASTDRIVE +LASTDRIVEHIGH +Usage: lastdrive=x +where x is last drive letter available for use; A-Z +Example: lastdrive=z + +MENU +Usage: menu [text] +where text is the text you want to be shown while running +config.sys. Menu displays a menu while running config.sys. +Use menudefault to set a time delayed default option. +Lines that begin with 1? will only be processed if the user +presses 1. Lines beginning with 23? will be loaded if the +user presses either 2 or 3. Options other than 0 can only +be selected if at least one "numbers?" line actually uses +them, as shown in the example below. +Example: + menu Please Select Configuration: + menu + menu Option 0 basic stuff only + menu Option 1 CD-ROM + menu Option 2 TROUSERS + menu Option 3 CD-ROM and TROUSERS + 0?echo you selected option 0 + 13?device=xcdrom.sys /D:FDCD0001 + 23?install=trousers.com + +MENUCOLOR +Usage: menucolor foreground[,background] +Use Menucolor before the menu config command, to create a +full screen menu which supports the arrow cursor keys. +The following colors can be used for foreground and background: +0=Black; 1=Blue; 2=Green; 3=Cyan; 4=Red; 5=Magenta; +6=Brown; 7=Light Gray +The following colors can only be used for the foreground: +8=Dark Gray; 9=Light Blue; 10=Light Green; 11=Light Cyan; +12=Light Red; 13=Light Magenta; 14=Yellow; 15=White. +If you do not use MENUCOLOR, the menu will not be full +screen, so some of the BIOS, bootloader and kernel init +messages (list of drives, version info...) stays visible. +To change the colour to white text on blue, use the following: +Example: menucolor 15,1 + +MENUDEFAULT +Usage: menudefault=defaultoption,delay +where delay is the delay time in seconds and defaultoption is the +used standard option if the delay time is over. Menudefault sets +a time delayed default option for a config.sys menu: If no key +has been pressed during [delay] seconds, the default choice is +activated. Pressing a key stops the countdown, the kernel will +wait infinitely for the user to make a selection. Note that some +virtual machines like Bochs can have broken (too fast) timing. +Example: menudefault=0,5 + +NUMLOCK +Usage: numlock=on|off +Set the keyboard number lock to on or off. +Example: numlock=off + +REM +Usage: rem Your remarks! +This provides the ability to place comments within the configuration +file. The text following the rem until the end of the line is +reached is ignored. This may also be used to temporarily disable +loading a particular device or other option. A synonym for REM is +the semicolon, see the examples. +Example: REM DOS=HIGH,UMB +Example: ;DOS=HIGH,UMB + +SCREEN +Usage: screen=xx +Switches into videomode xxx (INT10/11xx/000) +where xx should be 0x11 for 8x14 font (28 lines VGA, 25 lines EGA) +or 0x12 for 8x8 font (43 lines EGA, 50 lines VGA) or 0x14 for the +default VGA font (25 lines VGA). Some newer graphics cards may not +have 8x14 fonts in the BIOS. In that case, a driver can be loaded +to load a suitable font in RAM, but SCREEN=0x11 should not be used. +If xx is less than 15 (0x0f), it is treated as screen mode number, +for example 1 for CGA 40x25 color text or 7 for monochrome text. +Example: SCREEN=0x12 + +SET +Usage: set ENVVAR=value +Sets the environment variable to provided value. +Example: set HOME=C:\home\me + +SHELL +SHELLHIGH +Usage: shell=[d:][path]file [options] +Indicates the shell to use; often used to alter COMMAND.COM's behavior. +Note: it is command.com that processes AUTOEXEC.BAT; by using the +shell option, you can get command.com to process a differently named +file (such as FDAUTO.BAT for coexisting with another DOS using different +configuration options) or run a completely different command interpreter +such as 4DOS or a (unix) sh variant. +Example: shell=C:\4DOS.COM /E:256 /P +Example: SHELL=C:\FDOS\bin\command.com C:\FDOS\bin /E:1024 /P=C:\fdauto.bat + +STACKS +STACKSHIGH +Usage: stacks=nn,mmm +where nn is in range 0,8-64 and nnn is in range 32-512 +Changes number and size of hardware interrupt stacks available +nn is number of different stacks and mmm is size in bytes of each one +In some cases you can use "stacks=0,0" to use only standard stacks +instead of letting DOS allocate extra stacks for hardware interrupts. +Example: stacks=16,256 + +SWITCHAR +Usage: switchar=c +Sets the default switchar to character c. Where c is a single character +that is used to indicate a command line parameter is an option switch. +The default is a forward slash (/). Note: This simply sets the value +returned by a get switchar query, it will not effect programs that use +hardcoded switch characters. The switch character is the sign used to +mark options, for example the "/" in "DIR /w". Good values: "/" and "-". +Example: switchar=- + +SWITCHES +Usage: switches=/E[:xxx] /F /K /N /W +Adjusts boot time processing behaviour. +/E enables moving of EBDA (Extended BIOS Data Area), optionally a + size in kilobytes may be specified [xxx, in range of 48-1024] +/F skips the delay checking for F5/F8 keystroke before processing + config.sys [equivalent to SYS CONFIG skipconfigseconds=0] + F5 and F8 are only processed if pressed before DOS boots but + after the keyboard is set up - right moment is easy to miss. +/K forces treating of keyboard as 86 key keyboard, not 102/105 key. + Might be useful with BIOSes or drivers which have no or broken + handling for 102/105 key keyboards. +/N disables F5/F8 support [equivalent to kernel config (SYS CONFIG, + run SYS CONFIG /? for explanations) skipconfigseconds=-1] + F5 (skip config) and F8 (single step config.sys) are ignored. +/W is NOT supported in FreeDOS. This option in MS DOS would set a flag + for Windows 3.0 to skip loading wina20.386 from the root directory. + +VERSION +Usage: version=x.y +FreeDOS specific command to specify what DOS version to report. For +a kernel with FAT32 support, 7.10 is a good choice. Otherwise, 5.0 +and 6.22 are common values. FreeCOM command.com "ver /r" displays +both the reported and the FreeDOS internal version numbers. +Example: version=6.22 + + + +Advanced - FreeDOS specific CONFIG.SYS menu processing: +------------------------------------------------------- + +normal + FILES=20 + DEVICE=MyNetWorkDriver.sys + +'?' - ALWAYS ask if a single line shall be executed + FILES=20 + DEVICE?=MyNetWorkDriver.sys + + +'!' - NEVER ask if a single line shall be executed, even if single stepping + !FILES=20 + !DOS=HIGH,UMB + !BUFFERS=30 + !DEVICE=MyNetWorkDriver.sys + + +configuration management - you may compose several configurations, +using following special commands: + +MENU +MENU select your configuration +MENU +MENU use (1) for CDROM operation +MENU use (2) for NETWORK configuration +MENU use (3) to load neither CDROM nor NETWORK drivers +MENU +MENUDEFAULT=3,60 (configuration 3, wait 60 seconds) + +rem CDROM +1? device=CDROM.SYS + +rem NETWORK +2? device=MyNetworkDriver.SYS + +rem Menu items can only be selected if at least one line uses them: +3? echo Basic configuration selected + +Although this is different than MSDOS menuing possibilities, it +allows for selecting from multiple options during bootup while +remaining simple. It, however, does not allow for multi-level +menuing based configuration schemes. + + +It's also possible to combine menu options, to avoid writing thing every +time again. +constructions like 0?devicehigh?=cdrom.sys are also possible +("if menu option 0 chosen, ask if you want to load this driver") + +the selected configuration can be determined in AUTOEXEC.BAT in the +environment variable CONFIG like + + if %CONFIG% == 0 echo configuration 0 selected + +however, if you have no MENUs in config.sys, then %config% has no value, +thus resulting in "IF == 0 echo configuration 0 selected." +(which causes syntax errors as there's nothing on the left side of == ) + +That's why you better use something like: +if [%config%]==[0] echo configuration 0 selected. -or- +if "%config%"=="0" echo configuration 0 selected. + +then if there is no menu you have: "IF []==[0] echo configuration 0 selected." +(which will of course output nothing) + +thus my config.sys now looks like + + +!files=20 +!dos=high,umb +!break=off +!buffers=30 +!screen=0x12 +!lastdrive=z +!shell=\command.com /p /e:512 /MSG + +MENU +MENU 0 - SoftIce+HIMEM+Network (default) +MENU 1 - SoftIce+HIMEM +MENU 2 - HIMEM+EMM386 +MENU +MENUDEFAULT=0,0 + + +01? DEVICE=C:\NUMEGA\S-ICE.EXE /TRA 3000 /SYM 400 +012?DEVICE=himem.exe +01? DEVICE=UMBPCI.SYS +2? DEVICE=EMM386.EXE NOEMS + +0?device=c:\ntclient\ifshlp.sys + +DEVICE=xcdrom.sys /D:MSCD000 + +Full Screen Menus (thanks to Rune Espeseth) + +Use MENUCOLOR=foreground[,background] to obtain a full screen menu +where you can use the arrow keys. Example (note that box drawing +characters are used that look strange in other character sets): + +REM *** This is the FreeDos Config.sys *** +REM *** executed before autoexec.bat *** + +REM *** Set white foreground, red background *** +menucolor=7,4 + +files=20 +buffers=20 + +REM *** The Menu *** +MENU +MENU *-------------------------------------------------------* +MENU ! My Menu - FreeDOS rules! ! +MENU *-------------------------------------------------------* +MENU ! ! +MENU ! 1. Test with border ! +MENU ! ! +MENU ! 2. Another test... ! +MENU ! ! +MENU ! 3. Third choice ! +MENU ! ! +MENU ! 4. Fourth choice. ! +MENU ! ! +MENU *-------------------------------------------------------* +MENU + +MENUDEFAULT=1,10 ( configuration 1, wait 10 seconds) + +REM 1st choice +1?ECHO You selected menu #1 + +REM 2nd choice +2?ECHO You selected menu #2 + +REM 3rd choice +3?ECHO You selected menu #3 + +REM 4th choice +4?ECHO You selected menu #4 + + +2002-11-28 - Tom Ehlert +2003-07-15 - Bernd Blaauw +2003-09-18 - Bart Oldeman +2004-07-24 - Jeremy Davis +... +2008-22-01 - Fritz Mueller / Eric Auer diff --git a/docs/contrib.txt b/docs/contrib.txt new file mode 100644 index 0000000..699fbcc --- /dev/null +++ b/docs/contrib.txt @@ -0,0 +1,44 @@ +These are the known contributors of the FreeDOS kernel. If you have +contributed in any way to the kernel, but are not on this list, please +email the current kernel maintainer so we can add you to the list! + +Thanks to all the following for contributing to the FreeDOS kernel: + +Aitor Santamaria (aitor.sm@wanadoo.es) +Arkady Belousov (ark@mos.ru) +Bart Oldeman (bart@dosemu.org) +Bernd Blaauw (bblaauw@home.nl) +Brian Reifsnyder (reifsnyderb@mindspring.com) +Charles Dye (raster@highfiber.com) +Eduardo Casino (casino_e@terra.es) +Eric Auer (e.auer@jpberlin.de) +Eric Biederman (ebiederm+eric@ccr.net) +Eric Luttmann (ecl@users.sourceforge.net) +Fritz Mueller (fritz.mueller@mail.com) +Geraldo Netto (geraldonetto@gmail.com) +Helmut Fritsch (helmut.fritsch@gcd-hs.de) +James Tabor (jimtabor@infohwy.com) +Jason Hood (jadoxa@yahoo.com.au) +Jens Horstmeier (Jens.Horstmeier@abg1.siemens.de) +Jeremy Davis (jeremyd@fdos.org) +Jim Hall (jhall@freedos.org) +John Price (linux-guru@gcfl.net) +Kolya Ksenev (7207@mx.csd.tsu.ru) +Lixing Yuan (yuanlixg@china.com) +Luchezar Georgiev (lig@linux.tu-varna.acad.bg) +Martin Stromberg (ams@ludd.luth.se) +Michal Bakowski (mb@orad.pl) +Ron Cemer (roncemer@gte.net) +"ror4" (ror4@angelfire.com) +Rune Espeseth (re@icd.no) +Steffen Kaiser (Steffen.Kaiser@fh-rhein-sieg.de) +Steve Miller (SMiller@dsfx.com) +Tom Ehlert (te@drivesnapshot.de) +Victor Vlasenko (victor_vlasenko@hotbox.ru) + +At this place we should also thank Ralf Brown for his interrupt list. +It is a truely invaluable resource for us. + +And last, but not least, a big thanks to Pasquale J. Villani +(patv@iop.com), who is the original author of DOS-C, on which +the FreeDOS kernel is based. diff --git a/docs/copying b/docs/copying new file mode 100644 index 0000000..7c9effb --- /dev/null +++ b/docs/copying @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software Foundation + Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/docs/fdkernel.lsm b/docs/fdkernel.lsm new file mode 100644 index 0000000..82ef3aa --- /dev/null +++ b/docs/fdkernel.lsm @@ -0,0 +1,13 @@ +Begin3 +Title: The FreeDOS Kernel +Version: SVN +Entered-date: N/A +Description: The FreeDOS Kernel +Keywords: kernel, FreeDOS, DOS, MSDOS +Author: (developers: can be reached on the freedos-kernel mailing list) +Maintained-by: freedos-kernel@lists.sourceforge.net +Primary-site: http://freedos.sourceforge.net/kernel/ +Original-site: http://www.gcfl.net/pub/FreeDOS/kernel +Platforms: DOS, FreeDOS, DOSEMU (OpenWatcom C or Turbo C, NASM, optionally UPX) +Copying-policy: GPL2 +End diff --git a/docs/history.txt b/docs/history.txt new file mode 100644 index 0000000..3fd82b0 --- /dev/null +++ b/docs/history.txt @@ -0,0 +1,3911 @@ + + +General web notes: You can read details about bugzilla bug NUMBER on +http://bugzilla.freedos.org/cgi-bin/bugzilla/show_bug.cgi?id=NUMBER +and details about newer bugs managed in our sourceforge bug tracker on +http://sf.net/tracker/?func=detail&aid=NUMBER&group_id=5109&atid=105109 + +You can read more details (diff, changelog) about SVN revision NUMBER on +http://freedos.svn.sf.net/viewvc/freedos?view=rev&sortby=rev&revision=NUMBER +Changelog items can list SVN revision rNUMBER and bugzilla bug NUMBER. + + +2012 Feb 07 - Build 2041 +-------- Jeremy Davis + ++ Changes Jeremy + * r1637 fix out of range byte in country.asm + * r1685 add int 2f subfunc 122B and 122D from Eduardo Casino + * r1697 from Pete Batard, do not display CHS mismatch warning + during booting when forcing LBA mode option set + * r1702 improve handling for sectors not 512 bytes in size + (up to 2048 bytes, larger sizes not yet working) + * r1705 add cpu detection so memdisk args supported in 8086 build + +2011 Jun 21 - Build 2040 +-------- Jeremy Davis, Bart Oldeman + ++ Changes Jeremy + * r1635 from Christian Masloch, correction for memdisk check + * r1634 optional CONFIG.SYS options via memdisk + * r1633 force DPT to 512 byte sectors + * r1501 sys/sys.c: correct return value from NULL to FALSE - + fix compile with OW1.9 + * r1500 docs/sys.txt, sys/sys.c: + handle case when source not specified but filename for boot + sector is given (sys X: bootfile.bin) + ++ Changes Bart + * r1632 make free cluster search circular + * r1631 do not use FSINFO if not valid + * r1609 truncating 0 byte file should not fail + * r1591 fix SF bug 3090610 - 386 register save/restore + * r1569 kernel/{config.c,kernel.asm,init-mod.h,globals.h}: + Allocate bigger chunk of memory for INSTALL for __WATCOMC__ + because the memory layout is different from other compilers. + Fixes issues mentioned by Bret Johnson and Christian Masloch + in freedos-user/freedos-kernel. + * r1568 kernel/asmsupt.asm, mkfiles/owlinux.mak: Make sure the + DOS native and Linux cross-builds produce identical binaries. + * r1567 drivers/rdpcclk.asm,kernel/{asmsupt,entry,irqstack,kernel, + nls_hc}.asm, kernel/makefile: + Remove useless END from nls_hc.asm, add explicit byte + overrides for older versions of NASM for more compact code, + and adjust silent relocation segments. + * r1565 sys/sys.c: Change // to /* comments for Turbo C compatibility. + * r1564 kernel/dosfns.c: If handle valid, close file in PSP + table before the low-level close + (perhaps) critical error. + Avoids closing the file twice (and hitting the critical + error twice) on abort/program termination. + Also, close can only return error 6 (DE_INVLDHNDL), not 5 + (DE_ACCESS), see RBIL. + * r1563 kernel/task.c: From Christian Masloch: + set flags to 0x200 (IF set) when transferring to int22 + termination address. + * r1562 kernel/fatfs.c: Check errors for callers of dir_write + and shrink_file. Fixes: Bug: File creation does not check + whether buffers are written correctly + (http://www.bttr-software.de/forum/forum_entry.php?id=9783) + * r1561 kernel/blockio.c, kernel/fatdir.c: + No longer force flush1() and dir_write_update() to return + TRUE if there were disk write errors. Part 1 for fixing + http://www.bttr-software.de/forum/forum_entry.php?id=9783 + Bug: File creation does not check whether buffers are + written correctly + * r1560 kernel/kernel.asm: + Enlarge clock and block driver stacks. Thanks to Damien Guibouret + . + * r1559 kernel/fatfs.c: Fix value that is used before being initialised. + This lead to a drive to not be considered as FAT32 despite it is + (or vice-versa). + Thanks to Damien Guibouret . + * r1499 kernel/makefile: + With the stack changes the DOS segment has moved to 0x79. + * r1498 kernel/irqstack.asm: + New irqstack.asm: irq 2, 3, 4, 5, 6, 10, 11, 12, 14, 15 now + use the IBM interrupt sharing protocol for STACKS. Affect + int 2 too, but not IRQ 7 (INT 0fh) and IRQ 9 (INT 71h) + +2009 Aug 04 - Build 2039 +-------- Jeremy Davis, Bart Oldeman + ++ Changes Jeremy + * r1494, 1483 docs/sys.txt, sys/sys.c: update documentation to + include new options; add option to sys to force LBA or CHS + usage, allow using BIOS specified boot drive # on floppy, + add verbose output (debug prints), and reorder some steps in + copy() to avoid some unnecessary disk swaps on single drive systems + * r1493 boot/boot.asm: add comment about location that may be + modified by sys (and some whitespace changes due to editor) + * r1492 boot/makefile: create list file when assembling boot sectors + * r1489 kernel/main.c: update copyright year, add some comments + * r1488 kernel/kernel.asm: mark unused space in kernel for unused win + compatibility structs + * r1487 hdr/lol.h, hdr/win.h: comment/structure info update + * r1486 hdr/process.h: comments added + * r1485 hdr/device.h: comments added + * r1484 hdr/cds.h: update comments + * r1483 docs/sys.txt: update sys usage documentation + * r1482 boot/boot.asm, boot/makefile, boot/oemboot.asm, + build.bat, default.bat, hdr/debug.h, kernel/{dosfns.c,init-mod.h, + initdisk.c,inthndlr.c,prf.c,proto.h},sys/{fdkrncfg.c,makefile,sys.c}: + update sys to current version, adjust printf to support + percent modifier, consistent prototype, and handle text not in + current segment (FAR *) better, merge part of simplified debug (via + prints) support + * r1467 kernel/makefile, mkfiles/generic.mak: update build process to + include country.sys + * r1466 kernel/country.asm: sync country source with latest from + eduardocasino.es site + * r1465 kernel/country.asm: add source for country.sys from dev + branch + * r1456 hdr/version.h, kernel/globals.h: simplify how version + specified, enable SVN builds with revision# + * r1455 build.bat: add convenience options to build.bat for setting + various defines + * r1454 default.bat: clear some additional env variables + * r1431 kernel/makefile, utils/exeflat.c: More verbose output of UPX + method (sys or exe) used and fix case without UPX so kernel boots. + * r1385 docs/fdkernel.lsm, hdr/version.h: update version # in + preparation for next release and to avoid confusion between svn and + release kernels + ++ Changes Bart + * r1491 hdr/debug.h, kernel/{init-mod.h,kernel/int2f.asm,nls.c,prf.c, + proto.h}, sys/{fdkrncfg.c,sys.c}: Use near pointers for printf()s + where possible. Problematic is only the case where SS!=DS (which + happens sometimes in resident code), in which case va_list/va_arg + need to use FAR pointers. DS!=DGROUP never works, so I corrected + that for NLS_DEBUG, by setting DS in int2f.asm. + * r1490 kernel/fatfs.c: Check the BPB instead of the DPB for FAT32 + after a BUILDBPB device call, as the DPB may still be uninitialized + at this point. Fixes FAT32 drives in USBDRIVE (http://bretjohnson.us) + * r1480 utils/exeflat.c: Corrected a bug in exeflat: it was writing + 32 bytes too many from possibly unexisting buffers after compressing + exe files. + * r1479 kernel/{initdisk.c,newstuff.c}: Corrected DEBUG #if to + #ifdef for Turbo C and corrected debug printfs in truename(). + * r1478 kernel/newstuff.c: Simplified truename(): eliminated the + addSep state by adding a backslash in every new segment, including a + trailing backslash. Simplified . and .. logic. Converted switch to if + because there were few cases left. + * r1477 kernel/dosfns.c: DosChangeDir can only return DE_PATHNOTFND + in case of error, so force that error code. + * r1476 kernel/dosfns.c: Remove the wildcard check for DosChangeDir() + because truename() already does that. + * r1475 kernel/newstuff.c: Use simpler code for copying the current + directory constructing the "truename": instead of fmemcpy followed by + strcpy, just use strcpy. Also use the near TempCDS more. + * r1474 kernel/newstuff.c: Unify parse_name_ext for name and + extension and inline this function into truename(). This is an + optimization (200 bytes). + * r1473 kernel{fatdir.c,fatfs.c,newstuff.c}: If the current directory + is no longer valid, call dos_cd() for the root to update the CDS + cluster. Call media_check explicitly in truename() as a central + first and only place in directory-using DOS calls (except + DosFindNext) to call it. + * r1472 kernel/{dosfns.c,newstuff.c}: The original DosGetCuDir + is now inlined in truename(). DosGetCuDir now does truename("D:", + CDS_MODE_SKIP_PHYSICAL), and this mode was changed to no longer call + QRemote_Fn (int2f/ax=1123). + * r1471 kernel/newstuff.c: Fix truename("C:") where the current + directory is different from the root: then it should not append a + backslash. + * r1470 kernel/{inthndlr.c,makefile}: Turbo C 2.01 and Linux + cross-compilation compatibility fixes. + * r1469 kernel/{inthndlr.c,task.c}: For self-owning PSPs do + everything that a normal exit does except for closing files and + releasing memory (see RBIL). Thanks to Christian Masloch. + * r1468 kernel/fatdir.c: Fix problem with cd\ reported by + ibid_ag@lavabit.com on the mailing list. + * r1458 kernel/{blockio.c, fatfs.c, proto.h}: In case of + "not sure" if the removable media has changed, the IBM PCDOS + technical reference says to call BLDBPB if there are no used buffers, + so we only do it then, instead of flushing the buffers. + * r1457 hdr/{xstructs.h, inthndlr.c}: Merged int21/ax=7304, + subfunctions 3 and 4, which work very similarly. + * r1453 kernel/fatfs.c: Set the clean bit also on created/replaced + files, not just opened files, so the directory entry is only updated + after they are written too. Fixes SF bug #2380531. + * r1452 kernel/initdisk.c: Use a better formula for calculating FAT12 + clusters, by multiplying nominator and denominator by 3. + * r1451 kernel/{fatfs.c, initdisk.c}: initdisk: further optimizations + in CalculateFATData(): merging the FAT16 & FAT32 loops. + fatfs: #if DEBUG fix. + * r1450 kernel/initdisk.c: Optimized initdisk.c by using constants + instead of variables where possible. + * r1449 kernel/config.c, kernel/config.h: Removed unused config + variables and don't detect 'y' and 'n' if we're using toupper anyway. + * r1448 hdr/{fat.h, fatfs.c}: Cluster optimizations, mainly for FAT32 + eliminated checkdstart, replaced (cl == FREE || cl == 1) by (cl <= 1), + UWORD cluster cast for FAT12/16, and merge if branches for link_fat(). + * r1447 kernel/fatfs.c: Merged if status==S_OPENED logic in dos_open, + cache dir_attrib, and remove unnecessary init to 0. + * r1446 kernel/config.c: Make the built-in COUNTRY table more compact + and allow to merge duplicate strings for error message. + * r1445 kernel/fatfs.c: Optimization: changed find_fname() to call + split_path() because find_fname was always preceeded by split_path(). + The return code is now an error code, DE_FILENOTFND, DE_PATHNOTFND, + or SUCCESS, depending on the failure. + * r1444 kernel/{fatdir.c, fatfs.c, proto.h}: Added a + split boolean argument to dir_open so the trick with setting the + dir/filename separator to 0 can be avoided, and we don't need to + calculate its location in split_path(). Without the trick many more + char * path arguments in the kernel can become "const char *". + * r1443 utils/exeflat.c: Use tmp.exe instead of tmp$$$$$.exe -- the + Linux cross compilation really has trouble without quotes because $$ + can be expanded as a shell variable when passed to system(). + * r1442 kernel/{dosnames.c, fatfs.c, makefile, proto.h}: + Remove dosnames.c and inline ParseDosName, because there is only one + user left (split_path()) which only uses it to find out if the path + ends in a backslash and the length of the directory part. + * r1441 kernel/{dosnames.c, fatdir.c, fatfs.c, proto.h}: + dos_findfirst() now uses split_path(). The only thing + that needed to be added was the need to check for "d:\" paths which + return DE_NFILES. Also, findfirst("d:\nonexist\*.*",D_VOLID) should + fail even if it actually searches in d:\. + * r1440 kernel/{dosnames.c, newstuff.c}: The invalid pathname + character detection is moved from ParseDosName (dosnames.c) to + truename (newstuff.c), because TRUENAME should check these characters + before passing paths on to fatfs.c & fatdir.c. + * r1439 kernel/fatdir.c: Corrected the if-statement && logic for + attributes in the findnext loop. + * r1438 kernel/{dosfns.c, fatdir.c}: Make findfirst/findnext + more MSDOS compatible: + * ignore 0x40 (D_DEVICE) in search attribute. + * if you specify D_VOLID + one or more of D_HIDDEN, D_SYSTEM, and + D_DIR you will get files *and* volume labels in the specified + directory, not forced to the root directory. + * VOLID searches must look at the search pattern name too, + or do not match. + * r1437 kernel/{dosfns.c, fatfs.c}: For read/write don't update + sft_posit in dosfns.c anymore so fatfs.c takes care of it. + * r1436 kernel/{fatdir.c, fatfs.c}: Remove usage of the fnode + f_flags field where it is not relevant anymore. Because of the + explicit dir_write() calls we only need them in situations where SFTs + where used, that is for open files but not for directories. + * r1435 kernel/{fatdir.c, fatfs.c}: Eliminate fcbname[] on the + stack: we can use dm_name_pat in the dirmatch structures instead. + * r1434 kernel/asmsupt.asm: %if 0 unused asm functions and fix a + stack return problem with fstrcmp. + * r1433 kernel/{dosnames.c, fatdir.c, fatfs.c, proto.h}: + Split 8.3 FCB-style filename extraction from ParseDosName + into a new ConvertNameSZToName83 function, also used by dir_open(). + * r1432 hdr/fnode.h, kernel/{fatdir.c, fatfs.c, globals.h, init-mod.h, + kernel.asm}: + Move the fnode fields f_diroff and f_dirstart into a referenced + directory match structure with fields dm_entry and dm_dircluster. + * r1430 hdr/nls.h, kernel/{config.c, init-mod.h, inthndlr.c, intr.asm, + kernel/nls.c, kernel/nls_hc.asm, kernel/proto.h}: + Ported COUNTRY.SYS support from the unstable branch. + Simple country support is kept: COUNTRY=31 will look for country.sys + but if it does not exist, not complain and load the built-in info. + * r1429 hdr/sft.h, kernel/{dosfns.c, inthndlr.c, proto.h}: Seek changes: + * merge unstable kernel optimizations + * enable seek for int2f/AX=1228 + * -1 is a valid offset, so we need to process the return code + seperately + * r1428 kernel/dosfns.c: Merge pop_dmp optimization from the unstable + kernel. + * r1427 kernel/ioctl.c: This change was missed, as the changelog + mentioned it was in 2035a already: r_si/r_di contents added as + documented in PC-DOS Technical Update. I also moved the CharReqHdr + filling in to just before execrh, and made the command table a static + const so it is outside the SDA (OW places it in CONST2). + * r1426 kernel/ioctl.c: Optimization: move the attribute checks down + and localize some variables. + * r1425 kernel/ioctl.c: Streamline ioctl.c code so OW saves 2 more + words of stack. + * r1424 kernel/ioctl.c: r1115 set the dpb_subunit but that was wrong + for get_cds() called from AX=4409. Use a local variable unit to avoid + that, and simplify the AX=4409 logic like in the unstable kernel. + * r1423 kernel/ioctl.c: Inline ioctl helper routine back again. Save + stack by using the dev variable that points to the device smartly. + * r1422 kernel/ioctl.c: Split DosDevIoctl into two calls so execrh + can be called with minimal stack usage. Always return DE_ACCESS when + the device fails instead of DE_DEVICE, as DE_DEVICE is only used for + renames between devices that are not the same. + * r1421 kernel/fatfs.c: Introduce clear_dir() to clear a directory, + this was code shared between dos_mkdir() and extend_dir(). Now + dos_mkdir() calls this function to clear the new directory, and then + creates the . and .. entries using higher level functions instead of + dealing with the blocks directly. + * r1420 hdr/{fnode.h, sft.h}, kernel/{fatdir.c, fatfs.c}: Make + the fnode f_flags completely equal to the SFT sft_flags. Rename + SFT_FDIRTY to SFT_FCLEAN to avoid confusion. + * r1419 hdr/fnode.h, kernel/{fatdir.c, fatfs.c}: Eliminate the + fnode F_DDIR flag which has no SFT equivalent: f_sft_idx==0xff can do + the same. rwblock() is never called for directories so the checks + could be removed. + * r1418 kernel/fatfs.c: Flip target and source checks to avoid + calling ParseDosName for in-directory renames. Do not allow to rename + directories between different directories. + * r1417 kernel/fatfs.c: RENAME: if the source and target directories + are the same, rename the directory entry in-place instead of creating + a new one and deleting the old one. Fixes archived bugzilla bug: + http://www.freedos.org/bugzilla/cgi-bin/show_bug.cgi?id=1908 + * r1416 kernel/fatfs.c: Change dos_rmdir to only use 1 fnode. It now + first checks if the directory is empty and then opens the parent and + deletes the real directory. No longer returns DE_FILENOTFND(2), but + return DE_PATHNOTFND(3) instead. + * r1415 hdr/dirmatch.h: Cleanup dirmatch.h: make attributes and size + unsigned, and make the unused dm_flags field reserved. + * r1414 kernel/{dosfns.c, proto.h, task.c}: Introduce get_cds1 to merge + common code that checks for 0=default_drive,1=A,etc. + Make load_transfer() static. + * r1413 kernel/chario.c: Inline cooked_write_char() into cooked_write(). + * r1411 kernel/fatfs.c: Fix compilation with Turbo C. + * r1410 kernel/{fatdir.c, fatfs.c, proto.h}: Eliminate dir_close(). + Its only purpose left was to flush buffers, which isn't necessary + after just open/read, so we can move that to dir_write(). + * r1409 kernel/{dosfns.c, fatfs.c}: + Move the open/creat access checks to more efficient places. + * r1408 kernel/fatfs.c: Make merge_file_changes more direct dealing + with SFTs and merge the "close open files setfattr wants to change" + functionality there. + * r1407 kernel/dosfns.c: Eliminate DosGetFile -- it is no longer + necessary because the filename is already copied from the fnode. + * r1406 kernel/dosfns.c: Fix a regression with sft_flags overwriting + what dos_open wrote so file dates/times would always be updated, even + for reads! + * r1405 kernel/{dosfns.c, fatdir.c, fatfs.c, fcbfns.c, proto.h}: + Eliminate dos_setfsize, dos_setftime, and dos_lseek, by just using + the SFT. dos_setfsize still needed to merge changes for SHARE so the + call was replaced by a new dos_merge_file_changes() call. + * r1404 hdr/fnode.h, kernel/{fatdir.c, fatfs.c}: Eliminate + xlt_fd(), save_far_f_node(), and the redundant fnode f_mode field. + * r1403 kernel/{dosfns.c, fatfs.c}: Let merge_file_changes + operate directly on the other SFTs. dos_setfattr with SHARE now + closes open SFTs referring to that file in compat mode. + * r1402 kernel/fatfs.c: Fix SFT/fnode fields so the SHARE related + functions is_same_file() and merge_file_changes() work. + * r1401 hdr/fnode.h, kernel/{fatfs.c, globals.h}: Remove + redundant checks for fnodes==0 since the checks are done in dosfns.c. + Replace global f_nodes[] array by f_sft_idx fields in the fnodes. + * r1400 hdr/sft.h, kernel/{dosfns.c, fatfs.c, fcbfns.c, proto.h}: + Eliminate the sft_status field as it is now equal to the SFT index. + * r1399 kernel/{dosfns.c, fatfs.c, proto.h, task.c}: + Eliminate dos_getftime, dos_getfsize, and dos_getfattr_fd, because we + can now get these properties directly from the SFT. + * r1398 hdr/fnode.h, kernel/{fatdir.c, fatfs.c, proto.h}: + Eliminate f_count field in fnodes and some no-op functions. + * r1397 hdr/{fnode.h, lol.h}, kernel/{config.c, dosfns.c, fatfs.c, + globals.h, kernel.asm, proto.h}: + This is the main change to eliminate far fnodes. SFT info is copied + from and to the two near fnodes. Some cleanups still follow. + * r1396 hdr/sft.h: + Make the SFT DOS 4+ compatible and change fields to be unsigned. + * r1395 kernel/dosfns.c: + Handle sft_count before calling dos_open and after calling dos_close + so the SFT is open for longer, during fatfs.c operations. + * r1394 kernel/prf.c: Fix compilation with -DDOSEMU set. + * r1393 kernel/{dosfns.c, fatfs.c}: Handle dos_getfattr and + dos_setfattr directly at the directory level, instead of opening the + file, to avoid needing to claim SFTs in later changes. Clarify and + implement parts of the correct SHARE behaviour. + * r1392 hdr/fat.h, kernel/{fatdir.c, fatfs.c, proto.h}: + On close or commit, only update those directory entry fields that + have an SFT equivalent. The rest stays unmodified on disk. + * r1391 kernel/{fatdir.c, fatfs.c}: Use explicit dir_write() + instead of letting dir_close() do the writing. This is to prepare for + an updating version to deal with SFTs. + * r1390 hdr/fnode.h, kernel/fatdir.c: Add f_dirsector (sector + containing dentry) and f_diridx (index within sector) fields to the + fnode, to make fnodes more compatible with SFTs. Use them to simplify + dir_read() and dir_write(). + * r1389 kernel/{fatdir.c, fatfs.c, globals.h, inthndlr.c, lfnapi.c, + proto.h}: Force near fnode use to use either fnode[0] or fnode[1] + instead of the allocation scheme. This eliminates the checks + done in inthndlr.c because the f_count field is no longer checked. + * r1388 makefile, mkfiles/owlinux.mak: Change Linux makefiles to only + update what is necessary for subsequent makes. + * r1387 config.m, docs/build.txt, drivers/makefile, kernel/{makefile, + segs.inc}, makefile, mkfiles/{generic.mak, owlinux.mak, watcom.mak}, + sys/makefile, utils/{exeflat.c, makefile}: + Add Linux cross-compile capability, using Open Watcom: + * Flip \ to / where possible. + * Introduce $(DIRSEP) (/ or \) for use inside commands in + makefiles where / won't work in DOS. + * Override various settings for Linux in owlinux.mak. + * Add quotes in exeflat.c to avoid shell expansion of $$$$$. + * Let "make all", "make clean", and "make clobber" do the job. + * r1386 utils/echoto.bat: OW 1.8 MS2WLINK is too picky about leading + and trailing whitespace so echoto is changed to not generate any. + +2009 May 16 - Build 2038 +-------- Pat Villani, Bart Oldeman, Eric Auer + +Thanks to Geraldo Netto for summarizing the 2008 SVN changelog. See also: +http://freedos.svn.sourceforge.net/viewvc/freedos/kernel/trunk/?view=log +Patches are mostly from Bart and Eric, some from Jeremy and Tom. + ++ Changes Jeremy 2009 + + * r1412 from Eric: update this history.txt (and bugs.txt, contrib.txt) + * r1381-r1384 update bugs.txt version.h LSM, tag SVN for 2038 release + * r1374, r1380 fcbfns FCB open old GEM compat (bigsize/recsiz/recno) + http://sf.net/tracker/?func=detail&aid=2253450&group_id=5109&atid=355109 + * r1379 dosfns.c fatfs.c proto.h from Eric: only check for SHARE on + open/close, avoid extra 2f.1000 calls. + * r1378 dsk.c from Lucho: Press any key, not Press the any key ;-) + * r1377 initdisk.c from RayeR: Use total cyl count, not max cylinder + (fixes off by one bug on non-LBA PC) & fix overflow by ULONG cast. + Improve DebugPrintf calls, fix format string (only in debug kernels) + * r1376 inthndlr.c from Tom: 21.1c return AL=0xff for invalid drives + (fixes bug for apps which use int 21.1c to find FAT drive letters) + * r1372, r1375 from Bart: process.h/entry.asm make CP/M call PSP[5] + work (1 line jbe versus ja fix and detailed comments about stack) + This fixes SF tracked bug 2421577. + * r1373 kernel.asm add : after _HMATextAvailable avoid nasm warning + * r1371 watcom.mak make sure even Windows Watcom C builds a DOS SYS + (would otherwise make a SYS meant for use in Windows by default) + * r1370 default bat make compiling without UPX possible again + * r1369 let DosGetExtFree 21.7303 accept drive with and w/o slash + This fixes SF tracked bug 2380828 (GetDiskFreeSpaceEx if no slash) + * r1368 tag for ke2038test + ++ Changes Bart + Eric (mostly) + * r1367 sys.c from Bart: 32bit date/time if WATCOMC 1279+ (OW 1.8) + * r1366 config.c, config.txt allow BUFFERSHIGH as alias to BUFFERS, + buffers are in UMB, we use HMA anyway. Drop unused int 16.1 call. + * r1365 inthndlr.c allow/ignore type hints in int 21.7305 disk read + * r1364 fdkernel.lsm and version.h updated to 2038 / Apr 2008 + Updated this history.txt changelog to state of April 2008 + * r1363 add Geraldo (changelog) and Fritz (docs) to contrib.txt + New version of config.txt - verbose, readable, up to date + * r1362 update readme.cvs - add info about SVN / subversion + * r1361, 1355 update information about bugzilla. You can also + write the maintainer or mailinglist but we prefer bugzilla... + Add information about SourceForge feature request tracker, too + * r1360 new Free Software Foundation (FSF) mail addr in COPYING + * r1359 BIOS y2k bug workaround: If BIOS date 1900..1979, assume + date 2000..2079 (we only read CMOS date at boot) Fix bug 1748 + * r1358 more secure FAT handling to avoid crosslinks if reboot + with open files: Thanks to Hardi Stengelin for research help; + always test link_fat result, new is_free_cluster, checks in + link_fat and next_cluster (bad index/value, bad chain / extend + -> warning). Do link_fat before setdstart. Lazy FS INFO writes + * r1357 truename must use the current working directory of the + created-by-subst virtual drive when it resolves relative paths + even though the "real" drive/dir are returned in the end. Note + that "subst e: d:\" shows a warning as it tries "mkdir d:\" + Fixes bug 1862 "CHDIR fails on substituted drives" + * r1356 SYS has to update the backup boot sector of FAT32, else + dosfsck would show a warning about a boot / backup mismatch + * r1354 Use _dos_allocmem for OW, similar to Turbo C version + Split file copy into readfile and writefile, nicer source code + Preserve time and date of kernel.sys and command.com + * r1353 let exeflat call UPX, simpler makefile as in unstable branch + * r1351, 1352 exeflat reorganization, no functional changes + * r1350 add ASM/CDECL to HaltCpuWhileIdle decl, fix Turbo C compile + * r1349 change copy() in SYS to "read to RAM, update boot, write to + disk", reduces disk changes on single floppy PC, fixes bug 1840 + * r1348 treat load image size of EXE modulo 1 MB, do not abort if + size > 1 MB. Fixes bug 1854, Turbo C++ 3: paras=(word)(pages<<5) + * r1346 init HaltCpuWhileIdle to 0 before installing int handlers + * r1345 int 21.5a mktemp: only enforce root tempfile name if no dir + is given in template *and* DOS version is 5.xx, else no dirspec + Tried to make int 21.60 truename return 0 if okay, 3a00 if char + device and not join/net?? Set default FAT16 DOS version to 6.22 + (was 5.0, only int 21.5a/21.60 and userland differ from 6.22) + * r1344 clarified intfns.txt for int 21.63 (country/nlsfunc), int + 21.71 (LFN) and int 21.5d0x (share). The latter would need both + kernel and SHARE extension to be supported, neither are done yet + * r1341, 1343: fix Bochs incompatible (PostConfig crash) IRQTEXT, + now with corrected segment loads in irqstack.asm (segs->groups) + This fixes a problem introduced in SVN revision 1325/1326. We now + have a "fastboot" int 19 reboot hook from Japheth's JEMM JEMFBHLP + * r1342 fix fat32readwrite prototype, reg use in detect LBA pragma + + +2007 Jul 21 - Build 2036 svn, in other words, 2038 pre +-------- Eric Auer (eric@coli.uni-sb.de) + +Thanks to Geraldo Netto for summarizing the SVN changelog - See also: +http://freedos.svn.sourceforge.net/viewvc/freedos/kernel/trunk/?view=log +All main features of Tom's fork are available in kernel 2038 now. + ++ Changes Bart + Eric + * r1340 version 2038pre/2036svn (fdkernel.lsm, version.h, history) + * r1339 new IDLEHALT=n (HLT on idle, save energy) and KEYBUF=n[,m] + (relocate keyboard buffer, eg to 40:105-1ff) config.sys options + * r1338 removed "Dutch plurals" ("Dutch plural's" ;-)) + * r1336-1337 disable interrupts while storing interrupt vectors, + fix 8086 compatibility again + * r1335 use lastdrive Z for initial CDS, so device=f:... etc works + * r1334 fix bug 1953: int 21.29 now returns valid only for existing + drives, not for all, and leave FCB empty/unset if no valid drive + http://sf.net/tracker/?func=detail&aid=2362450&group_id=5109&atid=105109 + * r1333 fix stack for UPX compression as .sys, fix size limit 65420 + * r1332 fix F5/F8 zero timeout handling in GetBiosKey + * r1331 some config.txt / contrib.txt updates merged from UNSTABLE + * r1330 fix Turbo C compilation: nls.* adds ASM/CDECL nlsInfoBlock + and makefile uses "$(COMSPEC) /c if exist" in UPX handling + * r1329 UPX compress kernels below 64k as .sys, save 2k disk space + * r1328 process relocations before compressing kernel, save 130 by + * r1327 use more flexible exeflat UPX trailer from unstable branch + * r1325-1326 new IRQTEXT segment, put pre-boot interrupt vectors + at 70:100 so int 19 reboot with JEMM386 "fastboot" can work + (see r1341, r1343: this introduced a later fixed problem...) + * r1324 add SHARE driver/TSR for file locking to main SVN branch + * r1323 fix bug 1956: use segment, not offset, for file handle NULL + check - otherwise apps which allocate their own FILES can break + * r1322 fix problem with old game which uses findfirst attrib 77a8 + (do not return volume label as findfirst/findnext result here) + * r1320 add some comments about what intr() does + * r1319 read partitioning via CHS (unless Cyl>1023 / LBA forced via + SYS CONFIG) for better compat with old boot managers like "PROT" + * r1318 avoid compile time warning with OpenWatcom 1.7 in-devel + * r1313 call_nls optimization: ID in high word of long, no pointer + * r1312 always set lr.ES just before break, so OW can tail merge + * r1308 avoid OW 1.6 warnings about functions redeclared as static + * r1307 fix OW warning about comparing unsigned int to <= 0... + * r1306 NUL device has to return 0 bytes for reads even in raw + mode - fixes problem with DJGPP sed (possibly also bug 1793?) + ++ changes merged from Tom's extra stable fork of kernel 2035a: + * r1321 only move EBDA if ramsize == peek(0, RAMSIZE) + * r1317 extra free of near f_nodes to avoid INT24 problems + * r1316 remove unused intr prototype for resident code, + add dir kernel.exe to build process, cosmetic p=A -> p = A + * r1315 set OEM name in boot sector to FRDOS5.1 (5 uppercase + letter, 4 or 5, dot, digit: Win9x seems to like that better... + * r1314 implement int 2f.4a00 "DJ style" floppy change call + (let GUIs hook "Insert disk..." dialog on single floppy systems) + Some forgotten bits of int2f.asm NLS related updates + * r1311 optimized method to set extended error (smaller) + * r1310 use a command table for IOCTL, save ca 83 bytes + * r1309 fix typo "booot" + ++ these changes are already in FreeDOS 1.0 kernel 2036cvs Aug 18 2006: + * r1305 build system adjustments - suppress dos4g banner etc + * r1304 fix MS QB4 (QBasic/QuickBasic) problem, allow double free + (freed MCBs are unlinked from the chain but not invalidated) + * r1303 only use 28 bits of FAT32, mask out others, add logging + * r1302 add COMn/AUX func 6 (input status), remove read wait for DSR + + +2006 May 20 - Build 2036 cvs and 2037 test +-------- Eric Auer (eric@coli.uni-sb.de) + +WARNING: This changelog entry is a draft! The cvs log contains + data for both HEAD and UNSTABLE branch while a cvs checkout + seems to return only the HEAD branch. This file history.txt + should describe "2036 cvs" HEAD and "2037 test" UNSTABLE + separately rather than in one merged changelog item. + +In addition, the "Changes Eric" items yet have to be ported to + the UNSTABLE branch and the version.h for UNSTABLE should say + "03 Mar 2006" "2037 test" (revision 37)...! + +Most recent changes to source code (see version.h) are: + HEAD 9 Sep 2005 (not counting the Korean stub and execrh change + by Eric, and not counting the version number change itself) + UNSTABLE 3 Mar 2006 (includes SYS changes, more Win3 support, + COM port output for debug print, the SHARE tool...) + The head to unstable diff in general is quite large. As a rule + of thumb, use UNSTABLE if you need NLSFUNC or Win3 386 mode or if + you need a very new kernel, and use HEAD if you need stability. + ++ Changes Jeremy + * build.bat, config.b: UPX and WIN3 build options, for BUILDALL + * boot/oemboot.asm: set backup boot sector on FAT32, add update + option, fix oemboot to work with msdos 7+, in UNSTABLE branch. + * docs/bugs.txt: update Bugzilla URL + * docs/config.txt: document SWITCHES, based on suggestions from Eric + * docs/contrib.txt, docs/fdkernel.lsm: new email address + * docs/sys.htm, docs/sys.txt: see oemboot.asm + * docs/sys.txt: better check for valid backup boot sector # and add + option to skip setting it + * hdr/debug.h, kernel/prf.c: slight cleanup, send debug prints to COM + port, allow printf to work correctly when SS!=DS, debug changes + * hdr/device.h: add comments about what flags mean + * hdr/portab.h: from dev: add MK_PTR and MK_SEG_PTR macros + add/use halt() wrapper for issuing "hlt" asm instruction + * hdr/version.h: update version to 2035b-cvs (= not a release yet) + * kernel/config.c: fix read calls to detect error, from Eric / Brad + * kernel/console.asm, newstuff.c, prf.c, task.c: compile time option + to send debug output to COM port ("serial debugging console") + * kernel/dosfns.c: do not compares filenames to name field in block + devices, extra win3 support, misc debug output changes, IsDevice + should not compare filenames against block device driver headers + * kernel/dsk.c: works towards better SS!=DS support, centralized + debug macros, some comments + * kernel/entry.asm: more win3 support, debug output changes, comments + * kernel/execrh.asm: protect 386 registers, using hdr/stacks.inc + macros (Watcom: FS, GS Others: high 16 bits of EAX EDX, for MSCL8 + also ECX, for BC5 also EBX), for ALL device driver calls. Without + this, some versions of free-EMM386 crash 386 optimized kernels. + See list archives 24 Jul 2005 and later. + * kernel/fatfs.c: don't leave fd open when failing DIR bit check + bug 1874 fix, do not consider setting DIR bit an error for + int 21/4301=set attribute, if really is a directory + Added some disabled debug messages, improved win3 support. + * kernel/init-mod.h: allow printf to work correctly when SS!=DS + * kernel/initdisk.h: insure bpb_huge is initialized (zeroed) [merge + from dev kernel], fake floppy ddt so hd access works correctly on + floppyless systems, based on suggested fix from Eric + * kernel/int2f.asm kernel.asm main.c: initial BIOS disk int 13h wrapper, + only passively detects and notes floppy disk change, more win3 support + * kernel/inthndlr.c: potential fix for spurious near fnodes!=0 msg with + shsufdrv and >2 near fnodes in use for bug 1879, use halt() wrapper, + more win3 support, some debug output changes. + * kernel/intwrap.asm: assembly glue to wrap misc interrupts with C + handler, cleaner push immediate from Arkady and note big bug to be + fixed, later moved to UNSTABLE branch (also affects makefile) + * kernel/proto.h: fix prototype, add FAR + allow printf to work correctly when SS!=DS + * mkfiles/generic.mak: undo a local only change, build list option + is proper way to do this. more win3 support, upx build option. + * mkfiles/watcom.mak: allow printf to work correctly when SS!=DS + * share/MAKEFILE, share/share.c, share/share.hlp: FreeDOS SHARE + (initial revision, later moved to UNSTABLE branch) + * sys/fdkrncfg.c: sync printf prototypes (uncorrupt executables) + * sys/sys.c: sync printf prototypes (uncorrupt executables) + better check for valid backup boot sector # and add option to skip + setting it. set backup boot sector on FAT32, add update option, + fix oemboot to work with msdos 7+ + ++ Changes Eric + * kernel/globals.h changed the os_release version message to be + "build 2036 cvs [version Sep 09 2005 compiled May 20 2006]" as + opposed to the old + "version 1.1.35 (Build 2035b-cvs) [Jul 23 2005 12:34:56]" + -> removed the "1.1.35" and compile TIME, added SOURCE DATE + * hdr/version.h removed some no longer used version defines + Changed build to "2036 cvs" (revision 36) + WARNING: Version should be "2037 test" (revision 37) for UNSTABLE! + * docs/history.txt: summarized log -d '>Feb 25 2005' kernel for this + WARNING: some of the described changes might be available only + in the UNSTABLE cvs branch (like SYS OEMBOOT, Win3, COM port + output for debug print, the SHARE tool, ...) + * kernel/execrh.asm: removed the "protect 386 registers" patch + again, a fixed version of free-EMM386 is available. This reduces + device driver call overhead in terms of CPU and stack usage. + Older EMM386 versions destroyed eax ebx ecx edi esi ebp fs gs, + now go_driver_entry in emm386.asm saves those registers. Only the + INIT was broken, but the execrh.asm patch protected ALL functions. + * share/share.c: changes to reduce TSR memory footprint + * kernel/inthndlr.c: added stub for function 0x6301/0x6302 Korean + Hangul keyboard input methods (0x63xx is DBCS support related) + * docs/intfns.txt: updated list of supported DOS functions. When + DOSLFN is loaded for int 21.71, only remaining unsupported int + 21 functions are 21.4b05 (set execution state), int 21.63xx + (DBCS / Korean Hangul, see above) and int 21.5d01 - 21.5d05 + (close files by name/computer/task, list open files, commit all) + * made linebreaks in all batch files use CR LF, as Unix line breaks + confuse command.com, leading to "early abort" or "endless loop" + ++ Changes Lucho + * kernel/chario.c: Fix Ctrl-Z bug and retro-optimise a bit + * kernel/config.c, sys/sys.c: Fix BC 3.1 CONFIG.C compile and + SYS Abnormal Program Termination error for BC + * sys/sys.c: fix update option (compared too many characters) + ++ Changes Eduardo + * kernel/config.c: fix Spanish (34, not duplicate of 33) + * kernel/inthndlr.c: add int 2f subfunc 122B and 122D + ++ Changes Jason + * kernel/fatfs.c: extended DPBs and Set Extended Error function + * kernel/inthndlr.c, kernel/proto.h: same + ++ Changes Arkady + * kernel/inthndlr.c: use direct access instead of reading from copy + made on stack + * kernel/intwrap.asm, kernel/kernel.asm: cleaner push immediate from + Arkady and note big bug to be fixed + ++ Changes Michael + * share/share.c: bugfixes + ++ Changes Japheth + * share/share.c: HXDOS related improvements + ++ Changes Bart + * kernel/main.c: patch to make device=f:\foo.sys work. String printf + optimisation + + +2005 Feb 25 - Build 2035a +-------- Jeremy Davis (jeremyd@computer.org) ++ Changes Bart + * int2f.asm: call_nls: DI register was not preserved (bug 1812) ++ Changes Arkady + * floppy.asm: fix epilog for FL_SETMEDIATYPE & FL_SETDISKTYPE + to use 'ret' instead of 'ret 8'; improve comments + * entry.asm: use unsigned comparision instead of signed ++ Changes Lucho + * dsk.c: text in play_dj + * fatfs.c: + - zero creation/access stamp on directory entry write as MS-DOS 7.10 + - prevent removal or renaming of the current directory of that drive + * ioctl.c: + - r_si/r_di contents added as documented in PC-DOS Technical Update + * inthndlr.c + - fix: for INT21/5F07 and 5F08, before changing bit CDSPHYSDRV, + MS-DOS checks if physical device associated with drive letter. Without + this check MS-FORMAT under FreeDOS was destroys RAMDISK. + - zero serial number of Int 21h/30h (else buggy 32RTM thrashed stack) [& Bart] + - set AX = ES after Int 21h/4Ah (undocumented but expected by BRUN45) + (the last 2 changes needed to fix bugs discovered by Michael Devore) + - added Int 2Fh/2Fh processing to set DOS version as per MS-DOS 4.0 ++ Changes Eduardo + * inthndlr.c: added Int 2Fh/26-29h processing for NLSFUNC (with Lucho) + + +2004 May 30 - Build 2035 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Lucho + Tom + * config.c, fatfs.c, globals.h, init-mod.h: From Tom: must + set r_bpfat for C_BLDBPB, otherwise USBASPI.SYS, DI1000DD.SYS + won't like us. From Lucho: use DiskTransferBuffer for deblock_buf. ++ Changes Lucho + * docs/fdkernel.lsm, stacks.inc, version.h, + entry.asm, inthndlr.c, io.asm, nlssupt.asm: no need to preserve + high part of ecx for Borland, ebx for MSVC + * device.h, dsk.c, init-mod.h, ioctl.c: MSC fixes and small cleanup + * ioctl.c: Cache attr and control flow optimizations (~120 bytes) + * device.h, dsk.c, ioctl.c: deal with the correct + structure for generic and query ioctls. Fixes issues with + 3rd party device drivers (or ones that use dsk.c) + * dosfns.c, inthndlr.c, proto.h: Merge dosmkdir and dosrmdir + * config.c: strcasecmp and set_strategy common code optimizations. + * main.c: Add necessary cast for BC + * portab.h: Avoid problem with BC declaring __emit__, en/disable twice. + * dsk.c: DJ mechanism without memcpy. + * newstuff.c: replace loops by fmemset/fmemcpy (43 bytes) + * dosfns.c, fatdir.c, fcbfns.c, ioctl.c: Some small cleanups. + * config.c: GetNumArg and misc other cleanups + * time.h, fatfs.c: converted TM_ENCODE into a function. + * inthndlr.c, proto.h, fatfs.c: Inlined dos_setdta. + Various bug fixes and cleanups from Lucho and Arkady. + * inithma.c: moved fmemcmp's into a checkHMA function. + * inithma.c: HMAFree == 0xfff0 - bytesToAllocate + is valid and may happen if the buffers occupy exactly all HMA + space up to and including the last byte at ffff:ffff. Failing + caused all buffers to go low ... + * inthndlr.c: cleanups (merge common code into long_check and + short_check). Made int21/3301,2e,54 consistent with MSDOS + behaviour. + * globals.h, task.c, main.c: Convert setvec into a function + for the resident code ++ Changes Arkady + * initdisk.c: initdisk optimizations (65 bytes) and is_suspect fix. + * config.c, init-mod.h, intr.asm: optimized allocmem() + * fattab.c, kernel.asm: optimizations + * main.c: Make signon one big printf function call. + * ioctl.c: bugfix for INT21/440b (change NetRetry if DX is _non_zero). + * inthndlr.c: cntry == 0 doesn't make sense for Set Country + Information. Fix int21/5e02+ + * sys/talloc.c: Turbo C really wants unsigned __brklvl. Only shows + up if you enable stack checking. ++ Changes Bart + * memmgr.c, proto.h, inthndlr.c: DosUmbLink no longer + tries to merge free blocks. Also cleaned up a bit. + * inthndlr.c: Fix int21/3302 (the swap was wrong, Lucho & Bart) + * config.c: Pointer-ise specificCountriesSupported accesses. + * config.c: Reorganized GetBiosKey a bit -- inlining + GetBiosTime saves a slight amount of code, converted timeout < 0 + to a blocking read instead of polling. + * config.c: Use strcaseequal instead of strcasecmp since we + never care about order anyway. + * chario.c: Fix problem with redirected input and + int21/ah=0a (debug < foo.txt) -- could get you an invalid opcode! + * console.asm, main.c, prf.c: Use int29 for kernel console + output. Enables ansi escape sequences in config.sys once you load + nansi.sys. It also saves a couple of bytes. + * newstuff.c, proto.h: made dosmktmp to return a long: + consistent with DosOpen et al and avoids the cast. + * mkfiles/tc2.mak: Let TC2 warn for the utilities. + * config.c: Disabled EBDA moves by default. Automatic EBDA + moves now happen using switches=/e:-1 + * config.c: Pointer-ize MenuStruct[MenuSelected]... (from + Lucho). and InstallCommands[i]. (from Bart). Some other small + optimizations. + * memmgr.c: Some small optimizations (46 bytes) and dead + code removal from Lucho and Bart + * init-mod.h: Need to define strchr to init_strchr otherwise + the wrong one may be called. + * initdisk.c: Do a bit of printf merging. + * filelist, drivers/makefile, init-mod.h, inthndlr.c, + task.c, globals.h, main.c: Convert getvec into a C function. + * int2f.asm: Clean up int2f assembly a bit (merge some + common bits, clarify label names) + * fatfs.c, fattab.c: fattab.c now remembers if the old FAT + entry was free or not, so the free space adjustment could be + moved back to fattab.c. + * init-mod.h: Replaced setvec macro by a function. + * entry.asm, inthndlr.c: Made int21/ah=25,35 reentrant. + Solves problem with Intel PRO/1000 driver. + * portab.h, globals.h, main.c: Initialise all int + vectors except the ones at 70:xxxx using a table. Convert setvec + into a function that disables/enables ints (init code only for + now, resident code will follow later); cli/sti (disable/enable) + are now macros (inlined). + * fnode.h, fatdir.c, fatfs.c: dir_read() no longer updates the + diroff counter. This eliminates the NEW field, + simplifies remove_lfn_entries(), and avoids a bug if you delete + the first entry in the root directory on FAT32. + * fattab.c: Stop abusing "idx". The OW optimizer likes this better,too. + * fattab.c: Clean up FAT12 handling -- there's a portable + approach that's small too. + * fattab.c: Inlined much of getFATblock() into link_fat. + Saves the idx reference. The second call (for a FAT12 entry that + is divided in two sectors) can be much simpler, no need to + recalculate. Merged next_cluster and link_fat into one + function depending on a special Cluster2 value. + * fattab.c: Calculate the nibble/word/dword index of the FAT + entry in the sector centrally in getFATblock. + * fattab.c: "clussec" can be of CLUSTER size if we divide by + an adjusted "words per sector"(FAT16), or "dwords per + sector"(FAT32) value instead of multiplying it first. For FAT12 + the *3/2 works out a little differently: here we first multiply + by 3 and then divide by the number of "nibbles per sector". + * main.c: Config.cfgInitTail is a pointer now so sizeof + isn't good. Just using strcpy helps F5 and F8. + * main.c: "copyright" is near now so we have to use %s and not %S + * blockio.c, dosfns.c, int2f.asm, network.c, proto.h, task.c: + reduced the number of network redirector functions in + int2f.asm. The remote_ functions (with one far pointer + argument) are now called with the help of a + network_redirector() wrapper in C by one multiplex function + using a generic void *arg argument to pass the third + parameter which can be various things. + Split int2f.asm functions, don't let them preserve as many + registers, use pascal calling convention for the "open" + (but really: multiplex) function. + * dsk.c: floppy determination type optimization for format -- + based on Arkady's suggestions a long time ago. + + a few other small optimizations (~70 bytes total). + + +2004 Apr 17 - Build 2034 +-------- Bart Oldeman (bart@dosemu.org) + * break.c, chario.c, inthndlr.c, proto.h: Improve ctrl-c/ctrl-break + handling: + - read_char_sft_dev handles ^C at a fairly high level. + - ^C didn't work for int21/ah=3f. Corrected + - Do_DosIdle_loop still needs to wait even if it doesn't call the + idle int + - ^C needs to be echoed to STDOUT for low character functions + (ah<0xd) but to the device that is read from for handle + functions. So we need to pass either the STDOUT sft or that + device on to the ^C echoer which now correctly prints ^C\r\n. + - misc cleanups in break.c. + * main.c: Move memset up a little else it would overwrite too much. + * build.txt, config.c, init-mod.h, initdisk.c, inithma.c, main.c: Lucho + reported that MSC compiled kernels now work after all. Let's mark + those nasty "BSS" variables explicitly then to try to avoid + future problems. Also DATASTART should be FAR and not DOSFAR for MSC + * stacks.inc, generic.mak, entry.asm, int2f.asm, kernel.asm, segs.inc: + (suggested by Arkady): use CPU to enforce 8086 etc instructions. + * ioctl.c: Correct int21/ax=4401: returned AL = old value, should + set CY and DE_INVLDDATA if DH!=0 (RBIL is a little confusing here). + * memmgr.c: Converted nxtMCBsize back to a macro. There is no need + to use far2para; FP_SEG works fine since MCBs always have offset 0. + * build.txt, config.c, config.h, kernel.asm, main.c, segs.inc, task.c: + Removed obsolete BYTE cfgCSYS_fnam[NAMEMAX]; config variable. Changed + cfgInit and cfgInitTail to pointers, adjusted some code to cooperate. + * chario.c: The screen position (for TABs) is only for raw + *CONOUT* devices already updated in dosfns.c + * memmgr.c, proto.h: Make unnecessary far pointers near. + * device.h, dsk.c, initdisk.c: Move the ddt bitfields to + df_descflags. Let SetLogDev call GetLogdev, eliminating common code. + * init-mod.h, mscl8.mak: Some vars need to be DOSFAR; + init code is no longer tiny but small. + * segs.inc, inithma.c, main.c, asmsupt.asm, execrh.asm, init-mod.h, + kernel.asm, watcom.mak: + Make CS the same for INIT and HMA text for Watcom. Move HMA text + up in kernel.asm. Use std for the memory move: helps if there's + overlap (PCs with a very low amount of RAM). + No longer include duplicate execrh, asmsupt, and u8m/d functions + for the init text in the Watcom compiled kernel, since they can + be called "near" in the resident code. + * portab.h, kernel.asm, main.c, segs.inc: + Use the "small" model for the init code (split code/data). + * main.c: Use pointer to MK_FP(0,0x5e0) to save a bit of code. + * initdisk.c: Move some common code into a "push_ddt" function. + * sys.c: Correct int25/26 pragmas. Need to explicitly preserve bp + and pop flags. + * initdisk.c: fmemcpy->memcpy where possible + * config.c, init-mod.h, inithma.c, int2f.asm: Make + UMB_get_largest "pascal". Let it use the xms driver address from + the HMA code. Misc small config.c cleanups. + * initdisk.c: "Cache" far drive data table near. Enables elimination + of many far pointers in initdisk.c. Also clear up the + unnecessary casts in ConvPartTableEntryToIntern. + * drivers/getvec.asm, drivers/rdpcclk.asm, drivers/wratclk.asm, + drivers/wrpcclk.asm, globals.h: Use pascal calling + conventions for all clock related asm functions. + * drivers/floppy.asm, dsk.c: Use pascal calling conventions + for floppy asm functions. + * init-mod.h, intr.asm, proto.h, kernel.asm: Use the + pascal calling convention for all intr.asm functions, and let + them pop the stack (smaller code than using bx). Tell Watcom + which registers are clobbered; save some more registers for + intr() -- especially for intr() this helps. + * device.h, execrh.asm, init-mod.h: Use pascal calling conventions + for execrh(). + * mkfiles/watcom.mak: Use the "-r" switch for Watcom to preserve ES + around calls -- saves ~350 bytes. + * sys.c, init-mod.h, fdkrncfg.c, portab.h, prf.c, proto.h: + Introduce VA_CDECL: only Turbo C 2.01 needs an explicit cdecl + for printf, all other compilers can use it with pascal or + "register" calling conventions. Saves ~50 bytes for the init code. + * asmsupt.asm, config.c, init-mod.h: Use strchr and strlen + more often; also use strchr in the init code. + * memmgr.c: Better to call fmemset than to do things manually. + * asmsupt.asm, proto.h, init-mod.h: Be more specific about + which registers are clobbered by asmsupt.asm functions. Preserve + "ES" for Watcom. Saves ~150 bytes resident, ~90 bytes + nonresident, more for 386 kernels. + Preserve bx and cx for WATCOMC as well. Saves another 200 bytes. + * inthndlr.c: Simplify memory access mode check. + * dsk.c: Remove wrong "512" value for number of root directory + entries on FAT32 partitions. + * file.h, sft.h, dosfns.c, fcbfns.c: Get rid of SFT_M* mode + values. O_* values are sufficient. + * file.h, fatfs.c: Define O_ACCMODE and use it instead of "3" for + the open access mask. + * config.c, init-mod.h: Change default STACKS= size to 256. + * config.c, init-mod.h, main.c: Remove lpOldTop variable. + It is no longer necessary (has not been for some time) and the + assignment in config_init_buffers() was wrong (screwed up fnodes, + so that buffers overlapped fnodes...). + * lol.h, config.c, fatfs.c, globals.h, kernel.asm, proto.h: + Made the main fnodes far so they can be in the HMA. + Internally the kernel uses two near fnodes though, to save on + codesize and fmemcpy's if necessary. Having memory management on + two fnodes is a little silly but I just want to make sure with + the panic message that we never accidentally try to use three near + fnodes at the same time (two are used at the same time by rename, + commit, and merge_file_changes). This can be cleaned up later. + * fatfs.c: + - Merge three almost identical pieces of code used to allocate a new + directory entry in creat, rename, and mkdir into alloc_find_free. + - Merge find_fat_free() and extend() -- they were almost + identical. Have a simplified clause for f_cluster == + FREE. Set f_cluster = FREE in shrink_file if the file is set to + 0 bytes; in that case we should set the current cluster to FREE + even if it is currently a LONG_LAST_CLUSTER. + * fnode.h, fatdir.c, fatfs.c, lfnapi.c: + - Eliminate f_back field. extend() now uses f_cluster instead of + f_back, while map_cluster makes sure it's not set to + LONG_LAST_CLUSTER (but to the cluster before it) when calling + extend(). extend() and first_fat() now return the new cluster + number or LONG_LAST_CLUSTER, just like find_fat_free(). + - Eliminated f_sector and f_boff fields from fnodes. + - Avoid bitfields for fnodes, using flags instead. Replaced droot + field by checks for f_dirstart == 0. + - Make f_diroff an entry offset so it can be 16bits. Enforce the + 65536 entry limit in dir_read(), except for root directories. + For root directories it's checked against a different limit + later. Saves 80 bytes or so + 2 bytes in every f_node. + * dsk.c, fatfs.c, memmgr.c: Remove add_far. adjust_far can do the job. + * chario.c: Echo input LF as CR-LF unless it's the first + character. Never store LF in the buffer. + * memmgr.c, task.c: Eliminated long2para and avoided use of "long"s + in DosExeLoader, using paragraphs to measure size instead. Saves + ~130 bytes together. + * prf.c, asmsupt.asm: Saved ~75 bytes in printf and by elimination of + fstrlen. There's only one call; inlining doesn't increase the size. + * dosfns.c, int2f.asm, intr.asm, nls.c: Eliminate intr() + from resident code. Saves ~200 bytes of HMA resident code. Also + made the nls.c functions SS!=DS safe. + * init-mod.h, inthndlr.c, intr.asm, main.c, proto.h, task.c: + int21/ah=26: new_psp now copies the old psp and just sets a few + fields int21/ah=55: child_psp does the rest init code does the + init (fixed values are always copied now) + * dosfns.c: Commit each close, even if the ref count is > 0. + * prf.c: Borland C didn't like one pseudo register use. + * initdisk.c: Merge "suspect partition" copy/paste code into functions. + * asmsupt.asm: Save a couple bytes by moving the strncmp_retzero block. + * fcbfns.c, proto.h: Don't call truename from FcbNameInit(). It + was only necessary for "FcbRename", which can call it itself. + Fixes for FcbOpen/FcbFindFirstNext a consequence of + truename's funny behaviour: truename(c:nul) = c:/nul and + truename(c:/nul) = c:\nul. Fixes the EJECT problem from Lucho. + Remove unused variable lpFcb. + * portab.h, dsk.c, main.c, newstuff.c: Define I386 and I186 more + cleanly. Add (UWORD) casts to silence the compiler. Optimize + (head*sector) to secs_per_cyl. Add BORLANDC to compiler list + and simplify startup printf to one message. + #pragma enable_message(130) for Watcom C causes it to + behave a little more like Borland in terms of warnings. + * exeflat.c, fatfs.c, fattab.c, fcbfns.c, inthndlr.c, + memmgr.c, task.c, blockio.c, fatdir.c: Added explicit + (UWORD) type casts to avoid compiler warnings and sometimes save + a few bytes too. Also changed the FcbParseFname return value: + returns offset portion of pointer (SI) instead of the number of + bytes to be added to SI. ++ Changes Lucho + * task.c: fixes the CHKDSK I: "Invalid drive specification" bug + * mcb.h, inthndlr.c: save 33 bytes by eliminating a switch for + memory/UMB access modes. + * talloc.c: talloc won't work with MSC (no sbrk or brk available) + + fix + * stacks.inc: smaller Protect/Restore 386 register macros. + * inthndlr.c: Code size reduction and dead code removal. + * dosnames.c: Remove wrong automatic "*.*" code from Lixing + Yuan -- return DE_PATHNOTFND or D_NFILES instead + * ioctl.c: move the lock/unlock simulation of success before the + device GENIOCTL check so that it applies to any device. + * filelist, dosnames.h, dosfns.c, dosnames.c, fatdir.c, fatfs.c, + globals.h, init-mod.h: (with Bart) -- remove the dosnames path + 67 length check. Review the places where it really matters (chdir + and mkdir). + * init-mod.h, intr.asm, kernel.asm, main.c, procsupt.asm, + proto.h, task.c: enable interactive re-execution of the SHELL. + * nls.h, config.h, globals.h, init-mod.h: move NLS #defines to + nls.h. Move config structure to config.h. Some cosmetic changes. + * contrib.txt: From Lucho: update contributors list. + * config.c: From Lucho: fix EBDA problems with INSTALL. This + fixes the weird fmemcpy lockup; in reality kernel init code was + overwritten. + * asmsupt.asm, config.c, init-mod.h, inithma.c, main.c, makefile, + prf.c: Use asmsupt string and mem functions for the init code too. ++ Changes Arkady + * task.c: A few suggestions. Saves 5 bytes. + * inthndlr.c: Use AL, not AX, for int2f/ax=1213, as per RBIL + * inthndlr.c: Use xreg struct and macros to optimize the + int2f/12,4a handler a bit ~25 bytes + * config.c: Buffer config fixes. + * inthndlr.c, proto.h: Corrections to int2f/ax=4a01/2. + * blockio.c: buffer intersection check should use > instead + of >=. small optimization -- the segment in bp == firstbuf is + always the same so we just need to compare offsets. + AllocateHMASpace needs to check FP_SEG(firstbuf) for 0xffff, + since the buffers may not live in the HMA. + * *.bat, config.b, kernel/makefile, generic.mak: .BAT file and + makefile cleanups. Also Lucho reported that nmake/nologo doesn't + always work in 4dos, but nmake /nologo works. + + +2004 Jan 31 - Build 2033 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Bart + * config.c: allow "0" in full-screen config menus and plug a + few potential related overflows. + * sys.c: correct sectors/track, head and hidden sector values + if the boot sector disagrees with the default bpb (unless the + default bpb says that the number of hidden sectors is zero (usual + for floppies)). + * config.c, main.c: Only put PATH= in the environment if + it's still empty just before executing the shell. This repairs + SET PATH=.... in config.sys without confusing anyone. + * fatdir.c, fatfs.c: Fixed bug #1722: dir_close() was + called for normal files (via map_cluster and find_fat_free). This + completely messed up rwblock. Removed these calls (for + directories they are already covered at a higher level) and added + a few sanity checks to dir_close and dir_write. + * chario.c, inthndlr.c: Expand tabs for int21/ah=2,9 even + in raw device modes and if stdout is redirected. This solves bug + 1737 (grep2msg problem) + * ioctl.c: Adapted from Chris Rodie's patch for bugzilla + #1730: do a device input status request for int21/ax=4406 for + devices (not for files). Save ~100 bytes by replacing + s->sft_flags with flags, s->sft_dev->dh_attr with attr and + simplifying the if() statement a bit + * hdr/sft.h, dosfns.c: Adapted from Chris Rodie's patch + (bugzilla #1729): "open" and "close" should call the open/close + functions for devices using a device request when appropriate. + * hdr/fat.h, fatdir.c, fatfs.c, fattab.c, prf.c, proto.h: + + FAT32 kernels should ignore the upper word of the cluster + number for FAT16 partitions (just like FAT16 kernels do) + + added extra checks to make sure that invalid FAT entries are + never followed + + print a message in case of FAT corruption + + some small optimizations and header cleanups (some suggested by + Arkady) + * config.c: Make strupr code unambiguous + * filelist, sys/makefile, sys/sys.c, sys/talloc.c: ~1K size + reduction for sys.com by using Tom's talloc.c malloc/free + functions and using our own filelength for watcomc. + * initdisk.c: Better (for FAT32) and simpler FAT default + value calculations. Also use 16-bit instead of 32-bit quantities + where possible to save code size. Use a FAT32 table so that FATs + won't be too big for drives <= 64 GB + * dosfns.c: Do not clobber the DTA if findfirst or findnext fails. + Fixes bug #1712 + * fatfs.c: Rename blockio by rqblockio (namespace conflict with dsk.c) + * inthndlr.c: FAT32 kernels should fail int21/ah=71 with + al=0, carry set. + * hdr/portab.h, nls.c: (as reported by Tom) Fix nls upcase problem + with SS!=DS. + * fatfs.c: Move permission check to better place (only for + necessary for opening existing files), not for creating them -- + suggested by Steffen. Force r/o open for FCB and legacy creat + if the file is read-only + * fatfs.c: Move common code in media_check() to a new + blockio() function. + * fcbfns.c, globals.h, inthndlr.c: Change FcbReadWrite to + handle multiple records at once; this allows for the optimization + of FcbRandomBlockIO. + * fcbfns.c: Divide optimisation (ceiling) + some small cleanups + * fcbfns.c, globals.h, kernel.asm: Rename the global lpFcb + variable to sda_lpFcb. Then use local lpFcb variables where + necessary. This clears up the confusing shadowing. + * fcbfns.c, inthndlr.c, proto.h: Fix FCB problems with + int21/ah=27,28 (RandomBlockIO) + * boot32.asm: jmp -> jmp short (necessary for nasm 0.98) + * dosfns.c, inthndlr.c, proto.h: Implement support for + int2f/ax=1220. Fix int2f/ax=1216 (needs sft handles, not psp + handles, and to return the relative handle in BX, and to deal + with carry) + * boot.asm: Fix problem with FAT12 ++ Changes Eric Luttmann : + * main.c: Fix for multisegmented device drivers: If there are multiple + device drivers in a single driver file, only the END ADDRESS + returned by the last INIT call should be the used. It is + recommended that all the device drivers in the file return the + same address. This fixes a load problem with DUSE. + * config.c, init-mod.h, main.c: fix for multi-segment device + drivers; preserve rq_endaddr between init calls for the same driver. ++ Changes Lucho: + * inthndlr.c: Remove AL=0 check for AH=6c (from Arkady) Optimize DL check. + * main.c, serial.asm: (with some help from Tom): + initialize serial ports and retry serial reads on timeout. + * sys.c, boot.asm, boot32.asm, boot32lb.asm: + SYS 3.0 changes: added /L parameter to SYS to be able to change + the kernel boot segment + a few boot sector changes to get the + pointer at the same magic place for all boot sectors. + * makefile: clean up *.lnk files for "clean" and "clobber". + * dsk.c: the DJ mechanism needs to affect MEM 0050h:0004h - MS-DOS + LOGICAL DRIVE FOR SINGLE-FLOPPY SYSTEM (A: / B:) Size:BYTE + * int2f.asm, generic.mak: basic implementation of INT 2F/ax=4a33 - + CHECK MS-DOS VERSION 7; necessary for SpinRite (Steve Gibson) + * inthndlr.c: implement int2f/ax=1211 NORMALIZE ASCIZ FILENAME + * config.c, init-mod.h, main.c: Added SET support to config.sys + + +2003 Sep 24 - Build 2032a +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Bart + * fix segment problems with ctrl-c and character uppercase + handlers + * fix critical error callers to set the critical error code + immediately before calling the handler (in case they call + DOS-59); don't set the critical error in inthndlr.c if + something else already did. Return with an errorcode if + "truename" and "read"/"write" encountered a critical error. + * sys.c: add /k kernname.sys option to and straighten out SYS option + processing; remove the metakern magic. + * config.c: ignore the segment part for multi-part device drivers + + +2003 Sep 21 - Build 2032 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Rune Espeseth (modified by Bart) + * config.txt, config.c: Full screen config.sys menus (use MENUCOLOR=) ++ Changes Michal Bakowski (mb@orad.pl) + * initdisk.c, kernel.asm: Change the boot drive to always + be C: if DLASortByDriveNo==1 ++ Changes Arkady + * dsk.c: Use memcpy instead of fmemcpy; avoid downcasting + from far to near. + * sysclk.c: err if sizeof(struct ClockRecord) != rp->r_count + move year init below reading the BIOS + * main.c: init_device corrections/cleanups + * device.h: Change r_status and dh_name to unsigned quantities. + * task.c: Free memory if there is an error in the relocation + table. + * floppy.asm, getvec.asm, rdatclk.asm, rdpcclk.asm, wrpcclk.asm: + driver .asm files optimizations (also from Bart); remove + obsolete rdatclk. + * build.txt: Fix some typos. + * inthndlr.c: Add missing (); small optimization for DosGetdate/time. ++ Changes Lucho + * boot.asm, boot32.asm, boot32lb.asm, sys.c: add metakern support: + sys looks for a file metakern.sys which is a multiple of 512. + * break.c: Fix ctrl-break bug. + * ioctl.c: IOCTL 4406 provided reverse AL output on regular + files - FF if EOF, 0 if not. It should output 0 if EOF, FF if not. + * initclk.c: Initclk changes + * config.c, init-mod.h, initoem.c: Support for + switches=/e[[:]nnnn] and for moving the EBDA + * fatfs.c: Use 0x10000UL (avoids Turbo C warning) + * sys.c: Move manually added "RCS" entries to the CVS log. + * main.c: Adjustments for MSVC. + * ioctl.c: int21/ax=440d lock/unlock logical/physical volume + simulate success for MS-DOS 7+ SCANDISK etc. --LG + * main.c: && should be || in check for \, / and : + * task.c: Adjust registers used when starting programs. Some + demos expect undocumented values (with Bart). + * mscl8.mak: Forgotten HMA_TEXT for MS compilers. + * sys.c: Add lock/unlock drive to SYS + * history.txt: Changelog correction. + * fatfs.c: Use near bpb on the stack in bpb_to_dpb. Make + sure the number of FAT sectors is actually enough to hold that + many clusters. Otherwise back the number of clusters down + * procsupt.asm, proto.h, task.c: Don't disable a20 for + "exit" int21/ah=4c ++ Changes Lucho, Tom, Eric + * boot.asm, boot32.asm, boot32lb.asm, makefiles, sys.c: + * boot.asm modified to support non-512 byte sectors + (e.g. 1.2 MB NEC diskettes) + * 512 byte sector size check removed (although Eric's boot32ea.asm + does require 512-byte sectors, all LBA FAT32 volumes have + 512-byte sectors anyway). + * boot.asm cleaned up and modified to support Metakern + bsDriveNumber updated by SYS even #ifndef STORE_BOOT_INFO + * (nothing in common) + * SYS Now supports and includes the following new boot sectors: + 1) the combined CHS+LBA FAT12/FAT16 boot sector by Tom Ehlert(29 July) + 2) the CHS-only FAT32 boot sector -- as patched by Jon Gentle(08 July) + 3) the LBA-only FAT32 boot sector by Eric Auer and Jon Gentle (19 July) + * The old combined (CHS+LBA), no-CALCPARAMS, no-resizable, non-Ghostable, + non-standard FAT32 boot sector and STORE_BOOT_INFO is no longer used. + * dump_sector() showed ASCII debug printout for the old sector + only - fixed. + * Put a boot sector only if sector size= 512 (may it not be so in + Japan?!). If non-512 byte sectors encountered, report to the + fd-kernel mailing list. + * Now puts boot sector before copying kernel/shell so it works in + WinNT now. + * check_space() now implemented at last (required significant + modifications) + * New (FAT type) detection method according to a MS White Paper. + * Now BOOTONLY works even without preceding boot sector image file name. + * Some minor code cleanups. + * Bart: some cleanups to the above; replaced 386 code for CHS FAT32 + by 8088 code. Use boot32lb.asm instead of boot32ea.asm ++ Changes Bart + * portab.h, process.h, init-mod.h, inithma.c, kernel.asm, main.c, task.c: + * add support for the far jmp at "int 30" (0000:00c0) + * mirror it for the HMA (ffff:00d0) + * put all DOS int handler (and the CPM entry jumped to from + int30) jumpers in the "CONST" portion of DGROUP (instead of + LGROUP) This helps Turbo C++ 1.01 make with the -S (swap) + switch. + * adjustments to set the relevant PSP fields in task.c + * blockio.c: Always use huge block sectors if the relevant bit is + set in the device header. This solves a problem with xmsdsk. + * chario.c: Small optimizations + * clobber.bat: Remove duplicate clobber. + * Flip some slashes for Linux compat and simplifications in makefiles + * device.h, portab.h: Use STATIC=static for watcom C (statics + are in the mapfile); remove some cruft. + * makefile, wlinker.bat: More verbose mapfiles for watcom + C; some slash preparations to allow cross-building on Linux + * exeflat.c, patchobj.c: Fix warnings reported by Turbo C + * break.c, chario.c, dosfns.c, globals.h, inthndlr.c, + proto.h, systime.c: (with a little help from Arkady) + Simplifications and cleanups. + Pass a near pointer to the far pointer that points to the device + instead of an SFT index (in general). + Make cooked_write much faster by only testing for input every 32 + characters. No longer test for ctl_s on syscon if writing to + the printer: just read from the printer which will return zero + characters. Fix reading/writing zero characters by returning + "256" (special code). Adjust interfaces in other files. + * portab.h: New UNREFERENCED_PARAMETER macro that appears to + work for all compilers. + * floppy.asm: Remove unused code. + * init-mod.h: Solve compilation problem with Borland C++ 3.1 + * config.b: "-p" is no longer necessary in config.bat + * kernel.asm: Add necessary "BootHardDiskSeconds" for non + UPXed kernels. + * chario.c, dosfns.c: Add necessary casts to ? : constructions; + cleanup read_line_handle a little. + * portab.h: Add peek and poke #defines + * chario.c: Fix pointer overflow problem for reading line using handle. + * makefiles, exeflat.c Clean cleans a bit more; change () to (void) + * main.c: Set the PSP before the DTA. This solves an interrupt + vector table corruption. + * kernel.asm: Use "local" (instead of "global") disable/enable + A20. This solves the problems with NIOS. + * asmsupt.asm, misc.c, proto.h, strings.c: Remove (unused) strncpy. + + +2003 Jul 19 - Build 2031 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Luchezar Georgiev + * (with Bart) add extra low disk buffer to avoid HMA + problems with certain device drivers. + * Add an extra space character at the end of the command line + for device drivers to prevent wrong behavior at empty command line. + * point to a correct environment for INSTALL= + (fixes problems with xmsdsk). + * change device driver error code check (using S_ERROR | S_DONE) + (fixes problem with the SystemSoft PCMCIA socket services driver) + * correct parameter order in inthndlr.c, chario.c + * INSTALLHIGH correction. ++ Changes Tom + * Fix a problem with the 'BootFromHarddiskIfNoKeyHit' option. + that occurred with some Compaq and Fujitsu/Siemens highend equipment. ++ Changes Bernd Blaauw + * config.txt updates ++ Changes Steffen Kaiser + * NLS adjustments ++ Changes Bart + * Correct problem with multiple UMBs (bug #1671) + * main.c: there aren't lastdrive open file handles but a + maximum of 20. + * Make "unable to disable A20" message #ifdef DEBUG only. + * config.c,main.c: Small size optimizations (some proposed by + Arkady Belousov) + * asmsupt.asm: Removed unnecessary jcxz's (Arkady) + * intr.asm: intr() cleanup and small optimizations (Arkady) + * Use PASCAL calling convention by default for Turbo compilers. + * Move more externs to header files + * SFT init cleanup (+3 files need to be low) + * config.c, main.c: Fix bug in block device driver init of + DPBs (bug #1969, TDSK problem) + + +2003 Jun 18 - Build 2030 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * if user left accidentally floppy or CD in drive, + give him a chance to continue to boot from HD. + disabled by default, enablable by SYS CONFIG + (BOOTHARDDISKSECONDS) ++ Changes Lixing Yuan + * dosnames.c cleanup, fix for truename if the filename + contains wildcards and a trailing dot. ++ Changes Eric Auer + * add sanity check to initdisk.c for (driveParam->chs.Sector == 0) + + some display tweaks + * add EECHO (echo with $=ESC) support to the config.sys parser. + * distinguish between the builtin DOS version and the settable + DOS version. + * console.asm now accepts extended scancodes (modified by Bart, fixes + bug #1657) + * added BOOTONLY option to SYS (modified by Bart) ++ Changes David Bolen + * add support for UNC-style paths (that start with "\\") ++ Changes Luchezar Georgiev + * add Bulgarian country structure data ++ Changes Bart + * flip some slashes in drivers/*.asm + (enables cross-assembly on Linux) + * remove superfluous printf("\n") in patchobj.c + * combine the INIT class with the CODE class (classes can span + multiple physical segments) + * re-add _TEXT to LGROUP to be able to simplify the patchobj magic + * don't specify -zPI_GROUP for the init code in Borland compilers + (unnecessary, it will be put there because of segs.inc) + * remove STDPATCH; it is no longer necessary + * add FILESHIGH, LASTDRIVEHIGH, and STACKSHIGH and DOSDATA=UMB + to load these structures into UMBs + * make DOS sub-MCBs visible (seen by MEM) + * preliminary allocation of FILES etc. now takes place at the + top of conventional memory, and device drivers are loaded before + the final allocation takes place. + * handle multiple UMBs more correctly (but config.sys can use + only one UMB for devicehigh -- /Ln,xxxx is not yet implemented) + * minor size optimizations in newstuff.c, chario.c, dosfns.c and fcbfns.c. + asmsupt.asm: correct fmemchr (all n's) and *memset/*memcpy + (n==0) + * introduce lol structure for list of lists; avoid lots of + relocations + * avoid more relocations in the asm files by loading ds from + [cs:_DGROUP_] + * Fix problem with attributes with the volume label bit + findnext + * SYS: avoid copying kernel.sys and command.com if the destination + is identical to the source (fixes bug #1656). + * Fix bug in DeleteBlockInBufferCache: needs to make the block + invalid, not flush it, if we're writing (bug #1635). + * added switches=/k/n/f support to the config.sys parser. + + +2003 Mar 14 - Build 2029 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * fattab.c, fat.h removed the wrong ELSE_ISFAT32() + * fatfs.c: rmdir would crash if you rmdir'ed an existing file + * config.c, main.c, portab.h + implement INSTALL and INSTALLHIGH for config.sys + basic COUNTRY=xxx support (with a little help from others, + mentioned in config.c) + * execrh.asm: save si, di for strategy device driver handler + * (adjusted by Bart): the internal "truename" has to reject + wildcards for all commands except for the exposed "truename" + (DosTrueName, int21/ah=60), FindFirst and FCB functions. ++ Changes Bart + * add top level makefile with list of files to zip for releases + * remove obsolete documentation and intr.h + * eliminated the "f_highwater" fnode field. + * reintroduced HMA_TEXT segment and adjust segments in libm.lib + to solve problems with Borland compilers. + + +2002 Dec 9 - Build 2028 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * move clock driver initialization to inittext + * new ELSE_ISFAT16 macro to save some bytes + * use _TEXT for old HMA_TEXT, _LOWTEXT for old _TEXT to get + a slightly less complicated memory model from the C compiler's + point of view. + * add support for int2f/4a01,4a02: query/allocate HMA space. + * updated config.txt ++ Changes Arkady V. Belousov + * slightly improved asm for print_hex and int2f clear_ax stuff + * use #error for unknown compilers + * remove hexDigits reference + * correct comment in kernel.asm (pad to 05fdh) ++ Changes Bart + * fix ss:sp init bug for int21/ax=4b01 (visible in DEBUG) + * fix redirection problem for character output routines + * fix press the any key message for floppy swaps + * correct cluster value for BAD cluster + * correct FAT12/16/32 cutoff magic values as per the MS spec + * the BUFFERS structure is now the same as in MSDOS 5+ and uses + a circular double-linked list using near pointers. + * move all old RCS log messages into one seperate file + * divide the fnode f_cluster_offset field by the size of a cluster: + this gives a more efficient map_cluster(). + * point the CharMapSrvc pointer to the DOS DS for AARD compliance. + * nls.c: set CX to cooperate with load_unf.exe + + +2002 Nov 9 - Build 2027 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * memset ErrorAlreadyPrinted to 0 in config.c ++ Changes Bart + * reset drive before and after int26 in SYS for winnt compatibility + * propagate sharing bits correctly in DosOpen + * return DE_NFILES if a volume label is not found; search for volume + label if attr & 8 not just if attr==8 + * initialize the critical error code to 0 in inthndlr.c + * ignore value of DH for extended open int21/ah=6c + * fix problem with NULL device code being in the wrong segment + * Hopefully innocent hack to deal with NDN in ioctl.c (ignore upper bits + of the drive number) + * use subst bit 15 for int21/ax=4409(IOCTL-CHECK IF BLOCK DEVICE REMOTE). + + +2002 Oct 27 - Build 2027rc +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Bart + * reorganized chario.c, got F1-F6, Ins, Del, etc. working + * fixed bug in extended open + * fixed bug in memory manager (realloc should try to defragment; + UMB fixes) + * consistently pass sft_idx around for all SFT functions (instead of + the far pointer) + * lpUserStack is gone :) + * Idle interrupt: now uses disk i/o stack instead of error stack if it + re-enters DOS; can not be called from int21/ah=3f. It also checks + InDos now (as documented in "undocumented dos"). + * int21/ah=59 should use the disk i/o stack, not the character stack. + * get_cds: a uniform way to get the CDS for drive X which can do error + checking too. get_dpb: similar. + * task.c uses mid-level system file handles instead of PSP handles. + * SFT sequence is MS/DR DOS like: 0=AUX 1=CON 2=PRN + * int21/ah=4d needs to clear the return code after returning it. + * Removed need for "unusedretval" because some functions return a long int + now. + * Do not warn for some additional LBA partition layouts (begin/end + cylinder=1023) in initdisk.c. + * support int2f/ax=1213 (uppercase character) (ASCII only for now). + * fix for top of memory parameter to device driver - fixes problem + with DRDOS emm386 + * eliminated printf for non-init code -- use put_unsigned and + put_string instead + * better MK_FP for Turbo C++ 1.01 and later + * PSP related task.c cleanups + * use --best and new upx (1.23) for binary build + Changes Tom and Bart: + * Use Pascal calling convention for memcpy and friends in asmsupt.asm + * Fixed make temp file + * fix bug in DosFindNext + * misc makefile fixes + + +2002 Aug 3 - Build 2027test +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * enable LBA FAT16 booting + * workaround for redirectors that do/do not set the opencount + * int25/26 should fail for redirectors + * set the number of sectors per track in the INT 1E table when + reading/writing floppies + * disabled fatal() in error.c + * Disable the A20 line upon exec (int21/ah=4B). This is necessary for some + brain-dead exepacked programs. + * removed unnecessary "BUFFERS" fields + * proper check for network/non-existing drive for int25/26. + * save more bytes on the stack at various places + * made the local registers for inthndlr.c "near" instead of "far". + * fix bug in strchr handling for fcbfns.c (FcbParseFname) ++ Changes Steffen (but changed a lot by Bart) + * new truename (Bart: but without mapPath() style struct) + * merge open/create functions into one extended open function + * also honor the sharing bits better for "open" + * use local 8+3 path names in fatfs.c; merge name+extension + into one array + * take care of filenames that start with ASCII 5: they should be + treated as starting with 0xe5 + * exploit the fact that the filenames are already "truenames", + i.e., fully qualified in fatfs.c. This simplifies parsing a lot. ++ Changes Bart + * make "if exist c:\dir\nul" working + * honor "do not inherit handle on exec" flag for "open". + * improve the FCB functions so that they set the critical error code + properly + * next_cluster returns "1" instead of DE_xxx in case of failure. + * create one function to do binary character IO (used for CLOCK$ + driver and character drivers such as CON) + * better handling of ABORT/FAIL + * merge all read and write functions + * patchobj makefile correction + * printf uses va_list etc. + * quicker and more robust Watcom build + * use FS: and GS: for Watcom 386. + * workaround: don't use DL for floppy boots, but fixed A: + * disable unused functions in floppy.asm + * cleaner prototypes (thanks to gcc) + * reorganized ioctl.c; there was an uninitialized variable. + * inlined some functions of fattab.c + * added (f)strcmp, (f)memcmp and (f)memchr to asmsupt.asm + * initially suggested by Arkady: dsk.c FS_info copy optimization + * initialize a VDISK signature in the HMA + * sysclk.c: small size optimization + * small UMB fixes + * made the CDS into a proper array instead of a structure with + one member + * large task.c cleanups - + merge as much as possible from DosExeLoader and DosComLoader + (from Tom:) eliminate some structures in low memory + * main.c: slightly cleanup "SHELL=" line parsing. + + +2002 May 9 - Build 2026b +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * limit output at boot time somewhat + * GetCurrentDirectory should fail, if drive is accessible + * fixed some minor config.sys parser bugs and have the possibility + of things like 123?device=EMM386.EXE NOEMS + * shorter version of DosMemLargest() ++ Changes Bart + * repaired makefile dependencies + * implemented multi-sector writes, and re-merged + readblock()/writeblock() into rwblock () + * implemented int21/ah=1c for network drives (RHIDE needs this) + * initialize current_ldt for findnext (hinted by Steffen) + * check serial number for floppy disk changes where the drive + does not feature a changeline + * reset to root directory when floppy has changed + * cleaned up endian helpers {get,put}{byte,word,long} + * don't close file if disk is full + * enforce minimum of 9 sectors per track for INT1E (necessary for + some floppies on some XTs) + * clear carry when calling INT23 (ctrl-break handler) as per RBIL + * don't copy FCBs on exec if they are pointed to by FFFF:FFFF. + * resolved warnings for Watcom (now compiles with -wx -we) + * truename fix (return DE_FILENOTFND for foo.bar.foo) ++ Changes Jeremy + * fixed SYS _dos_getdrive for non-Borland compilers ++ Changes Tom and Bart + * cleaned up fatfs.c, fattab.c, sysclk.c (CLOCK$ driver), systime.c + + +2002 Feb 17 - Build 2026a +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Martin + * fixed SYS for non-Watcom compilers ++ Changes Tom + * set CONFIG environment variable to selected number of CONFIG.SYS + menu entry, for example for use in AUTOEXEC.BAT. ++ Changes Bart + * fixed FCBOpen + * network redirector fixes ; it appears that clearing CF before calling + the redirector is safer than setting CF + * allow creating, renaming and deleting volume labels using FCBs + * fix renaming with wildcards using FCBs + * some dosfns.c and fcbfns.c clean-ups + * booting from hard disk now always sets the default drive to C:, + not D: if booting from the second physical hard disk, etc (bug #1062). + + +2002 Feb 9 - Build 2026 +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * fixed various typos, #includes ++ Changes Bart + * fixed ECHO in config.sys + * made passing parameters to command.com more robust: + zero commandline before use, fixed buffer overflow for F5+F8 + * "uppermem_root" in the List of Lists is now FFFF if no UMBs + available, as documented in RBIL + * removed all direct hooks from init_text to hma_text; duplicated + the remaining functions (memset, memcpy and friends). + * bumped up default DOS version of FAT32 enabled kernel to 7.10 + + +2002 Feb 3 - Build 2026test +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * FCB clean-ups and fixes (bug in FCB Random IO, + CYRUS CHESS, bug #1014) + * initial config.sys menus (see config.txt) + * execrh.asm: construct 'interrupt' address after strategy to avoid + some issues with non-trivial 'strategy' routines. + * make kernel UPX-able + * cleaned up midnight flag, dates + * tmark() and friends are floppy specific and implemented in C + instead of ASM (parts by Bart) + * DMA boundary checking gives the right number of sectors if + the start sector is 512-bytes-aligned. ++ Changes Victor + * lfn fixes (lfn is only a place holder, does not work yet) + * FAT32 fixes + * dosemu log nicer ++ Changes Martin + * log output + * warning fixes for sys, patchobj and prf.c ++ Changes Bart + * FCB clean-ups and fixes + * make Watcom compiled kernel runnable + * make compilation with Pascal style calling conventions + for Borland compilers (-p) possible + * initialize CDS before opening devices + * implement lock/unlock for remote drives + * implement commit file (int21/ah=68,6a) + * implement ioctl get/set logical drive map (int21/ax=440E--F) + * implement get address of drive data table (int2f/ax=0803) + * fix "get address of SDA" (int21/ax=5d06) + * do not use CHS if the root extended partition of the relevant + logical partition is labelled LBA (bug #1011) + * hopefully avoid format problem (bug #1030) by not setting drive + to "non-accessible" while reading the bpb. + * boot sector fixes: + enable booting beyond cylinder x where x * number of heads >= 65536. + still uses CHS to boot (not able to boot beyond cylinder 1023) + recognize FF8-FFF as FAT12 ending (was only FFF) (bug #1021) + * avoid using LIB when linking the kernel by echo-ing to a linker + resource file. Use a batch file to bypass Borlands Make 2.0 + unwillingness to redirect stdout. + * UMB variable clean-up + * use of "const" for constant global variables + * reduced size of Watcom-compiled SYS binary + + +2001 Nov 18 - Build 2025c +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Bart + * ran source code .c and .h files through "indent" + * fixed new printf bug + * removed some duplicate documents ++ Changes Victor & Bart + * fixed sys.c fat32 detection bug (offset 0x10, not 0x2c) + + +2001 Nov 17 - Build 2025b +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * fix a few more batch file and makefile details + * fix problems with command line editing: F1 and right key + * string merging in dosnames.c + * optimizations for MSC ++ Changes Bart + * fix readblock problem not properly detecting EOF - it sometimes + returned an error where it should just report a short count. + Also fnp->f_offset==0 is not a special case for blockread + (neither should it be for write - but that'll be for later) + For both cases it's perfectly legal to do a seek first. + * fix writeblock not setting highwater to offset when doing a + truncate (count == 0) + * hopefully now really fix the floppy change problem - + dsk.c: getbpb() should query changeline BEFORE reading the BPB. + * fixed warnings from WATCOM compiler - one of them was in fact + a bug in fcbfns.c + * started big clean-up + - converted obsolete bcopy(), sncopy() and friends to memcpy(), + strncpy() etc. + - removed $Log entries that are also on the CVS server and + removed the $ so no new entries will be added in files. + indenting will be next - other fixes will be buried in diffs if + I do that now. + + +2001 Nov 12 - Build 2025a +-------- Bart Oldeman (bart@dosemu.org) ++ Changes Tom + * initialize LBA parameter struct to 0's - some BIOSes don't fill + in everything. Thanks to Bernd Blaauw's bug report. + * Minor boot sector optimization. + * added some exeflat options ++ Changes Jeremy + * changes to fdkrncfg.c: mostly cosmetic to the output + * added sys.doc file (updated by Bart) ++ Changes Bart + * let int 0 (divide by zero) and int 6 (invalid opcode) print a + stack trace to aid in debugging + * fixed floppy drive detection for XT's. + * fixed bug in int21/ah=0x32 and friends - we should flush data before the + forced media_check + * Use CHS addressing if possible on partitions with the relevant ID, + you can overide this using the new FORCELBA and GLOBALENABLELBASUPPORT + sys config options. + * Always use BIOS values for translating LBA to CHS for fixed disks - + ignoring the boot sector values. For floppies the boot sector is used. + * fixed "truename hello." to remove the trailing dot. + * added options to SYS to write to a boot sector image file + * set Critical Error Code for ioctl's + * fake cluster size for 64k clusters just like FAT32 for INT21/AH=0x36 + and friends. ++ Changes Bart+Tom+Victor + * make makefile system more robust ++ Changes Victor + * cleaned up map_cluster and dir_read (bug fixed by Bart) + * updated LFN API (in development, not used yet) + + +2001 Nov 4 - Build 2025a (test) +-------- Bart Oldeman (bart@dosemu.org) ++ Changes tom + * config.sys processing: placing ? on the left side of '=' like + ?device= or device ?= + asks for this single line + fill the available HMA with buffers + * added kernel configuration options to sys.com, small area at 60:xx + (in cooperation with Jeremy) + * readblock optimized to read as many data as possible in one + int13 request - great speedups for large reads + * some more SDA variables need to be updated for the network + redirector (the sft index) + * reduce stack usage in task.c, fattab.c, ioctl.c, execrh.asm, inthndlr.c + * protect high part of 32-bit registers (stacks.inc) + * moved copyright messages to init data to save a bit of memory + * added relocinf, patchobj, sorted + some more output of exeflat + * UMB fixes ++ Fixes Bart, Victor, Tom + * more FAT32 fixes - to work with device drivers + * fixed overflow problem with more than 2048 directory entries + * various space saving changes, dir_init_fnode ++ Changes Bart, Tom + * many makefile changes to enable compilation with different + compilers (MS, Watcom, Borland). Watcom compiles but the result + does not run yet. ++ Changes Bart + * extended the double-byte lead table from int21/ah=63 to 4 zeros + to make Watcom happy + * support for IOCTL AX=440D, CL=40,41,42,61,62 for + read/write/format track - this enables R. Nordier format to work + * default floppy type depends on the drive + * rewrote many parts of int2f.asm to have a cleaner remote_xxx + interface with less code and stack usage. + * limit for int21/ah=36 is FFF6 total/free sectors + * made the rtc clock reading code a bit more robust - assumes + there is no rtc if the returned date is zero + * removed non-necessary code in dosnames.c because we're always + dealing with a TRUENAME there + * added zero extending of files, but removed it (unless you force + it) since MSDOS doesn't zero-extend files either + * wrote a source for exeflat, removed all binaries from the source + * added more INT2F/AH=12 functions to solve some MSCDEX issues + * changed BAD sector handling : only ....FF7 is recognized as BAD, + but FORMAT information from initdisk will only give ....FEF as + the largest cluster (for safety), so ....FF0-....FF6 are not used + for newly formatted disks (here .... is either nothing, F, or + FFFF, FAT12/FAT16/FAT32). + * more fatfs/fatdir clean-ups - now unnecessary fields dfull, + dremote and dsize removed from fnodes. + + +2001 Sep 24 - Build 2025 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Victor + * More FAT32 fixes ++ Fixes Tom + * Printer handling + * misc INT2F/AH=12 fixes. + * misc clean-ups ++ Fixes Bart + * Added drive B: handling if only one floppy drive available + (look for play_dj() in dsk.c) + * Simplify Victor's FAT32 fixes a bit + * More printer clean-ups + * fixed sys (thanks Jeremy) + * DosChangeDir fails for path name too long. ++ Fixes Jeremy + * Changed SYS so if no source given or only source drive (no path) + given, then checks for kernel.sys & command.com in current + path (of current drive or given drive) and if not there + uses root (but only if source & destination drive are different). + Fix printf to include count(ret) if copy can't write all requested bytes + + +2001 Sep 22 - Build 2025 (test) +-------- Bart Oldeman (bart@dosemu.org) ++ Added Victor + * FAT32 support (credits to Martin Stromberg for boot32.asm optimizations) + * Delete long file names if short file name given ++ Added Jeremy + * modified SYS so it takes optional 2nd parameter (similar to PC DOS) + where if only 1 argument is given, assume to be destination drive, + but if two arguments given, 1st is source (drive and/or path) + and second is destination drive ++ fixes Victor + * some small FCB and dsk.c fixes ++ fixes Tom + * some FAT32 issues + * many compiler portability changes (compiles with Watcom, MSC, ...) + * DosMemChange should set the PSP + * converted INT2F/AH=12 functions to C and added some - enough to + get most of the MS LAN network client working ++ fixes Bart + * some FAT32 issues + * Dos{Open,Creat}Sft drive letter issues + for CDROMs (thanks Jeremy) + * shrink_file should ALWAYS fail for directories, also with + dos_set_fattr (thanks Jeremy) + * only give warnings for slightly suspect partitions at boot + time where CHS does not match LBA. + * re-enabled copyright notice. + * some dsk.c clean-ups to avoid DIR giving the same contents for + a different floppy (get serial number/volume label did reset the + changed state). + * attribute should be 8-bit fix + + +2001 Aug 19 - Build 2024/h +-------- Bart Oldeman (bart@dosemu.org) ++ fixes Bart + * truename fixes (#580) + * free space fixes (#249) + * Ctrl-C/Ctrl-Break fix + + +2001 Aug 19 - Build 2024/g +-------- Bart Oldeman (bart@dosemu.org) ++ fixes Bart + * set file time fixes + * clock fixes + * findfirst/next fixes + * added a bit more int2f/ax=12xx functionality + * buffers trick to fool MFT so that it does not crash + * Ctrl-S (pause) and Ctrl-P (printer echo) now work. + Ctrl-Q is ignored by DOS. + * FCB "closing twice is legal" fix. Necessary for visicalc. ++ fixes Bart + Tom + * fixed shsucdx /u unloading problem + + +2001 Jul 28 - Build 2024/f +-------- Bart Oldeman (bart@dosemu.org) ++ fixes Bart + * fixed get current directory - MSCDEX works now (always) + * initdisk.c correctly sets number of hidden sectors: necessary + for FORMAT - SYS chain to work ++ updates Bart + * initialisation memory situation changed: kernel is loaded + to the top of conventional memory in the beginning. Then + move it back low or high depending on DOS=HIGH and the presence + of an XMS driver. + DOS=HIGH without an XMS driver (such as FDXMS) has no effect anymore! ++ fixes Tom, Victor, Bart + * various fatfs.c fixes and clean ups + + +2001 Jul 23 - Build 2024/e +-------- Bart Oldeman (bart@dosemu.org) ++ fixes Tom + * dyninit allocation fix + * various clean ups ++ fixes Bart + * #define DBLBYTE in inhndlr.c. Necessary for PQDI + * FCB corrections and cleanups (with a little help from Tom) + * cleaned up (FCB)FindFirst/FindNext a little more. + * task.c: copies default FCBs, initializes AX properly and + an int21/ax=4b01 fix. Also closes all FCB opened files upon + termination of a program. + * dosnames.c: fixed DJGPP "ls c:/" problem reported by Martin ++ fixes Victor Vlasenko + * Makefile fix for dealing with Borland make 3.6 + * fix for fatfs.c shrink_file() ++ fixes Bart + * handle B: just like A: on a single floppy system. There still needs to be + user interaction like "Please put a floppy in drive B:". + * ioctl.c fix for INT21/AX=4400 + sft driveno field + * various small fcb fixes + * put file position number and pointers to Pri/SecPathName into + SDA. Now MSCDEX works as redirector (but still not always :-() + * redirector set attribute fixes + various cleanups + * truename+attr+ioctl fix => DJGPP libc compiles cleanly! ++ changes Bart + * use the output of truename() consistently: this saves a lot of + headaches in parsing later and also allows a lot of simplifying: + made many parameters in fatfs.c and fatdir.c NEAR ++ added Bart + * partly implemented the "Drive Data Table" see RBIL INT2f/AX=0803 + * implemented construction of default BPB in initdisk.c + * implemented the access flag in dsk.c + * printf writes to DOSEMU log if prf.c compiled with #define DOSEMU ++ fixes Bart + * dsk.c uses default BPB in the right places (with help from Tom and Brian) + * Brian's FORMAT now works + * Tab fix (bug reported by Martin Stromberg) + * INT21/AH=0x1f now simply uses AH=0x32 for the default drive ++ fixes Tom + * saved some static variables + * implementation of int_2f_111e_call() for network/LAN manager + * return AX=0001 for default redirector handler + * enable use of multiple UMBs + * fixed task.c 'LOADHIGH executables': minAlloc == maxAlloc = 0 + and an fixed overwriting the MCB + + +2001 Jul 9 - Build 2024/d +-------- Bart Oldeman (bart@dosemu.org) ++ fixes Bart: + * fixed Ctrl-C (Ctrl-S and Ctrl-Q still missing). + * ioctl EOF fix (DJGPP less&gdb problem reported by Martin Stromberg) + * INT21/AH=29 (Parse Filename into FCB) fix (NC problem reported + by Ken Martwick) with clean up from Tom. + * ioctl should do a media_check before calling the block driver: + this fixes bug #726 (first dir gave serial no. 1234-5678). + * initdisk.c now uses the init data segment. ++ fixes Tom: + * fixes for INT21/AH=32; this should cure the problems with + Brian's new format. + * more SYS fixes. ++ added Tom: + * some more diagnostics (123) to aid finding bugs when booting from + a hard disk. + +from 2001 jun 23 : KE2024BP + ++ fixes Tom: + * FAT FS: would not expand files correctly, if lseek() + beyond EOF (see also relnotes.txt) + * FcbFindFirst/Next made compatible with MSDOS CHKDSK + * saved even more bytes (now 24 buffers in HMA :-) + +from KE2024BM ++ added Tom: + * a mechanism, to regain near data (like miarray, bpbarray,...) + this is somewhat braindamaging, moving the kernel up and down, + working with different CS/DS combinations, but somehow working, :-) + miarray allocated, using this mechanism. + * made f_nodes near (2 K saving in HMA_TEXT) + this technic might as well applied to CDs, DPB, sft's, ... + this even saves a few bytes on stack :-) + +from 2001 May 21: Build2024L ++ Fixes Tom: + * Clustersize 64K made working (one small ULONG was missing) + * check for drive existence for INT25/26 + * NDEV = max number of possible harddisk partitions bumped + from 8 to 20 (my testconfiguration has 13) + ++ Added tom: + * LBA support for disks > 8GB (with the help from Brian + Reifsnyder, see also relnotes.txt) + * moved initialization for DISK (partition scanning) to INIT_CODE + + +2001 Jun 2 - Build 2024 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Tom: + * small fixes again. + * one possible cause for data corruption (BFR_VALID) detected + * directories with 'ARCHIVE' attribute could not be deleted + * saved even more bytes (now 20 buffers in HMA :-) + * some issues with pathnames around PARSE_MAX removed + * blanks in filenames weren't proper handled + * there was (at rare circumstances) a buffer overflow + while config.sys parsing. ++ Fixes Bart: + * INT 21 0A - Dos Buffered Input reworked + * init_PSPSet() fix for setting the PSP ++ Added tom: + * slighly better buffer handling (search BFR_UNCACHE) + now go more FAT+DIR sectors, less DATA sectors into cache + * dos_mkdir tuned (was ~0.5 sec on 64K cluster partitions) + +2001 Apr 29 - Build 2024 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Bart: + * fixed the "TYPE > FOO.TXT" poor man's editor. + * use "fast console output" (int 29) when applicable. + * moved 5 FILES to DOS DS:00CC and fixed the SFT linked list. + * cleaned up findfirst/findnext for redirected drives. + Tom: + * more VDISK changes (changed slightly by Bart) + * check for presence of A:/B: (changed by Bart to use the BIOS equipment flag + from INT11 instead of INT13). + * added F5/F8 stepping through config.sys; default SHELL=COMMAND.COM /P/E:256 + Use ESC to stop single stepping, F5 to skip remaining config.sys/autoexec.bat. + * new sys: uses INT25/26 instead of the low level INT13 related kernel code from + floppy.asm (see also comments in sys.c) + a few fixes (also boot.asm related) + from Bart. + * Hopefully fixed DateTime Changed + ATTRIB |= ARCHIVE bug. + * cleaned up dsk.c and saved more bytes. + Przemyslaw Czerpak: + * Default lastdrive should be 5 (E) not 6 (F). + * fixed not ignoring whitespace after '=' in config.sys + * noted INT21/AX=3800 bug for getting the country. Put in a workaround for now. + +2001 Apr 21 - Build 2024 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Tom: + * fixed a missing close_dir in fatfs.c. + * many reductions of stack space requirements. + we hope this fixes some FAT corruption problems. + Bart: + * fixed "copy con" and INT21/AH=0B. The SFT_FEOF flag, + strangely enough, if true indicates NOT end-of-file. + * VDISK signature required in HMA (bug 701 dborca@usa.net). + Alan Kamrowski + * fixed intr: it wasn't putting the flags back correctly + and swapped si and bp. ++ Update Bart: + * Changed initialization data segment to its code segment. + This frees up a few more kb. + * This required some header reorganisation: + init-mod.h is for the init modules, globals.h for all the + others. + * Eliminated the master environment, as it is normally + managed by command.com, not by the kernel. This saves 512 + bytes and command.com now copies a default environment from + 0068:0000; this is in the DOS_PSP at 60:0. + * Moved low memory code segment to 70:0. ++ Add Tom: + * Default interrupt 6 handler (invalid opcode). + +2001 Apr 16 - Build 2024 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes * Use turboc.cfg to avoid long command lines; edit ALLCFLAGS + in config.mak to enable DEBUG etc. + * Fixed critical error handler. + * Fixed loading .exe's in UMBs if not enough space available. + * Some device drivers require \r\n at the end of their + parameter line. + + +2001 Apr 16 - Build 2023 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes * Thanks to Martin Stromberg for pointing some bugs out: + * more warnings fixed. + * accidentally opened too many file handles at boot time. + * device drivers should not be linked into the device chain + if they do not take up memory. ++ Add * added printf "%S" and "%Fs" to print far strings. + * enabled and cleaned up INT21/AH=6C (extended open/create). + +2001 Apr 15 - Build 2023 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Tom: + * apisupt.asm not necessary anymore. + * fix warnings. + * Don't allow directories to be created in DOS_CREAT. + * LoadDevice: drivers should not hang the computer if they fail. + Bart: + * fixed SYS. + * made most calls near again, with a jump/stack trick to + switch between INIT_TEXT and HMA_TEXT. + * INIT_TEXT now calls INT21 itself for some things (setting + PSP, opening/reading/closing devices and (fd)config.sys). + * fixed some carry handling in inthndlr.c and + * drives are checked before trying to access them. + * fixed console driver "busy state" confusion: the built-in + driver had it wrong, nansi.sys had it right: + "If no characters in buffer, return BUSY". + * space savings (RTL related and various other places) + * redirector fixes for find_next. + * CREAT on a device file failed (FD said it already existed). + But for some reason it should not fail in DOS. + * get ATTRIB/other things on a device file should return + FILENOTFOUND, not PATHNOTFOUND. + The sft_status field is not used for redirected drives. + * DosSelectDrv checks the media before setting the default + drive. + * Fixed INT21/AH=3,4,5 (character R/W AUX/PRN). + Hans Lermen: + * critical error handler destroyed AH (entry.asm). + Martin Stromberg + * find_first for volume labels fix. + * check drive at more places and avoid drive "@:" for drive "':". + * config.m: comment out NASM= by default. + * printf fix with DEBUG on. ++ Add Tom: Introduce init_data segment. + New temp file creation implementation. + Bart: added INT21/AH=53. XMSDSK works fine now. + dynamic allocation of Drive Parameter Blocks (they are + all FAR now). ++ Update Bart: moved DOS_PSP to segment 0x60 as segment 0x50 is already used by + GWBASIC/BASICA + +2001 Apr 2 - Build 2023 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Bart: Volkov Commander revealed a few bugs: + -int 21/ah=55 forgot to set current psp to child psp. + -memory allocation: mem_access_mode was a signed byte, and hence 0x80 was + translated to 0xff80 and not 0x0080 when converting to a COUNT. Hence + changed it to become a UBYTE. + -An error in memmgr.c: search again in low mem for modes 0x80,81,82, not + 0x40,0x41,0x42 + * execrh.asm & int2f.asm: made code executable on a 8088 (no push + constant) + * entry.asm: made sure dos_crit_sect is executed when required to. + * Another redirector fix. int 2f/1122 needed DS=current psp. This caused a + bug for me: after compiling FreeCOM on a redirected drive "dir" did not + work any more. + * The nansi.sys problem: as it was, the initialisation phase of nansi + called int/ah=30, which checked control-break, which checks the console + driver, which at that point is the still not initialized nansi. This + messed up the request header passed to it. A solution I found is to link + a device into the device chain _after_ initialisation, not before. + * Redirector fix: network.c uses fmemcpy instead of fsncopy. + * Fixed INT 21/AH=6 (direct console input). + Tom: + * DE_NFILES instead of DE_FILENOTFOUND to allow Volkov Commander to browse empty + drives. + * Fixed bug wrt zero terminated device names (should be spaces terminated). + +2001 Mar 30 - Build 2023 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Tom: Kernel alloc initialises to 0. This avoids some weird errors. + Implemented default divide by 0 handler (INT 0) + FILES= fixes from config.sys. fatfs.c ignored it and always + used the default of 16. + Misc debug code removal. + int 21/ax=3306 report running HIGH fix. + int 21/ah=69 : save CX + InitializeAllBPBs() or MakeNortonDiskEditorHappy() + More extended information if MCB chain corruption occurs. + Bart: getdpb fixes (int 21/ah=32). + fix carry handling in int 21/ah=5e. + fix {get,set}_machine_name in network.c + saner lastdrive handling ++ Add Support for SHELLHIGH in config.sys + +2001 Mar 28 - Build 2023 +-------- ++ Fixes Bug fix release 2023b: dsk.c (reported by Nagy Daniel), inthndlr and + int25/26 fixes by Tom Ehlert. + +2001 Mar 27 - Build 2023 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Bug fix release 2023a: fixed stack segment bug in entry.asm. + +2001 Mar 25 - Build 2023 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes sys.com compilation: it is a proper .com and works again. + Suggestions from Martin Stromberg: warning removal and some + debugging related changes. + Suggestion from Aitor Santamaria Merino: implemented NUMLOCK=ON/OFF + in config.sys. Also implemented strcasecmp. + Updated intfns.txt; reported version is now 5.0. + + +2001 Mar 24 - Build 2022 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes Tom and Bart: cli/sti handling and other fixes in entry.asm, + procsupt.asm and apisupt.asm. + Bart: warning removal + other compile time fixes. + Tom: * more partition detection fixes in dsk.c. + * dos_gettime() fix. + +2001 Mar 21 - Build 2022 +-------- Bart Oldeman (bart@dosemu.org) ++ Clean A lot of space savings by Tom Ehlert, merely because Turbo C 2.01 does not + do it. And several more complicated situations as well, like coding some + string functions in assembly (asmsupt.asm). ++ Add Tom Ehlert: support for DOS=HIGH. Now most of the kernel can be loaded into + the HMA. This required a lot of segmentation changes. Let's hope the best + of it. Support for device drivers with multiple devices. ++ Fixes From Tom Ehlert: + task.c bug fix (image_size is in bytes) + dosfns.c change dir to E:\FREEDOS\*.PRJ fix + fcbfns.c fixes. + break.c Ctrl-C Ctrl-C -> crash temporary fix. ++ Fixes From Bart: + Let UMBs work again after HMA changes. + Be able to compile sys.com again. Is now really a .exe file but still masks + as .com in the hope that we can make it a real .com again. + DeviceHigh loads low if there are not enough UMB's available. + Fixed another redirector problem. ++ Update Optimized asmsupt.asm a bit with help of the glibc 2.2 source. ++ Fixes Tom Ehlert and Brian Reifsnyder: fix partition detection in dsk.c + + other bug fixes (also: floppy.asm). ++ Update Tom Ehlert optimized blockio.c. ++ Fixes a few small ones from Tom I forgot. + +2001 Mar 08 - Build 2022 +-------- Bart Oldeman (bart@dosemu.org) ++ Fixes MCB chain corruption fix (thanks Tom Ehlert and Martin Stromberg) + Redirector fixes (CDROMs and DOSEmu lredir'ed drives appear to work fine now) + UMB fixes + Various recodings (dsk.c, prf.c, portab.h) to make kernel + object footprint 3k smaller (Tom Ehlert) + Fix handling of very long path names (Tom Ehlert) + FindFirst/FindNext fixes (Tom Ehlert) + Configuration for libm.mak is in config.mak (Martin Stromberg) + NLS fix to include pointer to CharMapSrvc. Note: these are + changes to automatically generated .asm files, but the + generator (GRAB_UNF.EXE) is missing. (thanks Tom Ehlert) + DosSelectDrv fix (Martin Stromberg) + config.c always converts to upper case and handles dos=umb correctly + +2000 Dec 15 - Build 2022 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixes Added Patches from Bart Oldeman (bart@dosemu.org) + Fix for NLAST in globals.h and change default return in inthndlr.c. + +2000 Oct 29 - Build 2022 +-------- James Tabor (jimtabor@infohwy.com) + Rebuild local cvs tree after a crash. Update CVS at Sourceforge.net + with changes. + +2000 Sep 04 - Build 2022 +-------- James Tabor (jimtabor@infohwy.com) ++ ADD Adding Ron Cemer patch for Share support! + +2000 Sep 04 - Build 2022 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixes Brian Reifsnyder (reifsnyderb@mindspring.com) + Modified dskxfer() such that error codes are now returned. + Functions that rely on dskxfer() have also been modified accordingly. + Modified interrupts 0x25 & 0x26 to return more accurate error codes. + Updated dskxfer() prototype. + +2000 Aug 15 - Build 2022 +-------- James Tabor (jimtabor@infohwy.com) + 2000/08/12 22:49:00 Ron Cemer (roncemer@gte.net) + Fixed writeblock() to only use getbuf() if writing a + complete sector; otherwise use getbloc() and do a + read-modify-write to prevent writing garbage back + over pre-existing data in the file. + This was a major BUG. + + +2000 Aug 05 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) + Clean up and finish umb code to get 2021 out. + +2000 Jul 26 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Fix New patch from Ron IsDevice and truename fix. + +2000 Jul 14 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Add Added NLS patches from Steffen Kaiser and patch from Ron + (roncemer@gte.net). + +2000 Jun 25 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Add Add and Fix support for UMB's. + +2000 Jun 20 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Fix Bart Oldeman (bart@dosemu.org) found bugs with copy + command using Dosemu Lredir. Fixed Dosfns return for ReadCount, + WriteCount and DosGetFattr. Fixed the return in int2f.asm for + Read/Write Remote. By adding xor ax,ax. + I found some more return bugs in int2f.asm after adding Barts + patch. + +2000 Jun 08 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Add Started the UMB code. Devicehigh and dos=umb only works with + Dosemu for now. + +2000 Jun 07 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Add Int2f added code for Fastopen call. + Now MSD Scandisk works! + +2000 Jun 06 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Add Dos Func 0x59 and found a redirector bug in fncfns.c. + +2000 Jun 01 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Fix Lastdrive is a real number 1 thru 26 not 0 thru 25. ++ Fix Ioctl and Dsk did not return the currect AX for Ioctl calls. + +2000 Jun 01 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Clean Removed test prinf statements in source. +* Thanks to Lixing Yuan for pointing out an copy to root error. + +2000 May 31 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Patch Lixing Yuan (yuanlixg@china.com) Patch for parsing bug in + FindFirst with wildcards -> ParseDosName (dosnames.c). + +2000 May 28 - Build 2021 +-------- James Tabor (jimtabor@infohwy.com) ++ Added Open/Close/Media check to dsk.c and io.asm. ++ Fixed Device checking in truename. Truename needs to be rewriten. + + +2000 May 26 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) + Code Clean up and Now the Release. + +2000 May 26 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixed IsDevice is used in FcbFns.c and DosFns.c. I removed IsDevice + from DosNames.c an placed it in DosFns.c. FcbFns had dup code + and it was removed. This fixed all the functions using IsDevice. + + Truename works now. I consider it dangerous and brain damaged. + Note: + truename X:\DIR\con -> X:/CON, note the '/'. + truename foo*.* -> X:\DIR\FOO?????.??? + truename *.*\*.*\*.* -> ????????.???\????????.???\????????.??? + truename *.*\*.**\*.* -> endless Loop + I will fix this later ;^) + + Found InitPSP running 3 time. On the 2'nd run the standard handles + were closed with out DosClose. Now Device Drivers can Print out + there startup info. + ++ Added New IOCTL code in Dsk.c. + +2000 May 26 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Fix Kolyan Ksenev (7207@mx.csd.tsu.ru) (nik0la@acm.org) + found Major bugs in Task.c and chario.c. + +2000 May 25 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixed Project history. + +2000 May 17 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixed Delete, Rename, Mkdir, and Rmdir. Comment out isDevice. There is + a serious bug in isDevice. ++ Added Finished adding function code for disk serial number support. ++ Clean Cleaned up source and removed duplicate functions. + +2000 May 14 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Clean Cleaned out the remaining CR's. + +2000 May 08 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Update Started Update to the New CVS at Sourceforge.net. Setting source + from 2018 to 2020. + +2000 May 06 +-------- Jim Hall (jhall1.isd.net) ++ Import Jim Hall imported the CVS from gcfl.net to Sourceforge.net. + +2000 Apr 28 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Added Dos Function calls 0x69, and 0x6C. IOCTL support in disk driver. + New functions not yet fully implemented. + Clean up DSK.C, IOCTL.C and FCBFNS.C. Removed old blk_device + pointers. + +2000 Apr 03 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixed All DPB chains were linking to -1. + +2000 Apr 02 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ Fixed Dos_Free returned wrong due to MaxCluster Calc. + Media_Check MaxCluster count wrong, needed +1. + +2000 Apr 01 - Build 2020 +-------- James Tabor (jimtabor@infohwy.com) ++ fixed Unable to cd back out of cdrom directories. + + +2000 Mar 31 - Build 2019 +-------- James Tabor (jimtabor@infohwy.com) ++ added Eric W. Biederman patches via CVS. + +2000 Mar 25 +-------- Eric Biederman ++ Fixed Lastdrive handling ++ Fixed Not enough drives for number present devices ++ Added Working (though not perfect network redirector) + Note: Error codes internal to freedos are negative + Error codes external to freedos are postive. + The network redirector is external to freedos... + Note: Running the nonredirected functions on a redirected + drive is dangerous. My patch is very careful + not to. Except in truename. Where (a) it is safe + and (b) I think it is required, and (c) it is needed + by dosemu. + +2000 Mar 19 - Build 2019 +-------- James Tabor (jimtabor@infohwy.com) +* Jean-Francois email noting + the set/clear interrupt was reverse in order. + +2000 Mar 17 - Build 2019 +-------- Steffen Kaiser (Steffen.Kaiser@fh-rhein-sieg.de) ++ Fixed Config.c COUNTRY= statement ++ Fixed *.c to call upFMem() when upcasing filenames +- Removed everything to load NLS into memory += Redesigned hardcoded NLS information + +--> The kernel will now return the proper information for the + hardcoded NLS (U.S.A. / CP437), it would return the correct + information for other NLS, too, if there would be a NLSFUNC + available, which is not at this time. + +NOTE: The way the external NLSFUNC is called does not look well, +therefore expect a change soon. + +2000 Mar 15 - Build 2019 +-------- James Tabor (jimtabor@infohwy.com) +* Dennis Newbold and Massimo De Munari email kernel bug reports + with changes to Globals.h and Inthndlr.c. Fix to leap year and + Delete file return code. +* Michal Meller found a bug in media_check. It return the wrong + value of sector count. Change in FATFS.C. +* Fixed Func 0x32 based on information from Marty . + Func 0x32 Get Drive Parameter BLK did not work. + + +2000 Mar 09 - Build 2018 +-------- James Tabor (jimtabor@infohwy.com) +Added CDS and made FD CDS based. Changes encompass all of the + code for FD. +Fixed Task.c, rewritten code from FINODE to SFT function calls. + Unable to execute from CD. Main.c and Config.c has small + changes. +Fixed Device drivers are unable to write to con. Rewritten code to + relocate DOS_PSP pointer to 050:0000. Removed references to + DOS_PSP in DosFns.c. +Added Network and Redirection function calls in Inthndlr.c and + network.c. + +I have a note in FatFs.c line 313, describing functions not yet +supported for networking. I don't understand Pats thoughts on SFT to +FINODE. IMHO it would have been easier to stay with SFT all through +the code. + +I tested MS-Dos 6.22 Command and found it unable to do Find First or +Next. This too could explain why MSCDEX does the same thing. I only +test this with the current FDCommand at the time, so this could have +changed. + + +1999 Sep 24 - Build 2017 +-------- John Price (linux-guru@gcfl.net) +* Per Jens Horstmeier's email, changed boot sector code to make + Siemens CDROM's bootable. The changes should be OK for all other + machines too (in theory). + + +1999 Sep 22 - Build 2016 +-------- John Price (linux-guru@gcfl.net) +* Turned off debug output from the kernel. It does not seem to be + necessary at this time. +* Changed boot sector to do single-sector reads instead of + multi-sector reads. Appearantly this was part of the reason the + kernel would not boot from a 720K, or other format floppies. Thanx + to Charles Dye for the info. + +1999 Sep 16 - Build 2016 +-------- James Tabor (jimtabor@infohwy.com) +* Added Networking and Server Call +* Added Dos Idle call +* fixed Console.asm ConInStat + + +1999 Sep 13 - Build 2014 +-------- John Price (linux-guru@gcfl.net) +* Deleted some files from the drivers directory that were not being + used. +* Changed the LIB.MAK file so it would work for TC2 or TC3 or higher. +* Changed SYS.COM so that it creates a sys.log file with more debug + information to help debug problems with making boot disks. + +1999 Sep 13 - Build 2014 +-------- James Tabor (jimtabor@infohwy.com) +* Submitted changes to CONSOLE.ASM & INTHNDLR.ASM to fix the INT21 + func 0B bug. + +1999 Sep 13 - Build 2014 +-------- Helmut Fritsch (helmut.fritsch@gcd-hs.de) +* Submitted changes to CONSOLE.ASM to fix the INT21 func 0B bug. + +1999 Sep 10 - Build 2014 +-------- ror4 (f2xm1@crosswinds.net) +* At the suggestion of Mr John Price, modified the int 0x25 and int + 0x26 so that they no longer update the disk buffers (int 0x26 only + invalidates the buffers for the specified drive). This is to avoid + inconsistent disk buffers from appearing in the buffer chain due to + interactions between int 0x25/0x26 and file read/write operations. + + +1999 Aug 24 - Build 2013 +-------- John Price (linux-guru@gcfl.net) +* With ideas from ror4, I redid the build batch file so you can + specify where what make to use. +* Also created CONFIG.M and CONFIG.B which should be copied to + CONFIG.MAK and CONFIG.BAT, respecively, and edited to reflect the + users configuration. This keeps new versions from replacing the + configuration files so the user does not have to keep reseting + their configutation. + +1999 Aug 15 - Build 2013 +-------- ror4 (ror4@angelfire.com) +* Patched the source so that it can be compiled with Turbo C 2.01. + (`asm' statements were rewritten into very ugly equivalents... they + probably need more work. :( ) +* Modified the `dmatch' structure in `hdr/dirmatch.h' so that the + `dm_dirstart' field is in the right place, and also to make it + compile under TC 2.01, which doesn't allow bit fields of any types + other than signed or unsigned int. +* Fixed a few minor bugs in error code returning in `kernel/fatfs.c'. + + +1999 Jul 16 - Build 2012 +-------- ror4 (ror4@iname.com) +* Finally ported all the assembly modules to `nasm'. *phew* +* Undid plonee's patches to `kernel/fatfs.c' (sorry). They were + causing the resulting findfirst/findnext DTA structures to be + incompatible with MSDOS's. +* Also rewrote all the pattern copying code in `dos_findfirst' in + `kernel/fatdir.c' to prevent a bad buffer overflow problem. +* Modified the disk buffer handling code, so that logical sector + numbers in disk buffers are now 0-based instead of 1-based. +* int 0x25 and int 0x26 now do multi-sector reads/writes. + +1999 Jul 14 - Build 2012 +-------- ror4 (ror4@iname.com) +* Ported the modules in the `drivers/' branch to `nasm'. + + +1999 May 04 - Build 2011 +-------- ror4 (ror4@cryogen.com) +* Fixed the code for converting day numbers into Julian calendar + dates: the first and last days of each month are now returned + correctly. +* Undid a change to the code to get the day of the week. + +1999 May 02 - Build 2011 +-------- John Price (linux-guru@gcfl.net) +* blockio.c: changed getblock and getbuf so that they leave at least + 3 FAT type buffers valid. This helps because the FAT is accessed + very often compared to other sectors. +* fatfs.c: Fixed a bug in map_cluster so it will optimize FAT reads + on disks that have more than one sector per cluster. This + sigificantly improved disk access of big files on hard drives. + +1999 May 02 - Build 2011 +-------- ror4 (ror4@cryogen.com) +* Corrected the `struct buffer' definition in `kernel/globals.h' so + that it corresponds exactly to Ralf Brown's description of a DOS 3.x + buffer. +* Also fixed the problem with FATs > 255 sectors, by making use of an + originally unused field in the buffer structure. + +1999 May 01 - Build 2011 +-------- ror4 (ror4@cryogen.com) +* Fixed a problem which caused disk corruption on partitions with + FATs larger than 127 sectors. (However, FATs larger than 255 + sectors may still experience problems -- this is due to a + limitation of the DOS 3.x buffering scheme.) +* Fixed a bug in the handling of the `stacks=' command in + `(fd)config.sys' which caused the system to behave strangely. + +1999 Apr 22 - Build 2011 +-------- Steffen Kaiser (Steffen.Kaiser@fh-rhein-sieg.de) +bugfix: memmgr.c: Invalid returned largest size in MemLargest() +fix: memmgr.c: DosMemLargest: change prototype to match its useage +bugfix: inthdlr.c: 0x49: ES is decremented +fix: inthdlr.c: 0x00: DosMemCheck() does nothing --> added panic() +fix: inthdlr.c: 0x4c: DosMemCheck() does nothing --> added panic() +fix: inthdlr.c: 0x00: changed to make it the same as DOS-4C-00 + Both actions differed e.g. in ErrorMode +chg: memmgr.c: the 'name' field of the MCB is never initialized by + DOS-48, DOS-49 or DOS-4A. Leave this to the program loading function. +bugfix: memmgr.c: adjust_far() / add_far(): + Both function together (and the way they are used) don't make sense: + adjust_far() normalizes a far pointer, add_far() generates a linear + address. Usually both are used this way: + far_poi = adjust_far(far_poi); + while(...) { + ... + far_poi = add_far(far_poi, uword); + ... + } + First one makes sure that 'far_poi' is normalized, then far_poi + becomes a linear address, which makes it very difficult to use + it, because the possibility to get a segment warp gets very high. + --> + Change: add_far() also returns a normalized real mode pointer + as adjust_far() does. + Probably in DOS-C supporting various architecures thee functions + served other duties, but the current useage is highly dangerous. +bugfix: task.c: ChildEnv(): nEnvSize didn't counted the last '\0' +bugfix: task.c: ChildEnv(): Allocation: maximum absolute filename to + short and forgot the word counter +bugfix: task.c: ChildEnv(): for very corrupt environments, the + copy function failed. +bugfix: task.c: DosExeLoader(): If exe_size > allocated_size or + DosMemLargest() failes, the environment is not deallocated +bugfix: task.c: DosExeLoader(): Calculating the exe_size to be + allocated. At both places (+ header.exMinAlloc & ...MaxAlloc) + sizeof(psp) is added to exe_size. Why? image_size already + contains sizeof(psp). +chg: task.c: DosExeLoader()/DosComLoader(): MCB patching and command + line copying is no outside of those functions +chg: asmsupt.asm: _fbcopy: re-use parts of _bcopy +add: asmsupt.asm: fmemset, fmemclr, fmemclra {Replace the explicit + for() loops} + +1999 Apr 22 - Build 2011 +-------- ror4 (ror4@cryogen.com) +* Ported boot.asm to NASM. The plan is to port all assembly to NASM + over time. + + +1999 Apr 19 - Build 2010 +-------- John Price (linux-guru@gcfl.net) +* Undid the change I made to getblock below because it DID NOT speed +anything up, and in fact slowed access down. + + +1999 Apr 18 - Build 2009 +-------- John Price (linux-guru@gcfl.net) +* change getblock so that it flushes all buffers for a drive when it + has to flush one of them to make room. This should speed disk + access slightly. +* Change the boot sector so there is a compile-time option to use + multi-sector IO or single-sector IO. The default is multi since + ror4 seemed to have fixed the problem we had before. + +1999 Apr 18 - Build 2009 +-------- ror4 (ror4@cryogen.com) +* The boot sector can now load the kernel properly from a hard disk. +* Other minor changes. + + +1999 Apr 16 - Build 2008 +-------- ror4 (ror4@cryogen.com) +* Modified the block device driver to prepare it for multi-sector I/O + support. Among other things, the driver can now handle transfer + buffers which cross DMA boundaries. +* Some other minor changes. + +1999 Apr 15 - Build 2008 +-------- John Price (linux-guru@gcfl.net) +* Changed mainly the map_cluster function in fatfs.c so that instead + of starting at the beginning of the FAT chain every time, it will + be smart about it, and start at the last FAT location that it was + before if it can. This speeds up disk access considerably + especially on slower machines. + +1999 Apr 15 - Build 2008 +-------- Steffen Kaiser (Steffen.Kaiser@fh-rhein-sieg.de) +bugfix: ^Break handler according cmt1.txt +bugfix: DosCreat(): Detection for Devices and extension: + the semi-colon behind if(*froot) is definitely wrong, whether + one wants CON.EXT to be interpreted as CON or not. +bugfix: DosOpen(): dito + +* Re-implementation of ^Break handler -- 1999/03/27 ska + + Warning: The handle_break() function assumes that the InDOS flag + was incremented (except if ErrorMode is true). Never call + handle_break() unless the InDOS flag has been incremented within + this reentrant call of DOS. + + + ^Break is detected and handled at certain places within the + kernel only: a) within the CON: device when reading or writing a + character, and b) when entering the INT-21 service (if extended + break checking is enabled). At these places the process flow can + be modified to: either a) redo the interrupted function or b) abort + the currently running process. + + + Both actions are performed by switching back to the user stack + and enter INT-21 handler again. If to terminate the program, AX is + modified into 4C00h. + + + By default, if the user has no ^Break handler installed, the + program is terminated. + + + Heavy change: The original implementation installed an unique + INT-23 handler that directly called the actions performed + DOS-4C-XX. In fact, this was identically with when the user had an + own handler installed and returned the Carry flag set, except that + it was somewhat quicker, because the kernel need not decode the + 4C00h command. Now the Carry flag is set prior the call of INT-23, + so the default action is to terminate the program. + + + Note: INT-23 is called with all registers as they are passed to + the INT-21 entry. When they are modified, they are passed + _modified_ to the API interpreter. This also allows the DOS1-style + termination by to load register AH with 0 (zero). + + + RBIL says: + "any DOS call may safely be made within the INT 23 handler, + although the handler must check for a recursive invocation if it + does call DOS" + This can be interpreted so or so, the problem is that the user can + call DOS again, what would overwrite the saved _usr_stack pointer + with a different value and, therefore, cannot be used to check if + INT-23 was returned by RETF or RETF2/IRET. + + Because a recursive invokation of INT-23 is to prevented by the + user, the kernel could internally save SP to somewhere else. + However: + a) where? + b) is it reliable that the user ever returns from INT-23 at all? + + The implemented method uses the same mechanism as fail-safe intr() + function is implemented: A little piece of code is constructed + within the stack, which contains the value of SP as an operand of + an immediate MOV instruction. + + +1999 Apr 13 - Build 2007 +-------- ror4 (ror4@cryogen.com) +* The boot sector now moves itself to the last 512 bytes of + conventional memory instead of a lower memory location. +* The kernel startup code has also been modified so that it works + with the new boot sector. + +1999 Apr 12 - Build 2007 +-------- ror4 (ror4@cryogen.com) +* The directory scanning functions (`findfirst'/`findnext') now also + recognize more flavours of the volume label attribute byte (namely + 0x09, 0x28 and 0x29). +* Subdirectories are now no longer assumed to have the same size as + the root directory. +* `device/device.lib' is now included as a dependency in the kernel + makefile. +* Removed several unused assembler modules from the `device/' branch + (see `device/device.mak'). + +1999 Apr 11 - Build 2007 +-------- ror4 (ror4@cryogen.com) +* The kernel now reads times from the system clock (0x40:0x6c) + instead of the RTC. The RTC is only used during startup to + initialize the system clock. (As a side effect of this, + `ReadATClock' has been moved from `_TEXT' to `INIT_TEXT'.) +* Checking for leap years is now improved -- year numbers which are + divisible by 100 but not by 400 are not counted as leap years. (Not + that it matters for year 2000, though.) +* The scaling factor used to convert the system time count to a + second count has been changed from 18.2 to the more accurate (?) + 19663/1080. +* Day numbers used by `clock$' are now 0-based (as in MSDOS) instead + of 1-based. Thus 1 Jan 1980 is now day number 0. + +1999 Apr 10 - Build 2007 +-------- ror4 (ror4@cryogen.com) +* Added code to prevent the kernel from returning path names + containing double backslashes. + +1999 Apr 9 - Build 2007 +-------- ror4 (ror4@usa.net) +* File handles are now cloned properly when a child process is spawned. +* The `DosClose' function now also frees SFT entries corresponding to + devices, not only those entries corresponding to files. +* Removed a (minor) memory corruption bug in the code for int 0x21, + ah = 0x09. + +1999 Apr 6 - Build 2007 +-------- ror4 (ror4@cryogen.com) +* Functions ax = 0x5700 and 0x5701 (get/set file date and time) now + return the right values at the right times. (They used to return + success when there's an error, and return error when there's a + success.) +* Removed the `/k' switch to the linker in `sys/sys.mak'. + + +1999 Apr 4 - Build 2006 +-------- John Price (linux-guru@gcfl.net) +* added "version=" directive so that you can change the version that + the kernel reports. Usage: version=. (i.e. + version=6.22) + +1999 Apr 4 - Build 2006 +-------- ror4 (ror4@usa.net) +* Fixed the file name parsing function (`ParseDosNames') so that it + handles single-character path names correctly. +* Also modified the functions which call `ParseDosNames' to check its + return value instead of assuming that it is always successful. + (This is not currentl useful, but it will be when error checking is + introduced into `ParseDosNames'. In other words, there'll be more + changes to `ParseDosNames' in the near future...) + +* After wondering for a long time why the kernel text segment was + always getting corrupted when I ran DJGPP `bash' 1.14.7, I finally + decided to examine the code occurring before the handler for int + 0x21, ah = 0x60, and I found out why... :) +* Fixed the problem of int 0x21, ax = 0x5d06 causing memory + corruption. +* Corrected the types of `internal_data', `swap_always' and + `swap_indos' in `kernel/globals.h'. + +* Improved checking for invalid file names in `ParseDosName' + (although I'm still not sure whether the check is water-tight or + not). +* Changed the default path setting from `PATH=' to `PATH=.'. + +* Output from character I/O functions now goes to standard output as + it should, instead of the console. Also, there's now a clear + distinction between console input/output and standard input/output. +* Tabs are now expanded during writes to the console device. +* Removed a hard-wired limit on the number of entries in a JFT. + (Although I'm not sure whether this is really correct...) +* Many other changes to the file descriptor handling code. + +1999 Mar 29 - Build 2006 +-------- John Price (linux-guru@gcfl.net) +* Changed boot loader so it prints some feedback info while booting. + Removed code to handle FAT12 and FAT16, and code to calculate the + start of the fat, rootdir, and data. Moved these functions into + the sys command. Now there are two versions of the boot loader + created, one to handle FAT16, and one for FAT12. These are + hard-coded into the sys command, so the need for the boot.bin file + is obsolete. +* created a new program (bin2c) to convert the boot loader binary + file into a header file that can be included in the sys program as + an array of bytes. + +1999 Mar 29 - Build 2006 +-------- ror4 (ror4@usa.net) +* Changed the class of `_BSSEND' from "STACK" to "BSS" in the + `drivers/' branch (which I forgot about in my last patch). +* Removed all traces of the `CONST' segment, since it was causing + `IGROUP' to be assimilated into `DGROUP', which shouldn't happen. +* Added a `(void)' cast to the `setvec' macro in `kernel/globals.h' + (`setvec' no longer returns the original ISR vector). +* Changed an incorrect error message in `sys/sys.c'. +* Removed `drivers/setvec.asm', since it's no longer needed. +* Also removed `kernel/krnstart'. +* The name field in a process's MCB is now filled in the same manner + as in MSDOS -- instead of being padded to the right with spaces, it + is now terminated with '\0'. Also, if the original file name + doesn't have an extension, the code will stop copying the file name + at '\0' instead of continuing to look for a '.'. +* Fixed the problem of the `switchar' syscall (int 0x21, ax = 0x3700) not + returning the correct value. + + +1999 Mar 28 - Build 2005 +-------- ror4 (ror4@usa.net) +* Removed the need for `ipl.sys'. (!) The kernel makefile now + statically relocates `kernel.exe' to 0x60:0 and outputs the + resulting binary to `kernel.sys', and the boot sector has also been + modified to load `kernel.sys' at 0x60:0 instead of `ipl.sys' at + 0x2000:0. (I chose 0x60:0 because it's the first 512-byte boundary + occurring after the BIOS data area, 0x40:0.) Finally, `sys.com' has + also been updated. + +* Also changed the boot sector code in some other ways. In + particular, because `kernel.sys' is rather large, I had to add some + code to move the boot sector away from 0:0x7c00 to somewhere + higher. (For 640K systems the boot sector will be shifted to + 0x6000:0x7c00. However, there may be problems on systems with very + little conventional memory -- I'll probably look into this later.) + +* Made some minor changes to the assembler source files so that they + can compile on `masm'. (JP: The code still compiles fine with tasm + too). + +* Also changed several incorrect label references in the assembler + sources. (JP: These changes fixed the "Fixup" errors we been + talking about in the list) + +* Eliminated redundant re-makes of files in the various makefiles. + For one thing, `*.cfg' files are no longer generated from the + makefiles, but are independent from them. (I didn't like the idea + of having to compile an entire branch each time I edit a + makefile...) Also, intermediate files are now retained instead of + deleted. + +* Also made some changes to `build.bat' (you'll know them when you + see them). + +* Added a file `lib/libm.mak' + +* Added a file `kernel/krnstart + +* The code required to initialize the kernel (or rather most of it) + is no longer retained in memory after the initialization process is + done. I accomplished this by moving most of the initialization code + from `_TEXT' to a new segment named `INIT_TEXT'. Of course, I also + had to introduce lots of other changes in order for everything to + compile and run properly: + - Added code to `kernel/src/kernel/kernel.asm' to move the contents + of `INIT_TEXT' to the top of conventional memory and continue + from there. Control is only transferred back to `_TEXT' when the + kernel calls `p_0'. + - Many functions are called from both `_TEXT' and `INIT_TEXT'. To + fix this, I created far wrappers for these functions which can + then be called from `INIT_TEXT'. (E.g. for `execrh' there's a + corresponding far function named `init_call_execrh' which simply + calls `execrh' with its own parameters.) One exception to this is + `printf' -- instead of creating a far wrapper for a near + `printf', I created a near wrapper for a far `printf' (now called + `init_call_printf'), because it was easier that way. :) + - Most functions which are required only during initialization time + were shifted into `INIT_TEXT'. (There are still some functions + which should rightfully go into `INIT_TEXT', but are retained in + `_TEXT' as far functions, because I found it too difficult to + move them out. :( ) Because Turbo C only allows at most one code + segment to be defined for each module, I had to shift some + functions around within the source tree -- the file + `kernel/src/kernel/proto.h' says it all. + - A cosmetic change mentioned here for completeness: all functions + defined in `INIT_TEXT' are now marked with the word `INIT' (in + fact a null macro) so that the reader can easily distinguish them + from functions defined in `_TEXT'. + +* Replaced `exit' calls with `for (;;);'. + +* Changed `strcpy' into a macro which calls `scopy'. + +* Also redefined `setvec' to be a macro (I didn't want to waste time + writing a far wrapper for it). + +* Removed the `break_key' function in `kernel/src/kernel/kernel.asm'. + +* `low_int25_handler' and `low_int26_handler' are now of type + `void interrupt far()' instead of `void near()'. (I hope I updated + `entry.asm' correctly -- I never tested `int 0x25' and `int 0x26'...) + +* Changed the class of `_BSSEND' from "STACK" to "BSS" -- "STACK" is + now used for a separate stack segment (`_STACK'). + +* Assembler modules now include `segs.inc' instead of having their + own long list of segment definitions. (Some day I'll update the + makefile dependencies to reflect this.) + +* Also made a few minor changes to the assembler modules so that + `masm' won't complain. + +* Changed the `-X' switch in `kernel.cfg' to `-X-', so that I don't + have to worry about C module dependencies. + +* Removed the definition of `CFLAGS' from the makefile -- everything + is now in `kernel.cfg'. + +* Created a file `kernel/src/kernel/init-mod.h' which is included by + modules whose code is supposed to go into `INIT_TEXT' instead of + `TEXT'. + +* This diff solves the problem of the MCB of a process not having a + correct value in its name field (bug report #6). + (The definition of the `toupper' macro is because I shifted the + `toupper' function into `INIT_TEXT' a while ago, and therefore + can't be called from `_TEXT' now...) + + +-------- John Price (linux-guru@gcfl.net) +* Made changes so you can create a directory with the same name as a + volume label, but you still can't rename or delete it! + +* Fix findfirst and findnext functions so that act as they should. + (i.e. If the attrib has only the volume label set, then it returns + the volume label entry in the root directory, else it returns the + files/directories that are specified with the attrib, ignoring the + read-only and archive bits (these are always returned). + +* reorginize the source tree. Removed IPL directory, and command. + Moved all the file system C files into the kernel directory. + Modifed build.bat, clean.bat, and all the make files to reflect the + new tree. + +* changed so that kernel will look for a "fdconfig.sys" file, and use + it INSTEAD of config.sys. If it does not find it, it will look + for, and read config.sys, if it exists. + +* Fixed so that if you call an INT 21 function with AH containing a + unsupported function, the carry flag is set. + + +----- older history, from rcs logs. + +13 Nov 2002 tom +initclk.c: +Initial revision + +2001/11/04 bartoldeman +install.bat: +Text files need to be LF ended at the server. So be it... + +2001/04/29 brianreifsnyder +dsk.c: +Added phase 1 support for LBA hard drives + +20 Apr 2001 Bart Oldeman +buffer.h: +Initial revision. + +2001/04/16 bartoldeman +dsk.c: +Fixed handles, config.sys drivers, warnings. Enabled INT21/AH=6C, printf %S/%Fs + +2001/04/15 bartoldeman +dsk.c: +See history.txt for the list of fixes. + +2001/03/27 bartoldeman +dsk.c: +dsk.c (reported by Nagy Daniel), inthndlr and int25/26 fixes by Tom Ehlert. + +2001/03/24 bartoldeman +dsk.c: +See history.txt: dsk.c changes, warning removal and int21 entry handling. + +2001/03/22 bartoldeman +install.bat: +Change LF to CR/LF in batch files. + +2001/03/21 bartoldeman +dsk.c: +See history.txt for changes. Bug fixes and HMA support are the main ones. + +2001/03/16 tom ehlert +inithma.c: +initial creation + +2001/03/08 bartoldeman +dsk.c: +Space saving fixes from Tom Ehlert + +2001/03/07 10:00:00 tomehlert +prf.c: +recoded for smaller object footprint, added main() for testing+QA + +2000/10/29 jimtabor +inthndlr.c: +Adding Share Support by Ron Cemer + +2000/08/15 jhall1 +build.txt: +update to the build.txt file to remove references to the now-defunct +web site at gcfl.net (John's old site). + +2000/08/06 jimtabor +inthndlr.c, nls_load.c: +Add new files and update cvs with patches and changes + +2000/06/21 jimtabor +dsk.c, inthndlr.c: +Add UMB code, patch, and code fixes + +2000/06/01 jimtabor +dsk.c: +Read History for Changes + +2000/05/26 jimtabor +dsk.c: +Read History file for Change info + +2000/05/25 jimtabor +dsk.c, inthndlr.c: +Fixed project history + +2000/05/17 jimtabor +dsk.c, inthndlr.c: +Cleanup, add and fix source. + +2000/05/11 jimtabor +inthndlr.c: +Removed #if statement + +2000/05/11 jimtabor +dsk.c, inthndlr.c: +Added code for DOS FN 69 & 6C + +2000/05/11 jimtabor +install.bat, inthndlr.c: +Clean up and Release + +2000/05/08 jimtabor +inthndlr.c, dosnames.c, dsk.c, dosnames.h, build.txt: +Update CVS to 2020 + +2000/05/06 jhall1 +getvec.asm, dsk.c, inthndlr.c: +The FreeDOS Kernel. A DOS kernel that aims to be 100% compatible with +MS-DOS. Distributed under the GNU GPL. + +2000/04/29 jtabor +device.h, blockio.c, dsk.c, fatfs.c, inthndlr.c, ioctl.c: +Added new functions and clean up code + +2000/04/02 jtabor +newstuff.c: +Fix ChgDir Code + +2000/04/02 jtabor +dosfns.c: +Replaced ChgDir Code + +2000/04/02 jtabor +dosfns.c: +Fix to DosChgDir + +2000/03/31 jprice +sys.c: +Added discription of program. + +2000/03/31 jtabor +config.c, dosfns.c, dosnames.c, fatdir.c, fcbfns.c, int2f.asm, main.c, +makefile, network.c, newstuff.c, proto.h, task.c: +Added Eric W. Biederman Patches + +2000/03/23 ska +nls.c: +Initial revision + +2000/03/20 kernel +entry.asm: +Change in Entry.asm + +2000/03/18 kernel +intfns.txt: +changes in supported functions + +2000/03/17 kernel +config.c, fatdir.c, fatfs.c, fcbfns.c, inthndlr.c, makefile, +network.c, nlssupt.asm, proto.h: +Steffen Kaiser's NLS changes + +2000/03/17 kernel +inthndlr.c: +Fixed Func 0x32 + +2000/03/17 kernel +fatfs.c: +Added Change for media_check + +2000/03/16 kernel +globals.h, inthndlr.c: +*** empty log message *** + +2000/03/09 kernel +dosfns.c, dosnames.c, dsk.c, error.c, execrh.asm, fatdir.c, fatfs.c, +fcbfns.c, globals.h, initoem.c, int2f.asm, inthndlr.c, io.asm, +ioctl.c, kernel.asm, main.c, makefile, memmgr.c, misc.c, network.c, +newstuff.c, prf.c, proto.h, strings.c, sysclk.c, task.c, blockio.c, +break.c, chario.c, config.c, console.asm, cds.h, dcb.h, device.h, +dirmatch.h, fnode.h, mcb.h, sft.h, stacks.inc: +2017f updates by James Tabor + +1999/09/25 jprice +boot.asm: +Optimize boot loader. Documentation. + +1999/09/24 jprice +boot.asm: +Added changes recommended by Jens Horstmeier +to make their bootable CD work. + +1999/09/23 jprice +main.c, network.c, proto.h, globals.h, inthndlr.c, kernel.asm, +makefile, config.c, console.asm, dosfns.c, entry.asm, fatfs.c, +fcbfns.c, chario.c, boot.asm, fcb.h, sys/makefile, sys.c: +*** empty log message *** + +1999/09/20 jprice +sys.c: +Changed open/creat to fopen to make TC2 happy. + +1999/09/15 jprice +sys.c: +Changed boot sector writing code so easier to read. + +1999/09/14 jprice +lib/makefile: +no message + +1999/09/14 jprice +sys.c: +Added debug log creation to sys.com. + +1999/09/14 jprice +console.asm: +no message + +1999/09/14 jprice +inthndlr.c: +ror4: fix int25 & 26 are not cached. + +1999/09/14 jprice +fatfs.c, dosfns.c: +Fixed bug where you could write over directories. + +1999/09/13 jprice +inthndlr.c, console.asm: +Fix 210B function + +1999/09/13 jprice +console.asm: +Changes from Helmut Fritsch to fix INT21 func B + +1999/09/13 jprice +makefile: +Some clean up. + +1999/09/13 jprice +config.b, config.b: +Added COMPILER variable + +1999/09/13 jprice +lib/makefile: +Added !if so we can use TC2 or TC3 to compile. + +1999/08/25 jprice +build.txt: +update + +1999/08/25 jprice +config.b, clobber.bat, clean.bat, config.b, build.bat: +New build batch files. + +1999/08/25 jprice +intfns.txt, build.txt, build.bat: +New build config + +1999/08/25 jprice +config.b, sys/makefile, sys.c, lib/makefile, task.c, main.c, makefile, +memmgr.c, newstuff.c, proto.h, strings.c, fatfs.c, globals.h, +initoem.c, inthndlr.c, blockio.c, chario.c, config.c, dosfns.c, +fatdir.c, date.h, dirmatch.h, portab.h, time.h, drivers/makefile, +install.bat: +ror4 patches to allow TC 2.01 compile. + +1999/08/10 jprice +clobber.bat: +case + +1999/08/10 jprice +dsk.c, inthndlr.c: +ror4 2011-04 patch + +1999/08/10 jprice +globals.h, inthndlr.c, fatfs.c, fattab.c, blockio.c: +ror4 2011-03 patch + +1999/08/10 jprice +irqstack.asm, kernel.asm, makefile, nlssupt.asm, printer.asm, +procsupt.asm, segs.inc, apisupt.asm, asmsupt.asm, console.asm, entry.asm, execrh.asm, fatdir.c, +int2f.asm, io.asm, io.inc, stacks.inc: +ror4 2011-02 patch + +1999/08/10 jprice +wrpcclk.asm, wratclk.asm, rdpcclk.asm, drivers/makefile, getvec.asm, floppy.asm: +ror4 2011-01 patch + +1999/05/04 jprice +systime.c: +ror4 date fix + +1999/05/03 jprice +fat.h: +Changed some variables from signed to unsigned. + +1999/05/03 jprice +blockio.c, config.c, dosfns.c, fatdir.c, fatfs.c, fattab.c, globals.h, +inthndlr.c, misc.c, proto.h: +Patches from ror4 and many changed of signed to unsigned variables. + +1999/05/03 jprice +sys/makefile: +no message + +1999/05/03 jprice +fatfs.c: +Fixed bug in map_cluster function + +1999/05/03 jprice +blockio.c: +Changed getblock & getbuf so that they leave at least 3 buffer for FAT data. + +1999/04/23 jprice +procsupt.asm: +Fixed got_cbreak function. + +1999/04/23 jprice +makefile: +no message + +1999/04/23 jprice +asmsupt.asm, inthndlr.c, memmgr.c, misc.c, proto.h, task.c: +Memory manager changes made by ska + +1999/04/23 jprice +clobber.bat: +Initial include + +1999/04/23 jprice +clean.bat, build.bat, sys/makefile, lib/makefile, makefile, drivers/makefile: +Improved by jprice + +1999/04/23 jprice +boot/makefile: +Ported to NASM by ror4. Improvements + +1999/04/23 jprice +boot.asm: +Ported to NASM by ror4 + +1999/04/21 jprice +blockio.c: +no message + +1999/04/18 jprice +blockio.c: +no message + +1999/04/17 jprice +sys.c, boot.asm: +Fixed multi-sector code + +1999/04/17 jprice +build.bat: +ror4 patches + +1999/04/17 jprice +boot.asm: +Changed so multi-sector IO is optional. + +1999/04/16 jprice +blockio.c, config.c, dsk.c, globals.h, main.c, proto.h, floppy.asm: +ror4 multi-sector IO + +1999/04/16 jprice +break.c: +Steffen contributed. + +1999/04/16 jprice +dosfns.c, globals.h, inthndlr.c, irqstack.asm, main.c, makefile, procsupt.asm, +proto.h, chario.c, config.c: +Steffen c-break handler changes + +1999/04/16 jprice +fatfs.c, fattab.c, globals.h, main.c, task.c, blockio.c, config.c, +dsk.c, fatdir.c, fnode.h, dcb.h: +Optimized FAT handling + +1999/04/13 jprice +kernel.asm: +changes for boot loader + +1999/04/13 jprice +boot.asm: +Moves boot sector to top of mem + +1999/04/13 jprice +makefile, fatdir.c, drivers/makefile: +no message + +1999/04/12 jprice +fatfs.c, blockio.c: +Using getbuf to write data instead of getblock +using getblock made it read the block before it wrote it + +1999/04/12 jprice +systime.c, config.c, dosfns.c, fatfs.c, globals.h, main.c, proto.h, +sysclk.c: +more ror4 patches. Changes for multi-block IO + +1999/04/12 jprice +rdpcclk.asm, rdatclk.asm: +more ror4 patches + +1999/04/11 jprice +blockio.c: +Working on multi-block IO + +1999/04/11 jprice +globals.h, inthndlr.c, main.c, newstuff.c, proto.h, task.c, blockio.c, +config.c, dosfns.c, fatdir.c, fatfs.c, fattab.c: +ror4 patches + +1999/04/06 jprice +boot.asm: +Put back code to read multiple sectors at a time. + +1999/04/04 jprice +config.c, globals.h, inthndlr.c, main.c, dosfns.c, dosnames.c, +fatdir.c, fatfs.c, fcbfns.c, globals.h, inthndlr.c, ioctl.c, main.c, +newstuff.c, prf.c, proto.h, strings.c, chario.c, sft.h, device.h: +no message + +1999/04/01 jprice +sys.c: +SYS modified for new boot loader + +1999/04/01 jprice +boot/makefile, boot.asm: +New boot loader + +1999/04/01 jprice +install.bat: +no message + +1999/03/29 jprice +wrpcclk.asm, wratclk.asm, rdpcclk.asm, rdatclk.asm, drivers/makefile, +getvec.asm, floppy.asm, globals.h, io.inc, task.c: +ror4 changes + +1999/03/29 jprice +sys.c: +Fixed error message + +1999/03/29 jprice +sys.c, syspack.c, prf.c, misc.c, fcbfns.c, fattab.c, fatfs.c, +fatdir.c, error.c, dosnames.c, dosfns.c, chario.c, blockio.c, task.c, +systime.c, sysclk.c, strings.c, proto.h, segs.inc, procsupt.asm, +printer.asm, nlssupt.asm, newstuff.c, memmgr.c, main.c, makefile, +kernel.asm, irqstack.asm, ioctl.c, io.inc, io.asm, inthndlr.c, +int2f.asm, globals.h, initoem.c, execrh.asm, entry.asm, dsk.c, +console.asm, config.c, asmsupt.asm, apisupt.asm, wrpcclk.asm, +wratclk.asm, rdpcclk.asm, rdatclk.asm, getvec.asm, floppy.asm, +drivers/makefile, install.bat, boot/makefile, boot.asm, tail.h, +time.h, sft.h, stacks.inc, process.h, portab.h, pcb.h, kbd.h, mcb.h, +file.h, fnode.h, fcb.h, exe.h, fat.h, dosnames.h, error.h, device.h, +date.h, dcb.h, cds.h, clock.h, dirmatch.h, intfns.txt, clean.bat, +build.bat: +New version without IPL.SYS + +1999/03/25 jprice +fatdir.c: +Fixed findfirst & findnext functions to treat the attributes like MSDOS does. + +1999/03/23 jprice +inthndlr.c: +Now sets carry when we don't support a function + +1999/03/23 jprice +config.c: +Now checks for a reads fdconfig.sys file, if exists + +1999/03/23 jprice +fatfs.c: +Fixed mkdir DOS function so it will create a directory with same name as the volument label + +1999/03/02 jprice +inthndlr.c: +Added some comments. Fixed some minor bugs. + +1999/03/02 jprice +fatfs.c: +Fixed bugs with dos set attribute function. Now returns correct +error code, and errors if user tries to set bits 6 & 7. + +1999/03/02 jprice +boot.asm: +Added entry address for more recent versions of TLINK + +1999/03/02 jprice +intfns.txt: +Updated interrupt list + +1999/03/01 jprice +makefile: +Fixed so it'll work with config.mak + +1999/03/01 jprice +makefile: +Turned off DEBUG define. + +1999/03/01 jprice +inthndlr.c: +Added some DEBUG ifdef's so that it will compile without DEBUG defined. + +1999/02/14 jprice +fatdir.c, dsk.c: +Changed check media so that it checks if a floppy disk has been changed. + +1999/02/14 jprice +floppy.asm: +Added functions to check if a floppy disk has been changed. + +1999/02/09 jprice +makefile, drivers/makefile, boot/makefile, clean.bat, build.bat: +Make makefile use common config.mak file + +1999/02/09 jprice +blockio.c, chario.c, dosfns.c, error.c, fatdir.c, fatfs.c, fattab.c, +fcbfns.c, device.h, error.h, sysclk.c, systime.c, task.c, apisupt.asm, +asmsupt.asm, config.c, console.asm, dsk.c, entry.asm, execrh.asm, +globals.h, initoem.c, int2f.asm, inthndlr.c, io.asm, io.inc, ioctl.c, +irqstack.asm, kernel.asm, main.c, makefile, memmgr.c, newstuff.c, +nlssupt.asm, printer.asm, procsupt.asm, proto.h, segs.inc, floppy.asm: +Added Pat's 1937 kernel patches + +1999/02/04 jprice +chario.c, fatfs.c, fcbfns.c, strings.c, sysclk.c, systime.c, task.c: +Formating. Added comments. + +1999/02/04 jprice +inthndlr.c: +Formating + +1999/02/04 jprice +makefile: +Added option to share constants (-d). + +1999/02/04 jprice +device.h: +no message + +1999/02/02 jprice +dosnames.c: +Steve Miller fixed a bug with doing "cd ." would lock the machine. + +1999/02/01 jprice +apisupt.asm, asmsupt.asm, config.c, dsk.c, entry.asm, execrh.asm, globals.h, +initoem.c, int2f.asm, inthndlr.c, ioctl.c, irqstack.asm, kernel.asm, +main.c, memmgr.c, newstuff.c, nlssupt.asm, procsupt.asm, proto.h, +strings.c, sysclk.c, systime.c, task.c: +Clean up; Now you can use hex numbers in config.sys. added config.sys screen function to change screen mode (28 or 43/50 lines) + +1999/02/01 jprice +chario.c, dosfns.c, dosnames.c, error.c, fatdir.c, fatfs.c, fattab.c, +fcbfns.c, misc.c, prf.c, syspack.c, blockio.c: +Fixed findfirst function to find volume label with Windows long filenames + +1999/02/01 jprice +cds.h, clock.h, date.h, dcb.h, device.h, dirmatch.h, dosnames.h, error.h, +exe.h, fat.h, fcb.h, file.h, fnode.h, kbd.h, mcb.h, pcb.h, portab.h, process.h, +sft.h, stacks.inc, tail.h, time.h: +Clean up + +1999/01/30 jprice +clean.bat, build.bat: +Clean up + +1999/01/30 jprice +main.c, config.c, initoem.c, inthndlr.c: +Clean up; Fixed bug with set attribute function. + +1999/01/30 jprice +globals.h: +Clean up; commented out copyright messages while we debug. + +1999/01/30 jprice +blockio.c, fatdir.c, fatfs.c: +Clean up; Fixed bug with set attribute function. If you tried to +change the attributes of a directory, it would erase it. + +1999/01/30 jprice +cds.h, clock.h, error.h, fat.h, fnode.h, build.bat: +Clean up + +1999/01/22 jprice +cds.h, clock.h, date.h, dcb.h, device.h, dirmatch.h, dosnames.h, error.h, +exe.h, fat.h, fcb.h, file.h, fnode.h, kbd.h, mcb.h, pcb.h, portab.h, process.h, +sft.h, stacks.inc, tail.h, time.h, wrpcclk.asm, wratclk.asm, +rdpcclk.asm, rdatclk.asm, drivers/makefile, getvec.asm, floppy.asm, +blockio.c, chario.c, dosfns.c, dosnames.c, error.c, fatdir.c, fatfs.c, +fattab.c, fcbfns.c, misc.c, prf.c, syspack.c, procsupt.asm, proto.h, +strings.c, sysclk.c, systime.c, task.c, globals.h, initoem.c, +int2f.asm, inthndlr.c, ioctl.c, irqstack.asm, kernel.asm, main.c, +makefile, memmgr.c, newstuff.c, nlssupt.asm, apisupt.asm, asmsupt.asm, +config.c, dsk.c, entry.asm, execrh.asm, boot/makefile, boot.asm: +Formating. + +1999/01/21 jprice Fixed comments. +sys.c: +Added indent program + +1999/01/21 jprice Added messages to sys. Also made +sys.c: +it create a .COM file. + +1999/01/20 jprice +cds.h, clock.h, date.h, dcb.h, device.h, dirmatch.h, dosnames.h, error.h, +exe.h, fat.h, fcb.h, file.h, fnode.h, kbd.h, mcb.h, pcb.h, portab.h, process.h, +sft.h, stacks.inc, tail.h, time.h, apisupt.asm, asmsupt.asm, config.c, dsk.c, +entry.asm, execrh.asm, globals.h, initoem.c, int2f.asm, ioctl.c, irqstack.asm, +kernel.asm, main.c, makefile, memmgr.c, newstuff.c, nlssupt.asm, +procsupt.asm, proto.h, strings.c, sysclk.c, systime.c, task.c: +Imported sources + +1999/01/20 jprice +wrpcclk.asm, wratclk.asm, rdpcclk.asm, rdatclk.asm, drivers/makefile, +getvec.asm, floppy.asm, boot/makefile, boot.asm, blockio.c, chario.c, dosfns.c, +dosnames.c, error.c, fatdir.c, fatfs.c, fattab.c, fcbfns.c, +inthndlr.c, misc.c, prf.c, syspack.c: +Imported sources + +10 Jan 1999 SRM +makefile: +Took out "/P-" from TLINK +Changed "bcc" to "tcc" + +06 Dec 1998 patv +entry.asm: +New int 21h handler code. + +06 Dec 1998 patv +inthndlr.c: +Expanded due to improved int 21h handler code. + +06 Dec 1998 patv +ioctl.c, proto.h, apisupt.asm, globals.h: +Expanded due to new I/O subsystem. + +06 Dec 1998 patv +makefile: +Added new files for I/O subsystem. + +06 Dec 1998 patv +main.c, dsk.c: +Changed due to new I/O subsystem. + +06 Dec 1998 patv +irqstack.asm, newstuff.c, int2f.asm, kernel.asm, systime.c, +nlssupt.asm, asmsupt.asm, procsupt.asm, task.c, execrh.asm, fatdir.c, +fatfs.c: +Bug fixes. + +06 Dec 1998 patv +dosfns.c: +Expanded dos functions due to new I/O subsystem. + +06 Dec 1998 patv +fcbfns.c: +Expanded fcb functions for new I/O subsystem. + +06 Dec 1998 patv +error.c: +Now handles errors like MS-DOS. + +06 Dec 1998 patv +chario.c: +changes in character I/O because of new I/O subsystem. + +06 Dec 1998 patv +blockio.c: +Changes in block I/O because of new I/O subsystem. + +06 Dec 1998 patv +floppy.asm: +New floppy support functions. + +06 Dec 1998 patv +device.h: +Changed for new I/O subsystem + +06 Dec 1998 patv +error.h: +Added new errors for new I/O subsystem. + +06 Dec 1998 patv +io.inc, segs.inc: +Initial revision. + +09 Feb 1998 patv +fatfs.c, fattab.c: +Eliminated FAT12 EOF and error returns. + +07 Feb 1998 patv +stacks.inc, pcb.h, entry.asm, procsupt.asm, inthndlr.c, task.c, +globals.h, proto.h: +Modified stack fram to match DOS standard + +03 Feb 1998 patv +kernel.asm: +Added a start-up stack for loadable device drivers. Need the separate +stack so that all int 21h functions can be called. + +03 Feb 1998 patv +fatfs.c: +Fixed lseek bug. + +02 Feb 1998 patv +globals.h: +Fixed size of default_drive. Caused failures when break_ena was not zero. + +31 Jan 1998 patv +task.c: +Corrected type in load high code. + +31 Jan 1998 patv +task.c: +Added load high in memory option in DosExeLoader. + +22 Jan 1998 patv +task.c: +Eliminated warnings. + +22 Jan 1998 patv +process.h: +Had to change ps_prevps to VOID FAR * due to BC++ error. + +22 Jan 1998 patv +process.h: +Corrected ps_prevpsp declaration. + +22 Jan 1998 patv +task.c: +Corrected short .COM problem. + +22 Jan 1998 patv +makefile: +Outdated stacks.asm. + +22 Jan 1998 patv +fatfs.c: +Corrected remaining file name and extension copies that did not +account for far file nodes due to allocated FILES= spec. + +22 Jan 1998 patv +inthndlr.c, proto.h, config.c, globals.h, kernel.asm, main.c, +blockio.c, dosnames.c, fatdir.c, fatfs.c: +Fixed pointer problems affecting SDA + +11 Jan 1998 patv +ioctl.c, proto.h, chario.c, device.h: +Added functionality to ioctl. + +08 Jan 1998 patv +chario.c: +Changed automatic requestic packets to static to save stack space. + +06 Jan 1998 patv +inthndlr.c: +Broke apart int21_system from int21_handler. + +06 Jan 1998 patv +kernel.asm: +Reduced device driver stack sizes. + +04 Jan 1998 patv +globals.h, proto.h, inthndlr.c, newstuff.c, systime.c, main.c, +config.c, ioctl.c, memmgr.c, dsk.c, initoem.c, strings.c, sysclk.c, +task.c, fatfs.c, chario.c, dosfns.c, dosnames.c, fattab.c, fcbfns.c, +prf.c, syspack.c, blockio.c, error.c, fatdir.c, misc.c, device.h, +cds.h, clock.h, date.h, dcb.h, fat.h, file.h, fnode.h, kbd.h, mcb.h, +pcb.h, sft.h, dirmatch.h, error.h, exe.h, fcb.h, portab.h, process.h, +tail.h, time.h: +Changed Log for strip utility + +04 Jan 1998 patv +kernel.asm, inthndlr.c, main.c, config.c, newstuff.c, fatfs.c: +Corrected subdirectory bug + +03 Jan 1998 patv +globals.h, kernel.asm, makefile, systime.c, inthndlr.c, main.c, +proto.h, asmsupt.asm, dosfns.c, dosnames.c, fatfs.c, blockio.c, +fatdir.c, fcbfns.c: +Converted data area to SDA format + +31 Dec 1997 patv +strings.c: +Added new far string functions. + +30 Dec 1997 patv +chario.c: +Modified to support SDA + +01 Aug 1997 patv +inthndlr.c: +COMPATIBILITY: Added return '$' in AL for function int 21h fn 09h + +06 Feb 1997 patv +kernel.asm: +Reduced stack sizes for block and clock devices. + +06 Feb 1997 patv +globals.h: +Changed version format string + +06 Feb 1997 patv +main.c: +Modified to support new version format and changed debug message to +output drive letter instead of number. + +06 Feb 1997 patv +globals.h: +Modified to support new version format + +06 Feb 1997 patv +inthndlr.c, kernel.asm: +Added hooks for tsc command + +30 Jan 1997 patv +makefile: +Added TSC flag for trace support. + +22 Jan 1997 patv +newstuff.c, inthndlr.c, task.c, irqstack.asm: +pre-0.92 Svante Frey bug fixes. + +22 Jan 1997 patv +globals.h: +Changed to support version.h and pre-0.92 Svante Frey bug fixes. + +22 Jan 1997 patv +main.c: +Now does correct default drive initialization. + +22 Jan 1997 patv +fatfs.c, dosfns.c: +pre-0.92 bug fixes + +16 Jan 1997 patv +irqstack.asm: +Initial revision. + +16 Jan 1997 patv +globals.h, main.c, memmgr.c, task.c, ioctl.c, config.c, inthndlr.c, +apisupt.asm, nlssupt.asm, proto.h, makefile, fcbfns.c, chario.c, +dosnames.c, blockio.c, dosfns.c, fatdir.c, fatfs.c, fattab.c, +device.h, fcb.h, sft.h, dsk.c, boot.asm: +Corrected copyright + +10 Jan 1997 patv +boot.asm: +Re-written to support C drive and eliminate restrictions on IPL.SYS + +10 Jan 1997 patv +boot/makefile: +Changed to use FreeDOS exe2bin and support new boot code + +17 Dec 1996 patv +boot/makefile: +Converted to FreeDOS exe2bin. + +13 Sep 1996 patv +globals.h: +Fixed boot for hard drive + +29 Aug 1996 patv +makefile, globals.h, task.c, floppy.asm, wrpcclk.asm, wratclk.asm, +drivers/makefile, rdpcclk.asm, rdatclk.asm, getvec.asm, boot/makefile, +boot.asm: +Bug fixes for v0.91b + +29 May 1996 patv +clock.h, date.h, dcb.h, kbd.h, dirmatch.h, error.h, exe.h, sft.h, +tail.h, time.h, fnode.h, mcb.h, pcb.h, portab.h, process.h, +dosnames.h, fat.h, fcb.h, file.h, device.h, dosfns.c, fatdir.c, +misc.c, fatfs.c, fattab.c, fcbfns.c, chario.c, dosnames.c, syspack.c, +blockio.c, error.c, prf.c, initoem.c, sysclk.c, int2f.asm, config.c, +kernel.asm, inthndlr.c, proto.h, systime.c, apisupt.asm, asmsupt.asm, +nlssupt.asm, procsupt.asm, task.c, globals.h, memmgr.c, dsk.c, main.c, +makefile, execrh.asm, ioctl.c, strings.c: +bug fixes for v0.91a + +19 Feb 1996 patv +int2f.asm: +Initial revision. + +19 Feb 1996 patv +makefile, kernel.asm, nlssupt.asm, proto.h, globals.h, config.c, +inthndlr.c, task.c, dsk.c, main.c, memmgr.c, strings.c, initoem.c, +ioctl.c, sysclk.c, systime.c, fatdir.c, misc.c, fatfs.c, dosfns.c, +dosnames.c, fattab.c, drivers/makefile, cds.h, dirmatch.h, exe.h, +sft.h, tail.h, time.h, fcb.h, file.h, fnode.h, mcb.h, pcb.h, portab.h, +process.h, clock.h, date.h, dcb.h, device.h, dosnames.h, fat.h, +error.h, kbd.h: +Added NLS, int2f and config.sys processing + +01 Sep 1995 patv +wrpcclk.asm, wratclk.asm, rdpcclk.asm, rdatclk.asm, getvec.asm, +floppy.asm, boot.asm, apisupt.asm, asmsupt.asm, proto.h, kernel.asm, +procsupt.asm, execrh.asm, strings.c, task.c, inthndlr.c, memmgr.c, +dsk.c, main.c, sysclk.c, globals.h, initoem.c, ioctl.c, systime.c, +dosfns.c, blockio.c, error.c, misc.c, dosnames.c, fcbfns.c, chario.c, +fattab.c, prf.c, syspack.c, fatfs.c, fatdir.c, time.h, pcb.h, +portab.h, process.h, sft.h, tail.h, fat.h, fcb.h, file.h, fnode.h, +mcb.h, date.h, dcb.h, device.h, dirmatch.h, dosnames.h, clock.h, +error.h, exe.h, kbd.h: +First GPL release. + +30 Jul 1995 patv +dsk.c, memmgr.c, proto.h, strings.c, task.c, blockio.c, misc.c, chario.c, +dosnames.c, error.c, fattab.c, fcbfns.c, prf.c, syspack.c, dosfns.c, +fatdir.c, fatfs.c, mcb.h, pcb.h, portab.h, process.h, sft.h, tail.h, +time.h, date.h, dcb.h, device.h, dirmatch.h, dosnames.h, fat.h, fcb.h, +file.h, fnode.h, clock.h: +Eliminated version strings in ipl + +30 Jul 1995 patv +error.h, kbd.h, exe.h: +Fixed ipl + +30 Jul 1995 patv +boot.asm: +Initialized stack before use. + +05 Jul 1995 patv +asmsupt.asm, proto.h: +Initial revision. + +02 Jul 1995 patv +boot.asm, time.h, tail.h, process.h, sft.h, portab.h, pcb.h, kbd.h, +mcb.h, fnode.h, file.h, fat.h, fcb.h, exe.h, error.h, dirmatch.h, +dosnames.h, dcb.h, device.h, date.h, clock.h, boot/makefile, +procsupt.asm, kernel.asm, execrh.asm, apisupt.asm, task.c, strings.c, +inthndlr.c, main.c, memmgr.c, dsk.c, sysclk.c, systime.c, ioctl.c, +initoem.c, globals.h, makefile, misc.c, error.c, fcbfns.c, dosnames.c, +chario.c, syspack.c, prf.c, fattab.c, fatfs.c, fatdir.c, dosfns.c, +blockio.c, wrpcclk.asm, wratclk.asm, getvec.asm, rdpcclk.asm, +rdatclk.asm, floppy.asm, drivers/makefile: +Initial revision. + +25 May 1993 patv +dirmatch.h: +Initial revision. + diff --git a/docs/intfns.txt b/docs/intfns.txt new file mode 100644 index 0000000..020de90 --- /dev/null +++ b/docs/intfns.txt @@ -0,0 +1,198 @@ + Technical Data + DOS-C Systems Calls + +The following table represents the industry standard kernel DOS calls +currently supported by DOS-C. This list is for FreeDOS build 2036 (5/2006). + +int 20: Terminated Current Process + Supported + +int 21: DOS System Call + Supported. See table below. + +int 21 Description State Ver Status +--------------------------------------------------------------------------- +00h Terminate Program superseded 1.00 supported +01h Read Keyboard with Echo superseded 1.00 supported +02h Display Character superseded 1.00 supported +03h Auxilliary Input superseded 1.00 supported +04h Auxilliary Output superseded 1.00 supported +05h Print Character superseded 1.00 supported +06h Direct Console I/O active 1.00 supported +07h Direct Console Input active 1.00 supported +08h Read Keyboard Without Echo active 1.00 supported +09h Display String superseded 1.00 supported +0ah Buffered Keyboard Input superseded 1.00 supported +0bh Check Keyboard Status active 1.00 supported +0ch Flush Buffer, Read Keyboard active 1.00 supported +0dh Reset Drive active 1.00 supported +0eh Set Default Drive active 1.00 supported +0fh Open File with FCB superseded 1.00 supported +10h Close File with FCB superseded 1.00 supported +11h Find First File with FCB superseded 1.00 supported +12h Find Next File with FCB superseded 1.00 supported +13h Delete File with FCB superseded 1.00 supported +14h Sequential Read superseded 1.00 supported +15h Sequential Write superseded 1.00 supported +16h Create File with FCB superseded 1.00 supported +17h Rename File with FCB superseded 1.00 supported +18h CP/M compatibility obsolete 1.00 supported +19h Get Default Drive active 1.00 supported +1ah Set Disk Transfer Address active 1.00 supported +1bh Get Default Drive Data superseded 2.00 supported +1ch Get Drive Data superseded 2.00 supported +1dh CP/M compatibility obsolete 1.00 supported +1eh CP/M compatibility obsolete 1.00 supported +1fh Get Default DPB active 5.00 supported +20h CP/M compatibility obsolete 1.00 supported +21h Random Read superseded 1.00 supported +22h Random Write superseded 1.00 supported +23h Get File Size superseded 1.00 supported +24h Set Random Record Number superseded 1.00 supported +25h Set Interrupt Vector active 1.00 supported +26h Create New PSP superseded 1.00 supported +27h Random Block Read superseded 1.00 supported +28h Random Block Write superseded 1.00 supported +29h Parse Filename active 1.00 supported +2ah Get Date active 1.00 supported +2bh Set Date active 1.00 supported +2ch Get Time active 1.00 supported +2dh Set Time active 1.00 supported +2eh Set/Reset Verify Flag active 1.00 supported +2fh Get DTA active 2.00 supported +30h Get Version Number active 2.00 supported +31h Keep Program active 2.00 supported +32h Get DPB active 5.00 supported +3300h Get CTRL+C Check Flag active 2.00 supported +3301h Set CTRL+C Check Flag active 2.00 supported +3305h Get Startup Drive active 2.00 supported +3306h Get MS-DOS Version active 5.00 supported +33ffh Get DOS-C Release superset supported +34h Get InDOS Flag Address active 2.00 supported +35h Get Interrupt Vector active 2.00 supported +36h Get Disk Free Space active 2.00 supported +37h Get/Set Switchar undocumented 2.00 supported +38h Get/Set Country Information active 2.00 supported +39h Create Directory active 2.00 supported +3ah Remove Directory active 2.00 supported +3bh Change Current Directory active 2.00 supported +3ch Create File with Handle active 2.00 supported +3dh Open File with Handle active 2.00 supported +3eh Close File with Handle active 2.00 supported +3fh Read File or Device active 2.00 supported +40h Write File or Device active 2.00 supported +41h Delete File active 2.00 supported +42h Move File Pointer active 2.00 supported +4300h Get File Attributes active 2.00 supported +4301h Set File Attributes active 2.00 supported +44h Ioctl entry active 2.00 supported +45h Duplicate File Handle active 2.00 supported +46h Force Duplicate File Handle active 2.00 supported +47h Get Current Directory active 2.00 supported +48h Allocate Memory active 2.00 supported +49h Free Allocated Memory active 2.00 supported +4ah Set Memory Block Size active 2.00 supported +4b00h Load and Execute Program active 2.00 supported +4b01h Load Program active 5.00 supported +4b03h Load Overlay active 2.00 supported +4b05h Set Execution State active 5.00 PLANNED +4ch End Program active 2.00 supported +4dh Get Child-Program Return Value active 2.00 supported +4eh Find First File active 2.00 supported +4fh Find Next File active 2.00 supported +50h Set PSP Address active 2.00 supported +51h Get PSP Address active 2.00 supported +52h Get List of Lists undocumented 2.00 supported +53h Translate BPB to DPB undocumented supported +54h Get Verify State active 2.00 supported +55h Create New Psp undocumented 2.00 supported +56h Rename File active 2.00 supported +5700h Get File Date and Time active 2.00 supported +5701h Set File Date and Time active 2.00 supported +5800h Get Allocation Strategy active 3.00 supported +5801h Set Allocation Strategy active 3.00 supported +5802h Get Upper-Memory Link active 5.00 supported +5803h Set Upper-Memory Link active 5.00 supported +59h Get Extended Error active 3.00 supported +5ah Create Temporary File active 3.00 supported +5bh Create New File active 3.00 supported +5ch Lock/Unlock File active 3.10 supported +5d00h Server Function Call active 3.10 supported +5d01h Commit All Files active 3.10 NOTE 3 +5d02h Close File by Name active 3.10 NOTE 3 +5d03h Close All Files for Computer active 3.10 NOTE 3 +5d04h Close All Files for Process active 3.10 NOTE 3 +5d05h Get Open File List active 3.10 NOTE 3 +5d06h Get Multiple SDA active 4.00 supported +5d07h Get Redirected Printer Mode active 3.10 supported +5d08h Set Redirected Printer Mode active 4.00 supported +5d09h Flush Redirected Printer Output active 4.00 supported +5d0ah Set Extended Error active 4.00 supported +5eh Generic Network Functions #1 active 3.10 supported +5fh Generic Network Functions #2 active 3.10 supported +60h Truename function undocumented 3.00 supported +61h UNUSED obsolete supported +62h Get current PSP active 3.00 supported +63h Multibyte char ops undocumented 3.20 NOTE 1 +64h ? undocumented returns error +65h NLS Functions active 3.30 supported +66h Code Page Functions active 3.30 supported +67h Set Maximum Handle Count active 3.30 supported +68h Commit File active 3.30 supported +69h GET/SET DISK SERIAL NUMBER active 4.00 supported +6ah COMMIT FILE (same as 68h) active 4.00 supported +6bh NULL FUNCTION active 5.00 supported +6ch Extended Open/Create active 4.00 supported +71h LONG FILENAME FUNCTIONS active 7.00 NOTE 2 + +int 22: Program Termination Address. + Supported. + +int 23: Ctrl-C/Ctrl_Break Handler. + Supported. + +int 24: Critical Error Handler + Dummy routine default. + +int 25: Absolute Disk Read + Supported. + +int 26: Absolute Disk Write + Supported. + +int 27: TSR + Supported. + +int 28: DOS Idle. + Supported. + +int 29: Fast Console Output. + Supported. + +int 2F: DOS Multiplex. + Supported (not ALL functions, but MOST functions supported) + +Notes: + +Note 1 - function 63 Returns error code and lead byte table pointer + DS:SI (function 0). Functions 1 and 2 return error code -1 + (Korean Hangul keyboard input method not supported), but our + UNSTABLE kernels can contain more NLSFUNC / COUNTRY support. + +Note 2 - for LFN support, you can load a separate driver like DOSLFN. + It will hook int 21 and provide long file name functionality. + +Note 3 - planned, but the implementation will be in SHARE. The DOS + kernel only calls hooks (via far call) in a table which is + right before the SFT (list of lists [4] points to SFT). As + long as our SHARE does not support the hooks, they are not + supported either, the unused hook table would waste memory. + +License +------- +See COPYING in DOS-C root directory for license. + + +--------------------------------------------------------------------- + +$Id: intfns.txt 1344 2007-07-28 18:29:50Z mceric $ diff --git a/docs/lfnapi.txt b/docs/lfnapi.txt new file mode 100644 index 0000000..2a32304 --- /dev/null +++ b/docs/lfnapi.txt @@ -0,0 +1,21 @@ + FreeDOS LFN helper API. + +struct lfn_inode +{ + UNICODE name[261]; + + struct dirent l_dir; /* this file's dir entry image */ + + ULONG l_diroff; /* offset of the dir entry */ +}; +typedef struct lfn_inode FAR * lfn_inode_ptr; + +COUNT lfn_allocate_inode(VOID); +COUNT lfn_free_inode(COUNT handle); + +COUNT lfn_setup_inode(COUNT handle, ULONG dirstart, ULONG diroff); + +COUNT lfn_create_entries(COUNT handle, lfn_inode_ptr lip); + +COUNT lfn_dir_read(COUNT handle, lfn_inode_ptr lip); +COUNT lfn_dir_write(COUNT handle); diff --git a/docs/mkboot.txt b/docs/mkboot.txt new file mode 100644 index 0000000..979cf7a --- /dev/null +++ b/docs/mkboot.txt @@ -0,0 +1,11 @@ +To create a bootable floppy suitable for copying the system to +another drive: + +1. Change directory (if necessary) to where the FreeDOS Kernel BIN + directory. + +3. Enter the command "install" to transfer the system files to the + diskette in drive A. If you want to install on drive B, type + "install b:" + +4. Write protect this disk and use it to boot from. diff --git a/docs/nls.txt b/docs/nls.txt new file mode 100644 index 0000000..3f66feb --- /dev/null +++ b/docs/nls.txt @@ -0,0 +1,191 @@ +Current version: $Id: nls.txt 59 2000-08-06 04:42:32Z jimtabor $ + +This document describes all aspects of the implementation +of NLS in the FreeDOS kernel -- 2000/06/16 ska + +Note: + At this time this document contains only an overall description + of how the FreeDOS NLS works; detailed implementation details are + found in HDR\NLS.H and KERNEL\NLS_LOAD.C. When the FreeDOS developers + finally adopted the current scheme, the larger comments of both + files will be merged into a single document -> this file. + += TOC + += Capabilites of the current implementation. + +Tested is: ++ DOS-38 - Get Country Information ++ DOS-65-[2A][0-2] - upcase normal/filename characters ++ DOS-65-23 - YesNo prompt character ++ DOS-65-01 - Get Extended Country Information ++ DOS-65-0[24] - Get pointer to normal/filename upcase table ++ DOS-65-05 - Get pointer to filename terminator table ++ DOS-65-06 - Get pointer to collating sequence table ++ DOS-65-07 - Get pointer to DBCS table + Note: Because I don't know how this used, only an empty table + has been verified to work properly. ++ DOS-66-01 - Get active codepage ++ MUX-14-00 - Installation check ++ MUX-14-02 - Get extended country information ++ MUX-14-04 - Get country information ++ MUX-14-FE - DRDOS get extended country information ++ MUX-14-23 - validate Yes/No prompt (FreeDOS extension) ++ MUX-14-22 - upcase normal character area (FreeDOS extension) ++ MUX-14-A2 - upcase filename character area (FreeDOS extension) + +Not implemented is: ++ DOS-65-00 - Change DOS-65-XX information ++ DOS-66-02 - Set active codepage + Note: The rough interface is available, but no code to actually + to change the codepage. ++ external TSR "NLSFUNC" ++ MUX-14-FF - DRDOS prepare codepage + +Not validated is: ++ DOS-38 - Set Country code, because: + 1) it relies on DOS-66-02 (Set active code page) and + 2) requires external NLSFUNC. ++ COUNTRY= statement in CONFIG.SYS (code avilable, but not tested at all) ++ MUX-14-01 - change codepage & MUX-14-03 - Set codepage, because + the meaning of them is not intentional to me. Both function perform + the same request currently, to change the current codepage or country + code or both (though, see DOS-66-02). + + += Supported NLS packages + +A NLS package may contain data only or data and code. + +If the NLS package shall not contain any code, it must conform to the +code already included within the kernel; otherwise an external TSR, +usually NLSFUNC, must provide all code by hooking and intercepting +the MUX-14-XX API. + +In order to support the external NLSFUNC, all requests for DOS-XX are +re-routed through MUX-14; but because the NLS API must work, even if no +NLSFUNC has been loaded, the kernel implements a MUX-14 interface of its +own and performs all MUX-14 requests. + +However, because the channeling of each request through the MUX chain +is considered a very heavy operation (aka time-consuming), flags are +introduced when to _bypass_ the MUX chain and directly call the +function, which would be activated, if the request would reach the +MUX-14 interface of the kernel. + +Because the kernel can only load NLS packages structurally identical to +U.S.A./CP437 per definition, the kernel automatically sets those flags, +thus, retreives all information from them without to channel the request +through the MUX interrupt chain. + +The term "structurally identical" is explained in NLS.H. + += Using NLS functions from within the kernel + +There are functions to: ++ upcase normal characters: DosUpMem(), DosUpString(), DosUpChar() ++ upcase filename characters: DosUpFMem(), DosUpFString(), DosUpFChar() ++ verify yes/no prompt characters: DosYesNo() ++ retreive data (country informaion): DosGetData() [DOS-65-XX], + DosGetCountryInformation() [DOS-38] + +They implement the usual DOS interface and refer to the country code and +codepage by the usual UWORD numbers; NLS_DEFAULT can be used to specify +"current country/codepage". The "Up*()" functions always use the currently +active NLS package. + +These functions are also called by the INT-21 handler. + +Because of the MUX chain support these functions more or less wrap the +real functions only and check the flags whether to call the internal +function directly or re-route the request through MUX. + +Therefore NLS data must not be accessed directly from outside the NLS +implementation, but through these functions only. + +CAUTION: The DOS NLS differs between "normal" characters and "filename" +characters, that's why one must call DosUpFString() to upcase a +filename rather than DosUpString()! + +Note: The NLS subsystem is robust against any type of characters, +that means DosUpFMem() can be called with any type of junk, except +the pointer to the buffer must not be NULL. + += NLS and fileformats (UNF) + +The current implementation does not implemented everything MS-DOS like, +this includes the internal NLS information block and the fileformat of +COUNTRY.SYS. Both structures shall be updated to increase performance, +rather than require the kernel to simulate old and obsolated interfaces. +To overcome the traditional problem with ever-changing structures +a toolset is provided to represent the NLS package in an implementation- +independed way and read/write/manipulate etc. pp. this data. + +In the final state NLSFUNC will automatically detect the structures +and transform them into the structure required by the kernel. + +To minimize the complexity of these data transformation processes +an independed fileformat called UNF (Uniform NLS file Format) has been +founded, which is totally plain text (except comments) and somewhat +human-readable. Tools will be provided to convert any or particular binary +forms of NLS packages into UNF and back. + +Currently available tools: +GRAB_UNF: Extracts all information from the current NLS API and dumps it + into an UNF file. Supports standard information and DOS-65-03 (lowercase). +UNF2HC: Transforms an UNF file into the format of the hardcoded NLS package + ready to be used when the kernel is make'ed. + + += Testing / Verifying NLS + +Above mentioned UNF toolset includes: +GRAB_UNF: Dump NLS package into UNF file and +NLSUPTST: Test upcase API (DOS-65-2[0-2]). + +Testing steps: +1) Generate an UpCase test verifaction file by running "NLSUPTST /c" on + a DOS computer that is entitled to run a good NLS. + Alternatively download an UP file corresponding to your locale, + that means -.UP (without the angle brackets). + Note: The numerical country code and codepage must match the settings + of your testee system! +2) Do the same an generate an sample UNF of a good NLS, by running + "GRAB_UNF.EXE" or download one from the internet. the filename is: + -.UNF + Note: If you manually edit the file, run "READ_UNF " to + check the file for errors and dump it in the very same format as + GRAB_UNF will. +3) Copy GRAB_UNF.EXE, NLSUPTST.EXE and the UP file onto the testee, e.g. + floppy. Make sure no .UNF file is located there. +4) Create the CONFIG.SYS with only the minimum settings, more than + a COUNTRY= and a SHELL= are usually NOT required. +5) Create an AUTOEXEC.BAT with this contents (strip leading tabs): + GRAB_UNF.EXE + NLSUPTST.EXE + Note: If you have NLS_DEBUG enabled, a lot of noise will be displayed! +6) Reboot the testee +7) The GRAB_UNF.EXE will display its success by: + "NLS info file for - has been created sucessfully" + In this case an UNF file has been created <-> the only way to see this + success status, if NLS_DEBUG is enabled within the kernel. +8) At some point you should see an error message or the good news: + "NLS passed all DOS-65-2[0-2] tests" + This means that NLSUPTST was successful, because there is no other + way to detect this, NLSUPTST must be placed last. +9) Compare the -.UNF file form the directory you + run GRAB_UNF.EXE in with the _equally_ named sample file. + Both must be 100% identical, even the number of spaces are. + +If COMMAND.COM fails to run AUTOEXEC.BAT, change the SHELL= line within +CONFIG.SYS into: + SHELL=GRAB_UNF.EXE +-and- + SHELL=NLSUPTST.EXE +and boot the testee once with each line. + +What do these tests miss? ++ None of these tests try to change neither country code nor code page. ++ By default, these tests cannot override the internal performance flags + and so either the direct-calling or the MUX-re-routing mechanism + is tested, but never both. diff --git a/docs/readme.cvs b/docs/readme.cvs new file mode 100644 index 0000000..0702115 --- /dev/null +++ b/docs/readme.cvs @@ -0,0 +1,64 @@ + +Thanks to Bart Oldeman for helping us with moving the FreeDOS source code +from CVS to Subversion! The old CVS repository is still available for +browsing, but will no longer be used for managing FreeDOS Projects - and +will probably be deleted later. Please use Subversion for the FreeDOS +kernel, FreeCOM (FreeDOS command.com), Install, and Mem. + +Bart has also written a Subversion at SourceForge Mini How-to: +http://fd-doc.sourceforge.net/wiki/index.php?n=FdDocEn.SVN + +This information was mostly lifted from SourceForge.net: +https://sourceforge.net/svn/?group_id + +FreeDOS Subversion: + +Subversion (SVN) is a tool used by many software developers to manage +changes within their source code tree. SVN provides the means to store not +only the current version of a piece of source code, but a record of all +changes (and who made those changes) that have occurred to that source code. +Use of SVN is particularly common on projects with multiple developers, +since SVN ensures changes made by one developer are not accidentally removed +when another developer posts their changes to the source tree. + +In order to access a Subversion repository, you must install a special piece +of software called a Subversion client. Subversion clients are available for +most any operating system. + +To get a working copy, do svn co URL freedos where URL is the complete path +to the trunk of the project you want. For example: + +FreeDOS kernel + https://freedos.svn.sourceforge.net/svnroot/freedos/kernel/trunk +FreeDOS FreeCOM + https://freedos.svn.sourceforge.net/svnroot/freedos/freecom/trunk +FreeDOS MEM + https://freedos.svn.sourceforge.net/svnroot/freedos/mem/trunk +FreeDOS Install + https://freedos.svn.sourceforge.net/svnroot/freedos/install/trunk + +Be careful NOT to use the top level + * https://freedos.svn.sourceforge.net/svnroot/freedos URL +instead of one of the trunk URLs. This will pull all modules, tags and/or +branches of the project - it will be huge. Instead, you will want to use +/trunk to the URL to check out only the trunk code (main development line). + +Though Subversion repositories are most commonly accessed using a special +piece of software called a Subversion client, SourceForge also provides a +web-based interface to view Subversion repositories. Browsing the Subversion +tree gives you a great view into the current status of this project's code. +You may also view the complete history of any file in the repository. + + * Browse Subversion repository +http://freedos.svn.sourceforge.net/viewvc/freedos/ + +FreeDOS is a trademark of Jim Hall. + + + +Note: Readonly access via the old CVS interface worked as follows: +To check out the code, first log in: +cvs -z3 -d:pserver:anonymous@cvs.freedos.sourceforge.net:/cvsroot/freedos login +Password: Press the Enter key. +Then, to get the kernel code: +cvs -z3 -d:pserver:anonymous@cvs.freedos.sourceforge.net:/cvsroot/freedos checkout kernel diff --git a/docs/readme.txt b/docs/readme.txt new file mode 100644 index 0000000..b24c598 --- /dev/null +++ b/docs/readme.txt @@ -0,0 +1,38 @@ +INTRODUCTION +------------ + +This archive contains the current FreeDOS Kernel, also +known as DOS-C, originally written by Pasquale J. Villani. + +The FreeDOS Kernel is available from http://freedos.sourceforge.net/ +It's also available from http://www.dosemu.org/ (somewhere on there). + +The FreeDOS Kernel is also available through the FreeDOS Project at +http://www.freedos.org/ + +See the DOCS directory for more documentation and information about +the FreeDOS Kernel. + +Contents of zip files: +ke20xx_16.zip : binaries for 8086, FAT16 +ke20xx_32.zip : binaries for 8086, FAT16, FAT32 +ke20xxsrc.zip : sources for the kernel + +BUG REPORTS +----------- + +If you have found a bug, think you have found a bug, or would just +like to make a suggestion, go to the bug tracking web page at +http://sourceforge.net/tracker/?group_id=5109&atid=105109 + +An archive of old (Bugzilla) items is at www.freedos.org/bugzilla/ + +There is also a feature request tracker on our SourceForge pages at +http://sourceforge.net/tracker/?atid=355109&group_id=5109&func=browse + + +Copyright +--------- + +DOS-C is (c) Copyright 1995, 1996 by Pasquale J. Villani +All Rights Reserved. diff --git a/docs/sys.txt b/docs/sys.txt new file mode 100644 index 0000000..38b808e --- /dev/null +++ b/docs/sys.txt @@ -0,0 +1,223 @@ +FreeDOS System Installer v3.6e - Nov 13, 2009 +documentation by: + Jeremy Davis + Bart Oldeman + +SYS's standard behavior is very similar (though in +my opinion improved) to that of other DOSes. +SYS /? (or no options) should provide a general usage, +and SYS CONFIG /help (or SYS CONFIG /?) should +provide usage for the new configuration options. + +The best documentation is the source itself, but +we try to keep this document updated. + + +Usage: SYS [source] drive: [bootsect] [{option}] + source = A:,B:,C:\KERNEL\BIN\,etc., or current directory if not given + dest = drive (A:,B:,C:,... or A,B,C,...) to install system to + bootsect = name of 512-byte boot sector file image for drive: + to write to *instead* of real boot sector + {option} is one or more of the following: + /BOTH : write to *both* the real boot sector and the image file + /BOOTONLY: do *not* copy kernel / shell, only update boot sector or image + /UPDATE : copy kernel and update boot sector (do *not* copy shell) + /OEM : indicates boot sector, filenames, and load segment to use + /OEM:FD use FreeDOS compatible settings + /OEM:DR use DR DOS 7+ compatible settings (same as /OEM) + /OEM:PC use PC-DOS compatible settings + /OEM:MS use MS-DOS compatible settings + /OEM:W9x use MS Win9x DOS compatible settings + default is /OEM:AUTO, select DOS based on existing files + /K name : name of kernel to use in boot sector instead of KERNEL.SYS + /L segm : hex load segment to use in boot sector instead of 0x60 + /B btdrv : hex BIOS # of boot drive set in bs, 0=A:, 80=1st hd,... + /FORCE : override automatic selection of BIOS related settings + /FORCE:BSDRV (/FORCEDRV) use boot drive # set in bootsector + /FORCE:BIOSDRV use boot drive # provided by BIOS + /FORCE:AUTO select LBA or CHS depending on BIOS availability + /FORCE:LBA always use LBA + /FORCE:CHS always use CHS + /NOBAKBS : skips copying boot sector to backup bs, FAT32 only else ignored + /SKFN filename : copy from filename to KERNEL.SYS; settings same as /OEM:FD + /SCFN filename : copy from filename to COMMAND.COM + /BACKUPBS [path]filename : save current bs before overwriting + /DUMPBS [path]filename : save current bs and exit + /RESTORBS [path]filename : overwrite bs and exit + /VERBOSE : display additional (debug) output + +SYS CONFIG /help + + +The simplest usage: + +SYS dest: + +dest should be the drive (A:, B:, C:, ...) you wish +to be bootable with FreeDOS (kernel & command.com) +When using this form, KERNEL.SYS and COMMAND.COM +must reside either in the current directory (which +is searched first) or in recent revisions may also +be in the root directory of the current drive. + +Complete form: + +SYS [source] dest: [bootsect [/BOTH]] + +Here dest is the same as before, but this time +you specify where KERNEL.SYS and COMMAND.COM are. +Source may simply be a drive (in this case it +is similar to PC & MS SYS). The current directory +of the specified drive is first searched for +KERNEL.SYS & COMMAND.COM and if not found then +the root directory of the specified drive is tried. +Alternatively, you may specify a path (either fully +qualified or relative) to where KERNEL.SYS and +COMMAND.COM may be found; note that this should +only search this directory and will fail if they +are not found, ie it will not check for them on +the root directory of the drive specified when +a path is given. It should also fail if the +source and destination drive are both the same +and would result in trying to SYS from the root +to the root (ie trying to SYS from C:\ to C:\). + +If you specify a name for "bootsect", for instance, +bootsect.fd, SYS will write to that file instead of +the real boot sector. You will obtain a 512-byte file +containing the boot sector, which can then be used +for dual booting or diagnostic purposes. + +If you also specify BOTH, sys will write to both +the image file and the boot sector. + +The FORCE options override the default actions +to use. On FAT32 drives /FORCE:LBA and /FORCE:CHS +will select which boot sector code is used (default +same as /FORCE:AUTO will choose based on query of +BIOS support for LBA extensions and use LBA if it +is supported else only CHS will be used). On FAT12 +and FAT16 drives specifying /FORCE:LBA will ensure +even 1st floppy drive attempts to use LBA support +(note that CHS may still be used if LBA check fails) +and /FORCE:CHS will always bypass use of LBA extensions. + + +Kernel Configuration Options: + +Simplest form: + +SYS CONFIG + +This will simply display the current settings +for the file KERNEL.SYS in the current directory. +It is useful to see what the options are currently +set to, what options are supported, and should +show valid values along with defaults (defaults are +the valid values with a '*' next to them). + +Optionally specify file: + +SYS CONFIG [drive][path]KERNEL.SYS + +This form behaves as above, except will display +the settings for the kernel file you specify. +drive and path are optional, and generally just +a \ will be used to indicate root directory of +current drive. KERNEL.SYS specifies the filename +of the kernel, which may not be "KERNEL.SYS", +for example when testing you want to alter +KERNTEST.SYS and later copy (or rename) this to +KERNEL.SYS for booting. + + +Changing options: + +SYS CONFIG OPTION1=value [OPTION2=value ...] + +This form will read the current settings from +the kernel (KERNEL.SYS in the current directory) +and set the options specified to the value given. +If the value is potentially invalid (too large, too +small, etc) then a warning will be displayed, but +the change will still occur. The kernel file is +only updated if at least one option is different from the +current settings. If you wish to force the kernel +file to be written to, then set the same option +twice (OPTION1=oddvalue OPTION1=desiredvalue), with +the 1st time the value being different from the +current one and the rightmost one being the desired +value. Currently three options are supported. +Note: currently only the 1st three letters are +actually checked, so they may be abreviated to +DLA, SHO, and SKI and with my recent patch you may +specify the value as either a decimal number 0,10,255,... +or as a hexidecimal number 0x0,0xA, 0xFF... + +DLASORT which may be set to 0 or 1 +DLASORT=0 or DLASORT=1 +This option is for specifying whether Drive Letter +Assignment should follow the normal MSDOS way of +all primary partitions across drives and then +extended partitions, or the more logical +all partitions (primary & extended) on the 1st +drive, then repeat for all following drives +(all primary & extended, then try next drive). +0 corresponds to MS way and 1 corresponds to first +drive completely, then next ... + +SHOWDRIVEASSIGNMENT which may be 0 or 1 +SHOWDRIVEASSIGNMENT=0 or SHOWDRIVEASSIGNMENT=1 +If 1 then the normal drive assignment information +is displayed upon booting. If 0 then this information +is supressed (not shown). + +SKIPCONFIGSECONDS which may be -128 to 127. +A negative value ( < 0 ) indicates that F5/F8 +processing will be skipped (the kernel won't check +if you pressed these keys, so you can't skip config +file (CONFIG.SYS) processing). A 0 means you must +have pressed the key precisely for when the kernel +checks for it - essentially skipping, though a well +timed finger will still get to use it. And any value +greater than 0 is the number of seconds the kernel will +display the prompt and wait for you to press the key +before assuming you didn't. + +FORCELBA which may be 0 or 1 +FORCELBA=0 or FORCELBA=1 +If 1 then the kernel will use LBA (extended INT13) +techniques to address all partitions if possible, +even if these have a non-LBA partition type and +are completely below cylinder 1023 (usually the 8GB +boundary). This is 0 by default, for compatibility +reasons. Setting this to 1 may bypass some buggy +BIOSes and gives slightly better performance. + +GLOBALENABLELBASUPPORT which maybe 0 or 1 +GLOBALENABLELBASUPPORT=0 or GLOBALENABLELBASUPPORT=1 +If 0 then LBA will be completely disabled, irrespective +of the FORCELBA setting. You need this if FreeDOS thinks +you have LBA available, but in reality you do not. +This setting is set to 1 by default. + +Example: To set the kernel in the current directory +to have a timeout of 5 seconds (default is 2) run +SYS CONFIG SKI=5 + + +Changing options of specified file: + +SYS CONFIG [drive][path]KERNEL.SYS OPTION1=value ...] + +This is just like previous section on setting options, +except the first argument after CONFIG specifies which +kernel file to use. The filename is the same form used +for displaying options of specified kernel file described +above. + +Example2: To set a kernel in the root directory to +not show drive assignment and change the timeout +to never check +SYS CONFIG \KERNEL.SYS SKI=-1 SHOWDRIVEASSIGNMENT=0x0 + diff --git a/drivers/floppy.asm b/drivers/floppy.asm new file mode 100644 index 0000000..e9550f0 --- /dev/null +++ b/drivers/floppy.asm @@ -0,0 +1,229 @@ +; +; File: +; floppy.asm +; Description: +; floppy disk driver primitives +; +; 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. +; +; $Id: floppy.asm 980 2004-06-19 19:41:47Z perditionc $ +; + +%include "../kernel/segs.inc" +segment HMA_TEXT + +; +; BOOL ASMPASCAL fl_reset(WORD drive); +; +; Reset both the diskette and hard disk system. +; returns TRUE if successful. +; + + global FL_RESET +FL_RESET: + pop ax ; return address + pop dx ; drive (DL only) + push ax ; restore address + mov ah,0 ; BIOS reset diskette & fixed disk + int 13h + + sbb ax,ax ; carry set indicates error, AX=-CF={-1,0} + inc ax ; ...return TRUE (1) on success, + ret ; else FALSE (0) on failure + +; +; COUNT ASMPASCAL fl_diskchanged(WORD drive); +; +; Read disk change line status. +; returns 1 if disk has changed, 0 if not, 0xFFFF if error. +; + + global FL_DISKCHANGED +FL_DISKCHANGED: + pop ax ; return address + pop dx ; drive (DL only, 00h-7Fh) + push ax ; restore stack + + push si ; preserve value + mov ah,16h ; read change status type + xor si,si ; RBIL: avoid crash on AT&T 6300 + int 13h + pop si ; restore + + sbb al,al ; AL=-CF={-1,0} where 0==no change + jnc fl_dc ; carry set on error or disk change + cmp ah,6 ; if AH==6 then disk change, else error + jne fl_dc ; if error, return -1 + mov al, 1 ; set change occurred +fl_dc: cbw ; extend AL into AX, AX={1,0,-1} + ret ; note: AH=0 on no change, AL set above + +; +; Format tracks (sector should be 0). +; COUNT ASMPASCAL fl_format(WORD drive, WORD head, WORD track, WORD sector, WORD count, UBYTE FAR *buffer); +; Reads one or more sectors. +; COUNT ASMPASCAL fl_read (WORD drive, WORD head, WORD track, WORD sector, WORD count, UBYTE FAR *buffer); +; Writes one or more sectors. +; COUNT ASMPASCAL fl_write (WORD drive, WORD head, WORD track, WORD sector, WORD count, UBYTE FAR *buffer); +; COUNT ASMPASCAL fl_verify(WORD drive, WORD head, WORD track, WORD sector, WORD count, UBYTE FAR *buffer); +; +; Returns 0 if successful, error code otherwise. +; + + global FL_FORMAT +FL_FORMAT: + mov ah,5 ; format track + jmp short fl_common + + global FL_READ +FL_READ: + mov ah,2 ; read sector(s) + jmp short fl_common + + global FL_VERIFY +FL_VERIFY: + mov ah,4 ; verify sector(s) + jmp short fl_common + + global FL_WRITE +FL_WRITE: + mov ah,3 ; write sector(s) + +fl_common: + push bp ; setup stack frame + mov bp,sp + + mov cx,[bp+0Ch] ; cylinder number + + mov al,1 ; this should be an error code + cmp ch,3 ; this code can't write above 3FFh=1023 + ja fl_error ; as cylinder # is limited to 10 bits. + + xchg ch,cl ; ch=low 8 bits of cyl number + ror cl,1 ; bits 8-9 of cylinder number... + ror cl,1 ; ...to bits 6-7 in CL + or cl,[bp+0Ah] ; or in the sector number (bits 0-5) + + mov al,[bp+08h] ; count of sectors to read/write/... + les bx,[bp+04h] ; Load 32 bit buffer ptr into ES:BX + + mov dl,[bp+10h] ; drive (if or'ed 80h its a hard drive) + mov dh,[bp+0Eh] ; get the head number + + int 13h ; process sectors + + sbb al,al ; carry: al=ff, else al=0 + and al,ah ; carry: error code, else 0 +fl_error: + mov ah,0 ; extend AL into AX without sign extension + pop bp + ret 14 + +; +; COUNT ASMPASCAL fl_lba_ReadWrite(BYTE drive, WORD mode, void FAR * dap_p); +; +; Returns 0 if successful, error code otherwise. +; + + global FL_LBA_READWRITE +FL_LBA_READWRITE: + push bp ; setup stack frame + mov bp,sp + + push ds + push si ; wasn't in kernel < KE2024Bo6!! + + mov dl,[bp+10] ; drive (if or'ed with 80h a hard drive) + mov ax,[bp+8] ; get the command + lds si,[bp+4] ; get far dap pointer + int 13h ; read from/write to drive + + pop si + pop ds + + pop bp + + mov al,ah ; place any error code into al + mov ah,0 ; zero out ah + ret 8 + +; +; void ASMPASCAL fl_readkey (void); +; + + global FL_READKEY +FL_READKEY: xor ah, ah + int 16h + ret + +; +; COUNT ASMPASCAL fl_setdisktype (WORD drive, WORD type); +; + + global FL_SETDISKTYPE +FL_SETDISKTYPE: + pop bx ; return address + pop ax ; disk format type (al) + pop dx ; drive number (dl) + push bx ; restore stack + mov ah,17h ; floppy set disk type for format + int 13h +ret_AH: + mov al,ah ; place any error code into al + mov ah,0 ; zero out ah + ret + +; +; COUNT ASMPASCAL fl_setmediatype (WORD drive, WORD tracks, WORD sectors); +; + global FL_SETMEDIATYPE +FL_SETMEDIATYPE: + pop ax ; return address + pop bx ; sectors/track + pop cx ; number of tracks + pop dx ; drive number + push ax ; restore stack + push di + + dec cx ; number of cylinders - 1 (last cyl number) + xchg ch,cl ; CH=low 8 bits of last cyl number + + ror cl,1 ; extract bits 8-9 of cylinder number... + ror cl,1 ; ...into cl bit 6-7 + + or cl,bl ; sectors/track (bits 0-5) or'd with high cyl bits 7-6 + + mov ah,18h ; disk set media type for format + int 13h + jc skipint1e + + push es + xor dx,dx + mov es,dx + cli + pop word [es:0x1e*4+2] ; set int 0x1e table to es:di + mov [es:0x1e*4 ], di + sti +skipint1e: + pop di + jmp short ret_AH + diff --git a/drivers/makefile b/drivers/makefile new file mode 100644 index 0000000..e53c916 --- /dev/null +++ b/drivers/makefile @@ -0,0 +1,49 @@ +# +# makefile for device.lib +# +# $Id: makefile 1387 2009-05-19 21:39:29Z bartoldeman $ +# + + +!include "../mkfiles/generic.mak" + + +# MICROSOFT C +# ----------- +#MODEL = s +#CFLAGS = /c /Gs /A$(MODEL) +#AFLAGS = /Mx /Dmem$(MODEL)=1 +#TERM = ; + +# BORLAND C +# ----------- +#MODEL = s +#CFLAGS = -c -m$(MODEL) +#AFLAGS = /Mx /Dmem$(MODEL)=1 +#LIBFLAGS = /c + +OBJS = floppy.obj rdpcclk.obj wrpcclk.obj wratclk.obj + +LIBOBJS= +floppy.obj +rdpcclk.obj +wrpcclk.obj +wratclk.obj + + + +# Build the LIBRARY +# ----------------- +all: production + +production: ../lib/device.lib + +../lib/device.lib: device.lib + $(CP) device.lib ..$(DIRSEP)lib + +clobber: clean + -$(RM) device.lib status.me ..$(DIRSEP)lib$(DIRSEP)device.lib + +clean: + -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.cod *.err + +device.lib : $(OBJS) + -$(RM) device.lib + $(LIBUTIL) $(LIBFLAGS) device $(LIBOBJS) $(LIBTERM) + diff --git a/drivers/rdpcclk.asm b/drivers/rdpcclk.asm new file mode 100644 index 0000000..b14abf0 --- /dev/null +++ b/drivers/rdpcclk.asm @@ -0,0 +1,53 @@ +; +; File: +; rdpcclk.asm +; Description: +; read the PC style clock from bios +; +; 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. +; +; $Header$ +; + + %include "../kernel/segs.inc" + +segment HMA_TEXT + +; +; ULONG ReadPCClock(void) +; + global READPCCLOCK +READPCCLOCK: + mov ah,0 + int 1ah + extern _DaysSinceEpoch ; ; update days if necessary + + ; (ah is still 0, al contains midnight flag) + add word [_DaysSinceEpoch ],ax ; *some* BIOSes accumulate several days + adc word [_DaysSinceEpoch+2],byte 0; + + ; set return value dx:ax + xchg ax,cx ; ax=_cx, cx=_ax + xchg ax,dx ; dx=_cx, ax=_dx (cx=_ax) + + ret + diff --git a/drivers/wratclk.asm b/drivers/wratclk.asm new file mode 100644 index 0000000..38a4f80 --- /dev/null +++ b/drivers/wratclk.asm @@ -0,0 +1,63 @@ +; +; File: +; wratclk.asm +; Description: +; WriteATClock - sysclock support +; +; 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. +; +; $Header$ +; + + %include "../kernel/segs.inc" + +segment HMA_TEXT + +; +; VOID WriteATClock(bcdDays, bcdHours, bcdMinutes, bcdSeconds) +; BYTE *bcdDays; +; BYTE bcdHours; +; BYTE bcdMinutes; +; BYTE bcdSeconds; +; + global WRITEATCLOCK +WRITEATCLOCK: + push bp + mov bp,sp +; bcdSeconds = 4 +; bcdMinutes = 6 +; bcdHours = 8 +; bcdDays = 10 + mov ch,byte [bp+8] ;bcdHours + mov cl,byte [bp+6] ;bcdMinutes + mov dh,byte [bp+4] ;bcdSeconds + mov dl,0 + mov ah,3 + int 1ah + mov bx,word [bp+10] ;bcdDays + mov dx,word [bx] + mov cx,word [bx+2] + mov ah,5 + int 1ah + pop bp + ret 8 + diff --git a/drivers/wrpcclk.asm b/drivers/wrpcclk.asm new file mode 100644 index 0000000..051bc25 --- /dev/null +++ b/drivers/wrpcclk.asm @@ -0,0 +1,49 @@ +; +; File: +; wrpcclk.asm +; Description: +; WritePCClock - sysclock support +; +; 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. +; +; $Header$ +; + %include "../kernel/segs.inc" + +segment HMA_TEXT + + +; +; VOID WritePCClock(Ticks) +; ULONG Ticks; +; + global WRITEPCCLOCK +WRITEPCCLOCK: +; Ticks = 4 + pop ax ; return address + pop dx + pop cx ; Ticks + push ax ; restore stack + mov ah,1 + int 1ah + ret + diff --git a/filelist b/filelist new file mode 100644 index 0000000..33bd657 --- /dev/null +++ b/filelist @@ -0,0 +1,153 @@ +*/*/build.bat +*/*/buildall.bat +*/*/clean.bat +*/*/clobber.bat +*/*/config.b +*/*/filelist +*/*/default.bat +*/*/makefile +*/*/boot/boot.asm +*/*/boot/boot32.asm +*/*/boot/boot32lb.asm +*/*/boot/makefile +*/*/docs/bugs.txt +*/*/docs/build.txt +*/*/docs/config.txt +*/*/docs/contrib.txt +*/*/docs/copying +*/*/docs/fdkernel.lsm +*/*/docs/history.txt +*/*/docs/intfns.txt +*/*/docs/lfnapi.txt +*/*/docs/mkboot.txt +*/*/docs/nls.txt +*/*/docs/readme.cvs +*/*/docs/readme.txt +*/*/docs/sys.txt +*/*/drivers/floppy.asm +*/*/drivers/makefile +*/*/drivers/rdpcclk.asm +*/*/drivers/wratclk.asm +*/*/drivers/wrpcclk.asm +*/*/hdr/algnbyte.h +*/*/hdr/algndflt.h +*/*/hdr/buffer.h +*/*/hdr/cds.h +*/*/hdr/clock.h +*/*/hdr/date.h +*/*/hdr/dcb.h +*/*/hdr/device.h +*/*/hdr/dirmatch.h +*/*/hdr/error.h +*/*/hdr/exe.h +*/*/hdr/fat.h +*/*/hdr/fcb.h +*/*/hdr/file.h +*/*/hdr/fnode.h +*/*/hdr/kbd.h +*/*/hdr/kconfig.h +*/*/hdr/lol.h +*/*/hdr/mcb.h +*/*/hdr/network.h +*/*/hdr/nls.h +*/*/hdr/pcb.h +*/*/hdr/portab.h +*/*/hdr/process.h +*/*/hdr/sft.h +*/*/hdr/stacks.inc +*/*/hdr/tail.h +*/*/hdr/time.h +*/*/hdr/version.h +*/*/hdr/xstructs.h +*/*/kernel/nls/001-437.hc +*/*/kernel/nls/001-437.unf +*/*/kernel/nls/001-437.up +*/*/kernel/nls/049-850.hc +*/*/kernel/nls/049-850.unf +*/*/kernel/nls/049-850.up +*/*/kernel/nls/files +*/*/kernel/apisupt.asm +*/*/kernel/asmsupt.asm +*/*/kernel/blockio.c +*/*/kernel/break.c +*/*/kernel/chario.c +*/*/kernel/config.c +*/*/kernel/config.h +*/*/kernel/console.asm +*/*/kernel/dosfns.c +*/*/kernel/dosidle.asm +*/*/kernel/dosnames.c +*/*/kernel/dsk.c +*/*/kernel/dyndata.h +*/*/kernel/dyninit.c +*/*/kernel/entry.asm +*/*/kernel/error.c +*/*/kernel/execrh.asm +*/*/kernel/fatdir.c +*/*/kernel/fatfs.c +*/*/kernel/fattab.c +*/*/kernel/fcbfns.c +*/*/kernel/globals.h +*/*/kernel/init-dat.h +*/*/kernel/init-mod.h +*/*/kernel/initclk.c +*/*/kernel/initdisk.c +*/*/kernel/inithma.c +*/*/kernel/initoem.c +*/*/kernel/int2f.asm +*/*/kernel/inthndlr.c +*/*/kernel/intr.asm +*/*/kernel/makefile +*/*/kernel/io.asm +*/*/kernel/io.inc +*/*/kernel/ioctl.c +*/*/kernel/iprf.c +*/*/kernel/irqstack.asm +*/*/kernel/kernel.asm +*/*/kernel/kernel.cfg +*/*/kernel/lfnapi.c +*/*/kernel/ludivmul.inc +*/*/kernel/main.c +*/*/kernel/memdisk.asm +*/*/kernel/memmgr.c +*/*/kernel/misc.c +*/*/kernel/network.c +*/*/kernel/newstuff.c +*/*/kernel/nls.c +*/*/kernel/nls_hc.asm +*/*/kernel/nls_load.c +*/*/kernel/nlssupt.asm +*/*/kernel/prf.c +*/*/kernel/printer.asm +*/*/kernel/procsupt.asm +*/*/kernel/proto.h +*/*/kernel/segs.inc +*/*/kernel/serial.asm +*/*/kernel/strings.c +*/*/kernel/sysclk.c +*/*/kernel/syspack.c +*/*/kernel/systime.c +*/*/kernel/task.c +*/*/kernel/turboc.cfg +*/*/lib/makefile +*/*/mkfiles/generic.mak +*/*/mkfiles/bc5.mak +*/*/mkfiles/mscl8.mak +*/*/mkfiles/tc2.mak +*/*/mkfiles/tc3.mak +*/*/mkfiles/turbocpp.mak +*/*/mkfiles/watcom.mak +*/*/sys/fdkrncfg.c +*/*/sys/bin2c.c +*/*/sys/makefile +*/*/sys/sys.c +*/*/sys/talloc.c +*/*/utils/echoto.bat +*/*/utils/exeflat.c +*/*/utils/indent.ini +*/*/utils/makefile +*/*/utils/patchobj.c +*/*/utils/proto.bat +*/*/utils/relocinf.c +*/*/utils/rmfiles.bat +*/*/utils/wlinker.bat diff --git a/hdr/algnbyte.h b/hdr/algnbyte.h new file mode 100644 index 0000000..e66c2e3 --- /dev/null +++ b/hdr/algnbyte.h @@ -0,0 +1,13 @@ + +#if defined(_MSC_VER) +#if _MSC_VER >= 700 +#pragma warning(disable:4103) +#endif +#pragma pack(1) +#elif defined(_QC) || defined(__WATCOMC__) || defined(__GNUC__) +#pragma pack(1) +#elif defined(__ZTC__) +#pragma ZTC align 1 +#elif defined(__TURBOC__) && (__TURBOC__ > 0x202) +#pragma option -a- +#endif diff --git a/hdr/algndflt.h b/hdr/algndflt.h new file mode 100644 index 0000000..5c36f11 --- /dev/null +++ b/hdr/algndflt.h @@ -0,0 +1,7 @@ +#if defined (_MSC_VER) || defined(_QC) || defined(__WATCOMC__) || defined(__GNUC__) +#pragma pack() +#elif defined (__ZTC__) +#pragma ZTC align +#elif defined(__TURBOC__) && (__TURBOC__ > 0x202) +#pragma option -a. +#endif diff --git a/hdr/buffer.h b/hdr/buffer.h new file mode 100644 index 0000000..09c0e39 --- /dev/null +++ b/hdr/buffer.h @@ -0,0 +1,64 @@ +/****************************************************************/ +/* */ +/* buffer.h */ +/* */ +/* Sector buffer structure */ +/* */ +/* Copyright (c) 2001 */ +/* Bart Oldeman */ +/* */ +/* Largely taken from globals.h: */ +/* Copyright (c) 1995, 1996 */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *buffer_hRcsId = + "$Id: buffer.h 1702 2012-02-04 08:46:16Z perditionc $"; +#endif +#endif + +#include "dsk.h" /* only for MAX_SEC_SIZE */ +#define BUFFERSIZE MAX_SEC_SIZE + +struct buffer { + UWORD b_next; /* next buffer in LRU list */ + UWORD b_prev; /* previous buffer in LRU list */ + BYTE b_unit; /* disk for this buffer */ + BYTE b_flag; /* buffer flags */ + ULONG b_blkno; /* block for this buffer */ + UBYTE b_copies; /* number of copies to write */ + UWORD b_offset; /* offset in sectors between copies + to write for FAT sectors */ + struct dpb FAR *b_dpbp; /* pointer to DPB */ + UWORD b_remotesz; /* size of remote buffer if remote */ + BYTE b_padding; + UBYTE b_buffer[BUFFERSIZE]; /* 512 byte sectors for now */ +}; + +#define BFR_DIRTY 0x40 /* buffer modified */ +#define BFR_VALID 0x20 /* buffer contains valid data */ +#define BFR_DATA 0x08 /* buffer is from data area */ +#define BFR_DIR 0x04 /* buffer is from dir area */ +#define BFR_FAT 0x02 /* buffer is from fat area */ +#define BFR_UNCACHE 0x01 /* buffer to be released ASAP */ + diff --git a/hdr/cds.h b/hdr/cds.h new file mode 100644 index 0000000..1618b4a --- /dev/null +++ b/hdr/cds.h @@ -0,0 +1,91 @@ +/****************************************************************/ +/* */ +/* cds.h */ +/* */ +/* Current Directory structures */ +/* */ +/* 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 MAX_CDSPATH 67 + +struct cds { + BYTE cdsCurrentPath[MAX_CDSPATH]; + UWORD cdsFlags; /* see below */ + struct dpb FAR *cdsDpb; /* if != 0, associated DPB */ + + union { + BYTE FAR *_cdsRedirRec; /* IFS record */ + struct { + UWORD _cdsStrtClst; /* if local path (Flags & CDSPHYSDRV): + start cluster of CWD; root == 0, + never access == 0xFFFF */ + UWORD _cdsParam; + } _cdsRedir; + } _cdsUnion; + + UWORD cdsStoreUData; + +#define cdsJoinOffset cdsBackslashOffset + WORD cdsBackslashOffset; /* Position of "root directory" backslash for + this drive within CurrentPath[] + prerequisites: + + ofs <= strlen(currentPath) + + if UNC: ofs > share component + if local path: ofs > colon + */ + + BYTE cdsNetFlag1; /* According to PCDOS 7 Tech Ref: IFS drive, 2=IFS, 4=NetUse */ + BYTE FAR *cdsIfs; /* Pointer to Installable File System Header */ + UWORD cdsNetFlags2; /* File System specific data */ + +}; + +#define cdsStrtClst _cdsUnion._cdsRedir._cdsStrtClst +#define cdsRedirRec _cdsUnion._cdsRedirRec +#define cdsParam _cdsUnion._cdsRedir._cdsParam + +/* Bits for cdsFlags (OR combination) */ +#define CDSNETWDRV 0x8000 +#define CDSPHYSDRV 0x4000 +#define CDSJOINED 0x2000 /* not in combination with NETWDRV or SUBST */ +#define CDSSUBST 0x1000 /* not in combination with NETWDRV or JOINED */ +#define CDS_HIDDEN (1 << 7) /* hide drive from redirector's list */ + +/* NETWORK PHYSICAL meaning + 0 0 drive not accessable + 0 1 local file system + 1 0 networked file system (UNC naming convention) + 1 1 installable file system (IFS) +*/ +#define CDSMODEMASK (CDSNETWDRV | CDSPHYSDRV) + +/* #define CDSVALID (CDSNETWDRV | CDSPHYSDRV) */ +#define CDSVALID CDSMODEMASK + +#define IS_DEVICE 0x20 +#define IS_NETWORK 0x40 + +#define CDS_MODE_SKIP_PHYSICAL 0x01 /* don't resolve SUBST, JOIN, NETW */ +#define CDS_MODE_CHECK_DEV_PATH 0x02 /* check for existence of device path */ +#define CDS_MODE_ALLOW_WILDCARDS 0x04 /* allow wildcards in "truename" */ diff --git a/hdr/clock.h b/hdr/clock.h new file mode 100644 index 0000000..8d14160 --- /dev/null +++ b/hdr/clock.h @@ -0,0 +1,47 @@ +/****************************************************************/ +/* */ +/* clock.h */ +/* */ +/* Clock Driver data structures & declarations */ +/* */ +/* November 26, 1991 */ +/* */ +/* Adapted to DOS/NT June 12, 1993 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *clock_hRcsId = + "$Id: clock.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +struct ClockRecord { + UWORD clkDays; /* days since Jan 1, 1980. */ + UBYTE clkMinutes; /* residual minutes. */ + UBYTE clkHours; /* residual hours. */ + UBYTE clkHundredths; /* residual hundredths of a second. */ + UBYTE clkSeconds; /* residual seconds. */ +}; + diff --git a/hdr/date.h b/hdr/date.h new file mode 100644 index 0000000..5df3fae --- /dev/null +++ b/hdr/date.h @@ -0,0 +1,57 @@ +/****************************************************************/ +/* */ +/* date.h */ +/* */ +/* DOS General Date Structure */ +/* */ +/* 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. */ +/****************************************************************/ + +/* TC 2.01 complains if `date' is defined twice. -- ror4 */ +#ifndef DOSC_DATE_H +#define DOSC_DATE_H + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *date_hRcsId = + "$Id: date.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +/* FAT file date - takes the form of yyyy yyym mmmd dddd where physical */ +/* year=1980+yyyyyy */ + +#define DT_YEAR(d) (((d)>>9)&0x7f) +#define DT_MONTH(d) (((d)>>5)&0x0f) +#define DT_DAY(d) ((d)&0x1f) + +#define DT_ENCODE(m,d,y) ((((m)&0x0f)<<5)|((d)&0x1f)|(((y)&0x7f)<<9)) + +#define EPOCH_WEEKDAY 2 /* Tuesday (i. e.- 0 == Sunday) */ +#define EPOCH_MONTH 1 /* January */ +#define EPOCH_DAY 1 /* 1 for January 1 */ +#define EPOCH_YEAR 1980 /* for Tues 1-1-80 epoch */ + +typedef UWORD date; + +#endif + diff --git a/hdr/dcb.h b/hdr/dcb.h new file mode 100644 index 0000000..26044fc --- /dev/null +++ b/hdr/dcb.h @@ -0,0 +1,92 @@ +/****************************************************************/ +/* */ +/* dcb.h */ +/* */ +/* DOS Device Control Block Structure */ +/* */ +/* November 20, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *clock_hRcsId = + "$Id: dcb.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +/* Internal drive parameter block */ +struct dpb { + BYTE dpb_unit; /* unit for error reporting */ + BYTE dpb_subunit; /* the sub-unit for driver */ + UWORD dpb_secsize; /* sector size */ + UBYTE dpb_clsmask; /* mask (sectors/cluster-1) */ + UBYTE dpb_shftcnt; /* log base 2 of cluster size */ + UWORD dpb_fatstrt; /* FAT start sector */ + UBYTE dpb_fats; /* # of FAT copies */ + UWORD dpb_dirents; /* # of dir entries */ + UWORD dpb_data; /* start of data area */ + UWORD dpb_size; /* # of clusters+1 on media */ + UWORD dpb_fatsize; /* # of sectors / FAT */ + UWORD dpb_dirstrt; /* start sec. of root dir */ + struct dhdr FAR * /* pointer to device header */ + dpb_device; + UBYTE dpb_mdb; /* media descr. byte */ + BYTE dpb_flags; /* -1 = force MEDIA CHK */ + struct dpb FAR * /* next dpb in chain */ + dpb_next; /* -1 = end */ + UWORD dpb_cluster; /* cluster # of first free */ + /* -1 if not known */ +#ifndef WITHFAT32 + UWORD dpb_nfreeclst; /* number of free clusters */ + /* -1 if not known */ +#else + union { + struct { + UWORD dpb_nfreeclst_lo; + UWORD dpb_nfreeclst_hi; + } dpb_nfreeclst_st; + ULONG _dpb_xnfreeclst; /* number of free clusters */ + /* -1 if not known */ + } dpb_nfreeclst_un; +#define dpb_nfreeclst dpb_nfreeclst_un.dpb_nfreeclst_st.dpb_nfreeclst_lo +#define dpb_xnfreeclst dpb_nfreeclst_un._dpb_xnfreeclst + + UWORD dpb_xflags; /* extended flags, see bpb */ + UWORD dpb_xfsinfosec; /* FS info sector number, */ + /* 0xFFFF if unknown */ + UWORD dpb_xbackupsec; /* backup boot sector number */ + /* 0xFFFF if unknown */ + ULONG dpb_xdata; + ULONG dpb_xsize; /* # of clusters+1 on media */ + ULONG dpb_xfatsize; /* # of sectors / FAT */ + ULONG dpb_xrootclst; /* starting cluster of root dir */ + ULONG dpb_xcluster; /* cluster # of first free */ + /* -1 if not known */ +#endif +}; + +#define UNKNCLUSTER 0x0000 /* see RBIL INT 21/AH=52 entry */ +#define XUNKNCLSTFREE 0xffffffffl /* unknown for DOS */ +#define UNKNCLSTFREE 0xffff /* unknown for DOS */ + diff --git a/hdr/debug.h b/hdr/debug.h new file mode 100644 index 0000000..4869592 --- /dev/null +++ b/hdr/debug.h @@ -0,0 +1,145 @@ +/****************************************************************/ +/* */ +/* debug.h */ +/* */ +/* Routines to assist in debugging the kernel */ +/* */ +/* January, 2005 */ +/* */ +/* Copyright (c) 2005 */ +/* FreeDOS kernel dev. */ +/* 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. */ +/****************************************************************/ + +#ifndef __DEBUG_H +#define __DEBUG_H + +/* #define DEBUG (usually via 'build debug') to + enable debug support. + NOTE: this file included by INIT time code and normal + resident code, so use care for all memory references + */ + +/* allow output even in non-debug builds */ +#if 0 +#ifndef DEBUG_NEED_PRINTF +#define DEBUG_NEED_PRINTF +#endif +#endif + +/* use to limit output to debug builds */ +#ifdef DEBUG +#ifdef DEBUG_PRINT_COMPORT +#define DebugPrintf(x) dbgc_printf x +#else +#define DebugPrintf(x) printf x +#endif +#else +#define DebugPrintf(x) +#endif + +/* use to disable a chunk of debug output, but + keep around for later use. */ +#define DDebugPrintf(x) + + +/* enable or disable various chunks of debug output */ + +/* show stored IRQ vectors */ +/* #define DEBUGIRQ */ + +/* show output related to moving kernel into HMA */ +#ifdef DEBUG +#define HMAInitPrintf(x) DebugPrintf(x) +#else +#define HMAInitPrintf(x) +#endif + +/* display output during kernel config processing phase */ +/* #define DEBUGCFG */ +#ifdef DEBUGCFG +#define CfgDbgPrintf(x) DebugPrintf(x) +#else +#define CfgDbgPrintf(x) +#endif + +/* display info on various DOS functions (dosfns.c) */ +/* #define DEBUGDOSFNS */ +#ifdef DEBUGDOSFNS +#define DFnsDbgPrintf(x) DebugPrintf(x) +#else +#define DFnsDbgPrintf(x) +#endif + +/* extra debug output related to chdir */ +/* #define CHDIR_DEBUG */ + +/* extra debug output related to findfirst */ +/* #define FIND_DEBUG */ + +/* display info on various DOS directory functions (fatdir.c) */ +/* #define DEBUGFATDIR */ +#ifdef DEBUGFATDIR +#define FDirDbgPrintf(x) DebugPrintf(x) +#else +#define FDirDbgPrintf(x) +#endif + +/* extra debug output when transferring I/O chunks of data */ +/* #define DISPLAY_GETBLOCK */ + +/* extra output during read/write operations */ +/* #define DSK_DEBUG */ + +/* display info on various FAT handling functions (fatfs.c) */ +/* #define DEBUGFATFS */ +#ifdef DEBUGFATFS +#define FatFSDbgPrintf(x) DebugPrintf(x) +#else +#define FatFSDbgPrintf(x) +#endif + +/* debug truename */ +/* #define DEBUG_TRUENAME */ +#ifdef DEBUG_TRUENAME +#define tn_printf(x) DebugPrintf(x) +#else +#define tn_printf(x) +#endif + + +/* ensure printf is prototyped */ +#if defined(DEBUG) || defined(DEBUGIRQ) || defined(DEBUGCFG) || \ + defined(DEBUGDOSFNS) || defined(CHDIR_DEBUG) || defined(FIND_DEBUG) || \ + defined(DEBUGFATDIR) || defined(DEBUGFATFS) || \ + defined(FORCEPRINTF) +#ifndef DEBUG_NEED_PRINTF +#define DEBUG_NEED_PRINTF +#endif +#endif + +#ifdef DEBUG_NEED_PRINTF +int VA_CDECL printf(CONST char * fmt, ...); +#ifdef DEBUG_PRINT_COMPORT +int VA_CDECL dbgc_printf(CONST char * fmt, ...); +#endif +#endif + +#endif /* __DEBUG_H */ diff --git a/hdr/device.h b/hdr/device.h new file mode 100644 index 0000000..b192505 --- /dev/null +++ b/hdr/device.h @@ -0,0 +1,506 @@ +/****************************************************************/ +/* */ +/* device.h */ +/* Device Driver Header File */ +/* */ +/* November 20, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + + +/* + * Status Word Bits + */ + +#define S_ERROR 0x8000 /* Error bit */ +#define S_BUSY 0x0200 /* Device busy bit */ +#define S_DONE 0x0100 /* Device operation completed */ +#define S_MASK 0x00ff /* Mask to extract error code */ + +/* + * MEDIA Descriptor Byte Bits + */ + +#define MD_2SIDE 1 /* MEDIA is two sided */ +#define MD_8SECTOR 2 /* MEDIA is eight sectored */ +#define MD_REMOVABLE 4 /* MEDIA is removable (floppy) */ + +/* + * Media Return Codes + */ +#define M_CHANGED -1 /* MEDIA was changed */ +#define M_DONT_KNOW 0 /* MEDIA state unkown */ +#define M_NOT_CHANGED 1 /* MEDIA was not changed */ + +/* + * Error Return Codes + */ + +#define E_WRPRT 0 /* Write Protect */ +#define E_UNIT 1 /* Unknown Unit */ +#define E_NOTRDY 2 /* Device Not Ready */ +#define E_CMD 3 /* Unknown Command */ +#define E_CRC 4 /* Crc Error */ +#define E_LENGTH 5 /* Bad Length */ +#define E_SEEK 6 /* Seek Error */ +#define E_MEDIA 7 /* Unknown MEDIA */ +#define E_NOTFND 8 /* Sector Not Found */ +#define E_PAPER 9 /* No Paper */ +#define E_WRITE 10 /* Write Fault */ +#define E_READ 11 /* Read Fault */ +#define E_FAILURE 12 /* General Failure */ + +/* + * Command codes + */ + +#define C_INIT 0x00 /* Initialize */ +#define C_MEDIACHK 0x01 /* MEDIA Check */ +#define C_BLDBPB 0x02 /* Build BPB */ +#define C_IOCTLIN 0x03 /* Ioctl In */ +#define C_INPUT 0x04 /* Input (Read) */ +#define C_NDREAD 0x05 /* Non-destructive Read */ +#define C_ISTAT 0x06 /* Input Status */ +#define C_IFLUSH 0x07 /* Input Flush */ +#define C_OUTPUT 0x08 /* Output (Write) */ +#define C_OUTVFY 0x09 /* Output with verify */ +#define C_OSTAT 0x0a /* Output */ +#define C_OFLUSH 0x0b /* Output Flush */ +#define C_IOCTLOUT 0x0c /* Ioctl Out */ +#define C_OPEN 0x0d /* Device Open */ +#define C_CLOSE 0x0e /* Device Close */ +#define C_REMMEDIA 0x0f /* Removable MEDIA */ +#define C_OUB 0x10 /* Output till busy */ +#define C_GENIOCTL 0x13 /* Generic Ioctl */ +#define C_GETLDEV 0x17 /* Get Logical Device */ +#define C_SETLDEV 0x18 /* Set Logical Device */ +#define C_IOCTLQRY 0x19 /* Ioctl Query */ + +/* + * Convienence macros + */ +#define failure(x) (S_ERROR+S_DONE+x) +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * structures + */ + +/* Device header */ + +struct dhdr { + struct dhdr + FAR *dh_next; + UWORD dh_attr; + VOID(*dh_strategy) (void); + VOID(*dh_interrupt) (void); + UBYTE dh_name[8]; +}; + +#define ATTR_SUBST 0x8000 +#define ATTR_CHAR 0x8000 +#define ATTR_IOCTL 0x4000 +#define ATTR_BLDFAT 0x2000 +#define ATTR_REMOTE 0x1000 +#define ATTR_EXCALLS 0x0800 +#define ATTR_QRYIOCTL 0x0080 +#define ATTR_GENIOCTL 0x0040 +#define ATTR_RAW 0x0400 +#define ATTR_FASTCON 0x0010 +#define ATTR_CLOCK 0x0008 +#define ATTR_NULL 0x0004 +#define ATTR_CONOUT 0x0002 +#define ATTR_HUGE 0x0002 +#define ATTR_CONIN 0x0001 + +/* */ +/* Bios Parameter Block structure */ +/* */ + +#define FAT_NO_MIRRORING 0x80 + +#define BPB_SIZEOF 31 /* size of the standard BPB */ + +typedef struct { + UWORD bpb_nbyte; /* Bytes per Sector */ + UBYTE bpb_nsector; /* Sectors per Allocation Unit */ + UWORD bpb_nreserved; /* # Reserved Sectors */ + UBYTE bpb_nfat; /* # FATs */ + UWORD bpb_ndirent; /* # Root Directory entries */ + UWORD bpb_nsize; /* Size in sectors */ + UBYTE bpb_mdesc; /* MEDIA Descriptor Byte */ + UWORD bpb_nfsect; /* FAT size in sectors */ + UWORD bpb_nsecs; /* Sectors per track */ + UWORD bpb_nheads; /* Number of heads */ + ULONG bpb_hidden; /* Hidden sectors */ + ULONG bpb_huge; /* Size in sectors if */ + /* bpb_nsize == 0 */ +#ifdef WITHFAT32 + ULONG bpb_xnfsect; /* FAT size in sectors if */ + /* bpb_nfsect == 0 */ + UWORD bpb_xflags; /* extended flags */ + /* bit 7: disable mirroring */ + /* bits 6-4: reserved (0) */ + /* bits 3-0: active FAT number */ + UWORD bpb_xfsversion; /* filesystem version */ + ULONG bpb_xrootclst; /* starting cluster of root dir */ + UWORD bpb_xfsinfosec; /* FS info sector number, */ + /* 0xFFFF if unknown */ + UWORD bpb_xbackupsec; /* backup boot sector number */ + /* 0xFFFF if unknown */ +#endif +} bpb; + +#define N_RETRY 5 /* number of retries permitted */ + +#include "dsk.h" + +#define LBA_READ 0x4200 +#define LBA_WRITE 0x4300 + +struct _bios_LBA_address_packet + /* Used to access a hard disk via LBA */ + /* Added by Brian E. Reifsnyder */ +{ + unsigned char packet_size; /* size of this packet...set to 16 */ + unsigned char reserved_1; /* set to 0...unused */ + unsigned char number_of_blocks; /* 0 < number_of_blocks < 128 */ + unsigned char reserved_2; /* set to 0...unused */ + UBYTE far *buffer_address; /* addr of transfer buffer */ + unsigned long block_address; /* LBA address */ + unsigned long block_address_high; /* high bytes of LBA addr...unused */ +}; + +struct CHS { + UWORD Cylinder; + UWORD Head; + UWORD Sector; +}; + +/* DOS 4.0-7.0 drive data table (see RBIL at INT2F,AX=0803) */ +typedef struct ddtstruct { + struct ddtstruct FAR *ddt_next; + /* pointer to next table (offset FFFFh if last table) */ + UBYTE ddt_driveno; /* physical unit number (for INT 13) */ + UBYTE ddt_logdriveno; /* logical drive number (0=A:) */ + bpb ddt_bpb; /* BIOS Parameter Block */ + UBYTE ddt_flags; + /* bit 6: 16-bit FAT instead of 12-bit + bit 7: unsupportable disk (all accesses will return Not Ready) */ + UWORD ddt_FileOC; /* Count of Open files on Drv */ + UBYTE ddt_type; /* device type */ + UWORD ddt_descflags; /* bit flags describing drive */ + UWORD ddt_ncyl; /* number of cylinders + (for partition only, if hard disk) */ + bpb ddt_defbpb; /* BPB for default (highest) capacity supported */ + UBYTE ddt_reserved[6]; /* (part of BPB above) */ + UBYTE ddt_ltrack; /* last track accessed */ + union { + ULONG ddt_lasttime; /* removable media: time of last access + in clock ticks (FFFFFFFFh if never) */ + struct { + UWORD ddt_part; /* partition (FFFFh = primary, 0001h = extended) + always 0001h for DOS 5+ */ + UWORD ddt_abscyl; /* absolute cylinder number of partition's + start on physical drive + (FFFFh if primary partition in DOS 4.x) */ + } ddt_hd; + } ddt_fh; + UBYTE ddt_volume[12]; /* ASCIIZ volume label or "NO NAME " if none + (apparently taken from extended boot record + rather than root directory) */ + ULONG ddt_serialno; /* serial number */ + UBYTE ddt_fstype[9]; /* ASCIIZ filesystem type ("FAT12 " or "FAT16 ") */ + ULONG ddt_offset; /* relative partition offset */ +} ddt; + +/* description flag bits */ +#define DF_FIXED 0x001 /* fixed media, ie hard drive */ +#define DF_CHANGELINE 0x002 /* door lock or disk change detection reported as supported */ +#define DF_CURBPBLOCK 0x004 /* current BPB locked, use existing BPB instead of building one */ +#define DF_SAMESIZE 0x008 /* all sectors in a track are the same size */ +#define DF_MULTLOG 0x010 /* physical drive represents multiple logical ones, eg A: & B: */ +#define DF_CURLOG 0x020 /* active (current) logical drive for this physical drive */ +#define DF_DISKCHANGE 0x040 /* disk change was detected */ +#define DF_DPCHANGED 0x080 /* device parameters changed */ +#define DF_REFORMAT 0x100 /* disk formatted so BPB has changed */ +#define DF_NOACCESS 0x200 /* don't allow access (read or write) to fixed media */ +/* freedos specific flag bits */ +#define DF_LBA 0x400 +#define DF_WRTVERIFY 0x800 + +/* typedef struct ddtstruct ddt;*/ + +struct gblkio { + UBYTE gbio_spcfunbit; + UBYTE gbio_devtype; + UWORD gbio_devattrib; + UWORD gbio_ncyl; + UBYTE gbio_media; + bpb gbio_bpb; + UWORD gbio_nsecs; +}; + +struct gblkfv /* for format / verify track */ +{ + UBYTE gbfv_spcfunbit; + UWORD gbfv_head; + UWORD gbfv_cyl; + UWORD gbfv_ntracks; +}; + +struct gblkrw /* for read / write track */ +{ + UBYTE gbrw_spcfunbit; + UWORD gbrw_head; + UWORD gbrw_cyl; + UWORD gbrw_sector; + UWORD gbrw_nsecs; + UBYTE FAR *gbrw_buffer; +}; + +struct Gioc_media { + WORD ioc_level; + ULONG ioc_serialno; + BYTE ioc_volume[11]; + BYTE ioc_fstype[8]; +}; + +struct Access_info { + BYTE AI_spec; + BYTE AI_Flag; +}; + +/* */ +/* Boot Block (Super Block) */ +/* */ +/* See BPB comments for the offsets below */ +/* */ +#define BT_JUMP 0 +#define BT_OEM 3 +#define BT_BPB 11 +#define BT_SIZEOF 36 + +typedef struct { + BYTE bt_jump[3]; /* Boot Jump opcodes */ + BYTE bt_oem[8]; /* OEM Name */ + bpb bt_bpb; /* BPB for this media/device */ + WORD bt_nsecs; /* # Sectors per Track */ + WORD bt_nheads; /* # Heads */ + WORD bt_hidden; /* # Hidden sectors */ + LONG bt_huge; /* use if nsecs == 0 */ + BYTE bt_drvno; + BYTE bt_reserv; + BYTE bt_btid; + ULONG bt_serialno; + BYTE bt_volume[11]; + BYTE bt_fstype[8]; +} boot; + +/* File system information structure */ +struct fsinfo { + UDWORD fi_signature; /* must be 0x61417272 */ + DWORD fi_nfreeclst; /* number of free clusters, -1 if unknown */ + DWORD fi_cluster; /* most recently allocated cluster, -1 if unknown */ + UBYTE fi_reserved[12]; +}; + +typedef boot super; /* Alias for boot structure */ + +typedef struct { + UBYTE r_length; /* Request Header length */ + UBYTE r_unit; /* Unit Code */ + UBYTE r_command; /* Command Code */ + UWORD r_status; /* Status */ + BYTE r_reserved[8]; /* DOS Reserved Area */ + union { + struct { + UBYTE _r_nunits; /* number of units */ + BYTE FAR *_r_endaddr; /* Ending Address */ + bpb *FAR * _r_bpbptr; /* ptr to BPB array */ + UBYTE _r_firstunit; + } _r_init; + struct { + BYTE _r_meddesc; /* MEDIA Descriptor */ + BYTE _r_retcode; /* Return Code */ + BYTE FAR * _r_vid; /* volume id */ + } _r_media; + struct { + BYTE _r_meddesc; /* MEDIA Descriptor */ + boot FAR * _r_fat; /* boot sector pointer */ + bpb FAR * _r_bpbpt; /* ptr to BPB table */ + } _r_bpb; + struct { + BYTE _r_meddesc; /* MEDIA Descriptor */ + BYTE FAR * _r_trans; /* Transfer Address */ + UWORD _r_count; /* Byte/Sector Count */ + UWORD _r_start; /* Starting Sector No. */ + BYTE FAR * _r_vid; /* Pointer to volume id */ + LONG _r_huge; /* for > 32Mb drives */ + } _r_rw; + struct { + unsigned char _r_ndbyte; /* Byte Read From Device */ + } _r_nd; + struct { + UBYTE _r_cat; /* Category code */ + UBYTE _r_fun; /* Function code */ + UWORD _r_si; /* Contents of SI and DI */ + UWORD _r_di; /* (PC DOS 7 Technical Update, pp 104,105) */ + union + { + struct gblkio FAR *_r_io; + struct gblkrw FAR *_r_rw; + struct gblkfv FAR *_r_fv; + struct Gioc_media FAR *_r_gioc; + struct Access_info FAR *_r_ai; + } _r_par; /* Pointer to param. block from 440C/440D */ + } _r_gen; + } _r_x; +} request; + +#define HUGECOUNT 0xffff +#define MAXSHORT 0xffffl + +/* + * Macros to assist request structure legibility + */ + +/* Init packet macros */ +#define r_nunits _r_x._r_init._r_nunits +#define r_endaddr _r_x._r_init._r_endaddr +#define r_bpbptr _r_x._r_init._r_bpbptr +#define r_firstunit _r_x._r_init._r_firstunit + +/* MEDIA Check packet macros */ +#define r_mcmdesc _r_x._r_media._r_meddesc +#define r_mcretcode _r_x._r_media._r_retcode +#define r_mcvid _r_x._r_media._r_vid + +/* Build BPB packet macros */ +#define r_bpmdesc _r_x._r_bpb._r_meddesc +#define r_bpfat _r_x._r_bpb._r_fat +#define r_bpptr _r_x._r_bpb._r_bpbpt + +/* rw packet macros */ +#define r_meddesc _r_x._r_rw._r_meddesc +#define r_trans _r_x._r_rw._r_trans +#define r_count _r_x._r_rw._r_count +#define r_start _r_x._r_rw._r_start +#define r_rwvid _r_x._r_rw._r_vid +#define r_huge _r_x._r_rw._r_huge + +/* ndread packet macros */ +#define r_ndbyte _r_x._r_nd._r_ndbyte + +/* generic IOCTL and IOCTL query macros */ +#define r_cat _r_x._r_gen._r_cat +#define r_fun _r_x._r_gen._r_fun +#define r_si _r_x._r_gen._r_si +#define r_di _r_x._r_gen._r_di +#define r_rw _r_x._r_gen._r_par._r_rw +#define r_io _r_x._r_gen._r_par._r_io +#define r_fv _r_x._r_gen._r_par._r_fv +#define r_gioc _r_x._r_gen._r_par._r_gioc +#define r_ai _r_x._r_gen._r_par._r_ai + +/* + *interrupt support (spl & splx) support - IBM style + */ + +#define I_NONE 0 /* Initial value */ + +/* predefined interrupt levels - 8259 support */ +#define IRQ0 0x01 /* Level 0 - highest */ +#define IRQ1 0x02 +#define IRQ2 0x04 +#define IRQ3 0x08 +#define IRQ4 0x10 +#define IRQ5 0x20 +#define IRQ6 0x40 +#define IRQ7 0x80 /* Level 7 - lowest */ + +/* standard hardware configuration */ +#define I_RTC IRQ0 /* Timer */ +#define I_KBD IRQ1 /* Keyboard */ +#define I_COM2 IRQ3 /* COM1: */ +#define I_COM1 IRQ4 /* COM2: */ +#define I_HDC IRQ5 /* Fixed disk */ +#define I_FDC IRQ6 /* Diskette */ +#define I_PRT IRQ7 /* Printer */ + +/* standard hardware vectors - 8259 defined */ +#define V_RTC 0x08 /* Timer */ +#define V_KBD 0x09 /* Keyboard */ +#define V_LEV2 0x0a /* Level 2 - uncomitted */ +#define V_COM2 0x0b /* COM1: */ +#define V_COM1 0x0c /* COM2: */ +#define V_HDC 0x0d /* Fixed disk */ +#define V_FDC 0x0e /* Diskette */ +#define V_PRT 0x0f /* Printer */ + +#define V_LEV0 0x08 /* Level 0 - highest */ +#define V_LEV1 0x09 +#define V_LEV2 0x0a /* Level 2 - uncomitted */ +#define V_LEV3 0x0b +#define V_LEV4 0x0c +#define V_LEV5 0x0d +#define V_LEV6 0x0e +#define V_LEV7 0x0f /* Level 7 - lowest */ + +/* + */ +typedef request FAR *rqptr; +typedef bpb FAR *bpbptr; +typedef BYTE FAR *byteptr; +typedef struct dhdr FAR *dhdrptr; + +extern request /* I/O Request packets */ + ASM CharReqHdr, ASM IoReqHdr, ASM MediaReqHdr; + +/* dsk.c */ +COUNT ASMCFUNC FAR blk_driver(rqptr rp); +ddt * getddt(int dev); + +/* error.c */ +COUNT char_error(request * rq, struct dhdr FAR * lpDevice); +COUNT block_error(request * rq, COUNT nDrive, struct dhdr FAR * lpDevice, int mode); +/* sysclk.c */ +WORD ASMCFUNC FAR clk_driver(rqptr rp); + +/* execrh.asm */ +#if defined(__WATCOMC__) && _M_IX86 >= 300 +WORD execrh(request FAR *, struct dhdr FAR *); +#pragma aux execrh "^" parm reverse routine [] modify [ax bx cx dx es fs gs] +#else +WORD ASMPASCAL execrh(request FAR *, struct dhdr FAR *); +#endif + +/* + * end of device.h + */ + diff --git a/hdr/dirmatch.h b/hdr/dirmatch.h new file mode 100644 index 0000000..f4a953f --- /dev/null +++ b/hdr/dirmatch.h @@ -0,0 +1,54 @@ +/****************************************************************/ +/* */ +/* dirmatch.h */ +/* */ +/* FAT File System Match Data Structure */ +/* */ +/* January 4, 1992 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *dirmatch_hRcsId = + "$Id: dirmatch.h 1415 2009-06-02 13:18:24Z bartoldeman $"; +#endif +#endif + +typedef struct { + UBYTE dm_drive; + BYTE dm_name_pat[FNAME_SIZE + FEXT_SIZE]; + UBYTE dm_attr_srch; + UWORD dm_entry; + CLUSTER dm_dircluster; +#ifndef WITHFAT32 + UWORD reserved; +#endif + UWORD reserved2; + + UBYTE dm_attr_fnd; /* found file attribute */ + time dm_time; /* file time */ + date dm_date; /* file date */ + ULONG dm_size; /* file size */ + BYTE dm_name[FNAME_SIZE + FEXT_SIZE + 2]; /* file name */ +} dmatch; diff --git a/hdr/dsk.h b/hdr/dsk.h new file mode 100644 index 0000000..96cd257 --- /dev/null +++ b/hdr/dsk.h @@ -0,0 +1,31 @@ +/****************************************************************/ +/* */ +/* dsk.h */ +/* Disk access Header File */ +/* */ +/* Copyright (c) 2012 */ +/* FreeDOS */ +/* 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. */ +/****************************************************************/ + + +#ifndef MAX_SEC_SIZE +#define MAX_SEC_SIZE (1*512) /* max supported size of sector in bytes */ +#endif diff --git a/hdr/error.h b/hdr/error.h new file mode 100644 index 0000000..8ce3cf4 --- /dev/null +++ b/hdr/error.h @@ -0,0 +1,88 @@ +/****************************************************************/ +/* */ +/* error.h */ +/* */ +/* DOS-C error return codes */ +/* */ +/* December 1, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *error_hRcsId = + "$Id: error.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +/* Internal system error returns */ +#define SUCCESS 0 /* Function was successful */ +#define DE_INVLDFUNC -1 /* Invalid function number */ +#define DE_FILENOTFND -2 /* File not found */ +#define DE_PATHNOTFND -3 /* Path not found */ +#define DE_TOOMANY -4 /* Too many open files */ +#define DE_ACCESS -5 /* Access denied */ +#define DE_INVLDHNDL -6 /* Invalid handle */ +#define DE_MCBDESTRY -7 /* Memory control blocks shot */ +#define DE_NOMEM -8 /* Insufficient memory */ +#define DE_INVLDMCB -9 /* Invalid memory control block */ +#define DE_INVLDENV -10 /* Invalid enviornement */ +#define DE_INVLDFMT -11 /* Invalid format */ +#define DE_INVLDACC -12 /* Invalid access */ +#define DE_INVLDDATA -13 /* Invalid data */ +#define DE_INVLDDRV -15 /* Invalid drive */ +#define DE_RMVCUDIR -16 /* Attempt remove current dir */ +#define DE_DEVICE -17 /* Not same device */ +#define DE_NFILES -18 /* No more files */ +#define DE_WRTPRTCT -19 /* No more files */ +#define DE_BLKINVLD -20 /* invalid block */ +#define DE_INVLDBUF -24 /* invalid buffer size, ext fnc */ +#define DE_SEEK -25 /* error on file seek */ +#define DE_HNDLDSKFULL -28 /* handle disk full (?) */ + +#define DE_INVLDPARM -0x57 /* invalid parameter */ + +#define DE_DEADLOCK -36 +#define DE_LOCK -39 + +#define DE_FILEEXISTS -80 /* File exists */ + +/* Critical error flags */ +#define EFLG_READ 0x00 /* Read error */ +#define EFLG_WRITE 0x01 /* Write error */ +#define EFLG_RSVRD 0x00 /* Error in rserved area */ +#define EFLG_FAT 0x02 /* Error in FAT area */ +#define EFLG_DIR 0x04 /* Error in dir area */ +#define EFLG_DATA 0x06 /* Error in data area */ +#define EFLG_ABORT 0x08 /* Handler can abort */ +#define EFLG_RETRY 0x10 /* Handler can retry */ +#define EFLG_IGNORE 0x20 /* Handler can ignore */ +#define EFLG_CHAR 0x80 /* Error in char or FAT image */ + +/* error results returned after asking user */ +/* MS-DOS compatible -- returned by CriticalError */ +#define CONTINUE 0 +#define RETRY 1 +#define ABORT 2 +#define FAIL 3 + diff --git a/hdr/exe.h b/hdr/exe.h new file mode 100644 index 0000000..3c4866d --- /dev/null +++ b/hdr/exe.h @@ -0,0 +1,57 @@ +/****************************************************************/ +/* */ +/* exe.h */ +/* */ +/* DOS EXE Header Data Structure */ +/* */ +/* December 1, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *exe_hRcsId = + "$Id: exe.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +typedef struct { + UWORD exSignature; + UWORD exExtraBytes; + UWORD exPages; + UWORD exRelocItems; + UWORD exHeaderSize; + UWORD exMinAlloc; + UWORD exMaxAlloc; + UWORD exInitSS; + UWORD exInitSP; + UWORD exCheckSum; + UWORD exInitIP; + UWORD exInitCS; + UWORD exRelocTable; + UWORD exOverlay; +} exe_header; + +#define MAGIC 0x5a4d +#define OLD_MAGIC 0x4d5a + diff --git a/hdr/fat.h b/hdr/fat.h new file mode 100644 index 0000000..b55db0f --- /dev/null +++ b/hdr/fat.h @@ -0,0 +1,152 @@ +/****************************************************************/ +/* */ +/* fat.h */ +/* */ +/* FAT File System data structures & declarations */ +/* */ +/* November 26, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *fat_hRcsId = + "$Id: fat.h 1448 2009-06-16 21:45:17Z bartoldeman $"; +#endif +#endif + +/* FAT file system attribute bits */ +#define D_NORMAL 0 /* normal */ +#define D_RDONLY 0x01 /* read-only file */ +#define D_HIDDEN 0x02 /* hidden */ +#define D_SYSTEM 0x04 /* system */ +#define D_VOLID 0x08 /* volume id */ +#define D_DIR 0x10 /* subdir */ +#define D_ARCHIVE 0x20 /* archive bit */ + /* /// Added D_DEVICE bit. - Ron Cemer */ +#define D_DEVICE 0x40 /* device bit */ + +#define D_LFN (D_RDONLY | D_HIDDEN | D_SYSTEM | D_VOLID) +#define D_ALL (D_RDONLY | D_HIDDEN | D_SYSTEM | D_DIR | D_ARCHIVE) + +/* FAT file name constants */ +#define FNAME_SIZE 8 +#define FEXT_SIZE 3 + +/* FAT deleted flag */ +#define DELETED '\x5' /* if first char, delete file */ +#define EXT_DELETED '\xe5' /* external deleted flag */ + +/* Test for 16 bit or 12 bit FAT */ +#define SIZEOF_CLST16 2 +#define SIZEOF_CLST32 4 + +/* FAT cluster special flags */ +#define FREE 0x000 + +#ifdef WITHFAT32 +#define LONG_LAST_CLUSTER 0x0FFFFFFFUL +#define LONG_BAD 0x0FFFFFF7UL +#else +#define LONG_LAST_CLUSTER 0xFFFF +#define LONG_BAD 0xFFF7 +#endif +#define MASK16 0xFFF8 +#define BAD16 0xFFF7 +#define MASK12 0xFF8 +#define BAD12 0xFF7 + +/* magic constants: even though FF7 is BAD so FF6 could be a valid cluster + no., MS docs specify that FF5 is the maximal possible cluster number + for FAT12; similar for 16 and 32 */ + +#define FAT_MAGIC 4085 +#define FAT_MAGIC16 65525U +#define FAT_MAGIC32 268435455UL + +/* int ISFAT32(struct dpb FAR *dpbp);*/ +#define ISFAT32(x) _ISFAT32(x) + +/* +#define _ISFAT32(dpbp) (((dpbp)->dpb_size)>FAT_MAGIC16 && ((dpbp)->dpb_size)<=FAT_MAGIC32 ) +*/ +#define _ISFAT32(dpbp) (((dpbp)->dpb_fatsize)==0) +#define ISFAT16(dpbp) (((dpbp)->dpb_size)>FAT_MAGIC && ((dpbp)->dpb_size)<=FAT_MAGIC16 ) +#define ISFAT12(dpbp) ((((dpbp)->dpb_size)-1)dir_start) +#define setdstart(dpbp, dentry, value) \ + (((dentry)->dir_start) = (UWORD)(value)) +#endif + +#define DIR_NAME 0 +#define DIR_EXT FNAME_SIZE +#define DIR_ATTRIB (FNAME_SIZE+FEXT_SIZE) +#define DIR_RESERVED (FNAME_SIZE+FEXT_SIZE+1) +#define DIR_START_HIGH (FNAME_SIZE+FEXT_SIZE+9) +#define DIR_TIME (FNAME_SIZE+FEXT_SIZE+11) +#define DIR_DATE (FNAME_SIZE+FEXT_SIZE+13) +#define DIR_START (FNAME_SIZE+FEXT_SIZE+15) +#define DIR_SIZE (FNAME_SIZE+FEXT_SIZE+17) + +#define DIRENT_SIZE 32 + diff --git a/hdr/fcb.h b/hdr/fcb.h new file mode 100644 index 0000000..6935666 --- /dev/null +++ b/hdr/fcb.h @@ -0,0 +1,120 @@ +/****************************************************************/ +/* */ +/* fcb.h */ +/* */ +/* FAT FCB and extended FCB data structures & declarations */ +/* */ +/* November 23, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *fcb_hRcsId = + "$Id: fcb.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +/* fcb convience defines */ +/* block device info */ +#define FID_CHARDEV 0x80 /* 1 defines character device */ + /* 0 defines block file */ +#define FID_NOWRITE 0x40 /* 0 file dirty (write occured) */ + /* 1 file has no changes */ +#define FID_MASK 0x3f /* file # */ +/* char device info */ +#define FID_EOF 0x40 /* 1 = no eof detected */ + /* 0 = end of file on input */ +#define FID_BINARY 0x20 /* 1 = binary (raw) mode device */ + /* 0 = ascii (cooked) mode device */ +#define FID_CLOCK 0x08 /* Clock device */ +#define FID_NULL 0x04 /* Null device */ +#define FID_CONOUT 0x02 /* Console output device */ +#define FID_CONIN 0x01 /* Console input device */ + +#ifndef FNAME_SIZE +#define FNAME_SIZE 8 /* limit on file name */ +#endif + +#ifndef FEXT_SIZE +#define FEXT_SIZE 3 /* limit on extension */ +#endif + +#ifndef FDFLT_DRIVE +#define FDFLT_DRIVE 0 /* default drive */ +#endif + +#define PARSE_SEP_STOP 0x01 +#define PARSE_DFLT_DRIVE 0x02 +#define PARSE_BLNK_FNAME 0x04 +#define PARSE_BLNK_FEXT 0x08 + +#define PARSE_RET_NOWILD 0 +#define PARSE_RET_WILD 1 +#define PARSE_RET_BADDRIVE 0xff + +#define FCB_READ 0 +#define FCB_WRITE 1 + +/* File Control Block (FCB) */ +typedef struct { + UBYTE fcb_drive; /* Drive number 0=default, 1=A, etc */ + BYTE fcb_fname[FNAME_SIZE]; /* File name */ + BYTE fcb_fext[FEXT_SIZE]; /* File name Extension */ + UWORD fcb_cublock; /* Current block number of */ + /* 128 records/block, for seq. r/w */ + UWORD fcb_recsiz; /* Logical record size in bytes, */ + /* default = 128 */ + ULONG fcb_fsize; /* File size in bytes */ + date fcb_date; /* Date file created */ + time fcb_time; /* Time of last write */ + /* the following are reserved by system */ + BYTE fcb_sftno; /* Device ID */ + BYTE fcb_attrib_hi; /* share info, dev attrib word hi */ + BYTE fcb_attrib_lo; /* dev attrib word lo, open mode */ + UWORD fcb_strtclst; /* file starting cluster */ + UWORD fcb_dirclst; /* cluster of the dir entry */ + UBYTE fcb_diroff_unused; /* offset of the dir entry */ + /* end reserved */ + UBYTE fcb_curec; /* Current block number of */ + ULONG fcb_rndm; /* Current relative record number */ +} fcb; + +/* FAT extended fcb */ +typedef struct { + UBYTE xfcb_flag; /* 0xff indicates Extended FCB */ + BYTE xfcb_resvrd[5]; /* Reserved */ + UBYTE xfcb_attrib; /* Attribute */ + fcb xfcb_fcb; +} xfcb; + +typedef struct { + UBYTE renDriveID; /* drive no. */ + BYTE renOldName[8]; /* Old Filename */ + BYTE renOldExtent[3]; /* Old File Extension */ + BYTE renReserved1[5]; + BYTE renNewName[8]; /* New Filename */ + BYTE renNewExtent[3]; /* New FileExtension */ + BYTE renReserved2[9]; +} rfcb; + diff --git a/hdr/file.h b/hdr/file.h new file mode 100644 index 0000000..884f116 --- /dev/null +++ b/hdr/file.h @@ -0,0 +1,81 @@ +/****************************************************************/ +/* */ +/* file.h */ +/* */ +/* DOS File mode flags */ +/* */ +/* December 1, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *file_hRcsId = + "$Id: file.h 831 2004-03-27 00:27:11Z bartoldeman $"; +#endif +#endif + +/* 0 = CON, standard input, can be redirected */ +/* 1 = CON, standard output, can be redirected */ +/* 2 = CON, standard error */ +/* 3 = AUX, auxiliary */ +/* 4 = PRN, list device */ +/* 5 = 1st user file ... */ +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 +#define STDAUX 3 +#define STDPRN 4 + +/* mode bits */ +#define O_VALIDMASK 0xfff3 /* valid open mask */ + +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_ACCMODE 0x0003 + +/* bits 2, 3 reserved */ + +/* bits 4, 5, 6 sharing modes */ +#define O_SHAREMASK 0x0070 /* mask to isolate shared bits */ + +#define O_DENYALL 0x0010 /* sharing bits */ +#define O_DENYWRITE 0x0020 /* " " */ +#define O_DENYREAD 0x0030 /* " " */ +#define O_DENYNONE 0x0040 /* " " */ +#define O_NETFCB 0x0070 /* networked fcb */ + +#define O_NOINHERIT 0x0080 +#define O_OPEN 0x0100 /* not */ +#define O_TRUNC 0x0200 /* both */ +#define O_CREAT 0x0400 +#define O_LEGACY 0x0800 +#define O_LARGEFILE 0x1000 +#define O_NOCRIT 0x2000 +#define O_SYNC 0x4000 +#define O_FCB 0x8000 + +/* status for extended open */ +enum {S_OPENED = 1, S_CREATED = 2, S_REPLACED = 3}; + diff --git a/hdr/fnode.h b/hdr/fnode.h new file mode 100644 index 0000000..1e2face --- /dev/null +++ b/hdr/fnode.h @@ -0,0 +1,65 @@ +/****************************************************************/ +/* */ +/* fnode.h */ +/* */ +/* Internal File Node for FAT File System */ +/* */ +/* January 4, 1992 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *fnode_hRcsId = + "$Id: fnode.h 1432 2009-06-10 16:10:54Z bartoldeman $"; +#endif +#endif + +struct f_node { + UWORD f_flags; /* file flags */ + + dmatch *f_dmp; /* this file's dir match */ + struct dirent f_dir; /* this file's dir entry image */ + + ULONG f_dirsector; /* the sector containing dir entry*/ + UBYTE f_diridx; /* offset/32 of dir entry in sec*/ + /* when dir is not root */ + struct dpb FAR *f_dpb; /* the block device for file */ + + ULONG f_offset; /* byte offset for next op */ + CLUSTER f_cluster_offset; /* relative cluster number within file */ + CLUSTER f_cluster; /* the cluster we are at */ + UBYTE f_sft_idx; /* corresponding SFT index */ +}; + +typedef struct f_node *f_node_ptr; + +struct lfn_inode { + UNICODE l_name[261]; /* Long file name string */ + /* If the string is empty, */ + /* then file has the 8.3 name */ + struct dirent l_dir; /* Directory entry image */ + UWORD l_diroff; /* Current directory entry offset */ +}; + +typedef struct lfn_inode FAR * lfn_inode_ptr; diff --git a/hdr/kbd.h b/hdr/kbd.h new file mode 100644 index 0000000..2c13512 --- /dev/null +++ b/hdr/kbd.h @@ -0,0 +1,48 @@ +/****************************************************************/ +/* */ +/* kbd.h */ +/* */ +/* Buffered Keyboard Input data structures & declarations */ +/* */ +/* July 5, 1993 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *kbd_hRcsId = + "$Id: kbd.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +#define LINEBUFSIZECON 128 +#define KBD_MAXLENGTH LINEBUFSIZECON+1 /* the above + LF */ +#define LINEBUFSIZE0A 256 /* maximum length for int21/ah=0a */ + +/* Keyboard buffer */ +typedef struct { + UBYTE kb_size; /* size of buffer in bytes */ + UBYTE kb_count; /* number of bytes returned */ + BYTE kb_buf[KBD_MAXLENGTH]; /* the buffer itself */ +} keyboard; + diff --git a/hdr/kconfig.h b/hdr/kconfig.h new file mode 100644 index 0000000..b6a4fae --- /dev/null +++ b/hdr/kconfig.h @@ -0,0 +1,36 @@ +/* + KConfig.h + + DLASortByDriveNo + 0 : Drive Letter Assignement ike MSDOS + 1 : DLA - first drive completely first, then to next drive + + InitDiskShowDriveAssignment + 0 : don't show what drive/partition assigned to what drive letter + 1 : show info + + SkipConfigSeconds: + < 0 : not possible to skip config.sys + = 0 : only possible if already pressed before, no message + > 0 : wait so long for F5/F8 + + BootHarddiskSeconds: boots by default - and without user interaction - from HD + <= 0: normal + > 0: + display message + ' hit any key to continue to boot from 'diskette or CD' + wait ## seconds + if no key hit, boot from HD + +*/ +typedef struct _KernelConfig { + char CONFIG[6]; /* "CONFIG" */ + unsigned short ConfigSize; + + unsigned char DLASortByDriveNo; + unsigned char InitDiskShowDriveAssignment; + signed char SkipConfigSeconds; + unsigned char ForceLBA; + unsigned char GlobalEnableLBAsupport; /* = 0 --> disable LBA support */ + signed char BootHarddiskSeconds; +} KernelConfig; diff --git a/hdr/lol.h b/hdr/lol.h new file mode 100644 index 0000000..b18fa6f --- /dev/null +++ b/hdr/lol.h @@ -0,0 +1,91 @@ +/****************************************************************/ +/* */ +/* lol.h */ +/* */ +/* DOS List of Lists structure */ +/* */ +/* Copyright (c) 2003 */ +/* Bart Oldeman */ +/* 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; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, */ +/* Boston, MA 02111-1307 USA. */ +/****************************************************************/ + +enum {LOC_CONV=0, LOC_HMA=1}; + +/* note: we start at DOSDS:0, but the "official" list of lists starts a + little later at DOSDS:26 (this is what is returned by int21/ah=52) */ + +struct lol { + char filler[0x22]; + char *inputptr; /* -4 Pointer to unread CON input */ + unsigned short first_mcb; /* -2 Start of user memory */ + struct dpb far *DPBp; /* 0 First drive Parameter Block */ + struct sfttbl far *sfthead; /* 4 System File Table head */ + struct dhdr far *clock; /* 8 CLOCK$ device */ + struct dhdr far *syscon; /* c console device */ + unsigned short maxsecsize; /* 10 max bytes per sector for any blkdev */ + void far *inforecptr; /* 12 pointer to disk buffer info record */ + struct cds far *CDSp; /* 16 Current Directory Structure */ + struct sfttbl far *FCBp; /* 1a FCB table pointer */ + unsigned short nprotfcb; /* 1e number of protected fcbs */ + unsigned char nblkdev; /* 20 number of block devices */ + unsigned char lastdrive; /* 21 value of last drive */ + struct dhdr nul_dev; /* 22 NUL device driver header(no pointer!)*/ + unsigned char njoined; /* 34 number of joined devices */ + unsigned short specialptr; /* 35 pointer to list of spec. prog(unused)*/ + void far *setverPtr; /* 37 pointer to SETVER list */ + void (*a20ptr)(void); /* 3b pointer to fix A20 ctrl */ + unsigned short recentpsp; /* 3d PSP of most recently exec'ed prog */ + unsigned short nbuffers; /* 3f Number of buffers */ + unsigned short nlookahead; /* 41 Number of lookahead buffers */ + unsigned char BootDrive; /* 43 bootdrive (1=A:) */ + unsigned char cpu; /* 44 CPU family [was unused dword moves] */ + unsigned short xmssize; /* 45 extended memory size in KB */ + struct buffer far *firstbuf; /* 47 head of buffers linked list */ + unsigned short dirtybuf; /* 4b number of dirty buffers */ + struct buffer far *lookahead;/* 4d pointer to lookahead buffer */ + unsigned short slookahead; /* 51 number of lookahead sectors */ + unsigned char bufloc; /* 53 BUFFERS loc (1=HMA) */ + char far *deblock_buf; /* 54 pointer to workspace buffer */ + char filler2[5]; /* 58 ???/unused */ + unsigned char int24fail; /* 5d int24 fail while making i/o stat call*/ + unsigned char memstrat; /* 5e memory allocation strat during exec */ + unsigned char a20count; /* 5f nr. of int21 calls for which a20 off */ + unsigned char VgaSet; /* 60 bitflags switches=/w, int21/4b05 */ + unsigned short unpack; /* 61 offset of unpack code start */ + unsigned char uppermem_link; /* 63 UMB Link flag */ + unsigned short min_pars; /* 64 minimum para req by program execed */ + unsigned short uppermem_root;/* 66 Start of umb chain (usually 9fff) */ + unsigned short last_para; /* 68 para: start scanning during memalloc */ + /* ANY ITEM BELOW THIS POINT MAY CHANGE */ + /* FreeDOS specific entries */ + unsigned char os_setver_minor;/*6a settable minor DOS version */ + unsigned char os_setver_major;/*6b settable major DOS version */ + unsigned char os_minor; /* 6c minor DOS version */ + unsigned char os_major; /* 6d major DOS version */ + unsigned char rev_number; /* 6e DOS revision#, only 3 bits */ + unsigned char version_flags; /* 6f DOS version flags */ + char *os_release; /* 70 near pointer to os_release string */ +#ifdef WIN31SUPPORT + unsigned short winInstanced; /* WinInit called */ + unsigned long winStartupInfo[4]; + unsigned short instanceTable[5]; +#endif +}; + diff --git a/hdr/mcb.h b/hdr/mcb.h new file mode 100644 index 0000000..6fc47e5 --- /dev/null +++ b/hdr/mcb.h @@ -0,0 +1,69 @@ +/****************************************************************/ +/* */ +/* mcb.h */ +/* */ +/* Memory Control Block data structures and declarations */ +/* */ +/* November 23, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *mcb_hRcsId = + "$Id: mcb.h 822 2004-03-25 00:20:20Z bartoldeman $"; +#endif +#endif + +#define LARGEST -1 +#define FIRST_FIT 0 +#define BEST_FIT 1 +#define LAST_FIT 2 +#define FIRST_FIT_UO 0x40 +#define BEST_FIT_UO 0x41 +#define LAST_FIT_UO 0x42 +#define FIRST_FIT_U 0x80 +#define BEST_FIT_U 0x81 +#define LAST_FIT_U 0x82 +#define FIT_U_MASK 0xc0 +#define FIT_MASK 0x3f + +#define MCB_NORMAL 0x4d +#define MCB_LAST 0x5a + +#define DOS_PSP 0x0060 /* 0x0008 What? seg 8 =0:0080 */ +#define FREE_PSP 0 + +#define MCB_SIZE(x) ((((LONG)(x))<<4)+sizeof(mcb)) + +typedef UWORD seg; +typedef UWORD offset; + +typedef struct { + BYTE m_type; /* mcb type - chain or end */ + UWORD m_psp; /* owner id via psp segment */ + UWORD m_size; /* size of segment in paragraphs */ + BYTE m_fill[3]; + BYTE m_name[8]; /* owner name limited to 8 bytes */ +} mcb; + diff --git a/hdr/network.h b/hdr/network.h new file mode 100644 index 0000000..dcb66f0 --- /dev/null +++ b/hdr/network.h @@ -0,0 +1,80 @@ +/****************************************************************/ +/* */ +/* network.h */ +/* */ +/* DOS Networking */ +/* */ +/* October 10, 1999 */ +/* */ +/* Copyright (c) 1999 */ +/* James Tabor */ +/* 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. */ +/****************************************************************/ + +/* Defines for remote access functions */ +#define REM_RMDIR 0x1101 +#define REM_MKDIR 0x1103 +#define REM_CHDIR 0x1105 +#define REM_CLOSE 0x1106 +#define REM_FLUSH 0x1107 +#define REM_READ 0x1108 +#define REM_WRITE 0x1109 +#define REM_LOCK 0x110a +#define REM_UNLOCK 0x110b +#define REM_GETSPACE 0x110c +#define REM_SETATTR 0x110e +#define REM_GETATTRZ 0x110f +#define REM_RENAME 0x1111 +#define REM_DELETE 0x1113 +#define REM_OPEN 0x1116 +#define REM_CREATE 0x1117 +#define REM_CRTRWOCDS 0x1118 +#define REM_FND1WOCDS 0x1119 +#define REM_FINDFIRST 0x111B +#define REM_FINDNEXT 0x111C +#define REM_CLOSEALL 0x111d +#define REM_DOREDIRECT 0x111e +#define REM_PRINTSET 0x111f +#define REM_FLUSHALL 0x1120 +#define REM_LSEEK 0x1121 +#define REM_PROCESS_END 0x1122 +#define REM_FILENAME 0x1123 +#define REM_PRINTREDIR 0x1125 +#define REM_EXTOC 0x112e + +struct rgds { + UWORD r_spc; + UWORD r_navc; + UWORD r_bps; + UWORD r_nc; +}; + +struct remote_fileattrib { + UWORD rfa_file; /* File Attributes */ + union { + ULONG rfa_filesize; /* file size */ + struct { + UWORD rfa_filesize_lo; /* DI Low */ + UWORD rfa_filesize_hi; /* BX High */ + } _split_rfa_fz; + } rfa_fz_union; + UWORD rfa_time; + UWORD rfa_date; +}; diff --git a/hdr/nls.h b/hdr/nls.h new file mode 100644 index 0000000..bc075cf --- /dev/null +++ b/hdr/nls.h @@ -0,0 +1,628 @@ +/****************************************************************/ +/* */ +/* NLS.H */ +/* FreeDOS */ +/* */ +/* National Language Support data structures */ +/* */ +/* Copyright (c) 2000 */ +/* Steffen Kaiser */ +/* All Rights Reserved */ +/* */ +/* This file is part of FreeDOS. */ +/* */ +/* 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. */ +/****************************************************************/ + +/* one byte alignment */ +#include + +/* + * Description of the organization of NLS information -- 2000/02/13 ska + * + * Glossar: + * NLS package -- NLS information incl. any code required to access or + * correctly interprete this particular information + * + * Abbreviation: + * (NLS) pkg -- NLS package + * + * The code included into the kernel does "only" support NLS packages + * structurally compatible with the one of the U.S.A. / CP437. + * I guess that most NLS packages has been tweaked to be compatible, + * so that this is not a real limitation, but for all other packages + * the external NLSFUNC can supply every piece of code necessary. + * To allow this the interface between the kernel and NLSFUNC has been + * extended; at the same time the interface has been reduced, because some + * of the API functions do not seem to offer any functionality required + * for now. This, however, may be a misinterpretation because of + * lack of understanding. + * + * The supported structure consists of the following assumptions: + * 1) The pkg must contain the tables 2 (Upcase character), 4 + * (Upcase filename character) and 5 (filename termination + * characters); because they are used internally. + * 2) The tables 2 and 4 must contain exactly 128 (0x80) characters. + * The character at index 0 corresponses to character 128 (0x80). + * The characters in the range of 0..0x7f are constructed out of + * the 7-bit US-ASCII (+ control characters) character set and are + * upcased not through the table, but by the expression: + * (ch >= 'a' && ch <= 'z')? ch - 'a' + 'A': ch + * with: 'a' == 97; 'z' == 122; 'A' == 65 + * 3) The data to be returned by DOS-65 is enlisted in the + * nlsPointer[] array of the nlsPackage structure, including + * the DOS-65-01 data, which always must be last entry of the + * array. + * 4) DOS-38 returns the 34 bytes beginning with the byte at offset + * 4 behind the size field of DOS-65-01. + * + * It seems that pure DOS can internally maintain two NLS pkgs: + * NLS#1: The hardcoded pkg of U.S.A. on CP437, and + * NLS#2: the pkg loaded via COUNTRY= from within CONFIG.SYS. + * I do interprete this behaviour as follows: + * CONFIG.SYS is read in more passes; before COUTRY= can be evaluated, + * many actions must be performed, e.g. to load kernel at all, open + * CONFIG.SYS and begin reading. The kernel requires at least two + * NLS information _before_ COUNTRY= has been evaluated - both upcase + * tables. To not implement the same function multiple times, e.g. + * to upcase with and without table, the kernel uses the default + * NLS pkg until a more appropriate one can be loaded and hopes that + * the BIOS (and the user) can live with its outcome. + * Though, theoretically, the hardcoded NLS pkg could be purged + * or overwritten once the COUNTRY= statement has been evaluated. + * It would be possible that this NLS pkg internally performs different + * purposes, for now this behaviour will be kept. + * + * The current implementation extends the above "two maintained + * NLS pkgs" into that the kernel chains all NLS pkgs loaded in + * memory into one single linked list. When the user does neither + * wants to load other NLS pkgs without executing NLSFUNC and the + * loaded NLS pkgs do not contain code themselves, no other code is + * required, but some memory to store the NLS pkgs into. + * + * Furthermore, because the kernel needs to include the code for the + * hardcoded NLS pkg anyway, every NLS pkg can use it; so only + * NLS pkgs that structurally differ from U.S.A./CP437 actually need + * to add any code and residently install the MUX handler for NLSFUNC. + * This technique reduces the overhead calling the MUX handler, when + * it is not needed. + * However, NLSFUNC is always required if the user wants to return + * information about NLS pkgs _not_ loaded into memory. + * + *=== Attention: Because the nlsInfoBlock structure differs from the + *=== the "traditional" (aka MS) implementation, the MUX-14 interface + *=== is _not_ MS-compatible, although all the registers etc. + *=== do conform. -- 2000/02/26 ska + * + * Previous failed attempts to implement NLS handling and a full- + * featured MUX-14 supporting any-structured NLS pkgs suggest + * to keep the implement as simple as possible and keep the + * optimization direction off balance and to tend toward either + * an optimization for speed or size. + * + * The most problem is that the MUX interrupt chain is considered + * highly overcrowded, so if the kernels invokes it itself, the + * performance might decrease dramatically; on the other side, the + * more complex the interface between kernel and a _probably_ installed + * external NLSFUNC becomes the more difficult all the stuff is becoming + * and, most importantly, the size grows unnecessarily, because many + * people don't use NLSFUNC at all. + * + * The kernel uses the NLS pkg itself for two operations: + * 1) DOS-65-2x and DOS-65-Ax: Upcase character, string, memory area, & + * 2) whenever a filename is passed into the kernel, its components + * must be identified, invalid characters must be detected + * and, finally, all letters must be uppercased. + * I do not consider operation 1) an action critical for performance, + * because traditional DOS programming praxis says: Do it Yourself; so + * one can consider oneself lucky that a program aquires the upcase + * table once in its life time (I mean: lucky the program calls NLS at all). + * Operation 2), in opposite, might dramatically reduce performance, if + * it lacks proper implementations. + * + * Straight forward implementation: + * The basic implementation of the NLS channels all requests of DOS-65, + * DOS-66, and DOS-38 through MUX-14. Hereby, any external program, such + * as NLSFUNC, may (or may not) install a piece of code to filter + * one, few, or all requests in order to perform them itself, by default + * all requests will end within the root of the MUX interrupt, which is + * located within the kernel itself. An access path could look like this: + * 1. Call to DOS-65-XX, DOS-66-XX, or DOS-38. + * 2. The kernel is enterred through the usual INT-21 API handler. + * 3. The request is decoded and one of the NLS.C function is called. + * 4. This function packs a new request and calls MUX-14. + * 5. Every TSR/driver hooking INT-2F will check, if the request is + * directed for itself; + * 5.1. If not, the request is passed on to the next item of the MUX + * interrupt chain; + * 5.2. If so, the TSR, e.g. NLSFUNC, tests if the request is to be + * performed internally; + * 5.2.1. If so, the request is performed and the MUX-14 call is + * terminated (goto step 8.) + * 5.2.2. If not, the request is passed on (see step 5.1.) + * 6. If all TSRs had their chance to filter requests, but none decided + * to perform the request itself, the kernel is (re-)enterred + * through its INT-2F (MUX) API handler. + * 7. Here the request is decoded again and performed with the kernel- + * internal code; then the MUX-14 call is terminated. + * 8. When the MUX-14 call returns, it has setup all return parameters + * already, so the INT-21 call is terminated as well. + * + * Note: The traditional MUX-14 is NOT supported to offer functionality + * to the kernel at the first place, but to let the kernel access and + * return any values they must be loaded into memory, but the user may + * request information through the DOS-65 interface of NLS pkgs _not_ + * already loaded. Theoretically, NLSFUNC needs not allocate any internal + * buffer to load the data into, because the user already supplied one; + * also if the kernel would instruct NLSFUNC to load the requested + * NLS pkg, more memory than necessary would be allocated. However, all + * except subfunction 1 return a _pointer_ to the data rather than the + * data itself; that means that NLSFUNC must cache the requested data + * somewhere, but how long? + * + * Performance tweaks: + * When the system -- This word applies to the combination of kernel and + * any loaded MUX-14 extension á la NLSFUNC here. -- uppercases + * _filenames_, it must perform a DOS-65-A2 internally. In the basic + * implementation this request would be channeled through MUX-14, even + * if there is no external NLSFUNC at all. Also, when a NLS pkg had + * been loaded by the kernel itself, it complies to above mentioned + * rules and it is very unlikely that it is necessary to probe if + * a MUX-14 TSR might want to perform the request itself. Therefore + * each NLS pkg contains some flags that allow the kernel to bypass + * the MUX-14 request and invoke the proper function directly. Both + * default NLS pkgs will have those flags enabled, because they are + * already loaded into memory and must comply to the rules. + * + * Note: Those flags do not alter the way the request is actually + * performed, but the MUX-14 call is omitted only (steps 4. through 6.). + * + * ======= Description of the API + * + * There are three APIs to be supported by NLS: + * 1) DOS API: DOS-38, DOS-65, DOS-66; + * 2) MUX-14, and + * 3) internal: upcasing filenames. + * + * 1) and 2) address the used NLS pkg by the country code / codepage pair. + * 3) uses the currently active NLS pkg only; furthermore, these functions + * more or less match DOS-64-A*. Therefore, the NLS system merges the + * interfaces 1) and 3) and offers function suitable for both ones. + * + * Both 1) and 3) must channel the request through the MUX chain, if + * appropriate, whereas 2) is the back-end and does natively process the + * request totally on its own. + * + * The API of 1) and 3) consists of: + * + DosUpChar(), DosUpString(), and DosUpMem(): to upcase an object + * (DOS-65-2[0-2]); + * + DosYesNo(): to check a character, if it is the yes or no prompt + * (DOS-65-23); + * + DosUpFChar(), DosUpFString(), and DosUpFMem(): to upcase an object + * for filenames (DOS-65-A[0-2]); + * + DosGetData(): to retreive certain information (DOS-38, all the + * other DOS-65-** subfunctions); + * + DosSetCountry(): to change the currently active country code + * (DOS-38); + * + DosSetCodepage(): to change the currently active codepage (DOS-66). + * + * The API of 2) consists of: + * + syscall_MUX14(). + * This function is invoked for all MUX-14 requests and recieves the + * registers of the particular INT-2F call, it will then decode the + * registers and pass the request forth to a NLS-internal interface + * consisting of the following "static" functions: + * + nlsUpMem(): called for DosUp*(), + * + nlsUpFMem(): called for DosUpF*(), + * + nlsYesNo(): called for DosYesNo(), + * + nlsGetData(): called for DosGetData(),& + * + nlsSetPackage(): called for DosSetCountry() and DosSetCodepage(). + * In opposite of the APIs 1) through 3) the NLS-internal functions address + * the NLS pkg to operate upon by a (struct nlsInfoBlock *) pointer. + * + * This designs supports to easily implement to bypass the MUX chain to + * speed up especially the internal API to upcase filenames, because + * the Dos*() functions can decide do not pass the request through MUX, + * but directly call the nls*() function instead. This way it is ensured + * that the performed actions are the same in both cases and, with repect + * to the functions that operate with the currently active NLS pkg, the + * performance is rather high, because one can use the globally available + * pointer to the current NLS pkg and need not search for a country code/ + * codepage pair. + * + * ======== Compile-time options + * + * Win9x supports to change the individual portions of a NLS pkg + * through DOS-65-00; also there are no references what happens when + * a program changes the areas addressed by returned pointers. The + * current implementation does _not_ support changes of the NLS pkg + * except by invoking DOS-38 (Set Country Code) or DOS-66 (Set Codepage). + * Future implementations might offer this ability; to reduce the + * overhead introduced by this feature, the macro NLS_MODIFYABLE_DATA + * enables the appropriate code. + * NLS_MODIFYABLE_DATA is *disabled* by default. + * + * The tables 2 and 4 (upcase tables) are accessed relatively often, + * but theoretically these tables could be located at any position + * of the pointer array. If the macro NLS_REORDER_POINTERS is enabled, + * both NLSFUNC and the internal loader will reorder the pointers + * array so that mandatory tables are located at predictable indexes. + * This removes that the kernel must search for the table when + * one of the DOS-65-[2A]x functions is called or a filename has been + * passed in (which must be uppercased to be suitable for internal + * purpose). However, when some program try to tweak the internal + * tables this assumption could be wrong. + * This setting has any effect only, if the kernel tries to access + * information itself; it is ignored when the user calls DOS-65-0x + * to return such pointer. + * NLS_REORDER_POINTERS is *enabled* by default. + * UPDATE: With NLS_REORDER_POINTERS, now table 7 (DBCS) is also + * expected to be located at a predictable index. -- eca + */ + +/* Define if some user program possibly modifies the value of the internal + tables or the DOS-65-00 (Set Country Information) API function + is to be supported. */ +/* Currently unimplemented! -- 2000/02/13 ska*/ +/* #define NLS_MODIFYABLE_DATA */ + +/* Define if the pointer array shall be reordered to allow a quick + access to often used and mandatoryly present tables. */ +#define NLS_REORDER_POINTERS + +/* + * How the kernel and NLSFUNC communicate with each other + */ + /* Must be pased to and returned by NLSFUNC upon MUX-14-00 */ +#define NLS_FREEDOS_NLSFUNC_ID 0x534b + /* What version of nlsInfo and accompanying associations + Must be passed to NLSFUNC upon MUX-14-00 to identify the + correct kernel to the tools. */ +#define NLS_FREEDOS_NLSFUNC_VERSION 0xFD02 + /* Represents a call to DOS-38 within DOS-65 handlers. + Current implementation relys on 0x101! */ +#define NLS_DOS_38 0x101 + /* NLSFUNC may return NLS_REDO to instruct the kernel to + try to perform the same action another time. This is most + useful if the kernel only loads the NLS pkg into memory so + the kernel will find it and will process the request internally + now. */ +#define NLS_REDO 353 + +/* Codes of the subfunctions of external NLSFUNC */ +#define NLSFUNC_INSTALL_CHECK 0 +#define NLSFUNC_DOS38 4 +#define NLSFUNC_GETDATA 2 +#define NLSFUNC_DRDOS_GETDATA 0xfe +#define NLSFUNC_LOAD_PKG 3 +#define NLSFUNC_LOAD_PKG2 1 +#define NLSFUNC_UPMEM 0x22 +#define NLSFUNC_YESNO 0x23 +#define NLSFUNC_FILE_UPMEM 0xa2 + +/* The NLS implementation flags encode what feature is in effect; + a "1" in the bitfield means that the feature is active. + All currently non-defined bits are to be zero to allow future + useage. */ +#define NLS_CODE_MODIFYABLE_DATA 0x0001 +#define NLS_CODE_REORDER_POINTERS 0x0002 + +/* NLS package useage flags encode what feature is in effect for this + particular package: + a "1" in the bitfield means that the feature is active/enabled. + All currently non-defined bits are to be zero to allow future + useage. */ +#define NLS_FLAG_DIRECT_UPCASE 0x0001 /* DOS-65-2[012], */ +#define NLS_FLAG_DIRECT_FUPCASE 0x0002 /* DOS-65-A[012], internal */ +#define NLS_FLAG_DIRECT_YESNO 0x0004 /* DOS-65-23 */ +#define NLS_FLAG_DIRECT_GETDATA 0x0008 /* DOS-65-XX, DOS-38 */ + +#define NLS_FLAG_HARDCODED (NLS_FLAG_DIRECT_UPCASE \ + | NLS_FLAG_DIRECT_FUPCASE \ + | NLS_FLAG_DIRECT_YESNO \ + | NLS_FLAG_DIRECT_GETDATA) + + /* No codepage / country code given */ +#define NLS_DEFAULT ((UWORD)-1) + +struct CountrySpecificInfo { + short CountryID; /* = W1 W437 # Country ID & Codepage */ + short CodePage; + short DateFormat; /* Date format: 0/1/2: U.S.A./Europe/Japan */ + char CurrencyString[5]; /* '$' ,'EUR' */ + char ThousandSeparator[2]; /* ',' # Thousand's separator */ + char DecimalPoint[2]; /* '.' # Decimal point */ + char DateSeparator[2]; /* '-' */ + char TimeSeparator[2]; /* ':' */ + char CurrencyFormat; /* = 0 # Currency format (bit array) + 0Fh BYTE currency format + bit 2 = set if currency symbol replaces decimal point + bit 1 = number of spaces between value and currency symbol + bit 0 = 0 if currency symbol precedes value + 1 if currency symbol follows value + */ + char CurrencyPrecision; /* = 2 # Currency precision */ + char TimeFormat; /* = 0 # time format: 0/1: 12/24 houres */ +}; + +/* + * This is the data in the exact order returned by DOS-65-01 + */ +struct nlsExtCntryInfo { + UBYTE subfct; /* always 1 */ + WORD size; /* size of this structure + without this WORD itself */ + WORD countryCode; /* current country code */ + WORD codePage; /* current code page (CP) */ + + /* + * This is the data in the exact order as to return on + * DOS-38; it is also the most (important) part of DOS-65-01 + */ + /* Note: The ASCIZ strings might become + a totally different understanding with + DBCS (Double Byte Character Support) */ + WORD dateFmt; /* order of portions of date + 0: mm/dd/yyyy (USA) + 1: dd/mm/yyyy (Europe) + 2: yyyy/mm/dd (Japan) + */ + char curr[5]; /* ASCIZ of currency string */ + char thSep[2]; /* ASCIZ of thousand's separator */ + char point[2]; /* ASCIZ of decimal point */ + char dateSep[2]; /* ASCIZ of date separator */ + char timeSep[2]; /* ASCIZ of time separator */ + BYTE currFmt; /* format of currency: + bit 0: currency string is placed + 0: before number + 1: behind number + bit 1: currency string and number are + separated by a space + 0: No + 1: Yes + bit 2: currency string replaces decimal + sign + 0: No + 1: Yes + */ + BYTE prescision; /* of monetary numbers */ + BYTE timeFmt; /* time format: + 0: 12 hours (append AM/PM) + 1: 24 houres + */ + VOID(FAR * upCaseFct) (VOID); /* far call to a function upcasing the + character in register AL */ + char dataSep[2]; /* ASCIZ of separator in data records */ +}; + +struct nlsPointer { /* Information of DOS-65-0X is addressed + by a pointer */ + UBYTE subfct; /* number of the subfunction */ + VOID FAR *pointer; /* the pointer to be returned when the subfunction + of DOS-65 is called (Note: won't work for + subfunctions 0, 1, 0x20, 0x21, 0x22, 0x23, + 0xA0, 0xA1,& 0xA2 */ +}; + +struct nlsPackage { /* the contents of one chain item of the + list of NLS packages */ + struct nlsPackage FAR *nxt; /* next item in chain */ + UWORD cntry, cp; /* country ID / codepage of this NLS pkg */ + int flags; /* direct access and other flags */ + /* Note: Depending on the flags above all remaining + portions may be omitted, if the external NLSFUNC-like + MUX-14 processor does not require them and performs + all actions itself, so that the kernel never tries to + fetch this information itself. */ + UWORD yeschar; /* yes / no character DOS-65-23 */ + UWORD nochar; + unsigned numSubfct; /* number of supported sub-functions */ + struct nlsPointer nlsPointers[1]; /* grows dynamically */ +}; + +struct nlsDBCS { /* The internal structure is unknown to me */ + UWORD numEntries; + UWORD dbcsTbl[1]; +}; + +struct nlsCharTbl { + /* table containing a list of characters */ + UWORD numEntries; /* number of entries of this table. + If <= 0x80, the first element of + the table corresponse to character 0x80 */ + unsigned char tbl[1]; /* grows dynamically */ +}; +#define nlsChBuf(len) struct nlsCharTbl##len { \ + UWORD numEntries; \ + unsigned char tbl[len]; \ + } +nlsChBuf(128); +nlsChBuf(256); + +/* in file names permittable characters for DOS-65-05 */ +struct nlsFnamTerm { + WORD size; /* size of this structure */ + BYTE dummy1; + char firstCh, lastCh; /* first, last permittable character */ + BYTE dummy2; + char firstExcl, lastExcl; /* first, last excluded character */ + BYTE dummy3; + BYTE numSep; /* number of file name separators */ + char separators[1]; /* grows dynamically */ +}; + +struct nlsInfoBlock { /* This block contains all information + shared by the kernel and the external NLSFUNC program */ + char FAR *fname; /* filename from COUNTRY=; + maybe tweaked by NLSFUNC */ + UWORD sysCodePage; /* system code page */ + unsigned flags; /* implementation flags */ + struct nlsPackage FAR *actPkg; /* current NLS package */ + struct nlsPackage FAR *chain; /* first item of info chain -- + hardcoded U.S.A./CP437 */ +}; + +extern struct nlsInfoBlock ASM nlsInfo; +extern struct nlsPackage FAR ASM nlsPackageHardcoded; + /* These are the "must have" tables within the hard coded NLS pkg */ +extern struct nlsFnamTerm FAR ASM nlsFnameTermHardcoded; +extern struct nlsDBCS FAR ASM nlsDBCSHardcoded; +extern struct nlsCharTbl FAR ASM nlsUpcaseHardcoded; +extern struct nlsCharTbl FAR ASM nlsFUpcaseHardcoded; +extern struct nlsCharTbl FAR ASM nlsCollHardcoded; +extern struct nlsExtCntryInfo FAR ASM nlsCntryInfoHardcoded; +extern BYTE FAR hcTablesStart[], hcTablesEnd[]; + +/*********************************************************************** + ***** Definitions & Declarations for COUNTRY.SYS ********************** + ***********************************************************************/ + +/* Note: These definitions are shared among all tools accessing the + COUNTRY.SYS file as well -- 2000/06/11 ska*/ + +/* File structure: + S0: Base (Primary) structure -- file header + Offset Size Meaning + 0 array ID string "FreeDOS COUNTRY.SYS v1.0\r\n" + 26 array Copyright etc. (plain 7bit ASCII text) + 26+N 2byte \x1a\0 + 26+N+2 array padded with \0 upto next offset + 128 word number of country/codepage pairs (N1) + 130 8byte country code / codepage entries (S1) + 130+8*N1 end of array + === + S1: structure of country/codepage pair + Offset Size Meaning + 0 dword relative position of table definition (S2) + 4 word codepage ID + 6 word country code + 8 end of structure + === + S2: table definition of one country/codepage pair + Offset Size Meaning + 0 word number of function entries (N2) + 2 8byte function definition (S3) + 2+8*N2 end of array + === + S3: function definition + Offset Size Meaning + 0 dword relative position of function data (see S4) + 4 word number of bytes of data + 6 byte function ID (same as passed to DOS-65-XX) + 7 byte reserved for future use (currently 0 (zero)) + 8 end of structure + === + S4: function data + In opposite of the structures and arrays, the function data + is just a structure-less stream of bytes, which is used as it is. + Currently no validation check is performed over this data. + That means, for instance, that a definition of function 2 (upcase + table) has length 130 and the data consists of a word value with + the length (128) and 128 bytes individual information. + That way the DBCS is implemented exactly the same way as all the + other tables; the only exception is pseudo-table 0x23. + === + "relative position" means this DWord specifies the amount of bytes + between end of the current structure and the data the pointer is + referring to. This shall enable future implementations to embed + COUNTRY.SYS into other files. +*/ + +#define CSYS_FD_IDSTRING "FreeDOS COUNTRY.SYS v1.0\r\n\x1a" + +#if 0 +struct csys_function { /* S3: function definition */ + UDWORD csys_rpos; /* relative position to actual data */ + UWORD csys_length; + UBYTE csys_fctID; /* As passed to DOS-65-XX */ + UBYTE csys_reserved1; /* always 0, reserved for future use */ +}; + +struct csys_ccDefinition { /* S1: country/codepage reference */ + UDWORD csys_rpos; /* moving the 4byte value to the front + can increase performance */ + UWORD csys_cp; + UWORD csys_cntry; +}; +#endif + +struct csys_ccDefinition { /* country/codepage reference */ + UDWORD csys_pos; /* moving the 4byte value to the front + can increase performance */ + UWORD csys_cntry; + UWORD csys_cp; + UWORD csys_size1; /* size of nlsPackage struct rpos is pointing to */ + +/* initially the object rpos is pointing to conforms to a + struct nlsPackage, where: + struct nlsPackage FAR *nxt; is missing + UWORD cntry, cp; is missing + int flags; is NLS_FLAG_HARDCODED, if the + kernel is to handle the data of its own + UWORD yeschar; is filled + UWORD nochar; is filled + unsigned numSubfct; is filled + struct nlsPointer nlsPointers[1]; is filled + the pointer member is the absolute + position of the data within the file + of this structure: + UWORD count + count bytes + The "count" value is not a part + of the data itself. + Also: The data must be ordered corresponding to + NLS_CODE_REORDER_POINTERS. + Also: The last nlsPointer is subfct #1 _incl_ all its + data [is the extended country information: struct nlsExtCntryInfo] +*/ +}; + +struct csys_numEntries { /* helper structure for "number of entries" */ + UWORD csys_entries; +}; + +/* Header of the COUNTRY.SYS file */ +struct nlsCSys_fileHeader { /* COUNTRY.SYS header */ + unsigned char csys_idstring[sizeof(CSYS_FD_IDSTRING)]; + UWORD csys_maxTotalSize; /* maximal size of the total amount of + any individual definition, that includes + the nlsPackage skeleton and the sum of + all bytes required to load all the + subfunctions individually. + --> The code is to allocate maxTotalSize + and load any country definition of this + file into this buffer without any + overflow. */ + DWORD csys_posIndex; /* absolute position of index table */ +}; + +/* Structure created by CountryInfoLoad() */ +struct nlsCSys_loadPackage { + UWORD csys_size; + struct nlsPackage csys_pkg; +}; + +/* standard alignment */ +#include + +#ifdef DEBUG + /* Enable debugging of NLS part */ + + /* Caution: Enabling NLS debugging usually generates + _a_lot_ of noise. */ +/*& #define NLS_DEBUG */ + +#endif diff --git a/hdr/pcb.h b/hdr/pcb.h new file mode 100644 index 0000000..6ac29f8 --- /dev/null +++ b/hdr/pcb.h @@ -0,0 +1,172 @@ +/****************************************************************/ +/* */ +/* pcb.h */ +/* */ +/* Process Control and Interrupt data structures */ +/* */ +/* November 26, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + +/*************************************************************** + 2000/03/22 ska + There is a newly documented (though used previously) side effect + of the definitions and assumptions made herein: + The assembly sources may use a macro named "PUSH$ALL" to push + all processor registers onto the stack, see example below: + PUSH$ALL + mov ax, sp + ... + push ax + call _c_function + pop cx + The stack pointer immediately after the PUSH$ALL macro shall point to + a structure used as an "iregs" structure within the C language. + Therefore the internal of the structure "iregs" _must_ always + match the implementation of the macro "PUSH$ALL". +*/ + +#ifndef __PCB_H +#define __PCB_H + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *pcb_hRcsId = + "$Id: pcb.h 1316 2007-05-15 17:48:47Z bartoldeman $"; +#endif +#endif + + /* Force one-byte alignment for all the internal structures, see above */ +#include +/* */ +/* interrupt handler structure definition */ +/* */ +typedef union { + UWORD x; /* access mode for ax, bx, etc. */ + struct { + UBYTE l; /* access mode for al, bl, etc. */ + UBYTE h; /* access mode for ah, bh, etc. */ + } b; +} xreg; + +/* The structure assumes that: + 1) An interrupt was invoked, & + 2) the PUSH$ALL macro was invoked immediately after that. + Furthermore, the PUSH$ALL macro must push ES first and AX last. + -- 2000/03/22 ska*/ +/* maps MS-DOS unique stacking order */ +typedef struct _iregss { + xreg a, b, c, d; + UWORD si, di, bp, ds, es; + UWORD ip, cs, flags; +} iregs; + +/* struct used for local copy of registers */ +typedef struct { + xreg a, b, c, d; + UWORD si, di, ds, es; +} lregs; + + /* Registers directly passed to syscall; + must be the same order as iregs! + Is used to define parameters. */ +#define DIRECT_IREGS \ + xreg a, xreg b, xreg c, xreg d, \ + UWORD si, UWORD di, UWORD bp, UWORD ds, UWORD es, \ + UWORD ip, UWORD cs, UWORD flags + +/* Process control block for task switching */ +typedef struct { + UWORD pc_ss; + UWORD pc_sp; + iregs pc_regs; +} pcb; + +/* Note: The following figure is not made by myself and I assume that + the order of "ES" through "AX" are misinterpreted?! -- 2000/03/22 ska*/ + +/* For MSC, the following offsets must match the assembly process */ +/* support offsets */ +/* NOTE: Alignemnts must be set to 1 (-Zp1) */ +/* ss: 0 */ +/* sp: 2 */ +/* es: 4 */ +/* ds: 6 */ +/* di: 8 */ +/* si: 10 */ +/* bp: 12 */ +/* sp: 14 NOTE: not used in this structure */ +/* bx: 16 */ +/* dx: 18 */ +/* cx: 20 */ +/* ax: 22 */ +/* ip: 24 */ +/* cs: 26 */ +/* flags: 28 */ +/* */ +/* For Borland C, the following offsets must match the assembly process */ +/* support offsets */ +/* ss: 0 */ +/* sp: 2 */ +/* bp: 4 */ +/* di: 6 */ +/* si: 8 */ +/* ds: 10 */ +/* es: 12 */ +/* dx: 14 */ +/* cx: 16 */ +/* bx: 18 */ +/* ax: 20 */ +/* ip: 22 */ +/* cs: 24 */ +/* flags: 26 */ + +#define BP bp +#define DI di +#define SI si +#define DS ds +#define ES es +#define DX d.x +#define CX c.x +#define BX b.x +#define AX a.x +#define DH d.b.h +#define CH c.b.h +#define BH b.b.h +#define AH a.b.h +#define DL d.b.l +#define CL c.b.l +#define BL b.b.l +#define AL a.b.l +#define IP ip +#define CS cs +#define FLAGS flags + +#define FLG_ZERO 0x0040 +#define FLG_CARRY 0x0001 + + /* Allow default alignment from now on */ +#include + +#endif + diff --git a/hdr/portab.h b/hdr/portab.h new file mode 100644 index 0000000..d4f979d --- /dev/null +++ b/hdr/portab.h @@ -0,0 +1,325 @@ +/****************************************************************/ +/* */ +/* portab.h */ +/* */ +/* DOS-C portability typedefs, etc. */ +/* */ +/* May 1, 1995 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static char *portab_hRcsId = + "$Id: portab.h 1121 2005-03-15 15:25:08Z perditionc $"; +#endif +#endif + +/****************************************************************/ +/* */ +/* Machine dependant portable types. Note that this section is */ +/* used primarily for segmented architectures. Common types and */ +/* types used relating to segmented operations are found here. */ +/* */ +/* Be aware that segmented architectures impose on linear */ +/* architectures because they require special types to be used */ +/* throught the code that must be reduced to empty preprocessor */ +/* replacements in the linear machine. */ +/* */ +/* #ifdef */ +/* # define FAR far */ +/* # define NEAR near */ +/* #endif */ +/* */ +/* #ifdef */ +/* # define FAR */ +/* # define NEAR */ +/* #endif */ +/* */ +/****************************************************************/ + + /* commandline overflow - removing -DI86 TE */ +#if defined(__TURBOC__) + +#define I86 +#define CDECL cdecl +#if __TURBOC__ > 0x202 +/* printf callers do the right thing for tc++ 1.01 but not tc 2.01 */ +#define VA_CDECL +#else +#define VA_CDECL cdecl +#endif +#define PASCAL pascal +void __int__(int); +#ifndef FORSYS +void __emit__(char, ...); +#define disable() __emit__(0xfa) +#define enable() __emit__(0xfb) +#endif + +#elif defined (_MSC_VER) + +#define I86 +#define asm __asm +#pragma warning(disable: 4761) /* "integral size mismatch in argument; + conversion supplied" */ +#define CDECL _cdecl +#define VA_CDECL +#define PASCAL pascal +#define __int__(intno) asm int intno; +#define disable() asm cli +#define enable() asm sti +#define _CS getCS() +static unsigned short __inline getCS(void) +{ + asm mov ax, cs; +} +#define _SS getSS() +static unsigned short __inline getSS(void) +{ + asm mov ax, ss; +} + +#elif defined(__WATCOMC__) /* don't know a better way */ + +#define I86 +#define __int__(intno) asm int intno; +void disable(void); +#pragma aux disable = "cli" modify exact []; +void enable(void); +#pragma aux enable = "sti" modify exact []; +#define asm __asm +#define far __far +#define CDECL __cdecl +#define VA_CDECL +#define PASCAL pascal +#define _CS getCS() +unsigned short getCS(void); +#pragma aux getCS = "mov dx,cs" value [dx] modify exact[dx]; +#define _SS getSS() +unsigned short getSS(void); +#pragma aux getSS = "mov dx,ss" value [dx] modify exact[dx]; +#if !defined(FORSYS) && !defined(EXEFLAT) && _M_IX86 >= 300 +#pragma aux default parm [ax dx cx] modify [ax dx es fs] /* min.unpacked size */ +#endif + +/* enable Possible loss of precision warning for compatibility with Borland */ +#pragma enable_message(130) + +#if _M_IX86 >= 300 || defined(M_I386) +#define I386 +#endif + +#elif defined (_MYMC68K_COMILER_) + +#define MC68K + +#elif defined(__GNUC__) +/* for warnings only ! */ +#define MC68K + +#else +#error Unknown compiler +We might even deal with a pre-ANSI compiler. This will certainly not compile. +#endif + +#ifdef I86 +#if _M_IX86 >= 300 || defined(M_I386) +#define I386 +#elif _M_IX86 >= 100 || defined(M_I286) +#define I186 +#endif +#endif + +#ifdef MC68K +#define far /* No far type */ +#define interrupt /* No interrupt type */ +#define VOID void +#define FAR /* linear architecture */ +#define NEAR /* " " */ +#define INRPT interrupt +#define REG register +#define API int /* linear architecture */ +#define NONNATIVE +#define PARASIZE 4096 /* "paragraph" size */ +#define CDECL +#define PASCAL +#ifdef __GNUC__ +#define CONST const +#define PROTO +typedef __SIZE_TYPE__ size_t; +#else +#define CONST +typedef unsigned size_t; +#endif +#endif +#ifdef I86 +#define VOID void +#define FAR far /* segment architecture */ +#define NEAR near /* " " */ +#define INRPT interrupt +#define CONST const +#define REG register +#define API int far pascal /* segment architecture */ +#define NATIVE +#define PARASIZE 16 /* "paragraph" size */ +typedef unsigned size_t; +#endif + /* functions, that are shared between C and ASM _must_ + have a certain calling standard. These are declared + as 'ASMCFUNC', and is (and will be ?-) cdecl */ +#define ASMCFUNC CDECL +#define ASMPASCAL PASCAL +#define ASM ASMCFUNC +/* */ +/* Boolean type & definitions of TRUE and FALSE boolean values */ +/* */ +typedef int BOOL; +#define FALSE (1==0) +#define TRUE (1==1) + +/* */ +/* Common pointer types */ +/* */ +#ifndef NULL +#define NULL 0 +#endif + +/* */ +/* Convienence defines */ +/* */ +#define FOREVER while(TRUE) +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/* */ +/* Common byte, 16 bit and 32 bit types */ +/* */ +typedef char BYTE; +typedef short WORD; +typedef long DWORD; + +typedef unsigned char UBYTE; +typedef unsigned short UWORD; +typedef unsigned long UDWORD; + +typedef short SHORT; + +typedef unsigned int BITS; /* for use in bit fields(!) */ + +typedef int COUNT; +typedef unsigned int UCOUNT; +typedef unsigned long ULONG; + +#ifdef WITHFAT32 +typedef unsigned long CLUSTER; +#else +typedef unsigned short CLUSTER; +#endif +typedef unsigned short UNICODE; + +#if defined(STATICS) || defined(__WATCOMC__) +#define STATIC static /* local calls inside module */ +#else +#define STATIC +#endif + +#ifdef UNIX +typedef char FAR *ADDRESS; +#else +typedef void FAR *ADDRESS; +#endif + +#ifdef STRICT +typedef signed long LONG; +#else +#define LONG long +#endif + +#define MK_UWORD(hib,lob) (((UWORD)(hib) << 8u) | (UBYTE)(lob)) +#define MK_ULONG(hiw,low) (((ULONG)(hiw) << 16u) | (UWORD)(low)) + +/* General far pointer macros */ +#ifdef I86 +#ifndef MK_FP + +#if defined(__WATCOMC__) +#define MK_FP(seg,ofs) (((UWORD)(seg)):>((VOID *)(ofs))) +#elif defined(__TURBOC__) && (__TURBOC__ > 0x202) +#define MK_FP(seg,ofs) ((void _seg *)(seg) + (void near *)(ofs)) +#else +#define MK_FP(seg,ofs) ((void FAR *)(((ULONG)(seg)<<16)|(UWORD)(ofs))) +#endif + +#define pokeb(seg, ofs, b) (*((unsigned char far *)MK_FP(seg,ofs)) = b) +#define poke(seg, ofs, w) (*((unsigned far *)MK_FP(seg,ofs)) = w) +#define pokew poke +#define pokel(seg, ofs, l) (*((unsigned long far *)MK_FP(seg,ofs)) = l) +#define peekb(seg, ofs) (*((unsigned char far *)MK_FP(seg,ofs))) +#define peek(seg, ofs) (*((unsigned far *)MK_FP(seg,ofs))) +#define peekw peek +#define peekl(seg, ofs) (*((unsigned long far *)MK_FP(seg,ofs))) + +#if defined(__TURBOC__) && (__TURBOC__ > 0x202) +#define FP_SEG(fp) ((unsigned)(void _seg *)(void far *)(fp)) +#else +#define FP_SEG(fp) ((unsigned)((ULONG)(VOID FAR *)(fp)>>16)) +#endif + +#define FP_OFF(fp) ((unsigned)(fp)) + +#endif +#endif + +#ifdef MC68K +#define MK_FP(seg,ofs) ((VOID *)(&(((BYTE *)(size_t)(seg))[(ofs)]))) +#define FP_SEG(fp) (0) +#define FP_OFF(fp) ((size_t)(fp)) +#endif + +typedef VOID (FAR ASMCFUNC * intvec) (void); + +#define MK_PTR(type,seg,ofs) ((type FAR*) MK_FP (seg, ofs)) +#if __TURBOC__ > 0x202 +# define MK_SEG_PTR(type,seg) ((type _seg*) (seg)) +#else +# define _seg FAR +# define MK_SEG_PTR(type,seg) MK_PTR (type, seg, 0) +#endif + +/* + this suppresses the warning + unreferenced parameter 'x' + and (hopefully) generates no code +*/ +#define UNREFERENCED_PARAMETER(x) (void)x; + +#ifdef I86 /* commandline overflow - removing /DPROTO TE */ +#define PROTO +#endif + +#define LENGTH(x) (sizeof(x)/sizeof(x[0])) diff --git a/hdr/process.h b/hdr/process.h new file mode 100644 index 0000000..a336631 --- /dev/null +++ b/hdr/process.h @@ -0,0 +1,110 @@ +/****************************************************************/ +/* */ +/* process.h */ +/* */ +/* DOS exec data structures & declarations */ +/* */ +/* November 23, 1991 */ +/* */ +/* 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. */ +/****************************************************************/ + + +/* Modes available as first argument to the spawnxx functions. */ + +#define P_WAIT 0 /* child runs separately, parent waits until exit */ +#define P_NOWAIT 1 /* both concurrent -- not implemented */ +#define P_OVERLAY 2 /* child replaces parent, parent no longer exists */ + +typedef struct { + union { + struct { + UWORD load_seg; + UWORD reloc; + } _load; + struct { + UWORD env_seg; + CommandTail FAR *cmd_line; + fcb FAR *fcb_1; + fcb FAR *fcb_2; + BYTE FAR *stack; + BYTE FAR *start_addr; + } _exec; + } ldata; +} exec_blk; + +#define exec ldata._exec +#define load ldata._load + +typedef struct { + UWORD ps_exit; /* 00 CP/M-like exit point: int 20 */ + UWORD ps_size; /* 02 segment of first byte beyond */ + /* memory allocated to program */ + BYTE ps_fill1; /* 04 single char fill=0 */ + + /* CP/M-like entry point */ + /* offsets 5-9 are a far call to absolute address 0:00C0h + encoded using 1MB wrap form of address (e.g. 0F01D:FEF0h) + for compatiblity with CP/M apps that do a near call to psp:5 + and expect size (KB) of allocated segment in word at offset 6 */ + UBYTE ps_farcall; /* 05 far call opcode */ + VOID(FAR ASMCFUNC * ps_reentry) (void); /* 06 re-entry point */ + + intvec ps_isv22, /* 0a terminate address */ + ps_isv23, /* 0e ctrl-break address */ + ps_isv24; /* 12 critical error address */ + UWORD ps_parent; /* 16 parent psp segment */ + UBYTE ps_files[20]; /* 18 file table - 0xff is unused */ + UWORD ps_environ; /* 2c environment paragraph */ + BYTE FAR *ps_stack; /* 2e user stack pointer - int 21 */ + UWORD ps_maxfiles; /* 32 maximum open files */ + UBYTE FAR *ps_filetab; /* 34 open file table pointer */ + VOID FAR *ps_prevpsp; /* 38 previous psp pointer */ + UBYTE ps_fill2; /* 3c unused */ + UBYTE ps_truename; /* 3d [unused] append truename flag int2f/B711h */ + UBYTE ps_netx_taskid[2]; /* 3e [Novell only field] task id */ + UWORD ps_retdosver; /* 40 [unused] version to return on int21/30h */ + UWORD pdb_next; /* 42 [Win only field] PSP chain */ + UBYTE ps_fill2b[4]; /* 44 unused, 4 bytes */ + UBYTE ps_olddos; /* 48 [Win only field] DOS/Win program */ + UBYTE ps_fill2c[7]; /* 49 unused, 7 bytes */ + UBYTE ps_unix[3]; /* 50 unix style call - 0xcd 0x21 0xcb */ + BYTE ps_fill3[9]; /* 53 */ + union { + struct { + fcb _ps_fcb1; /* 5c first command line argument */ + } _u1; + struct { + BYTE fill4[16]; + fcb _ps_fcb2; /* second command line argument */ + } _u2; + struct { + BYTE fill5[36]; + CommandTail _ps_cmd; + } _u3; + } _u; +} psp; + +#define ps_fcb1 _u._u1._ps_fcb1 +#define ps_fcb2 _u._u2._ps_fcb2 +#define ps_cmd _u._u3._ps_cmd + diff --git a/hdr/sft.h b/hdr/sft.h new file mode 100644 index 0000000..f2e036c --- /dev/null +++ b/hdr/sft.h @@ -0,0 +1,143 @@ +/****************************************************************/ +/* */ +/* sft.h */ +/* DOS-C */ +/* */ +/* DOS System File Table Structure */ +/* */ +/* Copyright (c) 1995, 1996 */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *sft_hRcsId = + "$Id: sft.h 1429 2009-06-09 18:50:03Z bartoldeman $"; +#endif +#endif + +#define SFTMAX 128 + +/* Handle Definition entry */ +typedef struct { + WORD sft_count; /* 00 - reference count */ + WORD sft_mode; /* 02 - open mode - see below */ + BYTE sft_attrib; /* 04 - file attribute - dir style */ + + union /* 05 */ + { + WORD _sft_flags; + struct { + BYTE _sft_flags_lo; + BYTE _sft_flags_hi; + } _split_sft_flags; + } sft_flags_union; + + union /* 07 */ + { + struct dpb FAR *_sft_dcb; /* The device control block */ + struct dhdr FAR *_sft_dev; /* device driver for char dev */ + } sft_dcb_or_dev; +#ifdef WITHFAT32 + UWORD sft_relclust_high; /* 0b - High part of relative cluster */ +#else + CLUSTER sft_stclust; /* 0b - Starting cluster */ +#endif + time sft_time; /* 0d - File time */ + date sft_date; /* 0f - File date */ + ULONG sft_size; /* 11 - File size */ + ULONG sft_posit; /* 15 - Current file position */ + UWORD sft_relclust; /* 19 - File relative cluster (low part) */ + ULONG sft_dirsector; /* 1b - Sector containing cluster */ + UBYTE sft_diridx; /* 1f - directory index */ + BYTE sft_name[11]; /* 20 - dir style file name */ +#ifdef WITHFAT32 + CLUSTER sft_stclust; /* 2b - Starting cluster */ +#else + BYTE FAR *sft_bshare; /* 2b - backward link of file sharing sft */ +#endif + WORD sft_mach; /* 2f - machine number - network apps */ + WORD sft_psp; /* 31 - owner psp */ + WORD sft_shroff; /* 33 - Sharing offset */ + CLUSTER sft_cuclust; /* 35 - File current cluster */ +#ifdef WITHFAT32 + UWORD sft_pad; +#else + BYTE FAR *sft_ifsptr; /* 37 - pointer to IFS driver for file, 0000000h if native DOS */ +#endif +} sft; + +/* SFT Table header definition */ +typedef struct _sftheader { + struct sfttbl FAR * /* link to next table in list */ + sftt_next; + WORD sftt_count; /* # of handle definition */ + /* entries, this table */ +} sftheader; + +/* System File Definition List */ +typedef struct sfttbl { + struct sfttbl FAR * /* link to next table in list */ + sftt_next; + WORD sftt_count; /* # of handle definition */ + /* entries, this table */ + sft sftt_table[SFTMAX]; /* The array of sft for block */ +} sfttbl; + +/* defines for sft use */ +#define SFT_MASK 0x0060 /* splits device data */ + +/* flag bits */ + +/* the following bit is for redirection */ +#define SFT_FSHARED 0x8000 /* Networked access */ + +/* the following entry differntiates char & block access */ +#define SFT_FDEVICE 0x0080 /* device entry */ + +/* the following bits are file (block) unique */ +#define SFT_FDATE 0x4000 /* File date set */ +#define SFT_FCLEAN 0x0040 /* File has not been written to */ +#define SFT_FDMASK 0x003f /* File mask for drive no */ + +/* the following bits are device (char) unique */ +#define SFT_FIOCTL 0x4000 /* IOCTL support - device */ +#define SFT_FOCRM 0x0800 /* Open/Close/RM bit in device attribute*/ +#define SFT_FEOF 0x0040 /* device eof */ +#define SFT_FBINARY 0x0020 /* device binary mode */ +#define SFT_FSPECIAL 0x0010 /* int 29 support */ +#define SFT_FCLOCK 0x0008 /* device is clock */ +#define SFT_FNUL 0x0004 /* device is nul */ +#define SFT_FCONOUT 0x0002 /* device is console output */ +#define SFT_FCONIN 0x0001 /* device is console input */ + +/* Convenience defines */ +#define sft_dcb sft_dcb_or_dev._sft_dcb +#define sft_dev sft_dcb_or_dev._sft_dev + +#define sft_flags sft_flags_union._sft_flags +#define sft_flags_hi sft_flags_union._split_sft_flags._sft_flags_hi +#define sft_flags_lo sft_flags_union._split_sft_flags._sft_flags_lo + +/* defines for LSEEK */ +#define SEEK_SET 0u +#define SEEK_CUR 1u +#define SEEK_END 2u diff --git a/hdr/stacks.inc b/hdr/stacks.inc new file mode 100644 index 0000000..95df704 --- /dev/null +++ b/hdr/stacks.inc @@ -0,0 +1,198 @@ +; +; File: +; stacks.inc +; Description: +; Macro support for register stack frame +; +; Copyright (c) 1998 +; 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. +; +; $Id: stacks.inc 1591 2011-05-06 01:46:55Z bartoldeman $ +; + +; +; Standard stack frame used throughout DOS-C +; +; MS-DOS specific +; +; +---------------+ +; | irp hi | 26 +; +---------------+ +; | irp low | 24 +; +---------------+ +; | flags | 22 +; +---------------+ +; | cs | 20 +; +---------------+ +; | ip | 18 +; +---------------+ +; | es | 16 +; +---------------+ +; | ds | 14 +; +---------------+ +; | bp | 12 +; +---------------+ +; | di | 10 +; +---------------+ +; | si | 8 +; +---------------+ +; | dx | 6 +; +---------------+ +; | cx | 4 +; +---------------+ +; | bx | 2 +; +---------------+ +; | ax | 0 +; +---------------+ +; + +;; Note: The order of the pushed registers _must_ match with the definition +;; of the "iregs" structure within PCB.H, because a pointer to the last +;; pushed register is used as a pointer to a "iregs" structure within the +;; called C sources! -- 2000/03/22 ska + +; Don't use `struc RegFrame' etc. here because it interferes with segment +; definitions. +reg_ax equ 0 +reg_bx equ 2 +reg_cx equ 4 +reg_dx equ 6 +reg_si equ 8 +reg_di equ 10 +reg_bp equ 12 +reg_ds equ 14 +reg_es equ 16 +reg_ip equ 18 +reg_cs equ 20 +reg_flags equ 22 +irp_low equ 24 +irp_hi equ 26 + +%macro PUSH$ALL 0 + push es + push ds + push bp + push di + push si + push dx + push cx + push bx + push ax +%endmacro + +%macro POP$ALL 0 + pop ax + pop bx + pop cx + pop dx + pop si + pop di + pop bp + pop ds + pop es +%endmacro + +; I386.inc - 10/25/01 by tom ehlert +; +; compiling the kernel for 386 will (sometimes) change the +; high part of (some) registers, which will be (sometimes) be used +; later +; +; assumption: +; we have never seen MSVC to use anything but eax, ecx, edx, +; nor have we seen Borland C to use anything but eax, ebx, edx, +; so we only protect eax, ebx or ecx, edx to conserve stack space +; +; to save even more stack space, we save only HIGH part of regs +; at some expense of slower execution. it's easier anyway :-) +; +; WATCOM only uses FS: and GS: (using -zff and -zgf) and never +; any high part of the 386 registers +; + + +%IF XCPU < 386 + ; no need to save/restore anything + +; error 1 2 3 + %macro Protect386Registers 0 + %endmacro + + %macro RestoreSP 0 + mov sp, bp + %endmacro + + %macro Restore386Registers 0 + %endmacro + +%ELSE + %ifdef WATCOM + + %macro Protect386Registers 0 + push fs + push gs + %endmacro + + %macro RestoreSP 0 + lea sp, [bp-4] + %endmacro + + %macro Restore386Registers 0 + pop gs + pop fs + %endmacro + + %else + + %macro Protect386Registers 0 + push eax + pop ax + %ifdef MSCL8 + push ecx + pop cx + %else ;BC5 + push ebx + pop bx + %endif + push edx + pop dx + %endmacro + + %macro RestoreSP 0 + lea sp, [bp-6] + %endmacro + + %macro Restore386Registers 0 + push dx + pop edx + %ifdef MSCL8 + push cx + pop ecx + %else ;BC5 + push bx + pop ebx + %endif + push ax + pop eax + %endmacro + + %endif +%ENDIF diff --git a/hdr/tail.h b/hdr/tail.h new file mode 100644 index 0000000..810a6bd --- /dev/null +++ b/hdr/tail.h @@ -0,0 +1,44 @@ +/****************************************************************/ +/* */ +/* tail.h */ +/* */ +/* Command tail data structures */ +/* */ +/* July 1, 1993 */ +/* */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *tail_hRcsId = + "$Id: tail.h 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif +#endif + +#define CTBUFFERSIZE 127 + +typedef struct { + UBYTE ctCount; /* number of bytes returned */ + char ctBuffer[CTBUFFERSIZE]; /* the buffer itself */ +} CommandTail; + diff --git a/hdr/time.h b/hdr/time.h new file mode 100644 index 0000000..e2aaf2e --- /dev/null +++ b/hdr/time.h @@ -0,0 +1,56 @@ +/****************************************************************/ +/* */ +/* time.h */ +/* */ +/* DOS General Time Structure */ +/* */ +/* January 21, 1993 */ +/* */ +/* 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. */ +/****************************************************************/ + +/* TC 2.01 complains if `time' is defined twice. -- ror4 */ +#ifndef DOSC_TIME_H +#define DOSC_TIME_H + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *time_hRcsId = + "$Id: time.h 942 2004-05-23 15:00:37Z bartoldeman $"; +#endif +#endif + +typedef UWORD time; + +struct dostime +{ + unsigned char minute, hour, hundredth, second; +}; + +struct dosdate +{ + unsigned short year; + unsigned char monthday, month; +}; + +#endif + diff --git a/hdr/version.h b/hdr/version.h new file mode 100644 index 0000000..3586f6b --- /dev/null +++ b/hdr/version.h @@ -0,0 +1,51 @@ +/****************************************************************/ +/* */ +/* version.h */ +/* */ +/* Common version information */ +/* */ +/* Copyright (c) 1997 */ +/* 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. */ +/****************************************************************/ + +/* The version the kernel reports as compatible with */ +#ifdef WITHFAT32 +#define MAJOR_RELEASE 7 +#define MINOR_RELEASE 10 +#else +#define MAJOR_RELEASE 6 +#define MINOR_RELEASE 22 +#endif + +/* The actual kernel revision, 2000+REVISION_SEQ = 2.REVISION_SEQ */ +#define REVISION_SEQ 42 /* returned in BL by int 21 function 30 */ +#define OEM_ID 0xfd /* FreeDOS, returned in BH by int 21 30 */ + +/* Used for version information displayed to user at boot (& stored in os_release string) */ +#ifndef KERNEL_VERSION +#define KERNEL_VERSION "- SVN " +#endif + +/* actual version string */ +#define KVS(v,s,o) "FreeDOS kernel " v "(build 20" #s " OEM:" #o ") [compiled " __DATE__ "]\n" +#define xKVS(v,s,o) KVS(v,s,o) +#define KERNEL_VERSION_STRING xKVS(KERNEL_VERSION, REVISION_SEQ, OEM_ID) + diff --git a/hdr/win.h b/hdr/win.h new file mode 100644 index 0000000..fdf8483 --- /dev/null +++ b/hdr/win.h @@ -0,0 +1,39 @@ +#ifndef __WINSUPPORT_H +#define __WINSUPPORT_H +#ifdef WIN31SUPPORT /* defined to enable kernel hooks for win3.x compatibility */ + + +extern UWORD winInstanced; /* internal flag marking if Windows is active */ + +/* contains information about data that must be kept for each active DOS + instance, ie data that can NOT be shared between multiple VMs. + */ +struct WinStartupInfo +{ + UWORD winver; /* this structure version, matches Windows version */ + ULONG next; /* far pointer to next WinStartupInfo structure or NULL */ + ULONG vddName; /* far pointer to ASCIIZ pathname of virtual device driver */ + ULONG vddInfo; /* far pointer to vdd reference data or NULL if vddName=NULL */ + ULONG instanceTable; /* far pointer to array of instance data */ + ULONG optInstanceTable; /* used only if winver set to 0x400 (w95)*/ +}; +extern struct WinStartupInfo winStartupInfo; + +/* contains a list of offsets relative to DOS data segment of + various internal variables. + */ +struct WinPatchTable +{ + UWORD dosver; + UWORD OffTempDS; + UWORD OffTempBX; + UWORD OffInDOS; + UWORD OffMachineID; + UWORD OffCritSectPatches; + UWORD OffLastMCBSeg; /* used by Win 3.1 if DOS version 5 or higher */ +}; +extern struct WinPatchTable winPatchTable; + + +#endif /* WIN31SUPPORT */ +#endif /* __WINSUPPORT_H */ diff --git a/hdr/xstructs.h b/hdr/xstructs.h new file mode 100644 index 0000000..f29bbe4 --- /dev/null +++ b/hdr/xstructs.h @@ -0,0 +1,83 @@ +/****************************************************************/ +/* */ +/* xstructs.h */ +/* */ +/* Extended DOS 7.0+ structures */ +/* */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *XStructs_hRcsId = + "$Id: xstructs.h 1457 2009-06-26 20:00:41Z bartoldeman $"; +#endif +#endif + +struct xdpbdata { + UWORD xdd_dpbsize; + struct dpb xdd_dpb; +}; + +struct xfreespace { + UWORD xfs_datasize; /* size of this structure */ + union { + UWORD requested; /* requested structure version */ + UWORD actual; /* actual structure version */ + } xfs_version; + ULONG xfs_clussize; /* number of sectors per cluster */ + ULONG xfs_secsize; /* number of bytes per sector */ + ULONG xfs_freeclusters; /* number of available clusters */ + ULONG xfs_totalclusters; /* total number of clusters on the drive */ + ULONG xfs_freesectors; /* number of physical sectors available */ + ULONG xfs_totalsectors; /* total number of physical sectors */ + ULONG xfs_freeunits; /* number of available allocation units */ + ULONG xfs_totalunits; /* total allocation units */ + UBYTE xfs_reserved[8]; +}; + +struct xdpbforformat { + UWORD xdff_datasize; /* size of this structure */ + union { + UWORD requested; /* requested structure version */ + UWORD actual; /* actual structure version */ + } xdff_version; + UDWORD xdff_function; /* function number: + 00h invalidate DPB counts + 01h rebuild DPB from BPB + 02h force media change + 03h get/set active FAT number and mirroring + 04h get/set root directory cluster number + */ + union { + struct { + DWORD nfreeclst; /* # free clusters + (-1 - unknown, 0 - don't change) */ + DWORD cluster; /* cluster # of first free + (-1 - unknown, 0 - don't change) */ + UDWORD reserved[2]; + } setdpbcounts; + + struct { + UDWORD unknown; + bpb FAR *bpbp; + UDWORD reserved[2]; + } rebuilddpb; + + struct { + DWORD new; /* new active FAT/mirroring state, or -1 to get + bits 3-0: the 0-based FAT number of the active FAT + bits 6-4: reserved (0) + bit 7: do not mirror active FAT to inactive FATs + or: + set new root directory cluster, -1 - get current + */ + DWORD old; /* previous active FAT/mirroring state (as above) + or + get previous root directory cluster + */ + UDWORD reserved[2]; + } setget; + } xdff_f; +}; + +COUNT DosGetExtFree(BYTE FAR * DriveString, struct xfreespace FAR * xfsp); diff --git a/kernel/apisupt.asm b/kernel/apisupt.asm new file mode 100644 index 0000000..abc10c0 --- /dev/null +++ b/kernel/apisupt.asm @@ -0,0 +1,130 @@ +; File: +; apisupt.asm +; Description: +; Assembly support routines for stack manipulation, etc. +; +; Copyright (c) 1995, 1998 +; 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. +; +; $Id: apisupt.asm 538 2003-03-12 22:43:53Z bartoldeman $ +; + + %include "segs.inc" + +segment HMA_TEXT +%if 0 + + extern _api_sp:wrt DGROUP ; api stacks - for context + extern _api_ss:wrt DGROUP ; switching + extern _usr_sp:wrt DGROUP ; user stacks + extern _usr_ss:wrt DGROUP + + global _set_stack +; +; void set_stack(void) - +; save current stack and setup our local stack +; +_set_stack: + + ; save foreground stack + + ; we need to get the return values from the stack + ; since the current stack will change + pop ax ;get return offset + + ; Save the flags so that we can restore correct interrupt + ; state later. We need to disable interrupts so that we + ; don't trash memory with new sp-old ss combination + pushf + pop dx + cli + + ; save bp + push bp + + mov cx, sp + neg cx + + ; save away foreground process' stack + push word [_usr_ss] + push word [_usr_sp] + + mov word [_usr_ss],ss + mov word [_usr_sp],sp + + ; setup our local stack + mov ss,word [_api_ss] + mov sp,word [_api_sp] + + add cx, sp + add bp, cx + + ; setup for ret + push ax + + ; now restore interrupt state + push dx + popf + + ret + +; +; void restore_stack(void) - +; restore foreground stack, throw ours away +; + global _restore_stack +_restore_stack: + + ; we need to get the return values from the stack + ; since the current stack will change + pop cx ;get return offset + + ; Save the flags so that we can restore correct interrupt + ; state later. We need to disable interrupts so that we + ; don't trash memory with new sp-old ss combination + pushf + pop dx + cli + + ; save background stack + mov word [_api_ss],ss + mov word [_api_sp],sp + + ; restore foreground stack here + mov ss,word [_usr_ss] + mov sp,word [_usr_sp] + + pop word [_usr_sp] + pop word [_usr_ss] + + ; make bp relative to our stack frame + pop bp + ;mov bp,sp + + ; setup for ret + push cx + + ; now restore interrupt state + push dx + popf + + ret +%endif diff --git a/kernel/asmsupt.asm b/kernel/asmsupt.asm new file mode 100644 index 0000000..faa0a60 --- /dev/null +++ b/kernel/asmsupt.asm @@ -0,0 +1,554 @@ +; File: +; asmsupt.asm +; Description: +; Assembly support routines for miscellaneous functions +; +; Copyright (c) 1995, 1998 +; 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. +; +; version 1.4 by tom.ehlert@ginko.de +; added some more functions +; changed bcopy, scopy, sncopy,... +; to memcpy, strcpy, strncpy +; Bart Oldeman: optimized a bit: see /usr/include/bits/string.h from +; glibc 2.2 +; +; $Id: asmsupt.asm 1568 2011-04-09 02:42:51Z bartoldeman $ +; + +; for OW on Linux: +%ifdef owlinux +%define WATCOM +%endif + +%ifdef WATCOM +%ifdef _INIT +%define WATCOM_INIT ; no seperate init segment for watcom. +%endif +%endif + +%ifndef WATCOM_INIT + + %include "segs.inc" + +%ifdef _INIT + + segment INIT_TEXT + %define FMEMCPYBACK INIT_FMEMCPYBACK + %define MEMCPY INIT_MEMCPY + %define FMEMCPY INIT_FMEMCPY + %define MEMSET INIT_MEMSET + %define FMEMSET INIT_FMEMSET + %define STRCPY INIT_STRCPY + %define FSTRCPY INIT_FSTRCPY + %define STRLEN INIT_STRLEN + %define FSTRLEN INIT_FSTRLEN + %define FMEMCHR INIT_FMEMCHR + %define FSTRCHR INIT_FSTRCHR + %define STRCHR INIT_STRCHR + %define FSTRCMP INIT_FSTRCMP + %define STRCMP INIT_STRCMP + %define FSTRNCMP INIT_FSTRNCMP + %define STRNCMP INIT_STRNCMP + %define FMEMCMP INIT_FMEMCMP + %define MEMCMP INIT_MEMCMP + +%else + + segment HMA_TEXT + +%endif + +;********************************************************************* +; this implements some of the common string handling functions +; +; every function has 1 entry +; +; NEAR FUNC() +; +; currently done: +; +; fmemcpyBack(void FAR *dest, void FAR *src, int count) +; memcpy(void *dest, void *src, int count) +; fmemcpy(void FAR *dest, void FAR *src, int count) +; memset(void *dest, int ch, int count); +; fmemset(void FAR *dest, int ch, int count); +; strcpy (void *dest, void *src); +; fstrcpy (void FAR*dest, void FAR *src); +; strlen (void *dest); +; fstrlen (void FAR*dest); +; fmemchr (BYTE FAR *src , int ch); +; fstrchr (BYTE FAR *src , int ch); +; strchr (BYTE *src , int ch); +; fstrcmp (BYTE FAR *s1 , BYTE FAR *s2); +; strcmp (BYTE *s1 , BYTE *s2); +; fstrncmp(BYTE FAR *s1 , BYTE FAR *s2, int count); +; strncmp(BYTE *s1 , BYTE *s2, int count); +; fmemcmp(BYTE FAR *s1 , BYTE FAR *s2, int count); +; memcmp(BYTE *s1 , BYTE *s2, int count); + +;*********************************************** +; pascal_setup - set up the standard calling frame for C-functions +; and save registers needed later +; also preload the args for the near functions +; di=arg1 +; si=arg2 +; cx=arg3 +; +pascal_setup: + pop ax ; get return address + + push bp ; Standard C entry + mov bp,sp +%ifdef WATCOM + push bx + push cx + push es +%endif + push si + push di + push ds + ; Set both ds and es to same segment (for near copy) + push ds + pop es + + ; Set direction to autoincrement + cld + + mov bl,6 ; majority (4) wants that + mov cx,[4+bp] ; majority (8) wants that (near and far) + mov si,[6+bp] ; majority (3) wants that (near) + mov di,[8+bp] ; majority (3) wants that (near) + + jmp ax + + + + +;*********************************************** +; +; VOID memcpy(REG BYTE *s, REG BYTE *d, REG COUNT n); +; + global MEMCPY +MEMCPY: + call pascal_setup + + ;mov cx,[4+bp] - preset above + ;mov si,[6+bp] - preset above + ;mov di,[8+bp] - preset above + + ;mov bl,6 - preset above + + +domemcpy: + ; And do the built-in byte copy, but do a 16-bit transfer + ; whenever possible. + shr cx,1 + rep movsw + jnc memcpy_return + movsb +memcpy_return: +%if 0 ; only needed for fmemcpyback + cld +%endif + +; +; pascal_return - pop saved registers and do return +; + + jmp short pascal_return + + + +;************************************************************ +; +; VOID fmemcpy(REG BYTE FAR *d, REG BYTE FAR *s,REG COUNT n); +; VOID fmemcpyBack(REG BYTE FAR *d, REG BYTE FAR *s,REG COUNT n); +; + global FMEMCPY +%if 0 + global FMEMCPYBACK +FMEMCPYBACK: + std ; force to copy the string in reverse order +%endif +FMEMCPY: + call pascal_setup + + ; Get the repetition count, n preset above + ; mov cx,[bp+4] + + ; Get the far source pointer, s + lds si,[bp+6] + + ; Get the far destination pointer d + les di,[bp+10] + mov bl,10 + + jmp short domemcpy + +;*************************************************************** +; +; VOID fmemset(REG VOID FAR *d, REG BYTE ch, REG COUNT n); +; + global FMEMSET +FMEMSET: + call pascal_setup + + ; Get the repetition count, n - preset above + ; mov cx,[bp+4] + + ; Get the fill byte ch + mov ax,[bp+6] + + ; Get the far source pointer, s + les di,[bp+8] + mov bl,8 + +domemset: + mov ah, al + + shr cx,1 + rep stosw + jnc pascal_return + stosb + + jmp short pascal_return + +;*************************************************************** +; +; VOID memset(REG VOID *d, REG BYTE ch, REG COUNT n); +; + global MEMSET +MEMSET: + call pascal_setup + + ; Get the repitition count, n - preset above + ; mov cx,[bp+4] + + ; Get the char ch + mov ax, [bp+6] + + ; Get the far source pointer, d - preset above + ; mov di,[bp+8] + + ;mov bl, 6 ; preset above + + jmp short domemset + +;***** +pascal_return: + lds di, [bp] ; return address in ds, saved bp in di + mov bh, 0 + add bp, bx ; point bp to "as if there were 0 args" + mov [bp+2], ds ; put return address at first arg + mov [bp], di ; saved bp below that one + + pop ds + pop di + pop si +%ifdef WATCOM + pop es + pop cx + pop bx +%endif + mov sp,bp + pop bp + ret + +;***************************************************************** + +; fstrcpy (void FAR*dest, void FAR *src); + +%ifndef _INIT + global FSTRCPY +FSTRCPY: + call pascal_setup + + ; Get the source pointer, ss + lds si,[bp+4] + + ; and the destination pointer, d + les di,[bp+8] + + mov bl,8 + + jmp short dostrcpy +%endif + +;****** + global STRCPY +STRCPY: + call pascal_setup + + + ; Get the source pointer, ss + mov si,[bp+4] + + ; and the destination pointer, d + mov di,[bp+6] + mov bl,4 + +dostrcpy: + +strcpy_loop: + lodsb + stosb + test al,al + jne strcpy_loop + + jmp short pascal_return + +;****************************************************************** +%ifndef _INIT + global FSTRLEN +FSTRLEN: + call pascal_setup + + ; Get the source pointer, ss + les di,[bp+4] + mov bl,4 + + jmp short dostrlen +%endif + +;********************************************** + global STRLEN +STRLEN: + call pascal_setup + ; Get the source pointer, ss + mov di,[bp+4] + mov bl,2 + +dostrlen: + mov al,0 + mov cx,0xffff + repne scasb + + mov ax,cx + not ax + dec ax + + jmp short pascal_return + +;************************************************************ +; strchr (BYTE *src , int ch); + + global STRCHR +STRCHR: + call pascal_setup + + ; Get the source pointer, ss + ; mov cx,[bp+4] - preset above + ; mov si,[bp+6] - preset above + mov bl,4 + +strchr_loop: + lodsb + cmp al,cl + je strchr_found + test al,al + jne strchr_loop + +strchr_retzero: + xor ax, ax ; return NULL if not found + mov dx, ax ; for fstrchr() + jmp short pascal_return + +strchr_found: + mov ax, si + mov dx, ds ; for fstrchr() +strchr_found1: + dec ax + + jmp short pascal_return + +%ifndef _INIT + +;***** +; fstrchr (BYTE far *src , int ch); + global FSTRCHR +FSTRCHR: + call pascal_setup + + ; Get ch (preset above) + ;mov cx, [bp+4] + + ;and the source pointer, src + lds si, [bp+6] + + ;mov bl, 6 - preset above + + jmp short strchr_loop + +;****** + global FMEMCHR +FMEMCHR: + call pascal_setup + + ; Get the length - preset above + ; mov cx, [bp+4] + + ; and the search value + mov ax, [bp+6] + + ; and the source pointer, ss + les di, [bp+8] + + mov bl, 8 + + jcxz strchr_retzero + repne scasb + jne strchr_retzero + mov dx, es + mov ax, di + jmp short strchr_found1 + +;********************************************************************** + global FSTRCMP +FSTRCMP: + call pascal_setup + + ; Get the source pointer, ss + lds si,[bp+4] + + ; and the destination pointer, d + les di,[bp+8] + + mov bl,8 + +%if 0 + jmp short dostrcmp + +;****** + global STRCMP +STRCMP: + call pascal_setup + + mov bl,4 + + ; Get the source pointer, ss + ; mov si,[bp+4] + + ; and the destination pointer, d + ; mov di,[bp+6] + xchg si,di + +dostrcmp: +%endif + ; replace strncmp(s1,s2)--> + ; strncmp(s1,s2,0xffff) + mov cx,0xffff +%if 0 + jmp short dostrncmp + + +;********************************************************************** + global FSTRNCMP +FSTRNCMP: + call pascal_setup + + ; Get the source pointer, ss + lds si,[bp+4] + + ; and the destination pointer, d + les di,[bp+8] + mov cx,[bp+12] + mov bl,10 + + jmp short dostrncmp + +;****** + global _strncmp +_strncmp: + call pascal_setup + + ; Get the source pointer, ss + ;mov si,[bp+4] + + ; and the destination pointer, d + ;mov di,[bp+6] + ;mov cx,[bp+8] + xchg si,di + +dostrncmp: +%endif + jcxz strncmp_retzero + +strncmp_loop: + lodsb + scasb + jne strncmp_done + test al,al + loopne strncmp_loop + jmp short strncmp_retzero +%endif + +;********************************************************************** +; fmemcmp(BYTE FAR *s1 , BYTE FAR *s2, int count); + global FMEMCMP +FMEMCMP: + call pascal_setup + + ; the length - preset above + ; mov cx, [bp+4] + + ; Get the source pointer, ss + les di,[bp+6] + + ; and the destination pointer, d + lds si,[bp+10] + + mov bl,10 + + jmp short domemcmp + +;****** +; memcmp(BYTE *s1 , BYTE *s2, int count); + global MEMCMP +MEMCMP: + call pascal_setup + + ; all preset: Get the source pointer, ss + ;mov si,[bp+6] + + ; and the destination pointer, d + ;mov di,[bp+8] + ;mov cx,[bp+4] + ;mov bl,6 + xchg si,di + +domemcmp: + jcxz strncmp_retzero + repe cmpsb + jne strncmp_done +strncmp_retzero: + xor ax, ax + jmp short strncmp_done2 +strncmp_done: + lahf + ror ah,1 +%ifdef _INIT +strncmp_done2: jmp short pascal_return +%else +strncmp_done2: jmp pascal_return +%endif + +%endif diff --git a/kernel/blockio.c b/kernel/blockio.c new file mode 100644 index 0000000..ae2e819 --- /dev/null +++ b/kernel/blockio.c @@ -0,0 +1,517 @@ +/****************************************************************/ +/* */ +/* blockio.c */ +/* DOS-C */ +/* */ +/* Block cache functions and device driver interface */ +/* */ +/* 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. */ +/* */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *blockioRcsId = + "$Id: blockio.c 1702 2012-02-04 08:46:16Z perditionc $"; +#endif + +#define b_next(bp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), bp->b_next))) +#define b_prev(bp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), bp->b_prev))) +#define bufptr(fbp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), fbp))) + +/************************************************************************/ +/* */ +/* block cache routines */ +/* */ +/************************************************************************/ +/* #define DISPLAY_GETBLOCK */ + +STATIC BOOL flush1(struct buffer FAR * bp); + +/* + this searches the buffer list for the given disk/block. + + returns: + a far pointer to the buffer. + + If the buffer is found the UNCACHE bit is not set and else it is set. + + new: + upper layer may set UNCACHE attribute + UNCACHE buffers are recycled first. + intended to be used for full sector reads into application buffer + resets UNCACHE upon a "HIT" -- so then this buffer will not be + recycled anymore. +*/ + +STATIC void move_buffer(struct buffer FAR *bp, size_t firstbp) +{ + /* connect bp->b_prev and bp->b_next */ + b_next(bp)->b_prev = bp->b_prev; + b_prev(bp)->b_next = bp->b_next; + + /* insert bp between firstbp and firstbp->b_prev */ + bp->b_prev = bufptr(firstbp)->b_prev; + bp->b_next = firstbp; + b_next(bp)->b_prev = FP_OFF(bp); + b_prev(bp)->b_next = FP_OFF(bp); +} + +STATIC struct buffer FAR *searchblock(ULONG blkno, COUNT dsk) +{ + int fat_count = 0; + struct buffer FAR *bp; + size_t lastNonFat = 0; + size_t uncacheBuf = 0; + seg bufseg = FP_SEG(firstbuf); + size_t firstbp = FP_OFF(firstbuf); + +#ifdef DISPLAY_GETBLOCK + printf("[searchblock %d, blk %ld, buf ", dsk, blkno); +#endif + + /* Search through buffers to see if the required block */ + /* is already in a buffer */ + + bp = MK_FP(bufseg, firstbp); + do + { + if ((bp->b_blkno == blkno) && + (bp->b_flag & BFR_VALID) && (bp->b_unit == dsk)) + { + /* found it -- rearrange LRU links */ +#ifdef DISPLAY_GETBLOCK + printf("HIT %04x:%04x]\n", FP_SEG(bp), FP_OFF(bp)); +#endif + bp->b_flag &= ~BFR_UNCACHE; /* reset uncache attribute */ + if (FP_OFF(bp) != firstbp) + { + *(UWORD *)&firstbuf = FP_OFF(bp); + move_buffer(bp, firstbp); + } + return bp; + } + + if (bp->b_flag & BFR_UNCACHE) + uncacheBuf = FP_OFF(bp); + + if (bp->b_flag & BFR_FAT) + fat_count++; + else + lastNonFat = FP_OFF(bp); + bp = b_next(bp); + } while (FP_OFF(bp) != firstbp); + + /* + now take either the last buffer in chain (not used recently) + or, if we are low on FAT buffers, the last non FAT buffer + */ + + if (uncacheBuf) + { + bp = bufptr(uncacheBuf); + } + else if (bp->b_flag & BFR_FAT && fat_count < 3 && lastNonFat) + { + bp = bufptr(lastNonFat); + } + else + { + bp = b_prev(bufptr(firstbp)); + } + + bp->b_flag |= BFR_UNCACHE; /* set uncache attribute */ + +#ifdef DISPLAY_GETBLOCK + printf("MISS, replace %04x:%04x]\n", FP_SEG(bp), FP_OFF(bp)); +#endif + + if (FP_OFF(bp) != firstbp) /* move to front */ + { + move_buffer(bp, firstbp); + *(UWORD *)&firstbuf = FP_OFF(bp); + } + return bp; +} + +BOOL DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mode) +{ + struct buffer FAR *bp = firstbuf; + + /* Search through buffers to see if the required block */ + /* is already in a buffer */ + + do + { + if (blknolow <= bp->b_blkno && + bp->b_blkno <= blknohigh && + (bp->b_flag & BFR_VALID) && (bp->b_unit == dsk)) + { + if (mode == XFR_READ) + flush1(bp); + else + bp->b_flag = 0; + } + bp = b_next(bp); + } + while (FP_OFF(bp) != FP_OFF(firstbuf)); + + return FALSE; +} + +#if TOM +void dumpBufferCache(void) +{ + struct buffer FAR *bp = firstbuf; + int printed = 0; + + /* Search through buffers to see if the required block */ + /* is already in a buffer */ + + do + { + printf("%8lx %02x ", bp->b_blkno, bp->b_flag); + if (++printed % 6 == 0) + printf("\n"); + bp = b_next(bp); + } + while (FP_OFF(bp) != FP_OFF(firstbuf)); + printf("\n"); +} +#endif +/* */ +/* Return the address of a buffer structure containing the */ +/* requested block. */ +/* if overwrite is set, then no need to read first */ +/* */ +/* returns: */ +/* requested block with data */ +/* failure: */ +/* returns NULL */ +/* */ +struct buffer FAR *getblk(ULONG blkno, COUNT dsk, BOOL overwrite) +{ + /* Search through buffers to see if the required block */ + /* is already in a buffer */ + + struct buffer FAR *bp = searchblock(blkno, dsk); + + if (!(bp->b_flag & BFR_UNCACHE)) + { + return bp; + } + + /* The block we need is not in a buffer, we must make a buffer */ + /* available, and fill it with the desired block */ + + /* take the buffer that lbp points to and flush it, then read new block. */ + if (!flush1(bp)) + return NULL; + + /* Fill the indicated disk buffer with the current track and sector */ + + if (!overwrite && dskxfer(dsk, blkno, bp->b_buffer, 1, DSKREAD)) + { + return NULL; + } + + bp->b_flag = BFR_VALID | BFR_DATA; + bp->b_unit = dsk; + bp->b_blkno = blkno; + + return bp; +} + +/* */ +/* Mark all buffers for a disk as not valid */ +/* */ +VOID setinvld(REG COUNT dsk) +{ + struct buffer FAR *bp = firstbuf; + + do + { + if (bp->b_unit == dsk) + bp->b_flag = 0; + bp = b_next(bp); + } + while (FP_OFF(bp) != FP_OFF(firstbuf)); +} + +/* Check if there is at least one dirty buffer */ +/* */ +BOOL dirty_buffers(REG COUNT dsk) +{ + struct buffer FAR *bp = firstbuf; + + do + { + if (bp->b_unit == dsk && + (bp->b_flag & (BFR_VALID | BFR_DIRTY)) == (BFR_VALID | BFR_DIRTY)) + return TRUE; + bp = b_next(bp); + } + while (FP_OFF(bp) != FP_OFF(firstbuf)); + return FALSE; +} + +/* */ +/* */ +/* Flush all buffers for a disk */ +/* */ +/* returns: */ +/* TRUE on success */ +/* */ +BOOL flush_buffers(REG COUNT dsk) +{ + struct buffer FAR *bp = firstbuf; + REG BOOL ok = TRUE; + + bp = firstbuf; + do + { + if (bp->b_unit == dsk) + if (!flush1(bp)) + ok = FALSE; + bp = b_next(bp); + } + while (FP_OFF(bp) != FP_OFF(firstbuf)); + return ok; +} + +/* */ +/* Write one disk buffer */ +/* */ +STATIC BOOL flush1(struct buffer FAR * bp) +{ + BOOL ok = TRUE; + + if ((bp->b_flag & (BFR_VALID | BFR_DIRTY)) == (BFR_VALID | BFR_DIRTY)) + { +#ifdef WITHFAT32 + ULONG b_offset = 0; +#else + UWORD b_offset = 0; +#endif + UBYTE b_copies = 1; + ULONG blkno = bp->b_blkno; + if (bp->b_flag & BFR_FAT) + { + b_copies = bp->b_copies; + b_offset = bp->b_offset; +#ifdef WITHFAT32 + if (b_offset == 0) /* FAT32 FS */ + b_offset = bp->b_dpbp->dpb_xfatsize; +#endif + } + while (b_copies--) + { + if (dskxfer(bp->b_unit, blkno, bp->b_buffer, 1, DSKWRITE)) + ok = FALSE; + blkno += b_offset; + } + } + bp->b_flag &= ~BFR_DIRTY; /* even if error, mark not dirty */ + if (!ok) /* otherwise system has trouble */ + bp->b_flag &= ~BFR_VALID; /* continuing. */ + return ok; +} + +/* */ +/* Write all disk buffers */ +/* */ +BOOL flush(void) +{ + REG struct buffer FAR *bp = firstbuf; + REG BOOL ok; + + ok = TRUE; + do + { + if (!flush1(bp)) + ok = FALSE; + bp->b_flag &= ~BFR_VALID; + bp = b_next(bp); + } + while (FP_OFF(bp) != FP_OFF(firstbuf)); + + network_redirector(REM_FLUSHALL); + + return (ok); +} + +/************************************************************************/ +/* */ +/* Device Driver Interface Functions */ +/* */ +/************************************************************************/ +/* */ +/* Transfer one or more blocks to/from disk */ +/* */ + +UWORD dskxfer(COUNT dsk, ULONG blkno, VOID FAR * buf, UWORD numblocks, + COUNT mode) +{ + register struct dpb FAR *dpbp = get_dpb(dsk); + if (dpbp == NULL) + { + return 0x0201; /* illegal command */ + } + +#if TOM +#define KeyboardShiftState() (*(BYTE FAR *)(MK_FP(0x40,0x17))) + + if (KeyboardShiftState() & 0x01) + { + printf("dskxfer:%s %x - %lx %u\n", mode == DSKWRITE ? "write" : "read", + dsk, blkno, numblocks); + if ((KeyboardShiftState() & 0x03) == 3) + dumpBufferCache(); + } +#endif + + for (;;) + { + IoReqHdr.r_length = sizeof(request); + IoReqHdr.r_unit = dpbp->dpb_subunit; + + switch (mode) + { + case DSKWRITE: + if (verify_ena) + { + IoReqHdr.r_command = C_OUTVFY; + break; + } + /* else fall through */ + case DSKWRITEINT26: + IoReqHdr.r_command = C_OUTPUT; + break; + + case DSKREADINT25: + case DSKREAD: + IoReqHdr.r_command = C_INPUT; + break; + default: + return 0x0100; /* illegal command */ + } + + IoReqHdr.r_status = 0; + IoReqHdr.r_meddesc = dpbp->dpb_mdb; + IoReqHdr.r_count = numblocks; + if ((dpbp->dpb_device->dh_attr & ATTR_HUGE) || blkno >= MAXSHORT) + { + IoReqHdr.r_start = HUGECOUNT; + IoReqHdr.r_huge = blkno; + } + else + IoReqHdr.r_start = (UWORD)blkno; + /* + * Some drivers normalise transfer address so HMA transfers are disastrous! + * Then transfer block through xferbuf (DiskTransferBuffer doesn't work!) + * (But this won't work for multi-block HMA transfers... are there any?) + */ + if (FP_SEG(buf) >= 0xa000 && numblocks == 1 && bufloc != LOC_CONV) + { + IoReqHdr.r_trans = deblock_buf; + if (mode == DSKWRITE) + fmemcpy(deblock_buf, buf, dpbp->dpb_secsize); + execrh((request FAR *) & IoReqHdr, dpbp->dpb_device); + if (mode == DSKREAD) + fmemcpy(buf, deblock_buf, dpbp->dpb_secsize); + } + else + { + IoReqHdr.r_trans = (BYTE FAR *) buf; + execrh((request FAR *) & IoReqHdr, dpbp->dpb_device); + } + if ((IoReqHdr.r_status & (S_ERROR | S_DONE)) == S_DONE) + break; + + /* INT25/26 (_SEEMS_ TO) return immediately with 0x8002, + if drive is not online,... + + normal operations (DIR) wait for ABORT/RETRY + + other condition codes not tested + */ + if (mode >= DSKWRITEINT26) + return (IoReqHdr.r_status); + + loop: + switch (block_error(&IoReqHdr, dpbp->dpb_unit, dpbp->dpb_device, mode)) + { + case ABORT: + case FAIL: + return (IoReqHdr.r_status); + + case RETRY: + continue; + + case CONTINUE: + break; + + default: + goto loop; + } + break; + } /* retry loop */ +/* *** Changed 9/4/00 BER */ + return 0; /* Success! Return 0 for a successful operation. */ +/* End of change */ + +} + +/* + this removes any (additionally allocated) buffers + from the HMA buffer chain, because they get allocated to the 'user' +*/ + +void AllocateHMASpace (size_t lowbuffer, size_t highbuffer) +{ + REG struct buffer FAR *bp = firstbuf; + int n; + + if (FP_SEG(bp) != 0xffff) + return; + + n = LoL_nbuffers; + do + { + /* check if buffer intersects with requested area */ + if (FP_OFF(bp) < highbuffer && FP_OFF(bp+1) > lowbuffer) + { + flush1(bp); + /* unlink bp from buffer chain */ + + b_prev(bp)->b_next = bp->b_next; + b_next(bp)->b_prev = bp->b_prev; + if (FP_OFF(bp) == FP_OFF(firstbuf)) + firstbuf = b_next(bp); + LoL_nbuffers--; + } + bp = b_next(bp); + } + while (--n); +} diff --git a/kernel/break.c b/kernel/break.c new file mode 100644 index 0000000..5396142 --- /dev/null +++ b/kernel/break.c @@ -0,0 +1,93 @@ +/****************************************************************/ +/* */ +/* break.c */ +/* FreeDOS */ +/* */ +/* Control Break detection and handling */ +/* */ +/* Copyright (c) 1999 */ +/* Steffen Kaiser */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" +#include "proto.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: break.c 885 2004-04-14 15:40:51Z bartoldeman $"; +#endif + +#define CB_FLG *(UBYTE FAR*)MK_FP(0x0, 0x471) +#define CB_MSK 0x80 + +/* Check for ^Break/^C. + * Three sources are available: + * 1) flag at 40:71 bit 7 + * 2) syscon stream (usually CON:) + * 3) i/o stream (if unequal to syscon, e.g. AUX) + */ + +unsigned char ctrl_break_pressed(void) +{ + return CB_FLG & CB_MSK; +} + +unsigned char check_handle_break(struct dhdr FAR **pdev) +{ + unsigned char c = CTL_C; + if (!ctrl_break_pressed()) + c = (unsigned char)ndread(&syscon); + if (c != CTL_C && *pdev != syscon) + c = (unsigned char)ndread(pdev); + if (c == CTL_C) + handle_break(pdev, -1); + return c; +} + +/* + * Handles a ^Break state + * + * Actions: + * 1) clear the ^Break flag + * 2) clear the STDIN stream + * 3) echo ^C to sft_out or pdev if sft_out==-1 + * 4) decrease the InDOS flag as the kernel drops back to user space + * 5) invoke INT-23 and never come back + */ + +void handle_break(struct dhdr FAR **pdev, int sft_out) +{ + char *buf = "^C\r\n"; + + CB_FLG &= ~CB_MSK; /* reset the ^Break flag */ + con_flush(pdev); + if (sft_out == -1) + cooked_write(pdev, 4, buf); + else + DosRWSft(sft_out, 4, buf, XFR_FORCE_WRITE); + if (!ErrorMode) /* within int21_handler, InDOS is not incremented */ + if (InDOS) + --InDOS; /* fail-safe */ + + spawn_int23(); /* invoke user INT-23 and never come back */ +} + diff --git a/kernel/chario.c b/kernel/chario.c new file mode 100644 index 0000000..afc30d3 --- /dev/null +++ b/kernel/chario.c @@ -0,0 +1,548 @@ +/****************************************************************/ +/* */ +/* chario.c */ +/* DOS-C */ +/* */ +/* Character device functions and device driver interface */ +/* */ +/* Copyright (c) 1994 */ +/* 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. */ +/* */ +/****************************************************************/ + +#include "portab.h" + +#ifdef VERSION_STRINGS +static BYTE *charioRcsId = + "$Id: chario.c 1413 2009-06-01 13:41:03Z bartoldeman $"; +#endif + +#include "globals.h" + +STATIC int CharRequest(struct dhdr FAR **pdev, unsigned command) +{ + struct dhdr FAR *dev = *pdev; + CharReqHdr.r_command = command; + CharReqHdr.r_unit = 0; + CharReqHdr.r_status = 0; + CharReqHdr.r_length = sizeof(request); + execrh(&CharReqHdr, dev); + if (CharReqHdr.r_status & S_ERROR) + { + for (;;) { + switch (char_error(&CharReqHdr, dev)) + { + case ABORT: + case FAIL: + return DE_INVLDACC; + case CONTINUE: + CharReqHdr.r_count = 0; + return 0; + case RETRY: + return 1; + } + } + } + return SUCCESS; +} + +long BinaryCharIO(struct dhdr FAR **pdev, size_t n, void FAR * bp, + unsigned command) +{ + int err; + do + { + CharReqHdr.r_count = n; + CharReqHdr.r_trans = bp; + err = CharRequest(pdev, command); + } while (err == 1); + return err == SUCCESS ? (long)CharReqHdr.r_count : err; +} + +STATIC int CharIO(struct dhdr FAR **pdev, unsigned char ch, unsigned command) +{ + int err = (int)BinaryCharIO(pdev, 1, &ch, command); + if (err == 0) + return 256; + if (err < 0) + return err; + return ch; +} + +/* STATE FUNCTIONS */ + +STATIC void CharCmd(struct dhdr FAR **pdev, unsigned command) +{ + while (CharRequest(pdev, command) == 1); +} + +STATIC int Busy(struct dhdr FAR **pdev) +{ + CharCmd(pdev, C_ISTAT); + return CharReqHdr.r_status & S_BUSY; +} + +void con_flush(struct dhdr FAR **pdev) +{ + CharCmd(pdev, C_IFLUSH); +} + +/* if the sft is invalid, then we just monitor syscon */ +struct dhdr FAR *sft_to_dev(sft FAR *s) +{ + if (FP_OFF(s) == (size_t) -1) + return syscon; + if (s->sft_flags & SFT_FDEVICE) + return s->sft_dev; + return NULL; +} + +int StdinBusy(void) +{ + sft FAR *s = get_sft(STDIN); + struct dhdr FAR *dev = sft_to_dev(s); + + if (dev) + return Busy(&dev); + + return s->sft_posit >= s->sft_size; +} + +/* get character from the console - this is how DOS gets + CTL_C/CTL_S/CTL_P when outputting */ +int ndread(struct dhdr FAR **pdev) +{ + CharCmd(pdev, C_NDREAD); + if (CharReqHdr.r_status & S_BUSY) + return -1; + return CharReqHdr.r_ndbyte; +} + +/* OUTPUT FUNCTIONS */ + +#ifdef __WATCOMC__ +void fast_put_char(char c); +#pragma aux fast_put_char = "int 29h" parm[al] modify exact [bx] +#else + +/* writes a character in raw mode using int29 for speed */ +STATIC void fast_put_char(unsigned char chr) +{ +#if defined(__TURBOC__) + _AL = chr; + __int__(0x29); +#elif defined(I86) + asm + { + mov al, byte ptr chr; + int 0x29; + } +#endif +} +#endif + +void update_scr_pos(unsigned char c, unsigned char count) +{ + unsigned char scrpos = scr_pos; + + if (c == CR) + scrpos = 0; + else if (c == BS) { + if (scrpos > 0) + scrpos--; + } else if (c != LF && c != BELL) { + scrpos += count; + } + scr_pos = scrpos; +} + +STATIC int raw_get_char(struct dhdr FAR **pdev, BOOL check_break); + +long cooked_write(struct dhdr FAR **pdev, size_t n, char FAR *bp) +{ + size_t xfer; + + /* bit 7 means fastcon; low 5 bits count number of characters */ + unsigned char fast_counter = ((*pdev)->dh_attr & ATTR_FASTCON) << 3; + + for (xfer = 0; xfer < n; xfer++) + { + int err; + unsigned char count = 1, c = *bp++; + + if (c == CTL_Z) + break; + + /* write a character in cooked mode; maybe with printer echo; + handles TAB expansion */ + if (c == HT) { + count = 8 - (scr_pos & 7); + c = ' '; + } + update_scr_pos(c, count); + do { + /* if not fast then < 0x80; always check + otherwise check every 32 characters */ + if (fast_counter <= 0x80 && check_handle_break(pdev) == CTL_S) + raw_get_char(pdev, TRUE); /* Test for hold char and ctl_c */ + fast_counter++; + fast_counter &= 0x9f; + if (PrinterEcho) + DosWrite(STDPRN, 1, &c); + if (fast_counter & 0x80) + fast_put_char(c); + else + { + err = CharIO(pdev, c, C_OUTPUT); + if (err < 0) + return err; + } + } while (--count != 0); + } + return xfer; +} + +/* writes character for disk file or device */ +void write_char(int c, int sft_idx) +{ + unsigned char ch = (unsigned char)c; + DosRWSft(sft_idx, 1, &ch, XFR_FORCE_WRITE); +} + +void write_char_stdout(int c) +{ + unsigned char count = 1; + unsigned flags = get_sft(STDOUT)->sft_flags; + + /* ah=2, ah=9 should expand tabs even for raw devices and disk files */ + if ((flags & (SFT_FDEVICE|SFT_FBINARY)) != SFT_FDEVICE) + { + if (c == HT) { + count = 8 - (scr_pos & 7); + c = ' '; + } + /* for raw CONOUT devices already updated in dosfns.c */ + if ((flags & (SFT_FDEVICE|SFT_FCONOUT)) != (SFT_FDEVICE|SFT_FCONOUT)) + update_scr_pos(c, count); + } + + do { + write_char(c, get_sft_idx(STDOUT)); + } while (--count != 0); +} + +#define iscntrl(c) ((unsigned char)(c) < ' ') + +/* this is for handling things like ^C, mostly used in echoed input */ +STATIC int echo_char(int c, int sft_idx) +{ + int out = c; + if (iscntrl(c) && c != HT && c != LF && c != CR) + { + write_char('^', sft_idx); + out += '@'; + } + write_char(out, sft_idx); + return c; +} + +STATIC void destr_bs(int sft_idx) +{ + write_char(BS, sft_idx); + write_char(' ', sft_idx); + write_char(BS, sft_idx); +} + +/* READ FUNCTIONS */ + +long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) +{ + unsigned xfer = 0; + int c; + while(n--) + { + c = raw_get_char(pdev, TRUE); + if (c < 0) + return c; + if (c == 256) + break; + *bp++ = c; + xfer++; + if ((unsigned char)c == CTL_Z) + break; + } + return xfer; +} + +STATIC unsigned char read_char_sft_dev(int sft_in, int sft_out, + struct dhdr FAR **pdev, + BOOL check_break) +{ + unsigned char c; + + if (*pdev) + { + FOREVER + { + if (ctrl_break_pressed()) + { + c = CTL_C; + break; + } + if (!Busy(pdev)) + { + c = CharIO(pdev, 0, C_INPUT); + break; + } + if (check_break && *pdev != syscon) + check_handle_break(&syscon); + /* the idle int is only safe if we're using the character stack */ + if (user_r->AH < 0xd) + DosIdle_int(); + } + } + else + DosRWSft(sft_in, 1, &c, XFR_READ); + + /* check for break or stop on sft_in, echo to sft_out */ + if (check_break && (c == CTL_C || c == CTL_S)) + { + if (c == CTL_S) + c = read_char_sft_dev(sft_in, sft_out, pdev, FALSE); + if (c == CTL_C) + handle_break(pdev, sft_out); + /* DOS oddity: if you press ^S somekey ^C then ^C does not break */ + c = read_char(sft_in, sft_out, FALSE); + } + return c; +} + +STATIC int raw_get_char(struct dhdr FAR **pdev, BOOL check_break) +{ + return read_char_sft_dev(-1, -1, pdev, check_break); +} + +unsigned char read_char(int sft_in, int sft_out, BOOL check_break) +{ + struct dhdr FAR *dev = sft_to_dev(idx_to_sft(sft_in)); + return read_char_sft_dev(sft_in, sft_out, &dev, check_break); +} + +STATIC unsigned char read_char_check_break(int sft_in, int sft_out) +{ + return read_char(sft_in, sft_out, TRUE); +} + +unsigned char read_char_stdin(BOOL check_break) +{ + return read_char(get_sft_idx(STDIN), get_sft_idx(STDOUT), check_break); +} + +/* reads a line (buffered, called by int21/ah=0ah, 3fh) */ +void read_line(int sft_in, int sft_out, keyboard FAR * kp) +{ + unsigned c; + unsigned cu_pos = scr_pos; + unsigned count = 0, stored_pos = 0; + unsigned size = kp->kb_size, stored_size = kp->kb_count; + BOOL insert = FALSE, first = TRUE; + + if (size == 0) + return; + + /* the stored line is invalid unless it ends with a CR */ + if (kp->kb_buf[stored_size] != CR) + stored_size = 0; + + do + { + unsigned new_pos = stored_size; + + c = read_char_check_break(sft_in, sft_out); + if (c == 0) + c = (unsigned)read_char_check_break(sft_in, sft_out) << 8; + switch (c) + { + case LF: + /* show LF if it's not the first character. Never store it */ + if (!first) + { + write_char(CR, sft_out); + write_char(LF, sft_out); + } + break; + + case CTL_F: + break; + + case RIGHT: + case F1: + if (stored_pos < stored_size && count < size - 1) + local_buffer[count++] = echo_char(kp->kb_buf[stored_pos++], sft_out); + break; + + case F2: + case F4: + /* insert/delete up to character c */ + { + unsigned char c2 = read_char_check_break(sft_in, sft_out); + new_pos = stored_pos; + if (c2 == 0) + { + read_char_check_break(sft_in, sft_out); + } + else + { + char FAR *sp = fmemchr(&kp->kb_buf[stored_pos], + c2, stored_size - stored_pos); + if (sp != NULL) + new_pos = (FP_OFF(sp) - FP_OFF(&kp->kb_buf[stored_pos])) + 1; + } + } + /* fall through */ + case F3: + if (c != F4) /* not delete */ + { + while (stored_pos < new_pos && count < size - 1) + local_buffer[count++] = echo_char(kp->kb_buf[stored_pos++], sft_out); + } + stored_pos = new_pos; + break; + + case F5: + fmemcpy(kp->kb_buf, local_buffer, count); + stored_size = count; + write_char('@', sft_out); + goto start_new_line; + + case INS: + insert = !insert; + break; + + case DEL: + stored_pos++; + break; + + case LEFT: + case CTL_BS: + case BS: + if (count > 0) + { + unsigned new_pos; + char c2 = local_buffer[--count]; + if (c2 == HT) + { + unsigned i; + new_pos = cu_pos; + for (i = 0; i < count; i++) + { + if (local_buffer[i] == HT) + new_pos = (new_pos + 8) & ~7; + else if (iscntrl(local_buffer[i])) + new_pos += 2; + else + new_pos++; + } + do + destr_bs(sft_out); + while (scr_pos > new_pos); + } + else + { + if (iscntrl(c2)) + destr_bs(sft_out); + destr_bs(sft_out); + } + } + if (stored_pos > 0) + stored_pos--; + break; + + case ESC: + write_char('\\', sft_out); + start_new_line: + write_char(CR, sft_out); + write_char(LF, sft_out); + for (count = 0; count < cu_pos; count++) + write_char(' ', sft_out); + count = 0; + stored_pos = 0; + insert = FALSE; + break; + + case F6: + c = CTL_Z; + /* fall through */ + + default: + if (count < size - 1 || c == CR) + local_buffer[count++] = echo_char(c, sft_out); + else + write_char(BELL, sft_out); + if (stored_pos < stored_size && !insert) + stored_pos++; + break; + } + first = FALSE; + } while (c != CR); + fmemcpy(kp->kb_buf, local_buffer, count); + /* if local_buffer overflows into the CON default buffer we + must invalidate it */ + if (count > LINEBUFSIZECON) + kb_buf.kb_size = 0; + /* kb_count does not include the final CR */ + kp->kb_count = count - 1; +} + +/* called by handle func READ (int21/ah=3f) */ +size_t read_line_handle(int sft_idx, size_t n, char FAR * bp) +{ + size_t chars_left; + + if (inputptr == NULL) + { + /* can we reuse kb_buf or was it overwritten? */ + if (kb_buf.kb_size != LINEBUFSIZECON) + { + kb_buf.kb_count = 0; + kb_buf.kb_size = LINEBUFSIZECON; + } + read_line(sft_idx, sft_idx, &kb_buf); + kb_buf.kb_buf[kb_buf.kb_count + 1] = echo_char(LF, sft_idx); + inputptr = kb_buf.kb_buf; + if (*inputptr == CTL_Z) + { + inputptr = NULL; + return 0; + } + } + + chars_left = &kb_buf.kb_buf[kb_buf.kb_count + 2] - inputptr; + if (n > chars_left) + n = chars_left; + + fmemcpy(bp, inputptr, n); + inputptr += n; + if (n == chars_left) + inputptr = NULL; + return n; +} + diff --git a/kernel/config.c b/kernel/config.c new file mode 100644 index 0000000..7e6b663 --- /dev/null +++ b/kernel/config.c @@ -0,0 +1,2568 @@ +/****************************************************************/ +/* */ +/* config.c */ +/* DOS-C */ +/* */ +/* config.sys Processing Functions */ +/* */ +/* Copyright (c) 1996 */ +/* 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, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +/****************************************************************/ + +#include "portab.h" +#include "init-mod.h" +#include "dyndata.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: config.c 1705 2012-02-07 08:10:33Z perditionc $"; +#endif + +#ifdef DEBUG +#define DebugPrintf(x) printf x +#else +#define DebugPrintf(x) +#endif +#define para2far(seg) ((mcb FAR *)MK_FP((seg), 0)) + +/** + Menu selection bar struct: + x pos, ypos, string +*/ +#define MENULINEMAX 80 +#define MENULINESMAX 10 +struct MenuSelector +{ + int x; + int y; + BYTE bSelected; + BYTE Text[MENULINEMAX]; +}; + +/** Structure below holds the menu-strings */ +STATIC struct MenuSelector MenuStruct[MENULINESMAX] BSS_INIT({0}); + +int nMenuLine BSS_INIT(0); +int MenuColor = -1; + +STATIC void WriteMenuLine(struct MenuSelector *menu) +{ + iregs r; + unsigned char attr = (unsigned char)MenuColor; + char *pText = menu->Text; + + if (pText[0] == 0) + return; + + if(menu->bSelected) + attr = ((attr << 4) | (attr >> 4)); + + /* clear line */ + r.a.x = 0x0600; + r.b.b.h = attr; + r.c.b.l = r.d.b.l = menu->x; + r.c.b.h = r.d.b.h = menu->y; + r.d.b.l += strlen(pText) - 1; + init_call_intr(0x10, &r); + + /* set cursor position: */ + r.a.b.h = 0x02; + r.b.b.h = 0; + r.d.b.l = menu->x; + r.d.b.h = menu->y; + init_call_intr(0x10, &r); + + printf("%s", pText); +} + +/* Deselect the previously selected line */ +STATIC void DeselectLastLine(void) +{ + struct MenuSelector *menu; + for (menu = MenuStruct; menu < &MenuStruct[MENULINESMAX]; menu++) + { + if (menu->bSelected) + { + /* deselect it: */ + menu->bSelected = 0; + WriteMenuLine(menu); + break; + } + } +} + +STATIC void SelectLine(int MenuSelected) +{ + struct MenuSelector *menu; + + DeselectLastLine(); /* clear previous selection */ + menu = &MenuStruct[MenuSelected]; + menu->bSelected = 1; /* set selection flag for this one */ + WriteMenuLine(menu); +} + +UWORD umb_start BSS_INIT(0), UMB_top BSS_INIT(0); +UWORD ram_top BSS_INIT(0); /* How much ram in Kbytes */ +size_t ebda_size BSS_INIT(0); + +static UBYTE ErrorAlreadyPrinted[128] BSS_INIT({0}); + +char master_env[128] BSS_INIT({0}); +static char *envp = master_env; + +struct config Config = { + 0, + NUMBUFF, + NFILES, + 0, + NFCBS, + 0, + "command.com", + " /P /E:256\r\n", + NLAST, + 0, + NSTACKS, + 0, + STACKSIZE + /* COUNTRY= is initialized within DoConfig() */ + , 0 /* strategy for command.com is low by default */ + , 0 /* default value for switches=/E:nnnn */ +}; + +STATIC seg base_seg BSS_INIT(0); +STATIC seg umb_base_seg BSS_INIT(0); +BYTE FAR *lpTop BSS_INIT(0); +STATIC unsigned nCfgLine BSS_INIT(0); +COUNT UmbState BSS_INIT(0); +STATIC BYTE szLine[256] BSS_INIT({0}); +STATIC BYTE szBuf[256] BSS_INIT({0}); + +BYTE singleStep BSS_INIT(FALSE); /* F8 processing */ +BYTE SkipAllConfig BSS_INIT(FALSE); /* F5 processing */ +BYTE askThisSingleCommand BSS_INIT(FALSE); /* ?device= device?= */ +BYTE DontAskThisSingleCommand BSS_INIT(FALSE); /* !files= */ + +COUNT MenuTimeout = -1; +BYTE MenuSelected BSS_INIT(0); +UCOUNT MenuLine BSS_INIT(0); +UCOUNT Menus BSS_INIT(0); + +STATIC VOID CfgMenuColor(BYTE * pLine); + +STATIC VOID Config_Buffers(BYTE * pLine); +STATIC VOID CfgBuffersHigh(BYTE * pLine); +STATIC VOID sysScreenMode(BYTE * pLine); +STATIC VOID sysVersion(BYTE * pLine); +STATIC VOID CfgBreak(BYTE * pLine); +STATIC VOID Device(BYTE * pLine); +STATIC VOID DeviceHigh(BYTE * pLine); +STATIC VOID Files(BYTE * pLine); +STATIC VOID FilesHigh(BYTE * pLine); +STATIC VOID Fcbs(BYTE * pLine); +STATIC VOID CfgKeyBuf(BYTE * pLine); +STATIC VOID CfgLastdrive(BYTE * pLine); +STATIC VOID CfgLastdriveHigh(BYTE * pLine); +STATIC BOOL LoadDevice(BYTE * pLine, char FAR *top, COUNT mode); +STATIC VOID Dosmem(BYTE * pLine); +STATIC VOID DosData(BYTE * pLine); +STATIC VOID Country(BYTE * pLine); +STATIC VOID InitPgm(BYTE * pLine); +STATIC VOID InitPgmHigh(BYTE * pLine); +STATIC VOID CmdInstall(BYTE * pLine); +STATIC VOID CmdInstallHigh(BYTE * pLine); +STATIC VOID CmdSet(BYTE * pLine); + + +STATIC VOID CfgSwitchar(BYTE * pLine); +STATIC VOID CfgSwitches(BYTE * pLine); +STATIC VOID CfgFailure(BYTE * pLine); +STATIC VOID CfgIgnore(BYTE * pLine); +STATIC VOID CfgMenu(BYTE * pLine); + +STATIC VOID CfgMenuEsc(BYTE * pLine); + +STATIC VOID DoMenu(void); +STATIC VOID CfgMenuDefault(BYTE * pLine); +STATIC BYTE * skipwh(BYTE * s); +STATIC BYTE * scan(BYTE * s, BYTE * d); +STATIC BOOL isnum(char ch); +#if 0 +STATIC COUNT tolower(COUNT c); +#endif +STATIC char toupper(char c); +STATIC VOID strupr(char *s); +STATIC VOID mcb_init(UCOUNT seg, UWORD size, BYTE type); +STATIC VOID mumcb_init(UCOUNT seg, UWORD size); + +STATIC VOID Stacks(BYTE * pLine); +STATIC VOID StacksHigh(BYTE * pLine); + +STATIC VOID SetAnyDos(BYTE * pLine); +STATIC VOID SetIdleHalt(BYTE * pLine); +STATIC VOID Numlock(BYTE * pLine); +STATIC BYTE * GetNumArg(BYTE * pLine, COUNT * pnArg); +BYTE *GetStringArg(BYTE * pLine, BYTE * pszString); +STATIC int SkipLine(char *pLine); +#if 0 +STATIC char * stristr(char *s1, char *s2); +#endif +STATIC char strcaseequal(const char * d, const char * s); +STATIC int LoadCountryInfoHardCoded(COUNT ctryCode); +STATIC void umb_init(void); + +void HMAconfig(int finalize); +STATIC void config_init_buffers(int anzBuffers); /* from BLOCKIO.C */ + +#ifdef I86 +STATIC VOID FAR * AlignParagraph(VOID FAR * lpPtr); +#else +#define AlignParagraph(x) ((VOID *)x) +#endif + +#define EOF 0x1a + +STATIC struct table * LookUp(struct table *p, BYTE * token); + +typedef void config_sys_func_t(BYTE * pLine); + +struct table { + BYTE *entry; + signed char pass; + config_sys_func_t *func; +}; + +STATIC struct table commands[] = { + /* first = switches! this one is special since it is asked for but + also checked before F5/F8 */ + {"SWITCHES", 0, CfgSwitches}, + + /* rem is never executed by locking out pass */ + {"REM", 0, CfgIgnore}, + {";", 0, CfgIgnore}, + + {"MENUCOLOR",0,CfgMenuColor}, + + {"MENUDEFAULT", 0, CfgMenuDefault}, + {"MENU", 0, CfgMenu}, /* lines to print in pass 0 */ + {"ECHO", 2, CfgMenu}, /* lines to print in pass 2 - install(high) */ + {"EECHO", 2, CfgMenuEsc}, /* modified ECHO (ea) */ + + {"BREAK", 1, CfgBreak}, + {"BUFFERS", 1, Config_Buffers}, + {"BUFFERSHIGH", 1, CfgBuffersHigh}, /* as BUFFERS - we use HMA anyway */ + {"COMMAND", 1, InitPgm}, + {"COUNTRY", 1, Country}, + {"DOS", 1, Dosmem}, + {"DOSDATA", 1, DosData}, + {"FCBS", 1, Fcbs}, + {"KEYBUF", 1, CfgKeyBuf}, /* ea */ + {"FILES", 1, Files}, + {"FILESHIGH", 1, FilesHigh}, + {"LASTDRIVE", 1, CfgLastdrive}, + {"LASTDRIVEHIGH", 1, CfgLastdriveHigh}, + {"NUMLOCK", 1, Numlock}, + {"SHELL", 1, InitPgm}, + {"SHELLHIGH", 1, InitPgmHigh}, + {"STACKS", 1, Stacks}, + {"STACKSHIGH", 1, StacksHigh}, + {"SWITCHAR", 1, CfgSwitchar}, + {"SCREEN", 1, sysScreenMode}, /* JPP */ + {"VERSION", 1, sysVersion}, /* JPP */ + {"ANYDOS", 1, SetAnyDos}, /* tom */ + {"IDLEHALT", 1, SetIdleHalt}, /* ea */ + + {"DEVICE", 2, Device}, + {"DEVICEHIGH", 2, DeviceHigh}, + {"INSTALL", 2, CmdInstall}, + {"INSTALLHIGH", 2, CmdInstallHigh}, + {"SET", 2, CmdSet}, + + /* default action */ + {"", -1, CfgFailure} +}; + +/* RE function for menu. */ +int findend(BYTE * s) +{ + int nLen = 0; + /* 'marks' end if at least ten spaces, 0, or newline is found. */ + while (*s && (*s != 0x0d || *s != 0x0a) ) + { + BYTE *p= skipwh(s); + /* ah, more than 9 whitespaces ? We're done here (hrmph!) */ + if(p - s >= 10) + break; + nLen++; + ++s; + } + return nLen; +} + +BYTE *pLineStart BSS_INIT(0); + +BYTE HMAState BSS_INIT(0); +#define HMA_NONE 0 /* do nothing */ +#define HMA_REQ 1 /* DOS = HIGH detected */ +#define HMA_DONE 2 /* Moved kernel to HMA */ +#define HMA_LOW 3 /* Definitely LOW */ + +/* Do first time initialization. Store last so that we can reset it */ +/* later. */ +void PreConfig(void) +{ + /* Initialize the base memory pointers */ + +#ifdef DEBUG + { + printf("SDA located at 0x%p\n", internal_data); + } +#endif + /* Begin by initializing our system buffers */ +#ifdef DEBUG +/* printf("Preliminary %d buffers allocated at 0x%p\n", Config.cfgBuffers, buffers);*/ +#endif + + LoL->DPBp = + DynAlloc("DPBp", blk_dev.dh_name[0], sizeof(struct dpb)); + + LoL->sfthead = MK_FP(FP_SEG(LoL), 0xcc); /* &(LoL->firstsftt) */ + /* LoL->FCBp = (sfttbl FAR *)&FcbSft; */ + /* LoL->FCBp = (sfttbl FAR *) + KernelAlloc(sizeof(sftheader) + + Config.cfgFiles * sizeof(sft)); */ + + config_init_buffers(Config.cfgBuffers); + + LoL->CDSp = KernelAlloc(sizeof(struct cds) * LoL->lastdrive, 'L', 0); + +#ifdef DEBUG +/* printf(" FCB table 0x%p\n",LoL->FCBp);*/ + printf(" sft table 0x%p\n", LoL->sfthead); + printf(" CDS table 0x%p\n", LoL->CDSp); + printf(" DPB table 0x%p\n", LoL->DPBp); +#endif + + /* Done. Now initialize the MCB structure */ + /* This next line is 8086 and 80x86 real mode specific */ +#ifdef DEBUG + printf("Preliminary allocation completed: top at %p\n", lpTop); +#endif +} + +/* Do second pass initialization: near allocation and MCBs */ +void PreConfig2(void) +{ + struct sfttbl FAR *sp; + + /* initialize NEAR allocated things */ + + /* Initialize the base memory pointers from last time. */ + /* + if the kernel could be moved to HMA, everything behind the dynamic + near data is free. + otherwise, the kernel is moved down - behind the dynamic allocated data, + and allocation starts after the kernel. + */ + + base_seg = LoL->first_mcb = FP_SEG(AlignParagraph((BYTE FAR *) DynLast() + 0x0f)); + + if (Config.ebda2move) + { + ebda_size = ebdasize(); + ram_top += ebda_size / 1024; + if (ebda_size > Config.ebda2move) + ebda_size = Config.ebda2move; + } + + /* We expect ram_top as Kbytes, so convert to paragraphs */ + mcb_init(base_seg, ram_top * 64 - LoL->first_mcb - 1, MCB_LAST); + + sp = LoL->sfthead; + sp = sp->sftt_next = KernelAlloc(sizeof(sftheader) + 3 * sizeof(sft), 'F', 0); + sp->sftt_next = (sfttbl FAR *) - 1; + sp->sftt_count = 3; + + if (ebda_size) /* move the Extended BIOS Data Area from top of RAM here */ + movebda(ebda_size, FP_SEG(KernelAlloc(ebda_size, 'I', 0))); + + if (UmbState == 2) + umb_init(); +} + +/* Do third pass initialization. */ +/* Also, run config.sys to load drivers. */ +void PostConfig(void) +{ + sfttbl FAR *sp; + + /* We could just have loaded FDXMS or HIMEM */ + if (HMAState == HMA_REQ && MoveKernelToHMA()) + HMAState = HMA_DONE; + + if (Config.cfgDosDataUmb) + { + Config.cfgFilesHigh = TRUE; + Config.cfgLastdriveHigh = TRUE; + Config.cfgStacksHigh = TRUE; + } + + /* compute lastdrive ... */ + LoL->lastdrive = Config.cfgLastdrive; + if (LoL->lastdrive < LoL->nblkdev) + LoL->lastdrive = LoL->nblkdev; + + DebugPrintf(("starting FAR allocations at %x\n", base_seg)); + + /* Begin by initializing our system buffers */ + /* dma_scratch = (BYTE FAR *) KernelAllocDma(BUFFERSIZE); */ +#ifdef DEBUG + /* printf("DMA scratchpad allocated at 0x%p\n", dma_scratch); */ +#endif + + config_init_buffers(Config.cfgBuffers); + +/* LoL->sfthead = (sfttbl FAR *)&basesft; */ + /* LoL->FCBp = (sfttbl FAR *)&FcbSft; */ + /* LoL->FCBp = KernelAlloc(sizeof(sftheader) + + Config.cfgFiles * sizeof(sft)); */ + sp = LoL->sfthead->sftt_next; + sp = sp->sftt_next = (sfttbl FAR *) + KernelAlloc(sizeof(sftheader) + (Config.cfgFiles - 8) * sizeof(sft), 'F', + Config.cfgFilesHigh); + sp->sftt_next = (sfttbl FAR *) - 1; + sp->sftt_count = Config.cfgFiles - 8; + + LoL->CDSp = KernelAlloc(sizeof(struct cds) * LoL->lastdrive, 'L', Config.cfgLastdriveHigh); + +#ifdef DEBUG +/* printf(" FCB table 0x%p\n",LoL->FCBp);*/ + printf(" sft table 0x%p\n", LoL->sfthead->sftt_next); + printf(" CDS table 0x%p\n", LoL->CDSp); + printf(" DPB table 0x%p\n", LoL->DPBp); +#endif + if (Config.cfgStacks) + { + VOID FAR *stackBase = + KernelAlloc(Config.cfgStacks * Config.cfgStackSize, 'S', + Config.cfgStacksHigh); + init_stacks(stackBase, Config.cfgStacks, Config.cfgStackSize); + + DebugPrintf(("Stacks allocated at %p\n", stackBase)); + } + DebugPrintf(("Allocation completed: top at 0x%x\n", base_seg)); + +} + +/* This code must be executed after device drivers has been loaded */ +VOID configDone(VOID) +{ + if (UmbState == 1) + para2far(base_seg)->m_type = MCB_LAST; + + if (HMAState != HMA_DONE) + { + mcb FAR *p; + unsigned short kernel_seg; + unsigned short hma_paras = (HMAFree+0xf)/16; + + kernel_seg = allocmem(hma_paras); + p = para2far(kernel_seg - 1); + + p->m_name[0] = 'S'; + p->m_name[1] = 'C'; + p->m_psp = 8; + + DebugPrintf(("HMA not available, moving text to %x\n", kernel_seg)); + MoveKernel(kernel_seg); + + kernel_seg += hma_paras + 1; + + DebugPrintf(("kernel is low, start alloc at %x", kernel_seg)); + } + + /* The standard handles should be reopened here, because + we may have loaded new console or printer drivers in CONFIG.SYS */ +} + +STATIC seg prev_mcb(seg cur_mcb, seg start) +{ + /* determine prev mcb */ + seg mcb_prev, mcb_next; + mcb_prev = mcb_next = start; + while (mcb_next < cur_mcb && para2far(mcb_next)->m_type == MCB_NORMAL) + { + mcb_prev = mcb_next; + mcb_next += para2far(mcb_prev)->m_size + 1; + } + return mcb_prev; +} + +STATIC void umb_init(void) +{ + UCOUNT umb_seg, umb_size; + seg umb_max; + void far *xms_addr; + + if ((xms_addr = DetectXMSDriver()) == NULL) + return; + + if (UMB_get_largest(xms_addr, &umb_seg, &umb_size)) + { + UmbState = 1; + + /* reset root */ + LoL->uppermem_root = ram_top * 64 - 1; + + /* create link mcb (below) */ + para2far(base_seg)->m_type = MCB_NORMAL; + para2far(base_seg)->m_size--; + mumcb_init(LoL->uppermem_root, umb_seg - LoL->uppermem_root - 1); + + /* setup the real mcb for the devicehigh block */ + mcb_init(umb_seg, umb_size - 2, MCB_NORMAL); + + umb_base_seg = umb_max = umb_start = umb_seg; + UMB_top = umb_size; + + /* there can be more UMBs ! + this happens, if memory mapped devces are in between + like UMB memory c800..c8ff, d8ff..efff with device at d000..d7ff + However some of the xxxHIGH commands still only work with + the first UMB. + */ + + while (UMB_get_largest(xms_addr, &umb_seg, &umb_size)) + { + seg umb_prev, umb_next; + + /* setup the real mcb for the devicehigh block */ + mcb_init(umb_seg, umb_size - 2, MCB_NORMAL); + + /* determine prev and next umbs */ + umb_prev = prev_mcb(umb_seg, LoL->uppermem_root); + umb_next = umb_prev + para2far(umb_prev)->m_size + 1; + + if (umb_seg < umb_max) + { + if (umb_next - umb_seg - umb_size == 0) + { + /* should the UMB driver return + adjacent memory in several pieces */ + umb_size += para2far(umb_next)->m_size + 1; + para2far(umb_seg)->m_size = umb_size; + } + else + { + /* create link mcb (above) */ + mumcb_init(umb_seg + umb_size - 1, umb_next - umb_seg - umb_size); + } + } + else /* umb_seg >= umb_max */ + { + umb_prev = umb_next; + } + + if (umb_seg - umb_prev - 1 == 0) + /* should the UMB driver return + adjacent memory in several pieces */ + para2far(prev_mcb(umb_prev, LoL->uppermem_root))->m_size += umb_size; + else + { + /* create link mcb (below) */ + mumcb_init(umb_prev, umb_seg - umb_prev - 1); + } + + if (umb_seg > umb_max) + umb_max = umb_seg; + } + para2far(umb_max)->m_size++; + para2far(umb_max)->m_type = MCB_LAST; + DebugPrintf(("UMB Allocation completed: start at 0x%x\n", umb_base_seg)); + } +} + +#ifdef MEMDISK_ARGS +struct memdiskinfo { + UWORD bytes; /* Total size of this structure, value >= 26 */ + UBYTE version_minor; /* Memdisk minor version */ + UBYTE version; /* Memdisk major version */ + UDWORD base; /* Pointer to disk data in high memory */ + UDWORD size; /* Size of disk in 512 byte sectors */ + char FAR * cmdline; /* Command line */ + ADDRESS oldint13; /* Old INT 13h */ + ADDRESS oldint15; /* Old INT 15h */ + UWORD olddosmem; /* Amount of DOS memory before Memdisk loaded */ + UBYTE boot_id; /* major >= 3, boot loader ID */ + UBYTE unused; + UWORD DPT_offset; /* >= 3.71, ES based offset to installed DPT, +16 is Old INT 1Eh */ +}; + +/* query_memdisk() based on similar subroutine in Eric Auer's public domain getargs.asm which is based on IFMEMDSK */ +struct memdiskinfo FAR * ASMCFUNC query_memdisk(UBYTE drive); +#endif + + +VOID DoConfig(int nPass) +{ + COUNT nFileDesc; + BYTE *pLine; + BOOL bEof; + + +#ifdef MEMDISK_ARGS + /* check if MEMDISK used for LoL->BootDrive, if so check for special appended arguments */ + struct memdiskinfo FAR *mdsk; + BYTE FAR *mdsk_cfg = NULL; + /* memdisk check & usage requires 386+, DO NOT invoke if less than 386 */ + if (LoL->cpu >= 3) + { + UBYTE drv = (LoL->BootDrive < 3)?0x0:0x80; /* 1=A,2=B,3=C */ + mdsk = query_memdisk(drv); + } +#endif + + if (nPass==0) + { + HaltCpuWhileIdle = 0; /* init to "no HLT while idle" */ + +#ifdef MEMDISK_ARGS + if (mdsk != NULL) + { + printf("MEMDISK version %u.%02u (%lu sectors)\n", mdsk->version, mdsk->version_minor, mdsk->size); + DebugPrintf(("MEMDISK args:{%S} bootdrive=[%0Xh]\n", mdsk->cmdline, (unsigned int)drv)); + } +#endif + } + +#ifdef MEMDISK_ARGS + if (mdsk != NULL) + { + /* scan for FD= */ + /* when done mdsk->cmdline points to { character or assume no valid CONFIG options */ + for (mdsk_cfg=mdsk->cmdline; *mdsk_cfg; ++mdsk_cfg) + { + if (*mdsk_cfg != ' ') continue; + ++mdsk_cfg; + if (*mdsk_cfg != 'F') goto goback1; + ++mdsk_cfg; + if (*mdsk_cfg != 'D') goto goback2; + ++mdsk_cfg; + if (*mdsk_cfg != '=') goto goback3; + ++mdsk_cfg; + break; + + goback3: + --mdsk_cfg; + goback2: + --mdsk_cfg; + goback1: + --mdsk_cfg; + } + /* if FD= was not found then flag as no extra CONFIG lines */ + if (!*mdsk_cfg) mdsk_cfg = NULL; + } + else + { + DebugPrintf(("MEMDISK not detected! bootdrive=[%0Xh]\n", (unsigned int)drv)); + } +#endif + + + /* Check to see if we have a config.sys file. If not, just */ + /* exit since we don't force the user to have one (but 1st */ + /* also process MEMDISK passed config options if present). */ + if ((nFileDesc = open("fdconfig.sys", 0)) >= 0) + { + DebugPrintf(("Reading FDCONFIG.SYS...\n")); + } + else + { + DebugPrintf(("FDCONFIG.SYS not found\n")); + if ((nFileDesc = open("config.sys", 0)) < 0) + { + DebugPrintf(("CONFIG.SYS not found\n")); +#ifdef MEMDISK_ARGS + if (mdsk_cfg != NULL) + bEof = TRUE; + else +#endif + return; + } + else + { + DebugPrintf(("Reading CONFIG.SYS...\n")); + } + } + + /* Have one -- initialize. */ + nCfgLine = 0; + bEof = 0; + pLine = szLine; + + /* Read each line into the buffer and then parse the line, */ + /* do the table lookup and execute the handler for that */ + /* function. */ + +#ifdef MEMDISK_ARGS + for (; !bEof || (mdsk_cfg != NULL); nCfgLine++) +#else + for (; !bEof; nCfgLine++) +#endif + { + struct table *pEntry; + + pLineStart = szLine; + + +#ifdef MEMDISK_ARGS + if (!bEof) + { +#endif + + /* read in a single line, \n or ^Z terminated */ + + for (pLine = szLine;;) + { + if (read(nFileDesc, pLine, 1) == 0) + { + bEof = TRUE; + break; + } + + if (pLine >= szLine + sizeof(szLine) - 3) + { + CfgFailure(pLine); + printf("error - line overflow line %d \n", nCfgLine); + break; + } + + if (*pLine == '\n' || *pLine == EOF) /* end of line */ + break; + + if (*pLine != '\r') /* ignore CR */ + pLine++; + } + +#ifdef MEMDISK_ARGS + } + else if (mdsk_cfg != NULL) + { + pLine = szLine; + /* copy data to near buffer skipping { and } */ + if (*mdsk_cfg != '{') /* if not at start of line */ + { + mdsk_cfg = NULL; /* no longer need data, so set to NULL to flag done */ + } + else + { + for (pLine = szLine, mdsk_cfg++; *mdsk_cfg; mdsk_cfg++, pLine++) + { + /* copy character to near buffer */ + *pLine = *mdsk_cfg; + + /* ensure we don't copy too much, exceed our buffer size */ + if (pLine >= szLine + sizeof(szLine) - 3) + { + CfgFailure(pLine); + printf("error - line overflow line %d \n", nCfgLine); + break; + } + + /* if end of this simulated line is found, skip over EOL marker then proceed to process line */ + if (*pLine == '}') + { + mdsk_cfg++; + break; + } + } + } + } +#endif + + *pLine = 0; + pLine = szLine; + + DebugPrintf(("CONFIG=[%s]\n", pLine)); + + /* Skip leading white space and get verb. */ + pLine = scan(pLine, szBuf); + + /* If the line was blank, skip it. Otherwise, look up */ + /* the verb and execute the appropriate function. */ + if (*szBuf == '\0') + continue; + + pEntry = LookUp(commands, szBuf); + + if (pEntry->pass >= 0 && pEntry->pass != nPass) + continue; + + if (nPass == 0) /* pass 0 always executed (rem Menu prompt switches) */ + { + pEntry->func(pLine); + continue; + } + else + { + if (SkipLine(pLineStart)) /* F5/F8 processing */ + continue; + } + + if ((pEntry->func != CfgMenu) && (pEntry->func != CfgMenuEsc)) + { + /* compatibility "device foo.sys" */ + if (' ' != *pLine && '\t' != *pLine && '=' != *pLine) + { + CfgFailure(pLine); + continue; + } + pLine = skipwh(pLine); + } + if ('=' == *pLine || pEntry->func == CfgMenu || pEntry->func == CfgMenuEsc) + pLine = skipwh(pLine+1); + + /* YES. DO IT */ + pEntry->func(pLine); + } + close(nFileDesc); + + if (nPass == 0) + { + DoMenu(); + } +} + +STATIC struct table * LookUp(struct table *p, BYTE * token) +{ + while (p->entry[0] != '\0' && !strcaseequal(p->entry, token)) + ++p; + return p; +} + +/* + get BIOS key with timeout: + + timeout < 0: no timeout + timeout = 0: poll only once + timeout > 0: timeout in seconds + + return + 0xffff : no key hit + + 0xHH.. : scancode in upper half + 0x..LL : asciicode in lower half +*/ +#define GetBiosTime() peekl(0, 0x46c) + +UWORD GetBiosKey(int timeout) +{ + iregs r; + + ULONG startTime = GetBiosTime(); + + if (timeout >= 0) + { + do + { + /* optionally HLT here - timer will IRQ even if no keypress */ + r.a.x = 0x0100; /* are there keys available ? */ + init_call_intr(0x16, &r); + if (!(r.flags & FLG_ZERO)) { + r.a.x = 0x0000; + init_call_intr(0x16, &r); /* there is a key, so better fetch it! */ + return r.a.x; + } + } while ((unsigned)(GetBiosTime() - startTime) < timeout * 18u); + return 0xffff; + } + + /* blocking wait (timeout < 0): fetch it */ +#if 0 + do { + /* optionally HLT here */ + r.a.x = 0x0100; + init_call_intr(0x16, &r); + } while (r.flags & FLG_ZERO); +#endif + r.a.x = 0x0000; + init_call_intr(0x16, &r); + return r.a.x; +} + +STATIC BOOL SkipLine(char *pLine) +{ + short key; + + if (InitKernelConfig.SkipConfigSeconds >= 0) + { + + if (InitKernelConfig.SkipConfigSeconds > 0) + printf("Press F8 to trace or F5 to skip CONFIG.SYS/AUTOEXEC.BAT"); + + key = GetBiosKey(InitKernelConfig.SkipConfigSeconds); /* wait 2 seconds */ + + InitKernelConfig.SkipConfigSeconds = -1; + + if (key == 0x3f00) /* F5 */ + { + SkipAllConfig = TRUE; + } + else if (key == 0x4200) /* F8 */ + { + singleStep = TRUE; + } + + printf("\r%79s\r", ""); /* clear line */ + + if (SkipAllConfig) + printf("Skipping CONFIG.SYS/AUTOEXEC.BAT\n"); + } + + if (SkipAllConfig) + return TRUE; + + /* 1?device=CDROM.SYS */ + /* 12?device=OAKROM.SYS */ + /* 123?device=EMM386.EXE NOEMS */ + if ( MenuLine != 0 && + (MenuLine & (1 << MenuSelected)) == 0) + return TRUE; + + if (DontAskThisSingleCommand) /* !files=30 */ + return FALSE; + + if (!askThisSingleCommand && !singleStep) + return FALSE; + + printf("%s[Y,N]?", pLine); + + for (;;) + { + key = GetBiosKey(-1); + + switch (toupper(key & 0x00ff)) + { + case 'N': + printf("N\n"); + return TRUE; + + case 0x1b: /* don't know where documented + ESCAPE answers all following questions + with YES + */ + singleStep = FALSE; /* and fall through */ + + case '\r': + case '\n': + case 'Y': + printf("Y\n"); + return FALSE; + + } + + if (key == 0x3f00) /* YES, you may hit F5 here, too */ + { + printf("N\n"); + SkipAllConfig = TRUE; + return TRUE; + } + } + +} + +/* JPP - changed so will accept hex number. */ +/* ea - changed to accept hex digits in hex numbers */ +STATIC char *GetNumArg(char *p, int *num) +{ + static char digits[] = "0123456789ABCDEF"; + unsigned char base = 10; + int sign = 1; + int n = 0; + + /* look for NUMBER */ + p = skipwh(p); + if (*p == '-') + { + p++; + sign = -1; + } + else if (!isnum(*p)) + { + CfgFailure(p); + return NULL; + } + + for( ; *p; p++) + { + char ch = toupper(*p); + if (ch == 'X') + base = 16; + else + { + char *q = strchr(digits, ch); + if (q == NULL) + break; + n = n * base + (q - digits); + } + } + *num = n * sign; + return p; +} + +BYTE *GetStringArg(BYTE * pLine, BYTE * pszString) +{ + /* look for STRING */ + pLine = skipwh(pLine); + + /* just return whatever string is there, including null */ + return scan(pLine, pszString); +} + +STATIC void Config_Buffers(BYTE * pLine) +{ + COUNT nBuffers; + + /* Get the argument */ + if (GetNumArg(pLine, &nBuffers)) + Config.cfgBuffers = nBuffers; +} + +STATIC void CfgBuffersHigh(BYTE * pLine) +{ + Config_Buffers(pLine); + printf("Note: BUFFERS will be in HMA or low RAM, not in UMB\n"); +} + +/** + Set screen mode - rewritten to use init_call_intr() by RE / ICD +*/ +STATIC VOID sysScreenMode(BYTE * pLine) +{ + iregs r; + COUNT nMode; + COUNT nFunc = 0x11; + + /* Get the argument */ + if (GetNumArg(pLine, &nMode) == (BYTE *) 0) + return; + + if(nMode<0x10) + nFunc = 0; /* set lower screenmode */ + else if ((nMode != 0x11) && (nMode != 0x12) && (nMode != 0x14)) + return; /* do nothing; invalid screenmode */ + +/* Modes + 0x11 (17) 28 lines + 0x12 (18) 43/50 lines + 0x14 (20) 25 lines + */ + /* move cursor to pos 0,0: */ + r.a.b.h = nFunc; /* set videomode */ + r.a.b.l = nMode; + r.b.b.l = 0; + init_call_intr(0x10, &r); +} + +STATIC VOID sysVersion(BYTE * pLine) +{ + COUNT major, minor; + char *p = strchr(pLine, '.'); + + if (p == NULL) + return; + + p++; + + /* Get major number */ + if (GetNumArg(pLine, &major) == (BYTE *) 0) + return; + + /* Get minor number */ + if (GetNumArg(p, &minor) == (BYTE *) 0) + return; + + printf("Changing reported version to %d.%d\n", major, minor); + + LoL->os_setver_major = major; /* not the internal os_major */ + LoL->os_setver_minor = minor; /* not the internal os_minor */ +} + +STATIC VOID Files(BYTE * pLine) +{ + COUNT nFiles; + + /* Get the argument */ + if (GetNumArg(pLine, &nFiles) == (BYTE *) 0) + return; + + /* Got the value, assign either default or new value */ + Config.cfgFiles = max(Config.cfgFiles, nFiles); + Config.cfgFilesHigh = 0; +} + +STATIC VOID FilesHigh(BYTE * pLine) +{ + Files(pLine); + Config.cfgFilesHigh = 1; +} + +STATIC VOID CfgLastdrive(BYTE * pLine) +{ + /* Format: LASTDRIVE = letter */ + BYTE drv; + + pLine = skipwh(pLine); + drv = toupper(*pLine); + + if (drv < 'A' || drv > 'Z') + { + CfgFailure(pLine); + return; + } + drv -= 'A' - 1; /* Make real number */ + if (drv > Config.cfgLastdrive) + Config.cfgLastdrive = drv; + Config.cfgLastdriveHigh = 0; +} + +STATIC VOID CfgLastdriveHigh(BYTE * pLine) +{ + /* Format: LASTDRIVEHIGH = letter */ + CfgLastdrive(pLine); + Config.cfgLastdriveHigh = 1; +} + +/* + UmbState of confidence, 1 is sure, 2 maybe, 4 unknown and 0 no way. +*/ + +STATIC VOID Dosmem(BYTE * pLine) +{ + BYTE *pTmp; + BYTE UMBwanted = FALSE; + + pLine = GetStringArg(pLine, szBuf); + + strupr(szBuf); + + /* printf("DOS called with %s\n", szBuf); */ + + for (pTmp = szBuf;;) + { + if (memcmp(pTmp, "UMB", 3) == 0) + { + UMBwanted = TRUE; + pTmp += 3; + } + if (memcmp(pTmp, "HIGH", 4) == 0) + { + HMAState = HMA_REQ; + pTmp += 4; + } +/* if (memcmp(pTmp, "CLAIMINIT",9) == 0) { INITDataSegmentClaimed = 0; pTmp += 9; }*/ + pTmp = skipwh(pTmp); + + if (*pTmp != ',') + break; + pTmp++; + } + + if (UmbState == 0) + { + LoL->uppermem_link = 0; + LoL->uppermem_root = 0xffff; + UmbState = UMBwanted ? 2 : 0; + } + /* Check if HMA is available straight away */ + if (HMAState == HMA_REQ && MoveKernelToHMA()) + { + HMAState = HMA_DONE; + } +} + +STATIC VOID DosData(BYTE * pLine) +{ + pLine = GetStringArg(pLine, szBuf); + strupr(szBuf); + + if (memcmp(szBuf, "UMB", 3) == 0) + Config.cfgDosDataUmb = TRUE; +} + +STATIC VOID CfgSwitchar(BYTE * pLine) +{ + /* Format: SWITCHAR = character */ + + GetStringArg(pLine, szBuf); + init_switchar(*szBuf); +} + +STATIC VOID CfgSwitches(BYTE * pLine) +{ + pLine = skipwh(pLine); + if (*pLine == '=') + { + pLine = skipwh(pLine + 1); + } + while (*pLine) + { + if (*pLine == '/') { + pLine++; + switch(toupper(*pLine)) { + case 'K': + if (commands[0].pass == 1) + kbdType = 0; /* force conv keyb */ + break; + case 'N': + InitKernelConfig.SkipConfigSeconds = -1; + break; + case 'F': + InitKernelConfig.SkipConfigSeconds = 0; + break; + case 'E': /* /E[[:]nnnn] Set the desired EBDA amount to move in bytes */ + { /* Note that if there is no EBDA, this will have no effect */ + int n = 0; + if (*++pLine == ':') + pLine++; /* skip optional separator */ + if (!isnum(*pLine)) + { + pLine--; + break; + } + pLine = GetNumArg(pLine, &n) - 1; + /* allowed values: [48..1024] bytes, multiples of 16 + * e.g. AwardBIOS: 48, AMIBIOS: 1024 + * (Phoenix, MRBIOS, Unicore = ????) + */ + if (n == -1) + { + Config.ebda2move = 0xffff; + break; + } + else if (n >= 48 && n <= 1024) + { + Config.ebda2move = (n + 15) & 0xfff0; + break; + } + /* else fall through (failure) */ + } + default: + CfgFailure(pLine); + } + } else { + CfgFailure(pLine); + } + pLine = skipwh(pLine+1); + } + commands[0].pass = 1; +} + +STATIC VOID Fcbs(BYTE * pLine) +{ + /* Format: FCBS = totalFcbs [,protectedFcbs] */ + COUNT fcbs; + + if ((pLine = GetNumArg(pLine, &fcbs)) == 0) + return; + Config.cfgFcbs = fcbs; + + pLine = skipwh(pLine); + + if (*pLine == ',') + { + GetNumArg(++pLine, &fcbs); + Config.cfgProtFcbs = fcbs; + } + + if (Config.cfgProtFcbs > Config.cfgFcbs) + Config.cfgProtFcbs = Config.cfgFcbs; +} + +/* + Keyboard buffer relocation: KEYBUF=start[,end] + Select a new location for the keyboard buffer at 0x40:xx, + for example 0x40:0xac-0xff, but 0x50:5-0xff ("basica" only?) + feels safer? 0x60:0-0xff is scratch, we use it as SHELL PSP. + (sys / boot sector load_segment / LOADSEG, exeflat call in + makefile, DOS_PSP in mcb.h, main.c P_0, task.c, kernel.asm) + (50:e0..ff used as early kernel boot drive / config buffer) +*/ +STATIC VOID CfgKeyBuf(BYTE * pLine) +{ + /* Format: KEYBUF = startoffset [,endoffset] */ + UWORD FAR *keyfill = (UWORD FAR *) MK_FP(0x40, 0x1a); + UWORD FAR *keyrange = (UWORD FAR *) MK_FP(0x40, 0x80); + COUNT startbuf, endbuf; + + if ((pLine = GetNumArg(pLine, &startbuf)) == 0) + return; + pLine = skipwh(pLine); + endbuf = (startbuf | 0xff)+1; /* default end: end of the same "page" */ + if (*pLine == ',') + { + if ((pLine = GetNumArg(++pLine, &endbuf)) == 0) + return; + } + startbuf &= 0xfffe; + endbuf &= 0xfffe; + if (endbuf=0x100 && startbuf<0x105) || startbuf>0x1de) + { /* 50:0 / 50:4 are for prtscr / A:/B: DJ */ + printf("Must start at 0xac..0x1de, not 0x100..0x104\n"); + return; + } + keyfill[0] = startbuf; + keyfill[1] = startbuf; + keyrange[0] = startbuf; + keyrange[1] = endbuf; + keycheck(); +} + +/* LoadCountryInfo(): + * Searches a file in the COUNTRY.SYS format for an entry + * matching the specified code page and country code, and loads + * the corresponding information into memory. If code page is 0, + * the default code page for the country will be used. + * + * Returns TRUE if successful, FALSE if not. + */ +STATIC BOOL LoadCountryInfo(char *filenam, UWORD ctryCode, UWORD codePage) +{ + /* COUNTRY.SYS file data structures - see RBIL tables 2619-2622 */ + + struct { /* file header */ + char name[8]; /* "\377COUNTRY.SYS" */ + char reserved[11]; + ULONG offset; /* offset of first entry in file */ + } header; + struct { /* entry */ + int length; /* length of entry, not counting this word, = 12 */ + int country; /* country ID */ + int codepage; /* codepage ID */ + int reserved[2]; + ULONG offset; /* offset of country-subfunction-header in file */ + } entry; + struct subf_hdr { /* subfunction header */ + int length; /* length of entry, not counting this word, = 6 */ + int id; /* subfunction ID */ + ULONG offset; /* offset within file of subfunction data entry */ + }; + static struct { /* subfunction data */ + char signature[8]; /* \377CTYINFO|UCASE|LCASE|FUCASE|FCHAR|COLLATE|DBCS */ + int length; /* length of following table in bytes */ + UBYTE buffer[256]; + } subf_data; + struct subf_tbl { + char sig[8]; /* signature for each subfunction data */ + void FAR *p; /* pointer to data in nls_hc.asm to be copied to */ + }; + static struct subf_tbl table[8] = { + {"\377 ", NULL}, /* 0, unused */ + {"\377CTYINFO", &nlsCntryInfoHardcoded},/* 1 */ + {"\377UCASE ", &nlsUpcaseHardcoded}, /* 2 */ + {"\377LCASE ", NULL}, /* 3, not supported [yet] */ + {"\377FUCASE ", &nlsFUpcaseHardcoded}, /* 4 */ + {"\377FCHAR ", &nlsFnameTermHardcoded},/* 5 */ + {"\377COLLATE", &nlsCollHardcoded}, /* 6 */ + {"\377DBCS ", &nlsDBCSHardcoded} /* 7, not supported [yet] */ + }; + static struct subf_hdr hdr[8]; + int fd, entries, count, i; + char *filename = filenam == NULL ? "\\COUNTRY.SYS" : filenam; + BOOL rc = FALSE; + + if ((fd = open(filename, 0)) < 0) + { + if (filenam == NULL) + return !LoadCountryInfoHardCoded(ctryCode); + printf("%s not found\n", filename); + return rc; + } + if (read(fd, &header, sizeof(header)) != sizeof(header)) + { + printf("Error reading %s\n", filename); + goto ret; + } + if (memcmp(header.name, "\377COUNTRY", sizeof(header.name))) + { +err:printf("%s has invalid format\n", filename); + goto ret; + } + if (lseek(fd, header.offset) == 0xffffffffL + || read(fd, &entries, sizeof(entries)) != sizeof(entries)) + goto err; + for (i = 0; i < entries; i++) + { + if (read(fd, &entry, sizeof(entry)) != sizeof(entry) || entry.length != 12) + goto err; + if (entry.country != ctryCode || entry.codepage != codePage && codePage) + continue; + if (lseek(fd, entry.offset) == 0xffffffffL + || read(fd, &count, sizeof(count)) != sizeof(count) + || count > LENGTH(hdr) + || read(fd, &hdr, sizeof(struct subf_hdr) * count) + != sizeof(struct subf_hdr) * count) + goto err; + for (i = 0; i < count; i++) + { + if (hdr[i].length != 6) + goto err; + if (hdr[i].id < 1 || hdr[i].id > 6 || hdr[i].id == 3) + continue; + if (lseek(fd, hdr[i].offset) == 0xffffffffL + || read(fd, &subf_data, 10) != 10 + || memcmp(subf_data.signature, table[hdr[i].id].sig, 8) && (hdr[i].id !=4 + || memcmp(subf_data.signature, table[2].sig, 8)) /* UCASE for FUCASE ^*/ + || read(fd, subf_data.buffer, subf_data.length) != subf_data.length) + goto err; + if (hdr[i].id == 1) + { + if (((struct CountrySpecificInfo *)subf_data.buffer)->CountryID + != entry.country + || ((struct CountrySpecificInfo *)subf_data.buffer)->CodePage + != entry.codepage + && codePage) + continue; + nlsPackageHardcoded.cntry = entry.country; + nlsPackageHardcoded.cp = entry.codepage; + subf_data.length = /* MS-DOS "CTYINFO" is up to 38 bytes */ + min(subf_data.length, sizeof(struct CountrySpecificInfo)); + } + fmemcpy((BYTE FAR *)(table[hdr[i].id].p) + 2, subf_data.buffer, + /* skip length ^*/ subf_data.length); + } + rc = TRUE; + goto ret; + } + printf("could not find country info for country ID %u\n", ctryCode); +ret: + close(fd); + return rc; +} + +STATIC VOID Country(BYTE * pLine) +{ + /* Format: COUNTRY = countryCode, [codePage], filename */ + COUNT ctryCode; + COUNT codePage = 0; + char *filename = NULL; + + if ((pLine = GetNumArg(pLine, &ctryCode)) == 0) + goto error; + + pLine = skipwh(pLine); + if (*pLine == ',') + { + pLine = skipwh(pLine + 1); + + if (*pLine != ',') + if ((pLine = GetNumArg(pLine, &codePage)) == 0) + goto error; + + pLine = skipwh(pLine); + if (*pLine == ',') + { + GetStringArg(++pLine, szBuf); + filename = szBuf; + } + } + + if (LoadCountryInfo(filename, ctryCode, codePage)) + return; + +error: + CfgFailure(pLine); +} + +STATIC VOID Stacks(BYTE * pLine) +{ + COUNT stacks; + + /* Format: STACKS = stacks [, stackSize] */ + pLine = GetNumArg(pLine, &stacks); + Config.cfgStacks = stacks; + + pLine = skipwh(pLine); + + if (*pLine == ',') + { + GetNumArg(++pLine, &stacks); + Config.cfgStackSize = stacks; + } + + if (Config.cfgStacks) + { + if (Config.cfgStackSize < 32) + Config.cfgStackSize = 32; + if (Config.cfgStackSize > 512) + Config.cfgStackSize = 512; + if (Config.cfgStacks > 64) + Config.cfgStacks = 64; + } + Config.cfgStacksHigh = 0; +} + +STATIC VOID StacksHigh(BYTE * pLine) +{ + Stacks(pLine); + Config.cfgStacksHigh = 1; +} + +STATIC VOID InitPgmHigh(BYTE * pLine) +{ + InitPgm(pLine); + Config.cfgP_0_startmode = 0x80; +} + +STATIC VOID InitPgm(BYTE * pLine) +{ + static char init[NAMEMAX]; + static char inittail[NAMEMAX]; + + Config.cfgInit = init; + Config.cfgInitTail = inittail; + + /* Get the string argument that represents the new init pgm */ + pLine = GetStringArg(pLine, Config.cfgInit); + + /* Now take whatever tail is left and add it on as a single */ + /* string. */ + strcpy(Config.cfgInitTail, pLine); + + /* and add a DOS new line just to be safe */ + strcat(Config.cfgInitTail, "\r\n"); + + Config.cfgP_0_startmode = 0; +} + +STATIC VOID CfgBreak(BYTE * pLine) +{ + /* Format: BREAK = (ON | OFF) */ + GetStringArg(pLine, szBuf); + break_ena = strcaseequal(szBuf, "OFF") ? 0 : 1; +} + +STATIC VOID Numlock(BYTE * pLine) +{ + /* Format: NUMLOCK = (ON | OFF) */ + BYTE FAR *keyflags = (BYTE FAR *) MK_FP(0x40, 0x17); + + GetStringArg(pLine, szBuf); + + *keyflags &= ~32; + if (!strcaseequal(szBuf, "OFF")) *keyflags |= 32; + keycheck(); +} + +STATIC VOID DeviceHigh(BYTE * pLine) +{ + if (UmbState == 1) + { + if (LoadDevice(pLine, MK_FP(umb_start + UMB_top, 0), TRUE) == DE_NOMEM) + { + printf("Not enough free memory in UMBs: loading low\n"); + LoadDevice(pLine, lpTop, FALSE); + } + } + else + { + printf("UMBs unavailable!\n"); + LoadDevice(pLine, lpTop, FALSE); + } +} + +STATIC void Device(BYTE * pLine) +{ + LoadDevice(pLine, lpTop, FALSE); +} + +STATIC BOOL LoadDevice(BYTE * pLine, char FAR *top, COUNT mode) +{ + exec_blk eb; + struct dhdr FAR *dhp; + struct dhdr FAR *next_dhp; + BOOL result; + seg base, start; + + if (mode) + { + base = umb_base_seg; + start = umb_start; + } + else + { + base = base_seg; + start = LoL->first_mcb; + } + + if (base == start) + base++; + base++; + + /* Get the device driver name */ + GetStringArg(pLine, szBuf); + + /* The driver is loaded at the top of allocated memory. */ + /* The device driver is paragraph aligned. */ + eb.load.reloc = eb.load.load_seg = base; + +#ifdef DEBUG + printf("Loading device driver %s at segment %04x\n", szBuf, base); +#endif + + if ((result = init_DosExec(3, &eb, szBuf)) != SUCCESS) + { + CfgFailure(pLine); + return result; + } + + strcpy(szBuf, pLine); + /* uppercase the device driver command */ + strupr(szBuf); + + /* TE this fixes the loading of devices drivers with + multiple devices in it. NUMEGA's SoftIce is such a beast + */ + + /* add \r\n to the command line */ + strcat(szBuf, " \r\n"); + + dhp = MK_FP(base, 0); + + /* NOTE - Modification for multisegmented device drivers: */ + /* In order to emulate the functionallity experienced with other */ + /* DOS operating systems, the original 'top' end address is */ + /* updated with the end address returned from the INIT request. */ + /* The updated end address is then used when issuing the next */ + /* INIT request for the following device driver within the file */ + + for (next_dhp = NULL; FP_OFF(next_dhp) != 0xffff && + (result = init_device(dhp, szBuf, mode, &top)) == SUCCESS; + dhp = next_dhp) + { + next_dhp = MK_FP(FP_SEG(dhp), FP_OFF(dhp->dh_next)); + /* Link in device driver and save LoL->nul_dev pointer to next */ + dhp->dh_next = LoL->nul_dev.dh_next; + LoL->nul_dev.dh_next = dhp; + } + + /* might have been the UMB driver or DOS=UMB */ + if (UmbState == 2) + umb_init(); + + return result; +} + +STATIC VOID CfgFailure(BYTE * pLine) +{ + BYTE *pTmp = pLineStart; + + /* suppress multiple printing of same unrecognized lines */ + + if (nCfgLine < sizeof(ErrorAlreadyPrinted)*8) + { + if (ErrorAlreadyPrinted[nCfgLine/8] & (1 << (nCfgLine%8))) + return; + + ErrorAlreadyPrinted[nCfgLine/8] |= (1 << (nCfgLine%8)); + } + printf("CONFIG.SYS error in line %d\n", nCfgLine); + printf(">>>%s\n ", pTmp); + while (++pTmp != pLine) + printf(" "); + printf("^\n"); +} + +struct submcb +{ + char type; + unsigned short start; + unsigned short size; + char unused[3]; + char name[8]; +}; + +void FAR * KernelAllocPara(size_t nPara, char type, char *name, int mode) +{ + seg base, start; + struct submcb FAR *p; + + if (UmbState != 1) + mode = 0; + + if (mode) + { + base = umb_base_seg; + start = umb_start; + } + else + { + base = base_seg; + start = LoL->first_mcb; + } + + /* create the special DOS data MCB if it doesn't exist yet */ + DebugPrintf(("kernelallocpara: %x %x %x %c %d\n", start, base, nPara, type, mode)); + + if (base == start) + { + mcb FAR *p = para2far(base); + base++; + mcb_init(base, p->m_size - 1, p->m_type); + mumcb_init(FP_SEG(p), 0); + p->m_name[1] = 'D'; + } + + nPara++; + mcb_init(base + nPara, para2far(base)->m_size - nPara, para2far(base)->m_type); + para2far(start)->m_size += nPara; + + p = (struct submcb FAR *)para2far(base); + p->type = type; + p->start = FP_SEG(p)+1; + p->size = nPara-1; + if (name) + fmemcpy(p->name, name, 8); + base += nPara; + if (mode) + umb_base_seg = base; + else + base_seg = base; + return MK_FP(FP_SEG(p)+1, 0); +} + +void FAR * KernelAlloc(size_t nBytes, char type, int mode) +{ + void FAR *p; + size_t nPara = (nBytes + 15)/16; + + if (LoL->first_mcb == 0) + { + /* prealloc */ + lpTop = MK_FP(FP_SEG(lpTop) - nPara, FP_OFF(lpTop)); + p = AlignParagraph(lpTop); + } + else + { + p = KernelAllocPara(nPara, type, NULL, mode); + } + fmemset(p, 0, nBytes); + return p; +} + +#ifdef I86 +#if 0 +STATIC BYTE FAR * KernelAllocDma(WORD bytes, char type) +{ + if ((base_seg & 0x0fff) + (bytes >> 4) > 0x1000) { + KernelAllocPara((base_seg + 0x0fff) & 0xf000 - base_seg, type, NULL, 0); + } + return KernelAlloc(bytes, type); +} +#endif + +STATIC void FAR * AlignParagraph(VOID FAR * lpPtr) +{ + UWORD uSegVal; + + /* First, convert the segmented pointer to linear address */ + uSegVal = FP_SEG(lpPtr); + uSegVal += (FP_OFF(lpPtr) + 0xf) >> 4; + if (FP_OFF(lpPtr) > 0xfff0) + uSegVal += 0x1000; /* handle overflow */ + + /* and return an adddress adjusted to the nearest paragraph */ + /* boundary. */ + return MK_FP(uSegVal, 0); +} +#endif + +STATIC int iswh(unsigned char c) +{ + return (c == '\r' || c == '\n' || c == '\t' || c == ' '); +} + +STATIC BYTE * skipwh(BYTE * s) +{ + while (iswh(*s)) + ++s; + return s; +} + +STATIC BYTE * scan(BYTE * s, BYTE * d) +{ + askThisSingleCommand = FALSE; + DontAskThisSingleCommand = FALSE; + + s = skipwh(s); + + MenuLine = 0; + + /* does the line start with "123?" */ + + if (isnum(*s)) + { + unsigned numbers = 0; + for ( ; isnum(*s); s++) + numbers |= 1 << (*s -'0'); + + if (*s == '?') + { + MenuLine = numbers; + Menus |= numbers; + s = skipwh(s+1); + } + } + + + /* !dos=high,umb ?? */ + if (*s == '!') + { + DontAskThisSingleCommand = TRUE; + s = skipwh(s+1); + } + + if (*s == ';') + { + /* semicolon is a synonym for rem */ + *d++ = *s++; + } + else + while (*s && !iswh(*s) && *s != '=') + { + if (*s == '?') + askThisSingleCommand = TRUE; + else + *d++ = *s; + s++; + } + *d = '\0'; + return s; +} + +STATIC BOOL isnum(char ch) +{ + return (ch >= '0' && ch <= '9'); +} + +/* Yet another change for true portability (PJV) */ +STATIC char toupper(char c) +{ + if (c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + return c; +} + +/* Convert string s to uppercase */ +STATIC VOID strupr(char *s) +{ + while (*s) { + *s = toupper(*s); + s++; + } +} + +/* The following code is 8086 dependant */ + +#if 1 /* ifdef KERNEL */ +STATIC VOID mcb_init_copy(UCOUNT seg, UWORD size, mcb *near_mcb) +{ + near_mcb->m_size = size; + fmemcpy(MK_FP(seg, 0), near_mcb, sizeof(mcb)); +} + +STATIC VOID mcb_init(UCOUNT seg, UWORD size, BYTE type) +{ + static mcb near_mcb BSS_INIT({0}); + near_mcb.m_type = type; + mcb_init_copy(seg, size, &near_mcb); +} + +STATIC VOID mumcb_init(UCOUNT seg, UWORD size) +{ + static mcb near_mcb = { + MCB_NORMAL, + 8, 0, + {0,0,0}, + {"SC"} + }; + mcb_init_copy(seg, size, &near_mcb); +} +#endif + +char *strcat(register char * d, register const char * s) +{ + strcpy(d + strlen(d), s); + return d; +} + +/* compare two ASCII strings ignoring case */ +STATIC char strcaseequal(const char * d, const char * s) +{ + char ch; + while ((ch = toupper(*s++)) == toupper(*d++)) + if (ch == '\0') + return 1; + return 0; +} + +/* + moved from BLOCKIO.C here. + that saves some relocation problems +*/ + +STATIC void config_init_buffers(int wantedbuffers) +{ + struct buffer FAR *pbuffer; + unsigned buffers = 0; + + /* fill HMA with buffers if BUFFERS count >=0 and DOS in HMA */ + if (wantedbuffers < 0) + wantedbuffers = -wantedbuffers; + else if (HMAState == HMA_DONE) + buffers = (0xfff0 - HMAFree) / sizeof(struct buffer); + + if (wantedbuffers < 6) /* min 6 buffers */ + wantedbuffers = 6; + if (wantedbuffers > 99) /* max 99 buffers */ + { + printf("BUFFERS=%u not supported, reducing to 99\n", wantedbuffers); + wantedbuffers = 99; + } + if (wantedbuffers > buffers) /* more specified than available -> get em */ + buffers = wantedbuffers; + + LoL->nbuffers = buffers; + LoL->inforecptr = &LoL->firstbuf; + { + size_t bytes = sizeof(struct buffer) * buffers; + pbuffer = HMAalloc(bytes); + + if (pbuffer == NULL) + { + pbuffer = KernelAlloc(bytes, 'B', 0); + if (HMAState == HMA_DONE) + firstAvailableBuf = MK_FP(0xffff, HMAFree); + } + else + { + LoL->bufloc = LOC_HMA; + /* space in HMA beyond requested buffers available as user space */ + firstAvailableBuf = pbuffer + wantedbuffers; + } + } + LoL->deblock_buf = DiskTransferBuffer; + LoL->firstbuf = pbuffer; + + DebugPrintf(("init_buffers (size %u) at", sizeof(struct buffer))); + DebugPrintf((" (%p)", LoL->firstbuf)); + + buffers--; + pbuffer->b_prev = FP_OFF(pbuffer + buffers); + { + int i = buffers; + do + { + pbuffer->b_next = FP_OFF(pbuffer + 1); + pbuffer++; + pbuffer->b_prev = FP_OFF(pbuffer - 1); + } + while (--i); + } + pbuffer->b_next = FP_OFF(pbuffer - buffers); + + /* now, we can have quite some buffers in HMA + -- up to 50 for KE38616. + so we fill the HMA with buffers + but not if the BUFFERS count is negative ;-) + */ + + DebugPrintf((" done\n")); + + if (FP_SEG(pbuffer) == 0xffff) + { + buffers++; + printf("Kernel: allocated %d Diskbuffers = %u Bytes in HMA\n", + buffers, buffers * sizeof(struct buffer)); + } +} + +/* + Undocumented feature: ANYDOS + will report to MSDOS programs just the version number + they expect. be careful with it! +*/ +STATIC VOID SetAnyDos(BYTE * pLine) +{ + UNREFERENCED_PARAMETER(pLine); + ReturnAnyDosVersionExpected = TRUE; +} + +/* + Kernel built-in energy saving: IDLEHALT=haltlevel + -1 max savings, 0 never HLT, 1 safe kernel only HLT, + 2 (3) also hooks int2f.1680 (and sets al=0) +*/ +STATIC VOID SetIdleHalt(BYTE * pLine) +{ + COUNT haltlevel; + if (GetNumArg(pLine, &haltlevel)) + HaltCpuWhileIdle = haltlevel; /* 0 for no HLT, 1..n more, -1 max */ +} + +STATIC VOID CfgIgnore(BYTE * pLine) +{ + UNREFERENCED_PARAMETER(pLine); +} + +/* + 'MENU'ing stuff + although it's worse then MSDOS's , its better then nothing +*/ + +STATIC void ClearScreen(unsigned char attr); +STATIC VOID CfgMenu(BYTE * pLine) +{ + int nLen; + BYTE *pNumber = pLine; + + printf("%s\n",pLine); + if (MenuColor == -1) + return; + + pLine = skipwh(pLine); + + /* skip drawing characters in cp437, which is what we'll have + just after booting! */ + while ((unsigned char)*pLine >= 0xb0 && (unsigned char)*pLine < 0xe0) + pLine++; + + pLine = skipwh(pLine); /* skip more whitespaces... */ + + /* now I'm expecting a number here if this is a menu-choice line. */ + if (isnum(pLine[0])) + { + struct MenuSelector *menu = &MenuStruct[pLine[0]-'0']; + + menu->x = (pLine-pNumber); /* xpos is at start of number */ + menu->y = nMenuLine; + /* copy menu text: */ + nLen = findend(pLine); /* length is until cr/lf, null or three spaces */ + + /* max 40 chars including nullterminator + (change struct at top of file if you want more...) */ + if (nLen > MENULINEMAX-1) + nLen = MENULINEMAX-1; + memcpy(menu->Text, pLine, nLen); + menu->Text[nLen] = 0; /* nullTerminate */ + } + nMenuLine++; +} + +STATIC VOID CfgMenuEsc(BYTE * pLine) +{ + BYTE * check; + for (check = pLine; check[0]; check++) + if (check[0] == '$') check[0] = 27; /* translate $ to ESC */ + printf("%s\n",pLine); +} + +STATIC VOID DoMenu(void) +{ + iregs r; + int key = -1; + if (Menus == 0) + return; + + InitKernelConfig.SkipConfigSeconds = -1; + + if (MenuColor == -1) + Menus |= 1 << 0; /* '0' Menu always allowed */ + + nMenuLine+=2; /* use this to position "select menu" text (ypos): */ + + for (;;) + { + int i, j; + +RestartInput: + + if (MenuColor != -1) + { + SelectLine(MenuSelected); /* select current line. */ + + /* set new cursor position: */ + r.a.b.h = 0x02; + r.b.b.h = 0; + r.d.b.l = 3; + r.d.b.h = nMenuLine; + + init_call_intr(0x10, &r); /* set cursor pos */ + } + + printf("Select from Menu ["); + + for (i = 0, j = 1; i <= 9; i++, j<<=1) + if (Menus & j) + printf("%c", '0' + i); + printf("], or press [ENTER]"); + + if (MenuColor != -1) + printf(" (Selection=%d) ", MenuSelected); + + if (MenuTimeout >= 0) + printf("- %d \b", MenuTimeout); + else + printf(" \b\b\b\b\b"); + + if (MenuColor != -1) + printf("\r\n\n "); + else + printf(" -"); + + printf(" Singlestepping (F8) is: %s \r", singleStep ? "ON " : "OFF"); + + key = GetBiosKey(MenuTimeout >= 0 ? 1 : -1); + + if (key == -1) /* timeout, take default */ + { + if (MenuTimeout > 0) + { + MenuTimeout--; + goto RestartInput; + } + break; + } + else + MenuTimeout = -1; + + if (key == 0x3f00) /* F5 */ + { + SkipAllConfig = TRUE; + break; + } + if (key == 0x4200) /* F8 */ + { + singleStep = !singleStep; + } + else if(key == 0x4800 && MenuColor != -1) /* arrow up */ + { + if(MenuSelected>=1 && (Menus & (1 << (MenuSelected-1))) ) + { + MenuSelected--; + } + } + else if(key == 0x5000 && MenuColor != -1) /* arrow down */ + { + if(MenuSelectedCountryID == ctryCode) + { + nlsCountryInfoHardcoded.C.CountryID = country->CountryID; + nlsCountryInfoHardcoded.C.DateFormat = country->DateFormat; + nlsCountryInfoHardcoded.C.CurrencyString[0] = country->CurrencyString[0]; + nlsCountryInfoHardcoded.C.CurrencyString[1] = country->CurrencyString[1]; + nlsCountryInfoHardcoded.C.CurrencyString[2] = country->CurrencyString[2]; + nlsCountryInfoHardcoded.C.ThousandSeparator[0] = country->ThousandSeparator; + nlsCountryInfoHardcoded.C.DecimalPoint[0] = country->DecimalPoint; + nlsCountryInfoHardcoded.C.DateSeparator[0] = country->DateSeparator; + nlsCountryInfoHardcoded.C.TimeSeparator[0] = country->TimeSeparator; + nlsCountryInfoHardcoded.C.CurrencyFormat = country->CurrencyFormat; + nlsCountryInfoHardcoded.C.CurrencyPrecision = country->CurrencyPrecision; + nlsCountryInfoHardcoded.C.TimeFormat = country->TimeFormat; + return 0; + } + } + + printf("could not find country info for country ID %u\n", ctryCode); + printf("current supported countries are "); + + for (country = specificCountriesSupported; + country < specificCountriesSupported + LENGTH(specificCountriesSupported); + country++) + { + printf("%u ", country->CountryID); + } + printf("\n"); + + return 1; +} + + +/* **************************************************************** +** implementation of INSTALL=NANSI.COM /P /X /BLA +*/ + +int numInstallCmds BSS_INIT(0); +struct instCmds { + char buffer[128]; + int mode; +} InstallCommands[10] BSS_INIT({0}); + +#ifdef DEBUG +#define InstallPrintf(x) printf x +#else +#define InstallPrintf(x) +#endif + +STATIC VOID _CmdInstall(BYTE * pLine,int mode) +{ + struct instCmds *cmd; + + InstallPrintf(("Installcmd %d:%s\n",numInstallCmds,pLine)); + + if (numInstallCmds > LENGTH(InstallCommands)) + { + printf("Too many Install commands given (%d max)\n",LENGTH(InstallCommands)); + CfgFailure(pLine); + return; + } + cmd = &InstallCommands[numInstallCmds]; + memcpy(cmd->buffer,pLine,127); + cmd->buffer[127] = 0; + cmd->mode = mode; + numInstallCmds++; +} +STATIC VOID CmdInstall(BYTE * pLine) +{ + _CmdInstall(pLine,0); +} +STATIC VOID CmdInstallHigh(BYTE * pLine) +{ + _CmdInstall(pLine,0x80); /* load high, if possible */ +} + +STATIC VOID InstallExec(struct instCmds *icmd) +{ + BYTE filename[128], *args, *d, *cmd = icmd->buffer; + exec_blk exb; + + InstallPrintf(("installing %s\n",cmd)); + + cmd=skipwh(cmd); + + for (args = cmd, d = filename; ;args++,d++) + { + *d = *args; + if (*d <= 0x020 || *d == '/') + break; + } + *d = 0; + + args--; + *args = strlen(&args[1]); + args[*args+1] = '\r'; + args[*args+2] = 0; + + exb.exec.env_seg = 0; + exb.exec.cmd_line = (CommandTail FAR *) args; + exb.exec.fcb_1 = exb.exec.fcb_2 = (fcb FAR *) 0xfffffffful; + + + InstallPrintf(("cmd[%s] args [%u,%s]\n",filename,*args,args+1)); + + if (init_DosExec(icmd->mode, &exb, filename) != SUCCESS) + { + CfgFailure(cmd); + } +} + +STATIC void free(seg segment) +{ + iregs r; + + r.a.b.h = 0x49; /* free memory */ + r.es = segment; + init_call_intr(0x21, &r); +} + +/* set memory allocation strategy */ +STATIC void set_strategy(unsigned char strat) +{ + iregs r; + + r.a.x = 0x5801; + r.b.b.l = strat; + init_call_intr(0x21, &r); +} + +VOID DoInstall(void) +{ + int i; + unsigned short installMemory; + struct instCmds *cmd; + + if (numInstallCmds == 0) + return; + + InstallPrintf(("Installing commands now\n")); + + /* grab memory for this install code + we KNOW, that we are executing somewhere at top of memory + we need to protect the INIT_CODE from other programs + that will be executing soon + */ + + set_strategy(LAST_FIT); + installMemory = ((unsigned)_init_end + ebda_size + 15) / 16; +#ifdef __WATCOMC__ + installMemory += (_InitTextEnd - _InitTextStart + 15) / 16; +#endif + installMemory = allocmem(installMemory); + + InstallPrintf(("allocated memory at %x\n",installMemory)); + + for (i = 0, cmd = InstallCommands; i < numInstallCmds; i++, cmd++) + { + InstallPrintf(("%d:%s\n",i,cmd->buffer)); + set_strategy(cmd->mode); + InstallExec(cmd); + } + set_strategy(FIRST_FIT); + free(installMemory); + + InstallPrintf(("Done with installing commands\n")); + return; +} + +STATIC VOID CmdSet(BYTE *pLine) +{ + pLine = GetStringArg(pLine, szBuf); + pLine = skipwh(pLine); /* scan() stops at the equal sign or space */ + if (*pLine == '=') /* equal sign is required */ + { + int size; + strupr(szBuf); /* all environment variables must be uppercase */ + strcat(szBuf, "="); + pLine = skipwh(++pLine); + strcat(szBuf, pLine); /* append the variable value (may include spaces) */ + size = strlen(szBuf); + if (size < master_env + sizeof(master_env) - envp - 1) + { /* must end with two consequtive zeros */ + strcpy(envp, szBuf); + envp += size + 1; /* add next variables starting at the second zero */ + } + else + printf("Master environment is full - can't add \"%s\"\n", szBuf); + } + else + printf("Invalid SET command: \"%s\"\n", szBuf); +} diff --git a/kernel/config.h b/kernel/config.h new file mode 100644 index 0000000..9dbd306 --- /dev/null +++ b/kernel/config.h @@ -0,0 +1,46 @@ +/****************************************************************/ +/* */ +/* config.h */ +/* DOS-C */ +/* */ +/* Global data structures and declarations */ +/* */ +/* Copyright (c) 2000 */ +/* Steffen Kaiser */ +/* 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. */ +/****************************************************************/ + +struct config { /* Configuration variables */ + UBYTE cfgDosDataUmb; + BYTE cfgBuffers; /* number of buffers in the system */ + UBYTE cfgFiles; /* number of available files */ + UBYTE cfgFilesHigh; + UBYTE cfgFcbs; /* number of available FCBs */ + UBYTE cfgProtFcbs; /* number of protected FCBs */ + BYTE *cfgInit; /* init of command.com */ + BYTE *cfgInitTail; /* command.com's tail */ + UBYTE cfgLastdrive; /* last drive */ + UBYTE cfgLastdriveHigh; + BYTE cfgStacks; /* number of stacks */ + BYTE cfgStacksHigh; + UWORD cfgStackSize; /* stacks size for each stack */ + UBYTE cfgP_0_startmode; /* load command.com high or not */ + unsigned ebda2move; /* value for switches=/E:nnnn */ +}; diff --git a/kernel/console.asm b/kernel/console.asm new file mode 100644 index 0000000..e4a9944 --- /dev/null +++ b/kernel/console.asm @@ -0,0 +1,254 @@ +; +; File: +; console.asm +; Description: +; Console device driver +; +; Copyright (c) 1998 +; 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. +; +; $Header$ +; + + %include "io.inc" + + +segment _IO_FIXED_DATA + + global ConTable +ConTable db 0Ah + dw ConInit + dw _IOExit + dw _IOExit + dw _IOCommandError + dw ConRead + dw CommonNdRdExit + dw CommonNdRdExit + dw ConInpFlush + dw ConWrite + dw ConWrite + dw _IOExit + +CTL_PRT_SCREEN equ 7200h +CTL_P equ 10h + +segment _LOWTEXT + +uScanCode db 0 ; Scan code for con: device + +global _kbdType +_kbdType db 0 ; 00 for 84key, 10h for 102key + + global ConInit +ConInit: + xor ax,ax + mov ds,ax + mov al,[496h] + and al,10h + mov byte[cs:_kbdType],al ; enhanced keyboard if bit 4 set + jmp _IOExit + +; +; Name: +; ConRead +; +; Function: +; Read to address in es:di characters from the keyboard. Cx contains +; a count of how many characters are to be transferred. +; +; Description: +; Calls KbdRdChar to read the characters. Destroys ax. +; + global ConRead +ConRead: + jcxz ConRead2 ; Exit if read of zero + +ConRead1: + call KbdRdChar ; Get a char from kbd in al + stosb ; Store al to es:[di] + loop ConRead1 ; Loop until all are read + +ConRead2: + jmp _IOExit + + +readkey: + mov ah,[cs:_kbdType] + int 16h +checke0: cmp al,0xe0 ; must check for 0xe0 scan code + jne .ret + or ah,ah ; check for Greek alpha + jz .ret + mov al,0 ; otherwise destroy the 0xe0 +.ret: retn + +; +; Name: +; KbdRdChar +; +; Function: +; Read a character from the keyboard. +; +; Description: +; This subroutine reads a character from the keyboard. It also handles +; a couple of special functions. +; It converts ctrl-printscreen to a control-P. +; It also accounts for extended scan codes by saving off +; the high byte of the return and returning it if it was non-zero on +; the previous read. +; + global KbdRdChar +KbdRdChar: + xor ax,ax ; Zero the scratch register + xchg [cs:uScanCode],al ; and swap with scan code + ; now AL is set if previous key was extended, + ; and previous is erased in any case + or al,al ; Test to see if it was set + jnz KbdRdRtn ; Exit if it was, returning it + call readkey ; get keybd char in al, ah=scan + or ax,ax ; Zero ? + jz KbdRdChar ; Loop if it is + cmp ax,CTL_PRT_SCREEN ; Ctrl-Print screen? + jne KbdRd1 ; Nope, keep going + mov al,CTL_P ; Yep, make it ^P +KbdRd1: + or al,al ; Extended key? + jnz KbdRdRtn ; Nope, just exit + mov [cs:uScanCode],ah ; Yep, save the scan code +KbdRdRtn: + retn + +; +; Name: +; CommonNdRdExit +; +; Function: +; Checks the keyboard input buffer. +; +; Description: +; Calls int 16 (get status). Sets Busy-Flag in status field. Destroys ax. +; + global CommonNdRdExit +CommonNdRdExit: ; *** tell if key waiting and return its ASCII if yes + mov al,[cs:uScanCode] ; Test for last scan code + ; now AL is set if previous key was extended, + or al,al ; Was it zero ? + jnz ConNdRd2 ; Jump if there's a char waiting + mov ah,1 + add ah,[cs:_kbdType] + int 16h ; Get status, if zf=0 al=char + jz ConNdRd4 ; Jump if no char available + call checke0 ; check for e0 scancode + or ax,ax ; Zero ? + jnz ConNdRd1 ; Jump if not zero + call readkey + jmp short CommonNdRdExit + ; if char was there but 0, fetch and retry... + ; (why do we check uScanCode here?) + +ConNdRd1: + cmp ax,CTL_PRT_SCREEN ; Was ctl+prntscrn key pressed? + jne ConNdRd2 ; Jump if not + mov al,CTL_P + +ConNdRd2: + lds bx,[cs:_ReqPktPtr] ; Set the status + cmp byte[bx+2],6 ; input status call? + je ConNdRd3 + mov [bx+0Dh],al ; return the ASCII of that key + +ConNdRd3: + jmp _IOExit + +ConNdRd4: + jmp _IODone + + + + global ConInpFlush +ConInpFlush: ; *** flush that keyboard queue + call KbdInpChar ; get all available keys + jmp _IOExit ; do not even remember the last one + + + +KbdInpChar: ; *** get ??00 or the last waiting key after flushing the queue + xor ax,ax + mov byte [cs:uScanCode],al +KbdInpCh1: + mov ah,1 + add ah,[cs:_kbdType] + int 16h ; get status, if zf=0 al=char + jz KbdInpRtnZero ; Jump if zero + ; returns 0 or the last key that was waiting in AL + call readkey + jmp short KbdInpCh1 + ; just read any key that is waiting, then check if + ; more keys are waiting. if not, return AL of this + ; key (which is its ASCII). AH (scan) discarded! +KbdInpRtnZero: mov ah,1 ; if anybody wants "1 if no key was waiting"! +KbdInpRtn: + retn + + + global ConWrite +ConWrite: + jcxz ConNdRd3 ; Exit if nothing to write +ConWr1: + mov al,[es:di] + inc di + int 29h ; Do fast output call + loop ConWr1 ; Loop if more to output + jmp _IOExit + +CBreak: + mov byte [cs:uScanCode],3 ; Put a ^C into the buffer +IntRetn: + iret + + +; global _cso +;_cso +; push bp +; mov bp,sp +; push ax +; mov ax,[bp+4] +; int 29h +; pop ax +; pop bp +; retn + + global _int29_handler +_int29_handler: + push ax + push si + push di + push bp + push bx + mov ah,0Eh + mov bx,7 + int 10h ; write char al, teletype mode + pop bx + pop bp + pop di + pop si + pop ax + iret diff --git a/kernel/country.asm b/kernel/country.asm new file mode 100644 index 0000000..575e58f --- /dev/null +++ b/kernel/country.asm @@ -0,0 +1,5108 @@ +; File: +; country.asm +; Description: +; The FreeDOS COUNTRY.SYS source code +; +; Copyleft (G) 2004 +; The FreeDOS Project +; +; This file is part of FreeDOS. +; +; FreeDOS 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. +; +; FreeDOS 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 FreeDOS; see the file COPYING. If not, +; write to the Free Software Foundation, Inc., +; 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +; or go to http://www.gnu.org/licenses/gpl.html + +; $Id: country.asm 1637 2011-06-27 01:05:22Z perditionc $ + +; This COUNTRY.SYS is compatible with COUNTRY.SYS +; of MS-DOS, PC-DOS, PTS-DOS, OS/2, Win9x, WinNT +; File format described in RBIL tables 2619-2622 +; +; Created as a kernel table by Tom Ehlert +; Reformatted and commented by Bernd Blaauw +; Separated from the kernel by Luchezar Georgiev +; Case/collate tables added by Eduardo Casino +; Yes/No and page 850 table by Steffen Kaiser +; Amended by many contributors (see names below) + +; file header + +db 0FFh,"COUNTRY",0,0,0,0,0,0,0,0,1,0,1 ; reserved and undocumented values +dd ent ; first entry +ent dw 171; number of entries - don't forget to update when adding a new country + +; entries +; (size, country, codepage, reserved(2), offset) + +; Countries 0 - 999 (Standard) +; +__us_437 dw 12, 1,437,0,0 + dd _us_437 +__us_850 dw 12, 1,850,0,0 + dd _us_850 +__us_858 dw 12, 1,858,0,0 + dd _us_858 +__ca_863 dw 12, 2,863,0,0 + dd _ca_863 +__ca_850 dw 12, 2,850,0,0 + dd _ca_850 +__ca_858 dw 12, 2,858,0,0 + dd _ca_858 +__la_858 dw 12, 3,858,0,0 + dd _la_858 +__la_850 dw 12, 3,850,0,0 + dd _la_850 +__la_437 dw 12, 3,437,0,0 + dd _la_437 +__ru_866 dw 12, 7,866,0,0 + dd _ru_866 +__ru_808 dw 12, 7,808,0,0 + dd _ru_808 +__ru_855 dw 12, 7,855,0,0 + dd _ru_855 +__ru_872 dw 12, 7,872,0,0 + dd _ru_872 +__ru_852 dw 12, 7,852,0,0 + dd _ru_852 +__ru_850 dw 12, 7,850,0,0 + dd _ru_850 +__ru_858 dw 12, 7,858,0,0 + dd _ru_858 +__ru_437 dw 12, 7,437,0,0 + dd _ru_437 +__gr_869 dw 12, 30,869,0,0 + dd _gr_869 +__gr_737 dw 12, 30,737,0,0 + dd _gr_737 +__gr_850 dw 12, 30,850,0,0 + dd _gr_850 +__gr_858 dw 12, 30,858,0,0 + dd _gr_858 +__nl_858 dw 12, 31,858,0,0 + dd _nl_858 +__nl_850 dw 12, 31,850,0,0 + dd _nl_850 +__nl_437 dw 12, 31,437,0,0 + dd _nl_437 +__be_858 dw 12, 32,858,0,0 + dd _be_858 +__be_850 dw 12, 32,850,0,0 + dd _be_850 +__be_437 dw 12, 32,437,0,0 + dd _be_437 +__fr_858 dw 12, 33,858,0,0 + dd _fr_858 +__fr_850 dw 12, 33,850,0,0 + dd _fr_850 +__fr_437 dw 12, 33,437,0,0 + dd _fr_437 +__es_858 dw 12, 34,858,0,0 + dd _es_858 +__es_850 dw 12, 34,850,0,0 + dd _es_850 +__es_437 dw 12, 34,437,0,0 + dd _es_437 +__hu_852 dw 12, 36,852,0,0 + dd _hu_852 +__hu_850 dw 12, 36,850,0,0 + dd _hu_850 +__hu_858 dw 12, 36,858,0,0 + dd _hu_858 +__yu_852 dw 12, 38,852,0,0 + dd _yu_852 +__yu_855 dw 12, 38,855,0,0 + dd _yu_855 +__yu_872 dw 12, 38,872,0,0 + dd _yu_872 +__yu_858 dw 12, 38,858,0,0 + dd _yu_858 +__yu_850 dw 12, 38,850,0,0 + dd _yu_850 +__it_858 dw 12, 39,858,0,0 + dd _it_858 +__it_850 dw 12, 39,850,0,0 + dd _it_850 +__it_437 dw 12, 39,437,0,0 + dd _it_437 +__ro_852 dw 12, 40,852,0,0 + dd _ro_852 +__ro_850 dw 12, 40,850,0,0 + dd _ro_850 +__ro_858 dw 12, 40,858,0,0 + dd _ro_858 +__ch_858 dw 12, 41,858,0,0 + dd _ch_858 +__ch_850 dw 12, 41,850,0,0 + dd _ch_850 +__ch_437 dw 12, 41,437,0,0 + dd _ch_437 +__cz_852 dw 12, 42,852,0,0 + dd _cz_852 +__cz_850 dw 12, 42,850,0,0 + dd _cz_850 +__cz_858 dw 12, 42,858,0,0 + dd _cz_858 +__at_858 dw 12, 43,858,0,0 + dd _at_858 +__at_850 dw 12, 43,850,0,0 + dd _at_850 +__at_437 dw 12, 43,437,0,0 + dd _at_437 +__uk_858 dw 12, 44,858,0,0 + dd _uk_858 +__uk_850 dw 12, 44,850,0,0 + dd _uk_850 +__uk_437 dw 12, 44,437,0,0 + dd _uk_437 +__dk_865 dw 12, 45,865,0,0 + dd _dk_865 +__dk_850 dw 12, 45,850,0,0 + dd _dk_850 +__dk_858 dw 12, 45,858,0,0 + dd _dk_858 +__se_858 dw 12, 46,858,0,0 + dd _se_858 +__se_850 dw 12, 46,850,0,0 + dd _se_850 +__se_437 dw 12, 46,437,0,0 + dd _se_437 +__no_865 dw 12, 47,865,0,0 + dd _no_865 +__no_850 dw 12, 47,850,0,0 + dd _no_850 +__no_858 dw 12, 47,858,0,0 + dd _no_858 +__pl_852 dw 12, 48,852,0,0 + dd _pl_852 +__pl_850 dw 12, 48,850,0,0 + dd _pl_850 +__pl_858 dw 12, 48,858,0,0 + dd _pl_858 +__de_858 dw 12, 49,858,0,0 + dd _de_858 +__de_850 dw 12, 49,850,0,0 + dd _de_850 +__de_437 dw 12, 49,858,0,0 + dd _de_437 +__ar_858 dw 12, 54,858,0,0 + dd _ar_858 +__ar_850 dw 12, 54,850,0,0 + dd _ar_850 +__ar_437 dw 12, 54,437,0,0 + dd _ar_437 +__br_858 dw 12, 55,858,0,0 + dd _br_858 +__br_850 dw 12, 55,850,0,0 + dd _br_850 +__br_437 dw 12, 55,437,0,0 + dd _br_437 +__my_437 dw 12, 60,437,0,0 + dd _my_437 +__au_437 dw 12, 61,437,0,0 + dd _au_437 +__au_850 dw 12, 61,850,0,0 + dd _au_850 +__au_858 dw 12, 61,858,0,0 + dd _au_858 +__sg_437 dw 12, 65,437,0,0 + dd _sg_437 +__jp_437 dw 12, 81,437,0,0 + dd _jp_437 +__jp_932 dw 12, 81,932,0,0 + dd _jp_932 +__kr_437 dw 12, 82,437,0,0 + dd _kr_437 +__kr_934 dw 12, 82,934,0,0 + dd _kr_934 +__cn_437 dw 12, 86,437,0,0 + dd _cn_437 +__cn_936 dw 12, 86,936,0,0 + dd _cn_936 +__tr_857 dw 12, 90,857,0,0 + dd _tr_857 +__tr_850 dw 12, 90,850,0,0 + dd _tr_850 +__in_437 dw 12, 91,437,0,0 + dd _in_437 +__pt_860 dw 12,351,860,0,0 + dd _pt_860 +__pt_850 dw 12,351,850,0,0 + dd _pt_850 +__pt_858 dw 12,351,858,0,0 + dd _pt_858 +__fi_858 dw 12,358,858,0,0 + dd _fi_858 +__fi_850 dw 12,358,850,0,0 + dd _fi_850 +__fi_437 dw 12,358,437,0,0 + dd _fi_437 +__bg_855 dw 12,359,855,0,0 + dd _bg_855 +__bg_872 dw 12,359,872,0,0 + dd _bg_872 +__bg_850 dw 12,359,850,0,0 + dd _bg_850 +__bg_858 dw 12,359,858,0,0 + dd _bg_858 +__bg_866 dw 12,359,866,0,0 + dd _bg_866 +__bg_808 dw 12,359,808,0,0 + dd _bg_808 +__bg_849 dw 12,359,849,0,0 + dd _bg_849 +__bg_1131 dw 12,359,1131,0,0 + dd _bg_1131 +__bg_30033 dw 12,359,30033,0,0 + dd _bg_30033 +__by_849 dw 12,375,849,0,0 + dd _by_849 +__by_1131 dw 12,375,1131,0,0 + dd _by_1131 +__by_850 dw 12,375,850,0,0 + dd _by_850 +__by_858 dw 12,375,858,0,0 + dd _by_858 +__ua_848 dw 12,380,848,0,0 + dd _ua_848 +__ua_1125 dw 12,380,1125,0,0 + dd _ua_1125 +__sr_855 dw 12, 381,855,0,0 ; Serbia and Montenegro, Serbian, Cyrillic + dd _sr_855 +__sr_872 dw 12, 381,872,0,0 + dd _sr_872 +__sr_852 dw 12, 381,852,0,0 ; Serbia and Montenegro, Serbian, Latin + dd _sr_852 +__sr_850 dw 12, 381,850,0,0 + dd _sr_850 +__sr_858 dw 12, 381,858,0,0 + dd _sr_858 +__hr_852 dw 12, 384,852,0,0 ; Croatia, Croatian + dd _hr_852 +__hr_850 dw 12, 384,850,0,0 + dd _hr_850 +__hr_858 dw 12, 384,858,0,0 + dd _hr_858 +__si_852 dw 12, 386,852,0,0 ; Slovenia + dd _si_852 +__si_850 dw 12, 386,850,0,0 + dd _si_850 +__si_858 dw 12, 386,858,0,0 + dd _si_858 +__ba_852 dw 12, 387,852,0,0 ; Bosnia Herzegovina + dd _ba_852 +__ba_850 dw 12, 387,850,0,0 + dd _ba_850 +__ba_858 dw 12, 387,858,0,0 + dd _ba_858 +__ba_855 dw 12, 387,855,0,0 ; Bosnia Herzegovina, Cyrillic + dd _sr_855 +__ba_872 dw 12, 387,872,0,0 + dd _sr_872 +__mk_855 dw 12, 389,855,0,0 ; Macedonia + dd _mk_855 +__mk_872 dw 12, 389,872,0,0 + dd _mk_872 +__mk_850 dw 12, 389,850,0,0 + dd _mk_850 +__mk_858 dw 12, 389,858,0,0 + dd _mk_858 +__me_858 dw 12,785,858,0,0 + dd _me_858 +__me_850 dw 12,785,850,0,0 + dd _me_850 +__me_864 dw 12,785,864,0,0 + dd _me_864 +__il_858 dw 12,972,858,0,0 + dd _il_858 +__il_850 dw 12,972,850,0,0 + dd _il_850 +__il_862 dw 12,972,862,0,0 + dd _il_862 + +; Countries 4x000 - 4x999 (Multilingual) +; +__nl_BE_850 dw 12, 40032,850,0,0 + dd _nl_BE_850 +__nl_BE_858 dw 12, 40032,858,0,0 + dd _nl_BE_858 +__nl_BE_437 dw 12, 40032,437,0,0 + dd _nl_BE_437 +__fr_BE_850 dw 12, 41032,850,0,0 + dd _fr_BE_850 +__fr_BE_858 dw 12, 41032,858,0,0 + dd _fr_BE_858 +__fr_BE_437 dw 12, 41032,437,0,0 + dd _fr_BE_437 +__de_BE_850 dw 12, 42032,850,0,0 + dd _de_BE_850 +__de_BE_858 dw 12, 42032,858,0,0 + dd _de_BE_858 +__de_BE_437 dw 12, 42032,437,0,0 + dd _de_BE_437 +__es_ES_850 dw 12, 40034,850,0,0 + dd _es_ES_850 +__es_ES_858 dw 12, 40034,858,0,0 + dd _es_ES_858 +__es_ES_437 dw 12, 40034,437,0,0 + dd _es_ES_437 +__ca_ES_850 dw 12, 41034,850,0,0 + dd _ca_ES_850 +__ca_ES_858 dw 12, 41034,858,0,0 + dd _ca_ES_858 +__ca_ES_437 dw 12, 41034,437,0,0 + dd _ca_ES_437 +__gl_ES_850 dw 12, 42034,850,0,0 + dd _gl_ES_850 +__gl_ES_858 dw 12, 42034,858,0,0 + dd _gl_ES_858 +__gl_ES_437 dw 12, 42034,437,0,0 + dd _gl_ES_437 +__eu_ES_850 dw 12, 43034,850,0,0 + dd _eu_ES_850 +__eu_ES_858 dw 12, 43034,858,0,0 + dd _eu_ES_858 +__eu_ES_437 dw 12, 43034,437,0,0 + dd _eu_ES_437 +__de_CH_858 dw 12, 40041,858,0,0 + dd _de_CH_858 +__de_CH_850 dw 12, 40041,850,0,0 + dd _de_CH_850 +__de_CH_437 dw 12, 40041,437,0,0 + dd _de_CH_437 +__fr_CH_858 dw 12, 41041,858,0,0 + dd _fr_CH_858 +__fr_CH_850 dw 12, 41041,850,0,0 + dd _fr_CH_850 +__fr_CH_437 dw 12, 41041,437,0,0 + dd _fr_CH_437 +__it_CH_858 dw 12, 42041,858,0,0 + dd _it_CH_858 +__it_CH_850 dw 12, 42041,850,0,0 + dd _it_CH_850 +__it_CH_437 dw 12, 42041,437,0,0 + dd _it_CH_437 + +; subfunction headers +; (count, size, id, offset) +; add ofher subfunctions after each one + +_us_437 dw 7 + dw 6,1 + dd us_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_us_850 dw 7 + dw 6,1 + dd us_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_us_858 dw 7 + dw 6,1 + dd us_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_ca_863 dw 7 + dw 6,1 + dd ca_863 + dw 6,2 + dd ucase_863 + dw 6,4 + dd ucase_863 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_863 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_ca_850 dw 7 + dw 6,1 + dd ca_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_ca_858 dw 7 + dw 6,1 + dd ca_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_la_850 dw 7 + dw 6,1 + dd la_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_la_858 dw 7 + dw 6,1 + dd la_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_la_437 dw 7 + dw 6,1 + dd la_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_ru_866 dw 8 + dw 6,1 + dd ru_866 + dw 6,2 + dd ucase_866 + dw 6,3 + dd lcase_866 + dw 6,4 + dd ucase_866 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_866 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn_866 +_ru_808 dw 8 + dw 6,1 + dd ru_808 + dw 6,2 + dd ucase_808 + dw 6,3 + dd lcase_808 + dw 6,4 + dd ucase_808 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_808 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn_808 +_ru_855 dw 7 + dw 6,1 + dd ru_855 + dw 6,2 + dd ucase_855 + dw 6,4 + dd ucase_855 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_855 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn_855 +_ru_872 dw 7 + dw 6,1 + dd ru_872 + dw 6,2 + dd ucase_872 + dw 6,4 + dd ucase_872 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_872 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn_872 +_ru_852 dw 7 + dw 6,1 + dd ru_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn +_ru_850 dw 7 + dw 6,1 + dd ru_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn +_ru_858 dw 7 + dw 6,1 + dd ru_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn +_ru_437 dw 7 + dw 6,1 + dd ru_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd ru_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ru_yn +_gr_869 dw 7 + dw 6,1 + dd gr_869 + dw 6,2 + dd ucase_869 + dw 6,4 + dd ucase_869 + dw 6,5 + dd fchar + dw 6,6 + dd gr_collate_869 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gr_yn_869 +_gr_737 dw 7 + dw 6,1 + dd gr_737 + dw 6,2 + dd ucase_737 + dw 6,4 + dd ucase_737 + dw 6,5 + dd fchar + dw 6,6 + dd gr_collate_737 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gr_yn_737 +_gr_850 dw 7 + dw 6,1 + dd gr_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd gr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gr_yn +_gr_858 dw 7 + dw 6,1 + dd gr_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd gr_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gr_yn +_nl_850 dw 7 + dw 6,1 + dd nl_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd nl_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_nl_858 dw 7 + dw 6,1 + dd nl_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd nl_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_nl_437 dw 7 + dw 6,1 + dd nl_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd nl_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_be_850 dw 7 + dw 6,1 + dd be_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd be_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_be_858 dw 7 + dw 6,1 + dd be_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd be_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_be_437 dw 7 + dw 6,1 + dd be_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd be_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_fr_850 dw 7 + dw 6,1 + dd fr_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_fr_858 dw 7 + dw 6,1 + dd fr_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_fr_437 dw 7 + dw 6,1 + dd fr_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_es_850 dw 7 + dw 6,1 + dd es_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_es_858 dw 7 + dw 6,1 + dd es_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_es_437 dw 7 + dw 6,1 + dd es_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_hu_852 dw 7 + dw 6,1 + dd hu_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd hu_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd hu_yn +_hu_850 dw 7 + dw 6,1 + dd hu_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd hu_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd hu_yn +_hu_858 dw 7 + dw 6,1 + dd hu_850 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd hu_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd hu_yn +_yu_852 dw 7 + dw 6,1 + dd yu_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_yu_855 dw 7 + dw 6,1 + dd yu_855 + dw 6,2 + dd ucase_855 + dw 6,4 + dd ucase_855 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_855 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn_855 +_yu_872 dw 7 + dw 6,1 + dd yu_872 + dw 6,2 + dd ucase_872 + dw 6,4 + dd ucase_872 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_872 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn_872 +_yu_850 dw 7 + dw 6,1 + dd yu_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_yu_858 dw 7 + dw 6,1 + dd yu_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_it_850 dw 7 + dw 6,1 + dd it_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd it_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd it_yn +_it_858 dw 7 + dw 6,1 + dd it_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd it_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd it_yn +_it_437 dw 7 + dw 6,1 + dd it_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd it_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd it_yn +_ro_852 dw 7 + dw 6,1 + dd ro_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd ro_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ro_yn +_ro_850 dw 7 + dw 6,1 + dd ro_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd ro_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ro_yn +_ro_858 dw 7 + dw 6,1 + dd ro_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd ro_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ro_yn +_ch_850 dw 7 + dw 6,1 + dd ch_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd ch_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_ch_858 dw 7 + dw 6,1 + dd ch_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd ch_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_ch_437 dw 7 + dw 6,1 + dd ch_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd ch_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_cz_852 dw 7 + dw 6,1 + dd cz_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd cz_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd cz_yn +_cz_850 dw 7 + dw 6,1 + dd cz_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd cz_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd cz_yn +_cz_858 dw 7 + dw 6,1 + dd cz_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd cz_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd cz_yn +_at_850 dw 7 + dw 6,1 + dd at_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_at_858 dw 7 + dw 6,1 + dd at_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_at_437 dw 7 + dw 6,1 + dd at_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_uk_850 dw 7 + dw 6,1 + dd uk_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_uk_858 dw 7 + dw 6,1 + dd uk_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_uk_437 dw 7 + dw 6,1 + dd uk_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_dk_865 dw 7 + dw 6,1 + dd dk_865 + dw 6,2 + dd ucase_865 + dw 6,4 + dd ucase_865 + dw 6,5 + dd fchar + dw 6,6 + dd dk_collate_865 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd dk_yn +_dk_850 dw 7 + dw 6,1 + dd dk_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd dk_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd dk_yn +_dk_858 dw 7 + dw 6,1 + dd dk_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd dk_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd dk_yn +_se_850 dw 7 + dw 6,1 + dd se_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd se_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd se_yn +_se_858 dw 7 + dw 6,1 + dd se_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd se_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd se_yn +_se_437 dw 7 + dw 6,1 + dd se_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd se_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd se_yn +_no_865 dw 7 + dw 6,1 + dd no_865 + dw 6,2 + dd ucase_865 + dw 6,4 + dd ucase_865 + dw 6,5 + dd fchar + dw 6,6 + dd no_collate_865 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd no_yn +_no_850 dw 7 + dw 6,1 + dd no_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd no_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd no_yn +_no_858 dw 7 + dw 6,1 + dd no_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd no_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd no_yn +_pl_852 dw 7 + dw 6,1 + dd pl_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd pl_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pl_yn +_pl_850 dw 7 + dw 6,1 + dd pl_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd pl_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pl_yn +_pl_858 dw 7 + dw 6,1 + dd pl_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd pl_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pl_yn +_de_850 dw 7 + dw 6,1 + dd de_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_de_858 dw 7 + dw 6,1 + dd de_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_de_437 dw 7 + dw 6,1 + dd de_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_ar_437 dw 7 + dw 6,1 + dd ar_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_ar_850 dw 7 + dw 6,1 + dd ar_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_ar_858 dw 7 + dw 6,1 + dd ar_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_br_850 dw 7 + dw 6,1 + dd br_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd pt_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pt_yn +_br_858 dw 7 + dw 6,1 + dd br_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd pt_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pt_yn +_br_437 dw 7 + dw 6,1 + dd br_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd pt_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pt_yn +_my_437 dw 7 + dw 6,1 + dd my_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_au_437 dw 7 + dw 6,1 + dd au_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_au_850 dw 7 + dw 6,1 + dd au_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_au_858 dw 7 + dw 6,1 + dd au_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_sg_437 dw 7 + dw 6,1 + dd sg_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_jp_437 dw 7 + dw 6,1 + dd jp_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn ; Japanese MS-DOS uses "Y" and "N" - Yuki +_jp_932 dw 7 + dw 6,1 + dd jp_932 + dw 6,2 + dd ucase_932 + dw 6,4 + dd ucase_932 + dw 6,5 + dd fchar + dw 6,6 + dd jp_collate_932 + dw 6,7 + dd jp_dbcs_932 + dw 6,35 + dd en_yn +_kr_437 dw 7 + dw 6,1 + dd kr_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd kr_yn +_kr_934 dw 7 + dw 6,1 + dd kr_934 + dw 6,2 + dd ucase_934 + dw 6,4 + dd ucase_934 + dw 6,5 + dd fchar + dw 6,6 + dd kr_collate_934 + dw 6,7 + dd kr_dbcs_934 + dw 6,35 + dd kr_yn +_cn_437 dw 7 + dw 6,1 + dd cn_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd cn_yn +_cn_936 dw 7 + dw 6,1 + dd cn_936 + dw 6,2 + dd ucase_936 + dw 6,4 + dd ucase_936 + dw 6,5 + dd fchar + dw 6,6 + dd cn_collate_936 + dw 6,7 + dd cn_dbcs_936 + dw 6,35 + dd cn_yn_936 +_tr_857 dw 7 + dw 6,1 + dd tr_857 + dw 6,2 + dd ucase_857 + dw 6,4 + dd ucase_857 + dw 6,5 + dd fchar + dw 6,6 + dd tr_collate_857 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd tr_yn +_tr_850 dw 7 + dw 6,1 + dd tr_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd tr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd tr_yn +_in_437 dw 7 + dw 6,1 + dd in_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd en_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd en_yn +_pt_860 dw 7 + dw 6,1 + dd pt_860 + dw 6,2 + dd ucase_860 + dw 6,4 + dd ucase_860 + dw 6,5 + dd fchar + dw 6,6 + dd pt_collate_860 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pt_yn +_pt_850 dw 7 + dw 6,1 + dd pt_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd pt_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pt_yn +_pt_858 dw 7 + dw 6,1 + dd pt_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd pt_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd pt_yn +_fi_850 dw 7 + dw 6,1 + dd fi_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd fi_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fi_yn +_fi_858 dw 7 + dw 6,1 + dd fi_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd fi_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fi_yn +_fi_437 dw 7 + dw 6,1 + dd fi_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd fi_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fi_yn +_bg_855 dw 7 + dw 6,1 + dd bg_855 + dw 6,2 + dd ucase_855 + dw 6,4 + dd ucase_855 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_855 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_855 +_bg_872 dw 7 + dw 6,1 + dd bg_872 + dw 6,2 + dd ucase_872 + dw 6,4 + dd ucase_872 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_872 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_872 +_bg_850 dw 7 + dw 6,1 + dd bg_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn +_bg_858 dw 7 + dw 6,1 + dd bg_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn +_bg_866 dw 8 + dw 6,1 + dd bg_866 + dw 6,2 + dd ucase_866 + dw 6,3 + dd lcase_866 + dw 6,4 + dd ucase_866 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_866 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_866 +_bg_808 dw 8 + dw 6,1 + dd bg_808 + dw 6,2 + dd ucase_808 + dw 6,3 + dd lcase_808 + dw 6,4 + dd ucase_808 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_808 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_808 +_bg_849 dw 8 + dw 6,1 + dd bg_849 + dw 6,2 + dd ucase_849 + dw 6,3 + dd lcase_849 + dw 6,4 + dd ucase_849 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_849 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_849 +_bg_1131 dw 8 + dw 6,1 + dd bg_1131 + dw 6,2 + dd ucase_1131 + dw 6,3 + dd lcase_1131 + dw 6,4 + dd ucase_1131 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_1131 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_1131 +_bg_30033 dw 8 + dw 6,1 + dd bg_30033 + dw 6,2 + dd ucase_30033 + dw 6,3 + dd lcase_30033 + dw 6,4 + dd ucase_30033 + dw 6,5 + dd fchar + dw 6,6 + dd bg_collate_30033 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd bg_yn_30033 +_by_849 dw 8 + dw 6,1 + dd by_849 + dw 6,2 + dd ucase_849 + dw 6,3 + dd lcase_849 + dw 6,4 + dd ucase_849 + dw 6,5 + dd fchar + dw 6,6 + dd by_collate_849 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd by_yn_849 +_by_1131 dw 8 + dw 6,1 + dd by_1131 + dw 6,2 + dd ucase_1131 + dw 6,3 + dd lcase_1131 + dw 6,4 + dd ucase_1131 + dw 6,5 + dd fchar + dw 6,6 + dd by_collate_1131 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd by_yn_1131 +_by_850 dw 7 + dw 6,1 + dd by_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd by_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd by_yn +_by_858 dw 7 + dw 6,1 + dd by_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd by_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd by_yn +_ua_848 dw 8 + dw 6,1 + dd ua_848 + dw 6,2 + dd ucase_848 + dw 6,3 + dd lcase_848 + dw 6,4 + dd ucase_848 + dw 6,5 + dd fchar + dw 6,6 + dd ua_collate_848 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ua_yn_848 +_ua_1125 dw 8 + dw 6,1 + dd ua_1125 + dw 6,2 + dd ucase_1125 + dw 6,3 + dd lcase_1125 + dw 6,4 + dd ucase_1125 + dw 6,5 + dd fchar + dw 6,6 + dd ua_collate_1125 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ua_yn_1125 +_sr_852 dw 7 + dw 6,1 + dd sr_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_sr_855 dw 7 + dw 6,1 + dd sr_855 + dw 6,2 + dd ucase_855 + dw 6,4 + dd ucase_855 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_855 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn_855 +_sr_872 dw 7 + dw 6,1 + dd sr_872 + dw 6,2 + dd ucase_872 + dw 6,4 + dd ucase_872 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_872 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn_872 +_sr_850 dw 7 + dw 6,1 + dd sr_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_sr_858 dw 7 + dw 6,1 + dd sr_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_hr_852 dw 7 + dw 6,1 + dd hr_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd hr_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd hr_yn +_hr_850 dw 7 + dw 6,1 + dd hr_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd hr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd hr_yn +_hr_858 dw 7 + dw 6,1 + dd hr_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd hr_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd hr_yn +_si_852 dw 7 + dw 6,1 + dd si_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd si_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd si_yn +_si_850 dw 7 + dw 6,1 + dd si_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd si_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd si_yn +_si_858 dw 7 + dw 6,1 + dd si_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd si_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd si_yn +_ba_852 dw 7 + dw 6,1 + dd ba_852 + dw 6,2 + dd ucase_852 + dw 6,4 + dd ucase_852 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_852 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_ba_850 dw 7 + dw 6,1 + dd ba_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_ba_858 dw 7 + dw 6,1 + dd ba_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn +_ba_855 dw 7 + dw 6,1 + dd ba_855 + dw 6,2 + dd ucase_855 + dw 6,4 + dd ucase_855 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_855 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn_855 +_ba_872 dw 7 + dw 6,1 + dd ba_872 + dw 6,2 + dd ucase_872 + dw 6,4 + dd ucase_872 + dw 6,5 + dd fchar + dw 6,6 + dd sh_collate_872 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd sh_yn_872 +_mk_855 dw 7 + dw 6,1 + dd mk_855 + dw 6,2 + dd ucase_855 + dw 6,4 + dd ucase_855 + dw 6,5 + dd fchar + dw 6,6 + dd mk_collate_855 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd mk_yn_855 +_mk_872 dw 7 + dw 6,1 + dd mk_872 + dw 6,2 + dd ucase_872 + dw 6,4 + dd ucase_872 + dw 6,5 + dd fchar + dw 6,6 + dd mk_collate_872 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd mk_yn_872 +_mk_850 dw 7 + dw 6,1 + dd mk_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd mk_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd mk_yn +_mk_858 dw 7 + dw 6,1 + dd mk_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd mk_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd mk_yn +_me_850 dw 7 + dw 6,1 + dd me_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd me_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd me_yn +_me_858 dw 7 + dw 6,1 + dd me_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd me_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd me_yn +_me_864 dw 7 + dw 6,1 + dd me_864 + dw 6,2 + dd ucase_864 + dw 6,4 + dd ucase_864 + dw 6,5 + dd fchar + dw 6,6 + dd me_collate_864 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd me_yn_864 +_il_850 dw 7 + dw 6,1 + dd il_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd il_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd il_yn +_il_858 dw 7 + dw 6,1 + dd il_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd il_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd il_yn +_il_862 dw 7 + dw 6,1 + dd il_862 + dw 6,2 + dd ucase_862 + dw 6,4 + dd ucase_862 + dw 6,5 + dd fchar + dw 6,6 + dd il_collate_862 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd il_yn_862 +_nl_BE_850 dw 7 + dw 6,1 + dd nl_BE_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd nl_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_nl_BE_858 dw 7 + dw 6,1 + dd nl_BE_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd nl_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_nl_BE_437 dw 7 + dw 6,1 + dd nl_BE_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd nl_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd nl_yn +_fr_BE_850 dw 7 + dw 6,1 + dd fr_BE_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_fr_BE_858 dw 7 + dw 6,1 + dd fr_BE_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_fr_BE_437 dw 7 + dw 6,1 + dd fr_BE_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_de_BE_850 dw 7 + dw 6,1 + dd de_BE_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_de_BE_858 dw 7 + dw 6,1 + dd de_BE_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_de_BE_437 dw 7 + dw 6,1 + dd de_BE_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_es_ES_850 dw 7 + dw 6,1 + dd es_ES_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_es_ES_858 dw 7 + dw 6,1 + dd es_ES_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_es_ES_437 dw 7 + dw 6,1 + dd es_ES_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd es_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd es_yn +_ca_ES_850 dw 7 + dw 6,1 + dd ca_ES_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd ca_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ca_yn +_ca_ES_858 dw 7 + dw 6,1 + dd ca_ES_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd ca_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ca_yn +_ca_ES_437 dw 7 + dw 6,1 + dd ca_ES_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd ca_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd ca_yn +_gl_ES_850 dw 7 + dw 6,1 + dd gl_ES_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd gl_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gl_yn +_gl_ES_858 dw 7 + dw 6,1 + dd gl_ES_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd gl_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gl_yn +_gl_ES_437 dw 7 + dw 6,1 + dd gl_ES_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd gl_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd gl_yn +_eu_ES_850 dw 7 + dw 6,1 + dd eu_ES_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd eu_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd eu_yn +_eu_ES_858 dw 7 + dw 6,1 + dd eu_ES_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd eu_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd eu_yn +_eu_ES_437 dw 7 + dw 6,1 + dd eu_ES_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd eu_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd eu_yn +_de_CH_850 dw 7 + dw 6,1 + dd de_CH_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_de_CH_858 dw 7 + dw 6,1 + dd de_CH_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_de_CH_437 dw 7 + dw 6,1 + dd de_CH_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd de_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd de_yn +_fr_CH_850 dw 7 + dw 6,1 + dd fr_CH_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_fr_CH_858 dw 7 + dw 6,1 + dd fr_CH_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_fr_CH_437 dw 7 + dw 6,1 + dd fr_CH_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd fr_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd fr_yn +_it_CH_850 dw 7 + dw 6,1 + dd it_CH_850 + dw 6,2 + dd ucase_850 + dw 6,4 + dd ucase_850 + dw 6,5 + dd fchar + dw 6,6 + dd it_collate_850 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd it_yn +_it_CH_858 dw 7 + dw 6,1 + dd it_CH_858 + dw 6,2 + dd ucase_858 + dw 6,4 + dd ucase_858 + dw 6,5 + dd fchar + dw 6,6 + dd it_collate_858 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd it_yn +_it_CH_437 dw 7 + dw 6,1 + dd it_CH_437 + dw 6,2 + dd ucase_437 + dw 6,4 + dd ucase_437 + dw 6,5 + dd fchar + dw 6,6 + dd it_collate_437 + dw 6,7 + dd dbcs_empty + dw 6,35 + dd it_yn + +%define MDY 0 ; month/day/year +%define DMY 1 ; day/month/year +%define YMD 2 ; year/month/day + +%define _12 0 ; time as AM/PM +%define _24 1 ; 24-hour format + +; Country ID : international numbering +; Codepage : codepage to use by default +; Date format : M = Month, D = Day, Y = Year (4digit); 0=USA, 1=Europe, 2=Japan +; Currency : $ = dollar, EUR = EURO (ALT-128), UK uses the pound sign +; Thousands : separator for 1000s (1,000,000 bytes; Dutch: 1.000.000 bytes) +; Decimals : separator for decimals (2.5 KB; Dutch: 2,5 KB) +; Datesep : Date separator (2/4/2004 or 2-4-2004 for example) +; Timesep : usually ":" is used to separate hours, minutes and seconds +; Currencyf : Currency format (bit array) +; bit 2 = set if currency symbol replaces decimal point +; bit 1 = number of spaces between value and currency symbol +; bit 0 = 0 if currency symbol precedes value +; 1 if currency symbol follows value +; Currencyp : Currency precision +; Time format : 0=12 hour format (AM/PM), 1=24 hour format (4:12 PM is 16:12) + +%macro cnf 15 + db 0FFh,"CTYINFO" + dw 22; length +dw %1,%2,%3 ; ID,CP,DF + db %4,%5,%6,%7,%8 ; currency + dw %9,%10,%11,%12 ; 1000, 0.1, DS,TS + db %13,%14,%15 ; CF,Pr,TF +%endmacro; | | | | | | | | | | | +; ID CP DF currency 1000 0.1 DS TS CF Pr TF Country Contrib +;----------------------------------------------------------------------------- +us_437 cnf 1,437,MDY,"$", 0,0,0,0,",",".","-",":",0,2,_12; United States +us_850 cnf 1,850,MDY,"$", 0,0,0,0,",",".","-",":",0,2,_12; United States +us_858 cnf 1,858,MDY,"$", 0,0,0,0,",",".","-",":",0,2,_12; United States +ca_863 cnf 2,863,YMD,"$", 0,0,0,0," ",",","-",":",3,2,_24; Canada-French +ca_850 cnf 2,850,YMD,"$", 0,0,0,0," ",",","-",":",3,2,_24; Canada-French +ca_858 cnf 2,858,YMD,"$", 0,0,0,0," ",",","-",":",3,2,_24; Canada-French +la_850 cnf 3,850,DMY,"$", 0,0,0,0,",",".","/",":",0,2,_12; Latin America +la_858 cnf 3,858,DMY,"$", 0,0,0,0,",",".","/",":",0,2,_12; Latin America +la_437 cnf 3,437,DMY,"$", 0,0,0,0,",",".","/",":",0,2,_12; Latin America +ru_866 cnf 7,866,DMY,0E0h,".", 0,0,0," ",",",".",":",3,2,_24; Russia Arkady +ru_808 cnf 7,808,DMY,0E0h,".", 0,0,0," ",",",".",":",3,2,_24; Russia +ru_855 cnf 7,855,DMY,0E1h,".", 0,0,0," ",",",".",":",3,2,_24; Russia +ru_872 cnf 7,872,DMY,0E1h,".", 0,0,0," ",",",".",":",3,2,_24; Russia +ru_852 cnf 7,852,DMY,"R","U","B",0,0," ",",",".",":",3,2,_24; Russia +ru_850 cnf 7,850,DMY,"R","U","B",0,0," ",",",".",":",3,2,_24; Russia +ru_858 cnf 7,858,DMY,"R","U","B",0,0," ",",",".",":",3,2,_24; Russia +ru_437 cnf 7,437,DMY,"R","U","B",0,0," ",",",".",":",3,2,_24; Russia +gr_869 cnf 30,869,DMY,0A8h,0D1h,0C7h,0,0,".",",","/",":",1,2,_12; Greece +gr_737 cnf 30,737,DMY,84h,93h,90h,0,0,".",",","/",":",1,2,_12; Greece +gr_850 cnf 30,850,DMY,"E","Y","P",0,0,".",",","/",":",1,2,_12; Greece +gr_858 cnf 30,858,DMY,0D5h, 0,0,0,0,".",",","/",":",1,2,_12; Greece +nl_850 cnf 31,850,DMY,"E","U","R",0,0,".",",","-",":",0,2,_24; Netherlands Bart +nl_858 cnf 31,858,DMY,0D5h, 0,0,0,0,".",",","-",":",0,2,_24; Netherlands +nl_437 cnf 31,437,DMY,"E","U","R",0,0,".",",","-",":",0,2,_24; Netherlands +be_850 cnf 32,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Belgium +be_858 cnf 32,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24; Belgium +be_437 cnf 32,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Belgium +fr_850 cnf 33,850,DMY,"E","U","R",0,0," ",",",".",":",0,2,_24; France +fr_858 cnf 33,858,DMY,0D5h, 0,0,0,0," ",",",".",":",0,2,_24; France +fr_437 cnf 33,437,DMY,"E","U","R",0,0," ",",",".",":",0,2,_24; France +es_850 cnf 34,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Spain Aitor +es_858 cnf 34,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24; Spain +es_437 cnf 34,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Spain +hu_852 cnf 36,852,YMD,"F","t", 0,0,0," ",",",".",":",3,2,_24; Hungary +hu_850 cnf 36,850,YMD,"F","t", 0,0,0," ",",",".",":",3,2,_24; Hungary +hu_858 cnf 36,858,YMD,"F","t", 0,0,0," ",",",".",":",3,2,_24; Hungary +yu_852 cnf 38,852,YMD,"D","i","n",0,0,".",",","-",":",2,2,_24; Yugoslavia +yu_855 cnf 38,855,YMD,0A7h,0B7h,0D4h,0,0,".",",","-",":",2,2,_24; Yugoslavia +yu_872 cnf 38,872,YMD,0A7h,0B7h,0D4h,0,0,".",",","-",":",2,2,_24; Yugoslavia +yu_850 cnf 38,850,YMD,"D","i","n",0,0,".",",","-",":",2,2,_24; Yugoslavia +yu_858 cnf 38,858,YMD,"D","i","n",0,0,".",",","-",":",2,2,_24; Yugoslavia +it_850 cnf 39,850,DMY,"E","U","R",0,0,".",",","/",".",0,2,_24; Italy +it_858 cnf 39,858,DMY,0D5h, 0,0,0,0,".",",","/",".",0,2,_24; Italy +it_437 cnf 39,437,DMY,"E","U","R",0,0,".",",","/",".",0,2,_24; Italy +ro_852 cnf 40,852,YMD,"L","e","i",0,0,".",",","-",":",0,2,_24; Romania +ro_850 cnf 40,850,YMD,"L","e","i",0,0,".",",","-",":",0,2,_24; Romania +ro_858 cnf 40,858,YMD,"L","e","i",0,0,".",",","-",":",0,2,_24; Romania +ch_850 cnf 41,850,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; Switzerland +ch_858 cnf 41,858,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; Switzerland +ch_437 cnf 41,437,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; Switzerland +cz_852 cnf 42,852,YMD,"K","C","s",0,0,".",",","-",":",2,2,_24; Czechoslovakia +cz_850 cnf 42,850,YMD,"K","C","s",0,0,".",",","-",":",2,2,_24; Czechoslovakia +cz_858 cnf 42,858,YMD,"K","C","s",0,0,".",",","-",":",2,2,_24; Czechoslovakia +at_850 cnf 43,850,DMY,"E","U","R",0,0,".",",",".",".",0,2,_24; Austria +at_858 cnf 43,858,DMY,0D5h, 0,0,0,0,".",",",".",".",0,2,_24; Austria +at_437 cnf 43,437,DMY,"E","U","R",0,0,".",",",".",".",0,2,_24; Austria +uk_850 cnf 44,850,DMY,9Ch, 0,0,0,0,",",".","/",":",0,2,_24; United Kingdom +uk_858 cnf 44,858,DMY,9Ch, 0,0,0,0,",",".","/",":",0,2,_24; United Kingdom +uk_437 cnf 44,437,DMY,9Ch, 0,0,0,0,",",".","/",":",0,2,_24; United Kingdom +dk_865 cnf 45,865,DMY,"k","r", 0,0,0,".",",","-",".",2,2,_24; Denmark +dk_850 cnf 45,850,DMY,"k","r", 0,0,0,".",",","-",".",2,2,_24; Denmark +dk_858 cnf 45,858,DMY,"k","r", 0,0,0,".",",","-",".",2,2,_24; Denmark +se_850 cnf 46,850,YMD,"K","r", 0,0,0," ",",","-",".",3,2,_24; Sweden +se_858 cnf 46,858,YMD,"K","r", 0,0,0," ",",","-",".",3,2,_24; Sweden +se_437 cnf 46,437,YMD,"K","r", 0,0,0," ",",","-",".",3,2,_24; Sweden +no_865 cnf 47,865,DMY,"K","r", 0,0,0,".",",",".",":",2,2,_24; Norway +no_850 cnf 47,850,DMY,"K","r", 0,0,0,".",",",".",":",2,2,_24; Norway +no_858 cnf 47,858,DMY,"K","r", 0,0,0,".",",",".",":",2,2,_24; Norway +pl_852 cnf 48,852,YMD,"Z",88h, 0,0,0,".",",","-",":",0,2,_24; Poland Michal +pl_850 cnf 48,850,YMD,"P","L","N",0,0,".",",","-",":",0,2,_24; Poland +pl_858 cnf 48,858,YMD,"P","L","N",0,0,".",",","-",":",0,2,_24; Poland +de_850 cnf 49,850,DMY,"E","U","R",0,0,".",",",".",".",1,2,_24; Germany Tom +de_858 cnf 49,850,DMY,0D5h, 0,0,0,0,".",",",".",".",1,2,_24; Germany +de_437 cnf 49,437,DMY,"E","U","R",0,0,".",",",".",".",1,2,_24; Germany +ar_850 cnf 54,850,DMY,"$", 0,0,0,0,".",",","/",".",0,2,_24; Argentina +ar_858 cnf 54,858,DMY,"$", 0,0,0,0,".",",","/",".",0,2,_24; Argentina +ar_437 cnf 54,437,DMY,"$", 0,0,0,0,".",",","/",".",0,2,_24; Argentina +br_850 cnf 55,850,DMY,"C","r","$",0,0,".",",","/",":",2,2,_24; Brazil +br_858 cnf 55,858,DMY,"C","r","$",0,0,".",",","/",":",2,2,_24; Brazil +br_437 cnf 55,437,DMY,"C","r","$",0,0,".",",","/",":",2,2,_24; Brazil +my_437 cnf 60,437,DMY,"$", 0,0,0,0,",",".","/",":",0,2,_12; Malaysia +au_437 cnf 61,437,DMY,"$", 0,0,0,0,",",".","-",":",0,2,_12; Australia +au_850 cnf 61,850,DMY,"$", 0,0,0,0,",",".","-",":",0,2,_12; Australia +au_858 cnf 61,858,DMY,"$", 0,0,0,0,",",".","-",":",0,2,_12; Australia +sg_437 cnf 65,437,DMY,"$", 0,0,0,0,",",".","/",":",0,2,_12; Singapore +jp_932 cnf 81,932,YMD,5Ch, 0,0,0,0,",",".","-",":",0,0,_24; Japan Yuki +jp_437 cnf 81,437,YMD,9Dh, 0,0,0,0,",",".","-",":",0,0,_24; Japan +kr_934 cnf 82,934,YMD,5Ch, 0,0,0,0,",",".",".",":",0,0,_24; Korea +kr_437 cnf 82,437,YMD,"K","R","W",0,0,",",".",".",":",0,0,_24; Korea +cn_936 cnf 86,936,YMD,5Ch, 0,0,0,0,",",".",".",":",0,2,_12; China +cn_437 cnf 86,437,YMD,9Dh, 0,0,0,0,",",".",".",":",0,2,_12; China +tr_857 cnf 90,857,DMY,"T","L", 0,0,0,".",",","/",":",4,2,_24; Turkey +tr_850 cnf 90,850,DMY,"T","L", 0,0,0,".",",","/",":",4,2,_24; Turkey +in_437 cnf 91,437,DMY,"R","s", 0,0,0,".",",","/",":",0,2,_24; India +pt_860 cnf 351,860,DMY,"E","U","R",0,0,".",",","-",":",0,2,_24; Portugal +pt_850 cnf 351,850,DMY,"E","U","R",0,0,".",",","-",":",0,2,_24; Portugal +pt_858 cnf 351,858,DMY,0D5h, 0,0,0,0,".",",","-",":",0,2,_24; Portugal +fi_850 cnf 358,850,DMY,"E","U","R",0,0," ",",",".",".",3,2,_24; Finland Wolf +fi_858 cnf 358,858,DMY,0D5h, 0,0,0,0," ",",",".",".",3,2,_24; Finland +fi_437 cnf 358,437,DMY,"E","U","R",0,0," ",",",".",".",3,2,_24; +bg_855 cnf 359,855,DMY,0D0h,0EBh,".",0,0," ",",",".",",",3,2,_24; Bulgaria Lucho&RDPK7 +bg_872 cnf 359,872,DMY,0D0h,0EBh,".",0,0," ",",",".",",",3,2,_24; Bulgaria Lucho&RDPK7 +bg_850 cnf 359,850,DMY,"B","G","N",0,0," ",",",".",",",3,2,_24; Bulgaria RDPK7 +bg_858 cnf 359,858,DMY,"B","G","N",0,0," ",",",".",",",3,2,_24; Bulgaria RDPK7 +bg_866 cnf 359,866,DMY,0ABh,0A2h,".",0,0," ",",",".",",",3,2,_24; Bulgaria +bg_808 cnf 359,808,DMY,0ABh,0A2h,".",0,0," ",",",".",",",3,2,_24; Bulgaria +bg_849 cnf 359,849,DMY,0ABh,0A2h,".",0,0," ",",",".",",",3,2,_24; Bulgaria +bg_1131 cnf 359,1131,DMY,0ABh,0A2h,".",0,0," ",",",".",",",3,2,_24; Bulgaria +bg_30033 cnf 359,30033,DMY,0ABh,0A2h,".",0,0," ",",",".",",",3,2,_24; Bulgaria RDPK7 +by_849 cnf 375,849,DMY,0E0h,0E3h,0A1h,".",0," ",",",".",":",3,2,_24;Belarus +by_1131 cnf 375,1131,DMY,0E0h,0E3h,0A1h,".",0," ",",",".",":",3,2,_24; Belarus +by_850 cnf 375,850,DMY,"B","Y","R",0,0," ",",",".",",",3,2,_24; Belarus +by_858 cnf 375,858,DMY,"B","Y","R",0,0," ",",",".",",",3,2,_24; Belarus +ua_848 cnf 380,848,DMY,0A3h,0E0h,0ADh,".",0," ",",",".",":",3,2,_24;Ukraine Oleg +ua_1125 cnf 380,1125,DMY,0A3h,0E0h,0ADh,".",0," ",",",".",":",3,2,_24; Ukraine +sr_855 cnf 381,855,DMY,0A7h,0B7h,0D4h,0,0,".",",",".",":",3,2,_24; Serbia +sr_872 cnf 381,872,DMY,0A7h,0B7h,0D4h,0,0,".",",",".",":",3,2,_24; Serbia +sr_852 cnf 381,852,DMY,"D","i","n",0,0,".",",",".",":",3,2,_24; Serbia +sr_850 cnf 381,850,DMY,"D","i","n",0,0,".",",",".",":",3,2,_24; Serbia +sr_858 cnf 381,858,DMY,"D","i","n",0,0,".",",",".",":",3,2,_24; Serbia +hr_852 cnf 384,852,DMY,"k","n", 0,0,0,".",",",".",".",3,2,_24; Croatia +hr_850 cnf 384,850,DMY,"k","n", 0,0,0,".",",",".",".",3,2,_24; Croatia +hr_858 cnf 384,858,DMY,"k","n", 0,0,0,".",",",".",".",3,2,_24; Croatia +si_852 cnf 386,852,DMY,"S","I","T",0,0,".",",",".",":",3,2,_24; Slovenia +si_850 cnf 386,850,DMY,"S","I","T",0,0,".",",",".",":",3,2,_24; Slovenia +si_858 cnf 386,858,DMY,"S","I","T",0,0,".",",",".",":",3,2,_24; Slovenia +ba_852 cnf 387,852,DMY,"K","M", 0,0,0,".",",",".",".",1,2,_24; Bosnia +ba_850 cnf 387,850,DMY,"K","M", 0,0,0,".",",",".",".",1,2,_24; Bosnia +ba_858 cnf 387,858,DMY,"K","M", 0,0,0,".",",",".",".",1,2,_24; Bosnia +ba_855 cnf 387,855,DMY,"K","M", 0,0,0,".",",",".",":",1,2,_24; Bosnia +ba_872 cnf 387,872,DMY,"K","M", 0,0,0,".",",",".",":",1,2,_24; Bosnia +mk_855 cnf 389,855,DMY,0A7h,0A8h,0D4h,0,0,".",",",".",":",3,2,_24; Macedonia +mk_872 cnf 389,872,DMY,0A7h,0A8h,0D4h,0,0,".",",",".",":",3,2,_24; Macedonia +mk_850 cnf 389,850,DMY,"D","e","n",0,0,".",",",".",":",3,2,_24; Macedonia +mk_858 cnf 389,858,DMY,"D","e","n",0,0,".",",",".",":",3,2,_24; Macedonia +me_864 cnf 785,864,DMY,0A4h, 0,0,0,0,".",",","/",":",1,3,_12; Middle East +me_850 cnf 785,850,DMY,0CFh, 0,0,0,0,".",",","/",":",3,3,_12; Middle East +me_858 cnf 785,858,DMY,0CFh, 0,0,0,0,".",",","/",":",3,3,_12; Middle East +il_862 cnf 972,862,DMY,99h, 0,0,0,0,",","."," ",":",2,2,_24; Israel +il_850 cnf 972,850,DMY,"N","I","S",0,0,",","."," ",":",2,2,_24; Israel +il_858 cnf 972,858,DMY,"N","I","S",0,0,",","."," ",":",2,2,_24; Israel +es_ES_850 cnf 40034,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Spain: +es_ES_858 cnf 40034,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24; Spanish +es_ES_437 cnf 40034,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +ca_ES_850 cnf 41034,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Catalan +ca_ES_858 cnf 41034,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24 +ca_ES_437 cnf 41034,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +gl_ES_850 cnf 42034,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Galician +gl_ES_858 cnf 42034,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24 +gl_ES_437 cnf 42034,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +eu_ES_850 cnf 43034,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Basque +eu_ES_858 cnf 43034,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24 +eu_ES_437 cnf 43034,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +nl_BE_850 cnf 40032,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; Belgium: +nl_BE_858 cnf 40032,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24; Dutch +nl_BE_437 cnf 40032,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +fr_BE_850 cnf 41032,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; French +fr_BE_858 cnf 41032,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24 +fr_BE_437 cnf 41032,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +de_BE_850 cnf 42032,850,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24; German +de_BE_858 cnf 42032,858,DMY,0D5h, 0,0,0,0,".",",","/",":",0,2,_24 +de_BE_437 cnf 42032,437,DMY,"E","U","R",0,0,".",",","/",":",0,2,_24 +de_CH_850 cnf 40041,850,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; Switzerland +de_CH_858 cnf 40041,858,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; German +de_CH_437 cnf 40041,437,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24 +fr_CH_850 cnf 41041,850,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; French +fr_CH_858 cnf 41041,858,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24 +fr_CH_437 cnf 41041,437,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24 +it_CH_850 cnf 42041,850,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24; Italian +it_CH_858 cnf 42041,858,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24 +it_CH_437 cnf 42041,437,DMY,"F","r",".",0,0,"'",".",".",",",2,2,_24 + +; Uppercase equivalents of chars 80h to FFh +;------------------------------------------------------------------------------ +ucase_437 db 0FFh,"UCASE " ; Same as kernel's harcoded + dw 128 +db 128, 154, 69, 65, 142, 65, 143, 128 +db 69, 69, 69, 73, 73, 73, 142, 143 +db 144, 146, 146, 79, 153, 79, 85, 85 +db 89, 153, 154, 155, 156, 157, 158, 159 +db 65, 73, 79, 85, 165, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_850 db 0FFh,"UCASE " ; From Steffen Kaiser's UNF package + dw 128 ; small fix: 'ÿ' -> 'Y' -- eca +db 128, 154, 144, 182, 142, 183, 143, 128 +db 210, 211, 212, 216, 215, 222, 142, 143 +db 144, 146, 146, 226, 153, 227, 234, 235 +db 99, 153, 154, 157, 156, 157, 158, 159 +db 181, 214, 224, 233, 165, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 199, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 209, 209, 210, 211, 212, 73, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 229, 229, 230, 232 +db 232, 233, 234, 235, 237, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_858 db 0FFh,"UCASE " + dw 128 +db 128, 154, 144, 182, 142, 183, 143, 128 +db 210, 211, 212, 216, 215, 222, 142, 143 +db 144, 146, 146, 226, 153, 227, 234, 235 +db 99, 153, 154, 157, 156, 157, 158, 159 +db 181, 214, 224, 233, 165, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 199, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 209, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 229, 229, 230, 232 +db 232, 233, 234, 235, 237, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_860 db 0FFh,"UCASE " + dw 128 ; Derived from ucase_437 +db 128, 154, 144, 143, 142, 145, 134, 128 +db 137, 137, 146, 139, 140, 152, 142, 143 +db 144, 145, 146, 140, 153, 169, 150, 157 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 134, 139, 159, 150, 165, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_857 db 0FFh,"UCASE " ; Turkish. Needs NLSFUNC for proper uppercasing + dw 128 ; of letter "i" (dotted i) +db 128, 154, 144, 182, 142, 183, 143, 128 +db 210, 211, 212, 216, 215, 73, 142, 143 +db 144, 146, 146, 226, 153, 227, 234, 235 +db 152, 153, 154, 157, 156, 157, 158, 158 +db 181, 214, 224, 233, 165, 165, 166, 166 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 199, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 229, 229, 230, 231 +db 232, 233, 234, 235, 222, 89, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_863 db 0FFh,"UCASE " + dw 128 ; Derived from ucase_437 +db 128, 154, 144, 132, 132, 142, 134, 128 +db 146, 148, 145, 149, 168, 141, 142, 143 +db 144, 145, 146, 153, 148, 149, 158, 157 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 160, 161, 79, 85, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_865 db 0FFh,"UCASE " + dw 128 +db 128, 154, 144, 65, 142, 65, 143, 128 +db 69, 69, 69, 73, 73, 73, 142, 143 +db 144, 146, 146, 89, 153, 89, 85, 85 +db 89, 153, 154, 157, 156, 157, 158, 159 +db 65, 73, 79, 85, 165, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_866 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 240, 240, 242, 242, 244, 244, 246, 246 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_808 equ ucase_866 + +ucase_852 db 0FFh,"UCASE " + dw 128 +db 128, 154, 144, 182, 142, 222, 143, 128 +db 157, 211, 138, 138, 215, 141, 142, 143 +db 144, 145, 145, 226, 153, 149, 149, 151 +db 151, 153, 154, 155, 155, 157, 158, 172 +db 181, 146, 224, 233, 164, 164, 166, 166 +db 168, 168, 170, 141, 172, 184, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 189, 191 +db 192, 193, 194, 195, 196, 197, 198, 198 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 209, 209, 210, 211, 210, 213, 214, 215 +db 183, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 227, 213, 230, 230 +db 232, 233, 232, 235, 237, 237, 221, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 235, 252, 252, 254, 255 + +ucase_855 db 0FFh,"UCASE " + dw 128 +db 129, 129, 131, 131, 133, 133, 135, 135 +db 137, 137, 139, 139, 141, 141, 143, 143 +db 145, 145, 147, 147, 149, 149, 151, 151 +db 153, 153, 155, 155, 157, 157, 159, 159 +db 161, 161, 163, 163, 165, 165, 167, 167 +db 169, 169, 171, 171, 173, 173, 174, 175 +db 176, 177, 178, 179, 180, 182, 182, 184 +db 184, 185, 186, 187, 188, 190, 190, 191 +db 192, 193, 194, 195, 196, 197, 199, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 209, 209, 211, 211, 213, 213, 215, 215 +db 221, 217, 218, 219, 220, 221, 224, 223 +db 224, 226, 226, 228, 228, 230, 230, 232 +db 232, 234, 234, 236, 236, 238, 238, 239 +db 240, 242, 242, 244, 244, 246, 246, 248 +db 248, 250, 250, 252, 252, 253, 254, 255 + +ucase_872 equ ucase_855 + +ucase_30033 db 0FFh,"UCASE " ; MIK codepage + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_869 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 134, 155, 141, 143, 144 +db 145, 145, 146, 149, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 164, 165 +db 166, 217, 218, 219, 220, 167, 168, 223 +db 169, 170, 172, 173, 181, 182, 183, 184 +db 189, 190, 198, 199, 207, 207, 208, 239 +db 240, 241, 209, 210, 211, 245, 212, 247 +db 248, 249, 213, 150, 150, 152, 254, 255 + +ucase_737 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 145, 146, 147, 148, 149, 150 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 151, 234, 235, 236, 244, 237, 238, 239 +db 245, 240, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_932 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_934 equ ucase_932 +ucase_936 equ ucase_932 + +ucase_848 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 240, 240, 242, 242, 244, 244, 246, 246 +db 248, 248, 250, 251, 252, 253, 254, 255 + +ucase_1125 equ ucase_848 + +ucase_849 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 240, 240, 242, 242, 244, 244, 246, 246 +db 248, 248, 250, 251, 252, 252, 254, 255 + +ucase_1131 equ ucase_849 + +ucase_862 db 0FFh,"UCASE " + dw 128 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 65, 73, 79, 85, 165, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +ucase_864 equ ucase_932 + +; Lowercase equivalents of chars 00h to FFh +;------------------------------------------------------------------------------ +lcase_866 db 0FFh,"LCASE " + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 91, 92, 93, 94, 95 +db 96, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 123, 124, 125, 126, 127 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 241, 241, 243, 243, 245, 245, 247, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +lcase_808 equ lcase_866 + +lcase_848 db 0FFh,"LCASE " + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 91, 92, 93, 94, 95 +db 96, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 123, 124, 125, 126, 127 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 241, 241, 243, 243, 245, 245, 247, 247 +db 249, 249, 250, 251, 252, 253, 254, 255 + +lcase_1125 equ lcase_848 + +lcase_849 db 0FFh,"LCASE " + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 91, 92, 93, 94, 95 +db 96, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 123, 124, 125, 126, 127 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 241, 241, 243, 243, 245, 245, 247, 247 +db 249, 249, 250, 251, 253, 253, 254, 255 + +lcase_1131 equ lcase_849 + +lcase_30033 db 0FFh,"LCASE " + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 91, 92, 93, 94, 95 +db 96, 97, 98, 99, 100, 101, 102, 103 +db 104, 105, 106, 107, 108, 109, 110, 111 +db 112, 113, 114, 115, 116, 117, 118, 119 +db 120, 121, 122, 123, 124, 125, 126, 127 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +; Filename terminator table +;------------------------------------------------------------------------------ +fchar db 0FFh,"FCHAR " ; Same as kernel's hardcoded + dw 22 ; Comments from RBIL +db 142 ; ??? (01h for MS-DOS 3.30-6.00) +db 0 ; lowest permissible character value for filename +db 255 ; highest permissible character value for filename +db 65 ; ??? (00h for MS-DOS 3.30-6.00) +db 0 ; first excluded character in range \ all characters in this +db 32 ; last excluded character in range / range are illegal +db 238 ; ??? (02h for MS-DOS 3.30-6.00) +db 14 ; number of illegal (terminator) characters +; characters which terminate a filename: +db 46, 34, 47, 92, 91, 93, 58, 124 ; ."/\[]:| +db 60, 62, 43, 61, 59, 44 ; <>+=;, + +; Collating sequence +;------------------------------------------------------------------------------ +en_collate_437 db 0FFh,"COLLATE" ; English, CP437 + dw 256 ; Same as kernel's harcoded +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 65, 67 +db 69, 69, 69, 73, 73, 73, 65, 65 +db 69, 65, 65, 79, 79, 79, 85, 85 +db 89, 79, 85, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 83, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +en_collate_850 db 0FFh,"COLLATE" ; English, CP850 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 65, 67 +db 69, 69, 69, 73, 73, 73, 65, 65 +db 69, 65, 65, 79, 79, 79, 85, 85 +db 89, 79, 85, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 73, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 83, 79, 79, 79, 79, 230, 231 +db 232, 85, 85, 85, 89, 89, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +en_collate_858 db 0FFh,"COLLATE" ; English, CP858 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 65, 67 +db 69, 69, 69, 73, 73, 73, 65, 65 +db 69, 65, 65, 79, 79, 79, 85, 85 +db 89, 79, 85, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 36, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 83, 79, 79, 79, 79, 230, 231 +db 232, 85, 85, 85, 89, 89, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +es_collate_437 db 0FFh,"COLLATE" ; Spanish, CP437 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 69, 70, 71, 72 +db 73, 74, 75, 76, 77, 78, 79, 81 +db 82, 83, 84, 85, 87, 88, 89, 90 +db 91, 92, 93, 94, 95, 96, 97, 98 +db 99, 65, 66, 67, 69, 70, 71, 72 +db 73, 74, 75, 76, 77, 78, 79, 81 +db 82, 83, 84, 85, 87, 88, 89, 90 +db 91, 92, 93, 123, 124, 125, 126, 127 +db 68, 88, 70, 65, 65, 65, 65, 68 +db 70, 70, 70, 74, 74, 74, 65, 65 +db 70, 65, 65, 81, 81, 81, 88, 88 +db 92, 81, 88, 36, 36, 36, 36, 36 +db 65, 74, 81, 88, 80, 80, 65, 81 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 86, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 79, 50, 254, 255 + +es_collate_850 db 0FFh,"COLLATE" ; Spanish, CP850 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 69, 70, 71, 72 +db 73, 74, 75, 76, 77, 78, 79, 81 +db 82, 83, 84, 85, 87, 88, 89, 90 +db 91, 92, 93, 94, 95, 96, 97, 98 +db 99, 65, 66, 67, 69, 70, 71, 72 +db 73, 74, 75, 76, 77, 78, 79, 81 +db 82, 83, 84, 85, 87, 88, 89, 90 +db 91, 92, 93, 123, 124, 125, 126, 127 +db 68, 87, 70, 65, 65, 65, 65, 68 +db 70, 70, 70, 74, 74, 74, 65, 65 +db 70, 65, 65, 81, 81, 81, 88, 88 +db 92, 81, 88, 81, 36, 81, 158, 36 +db 65, 74, 81, 88, 80, 80, 65, 81 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 69, 69, 70, 70, 70, 74, 74, 74 +db 74, 217, 218, 219, 220, 221, 74, 223 +db 81, 86, 81, 81, 81, 81, 230, 231 +db 232, 88, 88, 88, 92, 92, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +es_collate_858 db 0FFh,"COLLATE" ; Spanish, CP858 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 80 +db 81, 82, 83, 84, 85, 86, 87, 88 +db 89, 90, 91, 92, 93, 94, 95, 96 +db 97, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 80 +db 81, 82, 83, 84, 85, 86, 87, 88 +db 89, 90, 91, 123, 124, 125, 126, 127 +db 68, 86, 69, 65, 65, 65, 65, 68 +db 69, 69, 69, 73, 73, 73, 65, 65 +db 69, 65, 65, 80, 80, 80, 86, 86 +db 90, 80, 86, 80, 36, 80, 158, 36 +db 65, 73, 80, 86, 79, 79, 65, 80 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 36, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 80, 225, 80, 80, 80, 80, 230, 231 +db 232, 86, 86, 86, 90, 90, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +ca_collate_850 equ en_collate_850 ; Catalan, CP850 +ca_collate_858 equ en_collate_858 ; Catalan, CP858 +ca_collate_437 equ en_collate_437 ; Catalan, CP437 +gl_collate_850 equ en_collate_850 ; Gallegan, CP850 +gl_collate_858 equ en_collate_858 ; Gallegan, CP858 +gl_collate_437 equ en_collate_437 ; Gallegan, CP437 +eu_collate_850 equ en_collate_850 ; Basque, CP850 +eu_collate_858 equ en_collate_858 ; Basque, CP858 +eu_collate_437 equ en_collate_437 ; Basque, CP437 + +de_collate_850 equ en_collate_850 ; German, CP850 +de_collate_858 equ en_collate_858 ; German, CP858 +de_collate_437 equ en_collate_437 ; German, CP437 + +pt_collate_860 db 0FFh,"COLLATE" ; Portuguese, CP860 + dw 256 ; Derived from English CP437 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 65, 67 +db 69, 69, 69, 73, 79, 73, 65, 65 +db 69, 65, 69, 79, 79, 79, 85, 85 +db 73, 79, 85, 36, 36, 85, 36, 79 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 79, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 83, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +pt_collate_850 equ en_collate_850 ; Portuguese CP850 +pt_collate_858 equ en_collate_858 ; Portuguese CP858 +pt_collate_437 equ en_collate_437 ; Portuguese CP437 + + +fr_collate_863 db 0FFh,"COLLATE" ; French, CP863 + dw 256 ; Derived from English CP437 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 134, 67 +db 69, 69, 69, 73, 73, 141, 65, 143 +db 69, 69, 69, 79, 69, 73, 85, 85 +db 36, 79, 85, 36, 36, 85, 85, 36 +db 160, 161, 79, 85, 164, 165, 166, 167 +db 63, 169, 170, 171, 172, 173, 34, 34 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 83, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +fr_collate_850 equ en_collate_850 ; French, CP850 +fr_collate_858 equ en_collate_858 ; French, CP858 +fr_collate_437 equ en_collate_437 ; French, CP437 + +it_collate_850 equ en_collate_850 ; Italian, CP850 +it_collate_858 equ en_collate_858 ; Italian, CP858 +it_collate_437 equ en_collate_437 ; Italian, CP437 + +nl_collate_850 equ en_collate_850 ; Dutch, CP850 +nl_collate_858 equ en_collate_858 ; Dutch, CP858 +nl_collate_437 equ en_collate_437 ; Dutch, CP437 + +be_collate_850 equ en_collate_850 ; Belgium, CP850 +be_collate_858 equ en_collate_858 ; Belgium, CP858 +be_collate_437 equ en_collate_437 ; Belgium, CP437 + +tr_collate_857 db 0FFh,"COLLATE" ; Turkish, CP857 (with Euro) + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 69, 70, 71, 72 +db 74, 75, 77, 78, 79, 80, 81, 82 +db 84, 85, 86, 87, 89, 90, 92, 93 +db 94, 95, 96, 97, 98, 99, 100, 101 +db 102, 65, 66, 67, 69, 70, 71, 72 +db 74, 76, 77, 78, 79, 80, 81, 82 +db 84, 85, 86, 87, 89, 90, 92, 93 +db 94, 95, 96, 123, 124, 125, 126, 127 +db 68, 91, 70, 65, 65, 65, 65, 68 +db 70, 70, 70, 76, 76, 75, 65, 65 +db 70, 145, 145, 82, 83, 82, 90, 90 +db 76, 83, 91, 155, 36, 155, 88, 88 +db 65, 76, 82, 90, 81, 81, 73, 73 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 82, 65, 70, 70, 70, 36, 76, 76 +db 76, 217, 218, 219, 220, 221, 76, 223 +db 82, 225, 82, 82, 82, 82, 230, 32 +db 232, 90, 90, 90, 76, 95, 238, 239 +db 240, 241, 32, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +tr_collate_850 db 0FFh,"COLLATE" ; Turkish, CP850 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 69, 70, 71, 72 +db 74, 75, 77, 78, 79, 80, 81, 82 +db 84, 85, 86, 87, 89, 90, 92, 93 +db 94, 95, 96, 97, 98, 99, 100, 101 +db 102, 65, 66, 67, 69, 70, 71, 72 +db 74, 76, 77, 78, 79, 80, 81, 82 +db 84, 85, 86, 87, 89, 90, 92, 93 +db 94, 95, 96, 123, 124, 125, 126, 127 +db 68, 91, 70, 65, 65, 65, 65, 68 +db 70, 70, 70, 76, 76, 76, 65, 65 +db 70, 145, 145, 82, 83, 82, 90, 90 +db 95, 83, 91, 155, 36, 155, 36, 36 +db 65, 76, 82, 90, 81, 81, 65, 82 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 209, 209, 70, 70, 70, 75, 76, 76 +db 76, 217, 218, 219, 220, 221, 76, 223 +db 82, 225, 82, 82, 82, 82, 230, 231 +db 231, 90, 90, 90, 95, 95, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +dk_collate_865 db 0FFh,"COLLATE" ; Danish, CP865 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 93, 94, 95, 96, 97 +db 98, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 92, 67 +db 69, 69, 69, 73, 73, 73, 65, 92 +db 69, 90, 90, 79, 79, 79, 85, 85 +db 88, 79, 85, 91, 36, 91, 36, 36 +db 65, 73, 79, 85, 78, 78, 65, 79 +db 63, 169, 170, 171, 172, 33, 34, 36 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 83, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 78, 50, 254, 255 + +dk_collate_850 db 0FFh,"COLLATE" ; Danish, CP850 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 93, 94, 95, 96, 97 +db 98, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 92, 67 +db 69, 69, 69, 73, 73, 73, 65, 92 +db 69, 90, 90, 79, 79, 79, 85, 85 +db 88, 79, 85, 91, 36, 91, 36, 36 +db 65, 73, 79, 85, 78, 78, 65, 79 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 169, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 73, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 83, 79, 79, 79, 79, 230, 231 +db 232, 85, 85, 85, 88, 88, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +dk_collate_858 db 0FFh,"COLLATE" ; Danish, CP858 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 93, 94, 95, 96, 97 +db 98, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 92, 67 +db 69, 69, 69, 73, 73, 73, 65, 92 +db 69, 90, 90, 79, 79, 79, 85, 85 +db 88, 79, 85, 91, 36, 91, 36, 36 +db 65, 73, 79, 85, 78, 78, 65, 79 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 169, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 36, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 83, 79, 79, 79, 79, 230, 231 +db 232, 85, 85, 85, 88, 88, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +no_collate_865 equ dk_collate_865 ; Norwegian CP865 +no_collate_850 equ dk_collate_850 ; Norwegian CP850 +no_collate_858 equ dk_collate_858 ; Norwegian CP858 + +ru_collate_866 db 0FFh,"COLLATE" ; Russian, CP866 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 129, 130, 131, 132, 135, 137, 138 +db 140, 143, 145, 146, 148, 149, 151, 152 +db 153, 154, 155, 158, 160, 161, 162, 163 +db 165, 166, 167, 168, 169, 170, 171, 172 +db 128, 129, 130, 131, 132, 135, 137, 138 +db 140, 143, 145, 146, 148, 149, 151, 152 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 153, 154, 155, 158, 160, 161, 162, 163 +db 165, 166, 167, 168, 169, 170, 171, 172 +db 135, 135, 136, 136, 142, 142, 159, 159 +db 248, 249, 250, 251, 252, 36, 254, 255 + +ru_collate_808 equ ru_collate_866 ; Russian, CP808 + +ru_collate_852 db 0FFh,"COLLATE" ; Russian, CP852 (with Euro) + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 68, 69, 72, 74, 76, 77 +db 78, 79, 81, 82, 83, 85, 86, 88 +db 92, 93, 94, 96, 100, 102, 105, 106 +db 107, 108, 109, 114, 115, 116, 117, 118 +db 119, 65, 68, 69, 72, 74, 76, 77 +db 78, 79, 81, 82, 83, 85, 86, 88 +db 92, 93, 94, 96, 100, 102, 105, 106 +db 107, 108, 109, 123, 124, 125, 126, 127 +db 69, 103, 74, 65, 65, 102, 71, 69 +db 84, 74, 91, 91, 80, 111, 65, 71 +db 74, 83, 83, 88, 90, 83, 83, 98 +db 98, 90, 103, 101, 101, 84, 36, 70 +db 65, 79, 88, 102, 67, 67, 110, 110 +db 75, 75, 36, 111, 70, 99, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 74 +db 99, 185, 186, 187, 188, 112, 112, 191 +db 192, 193, 194, 195, 196, 197, 66, 66 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 73, 73, 72, 74, 72, 86, 79, 80 +db 74, 217, 218, 219, 220, 113, 102, 223 +db 88, 225, 88, 87, 87, 86, 97, 97 +db 94, 102, 94, 104, 108, 108, 113, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 104, 95, 95, 254, 255 + +pl_collate_852 db 0FFh,"COLLATE" ; Polish, CP852 (with Euro) + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 68, 69, 72, 74, 76, 77 +db 78, 79, 81, 82, 83, 85, 86, 88 +db 92, 93, 94, 96, 100, 102, 105, 106 +db 107, 108, 109, 114, 115, 116, 117, 118 +db 119, 65, 68, 69, 72, 74, 76, 77 +db 78, 79, 81, 82, 83, 85, 86, 88 +db 92, 93, 94, 96, 100, 102, 105, 106 +db 107, 108, 109, 123, 124, 125, 126, 127 +db 69, 103, 74, 65, 65, 102, 71, 69 +db 84, 74, 91, 91, 80, 111, 65, 71 +db 74, 83, 83, 88, 90, 83, 83, 98 +db 98, 90, 103, 101, 101, 84, 36, 70 +db 65, 79, 89, 102, 67, 67, 110, 110 +db 75, 75, 36, 111, 70, 99, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 74 +db 99, 185, 186, 187, 188, 112, 112, 191 +db 192, 193, 194, 195, 196, 197, 66, 66 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 73, 73, 72, 74, 72, 86, 79, 80 +db 74, 217, 218, 219, 220, 113, 102, 223 +db 89, 225, 88, 87, 87, 86, 97, 97 +db 94, 102, 94, 104, 108, 108, 113, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 104, 95, 95, 254, 255 + +pl_collate_850 db 0FFh,"COLLATE" ; Polish, CP850 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 65, 67 +db 69, 69, 69, 73, 73, 73, 65, 65 +db 69, 65, 65, 79, 79, 79, 85, 85 +db 89, 79, 85, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 73, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 66, 79, 79, 79, 79, 230, 97 +db 97, 85, 85, 85, 89, 89, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +pl_collate_858 db 0FFh,"COLLATE" ; Polish, CP858 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 67, 85, 69, 65, 65, 65, 65, 67 +db 69, 69, 69, 73, 73, 73, 65, 65 +db 69, 65, 65, 79, 79, 79, 85, 85 +db 89, 79, 85, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 184, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 36, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 66, 79, 79, 79, 79, 230, 97 +db 97, 85, 85, 85, 89, 89, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +ru_collate_855 db 0FFh,"COLLATE" ; Russian, CP855 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 133, 133, 134, 134, 135, 135, 136, 136 +db 139, 139, 141, 141, 142, 142, 144, 144 +db 147, 147, 150, 150, 156, 156, 157, 157 +db 159, 159, 164, 164, 171, 171, 167, 167 +db 128, 128, 129, 129, 162, 162, 132, 132 +db 135, 135, 160, 160, 131, 131, 34, 34 +db 176, 177, 178, 179, 180, 161, 161, 140 +db 140, 185, 186, 187, 188, 143, 143, 191 +db 192, 193, 194, 195, 196, 197, 145, 145 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 146, 146, 148, 148, 149, 149, 151, 151 +db 152, 217, 218, 219, 220, 152, 172, 223 +db 172, 153, 153, 154, 154, 155, 155, 158 +db 158, 137, 137, 130, 130, 169, 169, 239 +db 240, 168, 168, 138, 138, 165, 165, 170 +db 170, 166, 166, 163, 163, 253, 254, 255 + +ru_collate_872 equ ru_collate_855 ; Russian CP872 +ru_collate_850 equ en_collate_850 ; Russian CP850 +ru_collate_858 equ en_collate_858 ; Russian CP858 +ru_collate_437 equ en_collate_437 ; Russian CP437 + +gr_collate_869 db 0FFh,"COLLATE" ; Greek, CP869 (with Euro) + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 117, 118, 119, 120, 121, 122, 123 +db 124, 125, 126, 127, 128, 129, 130, 131 +db 132, 133, 134, 135, 136, 137, 138, 139 +db 140, 141, 142, 65, 66, 67, 68, 69 +db 70, 117, 118, 119, 120, 121, 122, 123 +db 124, 125, 126, 127, 128, 129, 130, 131 +db 132, 133, 134, 135, 136, 137, 138, 139 +db 140, 141, 142, 71, 72, 73, 74, 75 +db 76, 77, 78, 79, 80, 81, 89, 36 +db 88, 83, 84, 85, 86, 93, 87, 95 +db 97, 97, 103, 147, 148, 108, 108, 151 +db 112, 50, 51, 89, 36, 93, 95, 97 +db 97, 97, 103, 108, 89, 90, 91, 92 +db 93, 94, 95, 171, 96, 97, 174, 175 +db 176, 177, 178, 179, 180, 98, 99, 100 +db 101, 185, 186, 187, 188, 102, 103, 191 +db 192, 193, 194, 195, 196, 197, 104, 105 +db 200, 201, 202, 203, 204, 205, 206, 106 +db 107, 108, 109, 110, 111, 112, 89, 90 +db 91, 217, 218, 219, 220, 92, 93, 223 +db 94, 95, 96, 97, 98, 99, 100, 101 +db 102, 103, 104, 105, 106, 106, 107, 113 +db 240, 241, 108, 109, 110, 245, 111, 114 +db 115, 116, 112, 108, 108, 112, 254, 255 + +gr_collate_737 db 0FFh,"COLLATE" ; Greek, CP737 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 100, 101, 102, 103, 104, 105, 106 +db 107, 108, 109, 110, 111, 112, 113, 114 +db 115, 116, 117, 118, 119, 120, 121, 122 +db 123, 124, 125, 65, 66, 67, 68, 69 +db 70, 100, 101, 102, 103, 104, 105, 106 +db 107, 108, 109, 110, 111, 112, 113, 114 +db 115, 116, 117, 118, 119, 120, 121, 122 +db 123, 124, 125, 71, 72, 73, 74, 75 +db 76, 77, 78, 79, 80, 81, 82, 83 +db 84, 85, 86, 87, 88, 89, 90, 91 +db 92, 93, 94, 95, 96, 97, 98, 99 +db 76, 77, 78, 79, 80, 81, 82, 83 +db 84, 85, 86, 87, 88, 89, 90, 91 +db 92, 93, 93, 94, 95, 96, 97, 98 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 99, 76, 80, 82, 84, 84, 90, 95 +db 95, 99, 76, 80, 82, 84, 90, 95 +db 99, 241, 242, 243, 84, 95, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +gr_collate_850 equ pl_collate_850 ; Polish, CP850 +gr_collate_858 equ pl_collate_858 ; Polish, CP858 + +hu_collate_852 equ ru_collate_852 ; Hungarian, CP852 +hu_collate_850 equ pl_collate_850 ; Hungarian, CP850 +hu_collate_858 equ gr_collate_858 ; Hungarian, CP858 + +sh_collate_852 equ ru_collate_852 ; Serbo-Croatian, CP852 +sh_collate_855 equ ru_collate_855 ; Serbo-Croatian, CP855 +sh_collate_872 equ ru_collate_872 ; Serbo-Croatian, CP872 +sh_collate_850 equ pl_collate_850 ; Serbo-Croatian, CP850 +sh_collate_858 equ gr_collate_858 ; Serbo-Croatian, CP858 + +ro_collate_852 equ ru_collate_852 ; Romanian, CP852 +ro_collate_850 equ pl_collate_850 ; Romanian, CP850 +ro_collate_858 equ gr_collate_858 ; Romanian, CP858 + +ch_collate_850 equ en_collate_850 ; Switzerland, CP850 +ch_collate_858 equ en_collate_858 ; Switzerland, CP858 +ch_collate_437 equ en_collate_437 ; Switzerland, CP437 + +cz_collate_852 equ ru_collate_852 ; Czech, CP852 +cz_collate_850 equ pl_collate_850 ; Czech, CP850 +cz_collate_858 equ gr_collate_858 ; Czech, CP858 + +se_collate_850 db 0FFh,"COLLATE" ; Swedish, CP850 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 93, 94, 95, 96, 97 +db 98, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 123, 124, 125, 126, 127 +db 67, 88, 69, 65, 91, 65, 90, 67 +db 69, 69, 69, 73, 73, 73, 91, 90 +db 69, 65, 65, 79, 92, 79, 85, 85 +db 88, 92, 88, 79, 36, 79, 36, 36 +db 65, 73, 79, 85, 78, 78, 65, 79 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 169, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 73, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 83, 79, 79, 79, 79, 230, 231 +db 232, 85, 85, 85, 88, 88, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +se_collate_858 db 0FFh,"COLLATE" ; Swedish, CP858 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 93, 94, 95, 96, 97 +db 98, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 123, 124, 125, 126, 127 +db 67, 88, 69, 65, 91, 65, 90, 67 +db 69, 69, 69, 73, 73, 73, 91, 90 +db 69, 65, 65, 79, 92, 79, 85, 85 +db 88, 92, 88, 79, 36, 79, 36, 36 +db 65, 73, 79, 85, 78, 78, 65, 79 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 65, 65, 65 +db 169, 185, 186, 187, 188, 36, 36, 191 +db 192, 193, 194, 195, 196, 197, 65, 65 +db 200, 201, 202, 203, 204, 205, 206, 36 +db 68, 68, 69, 69, 69, 36, 73, 73 +db 73, 217, 218, 219, 220, 221, 73, 223 +db 79, 83, 79, 79, 79, 79, 230, 231 +db 232, 85, 85, 85, 88, 88, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 49, 51, 50, 254, 255 + +se_collate_437 db 0FFh,"COLLATE" ; Swedish, CP437 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 93, 94, 95, 96, 97 +db 98, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 86 +db 87, 88, 89, 123, 124, 125, 126, 127 +db 67, 88, 69, 65, 91, 65, 90, 67 +db 69, 69, 69, 73, 73, 73, 91, 90 +db 69, 65, 65, 79, 92, 79, 85, 85 +db 88, 92, 88, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 65, 79 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 83, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 78, 50, 254, 255 + +fi_collate_850 equ se_collate_850 ; Finnish, CP850 +fi_collate_858 equ se_collate_858 ; Finnish, CP858 +fi_collate_437 equ se_collate_437 ; Finnish, CP437 + +jp_collate_932 db 0FFh,"COLLATE" ; Japanese, CP932 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 36, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 183, 184, 185, 186, 187, 188, 189 +db 190, 191, 192, 193, 194, 195, 196, 197 +db 198, 199, 200, 201, 202, 203, 204, 205 +db 206, 207, 208, 209, 210, 211, 212, 213 +db 129, 130, 131, 132, 133, 136, 182, 138 +db 139, 140, 141, 142, 173, 174, 175, 155 +db 137, 138, 139, 140, 141, 142, 143, 144 +db 145, 146, 147, 148, 149, 150, 151, 152 +db 153, 154, 155, 156, 157, 158, 159, 160 +db 161, 162, 163, 164, 165, 166, 167, 168 +db 168, 170, 171, 172, 173, 174, 175, 176 +db 177, 178, 179, 180, 181, 182, 134, 135 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +kr_collate_934 db 0FFh,"COLLATE" ; Korean, CP934 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 36, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 181, 182, 183, 184, 185, 186, 187 +db 188, 189, 190, 191, 192, 193, 194, 195 +db 196, 197, 198, 199, 200, 201, 202, 203 +db 204, 205, 206, 207, 208, 209, 210, 211 +db 212, 213, 214, 215, 216, 217, 218, 219 +db 220, 221, 222, 223, 224, 225, 226, 227 +db 228, 229, 230, 231, 232, 233, 234, 235 +db 236, 237, 238, 239, 240, 241, 242, 243 +db 129, 130, 131, 172, 132, 173, 174, 133 +db 134, 135, 175, 176, 177, 178, 179, 180 +db 149, 136, 137, 138, 150, 139, 140, 141 +db 142, 143, 144, 145, 146, 147, 148, 244 +db 245, 246, 151, 152, 153, 154, 155, 156 +db 247, 248, 157, 158, 159, 160, 161, 162 +db 249, 250, 163, 164, 165, 166, 167, 168 +db 251, 252, 169, 170, 171, 253, 254, 255 + +cn_collate_936 db 0FFh,"COLLATE" ; Chinese, CP936 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 36, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 36, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 160, 161, 162, 163, 164, 165, 166, 167 +db 168, 169, 170, 171, 172, 173, 174, 175 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +by_collate_849 db 0FFh,"COLLATE" ; Belarusian, CP849 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 129, 130, 131, 133, 134, 137, 138 +db 141, 142, 143, 144, 145, 146, 147, 148 +db 149, 150, 151, 152, 154, 155, 156, 157 +db 158, 159, 160, 161, 162, 163, 164, 165 +db 128, 129, 130, 131, 133, 134, 137, 138 +db 141, 142, 143, 144, 145, 146, 147, 148 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 201, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 149, 150, 151, 152, 154, 155, 156, 157 +db 158, 159, 160, 161, 162, 163, 164, 165 +db 136, 136, 135, 135, 140, 140, 153, 153 +db 139, 139, 250, 251, 132, 132, 254, 255 + +by_collate_1131 equ by_collate_849 ; Belarusian, CP1131 +by_collate_850 equ en_collate_850 ; Belarusian CP850 +by_collate_858 equ en_collate_858 ; Belarusian CP858 + +bg_collate_30033 db 0FFh,"COLLATE" ; Bulgarian, MIK codepage + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 153, 154, 155, 156, 157, 158, 159 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 225, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +bg_collate_855 equ ru_collate_855 ; Bulgarian, CP855 +bg_collate_872 equ ru_collate_872 ; Bulgarian, CP872 +bg_collate_850 equ en_collate_850 ; Bulgarian CP850 +bg_collate_858 equ en_collate_858 ; Bulgarian CP858 +bg_collate_866 equ ru_collate_866 ; Bulgarian CP866 +bg_collate_808 equ ru_collate_808 ; Bulgarian CP808 +bg_collate_849 equ by_collate_849 ; Bulgarian CP849 +bg_collate_1131 equ by_collate_1131 ; Bulgarian CP1131 + +ua_collate_848 db 0FFh,"COLLATE" ; Ukrainian, CP848 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 129, 130, 131, 133, 135, 137, 138 +db 140, 143, 145, 146, 148, 149, 151, 152 +db 153, 154, 155, 158, 160, 161, 162, 163 +db 165, 166, 167, 168, 169, 170, 171, 172 +db 128, 129, 130, 131, 133, 135, 137, 138 +db 140, 143, 145, 146, 148, 149, 151, 152 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 201, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 153, 154, 155, 158, 160, 161, 162, 163 +db 165, 166, 167, 168, 169, 170, 171, 172 +db 135, 135, 132, 132, 136, 136, 141, 141 +db 142, 142, 250, 251, 252, 36, 254, 255 + +ua_collate_1125 equ ua_collate_848 ; Ukrainian, CP1125 + +hr_collate_852 equ ru_collate_852 ; Croatian, CP852 +hr_collate_850 equ pl_collate_850 ; Croatian, CP850 +hr_collate_858 equ gr_collate_858 ; Croatian, CP858 + +si_collate_852 equ ru_collate_852 ; Slovenian, CP852 +si_collate_850 equ pl_collate_850 ; Slovenian, CP850 +si_collate_858 equ gr_collate_858 ; Slovenian, CP858 + +mk_collate_855 equ ru_collate_855 ; Macedonian, CP855 +mk_collate_872 equ ru_collate_872 ; Macedonian, CP872 +mk_collate_850 equ pl_collate_850 ; Macedonian, CP850 +mk_collate_858 equ gr_collate_858 ; Macedonian, CP858 + +il_collate_862 db 0FFh,"COLLATE" ; Hebrew, CP862 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 138, 139, 140, 140, 141 +db 141, 142, 143, 144, 144, 145, 145, 146 +db 147, 148, 149, 36, 36, 36, 36, 36 +db 65, 73, 79, 85, 78, 78, 166, 167 +db 63, 169, 170, 171, 172, 33, 34, 34 +db 176, 177, 178, 179, 180, 181, 182, 183 +db 184, 185, 186, 187, 188, 189, 190, 191 +db 192, 193, 194, 195, 196, 197, 198, 199 +db 200, 201, 202, 203, 204, 205, 206, 207 +db 208, 209, 210, 211, 212, 213, 214, 215 +db 216, 217, 218, 219, 220, 221, 222, 223 +db 224, 83, 226, 227, 228, 229, 230, 231 +db 232, 233, 234, 235, 236, 237, 238, 239 +db 240, 241, 242, 243, 244, 245, 246, 247 +db 248, 249, 250, 251, 252, 253, 254, 255 + +il_collate_850 equ en_collate_850 +il_collate_858 equ en_collate_858 + +me_collate_864 db 0FFh,"COLLATE" ; Arabic, CP864 + dw 256 +db 0, 1, 2, 3, 4, 5, 6, 7 +db 8, 9, 10, 11, 12, 13, 14, 15 +db 16, 17, 18, 19, 20, 21, 22, 23 +db 24, 25, 26, 27, 28, 29, 30, 31 +db 32, 33, 34, 35, 36, 37, 38, 39 +db 40, 41, 42, 43, 44, 45, 46, 47 +db 48, 49, 50, 51, 52, 53, 54, 55 +db 56, 57, 58, 59, 60, 61, 62, 63 +db 64, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 91, 92, 93, 94, 95 +db 96, 65, 66, 67, 68, 69, 70, 71 +db 72, 73, 74, 75, 76, 77, 78, 79 +db 80, 81, 82, 83, 84, 85, 86, 87 +db 88, 89, 90, 123, 124, 125, 126, 127 +db 128, 129, 130, 131, 132, 133, 134, 135 +db 136, 137, 138, 139, 140, 141, 142, 143 +db 144, 145, 146, 147, 148, 149, 150, 151 +db 152, 202, 202, 153, 154, 202, 202, 155 +db 156, 157, 175, 36, 36, 176, 158, 159 +db 179, 180, 182, 183, 160, 184, 185, 186 +db 164, 165, 166, 167, 168, 169, 170, 171 +db 172, 173, 199, 161, 191, 192, 193, 162 +db 36, 174, 175, 176, 177, 197, 178, 179 +db 180, 181, 182, 183, 184, 185, 186, 187 +db 188, 189, 190, 191, 192, 193, 194, 195 +db 196, 197, 198, 219, 220, 221, 222, 197 +db 163, 167, 200, 201, 202, 203, 204, 205 +db 206, 207, 208, 194, 197, 198, 198, 203 +db 209, 209, 204, 205, 205, 207, 208, 198 +db 200, 202, 202, 202, 201, 208, 254, 255 + +me_collate_850 equ en_collate_850 +me_collate_858 equ en_collate_858 + +; Dual Byte Character Sets +; lead-byte ranges +;------------------------------------------------------------------------------ +dbcs_empty db 0FFh,"DBCS " + dw 0 ; Table length + db 0, 0 ; Table terminator (even if length == 0) + +; Japan, CP932 +; Source: http://www.microsoft.com/globaldev/reference/dbcs/932.htm +jp_dbcs_932 db 0FFh,"DBCS " + dw 6 + db 081h, 09Fh + db 0E0h, 0FCh + db 000h, 000h + +; Korean, CP934 +kr_dbcs_934 db 0FFh,"DBCS " + dw 4 + db 081h, 0BFh + db 000h, 000h + +; Chinese, CP936 +cn_dbcs_936 db 0FFh,"DBCS " + dw 4 + db 081h, 0FCh + db 000h, 000h + +; Yes/No table +; yes_l : Character (single byte) or leadbyte (DBCS) for YES +; yes_h : trailbyte for YES +; no_l : Character (single byte) or leadbyte (DBCS) for NO +; no_h : trailbyte for NO +;------------------------------------------------------------------------------ +es_yn db 0FFh,"YESNO " + dw 4 + db 'S',0,'N',0 ; Spanish + +de_yn db 0FFh,"YESNO " + dw 4 + db 'J',0,'N',0 ; German + +en_yn db 0FFh,"YESNO " + dw 4 + db 'Y',0,'N',0 ; English + +fr_yn db 0FFh,"YESNO " + dw 4 + db 'O',0,'N',0 ; French + +pt_yn equ es_yn ; Portuguese + +fi_yn db 0FFh,"YESNO " + dw 4 + db 'K',0,'E',0 ; Finnish + + +it_yn equ es_yn ; Italian + +gr_yn db 0FFh,"YESNO " + dw 4 + db 'N',0,'O',0 ; Greek, latin alphabet + +gr_yn_869 db 0FFh,"YESNO " + dw 4 + db 0B8h,0,0BEh,0 ; Greek, codepage 869 + +gr_yn_737 db 0FFh,"YESNO " + dw 4 + db 8Ch,0,8Eh,0 ; Greek, codepage 737 + +nl_yn equ de_yn ; Dutch + +tr_yn db 0FFh,"YESNO " + dw 4 + db 'E',0,'H',0 ; Turkish + +ru_yn_866 db 0FFh,"YESNO " + dw 4 + db 84h,0,8Dh,0 ; Russian CP866 + +ru_yn_808 equ ru_yn_866 + +ru_yn_855 db 0FFh,"YESNO " + dw 4 + db 0A7h,0,0D5h,0 ; Russian CP855 + +ru_yn_872 equ ru_yn_855 + +ru_yn db 0FFh,"YESNO " + dw 4 + db 'D',0,'N',0 ; Russian Latin + +by_yn_849 equ ru_yn_866 ; Belarusian +by_yn_1131 equ ru_yn_866 +by_yn equ ru_yn ; Belarusian Latin + +ua_yn_848 equ ru_yn_866 ; Ukrainian +ua_yn_1125 equ ru_yn_866 + +bg_yn_855 equ ru_yn_855 ; Bulgarian CP855 +bg_yn_872 equ ru_yn_872 ; Bulgarian CP872 +bg_yn_866 equ ru_yn_866 ; Bulgarian CP866 +bg_yn_808 equ ru_yn_808 ; Bulgarian CP808 +bg_yn_849 equ by_yn_849 ; Bulgarian CP849 +bg_yn_1131 equ by_yn_1131 ; Bulgarian CP1131 +bg_yn_30033 equ bg_yn_866 ; Bulgarian MIK +bg_yn equ ru_yn ; Bulgarian Latin + +hu_yn db 0FFh,"YESNO " + dw 4 + db 'I',0,'N',0 ; Hungarian + + +sh_yn_855 equ ru_yn_855 ; Serbo-Croatian CP855 +sh_yn_872 equ ru_yn_872 ; Serbo-Croatian CP872 +sh_yn equ ru_yn ; Serbo-Croatian, latin alphabet + +hr_yn equ ru_yn ; Croatian, latin alphabet + +mk_yn_855 equ ru_yn_855 ; Macedonian CP855 +mk_yn_872 equ ru_yn_872 ; Macedonian CP872 +mk_yn equ ru_yn ; Macedonian latin alphabet + +ro_yn equ ru_yn ; Romanian + +cz_yn db 0FFh,"YESNO " + dw 4 + db 'A','0','N',0 ; Czech + +pl_yn db 0FFh,"YESNO " + dw 4 + db 'T','0','N',0 ; Polish + +dk_yn equ de_yn ; Danish + +se_yn equ de_yn ; Swedish + +no_yn equ de_yn ; Norwegian + +si_yn equ ru_yn ; Slovenian + +kr_yn db 0FFh,"YESNO " + dw 4 + db 'Y','0','A',0 ; Korean, latin alphabet (Yeh, Anio) + +kr_yn_934 db 0FFh,"YESNO " + dw 4 + db 0BFh,0B9h,0BEh,0C6h ; Korean, CP934 (Hangul syllables "Ye" and "A") + +cn_yn db 0FFh,"YESNO " + dw 4 + db 'S','0','B',0 ; Chinese (Mandrin), latin alphabet (Shi, Bushi) + +cn_yn_936 db 0FFh,"YESNO " + dw 4 + db 0CAh,0C7h,0B2h,0BBh; Chinese (Mandrin), CP936 + +il_yn db 0FFh,"YESNO " + dw 4 + db 'K','0','L',0 ; Hebrew, latin alphabet (Ken, Lo) + +il_yn_862 db 0FFh,"YESNO " + dw 4 + db 8Bh,'0',8Ch,0 ; Hebrew, CP862 + +me_yn db 0FFh,"YESNO " + dw 4 + db 'N','0','L',0 ; Arabic, latin alphabet (Nam, La) + +me_yn_864 db 0FFh,"YESNO " + dw 4 + db 0F2h,'0',9Dh,0 ; Arabic, CP864 + +ca_yn equ es_yn ; Catalan + +gl_yn equ es_yn ; Gallegan + +eu_yn db 0FFh,"YESNO " + dw 4 + db 'B','0','E',0 ; Basque + +db "FreeDOS" ; Trailing - as recommended by the Ralf Brown Interrupt List diff --git a/kernel/cpu.asm b/kernel/cpu.asm new file mode 100644 index 0000000..281dfd8 --- /dev/null +++ b/kernel/cpu.asm @@ -0,0 +1,74 @@ +; File: +; cpu.asm +; Description: +; Query basic CPU running on +; +; DOS-C +; Copyright (c) 2012 +; FreeDOS +; 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. +; +; + +%include "segs.inc" +segment INIT_TEXT + +CPU 386 +;********************************************************************* +; +; UWORD query_cpu() based on Eric Auer's public domain cpulevel.asm +; input: none +; output: ax = cpu, 0=8086/8088, 1=186/188, 2=286, 3=386+ + global _query_cpu + _query_cpu: + ; save registers, assumes enough space on stack & valid stack frame setup + ;push ax - no need to save, return value saved here + push bx + push cx + pushf ; save flags + + ; begin check, assume x86 unless later family detected + xor bx, bx ; 808x or 186 highest detected family stored in bx + push bx + popf ; try to clear all flag bits + pushf ; copy flags to ax so we can test if clear succeeded + pop ax + and ax, 0f000h + cmp ax, 0f000h + jnz is286 ; no the 4 msb stuck set to 1, so is a 808x or 8018x + mov ax,1 ; determine if 8086 or 186 + mov cl,64 ; try to shift further than size of ax + shr ax,cl + or ax,ax + jz is086 ; 186 ignores the upper bits of cl + mov bx, 1 ; 186: above 808x, below 286 +is086: jmp short cleanup +is286: mov bx, 2 ; at least 286 + mov ax, 0f000h + push ax + popf ; try to set 4 msb of flags + pushf ; copy flags to ax so we can test if clear succeeded + pop ax + test ax, 0f000h + jz cleanup ; 4 msb stuck to 0: 80286 + mov bx, 3 ; at least 386 + + cleanup: + mov ax, bx ; return CPU family + popf + pop cx + pop bx + retn + diff --git a/kernel/dosfns.c b/kernel/dosfns.c new file mode 100644 index 0000000..74ee025 --- /dev/null +++ b/kernel/dosfns.c @@ -0,0 +1,1377 @@ +/****************************************************************/ +/* */ +/* dosfns.c */ +/* */ +/* DOS functions */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" + +#ifdef VERSION_STRINGS +static BYTE *dosfnsRcsId = + "$Id: dosfns.c 1564 2011-04-08 18:27:48Z bartoldeman $"; +#endif + +#include "globals.h" + +/* /// Added for SHARE. - Ron Cemer */ + +BYTE share_installed = 0; + + /* DOS calls this to see if it's okay to open the file. + Returns a file_table entry number to use (>= 0) if okay + to open. Otherwise returns < 0 and may generate a critical + error. If < 0 is returned, it is the negated error return + code, so DOS simply negates this value and returns it in + AX. */ +extern int ASMPASCAL + share_open_check(char * filename, /* pointer to fully qualified filename */ + unsigned short pspseg, /* psp segment address of owner process */ + int openmode, /* 0=read-only, 1=write-only, 2=read-write */ + int sharemode); /* SHARE_COMPAT, etc... */ + + /* DOS calls this to record the fact that it has successfully + closed a file, or the fact that the open for this file failed. */ +extern void ASMPASCAL + share_close_file(int fileno); /* file_table entry number */ + + /* DOS calls this to determine whether it can access (read or + write) a specific section of a file. We call it internally + from lock_unlock (only when locking) to see if any portion + of the requested region is already locked. If pspseg is zero, + then it matches any pspseg in the lock table. Otherwise, only + locks which DO NOT belong to pspseg will be considered. + Returns zero if okay to access or lock (no portion of the + region is already locked). Otherwise returns non-zero and + generates a critical error (if allowcriter is non-zero). + If non-zero is returned, it is the negated return value for + the DOS call. */ +extern int ASMPASCAL + share_access_check(unsigned short pspseg, /* psp segment address of owner process */ + int fileno, /* file_table entry number */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to access */ + int allowcriter); /* allow a critical error to be generated */ + + /* DOS calls this to lock or unlock a specific section of a file. + Returns zero if successfully locked or unlocked. Otherwise + returns non-zero. + If the return value is non-zero, it is the negated error + return code for the DOS 0x5c call. */ +extern int ASMPASCAL + share_lock_unlock(unsigned short pspseg, /* psp segment address of owner process */ + int fileno, /* file_table entry number */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to lock or unlock */ + int unlock); /* one to unlock; zero to lock */ + +/* /// End of additions for SHARE. - Ron Cemer */ + +STATIC int remote_lock_unlock(sft FAR *sftp, /* SFT for file */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to lock or unlock */ + int unlock); /* one to unlock; zero to lock */ + +/* get current directory structure for drive + return NULL if the CDS is not valid or the + drive is not within range */ +struct cds FAR *get_cds(unsigned drive) +{ + struct cds FAR *cdsp; + unsigned flags; + + if (drive >= lastdrive) + return NULL; + cdsp = &CDSp[drive]; + flags = cdsp->cdsFlags; + /* Entry is disabled or JOINed drives are accessable by the path only */ + if (!(flags & CDSVALID) || (flags & CDSJOINED) != 0) + return NULL; + if (!(flags & CDSNETWDRV) && cdsp->cdsDpb == NULL) + return NULL; + return cdsp; +} + +/* same, but on input drv is 0 for default or 1=A, 2=B, etc. */ +struct cds FAR *get_cds1(unsigned drv) +{ + if (drv-- == 0) /* get default drive or convert to 0 = A:, 1 = B:, ... */ + drv = default_drive; + return get_cds(drv); +} + +#ifdef WITHFAT32 +struct dpb FAR * GetDriveDPB(UBYTE drive, COUNT * rc) +{ + struct dpb FAR *dpb; + struct cds FAR *cdsp; + + cdsp = get_cds1(drive); + + if (cdsp == NULL) + { + *rc = DE_INVLDDRV; + return 0; + } + dpb = cdsp->cdsDpb; + if (dpb == 0 || cdsp->cdsFlags & CDSNETWDRV) + { + *rc = DE_INVLDDRV; + return 0; + } + + *rc = SUCCESS; + return dpb; +} +#endif + +int idx_to_sft_(int SftIndex) +{ + /*called from below and int2f/ax=1216*/ + sfttbl FAR *sp; + + lpCurSft = (sft FAR *) - 1; + if (SftIndex < 0) + return -1; + + /* Get the SFT block that contains the SFT */ + for (sp = sfthead; sp != (sfttbl FAR *) - 1; sp = sp->sftt_next) + { + if (SftIndex < sp->sftt_count) + { + /* finally, point to the right entry */ + lpCurSft = (sft FAR *) & (sp->sftt_table[SftIndex]); + return SftIndex; + } + SftIndex -= sp->sftt_count; + } + + /* If not found, return an error */ + return -1; +} + +sft FAR * idx_to_sft(int SftIndex) +{ + /* called internally only */ + SftIndex = idx_to_sft_(SftIndex); + /* if not opened, the SFT is useless */ + if (SftIndex == -1 || lpCurSft->sft_count == 0) + return (sft FAR *) - 1; + return lpCurSft; +} + +int get_sft_idx(unsigned hndl) +{ + psp FAR *p = MK_FP(cu_psp, 0); + int idx; + + if (hndl >= p->ps_maxfiles) + return DE_INVLDHNDL; + + idx = p->ps_filetab[hndl]; + return idx == 0xff ? DE_INVLDHNDL : idx; +} + +sft FAR *get_sft(UCOUNT hndl) +{ + /* Get the SFT block that contains the SFT */ + return idx_to_sft(get_sft_idx(hndl)); +} + +long DosRWSft(int sft_idx, size_t n, void FAR * bp, int mode) +{ + /* Get the SFT block that contains the SFT */ + sft FAR *s = idx_to_sft(sft_idx); + + if (FP_OFF(s) == (size_t) - 1) + { + return DE_INVLDHNDL; + } + /* If for read and write-only or for write and read-only then exit */ + if((mode == XFR_READ && (s->sft_mode & O_WRONLY)) || + (mode == XFR_WRITE && (s->sft_mode & O_ACCMODE) == O_RDONLY)) + { + return DE_ACCESS; + } + if (mode == XFR_FORCE_WRITE) + mode = XFR_WRITE; + +/* + * Do remote first or return error. + * must have been opened from remote. + */ + if (s->sft_flags & SFT_FSHARED) + { + long XferCount; + VOID FAR *save_dta; + + save_dta = dta; + lpCurSft = s; + current_filepos = s->sft_posit; /* needed for MSCDEX */ + dta = bp; + XferCount = remote_rw(mode == XFR_READ ? REM_READ : REM_WRITE, s, n); + dta = save_dta; + return XferCount; + } + + /* Do a device transfer if device */ + if (s->sft_flags & SFT_FDEVICE) + { + struct dhdr FAR *dev = s->sft_dev; + + /* Now handle raw and cooked modes */ + if (s->sft_flags & SFT_FBINARY) + { + long rc = BinaryCharIO(&dev, n, bp, + mode == XFR_READ ? C_INPUT : C_OUTPUT); + if (mode == XFR_WRITE && rc > 0 && (s->sft_flags & SFT_FCONOUT)) + { + size_t cnt = (size_t)rc; + const char FAR *p = bp; + while (cnt--) + update_scr_pos(*p++, 1); + } + return rc; + } + + /* cooked mode */ + if (mode==XFR_READ) + { + long rc; + + /* Test for eof and exit */ + /* immediately if it is */ + if (!(s->sft_flags & SFT_FEOF)) + return 0; + + if (s->sft_flags & SFT_FCONIN) + rc = read_line_handle(sft_idx, n, bp); + else + rc = cooked_read(&dev, n, bp); + if (*(char *)bp == CTL_Z) + s->sft_flags &= ~SFT_FEOF; + return rc; + } + else + { + /* reset EOF state (set to no EOF) */ + s->sft_flags |= SFT_FEOF; + + /* if null just report full transfer */ + if (s->sft_flags & SFT_FNUL) + return n; + else + return cooked_write(&dev, n, bp); + } + } + + /* a block transfer */ + /* /// Added for SHARE - Ron Cemer */ + if (IsShareInstalled(FALSE) && (s->sft_shroff >= 0)) + { + int rc = share_access_check(cu_psp, s->sft_shroff, s->sft_posit, + (unsigned long)n, 1); + if (rc != SUCCESS) + return rc; + } + /* /// End of additions for SHARE - Ron Cemer */ + return rwblock(sft_idx, bp, n, mode); +} + +COUNT SftSeek(int sft_idx, LONG new_pos, unsigned mode) +{ + sft FAR *s = idx_to_sft(sft_idx); + if (FP_OFF(s) == (size_t) -1) + return DE_INVLDHNDL; + + /* Test for invalid mode */ + if (mode > SEEK_END) + return DE_INVLDFUNC; + + lpCurSft = s; + + /* Do special return for character devices */ + if (s->sft_flags & SFT_FDEVICE) + { + new_pos = 0; + } + else if (mode == SEEK_CUR) + { + new_pos += s->sft_posit; + } + else if (mode == SEEK_END) /* seek from end of file */ + { +/* + * RB list has it as Note: + * this function is called by the DOS 3.1+ kernel, but only when seeking + * from the end of a file opened with sharing modes set in such a manner + * that another process is able to change the size of the file while it + * is already open + * Tested this with Shsucdx ver 0.06 and 1.0. Both now work. + * Lredir via mfs.c from DosEMU works when writing appended files. + * Mfs.c looks for these mode bits set, so here is my best guess.;^) + */ + if ((s->sft_flags & SFT_FSHARED) && + (s->sft_mode & (O_DENYREAD | O_DENYNONE))) + new_pos = remote_lseek(s, new_pos); + else + new_pos += s->sft_size; + } + + s->sft_posit = new_pos; + return SUCCESS; +} + +ULONG DosSeek(unsigned hndl, LONG new_pos, COUNT mode, int *rc) +{ + int sft_idx = get_sft_idx(hndl); + + /* Get the SFT block that contains the SFT */ + *rc = SftSeek(sft_idx, new_pos, mode); + if (*rc == SUCCESS) + return idx_to_sft(sft_idx)->sft_posit; + return *rc; +} + +STATIC long get_free_hndl(void) +{ + psp FAR *p = MK_FP(cu_psp, 0); + UBYTE FAR *q = p->ps_filetab; + UBYTE FAR *r = fmemchr(q, 0xff, p->ps_maxfiles); + if (FP_SEG(r) == 0) return DE_TOOMANY; + return (unsigned)(r - q); +} + +STATIC sft FAR *get_free_sft(COUNT * sft_idx) +{ + COUNT sys_idx = 0; + sfttbl FAR *sp; + + /* Get the SFT block that contains the SFT */ + for (sp = sfthead; sp != (sfttbl FAR *) - 1; sp = sp->sftt_next) + { + REG COUNT i = sp->sftt_count; + sft FAR *sfti = sp->sftt_table; + + for (; --i >= 0; sys_idx++, sfti++) + { + if (sfti->sft_count == 0) + { + *sft_idx = sys_idx; + + /* MS NET uses this on open/creat TE */ + { + extern WORD ASM current_sft_idx; + current_sft_idx = sys_idx; + } + + return sfti; + } + } + } + /* If not found, return an error */ + return (sft FAR *) - 1; +} + +const char FAR *get_root(const char FAR * fname) +{ + /* find the end */ + register unsigned length = fstrlen(fname); + char c; + + /* now back up to first path seperator or start */ + fname += length; + while (length) + { + length--; + c = *--fname; + if (c == '/' || c == '\\' || c == ':') { + fname++; + break; + } + } + return fname; +} + +/* initialize SFT fields (for open/creat) for character devices */ +STATIC int DeviceOpenSft(struct dhdr FAR *dhp, sft FAR *sftp) +{ + int i; + + sftp->sft_shroff = -1; /* /// Added for SHARE - Ron Cemer */ + sftp->sft_count += 1; + sftp->sft_flags = + (dhp->dh_attr & ~(SFT_MASK | SFT_FSHARED)) | SFT_FDEVICE | SFT_FEOF; + fmemcpy(sftp->sft_name, dhp->dh_name, FNAME_SIZE); + + /* pad with spaces */ + for (i = FNAME_SIZE + FEXT_SIZE - 1; sftp->sft_name[i] == '\0'; i--) + sftp->sft_name[i] = ' '; + /* and uppercase */ + DosUpFMem(sftp->sft_name, FNAME_SIZE + FEXT_SIZE); + + sftp->sft_dev = dhp; + sftp->sft_date = dos_getdate(); + sftp->sft_time = dos_gettime(); + sftp->sft_attrib = D_DEVICE; + + if (sftp->sft_dev->dh_attr & SFT_FOCRM) + { + /* if Open/Close/RM bit in driver's attribute is set + * then issue an Open request to the driver + */ + struct dhdr FAR *dev = sftp->sft_dev; + if (BinaryCharIO(&dev, 0, MK_FP(0x0000, 0x0000), C_OPEN) != SUCCESS) + return DE_ACCESS; + } + return SUCCESS; +} + +/* +extended open codes +0000 0000 always fail +0000 0001 open O_OPEN +0000 0010 replace O_TRUNC + +0001 0000 create new file O_CREAT +0001 0001 create if not exists, open if exists O_CREAT | O_OPEN +0001 0010 create O_CREAT | O_TRUNC + +bits for flags (bits 11-8 are internal FreeDOS bits only) +15 O_FCB called from FCB open +14 O_SYNC commit for each write (not implemented yet) +13 O_NOCRIT do not invoke int23 (not implemented yet) +12 O_LARGEFILE allow files >= 2gb but < 4gb (not implemented yet) +11 O_LEGACY not called from int21/ah=6c: find right fn for redirector +10 O_CREAT if file does not exist, create it +9 O_TRUNC if file exists, truncate and open it \ not both +8 O_OPEN if file exists, open it / +7 O_NOINHERIT do not inherit handle on exec +6 \ +5 - sharing modes +4 / +3 reserved +2 bits 2,1,0 = 100: RDONLY and do not modify file's last access time + (not implemented yet) +1 \ 0=O_RDONLY, 1=O_WRONLY, +0 / 2=O_RDWR, 3=O_EXECCASE (preserve case for redirector EXEC, + (not implemented yet)) +*/ + +long DosOpenSft(char FAR * fname, unsigned flags, unsigned attrib) +{ + COUNT sft_idx; + sft FAR *sftp; + struct dhdr FAR *dhp; + long result; + + result = truename(fname, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + + /* now get a free system file table entry */ + if ((sftp = get_free_sft(&sft_idx)) == (sft FAR *) - 1) + return DE_TOOMANY; + + fmemset(sftp, 0, sizeof(sft)); + + sftp->sft_psp = cu_psp; + sftp->sft_mode = flags & 0xf0ff; + OpenMode = (BYTE) flags; + + sftp->sft_shroff = -1; /* /// Added for SHARE - Ron Cemer */ + sftp->sft_attrib = attrib = attrib | D_ARCHIVE; + + if (result & IS_NETWORK) + { + int status; + unsigned cmd; + if ((flags & (O_TRUNC | O_CREAT)) == O_CREAT) + attrib |= 0x100; + + lpCurSft = sftp; + cmd = REM_CREATE; + if (!(flags & O_LEGACY)) + { + extern UWORD ASM ext_open_mode, ASM ext_open_attrib, ASM ext_open_action; + ext_open_mode = flags & 0x70ff; + ext_open_attrib = attrib & 0xff; + ext_open_action = ((flags & 0x0300) >> 8) | ((flags & O_CREAT) >> 6); + cmd = REM_EXTOC; + } + else if (!(flags & O_CREAT)) + { + cmd = REM_OPEN; + attrib = (BYTE)flags; + } + status = (int)network_redirector_mx(cmd, sftp, (void *)attrib); + if (status >= SUCCESS) + { + if (sftp->sft_count == 0) + sftp->sft_count++; + return sft_idx | ((long)status << 16); + } + return status; + } + + /* check for a device */ + if ((result & IS_DEVICE) && (dhp = IsDevice(fname)) != NULL) + { + int rc = DeviceOpenSft(dhp, sftp); + /* check the status code returned by the + * driver when we tried to open it + */ + if (rc < SUCCESS) + return rc; + return sft_idx; + } + + /* First test the flags to see if the user has passed a valid */ + /* file mode... */ + if ((flags & O_ACCMODE) > 2) + return DE_INVLDACC; + + /* NEVER EVER allow directories to be created */ + /* ... though FCBs are weird :) */ + if (!(flags & O_FCB) && + (attrib & ~(D_RDONLY | D_HIDDEN | D_SYSTEM | D_ARCHIVE | D_VOLID))) + return DE_ACCESS; + +/* /// Added for SHARE. - Ron Cemer */ + if (IsShareInstalled(TRUE)) + { + if ((sftp->sft_shroff = + share_open_check(PriPathName, cu_psp, + flags & 0x03, (flags >> 4) & 0x07)) < 0) + return sftp->sft_shroff; + } + +/* /// End of additions for SHARE. - Ron Cemer */ + + sftp->sft_count++; + sftp->sft_flags = PriPathName[0] - 'A'; + result = dos_open(PriPathName, flags, attrib, sft_idx); + if (result < 0) + { +/* /// Added for SHARE *** CURLY BRACES ADDED ALSO!!! ***. - Ron Cemer */ + if (IsShareInstalled(TRUE)) + { + share_close_file(sftp->sft_shroff); + sftp->sft_shroff = -1; + } +/* /// End of additions for SHARE. - Ron Cemer */ + sftp->sft_count--; + return result; + } + return sft_idx | ((long)result << 16); +} + +long DosOpen(char FAR * fname, unsigned mode, unsigned attrib) +{ + long result; + unsigned hndl; + + /* test if mode is in range */ + if ((mode & ~O_VALIDMASK) != 0) + return DE_INVLDACC; + + /* get a free handle */ + if ((result = get_free_hndl()) < 0) + return result; + hndl = (unsigned)result; + + result = DosOpenSft(fname, mode, attrib); + if (result < SUCCESS) + return result; + + ((psp FAR *)MK_FP(cu_psp, 0))->ps_filetab[hndl] = (UBYTE)result; + return hndl | (result & 0xffff0000l); +} + +COUNT CloneHandle(unsigned hndl) +{ + /* now get the system file table entry */ + sft FAR *sftp = get_sft(hndl); + + if (sftp == (sft FAR *) -1 || (sftp->sft_mode & O_NOINHERIT)) + return DE_INVLDHNDL; + + /* now that we have the system file table entry, get the fnode */ + /* index, and increment the count, so that we've effectively */ + /* cloned the file. */ + sftp->sft_count += 1; + return SUCCESS; +} + +long DosDup(unsigned Handle) +{ + long NewHandle; + + if ((NewHandle = get_free_hndl()) < 0) + return NewHandle; + + if (DosForceDup(Handle, (unsigned)NewHandle) < 0) + return DE_INVLDHNDL; + else + return NewHandle; +} + +COUNT DosForceDup(unsigned OldHandle, unsigned NewHandle) +{ + psp FAR *p = MK_FP(cu_psp, 0); + sft FAR *Sftp; + + /* Get the SFT block that contains the SFT */ + if ((Sftp = get_sft(OldHandle)) == (sft FAR *) - 1) + return DE_INVLDHNDL; + + /* now close the new handle if it's open */ + if ((UBYTE) p->ps_filetab[NewHandle] != 0xff) + { + COUNT ret; + + if ((ret = DosClose(NewHandle)) != SUCCESS) + return ret; + } + + /* If everything looks ok, bump it up. */ + p->ps_filetab[NewHandle] = p->ps_filetab[OldHandle]; + /* possible hazard: integer overflow ska*/ + Sftp->sft_count += 1; + return SUCCESS; +} + +COUNT DosCloseSft(int sft_idx, BOOL commitonly) +{ + sft FAR *sftp = idx_to_sft(sft_idx); + int result; + + if (FP_OFF(sftp) == (size_t) - 1) + return DE_INVLDHNDL; + + lpCurSft = sftp; +/* + remote sub sft_count. + */ + if (sftp->sft_flags & SFT_FSHARED) + { + /* printf("closing SFT %d = %p\n",sft_idx,sftp); */ + return network_redirector_fp(commitonly ? REM_FLUSH: REM_CLOSE, sftp); + } + + if (sftp->sft_flags & SFT_FDEVICE) + { + if (sftp->sft_dev->dh_attr & SFT_FOCRM) + { + /* if Open/Close/RM bit in driver's attribute is set + * then issue a Close request to the driver + */ + struct dhdr FAR *dev = sftp->sft_dev; + if (BinaryCharIO(&dev, 0, MK_FP(0x0000, 0x0000), C_CLOSE) != SUCCESS) + return DE_INVLDHNDL; + } + /* now just drop the count if a device */ + if (!commitonly) + sftp->sft_count -= 1; + return SUCCESS; + } + + /* else call file system handler */ + result = dos_close(sft_idx); + if (commitonly || result != SUCCESS) + return result; + +/* /// Added for SHARE *** CURLY BRACES ADDED ALSO!!! ***. - Ron Cemer */ + if (sftp->sft_count == 1 && IsShareInstalled(TRUE)) + { + if (sftp->sft_shroff >= 0) + share_close_file(sftp->sft_shroff); + sftp->sft_shroff = -1; + } +/* /// End of additions for SHARE. - Ron Cemer */ + sftp->sft_count -= 1; + return SUCCESS; +} + +COUNT DosClose(COUNT hndl) +{ + psp FAR *p = MK_FP(cu_psp, 0); + int sft_idx = get_sft_idx(hndl); + + if (FP_OFF(idx_to_sft(sft_idx)) == (size_t) - 1) + return DE_INVLDHNDL; + + /* We must close the (valid) file handle before any critical error */ + /* may occur, else e.g. ABORT will try to close the file twice, */ + /* the second time after stdout is already closed */ + p->ps_filetab[hndl] = 0xff; + + /* Get the SFT block that contains the SFT */ + return DosCloseSft(sft_idx, FALSE); +} + +UWORD DosGetFree(UBYTE drive, UWORD * navc, UWORD * bps, UWORD * nc) +{ + /* navc==NULL means: called from FatGetDrvData, fcbfns.c */ + struct dpb FAR *dpbp; + struct cds FAR *cdsp; + COUNT rg[4]; + UWORD spc; + + /* first check for valid drive */ + spc = -1; + cdsp = get_cds1(drive); + + if (cdsp == NULL) + return spc; + + if (cdsp->cdsFlags & CDSNETWDRV) + { + if (remote_getfree(cdsp, rg) != SUCCESS) + return spc; + + /* for int21/ah=1c: + Undoc DOS says, its not supported for + network drives. so it's probably OK */ + /* some programs such as RHIDE want it though and + the redirector can provide all info + - Bart, 2002 Apr 1 */ + + spc = rg[0]; + if (navc != NULL) + { + *navc = (COUNT) rg[3]; + spc &= 0xff; /* zero out media ID byte */ + } + + *nc = (COUNT) rg[1]; + *bps = (COUNT) rg[2]; + return spc; + } + + dpbp = cdsp->cdsDpb; + if (dpbp == NULL) + return spc; + + if (navc == NULL) + { + /* hazard: no error checking! */ + flush_buffers(dpbp->dpb_unit); + dpbp->dpb_flags = M_CHANGED; + } + + if (media_check(dpbp) < 0) + return spc; + /* get the data available from dpb */ + spc = (dpbp->dpb_clsmask + 1); + *bps = dpbp->dpb_secsize; + + /* now tell fs to give us free cluster */ + /* count */ +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + ULONG cluster_size, ntotal, nfree; + + /* we shift ntotal until it is equal to or below 0xfff6 */ + cluster_size = (ULONG) dpbp->dpb_secsize << dpbp->dpb_shftcnt; + ntotal = dpbp->dpb_xsize - 1; + if (navc != NULL) + nfree = dos_free(dpbp); + while (ntotal > FAT_MAGIC16 && cluster_size < 0x8000) + { + cluster_size <<= 1; + spc <<= 1; + ntotal >>= 1; + nfree >>= 1; + } + /* get the data available from dpb */ + *nc = ntotal > FAT_MAGIC16 ? FAT_MAGIC16 : (UCOUNT) ntotal; + + /* now tell fs to give us free cluster */ + /* count */ + if (navc != NULL) + *navc = nfree > FAT_MAGIC16 ? FAT_MAGIC16 : (UCOUNT) nfree; + return spc; + } +#endif + /* a passed navc of NULL means: skip free; see FatGetDrvData + fcbfns.c */ + if (navc != NULL) + *navc = (COUNT) dos_free(dpbp); + *nc = dpbp->dpb_size - 1; + if (spc > 64) + { + /* fake for 64k clusters do confuse some DOS programs, but let + others work without overflowing */ + spc >>= 1; + if (navc != NULL) + *navc = ((unsigned)*navc < FAT_MAGIC16 / 2) ? + ((unsigned)*navc << 1) : FAT_MAGIC16; + *nc = ((unsigned)*nc < FAT_MAGIC16 / 2) ? ((unsigned)*nc << 1) : FAT_MAGIC16; + } + return spc; +} + +#ifdef WITHFAT32 +#define IS_SLASH(ch) (ch == '\\' || ch == '/') +COUNT DosGetExtFree(BYTE FAR * DriveString, struct xfreespace FAR * xfsp) +{ + struct dpb FAR *dpbp; + struct cds FAR *cdsp; + UCOUNT rg[4]; + + /* ensure all fields known value - clear reserved bytes & set xfs_version.actual to 0 */ + fmemset(xfsp, 0, sizeof(struct xfreespace)); + xfsp->xfs_datasize = sizeof(struct xfreespace); + + /* + DriveString should be in form of "C:", "C:\", "\", "", ., or .\ + where missing drive is treated as a request for the current drive, + or network name in form "\\SERVER\share" + however, network names like \\SERVER\C aren't supported yet + */ + cdsp = NULL; + if ( !*DriveString || (*DriveString == '.') || (IS_SLASH(DriveString[0]) && !IS_SLASH(DriveString[1])) ) + cdsp = get_cds(default_drive); /* if "" or .[\] or \[path] then use current drive */ + else if (DriveString[1] == ':') + cdsp = get_cds(DosUpFChar(*DriveString) - 'A'); /* assume drive specified */ + + if (cdsp == NULL) /* either error, really bad string, or network name */ + return DE_INVLDDRV; + + if (cdsp->cdsFlags & CDSNETWDRV) + { + if (remote_getfree(cdsp, rg) != SUCCESS) + return DE_INVLDDRV; + + xfsp->xfs_clussize = rg[0]; + xfsp->xfs_totalclusters = rg[1]; + xfsp->xfs_secsize = rg[2]; + xfsp->xfs_freeclusters = rg[3]; + } + else + { + dpbp = cdsp->cdsDpb; + if (dpbp == NULL || media_check(dpbp) < 0) + return DE_INVLDDRV; + xfsp->xfs_secsize = dpbp->dpb_secsize; + xfsp->xfs_totalclusters = + (ISFAT32(dpbp) ? dpbp->dpb_xsize : dpbp->dpb_size); + xfsp->xfs_freeclusters = dos_free(dpbp); + xfsp->xfs_clussize = dpbp->dpb_clsmask + 1; + } + xfsp->xfs_totalunits = xfsp->xfs_totalclusters; + xfsp->xfs_freeunits = xfsp->xfs_freeclusters; + xfsp->xfs_totalsectors = xfsp->xfs_totalclusters * xfsp->xfs_clussize; + xfsp->xfs_freesectors = xfsp->xfs_freeclusters * xfsp->xfs_clussize; + xfsp->xfs_datasize = sizeof(struct xfreespace); + + return SUCCESS; +} +#endif + +COUNT DosGetCuDir(UBYTE drive, BYTE FAR * s) +{ + char path[3]; + + if (drive-- == 0) /* get default drive or convert to 0 = A:, 1 = B:, ... */ + drive = default_drive; + path[0] = 'A' + (drive & 0x1f); + path[1] = ':'; + path[2] = '\0'; + + if (truename(path, PriPathName, CDS_MODE_SKIP_PHYSICAL) < SUCCESS) + return DE_INVLDDRV; + + /* skip d:\ */ + fstrcpy(s, PriPathName + 3); + return SUCCESS; +} + +#undef CHDIR_DEBUG +COUNT DosChangeDir(BYTE FAR * s) +{ + COUNT result; + + result = truename(s, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return DE_PATHNOTFND; + + if ((FP_OFF(current_ldt) != 0xFFFF) && + (strlen(PriPathName) >= sizeof(current_ldt->cdsCurrentPath))) + return DE_PATHNOTFND; + +#if defined(CHDIR_DEBUG) + printf("Remote Chdir: n='%Fs' p='%Fs\n", s, PriPathName); +#endif + /* now get fs to change to new */ + /* directory */ + result = (result & IS_NETWORK ? network_redirector(REM_CHDIR) : + dos_cd(PriPathName)); +#if defined(CHDIR_DEBUG) + printf("status = %04x, new_path='%Fs'\n", result, cdsd->cdsCurrentPath); +#endif + if (result != SUCCESS) + return result; +/* + Copy the path to the current directory + structure. + + Some redirectors do not write back to the CDS. + SHSUCdX needs this. jt +*/ + fstrcpy(current_ldt->cdsCurrentPath, PriPathName); + if (FP_OFF(current_ldt) != 0xFFFF) + { + fstrcpy(current_ldt->cdsCurrentPath, PriPathName); + if (PriPathName[7] == 0) + current_ldt->cdsCurrentPath[8] = 0; /* Need two Zeros at the end */ + } + return SUCCESS; +} + +STATIC int pop_dmp(int rc, dmatch FAR * dmp) +{ + dta = dmp; + if (rc == SUCCESS) + { + fmemcpy(dta, &sda_tmp_dm, 21); + dmp->dm_attr_fnd = (BYTE) SearchDir.dir_attrib; + dmp->dm_time = SearchDir.dir_time; + dmp->dm_date = SearchDir.dir_date; + dmp->dm_size = (LONG) SearchDir.dir_size; + ConvertName83ToNameSZ(dmp->dm_name, (BYTE FAR *) SearchDir.dir_name); + } + return rc; +} + +COUNT DosFindFirst(UCOUNT attr, BYTE FAR * name) +{ + int rc; + register dmatch FAR *dmp = dta; + + rc = truename(name, PriPathName, + CDS_MODE_CHECK_DEV_PATH | CDS_MODE_ALLOW_WILDCARDS); + if (rc < SUCCESS) + return rc; + + /* /// Added code here to do matching against device names. + DOS findfirst will match exact device names if the + filename portion (excluding the extension) contains + a valid device name. + Credits: some of this code was ripped off from truename() + in newstuff.c. + - Ron Cemer */ + + SAttr = (BYTE) attr; + +#if defined(FIND_DEBUG) + printf("Remote Find: n='%Fs\n", PriPathName); +#endif + + dta = &sda_tmp_dm; + memset(&sda_tmp_dm, 0, sizeof(dmatch)+sizeof(struct dirent)); + + if (rc & IS_NETWORK) + rc = network_redirector_fp(REM_FINDFIRST, current_ldt); + else if (rc & IS_DEVICE) + { + const char *p; + COUNT i; + + /* make sure the next search fails */ + sda_tmp_dm.dm_entry = 0xffff; + /* Found a matching device. Hence there cannot be wildcards. */ + SearchDir.dir_attrib = D_DEVICE; + SearchDir.dir_time = dos_gettime(); + SearchDir.dir_date = dos_getdate(); + p = (char *)FP_OFF(get_root(PriPathName)); + memset(SearchDir.dir_name, ' ', FNAME_SIZE + FEXT_SIZE); + for (i = 0; i < FNAME_SIZE && *p && *p != '.'; i++) + SearchDir.dir_name[i] = *p++; + rc = SUCCESS; + /* /// End of additions. - Ron Cemer ; heavily edited - Bart Oldeman */ + } + else + rc = dos_findfirst(attr, PriPathName); + + return pop_dmp(rc, dmp); +} + +COUNT DosFindNext(void) +{ + COUNT rc; + register dmatch FAR *dmp = dta; + +/* + * The new version of SHSUCDX 1.0 looks at the dm_drive byte to + * test 40h. I used RamView to see location MSD 116:04be and + * FD f??:04be, the byte set with 0xc4 = Remote/Network drive 4. + * Ralf Brown docs for dos 4eh say bit 7 set == remote so what is + * bit 6 for? + * SHSUCDX Mod info say "test redir not network bit". + * Just to confuse the rest, MSCDEX sets bit 5 too. + * + * So, assume bit 6 is redirector and bit 7 is network. + * jt + * Bart: dm_drive can be the drive _letter_. + * but better just stay independent of it: we only use + * bit 7 to detect a network drive; the rest untouched. + * RBIL says that findnext can only return one error type anyway + * (12h, DE_NFILES) + */ +#if 0 + printf("findnext: %d\n", dmp->dm_drive); +#endif + fmemcpy(&sda_tmp_dm, dmp, 21); + + /* findnext will always fail on a volume id search or device name */ + if ((sda_tmp_dm.dm_attr_srch & ~(D_RDONLY | D_ARCHIVE | D_DEVICE)) == D_VOLID + || sda_tmp_dm.dm_entry == 0xffff) + return DE_NFILES; + + memset(&SearchDir, 0, sizeof(struct dirent)); + dta = &sda_tmp_dm; + rc = (sda_tmp_dm.dm_drive & 0x80) ? + network_redirector_fp(REM_FINDNEXT, &sda_tmp_dm) : dos_findnext(); + + return pop_dmp(rc, dmp); +} + +COUNT DosGetFtime(COUNT hndl, date * dp, time * tp) +{ + sft FAR *s; +/*sfttbl FAR *sp;*/ + + /* Get the SFT block that contains the SFT */ + if (FP_OFF(s = get_sft(hndl)) == (size_t) - 1) + return DE_INVLDHNDL; + + *dp = s->sft_date; + *tp = s->sft_time; + return SUCCESS; +} + +COUNT DosSetFtimeSft(int sft_idx, date dp, time tp) +{ + /* Get the SFT block that contains the SFT */ + sft FAR *s = idx_to_sft(sft_idx); + + if (FP_OFF(s) == (size_t) - 1) + return DE_INVLDHNDL; + + /* If SFT entry refers to a device, do nothing */ + if (s->sft_flags & SFT_FDEVICE) + return SUCCESS; + + s->sft_flags |= SFT_FDATE; + s->sft_date = dp; + s->sft_time = tp; + + return SUCCESS; +} + +COUNT DosGetFattr(BYTE FAR * name) +{ + COUNT result; + + result = truename(name, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + +/* /// Added check for "d:\", which returns 0x10 (subdirectory) under DOS. + - Ron Cemer */ + /* Theoretically: If the redirectory's qualify function + doesn't return nonsense this check can be reduced to + PriPathname[3] == 0, because local path names always + have the three-byte string ?:\ and UNC path shouldn't + validy consist of just two slashes. + -- 2001/09/03 ska*/ + + if (PriPathName[3] == '\0') + return 0x10; + + if (result & IS_NETWORK) + return network_redirector(REM_GETATTRZ); + + if (result & IS_DEVICE) + return DE_FILENOTFND; + + return dos_getfattr(PriPathName); +} + +/* This function is almost identical to DosGetFattr(). + Maybe it is nice to join both functions. + -- 2001/09/03 ska*/ +COUNT DosSetFattr(BYTE FAR * name, UWORD attrp) +{ + COUNT result; + + result = truename(name, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + + if (result & IS_NETWORK) + return remote_setfattr(attrp); + + if (result & IS_DEVICE) + return DE_FILENOTFND; + + if (IsShareInstalled(TRUE)) + { + /* SHARE closes the file if it is opened in + * compatibility mode, else generate a critical error. + * Here generate a critical error by opening in "rw compat" mode */ + if ((result = share_open_check(PriPathName, cu_psp, O_RDWR, 0)) < 0) + return result; + /* else dos_setfattr will close the file */ + share_close_file(result); + } + return dos_setfattr(PriPathName, attrp); +} + +UBYTE DosSelectDrv(UBYTE drv) +{ + current_ldt = get_cds(drv); + + if (current_ldt != NULL) + default_drive = drv; + + return lastdrive; +} + +COUNT DosDelete(BYTE FAR * path, int attrib) +{ + COUNT result; + + result = truename(path, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + + if (result & IS_NETWORK) + return network_redirector(REM_DELETE); + + if (result & IS_DEVICE) + return DE_FILENOTFND; + + return dos_delete(PriPathName, attrib); +} + +COUNT DosRenameTrue(BYTE * path1, BYTE * path2, int attrib) +{ + if (path1[0] != path2[0]) + { + return DE_DEVICE; /* not same device */ + } + if (FP_OFF(current_ldt) == 0xFFFF || (current_ldt->cdsFlags & CDSNETWDRV)) + return network_redirector(REM_RENAME); + + return dos_rename(path1, path2, attrib); +} + +COUNT DosRename(BYTE FAR * path1, BYTE FAR * path2) +{ + COUNT result; + + result = truename(path2, SecPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + + if ((result & (IS_NETWORK | IS_DEVICE)) == IS_DEVICE) + return DE_FILENOTFND; + + result = truename(path1, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + + if ((result & (IS_NETWORK | IS_DEVICE)) == IS_DEVICE) + return DE_FILENOTFND; + + return DosRenameTrue(PriPathName, SecPathName, D_ALL); +} + +COUNT DosMkRmdir(const char FAR * dir, int action) +{ + COUNT result; + + result = truename(dir, PriPathName, CDS_MODE_CHECK_DEV_PATH); + if (result < SUCCESS) + return result; + + if (result & IS_NETWORK) + return network_redirector(action == 0x39 ? REM_MKDIR : REM_RMDIR); + + if (result & IS_DEVICE) + return DE_ACCESS; + + return (action == 0x39 ? dos_mkdir : dos_rmdir)(PriPathName); +} + +/* /// Added for SHARE. - Ron Cemer */ + +COUNT DosLockUnlock(COUNT hndl, LONG pos, LONG len, COUNT unlock) +{ + sft FAR *s; + + /* Get the SFT block that contains the SFT */ + if (FP_OFF(s = get_sft(hndl)) == (size_t) - 1) + return DE_INVLDHNDL; + + if (s->sft_flags & SFT_FSHARED) + return remote_lock_unlock(s, pos, len, unlock); + + /* Invalid function unless SHARE is installed or remote. */ + if (!IsShareInstalled(FALSE)) + return DE_INVLDFUNC; + + /* Lock violation if this SFT entry does not support locking. */ + if (s->sft_shroff < 0) + return DE_LOCK; + + /* Let SHARE do the work. */ + return share_lock_unlock(cu_psp, s->sft_shroff, pos, len, unlock); +} + +/* /// End of additions for SHARE. - Ron Cemer */ + +/* + * This seems to work well. + */ + +/* check for a device + returns device header if match, else returns NULL + can only match character devices (as only they have names) + */ +struct dhdr FAR *IsDevice(const char FAR * fname) +{ + struct dhdr FAR *dhp; + const char FAR *froot = get_root(fname); + int i; + +/* /// BUG!!! This is absolutely wrong. A filename of "NUL.LST" must be + treated EXACTLY the same as a filename of "NUL". The existence or + content of the extension is irrelevent in determining whether a + filename refers to a device. + - Ron Cemer + // if we have an extension, can't be a device <--- WRONG. + if (*froot != '.') + { +*/ + +/* BUGFIX: MSCD000<00> should be handled like MSCD000<20> TE + ie the 8 character device name may be padded with spaces ' ' or NULs '\0' + + Note: fname is assumed an ASCIIZ string (ie not padded, unknown length) + but the name in the device header is assumed FNAME_SIZE and padded. KJD +*/ + + + /* check for names that will never be devices to avoid checking all device headers. + only the file name (not path nor extension) need be checked, "" == root or empty name + */ + if ( (*froot == '\0') || + ((*froot=='.') && ((*(froot+1)=='\0') || (*(froot+2)=='\0' && *(froot+1)=='.'))) + ) + { + return NULL; + } + + /* cycle through all device headers checking for match */ + for (dhp = (struct dhdr FAR *)&nul_dev; dhp != (struct dhdr FAR *)-1; + dhp = dhp->dh_next) + { + if (!(dhp->dh_attr & ATTR_CHAR)) /* if this is block device, skip */ + continue; + + for (i = 0; i < FNAME_SIZE; i++) + { + unsigned char c1 = (unsigned char)froot[i]; + /* ignore extensions and handle filenames shorter than FNAME_SIZE */ + if (c1 == '.' || c1 == '\0') + { + /* check if remainder of device name consists of spaces or nulls */ + for (; i < FNAME_SIZE; i++) + { + unsigned char c2 = dhp->dh_name[i]; + if (c2 != ' ' && c2 != '\0') + break; + } + break; + } + if (DosUpFChar(c1) != DosUpFChar(dhp->dh_name[i])) + break; + } + + /* if found a match then return device header */ + if (i == FNAME_SIZE) + return dhp; + } + + return NULL; +} + +/* /// Added for SHARE. - Ron Cemer */ +/* Eric 8/2008: only re-check (2f.1000) on open/close, not on each access */ + +BOOL IsShareInstalled(BOOL recheck) +{ + extern unsigned char ASMPASCAL share_check(void); + if (recheck == FALSE) + return share_installed; + if (!share_installed && share_check() == 0xff) + share_installed = TRUE; + return share_installed; +} + +/* /// End of additions for SHARE. - Ron Cemer */ + +COUNT DosTruename(const char FAR *src, char FAR *dest) +{ + /* RBIL: The buffer has be unchanged, if the call fails. + Therefore, the name is created in an internal buffer + and copied into the user buffer only on success. + */ + COUNT rc = truename(src, PriPathName, CDS_MODE_ALLOW_WILDCARDS); + if (rc >= SUCCESS) + fstrcpy(dest, PriPathName); + return rc; +} + +STATIC int remote_lock_unlock(sft FAR *sftp, /* SFT for file */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to lock or unlock */ + int unlock) + /* one to unlock; zero to lock */ +{ + struct + { + unsigned long ofs, len; + int unlock; + } param_block; + param_block.ofs = ofs; + param_block.len = len; + param_block.unlock = unlock; + return (int)network_redirector_mx(REM_LOCK, sftp, ¶m_block); +} diff --git a/kernel/dosidle.asm b/kernel/dosidle.asm new file mode 100644 index 0000000..f62014e --- /dev/null +++ b/kernel/dosidle.asm @@ -0,0 +1,96 @@ +; File: +; DosIdle.asm +; Description: +; Dos Idle Interrupt Call +; +; DOS-C +; Copyright (c) 1995, 1999 +; James B. Tabor +; 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. +; +; + %include "segs.inc" + +PSP_USERSP equ 2eh +PSP_USERSS equ 30h + +segment HMA_TEXT + + global _DosIdle_int + global _DosIdle_hlt + + extern _InDOS:wrt DGROUP + extern _cu_psp:wrt DGROUP + extern _MachineId:wrt DGROUP + extern critical_sp:wrt DGROUP + extern _user_r:wrt DGROUP + ; variables as the following are "part of" module inthndlr.c + ; because of the define MAIN before include globals.h there! + extern _HaltCpuWhileIdle:wrt DGROUP + extern _DGROUP_:wrt HMA_TEXT +; +_DosIdle_hlt: + push ds + mov ds, [cs:_DGROUP_] + cmp byte [_HaltCpuWhileIdle],1 + jb DosId0 + pushf + sti + hlt ; save some energy :-) + popf +DosId0: pop ds + retn +; +_DosIdle_int: + call _DosIdle_hlt + push ds + mov ds, [cs:_DGROUP_] + cmp byte [_InDOS],1 + ja DosId1 + call Do_DosI +DosId1: + pop ds + retn + +Do_DosI: + push ax + push es + push word [_MachineId] + push word [_user_r] + push word [_user_r+2] + mov es,word [_cu_psp] + push word [es:PSP_USERSS] + push word [es:PSP_USERSP] + + int 28h + + mov es,word [_cu_psp] + pop word [es:PSP_USERSP] + pop word [es:PSP_USERSS] + pop word [_user_r+2] + pop word [_user_r] + pop word [_MachineId] + pop es + pop ax + ret + +; segment _DATA ; belongs to DGROUP +; whatever db whatever + diff --git a/kernel/dsk.c b/kernel/dsk.c new file mode 100644 index 0000000..833f049 --- /dev/null +++ b/kernel/dsk.c @@ -0,0 +1,1088 @@ +/****************************************************************/ +/* */ +/* dsk.c */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" +#include "dyndata.h" + +#ifdef VERSION_STRINGS +static BYTE *dskRcsId = + "$Id: dsk.c 1702 2012-02-04 08:46:16Z perditionc $"; +#endif + +#if defined(DEBUG) +#define DebugPrintf(x) printf x +#else +#define DebugPrintf(x) +#endif + +/* #define STATIC */ + +BOOL ASMPASCAL fl_reset(WORD); +COUNT ASMPASCAL fl_diskchanged(WORD); + +COUNT ASMPASCAL fl_format(WORD, WORD, WORD, WORD, WORD, UBYTE FAR *); +COUNT ASMPASCAL fl_read(WORD, WORD, WORD, WORD, WORD, UBYTE FAR *); +COUNT ASMPASCAL fl_write(WORD, WORD, WORD, WORD, WORD, UBYTE FAR *); +COUNT ASMPASCAL fl_verify(WORD, WORD, WORD, WORD, WORD, UBYTE FAR *); +COUNT ASMPASCAL fl_setdisktype(WORD, WORD); +COUNT ASMPASCAL fl_setmediatype(WORD, WORD, WORD); +VOID ASMPASCAL fl_readkey(VOID); +extern COUNT ASMPASCAL fl_lba_ReadWrite(BYTE drive, WORD mode, + struct _bios_LBA_address_packet FAR + * dap_p); +UWORD ASMPASCAL floppy_change(UWORD); +#ifdef __WATCOMC__ +#pragma aux (pascal) fl_reset modify exact [ax dx] +#pragma aux (pascal) fl_diskchanged modify exact [ax dx] +#pragma aux (pascal) fl_setdisktype modify exact [ax bx dx] +#pragma aux (pascal) fl_readkey modify exact [ax] +#pragma aux (pascal) fl_lba_ReadWrite modify exact [ax dx] +#pragma aux (pascal) floppy_change modify exact [ax cx dx] +#endif + +STATIC int LBA_Transfer(ddt * pddt, UWORD mode, VOID FAR * buffer, + ULONG LBA_address, unsigned total, UWORD * transferred); + +#define NENTRY 26 /* total size of dispatch table */ + +#define LBA_READ 0x4200 +#define LBA_WRITE 0x4300 +UWORD LBA_WRITE_VERIFY = 0x4302; +#define LBA_VERIFY 0x4400 +#define LBA_FORMAT 0xffff /* fake number for FORMAT track + (only for NON-LBA floppies now!) */ + + /* this buffer must not overlap a 64K boundary + due to DMA transfers + this is certainly true, if located somewhere + at 0xf+1000 and must hold already during BOOT time + */ +UBYTE DiskTransferBuffer[MAX_SEC_SIZE]; + +struct FS_info { + ULONG serialno; + BYTE volume[11]; + BYTE fstype[8]; +}; + +extern struct DynS ASM Dyn; + +/*TE - array access functions */ +ddt *getddt(int dev) +{ + return &(((ddt *) Dyn.Buffer)[dev]); +} + +STATIC VOID tmark(ddt *pddt) +{ + pddt->ddt_fh.ddt_lasttime = ReadPCClock(); +} + +STATIC BOOL tdelay(ddt *pddt, ULONG ticks) +{ + return ReadPCClock() - pddt->ddt_fh.ddt_lasttime >= ticks; +} + +#define N_PART 4 /* number of partitions per + table partition */ + +#define PARTOFF 0x1be + +#ifdef PROTO +typedef WORD dsk_proc(rqptr rq, ddt * pddt); +#else +typedef WORD dsk_proc(); +#endif + +STATIC dsk_proc mediachk, bldbpb, blockio, IoctlQueblk, + Genblkdev, Getlogdev, Setlogdev, blk_Open, blk_Close, + blk_Media, blk_noerr, blk_nondr, blk_error; + +STATIC WORD getbpb(ddt * pddt); +#ifdef PROTO +STATIC WORD dskerr(COUNT); +#else +STATIC WORD dskerr(); +#endif + +/* */ +/* the function dispatch table */ +/* */ + +static dsk_proc * const dispatch[NENTRY] = +{ + /* disk init is done in diskinit.c, so this should never be called */ + blk_error, /* Initialize */ + mediachk, /* Media Check */ + bldbpb, /* Build BPB */ + blk_error, /* Ioctl In */ + blockio, /* Input (Read) */ + blk_nondr, /* Non-destructive Read */ + blk_noerr, /* Input Status */ + blk_noerr, /* Input Flush */ + blockio, /* Output (Write) */ + blockio, /* Output with verify */ + blk_noerr, /* Output Status */ + blk_noerr, /* Output Flush */ + blk_error, /* Ioctl Out */ + blk_Open, /* Device Open */ + blk_Close, /* Device Close */ + blk_Media, /* Removable Media */ + blk_noerr, /* Output till busy */ + blk_error, /* undefined */ + blk_error, /* undefined */ + Genblkdev, /* Generic Ioctl Call */ + blk_error, /* undefined */ + blk_error, /* undefined */ + blk_error, /* undefined */ + Getlogdev, /* Get Logical Device */ + Setlogdev, /* Set Logical Device */ + IoctlQueblk /* Ioctl Query */ +}; + +#define hd(x) ((x) & DF_FIXED) + +/* ----------------------------------------------------------------------- */ +/* F U N C T I O N S --------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ + +COUNT ASMCFUNC FAR blk_driver(rqptr rp) +{ + if (rp->r_unit >= blk_dev.dh_name[0] && rp->r_command != C_INIT) + return failure(E_UNIT); + if (rp->r_command > NENTRY) + { + return failure(E_FAILURE); /* general failure */ + } + else + return ((*dispatch[rp->r_command]) (rp, getddt(rp->r_unit))); +} + +STATIC char template_string[] = "Remove diskette in drive X:\n"; +#define DRIVE_POS (sizeof(template_string) - 4) + +STATIC WORD play_dj(ddt * pddt) +{ + /* play the DJ ... */ + if ((pddt->ddt_descflags & (DF_MULTLOG | DF_CURLOG)) == DF_MULTLOG) + { + int i; + ddt *pddt2 = getddt(0); + for (i = 0; i < blk_dev.dh_name[0]; i++, pddt2++) + { + if (pddt->ddt_driveno == pddt2->ddt_driveno && + (pddt2->ddt_descflags & (DF_MULTLOG | DF_CURLOG)) == + (DF_MULTLOG | DF_CURLOG)) + break; + } + if (i == blk_dev.dh_name[0]) + { + put_string("Error in the DJ mechanism!\n"); /* should not happen! */ + } + else + { + xreg dx; + dx.b.l = pddt->ddt_logdriveno; + dx.b.h = pddt2->ddt_logdriveno; + /* call int2f/ax=4a00 */ + if (floppy_change(dx.x) != 0xffff) { + /* if someone else does not make a nice dialog... */ + template_string[DRIVE_POS] = 'A' + pddt2->ddt_logdriveno; + put_string(template_string); + put_string("Insert"); + template_string[DRIVE_POS] = 'A' + pddt->ddt_logdriveno; + put_string(template_string + 6); + put_string("Press any key to continue ... \n"); + fl_readkey(); + } + pddt2->ddt_descflags &= ~DF_CURLOG; + pddt->ddt_descflags |= DF_CURLOG; + pokeb(0, 0x504, pddt->ddt_logdriveno); + } + return M_CHANGED; + } + return M_NOT_CHANGED; +} + +STATIC WORD diskchange(ddt * pddt) +{ + COUNT result; + + /* if it's a hard drive, media never changes */ + if (hd(pddt->ddt_descflags)) + return M_NOT_CHANGED; + + if (play_dj(pddt) == M_CHANGED) + return M_CHANGED; + + if (pddt->ddt_descflags & DF_CHANGELINE) /* if we can detect a change ... */ + { + if ((result = fl_diskchanged(pddt->ddt_driveno)) == 1) + /* check if it has changed... */ + return M_CHANGED; + else if (result == 0) + return M_NOT_CHANGED; + } + + /* can not detect or error... */ + return tdelay(pddt, 37ul) ? M_DONT_KNOW : M_NOT_CHANGED; +} + +STATIC WORD mediachk(rqptr rp, ddt * pddt) +{ + /* check floppy status */ + if (pddt->ddt_descflags & DF_REFORMAT) + { + pddt->ddt_descflags &= ~DF_REFORMAT; + rp->r_mcretcode = M_CHANGED; + } + else if (pddt->ddt_descflags & DF_DISKCHANGE) + { + pddt->ddt_descflags &= ~DF_DISKCHANGE; + rp->r_mcretcode = M_DONT_KNOW; + } + else + { + rp->r_mcretcode = diskchange(pddt); + if (rp->r_mcretcode == M_DONT_KNOW) + { + /* don't know but can check serial number ... */ + ULONG serialno = pddt->ddt_serialno; + COUNT result = getbpb(pddt); + if (result != 0) + return (result); + if (serialno != pddt->ddt_serialno) + rp->r_mcretcode = M_CHANGED; + } + } + return S_DONE; +} + +/* + * Read Write Sector Zero or Hard Drive Dos Bpb + */ +STATIC WORD RWzero(ddt * pddt, UWORD mode) +{ + UWORD done; + + return LBA_Transfer(pddt, mode, + (UBYTE FAR *) & DiskTransferBuffer, + pddt->ddt_offset, 1, &done); +} + +/* + 0 if not set, 1 = a, 2 = b, etc, assume set. + page 424 MS Programmer's Ref. + */ +STATIC WORD Getlogdev(rqptr rp, ddt * pddt) +{ + int i; + ddt *pddt2; + + if (!(pddt->ddt_descflags & DF_MULTLOG)) { + rp->r_unit = 0; + return S_DONE; + } + + pddt2 = getddt(0); + for (i = 0; i < blk_dev.dh_name[0]; i++, pddt2++) + { + if (pddt->ddt_driveno == pddt2->ddt_driveno && + (pddt2->ddt_descflags & (DF_MULTLOG | DF_CURLOG)) == + (DF_MULTLOG | DF_CURLOG)) + break; + } + + rp->r_unit = i+1; + return S_DONE; +} + +STATIC WORD Setlogdev(rqptr rp, ddt * pddt) +{ + unsigned char unit = rp->r_unit; + Getlogdev(rp, pddt); + if (rp->r_unit == 0) + return S_DONE; + getddt(rp->r_unit - 1)->ddt_descflags &= ~DF_CURLOG; + pddt->ddt_descflags |= DF_CURLOG; + rp->r_unit = unit + 1; + return S_DONE; +} + +STATIC WORD blk_Open(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(rp); + + pddt->ddt_FileOC++; + return S_DONE; +} + +STATIC WORD blk_Close(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(rp); + + pddt->ddt_FileOC--; + return S_DONE; +} + +STATIC WORD blk_nondr(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(rp); + UNREFERENCED_PARAMETER(pddt); + + return S_BUSY | S_DONE; +} + +STATIC WORD blk_Media(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(rp); + + if (hd(pddt->ddt_descflags)) + return S_BUSY | S_DONE; /* Hard Drive */ + else + return S_DONE; /* Floppy */ +} + +STATIC WORD getbpb(ddt * pddt) +{ + ULONG count; + bpb *pbpbarray = &pddt->ddt_bpb; + unsigned secs_per_cyl; + WORD ret; + + /* pddt->ddt_descflags |= DF_NOACCESS; + * disabled for now - problems with FORMAT ?? */ + + /* set drive to not accessible and changed */ + if (diskchange(pddt) != M_NOT_CHANGED) + pddt->ddt_descflags |= DF_DISKCHANGE; + + ret = RWzero(pddt, LBA_READ); + if (ret != 0) + return (dskerr(ret)); + + pbpbarray->bpb_nbyte = getword(&DiskTransferBuffer[BT_BPB]); + + if (DiskTransferBuffer[0x1fe] != 0x55 + || DiskTransferBuffer[0x1ff] != 0xaa || pbpbarray->bpb_nbyte % 512) + { + /* copy default bpb to be sure that there is no bogus data */ + memcpy(pbpbarray, &pddt->ddt_defbpb, sizeof(bpb)); + return S_DONE; + } + + pddt->ddt_descflags &= ~DF_NOACCESS; /* set drive to accessible */ + +/*TE ~ 200 bytes*/ + + memcpy(pbpbarray, &DiskTransferBuffer[BT_BPB], sizeof(bpb)); + + /*?? */ + /* 2b is fat16 volume label. if memcmp, then offset 0x36. + if (fstrncmp((BYTE *) & DiskTransferBuffer[0x36], "FAT16",5) == 0 || + fstrncmp((BYTE *) & DiskTransferBuffer[0x36], "FAT12",5) == 0) { + TE: I'm not sure, what the _real_ decision point is, however MSDN + 'A_BF_BPB_SectorsPerFAT + The number of sectors per FAT. + Note: This member will always be zero in a FAT32 BPB. + Use the values from A_BF_BPB_BigSectorsPerFat... + */ + { + struct FS_info *fs = (struct FS_info *)&DiskTransferBuffer[0x27]; +#ifdef WITHFAT32 + if (pbpbarray->bpb_nfsect == 0) + { + /* FAT32 boot sector */ + fs = (struct FS_info *)&DiskTransferBuffer[0x43]; + } +#endif + pddt->ddt_serialno = getlong(&fs->serialno); + memcpy(pddt->ddt_volume, fs->volume, sizeof fs->volume); + memcpy(pddt->ddt_fstype, fs->fstype, sizeof fs->fstype); + } + +#ifdef DSK_DEBUG + printf("BPB_NBYTE = %04x\n", pbpbarray->bpb_nbyte); + printf("BPB_NSECTOR = %02x\n", pbpbarray->bpb_nsector); + printf("BPB_NRESERVED = %04x\n", pbpbarray->bpb_nreserved); + printf("BPB_NFAT = %02x\n", pbpbarray->bpb_nfat); + printf("BPB_NDIRENT = %04x\n", pbpbarray->bpb_ndirent); + printf("BPB_NSIZE = %04x\n", pbpbarray->bpb_nsize); + printf("BPB_MDESC = %02x\n", pbpbarray->bpb_mdesc); + printf("BPB_NFSECT = %04x\n", pbpbarray->bpb_nfsect); +#endif + + count = + pbpbarray->bpb_nsize == 0 ? + pbpbarray->bpb_huge : pbpbarray->bpb_nsize; + secs_per_cyl = pbpbarray->bpb_nheads * pbpbarray->bpb_nsecs; + + if (secs_per_cyl == 0) + { + tmark(pddt); + return failure(E_FAILURE); + } + /* this field is problematic for partitions > 65535 cylinders, + in general > 512 GiB. However: we are not using it ourselves. */ + pddt->ddt_ncyl = (UWORD)((count + (secs_per_cyl - 1)) / secs_per_cyl); + + tmark(pddt); + +#ifdef DSK_DEBUG + printf("BPB_NSECS = %04x\n", pbpbarray->bpb_nsecs); + printf("BPB_NHEADS = %04x\n", pbpbarray->bpb_nheads); + printf("BPB_HIDDEN = %08lx\n", pbpbarray->bpb_hidden); + printf("BPB_HUGE = %08lx\n", pbpbarray->bpb_huge); +#endif + + return 0; +} + +STATIC WORD bldbpb(rqptr rp, ddt * pddt) +{ + WORD result; + + if ((result = getbpb(pddt)) != 0) + return result; + + rp->r_bpptr = &pddt->ddt_bpb; + return S_DONE; +} + +STATIC WORD IoctlQueblk(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(pddt); + +#ifdef WITHFAT32 + if (rp->r_cat == 8 || rp->r_cat == 0x48) +#else + if (rp->r_cat == 8) +#endif + { + switch (rp->r_fun) + { + case 0x46: + case 0x47: + case 0x60: + case 0x66: + case 0x67: + return S_DONE; + } + } + return failure(E_CMD); +} + +STATIC COUNT Genblockio(ddt * pddt, UWORD mode, WORD head, WORD track, + WORD sector, WORD count, VOID FAR * buffer) +{ + UWORD transferred; + + /* apparently sector is ZERO, not ONE based !!! */ + return LBA_Transfer(pddt, mode, buffer, + ((ULONG) track * pddt->ddt_bpb.bpb_nheads + head) * + (ULONG) pddt->ddt_bpb.bpb_nsecs + + pddt->ddt_offset + sector, count, &transferred); +} + +STATIC WORD Genblkdev(rqptr rp, ddt * pddt) +{ + int ret; + unsigned descflags = pddt->ddt_descflags; +#ifdef WITHFAT32 + int extended = 0; + + if (rp->r_cat == 0x48) + extended = 1; + else +#endif + if (rp->r_cat != 8) + return failure(E_CMD); + + switch (rp->r_fun) + { + case 0x40: /* set device parameters */ + { + struct gblkio FAR *gblp = rp->r_io; + bpb *pbpb; + + pddt->ddt_type = gblp->gbio_devtype; + pddt->ddt_descflags = (descflags & ~3) | (gblp->gbio_devattrib & 3) + | (DF_DPCHANGED | DF_REFORMAT); + pddt->ddt_ncyl = gblp->gbio_ncyl; + /* use default dpb or current bpb? */ + pbpb = + (gblp->gbio_spcfunbit & 0x01) == + 0 ? &pddt->ddt_defbpb : &pddt->ddt_bpb; +#ifdef WITHFAT32 + fmemcpy(pbpb, &gblp->gbio_bpb, + extended ? sizeof(gblp->gbio_bpb) : BPB_SIZEOF); +#else + fmemcpy(pbpb, &gblp->gbio_bpb, sizeof(gblp->gbio_bpb)); +#endif + /*pbpb->bpb_nsector = gblp->gbio_nsecs; */ + break; + } + case 0x41: /* write track */ + { + struct gblkrw FAR *rw = rp->r_rw; + ret = Genblockio(pddt, LBA_WRITE, rw->gbrw_head, rw->gbrw_cyl, + rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); + if (ret != 0) + return dskerr(ret); + } + break; + case 0x42: /* format/verify track */ + { + struct gblkfv FAR *fv = rp->r_fv; + COUNT tracks; + struct thst { + UBYTE track, head, sector, type; + } *addrfield, afentry; + + pddt->ddt_descflags &= ~DF_DPCHANGED; + if (hd(descflags)) + { + /* XXX no low-level formatting for hard disks implemented */ + fv->gbfv_spcfunbit = 1; /* "not supported by bios" */ + return S_DONE; + } + if (descflags & DF_DPCHANGED) + { + /* first try newer setmediatype function */ + ret = fl_setmediatype(pddt->ddt_driveno, pddt->ddt_ncyl, + pddt->ddt_bpb.bpb_nsecs); + if (ret == 0xc) + { + /* specified tracks, sectors/track not allowed for drive */ + fv->gbfv_spcfunbit = 2; + return dskerr(ret); + } + else if (ret == 0x80) + { + fv->gbfv_spcfunbit = 3; /* no disk in drive */ + return dskerr(ret); + } + else if (ret != 0) + /* otherwise, setdisktype */ + { + unsigned char type; + unsigned tracks, secs; + if ((fv->gbfv_spcfunbit & 1) && + (ret = + fl_read(pddt->ddt_driveno, 0, 0, 1, 1, + DiskTransferBuffer)) != 0) + { + fv->gbfv_spcfunbit = 3; /* no disk in drive */ + return dskerr(ret); + } + /* type 1: 320/360K disk in 360K drive */ + /* type 2: 320/360K disk in 1.2M drive */ + tracks = pddt->ddt_ncyl; + secs = pddt->ddt_bpb.bpb_nsecs; + type = pddt->ddt_type + 1; + if (!(tracks == 40 && (secs == 9 || secs == 8) && type < 3)) + { + /* type 3: 1.2M disk in 1.2M drive */ + /* type 4: 720kb disk in 1.44M or 720kb drive */ + type++; + if (type == 9) /* 1.44M drive */ + type = 4; + if (!(tracks == 80 && ((secs == 15 && type == 3) || + (secs == 9 && type == 4)))) + { + /* specified tracks, sectors/track not allowed for drive */ + fv->gbfv_spcfunbit = 2; + return dskerr(0xc); + } + } + fl_setdisktype(pddt->ddt_driveno, type); + } + } + if (fv->gbfv_spcfunbit & 1) + return S_DONE; + + afentry.type = 2; /* 512 byte sectors */ + afentry.track = fv->gbfv_cyl; + afentry.head = fv->gbfv_head; + + for (tracks = fv->gbfv_spcfunbit & 2 ? fv->gbfv_ntracks : 1; + tracks > 0; tracks--) + { + addrfield = (struct thst *)DiskTransferBuffer; + + if (afentry.track > pddt->ddt_ncyl) + return failure(E_FAILURE); + + for (afentry.sector = 1; + afentry.sector <= pddt->ddt_bpb.bpb_nsecs; afentry.sector++) + memcpy(addrfield++, &afentry, sizeof(afentry)); + + ret = + Genblockio(pddt, LBA_FORMAT, afentry.head, afentry.track, 0, + pddt->ddt_bpb.bpb_nsecs, DiskTransferBuffer); + if (ret != 0) + return dskerr(ret); + } + afentry.head++; + if (afentry.head >= pddt->ddt_bpb.bpb_nheads) + { + afentry.head = 0; + afentry.track++; + } + } + + /* fall through to verify */ + + case 0x62: /* verify track */ + { + struct gblkfv FAR *fv = rp->r_fv; + + ret = Genblockio(pddt, LBA_VERIFY, fv->gbfv_head, fv->gbfv_cyl, 0, + (fv->gbfv_spcfunbit ? + fv->gbfv_ntracks * pddt->ddt_defbpb.bpb_nsecs : + pddt->ddt_defbpb.bpb_nsecs), DiskTransferBuffer); + if (ret != 0) + return dskerr(ret); + fv->gbfv_spcfunbit = 0; /* success */ + } + break; + case 0x46: /* set volume serial number */ + { + struct Gioc_media FAR *gioc = rp->r_gioc; + struct FS_info *fs; + + ret = getbpb(pddt); + if (ret != 0) + return (ret); + + fs = (struct FS_info *)&DiskTransferBuffer + [(pddt->ddt_bpb.bpb_nfsect != 0 ? 0x27 : 0x43)]; + fs->serialno = gioc->ioc_serialno; + pddt->ddt_serialno = fs->serialno; + + ret = RWzero(pddt, LBA_WRITE); + if (ret != 0) + return (dskerr(ret)); + } + break; + case 0x47: /* set access flag */ + { + struct Access_info FAR *ai = rp->r_ai; + pddt->ddt_descflags = (descflags & ~DF_NOACCESS) | + (ai->AI_Flag ? 0 : DF_NOACCESS); + } + break; + case 0x60: /* get device parameters */ + { + struct gblkio FAR *gblp = rp->r_io; + bpb *pbpb; + + gblp->gbio_devtype = pddt->ddt_type; + gblp->gbio_devattrib = descflags & 3; + /* 360 kb disk in 1.2 MB drive */ + gblp->gbio_media = (pddt->ddt_type == 1) && (pddt->ddt_ncyl == 40); + gblp->gbio_ncyl = pddt->ddt_ncyl; + /* use default dpb or current bpb? */ + pbpb = + (gblp->gbio_spcfunbit & 0x01) == + 0 ? &pddt->ddt_defbpb : &pddt->ddt_bpb; +#ifdef WITHFAT32 + fmemcpy(&gblp->gbio_bpb, pbpb, + extended ? sizeof(gblp->gbio_bpb) : BPB_SIZEOF); +#else + fmemcpy(&gblp->gbio_bpb, pbpb, sizeof(gblp->gbio_bpb)); +#endif + /*gblp->gbio_nsecs = pbpb->bpb_nsector; */ + break; + } + case 0x61: /* read track */ + { + struct gblkrw FAR *rw = rp->r_rw; + ret = Genblockio(pddt, LBA_READ, rw->gbrw_head, rw->gbrw_cyl, + rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); + if (ret != 0) + return dskerr(ret); + } + break; + case 0x66: /* get volume serial number */ + { + struct Gioc_media FAR *gioc = rp->r_gioc; + + ret = getbpb(pddt); + if (ret != 0) + return (ret); + + gioc->ioc_serialno = pddt->ddt_serialno; + fmemcpy(gioc->ioc_volume, pddt->ddt_volume, 11); + fmemcpy(gioc->ioc_fstype, pddt->ddt_fstype, 8); + } + break; + case 0x67: /* get access flag */ + { + struct Access_info FAR *ai = rp->r_ai; + ai->AI_Flag = descflags & DF_NOACCESS ? 0 : 1; /* bit 9 */ + } + break; + default: + return failure(E_CMD); + } + return S_DONE; +} + +STATIC WORD blockio(rqptr rp, ddt * pddt) +{ + ULONG start, size; + WORD ret; + UWORD done; + + int action; + bpb *pbpb; + + switch (rp->r_command) + { + case C_INPUT: + action = LBA_READ; + break; + case C_OUTPUT: + action = LBA_WRITE; + break; + case C_OUTVFY: + action = LBA_WRITE_VERIFY; + break; + default: + return failure(E_FAILURE); + } + + if (pddt->ddt_descflags & DF_NOACCESS) /* drive inaccessible */ + return failure(E_FAILURE); + + tmark(pddt); + start = (rp->r_start != HUGECOUNT ? rp->r_start : rp->r_huge); + pbpb = hd(pddt->ddt_descflags) ? &pddt->ddt_defbpb : &pddt->ddt_bpb; + size = (pbpb->bpb_nsize ? pbpb->bpb_nsize : pbpb->bpb_huge); + + if (start >= size || start + rp->r_count > size) + { + return 0x0408; + } + start += pddt->ddt_offset; + + ret = LBA_Transfer(pddt, action, + rp->r_trans, + start, rp->r_count, &done); + rp->r_count = done; + + if (ret != 0) + { + return dskerr(ret); + } + return S_DONE; +} + +STATIC WORD blk_error(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(pddt); + + rp->r_count = 0; + return failure(E_FAILURE); /* general failure */ +} + +STATIC WORD blk_noerr(rqptr rp, ddt * pddt) +{ + UNREFERENCED_PARAMETER(rp); + UNREFERENCED_PARAMETER(pddt); + + return S_DONE; +} + +STATIC WORD dskerr(COUNT code) +{ +/* printf("diskette error:\nhead = %d\ntrack = %d\nsector = %d\ncount = %d\n", + head, track, sector, count); */ + switch (code & 0x03) + { + case 1: /* invalid command - general failure */ + if (code & 0x08) + return S_ERROR | E_NOTRDY; /* failure(E_NOTRDY); at least on yhe INT25 route, + 0x8002 is returned */ + else + return failure(E_CMD); + + case 2: /* address mark not found - general failure */ + return failure(E_FAILURE); + + case 3: /* write protect */ + return failure(E_WRPRT); + + default: + if (code & 0x80) /* time-out */ + return failure(E_NOTRDY); + else if (code & 0x40) /* seek error */ + return failure(E_SEEK); + else if (code & 0x10) /* CRC error */ + return failure(E_CRC); + else if (code & 0x04) + return failure(E_NOTFND); + else + return failure(E_FAILURE); + } +} + +/* + translate LBA sectors into CHS addressing +*/ + +STATIC int LBA_to_CHS(ULONG LBA_address, struct CHS *chs, const ddt * pddt) +{ + /* we need the defbpb values since those are taken from the + BIOS, not from some random boot sector, except when + we're dealing with a floppy */ + + const bpb *pbpb = hd(pddt->ddt_descflags) ? &pddt->ddt_defbpb : &pddt->ddt_bpb; + unsigned hs = pbpb->bpb_nsecs * pbpb->bpb_nheads; + unsigned hsrem = (unsigned)(LBA_address % hs); + + LBA_address /= hs; + + if (LBA_address > 1023ul) + { +#ifdef DEBUG + printf("LBA-Transfer error : cylinder %lu > 1023\n", LBA_address); +#else + put_string("LBA-Transfer error : cylinder > 1023\n"); +#endif + return 1; + } + + chs->Cylinder = (UWORD)LBA_address; + chs->Head = hsrem / pbpb->bpb_nsecs; + chs->Sector = hsrem % pbpb->bpb_nsecs + 1; + return 0; +} + + /* Test for 64K boundary crossing and return count small */ + /* enough not to exceed the threshold. */ + +STATIC unsigned DMA_max_transfer(void FAR * buffer, unsigned count) +{ + unsigned dma_off = (UWORD)((FP_SEG(buffer) << 4) + FP_OFF(buffer)); + unsigned sectors_to_dma_boundary = (dma_off == 0 ? + 0xffff / maxsecsize : + (UWORD)(-dma_off) / maxsecsize); + + return min(count, sectors_to_dma_boundary); +} + +/* + int LBA_Transfer( + ddt *pddt, physical characteristics of drive + UWORD mode, LBA_READ/WRITE/WRITE_VERIFY/VERIFY + VOID FAR *buffer, user buffer + ULONG LBA_address, absolute sector address + unsigned totaltodo, number of sectors to transfer + UWORD *transferred sectors actually transferred + + Read/Write/Write+verify some sectors, using LBA addressing. + + + This function handles all the minor details, including: + + retry in case of errors + + crossing the 64K DMA boundary + + translation to CHS addressing if necessary + + crossing track boundaries (necessary for some BIOSes + + High memory doesn't work very well, use internal buffer + + write with verify details for LBA + +*/ + +STATIC int LBA_Transfer(ddt * pddt, UWORD mode, VOID FAR * buffer, + ULONG LBA_address, unsigned totaltodo, + UWORD * transferred) +{ + static struct _bios_LBA_address_packet dap = { + 16, 0, 0, 0, 0, 0, 0 + }; + + unsigned count; + unsigned error_code = 0; + struct CHS chs; + void FAR *transfer_address; + unsigned char driveno = pddt->ddt_driveno; + + int num_retries; + + UWORD bytes_sector = pddt->ddt_bpb.bpb_nbyte; /* bytes per sector, usually 512 */ + *transferred = 0; + + /* only low-level format floppies for now ! */ + if (mode == LBA_FORMAT && hd(pddt->ddt_descflags)) + return 0; + + /* optionally change from A: to B: or back */ + play_dj(pddt); + + if (!hd(pddt->ddt_descflags)) + { + UBYTE FAR *int1e_ptr = (UBYTE FAR *)getvec(0x1e); + unsigned char nsecs = (unsigned char)(pddt->ddt_bpb.bpb_nsecs); + + if (int1e_ptr[4] != nsecs) + { + int1e_ptr[4] = nsecs; + fl_reset(driveno); + } + } + +/* + if (LBA_address+totaltodo > pddt->total_sectors) + { + printf("LBA-Transfer error : address overflow = %lu > %lu max\n",LBA_address+totaltodo,driveParam->total_sectors); + return 1; + } +*/ + + buffer = adjust_far(buffer); + for (; totaltodo != 0;) + { + /* avoid overflowing 64K DMA boundary */ + count = DMA_max_transfer(buffer, totaltodo); + + if (FP_SEG(buffer) >= 0xa000 || count == 0) + { + transfer_address = DiskTransferBuffer; + count = 1; + + if ((mode & 0xff00) == (LBA_WRITE & 0xff00)) + { + fmemcpy(DiskTransferBuffer, buffer, bytes_sector); + } + } + else + { + transfer_address = buffer; + } + + for (num_retries = 0; num_retries < N_RETRY; num_retries++) + { + if ((pddt->ddt_descflags & DF_LBA) && mode != LBA_FORMAT) + { + dap.number_of_blocks = count; + + dap.buffer_address = transfer_address; + + dap.block_address_high = 0; /* clear high part */ + dap.block_address = LBA_address; /* clear high part */ + + /* Load the registers and call the interrupt. */ + + if ((pddt->ddt_descflags & DF_WRTVERIFY) || mode != LBA_WRITE_VERIFY) + { + error_code = fl_lba_ReadWrite(driveno, mode, &dap); + } + else + { + /* verify requested, but not supported */ + error_code = + fl_lba_ReadWrite(driveno, LBA_WRITE, &dap); + + if (error_code == 0) + { + error_code = + fl_lba_ReadWrite(driveno, LBA_VERIFY, &dap); + } + } + } + else + { /* transfer data, using old bios functions */ + + if (LBA_to_CHS(LBA_address, &chs, pddt)) + return 1; + + /* avoid overflow at end of track */ + + if (chs.Sector + count > (unsigned)pddt->ddt_bpb.bpb_nsecs + 1) + { + count = pddt->ddt_bpb.bpb_nsecs + 1 - chs.Sector; + } + + error_code = (mode == LBA_READ ? fl_read : + mode == LBA_VERIFY ? fl_verify : + mode == + LBA_FORMAT ? fl_format : fl_write) (driveno, + chs.Head, + chs.Cylinder, + chs.Sector, + count, + transfer_address); + + if (error_code == 0 && mode == LBA_WRITE_VERIFY) + { + error_code = fl_verify(driveno, chs.Head, chs.Cylinder, + chs.Sector, count, transfer_address); + } + } + if (error_code == 0) + break; + + fl_reset(driveno); + + } /* end of retries */ + + if (error_code) + { + return error_code; + } + + /* copy to user buffer if nesessary */ + if (transfer_address == DiskTransferBuffer && + (mode & 0xff00) == (LBA_READ & 0xff00)) + { + fmemcpy(buffer, DiskTransferBuffer, bytes_sector); + } + + *transferred += count; + LBA_address += count; + totaltodo -= count; + + buffer = adjust_far((char FAR *)buffer + count * bytes_sector); + } + + return (error_code); +} + +/* + * Revision 1.17 2001/05/13 tomehlert + * Added full support for LBA hard drives + * initcode moved (mostly) to initdisk.c + * lower interface partly redesigned + */ diff --git a/kernel/dyndata.h b/kernel/dyndata.h new file mode 100644 index 0000000..e980a2c --- /dev/null +++ b/kernel/dyndata.h @@ -0,0 +1,19 @@ +/* + DynData.h + + declarations for dynamic NEAR data allocations + + the DynBuffer must initially be large enough to hold + the PreConfig data. + after the disksystem has been initialized, the kernel is + moveable and Dyn.Buffer resizable, but not before +*/ + +void far *DynAlloc(char *what, unsigned num, unsigned size); +void far *DynLast(void); +void DynFree(void *ptr); + +struct DynS { + unsigned Allocated; + char Buffer[1]; +}; diff --git a/kernel/dyninit.c b/kernel/dyninit.c new file mode 100644 index 0000000..8bd0d37 --- /dev/null +++ b/kernel/dyninit.c @@ -0,0 +1,98 @@ +/* + DYNINIT.C + + this serves requests from the INIT modules to + allocate dynamic data. + +kernel layout: + 00000H 000FFH 00100H PSP PSP + 00100H 004E1H 003E2H _TEXT CODE + 004E2H 007A7H 002C6H _IO_TEXT CODE + 007A8H 008E5H 0013EH _IO_FIXED_DATA CODE + 008F0H 0139FH 00AB0H _FIXED_DATA DATA + 013A0H 019F3H 00654H _DATA DATA + 019F4H 0240DH 00A1AH _BSS BSS + +additionally: + DYN_DATA DYN + + + 02610H 0F40EH 0CDFFH HMA_TEXT HMA + + FCBs, f_nodes, buffers,... + drivers + + + 0F410H 122DFH 02ED0H INIT_TEXT INIT + 122E0H 12AA5H 007C6H ID ID + 12AA6H 12CBFH 0021AH IB IB + + purpose is to move the HMA_TEXT = resident kernel + around, so that below it - after BSS, there is data + addressable near by the kernel, to hold some arrays + like f_nodes + + making f_nodes near saves ~2.150 code in HMA + +*/ +#include "portab.h" +#include "init-mod.h" +#include "dyndata.h" + +#if defined(DEBUG) +#define DebugPrintf(x) printf x +#else +#define DebugPrintf(x) +#endif + +/*extern struct DynS FAR Dyn;*/ + +#ifndef __TURBOC__ +#include "init-dat.h" +extern struct DynS DOSFAR ASM Dyn; +#else +extern struct DynS FAR ASM Dyn; +#endif + +void far *DynAlloc(char *what, unsigned num, unsigned size) +{ + void far *now; + unsigned total = num * size; + struct DynS far *Dynp = MK_FP(FP_SEG(LoL), FP_OFF(&Dyn)); + +#ifndef DEBUG + UNREFERENCED_PARAMETER(what); +#endif + + if ((ULONG) total + Dynp->Allocated > 0xffff) + { + printf("PANIC:Dyn %lu\n", (ULONG) total + Dynp->Allocated); + for (;;) ; + } + + DebugPrintf(("DYNDATA:allocating %s - %u * %u bytes, total %u, %u..%u\n", + what, num, size, total, Dynp->Allocated, + Dynp->Allocated + total)); + + now = (void far *)&Dynp->Buffer[Dynp->Allocated]; + fmemset(now, 0, total); + + Dynp->Allocated += total; + + return now; +} + +void DynFree(void *ptr) +{ + struct DynS far *Dynp = MK_FP(FP_SEG(LoL), FP_OFF(&Dyn)); + Dynp->Allocated = (char *)ptr - (char *)Dynp->Buffer; +} + +void FAR * DynLast() +{ + struct DynS far *Dynp = MK_FP(FP_SEG(LoL), FP_OFF(&Dyn)); + DebugPrintf(("dynamic data end at %p\n", + (void FAR *)(Dynp->Buffer + Dynp->Allocated))); + + return Dynp->Buffer + Dynp->Allocated; +} diff --git a/kernel/entry.asm b/kernel/entry.asm new file mode 100644 index 0000000..d881751 --- /dev/null +++ b/kernel/entry.asm @@ -0,0 +1,671 @@ +; +; File: +; entry.asm +; Description: +; System call entry code +; +; Copyright (c) 1998 +; 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. +; +; $Id: entry.asm 1701 2012-01-16 22:06:21Z perditionc $ +; + + %include "segs.inc" + %include "stacks.inc" + +segment HMA_TEXT + extern _int21_syscall + extern _int21_service + extern _int2526_handler + extern _error_tos:wrt DGROUP + extern _char_api_tos:wrt DGROUP + extern _disk_api_tos:wrt DGROUP + extern _user_r:wrt DGROUP + extern _ErrorMode:wrt DGROUP + extern _InDOS:wrt DGROUP + extern _cu_psp:wrt DGROUP + extern _MachineId:wrt DGROUP + extern critical_sp:wrt DGROUP + + extern int21regs_seg:wrt DGROUP + extern int21regs_off:wrt DGROUP + + extern _Int21AX:wrt DGROUP + + extern _DGROUP_ + + global reloc_call_cpm_entry + global reloc_call_int20_handler + global reloc_call_int21_handler + global reloc_call_low_int25_handler + global reloc_call_low_int26_handler + global reloc_call_int27_handler + +; +; MS-DOS CP/M style entry point +; +; VOID FAR +; cpm_entry(iregs UserRegs) +; +; For CP/M compatibility allow a program to invoke any DOS API function +; between 0 and 24h by doing a near call to psp:0005h which embeds a far call +; to absolute address 0:00C0h (int vector 30h & 31h) or FFFF:00D0 (hma). +; 0:00C0h contains the jmp instruction to reloc_call_cpm_entry which should +; be duplicated in hma to ensure correct operation with either state of A20 line. +; Note: int 31h is also used for DPMI but only in protected mode. +; Upon entry the stack has a near return offset (desired return address offset) +; and far return seg:offset (desired return segment of PSP, and useless offset +; which if used will return to the data, not code, at offset 0ah after far call +; in psp). We convert it to a normal call and correct the stack to appear same +; as if invoked via an int 21h call including proper return address. +; +reloc_call_cpm_entry: + ; Stack is: + ; return offset + ; psp seg + ; 000ah + ; + add sp, byte 2 ; remove unneeded far return offset 0ah + pushf ; start setting up int 21h stack + ; + ; now stack is + ; return offset + ; psp seg + ; flags + ; + push bp + mov bp,sp ; set up reference frame + ; + ; reference frame stack is + ; return offset bp + 6 + ; psp seg bp + 4 + ; flags bp + 2 + ; bp <--- bp + ; + push ax + mov ax,[2+bp] ; get the flags + xchg ax,[6+bp] ; swap with return address + mov [2+bp],ax + pop ax ; restore working registers + pop bp + ; + ; Done. Stack is + ; flags + ; psp seg (alias .COM cs) + ; return offset + ; + cmp cl,024h ; restrict calls to functions 0-24h + ja cpm_error + mov ah,cl ; get the call # from cl to ah + jmp reloc_call_int21_handler ; do the system call +cpm_error: mov al,0 + iret ; cleanup stack and return to caller + +; +; interrupt zero divide handler: +; print a message 'Interrupt divide by zero' +; Terminate the current process +; +; VOID INRPT far +; int20_handler(iregs UserRegs) +; + +print_hex: mov cl, 12 +hex_loop: + mov ax, dx + shr ax, cl + and al, 0fh + cmp al, 10 + sbb al, 69h + das + mov bx, 0070h + mov ah, 0eh + int 10h + sub cl, 4 + jae hex_loop + ret + +divide_by_zero_message db 0dh,0ah,'Interrupt divide by zero, stack:',0dh,0ah,0 + + global reloc_call_int0_handler +reloc_call_int0_handler: + + mov si,divide_by_zero_message + +zero_message_loop: + mov al, [cs:si] + test al,al + je zero_done + + inc si + mov bx, 0070h + mov ah, 0eh + + int 10h + + jmp short zero_message_loop + +zero_done: + mov bp, sp + xor si, si ; print 13 words of stack for debugging LUDIV etc. +stack_loop: + mov dx, [bp+si] + call print_hex + mov al, ' ' + int 10h + inc si + inc si + cmp si, byte 13*2 + jb stack_loop + mov al, 0dh + int 10h + mov al, 0ah + int 10h + + mov ax,04c7fh ; terminate with errorlevel 127 + int 21h + sti +thats_it: hlt + jmp short thats_it ; it might be command.com that nukes + +invalid_opcode_message db 0dh,0ah,'Invalid Opcode at ',0 + + global reloc_call_int6_handler +reloc_call_int6_handler: + + mov si,invalid_opcode_message + jmp short zero_message_loop + + global reloc_call_int19_handler +reloc_call_int19_handler: +; from Japheth's public domain code (JEMFBHLP.ASM) +; restores int 10,13,15,19,1b and then calls the original int 19. + cld + xor ax,ax + mov es,ax + mov al,70h + mov ds,ax + mov si,100h + mov cx,5 + cli +nextitem: lodsb + mov di,ax +%if XCPU >= 186 + shl di,2 +%else + shl di,1 + shl di,1 +%endif + movsw + movsw + loop nextitem + int 19h + +; +; Terminate the current process +; +; VOID INRPT far +; int20_handler(iregs UserRegs) +; +reloc_call_int20_handler: + mov ah,0 ; terminate through int 21h + + +; +; MS-DOS system call entry point +; +; VOID INRPT far +; int21_handler(iregs UserRegs) +; +reloc_call_int21_handler: + ; + ; Create the stack frame for C call. This is done to + ; preserve machine state and provide a C structure for + ; access to registers. + ; + ; Since this is an interrupt routine, CS, IP and flags were + ; pushed onto the stack by the processor, completing the + ; stack frame. + ; + ; NB: stack frame is MS-DOS dependent and not compatible + ; with compiler interrupt stack frames. + ; + sti + PUSH$ALL + mov bp,sp + ; + ; Create kernel reference frame. + ; + ; NB: At this point, SS != DS and won't be set that way + ; until later when which stack to run on is determined. + ; +int21_reentry: + Protect386Registers + mov dx,[cs:_DGROUP_] + mov ds,dx + + cmp ah,25h + je int21_user + cmp ah,33h + je int21_user + cmp ah,35h + je int21_user + cmp ah,50h + je int21_user + cmp ah,51h + je int21_user + cmp ah,62h + jne int21_1 + +int21_user: + call dos_crit_sect + + push ss + push bp + call _int21_syscall + pop cx + pop cx + jmp short int21_ret + +; +; normal entry, use one of our 4 stacks +; +; DX=DGROUP +; CX=STACK +; SI=userSS +; BX=userSP + + +int21_1: + mov si,ss ; save user stack, to be retored later + + + ; + ; Now DS is set, let's save our stack for rentry (???TE) + ; + ; I don't know who needs that, but ... (TE) + ; + mov word [_user_r+2],ss + mov word [_user_r],bp ; store and init + + ; + ; Decide which stack to run on. + ; + ; Unlike previous versions of DOS-C, we need to do this here + ; to guarantee the user stack for critical error handling. + ; We need to do the int 24h from this stack location. + ; + ; There are actually four stacks to run on. The first is the + ; user stack which is determined by system call number in + ; AH. The next is the error stack determined by _ErrorMode. + ; Then there's the character stack also determined by system + ; call number. Finally, all others run on the disk stack. + ; They are evaluated in that order. + + cmp byte [_ErrorMode],0 + je int21_2 + +int21_onerrorstack: + mov cx,_error_tos + + + cli + mov ss,dx + mov sp,cx + sti + + push si ; user SS:SP + push bp + + call _int21_service + jmp short int21_exit_nodec + + +int21_2: inc byte [_InDOS] + mov cx,_char_api_tos + or ah,ah + jz int21_3 + cmp ah,0ch + jbe int21_normalentry + +int21_3: + call dos_crit_sect + mov cx,_disk_api_tos + +int21_normalentry: + + cli + mov ss,dx + mov sp,cx + sti + + ; + ; Push the far pointer to the register frame for + ; int21_syscall and remainder of kernel. + ; + + push si ; user SS:SP + push bp + call _int21_service + +int21_exit: dec byte [_InDOS] + + ; + ; Recover registers from system call. Registers and flags + ; were modified by the system call. + ; + + +int21_exit_nodec: + pop bp ; get back user stack + pop si + + global _int21_iret +_int21_iret: + cli + mov ss,si + RestoreSP + +int21_ret: + Restore386Registers + POP$ALL + + ; + ; ... and return. + ; + iret +; +; end Dos Critical Section 0 thur 7 +; +; +dos_crit_sect: + mov [_Int21AX],ax ; needed! + push ax ; This must be here!!! + mov ah,82h ; re-enrty sake before disk stack + int 2ah ; Calling Server Hook! + pop ax + ret + +; +; Terminate the current process +; +; VOID INRPT far +; int27_handler(iregs UserRegs) +; +reloc_call_int27_handler: + ; + ; First convert the memory to paragraphs + ; + add dx,byte 0fh ; round up + rcr dx,1 + shr dx,1 + shr dx,1 + shr dx,1 + ; + ; ... then use the standard system call + ; + mov ax,3100h + jmp reloc_call_int21_handler ; terminate through int 21h + +; +; + +reloc_call_low_int26_handler: + sti + pushf + push ax + mov ax,026h + jmp short int2526 +reloc_call_low_int25_handler: + sti + pushf + push ax + mov ax,025h +int2526: + push cx + push dx + push bx + push sp + push bp + push si + push di + push ds + push es + + mov cx, sp ; save stack frame + mov dx, ss + + cld + mov bx, [cs:_DGROUP_] + mov ds, bx + + ; setup our local stack + cli + mov ss,bx + mov sp,_disk_api_tos + sti + + Protect386Registers + + push dx + push cx ; save user stack + + push dx ; SS:SP -> user stack + push cx + push ax ; was set on entry = 25,26 + call _int2526_handler + add sp, byte 6 + + pop cx + pop dx ; restore user stack + + Restore386Registers + + ; restore foreground stack here + cli + mov ss, dx + mov sp, cx + + pop es + pop ds + pop di + pop si + pop bp + pop bx ; pop off sp value + pop bx + pop dx + pop cx + pop ax + popf + retf ; Bug-compatiblity with MS-DOS. + ; This function is supposed to leave the original + ; flag image on the stack. + + + +CONTINUE equ 00h +RETRY equ 01h +ABORT equ 02h +FAIL equ 03h + +OK_IGNORE equ 20h +OK_RETRY equ 10h +OK_FAIL equ 08h + +PSP_PARENT equ 16h +PSP_USERSP equ 2eh +PSP_USERSS equ 30h + + + +; +; COUNT +; CriticalError(COUNT nFlag, COUNT nDrive, COUNT nError, struct dhdr FAR *lpDevice); +; + global _CriticalError +_CriticalError: + ; + ; Skip critical error routine if handler is active + ; + cmp byte [_ErrorMode],0 + je CritErr05 ; Jump if equal + + mov ax,FAIL + retn + ; + ; Do local error processing + ; +CritErr05: + ; + ; C Entry + ; + push bp + mov bp,sp + push si + push di + ; + ; Get parameters + ; + mov ah,byte [bp+4] ; nFlags + mov al,byte [bp+6] ; nDrive + mov di,word [bp+8] ; nError + ; + ; make cx:si point to dev header + ; after registers restored use bp:si + ; + mov si,word [bp+10] ; lpDevice Offset + mov cx,word [bp+12] ; lpDevice segment + ; + ; Now save real ss:sp and retry info in internal stack + ; + cli + mov es,[_cu_psp] + push word [es:PSP_USERSS] + push word [es:PSP_USERSP] + push word [_MachineId] + push word [int21regs_seg] + push word [int21regs_off] + push word [_user_r+2] + push word [_user_r] + mov [critical_sp],sp + ; + ; do some clean up because user may never return + ; + inc byte [_ErrorMode] + dec byte [_InDOS] + ; + ; switch to user's stack + ; + mov ss,[es:PSP_USERSS] + mov bp,[es:PSP_USERSP] + RestoreSP + Restore386Registers + mov bp,cx + ; + ; and call critical error handler + ; + int 24h ; DOS Critical error handler + + ; + ; recover context + ; + cld + cli + mov bp, [cs:_DGROUP_] + mov ds,bp + mov ss,bp + mov sp,[critical_sp] + pop word [_user_r] + pop word [_user_r+2] + pop word [int21regs_off] + pop word [int21regs_seg] + pop word [_MachineId] + mov es,[_cu_psp] + pop word [es:PSP_USERSP] + pop word [es:PSP_USERSS] + mov bp, sp + mov ah, byte [bp+4+4] ; restore old AH from nFlags + sti ; Enable interrupts + ; + ; clear flags + ; + mov byte [_ErrorMode],0 + inc byte [_InDOS] + ; + ; Check for ignore and force fail if not ok + cmp al,CONTINUE + jne CritErr10 ; not ignore, keep testing + test ah,OK_IGNORE + jnz CritErr10 + mov al,FAIL + ; + ; Check for retry and force fail if not ok + ; +CritErr10: + cmp al,RETRY + jne CritErr20 ; not retry, keep testing + test ah,OK_RETRY + jnz CritErr20 + mov al,FAIL + ; + ; You know the drill, but now it's different. + ; check for fail and force abort if not ok + ; +CritErr20: + cmp al,FAIL + jne CritErr30 ; not fail, do exit processing + test ah,OK_FAIL + jnz CritErr30 + mov al,ABORT + ; + ; OK, if it's abort we do extra processing. Otherwise just + ; exit. + ; +CritErr30: + cmp al,ABORT + je CritErrAbort ; process abort + +CritErrExit: + xor ah,ah ; clear out top for return + pop di + pop si + pop bp + ret + + ; + ; Abort processing. + ; +CritErrAbort: + mov ax,[_cu_psp] + mov es,ax + cmp ax,[es:PSP_PARENT] + mov al,FAIL + jz CritErrExit + cli + mov bp,word [_user_r+2] ;Get frame + mov ss,bp + mov bp,word [_user_r] + mov sp,bp + mov byte [_ErrorMode],1 ; flag abort + mov ax,4C00h + mov [bp+reg_ax],ax + sti + jmp int21_reentry ; restart the system call diff --git a/kernel/error.c b/kernel/error.c new file mode 100644 index 0000000..da7d382 --- /dev/null +++ b/kernel/error.c @@ -0,0 +1,95 @@ +/****************************************************************/ +/* */ +/* error.c */ +/* */ +/* Main Kernel Error Handler Functions */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" + +#ifdef VERSION_STRINGS +static BYTE *errorRcsId = + "$Id: error.c 709 2003-09-24 19:34:11Z bartoldeman $"; +#endif + +#include "globals.h" + +#ifdef DEBUG +/* error registers */ +VOID dump(void) +{ + printf("Register Dump [AH = %02x CS:IP = %04x:%04x FLAGS = %04x]\n", + error_regs.AH, error_regs.CS, error_regs.IP, error_regs.FLAGS); + printf("AX:%04x BX:%04x CX:%04x DX:%04x\n", + error_regs.AX, error_regs.BX, error_regs.CX, error_regs.DX); + printf("SI:%04x DI:%04x DS:%04x ES:%04x\n", + error_regs.SI, error_regs.DI, error_regs.DS, error_regs.ES); +} +#endif + +/* issue a panic message for corrupted data structures */ +VOID panic(BYTE * s) +{ + put_string("\nPANIC: "); + put_string(s); + put_string("\nSystem halted"); + for (;;) ; +} + +#ifdef IPL +/* issue an internal error message */ +VOID fatal(BYTE * err_msg) +{ + printf("\nInternal IPL error - %s\nSystem halted\n", err_msg); + exit(-1); +} +#else +/* issue an internal error message */ +#if 0 +VOID fatal(BYTE * err_msg) +{ + printf("\nInternal kernel error - \n"); + panic(err_msg); +} +#endif +#endif + +/* Abort, retry or fail for character devices */ +COUNT char_error(request * rq, struct dhdr FAR * lpDevice) +{ + CritErrCode = (rq->r_status & S_MASK) + 0x13; + return CriticalError(EFLG_CHAR | EFLG_ABORT | EFLG_RETRY | EFLG_IGNORE, + 0, rq->r_status & S_MASK, lpDevice); +} + +/* Abort, retry or fail for block devices */ +COUNT block_error(request * rq, COUNT nDrive, struct dhdr FAR * lpDevice, + int mode) +{ + CritErrCode = (rq->r_status & S_MASK) + 0x13; + return CriticalError(EFLG_ABORT | EFLG_RETRY | EFLG_IGNORE | + (mode == DSKWRITE ? EFLG_WRITE : 0), + nDrive, rq->r_status & S_MASK, lpDevice); +} + diff --git a/kernel/execrh.asm b/kernel/execrh.asm new file mode 100644 index 0000000..13198e4 --- /dev/null +++ b/kernel/execrh.asm @@ -0,0 +1,95 @@ +; +; File: +; execrh.asm +; Description: +; request handler for calling device drivers +; +; Copyright (c) 1995, 1998 +; 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. +; +; $Id: execrh.asm 1184 2006-05-20 20:49:59Z mceric $ +; + + %include "segs.inc" + %include "stacks.inc" + +segment HMA_TEXT + ; EXECRH + ; Execute Device Request + ; + ; execrh(rhp, dhp) + ; request far *rhp; + ; struct dhdr far *dhp; + ; +; +; The stack is very critical in here. +; + global EXECRH + global INIT_EXECRH + +%macro EXECRHM 0 + push bp ; perform c entry + mov bp,sp + push si + push ds ; sp=bp-8 + + lds si,[bp+4] ; ds:si = device header + les bx,[bp+8] ; es:bx = request header + + + mov ax, [si+6] ; construct strategy address + mov [bp+4], ax + + push si ; the bloody fucking RTSND.DOS + push di ; driver destroys SI,DI (tom 14.2.03) + + call far[bp+4] ; call far the strategy + + pop di + pop si + + ; Protect386Registers ; old free-EMM386 versions destroy regs in their INIT method + + mov ax,[si+8] ; construct 'interrupt' address + mov [bp+4],ax ; construct interrupt address + call far[bp+4] ; call far the interrupt + + ; Restore386Registers ; less stack load and better performance... + + sti ; damm driver turn off ints + cld ; has gone backwards + pop ds + pop si + pop bp + ret 8 +%endmacro + +EXECRH: + EXECRHM + +%ifndef WATCOM + +segment INIT_TEXT + +INIT_EXECRH: + EXECRHM + +%endif diff --git a/kernel/fatdir.c b/kernel/fatdir.c new file mode 100644 index 0000000..fdead1b --- /dev/null +++ b/kernel/fatdir.c @@ -0,0 +1,482 @@ +/****************************************************************/ +/* */ +/* fatdir.c */ +/* DOS-C */ +/* */ +/* FAT File System dir Functions */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *fatdirRcsId = + "$Id: fatdir.c 1561 2011-04-08 15:35:23Z bartoldeman $"; +#endif + +/* Description. + * Initialize a fnode so that it will point to the directory with + * dirstart starting cluster; in case of passing dirstart == 0 + * fnode will point to the start of a root directory */ +VOID dir_init_fnode(f_node_ptr fnp, CLUSTER dirstart) +{ + /* reset the directory flags */ + fnp->f_sft_idx = 0xff; + fnp->f_dmp = &sda_tmp_dm; + if (fnp == &fnode[1]) + fnp->f_dmp = &sda_tmp_dm_ren; + fnp->f_offset = 0l; + fnp->f_cluster_offset = 0; + + /* root directory */ +#ifdef WITHFAT32 + if (dirstart == 0) + if (ISFAT32(fnp->f_dpb)) + dirstart = fnp->f_dpb->dpb_xrootclst; +#endif + fnp->f_cluster = fnp->f_dmp->dm_dircluster = dirstart; +} + +f_node_ptr dir_open(register const char *dirname, BOOL split, f_node_ptr fnp) +{ + int i; + char *fcbname; + + /* determine what drive and dpb we are using... */ + fnp->f_dpb = get_dpb(dirname[0]-'A'); + /* Perform all directory common handling after all special */ + /* handling has been performed. */ + + /* truename() already did a media check() */ + + /* Walk the directory tree to find the starting cluster */ + /* */ + /* Start from the root directory (dirstart = 0) */ + + /* The CDS's cdsStartCls may be used to shorten the search + beginning at the CWD, see mapPath() and CDS.H in order + to enable this behaviour there. + -- 2001/09/04 ska*/ + + dir_init_fnode(fnp, 0); + fnp->f_dmp->dm_entry = 0; + + dirname += 2; /* Assume FAT style drive */ + fcbname = fnp->f_dmp->dm_name_pat; + while(*dirname != '\0') + { + /* skip the path seperator */ + ++dirname; + + /* don't continue if we're at the end: this check is */ + /* for root directories, the only fully-qualified path */ + /* names that end in a \ */ + if (*dirname == '\0') + break; + + /* Convert the name into an absolute name for */ + /* comparison... */ + + dirname = ConvertNameSZToName83(fcbname, dirname); + + /* do not continue if we split the filename off and are */ + /* at the end */ + if (split && *dirname == '\0') + break; + + /* Now search through the directory to */ + /* find the entry... */ + i = FALSE; + + while (dir_read(fnp) == 1) + { + if (!(fnp->f_dir.dir_attrib & D_VOLID) && + fcbmatch(fcbname, fnp->f_dir.dir_name)) + { + i = TRUE; + break; + } + fnp->f_dmp->dm_entry++; + } + + if (!i || !(fnp->f_dir.dir_attrib & D_DIR)) + { + return (f_node_ptr) 0; + } + else + { + /* make certain we've moved off */ + /* root */ + dir_init_fnode(fnp, getdstart(fnp->f_dpb, &fnp->f_dir)); + fnp->f_dmp->dm_entry = 0; + } + } + return fnp; +} + +/* swap internal and external delete flags */ +STATIC void swap_deleted(char *name) +{ + if (name[0] == DELETED || name[0] == EXT_DELETED) + name[0] ^= EXT_DELETED - DELETED; /* 0xe0 */ +} + +/* Description. + * Read next consequitive directory entry, pointed by fnp. + * If some error occures the other critical + * fields aren't changed, except those used for caching. + * The fnp->f_dmp->dm_entry always corresponds to the directory entry + * which has been read. + * Return value. + * 1 - all OK, directory entry having been read is not empty. + * 0 - Directory entry is empty. + * DE_SEEK - Attempt to read beyound the end of the directory. + * DE_BLKINVLD - Invalid block. + * Note. Empty directory entries always resides at the end of the directory. */ +COUNT dir_read(REG f_node_ptr fnp) +{ + struct buffer FAR *bp; + REG UWORD secsize = fnp->f_dpb->dpb_secsize; + unsigned sector; + unsigned entry = fnp->f_dmp->dm_entry; + + /* can't have more than 65535 directory entries */ + if (entry >= 65535U) + return DE_SEEK; + + /* Determine if we hit the end of the directory. If we have, */ + /* bump the offset back to the end and exit. If not, fill the */ + /* dirent portion of the fnode, set the SFT_FCLEAN bit and leave,*/ + /* but only for root directories */ + + if (fnp->f_dmp->dm_dircluster == 0) + { + if (entry >= fnp->f_dpb->dpb_dirents) + return DE_SEEK; + + fnp->f_dirsector = entry / (secsize / DIRENT_SIZE) + + fnp->f_dpb->dpb_dirstrt; + } + else + { + /* Do a "seek" to the directory position */ + fnp->f_offset = entry * (ULONG)DIRENT_SIZE; + + /* Search through the FAT to find the block */ + /* that this entry is in. */ + if (map_cluster(fnp, XFR_READ) != SUCCESS) + return DE_SEEK; + + /* Compute the block within the cluster and the */ + /* offset within the block. */ + sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; + + fnp->f_dirsector = clus2phys(fnp->f_cluster, fnp->f_dpb) + sector; + /* Get the block we need from cache */ + } + + bp = getblock(fnp->f_dirsector, fnp->f_dpb->dpb_unit); + +#ifdef DISPLAY_GETBLOCK + printf("DIR (dir_read)\n"); +#endif + + /* Now that we have the block for our entry, get the */ + /* directory entry. */ + if (bp == NULL) + return DE_BLKINVLD; + + bp->b_flag &= ~(BFR_DATA | BFR_FAT); + bp->b_flag |= BFR_DIR | BFR_VALID; + + fnp->f_diridx = entry % (secsize / DIRENT_SIZE); + getdirent(&bp->b_buffer[fnp->f_diridx * DIRENT_SIZE], &fnp->f_dir); + + swap_deleted(fnp->f_dir.dir_name); + + /* and for efficiency, stop when we hit the first */ + /* unused entry. */ + /* either returns 1 or 0 */ + return (fnp->f_dir.dir_name[0] != '\0'); +} + +/* Description. + * Writes directory entry pointed by fnp to disk. In case of erroneous + * situation fnode is released. + * The caller should set + * 1. F_DMOD flag if original directory entry was modified. + * Return value. + * TRUE - all OK. + * FALSE - error occured (fnode is released). + */ +BOOL dir_write_update(REG f_node_ptr fnp, BOOL update) +{ + struct buffer FAR *bp; + UBYTE FAR *vp; + + /* Update the entry if it was modified by a write or create... */ + if (!update || (fnp->f_flags & (SFT_FCLEAN|SFT_FDATE)) != SFT_FCLEAN) + { + bp = getblock(fnp->f_dirsector, fnp->f_dpb->dpb_unit); + + /* Now that we have a block, transfer the directory */ + /* entry into the block. */ + if (bp == NULL) + return FALSE; + +#ifdef DISPLAY_GETBLOCK + printf("DIR (dir_write)\n"); +#endif + + swap_deleted(fnp->f_dir.dir_name); + + vp = &bp->b_buffer[fnp->f_diridx * DIRENT_SIZE]; + + if (update) + { + /* only update fields that are also in the SFT, for dos_close/commit */ + fmemcpy(&vp[DIR_NAME], fnp->f_dir.dir_name, FNAME_SIZE + FEXT_SIZE); + fputbyte(&vp[DIR_ATTRIB], fnp->f_dir.dir_attrib); + fputword(&vp[DIR_TIME], fnp->f_dir.dir_time); + fputword(&vp[DIR_DATE], fnp->f_dir.dir_date); + fputword(&vp[DIR_START], fnp->f_dir.dir_start); +#ifdef WITHFAT32 + if (ISFAT32(fnp->f_dpb)) + fputword(&vp[DIR_START_HIGH], fnp->f_dir.dir_start_high); +#endif + fputlong(&vp[DIR_SIZE], fnp->f_dir.dir_size); + } + else + { + putdirent(&fnp->f_dir, vp); + } + + swap_deleted(fnp->f_dir.dir_name); + + bp->b_flag &= ~(BFR_DATA | BFR_FAT); + bp->b_flag |= BFR_DIR | BFR_DIRTY | BFR_VALID; + } + /* Clear buffers after directory write or DOS close */ + return flush_buffers(fnp->f_dpb->dpb_unit); +} + +#ifndef IPL +COUNT dos_findfirst(UCOUNT attr, BYTE * name) +{ + REG f_node_ptr fnp; + REG dmatch *dmp = &sda_tmp_dm; + +/* printf("ff %Fs\n", name);*/ + + /* The findfirst/findnext calls are probably the worst of the */ + /* DOS calls. They must work somewhat on the fly (i.e. - open */ + /* but never close). The near fnodes now work this way. Every */ + /* time a directory is searched, we will initialize the DOS */ + /* dirmatch structure and then for every find, we will open the */ + /* current directory, do a seek and read. */ + + /* first: findfirst("D:\\") returns DE_NFILES */ + if (name[3] == '\0') + return DE_NFILES; + + /* Now open this directory so that we can read the */ + /* fnode entry and do a match on it. */ + if ((fnp = split_path(name, &fnode[0])) == NULL) + return DE_PATHNOTFND; + + /* Now search through the directory to find the entry... */ + + /* Special handling - the volume id is only in the root */ + /* directory and only searched for once. So we need to open */ + /* the root and return only the first entry that contains the */ + /* volume id bit set (while ignoring LFN entries). */ + /* RBIL: ignore ReaDONLY and ARCHIVE bits but DEVICE ignored too*/ + /* For compatibility with bad search requests, only treat as */ + /* volume search if only volume bit set, else ignore it. */ + if ((attr & ~(D_RDONLY | D_ARCHIVE | D_DEVICE)) == D_VOLID) + /* if ONLY label wanted redirect search to root dir */ + dir_init_fnode(fnp, 0); + + /* Now further initialize the dirmatch structure. */ + dmp->dm_drive = name[0] - 'A'; + dmp->dm_attr_srch = attr; + + return dos_findnext(); +} + +/* + BUGFIX TE 06/28/01 + + when using FcbFindXxx, the only information available is + the cluster number + entrycount. everything else MUST\ + be recalculated. + a good test for this is MSDOS CHKDSK, which now (seems too) work +*/ + +COUNT dos_findnext(void) +{ + REG f_node_ptr fnp; + REG dmatch *dmp; + + /* Select the default to help non-drive specified path */ + /* searches... */ + fnp = &fnode[0]; + dmp = &sda_tmp_dm; + fnp->f_dpb = get_dpb(dmp->dm_drive); + if (media_check(fnp->f_dpb) < 0) + return DE_NFILES; + + dir_init_fnode(fnp, dmp->dm_dircluster); + + /* Search through the directory to find the entry, but do a */ + /* seek first. */ + /* Loop through the directory */ + while (dir_read(fnp) == 1) + { + ++dmp->dm_entry; + if (fnp->f_dir.dir_name[0] != DELETED + && (fnp->f_dir.dir_attrib & D_LFN) != D_LFN) + { + if (fcmp_wild(dmp->dm_name_pat, fnp->f_dir.dir_name, FNAME_SIZE + FEXT_SIZE)) + { + /* + MSD Command.com uses FCB FN 11 & 12 with attrib set to 0x16. + Bits 0x21 seem to get set some where in MSD so Rd and Arc + files are returned. + RdOnly + Archive bits are ignored + */ + + /* Test the attribute as the final step */ + /* It's either a special volume label search or an */ + /* attribute inclusive search. The attribute inclusive search */ + /* can also find volume labels if you set e.g. D_DIR|D_VOLUME */ + UBYTE attr_srch; + attr_srch = dmp->dm_attr_srch & ~(D_RDONLY | D_ARCHIVE | D_DEVICE); + if (attr_srch == D_VOLID) + { + if (!(fnp->f_dir.dir_attrib & D_VOLID)) + continue; + } + else if (~attr_srch & (D_DIR | D_SYSTEM | D_HIDDEN | D_VOLID) & + fnp->f_dir.dir_attrib) + continue; + /* If found, transfer it to the dmatch structure */ + memcpy(&SearchDir, &fnp->f_dir, sizeof(struct dirent)); + /* return the result */ + return SUCCESS; + } + } + } + + +#ifdef DEBUG + printf("dos_findnext: %11s\n", fnp->f_dir.dir_name); +#endif + /* return the result */ + return DE_NFILES; +} +#endif +/* + this receives a name in 11 char field NAME+EXT and builds + a zeroterminated string + + unfortunately, blanks are allowed in filenames. like + "test e", " test .y z",... + + so we have to work from the last blank backward +*/ +void ConvertName83ToNameSZ(BYTE FAR * destSZ, BYTE FAR * srcFCBName) +{ + int loop; + int noExtension = FALSE; + + if (*srcFCBName == '.') + { + noExtension = TRUE; + } + + fmemcpy(destSZ, srcFCBName, FNAME_SIZE); + + srcFCBName += FNAME_SIZE; + + for (loop = FNAME_SIZE; --loop >= 0;) + { + if (destSZ[loop] != ' ') + break; + } + destSZ += loop + 1; + + if (!noExtension) /* not for ".", ".." */ + { + + for (loop = FEXT_SIZE; --loop >= 0;) + { + if (srcFCBName[loop] != ' ') + break; + } + if (loop >= 0) + { + *destSZ++ = '.'; + fmemcpy(destSZ, srcFCBName, loop + 1); + destSZ += loop + 1; + } + } + *destSZ = '\0'; +} + +#if 0 +/* + returns the asciiSZ length of a 8.3 filename +*/ + +int FileName83Length(BYTE * filename83) +{ + BYTE buff[13]; + + ConvertName83ToNameSZ(buff, filename83); + + return strlen(buff); +} +#endif + +/* this routine converts a name portion of a fully qualified path */ +/* name, so . and .. are not allowed, only straightforward 8+3 names */ +const char *ConvertNameSZToName83(char *fcbname, const char *dirname) +{ + int i; + memset(fcbname, ' ', FNAME_SIZE + FEXT_SIZE); + + for (i = 0; i < FNAME_SIZE + FEXT_SIZE; i++, dirname++) + { + char c = *dirname; + if (c == '.') + i = FNAME_SIZE - 1; + else if (c != '\0' && c != '\\') + fcbname[i] = c; + else + break; + } + return dirname; +} + diff --git a/kernel/fatfs.c b/kernel/fatfs.c new file mode 100644 index 0000000..c7537e8 --- /dev/null +++ b/kernel/fatfs.c @@ -0,0 +1,1870 @@ +/****************************************************************/ +/* */ +/* fatfs.c */ +/* DOS-C */ +/* */ +/* FAT File System I/O Functions */ +/* */ +/* Copyright (c) 1995,1998 */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +BYTE *RcsId = "$Id: fatfs.c 1632 2011-06-13 16:29:14Z bartoldeman $"; +#endif + +/* */ +/* function prototypes */ +/* */ +STATIC f_node_ptr sft_to_fnode(int fd); +STATIC void fnode_to_sft(f_node_ptr fnp); +STATIC int find_fname(const char *path, int attr, f_node_ptr fnp); + /* /// Added - Ron Cemer */ +STATIC int merge_file_changes(f_node_ptr fnp, int collect); +STATIC BOOL find_free(f_node_ptr); +STATIC int alloc_find_free(f_node_ptr fnp, char *path); +STATIC VOID wipe_out(f_node_ptr); +STATIC CLUSTER extend(f_node_ptr); +STATIC COUNT extend_dir(f_node_ptr); +CLUSTER first_fat(f_node_ptr); +COUNT map_cluster(f_node_ptr, COUNT); +STATIC int shrink_file(f_node_ptr fnp); + +/* FAT time notation in the form of hhhh hmmm mmmd dddd (d = double second) */ +STATIC time time_encode(struct dostime *t) +{ + return (t->hour << 11) | (t->minute << 5) | (t->second >> 1); +} + +#ifdef WITHFAT32 +CLUSTER getdstart(struct dpb FAR *dpbp, struct dirent *dentry) +{ + if (!ISFAT32(dpbp)) + return dentry->dir_start; + return (((CLUSTER)dentry->dir_start_high << 16) | dentry->dir_start); +} + +void setdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value) +{ + dentry->dir_start = (UWORD)value; + if (ISFAT32(dpbp)) + dentry->dir_start_high = (UWORD)(value >> 16); +} +#endif + +ULONG clus2phys(CLUSTER cl_no, struct dpb FAR * dpbp) +{ + CLUSTER data = +#ifdef WITHFAT32 + ISFAT32(dpbp) ? dpbp->dpb_xdata : +#endif + dpbp->dpb_data; + return ((ULONG) (cl_no - 2) << dpbp->dpb_shftcnt) + data; +} + +struct dpb FAR *get_dpb(COUNT dsk) +{ + register struct cds FAR *cdsp = get_cds(dsk); + + if (cdsp == NULL || cdsp->cdsFlags & CDSNETWDRV) + return NULL; + return cdsp->cdsDpb; +} + +/* initialize directory entry (creation/access stamps 0 as per MS-DOS 7.10) */ +STATIC void init_direntry(struct dirent *dentry, unsigned attrib, + CLUSTER cluster, char *name) +{ + memset(dentry, 0, sizeof(struct dirent)); + memcpy(dentry->dir_name, name, FNAME_SIZE + FEXT_SIZE); +#ifdef WITHFAT32 + dentry->dir_start_high = (UWORD)(cluster >> 16); +#endif + dentry->dir_start = (UWORD)cluster; + dentry->dir_attrib = (UBYTE)attrib; + dentry->dir_time = dos_gettime(); + dentry->dir_date = dos_getdate(); +} + +/************************************************************************/ +/* */ +/* Internal file handlers - open, create, read, write, close, etc. */ +/* */ +/************************************************************************/ + +/* Open a file given the path. Flags is 0 for read, 1 for write and 2 */ +/* for update. */ +/* Returns an long where the high word is a status code and the low */ +/* word is an integer file descriptor or a negative error code */ +/* see DosOpenSft(), dosfns.c for an explanation of the flags bits */ +/* directory opens are allowed here; these are not allowed by DosOpenSft*/ + +int dos_open(char *path, unsigned flags, unsigned attrib, int fd) +{ + REG f_node_ptr fnp = sft_to_fnode(fd); + int status = find_fname(path, D_ALL | attrib, fnp); + + /* Check that we don't have a duplicate name, so if we */ + /* find one, truncate it (O_CREAT). */ + if (status == SUCCESS) + { + unsigned char dir_attrib = fnp->f_dir.dir_attrib; + if (flags & O_TRUNC) + { + /* The only permissable attribute is archive, */ + /* check for any other bit set. If it is, give */ + /* an access error. */ + if ((dir_attrib & (D_RDONLY | D_DIR | D_VOLID)) + || (dir_attrib & ~D_ARCHIVE & ~attrib)) + return DE_ACCESS; + + /* Release the existing files FAT and set the */ + /* length to zero, effectively truncating the */ + /* file to zero. */ + wipe_out(fnp); + status = S_REPLACED; + } + else if (flags & O_OPEN) + { + /* force r/o open for FCB if the file is read-only */ + if ((flags & O_FCB) && (dir_attrib & D_RDONLY)) + flags = (flags & ~3) | O_RDONLY; + + /* Check permissions. -- JPP + (do not allow to open volume labels/directories, + and do not allow writing to r/o files) */ + if ((dir_attrib & (D_DIR | D_VOLID)) || + ((dir_attrib & D_RDONLY) && ((flags & O_ACCMODE) != O_RDONLY))) + return DE_ACCESS; + status = S_OPENED; + } + else + { + return DE_FILEEXISTS; + } + } + else if (status == DE_FILENOTFND && (flags & O_CREAT)) + { + int ret = alloc_find_free(fnp, path); + if (ret != SUCCESS) + return ret; + status = S_CREATED; + } + else + { + /* open: If we can't find the file, just return a not */ + /* found error. */ + return status; + } + + /* Now change to file */ + fnp->f_sft_idx = fd; + fnp->f_offset = 0l; + fnp->f_cluster_offset = 0; + + fnp->f_flags &= ~SFT_FDATE; + /* use FCLEAN even on replaced/created files: the bit is reset */ + /* if the file is written to later */ + fnp->f_flags |= SFT_FCLEAN; + if (status != S_OPENED) + { + init_direntry(&fnp->f_dir, attrib, FREE, fnp->f_dmp->dm_name_pat); + if (!dir_write(fnp)) + return DE_ACCESS; + } + + merge_file_changes(fnp, status == S_OPENED); /* /// Added - Ron Cemer */ + /* /// Moved from above. - Ron Cemer */ + fnp->f_cluster = getdstart(fnp->f_dpb, &fnp->f_dir); + + fnode_to_sft(fnp); + return status; +} + +BOOL fcmp_wild(const char * s1, const char * s2, unsigned n) +{ + for ( ; n--; ++s1, ++s2) + if (*s1 != '?' && *s1 != *s2) + return FALSE; + return TRUE; +} + +COUNT dos_close(COUNT fd) +{ + /* Translate the fd into a useful pointer */ + f_node_ptr fnp = sft_to_fnode(fd); + + if (!(fnp->f_flags & SFT_FCLEAN)) + { + if (!(fnp->f_flags & SFT_FDATE)) + { + fnp->f_dir.dir_time = dos_gettime(); + fnp->f_dir.dir_date = dos_getdate(); + } + + merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ + } + fnp->f_sft_idx = 0xff; + + return dir_write_update(fnp, TRUE) ? SUCCESS : DE_INVLDHNDL; +} + +/* */ +/* split a path into it's component directory and file name */ +/* */ +f_node_ptr split_path(const char * path, f_node_ptr fnp) +{ + /* check if the path ends in a backslash */ + if (path[strlen(path) - 1] == '\\') + return (f_node_ptr) 0; + +/* 11/29/99 jt + * Networking and Cdroms. You can put in here a return. + * Maybe a return of 0xDEADBEEF or something for Split or Dir_open. + * Just to let upper level Fdos know its a sft, CDS function. + * Right now for Networking there is no support for Rename, MkDir + * RmDir & Delete. + + + + */ +#ifdef DEBUG + if (get_cds(path[0]-'A')->cdsFlags & CDSNETWDRV) + { + printf("split path called for redirected file: `%s'\n", path); + return (f_node_ptr) 0; + } +#endif + + /* Translate the path into a useful pointer */ + return dir_open(path, TRUE, fnp); +} + +/* checks whether directory part of path exists */ +BOOL dir_exists(char * path) +{ + return split_path(path, &fnode[0]) != NULL; +} + +BOOL fcbmatch(const char *fcbname1, const char *fcbname2) +{ + return memcmp(fcbname1, fcbname2, FNAME_SIZE + FEXT_SIZE) == 0; +} + +STATIC int find_fname(const char *path, int attr, f_node_ptr fnp) +{ + /* check for leading backslash and open the directory given that */ + /* contains the file given by path. */ + if ((fnp = split_path(path, fnp)) == NULL) + return DE_PATHNOTFND; + + while (dir_read(fnp) == 1) + { + if (fcbmatch(fnp->f_dir.dir_name, fnp->f_dmp->dm_name_pat) + && (fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE | attr)) == 0) + { + return SUCCESS; + } + fnp->f_dmp->dm_entry++; + } + return DE_FILENOTFND; +} + +/* Description. + * Remove entries with D_LFN attribute preceeding the directory entry + * pointed by fnp, fnode isn't modified (I hope). + * Return value. + * SUCCESS - completed successfully. + * DE_ACCESS - error occurred, fnode is released. + * input: fnp with valid non-LFN directory entry, not equal to '..' or + * '.' + */ +COUNT remove_lfn_entries(f_node_ptr fnp) +{ + unsigned original_diroff = fnp->f_dmp->dm_entry; + + while (TRUE) + { + if (fnp->f_dmp->dm_entry == 0) + break; + fnp->f_dmp->dm_entry--; + if (dir_read(fnp) <= 0) + return DE_ACCESS; + if (fnp->f_dir.dir_attrib != D_LFN) + break; + fnp->f_dir.dir_name[0] = DELETED; + if (!dir_write(fnp)) return DE_ACCESS; + } + fnp->f_dmp->dm_entry = original_diroff; + if (dir_read(fnp) <= 0) + return DE_ACCESS; + + return SUCCESS; +} + + /* /// Added - Ron Cemer */ + /* If more than one SFT has a file open, and a write + occurs, this function must be called to propagate the + results of that write to the other f_nodes which have + that file open. Note that this function only has an + effect if SHARE is installed. This is for compatibility + reasons, since DOS without SHARE does not share changes + between two or more open instances of the same file + unless these instances were generated by dup() or dup2(). */ +STATIC int merge_file_changes(f_node_ptr fnp, int collect) +{ + int i, j; + sft FAR *sftp; + sfttbl FAR *sp; + + if (!IsShareInstalled(FALSE)) + return SUCCESS; + + i = 0; + for (sp = sfthead; sp != (sfttbl FAR *) - 1; sp = sp->sftt_next) + { + for(j = sp->sftt_count, sftp = sp->sftt_table; --j >= 0; sftp++, i++) + { + if (i != fnp->f_sft_idx && sftp->sft_count != 0 + && fnp->f_dpb == sftp->sft_dcb + && (fnp->f_dir.dir_attrib & D_VOLID) == 0 + && (sftp->sft_attrib & D_VOLID) == 0 + && fnp->f_diridx == sftp->sft_diridx + && fnp->f_dirsector == sftp->sft_dirsector + ) /* same file, but different FD */ + { + if (collect == -1) + { + /* set attrib: close open files */ + int rc = DosCloseSft(i, FALSE); + if (rc != SUCCESS) + return rc; + } + else if (collect) + { + /* We're collecting file changes from any other + SFT which refers to this file. */ + if ((sftp->sft_mode & O_ACCMODE) != RDONLY) + { + setdstart(fnp->f_dpb, &fnp->f_dir, sftp->sft_stclust); + fnp->f_dir.dir_size = sftp->sft_size; + fnp->f_dir.dir_date = sftp->sft_date; + fnp->f_dir.dir_time = sftp->sft_time; + return SUCCESS; + } + } + else + { + /* We just made changes to this file, so we are + distributing these changes to the other f_nodes + which refer to this file. */ + sftp->sft_stclust = getdstart(fnp->f_dpb, &fnp->f_dir); + sftp->sft_size = fnp->f_dir.dir_size; + sftp->sft_date = fnp->f_dir.dir_date; + sftp->sft_time = fnp->f_dir.dir_time; + } + } + } + } + return SUCCESS; +} + +void dos_merge_file_changes(int fd) +{ + merge_file_changes(sft_to_fnode(fd), FALSE); +} + +STATIC COUNT delete_dir_entry(f_node_ptr fnp) +{ + COUNT rc; + + /* Ok, so we can delete. Start out by */ + /* clobbering all FAT entries for this file */ + /* (or, in English, truncate the FAT). */ + if ((rc = remove_lfn_entries(fnp)) < 0) + return rc; + + wipe_out(fnp); + *(fnp->f_dir.dir_name) = DELETED; + + /* The directory has been modified, so set the */ + /* bit before closing it, allowing it to be */ + /* updated */ + if (!dir_write(fnp)) + return DE_ACCESS; + + /* SUCCESSful completion, return it */ + return SUCCESS; +} + +COUNT dos_delete(BYTE * path, int attrib) +{ + REG f_node_ptr fnp = &fnode[0]; + + /* Check that we don't have a duplicate name, so if we */ + /* find one, it's an error. */ + int ret = find_fname(path, attrib, fnp); + if (ret == SUCCESS) + { + /* Do not delete directories or r/o files */ + /* lfn entries and volume labels are only found */ + /* by find_fname() if attrib is set to a */ + /* special value */ + if (fnp->f_dir.dir_attrib & (D_RDONLY | D_DIR)) + return DE_ACCESS; + + return delete_dir_entry(fnp); + } + else + /* No such file, return the error */ + return ret; +} + +COUNT dos_rmdir(BYTE * path) +{ + REG f_node_ptr fnp; + + /* prevent removal of the current directory of that drive */ + register struct cds FAR *cdsp = get_cds(path[0] - 'A'); + if (!fstrcmp(path, cdsp->cdsCurrentPath)) + return DE_RMVCUDIR; + + /* Check that we're not trying to remove the root! */ + if (path[2] == '\\' && path[3] == '\0') + return DE_ACCESS; + + /* Check that the directory is empty. Only the */ + /* "." and ".." are permissable. */ + fnp = dir_open(path, FALSE, &fnode[0]); + if (fnp == NULL) + return DE_PATHNOTFND; + + /* Directories may have attributes, but if other than 'archive' */ + /* then do not allow (RDONLY|SYSTEM|HIDDEN) directory to be deleted. */ + if (fnp->f_dir.dir_attrib & ~(D_DIR |D_ARCHIVE)) + return DE_ACCESS; + + dir_read(fnp); + /* 1st entry should be ".", else directory corrupt or not empty */ + if (fnp->f_dir.dir_name[0] != '.' || fnp->f_dir.dir_name[1] != ' ') + return DE_ACCESS; + + fnp->f_dmp->dm_entry++; + dir_read(fnp); + /* second entry should be ".." */ + if (fnp->f_dir.dir_name[0] != '.' || fnp->f_dir.dir_name[1] != '.') + return DE_ACCESS; + + /* Now search through the directory and make certain */ + /* that there are no entries */ + fnp->f_dmp->dm_entry++; + while (dir_read(fnp) == 1) + { + /* If anything was found, exit with an error. */ + if (fnp->f_dir.dir_name[0] != DELETED && fnp->f_dir.dir_attrib != D_LFN) + return DE_ACCESS; + fnp->f_dmp->dm_entry++; + } + + /* next, split the passed dir into components (i.e. - */ + /* path to new directory and name of new directory */ + if (find_fname(path, D_ALL, fnp) != SUCCESS) + /* this error should not happen because dir_open() succeeded above */ + return DE_PATHNOTFND; + + return delete_dir_entry(fnp); +} + +COUNT dos_rename(BYTE * path1, BYTE * path2, int attrib) +{ + REG f_node_ptr fnp1; + REG f_node_ptr fnp2; + COUNT ret; + char *fcbname; + + /* prevent renaming of the current directory of that drive */ + register struct cds FAR *cdsp = get_cds(path1[0] - 'A'); + if (!fstrcmp(path1, cdsp->cdsCurrentPath)) + return DE_RMVCUDIR; + + /* first check if the source file exists */ + fnp1 = &fnode[0]; + ret = find_fname(path1, attrib, fnp1); + if (ret != SUCCESS) + return ret; + + /* Check that we don't have a duplicate name, so if we find */ + /* one, it's an error. */ + fnp2 = &fnode[1]; + ret = find_fname(path2, attrib, fnp2); + if (ret != DE_FILENOTFND) + return ret == SUCCESS ? DE_ACCESS : ret; + + fcbname = fnp2->f_dmp->dm_name_pat; + if (fnp1->f_dmp->dm_dircluster == fnp2->f_dmp->dm_dircluster) + { + /* rename in the same directory: change the directory entry in-place */ + fnp2 = fnp1; + if ((ret = remove_lfn_entries(fnp1)) < 0) + return ret; + } + else + { + /* do not allow to rename directories between different directories */ + if (fnp1->f_dir.dir_attrib & D_DIR) + return DE_ACCESS; + + /* create new entry in other directory */ + ret = alloc_find_free(fnp2, path2); + if (ret != SUCCESS) + return ret; + + if ((ret = remove_lfn_entries(fnp1)) < 0) + return ret; + + /* init fnode for new file name to match old file name */ + memcpy(&fnp2->f_dir, &fnp1->f_dir, sizeof(struct dirent)); + + /* Ok, so we can delete this one. Save the file info. */ + *(fnp1->f_dir.dir_name) = DELETED; + + if (!dir_write(fnp1)) + return DE_ACCESS; + } + + /* put the fnode's name into the directory. */ + memcpy(fnp2->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE); + + /* SUCCESSful completion, return it */ + return dir_write(fnp2) ? SUCCESS : DE_ACCESS; +} + +/* */ +/* wipe out all FAT entries starting from st for create, delete, etc. */ +/* */ +STATIC VOID wipe_out_clusters(struct dpb FAR * dpbp, CLUSTER st) +{ + REG CLUSTER next; + + /* Loop from start until either a FREE entry is */ + /* encountered (due to a fractured file system) of the */ + /* last cluster is encountered. */ + while (st != LONG_LAST_CLUSTER) /* remove clusters at start until empty */ + { + /* get the next cluster pointed to */ + next = next_cluster(dpbp, st); + + /* just exit if a damaged file system exists */ + if (next <= 1) + return; + + /* zap the FAT pointed to */ + if (link_fat(dpbp, st, FREE) != SUCCESS) /* nonfree->free */ + return; /* better abort on error */ + + /* and the start of free space pointer */ +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + if ((dpbp->dpb_xcluster == UNKNCLUSTER) || (dpbp->dpb_xcluster > st)) + dpbp->dpb_xcluster = st; + } + else +#endif + if ((dpbp->dpb_cluster == UNKNCLUSTER) || (dpbp->dpb_cluster > (UWORD)st)) + dpbp->dpb_cluster = (UWORD)st; + + /* and just follow the linked list */ + st = next; + } +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + write_fsinfo(dpbp); +#endif +} + +/* wipe out all FAT entries for create, delete, etc. */ +/* called by delete_dir_entry and dos_open open in O_TRUNC mode */ +STATIC VOID wipe_out(f_node_ptr fnp) +{ + /* if not already free and valid file, do it */ + CLUSTER cluster = getdstart(fnp->f_dpb, &fnp->f_dir); + if (cluster != FREE) + wipe_out_clusters(fnp->f_dpb, cluster); + /* no flushing here: could get lost chain or "crosslink seed" but */ + /* it would be annoying if mass-deletes could not use BUFFERS... */ +} + +STATIC BOOL find_free(f_node_ptr fnp) +{ + COUNT rc; + + while ((rc = dir_read(fnp)) == 1) + { + if (fnp->f_dir.dir_name[0] == DELETED) + return TRUE; + fnp->f_dmp->dm_entry++; + } + return rc >= 0; +} + +/* alloc_find_free: resets the directory */ +/* Then finds a spare directory entry and if not */ +/* available, tries to extend the directory. */ +STATIC int alloc_find_free(f_node_ptr fnp, char *path) +{ + fnp = split_path(path, fnp); + + /* Get a free f_node pointer so that we can use */ + /* it in building the new file. */ + /* Note that if we're in the root and we don't */ + /* find an empty slot, we need to abort. */ + if (find_free(fnp) == 0) + { + if (fnp->f_dmp->dm_dircluster == 0) + { + return DE_TOOMANY; + } + else + { + /* Otherwise just expand the directory */ + int ret; + + if ((ret = extend_dir(fnp)) != SUCCESS) + /* fnp already closed in extend_dir */ + return ret; + } + } + return SUCCESS; +} + + +/* */ +/* dos_getdate for the file date */ +/* */ +date dos_getdate(void) +{ + struct dosdate dd; + + /* First - get the system date set by either the user */ + /* on start-up or the CMOS clock */ + DosGetDate(&dd); + return DT_ENCODE(dd.month, dd.monthday, dd.year - EPOCH_YEAR); +} + +/* */ +/* dos_gettime for the file time */ +/* */ +time dos_gettime(void) +{ + struct dostime dt; + + /* First - get the system time set by either the user */ + /* on start-up or the CMOS clock */ + DosGetTime(&dt); + return time_encode(&dt); +} + +/* */ +/* Find free cluster in disk FAT table */ +/* */ +STATIC CLUSTER find_fat_free(f_node_ptr fnp) +{ + REG CLUSTER idx, size, cluster; + struct dpb FAR *dpbp = fnp->f_dpb; + +#ifdef DISPLAY_GETBLOCK + printf("[find_fat_free]\n"); +#endif + + /* Start from optimized lookup point for start of FAT */ + idx = 2; + size = dpbp->dpb_size; + +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + if (dpbp->dpb_xcluster != UNKNCLUSTER) + idx = dpbp->dpb_xcluster; + size = dpbp->dpb_xsize; + } + else +#endif + if (dpbp->dpb_cluster != UNKNCLUSTER) + idx = dpbp->dpb_cluster; + + /* Search the FAT table looking for the first free */ + /* entry. */ + cluster = idx; + for (;;) + { +#ifdef CHECK_FAT_DURING_CLUSTER_ALLOC /* slower but nice side effect ;-) */ + if (next_cluster(dpbp, idx) == FREE) +#else + if (is_free_cluster(dpbp, idx)) +#endif + { + cluster = idx; + break; + } + idx++; + /* wrap the search just in case there are free clusters before */ + /* dpbp->dpb_(x)cluster (the fsinfo entry is just a hint!) */ + if (idx > size) idx = 2; + if (idx == cluster) { + /* No empty clusters, disk is FULL! */ + cluster = UNKNCLUSTER; + idx = LONG_LAST_CLUSTER; + break; + } + } + +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + dpbp->dpb_xcluster = cluster; + /* return the free entry */ + write_fsinfo(dpbp); + return idx; + } +#endif + + dpbp->dpb_cluster = (UWORD)cluster; + /* return the free entry */ + return idx; +} + +/* clear out the blocks in the cluster for a directory */ +STATIC int clear_dir(f_node_ptr fnp, CLUSTER cluster) +{ + int idx; + for (idx = 0; idx <= fnp->f_dpb->dpb_clsmask; idx++) + { + struct buffer FAR *bp; + + /* as we are overwriting it completely, don't read first */ + bp = getblockOver(clus2phys(cluster, fnp->f_dpb) + idx, + fnp->f_dpb->dpb_unit); +#ifdef DISPLAY_GETBLOCK + printf("DIR (clear_dir)\n"); +#endif + if (bp == NULL) + return DE_ACCESS; + fmemset(bp->b_buffer, 0, BUFFERSIZE); + bp->b_flag |= BFR_DIRTY | BFR_VALID; + + if (idx != 0) + bp->b_flag |= BFR_UNCACHE; /* needs not be cached */ + } + return SUCCESS; +} + +/* */ +/* create a directory - returns success or a negative error */ +/* number */ +/* */ +COUNT dos_mkdir(BYTE * dir) +{ + REG f_node_ptr fnp; + CLUSTER free_fat, parent; + COUNT ret; + + /* check that the resulting combined path does not exceed + the 67 MAX_CDSPATH limit. this leads to problems: + A) you can't CD to this directory later + B) you can't create files in this subdirectory + C) the created dir will not be found later, so you + can create an unlimited amount of same dirs. this space + is lost forever + */ + if (strlen(dir) >= MAX_CDSPATH) /* dir is already output of "truename" */ + return DE_PATHNOTFND; + + /* Check that we don't have a duplicate name, so if we */ + /* find one, it's an error. */ + fnp = &fnode[0]; + ret = find_fname(dir, D_ALL, fnp); + if (ret != DE_FILENOTFND) + return ret == SUCCESS ? DE_ACCESS : ret; + + parent = fnp->f_dmp->dm_dircluster; + + ret = alloc_find_free(fnp, dir); + if (ret != SUCCESS) + return ret; + + /* get an empty cluster, so that we make it into a */ + /* directory. */ + /* TE this has to be done (and failed) BEFORE the dir entry */ + /* is changed */ + free_fat = find_fat_free(fnp); + + /* No empty clusters, disk is FULL! Translate into a */ + /* useful error message. */ + if (free_fat == LONG_LAST_CLUSTER) + return DE_HNDLDSKFULL; + + init_direntry(&fnp->f_dir, D_DIR, free_fat, fnp->f_dmp->dm_name_pat); + + /* Mark the cluster in the FAT as used and create new dir there */ + if (link_fat(fnp->f_dpb, free_fat, LONG_LAST_CLUSTER) != SUCCESS) /* free->last */ + return DE_HNDLDSKFULL; /* should never happen */ + + /* clean out the new directory */ + ret = clear_dir(fnp, free_fat); + if (ret != SUCCESS) + return ret; + + /* Write the new directory entry */ + if (!dir_write(fnp)) + return DE_ACCESS; + + /* Craft the new directory. Note that if we're in a new */ + /* directory just under the root, ".." pointer is 0. */ + + dir_init_fnode(fnp, free_fat); + fnp->f_dmp->dm_entry = 0; + find_free(fnp); + + /* Create the "." entry */ + init_direntry(&fnp->f_dir, D_DIR, free_fat, ". "); + + /* And put it out */ + if (!dir_write(fnp)) + return DE_ACCESS; + + /* create the ".." entry */ + if (!find_free(fnp) && ((ret = extend_dir(fnp)) != SUCCESS)) + return ret; +#ifdef WITHFAT32 + if (ISFAT32(fnp->f_dpb) && parent == fnp->f_dpb->dpb_xrootclst) + { + parent = 0; + } +#endif + /* use . to allow the compiler to merge duplicate strings */ + init_direntry(&fnp->f_dir, D_DIR, parent, ". "); + fnp->f_dir.dir_name[1] = '.'; + + /* and put it out */ + if (!dir_write(fnp)) + return DE_ACCESS; + + return SUCCESS; +} + +/* extend a directory or file by exactly one cluster */ +/* only map_cluster calls this in a loop (for files) */ +STATIC CLUSTER extend(f_node_ptr fnp) +{ + CLUSTER free_fat; + + /* get an empty cluster, so that we use it to extend the file. */ + free_fat = find_fat_free(fnp); + + /* No empty clusters, disk is FULL! Translate into a useful */ + /* error message. */ + if (free_fat == LONG_LAST_CLUSTER) + return free_fat; + + /* if 1a or 1b works but 2 fails, we get a pointer into an wrong FAT entry */ + /* our new fattab.c checks should be able to trap the bad pointers for now */ + if (link_fat(fnp->f_dpb, free_fat, LONG_LAST_CLUSTER) != SUCCESS) /* 2 */ /* free->last */ + return LONG_LAST_CLUSTER; /* do not try 1a/1b if 2 did not work out */ + /* if 2 works but 1a/1b fails, we only get a harmless lost cluster here */ + + /* Now that we have found a free FAT entry, mark it as the last entry of */ + /* the chain and save (note: BUFFERS cause nondeterministic write order) */ + if (fnp->f_cluster == FREE) /* if the file leaves the empty state */ + setdstart(fnp->f_dpb, &fnp->f_dir, free_fat); /* 1a */ + else + { + /* let previously last chain element chain to newly allocated cluster! */ + if (next_cluster(fnp->f_dpb, fnp->f_cluster) != LONG_LAST_CLUSTER) + { + /* we tried to "grow a file in the middle", f_node or FAT messed up? */ + put_string("FAT chain size bad!\n"); + return LONG_LAST_CLUSTER; + } + if (link_fat(fnp->f_dpb, fnp->f_cluster, free_fat) != SUCCESS) /* 1b */ /* last->used */ + return LONG_LAST_CLUSTER; /* should never happen */ + } + + return free_fat; +} + +STATIC COUNT extend_dir(f_node_ptr fnp) +{ + int ret; + CLUSTER cluster = extend(fnp); + if (cluster == LONG_LAST_CLUSTER) + return DE_HNDLDSKFULL; + + ret = clear_dir(fnp, cluster); + if (ret != SUCCESS) + return ret; + + if (!find_free(fnp)) + return DE_HNDLDSKFULL; + + /* flush the drive buffers so that all info is written */ + if (!flush_buffers(fnp->f_dpb->dpb_unit)) + return DE_ACCESS; + + return SUCCESS; + +} + +/* Description. + * Finds the cluster which contains byte at the fnp->f_offset offset and + * stores its number to the fnp->f_cluster. The search begins from the start of + * a file or a directory depending on whether the SFT index is valid + * and continues through the FAT chain until the target cluster is found. + * The mode can have only XFR_READ or XFR_WRITE values. + * In the XFR_WRITE mode map_cluster extends the FAT chain by creating + * new clusters upon necessity. + * Return value. + * DE_HNDLDSKFULL - [XFR_WRITE mode only] unable to find free cluster + * for extending the FAT chain, the disk is full. + * The fnode is released from memory. + * DE_SEEK - [XFR_READ mode only] byte at f_offset lies outside of + * the FAT chain. The fnode is not released. + * Notes. + * If we are moving forward, then use the relative cluster number offset + * that we are at now (f_cluster_offset) to start, instead of starting + * at the beginning. */ + +COUNT map_cluster(REG f_node_ptr fnp, COUNT mode) +{ + CLUSTER relcluster, cluster; + +#ifdef DISPLAY_GETBLOCK + printf("map_cluster: current %lu, offset %lu, diff=%lu ", + (ULONG)fnp->f_cluster_offset, fnp->f_offset, + fnp->f_offset - fnp->f_cluster_offset); +#endif + + if (fnp->f_cluster == FREE) + { + /* If this is a read but the file still has zero bytes return */ + /* immediately.... */ + if (mode == XFR_READ) + return DE_SEEK; + + /* If someone did a seek, but no writes have occured, we will */ + /* need to initialize the fnode. */ + /* (mode == XFR_WRITE) */ + /* If there are no more free fat entries, then we are full! */ + cluster = extend(fnp); + if (cluster == LONG_LAST_CLUSTER) + { + return DE_HNDLDSKFULL; + } + fnp->f_cluster = cluster; + } + + relcluster = (CLUSTER)((fnp->f_offset / fnp->f_dpb->dpb_secsize) >> + fnp->f_dpb->dpb_shftcnt); + if (relcluster < fnp->f_cluster_offset) + { + /* If seek is to earlier in file than current position, */ + /* we have to follow chain from the beginning again... */ + /* Set internal index and cluster size. */ + fnp->f_cluster = fnp->f_sft_idx == 0xff ? fnp->f_dmp->dm_dircluster : + getdstart(fnp->f_dpb, &fnp->f_dir); + fnp->f_cluster_offset = 0; + } + + /* Now begin the linear search. The relative cluster is */ + /* maintained as part of the set of physical indices. It is */ + /* also the highest order index and is mapped directly into */ + /* physical cluster. Our search is performed by pacing an index */ + /* up to the relative cluster position where the index falls */ + /* within the cluster. */ + + while (fnp->f_cluster_offset != relcluster) + { + /* get next cluster in the chain */ + cluster = next_cluster(fnp->f_dpb, fnp->f_cluster); + if (cluster <= 1) /* 1/error or 0/FREE chain into the void */ + return DE_SEEK; + + /* If this is a read and the next is a LAST_CLUSTER, */ + /* then we are going to read past EOF, return zero read */ + /* or expand the list if we're going to write and have run into */ + /* the last cluster marker. */ + if (cluster == LONG_LAST_CLUSTER) + { + if (mode == XFR_READ) + return DE_SEEK; + + /* mode == XFR_WRITE */ + cluster = extend(fnp); + if (cluster == LONG_LAST_CLUSTER) + return DE_HNDLDSKFULL; + } + + fnp->f_cluster = cluster; + fnp->f_cluster_offset++; + } + +#ifdef DISPLAY_GETBLOCK + printf("done.\n"); +#endif + + return SUCCESS; +} + +/* extends a file from f_dir.dir_size to f_offset */ +/* Proper OSes write zeros in between, but DOS just adds */ +/* garbage sectors, and lets the caller do the zero filling */ +/* if you prefer you can have this enabled using */ +/* #define WRITEZEROS 1 */ +/* but because we want to be compatible, we don't do this by */ +/* default */ +STATIC COUNT dos_extend(f_node_ptr fnp) +{ +#ifdef WRITEZEROS + struct buffer FAR *bp; + UCOUNT xfr_cnt = 0; + /* The variable secsize will be used later. */ + UWORD secsize = fnp->f_dpb->dpb_secsize; + ULONG count; + unsigned sector, boff; +#endif + + if (fnp->f_offset <= fnp->f_dir.dir_size) + return SUCCESS; + +#ifdef WRITEZEROS + count = fnp->f_offset - fnp->f_dir.dir_size; + fnp->f_offset = fnp->f_dir.dir_size; + while (count > 0) +#endif + { + if (map_cluster(fnp, XFR_WRITE) != SUCCESS) + return DE_HNDLDSKFULL; + +#ifdef WRITEZEROS + /* Compute the block within the cluster and the offset */ + /* within the block. */ + sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; + boff = (UWORD)(fnp->f_offset % secsize); + +#ifdef DSK_DEBUG + printf("write %d links; dir offset %ld, cluster %d\n", + fnp->f_count, fnp->f_dmp->dm_entry, fnp->f_cluster); +#endif + + xfr_cnt = count < (ULONG) secsize - boff ? + (UWORD) count : secsize - boff; + + /* get a buffer to store the block in */ + if ((boff == 0) && (xfr_cnt == secsize)) + { + bp = getblockOver(clus2phys(fnp->f_cluster, fnp->f_dpb) + + sector, fnp->f_dpb->dpb_unit); + + } + else + { + bp = getblock(clus2phys(fnp->f_cluster, fnp->f_dpb) + sector, + fnp->f_dpb->dpb_unit); + } + if (bp == NULL) + { + return DE_ACCESS; + } + + /* set a block to zero */ + fmemset((BYTE FAR *) & bp->b_buffer[boff], 0, xfr_cnt); + bp->b_flag |= BFR_DIRTY | BFR_VALID; + + if (xfr_cnt == sizeof(bp->b_buffer)) /* probably not used later */ + { + bp->b_flag |= BFR_UNCACHE; + } + + /* update pointers and counters */ + count -= xfr_cnt; + fnp->f_offset += xfr_cnt; +#endif + fnp->f_dir.dir_size = fnp->f_offset; + merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ + } + return SUCCESS; +} + +/* + comments read optimization for large reads: read total clusters in one piece + + running a program like + + while (1) { + read(fd, header, sizeof(header)); // small read + read(fd, buffer, header.size); // where size is large, up to 63K + // with average ~32K + } + + FreeDOS 2025 is really slow. + on a P200 with modern 30GB harddisk, doing above for a 14.5 MB file + + MSDOS 6.22 clustersize 8K ~2.5 sec (accumulates over clusters, reads for 63 sectors seen), + IBM PCDOS 7.0 8K ~4.3 + IBM PCDOS 7.0 16K ~2.8 + FreeDOS ke2025 ~17.5 + + with the read optimization (ke2025a), + + clustersize 8K ~6.5 sec + clustersize 16K ~4.2 sec + + it was verified with IBM feature tool, + that the drive read ahead cache (says it) is on. still this huge difference ;-) + + + it's coded pretty conservative to avoid all special cases, + so it shouldn't break anything :-) + + possible further optimization: + + collect read across clusters (if file is not fragmented). + MSDOS does this (as readcounts up to 63 sectors where seen) + specially important for diskettes, where clustersize is 1 sector + + the same should be done for writes as well + + the time to compile the complete kernel (on some P200) is + reduced from 67 to 56 seconds - in an otherwise identical configuration. + + it's not clear if this improvement shows up elsewhere, but it shouldn't harm either + + + TE 10/18/01 14:00 + + collect read across clusters (if file is not fragmented) done. + + seems still to work :-)) + + no large performance gains visible, but should now work _much_ + better for the people, that complain about slow floppy access + + the + fnp->f_offset +to_xfer < fnp->f_dir.dir_size && avoid EOF problems + + condition can probably _carefully_ be dropped + + + TE 10/18/01 19:00 + +*/ + +/* Read/write block from disk */ +/* checking for valid access was already done by the functions in + dosfns.c */ +long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) +{ + /* Translate the fd into an fnode pointer, since all internal */ + /* operations are achieved through fnodes. */ + REG f_node_ptr fnp = sft_to_fnode(fd); + REG struct buffer FAR *bp; + UCOUNT xfr_cnt = 0; + UCOUNT ret_cnt = 0; + unsigned secsize; + unsigned to_xfer = count; + ULONG currentblock; + +#if 0 /*DSK_DEBUG*/ + if (bDumpRdWrParms) + { + printf("rwblock:fd %02x buffer %04x:%04x count %x\n", + fd, FP_SEG(buffer), FP_OFF(buffer), count); + } +#endif + + if (mode==XFR_WRITE) + { + fnp->f_dir.dir_attrib |= D_ARCHIVE; + /* mark file as modified and set date not valid any more */ + fnp->f_flags &= ~(SFT_FCLEAN|SFT_FDATE); + + if (dos_extend(fnp) != SUCCESS) + { + fnode_to_sft(fnp); + return 0; + } + } + + /* Test that we are really about to do a data transfer. If the */ + /* count is zero and the mode is XFR_READ, just exit. (Any */ + /* read with a count of zero is a nop). */ + /* */ + /* A write (mode is XFR_WRITE) is a special case. It sets the */ + /* file length to the current length (truncates it). */ + /* */ + /* NOTE: doing this up front saves a lot of headaches later. */ + + if (count == 0) + { + /* NOTE: doing this up front made a lot of headaches later :-( TE */ + /* FAT allocation has to be extended if necessary TE */ + /* Now done in dos_extend BO */ + /* remove all the following allocated clusters in shrink_file */ + if (mode == XFR_WRITE) + { + fnp->f_dir.dir_size = fnp->f_offset; + if (shrink_file(fnp) < 0) /* this is the only call to shrink_file... */ + return DE_ACCESS; + /* why does empty write -always- truncate to current offset? */ + } + fnode_to_sft(fnp); + return 0; + } + + /* The variable secsize will be used later. */ + secsize = fnp->f_dpb->dpb_secsize; + + /* Adjust the far pointer from user space to supervisor space */ + buffer = adjust_far(buffer); + + /* Do the data transfer. Use block transfer methods so that we */ + /* can utilize memory management in future DOS-C versions. */ + while (ret_cnt < count) + { + unsigned sector, boff; + + /* Do an EOF test and return whatever was transferred */ + if (mode == XFR_READ && fnp->f_offset >= fnp->f_dir.dir_size) + { + fnode_to_sft(fnp); + return ret_cnt; + } + + /* Position the file to the fnode's pointer position. This is */ + /* done by updating the fnode's cluster, block (sector) and */ + /* byte offset so that read or write becomes a simple data move */ + /* into or out of the block data buffer. */ + + /* The more difficult scenario is the (more common) */ + /* file offset case. Here, we need to take the fnode's */ + /* offset pointer (f_offset) and translate it into a */ + /* relative cluster position, cluster block (sector) */ + /* offset (sector) and byte offset (boff). Once we */ + /* have this information, we need to translate the */ + /* relative cluster position into an absolute cluster */ + /* position (f_cluster). This is unfortunate because it */ + /* requires a linear search through the file's FAT */ + /* entries. It made sense when DOS was originally */ + /* designed as a simple floppy disk operating system */ + /* where the FAT was contained in core, but now */ + /* requires a search through the FAT blocks. */ + /* */ + /* The algorithm in this function takes advantage of */ + /* the blockio block buffering scheme to simplify the */ + /* task. */ +#ifdef DISPLAY_GETBLOCK + printf("rwblock: "); +#endif + if (map_cluster(fnp, mode) != SUCCESS) + { + fnode_to_sft(fnp); + return ret_cnt; + } + if (mode == XFR_WRITE) + { + merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ + } + + /* Compute the block within the cluster and the offset */ + /* within the block. */ + sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; + boff = (UWORD)(fnp->f_offset % secsize); + + currentblock = clus2phys(fnp->f_cluster, fnp->f_dpb) + sector; + + /* see comments above */ + + if (boff == 0) /* complete sectors only */ + { + static ULONG startoffset; + UCOUNT sectors_to_xfer, sectors_wanted; + + startoffset = fnp->f_offset; + sectors_wanted = to_xfer; + + /* avoid EOF problems */ + if (mode == XFR_READ && to_xfer > fnp->f_dir.dir_size - fnp->f_offset) + sectors_wanted = (UCOUNT)(fnp->f_dir.dir_size - fnp->f_offset); + + sectors_wanted /= secsize; + + if (sectors_wanted == 0) + goto normal_xfer; + + sectors_to_xfer = fnp->f_dpb->dpb_clsmask + 1 - sector; + + sectors_to_xfer = min(sectors_to_xfer, sectors_wanted); + + fnp->f_offset += sectors_to_xfer * secsize; + + while (sectors_to_xfer < sectors_wanted) + { + if (map_cluster(fnp, mode) != SUCCESS) + break; + + if (clus2phys(fnp->f_cluster, fnp->f_dpb) != + currentblock + sectors_to_xfer) + break; + + sectors_to_xfer += fnp->f_dpb->dpb_clsmask + 1; + + sectors_to_xfer = min(sectors_to_xfer, sectors_wanted); + + fnp->f_offset = startoffset + sectors_to_xfer * secsize; + + } + + xfr_cnt = sectors_to_xfer * secsize; + + /* avoid caching trouble */ + + DeleteBlockInBufferCache(currentblock, + currentblock + sectors_to_xfer - 1, + fnp->f_dpb->dpb_unit, mode); + + if (dskxfer(fnp->f_dpb->dpb_unit, + currentblock, + (VOID FAR *) buffer, sectors_to_xfer, + mode == XFR_READ ? DSKREAD : DSKWRITE)) + { + fnp->f_offset = startoffset; + fnode_to_sft(fnp); + return DE_ACCESS; + } + + goto update_pointers; + } + + /* normal read: just the old, buffer = sector based read */ + normal_xfer: + +#ifdef DSK_DEBUG + printf("r/w %d links; dir offset %d, cluster %d, mode %x\n", + fnp->f_count, fnp->f_dmp->dm_entry, fnp->f_cluster, mode); +#endif + + /* Get the block we need from cache */ + bp = getblock(currentblock + /*clus2phys(fnp->f_cluster, fnp->f_dpb) + fnp->f_sector */ + , fnp->f_dpb->dpb_unit); + +#ifdef DISPLAY_GETBLOCK + printf("DATA (rwblock)\n"); +#endif + if (bp == NULL) /* (struct buffer *)0 --> DS:0 !! */ + { + fnode_to_sft(fnp); + return ret_cnt; + } + + /* transfer a block */ + /* Transfer size as either a full block size, or the */ + /* requested transfer size, whichever is smaller. */ + /* Then compare to what is left, since we can transfer */ + /* a maximum of what is left. */ + xfr_cnt = min(to_xfer, secsize - boff); + if (mode == XFR_READ) + xfr_cnt = (UWORD) min(xfr_cnt, fnp->f_dir.dir_size - fnp->f_offset); + + /* transfer a block */ + /* Transfer size as either a full block size, or the */ + /* requested transfer size, whichever is smaller. */ + /* Then compare to what is left, since we can transfer */ + /* a maximum of what is left. */ + if (mode == XFR_WRITE) + { + fmemcpy(&bp->b_buffer[boff], buffer, xfr_cnt); + bp->b_flag |= BFR_DIRTY | BFR_VALID; + } + else + { + fmemcpy(buffer, &bp->b_buffer[boff], xfr_cnt); + } + + /* complete buffer transferred ? + probably not reused later + */ + if (xfr_cnt == sizeof(bp->b_buffer) || + (mode == XFR_READ && fnp->f_offset + xfr_cnt == fnp->f_dir.dir_size)) + { + bp->b_flag |= BFR_UNCACHE; + } + + /* update pointers and counters */ + fnp->f_offset += xfr_cnt; + + update_pointers: + ret_cnt += xfr_cnt; + to_xfer -= xfr_cnt; + buffer = adjust_far((char FAR *)buffer + xfr_cnt); + if (mode == XFR_WRITE) + { + if (fnp->f_offset > fnp->f_dir.dir_size) + { + fnp->f_dir.dir_size = fnp->f_offset; + } + merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ + } + } + fnode_to_sft(fnp); + return ret_cnt; +} + +/* returns the number of unused clusters */ +CLUSTER dos_free(struct dpb FAR * dpbp) +{ + /* There's an unwritten rule here. All fs */ + /* cluster start at 2 and run to max_cluster+2 */ + REG CLUSTER i; + REG CLUSTER cnt; + CLUSTER max_cluster = dpbp->dpb_size; + +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + if (dpbp->dpb_xnfreeclst != XUNKNCLSTFREE) + return dpbp->dpb_xnfreeclst; + max_cluster = dpbp->dpb_xsize; + } + else +#endif + if (dpbp->dpb_nfreeclst != UNKNCLSTFREE) + return dpbp->dpb_nfreeclst; + + cnt = 0; + for (i = 2; i <= max_cluster; i++) + { +#ifdef CHECK_FAT_DURING_SPACE_CHECK /* slower but nice side effect ;-) */ + if (next_cluster(dpbp, i) == FREE) +#else + if (is_free_cluster(dpbp, i)) +#endif + { + if (cnt == 0) + { + /* update first free cluster number */ +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + dpbp->dpb_xcluster = i; + else +#endif + dpbp->dpb_cluster = (UWORD)i; + } + ++cnt; + } + } +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + dpbp->dpb_xnfreeclst = cnt; + write_fsinfo(dpbp); + return cnt; + } +#endif + dpbp->dpb_nfreeclst = (UWORD)cnt; + return cnt; +} + +#ifndef IPL +int dos_cd(char * PathName) +{ + f_node_ptr fnp; + struct cds FAR *cdsp; + + /* now test for its existance. If it doesn't, return an error. */ + if ((fnp = dir_open(PathName, FALSE, &fnode[0])) == NULL) + return DE_PATHNOTFND; + + /* problem: RBIL table 01643 does not give a FAT32 field for the + CDS start cluster. But we are not using this field ourselves */ + cdsp = get_cds(PathName[0] - 'A'); + cdsp->cdsStrtClst = (UWORD)fnp->f_dmp->dm_dircluster; + return SUCCESS; +} +#endif + +#ifndef IPL +COUNT dos_getfattr(BYTE * name) +{ + f_node_ptr fnp = &fnode[0]; + int ret = find_fname(name, D_ALL, fnp); + return ret == SUCCESS ? fnp->f_dir.dir_attrib : ret; +} + +COUNT dos_setfattr(BYTE * name, UWORD attrp) +{ + f_node_ptr fnp; + int rc; + + /* JPP-If user tries to set VOLID or RESERVED bits, return error. + We used to also check for D_DIR here, but causes issues with deltree + which is trying to work around another issue. So now we check + these here, and only report DE_ACCESS if user tries to set directory + bit on a non-directory entry. + */ + if ((attrp & (D_VOLID | 0xC0)) != 0) + return DE_ACCESS; + + fnp = &fnode[0]; + rc = find_fname(name, D_ALL, fnp); + if (rc != SUCCESS) + return rc; + + /* if caller tries to set DIR on non-directory, return error */ + if ((attrp & D_DIR) && !(fnp->f_dir.dir_attrib & D_DIR)) + return DE_ACCESS; + + /* Set the attribute from the fnode and return */ + /* clear all attributes but DIR and VOLID */ + fnp->f_dir.dir_attrib &= (D_VOLID | D_DIR); /* JPP */ + + /* set attributes that user requested */ + fnp->f_dir.dir_attrib |= attrp; /* JPP */ + + /* close open files in compat mode, otherwise there was a critical error */ + rc = merge_file_changes(fnp, -1); + if (rc == SUCCESS && !dir_write(fnp)) + rc = DE_ACCESS; + return rc; +} +#endif + +#ifdef WITHFAT32 +VOID dpb16to32(struct dpb FAR *dpbp) +{ + dpbp->dpb_xflags = 0; + dpbp->dpb_xfsinfosec = 0xffff; + dpbp->dpb_xbackupsec = 0xffff; + dpbp->dpb_xrootclst = 0; + dpbp->dpb_xdata = dpbp->dpb_data; + dpbp->dpb_xsize = dpbp->dpb_size; +} + +VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp, BOOL extended) +#else +VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp) +#endif +{ + ULONG size; + REG UWORD shftcnt; + bpb sbpb; + + fmemcpy(&sbpb, bpbp, sizeof(sbpb)); + for (shftcnt = 0; (sbpb.bpb_nsector >> shftcnt) > 1; shftcnt++) + ; + dpbp->dpb_shftcnt = shftcnt; + + dpbp->dpb_mdb = sbpb.bpb_mdesc; + dpbp->dpb_secsize = sbpb.bpb_nbyte; + dpbp->dpb_clsmask = sbpb.bpb_nsector - 1; + dpbp->dpb_fatstrt = sbpb.bpb_nreserved; + dpbp->dpb_fats = sbpb.bpb_nfat; + dpbp->dpb_dirents = sbpb.bpb_ndirent; + size = sbpb.bpb_nsize == 0 ? sbpb.bpb_huge : (ULONG) sbpb.bpb_nsize; + dpbp->dpb_fatsize = sbpb.bpb_nfsect; + dpbp->dpb_dirstrt = dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_fatsize; + dpbp->dpb_data = dpbp->dpb_dirstrt + + (dpbp->dpb_dirents + dpbp->dpb_secsize/DIRENT_SIZE - 1) / + (dpbp->dpb_secsize/DIRENT_SIZE); + dpbp->dpb_size = (UWORD)((size - dpbp->dpb_data) >> shftcnt) + 1; + { /* Make sure the number of FAT sectors is actually enough to hold that */ + /* many clusters. Otherwise back the number of clusters down (LG & AB) */ + unsigned fatsiz; + ULONG tmp = dpbp->dpb_fatsize * (ULONG)(dpbp->dpb_secsize / 2);/* entries/2 */ + if (tmp >= 0x10000UL) + goto ckok; + fatsiz = (unsigned) tmp; + if (dpbp->dpb_size > FAT_MAGIC) {/* FAT16 */ + if (fatsiz <= FAT_MAGIC) /* FAT12 - let it pass through rather */ + goto ckok; /* than lose data correcting FAT type */ + } else { /* FAT12 */ + if (fatsiz >= 0x4000) + goto ckok; + fatsiz = fatsiz * 4 / 3; + } + if (dpbp->dpb_size >= fatsiz) /* FAT too short */ + dpbp->dpb_size = fatsiz - 1; /* - 2 reserved entries + 1 */ +ckok:; + } + dpbp->dpb_flags = 0; + dpbp->dpb_cluster = UNKNCLUSTER; + /* number of free clusters */ + dpbp->dpb_nfreeclst = UNKNCLSTFREE; + +#ifdef WITHFAT32 + if (extended) + { + dpbp->dpb_xfatsize = sbpb.bpb_nfsect == 0 ? sbpb.bpb_xnfsect + : sbpb.bpb_nfsect; + dpbp->dpb_xcluster = UNKNCLUSTER; + dpbp->dpb_xnfreeclst = XUNKNCLSTFREE; /* number of free clusters */ + + dpb16to32(dpbp); + + if (ISFAT32(dpbp)) + { + dpbp->dpb_xflags = sbpb.bpb_xflags; + dpbp->dpb_xfsinfosec = sbpb.bpb_xfsinfosec; + dpbp->dpb_xbackupsec = sbpb.bpb_xbackupsec; + dpbp->dpb_dirents = 0; + dpbp->dpb_dirstrt = 0xffff; + dpbp->dpb_size = 0; + dpbp->dpb_xdata = + dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_xfatsize; + dpbp->dpb_xsize = ((size - dpbp->dpb_xdata) >> shftcnt) + 1; + dpbp->dpb_xrootclst = sbpb.bpb_xrootclst; + read_fsinfo(dpbp); + } + } +#endif +} + +STATIC int rqblockio(unsigned char command, struct dpb FAR * dpbp) +{ + retry: + MediaReqHdr.r_length = sizeof(request); + MediaReqHdr.r_unit = dpbp->dpb_subunit; + MediaReqHdr.r_command = command; + MediaReqHdr.r_mcmdesc = dpbp->dpb_mdb; + MediaReqHdr.r_status = 0; + + if (command == C_BLDBPB) /* help USBASPI.SYS & DI1000DD.SYS (TE) */ + MediaReqHdr.r_bpfat = (boot FAR *)DiskTransferBuffer; + execrh((request FAR *) & MediaReqHdr, dpbp->dpb_device); + if ((MediaReqHdr.r_status & S_ERROR) || !(MediaReqHdr.r_status & S_DONE)) + { + FOREVER + { + switch (block_error(&MediaReqHdr, dpbp->dpb_unit, dpbp->dpb_device, 0)) + { + case ABORT: + case FAIL: + return DE_INVLDDRV; + + case RETRY: + goto retry; + + case CONTINUE: + return SUCCESS; + } + } + } + return SUCCESS; +} + +COUNT media_check(REG struct dpb FAR * dpbp) +{ + int ret; + if (dpbp == NULL) + return DE_INVLDDRV; + + /* First test if anyone has changed the removable media */ + ret = rqblockio(C_MEDIACHK, dpbp); + if (ret < SUCCESS) + return ret; + + switch (MediaReqHdr.r_mcretcode | dpbp->dpb_flags) + { + case M_NOT_CHANGED: + /* It was definitely not changed, so ignore it */ + return SUCCESS; + + /* If it is forced or the media may have changed, */ + /* rebuild the bpb */ + case M_DONT_KNOW: + /* IBM PCDOS technical reference says to call BLDBPB if */ + /* there are no used buffers */ + if (dirty_buffers(dpbp->dpb_unit)) + return SUCCESS; + + /* If it definitely changed, don't know (falls through) */ + /* or has been changed, rebuild the bpb. */ + /* case M_CHANGED: */ + default: + setinvld(dpbp->dpb_unit); + ret = rqblockio(C_BLDBPB, dpbp); + if (ret < SUCCESS) + return ret; +#ifdef WITHFAT32 + /* extend dpb only for internal or FAT32 devices */ + bpb_to_dpb(MediaReqHdr.r_bpptr, dpbp, + MediaReqHdr.r_bpptr->bpb_nfsect == 0 || + FP_SEG(dpbp) == FP_SEG(&os_major)); +#else + bpb_to_dpb(MediaReqHdr.r_bpptr, dpbp); +#endif + return SUCCESS; + } +} + +/* copy the SFT fd into the first near fnode */ +STATIC f_node_ptr sft_to_fnode(int fd) +{ + sft FAR *sftp = idx_to_sft(fd); + f_node_ptr fnp = &fnode[0]; + + fnp->f_sft_idx = fd; + + fnp->f_flags = sftp->sft_flags; + + fnp->f_dir.dir_attrib = sftp->sft_attrib; + fmemcpy(fnp->f_dir.dir_name, sftp->sft_name, FNAME_SIZE + FEXT_SIZE); + fnp->f_dir.dir_time = sftp->sft_time; + fnp->f_dir.dir_date = sftp->sft_date; + fnp->f_dir.dir_size = sftp->sft_size; + fnp->f_dpb = sftp->sft_dcb; + setdstart(fnp->f_dpb, &fnp->f_dir, sftp->sft_stclust); + + fnp->f_diridx = sftp->sft_diridx; + fnp->f_dirsector = sftp->sft_dirsector; + fnp->f_offset = sftp->sft_posit; + fnp->f_cluster = sftp->sft_cuclust; +#ifdef WITHFAT32 + fnp->f_cluster_offset = sftp->sft_relclust | + ((ULONG)sftp->sft_relclust_high << 16); +#else + fnp->f_cluster_offset = sftp->sft_relclust; +#endif + return fnp; +} + +STATIC void fnode_to_sft(f_node_ptr fnp) +{ + sft FAR *sftp = idx_to_sft(fnp->f_sft_idx); + + sftp->sft_flags = fnp->f_flags; + + sftp->sft_attrib = fnp->f_dir.dir_attrib; + fmemcpy(sftp->sft_name, fnp->f_dir.dir_name, FNAME_SIZE + FEXT_SIZE); + sftp->sft_time = fnp->f_dir.dir_time; + sftp->sft_date = fnp->f_dir.dir_date; + sftp->sft_size = fnp->f_dir.dir_size; + sftp->sft_stclust = getdstart(fnp->f_dpb, &fnp->f_dir); + + sftp->sft_diridx = fnp->f_diridx; + sftp->sft_dirsector = fnp->f_dirsector; + sftp->sft_dcb = fnp->f_dpb; + sftp->sft_posit = fnp->f_offset; + sftp->sft_cuclust = fnp->f_cluster; + sftp->sft_relclust = (UWORD)fnp->f_cluster_offset; +#ifdef WITHFAT32 + sftp->sft_relclust_high = (UWORD)(fnp->f_cluster_offset >> 16); +#endif +} + +/* TE + if the current filesize in FAT is larger then the dir_size + it's truncated here. + the BUG was: + copy COMMAND.COM xxx + echo >xxx + + then, the dirsize of xxx was set to ~20, but the allocated + FAT entries not returned. + this code corrects this + + Unfortunately, this code _nearly_ works, but fails one of the + Apps tested (VB ISAM); BO: confirmation??? +*/ + +STATIC int shrink_file(f_node_ptr fnp) +{ + + ULONG lastoffset = fnp->f_offset; /* has to be saved */ + CLUSTER last, next, st; + struct dpb FAR *dpbp = fnp->f_dpb; + int ret = DE_ACCESS; + + if (fnp->f_offset) + fnp->f_offset--; /* last existing cluster */ + else if (fnp->f_cluster == FREE) + /* zero offset, 0-byte file: nothing to do ! */ + goto done_success; + + if (map_cluster(fnp, XFR_READ) != SUCCESS) /* error, don't truncate */ + goto done; + + st = fnp->f_cluster; + + next = next_cluster(dpbp, st); /* return nr. of 1st cluster after new end */ + + if (next <= 1) /* 1/error or 0/FREE chain points into the void */ + goto done; + + /* Loop from start until either a FREE entry is */ + /* encountered (due to a damaged file system) or the */ + /* last cluster is encountered. */ + /* zap the FAT pointed to */ + + if (fnp->f_dir.dir_size == 0) /* file shrinks to size 0 */ + { + fnp->f_cluster = FREE; + setdstart(dpbp, &fnp->f_dir, FREE); /* file no longer has start cluster */ + last = FREE; + } + else + { + if (next == LONG_LAST_CLUSTER) /* nothing to do, file already ends here */ + goto done_success; + last = LONG_LAST_CLUSTER; /* make file end */ + } + if (link_fat(dpbp, st, last) != SUCCESS) + goto done; /* do not wipe remainder of chain if FAT is broken */ + + wipe_out_clusters(dpbp, next); /* free clusters after the end */ + /* flush buffers, make sure disk is updated */ + if (!flush_buffers(fnp->f_dpb->dpb_unit)) + goto done; + +done_success: + ret = SUCCESS; + +done: + fnp->f_offset = lastoffset; /* has to be restored */ + return ret; +} + +/* + * TE 12 jun 2001 bugs corrected + * handles disk full (in a incompatible way :-( ) + * allows use of last cluster + * prevents mkdir, if disk is full (was creating crosslinked dirs) + * bugs detected, but NOT corrected + * on disk full, MSDOS will NOT write any byte, simply return SUCCESS, 0 bytes + * FreeDOS will write all possible bytes, then close file(BUG) + * + * the dos_mkdir/extenddir (with getblock() instead of getblockOver) was a real + * performance killer on large drives. (~0.5 sec /dos_mkdir) TE + */ diff --git a/kernel/fattab.c b/kernel/fattab.c new file mode 100644 index 0000000..0088a4a --- /dev/null +++ b/kernel/fattab.c @@ -0,0 +1,413 @@ +/****************************************************************/ +/* */ +/* fattab.c */ +/* */ +/* FAT File System Table Functions */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: fattab.c 1631 2011-06-13 16:27:34Z bartoldeman $"; +#endif + +/************************************************************************/ +/* */ +/* cluster/sector routines */ +/* */ +/************************************************************************/ + +/* special "impossible" "Cluster2" value of 1 denotes reading the + cluster number rather than overwriting it */ +#define READ_CLUSTER 1 + +#ifndef ISFAT32 +int ISFAT32(struct dpb FAR * dpbp) +{ + return _ISFAT32(dpbp); +} +#endif + +void clusterMessage(const char * msg, CLUSTER clussec) +{ + put_string("Run chkdsk: Bad FAT "); + put_string(msg); +#ifdef WITHFAT32 + put_unsigned((unsigned)(clussec >> 16), 16, 4); +#endif + put_unsigned((unsigned)(clussec & 0xffffu), 16, 4); + put_console('\n'); +} + +struct buffer FAR *getFATblock(struct dpb FAR * dpbp, CLUSTER clussec) +{ + /* *** why dpbp->dpb_unit? only useful to know in context of the dpbp...? *** */ + struct buffer FAR *bp = getblock(clussec, dpbp->dpb_unit); + + if (bp) + { + bp->b_flag &= ~(BFR_DATA | BFR_DIR); + bp->b_flag |= BFR_FAT | BFR_VALID; + bp->b_dpbp = dpbp; + bp->b_copies = dpbp->dpb_fats; + bp->b_offset = dpbp->dpb_fatsize; /* 0 for FAT32 but blockio.c knows that */ +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + { + if (dpbp->dpb_xflags & FAT_NO_MIRRORING) + bp->b_copies = 1; + } +#endif + } else { + clusterMessage("I/O: 0x",clussec); + } + return bp; +} + +#ifdef WITHFAT32 +void read_fsinfo(struct dpb FAR * dpbp) +{ + struct buffer FAR *bp; + struct fsinfo FAR *fip; + CLUSTER cluster; + + if (dpbp->dpb_xfsinfosec == 0xffff) + return; + + bp = getblock(dpbp->dpb_xfsinfosec, dpbp->dpb_unit); + bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT | BFR_DIRTY); + bp->b_flag |= BFR_VALID; + + fip = (struct fsinfo FAR *)&bp->b_buffer[0x1e4]; + /* need to range check values because they may not be correct */ + cluster = fip->fi_nfreeclst; + if (cluster >= dpbp->dpb_xsize) + cluster = XUNKNCLSTFREE; + dpbp->dpb_xnfreeclst = cluster; + cluster = fip->fi_cluster; + if (cluster < 2 || cluster > dpbp->dpb_xsize) + cluster = UNKNCLUSTER; + dpbp->dpb_xcluster = cluster; +} + +void write_fsinfo(struct dpb FAR * dpbp) +{ + struct buffer FAR *bp; + struct fsinfo FAR *fip; + + if (dpbp->dpb_xfsinfosec == 0xffff) + return; + + bp = getblock(dpbp->dpb_xfsinfosec, dpbp->dpb_unit); + bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT); + bp->b_flag |= BFR_VALID; + + fip = (struct fsinfo FAR *)&bp->b_buffer[0x1e4]; + + if (fip->fi_nfreeclst != dpbp->dpb_xnfreeclst || + fip->fi_cluster != dpbp->dpb_xcluster) + bp->b_flag |= BFR_DIRTY; /* only flag for update if we had real news */ + + fip->fi_nfreeclst = dpbp->dpb_xnfreeclst; + fip->fi_cluster = dpbp->dpb_xcluster; +} +#endif + +/* */ +/* The FAT file system is difficult to trace through FAT table. */ +/* There are two kinds of FATs, 12 bit and 16 bit. The 16 bit */ +/* FAT is the easiest, since it is nothing more than a series */ +/* of UWORDs. The 12 bit FAT is difficult, because it packs 3 */ +/* FAT entries into two BYTEs. These are packed as follows: */ +/* */ +/* 0x0003 0x0004 0x0005 0x0006 0x0007 0x0008 0x0009 ... */ +/* */ +/* are packed as */ +/* */ +/* 0x03 0x40 0x00 0x05 0x60 0x00 0x07 0x80 0x00 0x09 ... */ +/* */ +/* 12 bytes are compressed to 9 bytes */ +/* */ + +/* either read the value at Cluster1 (if Cluster2 is READ_CLUSTER) */ +/* or write the Cluster2 value to the FAT entry at Cluster1 */ +/* Read is always via next_cluster wrapper which has extra checks */ +/* It might make sense to manually check old values before a write */ +/* returns: the cluster number (or 1 on error) for read mode */ +/* returns: SUCCESS (or 1 on error) for write mode */ +CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, + REG CLUSTER Cluster2) +{ + struct buffer FAR *bp; + unsigned idx; + unsigned secdiv; /* FAT entries per sector; nibbles for FAT12! */ + unsigned char wasfree; + CLUSTER clussec = Cluster1; + CLUSTER max_cluster = dpbp->dpb_size; + +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + max_cluster = dpbp->dpb_xsize; +#endif + + if (clussec <= 1 || clussec > max_cluster) /* try to read out of range? */ + { + clusterMessage("index: 0x",clussec); /* bad array offset */ + return 1; + } + + /* Cluster2 can 0 (FREE) or 1 (READ_CLUSTER), a cluster nr. >= 2, */ + /* (range check this case!) LONG_LAST_CLUSTER or LONG_BAD here... */ + if (Cluster2 < LONG_BAD && Cluster2 > max_cluster) /* writing bad value? */ + { + clusterMessage("write: 0x",Cluster2); /* refuse to write bad value */ + return 1; + } + + secdiv = dpbp->dpb_secsize; + if (ISFAT12(dpbp)) + { + clussec = (unsigned)clussec * 3; + secdiv *= 2; + } + else /* FAT16 or FAT32 */ + { + secdiv /= 2; +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + secdiv /= 2; +#endif + } + + /* idx is a pointer to an index which is the nibble offset of the FAT + entry within the sector for FAT12, or word offset for FAT16, or + dword offset for FAT32 */ + idx = (unsigned)(clussec % secdiv); + clussec /= secdiv; + clussec += dpbp->dpb_fatstrt; +#ifdef WITHFAT32 + if (ISFAT32(dpbp) && (dpbp->dpb_xflags & FAT_NO_MIRRORING)) + { + /* we must modify the active fat, + it's number is in the 0-3 bits of dpb_xflags */ + clussec += (dpbp->dpb_xflags & 0xf) * dpbp->dpb_xfatsize; + } +#endif + + /* Get the block that this cluster is in */ + bp = getFATblock(dpbp, clussec); + + if (bp == NULL) { + return 1; /* the only error code possible here */ + } + + if (ISFAT12(dpbp)) + { + REG UBYTE FAR *fbp0, FAR * fbp1; + struct buffer FAR * bp1; + unsigned cluster, cluster2; + + /* form an index so that we can read the block as a */ + /* byte array */ + idx /= 2; + + /* Test to see if the cluster straddles the block. If */ + /* it does, get the next block and use both to form the */ + /* the FAT word. Otherwise, just point to the next */ + /* block. */ + fbp0 = &bp->b_buffer[idx]; + + /* pointer to next byte, will be overwritten, if not valid */ + fbp1 = fbp0 + 1; + + if (idx >= (unsigned)dpbp->dpb_secsize - 1) + { + /* blockio.c LRU logic ensures that bp != bp1 */ + bp1 = getFATblock(dpbp, (unsigned)clussec + 1); + if (bp1 == 0) + return 1; /* the only error code possible here */ + + if (Cluster2 != READ_CLUSTER) + bp1->b_flag |= BFR_DIRTY | BFR_VALID; + + fbp1 = &bp1->b_buffer[0]; + } + + cluster = *fbp0 | (*fbp1 << 8); + { + unsigned res = cluster; + + /* Now to unpack the contents of the FAT entry. Odd and */ + /* even bytes are packed differently. */ + + if (Cluster1 & 0x01) + cluster >>= 4; + cluster &= 0x0fff; + + if ((unsigned)Cluster2 == READ_CLUSTER) + { + if (cluster >= MASK12) + return LONG_LAST_CLUSTER; + if (cluster == BAD12) + return LONG_BAD; + return cluster; + } + + wasfree = 0; + if (cluster == FREE) + wasfree = 1; + + cluster = res; + } + + /* Cluster2 may be set to LONG_LAST_CLUSTER == 0x0FFFFFFFUL or 0xFFFF */ + /* -- please don't remove this mask! */ + cluster2 = (unsigned)Cluster2 & 0x0fff; + + /* Now pack the value in */ + if ((unsigned)Cluster1 & 0x01) + { + cluster &= 0x000f; + cluster2 <<= 4; + } + else + { + cluster &= 0xf000; + } + cluster |= cluster2; + *fbp0 = (UBYTE)cluster; + *fbp1 = (UBYTE)(cluster >> 8); + } + else if (ISFAT16(dpbp)) + { + /* form an index so that we can read the block as a */ + /* byte array */ + /* and get the cluster number */ + UWORD res = fgetword(&bp->b_buffer[idx * 2]); + if ((unsigned)Cluster2 == READ_CLUSTER) + { + if (res >= MASK16) + return LONG_LAST_CLUSTER; + if (res == BAD16) + return LONG_BAD; + + return res; + } + /* Finally, put the word into the buffer and mark the */ + /* buffer as dirty. */ + fputword(&bp->b_buffer[idx * 2], (UWORD)Cluster2); + wasfree = 0; + if (res == FREE) + wasfree = 1; + } +#ifdef WITHFAT32 + else if (ISFAT32(dpbp)) + { + /* form an index so that we can read the block as a */ + /* byte array */ + UDWORD res = fgetlong(&bp->b_buffer[idx * 4]) & LONG_LAST_CLUSTER; + if (Cluster2 == READ_CLUSTER) + { + if (res > LONG_BAD) + return LONG_LAST_CLUSTER; + + return res; + } + /* Finally, put the word into the buffer and mark the */ + /* buffer as dirty. */ + fputlong(&bp->b_buffer[idx * 4], Cluster2 & LONG_LAST_CLUSTER); + wasfree = 0; + if (res == FREE) + wasfree = 1; + } +#endif + else { + put_string("Bad DPB!\n"); /* FAT1x size field > 65525U (see fat.h) */ + return 1; + } + + /* update the free space count */ + bp->b_flag |= BFR_DIRTY | BFR_VALID; + if (Cluster2 == FREE || wasfree) + { + int adjust = 0; + if (!wasfree) + adjust = 1; + else if (Cluster2 != FREE) + adjust = -1; +#ifdef WITHFAT32 + if (ISFAT32(dpbp) && dpbp->dpb_xnfreeclst != XUNKNCLSTFREE) + { + /* update the free space count for returned */ + /* cluster */ + dpbp->dpb_xnfreeclst += adjust; + write_fsinfo(dpbp); + } + else +#endif + if (dpbp->dpb_nfreeclst != UNKNCLSTFREE) + dpbp->dpb_nfreeclst += adjust; + } + return SUCCESS; +} + +/* Given the disk parameters, and a cluster number, this function */ +/* looks at the FAT, and returns the next cluster in the clain or */ +/* 0 if there is no chain, 1 on error, LONG_LAST_CLUSTER at end. */ +CLUSTER next_cluster(struct dpb FAR * dpbp, CLUSTER ClusterNum) +{ + CLUSTER candidate, following, max_cluster; + candidate = link_fat(dpbp, ClusterNum, READ_CLUSTER); + /* empty (0) error (1) bad (LONG_BAD) last (>LONG_BAD) need no checks */ +#if 0 + if (candidate == ClusterNum) + return 1; /* chain has a tiny loop - easy but boring error check */ +#endif + if (candidate < 2 || candidate >= LONG_BAD) + return candidate; + max_cluster = dpbp->dpb_size; +#ifdef WITHFAT32 + if (ISFAT32(dpbp)) + max_cluster = dpbp->dpb_xsize; +#endif + /* FAT entry points to a possibly invalid next cluster */ + following = link_fat(dpbp, candidate, READ_CLUSTER); + if (following<2 || (following < LONG_BAD && following > max_cluster)) + { + /* chain must not contain free or out of range clusters */ + clusterMessage("value: 0x",following); /* read returned bad value */ + return 1; /* only possible error code here */ + } + /* without checking "following", a chain can dangle to a free cluster: */ + /* if that cluster is later used by another chain, you get cross links */ + return candidate; +} + +/* check if the selected cluster is free (faster than next_cluster) */ +BOOL is_free_cluster(struct dpb FAR * dpbp, CLUSTER ClusterNum) +{ + return (link_fat(dpbp, ClusterNum, READ_CLUSTER) == FREE); +} diff --git a/kernel/fcbfns.c b/kernel/fcbfns.c new file mode 100644 index 0000000..62bbd11 --- /dev/null +++ b/kernel/fcbfns.c @@ -0,0 +1,713 @@ +/****************************************************************/ +/* */ +/* fcbfns.c */ +/* */ +/* Old CP/M Style Function Handlers 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: fcbfns.c 1405 2009-05-26 20:44:44Z bartoldeman $"; +#endif + +#define FCB_SUCCESS 0 +#define FCB_ERR_NODATA 1 +#define FCB_ERR_SEGMENT_WRAP 2 +#define FCB_ERR_EOF 3 +#define FCB_ERROR 0xff + +STATIC fcb FAR *ExtFcbToFcb(xfcb FAR * lpExtFcb); +STATIC fcb FAR *CommonFcbInit(xfcb FAR * lpExtFcb, BYTE * pszBuffer, + COUNT * pCurDrive); +STATIC void FcbNameInit(fcb FAR * lpFcb, BYTE * pszBuffer, COUNT * pCurDrive); +STATIC void FcbNextRecord(fcb FAR * lpFcb); +STATIC void FcbCalcRec(xfcb FAR * lpXfcb); + +#define TestCmnSeps(lpFileName) (*lpFileName && strchr(":<|>+=,", *lpFileName) != NULL) +#define TestFieldSeps(lpFileName) ((unsigned char)*lpFileName <= ' ' || strchr("/\"[]<>|.", *lpFileName) != NULL) + +static dmatch Dmatch; + +BYTE FAR *FatGetDrvData(UBYTE drive, UBYTE * pspc, UWORD * bps, UWORD * nc) +{ + static BYTE mdb; + UWORD spc; + + /* get the data available from dpb */ + spc = DosGetFree(drive, NULL, bps, nc); + if (spc != 0xffff) + { + struct dpb FAR *dpbp = get_dpb(drive == 0 ? default_drive : drive - 1); + /* Point to the media desctriptor for this drive */ + *pspc = (UBYTE)spc; + if (dpbp == NULL) + { + mdb = spc >> 8; + spc &= 0xff; + return &mdb; + } + else + { + return (BYTE FAR *) & (dpbp->dpb_mdb); + } + } + return NULL; +} + +#define PARSE_SEP_STOP 0x01 +#define PARSE_DFLT_DRIVE 0x02 +#define PARSE_BLNK_FNAME 0x04 +#define PARSE_BLNK_FEXT 0x08 + +#define PARSE_RET_NOWILD 0 +#define PARSE_RET_WILD 1 +#define PARSE_RET_BADDRIVE 0xff + +#ifndef IPL +UWORD FcbParseFname(UBYTE *wTestMode, const BYTE FAR * lpFileName, fcb FAR * lpFcb) +{ + WORD wRetCodeName = FALSE, wRetCodeExt = FALSE; + + /* pjv -- ExtFcbToFcb? */ + if (!(*wTestMode & PARSE_SEP_STOP)) + { + lpFileName = ParseSkipWh(lpFileName); + if (TestCmnSeps(lpFileName)) + ++lpFileName; + } + + /* Undocumented "feature," we skip white space anyway */ + lpFileName = ParseSkipWh(lpFileName); + + /* Now check for drive specification */ + if (*(lpFileName + 1) == ':') + { + /* non-portable construct to be changed */ + REG UBYTE Drive = DosUpFChar(*lpFileName) - 'A'; + + if (get_cds(Drive) == NULL) + { + *wTestMode = PARSE_RET_BADDRIVE; + return FP_OFF(lpFileName); + } + + lpFcb->fcb_drive = Drive + 1; + lpFileName += 2; + } else if (!(*wTestMode & PARSE_DFLT_DRIVE)) { + lpFcb->fcb_drive = FDFLT_DRIVE; + } + + /* Undocumented behavior, set record number & record size to 0 */ + lpFcb->fcb_cublock = lpFcb->fcb_recsiz = 0; + + if (!(*wTestMode & PARSE_BLNK_FNAME)) + { + fmemset(lpFcb->fcb_fname, ' ', FNAME_SIZE); + } + if (!(*wTestMode & PARSE_BLNK_FEXT)) + { + fmemset(lpFcb->fcb_fext, ' ', FEXT_SIZE); + } + + /* special cases: '.' and '..' */ + if (*lpFileName == '.') + { + lpFcb->fcb_fname[0] = '.'; + ++lpFileName; + if (*lpFileName == '.') + { + lpFcb->fcb_fname[1] = '.'; + ++lpFileName; + } + *wTestMode = PARSE_RET_NOWILD; + return FP_OFF(lpFileName); + } + + /* Now to format the file name into the string */ + lpFileName = + GetNameField(lpFileName, (BYTE FAR *) lpFcb->fcb_fname, FNAME_SIZE, + (BOOL *) & wRetCodeName); + + /* Do we have an extension? If do, format it else return */ + if (*lpFileName == '.') + lpFileName = + GetNameField(++lpFileName, (BYTE FAR *) lpFcb->fcb_fext, + FEXT_SIZE, (BOOL *) & wRetCodeExt); + + *wTestMode = (wRetCodeName | wRetCodeExt) ? PARSE_RET_WILD : PARSE_RET_NOWILD; + return FP_OFF(lpFileName); +} + +const BYTE FAR * ParseSkipWh(const BYTE FAR * lpFileName) +{ + while (*lpFileName == ' ' || *lpFileName == '\t') + ++lpFileName; + return lpFileName; +} + +#if 0 /* defined above */ +BOOL TestCmnSeps(BYTE FAR * lpFileName) +{ + BYTE *pszTest, *pszCmnSeps = ":<|>+=,"; + + for (pszTest = pszCmnSeps; *pszTest != '\0'; ++pszTest) + if (*lpFileName == *pszTest) + return TRUE; + return FALSE; +} +#endif + +#if 0 +BOOL TestFieldSeps(BYTE FAR * lpFileName) +{ + BYTE *pszTest, *pszCmnSeps = "/\"[]<>|."; + + /* Another non-portable construct */ + if (*lpFileName <= ' ') + return TRUE; + + for (pszTest = pszCmnSeps; *pszTest != '\0'; ++pszTest) + if (*lpFileName == *pszTest) + return TRUE; + return FALSE; +} +#endif + +const BYTE FAR * GetNameField(const BYTE FAR * lpFileName, BYTE FAR * lpDestField, + COUNT nFieldSize, BOOL * pbWildCard) +{ + COUNT nIndex = 0; + BYTE cFill = ' '; + + while (*lpFileName != '\0' && !TestFieldSeps(lpFileName) + && nIndex < nFieldSize) + { + if (*lpFileName == ' ') + break; + if (*lpFileName == '*') + { + *pbWildCard = TRUE; + cFill = '?'; + ++lpFileName; + break; + } + if (*lpFileName == '?') + *pbWildCard = TRUE; + *lpDestField++ = DosUpFChar(*lpFileName++); + ++nIndex; + } + + /* Blank out remainder of field on exit */ + fmemset(lpDestField, cFill, nFieldSize - nIndex); + return lpFileName; +} + +STATIC VOID FcbNextRecord(fcb FAR * lpFcb) +{ + if (++lpFcb->fcb_curec >= 128) + { + lpFcb->fcb_curec = 0; + ++lpFcb->fcb_cublock; + } +} + +STATIC ULONG FcbRec(fcb FAR *lpFcb) +{ + return ((ULONG) lpFcb->fcb_cublock * 128) + lpFcb->fcb_curec; +} + +UBYTE FcbReadWrite(xfcb FAR * lpXfcb, UCOUNT recno, int mode) +{ + ULONG lPosit; + long nTransfer; + fcb FAR *lpFcb; + unsigned size; + unsigned long bigsize; + unsigned recsiz; + + /* Convert to fcb if necessary */ + lpFcb = ExtFcbToFcb(lpXfcb); + + recsiz = lpFcb->fcb_recsiz; + bigsize = (ULONG)recsiz * recno; + if (bigsize > 0xffff) + return FCB_ERR_SEGMENT_WRAP; + size = (unsigned)bigsize; + + if (FP_OFF(dta) + size < FP_OFF(dta)) + return FCB_ERR_SEGMENT_WRAP; + + /* Now update the fcb and compute where we need to position */ + /* to. */ + lPosit = FcbRec(lpFcb) * recsiz; + if ((CritErrCode = -SftSeek(lpFcb->fcb_sftno, lPosit, 0)) != SUCCESS) + return FCB_ERR_NODATA; + + /* Do the read */ + nTransfer = DosRWSft(lpFcb->fcb_sftno, size, dta, mode & ~XFR_FCB_RANDOM); + if (nTransfer < 0) + CritErrCode = -(int)nTransfer; + + /* Now find out how we will return and do it. */ + if (mode & XFR_WRITE) + lpFcb->fcb_fsize = SftGetFsize(lpFcb->fcb_sftno); + + /* if end-of-file, then partial read should count last record */ + if (mode & XFR_FCB_RANDOM && recsiz > 0) + lpFcb->fcb_rndm += ((unsigned)nTransfer + recsiz - 1) / recsiz; + size -= (unsigned)nTransfer; + if (size == 0) + { + FcbNextRecord(lpFcb); + return FCB_SUCCESS; + } + size %= lpFcb->fcb_recsiz; + if (mode & XFR_READ && size > 0) + { + fmemset((char FAR *)dta + (unsigned)nTransfer, 0, size); + FcbNextRecord(lpFcb); + return FCB_ERR_EOF; + } + return FCB_ERR_NODATA; +} + +UBYTE FcbGetFileSize(xfcb FAR * lpXfcb) +{ + int FcbDrive, sft_idx; + unsigned recsiz; + + /* Build a traditional DOS file name */ + fcb FAR *lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); + recsiz = lpFcb->fcb_recsiz; + + /* check for a device */ + if (!lpFcb || IsDevice(SecPathName) || (recsiz == 0)) + return FCB_ERROR; + + sft_idx = (short)DosOpenSft(SecPathName, O_LEGACY | O_RDONLY | O_OPEN, 0); + if (sft_idx >= 0) + { + ULONG fsize; + + /* Get the size */ + fsize = SftGetFsize(sft_idx); + + /* compute the size and update the fcb */ + lpFcb->fcb_rndm = (fsize + (recsiz - 1)) / recsiz; + + /* close the file and leave */ + if ((CritErrCode = -DosCloseSft(sft_idx, FALSE)) == SUCCESS) + return FCB_SUCCESS; + } + else + CritErrCode = -sft_idx; + return FCB_ERROR; +} + +void FcbSetRandom(xfcb FAR * lpXfcb) +{ + /* Convert to fcb if necessary */ + fcb FAR *lpFcb = ExtFcbToFcb(lpXfcb); + + /* Now update the fcb and compute where we need to position */ + /* to. */ + lpFcb->fcb_rndm = FcbRec(lpFcb); +} + +void FcbCalcRec(xfcb FAR * lpXfcb) +{ + + /* Convert to fcb if necessary */ + fcb FAR *lpFcb = ExtFcbToFcb(lpXfcb); + + /* Now update the fcb and compute where we need to position */ + /* to. */ + lpFcb->fcb_cublock = (UWORD)(lpFcb->fcb_rndm / 128); + lpFcb->fcb_curec = (UBYTE)lpFcb->fcb_rndm & 127; +} + +UBYTE FcbRandomBlockIO(xfcb FAR * lpXfcb, UWORD *nRecords, int mode) +{ + UBYTE nErrorCode; + fcb FAR *lpFcb; + unsigned long old; + + FcbCalcRec(lpXfcb); + + /* Convert to fcb if necessary */ + lpFcb = ExtFcbToFcb(lpXfcb); + + old = lpFcb->fcb_rndm; + nErrorCode = FcbReadWrite(lpXfcb, *nRecords, mode); + *nRecords = (UWORD)(lpFcb->fcb_rndm - old); + + /* Now update the fcb */ + FcbCalcRec(lpXfcb); + + return nErrorCode; +} + +UBYTE FcbRandomIO(xfcb FAR * lpXfcb, int mode) +{ + UWORD uwCurrentBlock; + UBYTE ucCurrentRecord; + UBYTE nErrorCode; + fcb FAR *lpFcb; + + FcbCalcRec(lpXfcb); + + /* Convert to fcb if necessary */ + lpFcb = ExtFcbToFcb(lpXfcb); + + uwCurrentBlock = lpFcb->fcb_cublock; + ucCurrentRecord = lpFcb->fcb_curec; + + nErrorCode = FcbReadWrite(lpXfcb, 1, mode); + + lpFcb->fcb_cublock = uwCurrentBlock; + lpFcb->fcb_curec = ucCurrentRecord; + return nErrorCode; +} + +/* FcbOpen and FcbCreate + Expects lpXfcb to point to a valid, unopened FCB, containing file name to open (create) + Create will attempt to find the file name in the current directory, if found truncates + setting file size to 0, otherwise if does not exist will create the new file; the + FCB is filled in same as the open call. + On any error returns FCB_ERROR + On success returns FCB_SUCCESS, and sets the following fields (other non-system reserved ones left unchanged) + drive identifier (fcb_drive) set to actual drive (1=A, 2=B, ...; always >0 if not device) + current block number (fcb_cublock) to 0 + file size (fcb_fsize) value from directory entry (0 if create) + record size (fcb_recsiz) to 128; set to 0 for devices + time & date (fcb_time & fcb_date) values from directory entry + fcb_sftno, fcb_attrib_hi/_lo, fcb_strtclst, fcb_dirclst/off_unused are for internal use (system reserved) +*/ +UBYTE FcbOpen(xfcb FAR * lpXfcb, unsigned flags) +{ + sft FAR *sftp; + COUNT sft_idx, FcbDrive; + unsigned attr = 0; + + /* Build a traditional DOS file name */ + fcb FAR *lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); + if ((flags & O_CREAT) && lpXfcb->xfcb_flag == 0xff) + /* pass attribute without constraints (dangerous for directories) */ + attr = lpXfcb->xfcb_attrib; + + sft_idx = (short)DosOpenSft(SecPathName, flags, attr); + if (sft_idx < 0) + { + CritErrCode = -sft_idx; + return FCB_ERROR; + } + + sftp = idx_to_sft(sft_idx); + sftp->sft_mode |= O_FCB; + + lpFcb->fcb_sftno = sft_idx; + lpFcb->fcb_cublock = 0; + /* should not be cleared, programs e.g. GEM depend on these values remaining unchanged + lpFcb->fcb_curec = 0; + lpFcb->fcb_rndm = 0; + */ + + lpFcb->fcb_recsiz = 0; /* true for devices */ + if (!(sftp->sft_flags & SFT_FDEVICE)) /* check for a device */ + { + lpFcb->fcb_drive = FcbDrive; + lpFcb->fcb_recsiz = 128; + } + lpFcb->fcb_fsize = sftp->sft_size; + lpFcb->fcb_date = sftp->sft_date; + lpFcb->fcb_time = sftp->sft_time; + return FCB_SUCCESS; +} + + +STATIC fcb FAR *ExtFcbToFcb(xfcb FAR * lpExtFcb) +{ + if (*((UBYTE FAR *) lpExtFcb) == 0xff) + sda_lpFcb = &lpExtFcb->xfcb_fcb; + else + sda_lpFcb = (fcb FAR *) lpExtFcb; + return sda_lpFcb; +} + +STATIC fcb FAR *CommonFcbInit(xfcb FAR * lpExtFcb, BYTE * pszBuffer, + COUNT * pCurDrive) +{ + fcb FAR *lpFcb; + + /* convert to fcb if needed first */ + sda_lpFcb = lpFcb = ExtFcbToFcb(lpExtFcb); + + /* Build a traditional DOS file name */ + FcbNameInit(lpFcb, pszBuffer, pCurDrive); + /* and return the fcb pointer */ + return lpFcb; +} + +STATIC void FcbNameInit(fcb FAR * lpFcb, BYTE * szBuffer, COUNT * pCurDrive) +{ + BYTE *pszBuffer = szBuffer; + + /* Build a traditional DOS file name */ + *pCurDrive = default_drive + 1; + if (lpFcb->fcb_drive != 0) + { + *pCurDrive = lpFcb->fcb_drive; + pszBuffer[0] = 'A' + lpFcb->fcb_drive - 1; + pszBuffer[1] = ':'; + pszBuffer += 2; + } + ConvertName83ToNameSZ(pszBuffer, lpFcb->fcb_fname); +} + +UBYTE FcbDelete(xfcb FAR * lpXfcb) +{ + COUNT FcbDrive; + UBYTE result = FCB_SUCCESS; + void FAR *lpOldDta = dta; + + /* Build a traditional DOS file name */ + CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); + /* check for a device */ + if (IsDevice(SecPathName)) + { + result = FCB_ERROR; + } + else + { + int attr = (lpXfcb->xfcb_flag == 0xff ? lpXfcb->xfcb_attrib : D_ALL); + dmatch Dmatch; + + dta = &Dmatch; + if ((CritErrCode = -DosFindFirst(attr, SecPathName)) != SUCCESS) + { + result = FCB_ERROR; + } + else do + { + SecPathName[0] = 'A' + FcbDrive - 1; + SecPathName[1] = ':'; + strcpy(&SecPathName[2], Dmatch.dm_name); + if (DosDelete(SecPathName, attr) != SUCCESS) + { + result = FCB_ERROR; + break; + } + } + while ((CritErrCode = -DosFindNext()) == SUCCESS); + } + dta = lpOldDta; + return result; +} + +UBYTE FcbRename(xfcb FAR * lpXfcb) +{ + rfcb FAR *lpRenameFcb; + COUNT FcbDrive; + UBYTE result = FCB_SUCCESS; + void FAR *lpOldDta = dta; + + /* Build a traditional DOS file name */ + lpRenameFcb = (rfcb FAR *) CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); + + /* check for a device */ + if (IsDevice(SecPathName)) + { + result = FCB_ERROR; + } + else + { + dmatch Dmatch; + COUNT result; + + wAttr = (lpXfcb->xfcb_flag == 0xff ? lpXfcb->xfcb_attrib : D_ALL); + dta = &Dmatch; + if ((CritErrCode = -DosFindFirst(wAttr, SecPathName)) != SUCCESS) + { + result = FCB_ERROR; + } + else do + { + /* 'A:' + '.' + '\0' */ + BYTE loc_szBuffer[2 + FNAME_SIZE + 1 + FEXT_SIZE + 1]; + fcb LocalFcb; + BYTE *pToName; + const BYTE FAR *pFromPattern = Dmatch.dm_name; + int i; + UBYTE mode = 0; + + FcbParseFname(&mode, pFromPattern, &LocalFcb); + /* Overlay the pattern, skipping '?' */ + /* I'm cheating because this assumes that the */ + /* struct alignments are on byte boundaries */ + pToName = LocalFcb.fcb_fname; + pFromPattern = lpRenameFcb->renNewName; + for (i = 0; i < FNAME_SIZE + FEXT_SIZE; i++) + { + if (*pFromPattern != '?') + *pToName = *pFromPattern; + pToName++; + pFromPattern++; + } + + SecPathName[0] = 'A' + FcbDrive - 1; + SecPathName[1] = ':'; + strcpy(&SecPathName[2], Dmatch.dm_name); + result = truename(SecPathName, PriPathName, 0); + + if (result < SUCCESS || (result & IS_DEVICE)) + { + result = FCB_ERROR; + break; + } + /* now to build a dos name again */ + LocalFcb.fcb_drive = FcbDrive; + FcbNameInit(&LocalFcb, loc_szBuffer, &FcbDrive); + result = truename(loc_szBuffer, SecPathName, 0); + if (result < SUCCESS || (result & (IS_NETWORK|IS_DEVICE)) == IS_DEVICE + || DosRenameTrue(PriPathName, SecPathName, wAttr) != SUCCESS) + { + result = FCB_ERROR; + break; + } + } + while ((CritErrCode = -DosFindNext()) == SUCCESS); + } + dta = lpOldDta; + return result; +} + +/* TE:the MoveDirInfo() is now done by simply copying the dirEntry into the FCB + this prevents problems with ".", ".." and saves code + BO:use global SearchDir, as produced by FindFirst/Next +*/ + +UBYTE FcbClose(xfcb FAR * lpXfcb) +{ + sft FAR *s; + + /* Convert to fcb if necessary */ + fcb FAR *lpFcb = ExtFcbToFcb(lpXfcb); + + /* An already closed FCB can be closed again without error */ + if (lpFcb->fcb_sftno == (BYTE) 0xff) + return FCB_SUCCESS; + + /* Get the SFT block that contains the SFT */ + if ((s = idx_to_sft(lpFcb->fcb_sftno)) == (sft FAR *) - 1) + return FCB_ERROR; + + /* change time and set file size */ + s->sft_size = lpFcb->fcb_fsize; + if (!(s->sft_flags & SFT_FSHARED)) + dos_merge_file_changes(lpFcb->fcb_sftno); + DosSetFtimeSft(lpFcb->fcb_sftno, lpFcb->fcb_date, lpFcb->fcb_time); + if ((CritErrCode = -DosCloseSft(lpFcb->fcb_sftno, FALSE)) == SUCCESS) + { + lpFcb->fcb_sftno = (BYTE) 0xff; + return FCB_SUCCESS; + } + return FCB_ERROR; +} + +/* close all files the current process opened by FCBs */ +VOID FcbCloseAll() +{ + COUNT idx = 0; + sft FAR *sftp; + + for (idx = 0; (sftp = idx_to_sft(idx)) != (sft FAR *) - 1; idx++) + if ((sftp->sft_mode & O_FCB) && sftp->sft_psp == cu_psp) + DosCloseSft(idx, FALSE); +} + +UBYTE FcbFindFirstNext(xfcb FAR * lpXfcb, BOOL First) +{ + void FAR *orig_dta = dta; + BYTE FAR *lpDir; + COUNT FcbDrive; + fcb FAR *lpFcb; + + /* First, move the dta to a local and change it around to match */ + /* our functions. */ + lpDir = dta; + dta = &Dmatch; + + /* Next initialze local variables by moving them from the fcb */ + lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); + /* Reconstrct the dirmatch structure from the fcb - doesn't hurt for first */ + Dmatch.dm_drive = lpFcb->fcb_sftno; + + fmemcpy(Dmatch.dm_name_pat, lpFcb->fcb_fname, FNAME_SIZE + FEXT_SIZE); + DosUpFMem((BYTE FAR *) Dmatch.dm_name_pat, FNAME_SIZE + FEXT_SIZE); + + Dmatch.dm_attr_srch = wAttr; + Dmatch.dm_entry = lpFcb->fcb_strtclst; + Dmatch.dm_dircluster = lpFcb->fcb_dirclst; + + wAttr = D_ALL; + + if ((xfcb FAR *) lpFcb != lpXfcb) + { + wAttr = lpXfcb->xfcb_attrib; + fmemcpy(lpDir, lpXfcb, 7); + lpDir += 7; + } + + CritErrCode = -(First ? DosFindFirst(wAttr, SecPathName) : DosFindNext()); + if (CritErrCode != SUCCESS) + { + dta = orig_dta; + return FCB_ERROR; + } + + *lpDir++ = FcbDrive; + fmemcpy(lpDir, &SearchDir, sizeof(struct dirent)); + + lpFcb->fcb_dirclst = (UWORD) Dmatch.dm_dircluster; + lpFcb->fcb_strtclst = Dmatch.dm_entry; + +/* + This is undocumented and seen using Pcwatch and Ramview. + The First byte is the current directory count and the second seems + to be the attribute byte. + */ + lpFcb->fcb_sftno = Dmatch.dm_drive; /* MSD seems to save this @ fcb_date. */ +#if 0 + lpFcb->fcb_cublock = Dmatch.dm_entry; + lpFcb->fcb_cublock *= 0x100; + lpFcb->fcb_cublock += wAttr; +#endif + dta = orig_dta; + return FCB_SUCCESS; +} +#endif + diff --git a/kernel/globals.h b/kernel/globals.h new file mode 100644 index 0000000..7ad6f58 --- /dev/null +++ b/kernel/globals.h @@ -0,0 +1,429 @@ +/****************************************************************/ +/* */ +/* globals.h */ +/* DOS-C */ +/* */ +/* Global data structures and declarations */ +/* */ +/* Copyright (c) 1995, 1996 */ +/* 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. */ +/****************************************************************/ + +#ifdef VERSION_STRINGS +#ifdef MAIN +static BYTE *Globals_hRcsId = + "$Id: globals.h 1705 2012-02-07 08:10:33Z perditionc $"; +#endif +#endif + +#include "device.h" +#include "mcb.h" +#include "pcb.h" +#include "date.h" +#include "time.h" +#include "fat.h" +#include "fcb.h" +#include "tail.h" +#include "process.h" +#include "sft.h" +#include "cds.h" +#include "exe.h" +#include "dirmatch.h" +#include "fnode.h" +#include "file.h" +#include "clock.h" +#include "kbd.h" +#include "error.h" +#include "version.h" +#include "network.h" +#include "buffer.h" +#include "dcb.h" +#include "xstructs.h" + +/* fatfs.c */ +#ifdef WITHFAT32 +VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp, BOOL extended); +#else +VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp); +#endif + +#ifdef WITHFAT32 +struct dpb FAR *GetDriveDPB(UBYTE drive, COUNT * rc); +#endif + +extern struct dpb +FAR * ASM DPBp; /* First drive Parameter Block */ + + +/* JPP: for testing/debuging disk IO */ +/*#define DISPLAY_GETBLOCK */ + +/* */ +/* Convience switch for maintaining variables in a single location */ +/* */ +#ifdef MAIN +#define GLOBAL +#else +#define GLOBAL extern +#endif + +/* */ +/* Convience definitions of TRUE and FALSE */ +/* */ +#ifndef TRUE +#define TRUE (1) +#endif +#ifndef FALSE +#define FALSE (0) +#endif + +/* */ +/* Constants and macros */ +/* */ +/* Defaults and limits - System wide */ +#define NAMEMAX MAX_CDSPATH /* Maximum path for CDS */ + +/* internal error from failure or aborted operation */ +#define ERROR -1 +#define OK 0 + +/* internal transfer direction flags */ +#define XFR_READ 1 +#define XFR_WRITE 2 +#define XFR_FORCE_WRITE 3 +/* flag to update fcb_rndm field */ +#define XFR_FCB_RANDOM 4 + +#define RDONLY 0 +#define WRONLY 1 +#define RDWR 2 + +/* special ascii code equates */ +#define SPCL 0x00 +#define CTL_C 0x03 +#define CTL_F 0x06 +#define BELL 0x07 +#define BS 0x08 +#define HT 0x09 +#define LF 0x0a +#define CR 0x0d +#define CTL_P 0x10 +#define CTL_Q 0x11 +#define CTL_S 0x13 +#define CTL_Z 0x1a +#define ESC 0x1b +#define CTL_BS 0x7f + +#define INS 0x5200 +#define DEL 0x5300 + +#define F1 0x3b00 +#define F2 0x3c00 +#define F3 0x3d00 +#define F4 0x3e00 +#define F5 0x3f00 +#define F6 0x4000 +#define LEFT 0x4b00 +#define RIGHT 0x4d00 + +/* Blockio constants */ +#define DSKWRITE 1 /* dskxfr function parameters */ +#define DSKREAD 2 +#define DSKWRITEINT26 3 +#define DSKREADINT25 4 + +/* NLS character table type */ +typedef BYTE *UPMAP; + +/* */ +/* External Assembly variables */ +/* */ +extern struct dhdr +FAR ASM clk_dev, /* Clock device driver */ + FAR ASM con_dev, /* Console device driver */ + FAR ASM prn_dev, /* Generic printer device driver */ + FAR ASM aux_dev, /* Generic aux device driver */ + FAR ASM blk_dev; /* Block device (Disk) driver */ +extern COUNT *error_tos, /* error stack */ + disk_api_tos, /* API handler stack - disk fns */ + char_api_tos; /* API handler stack - char fns */ +extern BYTE FAR _HMATextAvailable, /* first byte of available CODE area */ + FAR _HMATextStart[], /* first byte of HMAable CODE area */ + FAR _HMATextEnd[]; /* and the last byte of it */ +extern +BYTE DosLoadedInHMA; /* if InitHMA has moved DOS up */ + +extern struct ClockRecord + ASM ClkRecord; + +/* */ +/* Global variables */ +/* */ +extern BYTE ASM os_setver_major,/* editable major version number */ + ASM os_setver_minor, /* editable minor version number */ + ASM os_major, /* major version number */ + ASM os_minor, /* minor version number */ + ASM rev_number, /* minor version number */ + ASM version_flags; /* minor version number */ + +#ifdef DEBUG +GLOBAL WORD bDumpRegs +#ifdef MAIN + = FALSE; +#else + ; +#endif +GLOBAL WORD bDumpRdWrParms +#ifdef MAIN + = FALSE; +#else + ; +#endif +#endif + +#if 0 /* defined in MAIN.C now to save low memory */ + +GLOBAL BYTE copyright[] = + "(C) Copyright 1995-2006 Pasquale J. Villani and The FreeDOS Project.\n" + "All Rights Reserved. This is free software and comes with ABSOLUTELY NO\n" + "WARRANTY; you can redistribute it and/or modify it under the terms of the\n" + "GNU General Public License as published by the Free Software Foundation;\n" + "either version 2, or (at your option) any later version.\n"; + +#endif + +GLOBAL const BYTE ASM os_release[] +#ifdef MAIN + = KERNEL_VERSION_STRING +#if 0 + "For technical information and description of the DOS-C operating system\n\ +consult \"FreeDOS Kernel\" by Pat Villani, published by Miller\n\ +Freeman Publishing, Lawrence KS, USA (ISBN 0-87930-436-7).\n\ +\n" +#endif +#endif + ; + +/* Globally referenced variables - WARNING: ORDER IS DEFINED IN */ +/* KERNEL.ASM AND MUST NOT BE CHANGED. DO NOT CHANGE ORDER BECAUSE THEY */ +/* ARE DOCUMENTED AS UNDOCUMENTED (?) AND HAVE MANY PROGRAMS AND TSRs */ +/* ACCESSING THEM */ + +extern UWORD ASM NetBios; +extern BYTE * ASM net_name; +extern BYTE ASM net_set_count; +extern BYTE ASM NetDelay, ASM NetRetry; + +extern UWORD ASM first_mcb, /* Start of user memory */ + ASM uppermem_root; /* Start of umb chain (usually 9fff) */ +extern char * ASM inputptr; /* pointer to unread CON input */ +extern sfttbl FAR * ASM sfthead; /* System File Table head */ +extern struct dhdr +FAR * ASM clock, /* CLOCK$ device */ + FAR * ASM syscon; /* console device */ +extern WORD ASM maxsecsize; /* largest sector size in use (can use) */ +extern struct buffer +FAR *ASM firstbuf; /* head of buffers linked list */ +enum {LOC_CONV=0, LOC_HMA=1}; +extern unsigned char ASM bufloc; /* 0=conv, 1=HMA */ +extern void far * ASM deblock_buf; /* pointer to workspace buffer */ +GLOBAL char FAR *firstAvailableBuf; +extern struct cds FAR * ASM CDSp; /* Current Directory Structure */ +extern +struct cds FAR * ASM current_ldt; +extern LONG ASM current_filepos; /* current file position */ +extern sfttbl FAR * ASM FCBp; /* FCB table pointer */ +extern WORD ASM nprotfcb; /* number of protected fcbs */ +extern UBYTE ASM nblkdev, /* number of block devices */ + ASM lastdrive, /* value of last drive */ + ASM uppermem_link, /* UMB Link flag */ + ASM PrinterEcho; /* Printer Echo Flag */ + +extern UWORD ASM LoL_nbuffers; /* Number of buffers */ + +extern struct dhdr + ASM nul_dev; +extern UBYTE ASM mem_access_mode; /* memory allocation scheme */ +extern BYTE ASM ErrorMode, /* Critical error flag */ + ASM InDOS, /* In DOS critical section */ + ASM OpenMode, /* File Open Attributes */ + ASM SAttr, /* Attrib Mask for Dir Search */ + ASM dosidle_flag, ASM Server_Call, ASM CritErrLocus, ASM CritErrAction, + ASM CritErrClass, ASM VgaSet, + ASM njoined; /* number of joined devices */ + +extern UWORD ASM Int21AX; +extern COUNT ASM CritErrCode; +extern BYTE FAR * ASM CritErrDev; + +extern struct dirent + ASM SearchDir; + +extern struct { + COUNT nDrive; + BYTE szName[FNAME_SIZE + 1]; + BYTE szExt[FEXT_SIZE + 1]; +} ASM FcbSearchBuffer; + +extern struct /* Path name parsing buffer */ +{ + BYTE _PriPathName[128]; +} ASM _PriPathBuffer; + +#define PriPathName _PriPathBuffer._PriPathName + +extern struct /* Alternate path name parsing buffer */ +{ + BYTE _SecPathName[128]; +} ASM _SecPathBuffer; + +#define SecPathName _SecPathBuffer._SecPathName + +extern UWORD ASM wAttr; + +extern BYTE ASM default_drive; /* default drive for dos */ + +extern dmatch ASM sda_tmp_dm; /* Temporary directory match buffer */ +extern dmatch ASM sda_tmp_dm_ren; /* 2nd Temporary directory match buffer */ +extern BYTE + ASM internal_data[], /* sda areas */ + ASM swap_always[], /* " " */ + ASM swap_indos[], /* " " */ + ASM tsr, /* true if program is TSR */ + ASM break_flg, /* true if break was detected */ + ASM break_ena; /* break enabled flag */ +extern void FAR * ASM dta; /* Disk transfer area (kludge) */ +extern seg ASM cu_psp; /* current psp segment */ +extern iregs FAR * ASM user_r; /* User registers for int 21h call */ + +extern struct dirent /* Temporary directory entry */ + ASM DirEntBuffer; + +extern fcb FAR * ASM sda_lpFcb; /* Pointer to users fcb */ + +extern sft FAR * ASM lpCurSft; + +extern BYTE ASM verify_ena, /* verify enabled flag */ + ASM switchar; /* switch char */ +extern UWORD ASM return_code; /* Process termination rets */ + +extern UBYTE ASM BootDrive, /* Drive we came up from */ + ASM CPULevel, /* CPU family, 0=8086, 1=186, ... */ + ASM scr_pos; /* screen position for bs, ht, etc */ +/*extern WORD + NumFloppies; !!*//* How many floppies we have */ + +extern keyboard ASM kb_buf; +extern char ASM local_buffer[LINEBUFSIZE0A]; +extern UBYTE DiskTransferBuffer[/*SEC_SIZE*/]; + +extern struct cds + ASM TempCDS; + +/* start of uncontrolled variables */ + +#ifdef DEBUG +GLOBAL iregs error_regs; /* registers for dump */ + +GLOBAL WORD dump_regs; /* dump registers of bad call */ + +#endif + +/* */ +/* Function prototypes - automatically generated */ +/* */ +#include "proto.h" + +/* Process related functions - not under automatic generation. */ +/* Typically, these are in ".asm" files. */ +VOID ASMCFUNC FAR cpm_entry(VOID) +/*INRPT FAR handle_break(VOID) */ ; +COUNT ASMCFUNC + CriticalError(COUNT nFlag, COUNT nDrive, COUNT nError, + struct dhdr FAR * lpDevice); + +VOID ASMCFUNC FAR CharMapSrvc(VOID); +#if 0 +VOID ASMCFUNC FAR set_stack(VOID); +VOID ASMCFUNC FAR restore_stack(VOID); +#endif +/*VOID INRPT FAR handle_break(VOID); */ + +ULONG ASMPASCAL ReadPCClock(VOID); +VOID ASMPASCAL WriteATClock(BYTE *, BYTE, BYTE, BYTE); +VOID ASMPASCAL WritePCClock(ULONG); +intvec getvec(unsigned char); +#ifdef __WATCOMC__ +#pragma aux (pascal) ReadPCClock modify exact [ax cx dx] +#pragma aux (pascal) WriteATClock modify exact [ax bx cx dx] +#pragma aux (pascal) WritePCClock modify exact [ax cx dx] +#endif + +/* */ +/* special word packing prototypes */ +/* */ +#ifdef NATIVE +#define getlong(vp) (*(UDWORD *)(vp)) +#define getword(vp) (*(UWORD *)(vp)) +#define getbyte(vp) (*(UBYTE *)(vp)) +#define fgetlong(vp) (*(UDWORD FAR *)(vp)) +#define fgetword(vp) (*(UWORD FAR *)(vp)) +#define fgetbyte(vp) (*(UBYTE FAR *)(vp)) +#define fputlong(vp, l) (*(UDWORD FAR *)(vp)=l) +#define fputword(vp, w) (*(UWORD FAR *)(vp)=w) +#define fputbyte(vp, b) (*(UBYTE FAR *)(vp)=b) +#else +UDWORD getlong(VOID *); +UWORD getword(VOID *); +UBYTE getbyte(VOID *); +UDWORD fgetlong(VOID FAR *); +UWORD fgetword(VOID FAR *); +UBYTE fgetbyte(VOID FAR *); +VOID fputlong(VOID FAR *, UDWORD); +VOID fputword(VOID FAR *, UWORD); +VOID fputbyte(VOID FAR *, UBYTE); +#endif + +#ifndef __WATCOMC__ +#define setvec setvec_resident +#endif +void setvec(unsigned char intno, intvec vector); +/*#define is_leap_year(y) ((y) & 3 ? 0 : (y) % 100 ? 1 : (y) % 400 ? 0 : 1) */ + +/* ^Break handling */ +#ifdef __WATCOMC__ +#pragma aux (cdecl) spawn_int23 aborts; +#endif +void ASMCFUNC spawn_int23(void); /* procsupt.asm */ +void ASMCFUNC DosIdle_hlt(void); /* dosidle.asm */ + +GLOBAL BYTE ReturnAnyDosVersionExpected; +GLOBAL BYTE ASM HaltCpuWhileIdle; + +/* near fnodes: + * fnode[0] is used internally for almost all cases. + * fnode[1] is only used for: + * 1) rename (target) + * 2) rmdir (checks if the directory to remove is empty) + * 3) commit (copies, than closes fnode[0]) + * 3) merge_file_changes (for SHARE) + */ +GLOBAL struct f_node fnode[2]; diff --git a/kernel/init-dat.h b/kernel/init-dat.h new file mode 100644 index 0000000..cda5e05 --- /dev/null +++ b/kernel/init-dat.h @@ -0,0 +1,32 @@ +/* Included by initialisation functions */ + +#if _MSC_VER != 0 +extern __segment DosDataSeg; /* serves for all references to the DOS DATA segment + necessary for MSC+our funny linking model + */ + +extern __segment DosTextSeg; + +#define DOSFAR __based(DosDataSeg) +#define DOSTEXTFAR __based(DosTextSeg) + +#elif defined(__TURBOC__) + +#define DOSFAR FAR +#define DOSTEXTFAR FAR + +#elif defined(__WATCOMC__) + +#define DOSFAR FAR +#define DOSTEXTFAR FAR + +#elif !defined(I86) + +#define DOSFAR +#define DOSTEXTFAR + +#else + +#error unknown compiler - please adjust +We might even deal with a pre-ANSI compiler. This will certainly not compile. +#endif diff --git a/kernel/init-mod.h b/kernel/init-mod.h new file mode 100644 index 0000000..e39d84d --- /dev/null +++ b/kernel/init-mod.h @@ -0,0 +1,336 @@ +/* Included by initialisation functions */ +#define IN_INIT_MOD + +#include "version.h" +#include "date.h" +#include "time.h" +#include "mcb.h" +#include "sft.h" +#include "fat.h" +#include "file.h" +#include "cds.h" +#include "device.h" +#include "kbd.h" +#include "error.h" +#include "fcb.h" +#include "tail.h" +#include "process.h" +#include "pcb.h" +#include "nls.h" +#include "buffer.h" +#include "dcb.h" +#include "lol.h" + +#include "init-dat.h" + +#include "kconfig.h" + +/* MSC places uninitialized data into COMDEF records, + that end up in DATA segment. this can't be tolerated in INIT code. + please make sure, that ALL data in INIT is initialized !! + + These guys are marked BSS_INIT to mark that they really should be BSS + but can't be because of MS +*/ +#ifdef _MSC_VER +#define BSS_INIT(x) = x +#else +#define BSS_INIT(x) +#endif + +extern struct _KernelConfig InitKernelConfig; + +/* + * Functions in `INIT_TEXT' may need to call functions in `_TEXT'. The entry + * calls for the latter functions therefore need to be wrapped up with far + * entry points. + */ +#define printf init_printf +#define sprintf init_sprintf +#ifndef __WATCOMC__ +#define execrh init_execrh +#define memcpy init_memcpy +#define fmemcpy init_fmemcpy +#define fmemset init_fmemset +#define fmemcmp init_fmemcmp +#define memcmp init_memcmp +#define memset init_memset +#define strchr init_strchr +#define strcpy init_strcpy +#define strlen init_strlen +#define fstrlen init_fstrlen +#endif +#define open init_DosOpen + +/* execrh.asm */ +#ifndef __WATCOMC__ +WORD ASMPASCAL execrh(request FAR *, struct dhdr FAR *); +#endif + +/* asmsupt.asm */ +VOID ASMPASCAL memset( void *s, int ch, size_t n); +VOID ASMPASCAL fmemset( void FAR *s, int ch, size_t n); +int ASMPASCAL memcmp(const void *m1, const void *m2, size_t n); +int ASMPASCAL fmemcmp(const void FAR *m1, const void FAR *m2, size_t n); +VOID ASMPASCAL memcpy( void *d, const void *s, size_t n); +VOID ASMPASCAL fmemcpy( void FAR *d, const void FAR *s, size_t n); +VOID ASMPASCAL strcpy(char *d, const char *s); +size_t ASMPASCAL strlen(const char *s); +size_t ASMPASCAL fstrlen(const char FAR *s); +char * ASMPASCAL strchr(const char *s, int ch); + +#ifdef __WATCOMC__ +/* bx, cx, dx and es not used or clobbered for all asmsupt.asm functions except + (f)memchr/(f)strchr (which clobber dx) */ +#pragma aux (pascal) pascal_ax modify exact [ax] +#pragma aux (pascal_ax) memset +#pragma aux (pascal_ax) fmemset +#pragma aux (pascal_ax) memcpy +#pragma aux (pascal_ax) fmemcpy +#pragma aux (pascal_ax) memcmp modify nomemory +#pragma aux (pascal_ax) fmemcmp modify nomemory +#pragma aux (pascal_ax) strcpy +#pragma aux (pascal_ax) strlen modify nomemory +#pragma aux (pascal_ax) fstrlen modify nomemory +#pragma aux (pascal) strchr modify exact [ax dx] nomemory +#endif + +#undef LINESIZE +#define LINESIZE KBD_MAXLENGTH + +/*inithma.c*/ +extern BYTE DosLoadedInHMA; +void MoveKernel(unsigned NewKernelSegment); + +void setvec(unsigned char intno, intvec vector); +#ifndef __WATCOMC__ +#define getvec init_getvec +#endif +intvec getvec(unsigned char intno); + +#define GLOBAL extern +#define NAMEMAX MAX_CDSPATH /* Maximum path for CDS */ +#define NFILES 16 /* number of files in table */ +#define NFCBS 16 /* number of fcbs */ +#define NSTACKS 8 /* number of stacks */ +#define STACKSIZE 256 /* default stacksize */ +#define NLAST 5 /* last drive */ +#define NUMBUFF 20 /* Number of track buffers at INIT time */ + /* -- must be at least 3 */ +#define MAX_HARD_DRIVE 8 +#define NDEV 26 /* up to Z: */ + +#include "config.h" /* config structure */ + +/* config.c */ +extern struct config Config; +VOID PreConfig(VOID); +VOID PreConfig2(VOID); +VOID DoConfig(int pass); +VOID PostConfig(VOID); +VOID configDone(VOID); +VOID FAR * KernelAlloc(size_t nBytes, char type, int mode); +void FAR * KernelAllocPara(size_t nPara, char type, char *name, int mode); +char *strcat(char * d, const char * s); +BYTE * GetStringArg(BYTE * pLine, BYTE * pszString); +void DoInstall(void); +UWORD GetBiosKey(int timeout); + +/* diskinit.c */ +COUNT dsk_init(VOID); + +/* int2f.asm */ +COUNT ASMPASCAL Umb_Test(void); +COUNT ASMPASCAL UMB_get_largest(void FAR * driverAddress, + UCOUNT * seg, UCOUNT * size); +#ifdef __WATCOMC__ +#pragma aux (pascal) UMB_get_largest modify exact [ax bx cx dx] +#endif + +/* inithma.c */ +int MoveKernelToHMA(void); +VOID FAR * HMAalloc(COUNT bytesToAllocate); + +/* initoem.c */ +unsigned init_oem(void); +void movebda(size_t bytes, unsigned new_seg); +unsigned ebdasize(void); + +/* dosidle.asm */ +extern void ASM DosIdle_hlt(VOID); + +/* intr.asm */ + +/* + * Invoke interrupt "nr" with all registers from *rp loaded + * into the processor registers (except: SS, SP,& flags) + * On return, all processor registers are stored into *rp (including + * flags). + */ +unsigned ASMPASCAL init_call_intr(int nr, iregs * rp); + +unsigned ASMPASCAL read(int fd, void *buf, unsigned count); +int ASMPASCAL open(const char *pathname, int flags); +int ASMPASCAL close(int fd); +int ASMPASCAL dup2(int oldfd, int newfd); +ULONG ASMPASCAL lseek(int fd, long position); +seg ASMPASCAL allocmem(UWORD size); +void ASMPASCAL init_PSPSet(seg psp_seg); +int ASMPASCAL init_DosExec(int mode, exec_blk * ep, char * lp); +int ASMPASCAL init_setdrive(int drive); +int ASMPASCAL init_switchar(int chr); +void ASMPASCAL keycheck(void); +void ASMPASCAL set_DTA(void far *dta); +#ifdef __WATCOMC__ +#pragma aux (pascal) init_call_intr modify exact [ax] +#pragma aux (pascal) read modify exact [ax bx cx dx] +#pragma aux (pascal) init_DosOpen modify exact [ax bx dx] +#pragma aux (pascal) close modify exact [ax bx] +#pragma aux (pascal) dup2 modify exact [ax bx cx] +#pragma aux (pascal) allocmem modify exact [ax bx] +#pragma aux (pascal) init_PSPSet modify exact [ax bx] +#pragma aux (pascal) init_DosExec modify exact [ax bx dx es] +#pragma aux (pascal) init_setdrive modify exact [ax bx dx] +#pragma aux (pascal) init_switchar modify exact [ax bx dx] +#pragma aux (pascal) keycheck modify exact [ax] +#pragma aux (pascal) set_DTA modify exact [ax bx dx] +#endif + +/* irqstack.asm */ +VOID ASMCFUNC init_stacks(VOID FAR * stack_base, COUNT nStacks, + WORD stackSize); + +/* inthndlr.c */ +VOID ASMCFUNC FAR int21_entry(iregs UserRegs); +VOID ASMCFUNC int21_service(iregs far * r); +VOID ASMCFUNC FAR int0_handler(void); +VOID ASMCFUNC FAR int6_handler(void); +VOID ASMCFUNC FAR int19_handler(void); +VOID ASMCFUNC FAR empty_handler(void); +VOID ASMCFUNC FAR int20_handler(void); +VOID ASMCFUNC FAR int21_handler(void); +VOID ASMCFUNC FAR int22_handler(void); +VOID ASMCFUNC FAR int24_handler(void); +VOID ASMCFUNC FAR low_int25_handler(void); +VOID ASMCFUNC FAR low_int26_handler(void); +VOID ASMCFUNC FAR int27_handler(void); +VOID ASMCFUNC FAR int28_handler(void); +VOID ASMCFUNC FAR int29_handler(void); +VOID ASMCFUNC FAR int2a_handler(void); +VOID ASMCFUNC FAR int2f_handler(void); +VOID ASMCFUNC FAR cpm_entry(void); + +/* kernel.asm */ +VOID ASMCFUNC FAR init_call_p_0(struct config FAR *Config); /* P_0, actually */ + +/* main.c */ +VOID ASMCFUNC FreeDOSmain(void); +BOOL init_device(struct dhdr FAR * dhp, char * cmdLine, + COUNT mode, char FAR **top); +VOID init_fatal(BYTE * err_msg); + +/* prf.c */ +int VA_CDECL init_printf(CONST char * fmt, ...); +int VA_CDECL init_sprintf(char * buff, CONST char * fmt, ...); + +/* procsupt.asm */ +VOID ASMCFUNC FAR got_cbreak(void); + +/* initclk.c */ +extern void Init_clk_driver(void); + +extern UWORD HMAFree; /* first byte in HMA not yet used */ + +extern unsigned CurrentKernelSegment; +extern struct _KernelConfig FAR ASM LowKernelConfig; +extern WORD days[2][13]; +extern BYTE FAR *lpTop; +extern BYTE ASM _ib_start[], ASM _ib_end[], ASM _init_end[]; +extern UWORD ram_top; /* How much ram in Kbytes */ +extern char singleStep; +extern char SkipAllConfig; +extern char master_env[128]; + +extern struct lol FAR *LoL; + +extern struct dhdr DOSTEXTFAR ASM blk_dev; /* Block device (Disk) driver */ + +extern struct buffer FAR *DOSFAR firstAvailableBuf; /* first 'available' buffer */ +extern struct lol ASM FAR DATASTART; + +extern BYTE DOSFAR ASM _HMATextAvailable, /* first byte of available CODE area */ + FAR ASM _HMATextStart[], /* first byte of HMAable CODE area */ + FAR ASM _HMATextEnd[], DOSFAR ASM break_ena; /* break enabled flag */ +extern BYTE DOSFAR ASM _InitTextStart[], /* first available byte of ram */ + DOSFAR ASM _InitTextEnd[], + DOSFAR ReturnAnyDosVersionExpected, + DOSFAR ASM HaltCpuWhileIdle; + +extern BYTE FAR ASM internal_data[]; +extern unsigned char FAR ASM kbdType; + +extern struct { + char ThisIsAConstantOne; + short TableSize; + + struct CountrySpecificInfo C; + +} FAR ASM nlsCountryInfoHardcoded; + +/* + data shared between DSK.C and INITDISK.C +*/ + +extern UWORD DOSFAR LBA_WRITE_VERIFY; + +/* original interrupt vectors, at 70:xxxx */ +extern struct lowvec { + unsigned char intno; + intvec isv; +} DOSTEXTFAR ASM intvec_table[5]; + +/* floppy parameter table, at 70:xxxx */ +extern unsigned char DOSTEXTFAR ASM int1e_table[0xe]; + +extern char DOSFAR DiskTransferBuffer[/*MAX_SEC_SIZE*/]; /* in dsk.c */ + +struct RelocationTable { + UBYTE jmpFar; + UWORD jmpOffset; + UWORD jmpSegment; + UBYTE callNear; + UWORD callOffset; +}; + +struct RelocatedEntry { + UBYTE callNear; + UWORD callOffset; + UBYTE jmpFar; + UWORD jmpOffset; + UWORD jmpSegment; +}; + +extern struct RelocationTable + DOSFAR ASM _HMARelocationTableStart[], + DOSFAR ASM _HMARelocationTableEnd[]; + +extern void FAR *DOSFAR ASM XMSDriverAddress; +extern VOID ASMPASCAL FAR _EnableA20(VOID); +extern VOID ASMPASCAL FAR _DisableA20(VOID); + +extern void FAR * ASMPASCAL DetectXMSDriver(VOID); +extern int ASMPASCAL init_call_XMScall(void FAR * driverAddress, UWORD ax, + UWORD dx); +#ifdef __WATCOMC__ +#pragma aux (pascal) DetectXMSDriver modify exact [ax dx] +#pragma aux (pascal) _EnableA20 modify exact [ax] +#pragma aux (pascal) _DisableA20 modify exact [ax] +#endif + +#if defined(WATCOM) && 0 +ULONG ASMCFUNC FAR MULULUS(ULONG mul1, UWORD mul2); /* MULtiply ULong by UShort */ +ULONG ASMCFUNC FAR MULULUL(ULONG mul1, ULONG mul2); /* MULtiply ULong by ULong */ +ULONG ASMCFUNC FAR DIVULUS(ULONG mul1, UWORD mul2); /* DIVide ULong by UShort */ +ULONG ASMCFUNC FAR DIVMODULUS(ULONG mul1, UWORD mul2, UWORD * rem); /* DIVide ULong by UShort */ +#endif + diff --git a/kernel/initclk.c b/kernel/initclk.c new file mode 100644 index 0000000..8dce072 --- /dev/null +++ b/kernel/initclk.c @@ -0,0 +1,74 @@ +/****************************************************************/ +/* */ +/* initclk.c */ +/* */ +/* System Clock Driver - initialization */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "init-mod.h" + +#ifdef VERSION_STRINGS +static char *RcsId = + "$Id: initclk.c 1359 2008-03-09 16:11:10Z mceric $"; +#endif + +/* */ +/* WARNING - THIS DRIVER IS NON-PORTABLE!!!! */ +/* */ + +STATIC int InitBcdToByte(int x) +{ + return ((x >> 4) & 0xf) * 10 + (x & 0xf); +} + +void Init_clk_driver(void) +{ + static iregs regsT = {0x200}; /* ah=0x02 */ + static iregs regsD = {0x400, 0, 0x1400, 0x101}; + /* ah=4, ch=20^ ^cl=0, ^dh=dl=1 (2000/1/1) + * (above date will be set on error) */ + iregs dosregs; + + init_call_intr(0x1a, ®sT); /* get BIOS time */ + init_call_intr(0x1a, ®sD); /* get BIOS date */ + + /* DosSetDate */ + dosregs.a.b.h = 0x2b; + dosregs.c.x = 100 * InitBcdToByte(regsD.c.b.h) /* century */ + + InitBcdToByte(regsD.c.b.l);/* year */ + /* A BIOS with y2k (year 2000) bug will always report year 19nn */ + if ((dosregs.c.x >= 1900) && (dosregs.c.x < 1980)) dosregs.c.x += 100; + dosregs.d.b.h = InitBcdToByte(regsD.d.b.h); /* month */ + dosregs.d.b.l = InitBcdToByte(regsD.d.b.l); /* day */ + init_call_intr(0x21, &dosregs); + + /* DosSetTime */ + dosregs.a.b.h = 0x2d; + dosregs.c.b.l = InitBcdToByte(regsT.c.b.l); /* minutes */ + dosregs.c.b.h = InitBcdToByte(regsT.c.b.h); /* hours */ + dosregs.d.b.h = InitBcdToByte(regsT.d.b.h); /*seconds */ + dosregs.d.b.l = 0; + init_call_intr(0x21, &dosregs); +} diff --git a/kernel/initdisk.c b/kernel/initdisk.c new file mode 100644 index 0000000..16a6929 --- /dev/null +++ b/kernel/initdisk.c @@ -0,0 +1,1401 @@ +/****************************************************************/ +/* */ +/* initDISK.c */ +/* */ +/* Copyright (c) 2001 */ +/* tom ehlert */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "debug.h" +#include "init-mod.h" +#include "dyndata.h" + +#define FLOPPY_SEC_SIZE 512u /* common sector size */ + +UBYTE InitDiskTransferBuffer[MAX_SEC_SIZE] BSS_INIT({0}); +COUNT nUnits BSS_INIT(0); + +/* + * Rev 1.0 13 May 2001 tom ehlert + * Initial revision. + * + * this module implements the disk scanning for DOS accesible partitions + * the drive letter ordering is somewhat chaotic, but like MSDOS does it. + * + * this module expects to run with CS = INIT_TEXT, like other init_code, + * but SS = DS = DATA = DOS_DS, unlike other init_code. + * + * history: + * 1.0 extracted the disk init code from DSK.C + * added LBA support + * moved code to INIT_TEXT + * done the funny code segment stuff to switch between INIT_TEXT and TEXT + * added a couple of snity checks for partitions + * + **************************************************************************** + * + * Implementation note: + * this module needs some interfacing to INT 13 + * how to implement them + * + * a) using inline assembly + * _ASM mov ax,0x1314 + * + * b) using assembly routines in some external FLOPPY.ASM + * + * c) using the funny TURBO-C style + * _AX = 0x1314 + * + * d) using intr(intno, ®s) method. + * + * why not? + * + * a) this is my personal favorite, combining the best aof all worlds. + * TURBO-C does support inline assembly, but only by using TASM, + * which is not free. + * so - unfortunately- its excluded. + * + * b) keeping funny memory model in sync with external assembly + * routines is everything, but not fun + * + * c) you never know EXACT, what the compiler does, if its a bit + * more complicated. does + * _DL = drive & 0xff + * _BL = driveParam.chs.Sector; + * destroy any other register? sure? _really_ sure? + * at least, it has it's surprises. + * and - I found a couple of optimizer induced bugs (TC 2.01) + * believe me. + * it was coded - and operational that way. + * but - there are many surprises waiting there. so I opted against. + * + * + * d) this method is somewhat clumsy and certainly not the + * fastest way to do things. + * on the other hand, this is INIT code, executed once. + * and since it's the only portable method, I opted for it. + * + * e) and all this is my private opinion. tom ehlert. + * + * + * Some thoughts about LBA vs. CHS. by Bart Oldeman 2001/Nov/11 + * Matthias Paul writes in www.freedos.org/freedos/news/technote/113.html: + * (...) MS-DOS 7.10+, which will always access logical drives in a type + * 05h extended partition via CHS, even if the individual logical drives + * in there are of LBA type, or go beyond 8 Gb... (Although this workaround + * is sometimes used in conjunction with OS/2, using a 05h partition going + * beyond 8 Gb may cause MS-DOS 7.10 to hang or corrupt your data...) (...) + * + * Also at http://www.win.tue.nl/~aeb/partitions/partition_types-1.html: + * (...) 5 DOS 3.3+ Extended Partition + * Supports at most 8.4 GB disks: with type 5 DOS/Windows will not use the + * extended BIOS call, even if it is available. (...) + * + * So MS-DOS 7.10+ is brain-dead in this respect, but we knew that ;-) + * However there is one reason to use old-style CHS calls: + * some programs intercept int 13 and do not support LBA addressing. So + * it is worth using CHS if possible, unless the user asks us not to, + * either by specifying a 0x0c/0x0e/0x0f partition type or enabling + * the ForceLBA setting in the fd kernel (sys) config. This will make + * multi-sector reads and BIOS computations more efficient, at the cost + * of some compatibility. + * + * However we need to be safe, and with varying CHS at different levels + * that might be difficult. Hence we _only_ trust the LBA values in the + * partition tables and the heads and sectors values the BIOS gives us. + * After all these are the values the BIOS uses to process our CHS values. + * So unless the BIOS is buggy, using CHS on one partition and LBA on another + * should be safe. The CHS values in the partition table are NOT trusted. + * We print a warning if there is a mismatch with the calculated values. + * + * The CHS values in the boot sector are used at a higher level. The CHS + * that DOS uses in various INT21/AH=44 IOCTL calls are converted to LBA + * using the boot sector values and then converted back to CHS using BIOS + * values if necessary. Internally we do LBA as much as possible. + * + * However if the partition extends beyond cylinder 1023 and is not labelled + * as one of the LBA types, we can't use CHS and print a warning, using LBA + * instead if possible, and otherwise refuse to use it. + * + * As for EXTENDED_LBA vs. EXTENDED, FreeDOS makes no difference. This is + * boot time - there is no reason not to use LBA for reading partition tables, + * and the MSDOS 7.10 behaviour is not desirable. + * + * Note: for floppies we need the boot sector values though and the boot sector + * code does not use LBA addressing yet. + * + * Conclusion: with all this implemented, FreeDOS should be able to gracefully + * handle and read foreign hard disks moved across computers, whether using + * CHS or LBA, strengthening its role as a rescue environment. + */ + +#define LBA_to_CHS init_LBA_to_CHS + +/* + interesting macros - used internally only +*/ + +#define SCAN_PRIMARYBOOT 0x00 +#define SCAN_PRIMARY 0x01 +#define SCAN_EXTENDED 0x02 +#define SCAN_PRIMARY2 0x03 + +#define FAT12 0x01 +#define FAT16SMALL 0x04 +#define EXTENDED 0x05 +#define FAT16LARGE 0x06 +#define FAT32 0x0b /* FAT32 partition that ends before the 8.4 */ + /* GB boundary */ +#define FAT32_LBA 0x0c /* FAT32 partition that ends after the 8.4GB */ + /* boundary. LBA is needed to access this. */ +#define FAT16_LBA 0x0e /* like 0x06, but it is supposed to end past */ + /* the 8.4GB boundary */ +#define FAT12_LBA 0xff /* fake FAT12 LBA entry for internal use */ +#define EXTENDED_LBA 0x0f /* like 0x05, but it is supposed to end past */ + +/* Let's play it safe and do not allow partitions with clusters above * + * or equal to 0xff0/0xfff0/0xffffff0 to be created * + * the problem with fff0-fff6 is that they might be interpreted as BAD * + * even though the standard BAD value is ...ff7 */ + +#define FAT12MAX (FAT_MAGIC-6) +#define FAT16MAX (FAT_MAGIC16-6) +#define FAT32MAX (FAT_MAGIC32-6) + +#define IsExtPartition(parttyp) ((parttyp) == EXTENDED || \ + (parttyp) == EXTENDED_LBA ) + +#define IsLBAPartition(parttyp) ((parttyp) == FAT12_LBA || \ + (parttyp) == FAT16_LBA || \ + (parttyp) == FAT32_LBA) + +#ifdef WITHFAT32 +#define IsFATPartition(parttyp) ((parttyp) == FAT12 || \ + (parttyp) == FAT16SMALL || \ + (parttyp) == FAT16LARGE || \ + (parttyp) == FAT16_LBA || \ + (parttyp) == FAT32 || \ + (parttyp) == FAT32_LBA) +#else +#define IsFATPartition(parttyp) ((parttyp) == FAT12 || \ + (parttyp) == FAT16SMALL || \ + (parttyp) == FAT16LARGE || \ + (parttyp) == FAT16_LBA) +#endif + +#define MSDOS_EXT_SIGN 0x29 /* extended boot sector signature */ +#define MSDOS_FAT12_SIGN "FAT12 " /* FAT12 filesystem signature */ +#define MSDOS_FAT16_SIGN "FAT16 " /* FAT16 filesystem signature */ +#define MSDOS_FAT32_SIGN "FAT32 " /* FAT32 filesystem signature */ + +/* local - returned and used for BIOS interface INT 13, AH=48*/ +struct _bios_LBA_disk_parameterS { + UWORD size; + UWORD information; + ULONG cylinders; + ULONG heads; + ULONG sectors; + + ULONG totalSect; + ULONG totalSectHigh; + UWORD BytesPerSector; + + ULONG eddparameters; +}; + +/* physical characteristics of a drive */ + +struct DriveParamS { + UBYTE driveno; /* = 0x8x */ + UWORD descflags; + ULONG total_sectors; + + struct CHS chs; /* for normal INT 13 */ +}; + +struct PartTableEntry /* INTERNAL representation of partition table entry */ +{ + UBYTE Bootable; + UBYTE FileSystem; + struct CHS Begin; + struct CHS End; + ULONG RelSect; + ULONG NumSect; +}; + +/* + internal global data +*/ + +BOOL ExtLBAForce = FALSE; + +COUNT init_readdasd(UBYTE drive) +{ + static iregs regs; + + regs.a.b.h = 0x15; + regs.d.b.l = drive; + init_call_intr(0x13, ®s); + if ((regs.flags & 1) == 0) + switch (regs.a.b.h) + { + case 2: + return DF_CHANGELINE; + case 3: + return DF_FIXED; + } + return 0; +} + +typedef struct { + UWORD bpb_nbyte; /* Bytes per Sector */ + UBYTE bpb_nsector; /* Sectors per Allocation Unit */ + UWORD bpb_nreserved; /* # Reserved Sectors */ + UBYTE bpb_nfat; /* # FATs */ + UWORD bpb_ndirent; /* # Root Directory entries */ + UWORD bpb_nsize; /* Size in sectors */ + UBYTE bpb_mdesc; /* MEDIA Descriptor Byte */ + UWORD bpb_nfsect; /* FAT size in sectors */ + UWORD bpb_nsecs; /* Sectors per track */ + UWORD bpb_nheads; /* Number of heads */ +} floppy_bpb; + +floppy_bpb floppy_bpbs[5] = { +/* copied from Brian Reifsnyder's FORMAT, bpb.h */ + {FLOPPY_SEC_SIZE, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2}, /* FD360 5.25 DS */ + {FLOPPY_SEC_SIZE, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2}, /* FD1200 5.25 HD */ + {FLOPPY_SEC_SIZE, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2}, /* FD720 3.5 LD */ + {FLOPPY_SEC_SIZE, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2}, /* FD1440 3.5 HD */ + {FLOPPY_SEC_SIZE, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2} /* FD2880 3.5 ED */ +}; + +COUNT init_getdriveparm(UBYTE drive, bpb * pbpbarray) +{ + static iregs regs; + REG UBYTE type; + + if (drive & 0x80) + return 5; + regs.a.b.h = 0x08; + regs.d.b.l = drive; + init_call_intr(0x13, ®s); + type = regs.b.b.l - 1; + if (regs.flags & 1) + type = 0; /* return 320-360 for XTs */ + else if (type > 6) + type = 8; /* any odd ball drives get 8&7=0: the 320-360 table */ + else if (type == 5) + type = 4; /* 5 and 4 are both 2.88 MB */ + + memcpy(pbpbarray, &floppy_bpbs[type & 7], sizeof(floppy_bpb)); + ((bpb *)pbpbarray)->bpb_hidden = 0; /* very important to init to 0, see bug#1789 */ + ((bpb *)pbpbarray)->bpb_huge = 0; + + if (type == 3) + return 7; /* 1.44 MB */ + + if (type == 4) + return 9; /* 2.88 almost forgot this one */ + + /* 0=320-360kB, 1=1.2MB, 2=720kB, 8=any odd ball drives */ + return type; +} + +/* + translate LBA sectors into CHS addressing + initially copied and pasted from dsk.c! + + LBA to/from CHS conversion - see http://www.ata-atapi.com/ How It Works section on CHSxlat - CHS Translation + LBA (logical block address) simple 0 to N-1 used internally and with extended int 13h (BIOS) + L-CHS (logical CHS) is the CHS view when using int 13h (BIOS) + P-CHS (physical CHS) is the CHS view when directly accessing disk, should not, but could be used in BS or MBR + + LBA = ( (cylinder * heads_per_cylinder + heads ) * sectors_per_track ) + sector - 1 + + cylinder = LBA / (heads_per_cylinder * sectors_per_track) + temp = LBA % (heads_per_cylinder * sectors_per_track) + head = temp / sectors_per_track + sector = temp % sectors_per_track + 1 + + where heads_per_cylinder and sectors_per_track are the current translation mode values. + cyclinder and heads are 0 to N-1 based, sector is 1 to N based +*/ + +void init_LBA_to_CHS(struct CHS *chs, ULONG LBA_address, + struct DriveParamS *driveparam) +{ + unsigned hs = driveparam->chs.Sector * driveparam->chs.Head; + unsigned hsrem = (unsigned)(LBA_address % hs); + + LBA_address /= hs; + + chs->Cylinder = LBA_address >= 0x10000ul ? 0xffffu : (unsigned)LBA_address; + chs->Head = hsrem / driveparam->chs.Sector; + chs->Sector = hsrem % driveparam->chs.Sector + 1; +} + +void printCHS(char *title, struct CHS *chs) +{ + /* has no fixed size for head/sect: is often 1/1 in our context */ + printf("%s%4u-%u-%u", title, chs->Cylinder, chs->Head, chs->Sector); +} + +/* + reason for this modules existence: + + we have found a partition, and add them to the global + partition structure. + +*/ + +/* Compute ceil(a/b) */ +#define cdiv(a, b) (((a) + (b) - 1) / (b)) + +/* calculates FAT data: + code adapted by Bart Oldeman from mkdosfs from the Linux dosfstools: + Author: Dave Hudson + Updated by: Roman Hodek + Portions copyright 1992, 1993 Remy Card + and 1991 Linus Torvalds +*/ +/* defaults: */ +#define MAXCLUSTSIZE 128 +#define NSECTORFAT12 8 +#define NFAT 2 + +VOID CalculateFATData(ddt * pddt, ULONG NumSectors, UBYTE FileSystem) +{ + ULONG fatdata; + + bpb *defbpb = &pddt->ddt_defbpb; + + /* FAT related items */ + defbpb->bpb_nfat = NFAT; + /* normal value of number of entries in root dir */ + defbpb->bpb_ndirent = 512; + defbpb->bpb_nreserved = 1; + /* SEC_SIZE * DIRENT_SIZE / defbpb->bpb_ndirent + defbpb->bpb_nreserved */ + fatdata = NumSectors - (DIRENT_SIZE + 1); + if (FileSystem == FAT12 || FileSystem == FAT12_LBA) + { + unsigned fatdat; + /* in DOS, FAT12 defaults to 4096kb (8 sector) - clusters. */ + defbpb->bpb_nsector = NSECTORFAT12; + /* Force maximal fatdata=32696 sectors since with our only possible sector + size (512 bytes) this is the maximum for 4k clusters. + #clus*secperclus+#fats*fatlength= 4077 * 8 + 2 * 12 = 32640. + max FAT12 size for FreeDOS = 16,728,064 bytes */ + fatdat = (unsigned)fatdata; + if (fatdata > 32640) + fatdat = 32640; + /* The "+2*NSECTORFAT12" is for the reserved first two FAT entries */ + defbpb->bpb_nfsect = (UWORD)cdiv((fatdat + 2 * NSECTORFAT12) * 3UL, + FLOPPY_SEC_SIZE * 2 * NSECTORFAT12 + NFAT*3); +#ifdef DEBUG + /* Need to calculate number of clusters, since the unused parts of the + * FATS and data area together could make up space for an additional, + * not really present cluster. + * (This is really done in fatfs.c, bpbtodpb) */ + { + unsigned clust = (fatdat - 2 * defbpb->bpb_nfsect) / NSECTORFAT12; + unsigned maxclust = (defbpb->bpb_nfsect * 2 * SEC_SIZE) / 3; + if (maxclust > FAT12MAX) + maxclust = FAT12MAX; + printf("FAT12: #clu=%u, fatlength=%u, maxclu=%u, limit=%u\n", + clust, defbpb->bpb_nfsect, maxclust, FAT12MAX); + if (clust > maxclust - 2) + { + clust = maxclust - 2; + printf("FAT12: too many clusters: setting to maxclu-2\n"); + } + } +#endif + memcpy(pddt->ddt_fstype, MSDOS_FAT12_SIGN, 8); + } + else + { /* FAT16/FAT32 */ + CLUSTER fatlength, maxcl; + unsigned long clust, maxclust; + unsigned fatentpersec; + unsigned divisor; + +#ifdef WITHFAT32 + if (FileSystem == FAT32 || FileSystem == FAT32_LBA) + { + /* For FAT32, use the cluster size table described in the FAT spec: + * http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf + */ + unsigned sz_gb = (unsigned)(NumSectors / 2097152UL); + unsigned char nsector = 64; /* disks greater than 32 GB, 32K cluster */ + if (sz_gb <= 32) /* disks up to 32 GB, 16K cluster */ + nsector = 32; + if (sz_gb <= 16) /* disks up to 16 GB, 8K cluster */ + nsector = 16; + if (sz_gb <= 8) /* disks up to 8 GB, 4K cluster */ + nsector = 8; + if (NumSectors <= 532480UL) /* disks up to 260 MB, 0.5K cluster */ + nsector = 1; + defbpb->bpb_nsector = nsector; + defbpb->bpb_ndirent = 0; + defbpb->bpb_nreserved = 0x20; + fatdata = NumSectors - 0x20; + fatentpersec = FLOPPY_SEC_SIZE/4; + maxcl = FAT32MAX; + } + else +#endif + { + /* FAT16: start at 4 sectors per cluster */ + defbpb->bpb_nsector = 4; + /* Force maximal fatdata=8387584 sectors (NumSectors=8387617) + since with our only possible sectorsize (512 bytes) this is the + maximum we can address with 64k clusters + #clus*secperclus+#fats*fatlength=65517 * 128 + 2 * 256=8386688. + max FAT16 size for FreeDOS = 4,293,984,256 bytes = 4GiB-983,040 */ + if (fatdata > 8386688ul) + fatdata = 8386688ul; + fatentpersec = FLOPPY_SEC_SIZE/2; + maxcl = FAT16MAX; + } + + DebugPrintf(("%ld sectors for FAT+data, starting with %d sectors/cluster\n", fatdata, defbpb->bpb_nsector)); + do + { + DebugPrintf(("Trying with %d sectors/cluster:\n", defbpb->bpb_nsector)); + divisor = fatentpersec * defbpb->bpb_nsector + NFAT; + fatlength = (CLUSTER)((fatdata + (2 * defbpb->bpb_nsector + divisor - 1))/ + divisor); + /* Need to calculate number of clusters, since the unused parts of the + * FATS and data area together could make up space for an additional, + * not really present cluster. */ + clust = (fatdata - NFAT * fatlength) / defbpb->bpb_nsector; + maxclust = fatlength * fatentpersec; + if (maxclust > maxcl) + maxclust = maxcl; + DebugPrintf(("FAT: #clu=%lu, fatlen=%lu, maxclu=%lu, limit=%lu\n", + clust, fatlength, maxclust, maxcl)); + if (clust > maxclust - 2) + { + clust = 0; + DebugPrintf(("FAT: too many clusters\n")); + } + else if (clust <= FAT_MAGIC) + { + /* The <= 4086 avoids that the filesystem will be misdetected as having a + * 12 bit FAT. */ + DebugPrintf(("FAT: would be misdetected as FAT12\n")); + clust = 0; + } + if (clust) + break; + defbpb->bpb_nsector <<= 1; + } + while (defbpb->bpb_nsector && defbpb->bpb_nsector <= MAXCLUSTSIZE); +#ifdef WITHFAT32 + if (FileSystem == FAT32 || FileSystem == FAT32_LBA) + { + defbpb->bpb_nfsect = 0; + defbpb->bpb_xnfsect = fatlength; + /* set up additional FAT32 fields */ + defbpb->bpb_xflags = 0; + defbpb->bpb_xfsversion = 0; + defbpb->bpb_xrootclst = 2; + defbpb->bpb_xfsinfosec = 1; + defbpb->bpb_xbackupsec = 6; + memcpy(pddt->ddt_fstype, MSDOS_FAT32_SIGN, 8); + } + else +#endif + { + defbpb->bpb_nfsect = (UWORD)fatlength; + memcpy(pddt->ddt_fstype, MSDOS_FAT16_SIGN, 8); + } + } + pddt->ddt_fstype[8] = '\0'; +} + +STATIC void push_ddt(ddt *pddt) +{ + ddt FAR *fddt = DynAlloc("ddt", 1, sizeof(ddt)); + fmemcpy(fddt, pddt, sizeof(ddt)); + if (pddt->ddt_logdriveno != 0) { + (fddt - 1)->ddt_next = fddt; + if (pddt->ddt_driveno == 0 && pddt->ddt_logdriveno == 1) + (fddt - 1)->ddt_descflags |= DF_CURLOG | DF_MULTLOG; + } +} + +void DosDefinePartition(struct DriveParamS *driveParam, + ULONG StartSector, struct PartTableEntry *pEntry, + int extendedPartNo, int PrimaryNum) +{ + ddt nddt; + ddt *pddt = &nddt; + struct CHS chs; + + if (nUnits >= NDEV) + { + printf("more Partitions detected then possible, max = %d\n", NDEV); + return; /* we are done */ + } + + pddt->ddt_next = MK_FP(0, 0xffff); + pddt->ddt_driveno = driveParam->driveno; + pddt->ddt_logdriveno = nUnits; + pddt->ddt_descflags = driveParam->descflags; + /* Turn of LBA if not forced and the partition is within 1023 cyls and of the right type */ + /* the FileSystem type was internally converted to LBA_xxxx if a non-LBA partition + above cylinder 1023 was found */ + if (!InitKernelConfig.ForceLBA && !ExtLBAForce && !IsLBAPartition(pEntry->FileSystem)) + pddt->ddt_descflags &= ~DF_LBA; + pddt->ddt_ncyl = driveParam->chs.Cylinder; + + DebugPrintf(("LBA %senabled for drive %c:\n", (pddt->ddt_descflags & DF_LBA)?"":"not ", 'A' + nUnits)); + + pddt->ddt_offset = StartSector; + + pddt->ddt_defbpb.bpb_nbyte = FLOPPY_SEC_SIZE; + pddt->ddt_defbpb.bpb_mdesc = 0xf8; + pddt->ddt_defbpb.bpb_nheads = driveParam->chs.Head; + pddt->ddt_defbpb.bpb_nsecs = driveParam->chs.Sector; + pddt->ddt_defbpb.bpb_hidden = pEntry->RelSect; + + pddt->ddt_defbpb.bpb_nsize = 0; + pddt->ddt_defbpb.bpb_huge = pEntry->NumSect; + if (pEntry->NumSect <= 0xffff) + { + pddt->ddt_defbpb.bpb_nsize = (UWORD) (pEntry->NumSect); + pddt->ddt_defbpb.bpb_huge = 0; /* may still be set on Win95 */ + } + + /* sectors per cluster, sectors per FAT etc. */ + CalculateFATData(pddt, pEntry->NumSect, pEntry->FileSystem); + + pddt->ddt_serialno = 0x12345678l; + /* drive inaccessible until bldbpb successful */ + pddt->ddt_descflags |= init_readdasd(pddt->ddt_driveno) | DF_NOACCESS; + pddt->ddt_type = 5; + memcpy(&pddt->ddt_bpb, &pddt->ddt_defbpb, sizeof(bpb)); + + push_ddt(pddt); + + /* Alain whishes to keep this in later versions, too + Tom likes this too, so he made it configurable by SYS CONFIG ... + */ + + if (InitKernelConfig.InitDiskShowDriveAssignment) + { + char *ExtPri; + int num; + + LBA_to_CHS(&chs, StartSector, driveParam); + + ExtPri = "Pri"; + num = PrimaryNum + 1; + if (extendedPartNo) + { + ExtPri = "Ext"; + num = extendedPartNo; + } + printf("\r%c: HD%d, %s[%2d]", 'A' + nUnits, + (driveParam->driveno & 0x7f) + 1, ExtPri, num); + + printCHS(", CHS= ", &chs); + + printf(", start=%6lu MB, size=%6lu MB\n", + StartSector / 2048, pEntry->NumSect / 2048); + } + + nUnits++; +} + +/* Get the parameters of the hard disk */ +STATIC int LBA_Get_Drive_Parameters(int drive, struct DriveParamS *driveParam) +{ + iregs regs; + struct _bios_LBA_disk_parameterS lba_bios_parameters; + + ExtLBAForce = FALSE; + + memset(driveParam, 0, sizeof *driveParam); + drive |= 0x80; + + /* for tests - disable LBA support, + even if exists */ + if (!InitKernelConfig.GlobalEnableLBAsupport) + { + goto StandardBios; + } + /* check for LBA support */ + regs.b.x = 0x55aa; + regs.a.b.h = 0x41; + regs.d.b.l = drive; + + init_call_intr(0x13, ®s); + + if (regs.b.x != 0xaa55 || (regs.flags & 0x01)) + { + goto StandardBios; + } + + /* by ralph : + if DAP cannot be used, don't use + LBA + */ + if ((regs.c.x & 1) == 0) + { + goto StandardBios; + } + + /* drive supports LBA addressing */ + + /* version 1.0, 2.0 have different verify */ + if (regs.a.x < 0x2100) + LBA_WRITE_VERIFY = 0x4301; + + memset(&lba_bios_parameters, 0, sizeof(lba_bios_parameters)); + lba_bios_parameters.size = sizeof(lba_bios_parameters); + + regs.si = FP_OFF(&lba_bios_parameters); + regs.ds = FP_SEG(&lba_bios_parameters); + regs.a.b.h = 0x48; + regs.d.b.l = drive; + init_call_intr(0x13, ®s); + + /* error or DMA boundary errors not handled transparently */ + if (regs.flags & 0x01) + { + goto StandardBios; + } + + /* verify maximum settings, we can't handle more */ + + if (lba_bios_parameters.heads > 0xffff || + lba_bios_parameters.sectors > 0xffff || + lba_bios_parameters.totalSectHigh != 0) + { + printf("Drive is too large to handle, using only 1st 8 GB\n" + " drive %02x heads %lu sectors %lu , total=0x%lx-%08lx\n", + drive, + (ULONG) lba_bios_parameters.heads, + (ULONG) lba_bios_parameters.sectors, + (ULONG) lba_bios_parameters.totalSect, + (ULONG) lba_bios_parameters.totalSectHigh); + + goto StandardBios; + } + + driveParam->total_sectors = lba_bios_parameters.totalSect; + + /* if we arrive here, success */ + driveParam->descflags = DF_LBA; + if (lba_bios_parameters.information & 8) + driveParam->descflags |= DF_WRTVERIFY; + +StandardBios: /* old way to get parameters */ + + regs.a.b.h = 0x08; + regs.d.b.l = drive; + + init_call_intr(0x13, ®s); + + if (regs.flags & 0x01) + goto ErrorReturn; + + /* int13h call returns max value, store as count (#) i.e. +1 for 0 based heads & cylinders */ + driveParam->chs.Head = (regs.d.x >> 8) + 1; /* DH = max head value = # of heads - 1 (0-255) */ + driveParam->chs.Sector = (regs.c.x & 0x3f); /* CL bits 0-5 = max sector value = # (sectors/track) - 1 (1-63) */ + /* max cylinder value = # cylinders - 1 (0-1023) = [high two bits]CL7:6=cyls9:8, [low byte]CH=cyls7:0 */ + driveParam->chs.Cylinder = (regs.c.x >> 8) | ((regs.c.x & 0xc0) << 2) + 1; + + if (driveParam->chs.Sector == 0) { + /* happens e.g. with Bochs 1.x if no harddisk defined */ + driveParam->chs.Sector = 63; /* avoid division by zero...! */ + printf("BIOS reported 0 sectors/track, assuming 63!\n"); + } + + if (!(driveParam->descflags & DF_LBA)) + { + driveParam->total_sectors = + (ULONG)driveParam->chs.Cylinder + * driveParam->chs.Head * driveParam->chs.Sector; + } + + driveParam->driveno = drive; + + DebugPrintf(("drive %02Xh total: C = %u, H = %u, S = %u,", + drive, + driveParam->chs.Cylinder, + driveParam->chs.Head, driveParam->chs.Sector)); + DebugPrintf((" total size %luMB\n\n", driveParam->total_sectors / 2048)); + +ErrorReturn: + + return driveParam->driveno; +} + +/* + converts physical into logical representation of partition entry +*/ + +STATIC void ConvCHSToIntern(struct CHS *chs, UBYTE * pDisk) +{ + chs->Head = pDisk[0]; + chs->Sector = pDisk[1] & 0x3f; + chs->Cylinder = pDisk[2] + ((pDisk[1] & 0xc0) << 2); +} + +BOOL ConvPartTableEntryToIntern(struct PartTableEntry * pEntry, + UBYTE * pDisk) +{ + int i; + + if (pDisk[0x1fe] != 0x55 || pDisk[0x1ff] != 0xaa) + { + memset(pEntry, 0, 4 * sizeof(struct PartTableEntry)); + + return FALSE; + } + + pDisk += 0x1be; + + for (i = 0; i < 4; i++, pDisk += 16, pEntry++) + { + + pEntry->Bootable = pDisk[0]; + pEntry->FileSystem = pDisk[4]; + + ConvCHSToIntern(&pEntry->Begin, pDisk+1); + ConvCHSToIntern(&pEntry->End, pDisk+5); + + pEntry->RelSect = *(ULONG *) (pDisk + 8); + pEntry->NumSect = *(ULONG *) (pDisk + 12); + } + return TRUE; +} + +BOOL is_suspect(struct CHS *chs, struct CHS *pEntry_chs) +{ + /* Valid entry: + entry == chs || // partition entry equal to computed values + (chs->Cylinder > 1023 && // or LBA partition + (entry->Cylinder == 1023 || + entry->Cylinder == (0x3FF & chs->Cylinder))) + */ + return !((pEntry_chs->Cylinder == chs->Cylinder && + pEntry_chs->Head == chs->Head && + pEntry_chs->Sector == chs->Sector) || + chs->Cylinder > 1023u && + (pEntry_chs->Cylinder == 1023 || + pEntry_chs->Cylinder == (0x3ff & chs->Cylinder))); +} + +void print_warning_suspect(char *partitionName, UBYTE fs, struct CHS *chs, + struct CHS *pEntry_chs) +{ + if (!InitKernelConfig.ForceLBA) + { + printf("WARNING: using suspect partition %s FS %02x:", partitionName, fs); + printCHS(" with calculated values ", chs); + printCHS(" instead of ", pEntry_chs); + printf("\n"); + } + memcpy(pEntry_chs, chs, sizeof(struct CHS)); +} + +BOOL ScanForPrimaryPartitions(struct DriveParamS * driveParam, int scan_type, + struct PartTableEntry * pEntry, ULONG startSector, + int partitionsToIgnore, int extendedPartNo) +{ + int i; + struct CHS chs, end; + ULONG partitionStart; + char partitionName[12]; + + for (i = 0; i < 4; i++, pEntry++) + { + if (pEntry->FileSystem == 0) + continue; + + if (partitionsToIgnore & (1 << i)) + continue; + + if (IsExtPartition(pEntry->FileSystem)) + continue; + + if (scan_type == SCAN_PRIMARYBOOT && !pEntry->Bootable) + continue; + + partitionStart = startSector + pEntry->RelSect; + + if (!IsFATPartition(pEntry->FileSystem)) + { + continue; + } + + if (extendedPartNo) + sprintf(partitionName, "Ext:%d", extendedPartNo); + else + sprintf(partitionName, "Pri:%d", i + 1); + + /* + some sanity checks, that partition + structure is OK + */ + LBA_to_CHS(&chs, partitionStart, driveParam); + LBA_to_CHS(&end, partitionStart + pEntry->NumSect - 1, driveParam); + + /* some FDISKs enter for partitions + > 8 GB cyl = 1023, other (cyl&1023) + */ + + if (is_suspect(&chs, &pEntry->Begin)) + { + print_warning_suspect(partitionName, pEntry->FileSystem, &chs, + &pEntry->Begin); + } + + if (is_suspect(&end, &pEntry->End)) + { + if (pEntry->NumSect == 0) + { + printf("Not using partition %s with 0 sectors\n", partitionName); + continue; + } + print_warning_suspect(partitionName, pEntry->FileSystem, &end, + &pEntry->End); + } + + if (chs.Cylinder > 1023 || end.Cylinder > 1023) + { + + if (!(driveParam->descflags & DF_LBA)) + { + printf + ("can't use LBA partition without LBA support - part %s FS %02x", + partitionName, pEntry->FileSystem); + + printCHS(" start ", &chs); + printCHS(", end ", &end); + printf("\n"); + + continue; + } + + if (!InitKernelConfig.ForceLBA && !ExtLBAForce + && !IsLBAPartition(pEntry->FileSystem)) + { + printf + ("WARNING: Partition ID does not suggest LBA - part %s FS %02x.\n" + "Please run FDISK to correct this - using LBA to access partition.\n", + partitionName, pEntry->FileSystem); + + printCHS(" start ", &chs); + printCHS(", end ", &end); + printf("\n"); + pEntry->FileSystem = (pEntry->FileSystem == FAT12 ? FAT12_LBA : + pEntry->FileSystem == FAT32 ? FAT32_LBA : + /* pEntry->FileSystem == FAT16 ? */ + FAT16_LBA); + } + + /* else its a diagnostic message only */ +#ifdef DEBUG + printf("found and using LBA partition %s FS %02x", + partitionName, pEntry->FileSystem); + printCHS(" start ", &chs); + printCHS(", end ", &end); + printf("\n"); +#endif + } + + /* + here we have a partition table in our hand !! + */ + + partitionsToIgnore |= 1 << i; + + DosDefinePartition(driveParam, partitionStart, pEntry, + extendedPartNo, i); + + if (scan_type == SCAN_PRIMARYBOOT || scan_type == SCAN_PRIMARY) + { + return partitionsToIgnore; + } + } + + return partitionsToIgnore; +} + +void BIOS_drive_reset(unsigned drive); + +int Read1LBASector(struct DriveParamS *driveParam, unsigned drive, + ULONG LBA_address, void * buffer) +{ + static struct _bios_LBA_address_packet dap = { + 16, 0, 0, 0, 0, 0, 0 + }; + + struct CHS chs; + iregs regs; + int num_retries; + +/* disabled because this should not happen and if it happens the BIOS + should complain; also there are weird disks around with + CMOS geometry < real geometry */ +#if 0 + if (LBA_address >= driveParam->total_sectors) + { + printf("LBA-Transfer error : address overflow = %lu, > %lu total sectors\n", + LBA_address, driveParam->total_sectors); + return 1; + } +#endif + + for (num_retries = 0; num_retries < N_RETRY; num_retries++) + { + regs.d.b.l = drive | 0x80; + LBA_to_CHS(&chs, LBA_address, driveParam); + /* Some old "security" software (PROT) traps int13 and assumes non + LBA accesses. This statement causes partition tables to be read + using CHS methods even if LBA is available unless CHS can't reach + them. This can be overridden using kernel config parameters and + the extended LBA partition type indicator. + */ + if ((driveParam->descflags & DF_LBA) && + (InitKernelConfig.ForceLBA || ExtLBAForce || chs.Cylinder > 1023)) + { + dap.number_of_blocks = 1; + dap.buffer_address = buffer; + dap.block_address_high = 0; /* clear high part */ + dap.block_address = LBA_address; /* clear high part */ + + /* Load the registers and call the interrupt. */ + regs.a.x = LBA_READ; + regs.si = FP_OFF(&dap); + regs.ds = FP_SEG(&dap); + } + else + { /* transfer data, using old bios functions */ + /* avoid overflow at end of track */ + + if (chs.Cylinder > 1023) + { + printf("LBA-Transfer error : address = %lu, cylinder %u > 1023\n", LBA_address, chs.Cylinder); + return 1; + } + + regs.a.x = 0x0201; + regs.b.x = FP_OFF(buffer); + regs.c.x = + ((chs.Cylinder & 0xff) << 8) + ((chs.Cylinder & 0x300) >> 2) + + chs.Sector; + regs.d.b.h = chs.Head; + regs.es = FP_SEG(buffer); + } /* end of retries */ + init_call_intr(0x13, ®s); + if ((regs.flags & FLG_CARRY) == 0) + break; + BIOS_drive_reset(driveParam->driveno); + } + + return regs.flags & FLG_CARRY ? 1 : 0; +} + +/* Load the Partition Tables and get information on all drives */ +int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) +{ + + struct PartTableEntry PTable[4]; + ULONG RelSectorOffset; + ULONG ExtendedPartitionOffset; + int iPart; + int strangeHardwareLoop; + + int num_extended_found = 0; + + struct DriveParamS driveParam; + + /* Get the hard drive parameters and ensure that the drive exists. */ + /* If there was an error accessing the drive, skip that drive. */ + + if (!LBA_Get_Drive_Parameters(drive, &driveParam)) + { + printf("can't get drive parameters for drive %02x\n", drive); + return PartitionsToIgnore; + } + + RelSectorOffset = 0; /* boot sector */ + ExtendedPartitionOffset = 0; /* not found yet */ + + /* Read the Primary Partition Table. */ + +ReadNextPartitionTable: + + strangeHardwareLoop = 0; +strange_restart: + + if (Read1LBASector + (&driveParam, drive, RelSectorOffset, InitDiskTransferBuffer)) + { + printf("Error reading partition table drive %02Xh sector %lu", drive, + RelSectorOffset); + return PartitionsToIgnore; + } + + if (!ConvPartTableEntryToIntern(PTable, InitDiskTransferBuffer)) + { + /* there is some strange hardware out in the world, + which returns OK on first read, but the data are + rubbish. simply retrying works fine. + there is no logic behind this, but it works TE */ + + if (++strangeHardwareLoop < 3) + goto strange_restart; + + printf("illegal partition table - drive %02x sector %lu\n", drive, + RelSectorOffset); + return PartitionsToIgnore; + } + + if (scanType == SCAN_PRIMARYBOOT || + scanType == SCAN_PRIMARY || + scanType == SCAN_PRIMARY2 || num_extended_found != 0) + { + + PartitionsToIgnore = ScanForPrimaryPartitions(&driveParam, scanType, + PTable, RelSectorOffset, + PartitionsToIgnore, + num_extended_found); + } + + if (scanType != SCAN_EXTENDED) + { + return PartitionsToIgnore; + } + + /* scan for extended partitions now */ + PartitionsToIgnore = 0; + + for (iPart = 0; iPart < 4; iPart++) + { + if (IsExtPartition(PTable[iPart].FileSystem)) + { + RelSectorOffset = ExtendedPartitionOffset + PTable[iPart].RelSect; + + if (ExtendedPartitionOffset == 0) + { + ExtendedPartitionOffset = PTable[iPart].RelSect; + /* grand parent LBA -> all children and grandchildren LBA */ + ExtLBAForce = (PTable[iPart].FileSystem == EXTENDED_LBA); + } + + num_extended_found++; + + if (num_extended_found > 30) + { + printf("found more then 30 extended partitions, terminated\n"); + return 0; + } + + goto ReadNextPartitionTable; + } + } + + return PartitionsToIgnore; +} + +int BIOS_nrdrives(void) +{ + iregs regs; + + regs.a.b.h = 0x08; + regs.d.b.l = 0x80; + init_call_intr(0x13, ®s); + + if (regs.flags & 1) + { + printf("no hard disks detected\n"); + return 0; + } + + return regs.d.b.l; +} + +void BIOS_drive_reset(unsigned drive) +{ + iregs regs; + + regs.d.b.l = drive | 0x80; + regs.a.b.h = 0; + + init_call_intr(0x13, ®s); +} + +/* + thats what MSDN says: + + How Windows 2000 Assigns, Reserves, and Stores Drive Letters + ID: q234048 + + BASIC Disk - Drive Letter Assignment Rules +The following are the basic disk drive letter assignment rules for Windows 2000: +Scan all fixed hard disks as they are enumerated, assign drive letters +starting with any active primary partitions (if there is one), otherwise, +scan the first primary partition on each drive. Assign next available +letter starting with C: + +Repeat scan for all fixed hard disks and removable (JAZ, MO) disks +and assign drive letters to all logical drives in an extended partition, +or the removable disk(s) as enumerated. Assign next available letter +starting with C: + +Finally, repeat scan for all fixed hard disk drives, and assign drive +letters to all remaining primary partitions. Assign next available letter +starting with C: + +Floppy drives. Assign letter starting with A: + +CD-ROM drives. Assign next available letter starting with D: + +************************************************************************* +Order in Which MS-DOS and Windows Assign Drive Letters +ID: q51978 + +MORE INFORMATION +The following occurs at startup: + +MS-DOS checks all installed disk devices, assigning the drive letter A +to the first physical floppy disk drive that is found. + +If a second physical floppy disk drive is present, it is assigned drive letter B. If it is not present, a logical drive B is created that uses the first physical floppy disk drive. + +Regardless of whether a second floppy disk drive is present, +MS-DOS then assigns the drive letter C to the primary MS-DOS +partition on the first physical hard disk, and then goes on +to check for a second hard disk. + +If a second physical hard disk is found, and a primary partition exists +on the second physical drive, the primary MS-DOS partition on the second +physical hard drive is assigned the letter D. MS-DOS version 5.0, which +supports up to eight physical drives, will continue to search for more +physical hard disk drives at this point. For example, if a third physical +hard disk is found, and a primary partition exists on the third physical +drive, the primary MS-DOS partition on the third physical hard drive is +assigned the letter E. + +MS-DOS returns to the first physical hard disk drive and assigns drive +letters to any additional logical drives (in extended MS-DOS partitions) +on that drive in sequence. + +MS-DOS repeats this process for the second physical hard disk drive, +if present. MS-DOS 5.0 will repeat this process for up to eight physical +hard drives, if present. After all logical drives (in extended MS-DOS +partitions) have been assigned drive letters, MS-DOS 5.0 returns to +the first physical drive and assigns drive letters to any other primary +MS-DOS partitions that exist, then searches other physical drives for +additional primary MS-DOS partitions. This support for multiple primary +MS-DOS partitions was added to version 5.0 for backward compatibility +with the previous OEM MS-DOS versions that support multiple primary partitions. + +After all logical drives on the hard disk(s) have been assigned drive +letters, drive letters are assigned to drives installed using DRIVER.SYS +or created using RAMDRIVE.SYS in the order in which the drivers are loaded +in the CONFIG.SYS file. Which drive letters are assigned to which devices +can be influenced by changing the order of the device drivers or, if necessary, +by creating "dummy" drive letters with DRIVER.SYS. + +******************************************************** + +or + + as rather well documented, DOS searches 1st) 1 primary patitions on + all drives, 2nd) all extended partitions. that + makes many people (including me) unhappy, as all DRIVES D:,E:... + on 1st disk will move up/down, if other disk with + primary partitions are added/removed, but + thats the way it is (hope I got it right) + TE (with a little help from my friends) + see also above for WIN2000,DOS,MSDN + +I don't know, if I did it right, but I tried to do it that way. TE + +***********************************************************************/ + +STATIC void make_ddt (ddt *pddt, int Unit, int driveno, int flags) +{ + pddt->ddt_next = MK_FP(0, 0xffff); + pddt->ddt_logdriveno = Unit; + pddt->ddt_driveno = driveno; + pddt->ddt_type = init_getdriveparm(driveno, &pddt->ddt_defbpb); + pddt->ddt_ncyl = (pddt->ddt_type & 7) ? 80 : 40; + pddt->ddt_descflags = init_readdasd(driveno) | flags; + + pddt->ddt_offset = 0; + pddt->ddt_serialno = 0x12345678l; + memcpy(&pddt->ddt_bpb, &pddt->ddt_defbpb, sizeof(bpb)); + push_ddt(pddt); +} + +void ReadAllPartitionTables(void) +{ + UBYTE foundPartitions[MAX_HARD_DRIVE]; + + int HardDrive; + int nHardDisk; + ddt nddt; + static iregs regs; + + /* quick adjustment of diskette parameter table */ + fmemcpy(int1e_table, *(char FAR * FAR *)MK_FP(0, 0x1e*4), sizeof(int1e_table)); + /* currently only 512 bytes per sector floppies are supported, log2(512/128)=2 */ + int1e_table[3] = 2; + /* enforce min. 9 sectors per track */ + if (int1e_table[4] < 9) + int1e_table[4] = 9; + /* and adjust int1e */ + setvec(0x1e, (intvec)int1e_table); + + /* Setup media info and BPBs arrays for floppies */ + make_ddt(&nddt, 0, 0, 0); + + /* + this is a quick patch - see if B: exists + test for A: also, need not exist + */ + init_call_intr(0x11, ®s); /* get equipment list */ +/*if ((regs.AL & 1)==0)*//* no floppy drives installed */ + if ((regs.AL & 1) && (regs.AL & 0xc0)) + { + /* floppy drives installed and a B: drive */ + make_ddt(&nddt, 1, 1, 0); + } + else + { + /* set up the DJ method : multiple logical drives */ + make_ddt(&nddt, 1, 0, DF_MULTLOG); + } + + /* Initial number of disk units */ + nUnits = 2; + + nHardDisk = BIOS_nrdrives(); + if (nHardDisk > LENGTH(foundPartitions)) + nHardDisk = LENGTH(foundPartitions); + + DebugPrintf(("DSK init: found %d disk drives\n", nHardDisk)); + + /* Reset the drives */ + for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) + { + BIOS_drive_reset(HardDrive); + foundPartitions[HardDrive] = 0; + } + + if (InitKernelConfig.DLASortByDriveNo == 0) + { + /* printf("Drive Letter Assignment - DOS order\n"); */ + + /* Process primary partition table 1 partition only */ + for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) + { + foundPartitions[HardDrive] = + ProcessDisk(SCAN_PRIMARYBOOT, HardDrive, 0); + + if (foundPartitions[HardDrive] == 0) + foundPartitions[HardDrive] = + ProcessDisk(SCAN_PRIMARY, HardDrive, 0); + } + + /* Process extended partition table */ + for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) + { + ProcessDisk(SCAN_EXTENDED, HardDrive, 0); + } + + /* Process primary a 2nd time */ + for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) + { + ProcessDisk(SCAN_PRIMARY2, HardDrive, foundPartitions[HardDrive]); + } + } + else + { + UBYTE bootdrv = peekb(0,0x5e0); + + /* printf("Drive Letter Assignment - sorted by drive\n"); */ + + /* Process primary partition table 1 partition only */ + for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) + { + struct DriveParamS driveParam; + if (LBA_Get_Drive_Parameters(HardDrive, &driveParam) && + driveParam.driveno == bootdrv) + { + foundPartitions[HardDrive] = + ProcessDisk(SCAN_PRIMARYBOOT, HardDrive, 0); + break; + } + } + + for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) + { + if (foundPartitions[HardDrive] == 0) + { + foundPartitions[HardDrive] = + ProcessDisk(SCAN_PRIMARYBOOT, HardDrive, 0); + + if (foundPartitions[HardDrive] == 0) + foundPartitions[HardDrive] = + ProcessDisk(SCAN_PRIMARY, HardDrive, 0); + } + + /* Process extended partition table */ + ProcessDisk(SCAN_EXTENDED, HardDrive, 0); + + /* Process primary a 2nd time */ + ProcessDisk(SCAN_PRIMARY2, HardDrive, foundPartitions[HardDrive]); + } + } +} + +/* disk initialization: returns number of units */ +COUNT dsk_init() +{ + printf(" - InitDisk"); + +#ifdef DEBUG + { + iregs regs; + regs.a.x = 0x1112; /* select 43 line mode - more space for partinfo */ + regs.b.x = 0; + init_call_intr(0x10, ®s); + } +#endif + + /* Reset the drives */ + BIOS_drive_reset(0); + + ReadAllPartitionTables(); + + return nUnits; +} diff --git a/kernel/inithma.c b/kernel/inithma.c new file mode 100644 index 0000000..0462e5d --- /dev/null +++ b/kernel/inithma.c @@ -0,0 +1,410 @@ +/****************************************************************/ +/* */ +/* initHMA.c */ +/* DOS-C */ +/* */ +/* move kernel to HMA area */ +/* */ +/* Copyright (c) 2001 */ +/* tom ehlert */ +/* 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. */ +/****************************************************************/ + +/* + current status: + + load FreeDOS high, if DOS=HIGH detected + + suppress High Loading, if any SHIFT status detected (for debugging) + + if no XMS driver (HIMEM,FDXMS,...) loaded, should work + + cooperation with XMS drivers as follows: + + copy HMA_TEXT segment up. + + after each loaded DEVICE=SOMETHING.SYS, try to request the HMA + (XMS function 0x01). + if no XMS driver detected, during ONFIG.SYS processing, + create a dummy VDISK entry in high memory + + this works with + + FD FDXMS - no problems detected + + + MS HIMEM.SYS (from DOS 6.2, 9-30-93) + + works if and only if + + /TESTMEM:OFF + + is given + + otherwise HIMEM will TEST AND ZERO THE HIGH MEMORY+HMA. + so, in CONFIG.C, if "HIMEM.SYS" is detected, a "/TESTMEM:OFF" + parameter is forced. +*/ + +#include "portab.h" +#include "init-mod.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: inithma.c 956 2004-05-24 17:07:04Z bartoldeman $"; +#endif + +BYTE DosLoadedInHMA BSS_INIT(FALSE); /* set to TRUE if loaded HIGH */ +BYTE HMAclaimed BSS_INIT(0); /* set to TRUE if claimed from HIMEM */ +UWORD HMAFree BSS_INIT(0); /* first byte in HMA not yet used */ + +STATIC void InstallVDISK(void); + +#ifdef DEBUG +#ifdef __TURBOC__ +#define int3() __int__(3); +#else +void int3() +{ + __asm int 3; +} +#endif +#else +#define int3() +#endif + +#ifdef DEBUG +#define HMAInitPrintf(x) printf x +#else +#define HMAInitPrintf(x) +#endif + +#ifdef DEBUG +VOID hdump(BYTE FAR * p) +{ + int loop; + HMAInitPrintf(("%p", p)); + + for (loop = 0; loop < 16; loop++) + HMAInitPrintf(("%02x ", p[loop])); + + printf("\n"); +} +#else +#define hdump(ptr) +#endif + +#define KeyboardShiftState() (*(BYTE FAR *)(MK_FP(0x40,0x17))) + +/* + this tests, if the HMA area can be enabled. + if so, it simply leaves it on +*/ + +STATIC int EnabledA20(void) +{ + return fmemcmp(MK_FP(0, 0), MK_FP(0xffff, 0x0010), 128); +} + +int EnableHMA(VOID) +{ + + _EnableA20(); + + if (!EnabledA20()) + { + printf("HMA can't be enabled\n"); + return FALSE; + } + + _DisableA20(); + +#ifdef DEBUG + if (EnabledA20()) + { + printf("HMA can't be disabled - no problem for us\n"); + } +#endif + + _EnableA20(); + if (!EnabledA20()) + { + printf("HMA can't be enabled second time\n"); + return FALSE; + } + + HMAInitPrintf(("HMA success - leaving enabled\n")); + + return TRUE; + +} + +/* + move the kernel up to high memory + this is very unportable + + if we thin we succeeded, we return TRUE, else FALSE +*/ + +#define HMAOFFSET 0x20 +#define HMASEGMENT 0xffff + +int MoveKernelToHMA() +{ + void far *xms_addr; + + if (DosLoadedInHMA) + { + return TRUE; + } + + if ((xms_addr = DetectXMSDriver()) == NULL) + return FALSE; + + XMSDriverAddress = xms_addr; + +#ifdef DEBUG + /* A) for debugging purpose, suppress this, + if any shift key is pressed + */ + if (KeyboardShiftState() & 0x0f) + { + printf("Keyboard state is %0x, NOT moving to HMA\n", + KeyboardShiftState()); + return FALSE; + } +#endif + + /* B) check out, if we can have HMA */ + + if (!EnableHMA()) + { + printf("Can't enable HMA area (the famous A20), NOT moving to HMA\n"); + + return FALSE; + } + + /* allocate HMA through XMS driver */ + + if (HMAclaimed == 0 && + (HMAclaimed = + init_call_XMScall(xms_addr, 0x0100, 0xffff)) == 0) + { + printf("Can't reserve HMA area ??\n"); + + return FALSE; + } + + MoveKernel(0xffff); + + { + /* E) up to now, nothing really bad was done. + but now, we reuse the HMA area. bad things will happen + + to find bugs early, + cause INT 3 on all accesses to this area + */ + + DosLoadedInHMA = TRUE; + } + + /* + on finalize, will install a VDISK + */ + + InstallVDISK(); + + /* report the fact we are running high through int 21, ax=3306 */ + LoL->version_flags |= 0x10; + + return TRUE; + +} + +/* + now protect against HIMEM/FDXMS/... by simulating a VDISK + FDXMS should detect us and not give HMA access to ohers + unfortunately this also disables HIMEM completely + + so: we install this after all drivers have been loaded +*/ +STATIC void InstallVDISK(void) +{ + static struct { /* Boot-Sektor of a RAM-Disk */ + UBYTE dummy1[3]; /* HIMEM.SYS uses 3, but FDXMS uses 2 */ + char Name[5]; + BYTE dummy2[3]; + WORD BpS; + BYTE dummy3[6]; + WORD Sektoren; + BYTE dummy4; + } VDISK_BOOT_SEKTOR = { + { + 0xcf, ' ', ' '}, + { + 'V', 'D', 'I', 'S', 'K'}, + { + ' ', ' ', ' '}, 512, + { + 'F', 'D', 'O', 'S', ' ', ' '}, 128, /* 128*512 = 64K */ + ' '}; + + if (!DosLoadedInHMA) + return; + + fmemcpy(MK_FP(0xffff, 0x0010), &VDISK_BOOT_SEKTOR, + sizeof(VDISK_BOOT_SEKTOR)); + + *(WORD FAR *) MK_FP(0xffff, 0x002e) = 1024 + 64; +} + +/* + this allocates some bytes from the HMA area + only available if DOS=HIGH was successful +*/ + +VOID FAR * HMAalloc(COUNT bytesToAllocate) +{ + VOID FAR *HMAptr; + + if (!DosLoadedInHMA) + return NULL; + + if (HMAFree > 0xfff0 - bytesToAllocate) + return NULL; + + HMAptr = MK_FP(0xffff, HMAFree); + + /* align on 16 byte boundary */ + HMAFree = (HMAFree + bytesToAllocate + 0xf) & 0xfff0; + + /*printf("HMA allocated %d byte at %x\n", bytesToAllocate, HMAptr); */ + + fmemset(HMAptr, 0, bytesToAllocate); + + return HMAptr; +} + +unsigned CurrentKernelSegment = 0; + +void MoveKernel(unsigned NewKernelSegment) +{ + UBYTE FAR *HMADest; + UBYTE FAR *HMASource; + unsigned len; + unsigned jmpseg = CurrentKernelSegment; + + if (CurrentKernelSegment == 0) + CurrentKernelSegment = FP_SEG(_HMATextEnd); + + if (CurrentKernelSegment == 0xffff) + return; + + HMASource = + MK_FP(CurrentKernelSegment, (FP_OFF(_HMATextStart) & 0xfff0)); + HMADest = MK_FP(NewKernelSegment, 0x0000); + + len = (FP_OFF(_HMATextEnd) | 0x000f) - (FP_OFF(_HMATextStart) & 0xfff0); + + if (NewKernelSegment == 0xffff) + { + HMASource += HMAOFFSET; + HMADest += HMAOFFSET; + len -= HMAOFFSET; + } + + HMAInitPrintf(("HMA moving %p up to %p for %04x bytes\n", + HMASource, HMADest, len)); + + if (NewKernelSegment < CurrentKernelSegment || + NewKernelSegment == 0xffff) + fmemcpy(HMADest, HMASource, len); + /* else it's the very first relocation: handled by kernel.asm */ + + HMAFree = (FP_OFF(HMADest) + len + 0xf) & 0xfff0; + /* first free byte after HMA_TEXT on 16 byte boundary */ + + { + /* D) but it only makes sense, if we can relocate + all our entries to make use of HMA + */ + + /* this is for a + call near enableA20 + jmp far kernelentry + style table + */ + + struct RelocationTable FAR *rp, rtemp; + + /* verify, that all entries are valid */ + + for (rp = _HMARelocationTableStart; rp < _HMARelocationTableEnd; rp++) + { + if (rp->jmpFar != 0xea || /* jmp FAR */ + rp->jmpSegment != jmpseg || /* will only relocate HMA_TEXT */ + rp->callNear != 0xe8 || /* call NEAR */ + 0) + { + printf("illegal relocation entry # %d\n", + (FP_OFF(rp) - + FP_OFF(_HMARelocationTableStart)) / + sizeof(struct RelocationTable)); + int3(); + goto errorReturn; + } + } + + /* OK, all valid, go to relocate */ + + for (rp = _HMARelocationTableStart; rp < _HMARelocationTableEnd; rp++) + { + if (NewKernelSegment == 0xffff) + { + struct RelocatedEntry FAR *rel = (struct RelocatedEntry FAR *)rp; + + fmemcpy(&rtemp, rp, sizeof(rtemp)); + + rel->jmpFar = rtemp.jmpFar; + rel->jmpSegment = NewKernelSegment; + rel->jmpOffset = rtemp.jmpOffset; + rel->callNear = rtemp.callNear; + rel->callOffset = rtemp.callOffset + 5; /* near calls are relative */ + } + else + rp->jmpSegment = NewKernelSegment; + + } + + if (NewKernelSegment == 0xffff) + { + /* jmp far cpm_entry (copy from 0:c0) */ + pokeb(0xffff, 0x30 * 4 + 0x10, 0xea); + pokel(0xffff, 0x30 * 4 + 0x11, (ULONG)cpm_entry); + } + } + + CurrentKernelSegment = NewKernelSegment; + return; + +errorReturn: + for (;;) ; +} + diff --git a/kernel/initoem.c b/kernel/initoem.c new file mode 100644 index 0000000..2b0b0fa --- /dev/null +++ b/kernel/initoem.c @@ -0,0 +1,73 @@ +/****************************************************************/ +/* */ +/* initoem.c */ +/* */ +/* OEM Initializattion Functions */ +/* */ +/* 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. */ +/* */ +/****************************************************************/ + +#include "portab.h" +#include "init-mod.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: initoem.c 1321 2007-05-21 02:16:36Z bartoldeman $"; +#endif + +#define EBDASEG 0x40e +#define RAMSIZE 0x413 + +unsigned init_oem(void) +{ + iregs r; + init_call_intr(0x12, &r); + return r.a.x; +} + +void movebda(size_t bytes, unsigned new_seg) +{ + unsigned old_seg = peek(0, EBDASEG); + fmemcpy(MK_FP(new_seg, 0), MK_FP(old_seg, 0), bytes); + poke(0, EBDASEG, new_seg); + poke(0, RAMSIZE, ram_top); +} + +unsigned ebdasize(void) +{ + unsigned ebdaseg = peek(0, EBDASEG); + unsigned ramsize = ram_top; + + if (ramsize == peek(0, RAMSIZE)) + if (ramsize * 64 == ebdaseg && ramsize < 640 && peek(0, RAMSIZE) == ramsize) + { + unsigned ebdasz = peekb(ebdaseg, 0); + + /* sanity check: is there really no more than 63 KB? + * must be at 640k (all other values never seen and are untested) + */ + if (ebdasz <= 63 && ramsize + ebdasz == 640) + return ebdasz * 1024U; + } + return 0; +} diff --git a/kernel/int2f.asm b/kernel/int2f.asm new file mode 100644 index 0000000..4f20bd7 --- /dev/null +++ b/kernel/int2f.asm @@ -0,0 +1,539 @@ +; +; File: +; int2f.asm +; Description: +; multiplex interrupt support code +; +; Copyright (c) 1996, 1998 +; 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. +; +; $Id: int2f.asm 1591 2011-05-06 01:46:55Z bartoldeman $ +; + + %include "segs.inc" + %include "stacks.inc" + +segment HMA_TEXT + extern _cu_psp:wrt DGROUP + extern _HaltCpuWhileIdle:wrt DGROUP + extern _syscall_MUX14 + + extern _DGROUP_ + + global reloc_call_int2f_handler +reloc_call_int2f_handler: + sti ; Enable interrupts + cmp ah,11h ; Network interrupt? + jne Int2f3 ; No, continue +Int2f1: + or al,al ; Installation check? + jz FarTabRetn ; yes, just return +Int2f2: + mov ax,1 ; TE 07/13/01 + ; at least for redirected INT21/5F44 + ; --> 2f/111e + ; the error code is AX=0001 = unknown function + stc +FarTabRetn: + retf 2 ; Return far + +WinIdle: ; only HLT if at haltlevel 2+ + push ds + mov ds, [cs:_DGROUP_] + cmp byte [_HaltCpuWhileIdle],2 + pop ds + jb FarTabRetn + pushf + sti + hlt ; save some energy :-) + popf + push ds + mov ds, [cs:_DGROUP_] + cmp byte [_HaltCpuWhileIdle],3 + pop ds + jb FarTabRetn + mov al,0 ; even admit we HLTed ;-) + jmp short FarTabRetn + +Int2f3: cmp ax,1680h ; Win "release time slice" + je WinIdle + cmp ah,16h + je FarTabRetn ; other Win Hook return fast + cmp ah,12h + je IntDosCal ; Dos Internal calls + + cmp ax,4a01h + je IntDosCal ; Dos Internal calls + cmp ax,4a02h + je IntDosCal ; Dos Internal calls +%ifdef WITHFAT32 + cmp ax,4a33h ; Check DOS version 7 + jne Check4Share + xor ax,ax ; no undocumented shell strings + iret +Check4Share: +%endif + cmp ah,10h ; SHARE.EXE interrupt? + je Int2f1 ; yes, do installation check + cmp ah,08h + je DriverSysCal ; DRIVER.SYS calls + cmp ah,14h ; NLSFUNC.EXE interrupt? + jne Int2f?iret ; yes, do installation check +Int2f?14: ;; MUX-14 -- NLSFUNC API + ;; all functions are passed to syscall_MUX14 + push bp ; Preserve BP later on + Protect386Registers + PUSH$ALL + mov ds, [cs:_DGROUP_] + call _syscall_MUX14 + pop bp ; Discard incoming AX + push ax ; Correct stack for POP$ALL + POP$ALL + Restore386Registers + mov bp, sp + or ax, ax + jnz Int2f?14?1 ; must return set carry + ;; -6 == -2 (CS), -2 (IP), -2 (flags) + ;; current SP = on old_BP + and BYTE [bp-6], 0feh ; clear carry as no error condition + pop bp + iret +Int2f?14?1: or BYTE [bp-6], 1 + pop bp +Int2f?iret: + iret + +; DRIVER.SYS calls - now only 0803. +DriverSysCal: + extern _Dyn:wrt DGROUP + cmp al, 3 + jne Int2f?iret + mov ds, [cs:_DGROUP_] + mov di, _Dyn+2 + jmp short Int2f?iret + + +;********************************************************************** +; internal dos calls INT2F/12xx and INT2F/4A01,4A02 - handled through C +;********************************************************************** +IntDosCal: + ; set up register frame +;struct int2f12regs +;{ +; [space for 386 regs] +; UWORD es,ds; +; UWORD di,si,bp,bx,dx,cx,ax; +; UWORD ip,cs,flags; +; UWORD callerARG1; +;} + push ax + push cx + push dx + push bx + push bp + push si + push di + push ds + push es + + cld + +%if XCPU >= 386 + %ifdef WATCOM + mov si,fs + mov di,gs + %else + Protect386Registers + %endif +%endif + + mov ds,[cs:_DGROUP_] + extern _int2F_12_handler + call _int2F_12_handler + +%if XCPU >= 386 + %ifdef WATCOM + mov fs,si + mov gs,di + %else + Restore386Registers + %endif +%endif + + pop es + pop ds + pop di + pop si + pop bp + pop bx + pop dx + pop cx + pop ax + + iret + + global SHARE_CHECK +SHARE_CHECK: + mov ax, 0x1000 + int 0x2f + ret + +; DOS calls this to see if it's okay to open the file. +; Returns a file_table entry number to use (>= 0) if okay +; to open. Otherwise returns < 0 and may generate a critical +; error. If < 0 is returned, it is the negated error return +; code, so DOS simply negates this value and returns it in +; AX. +; STATIC int share_open_check(char * filename, +; /* pointer to fully qualified filename */ +; unsigned short pspseg, +; /* psp segment address of owner process */ +; int openmode, +; /* 0=read-only, 1=write-only, 2=read-write */ +; int sharemode) /* SHARE_COMPAT, etc... */ + global SHARE_OPEN_CHECK +SHARE_OPEN_CHECK: + mov es, si ; save si + pop ax ; return address + pop dx ; sharemode; + pop cx ; openmode; + pop bx ; pspseg; + pop si ; filename + push ax ; return address + mov ax, 0x10a0 + int 0x2f ; returns ax + mov si, es ; restore si + ret + +; DOS calls this to record the fact that it has successfully +; closed a file, or the fact that the open for this file failed. +; STATIC void share_close_file(int fileno) /* file_table entry number */ + + global SHARE_CLOSE_FILE +SHARE_CLOSE_FILE: + pop ax + pop bx + push ax + mov ax, 0x10a1 + int 0x2f + ret + +; DOS calls this to determine whether it can access (read or +; write) a specific section of a file. We call it internally +; from lock_unlock (only when locking) to see if any portion +; of the requested region is already locked. If pspseg is zero, +; then it matches any pspseg in the lock table. Otherwise, only +; locks which DO NOT belong to pspseg will be considered. +; Returns zero if okay to access or lock (no portion of the +; region is already locked). Otherwise returns non-zero and +; generates a critical error (if allowcriter is non-zero). +; If non-zero is returned, it is the negated return value for +; the DOS call. +;STATIC int share_access_check(unsigned short pspseg, +; /* psp segment address of owner process */ +; int fileno, /* file_table entry number */ +; unsigned long ofs, /* offset into file */ +; unsigned long len, /* length (in bytes) of region to access */ +; int allowcriter) /* allow a critical error to be generated */ + global SHARE_ACCESS_CHECK +SHARE_ACCESS_CHECK: + mov ax, 0x10a2 +share_common: + push bp + mov bp, sp + push si + push di + mov bx, [bp + 16] ; pspseg + mov cx, [bp + 14] ; fileno + mov si, [bp + 12] ; high word of ofs + mov di, [bp + 10] ; low word of ofs + les dx, [bp + 6] ; len + or ax, [bp + 4] ; allowcriter/unlock + int 0x2f + pop di + pop si + pop bp + ret 14 ; returns ax + +; DOS calls this to lock or unlock a specific section of a file. +; Returns zero if successfully locked or unlocked. Otherwise +; returns non-zero. +; If the return value is non-zero, it is the negated error +; return code for the DOS 0x5c call. */ +;STATIC int share_lock_unlock(unsigned short pspseg, /* psp segment address of owner process */ +; int fileno, /* file_table entry number */ +; unsigned long ofs, /* offset into file */ +; unsigned long len, /* length (in bytes) of region to lock or unlock */ +; int unlock) /* one to unlock; zero to lock */ + global SHARE_LOCK_UNLOCK +SHARE_LOCK_UNLOCK: + mov ax,0x10a4 + jmp short share_common + +; Int 2F Multipurpose Remote System Calls +; +; added by James Tabor jimtabor@infohwy.com +; changed by Bart Oldeman +; +; assume ss == ds after setup of stack in entry +; sumtimes return data *ptr is the push stack word +; + +remote_lseek: ; arg is a pointer to the long seek value + mov bx, cx + mov dx, [bx] + mov cx, [bx+2] + ; "fall through" + +remote_getfattr: + clc ; set to succeed + int 2fh + jc ret_neg_ax + jmp short ret_int2f + +remote_lock_unlock: + mov dx, cx ; parameter block (dx) in arg + mov bx, cx + mov bl, [bx + 8] ; unlock or not + mov cx, 1 + int 0x2f + jnc ret_set_ax_to_carry + mov ah, 0 + jmp short ret_neg_ax + +;long ASMPASCAL network_redirector_mx(unsigned cmd, void far *s, void *arg) + global NETWORK_REDIRECTOR_MX +NETWORK_REDIRECTOR_MX: + pop bx ; ret address + pop cx ; stack value (arg); cx in remote_rw + pop dx ; off s + pop es ; seg s + pop ax ; cmd (ax) + push bx ; ret address +call_int2f: + push bp + push si + push di + cmp al, 0fh + je remote_getfattr + + mov di, dx ; es:di -> s and dx is used for 1125! + cmp al, 08h + je remote_rw + cmp al, 09h + je remote_rw + cmp al, 0ah + je remote_lock_unlock + cmp al, 21h + je remote_lseek + cmp al, 22h + je remote_process_end + cmp al, 23h + je qremote_fn + + push cx ; arg + cmp al, 0ch + je remote_getfree + cmp al, 1eh + je remote_print_doredir + cmp al, 1fh + je remote_print_doredir + +int2f_call: + xor cx, cx ; set to succeed; clear carry and CX + int 2fh + pop bx + jnc ret_set_ax_to_cx +ret_neg_ax: + neg ax +ret_int2f: + pop di + pop si + pop bp + ret + +ret_set_ax_to_cx: ; ext_open or rw -> status from CX in AX + ; otherwise CX was set to zero above + xchg ax, cx ; set ax:=cx (one byte shorter than mov) + jmp short ret_int2f + +remote_print_doredir: ; di points to an lregs structure + mov es,[di+0xe] + mov bx,[di+2] + mov cx,[di+4] + mov dx,[di+6] + mov si,[di+8] + lds di,[di+0xa] + + clc ; set to succeed + int 2fh + pop bx ; restore stack and ds=ss + push ss + pop ds + jc ret_neg_ax +ret_set_ax_to_carry: ; carry => -1 else 0 (SUCCESS) + sbb ax, ax + jmp short ret_int2f + +remote_getfree: + clc ; set to succeed + int 2fh + pop di ; retrieve pushed pointer arg + jc ret_set_ax_to_carry + mov [di],ax + mov [di+2],bx + mov [di+4],cx + mov [di+6],dx + jmp short ret_set_ax_to_carry + +remote_rw: + clc ; set to succeed + int 2fh + jc ret_min_dx_ax + xor dx, dx ; dx:ax := dx:cx = bytes read + jmp short ret_set_ax_to_cx +ret_min_dx_ax: neg ax + cwd + jmp short ret_int2f + +qremote_fn: + mov bx, cx + lds si, [bx] + jmp short int2f_restore_ds + +remote_process_end: ; Terminate process + mov ds, [_cu_psp] +int2f_restore_ds: + clc + int 2fh + push ss + pop ds + jmp short ret_set_ax_to_carry + +; extern UWORD ASMPASCAL call_nls(UWORD bp, UWORD FAR *buf, +; UWORD subfct, UWORD cp, UWORD cntry, UWORD bufsize); + + extern _nlsInfo:wrt DGROUP + global CALL_NLS +CALL_NLS: + pop es ; ret addr + pop cx ; bufsize + pop dx ; cntry + pop bx ; cp + pop ax ; sub fct + mov ah, 0x14 + push es ; ret addr + push bp + mov bp, sp + push si + push di + mov si, _nlsInfo ; nlsinfo + les di, [bp + 4] ; buf + mov bp, [bp + 8] ; bp + int 0x2f + mov dx, bx ; return id in high word + pop di + pop si + pop bp + ret 6 + +; extern UWORD ASMPASCAL floppy_change(UWORD drives) + + global FLOPPY_CHANGE +FLOPPY_CHANGE: + pop cx ; ret addr + pop dx ; drives + push cx ; ret addr + mov ax, 0x4a00 + xor cx, cx + int 0x2f + mov ax, cx ; return + ret + +; +; Test to see if a umb driver has been loaded. +; if so, retrieve largest available block+size +; +; From RB list and Dosemu xms.c. +; +; Call the XMS driver "Request upper memory block" function with: +; AH = 10h +; DX = size of block in paragraphs +; Return: AX = status +; 0001h success +; BX = segment address of UMB +; DX = actual size of block +; 0000h failure +; BL = error code (80h,B0h,B1h) (see #02775) +; DX = largest available block +; +; (Table 02775) +; Values for XMS error code returned in BL: +; 00h successful +; 80h function not implemented +; B0h only a smaller UMB is available +; B1h no UMBs are available +; B2h UMB segment number is invalid +; + +segment INIT_TEXT + ; int ASMPASCAL UMB_get_largest(void FAR * driverAddress, + ; UCOUNT * seg, UCOUNT * size); + global UMB_GET_LARGEST + +UMB_GET_LARGEST: + push bp + mov bp,sp + + mov dx,0xffff ; go for broke! + mov ax,1000h ; get the UMBs + call far [bp+8] ; Call the driver + +; +; bl = 0xB0 and ax = 0 so do it again. +; + cmp bl,0xb0 ; fail safe + jne umbt_error + + and dx,dx ; if it returns a size of zero. + je umbt_error + + mov ax,1000h ; dx set with largest size + call far [bp+8] ; Call the driver + + cmp ax,1 + jne umbt_error + ; now return the segment + ; and the size + + mov cx,bx ; *seg = segment + mov bx, [bp+6] + mov [bx],cx + + mov bx, [bp+4] ; *size = size + mov [bx],dx + +umbt_ret: + pop bp + ret 8 ; this was called NEAR!! + +umbt_error: xor ax,ax + jmp short umbt_ret diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c new file mode 100644 index 0000000..4a40f70 --- /dev/null +++ b/kernel/inthndlr.c @@ -0,0 +1,2086 @@ +/****************************************************************/ +/* */ +/* 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 1709 2012-02-08 02:13:49Z perditionc $"; +#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) + { + /* Set Ctrl-C flag; returns dl = break_ena */ + case 0x01: + break_ena = irp->DL & 1; + /* fall through so DL only low bit (as in MS-DOS) */ + + /* Get Ctrl-C flag */ + case 0x00: + irp->DL = break_ena; + 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 = 0; /* lower 3 bits revision #, remaining should be 0 */ + 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; + + /* the remaining are FreeDOS extensions */ + + /* set FreeDOS returned version for int 21.30 from BX */ + case 0xfc: + 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; + 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: + case 0x04: + { + ULONG value; + if (!ISFAT32(dpb)) + return DE_INVLDPARM; + + value = xdffp->xdff_f.setget.new; + if ((UWORD) xdffp->xdff_function == 0x03) + { + /* FAT mirroring */ + if (value != 0xFFFFFFFFUL && (value & ~(0xf | 0x80))) + return DE_INVLDPARM; + xdffp->xdff_f.setget.old = dpb->dpb_xflags; + } + else + { + /* root cluster */ + if (value != 0xFFFFFFFFUL && (value < 2 || value > dpb->dpb_xsize)) + return DE_INVLDPARM; + xdffp->xdff_f.setget.old = dpb->dpb_xrootclst; + } + if (value != 0xFFFFFFFFUL) + { + bpb FAR *bpbp; + struct buffer FAR *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]; + if ((UWORD) xdffp->xdff_function == 0x03) + bpbp->bpb_xflags = (UWORD)value; + else + bpbp->bpb_xrootclst = value; + } + goto rebuild_dpb; + } + default: + return DE_INVLDFUNC; + } + + 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; + /* bit 0 of SI is 0 read / 1 write, bits 13/14 indicate a type: */ + /* 0 any, 1 fat, 2 dir, 3 file. Type is mostly for "write hints" */ + + if (r->CX != 0xffff || (r->SI & ~0x6001)) + { + return DE_INVLDPARM; + } + + if (r->DL > lastdrive || r->DL == 0) + return -0x207; + + if ((r->SI & 1) == 0) /* while uncommon, reads CAN have type hints */ + 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 */ + + /* + what happened: + Application does FindFirst("I:\*.*"); + this fails, and causes Int24 + this sets ErrorMode, and calls Int24 + Application decides NOT to return to DOS, + but instead pop the stack and return to itself + (this is legal; see RBIL/INT 24 description + + *) errormode NEVER gets set back to 0 until exit() + + I have NO idea how real DOS handles this; + the appended patch cures the worst symptoms + */ + if (/*ErrorMode && */lr.AH > 0x0c && lr.AH != 0x30 && lr.AH != 0x59) + { + /*if (ErrorMode)*/ ErrorMode = 0; + } + /* 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++) != '$') + write_char_stdout(c); + + lr.AL = c; + } + break; + + /* Buffered Keyboard Input */ + case 0x0a: + DOS_0A: + read_line(get_sft_idx(STDIN), get_sft_idx(STDOUT), FP_DS_DX); + break; + + /* Check Stdin Status */ + case 0x0b: + lr.AL = 0xFF; + if (StdinBusy()) + lr.AL = 0x00; + break; + + /* Flush Buffer, Read Keyboard */ + case 0x0c: + { + struct dhdr FAR *dev = sft_to_dev(get_sft(STDIN)); + if (dev) + con_flush(&dev); + switch (lr.AL) + { + case 0x01: goto DOS_01; + case 0x06: goto DOS_06; + case 0x07: goto DOS_07; + case 0x08: goto DOS_08; + case 0x0a: goto DOS_0A; + } + lr.AL = 0x00; + break; + } + + /* Reset Drive */ + case 0x0d: + flush(); + break; + + /* Set Default Drive */ + case 0x0e: + lr.AL = DosSelectDrv(lr.DL); + break; + + case 0x0f: + lr.AL = FcbOpen(FP_DS_DX, O_FCB | O_LEGACY | O_OPEN | O_RDWR); + break; + + case 0x10: + lr.AL = FcbClose(FP_DS_DX); + break; + + case 0x11: + lr.AL = FcbFindFirstNext(FP_DS_DX, TRUE); + break; + + case 0x12: + lr.AL = FcbFindFirstNext(FP_DS_DX, FALSE); + break; + + case 0x13: + lr.AL = FcbDelete(FP_DS_DX); + break; + + case 0x14: + /* FCB read */ + lr.AL = FcbReadWrite(FP_DS_DX, 1, XFR_READ); + break; + + case 0x15: + /* FCB write */ + lr.AL = FcbReadWrite(FP_DS_DX, 1, XFR_WRITE); + break; + + case 0x16: + lr.AL = FcbOpen(FP_DS_DX, O_FCB | O_LEGACY | O_CREAT | O_TRUNC | O_RDWR); + break; + + case 0x17: + lr.AL = FcbRename(FP_DS_DX); + break; + + default: +#ifdef DEBUG + printf("Unsupported INT21 AH = 0x%x, AL = 0x%x.\n", lr.AH, lr.AL); +#endif + /* Fall through. */ + + /* CP/M compatibility functions */ + case 0x18: + case 0x1d: + case 0x1e: + case 0x20: +#ifndef TSC + case 0x61: +#endif + case 0x6b: + lr.AL = 0; + break; + + /* Get Default Drive */ + case 0x19: + lr.AL = default_drive; + break; + + /* Set DTA */ + case 0x1a: + dta = FP_DS_DX; + break; + + /* Get Default Drive Data */ + case 0x1b: + lr.DL = 0; + /* fall through */ + + /* Get Drive Data */ + case 0x1c: + { + BYTE FAR *p; + + if ((p = FatGetDrvData(lr.DL, &lr.AL, &lr.CX, &lr.DX)) != NULL) + { + lr.DS = FP_SEG(p); + lr.BX = FP_OFF(p); + } + else + lr.AL = 0xff; /* return 0xff on invalid drive */ + } + break; + + /* Get default DPB */ + /* case 0x1f: see case 0x32 */ + + /* Random read using FCB: fields not updated + (XFR_RANDOM should not be used here) */ + case 0x21: + lr.AL = FcbRandomIO(FP_DS_DX, XFR_READ); + break; + + /* Random write using FCB */ + case 0x22: + lr.AL = FcbRandomIO(FP_DS_DX, XFR_WRITE); + break; + + /* Get file size in records using FCB */ + case 0x23: + lr.AL = FcbGetFileSize(FP_DS_DX); + break; + + /* Set random record field in FCB */ + case 0x24: + FcbSetRandom(FP_DS_DX); + break; + + /* Set Interrupt Vector */ + /* case 0x25: handled above (re-entrant) */ + + /* Dos Create New Psp */ + case 0x26: + new_psp(lr.DX, r->CS); + break; + + /* Read random record(s) using FCB */ + case 0x27: + lr.AL = FcbRandomBlockIO(FP_DS_DX, &lr.CX, XFR_READ | XFR_FCB_RANDOM); + break; + + /* Write random record(s) using FCB */ + case 0x28: + lr.AL = FcbRandomBlockIO(FP_DS_DX, &lr.CX, XFR_WRITE | XFR_FCB_RANDOM); + break; + + /* Parse File Name */ + case 0x29: + lr.SI = FcbParseFname(&lr.AL, MK_FP(lr.DS, lr.SI), FP_ES_DI); + break; + + /* Get Date */ + case 0x2a: + lr.AL = DosGetDate((struct dosdate *)&lr.CX); + break; + + /* Set Date */ + case 0x2b: + lr.AL = DosSetDate ((struct dosdate*)&lr.CX) == SUCCESS ? 0 : 0xFF; + break; + + /* Get Time */ + case 0x2c: + DosGetTime((struct dostime *)&lr.CL); + break; + + /* Set Time */ + case 0x2d: + lr.AL = DosSetTime ((struct dostime*)&lr.CX) == SUCCESS ? 0 : 0xFF; + break; + + /* Set verify flag */ + case 0x2e: + verify_ena = lr.AL & 1; + break; + + /* Get DTA */ + case 0x2f: + lr.BX = FP_OFF(dta); + lr.ES = FP_SEG(dta); + break; + + /* Get (editable) DOS Version */ + case 0x30: + if (lr.AL == 1) /* from RBIL, if AL=1 then return version_flags */ + lr.BH = version_flags; + else + lr.BH = OEM_ID; + lr.AL = os_setver_major; + lr.AH = os_setver_minor; + lr.BL = REVISION_SEQ; + lr.CX = 0; /* do not set this to a serial number! + 32RTM won't like non-zero values */ + + if (ReturnAnyDosVersionExpected) + { + /* TE for testing purpose only and NOT + to be documented: + return programs, who ask for version == XX.YY + exactly this XX.YY. + this makes most MS programs more happy. + */ + UBYTE FAR *retp = MK_FP(r->cs, r->ip); + + if (retp[0] == 0x3d && /* cmp ax, xxyy */ + (retp[3] == 0x75 || retp[3] == 0x74)) /* je/jne error */ + { + lr.AL = retp[1]; + lr.AH = retp[2]; + } + else if (retp[0] == 0x86 && /* xchg al,ah */ + retp[1] == 0xc4 && retp[2] == 0x3d && /* cmp ax, xxyy */ + (retp[5] == 0x75 || retp[5] == 0x74)) /* je/jne error */ + { + lr.AL = retp[4]; + lr.AH = retp[3]; + } + + } + + break; + + /* Keep Program (Terminate and stay resident) */ + case 0x31: + DosMemChange(cu_psp, lr.DX < 6 ? 6 : lr.DX, 0); + return_code = lr.AL | 0x300; + tsr = TRUE; + return_user(); + break; + + /* Get default BPB */ + case 0x1f: + /* Get DPB */ + case 0x32: + /* r->DL is NOT changed by MS 6.22 */ + /* INT21/32 is documented to reread the DPB */ + { + int drv = (lr.DL == 0 || lr.AH == 0x1f) ? default_drive : lr.DL - 1; + struct dpb FAR *dpb = get_dpb(drv); + + if (dpb == NULL) + { + CritErrCode = -DE_INVLDDRV; + lr.AL = 0xFF; + break; + } + /* hazard: no error checking! */ + flush_buffers(dpb->dpb_unit); + dpb->dpb_flags = M_CHANGED; /* force flush and reread of drive BPB/DPB */ + +#ifdef WITHFAT32 + if (media_check(dpb) < 0 || ISFAT32(dpb)) +#else + if (media_check(dpb) < 0) +#endif + { + lr.AL = 0xff; + CritErrCode = -DE_INVLDDRV; + break; + } + lr.DS = FP_SEG(dpb); + lr.BX = FP_OFF(dpb); + lr.AL = 0; + } + + break; +/* + case 0x33: + see int21_syscall +*/ + /* Get InDOS flag */ + case 0x34: + lr.BX = FP_OFF(&InDOS); + lr.ES = FP_SEG(&InDOS); + break; + + /* Get Interrupt Vector */ + /* case 0x35: handled above (reentrant) */ + + /* Dos Get Disk Free Space */ + case 0x36: + lr.AX = DosGetFree(lr.DL, &lr.BX, &lr.CX, &lr.DX); + break; + + /* Undocumented Get/Set Switchar */ + case 0x37: + switch (lr.AL) + { + /* Get switch character */ + case 0x00: + lr.DL = switchar; + lr.AL = 0x00; + break; + + /* Set switch character */ + case 0x01: + switchar = lr.DL; + lr.AL = 0x00; + break; + + default: + goto error_invalid; + } + break; + + /* Get/Set Country Info */ + case 0x38: + { + UWORD cntry = lr.AL; + + if (cntry == 0xff) + cntry = lr.BX; + + if (0xffff == lr.DX) + { + /* Set Country Code */ + rc = DosSetCountry(cntry); + } + else + { + if (cntry == 0) + cntry--; + /* Get Country Information */ + rc = DosGetCountryInformation(cntry, FP_DS_DX); + if (rc >= SUCCESS) + { + /* HACK FIXME */ + if (cntry == (UWORD) - 1) + cntry = 1; + /* END OF HACK */ + lr.AX = lr.BX = cntry; + } + } + goto short_check; + } + + /* Dos Create Directory */ + case 0x39: + /* Dos Remove Directory */ + case 0x3a: + rc = DosMkRmdir(FP_DS_DX, lr.AH); + goto short_check; + + /* Dos Change Directory */ + case 0x3b: + rc = DosChangeDir(FP_DS_DX); + goto short_check; + + /* Dos Create File */ + case 0x3c: + lrc = DosOpen(FP_DS_DX, O_LEGACY | O_RDWR | O_CREAT | O_TRUNC, lr.CL); + goto long_check; + + /* Dos Open */ + case 0x3d: + lrc = DosOpen(FP_DS_DX, O_LEGACY | O_OPEN | lr.AL, 0); + goto long_check; + + /* Dos Close */ + case 0x3e: + rc = DosClose(lr.BX); + goto short_check; + + /* Dos Read */ + case 0x3f: + lrc = DosRead(lr.BX, lr.CX, FP_DS_DX); + goto long_check; + + /* Dos Write */ + case 0x40: + lrc = DosWrite(lr.BX, lr.CX, FP_DS_DX); + goto long_check; + + /* Dos Delete File */ + case 0x41: + rc = DosDelete((BYTE FAR *) FP_DS_DX, D_ALL); + goto short_check; + + /* Dos Seek */ + case 0x42: + if (lr.AL > 2) + goto error_invalid; + lrc = DosSeek(lr.BX, (LONG)((((ULONG) (lr.CX)) << 16) | lr.DX), lr.AL, + &rc); + if (rc == SUCCESS) + { + lr.DX = (UWORD)(lrc >> 16); + lr.AX = (UWORD) lrc; + } + goto short_check; + + /* Get/Set File Attributes */ + case 0x43: + switch (lr.AL) + { + case 0x00: + rc = DosGetFattr((BYTE FAR *) FP_DS_DX); + if (rc >= SUCCESS) + lr.CX = rc; + break; + + case 0x01: + rc = DosSetFattr((BYTE FAR *) FP_DS_DX, lr.CX); + lr.AX = lr.CX; + break; + +#if 0 + case 0x02: + /* get compressed size -> compression not support returns size in clusters */ + /* rc = DosGetClusterCnt((BYTE FAR *) FP_DS_DX); */ + goto error_invalid; +#endif + + case 0xff: /* DOS 7.20 (w98) extended name (128 char length) functions */ + { + switch(lr.CL) + { + /* Dos Create Directory */ + case 0x39: + /* Dos Remove Directory */ + case 0x3a: + rc = DosMkRmdir(FP_DS_DX, lr.AH); + goto short_check; + + /* Dos rename file */ + case 0x56: + rc = DosRename(FP_DS_DX, FP_ES_DI); + goto short_check; + + /* fall through to goto error_invaid */ + } + } + + default: + goto error_invalid; + } + goto short_check; + + /* Device I/O Control */ + case 0x44: + rc = DosDevIOctl(&lr); /* can set critical error code! */ + + if (rc < SUCCESS) + { + lr.AX = -rc; + if (rc != DE_DEVICE && rc != DE_ACCESS) + CritErrCode = lr.AX; + goto error_carry; + } + break; + + /* Duplicate File Handle */ + case 0x45: + lrc = DosDup(lr.BX); + goto long_check; + + /* Force Duplicate File Handle */ + case 0x46: + rc = DosForceDup(lr.BX, lr.CX); + goto short_check; + + /* Get Current Directory */ + case 0x47: + rc = DosGetCuDir(lr.DL, MK_FP(lr.DS, lr.SI)); + lr.AX = 0x0100; /*jpp: from interrupt list */ + goto short_check; + + /* Allocate memory */ + case 0x48: + if ((rc = DosMemAlloc(lr.BX, mem_access_mode, &lr.AX, &lr.BX)) < 0) + { + DosMemLargest(&lr.BX); + if (DosMemCheck() != SUCCESS) + panic("MCB chain corrupted"); + goto error_exit; + } + lr.AX++; /* DosMemAlloc() returns seg of MCB rather than data */ + break; + + /* Free memory */ + case 0x49: + if ((rc = DosMemFree(lr.ES - 1)) < SUCCESS) + { + if (DosMemCheck() != SUCCESS) + panic("MCB chain corrupted"); + goto error_exit; + } + break; + + /* Set memory block size */ + case 0x4a: + if (DosMemCheck() != SUCCESS) + panic("before 4a: MCB chain corrupted"); + + if ((rc = DosMemChange(lr.ES, lr.BX, &lr.BX)) < 0) + { +#if 0 + if (cu_psp == lr.ES) + { + psp FAR *p = MK_FP(cu_psp, 0); + p->ps_size = lr.BX + cu_psp; + } +#endif + if (DosMemCheck() != SUCCESS) + panic("after 4a: MCB chain corrupted"); + goto error_exit; + } + lr.AX = lr.ES; /* Undocumented MS-DOS behaviour expected by BRUN45! */ + break; + + /* Load and Execute Program */ + case 0x4b: + break_flg = FALSE; + + rc = DosExec(lr.AL, MK_FP(lr.ES, lr.BX), FP_DS_DX); + goto short_check; + + /* Terminate Program */ + case 0x00: + lr.AX = 0x4c00; + + /* End Program */ + case 0x4c: + tsr = FALSE; + rc = 0; + if (ErrorMode) + { + ErrorMode = FALSE; + rc = 0x200; + } + else if (break_flg) + { + break_flg = FALSE; + rc = 0x100; + } + return_code = lr.AL | rc; + if (DosMemCheck() != SUCCESS) + panic("MCB chain corrupted"); +#ifdef TSC + StartTrace(); +#endif + return_user(); + break; + + /* Get Child-program Return Value */ + case 0x4d: + lr.AX = return_code; + /* needs to be cleared (RBIL) */ + return_code = 0; + break; + + /* Dos Find First */ + case 0x4e: + /* dta for this call is set on entry. This */ + /* needs to be changed for new versions. */ + rc = DosFindFirst(lr.CX, FP_DS_DX); + lr.AX = 0; + goto short_check; + + /* Dos Find Next */ + case 0x4f: + /* dta for this call is set on entry. This */ + /* needs to be changed for new versions. */ + rc = DosFindNext(); + lr.AX = 0; + goto short_check; +/* + case 0x50: + case 0x51: + see int21_syscall +*/ + /* ************UNDOCUMENTED************************************* */ + /* Get List of Lists */ + case 0x52: + lr.BX = FP_OFF(&DPBp); + lr.ES = FP_SEG(&DPBp); + break; + + case 0x53: + /* DOS 2+ internal - TRANSLATE BIOS PARAMETER BLOCK TO DRIVE PARAM BLOCK */ + bpb_to_dpb((bpb FAR *) MK_FP(lr.DS, lr.SI), + (struct dpb FAR *)MK_FP(lr.ES, r->BP) +#ifdef WITHFAT32 + , (lr.CX == 0x4558 && lr.DX == 0x4152) +#endif + ); + break; + + /* Get verify state */ + case 0x54: + lr.AL = verify_ena; + break; + + /* ************UNDOCUMENTED************************************* */ + /* Dos Create New Psp & set p_size */ + case 0x55: + child_psp(lr.DX, cu_psp, lr.SI); + cu_psp = lr.DX; + break; + + /* Dos Rename */ + case 0x56: + rc = DosRename(FP_DS_DX, FP_ES_DI); + goto short_check; + + /* Get/Set File Date and Time */ + case 0x57: + switch (lr.AL) + { + case 0x00: + rc = DosGetFtime((COUNT) lr.BX, /* Handle */ + &lr.DX, /* FileDate */ + &lr.CX); /* FileTime */ + break; + + case 0x01: + rc = DosSetFtime((COUNT) lr.BX, /* Handle */ + (date) lr.DX, /* FileDate */ + (time) lr.CX); /* FileTime */ + break; + + default: + goto error_invalid; + } + goto short_check; + + /* Get/Set Allocation Strategy */ + case 0x58: + switch (lr.AL) + { + case 0x00: + lr.AL = mem_access_mode; + lr.AH = 0; + break; + + case 0x01: + if (lr.BL > LAST_FIT_U || /* 0x82 */ + (lr.BL & FIT_MASK) > LAST_FIT) /* 0x3f, 0x02 */ + goto error_invalid; + mem_access_mode = lr.BL; + break; + + case 0x02: + lr.AL = uppermem_link; + break; + + case 0x03: + if (uppermem_root != 0xffff) /* always error if not exists */ + { + DosUmbLink(lr.BX); + break; + } + /* else fall through */ + + default: + goto error_invalid; +#ifdef DEBUG + case 0xff: + show_chain(); + break; +#endif + } + break; + + /* Get Extended Error */ + case 0x59: + lr.AX = CritErrCode; + lr.CH = CritErrLocus; + lr.BH = CritErrClass; + lr.BL = CritErrAction; + lr.DI = FP_OFF(CritErrDev); + lr.ES = FP_SEG(CritErrDev); + break; + + /* Create Temporary File */ + case 0x5a: + lrc = DosMkTmp(FP_DS_DX, lr.CX); + goto long_check; + + /* Create New File */ + case 0x5b: + lrc = DosOpen(FP_DS_DX, O_LEGACY | O_RDWR | O_CREAT, lr.CX); + goto long_check; + +/* /// Added for SHARE. - Ron Cemer */ + /* Lock/unlock file access */ + case 0x5c: + rc = DosLockUnlock + (lr.BX, ((unsigned long)lr.CX << 16) | lr.DX, + ((unsigned long)lr.SI << 16) | lr.DI, lr.AL != 0); + if (rc != SUCCESS) + goto error_exit; + break; +/* /// End of additions for SHARE. - Ron Cemer */ + + /* UNDOCUMENTED: server, share.exe and sda function */ + case 0x5d: + switch (lr.AL) + { + /* Remote Server Call */ + case 0x00: + fmemcpy(&lr, FP_DS_DX, sizeof(lr)); + goto dispatch; + + case 0x06: + lr.DS = FP_SEG(internal_data); + lr.SI = FP_OFF(internal_data); + lr.CX = swap_indos - internal_data; + lr.DX = swap_always - internal_data; + CLEAR_CARRY_FLAG(); + break; + + case 0x07: + case 0x08: + case 0x09: + rc = remote_printredir(lr.DX, Int21AX); + CLEAR_CARRY_FLAG(); + if (rc != SUCCESS) + goto error_exit; + break; + + /* Set Extended Error */ + case 0x0a: + { + lregs far *er = FP_DS_DX; + CritErrCode = er->AX; + CritErrDev = MK_FP(er->ES, er->DI); + CritErrLocus = er->CH; + CritErrClass = er->BH; + CritErrAction = er->BL; + CLEAR_CARRY_FLAG(); + break; + } + + default: + CritErrCode = SUCCESS; + goto error_invalid; + } + break; + + case 0x5e: + switch (lr.AL) + { + case 0x00: + lr.CX = get_machine_name(FP_DS_DX); + break; + + case 0x01: + set_machine_name(FP_DS_DX, lr.CX); + break; + + default: + rc = (int)network_redirector_mx(REM_PRINTSET, &lr, (void *)Int21AX); + goto short_check; + } + break; + + case 0x5f: + if (lr.AL == 7 || lr.AL == 8) + { + if (lr.DL < lastdrive) + { + struct cds FAR *cdsp = CDSp + lr.DL; + if (FP_OFF(cdsp->cdsDpb)) /* letter of physical drive? */ + { + cdsp->cdsFlags &= ~CDSPHYSDRV; + if (lr.AL == 7) + cdsp->cdsFlags |= CDSPHYSDRV; + break; + } + } + rc = DE_INVLDDRV; + goto error_exit; + } + else + { + rc = (int)network_redirector_mx(REM_DOREDIRECT, &lr, (void *)Int21AX); + /* the remote function manipulates *r directly !, + so we should not copy lr to r here */ + if (rc != SUCCESS) + { + CritErrCode = -rc; /* Maybe set */ + SET_CARRY_FLAG(); + } + r->AX = -rc; /* okay because we use real_exit */ + goto real_exit; + } + + case 0x60: /* TRUENAME */ + rc = DosTruename(MK_FP(lr.DS, lr.SI), adjust_far(FP_ES_DI)); + lr.AX = rc; + goto short_check; + +#ifdef TSC + /* UNDOCUMENTED: no-op */ + /* */ + /* DOS-C: tsc support */ + case 0x61: +#ifdef DEBUG + switch (lr.AL) + { + case 0x01: + bTraceNext = TRUE; + break; + + case 0x02: + bDumpRegs = FALSE; + break; + } +#endif + lr.AL = 0x00; + break; +#endif + + /* UNDOCUMENTED: return current psp + case 0x62: is in int21_syscall + lr.BX = cu_psp; + break; + */ + + /* UNDOCUMENTED: Double byte and korean tables */ + case 0x63: + { + VOID FAR *p; +#if 0 + /* not really supported, but will pass. */ + lr.AL = 0x00; /*jpp: according to interrupt list */ + /*Bart: fails for PQDI and WATCOM utilities: + use the above again */ +#endif + switch (lr.AL) + { + case 0: + p = DosGetDBCS(); + lr.DS = FP_SEG(p); + lr.SI = FP_OFF(p); + break; + case 1: /* set Korean Hangul input method to DL 0/1 */ + lr.AL = 0xff; /* flag error (AL would be 0 if okay) */ + break; + case 2: /* get Korean Hangul input method setting to DL */ + lr.AL = 0xff; /* flag error, do not set DL */ + break; + default: /* is this the proper way to handle invalid AL? */ + rc = -1; + goto error_exit; + } + break; + } +/* + case 0x64: + see above (invalid) +*/ + + /* Extended country info */ + case 0x65: + switch (lr.AL) + { + case 0x20: /* upcase single character */ + lr.DL = DosUpChar(lr.DL); + break; + case 0x21: /* upcase memory area */ + DosUpMem(FP_DS_DX, lr.CX); + break; + case 0x22: /* upcase ASCIZ */ + DosUpString(FP_DS_DX); + break; + case 0xA0: /* upcase single character of filenames */ + lr.DL = DosUpFChar(lr.DL); + break; + case 0xA1: /* upcase memory area of filenames */ + DosUpFMem(FP_DS_DX, lr.CX); + break; + case 0xA2: /* upcase ASCIZ of filenames */ + DosUpFString(FP_DS_DX); + break; + case 0x23: /* check Yes/No response */ + lr.AX = DosYesNo(lr.DL); + break; + default: +#ifdef NLS_DEBUG + if ((rc = DosGetData(lr.AL, lr.BX, lr.DX, lr.CX, FP_ES_DI)) < 0) + { + printf("DosGetData() := %d\n", rc); + goto error_exit; + } + printf("DosGetData() returned successfully\n"); + break; +#else + rc = DosGetData(lr.AL, lr.BX, lr.DX, lr.CX, FP_ES_DI); + goto short_check; +#endif + } + break; + + /* Code Page functions */ + case 0x66: + switch (lr.AL) + { + case 1: + rc = DosGetCodepage(&lr.BX, &lr.DX); + break; + case 2: + rc = DosSetCodepage(lr.BX, lr.DX); + break; + + default: + goto error_invalid; + } + if (rc != SUCCESS) + goto error_exit; + break; + + /* Set Max file handle count */ + case 0x67: + rc = SetJFTSize(lr.BX); + goto short_check; + + /* Flush file buffer -- COMMIT FILE. */ + case 0x68: + case 0x6a: + rc = DosCommit(lr.BX); + goto short_check; + + /* Get/Set Serial Number */ + case 0x69: + rc = (lr.BL == 0 ? default_drive : lr.BL - 1); + if (lr.AL < 2) + { + if (get_cds(rc) == NULL) + { + rc = DE_INVLDDRV; + goto error_exit; + } + if (get_dpb(rc) != NULL) + { + UWORD saveCX = lr.CX; + lr.CX = lr.AL == 0 ? 0x0866 : 0x0846; + lr.AL = 0x0d; + rc = DosDevIOctl(&lr); + lr.CX = saveCX; + goto short_check; + } + } + goto error_invalid; +/* + case 0x6a: see case 0x68 + case 0x6b: dummy func: return AL=0 +*/ + /* Extended Open-Creat, not fully functional. (bits 4,5,6 of BH) */ + case 0x6c: + /* high nibble must be <= 1, low nibble must be <= 2 */ + if ((lr.DL & 0xef) > 0x2) + goto error_invalid; + lrc = DosOpen(MK_FP(lr.DS, lr.SI), + (lr.BX & 0x70ff) | ((lr.DL & 3) << 8) | + ((lr.DL & 0x10) << 6), lr.CL); + if (lrc >= SUCCESS) + /* action */ + lr.CX = (UWORD)(lrc >> 16); + goto long_check; + + /* case 0x6d and above not implemented : see default; return AL=0 */ + +#ifdef WITHFAT32 + /* LFN functions - fail with "function not supported" error code */ + case 0x71: + lr.AL = 00; + goto error_carry; + + /* DOS 7.0+ FAT32 extended functions */ + case 0x73: + CLEAR_CARRY_FLAG(); + CritErrCode = SUCCESS; + rc = int21_fat32(&lr); + goto short_check; +#endif + +#ifdef WITHLFNAPI + /* FreeDOS LFN helper API functions */ + case 0x74: + { + switch (lr.AL) + { + /* Allocate LFN inode */ + case 0x01: + rc = lfn_allocate_inode(); + break; + /* Free LFN inode */ + case 0x02: + rc = lfn_free_inode(lr.BX); + break; + /* Setup LFN inode */ + case 0x03: + rc = lfn_setup_inode(lr.BX, ((ULONG)lr.CX << 16) | lr.DX, ((ULONG)lr.SI << 16) | lr.DI); + break; + /* Create LFN entries */ + case 0x04: + rc = lfn_create_entries(lr.BX, (lfn_inode_ptr)FP_DS_DX); + break; + /* Read next LFN */ + case 0x05: + rc = lfn_dir_read(lr.BX, (lfn_inode_ptr)FP_DS_DX); + break; + /* Write SFN pointed by LFN inode */ + case 0x06: + rc = lfn_dir_write(lr.BX); + break; + default: + goto error_invalid; + } + lr.AX = rc; + CLEAR_CARRY_FLAG(); + goto short_check; + } +#endif + } + goto exit_dispatch; +long_check: + if (lrc >= SUCCESS) + { + lr.AX = (UWORD)lrc; + goto exit_dispatch; + } + rc = (int)lrc; +short_check: + if (rc < SUCCESS) + goto error_exit; + goto exit_dispatch; +error_invalid: + rc = DE_INVLDFUNC; +error_exit: + lr.AX = -rc; + if (CritErrCode == SUCCESS) + CritErrCode = lr.AX; /* Maybe set */ +error_carry: + SET_CARRY_FLAG(); +exit_dispatch: + fmemcpy(r, &lr, sizeof(lregs) - 4); /* copy lr -> r but exclude flags */ + r->DS = lr.DS; + r->ES = lr.ES; +real_exit:; + +#ifdef DEBUG + if (bDumpRegs) + { + fmemcpy(&error_regs, user_r, sizeof(iregs)); + dump_regs = TRUE; + dump(); + } +#endif +} + +#if 0 + /* No kernel INT-23 handler required no longer -- 1999/04/15 ska */ +/* ctrl-Break handler */ +#pragma argsused +VOID INRPT FAR int23_handler(int es, int ds, int di, int si, int bp, + int sp, int bx, int dx, int cx, int ax, + int ip, int cs, int flags) +{ + tsr = FALSE; + return_mode = 1; + return_code = -1; + mod_sto(CTL_C); + DosMemCheck(); +#ifdef TSC + StartTrace(); +#endif + return_user(); +} +#endif + +struct int25regs { + UWORD es, ds; + UWORD di, si, bp, sp; + UWORD bx, dx, cx, ax; + UWORD flags, ip, cs; +}; + +/* + this function is called from an assembler wrapper function +*/ +VOID ASMCFUNC int2526_handler(WORD mode, struct int25regs FAR * r) +{ + ULONG blkno; + UWORD nblks; + BYTE FAR *buf; + UBYTE drv; + + if (mode == 0x26) + mode = DSKWRITEINT26; + else + mode = DSKREADINT25; + + drv = r->ax; + + if (drv >= lastdrive) + { + r->ax = 0x201; + SET_CARRY_FLAG(); + return; + } + +#ifdef WITHFAT32 + { + struct dpb FAR *dpbp = get_dpb(drv); + if (dpbp != NULL && ISFAT32(dpbp)) + { + r->ax = 0x207; + SET_CARRY_FLAG(); + return; + } + } +#endif + + nblks = r->cx; + blkno = r->dx; + + buf = MK_FP(r->ds, r->bx); + + if (nblks == 0xFFFF) + { + /*struct HugeSectorBlock FAR *lb = MK_FP(r->ds, r->bx); */ + blkno = ((struct HugeSectorBlock FAR *)buf)->blkno; + nblks = ((struct HugeSectorBlock FAR *)buf)->nblks; + buf = ((struct HugeSectorBlock FAR *)buf)->buf; + } + + InDOS++; + + r->ax = dskxfer(drv, blkno, buf, nblks, mode); + + CLEAR_CARRY_FLAG(); + if (r->ax != 0) + { + SET_CARRY_FLAG(); + if (mode == DSKWRITEINT26) + setinvld(drv); + } + --InDOS; +} + +/* +VOID int25_handler(struct int25regs FAR * r) { int2526_handler(DSKREAD,r); } +VOID int26_handler(struct int25regs FAR * r) { int2526_handler(DSKWRITE,r); } +*/ + +#ifdef TSC +STATIC VOID StartTrace(VOID) +{ + if (bTraceNext) + { +#ifdef DEBUG + bDumpRegs = TRUE; +#endif + bTraceNext = FALSE; + } +#ifdef DEBUG + else + bDumpRegs = FALSE; +#endif +} +#endif + +/* this function is called from an assembler wrapper function + and serves the internal dos calls - int2f/12xx and int2f/4a01,4a02. +*/ +struct int2f12regs { +#ifdef I386 +#ifdef __WATCOMC__ + /* UWORD gs, fs; ** GS/FS are protected through SI/DI */ +#else + UWORD high_edx, +#ifdef _MSC_VER + high_ecx, +#else /* __BORLANDC__ */ + high_ebx, +#endif + high_eax; +#endif +#endif + UWORD es, ds; + UWORD di, si, bp; + xreg b, d, c, a; + UWORD ip, cs, flags; + UWORD callerARG1; /* used if called from INT2F/12 */ +}; + +/* WARNING: modifications in `r' are used outside of int2F_12_handler() + * On input r.AX==0x12xx, 0x4A01 or 0x4A02 + */ +VOID ASMCFUNC int2F_12_handler(struct int2f12regs r) +{ + COUNT rc; + long lrc; + + if (r.AH == 0x4a) + { + size_t size = 0, offs = 0xffff; + + r.ES = offs; + if (FP_SEG(firstAvailableBuf) == offs) /* HMA present? */ + { + offs = FP_OFF(firstAvailableBuf); + size = ~offs; /* BX for query HMA */ + if (r.AL == 0x02) /* allocate HMA space */ + { + if (r.BX < size) + size = r.BX; + AllocateHMASpace(offs, offs+size); + firstAvailableBuf += size; + } + } + r.DI = offs; + r.BX = size; + return; + } + + switch (r.AL) + { + case 0x00: /* installation check */ + r.AL = 0xff; + break; + + case 0x03: /* get DOS data segment */ + r.DS = FP_SEG(&nul_dev); + break; + + case 0x06: /* invoke critical error */ + + /* code, drive number, error, device header */ + r.AL = CriticalError(r.callerARG1 >> 8, + (r.callerARG1 & (EFLG_CHAR << 8)) ? 0 : + r.callerARG1 & 0xff, r.DI, MK_FP(r.BP, r.SI)); + break; + + case 0x08: /* decrease SFT reference count */ + { + sft FAR *p = MK_FP(r.ES, r.DI); + + r.AX = p->sft_count; + + if (--p->sft_count == 0) + --p->sft_count; + } + break; + + case 0x0c: /* perform "device open" for device, set owner for FCB */ + + if (lpCurSft->sft_flags & SFT_FDEVICE) + { + request rq; + + rq.r_unit = 0; + rq.r_status = 0; + rq.r_command = C_OPEN; + rq.r_length = sizeof(request); + execrh((request FAR *) & rq, lpCurSft->sft_dev); + } + + /* just do it always, not just for FCBs */ + lpCurSft->sft_psp = cu_psp; + break; + + case 0x0d: /* get dos date/time */ + + r.AX = dos_getdate(); + r.DX = dos_gettime(); + break; + + case 0x11: /* normalise ASCIIZ filename */ + { + char c; + char FAR *s = MK_FP(r.DS, r.SI); + char FAR *t = MK_FP(r.ES, r.DI); + + do + { + c = *s++; + /* uppercase character */ + /* for now, ASCII only because nls.c cannot handle DS!=SS */ + if (c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + else if (c == '/') + c = '\\'; + *t++ = c; + } + while (c); + break; + } + + case 0x12: /* get length of asciiz string */ + + r.CX = fstrlen(MK_FP(r.ES, r.DI)) + 1; + + break; + + case 0x13: + /* uppercase character */ + /* for now, ASCII only because nls.c cannot handle DS!=SS */ + r.AL = (unsigned char)r.callerARG1; + if (r.AL >= 'a' && r.AL <= 'z') + r.AL -= 'a' - 'A'; + break; + + case 0x16: + /* get address of system file table entry - used by NET.EXE + BX system file table entry number ( such as returned from 2F/1220) + returns + ES:DI pointer to SFT entry + BX relative entry number within SFT */ + { + int rel_idx = idx_to_sft_(r.BX); + + if (rel_idx == -1) + { + r.FLAGS |= FLG_CARRY; + break; + } + r.FLAGS &= ~FLG_CARRY; + r.BX = rel_idx; + r.ES = FP_SEG(lpCurSft); + r.DI = FP_OFF(lpCurSft); + break; + } + + case 0x17: /* get current directory structure for drive - used by NET.EXE + STACK: drive (0=A:,1=B,...) + ; returns + ; CF set if error + ; DS:SI pointer to CDS for drive + ; + ; called like + ; push 2 (c-drive) + ; mov ax,1217 + ; int 2f + ; + ; probable use: get sizeof(CDSentry) + */ + { + struct cds FAR *cdsp = get_cds(r.callerARG1 & 0xff); + + if (cdsp == NULL) + { + r.FLAGS |= FLG_CARRY; + break; + } + r.DS = FP_SEG(cdsp); + r.SI = FP_OFF(cdsp); + r.FLAGS &= ~FLG_CARRY; + break; + } + + case 0x18: /* get caller's registers */ + + r.DS = FP_SEG(user_r); + r.SI = FP_OFF(user_r); + break; + + case 0x1b: /* #days in February - valid until 2099. */ + + r.AL = (r.CL & 3) ? 28 : 29; + break; + + case 0x20: /* get job file table entry */ + { + psp FAR *p = MK_FP(cu_psp, 0); + unsigned char FAR *idx; + + if (r.BX >= p->ps_maxfiles) + { + r.AL = -DE_INVLDHNDL; + r.FLAGS |= FLG_CARRY; + break; + } + idx = &p->ps_filetab[r.BX]; + r.FLAGS &= ~FLG_CARRY; + r.ES = FP_SEG(idx); + r.DI = FP_OFF(idx); + } + break; + + case 0x21: /* truename */ + + DosTruename(MK_FP(r.DS, r.SI), MK_FP(r.ES, r.DI)); + + break; + + case 0x23: /* check if character device */ + { + struct dhdr FAR *dhp; + + dhp = IsDevice((BYTE FAR *) DirEntBuffer.dir_name); + + if (dhp == NULL) + { + r.FLAGS |= FLG_CARRY; + break; + } + r.BH = dhp->dh_attr; + r.FLAGS &= ~FLG_CARRY; + } + break; + + case 0x25: /* get length of asciiz string */ + + r.CX = fstrlen(MK_FP(r.DS, r.SI)) + 1; + break; + + case 0x26: /* open file */ + r.FLAGS &= ~FLG_CARRY; + CritErrCode = SUCCESS; + lrc = DosOpen(MK_FP(r.DS, r.DX), O_LEGACY | O_OPEN | r.CL, 0); + goto long_check; + + case 0x27: /* close file */ + r.FLAGS &= ~FLG_CARRY; + CritErrCode = SUCCESS; + rc = DosClose(r.BX); + goto short_check; + + case 0x28: /* move file pointer */ + /* + * RBIL says: "sets user stack frame pointer to dummy buffer, + * moves BP to AX, performs LSEEK, and restores frame pointer" + * We obviously don't do it like that. Does this do any harm?! --L.G. + */ + r.FLAGS &= ~FLG_CARRY; + CritErrCode = SUCCESS; + if (r.BP < 0x4200 || r.BP > 0x4202) + goto error_invalid; + lrc = DosSeek(r.BX, MK_ULONG(r.CX, r.DX), r.BP & 0xff, &rc); + if (rc == SUCCESS) + { + r.DX = (UWORD)(lrc >> 16); + r.AX = (UWORD) lrc; + } + goto short_check; + + case 0x29: /* read from file */ + r.FLAGS &= ~FLG_CARRY; + CritErrCode = SUCCESS; + lrc = DosRead(r.BX, r.CX, MK_FP(r.DS, r.DX)); + goto long_check; + + case 0x2a: /* Set FastOpen but does nothing. */ + + r.FLAGS &= ~FLG_CARRY; + break; + + case 0x2b: /* Device I/O Control */ + if (r.BP < 0x4400 || r.BP > 0x44ff) + goto error_invalid; + { + lregs lr; + lr.AX = r.BP; + lr.BX = r.BX; + lr.CX = r.CX; + lr.DX = r.DX; + lr.DI = r.DI; + lr.SI = r.SI; + lr.DS = r.DS; + rc = DosDevIOctl(&lr); /* can set critical error code! */ + } + + if (rc < SUCCESS) + { + r.AX = -rc; + if (rc != DE_DEVICE && rc != DE_ACCESS) + CritErrCode = r.AX; + goto error_carry; + } + break; + + case 0x2c: /* added by James Tabor For Zip Drives + Return Null Device Pointer */ + /* by UDOS+RBIL: get header of SECOND device driver in device chain, + omitting the NUL device TE */ + r.BX = FP_SEG(nul_dev.dh_next); + r.AX = FP_OFF(nul_dev.dh_next); + break; + + case 0x2d: /* Get Extended Error Code */ + r.AX = CritErrCode; + + break; + + case 0x2e: /* GET or SET error table addresse - ignored + called by MS debug with DS != DOSDS, printf + doesn't work!! */ + break; + + case 0x2f: + if (r.DX) + { + os_setver_major = r.DL; + os_setver_minor = r.DH; + } + else + { + os_setver_major = os_major; + os_setver_minor = os_minor; + } + break; + + default: + if (r.AL <= 0x31) + { + put_string("unimplemented internal dos function INT2F/12"); + put_unsigned(r.AL, 16, 2); + put_string("\n"); + r.FLAGS |= FLG_CARRY; + } + } + return; +long_check: + if (lrc >= SUCCESS) + { + r.AX = (UWORD)lrc; + return; + } + rc = (int)lrc; +short_check: + if (rc < SUCCESS) + goto error_exit; + return; +error_invalid: + rc = DE_INVLDFUNC; +error_exit: + r.AX = -rc; + if (CritErrCode == SUCCESS) + CritErrCode = r.AX; /* Maybe set */ +error_carry: + r.FLAGS |= FLG_CARRY; +} + +/* + * 2000/09/04 Brian Reifsnyder + * Modified interrupts 0x25 & 0x26 to return more accurate error codes. + */ + diff --git a/kernel/intr.asm b/kernel/intr.asm new file mode 100644 index 0000000..423bf9c --- /dev/null +++ b/kernel/intr.asm @@ -0,0 +1,324 @@ +; File: +; intr.asm +; Description: +; Assembly implementation of calling an interrupt +; +; Copyright (c) 2000 +; Steffen Kaiser +; All Rights Reserved +; +; This file is part of FreeDOS. +; +; FreeDOS 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, Inc., +; 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +; + + %include "segs.inc" + +%macro INTR 0 + + push bp ; Standard C entry + mov bp,sp + push si + push di +%ifdef WATCOM + push bx + push cx + push dx + push es +%endif + push ds + + mov ax, [bp+6] ; interrupt number + mov [cs:%%intr_1-1], al + jmp short %%intr_2 ; flush the instruction cache +%%intr_2 mov bx, [bp+4] ; regpack structure + mov ax, [bx] + mov cx, [bx+4] + mov dx, [bx+6] + mov si, [bx+8] + mov di, [bx+10] + mov bp, [bx+12] + push word [bx+14] ; ds + mov es, [bx+16] + mov bx, [bx+2] + pop ds + int 0 +%%intr_1: + + pushf + push ds + push bx + mov bx, sp + mov ds, [ss:bx+6] +%ifdef WATCOM + mov bx, [ss:bx+24] ; address of REGPACK +%else + mov bx, [ss:bx+16] ; address of REGPACK +%endif + mov [bx], ax + pop word [bx+2] + mov [bx+4], cx + mov [bx+6], dx + mov [bx+8], si + mov [bx+10], di + mov [bx+12], bp + pop word [bx+14] + mov [bx+16], es + pop word [bx+22] + + pop ds +%ifdef WATCOM + pop es + pop dx + pop cx + pop bx +%endif + pop di + pop si + pop bp + ret 4 +%endmacro + +segment HMA_TEXT + +;; COUNT ASMPASCAL res_DosExec(COUNT mode, exec_blk * ep, BYTE * lp) + global RES_DOSEXEC +RES_DOSEXEC: + pop es ; ret address + pop dx ; filename + pop bx ; exec block + pop ax ; mode + push es ; ret address + mov ah, 4bh + push ds + pop es ; es = ds + int 21h + jc short no_exec_error + xor ax, ax +no_exec_error: + ret + +;; UCOUNT ASMPASCAL res_read(int fd, void *buf, UCOUNT count); + global RES_READ +RES_READ: + pop ax ; ret address + pop cx ; count + pop dx ; buf + pop bx ; fd + push ax ; ret address + mov ah, 3fh + int 21h + jnc no_read_error + mov ax, -1 +no_read_error: + ret + +segment INIT_TEXT +; +; void init_call_intr(nr, rp) +; REG int nr +; REG struct REGPACK *rp +; + global INIT_CALL_INTR +INIT_CALL_INTR: + INTR + +; +; int init_call_XMScall( (WORD FAR * driverAddress)(), WORD AX, WORD DX) +; +; this calls HIMEM.SYS +; + global INIT_CALL_XMSCALL +INIT_CALL_XMSCALL: + pop bx ; ret address + pop dx + pop ax + pop cx ; driver address + pop es + + push cs ; ret address + push bx + push es ; driver address ("jmp es:cx") + push cx + retf + +; void FAR *DetectXMSDriver(VOID) +global DETECTXMSDRIVER +DETECTXMSDRIVER: + mov ax, 4300h + int 2fh ; XMS installation check + + cmp al, 80h + je detected + xor ax, ax + xor dx, dx + ret + +detected: + push es + push bx + mov ax, 4310h ; XMS get driver address + int 2fh + + mov ax, bx + mov dx, es + pop bx + pop es + ret + +global KEYCHECK +KEYCHECK: + mov ah, 1 + int 16h + ret + +;; int open(const char *pathname, int flags); + global INIT_DOSOPEN +INIT_DOSOPEN: + ;; init calling DOS through ints: + pop bx ; ret address + pop ax ; flags + pop dx ; pathname + push bx ; ret address + mov ah, 3dh + ;; AX will have the file handle + +common_int21: + int 21h + jnc common_no_error + mov ax, -1 +common_no_error: + ret + +;; int close(int fd); + global CLOSE +CLOSE: + pop ax ; ret address + pop bx ; fd + push ax ; ret address + mov ah, 3eh + jmp short common_int21 + +;; UCOUNT read(int fd, void *buf, UCOUNT count); + global READ +READ: + pop ax ; ret address + pop cx ; count + pop dx ; buf + pop bx ; fd + push ax ; ret address + mov ah, 3fh + jmp short common_int21 + +;; int dup2(int oldfd, int newfd); + global DUP2 +DUP2: + pop ax ; ret address + pop cx ; newfd + pop bx ; oldfd + push ax ; ret address + mov ah, 46h + jmp short common_int21 + +; +; ULONG ASMPASCAL lseek(int fd, long position); +; + global LSEEK +LSEEK: + pop ax ; ret address + pop dx ; position low + pop cx ; position high + pop bx ; fd + push ax ; ret address + mov ax,4200h ; origin: start of file + int 21h + jnc seek_ret ; CF=1? + sbb ax,ax ; then dx:ax = -1, else unchanged + sbb dx,dx +seek_ret: + ret + +;; VOID init_PSPSet(seg psp_seg) + global INIT_PSPSET +INIT_PSPSET: + pop ax ; ret address + pop bx ; psp_seg + push ax ; ret_address + mov ah, 50h + int 21h + ret + +;; COUNT init_DosExec(COUNT mode, exec_blk * ep, BYTE * lp) + global INIT_DOSEXEC +INIT_DOSEXEC: + pop es ; ret address + pop dx ; filename + pop bx ; exec block + pop ax ; mode + push es ; ret address + mov ah, 4bh + push ds + pop es ; es = ds + int 21h + jc short exec_no_error + xor ax, ax +exec_no_error: + ret + +;; int init_setdrive(int drive) + global INIT_SETDRIVE +INIT_SETDRIVE: + mov ah, 0x0e +common_dl_int21: + pop bx ; ret address + pop dx ; drive/char + push bx + int 21h + ret + +;; int init_switchar(int char) + global INIT_SWITCHAR +INIT_SWITCHAR: + mov ax, 0x3701 + jmp short common_dl_int21 + +; +; seg ASMPASCAL allocmem(UWORD size); +; + global ALLOCMEM +ALLOCMEM: + pop ax ; ret address + pop bx ; size + push ax ; ret address + mov ah, 48h + int 21h + sbb bx, bx ; carry=1 -> ax=-1 + or ax, bx ; segment + ret + +;; void set_DTA(void far *dta) + global SET_DTA +SET_DTA: + pop ax ; ret address + pop bx ; seg(dta) + pop dx ; off(dta) + push ax ; ret address + mov ah, 1ah + push ds + mov ds, bx + int 21h + pop ds + ret diff --git a/kernel/io.asm b/kernel/io.asm new file mode 100644 index 0000000..32d13af --- /dev/null +++ b/kernel/io.asm @@ -0,0 +1,593 @@ +; +; File: +; io.asm +; Description: +; DOS-C I/O Subsystem +; +; Copyright (c) 1998 +; 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. +; +; $Header$ +; + + %include "segs.inc" + %include "stacks.inc" + + extern ConTable:wrt LGROUP + extern LptTable:wrt LGROUP + extern ComTable:wrt LGROUP + extern uPrtNo:wrt LGROUP + extern CommonNdRdExit:wrt LGROUP +;!! extern _NumFloppies:wrt DGROUP + extern blk_stk_top:wrt DGROUP + extern clk_stk_top:wrt DGROUP + extern _reloc_call_blk_driver + extern _reloc_call_clk_driver + + extern _TEXT_DGROUP:wrt LGROUP + +;--------------------------------------------------- +; +; Device entry points +; +; This really should be a struct and go into a request.inc file +; +cmdlen equ 0 ; Length of this command +unit equ 1 ; Subunit Specified +cmd equ 2 ; Command Code +status equ 3 ; Status +media equ 13 ; Media Descriptor +trans equ 14 ; Transfer Address +count equ 18 ; Count of blocks or characters +start equ 20 ; First block to transfer +vid equ 22 ; Volume id pointer +huge equ 26 ; First block (32-bit) to transfer + +; +; The following is the "array" of device driver headers for the internal +; devices. There is one header per device including special aux: and prn: +; pseudo devices. These psuedo devices are necessary for printer +; redirection, i.e., serial or parallel ports, and com port aux selection. +; +; The devices are linked into each other and terminate with a -1 next +; pointer. This saves some time on boot up and also allows us to throw all +; device initialization into a single io_init function that may be placed +; into a discardable code segmemnt. +; +segment _IO_FIXED_DATA + + ; + ; The "CON" device + ; + ; This device is the standard console device used by + ; DOS-C and kernel + ; + global _con_dev +_con_dev equ $ + dw _prn_dev,LGROUP + dw 8013h ; con device (stdin & stdout) + dw GenStrategy + dw ConIntr + db 'CON ' + + ; + ; Generic prn device that can be redirected via mode + ; + global _prn_dev +_prn_dev dw _aux_dev,LGROUP + dw 0A040h + dw GenStrategy + dw PrnIntr + db 'PRN ' + + ; + ; Generic aux device that can be redirected via mode + ; + global _aux_dev +_aux_dev dw _Lpt1Dev,LGROUP + dw 8000h + dw GenStrategy + dw AuxIntr + db 'AUX ' + + ; + ; Printer device drivers + ; +_Lpt1Dev dw _Lpt2Dev,LGROUP + dw 0A040h + dw GenStrategy + dw Lpt1Intr + db 'LPT1 ' +_Lpt2Dev dw _Lpt3Dev,LGROUP + dw 0A040h + dw GenStrategy + dw Lpt2Intr + db 'LPT2 ' +_Lpt3Dev dw _Com1Dev,LGROUP + dw 0A040h + dw GenStrategy + dw Lpt3Intr + db 'LPT3 ' + + ; + ; Com device drivers + ; +_Com1Dev dw _Com2Dev,LGROUP + dw 8000h + dw GenStrategy + dw AuxIntr + db 'COM1 ' +_Com2Dev dw _Com3Dev,LGROUP + dw 8000h + dw GenStrategy + dw Com2Intr + db 'COM2 ' +_Com3Dev dw _Com4Dev,LGROUP + dw 8000h + dw GenStrategy + dw Com3Intr + db 'COM3 ' +_Com4Dev dw _clk_dev,LGROUP + dw 8000h + dw GenStrategy + dw Com4Intr + db 'COM4 ' + + ; + ; Header for clock device + ; + global _clk_dev +_clk_dev equ $ + dw _blk_dev,LGROUP + dw 8008h ; clock device + dw GenStrategy + dw clk_entry + db 'CLOCK$ ' + + ; + ; Header for device + ; + global _blk_dev +_blk_dev equ $ + dd -1 + dw 08c2h ; block device with ioctl + dw GenStrategy + dw blk_entry + db 4 + db 0,0,0,0,0,0,0 + + +; +; Temporary table until next release +; +segment _IO_FIXED_DATA +DiskTable db 0 + + +; +; Local storage +; +%if 0 +segment _BSS +blk_dos_stk resw 1 +blk_dos_seg resw 1 +clk_dos_stk resw 1 +clk_dos_seg resw 1 +%endif + +segment _IO_TEXT + global _ReqPktPtr +_ReqPktPtr dd 0 +uUnitNumber dw 0 + + +; +; Name: +; GenStrategy +; +; Function: +; Store the pointer to the request packet passed in es:bx +; +; Description: +; Generic strategy routine. Unlike the original multitasking versions, +; this version assumes that no more thank one device driver is active +; at any time. The request is stored into memory in the one and only +; location available for that purpose. +; +GenStrategy: + mov word [cs:_ReqPktPtr],bx + mov word [cs:_ReqPktPtr+2],es + retf + + +; +; Name: +; XXXXIntr +; +; Function: +; Individual Interrupt routines for each device driver +; +; Description: +; This is actually a single routine with entry points for each device. +; The name used for the entry point is the device name with Intr +; appended to it. +; +; Funtionally, each device driver has an entry and an associated +; table. The table is a structure that consists of a control byte +; followed by an array of pointers to C functions or assembly +; subroutines that implement the individual device driver functions. +; This allows the usage of common error dummy filler code to be used. +; It also allows standardization of the calling procedure for these +; internal device driver functions. +; +; Assembler call/return convention: +; Each driver function is entered by a jump into the function and +; exits by a jump to the appropriate success or error exit routine. +; This speeds up the call and return and helps to minimize the stack +; useage. The contents of the request packet are passed to each +; routine in registers as follows: +; +; Register Function Description +; -------- -------- ----------- +; al unit Subunit Specified +; ah media Media Descriptor +; cx count Count of blocks or characters +; dx start First block to transfer +; es:di trans Transfer Address +; ds:bx reqptr Request pointer +; cs kernel code segment +; ds kernel data segment +; +; The exit routines generally set the status based on the individual +; routine. For example, _IOSuccess will clear the count where +; _IOErrCnt will subtract the remaining amount in cx from the original +; count. See each utility routine for expectations. +; +; C call/return convention: +; The C calling convention simply sets up the C stack and passes the +; request packet pointer as a far pointer to the function. Although +; the utility routine names are such that they are accesible from the +; C name space, they are cannot used. Instead, the common interrupt +; code expects a return status to set in the request packet. It is up +; to the device driver function to set the appropriate fields such as +; count when an error occurs. +; +; How to differntiate between the two calling conventions: +; This code is entirely table driven. The table is a structure that +; is generally in the _IO_FIXED_DATA segment. It consists of a flag +; byte followed by short pointers to the driver functions. Selecting +; a driver type is accomplished by setting the type bit in the flag +; (see below). +; +; 7 6 5 4 3 2 1 0 +; +---+---+---+---+---+---+---+---+ +; | | | | | | | | | +; +---+---+---+---+---+---+---+---+ +; | | | |--- Number of table entries +; | | +-------------------+ +; | | |----------------------- Reserved +; | +-------+ +; +--------------------------------- type bit (1 == C / 0 == asm) +; +ConIntr: + push si + mov si,ConTable + jmp short CharIntrEntry + +PrnIntr: + push si + push ax + xor ax,ax + jmp short LptCmnIntr + +Lpt1Intr: + push si + push ax + xor al,al + mov ah,1 + jmp short LptCmnIntr + +Lpt2Intr: + push si + push ax + mov al,1 + mov ah,2 + jmp short LptCmnIntr + +Lpt3Intr: + push si + push ax + mov al,2 + mov ah,3 + +LptCmnIntr: + mov si,LptTable + mov [cs:uPrtNo],ah + jmp short DiskIntrEntry + + +AuxIntr: + push si + push ax + xor al,al + jmp short ComCmnIntr + +Com2Intr: + push si + push ax + mov al,1 + jmp short ComCmnIntr + +Com3Intr: + push si + push ax + mov al,2 + jmp short ComCmnIntr + +Com4Intr: + push si + push ax + mov al,3 + jmp short ComCmnIntr + +ComCmnIntr: + mov si,ComTable + jmp short DiskIntrEntry + + +DskIntr: + push si + mov si,DiskTable +CharIntrEntry: + push ax +DiskIntrEntry: + push cx + push dx + push di + push bp + push ds + push es + push bx + mov byte [cs:uUnitNumber],al + lds bx,[cs:_ReqPktPtr] + test byte [cs:si],80h + je AsmType + + mov al,[bx+cmd] + cmp al,[cs:si] + ja _IOCommandError + cbw + shl ax,1 + add si,ax + xchg di,ax + + push ds + push bx + mov bp,sp + mov ds,[cs:_TEXT_DGROUP] + cld + call word [cs:si+1] + pop cx + pop cx + jmp short StoreStatus + +AsmType: mov al,[bx+unit] + mov ah,[bx+media] + mov cx,[bx+count] + mov dx,[bx+start] + xchg di,ax + mov al,[bx+cmd] + cmp al,[cs:si] + ja _IOCommandError + cbw + shl ax,1 + add si,ax + xchg di,ax + + les di,[bx+trans] + mov ds,[cs:_TEXT_DGROUP] + cld + jmp word [cs:si+1] + +; +; Name: +; _IOXXXXXXX +; +; Function: +; Exit routines for internal device drivers. +; +; Description: +; These routines are the exit for internal device drivers. _IOSuccess +; is for read/write functions and correctly returns for a successful +; read/write operation by setting the remainng count to zero. _IOExit +; simply sets success bit and returns. _IODone returns complete and +; busy status. _IOCommandError returns and error status for invalid +; commands. _IOErrCnt corrects the remaining bytes for errors that +; occurred during partial read/write operation. _IOErrorExit is a +; generic error exit that sets done and error. +; + global _IOSuccess +_IOSuccess: + lds bx,[cs:_ReqPktPtr] + xor ax,ax + mov [bx+count],ax + + global _IOExit +_IOExit: + mov ah,1 + +StoreStatus: + lds bx,[cs:_ReqPktPtr] + mov [bx+status],ax + pop bx + pop es + pop ds + pop bp + pop di + pop dx + pop cx + pop ax + pop si + retf + + + global _IODone +_IODone: + mov ah,3 + jmp short StoreStatus + + global _IOCommandError +_IOCommandError: + mov al,3 + + global _IOErrCnt +_IOErrCnt: + lds bx,[cs:_ReqPktPtr] + sub [bx+count],cx + global _IOErrorExit +_IOErrorExit: + mov ah,81h + jmp short StoreStatus + +; +; Name: +; GetUnitNum +; +; Function: +; Return the internally set unit number. +; +; Description: +; Simply return the contents of uUnitNumber. This version relies on +; no segment registers and makes a safe call regardless of driver +; state. +; + global GetUnitNum +GetUnitNum: + mov dx,[cs:uUnitNumber] + ret + + ; + ; These are still old style DOS-C drivers. I'll replace + ; them in the next release + ; + + + ; + ; block device interrupt + ; + ; NOTE: This code is not standard device driver handlers + ; It is written for sperate code and data space. + ; + +blk_driver_params: + dw blk_stk_top + dw _reloc_call_blk_driver + dw seg _reloc_call_blk_driver + +clk_driver_params: + dw clk_stk_top + dw _reloc_call_clk_driver + dw seg _reloc_call_clk_driver + + ; clock device interrupt +clk_entry: + pushf + push bx + + mov bx, clk_driver_params + + jmp short clk_and_blk_common + + + ; block device interrupt +blk_entry: + pushf + push bx + + mov bx, blk_driver_params + +clk_and_blk_common: + + push ax + push cx + push dx + + + ; small model + mov ax,sp ; use internal stack + mov dx,ss + pushf ; put flags in cx + pop cx + cli ; no interrupts + mov ss,[cs:_TEXT_DGROUP] + mov sp,[cs:bx] + + push cx + popf ; restore interrupt flag + + + + push ax ; save old SS/SP + push dx + + ; push these registers on + push ds ; BLK_STACK + push bp ; to save stack space + push si + push di + push es + Protect386Registers + + mov ds,[cs:_TEXT_DGROUP] ; + + + push word [cs:_ReqPktPtr+2] + push word [cs:_ReqPktPtr] + call far [cs:bx+2] + pop cx + pop cx + + les bx,[cs:_ReqPktPtr] ; now return completion code + mov word [es:bx+status],ax ; mark operation complete + + + Restore386Registers + pop es + pop di + pop si + pop bp + pop ds + + + pop dx ; get back old SS/SP + pop ax + + cli ; no interrupts + mov ss,dx ; use dos stack + mov sp,ax + + + pop dx + pop cx + pop ax + pop bx + popf + retf diff --git a/kernel/io.inc b/kernel/io.inc new file mode 100644 index 0000000..5ab1984 --- /dev/null +++ b/kernel/io.inc @@ -0,0 +1,60 @@ +; +; File: +; io.inc +; Description: +; Segments and external common routines used by various device drivers +; +; Copyright (c) 1998 +; 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. +; +; $Header$ +; + + %include "segs.inc" + +; +; Error Return Codes +; + +%define E_WRPRT 0 ; Write Protect +%define E_UNIT 1 ; Unknown Unit +%define E_NOTRDY 2 ; Device Not Ready +%define E_CMD 3 ; Unknown Command +%define E_CRC 4 ; Crc Error +%define E_LENGTH 5 ; Bad Length +%define E_SEEK 6 ; Seek Error +%define E_MEDIA 7 ; Unknown MEDIA +%define E_NOTFND 8 ; Sector Not Found +%define E_PAPER 9 ; No Paper +%define E_WRITE 10 ; Write Fault +%define E_READ 11 ; Read Fault +%define E_FAILURE 12 ; General Failure + + + extern _IOExit:wrt LGROUP + extern _IOSuccess:wrt LGROUP + extern _IOErrorExit:wrt LGROUP + extern _IOErrCnt:wrt LGROUP + extern _IODone:wrt LGROUP + extern _IOCommandError:wrt LGROUP + extern GetUnitNum:wrt LGROUP + extern _ReqPktPtr:wrt LGROUP + diff --git a/kernel/ioctl.c b/kernel/ioctl.c new file mode 100644 index 0000000..9ea4d7a --- /dev/null +++ b/kernel/ioctl.c @@ -0,0 +1,274 @@ +/****************************************************************/ +/* */ +/* ioctl.c */ +/* */ +/* DOS-C ioctl system call */ +/* */ +/* Copyright (c) 1995,1998 */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: ioctl.c 1427 2009-06-09 12:23:14Z bartoldeman $"; +#endif + +/* + * WARNING: this code is non-portable (8086 specific). + */ + +/* TE 10/29/01 + + although device drivers have only 20 pushes available for them, + MS NET plays by its own rules + + at least TE's network card driver DM9PCI (some 10$ NE2000 clone) does: + with SP=8DC before calling down to execrh, and SP=8CC when + callf [interrupt], DM9PCI touches DOSDS:792, + 14 bytes into error stack :-((( + + so some optimizations were made. + this uses the fact, that only CharReq device buffer is ever used. + fortunately, this saves some code as well :-) + +*/ + +/* this is a file scope static because with Turbo C 2.01 "static const" does + * not work correctly inside the function */ +STATIC const UBYTE cmd [] = { + 0, 0, + /* 0x02 */ C_IOCTLIN, + /* 0x03 */ C_IOCTLOUT, + /* 0x04 */ C_IOCTLIN, + /* 0x05 */ C_IOCTLOUT, + /* 0x06 */ C_ISTAT, + /* 0x07 */ C_OSTAT, + /* 0x08 */ C_REMMEDIA, + 0, 0, 0, + /* 0x0c */ C_GENIOCTL, + /* 0x0d */ C_GENIOCTL, + /* 0x0e */ C_GETLDEV, + /* 0x0f */ C_SETLDEV, + /* 0x10 */ C_IOCTLQRY, + /* 0x11 */ C_IOCTLQRY, +}; + +int DosDevIOctl(lregs * r) +{ + struct dhdr FAR *dev; + + if (r->AL > 0x11) + return DE_INVLDFUNC; + + switch (r->AL) + { + case 0x0b: + /* skip, it's a special case. */ + NetDelay = r->CX; + if (r->DX) + NetRetry = r->DX; + return SUCCESS; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x06: + case 0x07: + case 0x0a: + case 0x0c: + case 0x10: + { + sft FAR *s; + unsigned flags; + + /* Test that the handle is valid and */ + /* get the SFT block that contains the SFT */ + if ((s = get_sft(r->BX)) == (sft FAR *) - 1) + return DE_INVLDHNDL; + + flags = s->sft_flags; + + switch (r->AL) + { + case 0x00: + /* Get the flags from the SFT */ + if (flags & SFT_FDEVICE) + r->AX = (flags & 0xff) | (s->sft_dev->dh_attr & 0xff00); + else + r->AX = flags; + /* Undocumented result, Ax = Dx seen using Pcwatch */ + r->DX = r->AX; + return SUCCESS; + + case 0x01: + /* sft_flags is a file, return an error because you */ + /* can't set the status of a file. */ + if (!(flags & SFT_FDEVICE)) + return DE_INVLDFUNC; + /* RBIL says this is only for DOS < 6, but MSDOS 7.10 */ + /* returns this as well... and some buggy program relies*/ + /* on it :( */ + if (r->DH != 0) + return DE_INVLDDATA; + + /* Undocumented: AL should get the old value */ + r->AL = s->sft_flags_lo; + /* Set it to what we got in the DL register from the */ + /* user. */ + s->sft_flags_lo = SFT_FDEVICE | r->DL; + return SUCCESS; + + case 0x0a: + r->DX = flags; + r->AX = 0; + return SUCCESS; + } + if (!(flags & SFT_FDEVICE)) + { + if (r->AL == 0x06) + r->AL = s->sft_posit >= s->sft_size ? 0 : 0xFF; + else if (r->AL == 0x07) + r->AL = 0; + else + return DE_INVLDFUNC; + return SUCCESS; + } + dev = s->sft_dev; + CharReqHdr.r_unit = 0; + break; + } + + default: /* block IOCTL: 4, 5, 8, 9, d, e, f, 11 */ + { + struct dpb FAR *dpbp; + unsigned attr; +/* + This line previously returned the deviceheader at r->bl. But, + DOS numbers its drives starting at 1, not 0. A=1, B=2, and so + on. Changed this line so it is now zero-based. + + -SRM + */ +/* JPP - changed to use default drive if drive=0 */ +/* JT Fixed it */ + + /* NDN feeds the actual ASCII drive letter to this function */ + dpbp = get_dpb((r->BL & 0x1f) == 0 ? default_drive : (r->BL & 0x1f) - 1); + if (dpbp) + { + CharReqHdr.r_unit = dpbp->dpb_subunit; + dev = dpbp->dpb_device; + attr = dev->dh_attr; + } + else + { + if (r->AL != 9) + return DE_INVLDDRV; + dev = NULL; + attr = ATTR_REMOTE; + } + + switch (r->AL) + { + case 0x09: + { + /* note from get_dpb() */ + /* that if cdsp == NULL then dev must be NULL too */ + struct cds FAR *cdsp = get_cds1(r->BL & 0x1f); + if (cdsp == NULL) + return DE_INVLDDRV; + if (cdsp->cdsFlags & CDSSUBST) + attr |= ATTR_SUBST; + r->AX = S_DONE | S_BUSY; + r->DX = attr; + return SUCCESS; + } + case 0x0d: + if ((r->CX & ~(0x486B-0x084A)) == 0x084A) + { /* 084A/484A, 084B/484B, 086A/486A, 086B/486B */ + r->AX = 0; /* (lock/unlock logical/physical volume) */ + /* simulate success for MS-DOS 7+ SCANDISK etc. --LG */ + return SUCCESS; + } + /* fall through */ + default: /* 0x04, 0x05, 0x08, 0x0e, 0x0f, 0x11 */ + break; + } + break; + } + } + + { + unsigned testattr = ATTR_QRYIOCTL; + if (r->AL<=0x0f) + testattr = ATTR_GENIOCTL; + if (r->AL<=0x08) + testattr = ATTR_EXCALLS; + if (r->AL<=0x07) + testattr = 0xffff; + if (r->AL<=0x05) + testattr = ATTR_IOCTL; + + if (!(dev->dh_attr & testattr)) + return DE_INVLDFUNC; + } + + CharReqHdr.r_command = cmd[r->AL]; + if (r->AL == 0x0C || r->AL == 0x0D || r->AL >= 0x10) /* generic or query */ + { + CharReqHdr.r_cat = r->CH; /* category (major) code */ + CharReqHdr.r_fun = r->CL; /* function (minor) code */ + CharReqHdr.r_si = r->SI; /* contents of SI and DI */ + CharReqHdr.r_di = r->DI; + CharReqHdr.r_io = MK_FP(r->DS, r->DX); /* parameter block */ + } + else + { + CharReqHdr.r_count = r->CX; + CharReqHdr.r_trans = MK_FP(r->DS, r->DX); + } + CharReqHdr.r_length = sizeof(request); + CharReqHdr.r_status = 0; + + execrh(&CharReqHdr, dev); + + if (CharReqHdr.r_status & S_ERROR) + { + CritErrCode = (CharReqHdr.r_status & S_MASK) + 0x13; + return DE_ACCESS; + } + + if (r->AL <= 0x05) /* 0x02, 0x03, 0x04, 0x05 */ + r->AX = CharReqHdr.r_count; + else if (r->AL <= 0x07) /* 0x06, 0x07 */ + r->AX = (CharReqHdr.r_status & S_BUSY) ? 0000 : 0x00ff; + else if (r->AL == 0x08) /* 0x08 */ + r->AX = (CharReqHdr.r_status & S_BUSY) ? 1 : 0; + else if (r->AL == 0x0e || r->AL == 0x0f) /* 0x0e, 0x0f */ + r->AL = CharReqHdr.r_unit; + else /* 0x0c, 0x0d, 0x10, 0x11 */ + r->AX = CharReqHdr.r_status; + return SUCCESS; +} diff --git a/kernel/iprf.c b/kernel/iprf.c new file mode 100644 index 0000000..873a7eb --- /dev/null +++ b/kernel/iprf.c @@ -0,0 +1,6 @@ +/* init code printf */ +/* simply include prf.c while defining */ +/* _INIT: reduces command line length */ +/* and simplifies make procedure */ +#define _INIT 1 +#include "prf.c" diff --git a/kernel/irqstack.asm b/kernel/irqstack.asm new file mode 100644 index 0000000..a283a01 --- /dev/null +++ b/kernel/irqstack.asm @@ -0,0 +1,246 @@ +; File: +; irqstack.asm +; Description: +; Assembly support routines for hardware stack support +; +; Copyright (c) 1997, 1998 +; Svante Frey +; 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. +; +; $Id: irqstack.asm 1567 2011-04-09 02:03:20Z bartoldeman $ +; + + +; Code for stack switching during hardware interrupts. + +; Format of interrupt sharing protocol interrupt handler entry point: +; Offset Size Description (Table 02568) +; 00h 2 BYTEs short jump to actual start of interrupt handler, immediately +; following this data block (EBh 10h) +; 02h DWORD address of next handler in chain +; 06h WORD signature 424Bh +; 08h BYTE EOI flag +; 00h software interrupt or secondary hardware interrupt handler +; 80h primary hardware interrupt handler (will issue EOI to +; interrupt controller) +; 09h 2 BYTEs short jump to hardware reset routine +; must point at a valid FAR procedure (may be just RETF) +; 0Bh 7 BYTEs reserved (0) by IBM for future expansion + +; Ralf Brown documents that irq 2, 3, 4, 5, 6, 10, 11, 12, 14, 15 use the above +; protocol.. +; MS (http://support.microsoft.com/kb/84300/) +; documents that STACKS= implements stacks for interrupt vectors +; 02H, 08-0EH, 70H, and 72-77H. +; that means that we need to redirect NMI (INT 2), irq 0, 1, 8, 13 without sharing +; irq 9 (==irq2) and irq 7 (printer) are not handled at all + +%include "segs.inc" + +segment _IRQTEXT + +stack_size dw 0 +stack_top dw 0 +stack_offs dw 0 +stack_seg dw 0 + +%macro irq 0 + call general_irq_service + dd 0 +%endmacro + +%macro irqshare 1 + jmp short %%1 + dd 0 + dw 424bh + db 0 + jmp short retf%1 + times 7 db 0 +%%1: call general_irq_service_share +%endmacro + +nmi: irq +irq_0: irq +irq_1: irq +irq_08: irq +irq_0d: irq + +retf1: retf +irq_2: irqshare 1 +irq_3: irqshare 1 +irq_4: irqshare 1 +irq_5: irqshare 1 +irq_6: irqshare 1 +irq_0a: irqshare 2 +irq_0b: irqshare 2 +irq_0c: irqshare 2 +irq_0e: irqshare 2 +irq_0f: irqshare 2 +retf2: retf + + ; align to 100h to align _LOWTEXT for interrupt vectors + ; in kernel.asm + times (100h - ($ - stack_size)) db 0 + +segment _IO_TEXT + +general_irq_service: + push bx + mov bx, sp + mov bx, [ss:bx+2] ; return address->old ivec + jmp short common_irq + +general_irq_service_share: + push bx + mov bx, sp + mov bx, [ss:bx+2] ; return address->old ivec + sub bx, byte irq_3 - irq_2 - 2 +common_irq: + push dx + push ax + push ds + + mov ax, cs + mov ds, ax + + mov ax, [stack_top] + cmp ax, [stack_offs] + jbe dont_switch + + mov dx, ss + mov ax, sp + + mov ss, [stack_seg] + mov sp, [stack_top] + + push dx ; save old SS:SP on new stack + push ax + + mov ax, [stack_size] + sub [stack_top], ax + + pushf + call far word [bx] + + cli + add [stack_top], ax + + pop ax ; get stored SS:SP + pop dx + + mov ss, dx ; switch back to old stack + mov sp, ax + +return: pop ds ; restore registers and return + pop ax + pop dx + pop bx + add sp, byte 2 + iret + +dont_switch: pushf + call far word [bx] + jmp short return + + +segment INIT_TEXT + +global _init_stacks +; VOID init_stacks(VOID FAR *stack_base, COUNT nStacks, WORD stackSize); + +int_numbers: db 2,8,9,70h,75h +int_numbers_share: db 0ah,0bh,0ch,0dh,0eh,72h,73h,74h,76h,77h + +_init_stacks: + push bp + mov bp, sp + push ds + push di + push si + + + mov ax,LGROUP + mov ds,ax + mov es,ax + + mov bx, [bp+4] + mov dx, [bp+6] + mov ax, [bp+8] + mov cx, [bp+0ah] + + mov [stack_size], cx + mov [stack_offs], bx + mov [stack_seg], dx + + mul cx + add ax, bx + ; stack_top = stack_size * nStacks + stack_seg:stack_offs + mov [stack_top], ax + + xor ax, ax + mov ds, ax + + mov di, nmi + 3 + mov dx, nmi + mov bx, int_numbers + mov cx, int_numbers_share - int_numbers + mov bp, irq_1 - irq_0 + call set_vect + + inc dx ; skip over retf (not di: go from nmi+3 to irq_2+2) + mov cx, _init_stacks - int_numbers_share + mov bp, irq_3 - irq_2 + call set_vect + + pop si + pop di + pop ds + pop bp + ret + +; set interrupt vectors: +; in: es=LGROUP, ds=0 +; bx: pointer to int_numbers bytes in cs +; cx: number of vectors to set +; dx: pointer to es:nmi and so on (new interrupt vectors) +; di: pointer to es:nmi+3 and so on (pointer to place of old interrupt vectors) +; bp: difference in offset between irq structures +; out: bx, si, di updated, cx=0, ax destroyed +set_vect: + mov al, [cs:bx] ; get next int vector offset + inc bx + cbw + mov si, ax + shl si, 1 + shl si, 1 ; now ds:si -> int vector, es:di -> nmi+3, etc + + movsw ; save old vector + movsw + + cli + mov [si-4], dx ; set new vector + mov [si-2], es + sti + + add dx, bp + lea di, [di+bp-4] ; update di, compensating for movsw + loop set_vect + + ret diff --git a/kernel/kernel.asm b/kernel/kernel.asm new file mode 100644 index 0000000..d62dd58 --- /dev/null +++ b/kernel/kernel.asm @@ -0,0 +1,1052 @@ +; +; File: +; kernel.asm +; Description: +; kernel start-up code +; +; Copyright (c) 1995, 1996 +; 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. +; +; $Id: kernel.asm 1705 2012-02-07 08:10:33Z perditionc $ +; + + %include "segs.inc" + %include "ludivmul.inc" + + +segment PSP + + extern _ReqPktPtr:wrt LGROUP + +STACK_SIZE equ 384/2 ; stack allocated in words + +;************************************************************ +; KERNEL BEGINS HERE, i.e. this is byte 0 of KERNEL.SYS +;************************************************************ + +..start: +entry: + jmp short realentry + +;************************************************************ +; KERNEL CONFIGURATION AREA +; this is copied up on the very beginning +; it's a good idea to keep this in sync with KConfig.h +;************************************************************ + global _LowKernelConfig +_LowKernelConfig: + db 'CONFIG' ; constant + dw configend-configstart; size of config area + ; to be checked !!! + +configstart: + +DLASortByDriveNo db 0 ; sort disks by drive order +InitDiskShowDriveAssignment db 1 ; +SkipConfigSeconds db 2 ; +ForceLBA db 0 ; +GlobalEnableLBAsupport db 1 ; +BootHarddiskSeconds db 0 ; + +configend: + +;************************************************************ +; KERNEL CONFIGURATION AREA END +;************************************************************ + + +;************************************************************ +; KERNEL real entry (at ~60:20) +; +; moves the INIT part of kernel.sys to high memory (~9000:0) +; then jumps there +; to aid debugging, some '123' messages are output +; this area is discardable and used as temporary PSP for the +; init sequence +;************************************************************ + + +realentry: ; execution continues here + + push ax + push bx + pushf + mov ax, 0e31h ; '1' Tracecode - kernel entered + mov bx, 00f0h + int 010h + popf + pop bx + pop ax + + jmp far kernel_start +beyond_entry: resb 256-(beyond_entry-entry) + ; scratch area for data (DOS_PSP) + +segment INIT_TEXT + + extern _FreeDOSmain + extern _query_cpu + + ; + ; kernel start-up + ; +kernel_start: + + push bx + pushf + mov ax, 0e32h ; '2' Tracecode - kernel entered + mov bx, 00f0h + int 010h + popf + pop bx + + mov ax,seg init_tos + cli + mov ss,ax + mov sp,init_tos + int 12h ; move init text+data to higher memory + mov cl,6 + shl ax,cl ; convert kb to para + mov dx,15 + init_end wrt INIT_TEXT + mov cl,4 + shr dx,cl + sub ax,dx + mov es,ax + mov dx,__INIT_DATA_START wrt INIT_TEXT ; para aligned + shr dx,cl + add ax,dx + mov ss,ax ; set SS to init data segment + sti ; now enable them + mov ax,cs + mov dx,__InitTextStart wrt HMA_TEXT ; para aligned + shr dx,cl +%ifdef WATCOM + add ax,dx +%endif + mov ds,ax + mov si,-2 + init_end wrt INIT_TEXT ; word aligned + lea cx,[si+2] + mov di,si + shr cx,1 + std ; if there's overlap only std is safe + rep movsw + + ; move HMA_TEXT to higher memory + sub ax,dx + mov ds,ax ; ds = HMA_TEXT + mov ax,es + sub ax,dx + mov es,ax ; es = new HMA_TEXT + + mov si,-2 + __InitTextStart wrt HMA_TEXT + lea cx,[si+2] + mov di,si + shr cx,1 + rep movsw + + cld +%ifndef WATCOM ; for WATCOM: CS equal for HMA and INIT + add ax,dx + mov es,ax ; otherwise CS -> init_text +%endif + push es + mov ax,cont + push ax + retf +cont: ; Now set up call frame + mov ds,[cs:_INIT_DGROUP] + mov bp,sp ; and set up stack frame for c + + push bx + pushf + mov ax, 0e33h ; '3' Tracecode - kernel entered + mov bx, 00f0h + int 010h + popf + pop bx + + mov byte [_BootDrive],bl ; tell where we came from + +;!! int 11h +;!! mov cl,6 +;!! shr al,cl +;!! inc al +;!! mov byte [_NumFloppies],al ; and how many + + call _query_cpu + mov byte [_CPULevel],al + ; TODO display error if built for 386 running on 8086 etc + + mov ax,ss + mov ds,ax + mov es,ax + jmp _FreeDOSmain + + +segment INIT_TEXT_END + + +;************************************************************ +; KERNEL CODE AREA END +; the NUL device +;************************************************************ + +segment CONST + + ; + ; NUL device strategy + ; + global _nul_strtgy +_nul_strtgy: + mov word [cs:_ReqPktPtr],bx ;save rq headr + mov word [cs:_ReqPktPtr+2],es + retf + + ; + ; NUL device interrupt + ; + global _nul_intr +_nul_intr: + push es + push bx + les bx,[cs:_ReqPktPtr] ;es:bx--> rqheadr + cmp byte [es:bx+2],4 ;if read, set 0 read + jne no_nul_read + mov word [es:bx+12h],0 +no_nul_read: + or word [es:bx+3],100h ;set "done" flag + pop bx + pop es + retf + +segment _LOWTEXT + + ; low interrupt vectors 10h,13h,15h,19h,1Bh + ; these need to be at 0070:0100 (see RBIL memory.lst) + global _intvec_table +_intvec_table: db 10h + dd 0 + db 13h + dd 0 + db 15h + dd 0 + db 19h + dd 0 + db 1Bh + dd 0 + + ; floppy parameter table + global _int1e_table +_int1e_table: times 0eh db 0 + +;************************************************************ +; KERNEL FIXED DATA AREA +;************************************************************ + + +segment _FIXED_DATA + +; Because of the following bytes of data, THIS MODULE MUST BE THE FIRST +; IN THE LINK SEQUENCE. THE BYTE AT DS:0004 determines the SDA format in +; use. A 0 indicates MS-DOS 3.X style, a 1 indicates MS-DOS 4.0-6.X style. + global DATASTART +DATASTART: + global _DATASTART +_DATASTART: +dos_data db 0 + dw kernel_start + db 0 ; padding + dw 1 ; Hardcoded MS-DOS 4.0+ style + + times (0eh - ($ - DATASTART)) db 0 + global _NetBios +_NetBios dw 0 ; NetBios Number + + times (26h - 0ch - ($ - DATASTART)) db 0 + +; Globally referenced variables - WARNING: DO NOT CHANGE ORDER +; BECAUSE THEY ARE DOCUMENTED AS UNDOCUMENTED (?) AND HAVE +; MANY MULTIPLEX PROGRAMS AND TSRs ACCESSING THEM + global _NetRetry +_NetRetry dw 3 ;-000c network retry count + global _NetDelay +_NetDelay dw 1 ;-000a network delay count + global _DskBuffer +_DskBuffer dd -1 ;-0008 current dos disk buffer + global _inputptr +_inputptr dw 0 ;-0004 Unread con input + global _first_mcb +_first_mcb dw 0 ;-0002 Start of user memory + global _DPBp + global MARK0026H +; A reference seems to indicate that this should start at offset 26h. +MARK0026H equ $ +_DPBp dd 0 ; 0000 First drive Parameter Block + global _sfthead +_sfthead dd 0 ; 0004 System File Table head + global _clock +_clock dd 0 ; 0008 CLOCK$ device + global _syscon +_syscon dw _con_dev,seg _con_dev ; 000c console device + global _maxsecsize +_maxsecsize dw 512 ; 0010 maximum bytes/sector of any block device + dd 0 ; 0012 pointer to buffers info structure + global _CDSp +_CDSp dd 0 ; 0016 Current Directory Structure + global _FCBp +_FCBp dd 0 ; 001a FCB table pointer + global _nprotfcb +_nprotfcb dw 0 ; 001e number of protected fcbs + global _nblkdev +_nblkdev db 0 ; 0020 number of block devices + global _lastdrive +_lastdrive db 0 ; 0021 value of last drive + global _nul_dev +_nul_dev: ; 0022 device chain root + extern _con_dev:wrt LGROUP + dw _con_dev, seg _con_dev + ; next is con_dev at init time. + dw 8004h ; attributes = char device, NUL bit set + dw _nul_strtgy + dw _nul_intr + db 'NUL ' + global _njoined +_njoined db 0 ; 0034 number of joined devices + dw 0 ; 0035 DOS 4 pointer to special names (always zero in DOS 5) +setverPtr dw 0,0 ; 0037 setver list + dw 0 ; 003B cs offset for fix a20 + dw 0 ; 003D psp of last umb exec + global _LoL_nbuffers +_LoL_nbuffers dw 1 ; 003F number of buffers + dw 1 ; 0041 size of pre-read buffer + global _BootDrive +_BootDrive db 1 ; 0043 drive we booted from + + global _CPULevel +_CPULevel db 0 ; 0044 cpu type (MSDOS >0 indicates dword moves ok, ie 386+) + ; unless compatibility issues arise FD uses + ; 0=808x, 1=18x, 2=286, 3=386+ + ; see cpu.asm, use >= as may add checks for 486 ... + + dw 0 ; 0045 Extended memory in KBytes +buf_info: + global _firstbuf +_firstbuf dd 0 ; 0047 disk buffer chain + dw 0 ; 004B Number of dirty buffers + dd 0 ; 004D pre-read buffer + dw 0 ; 0051 number of look-ahead buffers + global _bufloc +_bufloc db 0 ; 0053 00=conv 01=HMA + global _deblock_buf +_deblock_buf dd 0 ; 0054 deblock buffer + times 3 db 0 ; 0058 unknown + dw 0 ; 005B unknown + db 0, 0FFh, 0 ; 005D unknown + global _VgaSet +_VgaSet db 0 ; 0060 unknown + dw 0 ; 0061 unknown + global _uppermem_link +_uppermem_link db 0 ; 0063 upper memory link flag +_min_pars dw 0 ; 0064 minimum paragraphs of memory + ; required by program being EXECed + global _uppermem_root +_uppermem_root dw 0ffffh ; 0066 dmd_upper_root (usually 9fff) +_last_para dw 0 ; 0068 para of last mem search +SysVarEnd: + +;; FreeDOS specific entries +;; all variables below this point are subject to relocation. +;; programs should not rely on any values below this point!!! + + global _os_setver_minor +_os_setver_minor db 0 + global _os_setver_major +_os_setver_major db 5 + global _os_minor +_os_minor db 0 + global _os_major +_os_major db 5 +_rev_number db 0 + global _version_flags +_version_flags db 0 + + global os_release + extern _os_release +os_release dw _os_release + +%IFDEF WIN31SUPPORT + global _winStartupInfo, _winInstanced +_winInstanced dw 0 ; set to 1 on WinInit broadcast, 0 on WinExit broadcast +_winStartupInfo: + dw 0 ; structure version (same as windows version) + dd 0 ; next startup info structure, 0:0h marks end + dd 0 ; far pointer to name virtual device file or 0:0h + dd 0 ; far pointer, reference data for virtual device driver + dw instance_table,seg instance_table ; array of instance data +instance_table: ; should include stacks, Win may auto determine SDA region + ; we simply include whole DOS data segment + dw 0, seg _DATASTART ; [SEG:OFF] address of region's base + dw markEndInstanceData wrt seg _DATASTART ; size in bytes + dd 0 ; 0 marks end of table +patch_bytes: ; mark end of array of offsets of critical section bytes to patch + dw 0 ; and 0 length for end of instance_table entry + global _winPatchTable +_winPatchTable: ; returns offsets to various internal variables + dw 0x0006 ; DOS version, major# in low byte, eg. 6.00 + dw save_DS ; where DS stored during int21h dispatch + dw save_BX ; where BX stored during int21h dispatch + dw _InDOS ; offset of InDOS flag + dw _MachineId ; offset to variable containing MachineID + dw patch_bytes ; offset of to array of offsets to patch + ; NOTE: this points to a null terminated + ; array of offsets of critical section bytes + ; to patch, for now we just point this to + ; an empty table, purposely not _CritPatch + ; ie we just point to a 0 word to mark end + dw _uppermem_root ; seg of last arena header in conv memory + ; this matches MS DOS's location, but + ; do we have the same meaning? +%ENDIF ; WIN31SUPPORT + +;; The first 5 sft entries appear to have to be at DS:00cc + times (0cch - ($ - DATASTART)) db 0 + global _firstsftt +_firstsftt: + dd -1 ; link to next + dw 5 ; count + +; Some references seem to indicate that this data should start at 01fbh in +; order to maintain 100% MS-DOS compatibility. + times (01fbh - ($ - DATASTART)) db 0 + + global MARK01FBH +MARK01FBH equ $ + global _local_buffer ; local_buffer is 256 bytes long + ; so it overflows into kb_buf!! + ; only when kb_buf is used, local_buffer is limited to 128 bytes. +_local_buffer: times 128 db 0 + global _kb_buf +_kb_buf db 128,0 ; initialise buffer to empty + times 128+1 db 0 ; room for 128 byte readline + LF +; +; Variables that follow are documented as part of the DOS 4.0-6.X swappable +; data area in Ralf Browns Interrupt List #56 +; +; this byte is used for ^P support + global _PrinterEcho +_PrinterEcho db 0 ;-34 - 0 = no printer echo, ~0 echo + global _verify_ena +_verify_ena db 0 ; ~0, write with verify + +; this byte is used for TABs (shared by all char device writes??) + global _scr_pos +_scr_pos db 0 ; Current Cursor Column + global _switchar +_switchar db '/' ;-31 - switch char + global _mem_access_mode +_mem_access_mode db 0 ;-30 - memory allocation strategy + global sharing_flag +sharing_flag db 0 ; 00 = sharing module not loaded + ; 01 = sharing module loaded, but + ; open/close for block devices + ; disabled + ; FF = sharing module loaded, + ; open/close for block devices + ; enabled (not implemented) + global _net_set_count +_net_set_count db 1 ;-28 - count the name below was set + global _net_name +_net_name db ' ' ;-27 - 15 Character Network Name + db 00 ; Terminating 0 byte + + +; +; Variables contained the the "STATE_DATA" segment contain +; information about the STATE of the current DOS Process. These +; variables must be preserved regardless of the state of the INDOS +; flag. +; +; All variables that appear in "STATE_DATA" **MUST** be declared +; in this file as the offsets from the INTERNAL_DATA variable are +; critical to the DOS applications that modify this data area. +; +; + global _ErrorMode, _InDOS + global _CritErrLocus, _CritErrCode + global _CritErrAction, _CritErrClass + global _CritErrDev, _CritErrDrive + global _dta + global _cu_psp, _default_drive + global _break_ena + global _return_code + global _internal_data + + global _CritPatch +_CritPatch dw 0d0ch ;-11 zero list of patched critical + dw 0d0ch ; section variables + dw 0d0ch + dw 0d0ch + dw 0d0ch + db 0 ;-01 - unknown +_internal_data: ; <-- Address returned by INT21/5D06 +_ErrorMode db 0 ; 00 - Critical Error Flag +_InDOS db 0 ; 01 - Indos Flag +_CritErrDrive db 0 ; 02 - Drive on write protect error +_CritErrLocus db 0 ; 03 - Error Locus +_CritErrCode dw 0 ; 04 - DOS format error Code +_CritErrAction db 0 ; 06 - Error Action Code +_CritErrClass db 0 ; 07 - Error Class +_CritErrDev dd 0 ; 08 - Failing Device Address +_dta dd 0 ; 0C - current DTA +_cu_psp dw 0 ; 10 - Current PSP +break_sp dw 0 ; 12 - used in int 23 +_return_code dw 0 ; 14 - return code from process +_default_drive db 0 ; 16 - Current Drive +_break_ena db 1 ; 17 - Break Flag (default TRUE) + db 0 ; 18 - flag, code page switching + db 0 ; 19 - flag, copy of 18 on int 24h abort + + global _swap_always, _swap_indos +_swap_always: + + global _Int21AX +_Int21AX dw 0 ; 1A - AX from last Int 21 + + global owning_psp, _MachineId +owning_psp dw 0 ; 1C - owning psp +_MachineId dw 0 ; 1E - remote machine ID + dw 0 ; 20 - First usable mcb + dw 0 ; 22 - Best usable mcb + dw 0 ; 24 - Last usable mcb + dw 0 ; 26 - memory size in paragraphs + dw 0 ; 28 - unknown + db 0 ; 2A - unknown + db 0 ; 2B - unknown + db 0 ; 2C - unknown + global _break_flg +_break_flg db 0 ; 2D - Program aborted by ^C + db 0 ; 2E - unknown + db 0 ; 2F - not referenced + global _DayOfMonth +_DayOfMonth db 1 ; 30 - day of month + global _Month +_Month db 1 ; 31 - month + global _YearsSince1980 +_YearsSince1980 dw 0 ; 32 - year since 1980 +daysSince1980 dw 0FFFFh ; 34 - number of days since epoch + ; force rebuild on first clock read + global _DayOfWeek +_DayOfWeek db 2 ; 36 - day of week +_console_swap db 0 ; 37 console swapped during read from dev + global _dosidle_flag +_dosidle_flag db 1 ; 38 - safe to call int28 if nonzero +_abort_progress db 0 ; 39 - abort in progress + global _CharReqHdr +_CharReqHdr: + global _ClkReqHdr +_ClkReqHdr times 30 db 0 ; 3A - Device driver request header + dd 0 ; 58 - pointer to driver entry + global _MediaReqHdr +_MediaReqHdr times 22 db 0 ; 5C - Device driver request header + global _IoReqHdr +_IoReqHdr times 30 db 0 ; 72 - Device driver request header + times 6 db 0 ; 90 - unknown + global _ClkRecord +_ClkRecord times 6 db 0 ; 96 - CLOCK$ transfer record + dw 0 ; 9C - unknown + global __PriPathBuffer +__PriPathBuffer times 80h db 0 ; 9E - buffer for file name + global __SecPathBuffer +__SecPathBuffer times 80h db 0 ;11E - buffer for file name + global _sda_tmp_dm +_sda_tmp_dm times 21 db 0 ;19E - 21 byte srch state + global _SearchDir +_SearchDir times 32 db 0 ;1B3 - 32 byte dir entry + global _TempCDS +_TempCDS times 88 db 0 ;1D3 - TemporaryCDS buffer + global _DirEntBuffer +_DirEntBuffer times 32 db 0 ;22B - space enough for 1 dir entry + global _wAttr +_wAttr dw 0 ;24B - extended FCB file attribute + + + global _SAttr +_SAttr db 0 ;24D - Attribute Mask for Dir Search + global _OpenMode +_OpenMode db 0 ;24E - File Open Attribute + + times 3 db 0 + global _Server_Call +_Server_Call db 0 ;252 - Server call Func 5D sub 0 + db 0 + ; Pad to 05CCh + times (25ch - ($ - _internal_data)) db 0 + + global _tsr ; used by break and critical error +_tsr db 0 ;25C - handlers during termination + db 0 ;25D - padding + global term_psp +term_psp dw 0 ;25E - 0?? + global int24_esbp +int24_esbp times 2 dw 0 ;260 - pointer to criticalerr DPB + global _user_r, int21regs_off, int21regs_seg +_user_r: +int21regs_off dw 0 ;264 - pointer to int21h stack frame +int21regs_seg dw 0 + global critical_sp +critical_sp dw 0 ;268 - critical error internal stack + global current_ddsc +current_ddsc times 2 dw 0 + + ; Pad to 059ah + times (27ah - ($ - _internal_data)) db 0 + global current_device +current_device times 2 dw 0 ;27A - 0?? + global _lpCurSft +_lpCurSft times 2 dw 0 ;27e - Current SFT + global _current_ldt +_current_ldt times 2 dw 0 ;282 - Current CDS + global _sda_lpFcb +_sda_lpFcb times 2 dw 0 ;286 - pointer to callers FCB + global _current_sft_idx +_current_sft_idx dw 0 ;28A - SFT index for next open + ; used by MS NET + + ; Pad to 05b2h + times (292h - ($ - _internal_data)) db 0 + dw __PriPathBuffer ; 292 - "sda_WFP_START" offset in DOS DS of first filename argument + dw __SecPathBuffer ; 294 - "sda_REN_WFP" offset in DOS DS of second filename argument + + ; Pad to 05ceh + times (2aeh - ($ - _internal_data)) db 0 + global _current_filepos +_current_filepos times 2 dw 0 ;2AE - current offset in file + + ; Pad to 05eah + times (2cah - ($ - _internal_data)) db 0 + ;global _save_BX + ;global _save_DS +save_BX dw 0 ;2CA - unused by FreeDOS, for Win3.x +save_DS dw 0 ; compatibility, match MS's positions + dw 0 + global _prev_user_r + global prev_int21regs_off + global prev_int21regs_seg +_prev_user_r: +prev_int21regs_off dw 0 ;2D0 - pointer to prev int 21 frame +prev_int21regs_seg dw 0 + + ; Pad to 05fdh + times (2ddh - ($ - _internal_data)) db 0 + global _ext_open_action + global _ext_open_attrib + global _ext_open_mode +_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 + + ; Pad to 0620h + times (300h - ($ - _internal_data)) db 0 + + global apistk_bottom +apistk_bottom: + ; use bottom of error stack as scratch buffer + ; - only used during int 21 call + global _sda_tmp_dm_ren +_sda_tmp_dm_ren:times 21 db 0x90 ;300 - 21 byte srch state for rename + global _SearchDir_ren +_SearchDir_ren: times 32 db 0x90 ;315 - 32 byte dir entry for rename + + ; stacks are made to initialize to no-ops so that high-water + ; testing can be performed + times STACK_SIZE*2-($-apistk_bottom) db 0x90 + ;300 - Error Processing Stack + global _error_tos +_error_tos: + times STACK_SIZE dw 0x9090 ;480 - Disk Function Stack + global _disk_api_tos +_disk_api_tos: + times STACK_SIZE dw 0x9090 ;600 - Char Function Stack + global _char_api_tos +_char_api_tos: +apistk_top: + db 0 ; 780 ??? +_VolChange db 0 ;781 - volume change +_VirtOpen db 0 ;782 - virtual open flag + + ; controlled variables end at offset 78Ch so pad to end + times (78ch - ($ - _internal_data)) db 0 + +; +; end of controlled variables +; + +segment _BSS +;!! global _NumFloppies +;!!_NumFloppies resw 1 +;!!intr_dos_stk resw 1 +;!!intr_dos_seg resw 1 + + +; mark front and end of bss area to clear +segment IB_B + global __ib_start +__ib_start: +segment IB_E + global __ib_end +__ib_end: + ;; do not clear the other init BSS variables + STACK: too late. + +; kernel startup stack + global init_tos + resw 512 +init_tos: +; the last paragraph of conventional memory might become an MCB + resb 16 + global __init_end +__init_end: +init_end: + +segment _DATA +; blockdev private stack + global blk_stk_top + times 256 dw 0 +blk_stk_top: + +; clockdev private stack + global clk_stk_top + times 128 dw 0 +clk_stk_top: + +; Dynamic data: +; member of the DOS DATA GROUP +; and marks definitive end of all used data in kernel data segment +; + +segment _DATAEND + +_swap_indos: +; we don't know precisely what needs to be swapped before this, so set it here. +; this is just after FIXED_DATA+BSS+DATA and before (D)CONST+BSS +; probably, the clock and block stacks and disktransferbuffer should go past +; _swap_indos but only if int2a ah=80/81 (critical section start/end) +; are called upon entry and exit of the device drivers + + times 96 dw 0x9090 ; Process 0 Stack + global _p_0_tos +_p_0_tos: + +segment DYN_DATA + + global _Dyn +_Dyn: + DynAllocated dw 0 + +markEndInstanceData: ; mark end of DOS data seg we say needs instancing + + +segment ID_B + global __INIT_DATA_START +__INIT_DATA_START: +segment ID_E + global __INIT_DATA_END +__INIT_DATA_END: + + +segment INIT_TEXT_START + global __InitTextStart +__InitTextStart: ; and c version + +segment INIT_TEXT_END + global __InitTextEnd +__InitTextEnd: ; and c version + +; +; start end end of HMA area + +segment HMA_TEXT_START + global __HMATextAvailable +__HMATextAvailable: + global __HMATextStart +__HMATextStart: + +; +; the HMA area is filled with 1eh+3(=sizeof VDISK) = 33 byte dummy data, +; so nothing will ever be below 0xffff:0031 +; +segment HMA_TEXT +begin_hma: + times 10h db 0 ; filler [ffff:0..ffff:10] + times 20h db 0 + db 0 + +; to minimize relocations + global _DGROUP_ +_DGROUP_ dw DGROUP + +%ifdef WATCOM +; 32 bit multiplication + division +global __U4M +__U4M: + LMULU +global __U4D +__U4D: + LDIVMODU +%endif + + resb 0xd0 - ($-begin_hma) + ; reserve space for far jump to cp/m routine + resb 5 + +;End of HMA segment +segment HMA_TEXT_END + global __HMATextEnd +__HMATextEnd: ; and c version + + + +; The default stack (_TEXT:0) will overwrite the data area, so I create a dummy +; stack here to ease debugging. -- ror4 + +segment _STACK class=STACK stack + + + + + +segment CONST + ; dummy interrupt return handlers + + global _int22_handler + global _int28_handler + global _int2a_handler + global _empty_handler +_int22_handler: +_int28_handler: +_int2a_handler: +_empty_handler: + iret + + +global _initforceEnableA20 +initforceEnableA20: + call near forceEnableA20 + retf + + global __HMARelocationTableStart +__HMARelocationTableStart: + + global _int2f_handler + extern reloc_call_int2f_handler +_int2f_handler: jmp 0:reloc_call_int2f_handler + call near forceEnableA20 + + global _int20_handler + extern reloc_call_int20_handler +_int20_handler: jmp 0:reloc_call_int20_handler + call near forceEnableA20 + + global _int21_handler + extern reloc_call_int21_handler +_int21_handler: jmp 0:reloc_call_int21_handler + call near forceEnableA20 + + + global _low_int25_handler + extern reloc_call_low_int25_handler +_low_int25_handler: jmp 0:reloc_call_low_int25_handler + call near forceEnableA20 + + global _low_int26_handler + extern reloc_call_low_int26_handler +_low_int26_handler: jmp 0:reloc_call_low_int26_handler + call near forceEnableA20 + + global _int27_handler + extern reloc_call_int27_handler +_int27_handler: jmp 0:reloc_call_int27_handler + call near forceEnableA20 + + global _int0_handler + extern reloc_call_int0_handler +_int0_handler: jmp 0:reloc_call_int0_handler + call near forceEnableA20 + + global _int6_handler + extern reloc_call_int6_handler +_int6_handler: jmp 0:reloc_call_int6_handler + call near forceEnableA20 + + global _int19_handler + extern reloc_call_int19_handler +_int19_handler: jmp 0:reloc_call_int19_handler + call near forceEnableA20 + + global _cpm_entry + extern reloc_call_cpm_entry +_cpm_entry: jmp 0:reloc_call_cpm_entry + call near forceEnableA20 + + global _reloc_call_blk_driver + extern _blk_driver +_reloc_call_blk_driver: + jmp 0:_blk_driver + call near forceEnableA20 + + global _reloc_call_clk_driver + extern _clk_driver +_reloc_call_clk_driver: + jmp 0:_clk_driver + call near forceEnableA20 + + global _CharMapSrvc ; in _DATA (see AARD) + extern _reloc_call_CharMapSrvc +_CharMapSrvc: jmp 0:_reloc_call_CharMapSrvc + call near forceEnableA20 + + global _init_call_p_0 + extern reloc_call_p_0 +_init_call_p_0: jmp 0:reloc_call_p_0 + call near forceEnableA20 + + + global __HMARelocationTableEnd +__HMARelocationTableEnd: + +; +; if we were lucky, we found all entries from the outside to the kernel. +; if not, BUMS +; +; +; this routine makes the HMA area available. PERIOD. +; must conserve ALL registers +; will be only ever called, if HMA (DOS=HIGH) is enabled. +; for obvious reasons it should be located at the relocation table +; + global _XMSDriverAddress +_XMSDriverAddress: + dw 0 ; XMS driver, if detected + dw 0 + + global _ENABLEA20 +_ENABLEA20: + mov ah,5 +UsingXMSdriver: + push bx + call far [cs:_XMSDriverAddress] + pop bx + retf + + global _DISABLEA20 +_DISABLEA20: + mov ah,6 + jmp short UsingXMSdriver + +dslowmem dw 0 +eshighmem dw 0ffffh + + global forceEnableA20 +forceEnableA20: + + push ds + push es + push ax + +forceEnableA20retry: + mov ds, [cs:dslowmem] + mov es, [cs:eshighmem] + + mov ax, [ds:00000h] + cmp ax, [es:00010h] + jne forceEnableA20success + + mov ax, [ds:00002h] + cmp ax, [es:00012h] + jne forceEnableA20success + + mov ax, [ds:00004h] + cmp ax, [es:00014h] + jne forceEnableA20success + + mov ax, [ds:00006h] + cmp ax, [es:00016h] + jne forceEnableA20success + +; +; ok, we have to enable A20 )at least seems so +; + + call far _ENABLEA20 + + jmp short forceEnableA20retry + + + +forceEnableA20success: + pop ax + pop es + pop ds + ret + +; +; global f*cking compatibility issues: +; +; very old brain dead software (PKLITE, copyright 1990) +; forces us to execute with A20 disabled +; + +global _ExecUserDisableA20 + +_ExecUserDisableA20: + + cmp word [cs:_XMSDriverAddress], byte 0 + jne NeedToDisable + cmp word [cs:_XMSDriverAddress+2], byte 0 + je noNeedToDisable +NeedToDisable: + push ax + call far _DISABLEA20 + pop ax +noNeedToDisable: + iret + + +; +; Default Int 24h handler -- always returns fail +; so we have not to relocate it (now) +; +FAIL equ 03h + + global _int24_handler +_int24_handler: mov al,FAIL + iret + +; +; this makes some things easier +; + +segment _LOWTEXT + global _TEXT_DGROUP +_TEXT_DGROUP dw DGROUP + +segment INIT_TEXT + global _INIT_DGROUP +_INIT_DGROUP dw DGROUP diff --git a/kernel/kernel.cfg b/kernel/kernel.cfg new file mode 100644 index 0000000..38d5ef5 --- /dev/null +++ b/kernel/kernel.cfg @@ -0,0 +1,14 @@ +-1- +-f- +-ff- +-O +-Z +-d +-k- +-vi- +-w +-wpro +-weas +-wpre +-I..\hdr +-v -X- -I. -D__STDC__=0 -DTSC -DDEBUG -DKERNEL -DI86 -DPROTO -DSHWR -DASMSUPT diff --git a/kernel/lfnapi.c b/kernel/lfnapi.c new file mode 100644 index 0000000..b725d19 --- /dev/null +++ b/kernel/lfnapi.c @@ -0,0 +1,364 @@ +/****************************************************************/ +/* */ +/* lfnapi.c */ +/* */ +/* Directory access functions for LFN helper API */ +/* */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *lfnaidRcsId = + "$Id: lfnapi.c 1389 2009-05-20 18:13:37Z bartoldeman $"; +#endif + +#ifdef WITHLFNAPI + +#define RESERVED_FNODES 3 /* # of reserved fnodes for the kernel internal * + * usage. If something wrong happens with the * + * driver using helper API and it grabs all * + * possible fnodes, the kernel doesn't hang. */ + +/* All possible error codes, returned by directory access functions */ +/* Note. SUCCESS is returned if all OK. */ +#define LHE_INVLDHNDL -1 /* Invalid inode handle passed. */ +#define LHE_NOFREEHNDL -2 /* Couldn't allocate another inode handle. */ +#define LHE_IOERROR -3 /* Couldn't do I/O because of the lack of * + * memory or due to a physical damage. */ +#define LHE_INVLDDRV -4 /* Invalid drive chosen. */ +#define LHE_DAMAGEDFS -5 /* Damaged file system encountered. */ +#define LHE_NOSPACE -6 /* There are no free clusters on drive. */ +#define LHE_SEEK -7 /* Attempt to read beyound the end of the dir. */ + +#define lfn(fnp) ((struct lfn_entry FAR *)&(fnp->f_dir)) +#define CHARS_IN_LFN_ENTRY 13 +#define UNICODE_FILLER 0xffff + +COUNT ufstrlen(REG UNICODE FAR *); /* fstrlen for UNICODE strings */ +UBYTE lfn_checksum(UBYTE FAR *); +COUNT extend_dir(f_node_ptr); +BOOL lfn_to_unicode(UNICODE FAR **name, struct lfn_entry FAR *lep); +VOID unicode_to_lfn(UNICODE FAR **name, struct lfn_entry FAR *lep); + +/* Description. + * Allocates internal fnode and returns it's handle. + * Return value. + * LHE_NOFREEHNDL, LHE_INVLDDRV + * >= 0 - handle of the allocated fnode. + */ +COUNT lfn_allocate_inode(VOID) +{ + f_node_ptr fnp = get_f_node(&fnode[0]); + struct dpb FAR *dpbp; + COUNT handle; + if (fnp == 0) return LHE_NOFREEHNDL; + + handle = xlt_fnp(fnp); + /* Check if there is at least # RESERVED_FNODES left for the kernel */ + if (f_nodes_cnt - handle < RESERVED_FNODES) + { + release_f_node(fnp); + return LHE_NOFREEHNDL; + } + + /* Check that default drive is a block device */ + dpbp = get_dpb(default_drive); + + if (dpbp == 0) + { + release_f_node(fnp); + return LHE_INVLDDRV; + } + + fnp->f_dpb = dpbp; + + if (media_check(dpbp) < 0) + { + release_f_node(fnp); + return LHE_INVLDDRV; + } + + return handle; +} + +/* Description. + * Free allocated internal fnode. + * Return value. + * SUCCESS, LHE_INVLDHNDL + */ +COUNT lfn_free_inode(COUNT handle) +{ + f_node_ptr fnp = xlt_fd(handle); + if (fnp == 0 || fnp->f_count <= 0) return LHE_INVLDHNDL; + + dir_close(fnp); + + return SUCCESS; +} + +/* Description. + * Initialize internal fnode, so that it'll point to the directory entry + * at "diroff" entry offset from the start of the directory with the "dirstart" + * starting cluster. + * Return value. + * SUCCESS, LHE_INVLDHNDL + */ +COUNT lfn_setup_inode(COUNT handle, ULONG dirstart, UWORD diroff) +{ + f_node_ptr fnp = xlt_fd(handle); + if (fnp == 0 || fnp->f_count <= 0) return LHE_INVLDHNDL; + + dir_init_fnode(fnp, (CLUSTER)dirstart); + fnp->f_diroff = diroff; + + return SUCCESS; +} + +/* Description. + * Create LFN directory entries for the long name "lip->l_name", followed + * by the SFN entry with raw image "lip->l_dir". The "lip->l_diroff" points + * to the SFN entry on return. + * The internal fnode is released on fatal error, except LHE_INVLDHNDL of + * course. + * Return value. + * SUCCESS, LHE_INVLDHNDL, LHE_IOERROR, LHE_NOSPACE + */ +COUNT lfn_create_entries(COUNT handle, lfn_inode_ptr lip) +{ + f_node_ptr fnp = xlt_fd(handle); + COUNT entries_needed, free_entries, i, rc; + UNICODE FAR *lfn_name = lip->l_name; + UBYTE id = 1, sfn_checksum = lfn_checksum(lip->l_dir.dir_name); + unsigned sfn_offset; + if (fnp == 0 || fnp->f_count <= 0) return LHE_INVLDHNDL; + + entries_needed = (ufstrlen(lfn_name) + CHARS_IN_LFN_ENTRY - 1) + / CHARS_IN_LFN_ENTRY + 1; /* We want to create SFN entry too */ + + /* Scan the directory from the very begining for the free directory entries */ + lfn_setup_inode(handle, fnp->f_dirstart, 0); + + free_entries = 0; + while (TRUE) + { + rc = dir_read(fnp); + if (rc == 0 || fnp->f_dir.dir_name[0] == DELETED) + { + free_entries++; + if (free_entries == entries_needed) + break; + } + else if (rc == DE_BLKINVLD) + { + dir_close(fnp); + return LHE_IOERROR; + } + else if (rc == DE_SEEK) + { + if (extend_dir(fnp) != SUCCESS) return LHE_NOSPACE; + /* fnp points to the first free dir entry on return from extend_dir, + * so we go to previous entry to read this free entry on next cycle */ + fnp->f_diroff--; + } + else free_entries = 0; /* rc == 1 here => we've read some sfn entry */ + } + sfn_offset = fnp->f_diroff; + + fnp->f_flags.f_dmod = TRUE; + /* Write SFN entry */ + fmemcpy(&fnp->f_dir, &lip->l_dir, sizeof(struct dirent)); + dir_write(fnp); + + fnp->f_diroff--; + /* Go in the reverse direction and create LFN entries */ + for (i = 0; i < entries_needed - 1; i++, id++) + { + /* If this is the last LFN entry mark it's as those (6th bit is on) */ + if (i == (entries_needed - 2)) id |= 0x40; + lfn_name = &lip->l_name[i * CHARS_IN_LFN_ENTRY]; + unicode_to_lfn(&lfn_name, lfn(fnp)); + lfn(fnp)->lfn_checksum = sfn_checksum; + lfn(fnp)->lfn_id = id; + fnp->f_dir.dir_attrib = D_LFN; + if (!dir_write(fnp)) return LHE_IOERROR; + fnp->f_diroff--; + } + fnp->f_flags.f_dmod = FALSE; + + fnp->f_diroff = sfn_offset; + + return SUCCESS; +} + +/* Description. + * Read next consequitve long file name. The LFN is stored into the + * "lip->l_name" in unicode and the corresponding SFN entry raw image into the + * "lip->l_dir". If directory entry being read is a 8.3 file name, then + * it's image is stored into the "lip->l_dir" and "lip->l_name" has zero + * length, i.e. "lip->l_name[0]" == 0. + * Return value. + * SUCCESS, LHE_INVLDHNDL, LHE_IOERROR, LHE_SEEK, LHE_DAMAGEDFS + */ +COUNT lfn_dir_read(COUNT handle, lfn_inode_ptr lip) +{ + COUNT rc; + UBYTE id = 1, real_id; + UNICODE FAR *lfn_name = lip->l_name; + UWORD sfn_diroff; + BOOL name_tail; + f_node_ptr fnp = xlt_fd(handle); + if (fnp == 0 || fnp->f_count <= 0) return LHE_INVLDHNDL; + + /* Scan a directory for the next valid SFN entry */ + while (TRUE) + { + rc = dir_read(fnp); + if (rc == DE_SEEK) return LHE_SEEK; + else if (rc == DE_BLKINVLD) return LHE_IOERROR; + if (fnp->f_dir.dir_name[0] != DELETED && fnp->f_dir.dir_attrib != D_LFN) + { + fmemcpy(&lip->l_dir, &fnp->f_dir, sizeof(struct dirent)); + sfn_diroff = fnp->f_diroff; + break; + } + } + + /* Go in the reverse direction and find the LFN entries corresponding to + * the found SFN entry */ + while (TRUE) + { + if (fnp->f_diroff == 0) break; + fnp->f_diroff -= 2; + rc = dir_read(fnp); + if (rc == DE_BLKINVLD) return LHE_IOERROR; + if (fnp->f_dir.dir_name[0] == DELETED + || fnp->f_dir.dir_attrib != D_LFN) break; + real_id = lfn(fnp)->lfn_id; + if ((real_id & 0x3f) > 20) return LHE_DAMAGEDFS; + name_tail = lfn_to_unicode(&lfn_name, lfn(fnp)); + if (real_id & 0x40) + { + if ((id | 0x40) != real_id) return LHE_DAMAGEDFS; + break; + } + else + { + if (name_tail || real_id != id + || lfn(fnp)->lfn_checksum != lfn_checksum(lip->l_dir.dir_name)) + return LHE_DAMAGEDFS; + } + id++; + } + + *lfn_name = 0; /* Terminate LFN string */ + + fnp->f_diroff = lip->l_diroff = sfn_diroff; + + return SUCCESS; +} + +/* Description. + * Writes directory entry pointed by internal fnode to disk. + * The fnode is released on error. + * Return value. + * SUCCESS, LHE_INVLDHNDL, LHE_IOERROR. + */ +COUNT lfn_dir_write(COUNT handle) +{ + f_node_ptr fnp = xlt_fd(handle); + if (fnp == 0 || fnp->f_count <= 0) return LHE_INVLDHNDL; + + fnp->f_flags.f_dmod = TRUE; + if (!dir_write(fnp)) return LHE_IOERROR; + fnp->f_flags.f_dmod = FALSE; + + return SUCCESS; +} + +/*********************************************************************/ +/* Miscellaneous functions. These functions are not part of the API. */ +/*********************************************************************/ + +/* Description. + * Copy the block of "count" unicode characters from source pointed by + * "sptr" to destination pointed by "dptr". The trailing characters of + * destination are filled with "UNICODE_FILLER". + * Return value. + * TRUE - The source string is too short, trailing characters are filled + * with "UNICODE_FILLER". + * FALSE - The unicode strings have the same size, no filling occured. + */ +BOOL transfer_unicode(UNICODE FAR **dptr, UNICODE FAR **sptr, COUNT count) +{ + COUNT j; + BOOL found_zerro = FALSE; + + for (j = 0; j < count; j++, (*dptr)++, (*sptr)++) + { + if (found_zerro) **dptr = UNICODE_FILLER; + else **dptr = **sptr; + if (**sptr == 0) found_zerro = TRUE; + } + + return found_zerro; +} + +/* Description. + * Retrieve the LFN string chunk from the directory entry "lep" and store it + * to the "name" unicode string. + * Return value. + * TRUE - The LFN string chunk contains zero character. + * FALSE - Doesn't terminate with zero. + */ +BOOL lfn_to_unicode(UNICODE FAR **name, struct lfn_entry FAR *lep) +{ + UNICODE FAR *ptr; + + ptr = lep->lfn_name0_4; + if (transfer_unicode(name, &ptr, 5)) return TRUE; + ptr = lep->lfn_name5_10; + if (transfer_unicode(name, &ptr, 6)) return TRUE; + ptr = lep->lfn_name11_12; + if (transfer_unicode(name, &ptr, 2)) return TRUE; + + return FALSE; +} + +/* Description. + */ +VOID unicode_to_lfn(UNICODE FAR **name, struct lfn_entry FAR *lep) +{ + UNICODE FAR *ptr; + + ptr = lep->lfn_name0_4; + transfer_unicode(&ptr, name, 5); + ptr = lep->lfn_name5_10; + transfer_unicode(&ptr, name, 6); + ptr = lep->lfn_name11_12; + transfer_unicode(&ptr, name, 2); +} + +/* Calculate checksum for the 8.3 name */ +UBYTE lfn_checksum(UBYTE FAR *sfn_name) +{ + UBYTE sum; + COUNT i; + + for (sum = 0, i = 11; --i >= 0; sum += *sfn_name++) + sum = (sum << 7) | (sum >> 1); + + return sum; +} + +COUNT ufstrlen(REG UNICODE FAR *s) +{ + REG COUNT cnt = 0; + + while (*s++ != 0) + ++cnt; + return cnt; +} + +#endif diff --git a/kernel/ludivmul.inc b/kernel/ludivmul.inc new file mode 100644 index 0000000..1b2a80d --- /dev/null +++ b/kernel/ludivmul.inc @@ -0,0 +1,112 @@ +; this one adapted from elks, http://elks.sourceforge.net +; multiply cx:bx * dx:ax, result in dx:ax + +%macro LMULU 0 + + push si + push cx + mov si, ax ; save _ax in si + mov ax, bx ; cx:ax = _cx:_bx + mul dx ; dx:ax = _bx*_dx (forget dx) + xchg cx, ax ; cx = low(_dx*_bx) + mul si ; dx:ax = _cx*_ax (forget dx) + add cx, ax ; cx = low(_cx*_ax + _dx*_bx) + mov ax, si ; restore _ax + mul bx ; dx:ax = _bx*_ax + add dx, cx ; dx = high(_bx*_ax)+low(_cx*_ax + _dx*_bx) + pop cx + pop si + ret + +%endmacro + +; divide dx:ax / cx:bx, quotient in dx:ax, remainder in cx:bx + +%macro LDIVMODU 0 +; this one is adapted from an assembly gem: +; gem writer: Norbert Juffa, norbert.juffa@amd.com + +; Dividing 64-bit unsigned integers Assembler / 80386 + +; Here is a division routine for dividing two 64-bit unsigned integers. +; I derived it by modifying some old +; 16-bit code for dividing 32-bit integers that I did several years ago for a +; Turbo-Pascal replacement library. +; If a 64-bit signed integer division is needed, appropriate shell code for +; this routine can easily be written. +; +; (adapted back to 32-bit by Bart Oldeman ;-)) +; +; __U4D divides two unsigned long numbers, the dividend and the divisor +; resulting in a quotient and a remainder. +; +; input: +; dx:ax = dividend +; cx:bx = divisor +; +; output: +; dx:ax = quotient of division of dividend by divisor +; cx:bx = remainder of division of dividend by divisor +; +; destroys: +; flags +; + + test cx, cx ; divisor > 2^32-1 ? + jnz %%big_divisor ; yes, divisor > 32^32-1 + cmp dx, bx ; only one division needed ? (ecx = 0) + jb %%one_div ; yes, one division sufficient + + + xchg cx, ax ; save dividend-lo in cx, ax=0 + xchg ax, dx ; get dividend-hi in ax, dx=0 + div bx ; quotient-hi in eax + xchg ax, cx ; cx = quotient-hi, ax =dividend-lo + +%%one_div: + div bx ; ax = quotient-lo + mov bx, dx ; bx = remainder-lo + mov dx, cx ; dx = quotient-hi(quotient in dx:ax) + xor cx, cx ; cx = remainder-hi (rem. in cx:bx) + ret + +%%big_divisor: + push si ; save temp + push di ; variables + push dx ; save + push ax ; dividend + mov si, bx ; divisor now in + mov di, cx ; di:bx and cx:si +%%shift_loop: + shr dx, 1 ; shift both + rcr ax, 1 ; divisor and + shr di, 1 ; and dividend + rcr bx, 1 ; right by 1 bit + jnz %%shift_loop ; loop if di non-zero (rcr does not touch ZF) + mov di, cx ; restore original divisor (di:si) + div bx ; compute quotient + pop bx ; get dividend lo-word + mov cx, ax ; save quotient + mul di ; quotient * divisor hi-word (low only) + push di ; save divisor hi-word + xchg ax, di ; save in di + mov ax, cx ; ax=quotient + mul si ; quotient * divisor lo-word + add dx, di ; dx:ax = quotient * divisor + pop di ; restore divisor hi-word + sub bx, ax ; dividend-lo - (quot.*divisor)-lo + mov ax, cx ; get quotient + pop cx ; restore dividend hi-word + sbb cx, dx ; subtract divisor * quot. from dividend + sbb dx, dx ; 0 if remainder > 0, else FFFFFFFFh + and si, dx ; nothing to add + and di, dx ; back if remainder positive + add bx, si ; correct remaider + adc cx, di ; and quotient if + add ax, dx ; necessary + xor dx, dx ; clear hi-word of quot (ax<=FFFFFFFFh) + pop di ; restore temp + pop si ; variables + ret + +%endmacro \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c new file mode 100644 index 0000000..c9a52c8 --- /dev/null +++ b/kernel/main.c @@ -0,0 +1,782 @@ +/****************************************************************/ +/* */ +/* main.c */ +/* DOS-C */ +/* */ +/* Main Kernel Functions */ +/* */ +/* Copyright (c) 1995, 1996 */ +/* 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, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +/****************************************************************/ + +#include "portab.h" +#include "init-mod.h" +#include "dyndata.h" +#include "debug.h" + +#ifdef VERSION_STRINGS +static BYTE *mainRcsId = + "$Id: main.c 1699 2012-01-16 20:45:44Z perditionc $"; +#endif + +static char copyright[] = + "(C) Copyright 1995-2012 Pasquale J. Villani and The FreeDOS Project.\n" + "All Rights Reserved. This is free software and comes with ABSOLUTELY NO\n" + "WARRANTY; you can redistribute it and/or modify it under the terms of the\n" + "GNU General Public License as published by the Free Software Foundation;\n" + "either version 2, or (at your option) any later version.\n"; + +struct _KernelConfig InitKernelConfig BSS_INIT({0}); + +STATIC VOID InitIO(void); + +STATIC VOID update_dcb(struct dhdr FAR *); +STATIC VOID init_kernel(VOID); +STATIC VOID signon(VOID); +STATIC VOID kernel(VOID); +STATIC VOID FsConfig(VOID); +STATIC VOID InitPrinters(VOID); +STATIC VOID InitSerialPorts(VOID); +STATIC void CheckContinueBootFromHarddisk(void); +STATIC void setup_int_vectors(void); + +#ifdef _MSC_VER +BYTE _acrtused = 0; + +__segment DosDataSeg = 0; /* serves for all references to the DOS DATA segment + necessary for MSC+our funny linking model + */ +__segment DosTextSeg = 0; + +#endif + +struct lol FAR *LoL = &DATASTART; + +VOID ASMCFUNC FreeDOSmain(void) +{ + unsigned char drv; + unsigned char FAR *p; + +#ifdef _MSC_VER + extern FAR prn_dev; + DosDataSeg = (__segment) & DATASTART; + DosTextSeg = (__segment) & prn_dev; +#endif + + /* clear the Init BSS area (what normally the RTL does */ + memset(_ib_start, 0, _ib_end - _ib_start); + + /* if the kernel has been UPX'ed, + CONFIG info is stored at 50:e2 ..fc + and the bootdrive (passed from BIOS) + at 50:e0 + */ + + drv = LoL->BootDrive + 1; + p = MK_FP(0, 0x5e0); + if (fmemcmp(p+2,"CONFIG",6) == 0) /* UPX */ + { + fmemcpy(&InitKernelConfig, p+2, sizeof(InitKernelConfig)); + + drv = *p + 1; + *(DWORD FAR *)(p+2) = 0; + } + else + { + *p = drv - 1; + fmemcpy(&InitKernelConfig, &LowKernelConfig, sizeof(InitKernelConfig)); + } + + if (drv >= 0x80) + drv = 3; /* C: */ + LoL->BootDrive = drv; + + /* install DOS API and other interrupt service routines, basic kernel functionality works */ + setup_int_vectors(); + + CheckContinueBootFromHarddisk(); + + /* display copyright info and kernel emulation status */ + signon(); + + /* initialize all internal variables, process CONFIG.SYS, load drivers, etc */ + init_kernel(); + +#ifdef DEBUG + /* Non-portable message kludge alert! */ + printf("KERNEL: Boot drive = %c\n", 'A' + LoL->BootDrive - 1); +#endif + + DoInstall(); + + kernel(); +} + +/* + InitializeAllBPBs() + + or MakeNortonDiskEditorHappy() + + it has been determined, that FDOS's BPB tables are initialized, + only when used (like DIR H:). + at least one known utility (norton DE) seems to access them directly. + ok, so we access for all drives, that the stuff gets build +*/ +void InitializeAllBPBs(VOID) +{ + static char filename[] = "A:-@JUNK@-.TMP"; + int drive, fileno; + for (drive = 'C'; drive < 'A' + LoL->nblkdev; drive++) + { + filename[0] = drive; + if ((fileno = open(filename, O_RDONLY)) >= 0) + close(fileno); + } +} + +STATIC void PSPInit(void) +{ + psp far *p = MK_FP(DOS_PSP, 0); + + /* Clear out new psp first */ + fmemset(p, 0, sizeof(psp)); + + /* initialize all entries and exits */ + /* CP/M-like exit point */ + p->ps_exit = 0x20cd; + + /* CP/M-like entry point - call far to special entry */ + p->ps_farcall = 0x9a; + p->ps_reentry = MK_FP(0, 0x30 * 4); + /* unix style call - 0xcd 0x21 0xcb (int 21, retf) */ + p->ps_unix[0] = 0xcd; + p->ps_unix[1] = 0x21; + p->ps_unix[2] = 0xcb; + + /* Now for parent-child relationships */ + /* parent psp segment */ + p->ps_parent = FP_SEG(p); + /* previous psp pointer */ + p->ps_prevpsp = MK_FP(0xffff,0xffff); + + /* Environment and memory useage parameters */ + /* memory size in paragraphs */ + /* p->ps_size = 0; clear from above */ + /* environment paragraph */ + p->ps_environ = DOS_PSP + 8; + /* terminate address */ + p->ps_isv22 = getvec(0x22); + /* break address */ + p->ps_isv23 = getvec(0x23); + /* critical error address */ + p->ps_isv24 = getvec(0x24); + + /* user stack pointer - int 21 */ + /* p->ps_stack = NULL; clear from above */ + + /* File System parameters */ + /* maximum open files */ + p->ps_maxfiles = 20; + fmemset(p->ps_files, 0xff, 20); + + /* open file table pointer */ + p->ps_filetab = p->ps_files; + + /* first command line argument */ + /* p->ps_fcb1.fcb_drive = 0; already set */ + fmemset(p->ps_fcb1.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE); + /* second command line argument */ + /* p->ps_fcb2.fcb_drive = 0; already set */ + fmemset(p->ps_fcb2.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE); + + /* local command line */ + /* p->ps_cmd.ctCount = 0; command tail, already set */ + p->ps_cmd.ctBuffer[0] = 0xd; /* command tail */ +} + +#ifndef __WATCOMC__ +/* for WATCOMC we can use the ones in task.c */ +intvec getvec(unsigned char intno) +{ + intvec iv; + disable(); + iv = *(intvec FAR *)MK_FP(0,4 * (intno)); + enable(); + return iv; +} + +void setvec(unsigned char intno, intvec vector) +{ + disable(); + *(intvec FAR *)MK_FP(0,4 * intno) = vector; + enable(); +} +#endif + +STATIC void setup_int_vectors(void) +{ + static struct vec + { + unsigned char intno; + size_t handleroff; + } vectors[] = + { + /* all of these are in the DOS DS */ + { 0x0, FP_OFF(int0_handler) }, /* zero divide */ + { 0x1, FP_OFF(empty_handler) }, /* single step */ + { 0x3, FP_OFF(empty_handler) }, /* debug breakpoint */ + { 0x6, FP_OFF(int6_handler) }, /* invalid opcode */ + { 0x19, FP_OFF(int19_handler) }, + { 0x20, FP_OFF(int20_handler) }, + { 0x21, FP_OFF(int21_handler) }, + { 0x22, FP_OFF(int22_handler) }, + { 0x24, FP_OFF(int24_handler) }, + { 0x25, FP_OFF(low_int25_handler) }, + { 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) } + }; + struct vec *pvec; + struct lowvec FAR *plvec; + int i; + + for (plvec = intvec_table; plvec < intvec_table + 5; plvec++) + plvec->isv = getvec(plvec->intno); + for (i = 0x23; i <= 0x3f; i++) + setvec(i, empty_handler); + HaltCpuWhileIdle = 0; + for (pvec = vectors; pvec < vectors + (sizeof vectors/sizeof *pvec); pvec++) + setvec(pvec->intno, (intvec)MK_FP(FP_SEG(empty_handler), pvec->handleroff)); + pokeb(0, 0x30 * 4, 0xea); + pokel(0, 0x30 * 4 + 1, (ULONG)cpm_entry); + + /* these two are in the device driver area LOWTEXT (0x70) */ + setvec(0x1b, got_cbreak); + setvec(0x29, int29_handler); /* required for printf! */ +} + +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; + + /* Init oem hook - returns memory size in KB */ + ram_top = init_oem(); + + /* move kernel to high conventional RAM, just below the init code */ +#ifdef __WATCOMC__ + lpTop = MK_FP(_CS, 0); +#else + lpTop = MK_FP(_CS - (FP_OFF(_HMATextEnd) + 15) / 16, 0); +#endif + + MoveKernel(FP_SEG(lpTop)); + lpTop = MK_FP(FP_SEG(lpTop) - 0xfff, 0xfff0); + + /* Initialize IO subsystem */ + InitIO(); + InitPrinters(); + InitSerialPorts(); + + init_PSPSet(DOS_PSP); + set_DTA(MK_FP(DOS_PSP, 0x80)); + PSPInit(); + + Init_clk_driver(); + + /* Do first initialization of system variable buffers so that */ + /* we can read config.sys later. */ + + /* use largest possible value for the initial CDS */ + LoL->lastdrive = 26; + + /* init_device((struct dhdr FAR *)&blk_dev, NULL, 0, &ram_top); */ + blk_dev.dh_name[0] = dsk_init(); + + PreConfig(); + + /* Number of units */ + if (blk_dev.dh_name[0] > 0) + update_dcb(&blk_dev); + + /* Now config the temporary file system */ + FsConfig(); + + /* Now process CONFIG.SYS */ + DoConfig(0); + DoConfig(1); + + /* initialize near data and MCBs */ + PreConfig2(); + /* and process CONFIG.SYS one last time for device drivers */ + DoConfig(2); + + + /* Close all (device) files */ + for (i = 0; i < 20; i++) + close(i); + + /* and do final buffer allocation. */ + PostConfig(); + + /* Init the file system one more time */ + FsConfig(); + + configDone(); + + InitializeAllBPBs(); +} + +STATIC VOID FsConfig(VOID) +{ + struct dpb FAR *dpb = LoL->DPBp; + int i; + + /* Initialize the current directory structures */ + for (i = 0; i < LoL->lastdrive; i++) + { + struct cds FAR *pcds_table = &LoL->CDSp[i]; + + fmemcpy(pcds_table->cdsCurrentPath, "A:\\\0", 4); + + pcds_table->cdsCurrentPath[0] += i; + + if (i < LoL->nblkdev && (ULONG) dpb != 0xffffffffl) + { + pcds_table->cdsDpb = dpb; + pcds_table->cdsFlags = CDSPHYSDRV; + dpb = dpb->dpb_next; + } + else + { + pcds_table->cdsFlags = 0; + } + pcds_table->cdsStrtClst = 0xffff; + pcds_table->cdsParam = 0xffff; + pcds_table->cdsStoreUData = 0xffff; + pcds_table->cdsJoinOffset = 2; + } + + /* Log-in the default drive. */ + init_setdrive(LoL->BootDrive - 1); + + /* The system file tables need special handling and are "hand */ + /* built. Included is the stdin, stdout, stdaux and stdprn. */ + /* a little bit of shuffling is necessary for compatibility */ + + /* sft_idx=0 is /dev/aux */ + open("AUX", O_RDWR); + + /* handle 1, sft_idx=1 is /dev/con (stdout) */ + open("CON", O_RDWR); + + /* 3 is /dev/aux */ + dup2(STDIN, STDAUX); + + /* 0 is /dev/con (stdin) */ + dup2(STDOUT, STDIN); + + /* 2 is /dev/con (stdin) */ + dup2(STDOUT, STDERR); + + /* 4 is /dev/prn */ + open("PRN", O_WRONLY); + + /* Initialize the disk buffer management functions */ + /* init_call_init_buffers(); done from CONFIG.C */ +} + +STATIC VOID signon() +{ + printf("\r%S" + "Kernel compatibility %d.%d - " +#if defined(__BORLANDC__) + "BORLANDC" +#elif defined(__TURBOC__) + "TURBOC" +#elif defined(_MSC_VER) + "MSC" +#elif defined(__WATCOMC__) + "WATCOMC" +#elif defined(__GNUC__) + "GNUC" /* this is hypothetical only */ +#else +#error Unknown compiler + generate some bullshit error here, as the compiler should be known +#endif +#if defined (I386) + " - 80386 CPU required" +#elif defined (I186) + " - 80186 CPU required" +#endif + +#ifdef WITHFAT32 + " - FAT32 support" +#endif + "\n\n%s", + MK_FP(FP_SEG(LoL), FP_OFF(LoL->os_release)), + MAJOR_RELEASE, MINOR_RELEASE, copyright); +} + +STATIC void kernel() +{ + CommandTail Cmd; + + if (master_env[0] == '\0') /* some shells panic on empty master env. */ + strcpy(master_env, "PATH=."); + fmemcpy(MK_FP(DOS_PSP + 8, 0), master_env, sizeof(master_env)); + + /* process 0 */ + /* Execute command.com from the drive we just booted from */ + memset(Cmd.ctBuffer, 0, sizeof(Cmd.ctBuffer)); + strcpy(Cmd.ctBuffer, Config.cfgInitTail); + + for (Cmd.ctCount = 0; Cmd.ctCount < sizeof(Cmd.ctBuffer); Cmd.ctCount++) + if (Cmd.ctBuffer[Cmd.ctCount] == '\r') + break; + + /* if stepping CONFIG.SYS (F5/F8), tell COMMAND.COM about it */ + + /* 3 for string + 2 for "\r\n" */ + if (Cmd.ctCount < sizeof(Cmd.ctBuffer) - 5) + { + char *insertString = NULL; + + if (singleStep) + insertString = " /Y"; /* single step AUTOEXEC */ + + if (SkipAllConfig) + insertString = " /D"; /* disable AUTOEXEC */ + + if (insertString) + { + + /* insert /D, /Y as first argument */ + char *p, *q; + + for (p = Cmd.ctBuffer; p < &Cmd.ctBuffer[Cmd.ctCount]; p++) + { + if (*p == ' ' || *p == '\t' || *p == '\r') + { + for (q = &Cmd.ctBuffer[Cmd.ctCount + 1]; q >= p; q--) + q[3] = q[0]; + memcpy(p, insertString, 3); + break; + } + } + /* save buffer -- on the stack it's fine here */ + Config.cfgInitTail = Cmd.ctBuffer; + } + } + init_call_p_0(&Config); /* go execute process 0 (the shell) */ +} + +/* check for a block device and update device control block */ +STATIC VOID update_dcb(struct dhdr FAR * dhp) +{ + REG COUNT Index; + COUNT nunits = dhp->dh_name[0]; + struct dpb FAR *dpb; + + if (LoL->nblkdev == 0) + dpb = LoL->DPBp; + else + { + for (dpb = LoL->DPBp; (ULONG) dpb->dpb_next != 0xffffffffl; + dpb = dpb->dpb_next) + ; + dpb = dpb->dpb_next = + KernelAlloc(nunits * sizeof(struct dpb), 'E', Config.cfgDosDataUmb); + } + + for (Index = 0; Index < nunits; Index++) + { + dpb->dpb_next = dpb + 1; + dpb->dpb_unit = LoL->nblkdev; + dpb->dpb_subunit = Index; + dpb->dpb_device = dhp; + dpb->dpb_flags = M_CHANGED; + if ((LoL->CDSp != 0) && (LoL->nblkdev < LoL->lastdrive)) + { + LoL->CDSp[LoL->nblkdev].cdsDpb = dpb; + LoL->CDSp[LoL->nblkdev].cdsFlags = CDSPHYSDRV; + } + ++dpb; + ++LoL->nblkdev; + } + (dpb - 1)->dpb_next = (void FAR *)0xFFFFFFFFl; +} + +/* If cmdLine is NULL, this is an internal driver */ + +BOOL init_device(struct dhdr FAR * dhp, char *cmdLine, COUNT mode, + char FAR **r_top) +{ + request rq; + char name[8]; + + if (cmdLine) { + char *p, *q, ch; + int i; + + p = q = cmdLine; + for (;;) + { + ch = *p; + if (ch == '\0' || ch == ' ' || ch == '\t') + break; + p++; + if (ch == '\\' || ch == '/' || ch == ':') + q = p; /* remember position after path */ + } + for (i = 0; i < 8; i++) { + ch = '\0'; + if (p != q && *q != '.') + ch = *q++; + /* copy name, without extension */ + name[i] = ch; + } + } + + rq.r_unit = 0; + rq.r_status = 0; + rq.r_command = C_INIT; + rq.r_length = sizeof(request); + rq.r_endaddr = *r_top; + rq.r_bpbptr = (void FAR *)(cmdLine ? cmdLine : "\n"); + rq.r_firstunit = LoL->nblkdev; + + execrh((request FAR *) & rq, dhp); + +/* + * Added needed Error handle + */ + if ((rq.r_status & (S_ERROR | S_DONE)) == S_ERROR) + return TRUE; + + if (cmdLine) + { + /* Don't link in device drivers which do not take up memory */ + if (rq.r_endaddr == (BYTE FAR *) dhp) + return TRUE; + + /* Don't link in block device drivers which indicate no units */ + if (!(dhp->dh_attr & ATTR_CHAR) && !rq.r_nunits) + { + rq.r_endaddr = (BYTE FAR *) dhp; + return TRUE; + } + + + /* Fix for multisegmented device drivers: */ + /* If there are multiple device drivers in a single driver file, */ + /* only the END ADDRESS returned by the last INIT call should be */ + /* the used. It is recommended that all the device drivers in */ + /* the file return the same address */ + + if (FP_OFF(dhp->dh_next) == 0xffff) + { + KernelAllocPara(FP_SEG(rq.r_endaddr) + (FP_OFF(rq.r_endaddr) + 15)/16 + - FP_SEG(dhp), 'D', name, mode); + } + + /* Another fix for multisegmented device drivers: */ + /* To help emulate the functionallity experienced with other DOS */ + /* operating systems when calling multiple device drivers in a */ + /* single driver file, save the end address returned from the */ + /* last INIT call which will then be passed as the end address */ + /* for the next INIT call. */ + + *r_top = (char FAR *)rq.r_endaddr; + } + + if (!(dhp->dh_attr & ATTR_CHAR) && (rq.r_nunits != 0)) + { + dhp->dh_name[0] = rq.r_nunits; + update_dcb(dhp); + } + + if (dhp->dh_attr & ATTR_CONIN) + LoL->syscon = dhp; + else if (dhp->dh_attr & ATTR_CLOCK) + LoL->clock = dhp; + + return FALSE; +} + +STATIC void InitIO(void) +{ + struct dhdr far *device = &LoL->nul_dev; + + /* Initialize driver chain */ + do { + init_device(device, NULL, 0, &lpTop); + device = device->dh_next; + } + while (FP_OFF(device) != 0xffff); +} + +/* issue an internal error message */ +VOID init_fatal(BYTE * err_msg) +{ + printf("\nInternal kernel error - %s\nSystem halted\n", err_msg); + for (;;) ; +} + +/* + Initialize all printers + + this should work. IMHO, this might also be done on first use + of printer, as I never liked the noise by a resetting printer, and + I usually much more often reset my system, then I print :-) + */ + +STATIC VOID InitPrinters(VOID) +{ + iregs r; + int num_printers, i; + + init_call_intr(0x11, &r); /* get equipment list */ + + num_printers = (r.a.x >> 14) & 3; /* bits 15-14 */ + + for (i = 0; i < num_printers; i++) + { + r.a.x = 0x0100; /* initialize printer */ + r.d.x = i; + init_call_intr(0x17, &r); + } +} + +STATIC VOID InitSerialPorts(VOID) +{ + iregs r; + int serial_ports, i; + + init_call_intr(0x11, &r); /* get equipment list */ + + serial_ports = (r.a.x >> 9) & 7; /* bits 11-9 */ + + for (i = 0; i < serial_ports; i++) + { + r.a.x = 0xA3; /* initialize serial port to 2400,n,8,1 */ + r.d.x = i; + init_call_intr(0x14, &r); + } +} + +/***************************************************************** + if kernel.config.BootHarddiskSeconds is set, + the default is to boot from harddisk, because + the user is assumed to just have forgotten to + remove the floppy/bootable CD from the drive. + + user has some seconds to hit ANY key to continue + to boot from floppy/cd, else the system is + booted from HD +*/ + +STATIC int EmulatedDriveStatus(int drive,char statusOnly) +{ + iregs r; + char buffer[0x13]; + buffer[0] = 0x13; + + r.a.b.h = 0x4b; /* bootable CDROM - get status */ + r.a.b.l = statusOnly; + r.d.b.l = (char)drive; + r.si = (int)buffer; + init_call_intr(0x13, &r); + + if (r.flags & 1) + return FALSE; + + return TRUE; +} + +STATIC void CheckContinueBootFromHarddisk(void) +{ + char *bootedFrom = "Floppy/CD"; + iregs r; + int key; + + if (InitKernelConfig.BootHarddiskSeconds == 0) + return; + + if (LoL->BootDrive >= 3) + { +#if 0 + if (!EmulatedDriveStatus(0x80,1)) +#endif + { + /* already booted from HD */ + return; + } + } + else { +#if 0 + if (!EmulatedDriveStatus(0x00,1)) +#endif + bootedFrom = "Floppy"; + } + + printf("\n" + "\n" + "\n" + " Hit any key within %d seconds to continue boot from %s\n" + " Hit 'H' or wait %d seconds to boot from Harddisk\n", + InitKernelConfig.BootHarddiskSeconds, + bootedFrom, + InitKernelConfig.BootHarddiskSeconds + ); + + key = GetBiosKey(InitKernelConfig.BootHarddiskSeconds); + + if (key != -1 && (key & 0xff) != 'h' && (key & 0xff) != 'H') + { + /* user has hit a key, continue to boot from floppy/CD */ + printf("\n"); + return; + } + + /* reboot from harddisk */ + EmulatedDriveStatus(0x00,0); + EmulatedDriveStatus(0x80,0); + + /* now jump and run */ + r.a.x = 0x0201; + r.c.x = 0x0001; + r.d.x = 0x0080; + r.b.x = 0x7c00; + r.es = 0; + + init_call_intr(0x13, &r); + + { + void (far *reboot)(void) = (void (far*)(void)) MK_FP(0x0,0x7c00); + + (*reboot)(); + } +} diff --git a/kernel/makefile b/kernel/makefile new file mode 100644 index 0000000..ded0245 --- /dev/null +++ b/kernel/makefile @@ -0,0 +1,165 @@ +# +# Makefile for kernel.sys (originally for Borland C/C++ 3.1) +# + +!include "../mkfiles/generic.mak" + +LIBS=..$(DIRSEP)lib$(DIRSEP)device.lib ..$(DIRSEP)lib$(DIRSEP)libm.lib +HDR=../hdr/ + +# *List Macros* +# Only 8 files per definition; this is limitation of DOS batch +# files (only 9 directly accessible parameters). + +OBJS1=kernel.obj entry.obj io.obj console.obj serial.obj printer.obj dsk.obj \ +sysclk.obj +OBJS2=asmsupt.obj execrh.obj nlssupt.obj procsupt.obj dosidle.obj int2f.obj \ +nls_hc.obj +OBJS3=apisupt.obj intr.obj irqstack.obj blockio.obj chario.obj systime.obj \ +error.obj +OBJS4=break.obj dosfns.obj fatdir.obj fatfs.obj fattab.obj fcbfns.obj \ +inthndlr.obj +OBJS5=ioctl.obj memmgr.obj task.obj newstuff.obj nls.obj network.obj +OBJS6=prf.obj misc.obj strings.obj syspack.obj lfnapi.obj iasmsupt.obj memdisk.obj +OBJS7=main.obj config.obj initoem.obj inithma.obj dyninit.obj iprf.obj \ +initdisk.obj initclk.obj cpu.obj +OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(OBJS6) $(OBJS7) + +# *Explicit Rules* + +production: ../bin/$(TARGET).sys ../bin/country.sys + +../bin/$(TARGET).sys: kernel.sys + $(CP) kernel.sys ..$(DIRSEP)bin + $(CP) kernel.sys ..$(DIRSEP)bin$(DIRSEP)$(TARGET).sys + $(CP) kernel.map ..$(DIRSEP)bin$(DIRSEP)$(TARGET).map + +# -S to avoid showing expected relocations +# 0x10 & 0x78 or 0x79 depending on compilation options +kernel.sys: kernel.exe ../utils/exeflat.exe + ..$(DIRSEP)utils$(DIRSEP)exeflat.exe kernel.exe kernel.sys $(LOADSEG) -S0x10 -S0x78 -S0x79 $(UPXOPT) $(XUPX) + +kernel.exe: $(TARGET).lnk $(OBJS) $(LIBS) + $(LINK) @$(TARGET).lnk; + +../bin/country.sys: country.asm + $(NASM) -o $*.sys country.asm + +clobber: clean + -$(RM) kernel.exe kernel.sys status.me + +clean: + -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.cod *.err *.lnk + +# XXX: This is a very ugly way of linking the kernel, forced upon us by the +# inability of Turbo `make' 2.0 to perform command line redirection. -- ror4 + +$(TARGET).lnk: turboc.cfg makefile ../mkfiles/generic.mak ../mkfiles/$(COMPILER).mak + -$(RM) *.lnk + $(ECHOTO) $(TARGET).lnk $(OBJS1)+ + $(ECHOTO) $(TARGET).lnk $(OBJS2)+ + $(ECHOTO) $(TARGET).lnk $(OBJS3)+ + $(ECHOTO) $(TARGET).lnk $(OBJS4)+ + $(ECHOTO) $(TARGET).lnk $(OBJS5)+ + $(ECHOTO) $(TARGET).lnk $(OBJS6)+ + $(ECHOTO) $(TARGET).lnk $(OBJS7) + $(ECHOTO) $(TARGET).lnk kernel.exe + $(ECHOTO) $(TARGET).lnk kernel.map + $(ECHOTO) $(TARGET).lnk $(LIBS) + +# *Individual File Dependencies* +apisupt.obj: apisupt.asm segs.inc $(TARGET).lnk +asmsupt.obj: asmsupt.asm segs.inc $(TARGET).lnk +console.obj: console.asm io.inc $(TARGET).lnk +cpu.obj: cpu.asm segs.inc $(TARGET).lnk +dosidle.obj: dosidle.asm segs.inc $(TARGET).lnk +entry.obj: entry.asm segs.inc $(HDR)stacks.inc $(TARGET).lnk +execrh.obj: execrh.asm segs.inc $(TARGET).lnk +int2f.obj: int2f.asm segs.inc $(HDR)stacks.inc $(TARGET).lnk +intr.obj: intr.asm segs.inc $(TARGET).lnk +io.obj: io.asm segs.inc $(HDR)stacks.inc $(TARGET).lnk +irqstack.obj: irqstack.asm segs.inc $(TARGET).lnk +kernel.obj: kernel.asm segs.inc ludivmul.inc $(TARGET).lnk +memdisk.obj: memdisk.asm segs.inc $(TARGET).lnk +nls_hc.obj: nls_hc.asm segs.inc $(TARGET).lnk +nlssupt.obj: nlssupt.asm segs.inc $(HDR)stacks.inc $(TARGET).lnk +printer.obj: printer.asm io.inc $(TARGET).lnk +procsupt.obj: procsupt.asm segs.inc $(HDR)stacks.inc $(TARGET).lnk +serial.obj: serial.asm io.inc $(TARGET).lnk + +HDRS=\ + $(HDR)portab.h $(HDR)device.h $(HDR)mcb.h $(HDR)pcb.h \ + $(HDR)fat.h $(HDR)fcb.h $(HDR)tail.h $(HDR)time.h $(HDR)process.h \ + $(HDR)dcb.h $(HDR)sft.h $(HDR)cds.h $(HDR)exe.h $(HDR)fnode.h \ + $(HDR)dirmatch.h $(HDR)file.h $(HDR)clock.h $(HDR)kbd.h $(HDR)error.h \ + $(HDR)version.h dyndata.h +HEADERS=$(HDRS) globals.h proto.h +INITHEADERS=$(HDRS) init-mod.h init-dat.h + +blockio.obj: blockio.c $(HEADERS) $(TARGET).lnk +break.obj: break.c $(HEADERS) $(TARGET).lnk +chario.obj: chario.c $(HEADERS) $(TARGET).lnk +dosfns.obj: dosfns.c $(HEADERS) $(TARGET).lnk +dsk.obj: dsk.c $(HEADERS) $(TARGET).lnk +error.obj: error.c $(HEADERS) $(TARGET).lnk +fatdir.obj: fatdir.c $(HEADERS) $(TARGET).lnk +fatfs.obj: fatfs.c $(HEADERS) $(TARGET).lnk +fattab.obj: fattab.c $(HEADERS) $(TARGET).lnk +fcbfns.obj: fcbfns.c $(HEADERS) $(TARGET).lnk +inthndlr.obj: inthndlr.c $(HEADERS) $(TARGET).lnk +ioctl.obj: ioctl.c $(HEADERS) $(TARGET).lnk +memmgr.obj: memmgr.c $(HEADERS) $(TARGET).lnk +misc.obj: misc.c $(HEADERS) $(TARGET).lnk +lfnapi.obj: lfnapi.c $(HEADERS) $(TARGET).lnk +newstuff.obj: newstuff.c $(HEADERS) $(TARGET).lnk +network.obj: network.c $(HEADERS) $(TARGET).lnk +nls.obj: nls.c $(HEADERS) $(TARGET).lnk +prf.obj: prf.c $(HDR)portab.h $(TARGET).lnk +strings.obj: strings.c $(TARGET).lnk +sysclk.obj: sysclk.c $(HEADERS) $(TARGET).lnk +syspack.obj: syspack.c $(HEADERS) $(TARGET).lnk +systime.obj: systime.c $(HEADERS) $(TARGET).lnk +task.obj: task.c $(HEADERS) $(TARGET).lnk + +# now the funny stuff :-) +# Files in the INIT segment + +# XXX: Special handling for initialization modules -- this is required because +# TC 2.01 cannot handle `#pragma option' like TC 3 can. -- ror4 + +config.obj: config.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +initoem.obj: initoem.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +main.obj: main.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +inithma.obj: inithma.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +dyninit.obj: dyninit.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +initdisk.obj: initdisk.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +initclk.obj: initclk.c $(INITHEADERS) $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +#the string functions for INIT_TEXT +iasmsupt.obj: asmsupt.asm $(TARGET).lnk + $(NASM) -D$(COMPILER) -D_INIT $(NASMFLAGS) -f obj -o iasmsupt.obj asmsupt.asm + +#the printf for INIT_TEXT - yet another special case, this file includes prf.c +iprf.obj: iprf.c prf.c $(HDR)portab.h $(TARGET).lnk + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj diff --git a/kernel/memdisk.asm b/kernel/memdisk.asm new file mode 100644 index 0000000..fb76e64 --- /dev/null +++ b/kernel/memdisk.asm @@ -0,0 +1,79 @@ +; File: +; memdisk.asm +; Description: +; Query for memdisk provided config.sys parameters +; +; DOS-C +; Copyright (c) 2011 +; FreeDOS +; 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. +; +; + +; requires 386+ registers, check LoL->CPU >=3 prior to calling (or use 386 build) + +%include "segs.inc" +segment INIT_TEXT + +CPU 386 +;********************************************************************* +; +; query_memdisk() based on similar subroutine in Eric Auer's public domain getargs.asm which is based on IFMEMDSK +; input: drive (in AL) to query if memdisk provided disk +; output: a far * to a memdiskinfo structure as defined by memdisk (see config.c) +; struct memdiskinfo FAR * query_memdisk(UBYTE drive); + global _query_memdisk + _query_memdisk: + ; save registers, assumes enough space on stack & valid stack frame setup, ax & dx return values + push es + push di + push ebx + push ecx + push edx ; we only care about high word + push eax ; we only care about high word + mov edx,53490000h ; magic3 + + mov dl, al ; drive number (only argument, assumed to be in AL) + mov eax,454d0800h ; magic1 + AH=8 (get geometry) + mov ecx,444d0000h ; magic2 + mov ebx,3f4b0000h ; magic4 + int 13h ; BIOS DISK API + shr eax,16 ; ignore AX + shr ebx,16 ; ignore BX + shr ecx,16 ; ignore CX (geometry C/S) + shr edx,16 ; ignore DX (geometry H in DH) + cmp ax,4d21h ; magic5 + jnz nomemdisk + cmp cx,4d45h ; magic6 + jnz nomemdisk + cmp dx,4944h ; magic7 + jnz nomemdisk + cmp bx,4b53h ; magic8 + jnz nomemdisk + jmp cleanup + + nomemdisk: + xor di, di ; return NULL; + mov es, di + + cleanup: + pop eax + pop edx + mov ax, di ; return MK_FP(es, di); + mov dx, es + pop ecx + pop ebx + pop di + pop es + retn diff --git a/kernel/memmgr.c b/kernel/memmgr.c new file mode 100644 index 0000000..96edcef --- /dev/null +++ b/kernel/memmgr.c @@ -0,0 +1,495 @@ +/****************************************************************/ +/* */ +/* memmgr.c */ +/* */ +/* Memory Manager for Core Allocation */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRING +static BYTE *memmgrRcsId = + "$Id: memmgr.c 1338 2007-07-20 20:52:33Z mceric $"; +#endif + +#define nxtMCBsize(mcb,size) MK_FP(FP_SEG(mcb) + (size) + 1, FP_OFF(mcb)) +#define nxtMCB(mcb) nxtMCBsize((mcb), (mcb)->m_size) + +#define mcbFree(mcb) ((mcb)->m_psp == FREE_PSP) +#define mcbValid(mcb) ( ((mcb)->m_size != 0xffff) && \ + ((mcb)->m_type == MCB_NORMAL || (mcb)->m_type == MCB_LAST) ) +#define mcbFreeable(mcb) \ + ((mcb)->m_type == MCB_NORMAL || (mcb)->m_type == MCB_LAST) + +#define para2far(seg) (mcb FAR *)MK_FP((seg) , 0) + +/* + * Join any following unused MCBs to MCB 'p'. + * Return: + * SUCCESS: on success + * else: error number <> + */ +STATIC COUNT joinMCBs(seg para) +{ + mcb FAR *p = para2far(para); + mcb FAR *q; + + /* loop as long as the current MCB is not the last one in the chain + and the next MCB is unused */ + while (p->m_type == MCB_NORMAL) + { + q = nxtMCB(p); + if (!mcbFree(q)) + break; + if (!mcbValid(q)) + return DE_MCBDESTRY; + /* join both MCBs */ + p->m_type = q->m_type; /* possibly the next MCB is the last one */ + p->m_size += q->m_size + 1; /* one for q's MCB itself */ +#if 0 /* this spoils QB4's habit to double-free: */ + q->m_type = 'K'; /* Invalidate the magic number (whole MCB) */ +#else + q->m_size = 0xffff; /* mark the now unlinked MCB as "fake" */ +#endif + } + + return SUCCESS; +} + +/* + * Return a normalized far pointer + */ +void FAR * adjust_far(const void FAR * fp) +{ + /* and return an adddress adjusted to the nearest paragraph */ + /* boundary. */ + + if (FP_SEG(fp) == 0xffff) + return (void FAR *)fp; + +#ifndef I86 + if (FP_SEG(fp) == 0) + return (void FAR *)fp; +#endif + + return MK_FP(FP_SEG(fp) + (FP_OFF(fp) >> 4), FP_OFF(fp) & 0xf); +} + +#undef REG +#define REG + +#if 1 /* #ifdef KERNEL KERNEL */ +/* Allocate a new memory area. *para is assigned to the segment of the + MCB rather then the segment of the data portion */ +/* If mode == LARGEST, asize MUST be != NULL and will always recieve the + largest available block, which is allocated. + If mode != LARGEST, asize maybe NULL, but if not, it is assigned to the + size of the largest available block only on failure. + size is the minimum size of the block to search for, + even if mode == LARGEST. + */ +COUNT DosMemAlloc(UWORD size, COUNT mode, seg *para, UWORD *asize) +{ + REG mcb FAR *p; + mcb FAR *foundSeg; + mcb FAR *biggestSeg; + /* Initialize */ + +searchAgain: + + p = para2far(first_mcb); + + biggestSeg = foundSeg = NULL; +/* + Hack to the Umb Region direct for now. Save time and program space. +*/ + if ((uppermem_link & 1) && uppermem_root != 0xffff) + { + COUNT tmpmode = (mode == LARGEST ? mem_access_mode : mode); + if ((mode != LARGEST || size == 0xffff) && + (tmpmode & (FIRST_FIT_UO | FIRST_FIT_U))) + p = para2far(uppermem_root); + } + + /* Search through memory blocks */ + FOREVER + { + /* check for corruption */ + if (!mcbValid(p)) + return DE_MCBDESTRY; + + if (mcbFree(p)) + { /* unused block, check if it applies to the rule */ + if (joinMCBs(FP_SEG(p)) != SUCCESS) /* join following unused blocks */ + return DE_MCBDESTRY; /* error */ + + if (!biggestSeg || biggestSeg->m_size < p->m_size) + biggestSeg = p; + + if (p->m_size >= size) + { /* if the block is too small, ignore */ + /* this block has a "match" size, try the rule set */ + switch (mode) + { + case LAST_FIT: /* search for last possible */ + case LAST_FIT_U: + case LAST_FIT_UO: + default: + foundSeg = p; + break; + + case LARGEST: /* grab the biggest block */ + /* it is calculated when the MCB chain + was completely checked */ + break; + + case BEST_FIT: /* first, but smallest block */ + case BEST_FIT_U: + case BEST_FIT_UO: + if (!foundSeg || foundSeg->m_size > p->m_size) + /* better match found */ + foundSeg = p; + break; + + case FIRST_FIT: /* first possible */ + case FIRST_FIT_U: + case FIRST_FIT_UO: + foundSeg = p; + goto stopIt; /* OK, rest of chain can be ignored */ + + } + } + } + + if (p->m_type == MCB_LAST) + break; /* end of chain reached */ + + p = nxtMCB(p); /* advance to next MCB */ + } + + if (mode == LARGEST && biggestSeg && biggestSeg->m_size >= size) + *asize = (foundSeg = biggestSeg)->m_size; + + if (!foundSeg || !foundSeg->m_size) + { /* no block to fullfill the request */ + if ((mode != LARGEST) && (mode & FIRST_FIT_U) && + (uppermem_link & 1) && uppermem_root != 0xffff) + { + mode &= ~FIRST_FIT_U; + goto searchAgain; + } + if (asize) + *asize = biggestSeg ? biggestSeg->m_size : 0; + return DE_NOMEM; + } + +stopIt: /* reached from FIRST_FIT on match */ + + if (mode != LARGEST && size != foundSeg->m_size) + { + /* Split the found buffer because it is larger than requested */ + /* foundSeg := pointer to allocated block + p := pointer to MCB that will form the rest of the block + */ + if ((mode == LAST_FIT) || (mode == LAST_FIT_UO) + || (mode == LAST_FIT_U)) + { + /* allocate the block from the end of the found block */ + p = foundSeg; + p->m_size -= size + 1; /* size+1 paragraphes are allocated by + the new segment (+1 for MCB itself) */ + foundSeg = nxtMCB(p); + + /* initialize stuff because foundSeg > p */ + foundSeg->m_type = p->m_type; + p->m_type = MCB_NORMAL; + } + else + { /* all other modes allocate from the beginning */ + p = nxtMCBsize(foundSeg, size); + + /* initialize stuff because p > foundSeg */ + p->m_type = foundSeg->m_type; + p->m_size = foundSeg->m_size - size - 1; + foundSeg->m_type = MCB_NORMAL; + } + + /* Already initialized: + p->m_size, ->m_type, foundSeg->m_type + */ + p->m_psp = FREE_PSP; /* unused */ + + foundSeg->m_size = size; + } + + /* Already initialized: + foundSeg->m_size, ->m_type + */ + foundSeg->m_psp = cu_psp; /* the new block is for current process */ + foundSeg->m_name[0] = '\0'; + + *para = FP_SEG(foundSeg); + return SUCCESS; +} + +/* + * Unlike the name and the original prototype could suggest, this function + * is used to return the _size_ of the largest available block rather than + * the block itself. + * + * Known bug: a memory area with a size of the data area of 0 (zero) is + * not considered a "largest" block. <> + */ +COUNT DosMemLargest(UWORD *size) +{ + seg dummy; + *size = 0; + DosMemAlloc(0xffff, LARGEST, &dummy, size); + if (mem_access_mode & 0x80) /* then the largest block is probably low! */ + { + UWORD lowsize = 0; + mem_access_mode &= ~0x80; + DosMemAlloc(0xffff, LARGEST, &dummy, &lowsize); + mem_access_mode |= 0x80; + if (lowsize > *size) + *size = lowsize; + } + return *size ? SUCCESS : DE_NOMEM; +} + +/* + * Deallocate a memory block. para is the segment of the MCB itself + * This function can be called with para == 0, which eases other parts + * of the kernel. + */ +COUNT DosMemFree(UWORD para) +{ + REG mcb FAR *p; + + if (!para) /* let esp. the kernel call this fct with para==0 */ + return DE_INVLDMCB; + + /* Initialize */ + p = para2far(para); + + /* check for corruption */ + if (!mcbFreeable(p)) /* does not have to be valid, freeable is enough */ + return DE_INVLDMCB; + + /* Mark the mcb as free so that we can later */ + /* merge with other surrounding free MCBs */ + p->m_psp = FREE_PSP; + fmemset(p->m_name, '\0', 8); + + return SUCCESS; +} + +/* + * Resize an allocated memory block. + * para is the segment of the data portion of the block rather than + * the segment of the MCB itself. + * + * If the block shall grow, it is resized to the maximal size less than + * or equal to size. This is the way MS DOS is reported to work. + */ +COUNT DosMemChange(UWORD para, UWORD size, UWORD * maxSize) +{ + REG mcb FAR *p, FAR * q; + + /* Initialize */ + p = para2far(para - 1); /* pointer to MCB */ + + /* check for corruption */ + if (!mcbValid(p)) + return DE_MCBDESTRY; + + /* check if to grow the block */ + if (size > p->m_size) + { + /* first try to make the MCB larger by joining with any following + unused blocks */ + if (joinMCBs(FP_SEG(p)) != SUCCESS) + return DE_MCBDESTRY; + + if (size > p->m_size) + { /* block is still too small */ + if (maxSize) + *maxSize = p->m_size; + return DE_NOMEM; + } + } + + /* shrink it down */ + if (size < p->m_size) + { + /* make q a pointer to the new next block */ + q = nxtMCBsize(p, size); + /* reduce the size of p and add difference to q */ + q->m_size = p->m_size - size - 1; + q->m_type = p->m_type; + + p->m_size = size; + + /* Make certian the old psp is not last (if it was) */ + p->m_type = MCB_NORMAL; + + /* Mark the mcb as free so that we can later */ + /* merge with other surrounding free MCBs */ + q->m_psp = FREE_PSP; + fmemset(q->m_name, '\0', 8); + + /* try to join q with the free MCBs following it if possible */ + if (joinMCBs(FP_SEG(q)) != SUCCESS) + return DE_MCBDESTRY; + } + + /* MS network client NET.EXE: DosMemChange sets the PSP * + * not tested, if always, or only on success TE* + * only on success seems more logical to me - Bart */ + p->m_psp = cu_psp; + + return SUCCESS; +} + +/* + * Check the MCB chain for allocation corruption + */ +COUNT DosMemCheck(void) +{ + REG mcb FAR *p; + REG mcb FAR *pprev = 0; + + /* Initialize */ + p = para2far(first_mcb); + + /* Search through memory blocks */ + while (p->m_type != MCB_LAST) /* not all MCBs touched */ + { + /* check for corruption */ + if (p->m_type != MCB_NORMAL) + { + put_string("dos mem corrupt, first_mcb="); + put_unsigned(first_mcb, 16, 4); + hexd("\nprev ", pprev, 16); + hexd("notMZ", p, 16); + return DE_MCBDESTRY; + } + + /* not corrupted - but not end, bump the pointer */ + pprev = p; + p = nxtMCB(p); + } + return SUCCESS; +} + +COUNT FreeProcessMem(UWORD ps) +{ + mcb FAR *p; + BYTE oldumbstate = uppermem_link & 1; + + /* link in upper memory to free those , too */ + DosUmbLink(1); + + /* Search through all memory blocks */ + for (p = para2far(first_mcb);; p = nxtMCB(p)) + { + + if (!mcbValid(p)) /* check for corruption */ + return DE_MCBDESTRY; + + if (p->m_psp == ps) + DosMemFree(FP_SEG(p)); + + if (p->m_type == MCB_LAST) + break; + } + + DosUmbLink(oldumbstate); + + return SUCCESS; +} + +#ifdef DEBUG +VOID show_chain(void) +{ + mcb FAR *p; + p = para2far(first_mcb); + + for (;;) + { + mcb_print(p); + if (p->m_type == MCB_LAST || p->m_type != MCB_NORMAL) + return; + else + p = nxtMCB(p); + } +} + +VOID mcb_print(mcb FAR * mcbp) +{ + static BYTE buff[9]; + + fmemcpy(buff, mcbp->m_name, 8); + buff[8] = '\0'; + printf + ("%04x:%04x -> |%s| m_type = 0x%02x '%c'; m_psp = 0x%04x; m_size = 0x%04x\n", + FP_SEG(mcbp), FP_OFF(mcbp), *buff == '\0' ? "*NO-ID*" : buff, + mcbp->m_type, mcbp->m_type > ' ' ? mcbp->m_type : ' ', mcbp->m_psp, + mcbp->m_size); +} +#endif + +void DosUmbLink(unsigned n) +{ + REG mcb FAR *p; + REG mcb FAR *q; + + if (uppermem_root == 0xffff) + return; + + p = para2far(first_mcb); + if (n > 1 || (uppermem_link & 1) == n) + return; + while (FP_SEG(p) != uppermem_root && p->m_type != MCB_LAST) + { + if (!mcbValid(p)) + return; + q = p; + p = nxtMCB(p); + } + if (n == 0) + { + if (q->m_type == MCB_NORMAL && FP_SEG(p) == uppermem_root) + q->m_type = MCB_LAST; + } + else if (p->m_type == MCB_LAST) + p->m_type = MCB_NORMAL; + else + return; + uppermem_link = n; +} + +#endif + diff --git a/kernel/misc.c b/kernel/misc.c new file mode 100644 index 0000000..58007c5 --- /dev/null +++ b/kernel/misc.c @@ -0,0 +1,79 @@ +/****************************************************************/ +/* */ +/* misc.c */ +/* */ +/* Miscellaneous Kernel Functions */ +/* */ +/* Copyright (c) 1993 */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" + +#ifdef VERSION_STRINGS +static BYTE *miscRcsId = + "$Id: misc.c 653 2003-08-09 09:35:18Z bartoldeman $"; +#endif + +#include "globals.h" +#ifndef I86 + +char *strcpy(REG BYTE * d, REG CONST BYTE * s) +{ + char *tmp = d; + + while ((*d++ = *s++) != '\0') + ; + + return tmp; +} + +VOID fstrcpy(REG BYTE FAR * d, REG CONST BYTE FAR * s) +{ + while (*s) + *d++ = *s++; + *d = '\0'; +} + +VOID * memcpy(REG VOID * d, REG CONST VOID * s, REG size_t n) +{ + char *cd = d; + CONST char *cs = s; + + while (n--) + *cd++ = *cs++; + return d; +} + +VOID fmemcpy(REG VOID FAR * d, REG CONST VOID FAR * s, REG size_t n) +{ + while (n--) + *((BYTE FAR *) d)++ = *((BYTE FAR *) s)++; +} + +VOID fmemset(REG VOID FAR * s, REG int ch, REG size_t n) +{ + while (n--) + *((BYTE FAR *) s)++ = ch; +} + +#endif + diff --git a/kernel/network.c b/kernel/network.c new file mode 100644 index 0000000..8e9e3c8 --- /dev/null +++ b/kernel/network.c @@ -0,0 +1,63 @@ +/****************************************************************/ +/* */ +/* network.c */ +/* DOS-C */ +/* */ +/* Networking Support functions */ +/* */ +/* Copyright (c) 1995, 1999 */ +/* James Tabor */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: network.c 895 2004-04-21 17:40:12Z bartoldeman $"; +#endif + +/* see RBIL D-2152 and D-215D06 before attempting + to change these two functions! + */ +UWORD get_machine_name(BYTE FAR * netname) +{ + fmemcpy(netname, &net_name, 16); + return (NetBios); +} + +VOID set_machine_name(BYTE FAR * netname, UWORD name_num) +{ + NetBios = name_num; + fmemcpy(&net_name, netname, 15); + net_set_count++; +} + +int network_redirector_fp(unsigned cmd, void far *s) +{ + return (int)network_redirector_mx(cmd, s, 0); +} + +int network_redirector(unsigned cmd) +{ + return network_redirector_fp(cmd, NULL); +} + diff --git a/kernel/newstuff.c b/kernel/newstuff.c new file mode 100644 index 0000000..eef102d --- /dev/null +++ b/kernel/newstuff.c @@ -0,0 +1,717 @@ +/****************************************************************/ +/* */ +/* newstuff.c */ +/* DOS-C */ +/* */ +/* Copyright (c) 1996 */ +/* Svante Frey */ +/* 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. */ +/****************************************************************/ + +#ifdef VERSION_STRINGS +static BYTE *mainRcsId = + "$Id: newstuff.c 1479 2009-07-07 13:33:24Z bartoldeman $"; +#endif + +#include "portab.h" +#include "globals.h" + +/* + TE-TODO: if called repeatedly by same process, + last allocation must be freed. if handle count < 20, copy back to PSP +*/ +int SetJFTSize(UWORD nHandles) +{ + UWORD block, maxBlock, i; + psp FAR *ppsp = MK_FP(cu_psp, 0); + UBYTE FAR *newtab; + + if (nHandles <= ppsp->ps_maxfiles) + { + ppsp->ps_maxfiles = nHandles; + return SUCCESS; + } + + if ((DosMemAlloc + ((nHandles + 0xf) >> 4, mem_access_mode, &block, &maxBlock)) < 0) + return DE_NOMEM; + + ++block; + newtab = MK_FP(block, 0); + + i = ppsp->ps_maxfiles; + /* copy existing part and fill up new part by "no open file" */ + fmemcpy(newtab, ppsp->ps_filetab, i); + fmemset(newtab + i, 0xff, nHandles - i); + + ppsp->ps_maxfiles = nHandles; + ppsp->ps_filetab = newtab; + + return SUCCESS; +} + +long DosMkTmp(BYTE FAR * pathname, UWORD attr) +{ + /* create filename from current date and time */ + char FAR *ptmp; + unsigned long randvar; + long rc; + int loop; + + ptmp = pathname + fstrlen(pathname); + if (os_major == 5) { /* clone some bad habit of MS DOS 5.0 only */ + if (ptmp == pathname || (ptmp[-1] != '\\' && ptmp[-1] != '/')) + *ptmp++ = '\\'; + } + ptmp[8] = '\0'; + + randvar = ((unsigned long)dos_getdate() << 16) | dos_gettime(); + + loop = 0; + do { + unsigned long tmp = randvar++; + int i; + for(i = 7; i >= 0; tmp >>= 4, i--) + ptmp[i] = ((char)tmp & 0xf) + 'A'; + + /* DOS versions: > 5: characters A - P + < 5: hex digits */ + if (os_major < 5) + for (i = 0; i < 8; i++) + ptmp[i] -= (ptmp[i] < 'A' + 10) ? '0' - 'A' : 10; + + /* only create new file -- 2001/09/22 ska*/ + rc = DosOpen(pathname, O_LEGACY | O_CREAT | O_RDWR, attr); + } while (rc == DE_FILEEXISTS && loop++ < 0xfff); + + return rc; +} + +#ifdef DEBUG +#define DEBUG_TRUENAME +#endif + +#define drLetterToNr(dr) ((unsigned char)((dr) - 'A')) +/* Convert an uppercased drive letter into the drive index */ +#define drNrToLetter(dr) ((dr) + 'A') +/* the other direction */ + + /* In DOS there are no free-standing UNC paths, therefore there + is always a logical drive letter associated with a path + spec. This letter is also the index into the CDS */ + +/* + Definition of functions for the handling of the Current + Directory Structure. + + MUX-11-23: Qualify Remote Filename + DOS-0x60 calls this MUX functions to let the Network Redirector + qualify the filename. According INTRSPY MS DOS 6 does not pre- + process the passed in filename in any way (see attached transcripts). + + The DOS-60 interface TRUENAME looks like this: + + DosTruename(src, dest) { + if (MUX-11-23(src, dest) != Error) + return SUCCESS + return local_truename(src, dest); + } + + The CDS has the following entries: + + char cdsPath[CDSPATHLEN]; + The fully-qualified current working directory of this drive. + The format is DOS :\[{\}] + or UNC \\[{\}]. + The drive indicates the physical drive letter and is the + index into the blk_device[]. + + UWORD cdsFlags; + Indicates what kind this logical drive is: + NETWORK: drive is NOT local \ If both are set, drive is IFS + PHYSICAL: drive is local / If none is set, drive is non-existant + JOIN: drive is joined in as the path cdsPath. This Flag uses the + index into the CDS table to indicate the physical drive. + SUBST: drive substitutes the path cdsPath. + HIDDEN: drive is not included into the redirector's list. + + struct dpb FAR *cdsDpb; + Pointer to the DPB driving the physical drive. In DOS-C, the physical + drive letter is the index into the DPB[]. But for compatibly reason + this field will be set correctly. + + UWORD cdsStartCluster; + For local drives only: This holds the cluster number of + the start of the current working directory of this + logical drive. If 0000h, it's the root directory; if + 0ffffh, the drive was never accessed and has to be read + again. + + void FAR *cdsIFSrecord; + UWORD cdsIFSparameter; + For networked drives only: Holds pointer/parameters to/for IFS + driver. (Well, I don't know.) + + UWORD cdsPathOff; + Number of characters of the cdsPath[], which are hidden. The + logical path is combined by the logical drive letter and the + cdsPath[] part, which is not hidden. + + IFS FAR *cdsIFSdrv; + Will be zeroed for local drives. + + Revision 1.2 1995/12/03 22:17:41 ska + bugfix: Scanning of file name in 8.3 failed on "." and on longer names. + + Revision 1.1 1995/11/09 07:43:30 ska + # + +*/ + +#define PATH_ERROR goto errRet +#define PATHLEN 128 + + +/* Map a logical path into a physical one. + + 1) Uppercasing path. + 2) Flipping '/' -> '\\'. + 3) Removing empty directory components & ".". + 4) Processing ".." components. + 5) Convert path components into 8.3 convention. + 6) Make it fully-qualified. + 7) Map it to SUBST/UNC. + 8) Map to JOIN. + + Return: + *cdsItem will be point to the appropriate CDS entry. This will allow + the caller to aquire the DPB or the IFS informtion of this entry. + error number + Return value: + DE_FILENOTFND, or DE_PATHNOTFND (as described in RBIL) + If the output path pnfo->physPath exceeds the length MAX_PATH, the error + DE_FILENOTFND will be returned. +*/ + +/* + * Added support for external and internal calls. + * Clean buffer before use. Make the true path and expand file names. + * Example: *.* -> ????????.??? as in the currect way. + * MSD returns \\D.\A.\????????.??? with SHSUCDX. So, this code is not + * compatible MSD Func 60h. + */ + +/*TE TODO: + + experimenting with NUL on MSDOS 7.0 (win95) + + WIN95 FREEDOS + TRUENAME NUL C:/NUL OK + TRUENAME .\NUL C:\DOS\NUL + TRUENAME ..\NUL C:\NUL + TRUENAME ..\..\NUL path not found + TRUENAME Z:NUL invalid drive (not lastdrive!!) + TRUENAME A:NUL A:/NUL OK + TRUENAME A:\NUL A:\NUL + +*/ + +#ifdef DEBUG_TRUENAME +#define tn_printf(x) printf x +#else +#define tn_printf(x) +#endif + +#define PNE_WILDCARD 1 +#define PNE_DOT 2 + +STATIC const char _DirChars[] = "\"[]:|<>+=;,"; + +#define DirChar(c) (((unsigned char)(c)) >= ' ' && \ + !strchr(_DirChars, (c))) + +#define addChar(c) \ +{ \ + if (p >= dest + SFTMAX) PATH_ERROR; /* path too long */ \ + *p++ = c; \ +} + +COUNT truename(const char FAR * src, char * dest, COUNT mode) +{ + COUNT i; + struct dhdr FAR *dhp; + const char FAR *froot; + COUNT result; + unsigned state; + struct cds FAR *cdsEntry; + char *p = dest; /* dynamic pointer into dest */ + char *rootPos; + char src0; + + tn_printf(("truename(%S)\n", src)); + + /* First, adjust the source pointer */ + src = adjust_far(src); + + /* In opposite of the TRUENAME shell command, an empty string is + rejected by MS DOS 6 */ + src0 = src[0]; + if (src0 == '\0') + return DE_FILENOTFND; + + if (src0 == '\\' && src[1] == '\\') { + const char FAR *unc_src = src; + /* Flag UNC paths and short circuit processing. Set current LDT */ + /* to sentinel (offset 0xFFFF) for redirector processing. */ + tn_printf(("Truename: UNC detected\n")); + do { + src0 = unc_src[0]; + addChar(src0); + unc_src++; + } while (src0); + current_ldt = (struct cds FAR *)MK_FP(0xFFFF,0xFFFF); + tn_printf(("Returning path: \"%s\"\n", dest)); + /* Flag as network - drive bits are empty but shouldn't get */ + /* referenced for network with empty current_ldt. */ + return IS_NETWORK; + } + + /* Do we have a drive? */ + if (src[1] == ':') + result = drLetterToNr(DosUpFChar(src0)); + else + result = default_drive; + + cdsEntry = get_cds(result); + if (cdsEntry == NULL) + return DE_PATHNOTFND; + + fmemcpy(&TempCDS, cdsEntry, sizeof(TempCDS)); + tn_printf(("CDS entry: #%u @%p (%u) '%s'\n", result, cdsEntry, + TempCDS.cdsBackslashOffset, TempCDS.cdsCurrentPath)); + /* is the current_ldt thing necessary for compatibly?? + -- 2001/09/03 ska*/ + current_ldt = cdsEntry; + if (TempCDS.cdsFlags & CDSNETWDRV) + result |= IS_NETWORK; + + dhp = IsDevice(src); /* returns header if -char- device */ + if (dhp) + result |= IS_DEVICE; + + /* Try if the Network redirector wants to do it */ + dest[0] = '\0'; /* better probable for sanity check below -- + included by original truename() */ + /* MUX succeeded and really something */ + if (!(mode & CDS_MODE_SKIP_PHYSICAL) && + QRemote_Fn(dest, src) == SUCCESS && dest[0] != '\0') + { + tn_printf(("QRemoteFn() returned: \"%s\"\n", dest)); +#ifdef DEBUG_TRUENAME + if (strlen(dest) >= SFTMAX) + panic("Truename: QRemote_Fn() overflowed output buffer"); +#endif + if (dest[2] == '/' && (result & IS_DEVICE)) + result &= ~IS_NETWORK; + return result; + } + + /* Redirector interface failed --> proceed with local mapper */ + dest[0] = drNrToLetter(result & 0x1f); + dest[1] = ':'; + + /* Do we have a drive? */ + if (src[1] == ':') + src += 2; + +/* + Code repoff from dosfns.c + MSD returns X:/CON for truename con. Not X:\CON +*/ + /* check for a device */ + + dest[2] = '\\'; + if (result & IS_DEVICE) + { + froot = get_root(src); + if (froot == src || froot == src + 5) + { + if (froot == src + 5) + { + fmemcpy(dest + 3, src, 5); + DosUpMem(dest + 3, 5); + if (dest[3] == '/') dest[3] = '\\'; + if (dest[7] == '/') dest[7] = '\\'; + } + if (froot == src || memcmp(dest + 3, "\\DEV\\", 5) == 0) + { + /* /// Bugfix: NUL.LST is the same as NUL. This is true for all + devices. On a device name, the extension is irrelevant + as long as the name matches. + - Ron Cemer */ + dest[2] = '/'; + result &= ~IS_NETWORK; + /* /// DOS will return C:/NUL.LST if you pass NUL.LST in. + DOS will also return C:/NUL.??? if you pass NUL.* in. + Code added here to support this. + - Ron Cemer */ + src = froot; + } + } + } + + /* Make fully-qualified logical path */ + /* register these two used characters and the \0 terminator byte */ + /* we always append the current dir to stat the drive; + the only exceptions are devices without paths */ + rootPos = p = dest + 2; + if (*p != '/') /* i.e., it's a backslash! */ + { + BYTE *cp; + + cp = TempCDS.cdsCurrentPath; + /* ensure termination of strcpy */ + cp[MAX_CDSPATH - 1] = '\0'; + if ((TempCDS.cdsFlags & CDSNETWDRV) == 0) + { + if (media_check(TempCDS.cdsDpb) < 0) + return DE_PATHNOTFND; + + /* dos_cd ensures that the path exists; if not, we + need to change to the root directory */ + if (dos_cd(cp) != SUCCESS) { + cp[TempCDS.cdsBackslashOffset + 1] = + cdsEntry->cdsCurrentPath[TempCDS.cdsBackslashOffset + 1] = '\0'; + dos_cd(cp); + } + } + + if (!(mode & CDS_MODE_SKIP_PHYSICAL)) + { + tn_printf(("SUBSTing from: %s\n", cp)); +/* What to do now: the logical drive letter will be replaced by the hidden + portion of the associated path. This is necessary for NETWORK and + SUBST drives. For local drives it should not harm. + This is actually the reverse mechanism of JOINED drives. */ + + strcpy(dest, cp); + if (TempCDS.cdsFlags & CDSSUBST) + { + /* The drive had been changed --> update the CDS pointer */ + if (dest[1] == ':') + { /* sanity check if this really is a local drive still */ + unsigned i = drLetterToNr(dest[0]); + + /* truename returns the "real", not the "virtual" drive letter! */ + if (i < lastdrive) /* sanity check #2 */ + result = (result & 0xffe0) | i; + } + } + rootPos = p = dest + TempCDS.cdsBackslashOffset; + } + else + { + cp += TempCDS.cdsBackslashOffset; + /* truename must use the CuDir of the "virtual" drive letter! */ + /* tn_printf(("DosGetCuDir drive #%u\n", prevresult & 0x1f)); */ + strcpy(p, cp); + } + if (p[0] == '\0') + p[1] = p[0]; + p[0] = '\\'; /* force backslash! */ + + if (*src != '\\' && *src != '/') + p += strlen(p); + else /* skip the absolute path marker */ + src++; + /* remove trailing separator */ + if (p[-1] == '\\') p--; + } + + /* append the path specified in src */ + + state = 0; + while(*src) + { + /* New segment. If any wildcards in previous + segment(s), this is an invalid path. */ + if (state & PNE_WILDCARD) + return DE_PATHNOTFND; + + /* append backslash if not already there. + MS DOS preserves a trailing '\\', so an access to "C:\\DOS\\" + or "CDS.C\\" fails; in that case the last new segment consists of just + the \ */ + if (p[-1] != *rootPos) + addChar(*rootPos); + /* skip multiple separators (duplicated slashes) */ + while (*src == '/' || *src == '\\') + src++; + + if(*src == '.') + { + /* special directory component */ + ++src; + if (*src == '.') /* skip the second dot */ + ++src; + if (*src == '/' || *src == '\\' || *src == '\0') + { + --p; /* backup the backslash */ + if (src[-2] == '.') + { + /* ".." entry */ + /* remove last path component */ + while(*--p != '\\') + if (p <= rootPos) /* already on root */ + return DE_PATHNOTFND; + } + continue; /* next char */ + } + + /* ill-formed .* or ..* entries => return error */ + errRet: + /* The error is either PATHNOTFND or FILENOTFND + depending on if it is not the last component */ + return fstrchr(src, '/') == 0 && fstrchr(src, '\\') == 0 + ? DE_FILENOTFND + : DE_PATHNOTFND; + } + + /* normal component */ + /* append component in 8.3 convention */ + + /* *** parse name and extension *** */ + i = FNAME_SIZE; + state &= ~PNE_DOT; + while(*src != '/' && *src != '\\' && *src != '\0') + { + char c = *src++; + if (c == '*') + { + /* register the wildcard, even if no '?' is appended */ + c = '?'; + while (i) + { + --i; + addChar(c); + } + /** Alternative implementation: + if (i) + { + if (dest + SFTMAX - *p < i) + PATH_ERROR; + fmemset(p, '?', i); + p += i; + } **/ + } + if (c == '.') + { + if (state & PNE_DOT) /* multiple dots are ill-formed */ + PATH_ERROR; + /* strip trailing dot */ + if (*src == '/' || *src == '\\' || *src == '\0') + break; + /* we arrive here only when an extension-dot has been found */ + state |= PNE_DOT; + i = FEXT_SIZE + 1; + } + else if (c == '?') + state |= PNE_WILDCARD; + if (i) { /* name length in limits */ + --i; + if (!DirChar(c)) PATH_ERROR; + addChar(c); + } + } + /* *** end of parse name and extension *** */ + } + if (state & PNE_WILDCARD && !(mode & CDS_MODE_ALLOW_WILDCARDS)) + return DE_PATHNOTFND; + if (p == dest + 2) + { + /* we must always add a seperator if dest = "c:" */ + addChar('\\'); + } + + *p = '\0'; /* add the string terminator */ + DosUpFString(rootPos); /* upcase the file/path name */ + +/** Note: + Only the portions passed in by the user are upcased, because it is + assumed that the CDS is configured correctly and if it contains + lower case letters, it is required so **/ + + tn_printf(("Absolute logical path: \"%s\"\n", dest)); + + /* Now, all the steps 1) .. 7) are fullfilled. Join now */ + /* search, if this path is a joined drive */ + + if (dest[2] != '/' && (!(mode & CDS_MODE_SKIP_PHYSICAL)) && njoined) + { + struct cds FAR *cdsp = CDSp; + for(i = 0; i < lastdrive; ++i, ++cdsp) + { + /* How many bytes must match */ + size_t j = fstrlen(cdsp->cdsCurrentPath); + /* the last component must end before the backslash offset and */ + /* the path the drive is joined to leads the logical path */ + if ((cdsp->cdsFlags & CDSJOINED) && (dest[j] == '\\' || dest[j] == '\0') + && fmemcmp(dest, cdsp->cdsCurrentPath, j) == 0) + { /* JOINed drive found */ + dest[0] = drNrToLetter(i); /* index is physical here */ + dest[1] = ':'; + if (dest[j] == '\0') + { /* Reduce to root direc */ + dest[2] = '\\'; + dest[3] = 0; + /* move the relative path right behind the drive letter */ + } + else if (j != 2) + { + strcpy(dest + 2, dest + j); + } + result = (result & 0xffe0) | i; /* tweak drive letter (JOIN) */ + current_ldt = cdsp; + result &= ~IS_NETWORK; + if (cdsp->cdsFlags & CDSNETWDRV) + result |= IS_NETWORK; + tn_printf(("JOINed path: \"%s\"\n", dest)); + return result; + } + } + /* nothing found => continue normally */ + } + if ((mode & CDS_MODE_CHECK_DEV_PATH) && + ((result & (IS_DEVICE|IS_NETWORK)) == IS_DEVICE) && + dest[2] != '/' && !dir_exists(dest)) + return DE_PATHNOTFND; + + /* Note: Not reached on error or if JOIN or QRemote_Fn (2f.1123) matched */ + if (mode==CDS_MODE_ALLOW_WILDCARDS) /* DosTruename mode */ + { + /* in other words: result & 0x60 = 0x20...: */ + if (os_major==6 && (result & (IS_DEVICE|IS_NETWORK)) == IS_DEVICE) + result = 0x3a00; /* MS DOS 6.22, according to RBIL: AH=3a if char dev */ + else + result = 0; /* AL is 00, 2f, 5c, or last-of-TempCDS.cdsCurrentPath? */ + } + tn_printf(("Physical path: \"%s\"\n", dest)); + return result; +} + +#if 0 +/********************************************** + Result of INTRSPY + + Calling RBIL's INT.COM in MS DOS v6.22 + +=== Script: MUX.SCR + +intercept 2fh + function 11h ; network redirector + subfunction 23h ; Qualify path and filename + on_entry + output "1123: IN: " (ds:SI->byte,asciiz,64) + on_exit + if (cflag == 1) + sameline " [FAIL " ax "]" + output "1123: OUT: " (es:dI->byte,asciiz,64) + output "1123: orig buffer: " (ds:sI->byte,asciiz,64) + function 12h + subfunction 21h + on_entry + output "1221: IN: " (ds:SI->byte,asciiz,64) + on_exit + if (cflag == 1) + sameline " [FAIL " ax "]" + output "1221: OUT: " (es:dI->byte,asciiz,64) + +=== Batch file: SPY_INT.BAT +@echo off +if exist report.out del report.out +cmdspy stop +cmdspy flush +cmdspy restart +int ax=0x6000 -buf ds:si="abcöflkgsxkf\0" -buf es:di="%256s" -int 0x21 -d es:di:128 >spy_int.out +cmdspy stop +cmdspy report report.out +more report.out +=== Intspy report file: REPORT.OUT +1123: IN: C:\INTRSPY\SPY_INT.BAT [FAIL 0001] +1123: OUT:  +1123: orig buffer: C:\INTRSPY\SPY_INT.BAT +1123: IN: int.??? [FAIL 0001] +1123: OUT: C:\INTRSPY +1123: orig buffer: int.??? +1123: IN: C:\TOOL\int.??? [FAIL 0001] +1123: OUT: C:\INTRSPY +1123: orig buffer: C:\TOOL\int.??? +1123: IN: spy_int.out [FAIL 0001] +1123: OUT: C:\TOOL\INT.??? +1123: orig buffer: spy_int.out +1123: IN: C:\TOOL\INT.COM [FAIL 0001] +1123: OUT: C:\INTRSPY\SPY_INT.OUT +1123: orig buffer: C:\TOOL\INT.COM +1123: IN: abcöflkgsxkf [FAIL 0001] +1123: OUT: C:\TOOL\INT.COM +1123: orig buffer: abcöflkgsxkf +1123: IN: C:\INTRSPY\SPY_INT.BAT [FAIL 0001] +1123: OUT: C:\INTRSPY\ABCÖFLKG +1123: orig buffer: C:\INTRSPY\SPY_INT.BAT +1123: IN: cmdspy.??? [FAIL 0001] +1123: OUT: C:\INTRSPY +1123: orig buffer: cmdspy.??? +1123: IN: C:\INTRSPY\CMDSPY.EXE [FAIL 0001] +1123: OUT: C:\INTRSPY +1123: orig buffer: C:\INTRSPY\CMDSPY.EXE +=== INT.COM output: SPY_INT.OUT + 000 CX=0000 DX=0000 +SI=4A5E DI=4A76 BP=FF70 SP=FF64 +CS=0000 DS=279D ES=279D SS=0000 CPU Flags: 0n00oditsz0a0p1c + +INT: 0x21 + +AX=0059 BX=0000 CX=0000 DX=0000 +SI=4A5E DI=4A76 BP=FF70 SP=FF64 +CS=0000 DS=279D ES=279D SS=0000 CPU Flags: 0N11odItSz0A0P1c +DOSERR: 0000 (0) + +* { +43(C) 3A(:) 5C(\) 49(I) 4E(N) 54(T) 52(R) 53(S) 50(P) 59(Y) 5C(\) 41(A) +42(B) 43(C) 99(Ö) 46(F) 4C(L) 4B(K) 47(G) 00(.) 3D(=) 30(0) 30(0) 30(0) +30(0) 20( ) 20( ) 20( ) 43(C) 58(X) 3D(=) 30(0) 30(0) 30(0) 30(0) 28(() +30(0) 29()) 20( ) 32(2) 38(8) 28(() 28(() 29()) 20( ) 33(3) 30(0) 28(() +30(0) 29()) 20( ) 32(2) 39(9) 28(() 29()) 29()) 20( ) 32(2) 30(0) 28(() +20( ) 29()) 20( ) 33(3) 32(2) 28(() 32(2) 29()) 20( ) 33(3) 38(8) 28(() +38(8) 29()) 20( ) 32(2) 38(8) 28(() 28(() 29()) 20( ) 32(2) 38(8) 28(() +28(() 29()) 20( ) 32(2) 39(9) 28(() 29()) 29()) 20( ) 32(2) 30(0) 28(() +20( ) 29()) 20( ) 33(3) 33(3) 28(() 33(3) 29()) 20( ) 33(3) 30(0) 28(() +30(0) 29()) 20( ) 32(2) 38(8) 28(() 28(() 29()) 20( ) 33(3) 30(0) 28(() +30(0) 29()) 20( ) 32(2) 39(9) 28(() 29()) 29()) } +=== + +The actual interesting lines are the 6th "IN:" of the report file. +The DOS interface passed _exactly_ the same string to MUX-11-23 as +written on command line, the same applied to "con\0", a device driver. + +***************************************/ + +#endif + diff --git a/kernel/nls.c b/kernel/nls.c new file mode 100644 index 0000000..e885bdc --- /dev/null +++ b/kernel/nls.c @@ -0,0 +1,718 @@ +/****************************************************************/ +/* */ +/* nls.c */ +/* FreeDOS */ +/* */ +/* National Languge Support functions and data structures */ +/* */ +/* Copyright (c) 2000 */ +/* Steffen Kaiser */ +/* All Rights Reserved */ +/* */ +/* This file is part of FreeDOS. */ +/* */ +/* 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. */ +/****************************************************************/ + +/* + * Note 1: Some code assume certains prerequisites to be matched, + * e.g. character tables exactly 128 bytes long; I try to keep\ + * track of these conditions within comments marked with: + * ==ska*/ + +#include "portab.h" +#include "globals.h" +#include "pcb.h" +#include + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: nls.c 1491 2009-07-18 20:48:44Z bartoldeman $"; +#endif + +#ifdef NLS_DEBUG +#define log(a) printf a +#define log1(a) printf a +#else +#define log(a) +#ifdef NDEBUG +#define log1(a) +#else +#define log1(a) printf a +#endif +#endif + +struct nlsInfoBlock ASM nlsInfo = { + (char FAR *)0 /* filename to COUNTRY.SYS */ + , 437 /* system code page */ + /* Implementation flags */ + , 0 +#ifdef NLS_MODIFYABLE_DATA + | NLS_CODE_MODIFYABLE_DATA +#endif +#ifdef NLS_REORDER_POINTERS + | NLS_CODE_REORDER_POINTERS +#endif + , &nlsPackageHardcoded /* hardcoded first package */ + , &nlsPackageHardcoded /* first item in chain */ +}; + + /* getTableX return the pointer to the X'th table; X==subfct */ + /* subfct 2: normal upcase table; 4: filename upcase table */ +#ifdef NLS_REORDER_POINTERS +#define getTable2(nls) ((nls)->nlsPointers[0].pointer) +#define getTable4(nls) ((nls)->nlsPointers[1].pointer) +#define getTable7(nls) ((nls)->nlsPointers[4].pointer) +#else +#define getTable2(nls) getTable(2, (nls)) +#define getTable4(nls) getTable(4, (nls)) +#define getTable7(nls) getTable(7, (nls)) +#define NEED_GET_TABLE +#endif + /*== both chartables must be 128 bytes long and lower range is + identical to 7bit-US-ASCII ==ska*/ +#define getCharTbl2(nls) \ + (((struct nlsCharTbl FAR*)getTable2(nls))->tbl - 0x80) +#define getCharTbl4(nls) \ + (((struct nlsCharTbl FAR*)getTable4(nls))->tbl - 0x80) + +/******************************************************************** + ***** MUX calling functions **************************************** + ********************************************************************/ + +extern long ASMPASCAL call_nls(UWORD, VOID FAR *, UWORD, UWORD, UWORD, UWORD); +/*== DS:SI _always_ points to global NLS info structure <-> no + * subfct can use these registers for anything different. ==ska*/ +STATIC long muxGo(int subfct, UWORD bp, UWORD cp, UWORD cntry, UWORD bufsize, + void FAR *buf) +{ + long ret; + log(("NLS: muxGo(): subfct=%x, cntry=%u, cp=%u, ES:DI=%p\n", + subfct, cntry, cp, buf)); + ret = call_nls(bp, buf, subfct, cp, cntry, bufsize); + log(("NLS: muxGo(): return value = %lx\n", ret)); + return ret; +} + +/* + * Call NLSFUNC to load the NLS package + */ +STATIC COUNT muxLoadPkg(int subfct, UWORD cp, UWORD cntry) +{ + long ret; + + /* 0x1400 == not installed, ok to install */ + /* 0x1401 == not installed, not ok to install */ + /* 0x14FF == installed */ + +#if NLS_FREEDOS_NLSFUNC_VERSION == NLS_FREEDOS_NLSFUNC_ID + /* make sure the NLSFUNC ID is updated */ +#error "NLS_FREEDOS_NLSFUNC_VERSION == NLS_FREEDOS_NLSFUNC_ID" +#endif + /* Install check must pass the FreeDOS NLSFUNC version as codepage (cp) and + the FreeDOS NLSFUNC ID as buffer size (bufsize). If they match the + version in NLSFUNC, on return it will set BX (cp on entry) to FreeDOS + NLSFUNC ID. call_nls will set the high word = BX on return. + */ + ret = muxGo(0, 0, NLS_FREEDOS_NLSFUNC_VERSION, 0, NLS_FREEDOS_NLSFUNC_ID, 0); + if ((int)ret != 0x14ff) + return DE_FILENOTFND; /* No NLSFUNC --> no load */ + if ((int)(ret >> 16) != NLS_FREEDOS_NLSFUNC_ID) /* FreeDOS NLSFUNC will return */ + return DE_INVLDACC; /* This magic number */ + + /* OK, the correct NLSFUNC is available --> load pkg */ + /* If cp == -1 on entry, NLSFUNC updates cp to the codepage loaded + into memory. The system must then change to this one later */ + return (int)muxGo(subfct, 0, cp, cntry, 0, 0); +} + +STATIC int muxBufGo(int subfct, int bp, UWORD cp, UWORD cntry, + UWORD bufsize, VOID FAR * buf) +{ + log(("NLS: muxBufGo(): subfct=%x, BP=%u, cp=%u, cntry=%u, len=%u, buf=%p\n", + subfct, bp, cp, cntry, bufsize, buf)); + + return (int)muxGo(subfct, bp, cp, cntry, bufsize, buf); +} + +#define mux65(s,cp,cc,bs,b) muxBufGo(2, (s), (cp), (cc), (bs), (b)) +#define mux38(cp,cc,bs,b) muxBufGo(4, 0, (cp), (cc), (bs), (b)) +#define muxYesNo(ch) muxBufGo(NLSFUNC_YESNO,0, NLS_DEFAULT, NLS_DEFAULT, (ch), 0) +#define muxUpMem(s,b,bs) muxBufGo((s),0, NLS_DEFAULT,NLS_DEFAULT, (bs), (b)) + +/******************************************************************** + ***** Helper functions********************************************** + ********************************************************************/ + +/* + * Search for the NLS package within the chain + * Also resolves the default values (-1) into the currently + * active codepage/country code. + */ +STATIC struct nlsPackage FAR *searchPackage(UWORD cp, UWORD cntry) +{ + struct nlsPackage FAR *nls; + + if (cp == NLS_DEFAULT) + cp = nlsInfo.actPkg->cp; + if (cntry == NLS_DEFAULT) + cntry = nlsInfo.actPkg->cntry; + + nls = nlsInfo.chain; + while ((nls->cp != cp || nls->cntry != cntry) + && (nls = nls->nxt) != NULL) ; + + return nls; +} + +/* For various robustnesses reasons and to simplify the implementation + at other places, locateSubfct() returns NULL (== "not found"), + if nls == NULL on entry. */ +STATIC VOID FAR *locateSubfct(struct nlsPackage FAR * nls, int subfct) +{ + int cnt; + struct nlsPointer FAR *p; + + if (nls) + for (cnt = nls->numSubfct, p = &nls->nlsPointers[0]; cnt--; ++p) + if (p->subfct == (UBYTE) subfct) + return p; + + return NULL; +} + +#ifdef NEED_GET_TABLE +/* search the table (from a subfct) from the active package */ +/* Note: Because this table returns the pointers for stuff of + *internal* purpose, it seems to be more comfortable that this + function is guaranteed to return valid pointers, rather than + to let the user (some kernel function) deal with non-existing + tables -- 2000/02/26 ska*/ +STATIC VOID FAR *getTable(UBYTE subfct, struct nlsPackage FAR * nls) +{ + struct nlsPointer FAR *poi; + + if ((poi = locateSubfct(nls, subfct)) != NULL) + return poi; + + /* Failed --> return the hardcoded table */ + switch (subfct) + { + case 2: + return &nlsUpcaseHardcoded; + case 4: + return &nlsFUpcaseHardcoded; + /* case 5: return &nlsFnameTermHardcodedTable; */ + /* case 6: return &nlsCollHardcodedTable; */ + case 7: + return &nlsDBCSHardcoded; + } + return NULL; +} +#endif + +/* + * Copy a buffer and test the size of the buffer + * Returns SUCCESS on success; DE_INVLDFUNC on failure + * + * Efficiency note: This function is used as: + * return cpyBuf(buf, bufsize, ...) + * three times. If the code optimizer is some good, it can re-use + * the code to push bufsize, buf, call cpyBuf() and return its result. + * The parameter were ordered to allow this code optimization. + */ +STATIC COUNT cpyBuf(VOID FAR * dst, UWORD dstlen, VOID FAR * src, + UWORD srclen) +{ + if (srclen <= dstlen) + { + fmemcpy(dst, src, srclen); + return SUCCESS; + } + return DE_INVLDFUNC; /* buffer too small */ +} + +/* + * This function assumes that 'map' is adjusted such that + * map[0x80] is the uppercase of character 0x80. + *== 128 byte chartables, lower range conform to 7bit-US-ASCII ==ska*/ +STATIC VOID upMMem(UBYTE FAR * map, UBYTE FAR * str, unsigned len) +{ + REG unsigned c; + +#ifdef NLS_DEBUG + UBYTE FAR *oldStr; + unsigned oldLen; + + oldStr = str; + oldLen = len; + log(("NLS: upMMem(): len=%u, %04x:%04x=\"", len, FP_SEG(str), + FP_OFF(str))); + for (c = 0; c < len; ++c) + printf("%c", str[c] > 32 ? str[c] : '.'); + printf("\"\n"); +#endif + if (len) + do + { + if ((c = *str) >= 'a' && c <= 'z') + *str += 'A' - 'a'; + else if (c > 0x7f) + *str = map[c]; + ++str; + } + while (--len); +#ifdef NLS_DEBUG + printf("NLS: upMMem(): result=\""); + for (c = 0; c < oldLen; ++c) + printf("%c", oldStr[c] > 32 ? oldStr[c] : '.'); + printf("\"\n"); +#endif +} + +/******************************************************************** + ***** Lowlevel interface ******************************************* + ********************************************************************/ + +/* GetData function used by both the MUX-callback function and + the direct-access interface. + subfct == NLS_DOS_38 is a value > 0xff in order to not clash + with subfunctions valid to be passed as DOS-65-XX. */ +STATIC int nlsGetData(struct nlsPackage FAR * nls, int subfct, + UBYTE FAR * buf, unsigned bufsize) +{ + VOID FAR *poi; + + log(("NLS: nlsGetData(): subfct=%x, bufsize=%u, cp=%u, cntry=%u\n", + subfct, bufsize, nls->cp, nls->cntry)); + + /* Theoretically tables 1 and, if NLS_REORDER_POINTERS is enabled, + 2 and 4 could be hard-coded, because their + data is located at predictable (calculatable) locations. + However, 1 and subfct NLS_DOS_38 are to handle the same + data and the "locateSubfct()" call has to be implemented anyway, + in order to handle all subfunctions. + Also, NLS is often NOT used in any case, so this code is more + size than speed optimized. */ + if ((poi = locateSubfct(nls, subfct)) != NULL) + { + log(("NLS: nlsGetData(): subfunction found\n")); + switch (subfct) + { + case 1: /* Extended Country Information */ + return cpyBuf(buf, bufsize, poi, + ((struct nlsExtCntryInfo FAR *)poi)->size + 3); + case NLS_DOS_38: /* Normal Country Information */ + return cpyBuf(buf, bufsize, &(((struct nlsExtCntryInfo FAR *)poi)->dateFmt), 24); /* standard cinfo has no more 34 _used_ bytes */ + /* don't copy 34, copy only 0x18 instead, + see comment at DosGetCountryInformation TE */ + default: + /* All other subfunctions just return the found nlsPoinerInf + structure */ + return cpyBuf(buf, bufsize, poi, sizeof(struct nlsPointer)); + } + } + + /* The requested subfunction could not been located within the + NLS pkg --> error. Because the data corresponds to the subfunction + number passed to the API, the failure is the same as that a wrong + API function has been called. */ + log(("NLS: nlsGetData(): Subfunction not found\n")); + return DE_INVLDFUNC; +} + +VOID nlsCPchange(UWORD cp) +{ + UNREFERENCED_PARAMETER(cp); + put_string("\7\nchange codepage not yet done ska\n"); +} + +/* + * Changes the current active codepage or cntry + * + * Note: Usually any call sees a value of -1 (0xFFFF) as "the current + * country/CP". When a new NLS pkg is loaded, there is however a little + * difference, because one could mean that when switching to country XY + * the system may change to any codepage required. + * Example: + * MODE has prepared codepages 437 and 850. + * The user loaded a 2nd NLS pkg via CONFIG.SYS with: + * COUNTRY=49,850,C:\COUNTRY.SYS + * By default, the kernel maintains the hardcoded 001,437 (U.S.A./CP437) + * After the Country statement the system switches to codepage 850. + * But when the user invokes DOS-38-01/DX=FFFF (Set Country ID to 1) + * the system _must_ switch to codepage 437, because this is the only + * NLS pkg loaded. + * Therefore, setPackage() will substitute the current country ID, if + * cntry==-1, but leaves cp==-1 in order to let NLSFUNC choose the most + * appropriate codepage on its own. + */ + +STATIC COUNT nlsSetPackage(struct nlsPackage FAR * nls) +{ + if (nls->cp != nlsInfo.actPkg->cp) /* Codepage gets changed --> + inform all character drivers thereabout. + If this fails, it would be possible that the old + NLS pkg had been removed from memory by NLSFUNC. */ + nlsCPchange(nls->cp); + + nlsInfo.actPkg = nls; + + return SUCCESS; +} +STATIC COUNT DosSetPackage(UWORD cp, UWORD cntry) +{ + /* Right now, we do not have codepage change support in kernel, so push + it through the mux in any case. */ +#if 0 + struct nlsPackage FAR *nls; /* NLS package to use to return the info from */ + + /* nls := NLS package of cntry/codepage */ + if ((nls = searchPackage(cp, cntry)) != NULL) + /* OK the NLS pkg is loaded --> activate it */ + return nlsSetPackage(nls); + + /* not loaded --> invoke NLSFUNC to load it */ +#endif + return muxLoadPkg(NLSFUNC_LOAD_PKG2, cp, cntry); +} + +STATIC COUNT nlsLoadPackage(struct nlsPackage FAR * nls) +{ + + nlsInfo.actPkg = nls; + + return SUCCESS; +} +STATIC COUNT DosLoadPackage(UWORD cp, UWORD cntry) +{ + struct nlsPackage FAR *nls; /* NLS package to use to return the info from */ + + /* nls := NLS package of cntry/codepage */ + if ((nls = searchPackage(cp, cntry)) != NULL) + /* OK the NLS pkg is loaded --> activate it */ + return nlsLoadPackage(nls); + + /* not loaded --> invoke NLSFUNC to load it */ + return muxLoadPkg(NLSFUNC_LOAD_PKG, cp, cntry); +} + +STATIC void nlsUpMem(struct nlsPackage FAR * nls, VOID FAR * str, int len) +{ + log(("NLS: nlsUpMem()\n")); + upMMem(getCharTbl2(nls), (UBYTE FAR *) str, len); +} +STATIC void nlsFUpMem(struct nlsPackage FAR * nls, VOID FAR * str, int len) +{ + log(("NLS: nlsFUpMem()\n")); + upMMem(getCharTbl4(nls), (UBYTE FAR *) str, len); +} + +STATIC VOID xUpMem(struct nlsPackage FAR * nls, VOID FAR * str, + unsigned len) +/* upcase a memory area */ +{ + log(("NLS: xUpMem(): cp=%u, cntry=%u\n", nls->cp, nls->cntry)); + + if (nls->flags & NLS_FLAG_DIRECT_UPCASE) + nlsUpMem(nls, str, len); + else + muxBufGo(NLSFUNC_UPMEM, 0, nls->cp, nls->cntry, len, str); +} + +STATIC BOOL nlsIsDBCS(UBYTE ch) +{ + + if (ch < 128) + return FALSE; /* No leadbyte is smaller than that */ + + { + UWORD FAR *t= ((struct nlsDBCS FAR*)getTable7(nlsInfo.actPkg))->dbcsTbl; + + for (; *t != 0; ++t) + if (ch >= (*t & 0xFF) && ch <= (*t >> 8)) + return TRUE; + } + + return FALSE; +} + +STATIC int nlsYesNo(struct nlsPackage FAR * nls, UWORD ch) +{ + /* Check if it is a dual byte character */ + if (!nlsIsDBCS(ch & 0xFF)) { + ch &= 0xFF; + log(("NLS: nlsYesNo(): in ch=%u (%c)\n", ch, ch > 32 ? (char)ch : ' ')); + xUpMem(nls, MK_FP(_SS, &ch), 1); /* Upcase character */ + /* Cannot use DosUpChar(), because + maybe: nls != current NLS pkg + However: Upcase character within lowlevel + function to allow a yesNo() function + catched by external MUX-14 handler, which + does NOT upcase character. */ + log(("NLS: nlsYesNo(): upcased ch=%u (%c)\n", ch, ch > 32 ? (char)ch : ' ')); + } + else + log(("NLS: nlsYesNo(): in ch=%u (DBCS)\n", ch)); + + if (ch == nls->yeschar) + return 1; + if (ch == nls->nochar) + return 0; + return 2; +} + +/******************************************************************** + ***** DOS API ****************************************************** + ********************************************************************/ + +BYTE DosYesNo(UWORD ch) +/* returns: 0: ch == "No", 1: ch == "Yes", 2: ch crap */ +{ + if (nlsInfo.actPkg->flags & NLS_FLAG_DIRECT_YESNO) + return nlsYesNo(nlsInfo.actPkg, ch); + else + return muxYesNo(ch); +} + +#ifndef DosUpMem +VOID DosUpMem(VOID FAR * str, unsigned len) +{ + xUpMem(nlsInfo.actPkg, str, len); +} +#endif + +/* + * This function is also called by the backdoor entry specified by + * the "upCaseFct" member of the Country Information structure. Therefore + * the HiByte of the first argument must remain unchanged. + * See NLSSUPT.ASM -- 2000/03/30 ska + */ +unsigned char ASMCFUNC DosUpChar(unsigned char ch) + /* upcase a single character */ +{ + log(("NLS: DosUpChar(): in ch=%u (%c)\n", ch, ch > 32 ? ch : ' ')); + DosUpMem(MK_FP(_SS, &ch), 1); + log(("NLS: DosUpChar(): upcased ch=%u (%c)\n", ch, ch > 32 ? ch : ' ')); + return ch; +} + +VOID DosUpString(char FAR * str) +/* upcase a string */ +{ + DosUpMem(str, fstrlen(str)); +} + +VOID DosUpFMem(VOID FAR * str, unsigned len) +/* upcase a memory area for file names */ +{ +#ifdef NLS_DEBUG + unsigned c; + log(("NLS: DosUpFMem(): len=%u, %04x:%04x=\"", len, FP_SEG(str), + FP_OFF(str))); + for (c = 0; c < len; ++c) + printf("%c", ((char FAR *)str)[c] > 32 ? ((char FAR *)str)[c] : '.'); + printf("\"\n"); +#endif + if (nlsInfo.actPkg->flags & NLS_FLAG_DIRECT_FUPCASE) + nlsFUpMem(nlsInfo.actPkg, str, len); + else + muxUpMem(NLSFUNC_FILE_UPMEM, str, len); +} + +unsigned char DosUpFChar(unsigned char ch) + /* upcase a single character for file names */ +{ + DosUpFMem(MK_FP(_SS, & ch), 1); + return ch; +} + +VOID DosUpFString(char FAR * str) +/* upcase a string for file names */ +{ + DosUpFMem(str, fstrlen(str)); +} + +/* + * Called for all subfunctions other than 0x20-0x23,& 0xA0-0xA2 + * of DOS-65 + * + * If the requested NLS pkg specified via cntry and cp is _not_ + * loaded, MUX-14 is invoked; otherwise the pkg's NLS_Fct_buf + * function is invoked. + */ +COUNT DosGetData(int subfct, UWORD cp, UWORD cntry, UWORD bufsize, + VOID FAR * buf) +{ + struct nlsPackage FAR *nls; /* NLS package to use to return the info from */ + + log(("NLS: GetData(): subfct=%x, cp=%u, cntry=%u, bufsize=%u\n", + subfct, cp, cntry, bufsize)); + + if (!buf || !bufsize) + return DE_INVLDDATA; + if (subfct == 0) /* Currently not supported */ + return DE_INVLDFUNC; + + /* nls := NLS package of cntry/codepage */ + if ((nls = searchPackage(cp, cntry)) != NULL) + { + /* matching NLS package found */ + if (nls->flags & NLS_FLAG_DIRECT_GETDATA) + /* Direct access to the data */ + return nlsGetData(nls, subfct, buf, bufsize); + cp = nls->cp; + cntry = nls->cntry; + } + + /* If the NLS pkg is not loaded into memory or the direct-access + flag is disabled, the request must be passed through MUX */ + return (subfct == NLS_DOS_38) + ? mux38(cp, cntry, bufsize, buf) + : mux65(subfct, cp, cntry, bufsize, buf); +} + +/* + * Called for DOS-38 get info + * + * Note: DOS-38 does not receive the size of the buffer; therefore + * it is assumed the buffer is large enough as described in RBIL, + * which is 34 bytes _hardcoded_. + */ +/* TE 05/04/01 + * NETX calls Int 21 AX=3800 + * and gives a buffer of (at most) 0x20 bytes + * MSDOS 6.2 copies only 0x18 bytes + * RBIL documents 0x18 bytes and calls 10 bytes 'reserved' + * so we change the amount of copied bytes to 0x18 + */ + +#ifndef DosGetCountryInformation +COUNT DosGetCountryInformation(UWORD cntry, VOID FAR * buf) +{ + return DosGetData(NLS_DOS_38, NLS_DEFAULT, cntry, 0x18, buf); +} +#endif + +/* + * Called for DOS-38 set country code + */ +#ifndef DosSetCountry +COUNT DosSetCountry(UWORD cntry) +{ + return DosLoadPackage(NLS_DEFAULT, cntry); +} +#endif + +/* + * Called for DOS-66-01 get CP + */ +COUNT DosGetCodepage(UWORD * actCP, UWORD * sysCP) +{ + *sysCP = nlsInfo.sysCodePage; + *actCP = nlsInfo.actPkg->cp; + return SUCCESS; +} + +/* + * Called for DOS-66-02 set CP + * Note: One cannot change the system CP. Why it is necessary + * to specify it, is lost to me. (2000/02/13 ska) + */ +COUNT DosSetCodepage(UWORD actCP, UWORD sysCP) +{ + if (sysCP == NLS_DEFAULT || sysCP == nlsInfo.sysCodePage) + return DosSetPackage(actCP, NLS_DEFAULT); + return DE_INVLDDATA; +} + +VOID FAR *DosGetDBCS(void) +{ + return getTable7(nlsInfo.actPkg); +} + +/******************************************************************** + ***** MUX-14 API *************************************************** + ********************************************************************/ + +/* Registers: + AH == 14 + AL == subfunction + BX == codepage + DX == country code + DS:SI == internal global nlsInfo + ES:DI == user block + + Return value: AL register to be returned + if AL == 0, Carry must be cleared, otherwise set +*/ +UWORD ASMCFUNC syscall_MUX14(DIRECT_IREGS) +{ + struct nlsPackage FAR *nls; /* addressed NLS package */ + + UNREFERENCED_PARAMETER(flags); + UNREFERENCED_PARAMETER(cs); + UNREFERENCED_PARAMETER(ip); + UNREFERENCED_PARAMETER(ds); + UNREFERENCED_PARAMETER(es); + UNREFERENCED_PARAMETER(si); + + log(("NLS: MUX14(): subfct=%x, cp=%u, cntry=%u\n", AL, BX, DX)); + + if ((nls = searchPackage(BX, DX)) == NULL) + return DE_INVLDFUNC; /* no such package */ + + log(("NLS: MUX14(): NLS pkg found\n")); + + switch (AL) + { + case NLSFUNC_INSTALL_CHECK: + BX = NLS_FREEDOS_NLSFUNC_ID; + return SUCCESS; /* kernel just simulates default functions */ + case NLSFUNC_DOS38: + return nlsGetData(nls, NLS_DOS_38, MK_FP(ES, DI), 34); + case NLSFUNC_GETDATA: + return nlsGetData(nls, BP, MK_FP(ES, DI), CX); + case NLSFUNC_DRDOS_GETDATA: + /* Does not pass buffer length */ + return nlsGetData(nls, CL, MK_FP(ES, DI), 512); + case NLSFUNC_LOAD_PKG: + return nlsLoadPackage(nls); + case NLSFUNC_LOAD_PKG2: + return nlsSetPackage(nls); + case NLSFUNC_YESNO: + return nlsYesNo(nls, CX); + case NLSFUNC_UPMEM: + nlsUpMem(nls, MK_FP(ES, DI), CX); + return SUCCESS; + case NLSFUNC_FILE_UPMEM: +#ifdef NLS_DEBUG + { + unsigned j; + BYTE FAR *p; + log(("NLS: MUX14(FILE_UPMEM): len=%u, %04x:%04x=\"", CX, ES, DI)); + for (j = 0, p = MK_FP(ES, DI); j < CX; ++j) + printf("%c", p[j] > 32 ? p[j] : '.'); + printf("\"\n"); + } +#endif + nlsFUpMem(nls, MK_FP(ES, DI), CX); + return SUCCESS; + } + log(("NLS: MUX14(): Invalid function %x\n", AL)); + return DE_INVLDFUNC; /* no such function */ +} + diff --git a/kernel/nls/001-437.hc b/kernel/nls/001-437.hc new file mode 100644 index 0000000..c963ee4 --- /dev/null +++ b/kernel/nls/001-437.hc @@ -0,0 +1,111 @@ +; Hardcoded DOS-NLS information for country = 1, codepage = 437 +; This is an automatically generated file! +; Any modifications will be lost! + +; Prerequisites: +;; ==> Assuming that data of tables remains constant all the time +;; ==> Reordering tables 1, 2, 4 and 5 + + %include "segs.inc" +segment _DATA + + GLOBAL _nlsPackageHardcoded +_nlsPackageHardcoded: + DB 000h, 000h, 000h, 000h, 001h, 000h, 0b5h, 001h + DB 00fh, 000h, 059h, 04eh, 006h, 000h + DB 002h + DW ?table2, SEG ?table2 + DB 004h + DW ?table4, SEG ?table4 + DB 005h + DW ?table5, SEG ?table5 + DB 006h + DW ?table6, SEG ?table6 + DB 007h + DW ?table7, SEG ?table7 + GLOBAL _nlsCountryInfoHardcoded +_nlsCountryInfoHardcoded: + DB 001h +?table1: + DB 01ch, 000h, 001h, 000h, 0b5h, 001h, 000h, 000h + DB 024h, 000h, 000h, 000h, 000h, 02ch, 000h, 02eh + DB 000h, 02dh, 000h, 03ah, 000h, 000h, 002h, 000h +extern _CharMapSrvc:wrt TGROUP + DW _CharMapSrvc, SEG _CharMapSrvc + DB 02ch, 000h + GLOBAL _hcTablesStart +_hcTablesStart: + GLOBAL _nlsFUpcaseHardcoded +_nlsFUpcaseHardcoded: +?table4: + GLOBAL _nlsUpcaseHardcoded +_nlsUpcaseHardcoded: +?table2: + DB 080h, 000h, 080h, 09ah, 045h, 041h, 08eh, 041h + DB 08fh, 080h, 045h, 045h, 045h, 049h, 049h, 049h + DB 08eh, 08fh, 090h, 092h, 092h, 04fh, 099h, 04fh + DB 055h, 055h, 059h, 099h, 09ah, 09bh, 09ch, 09dh + DB 09eh, 09fh, 041h, 049h, 04fh, 055h, 0a5h, 0a5h + DB 0a6h, 0a7h, 0a8h, 0a9h, 0aah, 0abh, 0ach, 0adh + DB 0aeh, 0afh, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h + DB 0b6h, 0b7h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 0bdh + DB 0beh, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 0c6h, 0c7h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 0cfh, 0d0h, 0d1h, 0d2h, 0d3h, 0d4h, 0d5h + DB 0d6h, 0d7h, 0d8h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 0deh, 0dfh, 0e0h, 0e1h, 0e2h, 0e3h, 0e4h, 0e5h + DB 0e6h, 0e7h, 0e8h, 0e9h, 0eah, 0ebh, 0ech, 0edh + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsFnameTermHardcoded +_nlsFnameTermHardcoded: +?table5: + DB 016h, 000h, 08eh, 000h, 0ffh, 041h, 000h, 020h + DB 0eeh, 00eh, 02eh, 022h, 02fh, 05ch, 05bh, 05dh + DB 03ah, 07ch, 03ch, 03eh, 02bh, 03dh, 03bh, 02ch + GLOBAL _nlsCollHardcoded +_nlsCollHardcoded: +?table6: + DB 000h, 001h, 000h, 001h, 002h, 003h, 004h, 005h + DB 006h, 007h, 008h, 009h, 00ah, 00bh, 00ch, 00dh + DB 00eh, 00fh, 010h, 011h, 012h, 013h, 014h, 015h + DB 016h, 017h, 018h, 019h, 01ah, 01bh, 01ch, 01dh + DB 01eh, 01fh, 020h, 021h, 022h, 023h, 024h, 025h + DB 026h, 027h, 028h, 029h, 02ah, 02bh, 02ch, 02dh + DB 02eh, 02fh, 030h, 031h, 032h, 033h, 034h, 035h + DB 036h, 037h, 038h, 039h, 03ah, 03bh, 03ch, 03dh + DB 03eh, 03fh, 040h, 041h, 042h, 043h, 044h, 045h + DB 046h, 047h, 048h, 049h, 04ah, 04bh, 04ch, 04dh + DB 04eh, 04fh, 050h, 051h, 052h, 053h, 054h, 055h + DB 056h, 057h, 058h, 059h, 05ah, 05bh, 05ch, 05dh + DB 05eh, 05fh, 060h, 041h, 042h, 043h, 044h, 045h + DB 046h, 047h, 048h, 049h, 04ah, 04bh, 04ch, 04dh + DB 04eh, 04fh, 050h, 051h, 052h, 053h, 054h, 055h + DB 056h, 057h, 058h, 059h, 05ah, 07bh, 07ch, 07dh + DB 07eh, 07fh, 043h, 055h, 045h, 041h, 041h, 041h + DB 041h, 043h, 045h, 045h, 045h, 049h, 049h, 049h + DB 041h, 041h, 045h, 041h, 041h, 04fh, 04fh, 04fh + DB 055h, 055h, 059h, 04fh, 055h, 024h, 024h, 024h + DB 024h, 024h, 041h, 049h, 04fh, 055h, 04eh, 04eh + DB 0a6h, 0a7h, 03fh, 0a9h, 0aah, 0abh, 0ach, 021h + DB 022h, 022h, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h + DB 0b6h, 0b7h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 0bdh + DB 0beh, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 0c6h, 0c7h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 0cfh, 0d0h, 0d1h, 0d2h, 0d3h, 0d4h, 0d5h + DB 0d6h, 0d7h, 0d8h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 0deh, 0dfh, 0e0h, 053h, 0e2h, 0e3h, 0e4h, 0e5h + DB 0e6h, 0e7h, 0e8h, 0e9h, 0eah, 0ebh, 0ech, 0edh + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsDBCSHardcoded +_nlsDBCSHardcoded: +?table7: + DB 000h, 000h, 000h, 000h + GLOBAL _hcTablesEnd +_hcTablesEnd: + + +END diff --git a/kernel/nls/001-437.unf b/kernel/nls/001-437.unf new file mode 100644 index 0000000..881dcfe --- /dev/null +++ b/kernel/nls/001-437.unf @@ -0,0 +1,130 @@ +## Universal NLS data Format file: 001-437.unf +$country 1 +$codepage 437 + +# Global options +$radix 10 + + +[table 1] # Extended Country Information DOS-65-01 / DOS-38 +$make_size + = W1 W437 # Country ID & Codepage + = W0 # Date format: 0/1/2: U.S.A./Europe/Japan + = 36 0 0 0 0 # $.... # Currency string + = 44 0 # ,. # Thousand's separator + = 46 0 # .. # Decimal point + = 45 0 # -. # Date separator + = 58 0 # :. # Time separator + = 0 # Currency format (bit array) + = 2 # Currency precision + = 0 # time format: 0/1: 12/24 houres +$go_forward 4 # Far address of upcase function (to be calc at runtime) + = 44 0 # ,. # Data separator + + +[table 2] # normal character uppercase table +$make_size + + = 128 154 69 65 142 65 143 128 # €šEAŽA€ @ 0 + = 69 69 69 73 73 73 142 143 # EEEIIIŽ @ 8 + = 144 146 146 79 153 79 85 85 # ’’O™OUU @ 16 + = 89 153 154 155 156 157 158 159 # Y™š›œžŸ @ 24 + = 65 73 79 85 165 165 166 167 # AIOU¥¥¦§ @ 32 + = 168 169 170 171 172 173 174 175 # ¨©ª«¬­®¯ @ 40 + = 176 177 178 179 180 181 182 183 # °±²³´µ¶· @ 48 + = 184 185 186 187 188 189 190 191 # ¸¹º»¼½¾¿ @ 56 + = 192 193 194 195 196 197 198 199 # ÀÁÂÃÄÅÆÇ @ 64 + = 200 201 202 203 204 205 206 207 # ÈÉÊËÌÍÎÏ @ 72 + = 208 209 210 211 212 213 214 215 # ÐÑÒÓÔÕÖ× @ 80 + = 216 217 218 219 220 221 222 223 # ØÙÚÛÜÝÞß @ 88 + = 224 225 226 227 228 229 230 231 # àáâãäåæç @ 96 + = 232 233 234 235 236 237 238 239 # èéêëìíîï @ 104 + = 240 241 242 243 244 245 246 247 # ðñòóôõö÷ @ 112 + = 248 249 250 251 252 253 254 255 # øùúûüýþÿ @ 120 +$is_offset 128 + + +[table 4] # filename character uppercase table +$make_size + + = 128 154 69 65 142 65 143 128 # €šEAŽA€ @ 0 + = 69 69 69 73 73 73 142 143 # EEEIIIŽ @ 8 + = 144 146 146 79 153 79 85 85 # ’’O™OUU @ 16 + = 89 153 154 155 156 157 158 159 # Y™š›œžŸ @ 24 + = 65 73 79 85 165 165 166 167 # AIOU¥¥¦§ @ 32 + = 168 169 170 171 172 173 174 175 # ¨©ª«¬­®¯ @ 40 + = 176 177 178 179 180 181 182 183 # °±²³´µ¶· @ 48 + = 184 185 186 187 188 189 190 191 # ¸¹º»¼½¾¿ @ 56 + = 192 193 194 195 196 197 198 199 # ÀÁÂÃÄÅÆÇ @ 64 + = 200 201 202 203 204 205 206 207 # ÈÉÊËÌÍÎÏ @ 72 + = 208 209 210 211 212 213 214 215 # ÐÑÒÓÔÕÖ× @ 80 + = 216 217 218 219 220 221 222 223 # ØÙÚÛÜÝÞß @ 88 + = 224 225 226 227 228 229 230 231 # àáâãäåæç @ 96 + = 232 233 234 235 236 237 238 239 # èéêëìíîï @ 104 + = 240 241 242 243 244 245 246 247 # ðñòóôõö÷ @ 112 + = 248 249 250 251 252 253 254 255 # øùúûüýþÿ @ 120 +$is_offset 128 + + +[table 5] # Filename Termination Characters +$make_size +$go_forward 1 # skip one dummy byte + = 0 255 # Permittable characters +$go_forward 1 # skip one dummy byte + = 0 32 # Excluded characters (from above range) +$go_forward 1 # skip one dummy byte + = 14 # Number of enumerated excluded characters + + = 46 34 47 92 91 93 58 124 # ."/\[]:| @ 0 + = 60 62 43 61 59 44 # <>+=;, @ 8 +$is_offset 22 + + +[table 6] # collating sequence table +$make_size + + = 0 1 2 3 4 5 6 7 # ........ @ 0 + = 8 9 10 11 12 13 14 15 # ........ @ 8 + = 16 17 18 19 20 21 22 23 # ........ @ 16 + = 24 25 26 27 28 29 30 31 # ........ @ 24 + = 32 33 34 35 36 37 38 39 # !"#$%&' @ 32 + = 40 41 42 43 44 45 46 47 # ()*+,-./ @ 40 + = 48 49 50 51 52 53 54 55 # 01234567 @ 48 + = 56 57 58 59 60 61 62 63 # 89:;<=>? @ 56 + = 64 65 66 67 68 69 70 71 # @ABCDEFG @ 64 + = 72 73 74 75 76 77 78 79 # HIJKLMNO @ 72 + = 80 81 82 83 84 85 86 87 # PQRSTUVW @ 80 + = 88 89 90 91 92 93 94 95 # XYZ[\]^_ @ 88 + = 96 65 66 67 68 69 70 71 # `ABCDEFG @ 96 + = 72 73 74 75 76 77 78 79 # HIJKLMNO @ 104 + = 80 81 82 83 84 85 86 87 # PQRSTUVW @ 112 + = 88 89 90 123 124 125 126 127 # XYZ{|}~. @ 120 + = 67 85 69 65 65 65 65 67 # CUEAAAAC @ 128 + = 69 69 69 73 73 73 65 65 # EEEIIIAA @ 136 + = 69 65 65 79 79 79 85 85 # EAAOOOUU @ 144 + = 89 79 85 36 36 36 36 36 # YOU$$$$$ @ 152 + = 65 73 79 85 78 78 166 167 # AIOUNN¦§ @ 160 + = 63 169 170 171 172 33 34 34 # ?©ª«¬!"" @ 168 + = 176 177 178 179 180 181 182 183 # °±²³´µ¶· @ 176 + = 184 185 186 187 188 189 190 191 # ¸¹º»¼½¾¿ @ 184 + = 192 193 194 195 196 197 198 199 # ÀÁÂÃÄÅÆÇ @ 192 + = 200 201 202 203 204 205 206 207 # ÈÉÊËÌÍÎÏ @ 200 + = 208 209 210 211 212 213 214 215 # ÐÑÒÓÔÕÖ× @ 208 + = 216 217 218 219 220 221 222 223 # ØÙÚÛÜÝÞß @ 216 + = 224 83 226 227 228 229 230 231 # àSâãäåæç @ 224 + = 232 233 234 235 236 237 238 239 # èéêëìíîï @ 232 + = 240 241 242 243 244 245 246 247 # ðñòóôõö÷ @ 240 + = 248 249 250 251 252 253 254 255 # øùúûüýþÿ @ 248 +$is_offset 256 + + +[table 7] # Double Byte Character Support (DBCS) +$make_size +$stop_size + = W0 # DBCS end marker (mandotary) + + +[table 35] # Extended Country Information DOS-65-23 + = 89 78 # YN # Yes & No character + + diff --git a/kernel/nls/001-437.up b/kernel/nls/001-437.up new file mode 100644 index 0000000000000000000000000000000000000000..c73fc9466e695de83ee903b1618991be93df55b2 GIT binary patch literal 256 zcmZQzWMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{)Y8_`)zddH zG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13ZvA@C9)z#C}v#)=`q)GlW{X;_|XU>{EXYRcDj-LLZOP4NNzGCI7)oa$S zTfbrBrp;TnZri?N=dRs*_U_w%;NYRdM~)sle&Xb*(`U|}JAdKgrOQ{YUb}wd=B?Xz s?%uoq;NhdkPo6$|{^I4U*Kgjwd;j6%r_W!$e*6C8=da&?{{H(90L2M+aR2}S literal 0 HcmV?d00001 diff --git a/kernel/nls/049-850.hc b/kernel/nls/049-850.hc new file mode 100644 index 0000000..4f0204a --- /dev/null +++ b/kernel/nls/049-850.hc @@ -0,0 +1,111 @@ +; Hardcoded DOS-NLS information for country = 49, codepage = 850 +; This is an automatically generated file! +; Any modifications will be lost! + +; Prerequisites: +;; ==> Assuming that data of tables remains constant all the time +;; ==> Reordering tables 1, 2, 4 and 5 + + %include "segs.inc" +segment _DATA + + GLOBAL _nlsPackageHardcoded +_nlsPackageHardcoded: + DB 000h, 000h, 000h, 000h, 031h, 000h, 052h, 003h + DB 00fh, 000h, 04ah, 04eh, 006h, 000h + DB 002h + DW ?table2, SEG ?table2 + DB 004h + DW ?table4, SEG ?table4 + DB 005h + DW ?table5, SEG ?table5 + DB 006h + DW ?table6, SEG ?table6 + DB 007h + DW ?table7, SEG ?table7 + GLOBAL _nlsCountryInfoHardcoded +_nlsCountryInfoHardcoded: + DB 001h +?table1: + DB 01ch, 000h, 031h, 000h, 052h, 003h, 001h, 000h + DB 044h, 04dh, 000h, 000h, 000h, 02eh, 000h, 02ch + DB 000h, 02eh, 000h, 03ah, 000h, 003h, 002h, 001h +extern _CharMapSrvc:wrt TGROUP + DW _CharMapSrvc, SEG _CharMapSrvc + DB 03bh, 000h + GLOBAL _hcTablesStart +_hcTablesStart: + GLOBAL _nlsFUpcaseHardcoded +_nlsFUpcaseHardcoded: +?table4: + GLOBAL _nlsUpcaseHardcoded +_nlsUpcaseHardcoded: +?table2: + DB 080h, 000h, 080h, 09ah, 090h, 0b6h, 08eh, 0b7h + DB 08fh, 080h, 0d2h, 0d3h, 0d4h, 0d8h, 0d7h, 0deh + DB 08eh, 08fh, 090h, 092h, 092h, 0e2h, 099h, 0e3h + DB 0eah, 0ebh, 05fh, 099h, 09ah, 09dh, 09ch, 09dh + DB 09eh, 09fh, 0b5h, 0d6h, 0e0h, 0e9h, 0a5h, 0a5h + DB 0a6h, 0a7h, 0a8h, 0a9h, 0aah, 0abh, 0ach, 0adh + DB 0aeh, 0afh, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h + DB 0b6h, 0b7h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 0bdh + DB 0beh, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 0c7h, 0c7h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 0cfh, 0d1h, 0d1h, 0d2h, 0d3h, 0d4h, 049h + DB 0d6h, 0d7h, 0d8h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 0deh, 0dfh, 0e0h, 0e1h, 0e2h, 0e3h, 0e5h, 0e5h + DB 0e6h, 0e8h, 0e8h, 0e9h, 0eah, 0ebh, 0edh, 0edh + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsFnameTermHardcoded +_nlsFnameTermHardcoded: +?table5: + DB 016h, 000h, 08eh, 000h, 0ffh, 0b6h, 000h, 020h + DB 0eeh, 00eh, 02eh, 022h, 02fh, 05ch, 05bh, 05dh + DB 03ah, 07ch, 03ch, 03eh, 02bh, 03dh, 03bh, 02ch + GLOBAL _nlsCollHardcoded +_nlsCollHardcoded: +?table6: + DB 000h, 001h, 000h, 001h, 002h, 003h, 004h, 005h + DB 006h, 007h, 008h, 009h, 00ah, 00bh, 00ch, 00dh + DB 00eh, 00fh, 010h, 011h, 012h, 013h, 014h, 015h + DB 016h, 017h, 018h, 019h, 01ah, 01bh, 01ch, 01dh + DB 01eh, 01fh, 020h, 021h, 022h, 023h, 024h, 025h + DB 026h, 027h, 028h, 029h, 02ah, 02bh, 02ch, 02dh + DB 02eh, 02fh, 030h, 031h, 032h, 033h, 034h, 035h + DB 036h, 037h, 038h, 039h, 03ah, 03bh, 03ch, 03dh + DB 03eh, 03fh, 040h, 041h, 042h, 043h, 044h, 045h + DB 046h, 047h, 048h, 049h, 04ah, 04bh, 04ch, 04dh + DB 04eh, 04fh, 050h, 051h, 052h, 053h, 054h, 055h + DB 056h, 057h, 058h, 059h, 05ah, 05bh, 05ch, 05dh + DB 05eh, 05fh, 060h, 041h, 042h, 043h, 044h, 045h + DB 046h, 047h, 048h, 049h, 04ah, 04bh, 04ch, 04dh + DB 04eh, 04fh, 050h, 051h, 052h, 053h, 054h, 055h + DB 056h, 057h, 058h, 059h, 05ah, 07bh, 07ch, 07dh + DB 07eh, 07fh, 043h, 055h, 045h, 041h, 041h, 041h + DB 041h, 043h, 045h, 045h, 045h, 049h, 049h, 049h + DB 041h, 041h, 045h, 041h, 041h, 04fh, 04fh, 04fh + DB 055h, 055h, 059h, 04fh, 055h, 04fh, 024h, 04fh + DB 09eh, 024h, 041h, 049h, 04fh, 055h, 04eh, 04eh + DB 0a6h, 0a7h, 03fh, 0a9h, 0aah, 0abh, 0ach, 021h + DB 022h, 022h, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 041h + DB 041h, 041h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 024h + DB 024h, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 041h, 041h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 024h, 044h, 044h, 045h, 045h, 045h, 049h + DB 049h, 049h, 049h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 049h, 0dfh, 04fh, 053h, 04fh, 04fh, 04fh, 04fh + DB 0e6h, 0e8h, 0e8h, 055h, 055h, 055h, 059h, 059h + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsDBCSHardcoded +_nlsDBCSHardcoded: +?table7: + DB 000h, 000h, 000h, 000h + GLOBAL _hcTablesEnd +_hcTablesEnd: + + +END diff --git a/kernel/nls/049-850.unf b/kernel/nls/049-850.unf new file mode 100644 index 0000000..fd44a35 --- /dev/null +++ b/kernel/nls/049-850.unf @@ -0,0 +1,130 @@ +## Universal NLS data Format file: 049-850.unf +$country 49 +$codepage 850 + +# Global options +$radix 10 + + +[table 1] # Extended Country Information DOS-65-01 / DOS-38 +$make_size + = W49 W850 # Country ID & Codepage + = W1 # Date format: 0/1/2: U.S.A./Europe/Japan + = 68 77 0 0 0 # DM... # Currency string + = 46 0 # .. # Thousand's separator + = 44 0 # ,. # Decimal point + = 46 0 # .. # Date separator + = 58 0 # :. # Time separator + = 3 # Currency format (bit array) + = 2 # Currency precision + = 1 # time format: 0/1: 12/24 houres +$go_forward 4 # Far address of upcase function (to be calc at runtime) + = 59 0 # ;. # Data separator + + +[table 2] # normal character uppercase table +$make_size + + = 128 154 144 182 142 183 143 128 # €š¶Ž·€ @ 0 + = 210 211 212 216 215 222 142 143 # ÒÓÔØ×ÞŽ @ 8 + = 144 146 146 226 153 227 234 235 # ’’â™ãêë @ 16 + = 95 153 154 157 156 157 158 159 # _™šœžŸ @ 24 + = 181 214 224 233 165 165 166 167 # µÖà饥¦§ @ 32 + = 168 169 170 171 172 173 174 175 # ¨©ª«¬­®¯ @ 40 + = 176 177 178 179 180 181 182 183 # °±²³´µ¶· @ 48 + = 184 185 186 187 188 189 190 191 # ¸¹º»¼½¾¿ @ 56 + = 192 193 194 195 196 197 199 199 # ÀÁÂÃÄÅÇÇ @ 64 + = 200 201 202 203 204 205 206 207 # ÈÉÊËÌÍÎÏ @ 72 + = 209 209 210 211 212 73 214 215 # ÑÑÒÓÔIÖ× @ 80 + = 216 217 218 219 220 221 222 223 # ØÙÚÛÜÝÞß @ 88 + = 224 225 226 227 229 229 230 232 # àáâãååæè @ 96 + = 232 233 234 235 237 237 238 239 # èéêëííîï @ 104 + = 240 241 242 243 244 245 246 247 # ðñòóôõö÷ @ 112 + = 248 249 250 251 252 253 254 255 # øùúûüýþÿ @ 120 +$is_offset 128 + + +[table 4] # filename character uppercase table +$make_size + + = 128 154 144 182 142 183 143 128 # €š¶Ž·€ @ 0 + = 210 211 212 216 215 222 142 143 # ÒÓÔØ×ÞŽ @ 8 + = 144 146 146 226 153 227 234 235 # ’’â™ãêë @ 16 + = 95 153 154 157 156 157 158 159 # _™šœžŸ @ 24 + = 181 214 224 233 165 165 166 167 # µÖà饥¦§ @ 32 + = 168 169 170 171 172 173 174 175 # ¨©ª«¬­®¯ @ 40 + = 176 177 178 179 180 181 182 183 # °±²³´µ¶· @ 48 + = 184 185 186 187 188 189 190 191 # ¸¹º»¼½¾¿ @ 56 + = 192 193 194 195 196 197 199 199 # ÀÁÂÃÄÅÇÇ @ 64 + = 200 201 202 203 204 205 206 207 # ÈÉÊËÌÍÎÏ @ 72 + = 209 209 210 211 212 73 214 215 # ÑÑÒÓÔIÖ× @ 80 + = 216 217 218 219 220 221 222 223 # ØÙÚÛÜÝÞß @ 88 + = 224 225 226 227 229 229 230 232 # àáâãååæè @ 96 + = 232 233 234 235 237 237 238 239 # èéêëííîï @ 104 + = 240 241 242 243 244 245 246 247 # ðñòóôõö÷ @ 112 + = 248 249 250 251 252 253 254 255 # øùúûüýþÿ @ 120 +$is_offset 128 + + +[table 5] # Filename Termination Characters +$make_size +$go_forward 1 # skip one dummy byte + = 0 255 # Permittable characters +$go_forward 1 # skip one dummy byte + = 0 32 # Excluded characters (from above range) +$go_forward 1 # skip one dummy byte + = 14 # Number of enumerated excluded characters + + = 46 34 47 92 91 93 58 124 # ."/\[]:| @ 0 + = 60 62 43 61 59 44 # <>+=;, @ 8 +$is_offset 22 + + +[table 6] # collating sequence table +$make_size + + = 0 1 2 3 4 5 6 7 # ........ @ 0 + = 8 9 10 11 12 13 14 15 # ........ @ 8 + = 16 17 18 19 20 21 22 23 # ........ @ 16 + = 24 25 26 27 28 29 30 31 # ........ @ 24 + = 32 33 34 35 36 37 38 39 # !"#$%&' @ 32 + = 40 41 42 43 44 45 46 47 # ()*+,-./ @ 40 + = 48 49 50 51 52 53 54 55 # 01234567 @ 48 + = 56 57 58 59 60 61 62 63 # 89:;<=>? @ 56 + = 64 65 66 67 68 69 70 71 # @ABCDEFG @ 64 + = 72 73 74 75 76 77 78 79 # HIJKLMNO @ 72 + = 80 81 82 83 84 85 86 87 # PQRSTUVW @ 80 + = 88 89 90 91 92 93 94 95 # XYZ[\]^_ @ 88 + = 96 65 66 67 68 69 70 71 # `ABCDEFG @ 96 + = 72 73 74 75 76 77 78 79 # HIJKLMNO @ 104 + = 80 81 82 83 84 85 86 87 # PQRSTUVW @ 112 + = 88 89 90 123 124 125 126 127 # XYZ{|}~. @ 120 + = 67 85 69 65 65 65 65 67 # CUEAAAAC @ 128 + = 69 69 69 73 73 73 65 65 # EEEIIIAA @ 136 + = 69 65 65 79 79 79 85 85 # EAAOOOUU @ 144 + = 89 79 85 79 36 79 158 36 # YOUO$Ož$ @ 152 + = 65 73 79 85 78 78 166 167 # AIOUNN¦§ @ 160 + = 63 169 170 171 172 33 34 34 # ?©ª«¬!"" @ 168 + = 176 177 178 179 180 65 65 65 # °±²³´AAA @ 176 + = 184 185 186 187 188 36 36 191 # ¸¹º»¼$$¿ @ 184 + = 192 193 194 195 196 197 65 65 # ÀÁÂÃÄÅAA @ 192 + = 200 201 202 203 204 205 206 36 # ÈÉÊËÌÍÎ$ @ 200 + = 68 68 69 69 69 73 73 73 # DDEEEIII @ 208 + = 73 217 218 219 220 221 73 223 # IÙÚÛÜÝIß @ 216 + = 79 83 79 79 79 79 230 232 # OSOOOOæè @ 224 + = 232 85 85 85 89 89 238 239 # èUUUYYîï @ 232 + = 240 241 242 243 244 245 246 247 # ðñòóôõö÷ @ 240 + = 248 249 250 251 252 253 254 255 # øùúûüýþÿ @ 248 +$is_offset 256 + + +[table 7] # Double Byte Character Support (DBCS) +$make_size +$stop_size + = W0 # DBCS end marker (mandotary) + + +[table 35] # Extended Country Information DOS-65-23 + = 74 78 # JN # Yes & No character + + diff --git a/kernel/nls/049-850.up b/kernel/nls/049-850.up new file mode 100644 index 0000000000000000000000000000000000000000..67a9e91dedd3467d435bb3dcfd38ea797652dba5 GIT binary patch literal 256 zcmZQzWMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{)Y8_`)zddH zG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13EE{a#=Hgh`Vg&3ydob^Od(bLY&RH-GE32QQZ{UABD1%2lh^ ztX;Q$!^TaUw`|?EeaFsSyZ7wfxBtMwLx+zXJ%0Se$y2A#oIQ8`;zgiIp4YD5xOwaL toxAt$KX~})@zbZzUc7ku>h;^V@7{m-`04YPuiw7^`1$MipTGb90|1qgfBXOd literal 0 HcmV?d00001 diff --git a/kernel/nls/files b/kernel/nls/files new file mode 100644 index 0000000..3a662d5 --- /dev/null +++ b/kernel/nls/files @@ -0,0 +1,20 @@ +NLS files + +Filenames are encoded as: +CCC-PPP + CCC: country code + PPP: codepage ID + both are zero-padded three digits numbers; one number may + use four digits. + +Extensions: +UNF: Uniform NLS file Format + plain text representation of NLS package (7bit US-ASCII) + may be used to validate GRAB_UNF output + see UNF toolset for more information +UP : NLSUPTST data file + used to validate DOS API normal character upcase functions DOS-65-2[0-2] +HC : Hardcoded NLS file to be included into the kernel + produced by UNF2HC + copy to ..\NLS_HC.ASM in order to use this NLS package as the hardcoded one + kernel must be re-compiled diff --git a/kernel/nls_hc.asm b/kernel/nls_hc.asm new file mode 100644 index 0000000..85c7799 --- /dev/null +++ b/kernel/nls_hc.asm @@ -0,0 +1,127 @@ +; Hardcoded DOS-NLS information for country = 1, codepage = 437 +; This is an automatically generated file! +; Any modifications will be lost! + +; Prerequisites: +;; ==> Assuming that data of tables remains constant all the time +;; ==> Reordering tables 1, 2, 4 and 5 + + %include "segs.inc" +segment CONST2 + + GLOBAL _nlsPackageHardcoded +_nlsPackageHardcoded: + DB 000h, 000h, 000h, 000h, 001h, 000h, 0b5h, 001h + DB 00fh, 000h, 059h, 000h, 04eh, 000h, 006h, 000h + DB 002h + DW ?table2, SEG ?table2 + DB 004h + DW ?table4, SEG ?table4 + DB 005h + DW ?table5, SEG ?table5 + DB 006h + DW ?table6, SEG ?table6 + DB 007h + DW ?table7, SEG ?table7 + GLOBAL _nlsCountryInfoHardcoded +_nlsCountryInfoHardcoded: + DB 001h + GLOBAL _nlsCntryInfoHardcoded +_nlsCntryInfoHardcoded: +?table1: + DB 01ch, 000h, 001h, 000h, 0b5h, 001h, 000h, 000h + DB 024h, 000h, 000h, 000h, 000h, 02ch, 000h, 02eh + DB 000h, 02dh, 000h, 03ah, 000h, 000h, 002h, 000h +extern _CharMapSrvc:wrt DGROUP + DW _CharMapSrvc, SEG _CharMapSrvc + DB 02ch, 000h + GLOBAL _hcTablesStart +_hcTablesStart: + GLOBAL _nlsUpcaseHardcoded +_nlsUpcaseHardcoded: +?table2: + DB 080h, 000h, 080h, 09ah, 045h, 041h, 08eh, 041h + DB 08fh, 080h, 045h, 045h, 045h, 049h, 049h, 049h + DB 08eh, 08fh, 090h, 092h, 092h, 04fh, 099h, 04fh + DB 055h, 055h, 059h, 099h, 09ah, 09bh, 09ch, 09dh + DB 09eh, 09fh, 041h, 049h, 04fh, 055h, 0a5h, 0a5h + DB 0a6h, 0a7h, 0a8h, 0a9h, 0aah, 0abh, 0ach, 0adh + DB 0aeh, 0afh, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h + DB 0b6h, 0b7h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 0bdh + DB 0beh, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 0c6h, 0c7h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 0cfh, 0d0h, 0d1h, 0d2h, 0d3h, 0d4h, 0d5h + DB 0d6h, 0d7h, 0d8h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 0deh, 0dfh, 0e0h, 0e1h, 0e2h, 0e3h, 0e4h, 0e5h + DB 0e6h, 0e7h, 0e8h, 0e9h, 0eah, 0ebh, 0ech, 0edh + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsFUpcaseHardcoded +_nlsFUpcaseHardcoded: +?table4: + DB 080h, 000h, 080h, 09ah, 045h, 041h, 08eh, 041h + DB 08fh, 080h, 045h, 045h, 045h, 049h, 049h, 049h + DB 08eh, 08fh, 090h, 092h, 092h, 04fh, 099h, 04fh + DB 055h, 055h, 059h, 099h, 09ah, 09bh, 09ch, 09dh + DB 09eh, 09fh, 041h, 049h, 04fh, 055h, 0a5h, 0a5h + DB 0a6h, 0a7h, 0a8h, 0a9h, 0aah, 0abh, 0ach, 0adh + DB 0aeh, 0afh, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h + DB 0b6h, 0b7h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 0bdh + DB 0beh, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 0c6h, 0c7h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 0cfh, 0d0h, 0d1h, 0d2h, 0d3h, 0d4h, 0d5h + DB 0d6h, 0d7h, 0d8h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 0deh, 0dfh, 0e0h, 0e1h, 0e2h, 0e3h, 0e4h, 0e5h + DB 0e6h, 0e7h, 0e8h, 0e9h, 0eah, 0ebh, 0ech, 0edh + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsFnameTermHardcoded +_nlsFnameTermHardcoded: +?table5: + DB 016h, 000h, 08eh, 000h, 0ffh, 041h, 000h, 020h + DB 0eeh, 00eh, 02eh, 022h, 02fh, 05ch, 05bh, 05dh + DB 03ah, 07ch, 03ch, 03eh, 02bh, 03dh, 03bh, 02ch + GLOBAL _nlsCollHardcoded +_nlsCollHardcoded: +?table6: + DB 000h, 001h, 000h, 001h, 002h, 003h, 004h, 005h + DB 006h, 007h, 008h, 009h, 00ah, 00bh, 00ch, 00dh + DB 00eh, 00fh, 010h, 011h, 012h, 013h, 014h, 015h + DB 016h, 017h, 018h, 019h, 01ah, 01bh, 01ch, 01dh + DB 01eh, 01fh, 020h, 021h, 022h, 023h, 024h, 025h + DB 026h, 027h, 028h, 029h, 02ah, 02bh, 02ch, 02dh + DB 02eh, 02fh, 030h, 031h, 032h, 033h, 034h, 035h + DB 036h, 037h, 038h, 039h, 03ah, 03bh, 03ch, 03dh + DB 03eh, 03fh, 040h, 041h, 042h, 043h, 044h, 045h + DB 046h, 047h, 048h, 049h, 04ah, 04bh, 04ch, 04dh + DB 04eh, 04fh, 050h, 051h, 052h, 053h, 054h, 055h + DB 056h, 057h, 058h, 059h, 05ah, 05bh, 05ch, 05dh + DB 05eh, 05fh, 060h, 041h, 042h, 043h, 044h, 045h + DB 046h, 047h, 048h, 049h, 04ah, 04bh, 04ch, 04dh + DB 04eh, 04fh, 050h, 051h, 052h, 053h, 054h, 055h + DB 056h, 057h, 058h, 059h, 05ah, 07bh, 07ch, 07dh + DB 07eh, 07fh, 043h, 055h, 045h, 041h, 041h, 041h + DB 041h, 043h, 045h, 045h, 045h, 049h, 049h, 049h + DB 041h, 041h, 045h, 041h, 041h, 04fh, 04fh, 04fh + DB 055h, 055h, 059h, 04fh, 055h, 024h, 024h, 024h + DB 024h, 024h, 041h, 049h, 04fh, 055h, 04eh, 04eh + DB 0a6h, 0a7h, 03fh, 0a9h, 0aah, 0abh, 0ach, 021h + DB 022h, 022h, 0b0h, 0b1h, 0b2h, 0b3h, 0b4h, 0b5h + DB 0b6h, 0b7h, 0b8h, 0b9h, 0bah, 0bbh, 0bch, 0bdh + DB 0beh, 0bfh, 0c0h, 0c1h, 0c2h, 0c3h, 0c4h, 0c5h + DB 0c6h, 0c7h, 0c8h, 0c9h, 0cah, 0cbh, 0cch, 0cdh + DB 0ceh, 0cfh, 0d0h, 0d1h, 0d2h, 0d3h, 0d4h, 0d5h + DB 0d6h, 0d7h, 0d8h, 0d9h, 0dah, 0dbh, 0dch, 0ddh + DB 0deh, 0dfh, 0e0h, 053h, 0e2h, 0e3h, 0e4h, 0e5h + DB 0e6h, 0e7h, 0e8h, 0e9h, 0eah, 0ebh, 0ech, 0edh + DB 0eeh, 0efh, 0f0h, 0f1h, 0f2h, 0f3h, 0f4h, 0f5h + DB 0f6h, 0f7h, 0f8h, 0f9h, 0fah, 0fbh, 0fch, 0fdh + DB 0feh, 0ffh + GLOBAL _nlsDBCSHardcoded +_nlsDBCSHardcoded: +?table7: + DB 000h, 000h, 000h, 000h + GLOBAL _hcTablesEnd +_hcTablesEnd: diff --git a/kernel/nls_load.c b/kernel/nls_load.c new file mode 100644 index 0000000..0d338bb --- /dev/null +++ b/kernel/nls_load.c @@ -0,0 +1,51 @@ +/****************************************************************/ +/* */ +/* nls_load.c */ +/* FreeDOS */ +/* */ +/* National Languge Support functions and data structures */ +/* Load an entry from FreeDOS COUNTRY.SYS file. */ +/* */ +/* Copyright (c) 2000 */ +/* Steffen Kaiser */ +/* All Rights Reserved */ +/* */ +/* This file is part of FreeDOS. */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "init-mod.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: nls_load.c 625 2003-06-27 22:02:57Z bartoldeman $"; +#endif + +/** Setup the environment for shared source NLS_LOAD.SRC **/ +/**ska obsoleted #define cfgMemory Config.cfgCSYS_memory */ +/**ska obsoleted #define cfgFilename Config.cfgCSYS_fnam */ +#define cfgFilename nlsInfo.fname /* char FAR * */ +/**ska obsoleted #define cfgCountry Config.cfgCSYS_cntry */ +/**ska obsoleted #define cfgCodepage Config.cfgCSYS_cp */ +#define cfgData Config.cfgCSYS_data /* struct nlsCSys_loadPackage FAR * */ +#define getMem(bytes) KernelAlloc(bytes) +#define openSYSFile(filename) open(filename, 0) /* read-only, binary */ +#define nlsStartOfChain nlsInfo.chain +#define upCaseFct CharMapSrvc + +#include "nls_load.src" diff --git a/kernel/nlssupt.asm b/kernel/nlssupt.asm new file mode 100644 index 0000000..a87ed63 --- /dev/null +++ b/kernel/nlssupt.asm @@ -0,0 +1,73 @@ +; File: +; nls.asm +; Description: +; Assembly support routines for nls functions. +; +; Copyright (c) 1995, 1998 +; 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. +; +; $Id: nlssupt.asm 971 2004-05-30 19:31:07Z bartoldeman $ +; + + + %include "segs.inc" + %include "stacks.inc" + +segment HMA_TEXT + global _reloc_call_CharMapSrvc + extern _DosUpChar + extern _DGROUP_ +; +; CharMapSrvc: +; User callable character mapping service. +; Part of Function 38h +; +_reloc_call_CharMapSrvc: + + Protect386Registers + push ds + push es +; push bp +; push si +; push di + push dx + push cx + push bx + + push ax ; arg of _upChar + mov ds,[cs:_DGROUP_] + + call _DosUpChar + ;add sp, byte 2 // next POP retrieves orig AX + + pop bx + mov ah, bh ; keep hibyte untouched + + pop bx + pop cx + pop dx +; pop di +; pop si +; pop bp + pop es + pop ds + Restore386Registers + retf ; Return far diff --git a/kernel/prf.c b/kernel/prf.c new file mode 100644 index 0000000..fe585be --- /dev/null +++ b/kernel/prf.c @@ -0,0 +1,543 @@ +/****************************************************************/ +/* */ +/* prf.c */ +/* */ +/* Abbreviated printf Function */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" + +#ifdef FORSYS +#include +#include +#endif + +#ifdef _INIT +#define handle_char init_handle_char +#define put_console init_put_console +#define ltob init_ltob +#define do_printf init_do_printf +#define printf init_printf +#define sprintf init_sprintf +#define charp init_charp +#endif + +#include "debug.h" /* must be below xx to init_xx */ + +/* special console output routine */ +/*#define DOSEMU */ +#ifdef DOSEMU + +#define MAX_BUFSIZE 80 /* adjust if necessary */ +static int buff_offset = 0; +static char buff[MAX_BUFSIZE]; + +void put_console(int c) +{ + if (buff_offset >= MAX_BUFSIZE) + { + buff_offset = 0; + DebugPrintf(("Printf buffer overflow!\n")); + } + if (c == '\n') + { + buff[buff_offset] = 0; + buff_offset = 0; +#ifdef __TURBOC__ + _ES = FP_SEG(buff); + _DX = FP_OFF(buff); + _AX = 0x13; + __int__(0xe6); +#elif defined(I86) + asm + { + push ds; + pop es; + mov dx, offset buff; + mov ax, 0x13; + int 0xe6; + } +#endif + } + else + { + buff[buff_offset] = c; + buff_offset++; + } +} +#else +#ifdef __WATCOMC__ +void int29(char c); +#pragma aux int29 = "int 0x29" parm [al] modify exact [bx]; +#endif + +void put_console(int c) +{ + if (c == '\n') + put_console('\r'); + +#ifdef FORSYS + write(1, &c, 1); /* write character to stdout */ +#else +#if defined(__TURBOC__) + _AL = c; + __int__(0x29); +#elif defined(__WATCOMC__) + int29(c); +#elif defined(I86) + __asm + { + mov al, byte ptr c; + int 0x29; + } +#endif /* __TURBO__ */ +#endif /* FORSYS */ +} +#endif /* DOSEMU */ + +#if defined(DEBUG_NEED_PRINTF) || defined(FORSYS) || defined(_INIT) || defined(TEST) + +#if defined(DEBUG_NEED_PRINTF) && !defined(_INIT) && !defined(FORSYS) +/* need to use FAR pointers for resident DEBUG printf()s where SS != DS */ +#define SSFAR FAR +#else +#define SSFAR +#endif + +#ifndef FORSYS +/* copied from bcc (Bruce's C compiler) stdarg.h */ +typedef char SSFAR *va_list; +#define va_start(arg, last) ((arg) = (va_list) (&(last)+1)) +#define va_arg(arg, type) (((type SSFAR *)(arg+=sizeof(type)))[-1]) +#define va_end(arg) +#endif + +static BYTE SSFAR *charp = 0; + +STATIC VOID handle_char(COUNT); +STATIC void ltob(LONG, BYTE SSFAR *, COUNT); +STATIC void do_printf(const char *, REG va_list); + +/* special handler to switch between sprintf and printf */ +STATIC VOID handle_char(COUNT c) +{ + if (charp == 0) + put_console(c); + else + *charp++ = c; +} + +/* ltob -- convert an long integer to a string in any base (2-16) */ +STATIC void ltob(LONG n, BYTE SSFAR * s, COUNT base) +{ + ULONG u; + BYTE SSFAR *p, SSFAR *q; + int c; + + u = n; + + if (base == -10) /* signals signed conversion */ + { + base = 10; + if (n < 0) + { + u = -n; + *s++ = '-'; + } + } + + p = s; + do + { /* generate digits in reverse order */ + *p++ = "0123456789abcdef"[(UWORD) (u % base)]; + } + while ((u /= base) > 0); + + *p = '\0'; /* terminate the string */ + for (q = s; q < --p; q++) + { /* reverse the digits */ + c = *q; + *q = *p; + *p = c; + } +} + +#define LEFT 0 +#define RIGHT 1 +#define ZEROSFILL 2 +#define LONGARG 4 + +/* printf -- short version of printf to conserve space */ +int VA_CDECL printf(CONST char *fmt, ...) +{ + va_list arg; + va_start(arg, fmt); + charp = 0; + do_printf(fmt, arg); + return 0; +} + +#if defined(DEBUG_NEED_PRINTF) && !defined(_INIT) && !defined(FORSYS) +STATIC int VA_CDECL fsprintf(char FAR * buff, CONST char * fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + charp = buff; + do_printf(fmt, arg); + handle_char('\0'); + return 0; +} +#else +#define fsprintf sprintf +#endif + +int VA_CDECL sprintf(char * buff, CONST char * fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + charp = buff; + do_printf(fmt, arg); + handle_char('\0'); + return 0; +} + +STATIC void do_printf(CONST BYTE * fmt, va_list arg) +{ + int base; + BYTE s[11], FAR * p; + int size; + unsigned char flags; + + for (;*fmt != '\0'; fmt++) + { + if (*fmt != '%') + { + handle_char(*fmt); + continue; + } + + fmt++; + flags = RIGHT; + + if (*fmt == '-') + { + flags = LEFT; + fmt++; + } + + if (*fmt == '0') + { + flags |= ZEROSFILL; + fmt++; + } + + size = 0; + while (1) + { + unsigned c = (unsigned char)(*fmt - '0'); + if (c > 9) + break; + fmt++; + size = size * 10 + c; + } + + if (*fmt == 'l') + { + flags |= LONGARG; + fmt++; + } + + switch (*fmt) + { + case '\0': + va_end(arg); + return; + + case 'c': + handle_char(va_arg(arg, int)); + continue; + + case 'p': + { + UWORD w0 = va_arg(arg, unsigned); + char SSFAR *tmp = charp; + fsprintf(s, "%04x:%04x", va_arg(arg, unsigned), w0); + p = s; + charp = tmp; + break; + } + + case 's': + p = va_arg(arg, char *); + break; + + case 'F': + fmt++; + /* we assume %Fs here */ + case 'S': + p = va_arg(arg, char FAR *); + break; + + case 'i': + case 'd': + base = -10; + goto lprt; + + case 'o': + base = 8; + goto lprt; + + case 'u': + base = 10; + goto lprt; + + case 'X': + case 'x': + base = 16; + + lprt: + { + long currentArg; + if (flags & LONGARG) + currentArg = va_arg(arg, long); + else + { + currentArg = va_arg(arg, int); + if (base >= 0) + currentArg = (long)(unsigned)currentArg; + } + ltob(currentArg, s, base); + p = s; + } + break; + + default: + handle_char('?'); + case '%': + + handle_char(*fmt); + continue; + + } + { + size_t i = 0; + while(p[i]) i++; + size -= i; + } + + if (flags & RIGHT) + { + int ch = ' '; + if (flags & ZEROSFILL) ch = '0'; + for (; size > 0; size--) + handle_char(ch); + } + for (; *p != '\0'; p++) + handle_char(*p); + + for (; size > 0; size--) + handle_char(' '); + } + va_end(arg); +} + +#endif +#if !defined(FORSYS) && !defined(_INIT) + +extern void put_string(const char *); +extern void put_unsigned(unsigned, int, int); + +void hexd(char *title, UBYTE FAR * p, COUNT numBytes) +{ + int loop, start = 0; + put_string(title); + if (numBytes > 16) + put_console('\n'); + + for (start = 0; start < numBytes; start += 16) + { + put_unsigned(FP_SEG(p), 16, 4); + put_console(':'); + put_unsigned(FP_OFF(p + start), 16, 4); + put_console('|'); + for (loop = start; loop < numBytes && loop < start+16;loop++) + { + put_unsigned(p[loop], 16, 2); + put_console(' '); + } + for (loop = start; loop < numBytes && loop < start+16;loop++) + put_console(p[loop] < 0x20 ? '.' : p[loop]); + put_console('\n'); + } +} + +/* put_unsigned -- print unsigned int in base 2--16 */ +void put_unsigned(unsigned n, int base, int width) +{ + char s[6]; + int i; + + for (i = 0; i < width; i++) + { /* generate digits in reverse order */ + s[i] = "0123456789abcdef"[(UWORD) (n % base)]; + n /= base; + } + + while(i != 0) + { /* print digits in reverse order */ + put_console(s[--i]); + } +} + +void put_string(const char *s) +{ + while(*s != '\0') + put_console(*s++); +} + +#endif + +#ifdef TEST +/* + this testprogram verifies that the strings are printed correctly + ( or the way, I expect them to print) + + compile like (note -DTEST !) + + c:\tc\tcc -DTEST -DI86 -I..\hdr prf.c + + and run. if strings are wrong, the program will wait for the ANYKEY + +*/ +#include +#include + +void cso(char c) +{ + putchar(c); +} + +struct { + char *should; + char *format; + unsigned lowint; + unsigned highint; + +} testarray[] = { + { + "hello world", "%s %s", (unsigned)"hello", (unsigned)"world"}, + { + "hello", "%3s", (unsigned)"hello", 0}, + { + " hello", "%7s", (unsigned)"hello", 0}, + { + "hello ", "%-7s", (unsigned)"hello", 0}, + { + "hello", "%s", (unsigned)"hello", 0}, + { + "1", "%d", 1, 0}, + { + "-1", "%d", -1, 0}, + { + "65535", "%u", -1, 0}, + { + "-32768", "%d", 0x8000, 0}, + { + "32767", "%d", 0x7fff, 0}, + { + "-32767", "%d", 0x8001, 0}, + { + "8000", "%x", 0x8000, 0}, + { + " 1", "%4x", 1, 0}, + { + "0001", "%04x", 1, 0}, + { + "1 ", "%-4x", 1, 0}, + { + "1 ", "%-04x", 1, 0}, + { + "1", "%ld", 1, 0}, + { + "-1", "%ld", -1, -1}, + { + "65535", "%ld", -1, 0}, + { + "65535", "%u", -1, 0}, + { + "8000", "%lx", 0x8000, 0}, + { + "80000000", "%lx", 0, 0x8000}, + { + " 1", "%4lx", 1, 0}, + { + "0001", "%04lx", 1, 0}, + { + "1 ", "%-4lx", 1, 0}, + { + "1 ", "%-04lx", 1, 0}, + { + "-2147483648", "%ld", 0, 0x8000}, + { + "2147483648", "%lu", 0, 0x8000}, + { + "2147483649", "%lu", 1, 0x8000}, + { + "-2147483647", "%ld", 1, 0x8000}, + { + "32767", "%ld", 0x7fff, 0}, + { +"ptr 1234:5678", "ptr %p", 0x5678, 0x1234}, {0}}; + +void test(char *should, char *format, unsigned lowint, unsigned highint) +{ + char b[100]; + + sprintf(b, format, lowint, highint); + + printf("'%s' = '%s'\n", should, b); + + if (strcmp(b, should)) + { + printf("\nhit ENTER\n"); + getchar(); + } +} + +int main(void) +{ + int i; + printf("hello world\n"); + + for (i = 0; testarray[i].should; i++) + { + test(testarray[i].should, testarray[i].format, testarray[i].lowint, + testarray[i].highint); + } + return 0; +} +#endif + diff --git a/kernel/printer.asm b/kernel/printer.asm new file mode 100644 index 0000000..142a8b2 --- /dev/null +++ b/kernel/printer.asm @@ -0,0 +1,244 @@ +; +; File: +; printer.asm +; Description: +; Printer device driver +; +; Copyright (c) 1998 +; 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. +; +; $Header$ +; + + %include "io.inc" + + %define PRT_TIMEOUT 01h + %define PRT_IOERROR 08h + %define PRT_SELECTED 10h + %define PRT_OUTOFPAPER 20h + %define PRT_ACK 40h + %define PRT_NOTBUSY 80h + + %define PRT_WRITECHAR 00h + %define PRT_INITPORT 01h + %define PRT_GETSTATUS 02h + +segment _IO_FIXED_DATA + + global LptTable +LptTable db 18h + dw _IOExit + dw _IOExit + dw _IOExit + dw _IOCommandError + dw _IOSuccess + dw _IODone + dw _IOExit + dw _IOExit + dw PrtWrite + dw PrtWrite + dw PrtOutStat + dw _IOExit + dw _IOExit + dw _IOExit + dw _IOExit + dw _IOExit + dw PrtOutBsy + dw _IOExit + dw _IOExit + dw PrtGenIoctl + dw _IOExit + dw _IOExit + dw _IOExit + dw _IOCommandError + dw _IOCommandError + + +segment _IO_TEXT + global uPrtNo +uPrtNo db 0 +uPrtQuantum dw 50h + dw 50h, 50h + db 50h, 00h + +PrtWrite: + jcxz PrtWr3 ; Exit if nothing to write + +PrtCharLoop: ; next character loop + + mov bx, 2 ; number of retries +PrtRetryTwice: + mov ah, PRT_GETSTATUS ; get status, ah=2 + call PrtIOCall ; + jnz PrtWr4 + + mov al,[es:di] + + mov ah, PRT_WRITECHAR ; print character, ah=0 + call PrtIOCall ; (0800) + + jnz PrtWr4 ; NZ = error, retry + + inc di + loop PrtCharLoop ; next character +PrtWr3: + jmp _IOExit +PrtWr4: ; repeat + dec bx + jnz PrtRetryTwice +PrtWr5: + jmp _IOErrCnt + + + +PrtOutStat: + call GetPrtStat + jnz PrtWr5 + mov al, E_PAPER + test ah, PRT_OUTOFPAPER + jnz PrtWr5 + test ah, PRT_NOTBUSY + jnz PrtWr3 + jmp _IODone + + + +GetPrtStat: + mov ah,PRT_GETSTATUS + +PrtIOCall: + call GetUnitNum + int 17h ; print char al, get status ah + + mov al, ah ; if (stat & 0x30) == 0x30 return 10; + and al, PRT_SELECTED|PRT_OUTOFPAPER + cmp al, PRT_SELECTED|PRT_OUTOFPAPER + mov al, E_WRITE + je ret_error_code + + test ah, PRT_OUTOFPAPER|PRT_IOERROR|PRT_TIMEOUT ; 29h + mov al, E_NOTRDY + jz ret_error_code + + test ah, PRT_OUTOFPAPER ; 20h + mov al, E_WRITE + jz ret_error_code ; not out of paper -> E_WRITE + +ret_error_code_9: + mov al, E_PAPER + +ret_error_code: + cmp al, E_NOTRDY ; 2 = no error + retn + + + +PrtOutBsy: + push ds + push es + pop ds + mov si,di +PrtOtBsy1: + push cx + push bx + xor bx,bx + mov bl,[cs:uPrtNo] + shl bx,1 + mov cx,[cs:uPrtQuantum+bx] + pop bx +PrtOtBsy2: + call GetPrtStat + jnz PrtOtBsy3 + test ah, PRT_NOTBUSY + loopz PrtOtBsy2 + pop cx + jz PrtOtBsy4 + lodsb + xor ah,ah + call PrtIOCall + jnz PrtOtBsy4 + loop PrtOtBsy1 + pop ds + lds bx,[cs:_ReqPktPtr] + sub [bx+12h],cx + jmp _IOExit +PrtOtBsy3: + pop cx +PrtOtBsy4: + pop ds + lds bx,[cs:_ReqPktPtr] + sub [bx+12h],cx + jmp _IOErrorExit + + + +PrtGenIoctl: + les di,[cs:_ReqPktPtr] + cmp byte [es:di+0Dh],5 + je PrtGnIoctl2 +PrtGnIoctl1: + jmp _IOCommandError +PrtGnIoctl2: + mov al,[es:di+0Eh] + les di,[es:di+13h] + xor bx,bx + mov bl,[cs:uPrtNo] + shl bx,1 + mov cx,[cs:uPrtQuantum+bx] + cmp al,65h + je PrtGnIoctl3 + cmp al,45h + jne PrtGnIoctl1 + mov cx,[es:di] +PrtGnIoctl3: + mov [cs:uPrtQuantum+bx],cx + mov [es:di],cx + jmp _IOExit + + + +; +; some comments to last changes (TE, 23/09/01) +; +; original implementation didn't print at all - on my machine,LPT2 +; +; maybe this one is not much better either, +; but should print a little bit +; +; the status bits = AH +; +; 1 0 +; 80 - BUSY not busy busy +; 40 - ACK transfer finished not yet finished +; 20 - PAP no paper available paper OK +; 10 - ONOF printer online not online +; 08 - ERR some error no error +; 01 - TIM some error when transfer OK +; +; some states +; 30 - there is no printer at all +; c8 - there is a printer without power +; 10 - printer with power, but not initialized +; 90 - this one is fine +; +; you must not simply print without asking for status +; as the BIOS has a LARGE timeout before aborting +; diff --git a/kernel/procsupt.asm b/kernel/procsupt.asm new file mode 100644 index 0000000..60ece37 --- /dev/null +++ b/kernel/procsupt.asm @@ -0,0 +1,300 @@ +; +; File: +; procsupt.asm +; Description: +; Assembly support routines for process handling, etc. +; +; Copyright (c) 1995,1998 +; 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. +; +; $Id: procsupt.asm 1591 2011-05-06 01:46:55Z bartoldeman $ +; + + + %include "segs.inc" + + extern _user_r:wrt DGROUP + + extern _break_flg:wrt DGROUP ; break detected flag + extern _int21_handler:wrt DGROUP ; far call system services + + %include "stacks.inc" + +segment HMA_TEXT + + extern _DGROUP_ + +; +; Special call for switching processes +; +; void exec_user(iregs far *irp, int disable_a20) +; + global _exec_user +_exec_user: + +; PUSH$ALL +; mov ds,[_DGROUP_] +; cld +; +; +; + pop ax ; return address (unused) + + pop bp ; irp (user ss:sp) + pop si + pop cx ; disable A20? + or cx,cx + jz do_iret + + cli + mov ss,si + mov sp,bp ; set-up user stack + sti +; + POP$ALL + extern _ExecUserDisableA20 + jmp far _ExecUserDisableA20 +do_iret: + extern _int21_iret + jmp _int21_iret + +segment _LOWTEXT + + +;; Called whenever the BIOS detects a ^Break state + global _got_cbreak +_got_cbreak: + push ds + push ax + mov ax, 40h + mov ds, ax + or byte [71h], 80h ;; set the ^Break flag + pop ax + pop ds + iret + +segment HMA_TEXT + +; +; Special call for switching processes during break handling +; +; void interrupt far spawn_int23() +; +; +; +---------------+ +; | flags | 22 +; +---------------+ +; | cs | 20 +; +---------------+ +; | ip | 18 +; +---------------+ +; | es | 16 +; +---------------+ +; | ds | 14 +; +---------------+ +; | bp | 12 +; +---------------+ +; | di | 10 +; +---------------+ +; | si | 8 +; +---------------+ +; | dx | 6 +; +---------------+ +; | cx | 4 +; +---------------+ +; | bx | 2 +; +---------------+ +; | ax | 0 <--- bp & sp after mov bp,sp +; +---------------+ +; + global _spawn_int23 +_spawn_int23: + +;; 1999/03/27 ska - comments: see cmt1.txt + mov ds, [cs:_DGROUP_] ;; Make sure DS is OK + mov bp, [_user_r] + + ; restore to user stack + cli ;; Pre-8086 don't disable INT autom. +;*TE PATCH +; CtrlC at DosInput (like C:>DATE does) +; Nukes the Kernel. +; +; it looks like ENTRY.ASM+PROCSUPT.ASM +; got out of sync. +; +; spawn_int() assumes a stack layout at +; usr_ss:usr:sp. but usr:ss currently contains 0 +; +; this patch helps FreeDos to survive CtrlC, +; but should clearly be done somehow else. + mov ss, [_user_r+2] + RestoreSP + + sti + + ; get all the user registers back + Restore386Registers + POP$ALL + + ;; Construct the piece of code into the stack + + ;; stack frame: during generation of code piece + ;; + ;; BP | SP | Meaning + ;; 7 | 11 | offset CALL FAR will push onto stack + ;; 5 | 9 | CALL FAR segment + ;; 3 | 7 | CALL FAR offset + ;; 2 | 6 | CALL FAR ??regain_control_int23 | instruction byte + ;; 0 | 4 | INT 23 <> + ;; -2 | 2 | segment of address of INT-23 \ To jump to INT 23 + ;; -4 | 0 | offset of address of INT-23 / via RETF + ;; Upon return from INT-23 the CALL FAR pushes the address of + ;; the byte immediately following the CALL FAR onto the stack. + ;; This value POPed and decremented by 7 is the value SP must + ;; contain, if the INT-23 was returned with RETF2/IRET. + + sub sp, byte 8 ;; code piece needs 7 bytes --> 4 words + push ss ;; prepare jump to INT-23 via RETF + push bp ;; will be offset / temp: saved BP + mov bp, sp + add bp, byte 4 ;; position BP onto INT-23 + mov word [bp], 23cdh ;; INT 23h + mov byte [bp+2], 9ah ;; CALL FAR immediate + mov word [bp+3], ??regain_control_int23 + mov word [bp+5], cs + + ;; complete the jump to INT-23 via RETF and restore BP + xchg word [bp-4], bp + + clc ;; set default action --> resume + ; invoke the int 23 handler its address has been constructed + ;; on the stack + retf + +??regain_control_int23: + + ;; stack frame: constructed on entry to INT-23 + ;; + ; BP | SP | Meaning + ;; 7 | 11 | offset CALL FAR will push onto stack + ;; 5 | 9 | CALL FAR segment + ;; 3 | 7 | CALL FAR offset + ;; 2 | 6 | CALL FAR ??regain_control_int23 | instruction byte + ;; 0 | 4 | INT 23 <> + ;; -2 | 2 | segment of address of INT-23 \ To jump to INT 23 + ;; -4 | 0 | offset of address of INT-23 / via RETF + ;; Upon return from INT-23 the CALL FAR pushes the address of + ;; the byte immediately following the CALL FAR onto the stack. + ;; This value POPed and decremented by 7 is the value SP must + ;; contain, if the INT-23 was returned with RETF2/IRET. + + ;; stack frame: used during recovering from INT-23 + ;; + ;; BP | Meaning + ;; 1 | <> + ;; 0 | <> + ;; -1 | saved BP + ;; -3 | saved AX + ;; -7 | INT 23 <> + + ;; Somewhere on stack: + ;; SP | Meaning + ;; 4 | segment of return address of CALL FAR + ;; 2 | offset of return address of CALL FAR + ;; 0 | saved BP + + push bp + mov bp, sp + mov bp, [bp+2] ;; get should-be address + 7 + mov word [bp-3], ax ;; save AX + pop ax ;; old BP + mov word [bp-1], ax ;; preserve saved BP + mov ax, bp + dec ax ;; last used word of stack + dec ax ;; Don't use SUB to keep Carry flag + dec ax + xchg ax, sp ;; AX := current stack; SP corrected + ;; Currently: BP - 7 == address of INT-23 + ;; should be AX + 4 --> IRET or RETF 2 + ;; ==> Test if BP - 7 == AX + 4 + ;; ==> Test if AX + 4 - BP + 7 == 0 + pushf ;; preserve Carry flag + add ax, byte 4 + 7 + sub ax, bp ;; AX := SP + 4 + pop ax ;; saved Carry flag + jz ??int23_ign_carry ;; equal -> IRET --> ignore Carry + ;; Carry is already cleared + push ax + popf ;; restore Carry flag + +??int23_ign_carry: + pop ax ;; Restore the original register + jnc ??int23_respawn + ;; The user returned via RETF 0, Carry is set + ;; --> terminate program + ;; This is done by set the _break_flg and modify the + ;; AH value, which is passed to the _respawn_ call + ;; into 0, which is "Terminate program". + push ds ;; we need DGROUP + mov ds, [cs:_DGROUP_] + inc byte [_break_flg] + pop ds + + xor ah, ah ;; clear ah --> perform DOS-00 --> terminate + +??int23_respawn: + pop bp ;; Restore the original register + jmp far _int21_handler + +; +; interrupt enable and disable routines +; +; public _enable +;_enable proc near +; sti +; ret +;_enable endp +; +; public _disable +;_disable proc near +; cli +; ret +;_disable endp + + extern _p_0_tos,_P_0 + +; prepare to call process 0 (the shell) from P_0() in C + + global reloc_call_p_0 +reloc_call_p_0: + pop ax ; return address (32-bit, unused) + pop ax + pop ax ; fetch parameter 0 (32-bit) from the old stack + pop dx + mov ds,[cs:_DGROUP_] + cli + mov ss,[cs:_DGROUP_] + mov sp,_p_0_tos ; load the dedicated process 0 stack + sti + push dx ; pass parameter 0 onto the new stack + push ax + call _P_0 ; no return, allow parameter fetch from C diff --git a/kernel/proto.h b/kernel/proto.h new file mode 100644 index 0000000..b45a9fb --- /dev/null +++ b/kernel/proto.h @@ -0,0 +1,399 @@ +/****************************************************************/ +/* */ +/* proto.h */ +/* */ +/* Global Function Prototypes */ +/* */ +/* Copyright (c) 1995, 1996 */ +/* 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. */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *Proto_hRcsId = + "$Id: proto.h 1491 2009-07-18 20:48:44Z bartoldeman $"; +#endif +#endif + +/* blockio.c */ +struct buffer FAR *getblk(ULONG blkno, COUNT dsk, BOOL overwrite); +#define getblock(blkno, dsk) getblk(blkno, dsk, FALSE); +#define getblockOver(blkno, dsk) getblk(blkno, dsk, TRUE); +VOID setinvld(REG COUNT dsk); +BOOL dirty_buffers(REG COUNT dsk); +BOOL flush_buffers(REG COUNT dsk); +BOOL flush(void); +BOOL fill(REG struct buffer FAR * bp, ULONG blkno, COUNT dsk); +BOOL DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mode); +/* *** Changed on 9/4/00 BER */ +UWORD dskxfer(COUNT dsk, ULONG blkno, VOID FAR * buf, UWORD numblocks, + COUNT mode); +/* *** End of change */ +void AllocateHMASpace (size_t lowbuffer, size_t highbuffer); + +/* break.c */ +unsigned char ctrl_break_pressed(void); +unsigned char check_handle_break(struct dhdr FAR **pdev); +void handle_break(struct dhdr FAR **pdev, int sft_out); +#ifdef __WATCOMC__ +#pragma aux handle_break aborts; +#endif + +/* chario.c */ +struct dhdr FAR *sft_to_dev(sft FAR *sft); +long BinaryCharIO(struct dhdr FAR **pdev, size_t n, void FAR * bp, + unsigned command); +int ndread(struct dhdr FAR **pdev); +int StdinBusy(void); +void con_flush(struct dhdr FAR **pdev); +unsigned char read_char(int sft_in, int sft_out, BOOL check_break); +unsigned char read_char_stdin(BOOL check_break); +long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp); +void read_line(int sft_in, int sft_out, keyboard FAR * kp); +size_t read_line_handle(int sft_idx, size_t n, char FAR * bp); +void write_char(int c, int sft_idx); +void write_char_stdout(int c); +void update_scr_pos(unsigned char c, unsigned char count); +long cooked_write(struct dhdr FAR **pdev, size_t n, char FAR *bp); + +sft FAR *get_sft(UCOUNT); + +/* dosfns.c */ +const char FAR *get_root(const char FAR *); +BOOL check_break(void); +UCOUNT GenericReadSft(sft far * sftp, UCOUNT n, void FAR * bp, + COUNT * err, BOOL force_binary); +COUNT SftSeek(int sft_idx, LONG new_pos, unsigned mode); +/*COUNT DosRead(COUNT hndl, UCOUNT n, BYTE FAR * bp, COUNT FAR * err); */ +void BinarySftIO(int sft_idx, void *bp, int mode); +#define BinaryIO(hndl, bp, mode) BinarySftIO(get_sft_idx(hndl), bp, mode) +long DosRWSft(int sft_idx, size_t n, void FAR * bp, int mode); +#define DosRead(hndl, n, bp) DosRWSft(get_sft_idx(hndl), n, bp, XFR_READ) +#define DosWrite(hndl, n, bp) DosRWSft(get_sft_idx(hndl), n, bp, XFR_WRITE) +ULONG DosSeek(unsigned hndl, LONG new_pos, COUNT mode, int *rc); +long DosOpen(char FAR * fname, unsigned flags, unsigned attrib); +COUNT CloneHandle(unsigned hndl); +long DosDup(unsigned Handle); +COUNT DosForceDup(unsigned OldHandle, unsigned NewHandle); +long DosOpenSft(char FAR * fname, unsigned flags, unsigned attrib); +COUNT DosClose(COUNT hndl); +COUNT DosCloseSft(int sft_idx, BOOL commitonly); +#define DosCommit(hndl) DosCloseSft(get_sft_idx(hndl), TRUE) +UWORD DosGetFree(UBYTE drive, UWORD * navc, UWORD * bps, UWORD * nc); +COUNT DosGetCuDir(UBYTE drive, BYTE FAR * s); +COUNT DosChangeDir(BYTE FAR * s); +COUNT DosFindFirst(UCOUNT attr, BYTE FAR * name); +COUNT DosFindNext(void); +COUNT DosGetFtime(COUNT hndl, date * dp, time * tp); +COUNT DosSetFtimeSft(int sft_idx, date dp, time tp); +#define DosSetFtime(hndl, dp, tp) DosSetFtimeSft(get_sft_idx(hndl), (dp), (tp)) +COUNT DosGetFattr(BYTE FAR * name); +COUNT DosSetFattr(BYTE FAR * name, UWORD attrp); +UBYTE DosSelectDrv(UBYTE drv); +COUNT DosDelete(BYTE FAR * path, int attrib); +COUNT DosRename(BYTE FAR * path1, BYTE FAR * path2); +COUNT DosRenameTrue(BYTE * path1, BYTE * path2, int attrib); +COUNT DosMkRmdir(const char FAR * dir, int action); +struct dhdr FAR *IsDevice(const char FAR * FileName); +BOOL IsShareInstalled(BOOL recheck); +COUNT DosLockUnlock(COUNT hndl, LONG pos, LONG len, COUNT unlock); +int idx_to_sft_(int SftIndex); +sft FAR *idx_to_sft(int SftIndex); +int get_sft_idx(UCOUNT hndl); +struct cds FAR *get_cds(unsigned dsk); +struct cds FAR *get_cds1(unsigned dsk); +COUNT DosTruename(const char FAR * src, char FAR * dest); + +/* dosidle.asm */ +VOID ASMCFUNC DosIdle_int(void); +VOID ASMCFUNC DosIdle_hlt(void); +#ifdef __WATCOMC__ +#pragma aux (cdecl) DosIdle_int modify exact [] +#pragma aux (cdecl) DosIdle_hlt modify exact [] +#endif + +/* error.c */ +VOID dump(void); +VOID panic(BYTE * s); +VOID fatal(BYTE * err_msg); + +/* fatdir.c */ +VOID dir_init_fnode(f_node_ptr fnp, CLUSTER dirstart); +f_node_ptr dir_open(const char *dirname, BOOL split, f_node_ptr fnp); +COUNT dir_read(REG f_node_ptr fnp); +BOOL dir_write_update(REG f_node_ptr fnp, BOOL update); +#define dir_write(fnp) dir_write_update(fnp, FALSE) +COUNT dos_findfirst(UCOUNT attr, BYTE * name); +COUNT dos_findnext(void); +void ConvertName83ToNameSZ(BYTE FAR * destSZ, BYTE FAR * srcFCBName); +const char *ConvertNameSZToName83(char *destFCBName, const char *srcSZ); + +/* fatfs.c */ +struct dpb FAR *get_dpb(COUNT dsk); +ULONG clus2phys(CLUSTER cl_no, struct dpb FAR * dpbp); +int dos_open(char * path, unsigned flag, unsigned attrib, int fd); +BOOL fcbmatch(const char *fcbname1, const char *fcbname2); +BOOL fcmp_wild(const char * s1, const char * s2, unsigned n); +VOID touc(BYTE * s, COUNT n); +COUNT dos_close(COUNT fd); +COUNT dos_delete(BYTE * path, int attrib); +COUNT dos_rmdir(BYTE * path); +COUNT dos_rename(BYTE * path1, BYTE * path2, int attrib); +date dos_getdate(void); +time dos_gettime(void); +COUNT dos_mkdir(BYTE * dir); +BOOL last_link(f_node_ptr fnp); +COUNT map_cluster(REG f_node_ptr fnp, COUNT mode); +long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode); +COUNT dos_read(COUNT fd, VOID FAR * buffer, UCOUNT count); +COUNT dos_write(COUNT fd, const VOID FAR * buffer, UCOUNT count); +CLUSTER dos_free(struct dpb FAR * dpbp); +BOOL dir_exists(char * path); +VOID dpb16to32(struct dpb FAR *dpbp); + +f_node_ptr split_path(const char *, f_node_ptr fnp); + +int dos_cd(char * PathName); + +COUNT dos_getfattr(BYTE * name); +COUNT dos_setfattr(BYTE * name, UWORD attrp); +COUNT media_check(REG struct dpb FAR * dpbp); +f_node_ptr xlt_fd(COUNT fd); +COUNT xlt_fnp(f_node_ptr fnp); +struct dhdr FAR * select_unit(COUNT drive); +void dos_merge_file_changes(int fd); + +/* fattab.c */ +void read_fsinfo(struct dpb FAR * dpbp); +void write_fsinfo(struct dpb FAR * dpbp); +CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, + REG CLUSTER Cluster2); +CLUSTER next_cluster(struct dpb FAR * dpbp, REG CLUSTER ClusterNum); +BOOL is_free_cluster(struct dpb FAR * dpbp, REG CLUSTER ClusterNum); + +/* fcbfns.c */ +VOID DosOutputString(BYTE FAR * s); +int DosCharInputEcho(VOID); +int DosCharInput(VOID); +VOID DosDirectConsoleIO(iregs FAR * r); +VOID DosCharOutput(COUNT c); +VOID DosDisplayOutput(COUNT c); +BYTE FAR *FatGetDrvData(UBYTE drive, UBYTE * spc, UWORD * bps, + UWORD * nc); +UWORD FcbParseFname(UBYTE *wTestMode, const BYTE FAR *lpFileName, fcb FAR * lpFcb); +const BYTE FAR *ParseSkipWh(const BYTE FAR * lpFileName); +BOOL TestCmnSeps(BYTE FAR * lpFileName); +BOOL TestFieldSeps(BYTE FAR * lpFileName); +const BYTE FAR *GetNameField(const BYTE FAR * lpFileName, BYTE FAR * lpDestField, + COUNT nFieldSize, BOOL * pbWildCard); +UBYTE FcbReadWrite(xfcb FAR *, UCOUNT, int); +UBYTE FcbGetFileSize(xfcb FAR * lpXfcb); +void FcbSetRandom(xfcb FAR * lpXfcb); +UBYTE FcbRandomBlockIO(xfcb FAR * lpXfcb, UWORD *nRecords, int mode); +UBYTE FcbRandomIO(xfcb FAR * lpXfcb, int mode); +UBYTE FcbOpen(xfcb FAR * lpXfcb, unsigned flags); +UBYTE FcbDelete(xfcb FAR * lpXfcb); +UBYTE FcbRename(xfcb FAR * lpXfcb); +UBYTE FcbClose(xfcb FAR * lpXfcb); +void FcbCloseAll(void); +UBYTE FcbFindFirstNext(xfcb FAR * lpXfcb, BOOL First); + +/* intr.asm */ +COUNT ASMPASCAL res_DosExec(COUNT mode, exec_blk * ep, BYTE * lp); +UCOUNT ASMPASCAL res_read(int fd, void *buf, UCOUNT count); +#ifdef __WATCOMC__ +#pragma aux (pascal) res_DosExec modify exact [ax bx dx es] +#pragma aux (pascal) res_read modify exact [ax bx cx dx] +#endif + +/* ioctl.c */ +COUNT DosDevIOctl(lregs * r); + +/* memmgr.c */ +seg far2para(VOID FAR * p); +seg long2para(ULONG size); +void FAR *add_far(void FAR * fp, unsigned off); +VOID FAR *adjust_far(const void FAR * fp); +COUNT DosMemAlloc(UWORD size, COUNT mode, seg * para, UWORD * asize); +COUNT DosMemLargest(UWORD * size); +COUNT DosMemFree(UWORD para); +COUNT DosMemChange(UWORD para, UWORD size, UWORD * maxSize); +COUNT DosMemCheck(void); +COUNT FreeProcessMem(UWORD ps); +COUNT DosGetLargestBlock(UWORD * block); +VOID show_chain(void); +void DosUmbLink(unsigned n); +VOID mcb_print(mcb FAR * mcbp); + +/* lfnapi.c */ +COUNT lfn_allocate_inode(VOID); +COUNT lfn_free_inode(COUNT handle); + +COUNT lfn_setup_inode(COUNT handle, ULONG dirstart, UWORD diroff); + +COUNT lfn_create_entries(COUNT handle, lfn_inode_ptr lip); +COUNT lfn_remove_entries(COUNT handle); + +COUNT lfn_dir_read(COUNT handle, lfn_inode_ptr lip); +COUNT lfn_dir_write(COUNT handle); + +/* nls.c */ +BYTE DosYesNo(UWORD ch); +#ifndef DosUpMem +VOID DosUpMem(VOID FAR * str, unsigned len); +#endif +unsigned char ASMCFUNC DosUpChar(unsigned char ch); +VOID DosUpString(char FAR * str); +VOID DosUpFMem(VOID FAR * str, unsigned len); +unsigned char DosUpFChar(unsigned char ch); +VOID DosUpFString(char FAR * str); +COUNT DosGetData(int subfct, UWORD cp, UWORD cntry, UWORD bufsize, + VOID FAR * buf); +#ifndef DosGetCountryInformation +COUNT DosGetCountryInformation(UWORD cntry, VOID FAR * buf); +#endif +#ifndef DosSetCountry +COUNT DosSetCountry(UWORD cntry); +#endif +COUNT DosGetCodepage(UWORD * actCP, UWORD * sysCP); +COUNT DosSetCodepage(UWORD actCP, UWORD sysCP); +VOID FAR *DosGetDBCS(void); +UWORD ASMCFUNC syscall_MUX14(DIRECT_IREGS); + +/* prf.c */ +#ifdef DEBUG +int VA_CDECL printf(CONST char * fmt, ...); +int VA_CDECL sprintf(char * buff, CONST char * fmt, ...); +#endif +VOID hexd(char *title, VOID FAR * p, COUNT numBytes); +void put_unsigned(unsigned n, int base, int width); +void put_string(const char *s); +void put_console(int); + +/* strings.c */ +size_t /* ASMCFUNC */ ASMPASCAL strlen(const char * s); +size_t /* ASMCFUNC */ ASMPASCAL fstrlen(const char FAR * s); +char FAR * /*ASMCFUNC*/ ASMPASCAL _fstrcpy(char FAR * d, const char FAR * s); +int /*ASMCFUNC*/ ASMPASCAL strcmp(const char * d, const char * s); +int /*ASMCFUNC*/ ASMPASCAL fstrcmp(const char FAR * d, const char FAR * s); +int /*ASMCFUNC*/ ASMPASCAL fstrncmp(const char FAR * d, const char FAR * s, size_t l); +int /*ASMCFUNC*/ ASMPASCAL strncmp(const char * d, const char * s, size_t l); +char * /*ASMCFUNC*/ ASMPASCAL strchr(const char * s, int c); +char FAR * /*ASMCFUNC*/ ASMPASCAL fstrchr(const char FAR * s, int c); +void FAR * /*ASMCFUNC*/ ASMPASCAL fmemchr(const void FAR * s, int c, size_t n); + +/* misc.c */ +char * /*ASMCFUNC*/ ASMPASCAL strcpy(char * d, const char * s); +void /*ASMCFUNC*/ ASMPASCAL fmemcpyBack(void FAR * d, const void FAR * s, size_t n); +void /*ASMCFUNC*/ ASMPASCAL fmemcpy(void FAR * d, const void FAR * s, size_t n); +void /*ASMCFUNC*/ ASMPASCAL fstrcpy(char FAR * d, const char FAR * s); +void * /*ASMCFUNC*/ ASMPASCAL memcpy(void *d, const void * s, size_t n); +void * /*ASMCFUNC*/ ASMPASCAL fmemset(void FAR * s, int ch, size_t n); +void * /*ASMCFUNC*/ ASMPASCAL memset(void * s, int ch, size_t n); + +int /*ASMCFUNC*/ ASMPASCAL memcmp(const void *m1, const void *m2, size_t n); +int /*ASMCFUNC*/ ASMPASCAL fmemcmp(const void FAR *m1, const void FAR *m2, size_t n); + +#ifdef __WATCOMC__ +/* bx, cx, dx and es not used or clobbered for all asmsupt.asm functions except + (f)memchr/(f)strchr (which clobber dx) */ +#pragma aux (pascal) pascal_ax modify exact [ax] +#pragma aux (pascal_ax) fmemcpy +#pragma aux (pascal_ax) memcpy +#pragma aux (pascal_ax) fmemset +#pragma aux (pascal_ax) memset +#pragma aux (pascal_ax) fmemcmp modify nomemory +#pragma aux (pascal_ax) memcmp modify nomemory +#pragma aux (pascal_ax) fstrcpy +#pragma aux (pascal_ax) strcpy +#pragma aux (pascal_ax) fstrlen modify nomemory +#pragma aux (pascal_ax) strlen modify nomemory +#pragma aux (pascal) memchr modify exact [ax dx] nomemory +#pragma aux (pascal) fmemchr modify exact [ax dx] nomemory +#pragma aux (pascal) strchr modify exact [ax dx] nomemory +#pragma aux (pascal) fstrchr modify exact [ax dx] nomemory +#endif + +/* sysclk.c */ +COUNT BcdToByte(COUNT x); +COUNT BcdToWord(BYTE * x, UWORD * mon, UWORD * day, UWORD * yr); +LONG WordToBcd(BYTE * x, UWORD * mon, UWORD * day, UWORD * yr); + +/* syspack.c */ +#ifdef NONNATIVE +VOID getdirent(UBYTE FAR * vp, struct dirent FAR * dp); +VOID putdirent(struct dirent FAR * dp, UBYTE FAR * vp); +#else +#define getdirent(vp, dp) fmemcpy(dp, vp, sizeof(struct dirent)) +#define putdirent(dp, vp) fmemcpy(vp, dp, sizeof(struct dirent)) +#endif + +/* systime.c */ +void DosGetTime(struct dostime *dt); +int DosSetTime(const struct dostime *dt); +unsigned char DosGetDate(struct dosdate *dd); +int DosSetDate(const struct dosdate *dd); + +const UWORD *is_leap_year_monthdays(UWORD year); +UWORD DaysFromYearMonthDay(UWORD Year, UWORD Month, UWORD DayOfMonth); + +/* task.c */ +VOID new_psp(seg para, seg cur_psp); +VOID child_psp(seg para, seg cur_psp, int psize); +VOID return_user(void); +COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp); +ULONG SftGetFsize(int sft_idx); +VOID InitPSP(VOID); + +/* newstuff.c */ +int SetJFTSize(UWORD nHandles); +long DosMkTmp(BYTE FAR * pathname, UWORD attr); +COUNT truename(const char FAR * src, char * dest, COUNT t); + +/* network.c */ +int network_redirector(unsigned cmd); +int network_redirector_fp(unsigned cmd, void far *s); +long ASMPASCAL network_redirector_mx(unsigned cmd, void far *s, void *arg); +#define remote_rw(cmd,s,arg) network_redirector_mx(cmd, s, (void *)arg) +#define remote_getfree(s,d) (int)network_redirector_mx(REM_GETSPACE, s, d) +#define remote_lseek(s,new_pos) network_redirector_mx(REM_LSEEK, s, &new_pos) +#define remote_setfattr(attr) (int)network_redirector_mx(REM_SETATTR, NULL, (void *)attr) +#define remote_printredir(dx,ax) (int)network_redirector_mx(REM_PRINTREDIR, MK_FP(0,dx),(void *)ax) +#define QRemote_Fn(d,s) (int)network_redirector_mx(REM_FILENAME, d, (void *)&s) + +UWORD get_machine_name(BYTE FAR * netname); +VOID set_machine_name(BYTE FAR * netname, UWORD name_num); + +/* procsupt.asm */ +VOID ASMCFUNC exec_user(iregs FAR * irp, int disable_a20); + +/* new by TE */ + +/* + assert at compile time, that something is true. + + use like + ASSERT_CONST( SECSIZE == 512) + ASSERT_CONST( (BYTE FAR *)x->fcb_ext - (BYTE FAR *)x->fcbname == 8) +*/ + +#define ASSERT_CONST(x) { typedef struct { char _xx[x ? 1 : -1]; } xx ; } + diff --git a/kernel/segs.inc b/kernel/segs.inc new file mode 100644 index 0000000..e0a31c3 --- /dev/null +++ b/kernel/segs.inc @@ -0,0 +1,99 @@ +; File: +; segs.inc +; Description: +; Segment definitions for the kernel +; +; Copyright (c) 1998 +; 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. +; +; $Header$ +; + +; CPU specification -- putting it here because all .asm files include this +; file __NASM_VER__ was introduced in NASM after CPU -- ver 0.98 doesn't +; understand it +%ifdef __NASM_VER__ +%if XCPU == 86 +CPU 8086 +%else +CPU XCPU +%endif +%endif + +; for OW on Linux: +%ifdef owlinux +%define WATCOM +%endif + +group PGROUP PSP +group LGROUP _IRQTEXT _LOWTEXT _IO_TEXT _IO_FIXED_DATA _TEXT +group DGROUP _FIXED_DATA _BSS _DATA _DATAEND CONST CONST2 DCONST DYN_DATA +%ifdef WATCOM +group TGROUP HMA_TEXT_START HMA_TEXT HMA_TEXT_END INIT_TEXT_START INIT_TEXT INIT_TEXT_END +group I_GROUP ID_B I_DATA ICONST ICONST2 ID_E IB_B I_BSS IB_E +%else +group TGROUP HMA_TEXT_START HMA_TEXT HMA_TEXT_END +group IGROUP INIT_TEXT_START INIT_TEXT INIT_TEXT_END +group I_GROUP ID_B ID ID_E IC IDATA IB_B IB IB_E +%endif + +segment PSP class=PSP +segment _IRQTEXT class=LCODE +segment _LOWTEXT class=LCODE +segment _IO_TEXT class=LCODE +segment _IO_FIXED_DATA class=LCODE align=2 +segment _TEXT class=LCODE +segment _FIXED_DATA class=FDATA align=16 +segment _BSS class=BSS align=2 +segment _DATA class=DATA align=2 +segment _DATAEND class=DATA align=1 +;for WATCOM +segment CONST class=DATA align=2 +segment CONST2 class=DATA align=2 +;for MSC +segment DCONST class=DCONST align=2 +segment DYN_DATA class=DYN_DATA +segment HMA_TEXT_START class=CODE align=16 +segment HMA_TEXT class=CODE +segment HMA_TEXT_END class=CODE +segment INIT_TEXT_START class=CODE align=16 +segment INIT_TEXT class=CODE +segment INIT_TEXT_END class=CODE + +%ifdef WATCOM +segment ID_B class=FAR_DATA align=16 +segment I_DATA class=FAR_DATA align=2 +segment ICONST class=FAR_DATA align=2 +segment ICONST2 class=FAR_DATA align=2 +segment ID_E class=FAR_DATA align=2 +segment IB_B class=FAR_DATA align=2 +segment I_BSS class=FAR_DATA align=2 +segment IB_E class=FAR_DATA align=2 +%else +segment ID_B class=ID align=16 +segment ID class=ID align=2 +segment IDATA class=ID align=2 +segment ID_E class=ID align=2 +segment IC class=IC align=2 +segment IB_B class=IB align=2 +segment IB class=IB align=2 +segment IB_E class=IB align=2 +%endif diff --git a/kernel/serial.asm b/kernel/serial.asm new file mode 100644 index 0000000..d7fb3b6 --- /dev/null +++ b/kernel/serial.asm @@ -0,0 +1,182 @@ +; +; File: +; serial.asm +; Description: +; Serial device driver +; +; Copyright (c) 1998 +; 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. +; +; $Header$ +; + + %include "io.inc" + +segment _IO_FIXED_DATA + + global ComTable +ComTable db 0Ah + dw _IOExit + dw _IOExit + dw _IOExit + dw _IOCommandError + dw ComRead + dw ComNdRead + dw ComInStat + dw ComInpFlush + dw ComWrite + dw ComWrite + dw ComOutStat + + + +segment _IO_TEXT + + extern CommonNdRdExit:wrt LGROUP + +ComRead: + jcxz ComRd3 + call GetComStat + xor ax,ax + xchg [bx],al + or al,al + jnz ComRd2 +ComRd1: + call BiosRdCom + or ah,ah ; timeout? + js ComRd1 ; yes, try again +ComRd2: + stosb + loop ComRd1 + +ComRd3: + jmp _IOExit + + +BiosRdCom: + mov ah,2 + call ComIOCall + test ah,0Eh + jz BiosRdRetn + add sp,byte 2 + xor al,al + or al,0B0h + jmp _IOErrCnt +BiosRdRetn: + retn + + +ComInStat: ; similar to ComNdRead but returns no char, only flags + call GetComStat + mov al,[bx] + or al,al + jnz ComInAvail + call ComRdStatus + test ah,1 ; char waiting + jz ComNdRtn +; test al,20h ; DSR (why do we test this?) +; jz ComNdRtn +ComInAvail: jmp _IOExit ; return "ready" + + +ComNdRead: + call GetComStat + mov al,[bx] + or al,al + jnz ComNdRd1 + call ComRdStatus + test ah,1 ; char waiting + jz ComNdRtn +; test al,20h ; DSR (why do we test this?) +; jz ComNdRtn + call BiosRdCom + call GetComStat + mov [bx],al +ComNdRd1: + jmp CommonNdRdExit ; return that char +ComNdRtn: + jmp _IODone ; return "busy" + + +ComOutStat: + call ComRdStatus + test al,20h + jz ComNdRtn + test ah,20h + jz ComNdRtn + jmp _IOExit ; return "ready" + + +ComRdStatus: + mov ah,3 + call ComIOCall + retn + + +ComIOCall: + call GetUnitNum + int 14h ; RS-232 get char al, ah=return status + retn + + +ComInpFlush: + call GetComStat + mov byte [bx],0 + jmp _IOExit + + +ComWrite: + jcxz ComRd3 +ComWr1: + mov al,[es:di] + inc di + mov ah,1 + call ComIOCall + test ah,80h + jz ComWr2 + mov al,0Ah + jmp _IOErrCnt +ComWr2: + loop ComWr1 + jmp _IOExit + + +GetComStat: + call GetUnitNum + mov bx,dx + add bx,ComStatArray + retn + +segment _DATA + +ComStatArray db 0, 0, 0, 0 + +; Revision 1.2 1999/08/10 17:57:13 jprice +; ror4 2011-02 patch +; +; Revision 1.1.1.1 1999/03/29 15:41:31 jprice +; New version without IPL.SYS +; +; Revision 1.1 1999/02/08 05:55:57 jprice +; Added Pat's 1937 kernel patches +; +; EndLog +; diff --git a/kernel/strings.c b/kernel/strings.c new file mode 100644 index 0000000..e13a1f2 --- /dev/null +++ b/kernel/strings.c @@ -0,0 +1,138 @@ +/****************************************************************/ +/* */ +/* strings.c */ +/* */ +/* Global String Handling Functions */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" + +#ifdef VERSION_STRINGS +static BYTE *stringsRcsId = + "$Id: strings.c 653 2003-08-09 09:35:18Z bartoldeman $"; +#endif + +#ifndef I86 +size_t strlen(REG CONST BYTE * s) +{ + REG size_t cnt = 0; + + while (*s++ != 0) + ++cnt; + return cnt; +} + +size_t fstrlen(REG CONST BYTE FAR * s) +{ + REG size_t cnt = 0; + + while (*s++ != 0) + ++cnt; + return cnt; +} + +VOID _fstrcpy(REG BYTE FAR * d, REG BYTE FAR * s) +{ + while (*s != 0) + *d++ = *s++; + *d = 0; +} + +int strcmp(REG CONST BYTE * d, REG CONST BYTE * s) +{ + while (*s != '\0' && *d != '\0') + { + if (*d == *s) + ++s, ++d; + else + return *d - *s; + } + return *d - *s; +} + +COUNT fstrcmp(REG BYTE FAR * d, REG BYTE FAR * s) +{ + while (*s != '\0' && *d != '\0') + { + if (*d == *s) + ++s, ++d; + else + return *d - *s; + } + return *d - *s; +} + +int strncmp(register const char *d, register const char *s, size_t l) +{ + size_t index = 1; + while (*s != '\0' && *d != '\0' && index++ <= l) + { + if (*d == *s) + ++s, ++d; + else + return *d - *s; + } + return *d - *s; +} + +COUNT fstrncmp(REG BYTE FAR * d, REG BYTE FAR * s, COUNT l) +{ + COUNT index = 1; + while (*s != '\0' && *d != '\0' && index++ <= l) + { + if (*d == *s) + ++s, ++d; + else + return *d - *s; + } + return *d - *s; +} + +char *strchr(const char * s, int c) +{ + REG CONST BYTE *p; + p = s - 1; + do + { + if (*++p == (char)c) + return (char *)p; + } + while (*p); + return 0; +} + +void *memchr(const void * s, int c) +{ + REG unsigned char *p; + p = (unsigned char *)s - 1; + do + { + if (*++p == (unsigned char)c) + return (void *)p; + } + while (*p); + return 0; +} +#endif + diff --git a/kernel/sysclk.c b/kernel/sysclk.c new file mode 100644 index 0000000..67df7b2 --- /dev/null +++ b/kernel/sysclk.c @@ -0,0 +1,173 @@ +/****************************************************************/ +/* */ +/* sysclk.c */ +/* */ +/* System Clock Driver */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static char *RcsId = + "$Id: sysclk.c 681 2003-09-09 17:32:20Z bartoldeman $"; +#endif + +/* */ +/* WARNING - THIS DRIVER IS NON-PORTABLE!!!! */ +/* */ +UWORD ASM DaysSinceEpoch = 0; +typedef UDWORD ticks_t; + +STATIC int ByteToBcd(int x) +{ + return ((x / 10) << 4) | (x % 10); +} +/* +STATIC int BcdToByte(int x) +{ + return ((x >> 4) & 0xf) * 10 + (x & 0xf); +} +*/ +STATIC void DayToBcd(BYTE * x, unsigned mon, unsigned day, unsigned yr) +{ + x[1] = ByteToBcd(mon); + x[0] = ByteToBcd(day); + x[3] = ByteToBcd(yr / 100); + x[2] = ByteToBcd(yr % 100); +} + +WORD ASMCFUNC FAR clk_driver(rqptr rp) +{ + BYTE bcd_days[4], bcd_minutes, bcd_hours, bcd_seconds; + + switch (rp->r_command) + { + case C_INIT: + + /* done in initclk.c */ + /* rp->r_endaddr = device_end(); not needed - bart */ + rp->r_nunits = 0; + return S_DONE; + + case C_INPUT: + { + struct ClockRecord clk; + int tmp; + ticks_t ticks; + + if (sizeof(struct ClockRecord) != rp->r_count) + return failure(E_LENGTH); + + /* The scaling factor is now + 6553600/1193180 = 327680/59659 = 65536*5/59659 */ + + ticks = 5 * ReadPCClock(); + ticks = ((ticks / 59659u) << 16) + ((ticks % 59659u) << 16) / 59659u; + + tmp = (int)(ticks / 6000); + clk.clkHours = tmp / 60; + clk.clkMinutes = tmp % 60; + + tmp = (int)(ticks % 6000); + clk.clkSeconds = tmp / 100; + clk.clkHundredths = tmp % 100; + + clk.clkDays = DaysSinceEpoch; + + fmemcpy(rp->r_trans, &clk, sizeof(struct ClockRecord)); + } + return S_DONE; + + case C_OUTPUT: + { + const unsigned short *pdays; + unsigned Day, Month, Year; + struct ClockRecord clk; + ticks_t hs, Ticks; + + if (sizeof(struct ClockRecord) != rp->r_count) + return failure(E_LENGTH); + + fmemcpy(&clk, rp->r_trans, sizeof(struct ClockRecord)); + + /* Set PC Clock first */ + DaysSinceEpoch = clk.clkDays; + hs = 6000 * (ticks_t)(60 * clk.clkHours + clk.clkMinutes) + + (ticks_t)(100 * clk.clkSeconds + clk.clkHundredths); + + /* The scaling factor is now + 1193180/6553600 = 59659/327680 = 59659/65536/5 */ + + Ticks = ((hs >> 16) * 59659u + (((hs & 0xffff) * 59659u) >> 16)) / 5; + + WritePCClock(Ticks); + + /* Now set AT clock */ + /* Fix year by looping through each year, subtracting */ + /* the appropriate number of days for that year. */ + for (Year = 1980, Day = clk.clkDays;;) + { + pdays = is_leap_year_monthdays(Year); + if (Day >= pdays[12]) + { + ++Year; + Day -= pdays[12]; + } + else + break; + } + + /* Day contains the days left and count the number of */ + /* days for that year. Use this to index the table. */ + for (Month = 1; Month < 13; ++Month) + { + if (pdays[Month] > Day) + { + Day = Day - pdays[Month - 1] + 1; + break; + } + } + + DayToBcd(bcd_days, Month, Day, Year); + bcd_minutes = ByteToBcd(clk.clkMinutes); + bcd_hours = ByteToBcd(clk.clkHours); + bcd_seconds = ByteToBcd(clk.clkSeconds); + WriteATClock(bcd_days, bcd_hours, bcd_minutes, bcd_seconds); + } + return S_DONE; + + case C_OFLUSH: + case C_IFLUSH: + return S_DONE; + + case C_OUB: + case C_NDREAD: + case C_OSTAT: + case C_ISTAT: + default: + return failure(E_FAILURE); /* general failure */ + } +} + diff --git a/kernel/syspack.c b/kernel/syspack.c new file mode 100644 index 0000000..9676a1c --- /dev/null +++ b/kernel/syspack.c @@ -0,0 +1,123 @@ +/****************************************************************/ +/* */ +/* syspack.c */ +/* */ +/* System Disk Byte Order Packing Functions */ +/* */ +/* 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. */ +/* */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *syspackRcsId = + "$Id: syspack.c 485 2002-12-09 00:17:15Z bartoldeman $"; +#endif + +#ifdef NONNATIVE +UDWORD getlong(REG VOID * vp) +{ + return (((UBYTE *) vp)[0] & 0xff) + + ((((UBYTE *) vp)[1] & 0xff) << 8) + + ((((UBYTE *) vp)[2] & 0xff) << 16) + + ((((UBYTE *) vp)[3] & 0xff) << 24); +} + +UWORD getword(REG VOID * vp) +{ + return (((UBYTE *) vp)[0] & 0xff) + ((((UBYTE *) vp)[1] & 0xff) << 8); +} + +UBYTE getbyte(VOID * vp) +{ + return *((BYTE *) vp); +} + +UWORD fgetword(REG VOID FAR * vp) +{ + return (((UBYTE FAR *) vp)[0] & 0xff) + ((((UBYTE FAR *) vp)[1] & 0xff) << 8); +} + +UDWORD fgetlong(REG VOID FAR * vp) +{ + return (((UBYTE *) vp)[0] & 0xff) + + ((((UBYTE *) vp)[1] & 0xff) << 8) + + ((((UBYTE *) vp)[2] & 0xff) << 16) + + ((((UBYTE *) vp)[3] & 0xff) << 24); +} + +UBYTE fgetbyte(VOID FAR * vp) +{ + return *((UBYTE FAR *) vp); +} + +VOID fputlong(VOID FAR * vp, UDWORD l) +{ + REG UBYTE FAR *bp = (UBYTE FAR *) vp; + + bp[0] = l & 0xff; + bp[1] = (l >> 8) & 0xff; + bp[2] = (l >> 16) & 0xff; + bp[3] = (l >> 24) & 0xff; +} + +VOID fputword(VOID FAR * vp, UWORD w) +{ + REG UBYTE FAR *bp = (UBYTE FAR *) vp; + + bp[0] = w & 0xff; + bp[1] = (w >> 8) & 0xff; +} + +VOID fputbyte(VOID FAR * vp, UBYTE b) +{ + *(UBYTE FAR *) vp = b; +} + +VOID getdirent(UBYTE FAR * vp, struct dirent FAR * dp) +{ + fmemcpy(dp->dir_name, &vp[DIR_NAME], FNAME_SIZE + FEXT_SIZE); + dp->dir_attrib = fgetbyte(&vp[DIR_ATTRIB]); + dp->dir_time = fgetword(&vp[DIR_TIME]); + dp->dir_date = fgetword(&vp[DIR_DATE]); + dp->dir_start = fgetword(&vp[DIR_START]); + dp->dir_size = fgetlong(&vp[DIR_SIZE]); +} + +VOID putdirent(struct dirent FAR * dp, UBYTE FAR * vp) +{ + REG COUNT i; + REG BYTE FAR *p; + + fmemcpy(&vp[DIR_NAME], dp->dir_name, FNAME_SIZE + FEXT_SIZE); + fputbyte(&vp[DIR_ATTRIB], dp->dir_attrib); + fputword(&vp[DIR_TIME], dp->dir_time); + fputword(&vp[DIR_DATE], dp->dir_date); + fputword(&vp[DIR_START], dp->dir_start); + fputlong(&vp[DIR_SIZE], dp->dir_size); + for (i = 0, p = (UBYTE FAR *) & vp[DIR_RESERVED]; i < 10; i++) + *p++ = NULL; +} +#endif + diff --git a/kernel/systime.c b/kernel/systime.c new file mode 100644 index 0000000..a8b98b9 --- /dev/null +++ b/kernel/systime.c @@ -0,0 +1,178 @@ +/****************************************************************/ +/* */ +/* systime.c */ +/* */ +/* DOS/C Date/Time Functions */ +/* */ +/* Copyright (c) 1998 */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "time.h" +#include "date.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: systime.c 683 2003-09-09 17:43:43Z bartoldeman $"; +#endif + +const UWORD days[2][13] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} +}; + +extern request ASM ClkReqHdr; + +/* + return a pointer to an array with the days for that year +*/ + +const UWORD *is_leap_year_monthdays(UWORD y) +{ + /* this is correct in a strict mathematical sense + return ((y) & 3 ? days[0] : (y) % 100 ? days[1] : (y) % 400 ? days[0] : days[1]); */ + + /* this will work until 2200 - long enough for me - and saves 0x1f bytes */ + + if ((y & 3) || y == 2100) + return days[0]; + + return days[1]; +} + +UWORD DaysFromYearMonthDay(UWORD Year, UWORD Month, UWORD DayOfMonth) +{ + if (Year < 1980) + return 0; + + return DayOfMonth - 1 + + is_leap_year_monthdays(Year)[Month - 1] + + ((Year - 1980) * 365) + ((Year - 1980 + 3) / 4); + +} + +/* common - call the clock driver */ +void ExecuteClockDriverRequest(BYTE command) +{ + BinaryCharIO(&clock, sizeof(struct ClockRecord), &ClkRecord, command); +} + +void DosGetTime(struct dostime *dt) +{ + ExecuteClockDriverRequest(C_INPUT); + + if (ClkReqHdr.r_status & S_ERROR) + return; + + dt->hour = ClkRecord.clkHours; + dt->minute = ClkRecord.clkMinutes; + dt->second = ClkRecord.clkSeconds; + dt->hundredth = ClkRecord.clkHundredths; +} + +int DosSetTime(const struct dostime *dt) +{ + if (dt->hour > 23 || dt->minute > 59 || + dt->second > 59 || dt->hundredth > 99) + return DE_INVLDDATA; + + /* for ClkRecord.clkDays */ + ExecuteClockDriverRequest(C_INPUT); + + ClkRecord.clkHours = dt->hour; + ClkRecord.clkMinutes = dt->minute; + ClkRecord.clkSeconds = dt->second; + ClkRecord.clkHundredths = dt->hundredth; + + ExecuteClockDriverRequest(C_OUTPUT); + + if (ClkReqHdr.r_status & S_ERROR) + return char_error(&ClkReqHdr, (struct dhdr FAR *)clock); + return SUCCESS; +} + +unsigned char DosGetDate(struct dosdate *dd) +{ + UWORD c; + const UWORD *pdays; + UWORD Year, Month; + + ExecuteClockDriverRequest(C_INPUT); + + if (ClkReqHdr.r_status & S_ERROR) + return 0; + + for (Year = 1980, c = ClkRecord.clkDays;;) + { + pdays = is_leap_year_monthdays(Year); + if (c >= pdays[12]) + { + ++Year; + c -= pdays[12]; + } + else + break; + } + + /* c contains the days left and count the number of days for */ + /* that year. Use this to index the table. */ + Month = 1; + while (c >= pdays[Month]) + { + ++Month; + } + + dd->year = Year; + dd->month = Month; + dd->monthday = c - pdays[Month - 1] + 1; + + /* Day of week is simple. Take mod 7, add 2 (for Tuesday */ + /* 1-1-80) and take mod again */ + + return (ClkRecord.clkDays + 2) % 7; +} + +int DosSetDate(const struct dosdate *dd) +{ + UWORD Year = dd->year; + UWORD Month = dd->month; + UWORD DayOfMonth = dd->monthday; + const UWORD *pdays = is_leap_year_monthdays(Year); + + if (Year < 1980 || Year > 2099 + || Month < 1 || Month > 12 + || DayOfMonth < 1 + || DayOfMonth > pdays[Month] - pdays[Month - 1]) + return DE_INVLDDATA; + + ExecuteClockDriverRequest(C_INPUT); + + ClkRecord.clkDays = DaysFromYearMonthDay(Year, Month, DayOfMonth); + + ExecuteClockDriverRequest(C_OUTPUT); + + if (ClkReqHdr.r_status & S_ERROR) + return char_error(&ClkReqHdr, (struct dhdr FAR *)clock); + return SUCCESS; +} + diff --git a/kernel/task.c b/kernel/task.c new file mode 100644 index 0000000..2cd3fd2 --- /dev/null +++ b/kernel/task.c @@ -0,0 +1,842 @@ +/****************************************************************/ +/* */ +/* task.c */ +/* */ +/* Task Manager for DOS Processes */ +/* */ +/* 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. */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id: task.c 1563 2011-04-08 16:04:24Z bartoldeman $"; +#endif + +#define toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) + ('A' - 'a') : (c)) + +#define LOADNGO 0 +#define LOAD 1 +#define OVERLAY 3 + +#define LOAD_HIGH 0x80 + +/* static exe_header ExeHeader; + to save some bytes, both static and on stack, + we recycle SecPathBuffer TE */ + +#define ExeHeader (*(exe_header *)(SecPathName + 0)) +#define TempExeBlock (*(exec_blk *)(SecPathName + sizeof(exe_header))) +#define Shell (SecPathName + sizeof(exe_header) + sizeof(exec_blk)) + +#ifdef __TURBOC__ /* this is a Borlandism and doesn't work elsewhere */ + #if sizeof(SecPathName) < sizeof(exe_header) + sizeof(exec_blk) + NAMEMAX + #error No room in SecPathName to be recycled! + #endif +#endif + +#define CHUNK 32256 +#define MAXENV 32768u +#define ENV_KEEPFREE 83 /* keep unallocated by environment variables */ + /* The '65' added to nEnvSize does not cover the additional stuff: + + 2 bytes: number of strings + + 80 bytes: maximum absolute filename + + 1 byte: '\0' + -- 1999/04/21 ska */ + +intvec getvec(unsigned char intno) +{ + intvec iv; + disable(); + iv = *(intvec FAR *)MK_FP(0,4 * (intno)); + enable(); + return iv; +} + +void setvec(unsigned char intno, intvec vector) +{ + disable(); + *(intvec FAR *)MK_FP(0,4 * intno) = vector; + enable(); +} + +ULONG SftGetFsize(int sft_idx) +{ + sft FAR *s = idx_to_sft(sft_idx); + + /* Get the SFT block that contains the SFT */ + if (FP_OFF(s) == (size_t) -1) + return DE_INVLDHNDL; + + return s->sft_size; +} + +STATIC COUNT ChildEnv(exec_blk * exp, UWORD * pChildEnvSeg, char far * pathname) +{ + BYTE FAR *pSrc; + BYTE FAR *pDest; + UWORD nEnvSize; + COUNT RetCode; +/* UWORD MaxEnvSize; not used -- 1999/04/21 ska */ + psp FAR *ppsp = MK_FP(cu_psp, 0); + + /* create a new environment for the process */ + /* copy parent's environment if exec.env_seg == 0 */ + + pSrc = exp->exec.env_seg ? + MK_FP(exp->exec.env_seg, 0) : MK_FP(ppsp->ps_environ, 0); + +#if 0 + /* Every process requires an environment because of argv[0] + -- 1999/04/21 ska */ + */if (!pSrc) /* no environment to copy */ + { + *pChildEnvSeg = 0; + return SUCCESS; + } +#endif + + nEnvSize = 1; + /* This loop had not counted the very last '\0' + -- 1999/04/21 ska */ + if (pSrc) + { /* if no environment is available, one byte is required */ + + for (nEnvSize = 0;; nEnvSize++) + { + /* Test env size and abort if greater than max */ + if (nEnvSize >= MAXENV - ENV_KEEPFREE) + return DE_INVLDENV; + + if (*(UWORD FAR *) (pSrc + nEnvSize) == 0) + break; + } + nEnvSize += 2; /* account for trailing \0\0 */ + } + + /* allocate enough space for env + path */ + if ((RetCode = DosMemAlloc((nEnvSize + ENV_KEEPFREE + 15)/16, + mem_access_mode, pChildEnvSeg, + NULL /*(UWORD FAR *) MaxEnvSize ska */ )) < 0) + return RetCode; + pDest = MK_FP(*pChildEnvSeg + 1, 0); + + /* fill the new env and inform the process of its */ + /* location throught the psp */ + + /* copy the environment */ + if (pSrc) + { + fmemcpy(pDest, pSrc, nEnvSize); + pDest += nEnvSize; + } + else + *pDest++ = '\0'; /* create an empty environment */ + + /* initialize 'extra strings' count */ + *((UWORD FAR *) pDest) = 1; + pDest += sizeof(UWORD) / sizeof(BYTE); + + /* copy complete pathname */ + if ((RetCode = truename(pathname, PriPathName, CDS_MODE_SKIP_PHYSICAL)) < SUCCESS) + { + return RetCode; + } + fstrcpy(pDest, PriPathName); + + /* Theoretically one could either: + + resize the already allocated block to best-fit behind the pathname, or + + generate the filename into a temporary buffer to allocate only the + minimum required environment -- 1999/04/21 ska */ + + return SUCCESS; +} + +/* The following code is 8086 dependant */ +void new_psp(seg para, seg cur_psp) +{ + psp FAR *p = MK_FP(para, 0); + + fmemcpy(p, MK_FP(cur_psp, 0), sizeof(psp)); + + /* terminate address */ + p->ps_isv22 = getvec(0x22); + /* break address */ + p->ps_isv23 = getvec(0x23); + /* critical error address */ + p->ps_isv24 = getvec(0x24); + /* parent psp segment set to 0 (see RBIL int21/ah=26) */ + p->ps_parent = 0; +} + +void child_psp(seg para, seg cur_psp, int psize) +{ + psp FAR *p = MK_FP(para, 0); + psp FAR *q = MK_FP(cur_psp, 0); + int i; + + new_psp(para, cur_psp); + + /* Now for parent-child relationships */ + /* parent psp segment */ + p->ps_parent = cu_psp; + /* previous psp pointer */ + p->ps_prevpsp = q; + + /* Environment and memory useage parameters */ + /* memory size in paragraphs */ + p->ps_size = psize; + + /* File System parameters */ + /* maximum open files */ + p->ps_maxfiles = 20; + fmemset(p->ps_files, 0xff, 20); + + /* open file table pointer */ + p->ps_filetab = p->ps_files; + + /* clone the file table -- 0xff is unused */ + for (i = 0; i < 20; i++) + if (CloneHandle(i) >= 0) + p->ps_files[i] = q->ps_filetab[i]; + + /* first command line argument */ + p->ps_fcb1.fcb_drive = 0; + fmemset(p->ps_fcb1.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE); + /* second command line argument */ + p->ps_fcb2.fcb_drive = 0; + fmemset(p->ps_fcb2.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE); + + /* local command line */ + p->ps_cmd.ctCount = 0; + p->ps_cmd.ctBuffer[0] = 0xd; /* command tail */ +} + +STATIC UWORD patchPSP(UWORD pspseg, UWORD envseg, exec_blk FAR * exb, + BYTE FAR * fnam) +{ + psp FAR *psp; + mcb FAR *pspmcb; + int i; + BYTE FAR *np; + + pspmcb = MK_FP(pspseg, 0); + ++pspseg; + psp = MK_FP(pspseg, 0); + + /* complete the psp by adding the command line and FCBs */ + fmemcpy(&psp->ps_cmd, exb->exec.cmd_line, sizeof(CommandTail)); + if (FP_OFF(exb->exec.fcb_1) != 0xffff) + { + fmemcpy(&psp->ps_fcb1, exb->exec.fcb_1, 16); + fmemcpy(&psp->ps_fcb2, exb->exec.fcb_2, 16); + } + + /* identify the mcb as this functions' */ + pspmcb->m_psp = pspseg; + /* Patch in environment segment, if present, also adjust its MCB */ + if (envseg) + { + ((mcb FAR *) MK_FP(envseg, 0))->m_psp = pspseg; + envseg++; + } + psp->ps_environ = envseg; + + /* use the file name less extension - left adjusted and */ + np = fnam; + for (;;) + { + switch (*fnam++) + { + case '\0': + goto set_name; + case ':': + case '/': + case '\\': + np = fnam; + } + } +set_name: + for (i = 0; i < 8 && np[i] != '.' && np[i] != '\0'; i++) + { + pspmcb->m_name[i] = toupper(np[i]); + } + if (i < 8) + pspmcb->m_name[i] = '\0'; + + /* return value: AX value to be passed based on FCB values */ + return (get_cds1(psp->ps_fcb1.fcb_drive) ? 0 : 0xff) | + (get_cds1(psp->ps_fcb2.fcb_drive) ? 0 : 0xff00); +} + +STATIC int load_transfer(UWORD ds, exec_blk *exp, UWORD fcbcode, COUNT mode) +{ + psp FAR *p = MK_FP(ds, 0); + psp FAR *q = MK_FP(cu_psp, 0); + + /* Transfer control to the executable */ + p->ps_parent = cu_psp; + p->ps_prevpsp = q; + q->ps_stack = (BYTE FAR *)user_r; + user_r->FLAGS &= ~FLG_CARRY; + + cu_psp = ds; + /* process dta */ + dta = &p->ps_cmd; + + if (mode == LOADNGO) + { + iregs FAR *irp; + + /* build the user area on the stack */ + irp = (iregs FAR *)(exp->exec.stack - sizeof(iregs)); + + /* start allocating REGs (as in MS-DOS - some demos expect them so --LG) */ + /* see http://www.beroset.com/asm/showregs.asm */ + irp->DX = irp->ES = irp->DS = ds; + irp->CS = FP_SEG(exp->exec.start_addr); + irp->SI = irp->IP = FP_OFF(exp->exec.start_addr); + irp->DI = FP_OFF(exp->exec.stack); + irp->BP = 0x91e; /* this is more or less random but some programs + expect 0x9 in the high byte of BP!! */ + irp->AX = irp->BX = fcbcode; + irp->CX = 0xFF; + irp->FLAGS = 0x200; + + if (InDOS) + --InDOS; + exec_user(irp, 1); + + /* We should never be here + fatal("KERNEL RETURNED!!!"); */ + } + /* mode == LOAD */ + exp->exec.stack -= 2; + *((UWORD FAR *)(exp->exec.stack)) = fcbcode; + return SUCCESS; +} + +/* Now find out how many paragraphs are available + considering a threshold, trying HIGH then LOW */ +STATIC int ExecMemLargest(UWORD *asize, UWORD threshold) +{ + int rc; + if (mem_access_mode & 0x80) + { + mem_access_mode &= ~0x80; + mem_access_mode |= 0x40; + rc = DosMemLargest(asize); + mem_access_mode &= ~0x40; + /* less memory than the .COM/.EXE file has: + try low memory first */ + if (rc != SUCCESS || *asize < threshold) + rc = DosMemLargest(asize); + mem_access_mode |= 0x80; + } + else + rc = DosMemLargest(asize); + return (*asize < threshold ? DE_NOMEM : rc); +} + +STATIC int ExecMemAlloc(UWORD size, seg *para, UWORD *asize) +{ + /* We can still get an error on first fit if the above */ + /* returned size was a best fit case */ + /* ModeLoadHigh = 80 = try high, then low */ + int rc = DosMemAlloc(size, mem_access_mode, para, asize); + + if (rc != SUCCESS) + { + if (rc == DE_NOMEM) + { + rc = DosMemAlloc(0, LARGEST, para, asize); + if ((mem_access_mode & 0x80) && (rc != SUCCESS)) + { + mem_access_mode &= ~0x80; + rc = DosMemAlloc(0, LARGEST, para, asize); + mem_access_mode |= 0x80; + } + } + } + else + { + /* with no error, we got exactly what we asked for */ + *asize = size; + } + + /* This should never happen, but ... */ + if (rc == SUCCESS && *asize < size) + { + DosMemFree(*para); + return DE_NOMEM; + } + return rc; +} + +COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) +{ + UWORD mem; + UWORD env, asize = 0; + + { + UWORD com_size; + { + ULONG com_size_long = SftGetFsize(fd); + /* maximally 64k - 256 bytes stack - + 256 bytes psp */ + com_size = ((UWORD)min(com_size_long, 0xfe00u) >> 4) + 0x10; + } + + if ((mode & 0x7f) != OVERLAY) + { + COUNT rc; + UBYTE UMBstate = uppermem_link; + UBYTE orig_mem_access = mem_access_mode; + + if (mode & 0x80) + { + mem_access_mode |= 0x80; + DosUmbLink(1); /* link in UMBs */ + } + + rc = ChildEnv(exp, &env, namep); + + /* COMFILES will always be loaded in largest area. is that true TE */ + /* yes, see RBIL, int21/ah=48 -- Bart */ + + if (rc == SUCCESS) + rc = ExecMemLargest(&asize, com_size); + + if (rc == SUCCESS) + /* Allocate our memory and pass back any errors */ + rc = ExecMemAlloc(asize, &mem, &asize); + + if (rc != SUCCESS) + DosMemFree(env); + + if (mode & 0x80) + { + DosUmbLink(UMBstate); /* restore link state */ + mem_access_mode = orig_mem_access; + mode &= 0x7f; + } + + if (rc != SUCCESS) + return rc; + + ++mem; + } + else + mem = exp->load.load_seg; + } + +#ifdef DEBUG + printf("DosComLoader. Loading '%S' at %04x\n", namep, mem); +#endif + /* Now load the executable */ + { + BYTE FAR *sp; + + if (mode == OVERLAY) /* memory already allocated */ + sp = MK_FP(mem, 0); + else /* test the filesize against the allocated memory */ + sp = MK_FP(mem, sizeof(psp)); + + /* MS DOS always only loads the very first 64KB - sizeof(psp) bytes. + -- 1999/04/21 ska */ + + /* rewind to start */ + SftSeek(fd, 0, 0); + /* read everything, but at most 64K - sizeof(PSP) */ + DosRWSft(fd, 0xff00, sp, XFR_READ); + DosCloseSft(fd, FALSE); + } + + if (mode == OVERLAY) + return SUCCESS; + + { + UWORD fcbcode; + psp FAR *p; + + /* point to the PSP so we can build it */ + setvec(0x22, (intvec)MK_FP(user_r->CS, user_r->IP)); + child_psp(mem, cu_psp, mem + asize); + + fcbcode = patchPSP(mem - 1, env, exp, namep); + /* set asize to end of segment */ + if (asize > 0x1000) + asize = 0x1000; + if (asize < 0x11) + return DE_NOMEM; + asize -= 0x11; + /* CP/M compatibility--size of first segment for .COM files + while preserving the far call to 0:00c0 + + copy in HMA at ffff:00d0 */ + p = MK_FP(mem, 0); + p->ps_reentry = MK_FP(0xc - asize, asize << 4); + asize <<= 4; + asize += 0x10e; + exp->exec.stack = MK_FP(mem, asize); + exp->exec.start_addr = MK_FP(mem, 0x100); + *((UWORD FAR *) MK_FP(mem, asize)) = (UWORD) 0; + load_transfer(mem, exp, fcbcode, mode); + } + return SUCCESS; +} + +VOID return_user(void) +{ + psp FAR *p, FAR * q; + REG COUNT i; + iregs FAR *irp; +/* long j;*/ + + /* restore parent */ + p = MK_FP(cu_psp, 0); + + /* When process returns - restore the isv */ + setvec(0x22, p->ps_isv22); + setvec(0x23, p->ps_isv23); + setvec(0x24, p->ps_isv24); + + /* And free all process memory if not a TSR return */ + network_redirector(REM_PROCESS_END); + /* might be a good idea to do that after closing + but doesn't help NET either TE */ + + if (!tsr && p->ps_parent != cu_psp) + { + network_redirector(REM_CLOSEALL); + for (i = 0; i < p->ps_maxfiles; i++) + { + DosClose(i); + } + FcbCloseAll(); + FreeProcessMem(cu_psp); + } + + cu_psp = p->ps_parent; + q = MK_FP(cu_psp, 0); + + irp = (iregs FAR *) q->ps_stack; + + irp->CS = FP_SEG(p->ps_isv22); + irp->IP = FP_OFF(p->ps_isv22); + irp->FLAGS = 0x200; /* clear trace and carry flags, set interrupt flag */ + + if (InDOS) + --InDOS; + exec_user((iregs FAR *) q->ps_stack, 0); +} + +COUNT DosExeLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) +{ + UWORD mem, env, start_seg, asize = 0; + UWORD exe_size; + { + UWORD image_size; + + /* compute image size by removing the offset from the */ + /* number pages scaled to bytes plus the remainder and */ + /* the psp */ +#if 0 + if (ExeHeader.exPages >= 2048) + return DE_INVLDDATA; /* we're not able to get >=1MB in dos memory */ +#else + /* TurboC++ 3 BOSS NE stub: image > 1 MB but load only "X mod 1 MB" */ + /* ExeHeader.exPages &= 0x7ff; */ /* just let << 5 do the clipping! */ +#endif + /* First scale the size and remove the offset */ + image_size = (ExeHeader.exPages << 5) - ExeHeader.exHeaderSize; + + /* We should not attempt to allocate + memory if we are overlaying the current process, because the new + process will simply re-use the block we already have allocated. + Jun 11, 2000 - rbc */ + + if ((mode & 0x7f) != OVERLAY) + { + UBYTE UMBstate = uppermem_link; + UBYTE orig_mem_access = mem_access_mode; + COUNT rc; + + /* and finally add in the psp size */ + image_size += sizeof(psp) / 16; /* TE 03/20/01 */ + exe_size = image_size + ExeHeader.exMinAlloc; + + /* Clone the environement and create a memory arena */ + if (mode & 0x80) + { + DosUmbLink(1); /* link in UMBs */ + mem_access_mode |= 0x80; + } + + rc = ChildEnv(exp, &env, namep); + + if (rc == SUCCESS) + /* Now find out how many paragraphs are available */ + rc = ExecMemLargest(&asize, exe_size); + + exe_size = image_size + ExeHeader.exMaxAlloc; + /* second test is for overflow (avoiding longs) -- + exMaxAlloc can be high */ + if (exe_size > asize || exe_size < image_size) + exe_size = asize; + + /* TE if ExeHeader.exMinAlloc == ExeHeader.exMaxAlloc == 0, + DOS will allocate the largest possible memory area + and load the image as high as possible into it. + discovered (and after that found in RBIL), when testing NET */ + + if ((ExeHeader.exMinAlloc | ExeHeader.exMaxAlloc) == 0) + exe_size = asize; + + /* Allocate our memory and pass back any errors */ + if (rc == SUCCESS) + rc = ExecMemAlloc(exe_size, &mem, &asize); + + if (rc != SUCCESS) + DosMemFree(env); + + if (mode & 0x80) + { + mem_access_mode = orig_mem_access; /* restore old situation */ + DosUmbLink(UMBstate); /* restore link state */ + } + if (rc != SUCCESS) + return rc; + + mode &= 0x7f; /* forget about high loading from now on */ + +#ifdef DEBUG + printf("DosExeLoader. Loading '%S' at %04x\n", namep, mem); +#endif + + /* memory found large enough - continue processing */ + ++mem; + +/* /// Added open curly brace and "else" clause. We should not attempt + to allocate memory if we are overlaying the current process, because + the new process will simply re-use the block we already have allocated. + This was causing execl() to fail in applications which use it to + overlay (replace) the current exe file with a new one. + Jun 11, 2000 - rbc */ + } + else /* !!OVERLAY */ + { + mem = exp->load.load_seg; + } + + /* Now load the executable */ + /* offset to start of image */ + if (SftSeek(fd, ExeHeader.exHeaderSize * 16UL, 0) != SUCCESS) + { + if (mode != OVERLAY) + { + DosMemFree(--mem); + DosMemFree(env); + } + return DE_INVLDDATA; + } + + /* create the start seg for later computations */ + start_seg = mem; + exe_size = image_size; + if (mode != OVERLAY) + { + exe_size -= sizeof(psp) / 16; + start_seg += sizeof(psp) / 16; + if (exe_size > 0 && (ExeHeader.exMinAlloc | ExeHeader.exMaxAlloc) == 0) + { + mcb FAR *mp = MK_FP(mem - 1, 0); + + /* then the image should be placed as high as possible */ + start_seg += mp->m_size - image_size; + } + } + } + + /* read in the image in 32256 chunks */ + { + int nBytesRead, toRead = CHUNK; + seg sp = start_seg; + + while (1) + { + if (exe_size < CHUNK/16) + toRead = exe_size*16; + nBytesRead = (int)DosRWSft(fd, toRead, MK_FP(sp, 0), XFR_READ); + if (nBytesRead < toRead || exe_size <= CHUNK/16) + break; + sp += CHUNK/16; + exe_size -= CHUNK/16; + } + } + + { /* relocate the image for new segment */ + COUNT i; + UWORD reloc[2]; + seg FAR *spot; + + SftSeek(fd, ExeHeader.exRelocTable, 0); + for (i = 0; i < ExeHeader.exRelocItems; i++) + { + if (DosRWSft + (fd, sizeof(reloc), (VOID FAR *) & reloc[0], XFR_READ) != sizeof(reloc)) + { + if (mode != OVERLAY) + { + DosMemFree(--mem); + DosMemFree(env); + } + return DE_INVLDDATA; + } + if (mode == OVERLAY) + { + spot = MK_FP(reloc[1] + mem, reloc[0]); + *spot += exp->load.reloc; + } + else + { + /* spot = MK_FP(reloc[1] + mem + 0x10, reloc[0]); */ + spot = MK_FP(reloc[1] + start_seg, reloc[0]); + *spot += start_seg; + } + } + } + + /* and finally close the file */ + DosCloseSft(fd, FALSE); + + /* exit here for overlay */ + if (mode == OVERLAY) + return SUCCESS; + + { + UWORD fcbcode; + + /* point to the PSP so we can build it */ + setvec(0x22, (intvec)MK_FP(user_r->CS, user_r->IP)); + child_psp(mem, cu_psp, mem + asize); + + fcbcode = patchPSP(mem - 1, env, exp, namep); + exp->exec.stack = + MK_FP(ExeHeader.exInitSS + start_seg, ExeHeader.exInitSP); + exp->exec.start_addr = + MK_FP(ExeHeader.exInitCS + start_seg, ExeHeader.exInitIP); + + /* Transfer control to the executable */ + load_transfer(mem, exp, fcbcode, mode); + } + return SUCCESS; +} + +/* mode = LOAD or EXECUTE + ep = EXE block + lp = filename to load (string) + + leb = local copy of exe block + */ +COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp) +{ + COUNT rc; + COUNT fd; + + if ((mode & 0x7f) > 3 || (mode & 0x7f) == 2) + return DE_INVLDFMT; + + fmemcpy(&TempExeBlock, ep, sizeof(exec_blk)); + /* If file not found - free ram and return error */ + + if (IsDevice(lp) || /* we don't want to execute C:>NUL */ + (fd = (short)DosOpenSft(lp, O_LEGACY | O_OPEN | O_RDONLY, 0)) < 0) + { + return DE_FILENOTFND; + } + + rc = (int)DosRWSft(fd, sizeof(exe_header), (BYTE FAR *)&ExeHeader, XFR_READ); + + if (rc == sizeof(exe_header) && + (ExeHeader.exSignature == MAGIC || ExeHeader.exSignature == OLD_MAGIC)) + { + rc = DosExeLoader(lp, &TempExeBlock, mode, fd); + } + else if (rc != 0) + { + rc = DosComLoader(lp, &TempExeBlock, mode, fd); + } + + DosCloseSft(fd, FALSE); + + if (mode == LOAD && rc == SUCCESS) + fmemcpy(ep, &TempExeBlock, sizeof(exec_blk)); + + return rc; +} + +#include "config.h" /* config structure definition */ + +/* start process 0 (the shell) */ +VOID ASMCFUNC P_0(struct config FAR *Config) +{ + BYTE *tailp, *endp; + exec_blk exb; + UBYTE mode = Config->cfgP_0_startmode; + + /* build exec block and save all parameters here as init part will vanish! */ + exb.exec.fcb_1 = exb.exec.fcb_2 = (fcb FAR *)-1L; + exb.exec.env_seg = DOS_PSP + 8; + fstrcpy(Shell, MK_FP(FP_SEG(Config), Config->cfgInit)); + /* join name and tail */ + fstrcpy(Shell + strlen(Shell), MK_FP(FP_SEG(Config), Config->cfgInitTail)); + endp = Shell + strlen(Shell); + + for ( ; ; ) /* endless shell load loop - reboot or shut down to exit it! */ + { + BYTE *p; + /* if there are no parameters, point to end without "\r\n" */ + if((tailp = strchr(Shell,'\t')) == NULL && + (tailp = strchr(Shell, ' ')) == NULL) + tailp = endp - 2; + /* shift tail to right by 2 to make room for '\0', ctCount */ + for (p = endp - 1; p >= tailp; p--) + *(p + 2) = *p; + /* terminate name and tail */ + *tailp = *(endp + 2) = '\0'; + /* ctCount: just past '\0' do not count the "\r\n" */ + exb.exec.cmd_line = (CommandTail *)(tailp + 1); + exb.exec.cmd_line->ctCount = endp - tailp - 2; +#ifdef DEBUG + printf("Process 0 starting: %s%s\n\n", Shell, tailp + 2); +#endif + res_DosExec(mode, &exb, Shell); + put_string("Bad or missing Command Interpreter: "); /* failure _or_ exit */ + put_string(Shell); + put_string(tailp + 2); + put_string(" Enter the full shell command line: "); + endp = Shell + res_read(STDIN, Shell, NAMEMAX); + *endp = '\0'; /* terminate string for strchr */ + } +} diff --git a/kernel/turboc.cfg b/kernel/turboc.cfg new file mode 100644 index 0000000..f07a6c1 --- /dev/null +++ b/kernel/turboc.cfg @@ -0,0 +1,15 @@ +-f- +-ff- +-O +-Z +-d +-k- +-vi- +-wpro +-weas +-wpre +-w +-g1 +-I..\hdr +-p +-v- -I. -D__STDC__=0 -DKERNEL -DI86 -DPROTO -DASMSUPT diff --git a/lib/makefile b/lib/makefile new file mode 100644 index 0000000..c9a4ce6 --- /dev/null +++ b/lib/makefile @@ -0,0 +1,24 @@ +# +# makefile for libm.lib +# +# $Id: makefile 688 2003-09-15 10:46:24Z bartoldeman $ +# + + +!include "../mkfiles/generic.mak" + + +libm.lib: $(CLIB) + -$(RM) libm.lib + $(LIBUTIL) $(CLIB) $(MATH_EXTRACT) $(LIBTERM) + $(COMSPEC) /c for %i in (*.obj) do ..\utils\patchobj CODE=LCODE %i + $(LIBUTIL) libm $(MATH_INSERT) $(LIBTERM) + -$(RM) *.OBJ + + +clobber: clean + -$(RM) status.me + +clean: + -$(RM) *.obj *.bak libm.lib + diff --git a/makefile b/makefile new file mode 100644 index 0000000..0facb97 --- /dev/null +++ b/makefile @@ -0,0 +1,104 @@ +# What you WANT on DOS is: +# EDIT CONFIG.B, COPY CONFIG.B to CONFIG.BAT, RUN BUILD.BAT +# On Linux, use config.mak, and "make all", "make clean", or "make clobber" + +default: + @echo On DOS, please type build, clean, or clobber. + @echo On Linux, please type make all, make clean, or make clobber. + +build: + build + +bin\kwc8616.sys: + build -r wc 86 fat16 + +bin\kwc8632.sys: + build -r wc 86 fat32 + +# use as follows: wmake -ms zip VERSION=2029 +zip_src: + cd ..\.. + zip -9 -r -k source/ke$(VERSION)s.zip source/ke$(VERSION) -i@source/ke$(VERSION)/filelist + cd source\ke$(VERSION) + +BINLIST1 = doc bin/kernel.sys bin/sys.com +# removed - as the 2nd zip -r line to add those to the zip: +# BINLIST2 = bin/config.sys bin/autoexec.bat bin/command.com bin/install.bat + +zipfat16: bin\kwc8616.sys + mkdir doc + mkdir doc\kernel + copy docs\*.txt doc\kernel + copy docs\*.cvs doc\kernel + copy docs\copying doc\kernel + copy docs\*.lsm doc\kernel + del doc\kernel\build.txt + del doc\kernel\lfnapi.txt + copy bin\kwc8616.sys bin\kernel.sys + zip -r -k ../ke$(VERSION)16.zip $(BINLIST) + utils\rmfiles doc\kernel\*.txt doc\kernel\*.cvs doc\kernel\*.lsm doc\kernel\copying + rmdir doc\kernel + rmdir doc + +zipfat32: bin\kwc8632.sys + mkdir doc + mkdir doc\kernel + copy docs\*.txt doc\kernel + copy docs\*.cvs doc\kernel + copy docs\copying doc\kernel + copy docs\*.lsm doc\kernel + del doc\kernel\build.txt + del doc\kernel\lfnapi.txt + copy bin\kwc8632.sys bin\kernel.sys + zip -r -k ../ke$(VERSION)32.zip $(BINLIST) + utils\rmfiles doc\kernel\*.txt doc\kernel\*.cvs doc\kernel\*.lsm doc\kernel\copying + rmdir doc\kernel + rmdir doc + +zip: zip_src zipfat16 zipfat32 + +#Linux part +#defaults: override using config.mak +export +COMPILER=owlinux + +XCPU=86 +XFAT=32 +ifndef WATCOM + WATCOM=$(HOME)/watcom + PATH:=$(WATCOM)/binl:$(PATH) +endif +XUPX=upx --8086 --best +XNASM=nasm +MAKE=wmake -ms -h +XLINK=wlink +#ALLCFLAGS=-DDEBUG + +-include config.mak +ifdef XUPX + UPXOPT=-U +endif + +all: + cd utils && $(MAKE) production + cd lib && ( test -f libm.lib || touch libm.lib ) + cd drivers && $(MAKE) production + cd boot && $(MAKE) production + cd sys && $(MAKE) production + cd kernel && $(MAKE) production + +clean: + cd utils && $(MAKE) clean + cd lib && $(MAKE) clean + cd drivers && $(MAKE) clean + cd boot && $(MAKE) clean + cd sys && $(MAKE) clean + cd kernel && $(MAKE) clean + +clobber: + cd utils && $(MAKE) clobber + cd lib && $(MAKE) clobber + cd drivers && $(MAKE) clobber + cd boot && $(MAKE) clobber + cd sys && $(MAKE) clobber + cd kernel && $(MAKE) clobber diff --git a/mkfiles/bc5.mak b/mkfiles/bc5.mak new file mode 100644 index 0000000..64408fd --- /dev/null +++ b/mkfiles/bc5.mak @@ -0,0 +1,53 @@ +# +# BC5.MAK - kernel copiler options for Borland C++ +# + +# Use these for Borland C++ + +COMPILERPATH=$(BC5_BASE) +COMPILERBIN=$(COMPILERPATH)\bin +CC=$(COMPILERBIN)\bcc -c +CL=$(COMPILERBIN)\bcc +INCLUDEPATH=$(COMPILERPATH)\include +LIBUTIL=$(COMPILERBIN)\tlib +LIBPATH=$(COMPILERPATH)\lib +LIBTERM= +LIBPLUS=+ + +TINY=-lt +CFLAGST=-L$(LIBPATH) -mt -a- -k- -f- -ff- -O -Z -d +CFLAGSC=-L$(LIBPATH) -a- -mc + +TARGET=KBC + +# used for building the library + +CLIB=$(COMPILERPATH)\lib\cs.lib +MATH_EXTRACT=*H_LDIV *H_LLSH *H_LURSH *F_LXMUL +MATH_INSERT=+H_LDIV +H_LLSH +H_LURSH +F_LXMUL + +# +# heavy stuff - building the kernel +# Compiler and Options for Borland C++ +# ------------------------------------ +# +# -zAname ¦ ¦ Code class +# -zBname ¦ ¦ BSS class +# -zCname ¦ ¦ Code segment +# -zDname ¦ ¦ BSS segment +# -zEname ¦ ¦ Far segment +# -zFname ¦ ¦ Far class +# -zGname ¦ ¦ BSS group +# -zHname ¦ ¦ Far group +# -zPname ¦ ¦ Code group +# -zRname ¦ ¦ Data segment +# -zSname ¦ ¦ Data group +# -zTname ¦ ¦ Data class +# -zX ¦«¦ Use default name for "X" + +# +# ALLCFLAGS specified by turbo.cfg and config.mak +# +ALLCFLAGS=$(TARGETOPT) -zCHMA_TEXT $(ALLCFLAGS) +INITCFLAGS=$(ALLCFLAGS) -zCINIT_TEXT -zDIB -zRID -zTID -zBIB -zGI_GROUP -zSI_GROUP +CFLAGS=$(ALLCFLAGS) diff --git a/mkfiles/generic.mak b/mkfiles/generic.mak new file mode 100644 index 0000000..eca1bb0 --- /dev/null +++ b/mkfiles/generic.mak @@ -0,0 +1,56 @@ +# These are generic definitions + +#********************************************************************** +#* TARGET : we create a %TARGET%.sys file +#* TARGETOPT : options, handled down to the compiler +#********************************************************************** + +TARGETOPT=-1- + +!if $(XCPU) == 186 +TARGETOPT=-1 +!endif +!if $(XCPU) == 386 +TARGETOPT=-3 +!endif + +!if $(XFAT) == 32 +ALLCFLAGS=$(ALLCFLAGS) -DWITHFAT32 +NASMFLAGS=$(NASMFLAGS) -DWITHFAT32 +!endif + +NASM=$(XNASM) +NASMFLAGS = $(NASMFLAGS) -i../hdr/ -DXCPU=$(XCPU) + +LINK=$(XLINK) + +INITPATCH=@rem +DIRSEP=\ #a backslash +RM=..\utils\rmfiles +CP=copy +ECHOTO=..\utils\echoto +CLDEF=0 + +!if $(LOADSEG)0 == 0 +LOADSEG=0x60 +!endif + +!include "../mkfiles/$(COMPILER).mak" + +!if $(CLDEF) == 0 +CLT=$(CL) $(CFLAGST) $(TINY) -I$(INCLUDEPATH) +CLC=$(CL) $(CFLAGSC) -I$(INCLUDEPATH) +!endif + +TARGET=$(TARGET)$(XCPU)$(XFAT) + +.asm.obj : + $(NASM) -D$(COMPILER) $(NASMFLAGS) -f obj $*.asm + +# *Implicit Rules* +.c.obj : + $(CC) $(CFLAGS) $*.c + +.cpp.obj : + $(CC) $(CFLAGS) $*.cpp + diff --git a/mkfiles/mscl8.mak b/mkfiles/mscl8.mak new file mode 100644 index 0000000..cd5c53b --- /dev/null +++ b/mkfiles/mscl8.mak @@ -0,0 +1,47 @@ +# +# MSCL8.MAK - kernel copiler options for MS CL8 = MSVC1.52 +# + +# Use these for MSCV 1.52 +COMPILERPATH=$(MS_BASE) +COMPILERBIN=$(COMPILERPATH)\bin +INCLUDEPATH=$(COMPILERPATH)\include +CC=$(COMPILERBIN)\cl -c +CL=$(COMPILERBIN)\cl +TINY= +CFLAGST=/Fm /AT /Os /Zp1 +CFLAGSC=/Fm /AL /Os /Zp1 +LIBPATH=$(COMPILERPATH)\lib +LIB=$(COMPILERPATH)\lib +INCLUDE=$(COMPILERPATH)\include +LIBUTIL=$(COMPILERBIN)\lib /nologo +LIBPLUS=+ +LIBTERM=; +INCLUDE=$(COMPILERPATH)\include +LIB=$(COMPILERPATH)\lib + +# used for building the library + +CLIB=$(COMPILERPATH)\lib\slibce.lib +MATH_EXTRACT=*aflmul *aFlshl *aFNauldi *aFulrem *aFulshr *aFuldiv *aFlrem *aFldiv +MATH_INSERT= +aflmul +aFlshl +aFNauldi +aFulrem +aFulshr +aFuldiv +aFlrem +aFldiv + +TARGETOPT= +!if $(XCPU) == 186 +TARGETOPT=-G1 +!endif +!if $(XCPU) == 386 +TARGETOPT=-G3 +!endif + +TARGET=KMS + +# +# heavy stuff - building + + +ALLCFLAGS=-I..\hdr $(TARGETOPT) $(ALLCFLAGS) -nologo -Zl -Fc -WX -Gr -f- -Os -Gs -Ob1 -OV4 -Gy -Oe -Zp1 + +INITCFLAGS=$(ALLCFLAGS) -NTINIT_TEXT +CFLAGS=$(ALLCFLAGS) -NTHMA_TEXT +INITPATCH = ..\utils\patchobj _DATA=IDATA DATA=ID BSS=ID DGROUP=I_GROUP CONST=IC diff --git a/mkfiles/owlinux.mak b/mkfiles/owlinux.mak new file mode 100644 index 0000000..5172c15 --- /dev/null +++ b/mkfiles/owlinux.mak @@ -0,0 +1,19 @@ +# +# WATCOM.MAK - kernel compiler options for Open Watcom on Linux (cross-compile) +# + +# Get definitions from watcom.mak, then override +include "../mkfiles/watcom.mak" + +DIRSEP=/ +INCLUDEPATH=$(COMPILERPATH)/h +RM=rm -f +CP=cp +ECHOTO=echo>> +INITPATCH=@echo > /dev/null +CLDEF=1 +CLT=gcc -DDOSC_TIME_H -I../hdr -o $@ +CLC=$(CLT) +CFLAGST=-fo=.obj $(CFLAGST) +ALLCFLAGS=-fo=.obj $(ALLCFLAGS) +XLINK=$(XLINK) debug all op symfile format dos option map,statics,verbose F { $(OBJS) } L ../lib/device.lib N kernel.exe $# diff --git a/mkfiles/tc2.mak b/mkfiles/tc2.mak new file mode 100644 index 0000000..c5e5213 --- /dev/null +++ b/mkfiles/tc2.mak @@ -0,0 +1,53 @@ +# +# TURBOC.MAK - kernel copiler options for TURBOC +# + +# Use these for Turbo C 2.01 + +COMPILERPATH=$(TC2_BASE) +COMPILERBIN=$(COMPILERPATH) +CC=$(COMPILERBIN)\tcc -c +CL=$(COMPILERBIN)\tcc +INCLUDEPATH=$(COMPILERPATH)\include +LIBUTIL=$(COMPILERBIN)\tlib +LIBPATH=$(COMPILERPATH)\lib +LIBTERM= +LIBPLUS=+ + +TINY=-lt +CFLAGST=-L$(LIBPATH) -mt -a- -k- -f- -ff- -O -Z -d -w +CFLAGSC=-L$(LIBPATH) -a- -mc + +TARGET=KTC + +# used for building the library + +CLIB=$(COMPILERPATH)\lib\cs.lib +MATH_EXTRACT=*LDIV *LXMUL *LURSH *LLSH *LRSH +MATH_INSERT=+LDIV +LXMUL +LURSH +LLSH +LRSH + +# +# heavy stuff - building the kernel +# Compiler and Options for Borland C++ +# ------------------------------------ +# +# -zAname ¦ ¦ Code class +# -zBname ¦ ¦ BSS class +# -zCname ¦ ¦ Code segment +# -zDname ¦ ¦ BSS segment +# -zEname ¦ ¦ Far segment +# -zFname ¦ ¦ Far class +# -zGname ¦ ¦ BSS group +# -zHname ¦ ¦ Far group +# -zPname ¦ ¦ Code group +# -zRname ¦ ¦ Data segment +# -zSname ¦ ¦ Data group +# -zTname ¦ ¦ Data class +# -zX ¦«¦ Use default name for "X" + +# +# ALLCFLAGS specified by turbo.cfg and config.mak +# +ALLCFLAGS=$(TARGETOPT) -zCHMA_TEXT $(ALLCFLAGS) +INITCFLAGS=$(ALLCFLAGS) -zCINIT_TEXT -zDIB -zRID -zTID -zBIB -zGI_GROUP -zSI_GROUP +CFLAGS=$(ALLCFLAGS) diff --git a/mkfiles/tc3.mak b/mkfiles/tc3.mak new file mode 100644 index 0000000..1ac6986 --- /dev/null +++ b/mkfiles/tc3.mak @@ -0,0 +1,53 @@ +# +# TC3.MAK - kernel copiler options for Turbo C 3.0 +# + +# Use these for Turbo C 3.0 + +COMPILERPATH=$(TC3_BASE) +COMPILERBIN=$(COMPILERPATH)\bin +CC=$(COMPILERBIN)\tcc -c +CL=$(COMPILERBIN)\tcc +INCLUDEPATH=$(COMPILERPATH)\include +LIBUTIL=$(COMPILERBIN)\tlib +LIBPATH=$(COMPILERPATH)\lib +LIBTERM= +LIBPLUS=+ + +TINY=-lt +CFLAGST=-L$(LIBPATH) -mt -a- -k- -f- -ff- -O -Z -d +CFLAGSC=-L$(LIBPATH) -a- -mc + +TARGET=KT3 + +# used for building the library + +CLIB=$(COMPILERPATH)\lib\cs.lib +MATH_EXTRACT=*H_LDIV *H_LLSH *H_LURSH *F_LXMUL +MATH_INSERT=+H_LDIV +H_LLSH +H_LURSH +F_LXMUL + +# +# heavy stuff - building the kernel +# Compiler and Options for Borland C++ +# ------------------------------------ +# +# -zAname ¦ ¦ Code class +# -zBname ¦ ¦ BSS class +# -zCname ¦ ¦ Code segment +# -zDname ¦ ¦ BSS segment +# -zEname ¦ ¦ Far segment +# -zFname ¦ ¦ Far class +# -zGname ¦ ¦ BSS group +# -zHname ¦ ¦ Far group +# -zPname ¦ ¦ Code group +# -zRname ¦ ¦ Data segment +# -zSname ¦ ¦ Data group +# -zTname ¦ ¦ Data class +# -zX ¦«¦ Use default name for "X" + +# +# ALLCFLAGS specified by turbo.cfg and config.mak +# +ALLCFLAGS=$(TARGETOPT) -zCHMA_TEXT $(ALLCFLAGS) +INITCFLAGS=$(ALLCFLAGS) -zCINIT_TEXT -zDIB -zRID -zTID -zBIB -zGI_GROUP -zSI_GROUP +CFLAGS=$(ALLCFLAGS) diff --git a/mkfiles/turbocpp.mak b/mkfiles/turbocpp.mak new file mode 100644 index 0000000..db33118 --- /dev/null +++ b/mkfiles/turbocpp.mak @@ -0,0 +1,53 @@ +# +# TURBOCPP.MAK - kernel copiler options for TCPP 1.01 +# + +# Use these for Turbo CPP 1.01 + +COMPILERPATH=$(TP1_BASE) +COMPILERBIN=$(COMPILERPATH)\bin +CC=$(COMPILERBIN)\tcc -c +CL=$(COMPILERBIN)\tcc +INCLUDEPATH=$(COMPILERPATH)\include +LIBUTIL=$(COMPILERBIN)\tlib +LIBPATH=$(COMPILERPATH)\lib +LIBTERM= +LIBPLUS=+ + +TINY=-lt +CFLAGST=-L$(LIBPATH) -mt -a- -k- -f- -ff- -O -Z -d +CFLAGSC=-L$(LIBPATH) -a- -mc + +TARGET=KTP + +# used for building the library + +CLIB=$(COMPILERPATH)\lib\cs.lib +MATH_EXTRACT=*H_LDIV *H_LLSH *H_LURSH *F_LXMUL +MATH_INSERT=+H_LDIV +H_LLSH +H_LURSH +F_LXMUL + +# +# heavy stuff - building the kernel +# Compiler and Options for Borland C++ +# ------------------------------------ +# +# -zAname ¦ ¦ Code class +# -zBname ¦ ¦ BSS class +# -zCname ¦ ¦ Code segment +# -zDname ¦ ¦ BSS segment +# -zEname ¦ ¦ Far segment +# -zFname ¦ ¦ Far class +# -zGname ¦ ¦ BSS group +# -zHname ¦ ¦ Far group +# -zPname ¦ ¦ Code group +# -zRname ¦ ¦ Data segment +# -zSname ¦ ¦ Data group +# -zTname ¦ ¦ Data class +# -zX ¦«¦ Use default name for "X" + +# +# ALLCFLAGS specified by turbo.cfg and config.mak +# +ALLCFLAGS=$(TARGETOPT) -zCHMA_TEXT $(ALLCFLAGS) +INITCFLAGS=$(ALLCFLAGS) -zCINIT_TEXT -zDIB -zRID -zTID -zBIB -zGI_GROUP -zSI_GROUP +CFLAGS=$(ALLCFLAGS) diff --git a/mkfiles/watcom.mak b/mkfiles/watcom.mak new file mode 100644 index 0000000..e461688 --- /dev/null +++ b/mkfiles/watcom.mak @@ -0,0 +1,67 @@ +# +# WATCOM.MAK - kernel copiler options for WATCOM C 11.0c +# + +# Use these for WATCOM 11.0c +COMPILERPATH=$(WATCOM) +CC=*wcc +CL=wcl +INCLUDEPATH=$(COMPILERPATH)\H +INCLUDE=$(COMPILERPATH)\h +EDPATH=$(COMPILERPATH)\EDDAT + +!if $(XCPU) != 186 +!if $(XCPU) != 386 +TARGETOPT=-0 +!endif +!endif + +LIBPATH=$(COMPILERPATH)\lib286 +LIBUTIL=wlib -q +LIBPLUS= +LIBTERM= + +TINY=-mt +CFLAGST=-zq-zp1-os-s-we-e3-wx-bt=DOS +CFLAGSC=-mc-zq-zp1-os-s-we-e3-wx-bt=DOS + +TARGET=KWC + +# used for building the library + +CLIB=$(COMPILERPATH)\lib286\dos\clibm.lib + +# we use our own ones, which override these ones when linking. +# + +MATH_EXTRACT=*i4m +MATH_INSERT=+i4m + + +# +# heavy stuff - building +# +# -e= set limit on number of error messages +# -ms small memory model (small code/small data) +# -j change char default from unsigned to signed +#-nc= set code class name +#-nd= set data segment name +#-nm= set module name +#-nt= set name of text segment +# -g= set code group name +# -os -> favor code size over execution time in optimizations +# -s remove stack overflow checks +# -w= set warning level number +# -we treat all warnings as errors +# -ze enable extensions (i.e., near, far, export, etc.) +# -zl remove default library information +# -zp= pack structure members with alignment {1,2,4,8,16} +# -zq operate quietly +# +# -3 optimization for 386 - given in CONFIG.MAK, not here +# + +ALLCFLAGS=-I..$(DIRSEP)hdr $(TARGETOPT) $(ALLCFLAGS)-zq-os-s-e5-j-zl-zp1-wx-we-zgf-zff-r +INITCFLAGS=$(ALLCFLAGS)-ntINIT_TEXT-gTGROUP-ndI +CFLAGS=$(ALLCFLAGS)-ntHMA_TEXT + diff --git a/share/makefile b/share/makefile new file mode 100644 index 0000000..f8dbbde --- /dev/null +++ b/share/makefile @@ -0,0 +1,33 @@ + +# nmake makefile +# share must be linked as COM file +# best is to use TC 2.01 which is freely available + +USETC2=1 +COM=1 + +!if $(USETC2) +TCC=d:\alt\tc201\tcc +TLINK=d:\alt\tc201\tlink +LIBS=d:\alt\tc201 +COPT=-c -mt -1 -Id:\alt\tc201 +LOPT=/m /s /c /t +!else +TCC=d:\alt\tc30\bin\tcc +TLINK=d:\alt\tc30\bin\tlink +LIBS=d:\alt\tc30\lib +!if $(COM) +COPT=-c -mt -1 -Id:\alt\tc30\Include +LOPT=-m -s -c -t +!else +COPT=-c -ms -1 -Id:\alt\tc30\Include +LOPT=-m -s -c +!endif +!endif + +SHARE.COM: SHARE.OBJ + $(TLINK) $(LOPT) $(LIBS)\c0t.obj share.obj,share.com,,$(LIBS)\cs.lib + +SHARE.OBJ: SHARE.C + $(TCC) $(COPT) share.c + diff --git a/share/share.c b/share/share.c new file mode 100644 index 0000000..46777d4 --- /dev/null +++ b/share/share.c @@ -0,0 +1,761 @@ +/* + FreeDOS SHARE + Copyright (c) 2000 Ronald B. Cemer under the GNU GPL + You know the drill. + If not, see www.gnu.org for details. Read it, learn it, BE IT. :-) +*/ + +/* #include */ /* (fprintf removed...) */ +/* #include */ /* Not used, using defines below... */ +#include /* write (what else?) */ +#include /* _psp, NULL, malloc, free, atol, atoi */ +#include /* MK_FP, FP_OFF, FP_SEG, int86, intdosx, */ + /* freemem, keep */ +#include /* strchr, strlen, memset */ + +#ifndef __TURBOC__ +#error "This software must be compiled with TurboC or TurboC++." +#endif + +/* Changed by Eric Auer 5/2004: Squeezing executable size a bit -> */ +/* Replaced fprint(stderr or stdout,...) by write(hand, buf, size) */ +/* Keeps stream stuff and printf stuff outside the file and TSR... */ + + /* ------------- DEFINES ------------- */ +#define MUX_INT_NO 0x2f +#define MULTIPLEX_ID 0x10 + +#define FILE_TABLE_MIN 128 +#define FILE_TABLE_MAX 62000U + +#define LOCK_TABLE_MIN 1 +#define LOCK_TABLE_MAX 3800 + + /* Valid values for openmode: */ +#define OPEN_READ_ONLY 0 +#define OPEN_WRITE_ONLY 1 +#define OPEN_READ_WRITE 2 + + /* Valid values for sharemode: */ +#define SHARE_COMPAT 0 +#define SHARE_DENY_ALL 1 +#define SHARE_DENY_WRITE 2 +#define SHARE_DENY_READ 3 +#define SHARE_DENY_NONE 4 + + /* ------------- TYPEDEFS ------------- */ + /* Register structure for an interrupt function. */ +typedef struct { + unsigned bp; + unsigned di; + unsigned si; + unsigned ds; + unsigned es; + unsigned dx; + unsigned cx; + unsigned bx; + unsigned ax; + unsigned ip; + unsigned cs; + unsigned flags; +} intregs_t; + + /* This table determines the action to take when attempting to open + a file. The first array index is the sharing mode of a previous + open on the same file. The second array index is the sharing mode + of the current open attempt on the same file. Action codes are + defined as follows: + 0 = open may proceed + 1 = open fails with error code 05h + 2 = open fails and an INT 24h is generated + 3 = open proceeds if the file is read-only; otherwise fails + with error code (used only in exception table below) + 4 = open proceeds if the file is read-only; otherwise fails + with INT 24H (used only in exception table below) + Exceptions to the rules are handled in the table + below, so this table only covers the general rules. + */ +static unsigned char open_actions[5][5] = { + { 0, 1, 1, 1, 1 }, + { 2, 1, 1, 1, 1 }, + { 2, 1, 1, 1, 1 }, + { 2, 1, 1, 1, 1 }, + { 2, 1, 1, 1, 0 }, +}; + +typedef struct { + unsigned char first_sharemode; + unsigned char first_openmode; + unsigned char current_sharemode; + unsigned char current_openmode; + unsigned char action; +} open_action_exception_t; + +static open_action_exception_t open_exceptions[] = { + { 0, 0, 2, 0, 3 }, + { 0, 0, 4, 0, 3 }, /* compatibility-read/deny none-read, MED 08/2004 */ + { 2, 0, 0, 0, 4 }, + { 2, 0, 2, 0, 0 }, + { 2, 0, 4, 0, 0 }, + { 3, 0, 2, 1, 0 }, + { 3, 0, 4, 1, 0 }, + { 3, 1, 4, 1, 0 }, + { 3, 2, 4, 1, 0 }, + { 4, 0, 0, 0, 4 }, + { 4, 0, 0, 1, 0 }, /* deny none-read/compatibility-write */ + { 4, 0, 0, 2, 0 }, /* deny none-read/compatibility-read+write */ + { 4, 0, 2, 0, 0 }, + { 4, 0, 2, 1, 0 }, + { 4, 0, 2, 2, 0 }, + { 4, 1, 3, 0, 0 }, + { 4, 1, 3, 1, 0 }, + { 4, 1, 3, 2, 0 }, +}; + + /* One of these exists for each instance of an open file. */ +typedef struct { + char filename[128]; /* fully-qualified filename; "\0" if unused */ + unsigned short psp; /* PSP of process which opened this file */ + unsigned char openmode; /* 0=read-only, 1=write-only, 2=read-write */ + unsigned char sharemode;/* SHARE_COMPAT, etc... */ + unsigned char first_openmode; /* openmode of first open */ + unsigned char first_sharemode; /* sharemode of first open */ +} file_t; + + /* One of these exists for each active lock region. */ +typedef struct { + unsigned char used; /* Non-zero if this entry is used. */ + unsigned long start; /* Beginning offset of locked region */ + unsigned long end; /* Ending offset of locked region */ + unsigned short fileno; /* file_table entry number */ + unsigned short psp; /* PSP of process which owns the lock */ +} lock_t; + + + /* ------------- GLOBALS ------------- */ +static char progname[9]; +static unsigned int file_table_size_bytes = 2048; +static unsigned int file_table_size = 0; /* # of file_t we can have */ +static file_t *file_table = NULL; +static unsigned int lock_table_size = 20; /* # of lock_t we can have */ +static lock_t *lock_table = NULL; + + + /* ------------- PROTOTYPES ------------- */ +/* PRINT added by Eric */ +#define ERR 2 /* handle of stderr */ +#define OUT 1 /* handle of stdout */ +static void PRINT(int handle, char * text); +static void PRINT(int handle, char * text) { + (void)write (handle, text, strlen(text)); + /* return value is -1 error or N bytes_written. Ignored. */ +}; + + + /* DOS calls this to see if it's okay to open the file. + Returns a file_table entry number to use (>= 0) if okay + to open. Otherwise returns < 0 and may generate a critical + error. If < 0 is returned, it is the negated error return + code, so DOS simply negates this value and returns it in + AX. */ +static int open_check + (char far *filename,/* far pointer to fully qualified filename */ + unsigned short psp,/* psp segment address of owner process */ + int openmode, /* 0=read-only, 1=write-only, 2=read-write */ + int sharemode); /* SHARE_COMPAT, etc... */ + + /* DOS calls this to record the fact that it has successfully + closed a file, or the fact that the open for this file failed. */ +static void close_file + (int fileno); /* file_table entry number */ + + /* DOS calls this to determine whether it can access (read or + write) a specific section of a file. We call it internally + from lock_unlock (only when locking) to see if any portion + of the requested region is already locked. If psp is zero, + then it matches any psp in the lock table. Otherwise, only + locks which DO NOT belong to psp will be considered. + Returns zero if okay to access or lock (no portion of the + region is already locked). Otherwise returns non-zero and + generates a critical error (if allowcriter is non-zero). + If non-zero is returned, it is the negated return value for + the DOS call. */ +static int access_check + (unsigned short psp,/* psp segment address of owner process */ + int fileno, /* file_table entry number */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to access */ + int allowcriter); /* allow a critical error to be generated */ + + /* DOS calls this to lock or unlock a specific section of a file. + Returns zero if successfully locked or unlocked. Otherwise + returns non-zero. + If the return value is non-zero, it is the negated error + return code for the DOS 0x5c call. */ +static int lock_unlock + (unsigned short psp,/* psp segment address of owner process */ + int fileno, /* file_table entry number */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to lock or unlock */ + int unlock); /* non-zero to unlock; zero to lock */ + + /* Multiplex interrupt handler */ + +static void interrupt far (*old_handler2f)() = NULL; + + + /* ------------- HOOK ------------- */ +static void interrupt far handler2f(intregs_t iregs) { + +#define chain_old_handler2f { \ + _BX = iregs.bx; /* Restore BX */ \ + _CX = iregs.ax; /* Save original AX contents into CX */ \ + iregs.ax = FP_SEG((void far *)old_handler2f); /* Set chain segment */ \ + iregs.bx = FP_OFF((void far *)old_handler2f); /* Set chain offset */ \ + _AX = _CX; /* Restore AX */ \ + __emit__(0x5D); /* POP BP */ \ + __emit__(0x5F); /* POP DI */ \ + __emit__(0x5E); /* POP SI */ \ + __emit__(0x1F); /* POP DS */ \ + __emit__(0x07); /* POP ES */ \ + __emit__(0x5A); /* POP DX */ \ + __emit__(0x59); /* POP CX */ \ + __emit__(0xCB); /* RETF */ \ +} /* This evil trick probably only works with Turbo C!?! */ + /* would have been better to link a NASM handler core: */ + /* nasm -fobj -o foo.obj foo.asm ... */ + + if (((iregs.ax >> 8) & 0xff) == MULTIPLEX_ID) { + if ((iregs.ax & 0xff) == 0) { + /* Installation check. Return 0xff in AL. */ + iregs.ax |= 0xff; + return; + } + /* These subfuctions are nonstandard, but are highly + unlikely to be used by another multiplex TSR, since + our multiplex Id (0x10) is basically reserved for + SHARE. So we should be able to get away with using + these for our own purposes. */ + /* open_check */ + if ((iregs.ax & 0xff) == 0xa0) { + iregs.ax = open_check + (MK_FP(iregs.ds, iregs.si), + iregs.bx, + iregs.cx, + iregs.dx); + return; + } + /* close_file */ + if ((iregs.ax & 0xff) == 0xa1) { + close_file(iregs.bx); + return; + } + /* access_check (0xa2) */ + /* access_check with critical error (0xa3) */ + if ((iregs.ax & 0xfe) == 0xa2) { + iregs.ax = access_check + (iregs.bx, + iregs.cx, +#if 0 + ( ((((unsigned long)iregs.si)<<16) & 0xffff0000L) | + (((unsigned long)iregs.di) & 0xffffL) ), + ( ((((unsigned long)iregs.es)<<16) & 0xffff0000L) | + (((unsigned long)iregs.dx) & 0xffffL) ), +#else + ( (((unsigned long)iregs.si)<<16) + iregs.di ), + ( (((unsigned long)iregs.es)<<16) + iregs.dx ), +#endif + (iregs.ax & 0x01)); + return; + } + /* lock_unlock lock (0xa4)*/ + /* lock_unlock unlock (0xa5) */ + if ((iregs.ax & 0xfe) == 0xa4) { + iregs.ax = lock_unlock + (iregs.bx, + iregs.cx, +#if 0 + ( ((((unsigned long)iregs.si)<<16) & 0xffff0000L) | + (((unsigned long)iregs.di) & 0xffffL) ), + ( ((((unsigned long)iregs.es)<<16) & 0xffff0000L) | + (((unsigned long)iregs.dx) & 0xffffL) ), +#else + ( (((unsigned long)iregs.si)<<16) | ((unsigned long)iregs.di) ), + ( (((unsigned long)iregs.es)<<16) | ((unsigned long)iregs.dx) ), +#endif + (iregs.ax & 0x01)); + return; + } + } + /* Chain to the next handler. */ + chain_old_handler2f; +} + +static void remove_all_locks(int fileno) { + int i; + lock_t *lptr; + + for (i = 0; i < lock_table_size; i++) { + lptr = &lock_table[i]; + if (lptr->fileno == fileno) lptr->used = 0; + } +} + +static void free_file_table_entry(int fileno) { + file_table[fileno].filename[0] = '\0'; +} + +/* DOS 7 does not have read-only restrictions, MED 08/2004 */ +/* +static int file_is_read_only(char far *filename) { + union REGS regs; + struct SREGS sregs; + + regs.x.ax = 0x4300; + sregs.ds = FP_SEG(filename); + regs.x.dx = FP_OFF(filename); + intdosx(®s, ®s, &sregs); + if (regs.x.cflag) return 0; + return ((regs.h.cl & 0x19) == 0x01); +} +*/ + +static int fnmatches(char far *fn1, char far *fn2) { + while (*fn1) { + if (*fn1 != *fn2) return 0; + fn1++; + fn2++; + } + return (*fn1 == *fn2); +} + +static int do_open_check + (int fileno) { /* file_table entry number */ + file_t *p, *fptr = &file_table[fileno]; + int i, j, action = 0, foundexc; + unsigned char current_sharemode = fptr->sharemode; + unsigned char current_openmode = fptr->openmode; + open_action_exception_t *excptr; + + fptr->first_sharemode = fptr->sharemode; + fptr->first_openmode = fptr->openmode; + for (i = 0; i < file_table_size; i++) { + if (i == fileno) continue; + p = &file_table[i]; + if (p->filename[0] == '\0') continue; + if (!fnmatches(p->filename, fptr->filename)) continue; + fptr->first_sharemode = p->first_sharemode; + fptr->first_openmode = p->first_openmode; + /* Look for exceptions to the general rules first. */ + foundexc = 0; + for (j = 0; + j < (sizeof(open_exceptions)/sizeof(open_action_exception_t)); + j++) { + excptr = &open_exceptions[j]; + if ( (excptr->first_sharemode == fptr->first_sharemode) + && (excptr->current_sharemode == current_sharemode) + && (excptr->first_openmode == fptr->first_openmode) + && (excptr->current_openmode == current_openmode) ) { + foundexc = 1; + action = excptr->action; + break; + } + } + /* If no exception to rules, use normal rules. */ + if (!foundexc) + action = open_actions[fptr->first_sharemode][current_sharemode]; + /* Fail appropriately based on action. */ + switch (action) { + +/* DOS 7 does not have read-only restrictions, fall through to proceed, MED 08/2004 */ + case 3: + case 4: + + case 0: /* proceed with open */ + break; +/* case 3: */ /* succeed if file read-only, else fail with error 05h */ +/* if (file_is_read_only(fptr->filename)) break; */ + case 1: /* fail with error code 05h */ + free_file_table_entry(fileno); + return -5; +/* case 4: */ /* succeed if file read-only, else fail with int 24h */ +/* if (file_is_read_only(fptr->filename)) break; */ + case 2: /* fail with int 24h */ + { + union REGS regs; + + regs.h.ah = 0x0e; /* disk I/O; fail allowed; data area */ + regs.h.al = 0; + regs.x.di = 0x0d; /* sharing violation */ + if ( (fptr->filename[0]!='\0') && (fptr->filename[1]==':') ) + regs.h.al = fptr->filename[0]-'A'; + free_file_table_entry(fileno); + int86(0x24, ®s, ®s); + } + return -0x20; /* sharing violation */ + } + break; + } + return fileno; +} + + /* DOS calls this to see if it's okay to open the file. + Returns a file_table entry number to use (>= 0) if okay + to open. Otherwise returns < 0 and may generate a critical + error. If < 0 is returned, it is the negated error return + code, so DOS simply negates this value and returns it in + AX. */ +static int open_check + (char far *filename,/* far pointer to fully qualified filename */ + unsigned short psp,/* psp segment address of owner process */ + int openmode, /* 0=read-only, 1=write-only, 2=read-write */ + int sharemode) { /* SHARE_COMPAT, etc... */ + + int i, fileno = -1; + file_t *fptr; + + /* Whack off unused bits in the share mode + in case we were careless elsewhere. */ + sharemode &= 0x07; + + /* Assume compatibility mode if invalid share mode. */ +/* ??? IS THIS CORRECT ??? */ + if ( (sharemode < SHARE_COMPAT) || (sharemode > SHARE_DENY_NONE) ) + sharemode = SHARE_COMPAT; + + /* Whack off unused bits in the open mode + in case we were careless elsewhere. */ + openmode &= 0x03; + + /* Assume read-only mode if invalid open mode. */ +/* ??? IS THIS CORRECT ??? */ + if ( (openmode < OPEN_READ_ONLY) || (openmode > OPEN_READ_WRITE) ) + openmode = OPEN_READ_ONLY; + + for (i = 0; i < file_table_size; i++) { + if (file_table[i].filename[0] == '\0') { + fileno = i; + break; + } + } + if (fileno == -1) return -1; + fptr = &file_table[fileno]; + + /* Copy the filename into ftpr->filename. */ + for (i = 0; i < sizeof(fptr->filename); i++) { + if ((fptr->filename[i] = filename[i]) == '\0') break; + } + fptr->psp = psp; + fptr->openmode = (unsigned char)openmode; + fptr->sharemode = (unsigned char)sharemode; + /* Do the sharing check and return fileno if + okay, or < 0 (and free the entry) if error. */ + return do_open_check(fileno); +} + + /* DOS calls this to record the fact that it has successfully + closed a file, or the fact that the open for this file failed. */ +static void close_file + (int fileno) { /* file_table entry number */ + + remove_all_locks(fileno); + free_file_table_entry(fileno); +} + + /* DOS calls this to determine whether it can access (read or + write) a specific section of a file. We call it internally + from lock_unlock (only when locking) to see if any portion + of the requested region is already locked. If psp is zero, + then it matches any psp in the lock table. Otherwise, only + locks which DO NOT belong to psp will be considered. + Returns zero if okay to access or lock (no portion of the + region is already locked). Otherwise returns non-zero and + generates a critical error (if allowcriter is non-zero). + If non-zero is returned, it is the negated return value for + the DOS call. */ +static int access_check + (unsigned short psp,/* psp segment address of owner process */ + int fileno, /* file_table entry number */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to access */ + int allowcriter) { /* allow a critical error to be generated */ + int i; + file_t *fptr = &file_table[fileno]; + char far *filename = fptr->filename; + lock_t *lptr; + unsigned long endofs = ofs + len; + + if (endofs < ofs) { + endofs = 0xffffffffL; + len = endofs-ofs; + } + + if (len < 1L) return 0; + + for (i = 0; i < lock_table_size; i++) { + lptr = &lock_table[i]; + if ( (lptr->used) + && ( (psp == 0) || (lptr->psp != psp) ) + && (fnmatches(filename, file_table[lptr->fileno].filename)) + && ( ( (ofs>=lptr->start) && (ofsend) ) + || ( (endofs>lptr->start) && (endofs<=lptr->end) ) ) ) { + if (allowcriter) { + union REGS regs; + + regs.h.ah = 0x0e; /* disk I/O; fail allowed; data area */ + regs.h.al = 0; + regs.x.di = 0x0e; /* lock violation */ + if ( (fptr->filename[0]!='\0') && (fptr->filename[1]==':') ) + regs.h.al = fptr->filename[0]-'A'; + free_file_table_entry(fileno); + int86(0x24, ®s, ®s); + } + return -0x21; /* lock violation */ + } + } + return 0; +} + + /* DOS calls this to lock or unlock a specific section of a file. + Returns zero if successfully locked or unlocked. Otherwise + returns non-zero. + If the return value is non-zero, it is the negated error + return code for the DOS 0x5c call. */ +static int lock_unlock + (unsigned short psp,/* psp segment address of owner process */ + int fileno, /* file_table entry number */ + unsigned long ofs, /* offset into file */ + unsigned long len, /* length (in bytes) of region to lock or unlock */ + int unlock) { /* non-zero to unlock; zero to lock */ + + int i; + lock_t *lptr; + unsigned long endofs = ofs + len; + + if (endofs < ofs) { + endofs = 0xffffffffL; + len = endofs-ofs; + } + + if (len < 1L) return 0; + + /* there was a error in the code below preventing any other + than the first locked region to be unlocked (japheth, 09/2005) */ + + if (unlock) { + for (i = 0; i < lock_table_size; i++) { + lptr = &lock_table[i]; + if ( (lptr->used) + && (lptr->psp == psp) + && (lptr->fileno == fileno) + && (lptr->start == ofs) + && (lptr->end == endofs) ) { + lptr->used = 0; + return 0; + } + } + /* Not already locked by us; can't unlock. */ + return -(0x21); /* lock violation */ + } else { + if (access_check(0, fileno, ofs, len, 0)) { + /* Already locked; can't lock. */ + return -(0x21); /* lock violation */ + } + for (i = 0; i < lock_table_size; i++) { + lptr = &lock_table[i]; + if (!lptr->used) { + lptr->used = 1; + lptr->start = ofs; + lptr->end = ofs+(unsigned long)len; + lptr->fileno = fileno; + lptr->psp = psp; + return 0; + } + } + return -(0x24); /* sharing buffer overflow */ + } +} + + /* ------------- INIT ------------- */ + /* Allocate tables and install hooks into the kernel. + If we run out of memory, return non-zero. */ +static int init(void) { + /* int i; */ + + file_table_size = file_table_size_bytes/sizeof(file_t); + if ((file_table=malloc(file_table_size_bytes)) == NULL) + return 1; + memset(file_table, 0, file_table_size_bytes); + if ((lock_table=malloc(lock_table_size*sizeof(lock_t))) == NULL) + return 1; + memset(lock_table, 0, lock_table_size*sizeof(lock_t)); + return 0; +} + +static void usage(void) { + PRINT(ERR, + "Installs file-sharing and locking " + "capabilities on your hard disk.\r\n\r\n"); + PRINT(ERR, progname); + PRINT(ERR, " [/F:space] [/L:locks]\r\n\r\n" + " /F:space Allocates file space (in bytes) " + "for file-sharing information.\r\n" + " /L:locks Sets the number of files that can " + "be locked at one time.\r\n"); +} + +static void bad_params(void) { + PRINT(ERR, progname); + PRINT(ERR, ": parameter out of range!\r\n"); +} + +static void out_of_memory(void) { + PRINT(ERR, progname); + PRINT(ERR,": out of memory!\r\n"); +} + + /* ------------- MAIN ------------- */ +int main(int argc, char **argv) { + unsigned short far *usfptr; + unsigned char far *uscptr; + unsigned short top_of_tsr; + int installed = 0; + int i; + + /* Extract program name from argv[0] into progname. */ + if (argv[0] != NULL) { + char *p = argv[0], *p2, c; + int i; + if ( (p[0] != '\0') && (p[1] == ':') ) + p += 2; + while ((p2 = strchr(p, '\\')) != NULL) + p = p2+1; + p2 = progname; + for (i = 0; i < 8; i++) { + c = p[i]; + if ( (c == '.') || (c == '\0') ) + break; + *(p2++) = c; + } + *p2 = '\0'; + } + + /* See if the TSR is already installed. */ + /* disable(); */ /* no multitasking, so don't worry */ + if (getvect(MUX_INT_NO) != NULL) { + union REGS regs; + /* enable(); */ + regs.h.ah = MULTIPLEX_ID; + regs.h.al = 0; + int86(MUX_INT_NO,®s,®s); + installed = ((regs.x.ax & 0xff) == 0xff); + + } /* else { enable(); } */ + + /* Process command line arguments. Bail if errors. */ + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (arg == NULL) continue; + if (arg[0] != '/') { + usage(); + return 3; + } + arg++; + switch(*arg) { + case '?': + usage(); + return 3; + case 'f': + case 'F': + arg++; + if (*arg != ':') { + usage(); + return 3; + } + arg++; + { + long temp = atol(arg); + if ( (temp < (long)FILE_TABLE_MIN) + || (temp > (long)FILE_TABLE_MAX) ) { + bad_params(); + return 3; + } + file_table_size_bytes = (unsigned int)temp; + } + break; + case 'l': + case 'L': + arg++; + if (*arg != ':') { + usage(); + return 3; + } + arg++; + lock_table_size = atoi(arg); + if ( (lock_table_size < LOCK_TABLE_MIN) + || (lock_table_size > LOCK_TABLE_MAX) ) { + bad_params(); + return 3; + } + break; + } + } + + /* Now try to install. */ + + if (installed) { + PRINT(ERR, progname); + PRINT(ERR, " is already installed!\r\n"); + return 1; + } + + if (init() != 0) { + out_of_memory(); + return 2; + } + + /* Allocate a single byte. This tells us the size of the TSR. + Free the byte when we know the address. */ + uscptr = (unsigned char far *)malloc(1); + if (uscptr == NULL) { + out_of_memory(); + return 2; + } + top_of_tsr = (FP_SEG(uscptr)+((FP_OFF(uscptr)+15) >> 4)) - _psp; + /* resident paras, counting from PSP:0 */ + free((void *)uscptr); + + + /* Hook the interrupt for the handler routine. */ + /* disable(); */ + old_handler2f = getvect(MUX_INT_NO); + setvect(MUX_INT_NO,handler2f); + /* enable(); */ + + /* Let them know we're installed. */ + PRINT(OUT, progname); + PRINT(OUT, " installed.\r\n"); + + /* Any access to environment variables must */ + /* be done prior to this point. Here we */ + /* free the environment table to prevent */ + /* wasting that memory. In fact, if the */ + /* TSR were removed from memory and we did */ + /* not do this, we would not be able to */ + /* recover this memory. */ + + usfptr = MK_FP(_psp, 0x2c); /* MK_FP is the counterpart */ + /* of FP_OFF and FP_SEG ... */ + freemem(*usfptr); /* deallocate MCB of ENV segment */ + +#if 0 + /* Free the remainder of memory for use by applications. */ + setblock(_psp,top_of_tsr); + /* resize self: already done by keep() */ +#endif + + /* Terminate and stay resident. */ + keep(0,top_of_tsr); /* size is set to top_of_tsr paragraphs */ + return 0; +} + diff --git a/share/share.hlp b/share/share.hlp new file mode 100644 index 0000000..dbb7a1e --- /dev/null +++ b/share/share.hlp @@ -0,0 +1,6 @@ +Installs file-sharing and locking capabilities on your hard disk. + +SHARE [/F:space] [/L:locks] + + /F:space Allocates file space (in bytes) for file-sharing information. + /L:locks Sets the number of files that can be locked at one time. diff --git a/sys/bin2c.c b/sys/bin2c.c new file mode 100644 index 0000000..eb70f4a --- /dev/null +++ b/sys/bin2c.c @@ -0,0 +1,52 @@ +#include + +int main(int argc, char **argv) +{ + FILE *in, *out; + int col; + int c; + + if (argc < 4) + { + fprintf(stderr, + "Usage: bin2c \n"); + return 1; + } + + if ((in = fopen(argv[1], "rb")) == NULL) + { + fprintf(stderr, "Cannot open input file (%s).\n", argv[1]); + return 1; + } + + if ((out = fopen(argv[2], "wt")) == NULL) + { + fprintf(stderr, "Cannot open output file (%s).\n", argv[2]); + return 1; + } + + col = 0; + + fprintf(out, "unsigned char %s[] = {\n ", argv[3]); + + while ((c = fgetc(in)) != EOF) + { + if (col) + { + fprintf(out, ", "); + } + if (col >= 8) + { + fprintf(out, "\n "); + col = 0; + } + fprintf(out, "0x%02X", c); + col++; + } + + fprintf(out, "\n};\n"); + fclose(in); + fclose(out); + + return 0; +} diff --git a/sys/fdkrncfg.c b/sys/fdkrncfg.c new file mode 100644 index 0000000..4fd9051 --- /dev/null +++ b/sys/fdkrncfg.c @@ -0,0 +1,482 @@ +/*************************************************************************** +* * +* FDKRNCFG.C - FreeDOS Kernel Configuration * +* This is a simple little program that merely displays and/or changes * +* the configuration options specified within the CONFIG section of * +* the FreeDOS Kernel (if supported) * +* * +* Initially Written by Kenneth J. Davis Oct 11, 2001 (public domain) * +* Future versions may contain copyrighted portions, if so the * +* copyright holders should be listed after this line. * +* Initial release - public domain * +* * +* merged into SYS by tom ehlert * +***************************************************************************/ + +/* This source compiled & tested with Borland C/C++ 3.1 + TC 2.01*/ + +char VERSION[] = "v1.00"; +char PROGRAM[] = "SYS CONFIG"; +char KERNEL[] = "KERNEL.SYS"; + +#include +#include +#include + +#include "portab.h" +/* These definitions deliberately put here instead of + * #including to make executable MUCH smaller + * using [s]printf from prf.c! + */ +extern int VA_CDECL printf(CONST char * fmt, ...); +extern int VA_CDECL sprintf(char * buff, CONST char * fmt, ...); + +#ifdef __WATCOMC__ +unsigned _dos_close(int handle); +#define close _dos_close +#define SEEK_SET 0 +int open(const char *pathname, int flags, ...); +int read(int fd, void *buf, unsigned count); +int write(int fd, const void *buf, unsigned count); +int stat(const char *file_name, struct stat *buf); +unsigned long lseek(int fildes, unsigned long offset, int whence); +#pragma aux lseek = \ + "mov ah, 0x42" \ + "int 0x21" \ + parm [bx] [dx cx] [ax] \ + value [dx ax]; + +#else +#include +/* #include */ +#endif + +#define FAR far +#include "kconfig.h" + +KernelConfig cfg; /* static memory zeroed automatically */ + +typedef unsigned char byte; +typedef signed char sbyte; +typedef unsigned short word; +typedef signed short sword; +typedef unsigned long dword; +typedef signed long sdword; + + +/* Displays command line syntax */ +void showUsage(void) +{ + printf("Usage: \n" + " %s \n" + " %s [/help | /?]\n" + " %s [ [drive:][path]%s] [option=value ...] \n", + PROGRAM, PROGRAM, PROGRAM, KERNEL); + printf("\n"); + printf(" If no options are given, the current values are shown.\n"); + printf(" /help or /? displays this usage information.\n" + " [drive:][path]KERNEL.SYS specifies the kernel file to\n" + " modify, if not given defaults to %s\n", KERNEL); + printf("\n"); + printf + (" option=value ... specifies one or more options and the values\n" + " to set each to. If an option is given multiple times,\n" + " the value set will be the rightmost one.\n"); + printf(" Current Options are: DLASORT=0|1, SHOWDRIVEASSIGNMENT=0|1\n" + " SKIPCONFIGSECONDS=#, FORCELBA=0|1\n" + " GLOBALENABLELBASUPPORT=0|1\n" + " BootHarddiskSeconds=0|seconds to wait\n"); +} + +/* simply reads in current configuration values, exiting program + with an error message and error code unable to, otherwise + cfg & kfile are valid on return. +*/ + +/* Reads in the current kernel configuration settings, + return 0 on success, nonzero on error. If there was + an actual error the return value is positive, if there + were no errors, but the CONFIG section was not found + then a negative value is returned. cfg is only altered + if the return value is 0 (ie successfully found and + read in the config section). The position of the file + pointer on input does not matter, the file position + upon return may be anywhere. The memory allocated for + cfg should be freed to prevent memory leakage (it should + not point to allocated memory on entry, as that memory + will not be used, and will likely not be freed as a result). +*/ +int readConfigSettings(int kfile, char *kfilename, KernelConfig * cfg) +{ + /* Seek to start of kernel file */ + if (lseek(kfile, 2, SEEK_SET) != 2) + printf("can't seek to offset 2\n"), exit(1); + + if (read(kfile, cfg, sizeof(KernelConfig)) != sizeof(KernelConfig)) + printf("can't read %u bytes\n", sizeof(KernelConfig)), exit(1); + + if (memcmp(cfg->CONFIG, "CONFIG", 6) != 0) + { + printf("Error: no CONFIG section found in kernel file <%s>\n", + kfilename); + printf("Only FreeDOS kernels after 2025 contain a CONFIG section!\n"); + exit(1); + } + + return 1; +} + +/* Writes config values out to file. + Returns 0 on success, nonzero on error. +*/ +int writeConfigSettings(int kfile, KernelConfig * cfg) +{ + /* Seek to CONFIG section at start of options of kernel file */ + if (lseek(kfile, 2, SEEK_SET) != 2) + return 1; + + /* Write just the config option information out */ + if (write(kfile, cfg, sizeof(KernelConfig)) != sizeof(KernelConfig)) + return 1; + + /* successfully wrote out kernel config data */ + return 0; +} + +/* Displays kernel configuration information */ +void displayConfigSettings(KernelConfig * cfg) +{ + /* print known options and current value - only if available */ + + if (cfg->ConfigSize >= 1) + { + printf + ("DLASORT=0x%02X Sort disks by drive order: *0=no, 1=yes\n", + cfg->DLASortByDriveNo); + } + + if (cfg->ConfigSize >= 2) + { + printf + ("SHOWDRIVEASSIGNMENT=0x%02X Show how drives assigned: *1=yes 0=no\n", + cfg->InitDiskShowDriveAssignment); + } + + if (cfg->ConfigSize >= 3) + { + printf + ("SKIPCONFIGSECONDS=%-3d time to wait for F5/F8 : *2 sec (skip < 0)\n", + cfg->SkipConfigSeconds); + } + + if (cfg->ConfigSize >= 4) + { + printf + ("FORCELBA=0x%02X Always use LBA if possible: *0=no, 1=yes\n", + cfg->ForceLBA); + } + + if (cfg->ConfigSize >= 5) + { + printf + ("GLOBALENABLELBASUPPORT=0x%02X Enable LBA support: *1=yes, 0=no\n", + cfg->GlobalEnableLBAsupport); + } + + if (cfg->ConfigSize >= 6) + { + printf + ("BootHarddiskSeconds=%d : *0=no else seconds to wait for key\n", + cfg->BootHarddiskSeconds); + } + +#if 0 /* we assume that SYS is as current as the kernel */ + + /* Print value any options added that are unknown as hex dump */ + if (cfg->configHdr.configSize > sizeof(ConfigData)) + { + printf("Additional options are available, they are not currently\n" + "supported by this tool. The current extra values are (in Hex):\n"); + for (i = 0; i < (cfg->configSize - sizeof(ConfigData)); i++) + { + if ((i % 32) == 0) + printf("\n"); + else if ((i % 4) == 0) + printf(" "); + printf("%02X", (unsigned int)cfg->extra[i]); + } + printf("\n"); + } +#endif + printf("\n"); +} + +/* Note: The setXXXOption functions will set the config option of + type XXX to the value given. It will display a warning, but + allow probably invalid values to be used (cause I believe in + letting the user do what they want, not what we guess they mean). + Additionally, we only indicate a change if a new value is used, + to force changes written even if same value is used, use same + option twice, first with a different value & second time with + (same) value desired. kjd +*/ + +/* Sets the given location to an unsigned byte value if different, + displays warning if values exceeds max +*/ +void setByteOption(byte * option, char *value, word max, int *updated, + char *name) +{ + unsigned long optionValue; + + /* optionValue = atoi(value); Use strtoul instead of atoi/atol as it detect base (0xFF & 255) */ + optionValue = strtoul(value, NULL, 0); + + if (optionValue > 255) + { + printf("Warning: Option %s: Value <0x%02lX> will be truncated!\n", + name, optionValue); + } + if ((byte) optionValue > max) + { + printf("Warning: Option %s: Value <0x%02X> may be invalid!\n", + name, (unsigned int)((byte) optionValue)); + } + /* Don't bother updating if same value */ + if ((byte) optionValue != *option) + { + *option = (byte) optionValue; + *updated = 1; + } +} + +/* Sets the given location to a signed byte value if different, + displays warning if values exceeds max or is less than min +*/ +void setSByteOption(sbyte * option, char *value, sword min, sword max, + int *updated, char *name) +{ + signed long optionValue; + + /* optionValue = atoi(value); Use strtol instead of atoi/atol as it detects base */ + optionValue = strtol(value, NULL, 0); + + if ((optionValue < -128) || (optionValue > 127)) + { + printf("Warning: Option %s: Value <0x%02lX> will be truncated!\n", + name, optionValue); + } + if (((sbyte) optionValue > max) || ((sbyte) optionValue < min)) + { + printf("Warning: Option %s: Value <0x%02X> may be invalid!\n", + name, (signed int)((byte) optionValue)); + } + /* Don't bother updating if same value */ + if ((sbyte) optionValue != *option) + { + *option = (sbyte) optionValue; + *updated = 1; + } +} + +#if 0 /* disable until there are (un)signed word configuration values */ +/* Sets the given location to an unsigned word value if different, + displays warning if values exceeds max +*/ +void setWordOption(word * option, char *value, dword max, int *updated, + char *name) +{ + unsigned long optionValue; + + /* optionValue = atol(value); Use strtoul instead of atoi/atol as it allows 0xFF and 255 */ + optionValue = strtoul(value, NULL, 0); + + if (optionValue > 65535) + { + printf("Warning: Option %s: Value <0x%02lX> will be truncated!\n", + name, optionValue); + } + if ((word) optionValue > max) + { + printf("Warning: Option %s: Value <0x%02X> may be invalid!\n", + name, (unsigned int)optionValue); + } + /* Don't bother updating if same value */ + if ((word) optionValue != *option) + { + *option = (word) optionValue; + *updated = 1; + } +} + +/* Sets the given location to a signed byte value if different, + displays warning if values exceeds max or is less than min +*/ +void setSWordOption(sword * option, char *value, sdword min, sdword max, + int *updated, char *name) +{ + signed long optionValue; + + /* optionValue = atol(value); Use strtol instead of atoi/atol as it allows 0xFF and 255 */ + optionValue = strtol(value, NULL, 0); + + if ((optionValue < -32768) || (optionValue > 32767)) + { + printf("Warning: Option %s: Value <0x%02lX> will be truncated!\n", + name, optionValue); + } + + if (((sword) optionValue > max) || ((sword) optionValue < min)) + { + printf("Warning: Option %s: Value <0x%02X> may be invalid!\n", + name, (signed int)optionValue); + } + /* Don't bother updating if same value */ + if ((sword) optionValue != *option) + { + *option = (sword) optionValue; + *updated = 1; + } +} +#endif + +/* Main, processes command line options and calls above + functions as required. +*/ +int FDKrnConfigMain(int argc, char **argv) +{ + char *kfilename = KERNEL; + int kfile; + int updates = 0; /* flag used to indicate if we need to update kernel */ + int argstart, i; + char *cptr; + char *argptr; + + printf("FreeDOS Kernel Configuration %s\n", VERSION); + + /* 1st go through and just process arguments (help/filename/etc) */ + for (i = 2; i < argc; i++) + { + argptr = argv[i]; + + /* is it an argument or an option specifier */ + if (argptr[0] == '-' || argptr[0] == '/') + { + switch (argptr[1]) + { + case 'H': + case 'h': + case '?': + showUsage(); + exit(0); + + default: + printf("Invalid argument found <%s>.\nUse %s /help for usage.\n", + argptr, PROGRAM); + exit(1); + } + } + } + + argstart = 2; + + argptr = argv[argstart]; + +#if 0 /* No arguments is acceptable, just displays current settings using default kernel file */ + if (argptr == 0) + { + showUsage(); + exit(1); + } +#endif + + /* the first argument may be the kernel name */ + if ((argstart < argc) && (strchr(argptr, '=') == NULL)) + { + kfilename = argptr; + argstart++; + } + + kfile = open(kfilename, O_RDWR | O_BINARY); + + if (kfile < 0) + printf("Error: unable to open kernel file <%s>\n", kfilename), exit(1); + + /* now that we know the filename (default or given) get config info */ + readConfigSettings(kfile, kfilename, &cfg); + + for (i = argstart; i < argc; i++) + { + argptr = argv[i]; + + if ((cptr = strchr(argptr, '=')) == NULL) + goto illegal_arg; + + /* split argptr into 2 pieces and make cptr point to 2nd one */ + *cptr = '\0'; + cptr++; + + /* allow 3 valid characters */ + if (memicmp(argptr, "DLASORT", 3) == 0) + { + setByteOption(&(cfg.DLASortByDriveNo), cptr, 1, &updates, "DLASORT"); + } + else if (memicmp(argptr, "SHOWDRIVEASSIGNMENT", 3) == 0) + { + setByteOption(&(cfg.InitDiskShowDriveAssignment), + cptr, 1, &updates, "SHOWDRIVEASSIGNMENT"); + } + else if (memicmp(argptr, "SKIPCONFIGSECONDS", 3) == 0) + { + setSByteOption(&(cfg.SkipConfigSeconds), + cptr, -128, 127, &updates, "SKIPCONFIGSECONDS"); + } + else if (memicmp(argptr, "FORCELBA", 3) == 0) + { + setByteOption(&(cfg.ForceLBA), cptr, 1, &updates, "FORCELBA"); + } + else if (memicmp(argptr, "GLOBALENABLELBASUPPORT", 3) == 0) + { + setByteOption(&(cfg.GlobalEnableLBAsupport), + cptr, 1, &updates, "GLOBALENABLELBASUPPORT"); + } + else if (memicmp(argptr, "BootHarddiskSeconds", 3) == 0) + { + setSByteOption(&(cfg.BootHarddiskSeconds), + cptr, 0, 127, &updates, "BootHarddiskSeconds"); + } + else + { + illegal_arg: + printf("Unknown option found <%s>.\nUse %s /help for usage.\n", + argptr, PROGRAM); + exit(1); + } + } + + /* write out new config values if modified */ + if (updates) + { + /* update it */ + if (writeConfigSettings(kfile, &cfg)) + { + printf("Error: Unable to write configuration changes to kernel!\n"); + printf(" <%s>\n", kfilename); + close(kfile); + exit(1); + } + + /* display new settings */ + printf("\nUpdated Kernel settings.\n"); + } + else + printf("\nCurrent Kernel settings.\n"); + + /* display current settings */ + displayConfigSettings(&cfg); + + /* and done */ + close(kfile); + + return 0; +} diff --git a/sys/makefile b/sys/makefile new file mode 100644 index 0000000..9cf3812 --- /dev/null +++ b/sys/makefile @@ -0,0 +1,66 @@ +# +# makefile for bin2c.com and sys.com +# +# $Id: makefile 1482 2009-07-11 16:59:43Z perditionc $ +# + +!include "../mkfiles/generic.mak" + +CFLAGS = -I$(INCLUDEPATH) -I..$(DIRSEP)hdr -DFORSYS -DWITHFAT32 $(CFLAGST) +NASMFLAGS = -DSYS=1 + +# *List Macros* + +SYS_EXE_dependencies = \ + sys.obj \ + fdkrncfg.obj \ + prf.obj \ + talloc.obj + +# *Explicit Rules* +production: bin2c.com ../bin/sys.com + +bin2c.com: bin2c.c + $(CLT) bin2c.c + +../bin/sys.com: sys.com + $(CP) sys.com ..$(DIRSEP)bin + +fat12com.h: ../boot/fat12com.bin bin2c.com + .$(DIRSEP)bin2c.com ../boot/fat12com.bin fat12com.h fat12com + +fat16com.h: ../boot/fat16com.bin bin2c.com + .$(DIRSEP)bin2c.com ../boot/fat16com.bin fat16com.h fat16com + +fat32chs.h: ../boot/fat32chs.bin bin2c.com + .$(DIRSEP)bin2c.com ../boot/fat32chs.bin fat32chs.h fat32chs + +fat32lba.h: ../boot/fat32lba.bin bin2c.com + .$(DIRSEP)bin2c.com ../boot/fat32lba.bin fat32lba.h fat32lba + +oemfat12.h: ../boot/oemfat12.bin bin2c.com + .$(DIRSEP)bin2c.com ../boot/oemfat12.bin oemfat12.h oemfat12 + +oemfat16.h: ../boot/oemfat16.bin bin2c.com + .$(DIRSEP)bin2c.com ../boot/oemfat16.bin oemfat16.h oemfat16 + +prf.obj: ../kernel/prf.c + $(CC) $(CFLAGS) ..$(DIRSEP)kernel$(DIRSEP)prf.c + +fdkrncfg.obj: fdkrncfg.c ../hdr/kconfig.h + +talloc.obj: talloc.c + +sys.com: $(SYS_EXE_dependencies) + $(CL) $(CFLAGST) $(TINY) $(SYS_EXE_dependencies) + +clobber: clean + -$(RM) bin2c.com sys.com fat*.h oemfat*.h + +clean: + -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.las *.cod *.err status.me + +# *Individual File Dependencies* +sys.obj: sys.c ../hdr/portab.h ../hdr/device.h fat12com.h fat16com.h fat32chs.h fat32lba.h oemfat12.h oemfat16.h + $(CC) $(CFLAGS) $*.c + diff --git a/sys/sys.c b/sys/sys.c new file mode 100644 index 0000000..f8758bf --- /dev/null +++ b/sys/sys.c @@ -0,0 +1,1894 @@ +/*************************************************************** + + sys.c + DOS-C + + sys utility for DOS-C + + Copyright (c) 1991 + 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 DEBUG */ /* to display extra information */ +/* #define DDEBUG */ /* to enable display of sector dumps */ +/* #define WITHOEMCOMPATBS */ /* include support for OEM MS/PC DOS 3.??-6.x */ +#define FDCONFIG /* include support to configure FD kernel */ +/* #define DRSYS */ /* SYS for Enhanced DR-DOS (OpenDOS enhancement Project) */ + +#define SYS_VERSION "v3.6e" +#define SYS_NAME "FreeDOS System Installer " + + +#ifdef DRSYS /* set displayed name & drop FD kernel config */ +#undef SYS_NAME +#define SYS_NAME "Enhanced DR-DOS System Installer " +#ifdef FDCONFIG +#undef FDCONFIG +#endif +#ifdef WITHOEMCOMPATBS +#undef WITHOEMCOMPATBS +#endif +#endif + +#include +#include +#include +#include +#include +#ifdef __TURBOC__ +#include +#else +#include +#endif +#include +#ifdef __TURBOC__ +#include +#endif +#define SYS_MAXPATH 260 +#include "portab.h" +#include "algnbyte.h" +#include "device.h" +#include "dcb.h" +#include "xstructs.h" +#include "date.h" +#include "../hdr/time.h" +#include "fat.h" + +/* These definitions deliberately put here instead of + * #including to make executable MUCH smaller + * using [s]printf from prf.c! + */ +extern int VA_CDECL printf(CONST char * fmt, ...); +extern int VA_CDECL sprintf(char * buff, CONST char * fmt, ...); + +#include "fat12com.h" +#include "fat16com.h" +#ifdef WITHFAT32 +#include "fat32chs.h" +#include "fat32lba.h" +#endif +#ifdef WITHOEMCOMPATBS +#include "oemfat12.h" +#include "oemfat16.h" +#endif + +#ifndef __WATCOMC__ + +#include + +/* returns current DOS drive, A=0, B=1,C=2, ... */ +#ifdef __TURBOC__ +#define getcurdrive (unsigned)getdisk +#else +unsigned getcurdrive(void) +{ + union REGS regs; + regs.h.ah = 0x19; + int86(0x21, ®s, ®s); + return regs.h.al; +} +#endif + +#else + +/* returns current DOS drive, A=0, B=1,C=2, ... */ +unsigned getcurdrive(void); +#pragma aux getcurdrive = \ + "mov ah, 0x19" \ + "int 0x21" \ + "xor ah, ah" \ + value [ax]; + + +long filelength(int __handle); +#pragma aux filelength = \ + "mov ax, 0x4202" \ + "xor cx, cx" \ + "xor dx, dx" \ + "int 0x21" \ + "push ax" \ + "push dx" \ + "mov ax, 0x4200" \ + "xor cx, cx" \ + "xor dx, dx" \ + "int 0x21" \ + "pop dx" \ + "pop ax" \ + parm [bx] \ + modify [cx] \ + value [dx ax]; + +extern int unlink(const char *pathname); + +/* some non-conforming functions to make the executable smaller */ +int open(const char *pathname, int flags, ...) +{ + int handle; + int result = (flags & O_CREAT ? + _dos_creat(pathname, _A_NORMAL, &handle) : + _dos_open(pathname, flags & (O_RDONLY | O_WRONLY | O_RDWR), + &handle)); + + return (result == 0 ? handle : -1); +} + +int read(int fd, void *buf, unsigned count) +{ + unsigned bytes; + int result = _dos_read(fd, buf, count, &bytes); + + return (result == 0 ? bytes : -1); +} + +int write(int fd, const void *buf, unsigned count) +{ + unsigned bytes; + int result = _dos_write(fd, buf, count, &bytes); + + return (result == 0 ? bytes : -1); +} + +#define close _dos_close + +int stat(const char *file_name, struct stat *statbuf) +{ + struct find_t find_tbuf; + + int ret = _dos_findfirst(file_name, _A_NORMAL | _A_HIDDEN | _A_SYSTEM, &find_tbuf); + statbuf->st_size = (off_t)find_tbuf.size; + /* statbuf->st_attr = (ULONG)find_tbuf.attrib; */ + return ret; +} + +/* WATCOM's getenv is case-insensitive which wastes a lot of space + for our purposes. So here's a simple case-sensitive one */ +char *getenv(const char *name) +{ + char **envp, *ep; + const char *np; + char ec, nc; + + for (envp = environ; (ep = *envp) != NULL; envp++) { + np = name; + do { + ec = *ep++; + nc = *np++; + if (nc == 0) { + if (ec == '=') + return ep; + break; + } + } while (ec == nc); + } + return NULL; +} +#endif + + +BYTE pgm[] = "SYS"; + +#define SEC_SIZE 512 +#define COPY_SIZE 0x4000 + +struct bootsectortype { + UBYTE bsJump[3]; + char OemName[8]; + UWORD bsBytesPerSec; + UBYTE bsSecPerClust; + UWORD bsResSectors; + UBYTE bsFATs; + UWORD bsRootDirEnts; + UWORD bsSectors; + UBYTE bsMedia; + UWORD bsFATsecs; + UWORD bsSecPerTrack; + UWORD bsHeads; + ULONG bsHiddenSecs; + ULONG bsHugeSectors; + UBYTE bsDriveNumber; + UBYTE bsReserved1; + UBYTE bsBootSignature; + ULONG bsVolumeID; + char bsVolumeLabel[11]; + char bsFileSysType[8]; +}; + +struct bootsectortype32 { + UBYTE bsJump[3]; + char OemName[8]; + UWORD bsBytesPerSec; + UBYTE bsSecPerClust; + UWORD bsResSectors; + UBYTE bsFATs; + UWORD bsRootDirEnts; + UWORD bsSectors; + UBYTE bsMedia; + UWORD bsFATsecs; + UWORD bsSecPerTrack; + UWORD bsHeads; + ULONG bsHiddenSecs; + ULONG bsHugeSectors; + ULONG bsBigFatSize; + UBYTE bsFlags; + UBYTE bsMajorVersion; + UWORD bsMinorVersion; + ULONG bsRootCluster; + UWORD bsFSInfoSector; + UWORD bsBackupBoot; + ULONG bsReserved2[3]; + UBYTE bsDriveNumber; + UBYTE bsReserved3; + UBYTE bsExtendedSignature; + ULONG bsSerialNumber; + char bsVolumeLabel[11]; + char bsFileSystemID[8]; +}; + +/* + * globals needed by put_boot & check_space + */ +enum {FAT12 = 12, FAT16 = 16, FAT32 = 32} fs; /* file system type */ +/* static */ struct xfreespace x; /* we make this static to be 0 by default - + this avoids FAT misdetections */ + +#define SBOFFSET 11 +#define SBSIZE (sizeof(struct bootsectortype) - SBOFFSET) +#define SBSIZE32 (sizeof(struct bootsectortype32) - SBOFFSET) + +/* essentially - verify alignment on byte boundaries at compile time */ +struct VerifyBootSectorSize { + char failure1[sizeof(struct bootsectortype) == 62 ? 1 : -1]; + char failure2[sizeof(struct bootsectortype) == 62 ? 1 : 0]; +/* (Watcom has a nice warning for this, by the way) */ +}; + +#ifdef FDCONFIG +int FDKrnConfigMain(int argc, char **argv); +#endif + +/* FreeDOS sys, we default to our kernel and load segment, but + if not found (or explicitly given) support OEM DOS variants + (such as DR-DOS or a FreeDOS kernel mimicing other DOSes). + Note: other (especially older) DOS versions expect the boot + loader to perform particular steps, which we may not do; + older PC/MS DOS variants may work with the OEM compatible + boot sector (optionally included). +*/ +typedef struct DOSBootFiles { + const char * kernel; /* filename boot sector loads and chains to */ + const char * dos; /* optional secondary file for OS */ + WORD loadaddr; /* segment kernel file expects to start at for stdbs */ + /* or offset to jump into kernel for oem compat bs */ + BOOL stdbs; /* use FD boot sector (T) or oem compat one (F) */ + LONG minsize; /* smallest dos file can be and be valid, 0=existance optional */ +} DOSBootFiles; +#define FREEDOS_FILES { "KERNEL.SYS", NULL, 0x60/*:0*/, 1, 0 }, +DOSBootFiles bootFiles[] = { + /* Note: This order is the order OEM:AUTO uses to determine DOS flavor. */ +#ifndef DRSYS + /* FreeDOS */ FREEDOS_FILES +#endif + /* DR-DOS */ { "DRBIO.SYS", "DRDOS.SYS", 0x70/*:0*/, 1, 1 }, + /* DR-DOS */ { "IBMBIO.COM", "IBMDOS.COM", 0x70/*:0*/, 1, 1 }, +#ifdef DRSYS + /* FreeDOS */ FREEDOS_FILES +#endif +#ifdef WITHOEMCOMPATBS + /* PC-DOS */ { "IBMBIO.COM", "IBMDOS.COM", /*0x70:*/0x0, 0, 6138 }, /* pre v7 DR ??? */ + /* MS-DOS */ { "IO.SYS", "MSDOS.SYS", /*0x70:*/0x0, 0, 10240 }, + /* W9x-DOS */ { "IO.SYS", "MSDOS.SYS", /*0x70:*/0x0200, 0, 0 }, + /* Rx-DOS */ { "RXDOSBIO.SYS", "RXDOS.SYS", /*0x70:*/0x0, 0, 1 }, +#endif +}; +#define DOSFLAVORS (sizeof(bootFiles) / sizeof(*bootFiles)) + +/* associate friendly name with index into bootFiles array */ +#define OEM_AUTO (-1) /* attempt to guess DOS on source drive */ +#ifndef DRSYS +#define OEM_FD 0 /* standard FreeDOS mode */ +#define OEM_EDR 1 /* use FreeDOS boot sector, but OEM names */ +#define OEM_DR 2 /* FD boot sector,(Enhanced) DR-DOS names */ +#else +#define OEM_FD 2 /* standard FreeDOS mode */ +#define OEM_EDR 0 /* use FreeDOS boot sector, but OEM names */ +#define OEM_DR 1 /* FD boot sector,(Enhanced) DR-DOS names */ +#endif +#ifdef WITHOEMCOMPATBS +#define OEM_PC 3 /* use PC-DOS compatible boot sector and names */ +#define OEM_MS 4 /* use PC-DOS compatible BS with MS names */ +#define OEM_W9x 5 /* use PC-DOS compatible BS with MS names */ +#define OEM_RX 6 /* use PC-DOS compatible BS with Rx names */ +#endif + +CONST char * msgDOS[DOSFLAVORS] = { /* order should match above items */ + "\n", /* In standard FreeDOS/EnhancedDR mode, don't print anything special */ +#ifndef DRSYS + "Enhanced DR DOS (OpenDOS Enhancement Project) mode\n", +#endif + "DR DOS (OpenDOS Enhancement Project) mode\n", +#ifdef DRSYS + "\n", /* FreeDOS mode so don't print anything special */ +#endif +#ifdef WITHOEMCOMPATBS + "PC-DOS compatibility mode\n", + "MS-DOS compatibility mode\n", + "Win9x DOS compatibility mode\n", + "RxDOS compatibility mode\n", +#endif +}; + +typedef struct SYSOptions { + BYTE srcDrive[SYS_MAXPATH]; /* source drive:[path], root assumed if no path */ + BYTE dstDrive; /* destination drive [STD SYS option] */ + int flavor; /* DOS variant we want to boot, default is AUTO/FD */ + DOSBootFiles kernel; /* file name(s) and relevant data for kernel */ + BYTE defBootDrive; /* value stored in boot sector for drive, eg 0x0=A, 0x80=C */ + BOOL ignoreBIOS; /* true to NOP out boot sector code to get drive# from BIOS */ + BOOL skipBakBSCopy; /* true to not copy boot sector to backup boot sector */ + BOOL copyKernel; /* true to copy kernel files */ + BOOL copyShell; /* true to copy command interpreter */ + BOOL writeBS; /* true to write boot sector to drive/partition LBA 0 */ + BYTE *bsFile; /* file name & path to save bs to when saving to file */ + BYTE *bsFileOrig; /* file name & path to save original bs when backing up */ + BYTE *fnKernel; /* optional override to source kernel filename (src only) */ + BYTE *fnCmd; /* optional override to cmd interpreter filename (src & dest) */ + enum {AUTO=0,LBA,CHS} force; /* optional force boot sector to only use LBA or CHS */ + BOOL verbose; /* show extra (DEBUG) output */ +} SYSOptions; + +void dumpBS(const char *, int); +void restoreBS(const char *, int); +void put_boot(SYSOptions *opts); +BOOL check_space(COUNT, ULONG); +BOOL copy(const BYTE *source, COUNT drive, const BYTE * filename); + +void showHelpAndExit(void) +{ + printf( + "Usage: %s [source] drive: [bootsect] [{option}]\n" + " source = A:,B:,C:\\DOS\\,etc., or current directory if not given\n" + " drive = A,B,etc.\n" + " bootsect = name of 512-byte boot sector file image for drive:\n" + " to write to *instead* of real boot sector\n" + " {option} is one or more of the following:\n" + " /BOTH : write to *both* the real boot sector and the image file\n" + " /BOOTONLY: do *not* copy kernel / shell, only update boot sector or image\n" + " /UPDATE : copy kernel and update boot sector (do *not* copy shell)\n" + " /OEM : indicates boot sector, filenames, and load segment to use\n" + " /OEM:FD use FreeDOS compatible settings\n" + " /OEM:EDR use Enhanced DR DOS 7+ compatible settings\n" + " /OEM:DR use DR DOS 7+ compatible settings\n" +#ifdef WITHOEMCOMPATBS + " /OEM:PC use PC-DOS compatible settings\n" + " /OEM:MS use MS-DOS compatible settings\n" + " /OEM:W9x use MS Win9x DOS compatible settings\n" +#endif + " default is /OEM[:AUTO], select DOS based on existing files\n" + " /K name : name of kernel to use in boot sector instead of %s\n" + " /L segm : hex load segment to use in boot sector instead of %02x\n" + " /B btdrv : hex BIOS # of boot drive set in bs, 0=A:, 80=1st hd,...\n" + " /FORCE : override automatic selection of BIOS related settings\n" + " /FORCE:BSDRV use boot drive # set in bootsector\n" + " /FORCE:BIOSDRV use boot drive # provided by BIOS\n" + " /NOBAKBS : skips copying boot sector to backup bs, FAT32 only else ignored\n" +#ifdef FDCONFIG + "%s CONFIG /help\n" +#endif + /*SYS, KERNEL.SYS/DRBIO.SYS 0x60/0x70*/ + , pgm, bootFiles[0].kernel, bootFiles[0].loadaddr +#ifdef FDCONFIG + , pgm +#endif + ); + exit(1); +} + + +/* get and validate arguments */ +void initOptions(int argc, char *argv[], SYSOptions *opts) +{ + int argno; + int drivearg = 0; /* drive argument, position of 1st or 2nd non option */ + int srcarg = 0; /* nonzero if optional source argument */ + BYTE srcFile[SYS_MAXPATH]; /* full path+name of [kernel] file [to copy] */ + struct stat fstatbuf; + + /* initialize to defaults */ + memset(opts, 0, sizeof(SYSOptions)); + /* set srcDrive and dstDrive after processing args */ + opts->flavor = OEM_AUTO; /* attempt to detect DOS user wants to boot */ + opts->copyKernel = 1; /* actually copy the kernel and cmd interpreter to dstDrive */ + opts->copyShell = 1; + + /* cycle through processing cmd line arguments */ + for(argno = 1; argno < argc; argno++) + { + char *argp = argv[argno]; + + if (argp[0] == '/') /* optional switch */ + { + argp++; /* skip past the '/' character */ + + /* explicit request for base help/usage */ + if ((*argp == '?') || (memicmp(argp, "HELP", 4) == 0)) + { + showHelpAndExit(); + } + /* enable extra (DEBUG) output */ + else if (memicmp(argp, "VERBOSE", 7) == 0) + { + opts->verbose = 1; + } + /* write to *both* the real boot sector and the image file */ + else if (memicmp(argp, "BOTH", 4) == 0) + { + opts->writeBS = 1; /* note: if bs file omitted, then same as omitting /BOTH */ + } + /* do *not* copy kernel / shell, only update boot sector or image */ + else if (memicmp(argp, "BOOTONLY", 8) == 0) + { + opts->copyKernel = 0; + opts->copyShell = 0; + } + /* copy kernel and update boot sector (do *not* copy shell) */ + else if (memicmp(argp, "UPDATE", 6) == 0) + { + opts->copyKernel = 1; + opts->copyShell = 0; + } + /* indicates compatibility mode, fs, filenames, and load segment to use */ + else if (memicmp(argp, "OEM", 3) == 0) + { + argp += 3; + if (!*argp) + opts->flavor = OEM_AUTO; + else if (*argp == ':') + { + argp++; /* point to DR/PC/MS that follows */ + if (memicmp(argp, "AUTO", 4) == 0) + opts->flavor = OEM_AUTO; + else if (memicmp(argp, "EDR", 3) == 0) + opts->flavor = OEM_EDR; + else if (memicmp(argp, "DR", 2) == 0) + opts->flavor = OEM_DR; +#ifdef WITHOEMCOMPATBS + else if (memicmp(argp, "PC", 2) == 0) + opts->flavor = OEM_PC; + else if (memicmp(argp, "MS", 2) == 0) + opts->flavor = OEM_MS; + else if (memicmp(argp, "W9", 2) == 0) + opts->flavor = OEM_W9x; + else if (memicmp(argp, "RX", 2) == 0) + opts->flavor = OEM_RX; +#endif + else if (memicmp(argp, "FD", 2) == 0) + opts->flavor = OEM_FD; + else + { + printf("%s: unknown OEM qualifier %s\n", pgm, argp); + showHelpAndExit(); + } + } + else + { + printf("%s: unknown OEM qualifier %s\n", pgm, argp); + showHelpAndExit(); + } + } + /* override auto options */ + else if (memicmp(argp, "FORCE", 5) == 0) + { + argp += 5; + if (*argp == ':') + { + argp++; /* point to CHS/LBA/... that follows */ + + /* specify which BIOS access mode to use */ + if (memicmp(argp, "AUTO", 4) == 0) /* default */ + opts->force = AUTO; + else if (memicmp(argp, "CHS", 3) == 0) + opts->force = CHS; + else if (memicmp(argp, "LBA", 3) == 0) + opts->force = LBA; + + /* specify if BIOS or BOOTSECTOR provided boot drive # is to be used */ + else if (memicmp(argp, "BSDRV", 5) == 0) /* same as FORCEDRV */ + opts->ignoreBIOS = 1; + else if (memicmp(argp, "BIOSDRV", 7) == 0) /* always use BIOS passed */ + opts->ignoreBIOS = -1; + else + { + printf("%s: invalid FORCE qualifier %s\n", pgm, argp); + showHelpAndExit(); + } + } + else if (memicmp(argp, "DRV", 3) == 0) /* FORCEDRV */ + { + /* force use of drive # set in bs instead of BIOS boot value */ + /* deprecated, use FORCE:BSDRV */ + opts->ignoreBIOS = 1; + } + else + { + printf("%s: invalid FORCE qualifier %s\n", pgm, argp); + showHelpAndExit(); + } + } + /* skips copying boot sector to backup bs, FAT32 only else ignored */ + else if (memicmp(argp, "NOBAKBS", 7) == 0) + { + opts->skipBakBSCopy = 1; + } + else if (argno + 1 < argc) /* two part options, /SWITCH VALUE */ + { + argno++; + if (toupper(*argp) == 'K') /* set Kernel name */ + { + opts->kernel.kernel = argv[argno]; + } + else if (toupper(*argp) == 'L') /* set Load segment */ + { + opts->kernel.loadaddr = (WORD)strtol(argv[argno], NULL, 16); + } + else if (memicmp(argp, "B", 2) == 0) /* set boot drive # */ + { + opts->defBootDrive = (BYTE)strtol(argv[argno], NULL, 16); + } + /* options not documented by showHelpAndExit() */ + else if (memicmp(argp, "SKFN", 4) == 0) /* set KERNEL.SYS input file and /OEM:FD */ + { + opts->flavor = OEM_FD; + opts->fnKernel = argv[argno]; + } + else if (memicmp(argp, "SCFN", 4) == 0) /* sets COMMAND.COM input file */ + { + opts->fnCmd = argv[argno]; + } + else if (memicmp(argp, "BACKUPBS", 8) == 0) /* save current bs before overwriting */ + { + opts->bsFileOrig = argv[argno]; + } + else if (memicmp(argp, "DUMPBS", 6) == 0) /* save current bs and exit */ + { + if (drivearg) + dumpBS(argv[argno], (BYTE)(toupper(*(argv[drivearg])) - 'A')); + else + printf("%s: unspecified drive, unable to obtain boot sector\n", pgm); + exit(1); + } + else if (memicmp(argp, "RESTORBS", 8) == 0) /* overwrite bs and exit */ + { + if (drivearg) + restoreBS(argv[argno], (BYTE)(toupper(*(argv[drivearg])) - 'A')); + else + printf("%s: unspecified drive, unable to restore boot sector\n", pgm); + exit(1); + } + else + { + printf("%s: unknown option, %s\n", pgm, argv[argno]); + showHelpAndExit(); + } + } + else + { + printf("%s: unknown option or missing parameter, %s\n", pgm, argv[argno]); + showHelpAndExit(); + } + } + else if (!drivearg) + { + drivearg = argno; /* either source or destination drive */ + } + else if (!srcarg /* && drivearg */ && !opts->bsFile) + { + /* need to determine is user specified [source] dest or dest [bootfile] (or [source] dest [bootfile]) + - dest must be either X or X: as only a drive specifier without any path is valid - + if 1st arg not drive and 2nd is then [source] dest form + if 1st arg drive and 2nd is not drive then dest [bootfile] form + if both 1st arg and 2nd are not drives then invalid arguments + if both 1st arg and 2nd are drives then assume [source] dest form (use ./X form is single letter used) + */ + if (!argv[drivearg][1] || (argv[drivearg][1]==':' && !argv[drivearg][2])) /* if 1st arg drive */ + { + if (!argv[argno][1] || (argv[argno][1]==':' && !argv[argno][2])) /* if 2nd arg drive */ + { + srcarg = drivearg; /* set source path */ + drivearg = argno; /* set destination drive */ + } + else + { + opts->bsFile = argv[argno]; + } + } + else + { + if (!argv[argno][1] || (argv[argno][1]==':' && !argv[argno][2])) /* if 2nd arg drive */ + { + srcarg = drivearg; /* set source path */ + drivearg = argno; /* set destination drive */ + } + else + { + goto EXITBADARG; + } + } + } + else if (!opts->bsFile /* && srcarg && drivearg */) + { + opts->bsFile = argv[argno]; + } + else /* if (opts->bsFile && srcarg && drivearg) */ + { + EXITBADARG: + printf("%s: invalid argument %s\n", pgm, argv[argno]); + showHelpAndExit(); + } + } + + /* if neither BOTH nor a boot sector file specified, then write to boot record */ + if (!opts->bsFile) + opts->writeBS = 1; + + /* set dest path */ + if (!drivearg) + showHelpAndExit(); + opts->dstDrive = (BYTE)(toupper(*(argv[drivearg])) - 'A'); + if (/* (opts->dstDrive < 0) || */ (opts->dstDrive >= 26)) + { + printf("%s: drive %c must be A:..Z:\n", pgm, *(argv[drivearg])); + exit(1); + } + + /* set source path, default to current drive */ + sprintf(opts->srcDrive, "%c:", 'A' + getcurdrive()); + if (srcarg) + { + int slen; + /* set source path, reserving room to append filename */ + if ( (argv[srcarg][1] == ':') || ((argv[srcarg][0]=='\\') && (argv[srcarg][1] == '\\')) ) + strncpy(opts->srcDrive, argv[srcarg], SYS_MAXPATH-13); + else if (argv[srcarg][1] == '\0') /* assume 1 char is drive not path specifier */ + sprintf(opts->srcDrive, "%c:", toupper(*(argv[srcarg]))); + else /* only path provided, append to default drive */ + strncat(opts->srcDrive, argv[srcarg], SYS_MAXPATH-15); + slen = strlen(opts->srcDrive); + /* if path follows drive, ensure ends in a slash, ie X:-->X: or X:.\mypath-->X:.\mypath\ */ + if ((slen>2) && (opts->srcDrive[slen-1] != '\\') && (opts->srcDrive[slen-1] != '/')) + strcat(opts->srcDrive, "\\"); + } + /* source path is now in form of just a drive, "X:" + or form of drive + path + directory separator, "X:\path\" or "\\path\" + If just drive we try current path then root, else just indicated path. + */ + + + /* if source and dest are same drive, then source should not be root, + so if is same drive and not explicit path, force only current + Note: actual copy routine prevents overwriting self when src=dst + */ + if ( (opts->dstDrive == (toupper(*(opts->srcDrive))-'A')) && (!opts->srcDrive[2]) ) + strcat(opts->srcDrive, ".\\"); + + + /* attempt to detect compatibility settings user needs */ + if (opts->flavor == OEM_AUTO) + { + /* 1st loop checking current just source path provided */ + for (argno = 0; argno < DOSFLAVORS; argno++) + { + /* look for existing file matching kernel filename */ + sprintf(srcFile, "%s%s", opts->srcDrive, bootFiles[argno].kernel); + if (stat(srcFile, &fstatbuf)) continue; /* if !exists() try again */ + if (!fstatbuf.st_size) continue; /* file must not be empty */ + + /* now check if secondary file exists and of minimal size */ + if (bootFiles[argno].minsize) + { + sprintf(srcFile, "%s%s", opts->srcDrive, bootFiles[argno].dos); + if (stat(srcFile, &fstatbuf)) continue; + if (fstatbuf.st_size < bootFiles[argno].minsize) continue; + } + + /* above criteria succeeded, so default to corresponding DOS */ + opts->flavor = argno; + break; + } + + /* if no match, and source just drive, try root */ + if ( (opts->flavor == OEM_AUTO) && (!opts->srcDrive[2]) ) + { + for (argno = 0; argno < DOSFLAVORS; argno++) + { + /* look for existing file matching kernel filename */ + sprintf(srcFile, "%s\\%s", opts->srcDrive, bootFiles[argno].kernel); + if (stat(srcFile, &fstatbuf)) continue; /* if !exists() try again */ + if (!fstatbuf.st_size) continue; /* file must not be empty */ + + /* now check if secondary file exists and of minimal size */ + if (bootFiles[argno].minsize) + { + sprintf(srcFile, "%s\\%s", opts->srcDrive, bootFiles[argno].dos); + if (stat(srcFile, &fstatbuf)) continue; + if (fstatbuf.st_size < bootFiles[argno].minsize) continue; + } + + /* above criteria succeeded, so default to corresponding DOS */ + opts->flavor = argno; + strcat(opts->srcDrive, "\\"); /* indicate to use root from now on */ + break; + } + } + } + + /* if unable to determine DOS, assume FreeDOS */ + if (opts->flavor == OEM_AUTO) opts->flavor = +#ifdef DRSYS + OEM_EDR; +#else + OEM_FD; +#endif + + printf(msgDOS[opts->flavor]); + + /* set compatibility settings not explicitly set */ + if (!opts->kernel.kernel) opts->kernel.kernel = bootFiles[opts->flavor].kernel; + if (!opts->kernel.dos) opts->kernel.dos = bootFiles[opts->flavor].dos; + if (!opts->kernel.loadaddr) opts->kernel.loadaddr = bootFiles[opts->flavor].loadaddr; + opts->kernel.stdbs = bootFiles[opts->flavor].stdbs; + opts->kernel.minsize = bootFiles[opts->flavor].minsize; + + + /* did user insist on always using BIOS provided drive # */ + if (opts->ignoreBIOS == -1) + opts->ignoreBIOS = 0; /* its really a boolean value in rest of code */ + /* if destination is floppy (A: or B:) then use drive # stored in boot sector */ + else if (opts->dstDrive < 2) + opts->ignoreBIOS = 1; + + /* if bios drive to store in boot sector not set and not floppy set to 1st hd */ + if (!opts->defBootDrive && (opts->dstDrive >= 2)) + opts->defBootDrive = 0x80; + /* else opts->defBootDrive = 0x0; the 1st floppy */ + + + /* unless we are only setting boot sector, verify kernel file exists */ + if (opts->copyKernel) + { + /* check kernel (primary file) 1st */ + sprintf(srcFile, "%s%s", opts->srcDrive, (opts->fnKernel)?opts->fnKernel:opts->kernel.kernel); + if (stat(srcFile, &fstatbuf)) /* if !exists() */ + { + /* check root path as well if src is drive only */ + sprintf(srcFile, "%s\\%s", opts->srcDrive, (opts->fnKernel)?opts->fnKernel:opts->kernel.kernel); + if (opts->srcDrive[2] || stat(srcFile, &fstatbuf)) + { + printf("%s: failed to find kernel file %s\n", pgm, (opts->fnKernel)?opts->fnKernel:opts->kernel.kernel); + exit(1); + } + /* else found, but in root, so force to always use root */ + strcat(opts->srcDrive, "\\"); + } + + /* now check for secondary file */ + if (opts->kernel.dos && opts->kernel.minsize) + { + sprintf(srcFile, "%s%s", opts->srcDrive, opts->kernel.dos); + if (stat(srcFile, &fstatbuf)) + { + printf("%s: failed to find source file %s\n", pgm, opts->kernel.dos); + exit(1); + } + if (fstatbuf.st_size < opts->kernel.minsize) + { + printf("%s: source file %s appears corrupt, invalid size\n", pgm, opts->kernel.dos); + exit(1); + } + } + } + + /* if updating or only setting bootsector then skip this check */ + if (opts->copyShell) + { + /* lastly check for command interpreter */ + sprintf(srcFile, "%s%s", opts->srcDrive, (opts->fnCmd)?opts->fnCmd:"COMMAND.COM"); + if (stat(srcFile, &fstatbuf)) /* if !exists() */ + { + char *comspec = getenv("COMSPEC"); + if (opts->fnCmd || (comspec == NULL) || stat(comspec, &fstatbuf)) + { + printf("%s: failed to find command interpreter (shell) file %s\n", pgm, srcFile); + exit(1); + } + } + } +} + +int main(int argc, char **argv) +{ + SYSOptions opts; /* boot options and other flags */ + BYTE srcFile[SYS_MAXPATH]; /* full path+name of [kernel] file [to copy] */ + + printf(SYS_NAME SYS_VERSION ", " __DATE__ "\n"); + +#ifdef FDCONFIG + if (argc > 1 && memicmp(argv[1], "CONFIG", 6) == 0) + { + exit(FDKrnConfigMain(argc, argv)); + } +#endif + + initOptions(argc, argv, &opts); + + printf("Processing boot sector...\n"); + put_boot(&opts); + + if (opts.copyKernel) + { + printf("Now copying system files...\n"); + + sprintf(srcFile, "%s%s", opts.srcDrive, (opts.fnKernel)?opts.fnKernel:opts.kernel.kernel); + if (!copy(srcFile, opts.dstDrive, opts.kernel.kernel)) + { + printf("%s: cannot copy \"%s\"\n", pgm, srcFile); + exit(1); + } /* copy kernel */ + + if (opts.kernel.dos) + { + sprintf(srcFile, "%s%s", opts.srcDrive, opts.kernel.dos); + if (!copy(srcFile, opts.dstDrive, opts.kernel.dos) && opts.kernel.minsize) + { + printf("%s: cannot copy \"%s\"\n", pgm, srcFile); + exit(1); + } /* copy secondary file (DOS) */ + } + } + + if (opts.copyShell) + { + printf("Copying shell (command interpreter)...\n"); + + /* copy command.com, 1st try source path, then try %COMSPEC% */ + sprintf(srcFile, "%s%s", opts.srcDrive, (opts.fnCmd)?opts.fnCmd:"COMMAND.COM"); + if (!copy(srcFile, opts.dstDrive, "COMMAND.COM")) + { + char *comspec = getenv("COMSPEC"); + if (!opts.fnCmd && (comspec != NULL)) + printf("%s: Trying shell from %%COMSPEC%%=\"%s\"\n", pgm, comspec); + if (opts.fnCmd || (comspec == NULL) || !copy(comspec, opts.dstDrive, "COMMAND.COM")) + { + printf("\n%s: failed to find command interpreter (shell) file %s\n", pgm, (opts.fnCmd)?opts.fnCmd:"COMMAND.COM"); + exit(1); + } + } /* copy shell */ + } + + printf("\nSystem transferred.\n"); + return 0; +} + +#ifdef DDEBUG +VOID dump_sector(unsigned char far * sec) +{ + COUNT x, y; + char c; + + for (x = 0; x < 32; x++) + { + printf("%03X ", x * 16); + for (y = 0; y < 16; y++) + { + printf("%02X ", sec[x * 16 + y]); + } + for (y = 0; y < 16; y++) + { + c = sec[x * 16 + y]; + if (isprint(c)) + printf("%c", c); + else + printf("."); + } + printf("\n"); + } + + printf("\n"); +} + +#endif + + +#ifdef __WATCOMC__ + +int absread(int DosDrive, int nsects, int foo, void *diskReadPacket); +#pragma aux absread = \ + "push bp" \ + "int 0x25" \ + "sbb ax, ax" \ + "popf" \ + "pop bp" \ + parm [ax] [cx] [dx] [bx] \ + modify [si di] \ + value [ax]; + +int abswrite(int DosDrive, int nsects, int foo, void *diskReadPacket); +#pragma aux abswrite = \ + "push bp" \ + "int 0x26" \ + "sbb ax, ax" \ + "popf" \ + "pop bp" \ + parm [ax] [cx] [dx] [bx] \ + modify [si di] \ + value [ax]; + +int fat32readwrite(int DosDrive, void *diskReadPacket, unsigned intno); +#pragma aux fat32readwrite = \ + "mov ax, 0x7305" \ + "mov cx, 0xffff" \ + "int 0x21" \ + "sbb ax, ax" \ + parm [dx] [bx] [si] \ + modify [cx dx si] \ + value [ax]; + +void reset_drive(int DosDrive); +#pragma aux reset_drive = \ + "push ds" \ + "inc dx" \ + "mov ah, 0xd" \ + "int 0x21" \ + "mov ah,0x32" \ + "int 0x21" \ + "pop ds" \ + parm [dx] \ + modify [ax bx]; + +void truename(char far *dest, const char *src); +#pragma aux truename = \ + "mov ah,0x60" \ + "int 0x21" \ + parm [es di] [si]; + +int generic_block_ioctl(unsigned drive, unsigned cx, unsigned char *par); +#pragma aux generic_block_ioctl = \ + "mov ax, 0x440d" \ + "int 0x21" \ + "sbb ax, ax" \ + value [ax] \ + parm [bx] [cx] [dx]; /* BH must be 0 for lock! */ + +#else + +#ifndef __TURBOC__ + +int2526readwrite(int DosDrive, void *diskReadPacket, unsigned intno) +{ + union REGS regs; + + regs.h.al = (BYTE) DosDrive; + regs.x.bx = (short)diskReadPacket; + regs.x.cx = 0xffff; + + int86(intno, ®s, ®s); + + return regs.x.cflag; +} + +#define absread(DosDrive, foo, cx, diskReadPacket) \ +int2526readwrite(DosDrive, diskReadPacket, 0x25) + +#define abswrite(DosDrive, foo, cx, diskReadPacket) \ +int2526readwrite(DosDrive, diskReadPacket, 0x26) + +#endif + +int fat32readwrite(int DosDrive, void *diskReadPacket, unsigned intno) +{ + union REGS regs; + + regs.x.ax = 0x7305; + regs.h.dl = DosDrive; + regs.x.bx = (short)diskReadPacket; + regs.x.cx = 0xffff; + regs.x.si = intno; + intdos(®s, ®s); + + return regs.x.cflag; +} /* fat32readwrite */ + +void reset_drive(int DosDrive) +{ + union REGS regs; + + regs.h.ah = 0xd; + intdos(®s, ®s); + regs.h.ah = 0x32; + regs.h.dl = DosDrive + 1; + intdos(®s, ®s); +} /* reset_drive */ + +int generic_block_ioctl(unsigned drive, unsigned cx, unsigned char *par) +{ + union REGS regs; + + regs.x.ax = 0x440d; + regs.x.cx = cx; + regs.x.dx = (unsigned)par; + regs.x.bx = drive; /* BH must be 0 for lock! */ + intdos(®s, ®s); + return regs.x.cflag; +} /* generic_block_ioctl */ + +void truename(char *dest, const char *src) +{ + union REGS regs; + struct SREGS sregs; + + regs.h.ah = 0x60; + sregs.es = FP_SEG(dest); + regs.x.di = FP_OFF(dest); + sregs.ds = FP_SEG(src); + regs.x.si = FP_OFF(src); + intdosx(®s, ®s, &sregs); +} /* truename */ + +#endif + +int MyAbsReadWrite(int DosDrive, int count, ULONG sector, void *buffer, + int write) +{ + struct { + unsigned long sectorNumber; + unsigned short count; + void far *address; + } diskReadPacket; + + diskReadPacket.sectorNumber = sector; + diskReadPacket.count = count; + diskReadPacket.address = buffer; + + if ((!write && absread(DosDrive, -1, -1, &diskReadPacket) == -1) + || (write && abswrite(DosDrive, -1, -1, &diskReadPacket) == -1)) + { +#ifdef WITHFAT32 + return fat32readwrite(DosDrive + 1, &diskReadPacket, write); +#else + return 0xff; +#endif + } + return 0; +} /* MyAbsReadWrite */ + +#ifdef __WATCOMC__ + +unsigned getextdrivespace(void far *drivename, void *buf, unsigned buf_size); +#pragma aux getextdrivespace = \ + "mov ax, 0x7303" \ + "stc" \ + "int 0x21" \ + "sbb ax, ax" \ + parm [es dx] [di] [cx] \ + value [ax]; + +#else /* !defined __WATCOMC__ */ + +unsigned getextdrivespace(void *drivename, void *buf, unsigned buf_size) +{ + union REGS regs; + struct SREGS sregs; + + regs.x.ax = 0x7303; /* get extended drive free space */ + + sregs.es = FP_SEG(buf); + regs.x.di = FP_OFF(buf); + sregs.ds = FP_SEG(drivename); + regs.x.dx = FP_OFF(drivename); + + regs.x.cx = buf_size; + + intdosx(®s, ®s, &sregs); + return regs.x.ax == 0x7300 || regs.x.cflag; +} /* getextdrivespace */ + +#endif /* defined __WATCOMC__ */ + +#ifdef __WATCOMC__ +/* + * If BIOS has got LBA extensions, after the Int 13h call BX will be 0xAA55. + * If extended disk access functions are supported, bit 0 of CX will be set. + */ +BOOL haveLBA(void); /* return TRUE if we have LBA BIOS, FALSE otherwise */ +#pragma aux haveLBA = \ + "mov ax, 0x4100" /* IBM/MS Int 13h Extensions - installation check */ \ + "mov bx, 0x55AA" \ + "mov dl, 0x80" \ + "int 0x13" \ + "xor ax, ax" \ + "cmp bx, 0xAA55" \ + "jne quit" \ + "and cx, 1" \ + "xchg cx, ax" \ +"quit:" \ + modify [bx cx dx] \ + value [ax]; +#else + +BOOL haveLBA(void) +{ + union REGS r; + r.x.ax = 0x4100; + r.x.bx = 0x55AA; + r.h.dl = 0x80; + int86(0x13, &r, &r); + return r.x.bx == 0xAA55 && r.x.cx & 1; +} +#endif + +void correct_bpb(struct bootsectortype *default_bpb, + struct bootsectortype *oldboot, BOOL verbose) +{ + /* don't touch partitions (floppies most likely) that don't have hidden + sectors */ + if (default_bpb->bsHiddenSecs == 0) + return; + + if (verbose) + { + printf("Old boot sector values: sectors/track: %u, heads: %u, hidden: %lu\n", + oldboot->bsSecPerTrack, oldboot->bsHeads, oldboot->bsHiddenSecs); + printf("Default and new boot sector values: sectors/track: %u, heads: %u, " + "hidden: %lu\n", default_bpb->bsSecPerTrack, default_bpb->bsHeads, + default_bpb->bsHiddenSecs); + } + + oldboot->bsSecPerTrack = default_bpb->bsSecPerTrack; + oldboot->bsHeads = default_bpb->bsHeads; + oldboot->bsHiddenSecs = default_bpb->bsHiddenSecs; +} + + +/* reads in boot sector (1st SEC_SIZE bytes) from file */ +void readBS(const char *bsFile, UBYTE *bootsector) +{ + if (bsFile != NULL) + { + int fd; + +#ifdef DEBUG + printf("reading bootsector from file %s\n", bsFile); +#endif + + /* open boot sector file, it must exists, then overwrite + drive with 1st SEC_SIZE bytes from the [image] file + */ + if ((fd = open(bsFile, O_RDONLY | O_BINARY)) < 0) + { + printf("%s: can't open\"%s\"\nDOS errnum %d", pgm, bsFile, errno); + exit(1); + } + if (read(fd, bootsector, SEC_SIZE) != SEC_SIZE) + { + printf("%s: failed to read %u bytes from %s\n", pgm, SEC_SIZE, bsFile); + close(fd); + exit(1); + } + close(fd); + } +} + +/* write bs in bsFile to drive's boot record unmodified */ +void restoreBS(const char *bsFile, int drive) +{ + UBYTE bootsector[SEC_SIZE]; + + if (bsFile == NULL) + { + printf("%s: missing filename of boot sector to restore\n", pgm); + exit(1); + } + + readBS(bsFile, bootsector); + + /* lock drive */ + generic_block_ioctl(drive + 1, 0x84a, NULL); + + reset_drive(drive); + + /* write bootsector to drive */ + if (MyAbsReadWrite(drive, 1, 0, bootsector, 1) != 0) + { + printf("%s: failed to write boot sector to drive %c:\n", pgm, drive + 'A'); + exit(1); + } + + reset_drive(drive); + + /* unlock_drive */ + generic_block_ioctl(drive + 1, 0x86a, NULL); +} + +/* write bootsector to file bsFile */ +void saveBS(const char *bsFile, UBYTE *bootsector) +{ + if (bsFile != NULL) + { + int fd; + +#ifdef DEBUG + printf("writing bootsector to file %s\n", bsFile); +#endif + + /* open boot sector file, create it if not exists, + but don't truncate if exists so we can replace + 1st SEC_SIZE bytes of an image file + */ + if ((fd = open(bsFile, O_WRONLY | O_CREAT | O_BINARY, + S_IREAD | S_IWRITE)) < 0) + { + printf("%s: can't create\"%s\"\nDOS errnum %d", pgm, bsFile, errno); + exit(1); + } + if (write(fd, bootsector, SEC_SIZE) != SEC_SIZE) + { + printf("%s: failed to write %u bytes to %s\n", pgm, SEC_SIZE, bsFile); + close(fd); + /* unlink(bsFile); don't delete in case was image */ + exit(1); + } + close(fd); + } /* if write boot sector file */ +} + +/* write drive's boot record unmodified to bsFile */ +void dumpBS(const char *bsFile, int drive) +{ + UBYTE bootsector[SEC_SIZE]; + + if (bsFile == NULL) + { + printf("%s: missing filename to dump boot sector to\n", pgm); + exit(1); + } + + /* lock drive */ + generic_block_ioctl(drive + 1, 0x84a, NULL); + + reset_drive(drive); + + /* suggestion: allow reading from a boot sector or image file here */ + if (MyAbsReadWrite(drive, 1, 0, bootsector, 0) != 0) + { + printf("%s: failed to read boot sector for drive %c:\n", pgm, drive + 'A'); + exit(1); + } + + reset_drive(drive); + + /* unlock_drive */ + generic_block_ioctl(drive + 1, 0x86a, NULL); + + saveBS(bsFile, bootsector); +} + + + +void put_boot(SYSOptions *opts) +{ +#ifdef WITHFAT32 + struct bootsectortype32 *bs32; +#endif + struct bootsectortype *bs; + UBYTE oldboot[SEC_SIZE], newboot[SEC_SIZE]; + UBYTE default_bpb[0x5c]; + int bsBiosMovOff; /* offset in bs to mov [drive],dl that we NOP out */ + + if (opts->verbose) + { + printf("Reading old bootsector from drive %c:\n", opts->dstDrive + 'A'); + } + + /* lock drive */ + generic_block_ioctl(opts->dstDrive + 1, 0x84a, NULL); + + reset_drive(opts->dstDrive); + + /* suggestion: allow reading from a boot sector or image file here */ + if (MyAbsReadWrite(opts->dstDrive, 1, 0, oldboot, 0) != 0) + { + printf("%s: can't read old boot sector for drive %c:\n", pgm, opts->dstDrive + 'A'); + exit(1); + } + +#ifdef DDEBUG + printf("Old Boot Sector:\n"); + dump_sector(oldboot); +#endif + + /* backup original boot sector when requested */ + if (opts->bsFileOrig) + { + printf("Backing up original boot sector to %s\n", opts->bsFileOrig); + saveBS(opts->bsFileOrig, oldboot); + } + + bs = (struct bootsectortype *)&oldboot; + + if (bs->bsBytesPerSec != SEC_SIZE) + { + printf("Sector size is not 512 but %d bytes - not currently supported!\n", + bs->bsBytesPerSec); + exit(1); /* Japan?! */ + } + + { + /* see "FAT: General Overview of On-Disk Format" v1.02, 5.V.1999 + * (http://www.nondot.org/sabre/os/files/FileSystems/FatFormat.pdf) + */ + ULONG fatSize, totalSectors, dataSectors, clusters; + UCOUNT rootDirSectors; + + bs32 = (struct bootsectortype32 *)bs; + rootDirSectors = (bs->bsRootDirEnts * DIRENT_SIZE /* 32 */ + + bs32->bsBytesPerSec - 1) / bs32->bsBytesPerSec; + fatSize = bs32->bsFATsecs ? bs32->bsFATsecs : bs32->bsBigFatSize; + totalSectors = bs32->bsSectors ? bs32->bsSectors : bs32->bsHugeSectors; + dataSectors = totalSectors + - bs32->bsResSectors - (bs32->bsFATs * fatSize) - rootDirSectors; + clusters = dataSectors / bs32->bsSecPerClust; + + if (clusters < FAT_MAGIC) /* < 4085 */ + fs = FAT12; + else if (clusters < FAT_MAGIC16) /* < 65525 */ + fs = FAT16; + else + fs = FAT32; + } + + /* bit 0 set if function to use current BPB, clear if Device + BIOS Parameter Block field contains new default BPB + bit 1 set if function to use track layout fields only + must be clear if CL=60h + bit 2 set if all sectors in track same size (should be set) (RBIL) */ + default_bpb[0] = 4; + + if (fs == FAT32) + { + printf("FAT type: FAT32\n"); + /* get default bpb (but not for floppies) */ + if (opts->dstDrive >= 2 && + generic_block_ioctl(opts->dstDrive + 1, 0x4860, default_bpb) == 0) + correct_bpb((struct bootsectortype *)(default_bpb + 7 - 11), bs, opts->verbose); + +#ifdef WITHFAT32 /* copy one of the FAT32 boot sectors */ + if (!opts->kernel.stdbs) /* MS/PC DOS compatible BS requested */ + { + printf("%s: FAT32 versions of PC/MS DOS compatible boot sectors\n" + "are not supported.\n", pgm); + exit(1); + } + + /* user may force explicity lba or chs, otherwise base on if LBA available */ + if ((opts->force==LBA) || ((opts->force==AUTO) && haveLBA())) + memcpy(newboot, fat32lba, SEC_SIZE); + else /* either auto mode & no LBA detected or forced CHS */ + memcpy(newboot, fat32chs, SEC_SIZE); +#else + printf("SYS hasn't been compiled with FAT32 support.\n" + "Consider using -DWITHFAT32 option.\n"); + exit(1); +#endif + } + else + { /* copy the FAT12/16 CHS+LBA boot sector */ + printf("FAT type: FAT1%c\n", fs + '0' - 10); + if (opts->dstDrive >= 2 && + generic_block_ioctl(opts->dstDrive + 1, 0x860, default_bpb) == 0) + correct_bpb((struct bootsectortype *)(default_bpb + 7 - 11), bs, opts->verbose); + + if (opts->kernel.stdbs) + { + /* copy over appropriate boot sector, FAT12 or FAT16 */ + memcpy(newboot, (fs == FAT16) ? fat16com : fat12com, SEC_SIZE); + + /* !!! if boot sector changes then update these locations !!! */ + { + unsigned offset; + offset = (fs == FAT16) ? 0x175 : 0x178; + + if ( (newboot[offset]==0x84) && (newboot[offset+1]==0xD2) ) /* test dl,dl */ + { + /* if always use LBA then NOP out conditional jmp over LBA logic if A: */ + if (opts->force==LBA) + { + offset+=2; /* jz */ + newboot[offset] = 0x90; /* NOP */ ++offset; + newboot[offset] = 0x90; /* NOP */ + } + else if (opts->force==CHS) /* if force CHS then always skip LBA logic */ + { + newboot[offset] = 0x30; /* XOR */ + } + } + else + { + printf("%s : fat boot sector does not match expected layout\n", pgm); + exit(1); + } + } + } + else + { +#ifdef WITHOEMCOMPATBS + printf("Using OEM (PC/MS-DOS) compatible boot sector.\n"); + memcpy(newboot, (fs == FAT16) ? oemfat16 : oemfat12, SEC_SIZE); +#else + printf("Internal Error: no OEM compatible boot sector!\n"); +#endif + } + } + + /* Copy disk parameter from old sector to new sector */ +#ifdef WITHFAT32 + if (fs == FAT32) + memcpy(&newboot[SBOFFSET], &oldboot[SBOFFSET], SBSIZE32); + else +#endif + memcpy(&newboot[SBOFFSET], &oldboot[SBOFFSET], SBSIZE); + + bs = (struct bootsectortype *)&newboot; + + /* originally OemName was "FreeDOS", changed for better compatibility */ + memcpy(bs->OemName, "FRDOS5.1", 8); /* Win9x seems to require + 5 uppercase letters, + digit(4 or 5) dot digit */ + +#ifdef WITHFAT32 + if (fs == FAT32) + { + bs32 = (struct bootsectortype32 *)&newboot; + /* ensure appears valid, if not then force valid */ + if ((bs32->bsBackupBoot < 1) || (bs32->bsBackupBoot > bs32->bsResSectors)) + { + if (opts->verbose) + printf("BPB appears to have invalid backup boot sector #, forcing to default.\n"); + bs32->bsBackupBoot = 0x6; /* ensure set, 6 is MS defined bs size */ + } + bs32->bsDriveNumber = opts->defBootDrive; + + /* the location of the "0060" segment portion of the far pointer + in the boot sector is just before cont: in boot*.asm. + This happens to be offset 0x78 for FAT32 and offset 0x5c for FAT16 + + force use of value stored in bs by NOPping out mov [drive], dl + 0x82: 88h,56h,40h for fat32 chs & lba boot sectors + + i.e. BE CAREFUL WHEN YOU CHANGE THE BOOT SECTORS !!! + */ + if (opts->kernel.stdbs) + { + ((int *)newboot)[0x78/sizeof(int)] = opts->kernel.loadaddr; + bsBiosMovOff = 0x82; + } + else /* compatible bs */ + { + printf("%s: INTERNAL ERROR: how did you get here?\n", pgm); + exit(1); + } + +#ifdef DEBUG + printf(" FAT starts at sector %lx + %x\n", + bs32->bsHiddenSecs, bs32->bsResSectors); +#endif + } + else +#endif + { + + /* establish default BIOS drive # set in boot sector */ + bs->bsDriveNumber = opts->defBootDrive; + + /* the location of the "0060" segment portion of the far pointer + in the boot sector is just before cont: in boot*.asm. + This happens to be offset 0x78 for FAT32 and offset 0x5c for FAT16 + The oem boot sectors do not have/need this value for patching. + + the location of the jmp address (patching from + EA00007000 [jmp 0x0070:0000] to EA00207000 [jmp 0x0070:0200]) + 0x11b: for fat12 oem boot sector + 0x118: for fat16 oem boot sector + The standard boot sectors do not have/need this value patched. + + force use of value stored in bs by NOPping out mov [drive], dl + 0x66: 88h,56h,24h for fat16 and fat12 boot sectors + 0x4F: 88h,56h,24h for oem compatible fat16 and fat12 boot sectors + + i.e. BE CAREFUL WHEN YOU CHANGE THE BOOT SECTORS !!! + */ + if (opts->kernel.stdbs) + { + /* this sets the segment we load the kernel to, default is 0x60:0 */ + ((int *)newboot)[0x5c/sizeof(int)] = opts->kernel.loadaddr; + bsBiosMovOff = 0x66; + } + else + { + /* load segment hard coded to 0x70 in oem compatible boot sector, */ + /* this however changes the offset jumped to default 0x70:0 */ + if (fs == FAT12) + ((int *)newboot)[0x11c/sizeof(int)] = opts->kernel.loadaddr; + else + ((int *)newboot)[0x119/sizeof(int)] = opts->kernel.loadaddr; + bsBiosMovOff = 0x4F; + } + } + + if (opts->ignoreBIOS) + { + if ( (newboot[bsBiosMovOff]==0x88) && (newboot[bsBiosMovOff+1]==0x56) ) + { + newboot[bsBiosMovOff] = 0x90; /* NOP */ ++bsBiosMovOff; + newboot[bsBiosMovOff] = 0x90; /* NOP */ ++bsBiosMovOff; + newboot[bsBiosMovOff] = 0x90; /* NOP */ ++bsBiosMovOff; + } + else + { + printf("%s : fat boot sector does not match expected layout\n", pgm); + exit(1); + } + } + + if (opts->verbose) /* display information about filesystem */ + { + printf("Root dir entries = %u\n", bs->bsRootDirEnts); + + printf("FAT starts at sector (%lu + %u)\n", + bs->bsHiddenSecs, bs->bsResSectors); + printf("Root directory starts at sector (PREVIOUS + %u * %u)\n", + bs->bsFATsecs, bs->bsFATs); + } + + { + int i = 0; + memset(&newboot[0x1f1], ' ', 11); + while (opts->kernel.kernel[i] && opts->kernel.kernel[i] != '.') + { + if (i < 8) + newboot[0x1f1+i] = toupper(opts->kernel.kernel[i]); + i++; + } + if (opts->kernel.kernel[i] == '.') + { + /* copy extension */ + int j = 0; + i++; + while (opts->kernel.kernel[i+j] && j < 3) + { + newboot[0x1f9+j] = toupper(opts->kernel.kernel[i+j]); + j++; + } + } + } + + if (opts->verbose) + { + /* there's a zero past the kernel name in all boot sectors */ + printf("Boot sector kernel name set to %s\n", &newboot[0x1f1]); + if (opts->kernel.stdbs) + printf("Boot sector kernel load segment set to %X:0h\n", opts->kernel.loadaddr); + else + printf("Boot sector kernel jmp address set to 70:%Xh\n", opts->kernel.loadaddr); + } + +#ifdef DDEBUG + printf("\nNew Boot Sector:\n"); + dump_sector(newboot); +#endif + + if (opts->writeBS) + { +#ifdef DEBUG + printf("Writing new bootsector to drive %c:\n", opts->dstDrive + 'A'); +#endif + + /* write newboot to a drive */ + if (MyAbsReadWrite(opts->dstDrive, 1, 0, newboot, 1) != 0) + { + printf("Can't write new boot sector to drive %c:\n", opts->dstDrive + 'A'); + exit(1); + } + + /* for FAT32, we need to update the backup copy as well */ + /* unless user has asked us not to, eg for better dual boot support */ + /* Note: assuming sectors 1-5 & 7-11 (FSINFO+additional boot code) + are properly setup by prior format and need no modification + [technically freespace, etc. should be updated] + */ + if ((fs == FAT32) && !opts->skipBakBSCopy) + { + bs32 = (struct bootsectortype32 *)&newboot; +#ifdef DEBUG + printf("writing backup bootsector to sector %d\n", bs32->bsBackupBoot); +#endif + if (MyAbsReadWrite(opts->dstDrive, 1, bs32->bsBackupBoot, newboot, 1) != 0) + { + printf("Can't write backup boot sector to drive %c:\n", opts->dstDrive + 'A'); + exit(1); + } + } + + } /* if write boot sector to boot record*/ + + if (opts->bsFile != NULL) + { + if (opts->verbose) + printf("writing new bootsector to file %s\n", opts->bsFile); + + saveBS(opts->bsFile, newboot); + } /* if write boot sector to file*/ + + reset_drive(opts->dstDrive); + + /* unlock_drive */ + generic_block_ioctl(opts->dstDrive + 1, 0x86a, NULL); +} /* put_boot */ + + +/* + * Returns TRUE if `drive` has at least `bytes` free space, FALSE otherwise. + * put_sector() must have been already called to determine file system type. + */ +BOOL check_space(COUNT drive, ULONG bytes) +{ +#ifdef WITHFAT32 + if (fs == FAT32) + { + char *drivename = "A:\\"; + drivename[0] = 'A' + drive; + getextdrivespace(drivename, &x, sizeof(x)); + return x.xfs_freeclusters > (bytes / (x.xfs_clussize * x.xfs_secsize)); + } + else +#endif + { +#ifdef __TURBOC__ + struct dfree df; + getdfree(drive + 1, &df); + return (ULONG)df.df_avail * df.df_sclus * df.df_bsec >= bytes; +#else + struct _diskfree_t df; + _dos_getdiskfree(drive + 1, &df); + return (ULONG)df.avail_clusters * df.sectors_per_cluster + * df.bytes_per_sector >= bytes; +#endif + } +} /* check_space */ + + +BYTE copybuffer[COPY_SIZE]; + +/* allocate memory from DOS, return 0 on success, nonzero otherwise */ +int alloc_dos_mem(ULONG memsize, UWORD *theseg) +{ + unsigned dseg; +#ifdef __TURBOC__ + if (allocmem((unsigned)((memsize+15)>>4), &dseg)!=-1) +#else + if (_dos_allocmem((unsigned)((memsize+15)>>4), &dseg)!=0) +#endif + return -1; /* failed to allocate memory */ + + *theseg = (UWORD)dseg; + return 0; /* success */ +} +#ifdef __TURBOC__ +#define dos_freemem freemem +#else +#define dos_freemem _dos_freemem +#endif + +/* copies file (path+filename specified by srcFile) to drive:\filename */ +BOOL copy(const BYTE *source, COUNT drive, const BYTE * filename) +{ + static BYTE src[SYS_MAXPATH]; + static BYTE dest[SYS_MAXPATH]; + unsigned ret; + int fdin, fdout; + ULONG copied = 0; + +#if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */ +#if defined(__WATCOMC__) && __WATCOMC__ < 1280 + unsigned short date, time; +#else + unsigned date, time; +#endif +#elif defined __TURBOC__ + struct ftime ftime; +#endif + + printf("Copying %s...\n", source); + + truename(src, source); + sprintf(dest, "%c:\\%s", 'A' + drive, filename); + if (stricmp(src, dest) == 0) + { + printf("%s: source and destination are identical: skipping \"%s\"\n", + pgm, source); + return TRUE; + } + + if ((fdin = open(source, O_RDONLY | O_BINARY)) < 0) + { + printf("%s: failed to open \"%s\"\n", pgm, source); + return FALSE; + } + +#if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */ + _dos_getftime(fdin, &date, &time); +#elif defined __TURBOC__ + getftime(fdin, &ftime); +#endif + + if (!check_space(drive, filelength(fdin))) + { + printf("%s: Not enough space to transfer %s\n", pgm, filename); + close(fdin); + return FALSE; + } + + if ((fdout = + open(dest, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, + S_IREAD | S_IWRITE)) < 0) + { + printf(" %s: can't create\"%s\"\nDOS errnum %d\n", pgm, dest, errno); + close(fdin); + return FALSE; + } + +#if 0 /* simple copy loop, read chunk then write chunk, repeat until all data copied */ + while ((ret = read(fdin, copybuffer, COPY_SIZE)) > 0) + { + if (write(fdout, copybuffer, ret) != ret) + { + printf("Can't write %u bytes to %s\n", ret, dest); + close(fdout); + unlink(dest); + return FALSE; + } + copied += ret; + } + #else /* read in whole file, then write out whole file */ + { + ULONG filesize; + UWORD theseg; + BYTE far *buffer, far *bufptr; + UWORD offs; + unsigned chunk_size; + + /* get length of file to copy, then allocate enough memory for whole file */ + filesize = filelength(fdin); + if (alloc_dos_mem(filesize, &theseg)!=0) + { + printf("Not enough memory to buffer %lu bytes for %s\n", filesize, source); + return FALSE; + } + bufptr = buffer = MK_FP(theseg, 0); + + /* read in whole file, a chunk at a time; adjust size of last chunk to match remaining bytes */ + chunk_size = (COPY_SIZE < filesize)?COPY_SIZE:(unsigned)filesize; + while ((ret = read(fdin, copybuffer, chunk_size)) > 0) + { + for (offs = 0; offs < ret; offs++) + { + *bufptr = copybuffer[offs]; + bufptr++; + if (FP_OFF(bufptr) > 0x7777) /* watcom needs this in tiny model */ + { + bufptr = MK_FP(FP_SEG(bufptr)+0x700, FP_OFF(bufptr)-0x7000); + } + } + /* keep track of how much read in, and only read in filesize bytes */ + copied += ret; + chunk_size = (COPY_SIZE < (filesize-copied))?COPY_SIZE:(unsigned)(filesize-copied); + } + + /* write out file, a chunk at a time; adjust size of last chunk to match remaining bytes */ + bufptr = buffer; + copied = 0; + do + { + /* keep track of how much read in, and only read in filesize bytes */ + chunk_size = (COPY_SIZE < (filesize-copied))?COPY_SIZE:(unsigned)(filesize-copied); + copied += chunk_size; + + /* setup chunk of data to be written out */ + for (offs = 0; offs < chunk_size; offs++) + { + copybuffer[offs] = *bufptr; + bufptr++; + if (FP_OFF(bufptr) > 0x7777) /* watcom needs this in tiny model */ + { + bufptr = MK_FP(FP_SEG(bufptr)+0x700, FP_OFF(bufptr)-0x7000); + } + } + + /* write the data to disk, abort on any error */ + if (write(fdout, copybuffer, chunk_size) != chunk_size) + { + printf("Can't write %u bytes to %s\n", ret, dest); + close(fdout); + unlink(dest); + return FALSE; + } + } while (copied < filesize); + + dos_freemem(theseg); + } + #endif + +#if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */ + _dos_setftime(fdout, date, time); +#elif defined __TURBOC__ + setftime(fdout, &ftime); +#endif + + /* reduce disk swap on single drives, close file on drive last accessed 1st */ + close(fdout); + +#ifdef __SOME_OTHER_COMPILER__ + { +#include + struct utimbuf utimb; + + utimb.actime = /* access time */ + utimb.modtime = fstatbuf.st_mtime; /* modification time */ + utime(dest, &utimb); + }; +#endif + + /* and close input file, usually same drive as next action will access */ + close(fdin); + + + printf("%lu Bytes transferred\n", copied); + + return TRUE; +} /* copy */ + diff --git a/sys/talloc.c b/sys/talloc.c new file mode 100644 index 0000000..5b7b64a --- /dev/null +++ b/sys/talloc.c @@ -0,0 +1,225 @@ +/** + ** TALLOC.C + ** + ** lean_and_mean malloc()/free implementation + ** by tom ehlert, te@drivesnapshot.de + ** + ** please be careful: + ** + ** this is only slightly tested and has NO ERRORCHECCKING AT ALL + ** no internal checking. no stack checking. nothing !! + ** + ** use it only, if your programs are already debugged !! + **/ + +#ifndef _MSC_VER /* MSC has no brk/sbrk */ + +#include +#include + +#ifdef __TURBOC__ +extern unsigned __brklvl; +#define sbrk(x) ((void *)__brklvl) +#define brk(newbrk) \ + (((char *)(newbrk) > (char *)(&length) - 0x200) ? \ + -1 : \ + (__brklvl = (unsigned)(newbrk), 0)) +#endif + +#ifdef __WATCOMC__ +#include +#define brk(newbrk) ((int)__brk((unsigned)(newbrk))) +#endif + +#ifdef __GNUC__ +#include +#endif + +#define BUSY (sizeof(size_t)-1) /* Bit set if memory block in use*/ +#define isbusy(x) ((x->length)&BUSY) + + +/** +*** _memavl() +*** return max. memory available +*** Q & D +**/ + +#ifdef DEBUG +extern int printf(const char *x, ...); +#define dbprintf(x) printf x +#else +#define dbprintf(x) +#endif +/*#define printf getch() != ' ' ? exit(0) : printf*/ + +typedef union { + size_t length; + char data[1]; +} block; + +void *malloc(size_t length) +{ + static block *alloc_bottom = NULL; + + block *akt, *next; + block *ltop = sbrk(0); + + if (alloc_bottom == NULL) + alloc_bottom = ltop; + + length = (length + sizeof(size_t) + BUSY) & ~BUSY; + + akt = alloc_bottom; + for (;;) + { + if (akt == ltop) + { + /* end of initialized memory */ + next = (block *)&akt->data[length]; + if (next < akt || brk(next) == -1) + return NULL; + break; + } + dbprintf(("follow [%x] = %x\n",akt, akt->length)); + next = (block *)(&akt->data[akt->length & ~BUSY]); + if (isbusy(akt)) + { + akt = next; /* next block */ + } + else if (next == ltop || isbusy(next)) + { + size_t size = akt->length; + if (size >= length) /* try to split */ + { + if (size > length) /* split */ + { + ((block *)&akt->data[length])->length = + size - length; + } + break; + } + akt = next; /* next block */ + } + else + { + /* merge 2 blocks */ + akt->length += next->length; + } + } + akt->length = length | BUSY; + dbprintf(("set [%x] = %x\n",akt,akt->length)); + return &akt->data[sizeof(size_t)]; +} + +#ifdef __WATCOMC__ +void *_nmalloc(unsigned length) +{ + return malloc(length); +} +#endif + +/** + ** reset busy-bit + **/ + +void free(void *ptr) +{ + if (ptr) + ((char *) ptr)[-sizeof(size_t)] &= ~BUSY; +} + +#ifdef TALLOC_NEED_REALLOC + +/* there isn't often need for realloc ;) + */ + +void* realloc(void *ptr,size_t newlength) +{ + size_t oldlength = ((size_t*)ptr)[-1] & ~BUSY; + void *newptr; + + newptr = malloc(newlength); + + if (newptr == NULL) + { + if (newlength <= oldlength) + return ptr; + } + else + { + memcpy(newptr,ptr,oldlength); + } + + free(ptr); + return newptr; +} +#endif + +#ifdef TEST +#include + +int gallocated = 0; + +void *testalloc(size_t length) +{ + void *p; + + printf("alloc %x bytes - ",length); + + p = malloc(length); + + if (p) gallocated += length,printf("at %x - sum=%x\n",p,gallocated); + else printf("failed\n"); + return p; +} +void testfree(void* p) +{ + gallocated -= ((size_t*)p)[-1] & ~BUSY; + printf("free %x \n",p); + + free(p); +} + + + +main() +{ + char *s1,*s2,*s3,*s4,*s5,*s6; + unsigned size; + + s1 = testalloc(1); + s2 = testalloc(2); + s3 = testalloc(0x10); + s4 = testalloc(0x100); + s5 = testalloc(0x1000); + s6 = testalloc(0xfff0); + + testfree(s3); + s3 = testalloc(6); + testfree(s2); + testalloc(8); + +#ifdef __GNUC__ + for(size = 0xe0000000; size;) +#else + for(size = 0xe000; size;) +#endif + { + if (testalloc(size)) + ; + else + size >>= 1; + } + + + testfree(s1); + testfree(s5); + testfree(s4); + testfree(s6); + + return 1; +} +#endif + +#endif diff --git a/utils/echoto.bat b/utils/echoto.bat new file mode 100644 index 0000000..ec186cc --- /dev/null +++ b/utils/echoto.bat @@ -0,0 +1,12 @@ +@echo off +set FILE=%1 +set STR=%2 + +:loop +shift +if "%2" == "" goto end +set STR=%STR% %2 +goto loop +:end + +echo %STR%>> %FILE% diff --git a/utils/exeflat.c b/utils/exeflat.c new file mode 100644 index 0000000..5414b00 --- /dev/null +++ b/utils/exeflat.c @@ -0,0 +1,464 @@ +/****************************************************************/ +/* */ +/* exeflat.c */ +/* */ +/* EXE flattening program */ +/* */ +/* Copyright (c) 2001 */ +/* Bart E. Oldeman */ +/* 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. */ +/****************************************************************/ + +/* + +Usage: exeflat (src.exe) (dest.sys) (relocation-factor) + +large portions copied from task.c + +*/ + +/* history + + 10/??/01 - Bart Oldeman + primary release + + 11/28/01 - tom ehlert + added -UPX option to make the kernel compressable with UPX + +*/ + +#include "portab.h" +#include "exe.h" +#include +#include +#include +#include + +#define BUFSIZE 32768u + +#define KERNEL_START 0x10 /* the kernel code really starts here at 60:10 */ + +typedef struct { + UWORD off, seg; +} farptr; + +static int compReloc(const void *p1, const void *p2) +{ + farptr *r1 = (farptr *) p1; + farptr *r2 = (farptr *) p2; + if (r1->seg > r2->seg) + return 1; + if (r1->seg < r2->seg) + return -1; + if (r1->off > r2->off) + return 1; + if (r1->off < r2->off) + return -1; + return 0; +} + +static void usage(void) +{ + printf("usage: exeflat (src.exe) (dest.sys) (relocation-factor)\n"); + printf + (" -S10 - Silent relocate segment 10 (down list)\n"); + + exit(1); +} + +static int exeflat(const char *srcfile, const char *dstfile, + const char *start, short *silentSegments, short silentcount, + int UPX, exe_header *header) +{ + int i, j; + size_t bufsize; + farptr *reloc; + UWORD start_seg; + ULONG size, to_xfer; + UBYTE **buffers; + UBYTE **curbuf; + FILE *src, *dest; + short silentdone = 0; + int compress_sys_file; + + if ((src = fopen(srcfile, "rb")) == NULL) + { + printf("Source file %s could not be opened\n", srcfile); + exit(1); + } + if (fread(header, sizeof(*header), 1, src) != 1) + { + printf("Error reading header from %s\n", srcfile); + fclose(src); + exit(1); + } + if (header->exSignature != MAGIC) + { + printf("Source file %s is not a valid .EXE\n", srcfile); + fclose(src); + exit(1); + } + start_seg = (UWORD)strtol(start, NULL, 0); + if (header->exExtraBytes == 0) + header->exExtraBytes = 0x200; + printf("header len = %lu = 0x%lx\n", header->exHeaderSize * 16UL, + header->exHeaderSize * 16UL); + size = + ((DWORD) (header->exPages - 1) << 9) + header->exExtraBytes - + header->exHeaderSize * 16UL; + printf("image size (less header) = %lu = 0x%lx\n", size, size); + printf("first relocation offset = %u = 0x%u\n", header->exOverlay, + header->exOverlay); + + /* first read file into memory chunks */ + fseek(src, header->exHeaderSize * 16UL, SEEK_SET); + buffers = malloc((size_t)((size + BUFSIZE - 1) / BUFSIZE) * sizeof(char *)); + if (buffers == NULL) + { + printf("Allocation error\n"); + exit(1); + } + bufsize = BUFSIZE; + for (to_xfer = size, curbuf = buffers; to_xfer > 0; + to_xfer -= bufsize, curbuf++) + { + if (to_xfer < BUFSIZE) + bufsize = (size_t)to_xfer; + *curbuf = malloc(bufsize); + if (*curbuf == NULL) + { + printf("Allocation error\n"); + exit(1); + } + if (fread(*curbuf, sizeof(char), bufsize, src) != bufsize) + { + printf("Source file read error %ld %d\n", to_xfer, bufsize); + exit(1); + } + } + if (header->exRelocTable && header->exRelocItems) + { + fseek(src, header->exRelocTable, SEEK_SET); + reloc = malloc(header->exRelocItems * sizeof(farptr)); + if (reloc == NULL) + { + printf("Allocation error\n"); + exit(1); + } + if (fread(reloc, sizeof(farptr), header->exRelocItems, src) != + header->exRelocItems) + { + printf("Source file read error\n"); + exit(1); + } + } + fclose(src); + qsort(reloc, header->exRelocItems, sizeof(reloc[0]), compReloc); + for (i = 0; i < header->exRelocItems; i++) + { + ULONG spot = ((ULONG) reloc[i].seg << 4) + reloc[i].off; + UBYTE *spot0 = &buffers[(size_t)(spot / BUFSIZE)][(size_t)(spot % BUFSIZE)]; + UBYTE *spot1 = &buffers[(size_t)((spot + 1) / BUFSIZE)][(size_t)((spot + 1) % BUFSIZE)]; + UWORD segment = ((UWORD) * spot1 << 8) + *spot0; + + for (j = 0; j < silentcount; j++) + if (segment == silentSegments[j]) + { + silentdone++; + goto dontPrint; + } + + printf("relocation at 0x%04x:0x%04x ->%04x\n", reloc[i].seg, + reloc[i].off, segment); + + dontPrint: + + segment += start_seg; + *spot0 = segment & 0xff; + *spot1 = segment >> 8; + } + + printf("\nProcessed %d relocations, %d not shown\n", + header->exRelocItems, silentdone); + + if ((dest = fopen(dstfile, "wb+")) == NULL) + { + printf("Destination file %s could not be created\n", dstfile); + exit(1); + } + + /* The biggest .sys file that UPX accepts seems to be 65419 bytes long */ + compress_sys_file = size < 65420; + if (UPX) { + printf("Compressing kernel - %s format\n", (compress_sys_file)?"sys":"exe"); + } + if (UPX && !compress_sys_file) { + ULONG realsize; + /* write header without relocations to file */ + exe_header nheader = *header; + nheader.exRelocItems = 0; + nheader.exHeaderSize = 2; + realsize = size + 32; + nheader.exPages = (UWORD)(realsize >> 9); + nheader.exExtraBytes = (UWORD)realsize & 511; + if (nheader.exExtraBytes) + nheader.exPages++; + if (fwrite(&nheader, sizeof(nheader), 1, dest) != 1) { + printf("Destination file write error\n"); + exit(1); + } + fseek(dest, 32UL, SEEK_SET); + } + + /* write dest file from memory chunks */ + bufsize = BUFSIZE; + for (to_xfer = size, curbuf = buffers; to_xfer > 0; + to_xfer -= bufsize, curbuf++) + { + if (to_xfer < BUFSIZE) + bufsize = (size_t)to_xfer; + if (fwrite(*curbuf, sizeof(char), bufsize, dest) != bufsize) + + { + printf("Destination file write error\n"); + exit(1); + } + free(*curbuf); + } + + if (UPX && compress_sys_file) { + /* overwrite first 8 bytes with SYS header */ + UWORD dhdr[4]; + fseek(dest, 0, SEEK_SET); + for (i = 0; i < 3; i++) + dhdr[i] = 0xffff; + /* strategy will jump to us, interrupt never called */ + dhdr[3] = KERNEL_START; + fwrite(dhdr, sizeof(dhdr), 1, dest); + } + fclose(dest); + return compress_sys_file; +} + +static void write_header(FILE *dest, size_t size) +{ + /* UPX HEADER jump $+2+size */ + static char JumpBehindCode[] = { + /* kernel config header - 32 bytes */ + 0xeb, 0x1b, /* jmp short realentry */ + 'C', 'O', 'N', 'F', 'I', 'G', 32 - 2 - 6 - 2 - 3, 0, /* WORD */ + 0, /* DLASortByDriveNo db 0 */ + 1, /* InitDiskShowDriveAssignment db 1 */ + 2, /* SkipConfigSeconds db 2 */ + 0, /* ForceLBA db 0 */ + 1, /* GlobalEnableLBAsupport db 1 */ + 0, /* BootHarddiskSeconds */ + + 'n', 'u', 's', 'e', 'd', /* unused filler bytes */ + 8, 7, 6, 5, 4, 3, 2, 1, + /* real-entry: jump over the 'real' image do the trailer */ + 0xe9, 0, 0 /* 100: jmp 103 */ + }; + + struct x { + char y[sizeof(JumpBehindCode) == 0x20 ? 1 : -1]; + }; + + fseek(dest, 0, SEEK_SET); + /* this assumes <= 0xfe00 code in kernel */ + *(short *)&JumpBehindCode[0x1e] += (short)size; + fwrite(JumpBehindCode, 1, 0x20, dest); +} + +static void write_trailer(FILE *dest, size_t size, int compress_sys_file, + exe_header *header) +{ + /* UPX trailer */ + /* hand assembled - so this remains ANSI C ;-) */ + /* well almost: we still need packing and assume little endian ... */ + /* move kernel down to place CONFIG-block, which added above, + at start_seg-2:0 (e.g. 0x5e:0) instead of + start_seg:0 (e.g. 0x60:0) and store there boot drive number + from BL; kernel.asm will then check presence of additional + CONFIG-block at this address. */ + static char trailer[] = { /* shift down everything by sizeof JumpBehindCode */ + 0xB9, 0x00, 0x00, /* 0 mov cx,offset trailer */ + 0x0E, /* 3 push cs */ + 0x1F, /* 4 pop ds (=60) */ + 0x8C, 0xC8, /* 5 mov ax,cs */ + 0x48, /* 7 dec ax */ + 0x48, /* 8 dec ax */ + 0x8E, 0xC0, /* 9 mov es,ax */ + 0x93, /* 11 xchg ax,bx (to get al=bl) */ + 0x31, 0xFF, /* 12 xor di,di */ + 0xFC, /* 14 cld */ + 0xAA, /* 15 stosb (store drive number)*/ + 0x8B, 0xF7, /* 16 mov si,di */ + 0xF3, 0xA4, /* 18 rep movsb */ + 0x1E, /* 20 push ds */ + 0x58, /* 21 pop ax */ + 0x05, 0x00, 0x00, /* 22 add ax,... */ + 0x8E, 0xD0, /* 25 mov ss,ax */ + 0xBC, 0x00, 0x00, /* 27 mov sp,... */ + 0x31, 0xC0, /* 30 xor ax,ax */ + 0xFF, 0xE0 /* 32 jmp ax */ + }; + + *(short *)&trailer[1] = (short)size + 0x20; + *(short *)&trailer[23] = header->exInitSS; + *(short *)&trailer[28] = header->exInitSP; + if (compress_sys_file) { + /* replace by jmp word ptr [6]: ff 26 06 00 + (the .SYS strategy handler which will unpack) */ + *(long *)&trailer[30] = 0x000626ffL; + /* set up a 4K stack for the UPX decompressor to work with */ + *(short *)&trailer[23] = 0x1000; + *(short *)&trailer[28] = 0x1000; + } + fwrite(trailer, 1, sizeof trailer, dest); +} + +int main(int argc, char **argv) +{ + short silentSegments[20], silentcount = 0; + static exe_header header; /* must be initialized to zero */ + int UPX = FALSE; + int i; + size_t sz, len, len2, n; + int compress_sys_file; + char *buffer, *tmpexe, *cmdbuf; + FILE *dest; + long size; + + /* if no arguments provided, show usage and exit */ + if (argc < 4) usage(); + + /* do optional argument processing here */ + for (i = 4; i < argc && !UPX; i++) + { + char *argptr = argv[i]; + + if (argptr[0] != '-' && argptr[0] != '/') + usage(); + + argptr++; + + switch (toupper(argptr[0])) + { + case 'U': + UPX = i; + break; + case 'S': + if (silentcount >= LENGTH(silentSegments)) + { + printf("can't handle more then %d silent's\n", + LENGTH(silentSegments)); + exit(1); + } + + silentSegments[silentcount++] = (short)strtol(argptr + 1, NULL, 0); + break; + + default: + usage(); + } + } + + /* arguments left : + infile outfile relocation offset */ + + compress_sys_file = exeflat(argv[1], argv[2], argv[3], + silentSegments, silentcount, + UPX, &header); + if (!UPX) + exit(0); + + /* move kernel.sys tmp.exe */ + tmpexe = argv[2]; + if (!compress_sys_file) + { + tmpexe = "tmp.exe"; + rename(argv[2], tmpexe); + } + + len2 = strlen(tmpexe) + 1; + sz = len2; + if (sz < 256) sz = 256; + cmdbuf = malloc(sz); + len = 0; + for (i = UPX+1; i < argc; i++) + { + n = strlen(argv[i]); + if (len + len2 + n + 2 >= sz) { + sz *= 2; + cmdbuf = realloc(cmdbuf, sz); + } + if (i > UPX+1) + cmdbuf[len++] = ' '; + memcpy(cmdbuf + len, argv[i], n + 1); + len += n; + } + cmdbuf[len++] = ' '; + /* if tmpexe is tmpfile set above no quotes needed, if user needs quotes should add on cmd line */ + memcpy(cmdbuf + len, tmpexe, len2); + cmdbuf[len + len2] = '\0'; + printf("%s\n", cmdbuf); + if (system(cmdbuf)) + { + printf("Problems executing %s\n", cmdbuf); + printf("Removing [%s]\n", tmpexe); + remove(tmpexe); + exit(1); + } + free(cmdbuf); + + if (!compress_sys_file) + { + exeflat(tmpexe, argv[2], argv[3], + silentSegments, silentcount, + FALSE, &header); + remove(tmpexe); + } + + /* argv[2] now contains the final flattened file: just + header and trailer need to be added */ + /* the compressed file has two chunks max */ + + if ((dest = fopen(argv[2], "rb+")) == NULL) + { + printf("Destination file %s could not be opened\n", argv[2]); + exit(1); + } + + buffer = malloc(0xfe01); + + fread(buffer, 0xfe01, 1, dest); + size = ftell(dest); + if (size >= 0xfe00u) + { + printf("kernel; size too large - must be <= 0xfe00\n"); + exit(1); + } + fseek(dest, 0, SEEK_SET); + write_header(dest, (size_t)size); + fwrite(buffer, (size_t)size, 1, dest); + write_trailer(dest, (size_t)size, compress_sys_file, &header); + return 0; +} diff --git a/utils/indent.ini b/utils/indent.ini new file mode 100644 index 0000000..2828df8 --- /dev/null +++ b/utils/indent.ini @@ -0,0 +1,18 @@ +-kr +-di2 +-nbc +-nfca +-bl +-bli0 +-ss +-npcs +-ncs +-nbs +-i2 +-ci4 +-nce +-sob +-nut +-nbad +-cli2 +-hnl diff --git a/utils/makefile b/utils/makefile new file mode 100644 index 0000000..3709e7c --- /dev/null +++ b/utils/makefile @@ -0,0 +1,19 @@ +!include "../mkfiles/generic.mak" + +CFLAGS = -I..$(DIRSEP)hdr + +production: patchobj.com exeflat.exe + +patchobj.com: patchobj.c + $(CLT) $(CFLAGS) patchobj.c + +exeflat.exe: exeflat.c ../hdr/exe.h + $(CLC) $(CFLAGS) exeflat.c + + +clobber: clean + +clean: + $(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.las *.cod *.err status.me + $(RM) exeflat.exe patchobj.com + diff --git a/utils/patchobj.c b/utils/patchobj.c new file mode 100644 index 0000000..72d9870 --- /dev/null +++ b/utils/patchobj.c @@ -0,0 +1,204 @@ +/***************************************************************************** +** PATCHOBJ facility - change strings in the LNAMES record +** +** Copyright 2001 by tom ehlert +** +** GPL bla to be added, but intended as GPL +** +** +** 09/06/2001 - initial revision +** not my biggest kind of software; anyone willing to add +** comments, errormessages, usage info,...??? +** +*****************************************************************************/ + +#include +#ifdef __GNUC__ +#include +#else +#include +#endif +#include +#include +#include + +#ifndef TRUE +#define TRUE (1==1) +#define FALSE (0==1) +#endif + +struct { + char *sin, *sout; +} repl[100]; +int repl_count; + +void go_records(FILE * fdin, FILE * fdo); + +void quit(char *s, ...) +{ + vprintf(s, (void *)((char *)&s + sizeof(s))); + exit(1); +} + +void define_replace(char *sin) +{ + char *s; + + if (repl_count >= 99) + quit("too many replacements"); + + if ((s = strchr(sin, '=')) == NULL) + quit("illegal replacement <%s>, missing '='", sin); + + *s = 0; + repl[repl_count].sin = sin; + repl[repl_count].sout = s + 1; + + repl_count++; +} + +int main(int argc, char *argv[]) +{ + char *argptr; + FILE *fd, *fdo; + char *inname = 0, *outname = "~patchob.tmp"; + + int use_temp_file = TRUE; + + argc--, argv++; + + for (; argc != 0; argc--, argv++) + { + argptr = *argv; + + if (*argptr != '-' && *argptr != '/') + { + if (argc == 1) + { + inname = argptr; + continue; + } + define_replace(argptr); + continue; + } + switch (toupper(argptr[1])) + { + case 'O': + outname = argptr + 2; + use_temp_file = FALSE; + break; + default: + quit("illegal argument <%s>\n", argptr); + break; + } + } + + if (inname == 0) + quit("Inputfile must be specified\n"); + + if (repl_count == 0) + quit("no replacements defined"); + + if ((fd = fopen(inname, "rb")) == NULL) /* open for READ/WRITE */ + quit("can't read %s\n", inname); + + if ((fdo = fopen(outname, "wb")) == NULL) /* open for READ/WRITE */ + quit("can't write %s\n", outname); + + go_records(fd, fdo); + + fclose(fd); + fclose(fdo); + if (use_temp_file) + { + unlink(inname); + rename(outname, inname); + } + + return 0; + +} + +#include "algnbyte.h" +struct record { + unsigned char rectyp; + unsigned short datalen; + char buffer[0x2000]; +} Record, Outrecord; +#include "algndflt.h" + +struct verify_pack1 { char x[ sizeof(struct record) == 0x2003 ? 1 : -1];}; + +void go_records(FILE * fdin, FILE * fdo) +{ + unsigned char stringlen; + char *string, *s; + int i, j; + unsigned char chksum; + + do + { + if (fread(&Record, 1, 3, fdin) != 3) + { /* read type and reclen */ + /* printf("end of fdin read\n"); */ + break; + } + if (Record.datalen > sizeof(Record.buffer)) + quit("record to large : length %u Bytes \n", Record.datalen); + + if (fread(Record.buffer, 1, Record.datalen, fdin) != Record.datalen) + { + printf("invalid record format\n"); + quit("can't continue\n"); + } + + if (Record.rectyp != 0x96 && Record.rectyp != 0x8c) /* we are only interested in LNAMES */ + { + fwrite(&Record, 1, 3 + Record.datalen, fdo); + continue; + } + + /* printf("at %lx - record type %x len %x\n",ftell(fdin)-3,Record.rectyp, + Record.datalen);*/ + Outrecord.rectyp = Record.rectyp; + Outrecord.datalen = 0; + + for (i = 0; i < Record.datalen - 1;) + { + stringlen = (unsigned char)Record.buffer[i]; + i++; + + string = &Record.buffer[i]; + i += stringlen; + + if (i > Record.datalen) + quit("invalid lnames record"); + + for (j = 0; j < repl_count; j++) + if (memcmp(string, repl[j].sin, stringlen) == 0 + && strlen(repl[j].sin) == stringlen) + { + string = repl[j].sout; + stringlen = strlen(repl[j].sout); + } + Outrecord.buffer[Outrecord.datalen] = stringlen; + Outrecord.datalen++; + memcpy(Outrecord.buffer + Outrecord.datalen, string, stringlen); + Outrecord.datalen += stringlen; + } + + chksum = 0; + for (s = (char *)&Outrecord; + s < &Outrecord.buffer[Outrecord.datalen]; s++) + chksum += (unsigned char)*s; + + Outrecord.buffer[Outrecord.datalen] = ~chksum; + Outrecord.datalen++; + + /* printf("^sum = %02x - %02x\n",chksum,~chksum); */ + + fwrite(&Outrecord, 1, 3 + Outrecord.datalen, fdo); + + } + while (Record.rectyp != 0x00 /*ENDFIL*/); +} diff --git a/utils/proto.bat b/utils/proto.bat new file mode 100644 index 0000000..b57c208 --- /dev/null +++ b/utils/proto.bat @@ -0,0 +1 @@ +for %%f in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do mkptypes %%f >>proto.h diff --git a/utils/relocinf.c b/utils/relocinf.c new file mode 100644 index 0000000..89d778f --- /dev/null +++ b/utils/relocinf.c @@ -0,0 +1,162 @@ +/***************************************************************************** +** RelocInf.C +** +** provide some info about relocation entries in an exe file +** +** usage: +** RelocInfo exefile +** +** +** Copyright 2001 by tom ehlert +** +** GPL bla to be added, but intended as GPL +** +** +** 09/06/2001 - initial revision +** not my biggest kind of software; anyone willing to add +** comments, errormessages, usage info,...??? +** +*****************************************************************************/ + +* / +#include +#include +#include +typedef unsigned short UWORD; +typedef unsigned long ULONG; +#ifndef _MSC_VER +#define const +#define __cdecl cdecl +#endif + +/* from EXE.H */ +typedef struct { + UWORD exSignature; + UWORD exExtraBytes; + UWORD exPages; + UWORD exRelocItems; + UWORD exHeaderSize; + UWORD exMinAlloc; + UWORD exMaxAlloc; + UWORD exInitSS; + UWORD exInitSP; + UWORD exCheckSum; + UWORD exInitIP; + UWORD exInitCS; + UWORD exRelocTable; + UWORD exOverlay; +} exe_header; + +#define MAGIC 0x5a4d + +struct relocEntry { + UWORD off; + UWORD seg; + UWORD refseg; +}; + +int __cdecl compReloc(const void *p1, const void *p2) +{ + struct relocEntry *r1 = (struct relocEntry *)p1; + struct relocEntry *r2 = (struct relocEntry *)p2; + + if (r1->refseg > r2->refseg) + return 1; + if (r1->refseg < r2->refseg) + return -1; + + if (r1->seg > r2->seg) + return 1; + if (r1->seg < r2->seg) + return -1; + + if (r1->off > r2->off) + return 1; + if (r1->off < r2->off) + return -1; + + return 0; +} + +main(int argc, char *argv[]) +{ + FILE *fdin; + exe_header header; + struct relocEntry *reloc; + + int i; + ULONG image_offset; + + if (argc < 2 || (fdin = fopen(argv[1], "rb")) == NULL) + { + printf("can't open %s\n", argv[1]); + exit(1); + } + + if (fread(&header, sizeof(header), 1, fdin) != 1 || + header.exSignature != MAGIC) + { + printf("%s is no EXE file\n"); + exit(1); + } + + printf("%u relocation entries found\n", header.exRelocItems); + + if (header.exRelocItems > 0x8000 / sizeof(*reloc)) + { + printf("too many relocation entries \n"); + exit(1); + } + + if ((reloc = malloc(header.exRelocItems * sizeof(*reloc))) == NULL) + { + printf("can't alloc memory\n"); + exit(1); + } + + if (fseek(fdin, header.exRelocTable, 0)) + { + printf("can't seek\n"); + exit(1); + } + + for (i = 0; i < header.exRelocItems; i++) + if (fread(reloc + i, 4, 1, fdin) != 1) + { + printf("can't read reloc info\n"); + exit(1); + } + + for (i = 0; i < header.exRelocItems; i++) + { + image_offset = (ULONG) header.exHeaderSize * 16; + + image_offset += ((ULONG) reloc[i].seg << 4) + reloc[i].off; + + if (fseek(fdin, image_offset, 0)) + { + printf("can't seek reloc data\n"); + exit(1); + } + + if (fread(&reloc[i].refseg, 2, 1, fdin) != 1) + { + printf("can't read rel data for item %d\n", i); + exit(1); + } + /* printf("%04x:%04x -> %04x\n", reloc[i].seg, reloc[i].off, reloc[i].refseg); */ + } + + /* sort reloc entries */ + + qsort(reloc, header.exRelocItems, sizeof(*reloc), compReloc); + + for (i = 0; i < header.exRelocItems; i++) + { + if (i == 0) + printf("# seg:off references data in -->\n"); + printf("%3d %04x:%04x -> %04x\n", i, reloc[i].seg, reloc[i].off, + reloc[i].refseg); + } + +} diff --git a/utils/rmfiles.bat b/utils/rmfiles.bat new file mode 100644 index 0000000..a4a052e --- /dev/null +++ b/utils/rmfiles.bat @@ -0,0 +1,10 @@ +@echo off +:loop_commandline + +if \%1 == \ goto done_with_commandline +if exist %1 del %1>nul +shift +goto loop_commandline + +:done_with_commandline + diff --git a/utils/wlinker.bat b/utils/wlinker.bat new file mode 100644 index 0000000..9d25845 --- /dev/null +++ b/utils/wlinker.bat @@ -0,0 +1,4 @@ +@echo off +ms2wlink %1 %2 %3 %4 %5 %6 %7 %8 %9 ,,,, > kernel.lnk +echo op map,statics,verbose >> kernel.lnk +call wlink @kernel.lnk