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 0000000..c73fc94 Binary files /dev/null and b/kernel/nls/001-437.up differ 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 0000000..67a9e91 Binary files /dev/null and b/kernel/nls/049-850.up differ 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