diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index b6c1a288..00000000 --- a/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -* text eol=crlf -*.up -text -*.UP -text -ci_*.sh text eol=lf -.github/workflows/*.yml text eol=lf -test/** binary diff diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml deleted file mode 100644 index 594037f5..00000000 --- a/.github/workflows/ci-build.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Build -on: - pull_request: - types: - - opened - - ready_for_review - - reopened - - synchronize - push: - workflow_dispatch: - -jobs: - build: - if: contains(github.event.head_commit.message, '[skip ci]') == false - - runs-on: ubuntu-24.04 - - steps: - - name: Checkout repository and submodules - uses: actions/checkout@v6 - with: - submodules: recursive - - - name: Package install - run: ./ci_prereq.sh - env: - TC201_ARCHIVE_PATHNAME: ${{ vars.TC201_ARCHIVE_PATHNAME }} - TC201_ARCHIVE_FILENAME: ${{ vars.TC201_ARCHIVE_FILENAME }} - TC201_ARCHIVE_PASSPHRASE: ${{ secrets.TC201_ARCHIVE_PASSPHRASE }} - - - name: build - run: ./ci_build.sh - - - name: test - run: ./ci_test.sh - - - name: make snapshot name - id: snapshotname - run: | - ( - today=`date -u +%F | tr '\n' '-'` - s_sha=`echo -n ${GITHUB_SHA} | cut -c1-8` - printf "fname=snapshot-%s%s\n" $today $s_sha >> $GITHUB_OUTPUT - ) - - - name: upload - if: github.repository == 'FDOS/kernel' && - (github.event_name == 'push' || github.event.pull_request.merged == true) - uses: actions/upload-artifact@v6 - with: - name: ${{ steps.snapshotname.outputs.fname }} - path: _output/*/*.??? diff --git a/.gitignore b/.gitignore deleted file mode 100644 index fb8a43e0..00000000 --- a/.gitignore +++ /dev/null @@ -1,60 +0,0 @@ -# Object Files -*.OBJ -*.obj - -# List Files -*.LST -*.lst - -# Map files -*.MAP -*.map -*.SYM -*.sym - -# Executable files -*.EXE -*.exe -*.COM -*.com - -# Bin files -*.BIN -*.bin - -# Libraries -*.LIB -*.lib - -# generated text files -sys/*.h -sys/*.H -kernel/*.lnk -kernel/*.LNK - -# FreeDOS build tools configuration -config.bat -config.mak - -kernel/*.SYS -kernel/*.sys -bin/[kK]*.SYS -bin/[kK]*.sys -bin/COMMAND.COM -bin/command.com -bin/COUNTRY.SYS -bin/country.sys -bin/SETVER.SYS -bin/setver.sys - -# backup files -*.orig -*~ -*.diff -*.rej - -# CI build -_downloads/** -_output/** -_watcom/** -kernel/exeflat.rsp diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 77e0176b..00000000 --- a/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "share"] - path = share - url = https://github.com/FDOS/share.git - ignore = untracked -[submodule "country"] - path = country - url = https://github.com/FDOS/country.git diff --git a/MAKEPKGS.BAT b/MAKEPKGS.BAT deleted file mode 100644 index 22746ca9..00000000 --- a/MAKEPKGS.BAT +++ /dev/null @@ -1,138 +0,0 @@ -@ECHO OFF -IF "%1"=="" GOTO USAGE -REM assumes ran in same directory as this file, ie base of kernel source -SET BASEPATH=%CD% -CD .. -REM setup command aliases -SET ZIPIT=7z.exe a -tzip -mx9 -mm=deflate -mpass15 -r -REM when called from RELEASE.BAT assume clean source exported from version control -IF "%2"=="RELEASE" GOTO PACK - -ECHO create source copy -if EXIST SOURCE RMDIR /S /Q SOURCE > NUL -MKDIR SOURCE -ECHO \.svn>SOURCE\SKIPLIST -ECHO .git>>SOURCE\SKIPLIST -ECHO .yml>>SOURCE\SKIPLIST -ECHO CNAME>>SOURCE\SKIPLIST -XCOPY %BASEPATH% SOURCE\ke%1 /S /V /I /Q /G /H /R /Y /EXCLUDE:SOURCE\SKIPLIST -DEL SOURCE\SKIPLIST > NUL -ECHO ensuring clean -PUSHD . -CD SOURCE\ke%1 -CALL clobber.bat -POPD - -:PACK -SET VERSION=%1 -SET LSMRET=SRC -SET LSMFILE=SOURCE\ke%1\docs\fdkernel.lsm -GOTO LSM -:SRC -REM remove CONFIG.BAT if exists, such as building packages from develoment directory -IF EXIST SOURCE\ke%1\CONFIG.BAT DEL SOURCE\ke%1\CONFIG.BAT > NUL -ECHO zipping source -%ZIPIT% ke%1s.zip SOURCE\* -ECHO gathering source and creating APPINFO and expected packaging dir structure -REM FreeDOS package format, has APPINFO, BIN, DOC\KERNEL, SOURCE\KERNEL\ -IF EXIST PACKAGE ECHO PACKAGE directory exists, break now to avoid deleting it! -IF EXIST PACKAGE pause -IF EXIST PACKAGE RMDIR /S PACKAGE -MKDIR PACKAGE -MKDIR PACKAGE\SOURCE -XCOPY /S /I /Q SOURCE\ke%1 PACKAGE\SOURCE\KERNEL -MKDIR PACKAGE\DOC -MKDIR PACKAGE\DOC\KERNEL -COPY /N SOURCE\ke%1\DOCS\* PACKAGE\DOC\KERNEL\ -COPY SOURCE\ke%1\COPYING PACKAGE\DOC\KERNEL\COPYING -MKDIR PACKAGE\APPINFO -MOVE PACKAGE\DOC\KERNEL\fdkernel.lsm PACKAGE\APPINFO\KERNEL.LSM -MKDIR PACKAGE\BIN -ECHO using working configuration file -COPY %BASEPATH%\CONFIG.BAT SOURCE\ke%1\ > NUL -CD SOURCE\ke%1 - -ECHO build and packaging -SET VERSION=%1 (FAT12/FAT16) -SET FAT=16 -SET CPU=86 -SET BZKRET=F16 -GOTO BZK -:F16 -SET VERSION=%1 (FAT12/FAT16) -SET FAT=16 -SET CPU=386 -SET BZKRET=F16386 -GOTO BZK -:F16386 -SET VERSION=%1 (FAT12/FAT16/FAT32) -SET FAT=32 -SET CPU=386 -SET BZKRET=F32 -GOTO BZK -:F32 -SET VERSION=%1 (FAT12/FAT16/FAT32) -SET FAT=32 -SET CPU=86 -SET BZKRET=F3286 -GOTO BZK -:F3286 -ECHO building FreeDOS package -CD ..\..\PACKAGE -%ZIPIT% ..\kernel.zip APPINFO BIN DOC SOURCE -ECHO clean up -CD .. -RMDIR /S /Q SOURCE > NUL -RMDIR /S /Q PACKAGE > NUL -ECHO Done. -SET BZKRET= -GOTO DONE - - -:BZK -ECHO build kernel %VERSION% -CALL build.bat /D KERNEL_VERSION /V "%1 " %CPU% win 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 -%ZIPIT% ..\..\ke%1_%CPU%f%FAT%.zip BIN\* DOCS\* -ECHO storing binaries for FreeDOS package -COPY BIN\KERNEL.SYS ..\..\PACKAGE\BIN\KERNL%CPU%.SYS -COPY /B /Y BIN\country.sys ..\..\PACKAGE\BIN\COUNTRY.SYS -COPY /B /Y BIN\setver.sys ..\..\PACKAGE\BIN\SETVER.SYS -COPY /B /Y BIN\sys.com ..\..\PACKAGE\BIN\SYS.COM -IF EXIST BIN\share.com COPY /B /Y BIN\share.com ..\..\PACKAGE\BIN\SHARE.COM -ECHO cleaning up between builds -CALL clobber.bat -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://github.com/fdos/kernel>>%LSMFILE% -ECHO Alternate-site: http://www.fdos.org/kernel/>>%LSMFILE% -ECHO Alternate-site: http://freedos.sourceforge.net/kernel/>>%LSMFILE% -ECHO Original-site: http://www.gcfl.net/pub/FreeDOS/kernel>>%LSMFILE% -ECHO Platforms: DOS, FreeDOS, DOSEMU (OpenWatcom/Borland/GCC-ia16, NASM, UPX)>>%LSMFILE% -ECHO Copying-policy: GPL2>>%LSMFILE% -ECHO End>>%LSMFILE% -SET LSMFILE= -SET VERSION= -GOTO %LSMRET% - -:USAGE -ECHO Build kernel packages (interim builds or release without tagging) - usage: %0 {VERSION} e.g. %0 2039 or %0 git -:DONE -CD %BASEPATH% -SET BASEPATH= -SET ZIPIT= diff --git a/README.md b/README.md deleted file mode 100644 index 23e905a5..00000000 --- a/README.md +++ /dev/null @@ -1,17 +0,0 @@ -fd kernel -========= - -FreeDOS kernel - current 0xFD version is 2.45 (2045) - -http://www.fdos.org/kernel/ - -The FreeDOS kernel implements the core MS/PC-DOS (R) compatible functions. It is derived from Pat Villani's DOS-C kernel and released under the GPL v2. Please see http://www.freedos.org/ for more details about the FreeDOS (TM) Project. This was originally a branch based on 2042 SVN 0xFD kernel; the full svn history has since been added to git (see other branches) and current development of release kernels are available here. Please fork and submit a Pull Request! - -Compiled kernels ready to use (just copy kernel.sys over an existing install) are available at http://www.fdos.org/kernel/testing/git/ - also available are the source archive and fdpkg compatible packages. *** TODO update links/upload archives - - -This version of the kernel is intended only for 8086+ or 80386+ IBM compatible computers in continuation of the goals of the FreeDOS Project. Please see http://www.fdos.org/kernel for my 0xDC kernel that is work on merging back in some of the original portability aspects and other supported features at the cost of some compatibility with older hardware/software. - -Please feel free to email me - PerditionC@gmail.com - -Now with automatic builds and soon tests [![Build](../../workflows/Build/badge.svg)](../../actions) diff --git a/RELEASE.BAT b/RELEASE.BAT deleted file mode 100644 index 45034c8d..00000000 --- a/RELEASE.BAT +++ /dev/null @@ -1,30 +0,0 @@ -@ECHO OFF -IF "%1"=="" GOTO USAGE -REM assume ran in root directory of kernel checkout, e.g. C:\fdos\source\kernel\ - -ECHO tag git with release version - -git tag -a -m "Tag kernel release %1" ke%1 HEAD -ECHO get a clean tree -if EXIST ..\SOURCE RMDIR /S /Q ..\SOURCE > NUL -::git clone -v --local --branch ke%1 . ..\SOURCE\ke%1\ -git clone -v --recurse-submodules --local . ..\SOURCE\ke%1\ - -REM delete files to exclude -RD /S /Q ..\SOURCE\ke%1\.git > NUL -RD /S /Q ..\SOURCE\ke%1\.github > NUL -IF EXIST ..\SOURCE\ke%1\.git* DEL /Q ..\SOURCE\ke%1\.git* > NUL -IF EXIST ..\SOURCE\ke%1\*.yml DEL /Q ..\SOURCE\ke%1\*.yml > NUL -IF EXIST ..\SOURCE\ke%1\ci*.sh DEL /Q ..\SOURCE\ke%1\ci*.sh > NUL -IF EXIST ..\SOURCE\ke%1\docs\*.yml DEL /Q ..\SOURCE\ke%1\docs\*.yml > NUL -IF EXIST ..\SOURCE\ke%1\docs\CNAME DEL /Q ..\SOURCE\ke%1\docs\CNAME > NUL -::pause - -ECHO %CD% -CALL MAKEPKGS.BAT %1 RELEASE -GOTO DONE - -:USAGE -ECHO Tag and build release kernels - usage: RELEASE {VERSION} e.g. RELEASE 2039 -:DONE -ECHO Please git push the tag to origin and upload the archives. -ECHO E.g. git push origin ke%1 diff --git a/bin/autoexec.bat b/bin/autoexec.bat index 54f3e645..ec624b1d 100644 --- a/bin/autoexec.bat +++ b/bin/autoexec.bat @@ -1,3 +1 @@ -@echo off -echo Welcome to FreeDOS (http://www.freedos.org)! -path=a:\ +@echo Welcome to FreeDOS (http://www.freedos.org)! diff --git a/bin/config.sys b/bin/config.sys index 1810c89d..092bc2b0 100644 --- a/bin/config.sys +++ b/bin/config.sys @@ -1,5 +1 @@ -rem dos=high -rem device=fdxms.sys (or himem.sys) -files=20 -buffers=20 -rem screen=0x12 +; diff --git a/boot/boot.asm b/boot/boot.asm index 1c427d25..7367110c 100644 --- a/boot/boot.asm +++ b/boot/boot.asm @@ -24,83 +24,50 @@ ; License along with DOS-C; see the file COPYING. If not, ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. - - -; Memory layout for the FreeDOS FAT12/FAT16 boot process: ; -; ... -; |-------| 1FE0h:7E00h = 27C00h (159 KiB) -; |BOOTSEC| loader relocates itself here first thing, -; |RELOC. | before loading root directory/FAT/kernel file -; |-------| 1FE0h:7C00h = 27A00h (158 KiB) -; | gap | PARAMS live here -; |LBA PKT| LBA disk packet -; |-------| 1FE0h:7BC0h = 279C0h (158 KiB) -; | gap | READADDR_* live here -; |-------| 1FE0h:7BA0h = 279A0h (158 KiB) -; | STACK | below relocated loader, above sector buffer (size 5.9 KiB) -; ... -; |-------| 1FE0h:6400h = 26200h (152 KiB) -; |SEC.BUF| sector buffer, to avoid crossing 64 KiB DMA boundary (size 8 KiB) -; |-------| 1FE0h:4400h = 24200h (144 KiB) -; ... -; |-------| 1FE0h:4380h = 24182h (144 KiB) -; |CLUSTER| built from FAT, listing every cluster of the kernel file. -; | LIST | file <= 134 KiB, cluster >= 32 Byte, hence <= 8578 B list. -; |-------| 1FE0h:2200h = 22000h (136 KiB) -; ... -; |-------| 0000h:7E00h = 07E00h (31.5 KiB) -; |BOOTSEC| possibly overwritten by the FAT (<= 128 KiB) and the kernel, -; |ORIGIN | so the bootsector relocates itself up... -; |-------| 0000h:7C00h = 07C00h (31 KiB) -; ... -; |-------| -; |KERNEL | maximum size 128 KiB (overwrites bootsec origin) -; |LOADED | (holds directory then FAT before kernel file load) -; |-------| 0060h:0000h = 00600h (1.5 KiB) -; ... -; The entire root directory is loaded to the kernel load address -; to scan for the kernel file. It is assumed to fit into 128 KiB. -; Typical root directory size is up to 512 entries = 16 KiB. -; Further, it is assumed that at least one root directory entry -; starts with a NUL byte to signify the end of the directory. -; After the directory entry is found, the entire FAT is loaded to -; the kernel load address. It is assumed that the size of the FAT -; in sectPerFat will not lead to a FAT larger than 128 KiB, which -; is the maximum size a FAT16 may fully utilise. -; The kernel load segment may be patched using the SYS /L switch. -; We support values between 0x60 and 0x200 here, with file size -; of up to 128 KiB (rounded to cluster size). Default is 0x60. -; This loader traditionally supports file sizes up to 134 KiB, -; assuming the default segment of 0x60. This does require a -; cluster size of 4 KiB (leads to maximum 132 KiB) or 2 KiB or -; lower (maximum 134 KiB). A more portable maximum is 128 KiB, -; which works with cluster sizes up to 128 KiB. +; +; +--------+ 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 -;verify one and only one of ISFAT12 or ISFAT16 is defined -%ifdef ISFAT12 - %ifdef ISFAT16 - %error Must select one FS - %endif -%elifndef ISFAT16 - %error Must select one FS -%endif - ; NOTE: sys must be updated if magic offsets change -%assign ISFAT1216DUAL 1 - %include "magic.mac" - -segment .text +segment .text %define BASE 0x7c00 org BASE Entry: jmp short real_start - nop + nop ; bp is initialized to 7c00h %define bsOemName bp+0x03 ; OEM label @@ -124,8 +91,8 @@ Entry: jmp short real_start %define LOADSEG 0x0060 -%define CLUSTLIST 0x2200 ; offset of temporary buffer for FAT - ; chain cluster list +%define FATBUF 0x2000 ; offset of temporary buffer for FAT + ; chain ; Some extra variables @@ -133,21 +100,12 @@ Entry: jmp short real_start ;----------------------------------------------------------------------- - times 36h - ($ - $$) db 0 - ; The filesystem ID is used by lDOS's instsect (by ecm) - ; by default to validate that the filesystem matches. -%ifdef ISFAT12 - %define FATFS "FAT12" -%elifdef ISFAT16 - %define FATFS "FAT16" -%endif - db FATFS - times 3Eh - ($ - $$) db 32 + 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 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 @@ -159,9 +117,9 @@ Entry: jmp short real_start %define LBA_SECTOR_32 word [LBA_PACKET+12] %define LBA_SECTOR_48 word [LBA_PACKET+14] -%define READBUF 0x4400 ; max 8 KiB buffer -%define READADDR_OFF word BP-0x60 ; pointer within user buffer -%define READADDR_SEG word BP-0x60+2 +%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 @@ -178,51 +136,49 @@ Entry: jmp short real_start ;----------------------------------------------------------------------- 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 + 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 - magicoffset "loadseg", 5Ch, 5Ch -loadseg_seg dw LOADSEG +loadseg_off dw 0 +loadseg_seg dw LOADSEG cont: - mov ds, ax - mov ss, ax - lea sp, [bp-0x60] - sti + 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) ; - magicoffset "set unit", 66h, 66h - mov [drive], dl ; rely on BIOS drive number in DL + 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 + 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. @@ -279,7 +235,7 @@ cont: les di, [loadsegoff_60] ; es:di = 60:0 - ; Search for KERNEL.SYS file name, and find start cluster. + ; Search for KERNEL.SYS file name, and find start cluster. next_entry: mov cx, 11 mov si, filename @@ -290,10 +246,10 @@ next_entry: mov cx, 11 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 + 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 - jmp boot_error ; fail if not found + jc boot_error ; fail if not found ffDone: push ax ; store first cluster number @@ -310,7 +266,7 @@ ffDone: ; ; Call with: AX = first cluster in chain - les bx, [loadsegoff_60] ; es:bx=60:0 + les bx, [loadsegoff_60] ; es:bx=60:0 mov di, [sectPerFat] mov ax, word [fat_start] mov dx, word [fat_start+2] @@ -320,8 +276,8 @@ ffDone: ; Set ES:DI to the temporary storage for the FAT chain. push ds pop es - mov ds, [loadseg_60] - mov di, CLUSTLIST + mov ds, [loadseg_60] + mov di, FATBUF next_clust: stosw ; store cluster number mov si, ax ; SI = cluster number @@ -340,8 +296,8 @@ fat_12: add si, si ; multiply cluster number by 3... ; the number was odd, CF was set in the last shift instruction. jnc fat_even - mov cl, 4 - shr ax, cl + mov cl, 4 + shr ax, cl fat_even: and ah, 0x0f ; mask off the highest 4 bits cmp ax, 0x0ff8 ; check for EOF @@ -378,7 +334,7 @@ finished: ; Mark end of FAT chain with 0, so we have a single les bx, [loadsegoff_60] ; set ES:BX to load address 60:0 - mov si, CLUSTLIST ; set DS:SI to the FAT chain + mov si, FATBUF ; set DS:SI to the FAT chain cluster_next: lodsw ; AX = next cluster to read or ax, ax ; EOF? @@ -390,9 +346,7 @@ load_next: dec ax ; cluster numbers start with 2 dec ax mov di, word [bsSecPerClust] - dec di ; minus one if 256 spc - and di, 0xff ; DI = sectors per cluster - 1 - inc di ; = spc + and di, 0xff ; DI = sectors per cluster mul di add ax, [data_start] adc dx, [data_start+2] ; DX:AX = first sector to read @@ -401,19 +355,18 @@ load_next: dec ax ; cluster numbers start with 2 ; shows text after the call to this function. -show.do_show: - mov ah, 0Eh ; show character - int 10h ; via "TTY" mode show: pop si lodsb ; get character push si ; stack up potential return address - cmp al, 0 ; end of string? - jne .do_show ; until done + 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.",0 - db "Error!",0 +; db "Error! Hit a key to reboot." + db "Error!." xor ah,ah int 0x13 ; reset floppy @@ -432,59 +385,53 @@ boot_error: call show readDisk: push si - mov LBA_SECTOR_0,ax - mov LBA_SECTOR_16,dx - mov word [READADDR_SEG], es - mov word [READADDR_OFF], bx + mov LBA_SECTOR_0,ax + mov LBA_SECTOR_16,dx + mov word [READADDR_SEG], es + mov word [READADDR_OFF], bx -%ifndef QUIET call show - db ".",0 -%else ; ensure code after this still at same location - times 5 nop -%endif + db "." read_next: ;******************** LBA_READ ******************************* - ; check for LBA support - - mov ah,041h ; - mov bx,055aah ; + ; check for LBA support + + mov ah,041h ; + mov bx,055aah ; mov dl, [drive] - - magicoffset "LBA detection", 17Bh, 178h - test dl,dl ; don't use LBA addressing on A: - jz read_normal_BIOS ; might be a (buggy) - ; CDROM-BOOT floppy emulation + 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 + jc read_normal_BIOS - shr cx,1 ; CX must have 1 bit set + shr cx,1 ; CX must have 1 bit set - sbb bx,0aa55h - 1 ; tests for carry (from shr) too! - jne read_normal_BIOS + sbb bx,0aa55h - 1 ; tests for carry (from shr) too! + jne read_normal_BIOS - - ; OK, drive seems to support LBA addressing + + ; OK, drive seems to support LBA addressing - lea si,[LBA_PACKET] + 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 + ; 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 + mov cx,LBA_SECTOR_0 + mov dx,LBA_SECTOR_16 ; @@ -557,7 +504,6 @@ do_int13_read: times 0x01f1-$+$$ db 0 - magicoffset "kernel name", 1F1h, 1F1h filename db "KERNEL SYS",0,0 sign dw 0xAA55 @@ -565,29 +511,28 @@ 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 + 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 + 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 + 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 index a5cc1d9f..8ac4f3c6 100644 --- a/boot/boot32.asm +++ b/boot/boot32.asm @@ -1,37 +1,34 @@ - -; Memory layout for the FreeDOS FAT32 single stage boot process: -; -; ... -; |-------| 1FE0h:7E00h = 27C00h (159 KiB) -; |BOOTSEC| loader relocates itself here first thing, -; |RELOC. | before loading root directory/FAT/kernel file -; |-------| 1FE0h:7C00h = 27A00h (158 KiB) -; | STACK | below relocated loader, above FAT sector (size 22 KiB) -; ... -; |-------| 2200h:2000h = 24000h (144 KiB) -; | FAT | (only 1 sector buffered, maximum sector size 8 KiB) -; |-------| 2200h:0000h = 22000h (136 KiB) -; ... -; |-------| 0000h:7E00h = 07E00h (31.5 KiB) -; |BOOTSEC| overwritten by the kernel, so the -; |ORIGIN | bootsector relocates itself up... -; |-------| 0000h:7C00h = 07C00h (31 KiB) -; ... -; |-------| -; |KERNEL | maximum size 128 KiB (overwrites bootsec origin) -; |LOADED | (holds 1 sector directory buffer before kernel file load) -; |-------| 0060h:0000h = 00600h (1.5 KiB) -; ... -; The kernel load segment may be patched using the SYS /L switch. -; We support values between 0x60 and 0x200 here, with file size -; of up to 128 KiB (rounded to cluster size). Default is 0x60. +; +--------+ +; | | +; | | +; |--------| 4000:0000 +; | | +; | FAT | +; | | +; |--------| 2000:0000 +; |BOOT SEC| +; |RELOCATE| +; |--------| 1FE0:0000 +; | | +; | | +; | | +; | | +; |--------| +; |BOOT SEC| +; |ORIGIN | 07C0:0000 +; |--------| +; | | +; | | +; | | +; |--------| +; |KERNEL | +; |LOADED | +; |--------| 0060:0000 +; | | +; +--------+ ;%define MULTI_SEC_READ 1 - ; NOTE: sys must be updated if magic offsets change -%assign ISFAT1216DUAL 0 - %include "magic.mac" - segment .text @@ -60,16 +57,11 @@ Entry: jmp short real_start %define xrootClst bp+0x2c ; Starting cluster of root directory %define drive bp+0x40 ; Drive number - times 52h - ($ - $$) db 0 - ; The filesystem ID is used by lDOS's instsect (by ecm) - ; by default to validate that the filesystem matches. - db "FAT32" - times 5Ah - ($ - $$) db 32 - + times 0x5a-$+$$ db 0 %define LOADSEG 0x0060 -%define FATSEG 0x2200 +%define FATSEG 0x2000 %define fat_sector bp+0x48 ; last accessed sector of the FAT @@ -100,14 +92,12 @@ real_start: cld jmp word 0x1FE0:cont loadseg_off dw 0 - magicoffset "loadseg", 78h loadseg_seg dw LOADSEG cont: mov ds, ax mov ss, ax lea sp, [bp-0x20] sti - magicoffset "set unit", 82h mov [drive], dl ; BIOS passes drive number in DL ; call print @@ -149,7 +139,7 @@ secshift: inc ax shr cx, 1 cmp cx, 1 jne secshift - mov word [fat_secshift], ax + mov byte [fat_secshift], al dec cx ; FINDFILE: Searches for the file in the root directory. @@ -221,10 +211,6 @@ c6: jmp short c5 boot_error: - mov ax, 0E00h | '!' - int 10h ; display the error sign - mov ax, 0E07h - int 10h ; beep xor ah,ah int 0x16 ; wait for a key int 0x19 ; reboot the machine @@ -245,7 +231,8 @@ next_cluster: cn_loop: shr dx,1 rcr ax,1 - loop cn_loop ; DX:AX fat sector where our + dec cx + jnz cn_loop ; DX:AX fat sector where our ; cluster resides ; DI - cluster index in this ; sector @@ -277,9 +264,8 @@ cn_exit: ret -boot_success: - mov dl, [drive] ; for Enhanced DR-DOS load - mov bl, dl ; for FreeDOS load +boot_success: + mov bl, [drive] jmp far [loadsegoff_60] ; Convert cluster to the absolute sector @@ -303,9 +289,7 @@ c3: sub ax, 2 sbb cx, byte 0 ; CX:AX == cluster - 2 mov bl, [bsSecPerClust] - dec bx ; bl = spc - 1, 0FFh if 256 spc - sub bh, bh ; bx = spc - 1 - inc bx ; bx = spc + sub bh, bh xchg cx, ax ; AX:CX == cluster - 2 mul bx ; first handle high word ; DX must be 0 here @@ -316,7 +300,6 @@ c3: adc dx, [data_start + 2] ret -%if 0 ; prints text after call to this function. print_1char: @@ -329,8 +312,7 @@ print1: lodsb ; get token cmp al, 0 ; end of string? jne print_1char ; until done ret ; and jump to it -%endif - + ;input: ; DX:AX - 32-bit DOS sector number ; ES:BX - destination buffer @@ -399,15 +381,12 @@ read_ok: mov es, cx no_incr_es: - inc ax - jnz .no_carry - inc dx -.no_carry: + add ax,byte 1 + adc dx,byte 0 ret times 0x01f1-$+$$ db 0 - magicoffset "kernel name", 1F1h filename db "KERNEL SYS",0,0 sign dw 0xAA55 diff --git a/boot/boot32lb.asm b/boot/boot32lb.asm index 7f0e48b8..aa1631bd 100644 --- a/boot/boot32lb.asm +++ b/boot/boot32lb.asm @@ -27,36 +27,27 @@ ; Memory layout for the FreeDOS FAT32 single stage boot process: -; + ; ... -; |-------| 1FE0h:7E00h = 27C00h (159 KiB) -; |BOOTSEC| loader relocates itself here first thing, -; |RELOC. | before loading root directory/FAT/kernel file -; |-------| 1FE0h:7C00h = 27A00h (158 KiB) -; | STACK | below relocated loader, above FAT sector (size 22 KiB) +; |-------| 1FE0:7E00 +; |BOOTSEC| +; |RELOC. | +; |-------| 1FE0:7C00 ; ... -; |-------| 2200h:2000h = 24000h (144 KiB) -; | FAT | (only 1 sector buffered, maximum sector size 8 KiB) -; |-------| 2200h:0000h = 22000h (136 KiB) +; |-------| 2000:0200 +; | FAT | (only 1 sector buffered) +; |-------| 2000:0000 ; ... -; |-------| 0000h:7E00h = 07E00h (31.5 KiB) +; |-------| 0000:7E00 ; |BOOTSEC| overwritten by the kernel, so the ; |ORIGIN | bootsector relocates itself up... -; |-------| 0000h:7C00h = 07C00h (31 KiB) +; |-------| 0000:7C00 ; ... ; |-------| -; |KERNEL | maximum size 128 KiB (overwrites bootsec origin) -; |LOADED | (holds 1 sector directory buffer before kernel file load) -; |-------| 0060h:0000h = 00600h (1.5 KiB) +; |KERNEL | maximum size 134k (overwrites bootsec origin) +; |LOADED | (holds 1 sector directory buffer before kernel load) +; |-------| 0060:0000 ; ... -; The kernel load segment may be patched using the SYS /L switch. -; We support values between 0x60 and 0x200 here, with file size -; of up to 128 KiB (rounded to cluster size). Default is 0x60. - - ; NOTE: sys must be updated if magic offsets change -%assign ISFAT1216DUAL 0 - %include "magic.mac" - segment .text @@ -94,7 +85,7 @@ Entry: jmp short real_start %define LOADSEG 0x0060 -%define FATSEG 0x2200 +%define FATSEG 0x2000 %define fat_secshift fat_afterss-1 ; each fat sector describes 2^?? ; clusters (db) (selfmodifying) @@ -105,11 +96,7 @@ Entry: jmp short real_start %define data_start bp+0x4c ; first data sector (dd) ; (overwriting unused bytes) - times 52h - ($ - $$) db 0 - ; The filesystem ID is used by lDOS's instsect (by ecm) - ; by default to validate that the filesystem matches. - db "FAT32" - times 5Ah - ($ - $$) db 32 + times 0x5a-$+$$ db 0 ; not used: [0x42] = byte 0x29 (ext boot param flag) ; [0x43] = dword serial ; [0x47] = label (padded with 00, 11 bytes) @@ -134,9 +121,7 @@ real_start: cld rep movsw ; move boot code to the 0x1FE0:0x0000 jmp word 0x1FE0:cont -loadseg_off dw 0 - magicoffset "loadseg", 78h - dw LOADSEG +loadseg_off dw 0, LOADSEG ; ------------- @@ -144,15 +129,10 @@ cont: mov ds, ax mov ss, ax ; stack and BP-relative moves up, too lea sp, [bp-0x20] sti - magicoffset "set unit", 82h mov [drive], dl ; BIOS passes drive number in DL -%ifndef QUIET mov si, msg_LoadFreeDOS call print ; modifies AX BX SI -%else ; ensure code after this still at same location - times 6 nop -%endif ; ------------- @@ -254,9 +234,7 @@ rk_walk_fat: pop eax ;----------------------------------------------------------------------- -boot_success: - mov dl, [drive] ; for Enhanced DR-DOS load - mov bl, dl ; for FreeDOS load +boot_success: mov bl, [drive] jmp far [loadsegoff_60] ;----------------------------------------------------------------------- @@ -331,8 +309,6 @@ convert_cluster: dec eax movzx edx, byte [bsSecPerClust] - dec dl ; spc - 1 - inc dx ; spc push edx mul edx pop edx @@ -421,7 +397,6 @@ 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. - magicoffset "kernel name", 1F1h filename db "KERNEL SYS" sign dw 0, 0xAA55 diff --git a/boot/magic.mac b/boot/magic.mac deleted file mode 100644 index c97aa01c..00000000 --- a/boot/magic.mac +++ /dev/null @@ -1,76 +0,0 @@ - -; Public Domain 2024 by E. C. Masloch - -%macro _appenddigitstrdef 2.nolist -%substr %%ii "0123456789ABCDEF" (%2) + 1 -%strcat _%1 _%1,%%ii -%endmacro - - ; %1 = name of single-line macro to set. will be prefixed by underscore - ; %2 = number to write - ; %3 = minimal number of hexits, 0..8. defaults to 1 - ; (setting it to 0 with a number of 0 defines macro to "") -%macro _autohexitsstrdef 2-3.nolist 1 -%if %3 > 8 - %error Minimal number of hexits 9 or more: %3 -%endif -%define _%1 "" -%if (%2) >= 1_0000_0000h - %error Number has to use 9 or more hexits: %2 -%endif -%if (%2) >= 1000_0000h || %3 >= 8 -_appenddigitstrdef %1, (%2 >> (7 * 4)) & 0Fh -%endif -%if (%2) >= 100_0000h || %3 >= 7 -_appenddigitstrdef %1, (%2 >> (6 * 4)) & 0Fh -%endif -%if (%2) >= 10_0000h || %3 >= 6 -_appenddigitstrdef %1, (%2 >> (5 * 4)) & 0Fh -%endif -%if (%2) >= 1_0000h || %3 >= 5 -_appenddigitstrdef %1, (%2 >> (4 * 4)) & 0Fh -%endif -%if (%2) >= 1000h || %3 >= 4 -_appenddigitstrdef %1, (%2 >> (3 * 4)) & 0Fh -%endif -%if (%2) >= 100h || %3 >= 3 -_appenddigitstrdef %1, (%2 >> (2 * 4)) & 0Fh -%endif -%if (%2) >= 10h || %3 >= 2 -_appenddigitstrdef %1, (%2 >> (1 * 4)) & 0Fh -%endif -%if (%2) >= 1h || %3 >= 1 -_appenddigitstrdef %1, (%2 >> (0 * 4)) & 0Fh -%endif -%endmacro - - %macro magicoffset 2-4.nolist ,0 -%if ISFAT1216DUAL - %ifdef ISFAT12 - %define SYSOFFSET %2 - %elifdef ISFAT16 - %define SYSOFFSET %3 - %else - %define SYSOFFSET 0 - ; Just a placeholder, so the proper error message - ; will be shown when assembling without either - ; of the ISFATx defines. - %endif -%else - %define SYSOFFSET %2 - %ifnempty %3 - %error Not in dual mode - %endif -%endif -%assign NEWOFFSET $ + %4 - Entry -%if NEWOFFSET != SYSOFFSET - _autohexitsstrdef NEWOFFSETHEX, NEWOFFSET - %strcat _NEWOFFSETHEX _NEWOFFSETHEX,'h' - %deftok NEWOFFSET _NEWOFFSETHEX - %if ISFAT1216DUAL - %error Magic offset %1 changed for FATFS, old=SYSOFFSET, new=NEWOFFSET - %else - %error Magic offset %1 changed, old=SYSOFFSET, new=NEWOFFSET - %endif -%endif - %endmacro diff --git a/boot/makefile b/boot/makefile index 01ea832a..ebb355cd 100644 --- a/boot/makefile +++ b/boot/makefile @@ -1,33 +1,37 @@ # # makefile for DOS-C boot # - +# $Id$ +# !include "../mkfiles/generic.mak" -production: fat12com.bin fat16com.bin fat32chs.bin fat32lba.bin oemfat12.bin oemfat16.bin +######################################################################## -fat12com.bin: boot.asm magic.mac - $(NASM) -dISFAT12 $(NASMBOOTFLAGS) boot.asm -lfat12com.lst -ofat12com.bin +all: fat12.bin fat16.bin fat32chs.bin fat32lba.bin oemfat12.bin oemfat16.bin -fat16com.bin: boot.asm magic.mac - $(NASM) -dISFAT16 $(NASMBOOTFLAGS) boot.asm -lfat16com.lst -ofat16com.bin +fat12.bin: boot.asm $(DEPENDS) + $(NASM) -DISFAT12 boot.asm -l$*.lst -o$*.bin -fat32chs.bin: boot32.asm magic.mac - $(NASM) $(NASMBOOTFLAGS) boot32.asm -lfat32chs.lst -ofat32chs.bin +fat16.bin: boot.asm $(DEPENDS) + $(NASM) -DISFAT16 boot.asm -l$*.lst -o$*.bin -fat32lba.bin: boot32lb.asm magic.mac - $(NASM) $(NASMBOOTFLAGS) boot32lb.asm -lfat32lba.lst -ofat32lba.bin +fat32chs.bin: boot32.asm $(DEPENDS) + $(NASM) boot32.asm -l$*.lst -o$*.bin -oemfat12.bin: oemboot.asm magic.mac - $(NASM) -dISFAT12 $(NASMBOOTFLAGS) oemboot.asm -loemfat12.lst -ooemfat12.bin +fat32lba.bin: boot32lb.asm $(DEPENDS) + $(NASM) boot32lb.asm -l$*.lst -o$*.bin -oemfat16.bin: oemboot.asm magic.mac - $(NASM) -dISFAT16 $(NASMBOOTFLAGS) oemboot.asm -loemfat16.lst -ooemfat16.bin +oemfat12.bin: oemboot.asm $(DEPENDS) + $(NASM) -DISFAT12 oemboot.asm -l$*.lst -o$*.bin -clobber: clean - -$(RM) *.bin status.me +oemfat16.bin: oemboot.asm $(DEPENDS) + $(NASM) -DISFAT16 oemboot.asm -l$*.lst -o$*.bin + +######################################################################## clean: - -$(RM) *.lst *.map *.bak *.obj + -$(RM) *.bak *.cod *.crf *.err *.las *.lst *.map *.obj *.xrf +clobber: clean + -$(RM) *.bin status.me diff --git a/boot/oemboot.asm b/boot/oemboot.asm index 5b1de2e6..a57bdbcc 100644 --- a/boot/oemboot.asm +++ b/boot/oemboot.asm @@ -116,11 +116,6 @@ ; |IVT | Interrupt Vector Table ; +--------+ 0000:0000 - ; NOTE: sys must be updated if magic offsets change -%assign ISFAT1216DUAL 1 - %include "magic.mac" - - CPU 8086 ; enable assembler warnings to limit instruction set ;%define ISFAT12 1 ; only 1 of these should be set, @@ -148,7 +143,7 @@ segment .text %define FATBUF bp-0x7500 ; offset of temporary buffer for FAT ; chain 0:FATBUF = 0:0700 = LOADSEG:0 -%define ROOTDIR 0x7C00-0x7700 ; offset to buffer for root directory +%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 @@ -228,22 +223,7 @@ Entry: jmp short real_start db 0x29 ; extended boot record id dd 0x12345678 ; volume serial number db 'NO NAME '; volume label - times 36h - ($ - $$) db 0 - ; The filesystem ID is used by lDOS's instsect (by ecm) - ; by default to validate that the filesystem matches. -%ifdef ISFAT12 - %define FATFS "FAT12" - %ifdef ISFAT16 - %error Must select one FS - %endif -%elifdef ISFAT16 - %define FATFS "FAT16" -%else - %define FATFS "unknown" - %error Must select one FS -%endif - db FATFS ; filesystem id - times 3Eh - ($ - $$) db 32 + db 'FAT12 ' ; filesystem id ;----------------------------------------------------------------------- ; ENTRY @@ -289,7 +269,6 @@ real_start: ; 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) ; - magicoffset "set unit", 4Fh, 4Fh mov [drive], dl ; rely on BIOS drive number in DL @@ -340,11 +319,11 @@ real_start: pop di ; mov di, word [RootDirSecs] pop ax ; mov ax, word [root_dir_start] pop dx ; mov dx, word [root_dir_start+2] - mov bx, ROOTDIR ; es:bx = 0:0500 + lea bx, [ROOTDIR] ; es:bx = 0:0500 push es ; save pointer to ROOTDIR call readDisk pop es ; restore pointer to ROOTDIR - mov si, ROOTDIR ; ds:si = 0:0500 + lea si, [ROOTDIR] ; ds:si = 0:0500 ; Search for kernel file name, and find start cluster. @@ -361,7 +340,6 @@ next_entry: mov cx, 11 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 - jmp boot_error ffDone: mov [first_cluster], ax ; store first cluster number @@ -369,7 +347,7 @@ ffDone: %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) - mov di, ROOTDIR ; es:di = 0:0500 + lea di, [ROOTDIR] ; es:di = 0:0500 mov cx, 32 ; limit to this 1 entry (rest don't matter) rep movsw %endif @@ -421,12 +399,11 @@ fat_12: add si, si ; multiply cluster number by 3... ; 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. - mov cl, 4 ; always initialise shift counter - jc fat_odd ; is odd, only shift down --> - shl ax, cl ; shift up (effectively masks off - ; the highest 4 bits) -fat_odd: + 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 @@ -478,14 +455,13 @@ cluster_next: lodsw ; AX = next cluster to read %else jmp LOADSEG:0000 ; yes, pass control to kernel %endif - magicoffset "load jump ofs", 11Ah, 118h, -4 ; failed to boot boot_error: call show -; db "Error! Hit a key to reboot.",0 - db "):",0 +; db "Error! Hit a key to reboot." + db "):." %ifdef LOOPONERR jmp $ %else @@ -502,9 +478,7 @@ load_next: dec ax ; cluster numbers start with 2 dec ax mov di, word [bsSecPerClust] - dec di ; minus one if 256 spc - and di, 0xff ; DI = sectors per cluster - 1 - inc di ; = spc + and di, 0xff ; DI = sectors per cluster mul di add ax, [data_start] adc dx, [data_start+2] ; DX:AX = first sector to read @@ -514,14 +488,13 @@ load_next: dec ax ; cluster numbers start with 2 ; shows text after the call to this function. -show.do_show: - mov ah, 0Eh ; show character - int 10h ; via "TTY" mode show: pop si lodsb ; get character push si ; stack up potential return address - cmp al, 0 ; end of string? - jne .do_show ; until done + mov ah,0x0E ; show character + int 0x10 ; via "TTY" mode + cmp al,'.' ; end of string? + jne show ; until done ret @@ -543,7 +516,7 @@ readDisk: push si ; preserve cluster # mov word [LBA_OFF], bx call show - db ".",0 + db "." read_next: ; initialize constants @@ -664,8 +637,6 @@ read_skip: ret times 0x01f1-$+$$ db 0 - - magicoffset "kernel name", 1F1h, 1F1h %ifdef MSCOMPAT filename db "IO SYS" %else diff --git a/build.bat b/build.bat index d939faf2..5d75ef5d 100644 --- a/build.bat +++ b/build.bat @@ -1,21 +1,19 @@ @echo off -rem batch file to build everything -rem IF NOTHING COMPILES, CHECK IF YOUR CVS CHECKOUT USES CORRECT DOS LINEBREAKS + +:- batch file to build everything +:- $Id$ 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 ":- [com] [com# #] [printf] " echo ":- option case is significant !! " echo ":- Note: Open Watcom (wc) is the preferred compiler " -echo ":- com does debug output on COM2, whereas com# 0 for COM1 ... " echo ":-----------------------------------------------------------------------" goto end :start -:- assume an error until successful build set XERROR=1 if "%XERROR%" == "" goto noenv @@ -26,7 +24,7 @@ if not exist config.bat echo You must copy CONFIG.B to CONFIG.BAT and edit it to if not exist config.bat goto abort call config.bat -:-if "%LAST%" == "" goto noenv +if "%LAST%" == "" goto noenv :----------------------------------------------------------------------- :- following is command line handling @@ -38,10 +36,10 @@ call config.bat if "%1" == "fat32" set XFAT=32 if "%1" == "fat16" set XFAT=16 -if "%1" == "msc" set COMPILER=MSCL8 +if "%1" == "msc" set COMPILER=MSC if "%1" == "wc" set COMPILER=WATCOM -if "%1" == "tc" set COMPILER=TC2 -if "%1" == "tcpp" set COMPILER=TURBOCPP +if "%1" == "tc" set COMPILER=TC +if "%1" == "tcpp" set COMPILER=TCPP if "%1" == "bc" set COMPILER=BC if "%1" == "86" set XCPU=86 @@ -52,23 +50,11 @@ if "%1" == "x86" goto setCPU if "%1" == "upx" set XUPX=upx --8086 --best if "%1" == "debug" set ALLCFLAGS=%ALLCFLAGS% -DDEBUG -if "%1" == "print" set ALLCFLAGS=%ALLCFLAGS% -DDEBUG_NEED_PRINTF -if "%1" == "printf" set ALLCFLAGS=%ALLCFLAGS% -DDEBUG_NEED_PRINTF - -if "%1" == "lfn" set ALLCFLAGS=%ALLCFLAGS% -DWITHLFNAPI if "%1" == "lfnapi" set ALLCFLAGS=%ALLCFLAGS% -DWITHLFNAPI if "%1" == "win" set ALLCFLAGS=%ALLCFLAGS% -DWIN31SUPPORT if "%1" == "win" set NASMFLAGS=%NASMFLAGS% -DWIN31SUPPORT -if "%1" == "com" set ALLCFLAGS=%ALLCFLAGS% -DDEBUG_PRINT_COMPORT -if "%1" == "com" set NASMFLAGS=%ALLCFLAGS% -DDEBUG_PRINT_COMPORT -REM specify comport, default is COM2, 0=COM1, 1=COM2, 2=COM3 -if "%1" == "com#" set ALLCFLAGS=%ALLCFLAGS% -DDEBUG_PRINT_COMPORT %2 -if "%1" == "com#" set NASMFLAGS=%ALLCFLAGS% -DDEBUG_PRINT_COMPORT %2 -if "%1" == "com#" shift -if "%1" == "com#" goto nextOption - if "%1" == "list" set NASMFLAGS=%NASMFLAGS% -l$*.lst if "%1" == "/L" goto setLoadSeg @@ -78,8 +64,11 @@ if "%1" == "/D" goto setDefine shift if not "%1" == "" goto loop_commandline -call default.bat -:-if "%LAST%" == "" goto noenv +if "%COMPILER%" == "" echo you MUST define a COMPILER variable in CONFIG.BAT +if "%COMPILER%" == "" goto abort + +call defaults.bat +if "%LAST%" == "" goto noenv :----------------------------------------------------------------------- :- finally - we are going to compile @@ -91,35 +80,35 @@ echo. echo Process UTILS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ echo. cd utils -%MAKE% production +call %MAKE% all if errorlevel 1 goto abort-cd echo. echo Process LIB ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ echo. cd ..\lib -%MAKE% +call %MAKE% all if errorlevel 1 goto abort-cd echo. echo Process DRIVERS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ echo. cd ..\drivers -%MAKE% production +call %MAKE% all if errorlevel 1 goto abort-cd echo. echo Process BOOT +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ echo. cd ..\boot -%MAKE% production +call %MAKE% all if errorlevel 1 goto abort-cd echo. echo Process SYS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ echo. cd ..\sys -%MAKE% production +call %MAKE% all if errorlevel 1 goto abort-cd if NOT "%XUPX%" == "" %XUPX% ..\bin\sys.com @@ -127,30 +116,15 @@ echo. echo Process KERNEL +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ echo. cd ..\kernel -%MAKE% production -if errorlevel 1 goto abort-cd - -echo. -echo Process COUNTRY +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -echo. -cd ..\country -set TMAKE=%MAKE% -if "%COMPILER%" == "TC2" set TMAKE=c:\bin\make -%TMAKE% DIRSEP=\ CP=copy production -if errorlevel 1 goto abort-cd - -echo. -echo Process SETVER +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -echo. -cd ..\setver -%MAKE% production +call %MAKE% all if errorlevel 1 goto abort-cd cd .. +:- if you like, put finalizing commands (like copy to floppy) into build2.bat + set XERROR= -:- if you like, put finalizing commands (like copy to floppy) into build2.bat if exist build2.bat call build2.bat echo. @@ -181,18 +155,8 @@ 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 -REM $(NASMBOOTFLAGS) are extra flags only used when building boot sectors -set NASMBOOTFLAGS=%NASMBOOTFLAGS% -d%1 -goto nextOption - -:setDefineWithValue -set ALLCFLAGS=%ALLCFLAGS% -D%1=%3 -set NASMFLAGS=%NASMFLAGS% -D%1=%3 -shift -shift goto nextOption :noenv @@ -206,4 +170,4 @@ cd .. echo Compilation was aborted! :end -call default.bat clearset +call defaults.bat clearset diff --git a/buildall.bat b/buildall.bat index 64cfe257..548ed33b 100644 --- a/buildall.bat +++ b/buildall.bat @@ -1,65 +1,77 @@ @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 :-) +:- batch file to build _many_ KERNELS :---------------------------------------------------------- if "%1" == "$SUMMARY" goto summary -set onerror=if not "%XERROR%" == "" goto daswarwohlnix +call config.bat +if "%LAST%" == "" goto end -:***** MSCL kernels +:***** MSVC kernels -call config.bat +if "%MSC_BASE%" == "" goto no_ms + call build.bat -r msc 386 fat16 +if "%XERROR%" == "" call build.bat -r msc 186 fat16 +if "%XERROR%" == "" call build.bat -r msc 86 fat16 +if "%XERROR%" == "" call build.bat -r msc 386 fat32 +if "%XERROR%" == "" call build.bat -r msc 186 fat32 +if "%XERROR%" == "" call build.bat -r msc 86 fat32 -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% +if not "%XERROR%" == "" goto daswarwohlnix :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% +if "%TC_BASE%" == "" goto no_tc + call build.bat -r tc 186 fat16 +if "%XERROR%" == "" call build.bat -r tc 86 fat16 +if "%XERROR%" == "" call build.bat -r tc 186 fat32 +if "%XERROR%" == "" call build.bat -r tc 86 fat32 + +if not "%XERROR%" == "" goto daswarwohlnix :no_tc +:***** TCPP kernels + +if "%TCPP_BASE%" == "" goto no_tcpp + call build.bat -r tcpp 186 fat16 +if "%XERROR%" == "" call build.bat -r tcpp 86 fat16 +if "%XERROR%" == "" call build.bat -r tcpp 186 fat32 +if "%XERROR%" == "" call build.bat -r tcpp 86 fat32 + +if not "%XERROR%" == "" goto daswarwohlnix +:no_tcpp + +:***** BC kernels + +if "%BC_BASE%" == "" goto no_bc + call build.bat -r bc 386 fat16 +if "%XERROR%" == "" call build.bat -r bc 186 fat16 +if "%XERROR%" == "" call build.bat -r bc 86 fat16 +if "%XERROR%" == "" call build.bat -r bc 386 fat32 +if "%XERROR%" == "" call build.bat -r bc 186 fat32 +if "%XERROR%" == "" call build.bat -r bc 86 fat32 + +if not "%XERROR%" == "" goto daswarwohlnix +:no_bc + :***** (Open) Watcom kernels -if not "%COMPILER%" == "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% +if "%WATCOM%" == "" goto no_wc + call build.bat -r wc 386 fat32 +if "%XERROR%" == "" call build.bat -r wc 386 fat16 +if "%XERROR%" == "" call build.bat -r wc 86 fat32 +if "%XERROR%" == "" call build.bat -r wc 86 fat16 + +if not "%XERROR%" == "" goto daswarwohlnix :no_wc - + :***** now rebuild the default kernel -call build -r +call build.bat -r +if not "%XERROR%" == "" goto daswarwohlnix :************************************************************** :* now we build a summary of all kernels HMA size + total size @@ -71,30 +83,30 @@ set Sumfile=bin\ksummary.txt set TempSumfile=bin\tsummary.txt :****echo >%TempSumfile% Summary of all kernels build -:****echo.|date >>%TempSumfile% -:****echo.|time >>%TempSumfile% +:****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% +if exist %Sumfile% del %Sumfile%>nul +if exist %TempSumfile% del %TempSumfile%>nul >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 +del ktemp.bat>nul +del ktemps.bat>nul echo >>%Sumfile% Summary of all kernels build -echo.|date >>%Sumfile% -echo.|time >>%Sumfile% +echo.|date >>%Sumfile% +echo.|time >>%Sumfile% find <%TempSumfile% "H" >>%Sumfile% -del %TempSumfile% +del %TempSumfile%>nul set TempSumfile= set Sumfile= goto end -:summary +:summary echo H************************************************* %2 >>%TempSumfile% find<%2 " HMA_TEXT"|find/V "HMA_TEXT_START"|find/V "HMA_TEXT_END">>%TempSumfile% find<%2 " STACK">>%TempSumfile% @@ -104,6 +116,5 @@ goto end :daswarwohlnix echo Sorry, something didn't work as expected :-( -set ONERROR= :end diff --git a/ci_build.sh b/ci_build.sh deleted file mode 100755 index 284bbd4f..00000000 --- a/ci_build.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/sh - -set -e - -if [ -z "${BUILD_DIR}" ] ; then - BUILD_DIR=$(pwd) -fi -echo BUILD_DIR is \"${BUILD_DIR}\" - -# Output directory -rm -rf _output -mkdir _output - -# GCC -mkdir _output/gcc -git clean -x -d -f -e test -e _output -e _downloads -e _watcom -make -C country clean -make all COMPILER=gcc -mv -n bin/kgc*.map bin/kgc*.sys _output/gcc/. -mv -n bin/country.sys _output/gcc/. -# GCC share -( - cd share - git submodule update --init --recursive - git clean -x -d -f - env COMPILER=gcc ./build.sh -) -mv -n share/src/share.com _output/gcc/. -mv -n share/src/share.map _output/gcc/. - -# Open Watcom Environment Setup -export WATCOM=$BUILD_DIR/_watcom -export PATH=$BUILD_DIR/bin:$PATH:$WATCOM/binl64 - -mkdir _output/wc -git clean -x -d -f -e test -e _output -e _downloads -e _watcom -make -C country clean -make all COMPILER=owlinux -mv -n bin/kwc*.map bin/kwc*.sys _output/wc/. -mv -n bin/country.sys _output/wc/. - -## DOS (GCC) -#mkdir _output/gcc_dos -#git clean -x -d -f -e test -e _output -e _downloads -e _watcom -#{ -# echo set COMPILER=GCC -# echo set MAKE=make -# echo set XCPU=386 -# echo set XFAT=32 -# echo set XNASM=nasm -# echo set OLDPATH=%PATH% -# echo set PATH='C:\\devel\\i16gnu\\bin;C:\\devel\\nasm;C:\\bin;%OLDPATH%' -#} | unix2dos > config.bat - -#dosemu -td -q -K . -E "build.bat" - -# DOS (Watcom) -mkdir _output/wc_dos -git clean -x -d -f -e test -e _output -e _downloads -e _watcom -{ - echo set COMPILER=WATCOM - echo set WATCOM='C:\\devel\\watcomc' - echo set MAKE=wmake /ms - echo set XCPU=386 - echo set XFAT=32 - echo set XNASM=nasm - echo set XUPX=upx --8086 --best - echo set OLDPATH=%PATH% - echo set PATH='%WATCOM%\\binw;C:\\devel\\nasm;C:\\bin;%OLDPATH%' - echo set DOS4G=QUIET -} | unix2dos > config.bat - -dosemu -td -q -K . -E "build.bat" -mv -n bin/kwc*.map bin/kwc*.sys _output/wc_dos/. -mv -n bin/country.sys _output/wc_dos/. - - -# DOS (Turbo C 2.01) -if [ -d ${HOME}/.dosemu/drive_c/tc201 ] ; then - mkdir _output/tc_dos - git clean -x -d -f -e test -e _output -e _downloads -e _watcom - { - echo set COMPILER=TC2 - echo set TC2_BASE='C:\\tc201' - echo set MAKE=make - echo set XCPU=86 - echo set XFAT=32 - echo set XNASM=nasm - echo set OLDPATH=%PATH% - echo set PATH='%TC2_BASE%;C:\\devel\\nasm;C:\\bin;%OLDPATH%' - } | unix2dos > config.bat - - dosemu -td -q -K . -E "build.bat" - mv -n bin/ktc*.map bin/ktc*.sys _output/tc_dos/. - mv -n bin/country.sys _output/tc_dos/. - # TC share - ( - cd share - git submodule update --init --recursive - git clean -x -d -f - env COMPILER=tcc2-emu ./build.sh - ) - mv -n share/src/share.com _output/tc_dos/. - mv -n share/src/share.map _output/tc_dos/. -fi - -echo done diff --git a/ci_prereq.sh b/ci_prereq.sh deleted file mode 100755 index c8bf0329..00000000 --- a/ci_prereq.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/sh - -set -e - -sudo add-apt-repository -y ppa:tkchia/build-ia16 -sudo add-apt-repository -y ppa:dosemu2/ppa -sudo apt update - -# for cross building -sudo apt install gcc-ia16-elf libi86-ia16-elf nasm upx qemu-system-x86 mtools util-linux bash - -# for building with DOS using an emulator -sudo apt install dosemu2 dos2unix -# Perhaps later we should build using Freecom from published package - -mkdir -p _downloads -mkdir -p _watcom -cd _downloads - -HERE=$(pwd) - -# download and unpack Open Watcom snapshot -[ -f ow-snapshot.tar.xz ] || wget --no-verbose https://github.com/open-watcom/open-watcom-v2/releases/download/Current-build/ow-snapshot.tar.xz -tar -C ../_watcom -xf ow-snapshot.tar.xz - -IBIBLIO_PATH='https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/repositories/1.4' - -BASE=${IBIBLIO_PATH}/base - -# get FreeDOS kernel -[ -f kernel.zip ] || wget --no-verbose ${BASE}/kernel.zip - -# get FreeCOM -[ -f freecom.zip ] || wget --no-verbose ${BASE}/freecom.zip - -DEVEL=${IBIBLIO_PATH}/devel - -# get gnumake for DOS -[ -f dj_make.zip ] || wget --no-verbose ${DEVEL}/dj_make.zip - -# get nasm for DOS -[ -f nasm.zip ] || wget --no-verbose ${DEVEL}/nasm.zip - -# get upx for DOS -[ -f upx.zip ] || wget --no-verbose ${DEVEL}/upx.zip - -# grab ia16-gcc from ibiblio.org -#[ -f i16gcc.zip ] || wget --no-verbose ${DEVEL}/i16gcc.zip -#[ -f i16newli.zip ] || wget --no-verbose ${DEVEL}/i16newli.zip -#[ -f i16butil.zip ] || wget --no-verbose ${DEVEL}/i16butil.zip -#[ -f i16lbi86.zip ] || wget --no-verbose ${DEVEL}/i16lbi86.zip - -# get watcom for DOS -[ -f watcomc.zip ] || wget --no-verbose ${DEVEL}/watcomc.zip - -# get Turbo C 2.01 (maybe encrypted) tar file -if [ -n "${TC201_ARCHIVE_FILENAME}" ] && [ ! -f ${TC201_ARCHIVE_FILENAME} ] ; then - echo "Downloading Turbo C 2.01" - wget --no-verbose ${TC201_ARCHIVE_PATHNAME}/${TC201_ARCHIVE_FILENAME} -fi - -mkdir -p ${HOME}/.dosemu/drive_c -cd ${HOME}/.dosemu/drive_c && ( - - mkdir -p bin - - # Boot files - unzip -LL -q ${HERE}/kernel.zip - cp -p bin/kernl386.sys ./kernel.sys - unzip -LL -q ${HERE}/freecom.zip - cp -p bin/command.com ./command.com - cp -p /usr/share/dosemu/dosemu2-cmds-0.3/c/fdconfig.sys . - - # Development files - unzip -LL -q ${HERE}/dj_make.zip - cp -p devel/djgpp/bin/make.exe bin/. - unzip -LL -q ${HERE}/upx.zip - cp -p devel/upx/upx.exe bin/. - echo PATH to make and upx binaries is 'c:/bin' - - unzip -LL -q ${HERE}/nasm.zip - echo PATH to nasm binary is 'c:/devel/nasm' - -# unzip -LL -q ${HERE}/i16gcc.zip -# unzip -LL -q ${HERE}/i16newli.zip -# unzip -LL -q ${HERE}/i16butil.zip -# unzip -LL -q ${HERE}/i16lbi86.zip -# echo PATH to ia16 binaries is 'c:/devel/i16gnu/bin' - - unzip -LL -q ${HERE}/watcomc.zip - echo PATH to watcom binaries is 'c:/devel/watcomc/binw' - - # Turbo C - if [ -f ${HERE}/${TC201_ARCHIVE_FILENAME} ] && [ -n "${TC201_ARCHIVE_PASSPHRASE}" ] ; then - echo Decrypting and unpacking Turbo C 2.01 - echo "${TC201_ARCHIVE_PASSPHRASE}" | gpg --decrypt --batch --passphrase-fd 0 ${HERE}/${TC201_ARCHIVE_FILENAME} | tar -jxf - - elif [ -f ${HERE}/${TC201_ARCHIVE_FILENAME} ] ; then - echo Unpacking Turbo C 2.01 - tar -jxf ${HERE}/${TC201_ARCHIVE_FILENAME} - else - echo No Turbo C 2.01 archive available - fi -) diff --git a/ci_test.sh b/ci_test.sh deleted file mode 100755 index 4bed908c..00000000 --- a/ci_test.sh +++ /dev/null @@ -1,52 +0,0 @@ -#! /bin/bash - -KVER=8632 - -if [ ! -f _output/gcc/kgc${KVER}.sys ] ; then - echo GCC built kernel not present - exit 1 -fi - -if [ ! -f _output/wc/kwc${KVER}.sys ] ; then - echo Watcom built kernel not present - exit 1 -fi - -if [ ! -f _output/wc_dos/kwc38632.sys ] ; then - echo Watcom DOS built kernel not present - exit 1 -fi - -if [ ! -f _output/tc_dos/ktc8632.sys ] && [ -d ${HOME}/.dosemu/drive_c/tc201 ] ; then - echo Turbo C 2.01 built kernel not present - exit 1 -fi - -echo Kernels have all been built -find _output -ls - -cd test -if ! ./test.sh ../_output/gcc/kgc${KVER}.sys diskgc bootgc 'boot gcc: ' -then - echo GCC boot test failed - exit 2 -fi -if ! ./test.sh ../_output/wc/kwc${KVER}.sys diskwc bootwc 'boot wc: ' -then - echo OpenWatcom boot test failed - exit 2 -fi -if ! ./test.sh ../_output/wc_dos/kwc38632.sys diskwcd bootwcd 'boot wcd: ' -then - echo 'OpenWatcom(DOS) boot test failed' - exit 2 -fi -if [ -d ${HOME}/.dosemu/drive_c/tc201 ] ; then - if ! ./test.sh ../_output/tc_dos/ktc8632.sys disktcd boottcd 'boot tcd: ' - then - echo 'Turbo C 2.01 boot test failed' - exit 2 - fi -fi -cd .. -exit 0 diff --git a/clean.bat b/clean.bat index 76a2bb1c..ed74cd7a 100644 --- a/clean.bat +++ b/clean.bat @@ -1,40 +1,45 @@ @echo off -:- batch file to clean everything -:- $Id: clean.bat 1181 2006-05-20 20:45:59Z mceric $ +:- batch file to clean and clobber everything +:- $Id$ +if "%1" == "" %0 clean +goto %1 +goto end + +:clean +:clobber 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 +if not "%LAST%" == "" call defaults.bat +if "%LAST%" == "" goto end cd utils -%MAKE% clean +call %MAKE% %1 cd ..\lib -%MAKE% clean +call %MAKE% %1 cd ..\drivers -%MAKE% clean +call %MAKE% %1 cd ..\boot -%MAKE% clean +call %MAKE% %1 cd ..\sys -%MAKE% clean +call %MAKE% %1 cd ..\kernel -%MAKE% clean - -cd ..\setver -%MAKE% clean +call %MAKE% %1 cd ..\hdr -if exist *.bak del *.bak +if exist *.bak del *.bak>nul cd .. -if exist *.bak del *.bak +if exist *.bak del *.bak>nul +if "%1"=="clobber" if exist status.me del status.me>nul :end -default.bat clearset +defaults.bat clearset diff --git a/clobber.bat b/clobber.bat index 4c6d91d7..074a6363 100644 --- a/clobber.bat +++ b/clobber.bat @@ -1,46 +1 @@ -@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 ..\setver -%MAKE% clobber - -cd ..\hdr -if exist *.bak del *.bak - -cd ..\bin -if exist sys.com del sys.com -if exist country.sys del country.sys - -cd .. -if exist *.bak del *.bak -if exist status.me del status.me - - -:end -default.bat clearset +@clean clobber \ No newline at end of file diff --git a/config.b b/config.b index fd8ebf53..ecbd191f 100644 --- a/config.b +++ b/config.b @@ -1,126 +1,121 @@ -:- +@echo off + :- batch file that is included in all other batch files for configuration +:- $Id$ + +:----------------------------------------------------------------------- +:- NOTICE! You must edit and rename this file to CONFIG.BAT! +:----------------------------------------------------------------------- + +:- determine compiler(s) settings. :- +:- you REQUIRED to +:- search for NASM - and set the path to NASM +:- search for COMPILER - and set the default compiler name +:- search for ??_BASE - and set the path to (all) compiler(s) + +set LAST= -:-**************************************************************** -:- 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 -:- because DJGPP-nasm crashes when using protected mode Borland's -:- make under Windows NT/2k/XP -:-********************************************************************** - -set XNASM=nasm - -:********************************************************************** -:- define your COMPILER type here, pick one of them -:********************************************************************** +:----------------------------------------------------------------------- +:- define NASM executable. It should not be protected mode DJGPP +:- version if you're using Windows NT/2k/XP to compile. also: +:- NASM/DJGPP crashes when using protected mode Borland's make. + +set NASM=c:\bin\nasm16 +::set NASM=c:\bin\nasmw.exe + +:----------------------------------------------------------------------- +:- define COMPILER name here, pick one of them. :- Turbo C 2.01 -:- set COMPILER=TC2 +:: set COMPILER=TC :- Turbo C++ 1.01 -:- set COMPILER=TURBOCPP -:- Turbo C 3.0 -:- set COMPILER=TC3 -:- Borland C 3.1 -set COMPILER=BC3 +::set COMPILER=TCPP +:- Turbo C++ 3.0 +::set COMPILER=TCPP3 :- Borland C -:- set COMPILER=BC5 +::set COMPILER=BC :- Microsoft C -:- set COMPILER=MSCL8 -:- Watcom C (for DOS) -:- set COMPILER=WATCOM -:- Watcom C (for Windows) -:- set COMPILER=OWWIN - -:-********************************************************************** -:-- 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 BC3_BASE=c:\bc -:- 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 -:- set DOS4G=QUIET -: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! -:-********************************************************************** +::set COMPILER=MSC +:- Watcom C +set COMPILER=WATCOM + +:----------------------------------------------------------------------- +:- define BASE dir of compiler; +:- may be defined for all installed compilers. + +::set TC_BASE=c:\tc +::set TCPP_BASE=c:\tcpp +::set TCPP3_BASE=c:\tcpp3 +::set BC_BASE=c:\bc +::set MSC_BASE=c:\msc +set WATCOM=c:\watcom + +:----------------------------------------------------------------------- +:- define which linker to use OR it will be determined AUTOMATICALLY. :- Turbo Link -:- set XLINK=tlink /m/c/s/l +::set LINK=tlink /c/m/s/l :- Microsoft Link -:- set XLINK=d:\qb\link /ma -:- set XLINK=%MS_BASE%\bin\link /ONERROR:NOEXE /ma /nologo +::set LINK=link /ONERROR:NOEXE /nologo :- WATCOM Link (wlinker is a batch file calling ms2wlink and wlink) -:- set XLINK=..\utils\wlinker /ma /nologo +::set LINK=..\utils\wlinker /nologo -:- set path for Turbo Link - use OLDPATH to restore normal path -:- set OLDPATH=%PATH% -:- set PATH=%PATH%;%TC2_BASE% +:----------------------------------------------------------------------- +:- define which librarian to use OR it will be determined AUTOMATICALLY. -:********************************************************************** -:* 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 -:********************************************************************** +:- Turbo Lib +::set LIBUTIL=tlib +::set LIBTERM= +:- Microsoft Lib +::set LIBUTIL=lib /nologo +::set LIBTERM=; +:- WATCOM Lib +::set LIBUTIL=wlib -q +::set LIBTERM= + +:----------------------------------------------------------------------- +:- define which MAKE to use OR it will be determined AUTOMATICALLY. :- Borland MAKE -:- set MAKE=%TC2_BASE%\make +::set MAKE=make +::set MAKE=maker -S :- Watcom MAKE in MS mode -:- set MAKE=%WATCOM%\binw\wmake /ms +::set MAKE=wmake /ms :- Microsoft MAKE -:- set MAKE=%MS_BASE%\bin\nmake /nologo +::set MAKE=nmake /nologo +::set MAKE=nmaker /nologo + +:----------------------------------------------------------------------- +:- This section can still be used if you need special consideration +:- for UPX, such as it is not in your PATH or you do not want +:- 8086 compatible settings, otherwise the recommended use is now +:- to add 'upx' option to the build.bat command line -:********************************************************************** -:* select your default target: required CPU and what FAT system to support -:********************************************************************** +:- where is UPX and which options to use +:- (comment this out if you don't want to use it) -:- set XCPU=86 -:- set XCPU=186 -set XCPU=386 +::set XUPX=upx --8086 --best -:- set XFAT=16 -set XFAT=32 +:----------------------------------------------------------------------- +:- select default target: CPU type (default is 86) and +:- what FAT system (default is 32) to support +:- NOTE: Turbo C doesn't support 386 CPU. + +::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 +:- -DWIN31SUPPORT : extra Win3.x API support +::set ALLCFLAGS=-DDEBUG +:----------------------------------------------------------------------- -:- -:- $Id: config.b 864 2004-04-11 12:21:25Z bartoldeman $ -:- +set LAST=1 +if not "%LAST%" == "1" defaults.bat clearset diff --git a/config.m b/config.m deleted file mode 100644 index 5f89492f..00000000 --- a/config.m +++ /dev/null @@ -1,65 +0,0 @@ -# -# 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/country b/country deleted file mode 160000 index 7f83e041..00000000 --- a/country +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7f83e041d00f78b3912c761246930f3b437440f6 diff --git a/default.bat b/default.bat deleted file mode 100644 index 5f24f026..00000000 --- a/default.bat +++ /dev/null @@ -1,88 +0,0 @@ -@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%" == "BC3" set MAKE=%BC3_BASE%\bin\make -if "%COMPILER%" == "BC5" set MAKE=%BC5_BASE%\bin\make -if "%COMPILER%" == "WATCOM" set MAKE=wmake /ms /h -if "%COMPILER%" == "OWWIN" 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%" == "BC3" set XLINK=%BC3_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%" == "OWWIN" 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 BC3_BASE= -set BC5_BASE= -set MS_BASE= -set XNASM= -set NASMFLAGS= -set NASMBOOTFLAGS= -set XUPX= -set UPXOPT= -set LOADSEG= - -:end diff --git a/defaults.bat b/defaults.bat new file mode 100644 index 00000000..3835e3d9 --- /dev/null +++ b/defaults.bat @@ -0,0 +1,111 @@ +@echo off + +:- $Id$ + +set LAST= +if "%1" == "clearset" goto clearset + +:----------------------------------------------------------------------- + +if "%COMPILER%" == "TC" set BASE=%TC_BASE% +if "%COMPILER%" == "TCPP" set BASE=%TCPP_BASE% +if "%COMPILER%" == "TCPP3" set BASE=%TCPP3_BASE% +if "%COMPILER%" == "BC" set BASE=%BC_BASE% +if "%COMPILER%" == "WATCOM" set BASE=%WATCOM% +if "%COMPILER%" == "MSC" set BASE=%MSC_BASE% +if "%BASE%" == "" goto clearset + +:----------------------------------------------------------------------- + +if not "%BINPATH%" == "" goto skip_binpath +set BINPATH=%BASE%\bin +if "%COMPILER%" == "TC" set BINPATH=%BASE% +if "%COMPILER%" == "WATCOM" set BINPATH=%BASE%\binw +if "%COMPILER%-%OS%" == "WATCOM-Windows_NT" set BINPATH=%BASE%\binnt + +:skip_binpath +echo Path to compiler programs (binaries) is %BINPATH% + +:----------------------------------------------------------------------- +:- When compiling executable, compilers may invoke secondary programs +:- such as preprocessor, compiler component, or linker through PATH; + +set OLDPATH=%PATH% +set PATH=%BINPATH%;%PATH% + +:- MSC searches libraries only through LIB variable. +:- If already set then assume preset to include MSC's lib +if "%COMPILER%%LIB%" == "MSC" set LIB=%MSC_BASE%\lib + +:----------------------------------------------------------------------- + +if not "%LINK%" == "" goto skip_link + +set LINK=%BINPATH%\tlink /c/m/s/l +if "%COMPILER%" == "WATCOM" set LINK=..\utils\wlinker /nologo +if "%COMPILER%" == "MSC" set LINK=%BINPATH%\link /ONERROR:NOEXE /batch + +echo Linker is %LINK% + +:skip_link + +:----------------------------------------------------------------------- + +if not "%LIBUTIL%" == "" goto skip_lib + +set LIBUTIL=%BINPATH%\tlib +set LIBTERM= +if "%COMPILER%" == "WATCOM" set LIBUTIL=%BINPATH%\wlib -q +if "%COMPILER%" == "MSC" set LIBUTIL=%BINPATH%\lib /nologo +if "%COMPILER%" == "MSC" set LIBTERM=; + +echo Librarian is %LIBUTIL% + +:skip_lib + +:----------------------------------------------------------------------- + +if not "%MAKE%" == "" goto skip_make + +set MAKE=%BINPATH%\make +if "%COMPILER%" == "WATCOM" set MAKE=%BINPATH%\wmake /ms /h +if "%COMPILER%" == "MSC" set MAKE=%BINPATH%\nmake /nologo + +echo Make is %MAKE% + +:skip_make + +:----------------------------------------------------------------------- + +set LAST=1 +if "%LAST%" == "1" goto end + +:----------------------------------------------------------------------- + +:clearset + +set NASM= +set NASMFLAGS= +set COMPILER= +set BASE= +set BINPATH= +set TC_BASE= +set TCPP_BASE= +set TCPP3_BASE= +set BC_BASE= +set MSC_BASE= +set LINK= +set LIBUTIL= +set LIBTERM= +set MAKE= +set XUPX= +set XCPU= +set XCPU_EX= +set XFAT= +set ALLCFLAGS= +set LOADSEG= + +if not "%OLDPATH%" == "" set PATH=%OLDPATH% +set OLDPATH= + +:end diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index af56caf1..00000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -kernel.fdos.org \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 910185c2..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1,4 +0,0 @@ -theme: jekyll-theme-tactile -title: "FreeDOS kernel" -description: "Implementation of the core DOS API for FreeDOS, kernel.sys" -show_downloads: "true" diff --git a/docs/bugs.txt b/docs/bugs.txt index 1da21566..d6e71e18 100644 --- a/docs/bugs.txt +++ b/docs/bugs.txt @@ -1,15 +1,6 @@ -Please report kernel bugs / issues on GitHub at +The current bug database is available on the web at - https://github.com/FDOS/kernel/issues + http://www.freedos.org/freedos/bugs/ -For support (or if you don't wish to use GitHub) then -please use the FreeDOS developer and/or user mailing list. - -The former bug database is available on the web at - - http://sourceforge.net/tracker/?group_id=5109&atid=105109 - -(All bugs reported there are reviewed, but not updated!) - Thanks! diff --git a/docs/build.txt b/docs/build.txt index 19a92c27..c2f87de6 100644 --- a/docs/build.txt +++ b/docs/build.txt @@ -1,7 +1,4 @@ -Building on DOS or Windows: -=========================== - -To build the operating system a batch file (BUILD.BAT) is included +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. @@ -15,43 +12,8 @@ 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! -For example to build your custom branded kernel for 386+ with FAT32 -support using OpenWatcom compilers use a command such as: -BUILD.BAT 386 ow fat32 upx /D CUSTOM_BRANDING /V "MyDOS" - - -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 - -You can now also cross compile with T.K. Chia's fork of ia16-elf-gcc, -which is available at https://github.com/tkchia/gcc-ia16, using -make all COMPILER=gcc -or by setting COMPILER=gcc in config.mak. If you are using Ubuntu -Linux 20.04 LTS (Focal Fossa), 18.04 (Bionic Beaver), or 16.04 LTS -(Xenial Xerus), there are precompiled ia16-elf-gcc packages at -https://launchpad.net/~tkchia/+archive/ubuntu/build-ia16/. -Otherwise, for now ia16-elf-gcc needs to be compiled from source. -Only releases 20180708 and later are supported. - -Notes: -====== -The recommended compiler and assembler at the time of writing (2009/05/19) -are OpenWatcom 1.8 and NASM 2.05.01. +The recommended compiler and assembler at the time of writing (2004/01/31) +are OpenWatcom 1.2 and NASM 0.98.38. 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. @@ -130,6 +92,6 @@ component. Study the makefile to better understand this. --------------------------------------------------------------------- -$Id: build.txt 1387 2009-05-19 21:39:29Z bartoldeman $ +$Id$ diff --git a/docs/config.txt b/docs/config.txt index cff3423c..639cbcee 100644 --- a/docs/config.txt +++ b/docs/config.txt @@ -2,7 +2,6 @@ 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 @@ -30,41 +29,24 @@ 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 +e.g. break=off BUFFERS BUFFERSHIGH -Usage: buffers=nn[,m] where nn is in range 1-99 & m is in range 1-8 +Usage: buffers=nn[,n] where nn is in range 1-99 & n 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 +other DOS kernels, but is ignored by the FreeDOS kernel. +e.g. 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. +Only limited country=nnn support is presently available. +Enables/sets international features of DOS 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 +e.g. country=001,850,C:\FDOS\BIN\COUNTRY.SYS DEVICE Usage: device=[d:][path]file [options] @@ -72,7 +54,7 @@ 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 +e.g. device=himem.sys DEVICEHIGH Usage: devicehigh=[d:][path]file [options] @@ -83,9 +65,9 @@ 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 +Himem installed (prior device=FDXMS.SYS or device=HIMEM.SYS) before using this option. -Example: devicehigh=xcdrom.sys /D:FDCD0001 +e.g. devicehigh=atapicdd.sys /D:FDCD0001 DOS Usage: dos=high|low,umb|noumb @@ -95,23 +77,23 @@ 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 +e.g. dos=high,umb +or 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, +same as using the HIGH variant of kernel parameters, such as fileshigh, lastdrivehigh, and stackshigh (does not effect drivers loaded using device= or install=). -Example: dosdata=umb +e.g. 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: +e.g. ECHO loading driver 1 device=Driver1.sys ECHO driver1 successfully loaded @@ -121,17 +103,15 @@ 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 :-) +ansi driver loaded prior to use. 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 +(see files) most applications will not need this value adjusted. +e.g. fcbs=4 FILES FILESHIGH @@ -143,24 +123,7 @@ 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 +e.g. files=20 INSTALL INSTALLHIGH @@ -170,105 +133,35 @@ 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". +e.g. install=nansi.com 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 +e.g. lastdrive=z NUMLOCK Usage: numlock=on|off Set the keyboard number lock to on or off. -Example: numlock=off +e.g. 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 +reached are ignored. This may also be used to temporarily disable +loading a particular device or other option. 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 +where xx should be 0x11 for 28 lines or 0x12 for 43/50 (EGA/VGA) lines SET Usage: set ENVVAR=value Sets the environment variable to provided value. -Example: set HOME=C:\home\me +e.g. set HOME=C:\home\me SHELL SHELLHIGH @@ -279,18 +172,15 @@ 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 +e.g. shell=C:\COMMAND.COM /E:256 /P STACKS STACKSHIGH -Usage: stacks=nn,mmm +Usage: stacks=nn,nnn 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 +Changes number of stacks available +nn is number of different stacks and nnn is size in bytes of each one +e.g. stacks=16,256 SWITCHAR Usage: switchar=c @@ -298,44 +188,28 @@ 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=- +hardcoded switch characters. +e.g. switchar=- SWITCHES Usage: switches=/E[:xxx] /F /K /N /W Adjusts boot time processing behaviour. -/E specifies how to handle moving of EBDA (Extended BIOS Data Area), - if a size in bytes is specified [xxx, in range of 48-1024] - then the EBDA will be moved from the top of conventional memory - to a lower address (allowing for potentially larger free block - of conventional memory if video memory at A0000 is available). - without a size, the EBDA will not be moved -/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) key presses - are ignored (note: with /F a well timed F5/F8 still works, whereas - /N completely disables). -/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, - used when \WINA20.386 is moved into a subdirectory, a device line - with proper path must be added to Microsoft (R) Windows SYSTEM.INI - [386Enhanced] section. --- may be ignored for compatibility +/F skips the delay checking for F5/F8 keystroke before processing config.sys + [equivalent to setting kernel config option skipconfigseconds = 0] +/N disables F5/F8 support [equivalent to kernel config skipconfigseconds = -1] +(note: with /F a well timed F5/F8 still works, whereas /N completely disables) +/K forces treating of keyboard as 86 key keyboard +/E enables moving of EBDA (Extended BIOS Data Area), optionally a size in KB + may be specified [xxx, in range of 48-1024] +/W disables Windows 3.0 from loading WINA20.386 from the root directory (used + when \WINA20.386 is moved into a subdirectory, a device line with proper + path must be added to Microsoft (R) Windows' SYSTEM.INI [386Enhanced] + section.) --- Unsupported, though may be ignored for compatibility. 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 +FreeDOS specific command to specify what DOS version to report. +e.g. version=6.2 @@ -348,14 +222,14 @@ normal '?' - ALWAYS ask if a single line shall be executed FILES=20 - DEVICE?=MyNetWorkDriver.sys + ?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 + DEVICE=MyNetWorkDriver.sys configuration management - you may compose several configurations, @@ -364,20 +238,19 @@ using following special commands: MENU MENU select your configuration MENU +MENU use (0) for basic configuration 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) +MENUDEFAULT=0,1 ( configuration 0, wait 1 second) + -rem CDROM +1? rem CDROM 1? device=CDROM.SYS -rem NETWORK +2? 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 @@ -395,7 +268,7 @@ 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, +however, if you have no menu's 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 == ) @@ -415,7 +288,7 @@ thus my config.sys now looks like !buffers=30 !screen=0x12 !lastdrive=z -!shell=\command.com /p /e:512 /MSG +!shellhigh=a:\command.com /p /e:512 /MSG MENU MENU 0 - SoftIce+HIMEM+Network (default) @@ -432,7 +305,7 @@ MENUDEFAULT=0,0 0?device=c:\ntclient\ifshlp.sys -DEVICE=xcdrom.sys /D:MSCD000 +DEVICE=ATAPICDD.SYS /D:MSCD000 Full Screen Menus (thanks to Rune Espeseth) @@ -451,39 +324,37 @@ 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 ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» +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 +1? REM 1st choice +1? ECHO You selected menu #1 -REM 2nd choice -2?ECHO You selected menu #2 +2? REM 2nd choice +2? ECHO You selected menu #2 -REM 3rd choice -3?ECHO You selected menu #3 +3? REM 3rd choice +3? ECHO You selected menu #3 -REM 4th choice -4?ECHO You selected menu #4 +4? 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 index da8326bb..7b9a0be6 100644 --- a/docs/contrib.txt +++ b/docs/contrib.txt @@ -1,6 +1,6 @@ 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! +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: @@ -8,21 +8,17 @@ Aitor Santamaria (aitor.sm@wanadoo.es) Arkady Belousov (ark@mos.ru) Bart Oldeman (bart@dosemu.org) Bernd Blaauw (bblaauw@home.nl) -Bernd Böckmann (boeckmann) Brian Reifsnyder (reifsnyderb@mindspring.com) Charles Dye (raster@highfiber.com) Eduardo Casino (casino_e@terra.es) -E. C. Masloch (pushbx) -Eric Auer (e.auer@jpberlin.de) +Eric Auer (eric@coli.uni-sb.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) +Jeremy Davis (jeremyd@computer.org) Jim Hall (jhall@freedos.org) John Price (linux-guru@gcfl.net) Kolya Ksenev (7207@mx.csd.tsu.ru) @@ -33,7 +29,6 @@ Michal Bakowski (mb@orad.pl) Ron Cemer (roncemer@gte.net) "ror4" (ror4@angelfire.com) Rune Espeseth (re@icd.no) -sava (lpproj@gmail.com) Steffen Kaiser (Steffen.Kaiser@fh-rhein-sieg.de) Steve Miller (SMiller@dsfx.com) Tom Ehlert (te@drivesnapshot.de) @@ -43,5 +38,5 @@ 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. +(patv@iop.com), who was the original author of DOS-C, in which the +FreeDOS kernel was based. diff --git a/COPYING b/docs/copying similarity index 98% rename from COPYING rename to docs/copying index 7c9effb0..5b6e7c66 100644 --- a/COPYING +++ b/docs/copying @@ -2,7 +2,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -304,8 +304,8 @@ the "copyright" line and a pointer to where the full notice is found. 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 + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. diff --git a/docs/fdkernel.lsm b/docs/fdkernel.lsm index 021be3b9..a0fb3e1f 100644 --- a/docs/fdkernel.lsm +++ b/docs/fdkernel.lsm @@ -1,15 +1,13 @@ Begin3 Title: The FreeDOS Kernel -Version: git -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://github.com/fdos/kernel -Alternate-site: http://www.fdos.org/kernel/ -Alternate-site: http://freedos.sourceforge.net/kernel/ +Version: 2.0.35a-UNSTABLE +Entered-date: 30 May 2004 +Description: The FreeDOS Kernel. +Keywords: kernel freedos dos msdos +Author: (developers) +Maintained-by: jeremyd@computer.org +Primary-site: http://freedos.sourceforge.net Original-site: http://www.gcfl.net/pub/FreeDOS/kernel -Platforms: DOS, FreeDOS, DOSEMU (OpenWatcom/Borland/GCC-ia16, NASM, UPX) -Copying-policy: GPL2 +Platforms: dos dosemu +Copying-policy: GPL End diff --git a/docs/history.txt b/docs/history.txt index bfd0f71d..38043464 100644 --- a/docs/history.txt +++ b/docs/history.txt @@ -1,890 +1,433 @@ -Bug reports: -Current bug tracking for the kernel is on GitHub in the FDOS/kernel project. -Genera FreeDOS bug tracking (kernel bug reports also accepted) at GitLab FreeDOS project. - -Note: old bug tracker and source URLs: -bugzilla bug NUMBER at: - http://bugzilla.freedos.org/cgi-bin/bugzilla/show_bug.cgi?id=NUMBER -and sourceforge bug tracker at: - http://sf.net/tracker/?func=detail&aid=NUMBER&group_id=5109&atid=105109 -SVN source (no longer updated) for old SVN revision NUMBER at: - http://freedos.svn.sf.net/viewvc/freedos?view=rev&sortby=rev&revision=NUMBER -Changelog items may list old SVN revision NUMBER and bugzilla bug NUMBER. - - -2026 ?? - Build 20?? --------- Jeremy Davis - -+ Changes Jeremy Davis and Tom Ehlert - * GPT partition support - -2026 June 29 - Build 2046 --------- Jeremy Davis - -+ Changes Andrew Bird - * build fix for Borland Turbo C (new style comments unsupported) -+ Changes Jeremy Davis - * bugfix: CD on remote Lantastic mapped drives - * bugfix: print to Lantastic redirected printers - * misc: port some improvements from FDPP (Stas & Andrew) - * bugfix: move control-break handler off stack, fix Invisible Lan redir - * bugfix: rework truename so when on mapped drive with invalid CDS - properly resolves character devices (i.e. fix copy CON) - * misc: rename some unused fields in CDS to better match MSDOS 4 - -2026 May 01 - Build 2045 --------- Jeremy Davis - -+ Changes Andrew Bird - * ci: update GitHub ci actions for impending GitHub changes -+ Changes E.C.Masloch - * fix bug #241 - Trying to extend a zero-byte file using seek then write, where the seek doesn't fit on disk, doesn't update file size for allocated clusters - * fix bug #243 - Trying to write to the very end of a file, which should fit on the disk just so, extends the file size but doesn't write data -+ Changes Jeremy Davis - * nls: load YesNo characters in CONFIG.SYS via COUNTRY statement so can use without having to load NLSFUNC - * nls: support loading data separator from country.sys also, default is hardcoded comma (,) - * nls: update country.sys - * Int 2F/12xx documentation update and additional implementations - -2026 Jan 25 - Build 2044 --------- Jeremy Davis - -+ Changes Andrew Bird, Bernd Böckmann, E. C. Masloch, Stas Sergeev (stsp), - Tee-Kiah Chia (tkchia), Sava (lpproj), Jiri Malak, Jeremy Davis, Tom Ehlert - * disk: Set volume label also on BPB update - * fix INT21.7303 return cluster count one too high, https://github.com/FDOS/kernel/issues/194 - * fixes for building with various compilers / different environments - * boot sector improvements (improve compatibility/reduce boot problems) - * support determining kernel file version without booting it - * only print messages once, not each time processing partitions - * fix for Format GitHub issue #1 - format divide by 0 due to kernel function 440D, subfunction 60 returning a zero for logical_sectors_per_fat as initdisk overflows and calculates incorrect value - * From bzt, initialize drive parameter head & sector values to avoid potential divisions by 0 - * config: allow to delete variable with empty SET command - * truename: fix array overrun (pick from fdpp) - * main: insure master environment starts out empty - * config: make sure word marker trailing in environment is zero - * inthndlr: align hma size to para - * DosGetExtFree: Use new redirector function 11a3 - * sys: detect small FAT32 as FAT32 (zero in word SPF) - * boot: enable loading from file systems with 256 sectors per cluster - * fatfs.c: allow bpbSectorsPerCluster == 0 to mean 256 - * FCB (int 21h func 29h): should not accept field separator as "drive letter" - * FCB (int 21h func 29h): should keep parsing name even if drive letter invalid - * exeflat: update usage screen with -E, -D, and -U switches - * upxentry, upxdevic: add header comments - * exeflat: improve compressed stub handling, fixes, update documentation, various other updates - * kernel: optimise A20 check and enable/disable calls - * improve/fix gcc and OpenWatcom build support - * task: return Invalid format on empty executable (fixes #70) - * fdkrncfg: bugfix, version info check should not include signature - * fix 2nd parameter of "DOS=" statement in config.sys does not take effect in some cases: - * dosfns, int2f: make SHARE uninstallable - * CI: improvements - * Fix incorrect date format for Czech and Slovak Republic. Both Countries use DD.MM.YYYY date format. Microsoft DOS also use this format. - * dosfns: Check share table before delete/rename - * various build updates and move share and country to submodules - * FCB: Rename should support asterisk wildcards - based on dosemu fdpp, fixes issue #43 - * add tests for FCB rename - based on tests from andrewbird - * allow opening a character device prefixed with invalid drive letter (e.g. "@:NUL") but not with invalid path - * add test for opening character devices (all pass on DOS 5,6, NT VDM, @:dev fail currently on FD kernel) - * initial implementation of extended seek (0x7142 - LONG LSEEK with 64-bit file position) - * add implementation of int 0x2F function 0x1f build CDS from dosemu2/fdpp - * add skeleton for LFN API, includes 0x71a6 implementation (call to redirector only) from dosemu2/fdpp - * ensure offset to critical patch tables doesn't change - * From Tom Ehlert: don't split disk transfers crossing DMA boundary if BIOS indicates can handle transparently - * fcbfns: Fix for FcbFindFirstNext [fixes #40] - * task: don't zero parent_psp on 0x26 - * boot, oemboot: fix to abort properly on file not found - * oemboot: optimise FAT12 entry loading (picked from lDOS boot) - * adjust padding to be same as in PC-DOS (90h/nop) - * from RBIL int 21h/4400h (table 01423) add definition for bit 11 if SFT is not for a device (for a file) - media not removable, currently unused - * from dosemu2/fdpp - zero out critical patch list Personal NetWare Server really writes to these addresses, so putting 0x0d0c the way DOS does, is not safe. - * int 21h/4400h only return low byte of SFT flags if not a device, part of dosemu2/fdpp bug #147 fix - * check for unsupported function call in console - from dosemu2/fdpp bug# 101 fix - * improve support for Windows 3 Enhanced mode - * From Tom Ehlert: properly error when attempting to write past 4GB - - -2021 May 13 - Build 2043 --------- Jeremy Davis - -+ Changes Bart Oldeman, Jeremy Davis, Andrew Bird, Tee-Kiah Chia (tkchia), Sava (lpproj), - Stas Sergeev (stsp), C. Masloch, Jiri Malak, Piotr Durlej, Ricardo Hanke - * update for releases using git instead of svn - * Update README.md - * add support for building with ia16-elf-gcc, including multiple updates/fixes - * SYS: Reduce verbosity when the verbose flag is not set - * add safety check to FAT12/16 boot sector to warn about breaking sys if boot code updated - * Implement version table support for int21/ah=4b, subfunctions 0 and 1 - * CI: Add Github Action to automatically build and minimal test kernel on commit - * FATFS: rmdir of read only directories is valid - * boot: allow instsect to match the filesystem ID string - * boot: fix Int10.0E expected not to alter al (SBC188) - * Fix Func 2Dh (Set System Time) sets wrong time - * Fix func 0Bh (Get STDIN Status) always returns AL=FFh with some alternative CON drivers: - * Fix Func 30h (Get DOS Version) return version 0.0 in config.sys - * int2f: fix call interface around syscall_MUX14( ) (inthndlr.c) - * int2f: fix call interface around int2F_12_handler( ) - * int2f: Allow 1217h function to return new CDS entry - * from Mondgestein, Function 30h (Get DOS Version): Get DOS version from PSP - * Fix func 36h (Get free disk space) fails in some redirectors: - * dosfns.c: only copy to current_ldt if pointer is valid - * inthndlr.c: in Int21.43FF, dispatch DosMkRmdir on CL not AH - * EXEC (func 0x4b): fix: do not crash if exMinAlloc == 0xffff - * FCB: Rename return value lost - * Fix division for some large numbers such as 0xFFFF01FF/0x10101FF - * Fix comments (Gerd Grosse, https://sourceforge.net/p/freedos/bugs/106/) - * FCB: Rename return value lost - * Fix compilation with TC2 and MSVC 1.52c. - * disk: fix sectors count truncation for CHS [fixes #10] - * implement CHAIN directive for config.sys - * add some initial (minimal) tests - * Fix memory break in NUL device - * Fix initial DTA - * Implement Int 2F/AX=120Bh based on RBIL description - * Implement Int 2F/AX=120Ah based on RBIL description - untested! - * From Evelyn, CPU unsupported message missing loading error msg address (pop si) - * Copy FCB-format filename from PriPathName (some redirectors require FCB-format filename stored in SDA+22Bh DirEntBuffer) - * Fix an error at opening a character device prefixed with invalid drive letter (e.g. "@:NUL") (some application use it for opening character device driver) - * Fix incompletion on loading huge (more than 65280 bytes) binary device driver - * On creating child PSP (func 0x55), copy command line parameters from the parent (required for some device loaders) - * Improve support for older BPB based volumes lacking extended fields. (Based on lpproj's nec98:Fix for DOS 3.x partitions) - - -2016 May 16 - Build 2042 --------- Jeremy Davis, Sava - -+ Changes Jeremy - * support determining kernel file version without booting it - * from Christian Masloch, display error on unsupported CPU - * improve memdisk CONFIG.SYS processing support - * ensure top of RAM correctly adjusted after moving EBDA - * fix reading from NULL - * merge creation date & time from old dev branch - * use absolute not relative disk read/writes - (allows syslinux DOS installer to work correctly) - * Fix FCB parse filename (int21h func 29h) - * Improve support for older BPB based volumes lacking extended fields. - (Based on lpproj's nec98:Fix for DOS 3.x partitions) - * Int 2F/AX=120Ah & AX=120Bh based on RBIL, untested - -+ Changes Sava (lpproj) - * add cross-compile capability on Windows with OW and mingw32-make - * Fix pointer of DBCS table (int 0x21, func 0x6300) - * Enable to load DBCS table from COUNTRY.SYS - * Return current country code (func 0x38) - * Fix broken decompression on loading FAT16 kernel (compressed in dos/sys) - * On creating child PSP (func 0x55), copy command line parameters - from the parent (required for some device loaders) - * Fix incomplete loading of huge (more than 65280 bytes) binary device driver - * Fix an error at opening a character device prefixed with invalid - drive letter (e.g. "@:NUL") - * Copy FCB-format filename from PriPathName (some redirectors require - FCB-format filename stored in SDA+22Bh DirEntBuffer) - -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 +2005 Jan XX - UNSTABLE (-w) branch -------- Jeremy Davis (jeremyd@computer.org) + Changes Bart - * int2f.asm: call_nls: DI register was not preserved (bug 1812) + * exeflat.c + - new version exploiting better UPX compression for SYS files; calls UPX itself + * int2f.asm + - bugfix: call_nls: DI register was not preserved + * inthndlr.c + - int21/ah=6/dl=ff now calls int28 + * main.c + - use largest possible value for the initial CDS (make device=f:\foo.sys work) + * sys.c + - correct fat32readwrite's prototype to explicitly return int ++ Changes Tom + * inthndlr.c + - improve handling of case where eg. FindFirst(I:\*.*) fails, causes Int24, + and application chooses to pop stack returning to self and does NOT return + to DOS; so fnode[0] never freed and errormode not set back to 0 until exit() + 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 + * UTILS\PROTO.BAT, KERNEL\NLS_LOAD.C, KERNEL\KERNEL.CFG: removed. + + * all batch files now check if environment is enough; this prevents wrong + actions in case of small environment. + * *.BAT: %MAKE% now called through CALL; this allows to place into PATH + batch file instead utility itself. + * BUILDALL.BAT: removed ambiguous ONERROR variable. + * BUILDALL.BAT: added ">NUL" for DELs. + * CLOBBER.BAT now uses CLEAN.BAT for its job; this eases to update cleaning + code because no code duplication. + * CONFIG.B: XNASM replaced by NASM, XLINK by LINK, MS_BASE by MSC_BASE. + * CONFIG.B: added possibility to define librarian. + * CONFIG.B: added "MAKER -S" as choice for MAKE. + * DEFAULT.BAT renamed to DEFAULTS.BAT, for all "call " added + suffix .BAT; this solves compatability problem with 4DOS (where DEFAULT + is a built-in command). + * DEFAULTS.BAT: added variable BASE. + + * all MAKEFILEs now look similar. + * some makefiles renamed: BC5->BC, TURBOCPP->TCPP, TC3->TCPP3, MSCL8->MSC. + * MKFILES\*.MAK: removed space after "=" in macro definitions; this makes + command lines shorter. Typo fix, copiler->compiler + * common definitions from makefiles moved to MKFILES\GENERIC.MAK + (directories) and CONFIG.B/DEFAULTS.BAT (LINK, NASM, LIBUTIL, etc). + * MKFILES\GENERIC.MAK: XCPU=86 and XFAT=32 are defined here, if environment + doesn't contains these variables; this allows to reduce environment. + * MKFILES\GENERIC.MAK: ALLCFLAGS and NASMFLAGS placed after all options + (this allows to redefine some options in config.bat); for watcom.mak + this also adds space after ALLCFLAGS (which is required, if ALLCFLAGS + ends by option like -I). + * MKFILES\GENERIC.MAK: NASMFLAGS now includes -f and -D$(COMPILER) options. + * MKFILES\TCPP.MAK: -zC option moved from ALLCFLAGS into CFLAGS (this + eliminates option duplication in INITCFLAGS and reduces command line + length). ALLCFLAGS now includes -I..\hdr;$(INCLUDEPATH) option (this + allows to reuse compiler headers (for example, limits.h), but own time.h + anyway "overloads" compiler's header). + * MKFILES\TC2.MAK, MKFILES\TCPP3.MAK, MKFILES\BC.MAK: reused contents of + MKFILES\TCPP.MAK through "!include". + * MKFILES\WATCOM.MAK: removed INCLUDE and EDPATH macroses. + * MKFILES\WATCOM.MAK: added option -d1 (to allow make listings with sources). + + * added KERNEL\TCI.CFG, which allows noticeably reduce size of INITCFLAGS + definition in MKFILES\TCPP.MAK; options for other compilers also moved + from command line to consequent KERNEL\*.CFG files. + + * KERNEL\MAKEFILE: $(TARGET).lnk rule now removes *.obj (this allows to + remove explicit dependency for $(TARGET).lnk for all other rules). + * KERNEL\TURBOC.CFG: removed redefinition of __STDC__. + + * "production" target replaced by "all" to eliminate warning from NMAKE. + * DEVICE\MAKEFILE: device.lib now created directly in ..\lib directory + without intermediate copy. + * added SYS\TURBOC.CFG and UTILS\TURBOC.CFG. + * SYS\MAKEFILE, UTILS\MAKEFILE: reused implicit rules from MKFILES\GENERIC.MAK. + + * fdkrncfg.c + - fix: eliminated warning "Initialization is only partially bracketed". + * exeflat.c + - removed duplicated definition for macro LENGTH(). + * floppy.asm + - prototypes fixed and syncronized with dsk.c. + - fixed wrong comments, more and better comments. + - bugfix: when fl_lba_ReadWrite() converted to ASMPASCAL (and `ret' replaced + by `ret 8'), "ret_AH" was remained as label for this tail (whereas other + functions use plain `ret'); now ret_AH moved into another function. + * procsupt.asm + - exec_user(), reloc_call_p_0(): added "%ifndef WATCOM/%endif" around + popping return address, because exec_user() and init_call_p_0() now + declared with `aborts' attribute for Watcom. + * entry.asm + - fix: was used signed comparision instead unsigned. + * int2f.asm + - fixed wrong comment. + * intr.asm + - wrong prototypes fixed and syncronized with *.h headers. + - small code cleanup (removed jumps) and optimizations, more comments. + * break.c + - removed extraneous variable assignment. + * dsk.c + - bugfix: blk_driver(): should be checked ">= NENTRY", not "> NENTRY". + - bugfix: Getlogdev(): in case of no DF_CURLOG flag is set, in rp->r_unit + now returned last+1 (equal to blk_dev.dh_name[0]) unit (was last+2). + - Setlogdev(): added comment about undocumented behavior. + - bugfix: Genblkdev(): + - formatting loop (0x42 function) rewritten: instead formating many tracks, + was formated one track many times (because afentry.head++ outside loop); + - now checked "afentry.track >= pddt->ddt_ncyl" (instead ">"); + - now gbfv_spcfunbit cleared at ; + - not fixed: there remained two returns without setting gbfv_spcfunbit; + - verification (0x62) now check only bit 0 of gbfv_spcfunbit; + - not fixed: verification should set gbfv_spcfunbit in case of errors. + + - removed remained excerpt from history.txt at the end. + - removed all references to PROTO macro name. + - small source cleanup (expressions simplified, extraneous casts removed). + - small code cleanup and optimization for diskchange(), mediachk(), + blk_Media(), bldbpb(), IoctlQueblk(), blockio() and dskerr(). + - many variables (like `ret') moved deeply (by adding curly braces) - for + BC this noticeably decreases stack usage. + - getddt(0) and tmark are now macros. + - blk_error() removed, consequent dispatch[] entries contains NULL and they + checked by blk_driver() before calling getddt() and dispatch[] item. + - getbpb(): removed extraneous stack variable; instead (x+y-1)/y for roundup + used (x-1)/y+1 expression; printf sequences joined into one printf. + - LBA_Transfer() now converts error code through dskerr() by itself; + .ddt_offset field added to LBA_address also inside LBA_Transfer(). + * initdisk.c + - small code optimization. + - added `const' modifier into castings. + - `bootdrv' variable inlined. + * ioctl.c + - 3 nested switch splitted into 2 switch (1st prepares parameters for + 2nd, which calls execrh()). + - device attribute word checked through table lookup. + - CharReqHdr.r_command computed through table lookup. + - removed all goto, except one. + * memmgr.c + - joinMCBs(): check that mcb is valid now before check that mcb is free. + - all "(uppermem_link & 1)" replaced by "uppermem_link", because + DosUmbLink() stores there only 0 and 1. + * nls.c + - bugfix: (Eduardo Casino, Steffen Kaiser) DosGetData(): NULL pointer was + addressed when searchPackage returns NULL. + * globals.h + - bugfix: NetRetry and NetDelay are UWORD, not UBYTE values. + * init-mod.h + - cleaned prototype for function from intr.asm. + - init_fatal() described (for Watcom) as non-returned functions. + * proto.h + - fatal() and panic() described (for Watcom) as non-returned functions; + this improves code generation. + - cleaned prototypes for functions from intr.asm. + - removed prototypes for nonexisting functions. + - added brackets around parameters of macro. + * config.c + - source: added types PStr and PCStr to ease using string pointers. + - source: for iregs members used predefined names like BH (instead b.b.h). + - source: instead `seg' type used `seg_t'. + - source: HMAState values now `enum'; for UmbState values now also given + names through `enum'. + + - added testbit() macro to make source more readable (and code shorter). + - parameter of all command processing functions (like CfgMenu()) now have + `const' modifier. + - far pointers with zero offset now decalred with `_seg' modifier, MK_FP() + replaced by MK_SEG_PTR() macro: this makes more understandable source and + noticeably enhances code for BC. + - added gotoxy() and clearScreenArea() to incapsulate screen manipulations. + - GetNumArg(): returns value in global storage; added GetNumArg1() and + GetNumArg2(), which does all check for command line syntax for other + command processing functions. + + - bugfix: umb_init() was not checks that new UMB completely inside "hole" + and its size is greater than 2 paragraphs; now borders outside of holes + are trimmed. + - bugfix: umb_init(): when joining adjacent UMBs, umb_base_seg, umb_start + and umb_max was not adjusted if they equal to start of next joined block. + - fix: umb_init(): when joining adjacent UMBs, UMB_top was not adjusted if + it equal to end of previous block; this forces to use only part of given + UMB when loading drivers. + - bugfix: umb_init(): umb_start+UMB_top was point end addres when loading + drivers and initialized to end of (first, largest) block, but this was + overlap link MCB for next UMB if umb_start was not the furthest UMB. + - bugfix: umb_init(): when joining next adjacent UMB to new block, size of + joined block was maked greater than required by 1. + - bugfix: umb_init(): when new UMB is beyond of previous furthest block + (umb_max) and first byte in last paragraph of umb_max block contains 'M', + prev_mcb() was walk after umb_max. + - bugfix: umb_init(): when EMM386 joins A000 area to base memory, it updates + 0:413 BIOS variable, but umb_init() was use older value (from ram_top + variable) when adjusts base MCB and thus destroys MCBs chain. + + - bugfix: GetBiosKey() was wrongly handles timeout==0. + - fix: ClearScreen(): screen width at 0:44A is a word, not byte. + - fix: GetStringArg() was uses scan(), which skips some nonwhitspaces; + now replaced by scanword(). + - bugfix: AlignParagraph(): "overflow" on 32-bit targets not makes zero + value, so 0x1000 should be assigned, not added to uSegVal. + - fix: PreConfig2(): to argument of AlignParagraph() was added extra 0x0f, + this captures extra paragraph before first MCB. + - fix: sysVersion(): VERSION= now works properly by setting version for + INT21/30, not for INT21/3306. + - bugfix: _CmdInstall(): "numInstallCmds > LENGTH" - should be ">=". + - bugfix: InstallExec() was call CfgFailure(), but it called after config + file processing, when szLine buffer always contains last line/garbage. + + - fix: WriteMenuLine(): blink attribute for selected line in menu now cleared. + - fix: DoConfig(): config lines in error messages now counted from 1 (not 0). + - bugfix: DoConfig(): when reading config, EOF (0x1A) was accepted as '\n'. + - fix: DoConfig(): lines with alone sequences like "?" now diagnosed. + - fix: DoConfig(): errors for unknown commands now printed only after menu. + - fix: DoConfig(): in ECHO and EECHO arguments leading spaces now preserved. + - CfgFailure(): message about error in config now same, as in MS-DOS6. + - CfgFailure(): message now contains real config name (instead "CONFIG.SYS"). + - fix: CfgFailure(): "^" in error messages now shows proper position. + + - all pressed before menu keys (if any, but except F5/F8) now preserved in + keyboard buffer. + - config now parsed in 5 passes: SWITCHES=/F/N and MENUCOLOR/MENUDEFAULT + before menu, SHELL/SET/INSTALL after DEVICE (unlike MS-DOS6, which process + SETs before INSTALLs and thus can't redefine variables between INSTALL). + - screen now cleared (when MENUCOLOR present) before all MENU lines; after + menu screen not cleared. + - DoMenu(): now, when MENU lines are longer than screen width or them are + more, than screen height, menu lines highlighting disabled. + - menu selection shown only if there is more than one choice (in "123?" + prefixes), but CONFIG=n will be defined if even one choice is present. + - CONFIG= now not defined if F5 pressed in menu. + - DoMenu(): menu now looks more like MS-DOS6 (same words, hint at bottom). + - DoMenu(): choice 0 now not allowed if it not present in "123?". + - DoMenu(): in menu now allowed to press Left and Right keys; Esc in menu + now ignored; digit pressing not finish selection. + - when tracing, Esc now turns off asks for all following lines, including + lines with "?", and assumes "Y" for all; F8 now behaves similar to Esc. + - removed extraneous COMMAND verb. + - added BUFFERSHIGH verb (for compatability with MS-DOS6; currently dummy). + - SWITCHES=/E now handled after menu and may be asked/traced. + - (E)ECHO now executed without asking and tracing. + - DeviceHigh(): DEVICEHIGH= now reloads driver into low memory without + error messages about UMB (as in MS-DOS6). + - environment for INSTALL= now includes previous SETs. + - fix: CmdSet(): with SET environment variables now may be redefined and + removed ("V="). + + ? LoadDevice() uppercases command line for driver. Wrong? + * main.c + - fix: FreeDOSmain(): "drv >= 0x80" - should be ">". + - PSPinit(): DOS_PSP.ps_environ and ps_parent now set to zero. + - kernel(): "PATH=." now not placed into empty environment (because bug with + copying empty env in task.c:ChildEnv() is fixed). + - kernel(): now "/D" or "/Y" option inserted even if command line is too + long (by trimming command line tail). + - fix: CheckContinueBootFromHarddisk(): "InitKernelConfig.BootHarddiskSeconds == 0" - + should by "<=". + * task.c + ! P_0(): old shell command line stored in SecPathName buffer and, thus, will + be overwritten by DOS rename function with argument, longer than 50 bytes. + + - fix: new_psp(): as in MS-DOS6, ps_parent now not changed; ps_exit, ps_unix, + ps_farcall, ps_reentry, ps_prevpsp, ps_maxfiles, ps_filetab and ps_files + are initialized. + - fix: new_psp(): ps_reentry now have same value, as in MS-DOS6. + - fix: child_psp(): as in MS-DOS6, ps_fcb* and ps_cmd now not changed, + ps_prevpsp is set to -1 (from new_psp()). + - bugfix: ChildEnv(): empty environment now processed correctly. + - bugfix: ChildEnv(): DosMemAlloc() was called with NULL for `asize', but + asize not always checked inside DosMemAlloc() for NULL before dereference. + - fix: ChildEnv(): for environment now allocated memory not more, than + required to store path after environment (was always 80 extra bytes). + - patchPSP(): as in MS-DOS6, FCB addresses in exec block now don't checked + and copied only 12 bytes (drive+name+ext). + - DosComLoader()/DosExeLoader(): if childEnv() failed, then `env' contains + garbage and DosMemFree(env) now not called. + - bugfix: P_0() was copy argument of SHELL line into Shell buffer without + checking length of source (note: max length of SHELL argument is a 74 + bytes, because Shell=SecPathName+50 and sizeof SecPathName=128). + - P_0(): now supported command line without space between command and + options (starting from '/'). + * dosfns.c + - common code from DosFindFirst() and DosFindNext() moved to pop_dmp() + - optimization for SftSeek() + * ludivmul.inc + - bugfix: division of long numbers in LDIVMODU macro (used for Watcom) + was wrong. Example: 100000h%8000Fh was gives 0FFFF1h instead 7_FFF1h. + - shorter code. + * inthndlr.c + - fix: INT21/3301 now returns in DL low bit of input value (as in MS-DOS). + - callerARG1 declared as xreg instead UWORD. + * fcbfns.c: FatGetDrvData() and FcbParseFname() optimised ++ Changes Bernd, Aitor, & Arkady + * config.c + - source: (Bernd) the codepage table rewritten into a smaller layout. + - bugfix: (Bernd, Aitor) country ID for Spain set to 34 (instead 33). ++ Changes Jason + * inthndlr.c + - set FAT32 fields of FAT12/16 DPBs on Int21h/7302h. Fixes bug 1819 + - implement Set Extended Error function to help VC 4.99 with DOSLFN + Changes Lucho - * dsk.c: text in play_dj - * fatfs.c: + * exeflat.c + - fix: eliminated warning by explicit cast. + - reduced trailer, added to UPXed kernel. + - allow processing of files with 0 relocations + - UPX trailer no longer depends on load segment + * segs.inc + - fix: for MSVC CONST segment should be class CONST, not DATA. + * dsk.c + - play_dj() now says same words as MS-DOS6. + * boot.asm + - optimize and make more user friendly instead of retrying endlessly + * sys.c + - change OEM Name field to FRDOS4.1 per Eric Auer for better compatibility. + - added fat32readwrite int return type, now required by OpenWatcom 1.3 + - shrank copy buffer to avoid "Abnormal Program Termination" for Borland C. + * ludivmul.inc + - 32-bit division code for 386-enabled Watcom kernel. + * 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) + - 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 + - optimised Int 21h/AH=38h Get Country Information, removed cntry hack + * autoexec.bat: now single-line for FreeCOM compatibility when EOL=LF + * break.c: check_handle_break() return was undefined if no Ctrl-break + * config.c: fix "Suspicious pointer conversion" warning by Borland C 3.1 + * config.sys: all commands removed as they were close to defaults + * contrib.txt: added Aitor Santamaria, Bernd Blaauw and Eduardo Casino + * country.asm / config.c: COUNTRY.SYS now replaces hard-coded data + * 11 countries added to country.asm: GR,RO,AT,MA,SG,KR,CN,TR,IN,M.E,IL + * dosnames.c: macro to function conversion, optimisation and clean-up + * dyninit.c: excluded unused DynFree(), "what" passed only on DEBUG + * 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) - + - optimisation and clean-up + * fattab.c: ISFAT32 function removed (now macro), "wasfree" optimised + * globals.h: __TIME__ removed - no two kernels released on same day + * initdisk.c + - if no floppy drives present, don't initialise DDT for drive A: + - " - Initdisk" no longer shifts text if no FAT partitions found + - converted cdiv() from macro to function; optimise and clean-up + * inithma: InstallVDISK() function inlined, optimised and cleaned up + * intr.asm: lseek() added (necessary for COUNTRY.SYS processing) + * ioctl.c + - r_si/r_di contents added as documented in PC-DOS Technical Update + - r_unit now set to dpb_subunit (allows ZIP disk serial number) + * main.c + - copyright message cleanup, now shows URL for the full GNU GPL text + - (with Bart) LoL pointer made const (saves some size for Watcom) + - InitializeAllBPBs() kludge removed (no longer needed - verified) + - revision sequence now initialised along with DOS version in LoL + - CheckContinueBootFromHardDisk() function code and text cleaned up + - "PATH=." now static in config.c ->SET PATH=xxx in CONFIG.SYS works + * makefile: object files reordered to gain ~300B packed size + * newstuff.c, fatdir.c, blockio.c, chario.c, prf.c: cleanup & optimise + * portab.h: pragma aux default to gain ~800B unpacked size (Watcom) + (the last 2 changes proposed by Bart Oldeman) + + Changes Eduardo + * config.c: update hardcoded country and codepage IDs + * country.asm: added NLS uppercase/collating tables (437,850,857,858) + * inthndlr.c + - added Int 2Fh/26-29h processing for NLSFUNC (with Lucho) + - DOS-63-00 returns DBCS table from the active NLS package, not the + harcoded one. + - DOS-65-23: DosYesNo() arg is now DX, not DL. + - added Int 2Fh/122Bh&122Dh processing for NLSFUNC to work with DISPLAY 1.0 + * nls.c: MuxLoadPkg(), MuxGo() functions modified for NLSFUNC + - New macro getTable7() + - New functions nlsIsDBCS() (check if a byte is a dual byte char + leadbyte) and DosGetDBCS() (returns DBCS table from the active NLS + package) + - Add DBCS table to getTable() and fixes references to harcoded + UCASE and FUCASE tables. + - DosYesNo(): arg is now UWORD, not unsigned char. + - nlsYesNo(): Add DBCS support + - syscall_MUX14(): arg of nlsYesNo() is now CX instead of CL. + * nls.h + - yeschar and nochar are now UWORD instead of UBYTE. + - NLS_FREEDOS_NLSFUNC_VERSION bumped to 0xFD02. + - Add a small comment. + * nls_hc.asm: YesChar and NoChar are now two bytes each. + * proto.h + - DosYesNo(): Argument is now UWORD (dual byte) + - Add prototype for DosGetDBCS() + + Changes Jeremy + * updated build system to use NT OW binaries when building on NT + and add some additional options to build.bat command line + * added debug.h and changed to more easily allow selective DEBUG output + * boot.asm + - use static read buffer to avoid crossing 64KB boundary + - drop test for drive==0xFF, use sys to NOP use of BIOS provided # + * config.c + - always initialize boot time master environment + - KernelAlloc always 0's returned memory (fixes potential boot + time failure finding/loading CONFIG.SYS) + * config.txt + - update to include all CONFIG.SYS options (except ANYDOS) + * debug.h + - add additional debug style printfs to enable selective debug output + * entry.asm + - add [conditional compiled] support for OEM handler (int 21h ah>0xf8) + - work towards critical section entry/exit calls for Win3 support + * exeflat.c + - show usage also when number of arguments incorrect + * fatdir.c + - be more restrictive in what considered a volume search + * initdisk.c + - set hidden & huge fields in floppy bpb (bugfix 1789) + * inthndlr.c + - add [conditional compiled] support for Win3 API calls (entry/exit/...) + * int2f.asm + - switch to local stack when Win3 support compiled in, ?unneeded/to be removed? + * kernel.asm + - comment some additional variables + - use some unused spaces for OEMHandler variable and Win3 instancing information + * main.c + - treat block devices returning 0 units as load failure + * oemboot.asm - add [optional] PC/MS DOS compatible boot sector + * sys.c + - incorporate changes from/for DR-DOS enhancement project + - rework option handling, add backup & restore boot sector + - change boot time drive selection (BIOS provided or one in + boot sector) to be selected as SYS time via NOPing mov [drive],dl + * add sys.txt (documentation) and sys.html (htmlhelp file) + * task.c + - add debug output to see env & cmd line passed to exec'd program + < many other changes to be added by Jeremy himself :-> + +*** Sync - Stable Build 2035 *** 2004 May 30 - Build 2035 -------- Bart Oldeman (bart@dosemu.org) @@ -935,7 +478,7 @@ Most recent changes to source code (see version.h) are: + 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) + * 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 @@ -1007,11 +550,9 @@ Most recent changes to source code (see version.h) are: 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 -- + * 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 @@ -1019,7 +560,7 @@ Most recent changes to source code (see version.h) are: - 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 + 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 @@ -1044,7 +585,7 @@ Most recent changes to source code (see version.h) are: * 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-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: @@ -1073,7 +614,7 @@ Most recent changes to source code (see version.h) are: * 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 + 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. @@ -1104,7 +645,7 @@ Most recent changes to source code (see version.h) are: * 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...). + 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 @@ -1113,7 +654,7 @@ Most recent changes to source code (see version.h) are: 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: + * 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 @@ -1123,7 +664,7 @@ Most recent changes to source code (see version.h) are: 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 + 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(). @@ -1131,14 +672,14 @@ Most recent changes to source code (see version.h) are: - 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. + 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 + 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. @@ -1162,10 +703,10 @@ Most recent changes to source code (see version.h) are: * 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. + 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, + * 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: @@ -1173,7 +714,7 @@ Most recent changes to source code (see version.h) are: 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 + * 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 @@ -1209,11 +750,9 @@ Most recent changes to source code (see version.h) are: 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 + * *.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 @@ -1242,11 +781,11 @@ Most recent changes to source code (see version.h) are: * 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: + * 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 + never followed + print a message in case of FAT corruption + some small optimizations and header cleanups (some suggested by Arkady) @@ -1300,7 +839,7 @@ Most recent changes to source code (see version.h) are: 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 + 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 @@ -1309,8 +848,6 @@ Most recent changes to source code (see version.h) are: 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 @@ -1318,14 +855,12 @@ Most recent changes to source code (see version.h) are: 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 + 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) @@ -1373,14 +908,14 @@ Most recent changes to source code (see version.h) are: * 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 + * 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 + * 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 + 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) @@ -1391,11 +926,11 @@ Most recent changes to source code (see version.h) are: * 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 + 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 + * 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. @@ -1403,8 +938,8 @@ Most recent changes to source code (see version.h) are: * 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) + * 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 @@ -1422,9 +957,9 @@ Most recent changes to source code (see version.h) are: 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) + 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 + 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 @@ -1448,8 +983,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1464,7 +997,7 @@ Most recent changes to source code (see version.h) are: * correct parameter order in inthndlr.c, chario.c * INSTALLHIGH correction. + Changes Tom - * Fix a problem with the 'BootFromHarddiskIfNoKeyHit' option. + * Fix a problem with the 'BootFromHarddiskIfNoKeyHit' option. that occurred with some Compaq and Fujitsu/Siemens highend equipment. + Changes Bernd Blaauw * config.txt updates @@ -1476,7 +1009,7 @@ Most recent changes to source code (see version.h) are: maximum of 20. * Make "unable to disable A20" message #ifdef DEBUG only. * config.c,main.c: Small size optimizations (some proposed by - Arkady Belousov) + 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. @@ -1484,8 +1017,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1510,7 +1041,7 @@ Most recent changes to source code (see version.h) are: + Changes Luchezar Georgiev * add Bulgarian country structure data + Changes Bart - * flip some slashes in drivers/*.asm + * 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 @@ -1540,8 +1071,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1561,8 +1090,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1587,12 +1114,10 @@ Most recent changes to source code (see version.h) are: * 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: + * 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 @@ -1608,20 +1133,18 @@ Most recent changes to source code (see version.h) are: * 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; + * fixed bug in memory manager (realloc should try to defragment; UMB fixes) - * consistently pass sft_idx around for all SFT functions (instead of + * 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 + 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 @@ -1636,7 +1159,7 @@ Most recent changes to source code (see version.h) are: * 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 + * 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 @@ -1646,8 +1169,6 @@ Most recent changes to source code (see version.h) are: * Fixed make temp file * fix bug in DosFindNext * misc makefile fixes - - 2002 Aug 3 - Build 2027test -------- Bart Oldeman (bart@dosemu.org) + Changes Tom @@ -1704,8 +1225,6 @@ Most recent changes to source code (see version.h) are: 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 @@ -1735,8 +1254,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1753,8 +1270,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1767,13 +1282,11 @@ Most recent changes to source code (see version.h) are: 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 - - + * 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, + * 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 @@ -1816,8 +1329,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1826,8 +1337,6 @@ Most recent changes to source code (see version.h) are: * 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 @@ -1841,7 +1350,7 @@ Most recent changes to source code (see version.h) are: 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 + * 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. @@ -1854,8 +1363,6 @@ Most recent changes to source code (see version.h) are: 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 @@ -1870,12 +1377,12 @@ Most recent changes to source code (see version.h) are: * 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 + * 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 - + * 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 @@ -1887,20 +1394,18 @@ Most recent changes to source code (see version.h) are: + 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 + ?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 + * 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) @@ -1913,12 +1418,12 @@ Most recent changes to source code (see version.h) are: * 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 + 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 + * 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 @@ -1939,8 +1444,6 @@ Most recent changes to source code (see version.h) are: 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 @@ -1962,8 +1465,6 @@ Most recent changes to source code (see version.h) are: 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 @@ -1984,27 +1485,23 @@ Most recent changes to source code (see version.h) are: get most of the MS LAN network client working + fixes Bart * some FAT32 issues - * Dos{Open,Creat}Sft drive letter issues + * Dos{Open,Creat}Sft drive letter issues for CDROMs (thanks Jeremy) - * shrink_file should ALWAYS fail for directories, also with + * 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. + * 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 @@ -2013,13 +1510,11 @@ Most recent changes to source code (see version.h) are: * 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-S (pause) and Ctrl-P (printer echo) now work. Ctrl-Q is ignored by DOS. - * FCB "closing twice is legal" fix. Necessary for visicalc. + * 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 @@ -2035,7 +1530,6 @@ Most recent changes to source code (see version.h) are: + fixes Tom, Victor, Bart * various fatfs.c fixes and clean ups - 2001 Jul 23 - Build 2024/e -------- Bart Oldeman (bart@dosemu.org) + fixes Tom @@ -2058,7 +1552,7 @@ Most recent changes to source code (see version.h) are: * 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 :-() + 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 @@ -2082,8 +1576,6 @@ Most recent changes to source code (see version.h) are: * 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: @@ -2102,10 +1594,10 @@ Most recent changes to source code (see version.h) are: * some more diagnostics (123) to aid finding bugs when booting from a hard disk. -from 2001 jun 23 : KE2024BP +from 2001 jun 23 : KE2024BP + fixes Tom: - * FAT FS: would not expand files correctly, if lseek() + * 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 :-) @@ -2115,24 +1607,23 @@ from KE2024BM * 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. + 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 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) + * 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: @@ -2142,7 +1633,7 @@ from 2001 May 21: Build2024L * 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 + * there was (at rare circumstances) a buffer overflow while config.sys parsing. + Fixes Bart: * INT 21 0A - Dos Buffered Input reworked @@ -2166,7 +1657,7 @@ from 2001 May 21: Build2024L * 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) + 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. @@ -2174,8 +1665,7 @@ from 2001 May 21: Build2024L * 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 + 2001 Apr 21 - Build 2024 -------- Bart Oldeman (bart@dosemu.org) + Fixes Tom: * fixed a missing close_dir in fatfs.c. @@ -2184,7 +1674,7 @@ from 2001 May 21: Build2024L 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). + * 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. @@ -2193,15 +1683,14 @@ from 2001 May 21: Build2024L 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. + others. * Eliminated the master environment, as it is normally - managed by command.com, not by the kernel. This saves 512 + 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. + * 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 @@ -2210,8 +1699,6 @@ from 2001 May 21: Build2024L * 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: @@ -2221,36 +1708,35 @@ from 2001 May 21: Build2024L 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: ++ 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: + Bart: * fixed SYS. - * made most calls near again, with a jump/stack trick to + * 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 + * 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. + * 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 + * 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: + Hans Lermen: * critical error handler destroyed AH (entry.asm). Martin Stromberg * find_first for volume labels fix. @@ -2287,11 +1773,10 @@ from 2001 May 21: Build2024L 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: + 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. @@ -2304,20 +1789,16 @@ from 2001 May 21: Build2024L 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 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. @@ -2326,8 +1807,6 @@ from 2001 May 21: Build2024L 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, @@ -2335,7 +1814,6 @@ from 2001 May 21: Build2024L 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 @@ -2355,8 +1833,8 @@ from 2001 May 21: Build2024L 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 + ++ 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. @@ -2366,7 +1844,7 @@ from 2001 May 21: Build2024L + 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 + 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) @@ -2408,7 +1886,6 @@ from 2001 May 21: Build2024L 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. @@ -2429,7 +1906,7 @@ from 2001 May 21: Build2024L 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, + 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 @@ -2458,10 +1935,10 @@ from 2001 May 21: Build2024L -------- 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 ++ Patch Lixing Yuan (yuanlixg@china.com) Patch for parsing bug in FindFirst with wildcards -> ParseDosName (dosnames.c). 2000 May 28 - Build 2021 @@ -2469,7 +1946,6 @@ from 2001 May 21: Build2024L + 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. @@ -2481,7 +1957,7 @@ from 2001 May 21: Build2024L and it was removed. This fixed all the functions using IsDevice. Truename works now. I consider it dangerous and brain damaged. - Note: + Note: truename X:\DIR\con -> X:/CON, note the '/'. truename foo*.* -> X:\DIR\FOO?????.??? truename *.*\*.*\*.* -> ????????.???\????????.???\????????.??? @@ -2506,7 +1982,7 @@ from 2001 May 21: Build2024L 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. + a serious bug in isDevice. + Added Finished adding function code for disk serial number support. + Clean Cleaned up source and removed duplicate functions. @@ -2519,14 +1995,14 @@ from 2001 May 21: Build2024L + Update Started Update to the New CVS at Sourceforge.net. Setting source from 2018 to 2020. -2000 May 06 +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. + New functions not yet fully implemented. Clean up DSK.C, IOCTL.C and FCBFNS.C. Removed old blk_device pointers. @@ -2543,13 +2019,12 @@ from 2001 May 21: Build2024L -------- 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 ++ 2000 Mar 25 ++ -------- Eric Biederman + Fixed Lastdrive handling + Fixed Not enough drives for number present devices + Added Working (though not perfect network redirector) @@ -2579,8 +2054,8 @@ from 2001 May 21: Build2024L 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. +NOTE: The way the external NLSFUNC is called does not look well, +therfore expect a change soon. 2000 Mar 15 - Build 2019 -------- James Tabor (jimtabor@infohwy.com) @@ -2592,7 +2067,6 @@ therefore expect a change soon. * 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 @@ -2616,14 +2090,12 @@ 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 @@ -2639,7 +2111,6 @@ changed. * 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 @@ -2665,7 +2136,6 @@ changed. 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 @@ -2687,7 +2157,6 @@ changed. 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* @@ -2704,7 +2173,6 @@ changed. -------- 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 @@ -2789,13 +2257,11 @@ add: asmsupt.asm: fmemset, fmemclr, fmemclra {Replace the explicit * 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 @@ -2810,7 +2276,6 @@ anything up, and in fact slowed access down. * 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 @@ -2943,7 +2408,6 @@ bugfix: DosOpen(): dito 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 @@ -3147,10 +2611,9 @@ bugfix: DosOpen(): dito * 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 +13 Nov 2002 tom initclk.c: Initial revision @@ -4042,7 +3505,7 @@ 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: +error.h, exe.h, kbd.h: First GPL release. 30 Jul 1995 patv diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index feec9669..00000000 --- a/docs/index.md +++ /dev/null @@ -1,37 +0,0 @@ -INTRODUCTION ------------- - -The release archives contains the current FreeDOS Kernel, also -known as DOS-C, originally written by Pasquale J. Villani. - -The FreeDOS Kernel is available from https://github.com/FDOS/kernel/ -(formally 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_f16.zip](https://github.com/FDOS/kernel/releases/download/ke2043/ke2043_86f16.zip) : binaries for 8086, FAT12 and FAT16 only - * [ke20xx_f32.zip](https://github.com/FDOS/kernel/releases/download/ke2043/ke2043_86f32.zip) : binaries for 8086, FAT12, FAT16, and FAT32 - * [ke20xxs.zip](https://github.com/FDOS/kernel/releases/download/ke2043/ke2043s.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 -https://github.com/FDOS/kernel/issues - -(Previously at http://sourceforge.net/tracker/?group_id=5109&atid=105109, and -even earlier archive of old (Bugzilla) items is at www.freedos.org/bugzilla/ ) - - -Copyright ---------- - -DOS-C is (c) Copyright 1995, 1996 by Pasquale J. Villani -All Rights Reserved. diff --git a/docs/intfns.txt b/docs/intfns.txt index 020de90d..024b09ca 100644 --- a/docs/intfns.txt +++ b/docs/intfns.txt @@ -2,7 +2,8 @@ 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). +currently supported by DOS-C. This list is for Release 1.1, build +2003 as issued on Feb 28, 1999. int 20: Terminated Current Process Supported @@ -15,9 +16,9 @@ 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 +03h Auxilliary Input superseded 1.00 Note 1 +04h Auxilliary Output superseded 1.00 Note 1 +05h Print Character superseded 1.00 Note 1 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 @@ -95,7 +96,7 @@ int 21 Description State Ver Status 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 +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 @@ -118,22 +119,22 @@ int 21 Description State Ver Status 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 +5d01h Commit All Files active 3.10 planned +5d02h Close File by Name active 3.10 planned +5d03h Close All Files for Computer active 3.10 planned +5d04h Close All Files for Process active 3.10 planned +5d05h Get Open File List active 3.10 planned 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 +5d0ah Set Extended Error active 4.00 planned 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 +63h Multibyte char ops undocumented 3.20 Note 4 64h ? undocumented returns error 65h NLS Functions active 3.30 supported 66h Code Page Functions active 3.30 supported @@ -143,7 +144,7 @@ int 21 Description State Ver Status 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 +71h LONG FILENAME FUNCTIONS active 7.00 not supported int 22: Program Termination Address. Supported. @@ -170,23 +171,19 @@ int 29: Fast Console Output. Supported. int 2F: DOS Multiplex. - Supported (not ALL functions, but MOST functions supported) + Supported. Notes: +Note 1 - Although this system call is supported, there are no device +drivers to support these devices in this release. + +Note 2 - Returns error code because internal data structures differ. -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 3 - Only sub-functions 0 and 1 are currently supported. -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 4 - Returns error code. -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. +Note 5 - Vector supported but performs no action. License ------- @@ -195,4 +192,4 @@ See COPYING in DOS-C root directory for license. --------------------------------------------------------------------- -$Id: intfns.txt 1344 2007-07-28 18:29:50Z mceric $ +$Id$ diff --git a/docs/memdisk.txt b/docs/memdisk.txt deleted file mode 100644 index 2e9a0fcc..00000000 --- a/docs/memdisk.txt +++ /dev/null @@ -1,94 +0,0 @@ -FreeDOS kernel with memdisk support compiled in: - -When enabled one can supplement (or replace) CONFIG.SYS from the memdisk -command line. The kernel upon booting will verify running on a 386+ and -then check for memdisk using int 13h call with magic values. If found -then the memdisk command line is processed and simulated CONFIG.SYS lines -are evaluated left to right as though they logically followed the last -line in CONFIG.SYS (or FDCONFIG.SYS). - -Example syslinux.cfg section: -LABEL FreeDOS - KERNEL memdisk - MENU LABEL FreeDOS example - INITRD FDSTD.img - APPEND {ECHO Booting FreeDOS}{ECHO This is the second line.} - - -FreeDOS config lines are denoted by surrounding the line in curly braces {} -thus allowing multiple simulated lines on a single APPEND line. However, -the closing brace } may be omitted if it would be immediately followed by -an opening brace { or end of the APPEND line. Anything on the memdisk line -outside of the curly braces {} is ignored. The lines may be preceeded by -FD= to be compatible with earlier FD kernel release or any other key= to -specify the environment variable generated by getargs utility. All simulated -config lines (text between the { and }) are evaluated by the kernel asis -except the final line (the line within final {}). - -The final } is optional which results in the memdisk options initrd= and -BOOT_IMAGE= to appear as part of the config.sys line. To avoid issues -several memdisk options are ignored if after the last opening brace {. -Note that the syslinux/memdisk options are case sensitive. Currently -ignored options are: initrd, BOOT_IMAGE, floppy, harddisk, and iso. - -Additionally, to simplify passing and overriding arguments when syslinux -is booting, any key=value pairs seen after any memdisk options will cause -all corresponding key=??? prior to any memdisk options to be cleared on -the resulting config line. -For example if the final assembled memdisk line appears to the kernel as: -{ECHO HI{ECHO X=1 X=2 Y=1 Z=1 initrd=FDSTD10.img BOOT_IMAGE=memdisk X=386 -then the following two lines will evaluated by the kernel after processing -any CONFIG.SYS lines. -ECHO HI -ECHO Y=1 Z=1 X=386 - -The following APPEND lines are all treated identically by the kernel. -APPEND floppy FD={ECHO Welcome}{ECHO 2nd line}{ECHO third} -APPEND floppy FD={ECHO Welcome{ECHO 2nd line{ECHO third -APPEND {ECHO Welcome} {ECHO 2nd line} {ECHO third} floppy -APPEND {ECHO Welcome{Echo 2nd line} {ECHO third floppy -resulting in the following equivalent three CONFIG.SYS lines -ECHO Welcome -ECHO 2nd line -ECHO third - - -The following complete example syslinux.cfg and FreeDOS configuration files -could be used to boot various kernel options avoiding the use of the FreeDOS -kernel menu in addition to the Sylinux menu. - -# CONFIG.SYS -REM always executed, in common with all choices -FILES=20 -LASTDRIVE=Z -SHELLHIGH=\COMMAND.COM /E:256 /P - - -#AUTOEXEC.BAT -@ECHO OFF -CLS -ECHO Welcome to FreeDOS (http://www.freedos.org)! -ECHO User selected menu %CONFIG% - - -# SYSLINUX.CFG -UI vesamenu.c32 -DEFAULT clean - -LABEL clean -MENU LABEL FreeDOS with no drivers -KERNEL memdisk -INITRD /fdos0360.img -APPEND floppy FD={SET config=0} - -LABEL jemm -MENU LABEL FreeDOS with memory manager -KERNEL memdisk -INITRD /fdos0360.img -APPEND floppy FD={SET config=1}{DEVICE?=JEMMEX.EXE - - -Syslinux boot-prompt (when vesamenu not used): -jemm -or -jemm NOEMS diff --git a/docs/nls.txt b/docs/nls.txt index 3f66febd..3875b54b 100644 --- a/docs/nls.txt +++ b/docs/nls.txt @@ -1,4 +1,4 @@ -Current version: $Id: nls.txt 59 2000-08-06 04:42:32Z jimtabor $ +Current version: $Id$ This document describes all aspects of the implementation of NLS in the FreeDOS kernel -- 2000/06/16 ska diff --git a/docs/readme.cvs b/docs/readme.cvs new file mode 100644 index 00000000..e58ac431 --- /dev/null +++ b/docs/readme.cvs @@ -0,0 +1,14 @@ +You can check out the latest code (from a UNIX type machine) using +CVS as follows: + +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 + + +You can also view the CVS code from the web at +http://freedos.sourceforge.net/ +Go to the CVS page. diff --git a/docs/readme.txt b/docs/readme.txt index 30cf1545..215b3441 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -1,43 +1,29 @@ 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 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/ +http://www.freedos.org. See the DOCS directory for more documentation and information about the FreeDOS Kernel. -Contents of release zip files: +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 or feature request, then add an issue to -the kernel's GitHub site: -https://github.com/FDOS/kernel/issues - -Note: bugs (or feature requests) reported at the old bug tracking -web page http://sourceforge.net/tracker/?group_id=5109&atid=105109 -and http://sourceforge.net/tracker/?atid=355109&group_id=5109&func=browse -will still be reviewed, but not actively. - -An archive of old (Bugzilla) items is at www.freedos.org/bugzilla/ - +like to make a suggestion, go to the bug tracking web page at +http://www.freedos.org/bugs/ Copyright --------- - DOS-C is (c) Copyright 1995, 1996 by Pasquale J. Villani All Rights Reserved. - -Portions of FreeDOS kernel copyright others, 199?-2024 diff --git a/docs/sys.htm b/docs/sys.htm new file mode 100644 index 00000000..949db0ba --- /dev/null +++ b/docs/sys.htm @@ -0,0 +1,120 @@ + +sys - FreeDOS system file installer + +

sys

+Copy system files and make a floppy disk or hard disk bootable. +
+  sys [[d:]path] d: [bootsect] [switches]
+
+

Options

+
+  [[d:]path]
+  The (optional) location of the system files.
+  If not given, the current directory is assumed.
+
+  d:
+  The drive to make bootable.
+
+  bootsect
+  The name of file, to which the 512-byte boot sector image
+  will be written.
+  (the drive's real boot sector won't be
+   written to unless BOTH is used.)
+
+Switches (FreeDOS specific):
+
+  /BOTH
+  The new boot sector will be written to the image file
+  and to the actual drive boot sector.
+
+  /BOOTONLY
+  With this option the boot sector (or image) will be updated,
+  but the kernel and command.com will
+  not be copied to the destination.
+
+  /UPDATE
+  This option is for updating (or changing) your kernel while
+  leaving your shell alone.  Updates the boot sector and copies
+  the kernel file(s) to the destination.  [Allows installing
+  latest kernel and boot sector without making a copy of your
+  current COMMAND.COM or other shell first.]  Note: for FreeDOS
+  kernel, an upgrade can also be performed by simply copying
+  KERNEL.SYS over an existing bootable one (though making a 
+  backup of your current kernel is encouraged).
+
+  /K filename
+  Gives the filename of the kernel file to be copied. This option
+  is only required when the kernel is not called "kernel.sys"
+  Note: when combined with the /L option, allows one to use FreeDOS
+  sys to create a system to boot custom kernels (ie custom OS)
+
+  /L segment
+  The load segent, in hexadecimal, to use. The default is 0x60.
+
+  /B btdrv
+  Sets the BIOS boot drive # (in hex) stored within the boot sector.
+
+  /FORCEDRV
+  Causes the boot sector to only use the btdrv indicated in
+  boot sector.  NOPs the code that normally uses BIOS provided
+  drive # passed at boot time in the DL register.
+
+  /BACKUPBS [path]filename
+  The original boot sector is written to [path]filename prior
+  to overwriting with FreeDOS one.  The filename may refer to any
+  [image or bs] file, if exists only the 1st 512 bytes will be
+  overwritten.
+
+  /DUMPBS [path]filename
+  The original boot sector is written to [path]filename and
+  then exits.  The filename may refer to any [image or bs] file,
+  if exists only the 1st 512 bytes will be overwritten.
+  Note: /backupbs is intented to provide a backup of existing
+  boot sector in case one wishes to restore it later (see /restorbs),
+  whereas /dumpbs is intended only as a convenient method to
+  obtain current boot sector (such as for debugging purposes or
+  alternate installation scenerios).
+
+  /RESTORBS [path]filename
+  Restores original boot sector ([path]filename) and exits.
+  The boot sector specified is written with no modifications.
+  The filename may refer to any [image or bs] file, only the 1st
+  512 bytes are used.
+
+  /OEM:DOS
+  Where DOS is one of
+    AUTO - the default, attempts to determine automatically,
+                  checking for FreeDOS, DR-DOS, PC-DOS, then MS-DOS;
+    FD   - FreeDOS mode, setup destination drive to boot
+                  the FreeDOS kernel and copy FreeDOS system files
+                  (default to KERNEL.SYS and load segment of 0x60)
+    DR   - use DR DOS 7+ (including Udo Kuhnt's DR-DOS
+                  Enhanement Project) compatible settings
+                  (use IBMBIO.COM & IBMDOS.COM, and loadseg=0x70)
+    PC   - use PC-DOS (any) compatible settings, including
+                  alternate boot sector (supports FAT12/16 only)
+                  Must be explicitly choosen, AUTO selects DR mode.
+                  (use IBMBIO.COM & IBMDOS.COM, and loadseg=0x70)
+    MS   - use MS-DOS (pre 7) compatible settings, including
+                  alternate boot sector (supports FAT12/16 only)
+                  (use IO.SYS & MSDOS.SYS, and loadseg=0x70)
+    W9x  - use MS-DOS 7+, aka Windows 9x DOS compatible
+                  settings, Win ME unsupported ...
+
+  Note: when attempting to boot older PC/MS DOS versions, even when
+  using the alternate boot sector, one may need to ensure the
+  system files are the 1st two filesystem entries and in consecutive
+  sectors at the beginning of the drive; so for best results when
+  creating a PC/MS DOS boot disk, format the drive first, do NOT
+  create a label, and then run sys on it.  You can then add a label.
+  Newer releases, such as PC-DOS 7.x do not have these limitations.
+
+
+
+
+Copyright © 1998 Jim Hall
+This file is derived from the FreeDOS Spec Command HOWTO. +See the file H2Cpying.txt for copying conditions. +
+ + diff --git a/docs/sys.txt b/docs/sys.txt index d47bb1d1..4dbc6dac 100644 --- a/docs/sys.txt +++ b/docs/sys.txt @@ -1,4 +1,4 @@ -FreeDOS System Installer v3.6f - Nov 20, 2024 +FreeDOS SYS 3.6 documentation by: Jeremy Davis Bart Oldeman @@ -13,9 +13,10 @@ The best documentation is the source itself, but we try to keep this document updated. -Usage: SYS [source] drive: [bootsect] [{option}] +Usage: +SYS [source] dest: [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 + dest = A,B,etc. 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: @@ -23,34 +24,22 @@ Usage: SYS [source] drive: [bootsect] [{option}] /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 FreeDOS settings - /OEM:EDR Enhanced DR-DOS (DRBIO.SYS and DRDOS.SYS) - /OEM:LEDRPACK Enhanced DR-DOS (EDRPACK.SYS, lDOS drload) - /OEM:LEDR Enhanced DR-DOS (EDRDOS.COM, lDOS iniload) - /OEM:LMSPACK OSS MS-DOS (LMSPACK.SYS, lDOS drload) - /OEM:LMS OSS MS-DOS (LMSDOS.COM, lDOS iniload) - /OEM:OPENDOS Caldera OpenDOS 7.01 (and Novell DOS 7), - DR-DOS 7.02 - 7.03, 7.01.01 - 7.01.06 - /OEM:PC PC-DOS, DR DOS 5 - Novell DOS 7 - /OEM:MS MS-DOS - /OEM:W9x MS Win9x DOS - default is /OEM[:AUTO], select DOS based on existing files + /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 + /FORCEDRV: force use of drive # set in bs instead of BIOS boot value /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 + /SKFN filename : set KERNEL.SYS input file and /OEM:FD + /SCFN filename : sets COMMAND.COM input file /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 @@ -97,23 +86,6 @@ 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. - -SYS by default installs the FreeDOS kernel KERNEL.SYS. -If KERNEL.SYS is not found, it may install a different -kernel, like an Enhanced DR-DOS kernel, provided it -finds one. You may explicitly tell SYS which kernel -flavour to install via the /OEM argument. - Kernel Configuration Options: diff --git a/drivers/floppy.asm b/drivers/floppy.asm index d000ce1b..ae317680 100644 --- a/drivers/floppy.asm +++ b/drivers/floppy.asm @@ -25,15 +25,14 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: floppy.asm 980 2004-06-19 19:41:47Z perditionc $ +; $Id$ ; %include "../kernel/segs.inc" -%include "../hdr/stacks.inc" segment HMA_TEXT ; -; BOOL ASMPASCAL fl_reset(WORD drive); +; int ASMPASCAL fl_reset(UBYTE drive); ; ; Reset both the diskette and hard disk system. ; returns TRUE if successful. @@ -42,188 +41,175 @@ segment HMA_TEXT global FL_RESET FL_RESET: pop ax ; return address - pop dx ; drive (DL only) + pop dx ; drive push ax ; restore address - mov ah,0 ; BIOS reset diskette & fixed disk + mov ah,0 ; reset disk int 13h - - sbb ax,ax ; carry set indicates error, AX=-CF={-1,0} + sbb ax,ax ; CF=1: error inc ax ; ...return TRUE (1) on success, - ret ; else FALSE (0) on failure + ret ; FALSE (0) on error ; -; COUNT ASMPASCAL fl_diskchanged(WORD drive); +; int ASMPASCAL fl_diskchanged(UBYTE drive); ; ; Read disk change line status. -; returns 1 if disk has changed, 0 if not, 0xFFFF if error. +; returns 1 if disk has changed, 0 if not, 0xFF if error. ; global FL_DISKCHANGED FL_DISKCHANGED: pop ax ; return address - pop dx ; drive (DL only, 00h-7Fh) + pop dx ; drive push ax ; restore stack - push si ; preserve value - mov ah,16h ; read change status type + push si + mov ah,16h ; read change status type xor si,si ; RBIL: avoid crash on AT&T 6300 int 13h - pop si ; restore + pop si - 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 + sbb al,al ; CF=0 (disk has not changed) + jnc ret_AH_0 ; ...return 0 + cmp ah,6 ; ah!=6 (error) + jne ret_AH_0 ; ...return 0xFF + mov al,1 ; ah=6 (disk has changed) + jmp short ret_AH_0 ; ...return 1 ; -; 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. +; int ASMPASCAL fl_read (UBYTE drive, WORD head, WORD track, WORD sector, WORD count, void FAR *buffer); +; int ASMPASCAL fl_write (UBYTE drive, WORD head, WORD track, WORD sector, WORD count, void FAR *buffer); +; int ASMPASCAL fl_verify(UBYTE drive, WORD head, WORD track, WORD sector, WORD count, void FAR *buffer); +; int ASMPASCAL fl_format(UBYTE drive, WORD head, WORD track, WORD sector, WORD count, void FAR *buffer); ; +; Format tracks (sector should be 0). + global FL_FORMAT FL_FORMAT: - mov ah,5 ; format track - jmp short fl_common + 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 ah,4 ; verify sector(s) + jmp short fl_common -arg drive, head, track, sector, count, {buffer,4} - mov cx,[.track] ; cylinder number + global FL_READ +FL_READ: + mov ah,2 ; read sector(s) + jmp short fl_common - 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. + global FL_WRITE +FL_WRITE: + mov ah,3 ; write sector(s) - 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,[.sector] ; or in the sector number (bits 0-5) +fl_common: + push bp + mov bp,sp - mov al,[.count] ; count of sectors to read/write/... - les bx,[.buffer] ; Load 32 bit buffer ptr into ES:BX + mov cx,[bp+12] ; cylinder number + mov al,1 ; error code + cmp ch,3 + ja fl_error ; can't write above 3FFh=1023 - mov dl,[.drive] ; drive (if or'ed 80h its a hard drive) - mov dh,[.head] ; get the head number + xchg ch,cl ; ch=low 8 bits of cylinder number + mov dh,[bp+14] ; head number + ror cl,1 ; bits 8-9 of cylinder number... + ror cl,1 ; ...to bits 6-7 in CL + or cl,[bp+10] ; sector number (bits 0-5) - int 13h ; process sectors + mov al,[bp+8] ; number of sectors + les bx,[bp+4] ; 32-bit buffer ptr + mov dl,[bp+16] ; drive (if or'ed 80h its hard drive) + 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 + mov ah,0 + pop bp + ret 14 ; -; COUNT ASMPASCAL fl_lba_ReadWrite(BYTE drive, WORD mode, void FAR * dap_p); +; int ASMPASCAL fl_lba_ReadWrite(UBYTE drive, WORD mode, void FAR * dap); ; ; Returns 0 if successful, error code otherwise. ; - global FL_LBA_READWRITE + global FL_LBA_READWRITE FL_LBA_READWRITE: - push bp ; setup stack frame - mov bp,sp - - push ds - push si ; wasn't in kernel < KE2024Bo6!! - -arg drive, mode, {dap_p,4} - mov dl,[.drive] ; drive (if or'ed with 80h a hard drive) - mov ax,[.mode] ; get the command - lds si,[.dap_p] ; 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 + push bp + mov bp,sp + push si + push ds + mov dl,[bp+10] ; drive (if or'ed 80h its hard drive) + mov ax,[bp+8] ; command + lds si,[bp+4] ; far dap pointer + int 13h ; process sectors + pop ds + pop si + pop bp + mov al,ah ; place error code into al + mov ah,0 + ret 8 ; ; void ASMPASCAL fl_readkey (void); ; global FL_READKEY -FL_READKEY: xor ah, ah +FL_READKEY: + mov ah,0 int 16h ret ; -; COUNT ASMPASCAL fl_setdisktype (WORD drive, WORD type); +; int ASMPASCAL fl_setdisktype (UBYTE drive, WORD type); ; global FL_SETDISKTYPE FL_SETDISKTYPE: pop bx ; return address - popargs dx,ax ; drive number(dl),disk format type(al) + pop ax ; disk type + pop dx ; drive push bx ; restore stack - mov ah,17h ; floppy set disk type for format + mov ah,17h ; set disk type for format int 13h ret_AH: - mov al,ah ; place any error code into al - mov ah,0 ; zero out ah + mov al,ah ; place error code into al +ret_AH_0: + mov ah,0 ret - + ; -; COUNT ASMPASCAL fl_setmediatype (WORD drive, WORD tracks, WORD sectors); +; int ASMPASCAL fl_setmediatype (UBYTE drive, WORD tracks, WORD sectors); ; + global FL_SETMEDIATYPE FL_SETMEDIATYPE: pop ax ; return address - popargs dx,cx,bx ; drive number,#tracks,sectors/track + pop bx ; sectors/track + pop cx ; number of tracks + pop dx ; drive push ax ; restore stack push di - dec cx ; number of cylinders - 1 (last cyl number) + dec cx ; last cylinder 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 + ror cl,1 ; bits 8-9 of cylinder number... + ror cl,1 ; ...to bits 6-7 in CL + or cl,bl ; sectors/track (bits 0-5) + mov ah,18h ; set media type for format int 13h jc skipint1e push es - xor dx,dx - mov es,dx + 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 + mov [es:0x1e*4],di + pop word [es:0x1e*4+2] ; set int 0x1e table to es:di sti -skipint1e: - pop di +skipint1e: + pop di jmp short ret_AH - diff --git a/drivers/makefile b/drivers/makefile index 22a68f75..91348342 100644 --- a/drivers/makefile +++ b/drivers/makefile @@ -1,49 +1,28 @@ # # makefile for device.lib # -# $Id: makefile 1387 2009-05-19 21:39:29Z bartoldeman $ +# $Id$ # - !include "../mkfiles/generic.mak" +OBJS=floppy.obj rdpcclk.obj wrpcclk.obj wratclk.obj +LIBOBJS=+floppy +rdpcclk +wrpcclk +wratclk -# 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= $(LIBPLUS)floppy.obj $(LIBPLUS)rdpcclk.obj $(LIBPLUS)wrpcclk.obj $(LIBPLUS)wratclk.obj +# Build the LIBRARY #################################################### +all: ..\lib\device.lib +..\lib\device.lib: $(OBJS) + -$(RM) $*.lib + $(LIBUTIL) $(LIBFLAGS) $* $(LIBOBJS) $(LIBTERM) -# Build the LIBRARY -# ----------------- -all: production +$(OBJS): $(DEPENDS) ../kernel/segs.inc -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.lib $(LIBOBJS) $(LIBTERM) + -$(RM) *.bak *.cod *.crf *.err *.las *.lst *.map *.obj *.xrf +clobber: clean + -$(RM) ..\lib\device.lib status.me diff --git a/drivers/rdpcclk.asm b/drivers/rdpcclk.asm index b14abf06..fb886c7d 100644 --- a/drivers/rdpcclk.asm +++ b/drivers/rdpcclk.asm @@ -42,8 +42,8 @@ READPCCLOCK: 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; + add word [_DaysSinceEpoch ],ax ; *some* BIOS's accumulate several days + adc word [_DaysSinceEpoch+2],0 ; ; set return value dx:ax xchg ax,cx ; ax=_cx, cx=_ax diff --git a/drivers/wratclk.asm b/drivers/wratclk.asm index 1862dd36..38a4f800 100644 --- a/drivers/wratclk.asm +++ b/drivers/wratclk.asm @@ -29,7 +29,6 @@ ; %include "../kernel/segs.inc" - %include "../hdr/stacks.inc" segment HMA_TEXT @@ -48,14 +47,13 @@ WRITEATCLOCK: ; bcdMinutes = 6 ; bcdHours = 8 ; bcdDays = 10 -arg bcdDays, bcdHours, bcdMinutes, bcdSeconds - mov ch,byte [.bcdHours] - mov cl,byte [.bcdMinutes] - mov dh,byte [.bcdSeconds] + 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 [.bcdDays] + mov bx,word [bp+10] ;bcdDays mov dx,word [bx] mov cx,word [bx+2] mov ah,5 diff --git a/drivers/wrpcclk.asm b/drivers/wrpcclk.asm index c4e8129f..051bc259 100644 --- a/drivers/wrpcclk.asm +++ b/drivers/wrpcclk.asm @@ -28,7 +28,6 @@ ; $Header$ ; %include "../kernel/segs.inc" - %include "../hdr/stacks.inc" segment HMA_TEXT @@ -41,7 +40,8 @@ segment HMA_TEXT WRITEPCCLOCK: ; Ticks = 4 pop ax ; return address - popargs {cx,dx} ; Ticks + pop dx + pop cx ; Ticks push ax ; restore stack mov ah,1 int 1ah diff --git a/filelist b/filelist index e7c9a743..e49f924f 100644 --- a/filelist +++ b/filelist @@ -3,12 +3,16 @@ */*/clean.bat */*/clobber.bat */*/config.b +*/*/defaults.bat */*/filelist -*/*/default.bat */*/makefile +*/*/bin/autoexec.bat +*/*/bin/config.sys +*/*/bin/install.bat */*/boot/boot.asm */*/boot/boot32.asm */*/boot/boot32lb.asm +*/*/boot/oemboot.asm */*/boot/makefile */*/docs/bugs.txt */*/docs/build.txt @@ -34,11 +38,10 @@ */*/hdr/buffer.h */*/hdr/cds.h */*/hdr/clock.h +*/*/hdr/date.h */*/hdr/dcb.h -*/*/hdr/ddate.h */*/hdr/device.h */*/hdr/dirmatch.h -*/*/hdr/dtime.h */*/hdr/error.h */*/hdr/exe.h */*/hdr/fat.h @@ -57,6 +60,7 @@ */*/hdr/sft.h */*/hdr/stacks.inc */*/hdr/tail.h +*/*/hdr/time.h */*/hdr/version.h */*/hdr/xstructs.h */*/kernel/nls/001-437.hc @@ -74,6 +78,7 @@ */*/kernel/config.c */*/kernel/config.h */*/kernel/console.asm +*/*/kernel/country.asm */*/kernel/dosfns.c */*/kernel/dosidle.asm */*/kernel/dosnames.c @@ -104,18 +109,15 @@ */*/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 @@ -128,26 +130,30 @@ */*/kernel/syspack.c */*/kernel/systime.c */*/kernel/task.c +*/*/kernel/tci.cfg */*/kernel/turboc.cfg +*/*/kernel/msc.cfg +*/*/kernel/wc.cfg +*/*/kernel/wci.cfg */*/lib/makefile */*/mkfiles/generic.mak -*/*/mkfiles/bc5.mak -*/*/mkfiles/mscl8.mak -*/*/mkfiles/tc2.mak -*/*/mkfiles/tc3.mak -*/*/mkfiles/turbocpp.mak +*/*/mkfiles/bc.mak +*/*/mkfiles/tc.mak +*/*/mkfiles/tcpp.mak +*/*/mkfiles/tcpp3.mak +*/*/mkfiles/msc.mak */*/mkfiles/watcom.mak */*/sys/fdkrncfg.c */*/sys/bin2c.c */*/sys/makefile */*/sys/sys.c */*/sys/talloc.c +*/*/sys/turboc.cfg */*/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 +*/*/utils/turboc.cfg diff --git a/hdr/buffer.h b/hdr/buffer.h index 09c0e390..539df2be 100644 --- a/hdr/buffer.h +++ b/hdr/buffer.h @@ -33,13 +33,11 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *buffer_hRcsId = - "$Id: buffer.h 1702 2012-02-04 08:46:16Z perditionc $"; + "$Id$"; #endif #endif -#include "dsk.h" /* only for MAX_SEC_SIZE */ -#define BUFFERSIZE MAX_SEC_SIZE - +#define BUFFERSIZE 512 struct buffer { UWORD b_next; /* next buffer in LRU list */ UWORD b_prev; /* previous buffer in LRU list */ diff --git a/hdr/cds.h b/hdr/cds.h index 8dc39f6f..149f5905 100644 --- a/hdr/cds.h +++ b/hdr/cds.h @@ -26,6 +26,12 @@ /* Cambridge, MA 02139, USA. */ /****************************************************************/ +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *Cds_hRcsId = + "$Id$"; +#endif +#endif #define MAX_CDSPATH 67 @@ -44,7 +50,7 @@ struct cds { } _cdsRedir; } _cdsUnion; - UWORD cdsUserData; /* initialized to 0xFFFF, otherwise unused by kernel */ + UWORD cdsStoreUData; #define cdsJoinOffset cdsBackslashOffset WORD cdsBackslashOffset; /* Position of "root directory" backslash for @@ -55,9 +61,9 @@ struct cds { if local path: ofs > colon */ - BYTE cdsIfsType; /* According to PCDOS 7 Tech Ref: IFS drive, 2=IFS, 4=NetUse, unused by kernel */ - BYTE FAR *cdsIfs; /* Pointer to Installable File System Header */ - UWORD cdsFileSysData; /* File System specific data, unused by kernel */ + BYTE cdsNetFlag1; + BYTE FAR *cdsIfs; + UWORD cdsNetFlags2; }; diff --git a/hdr/clock.h b/hdr/clock.h index 8d141609..c8b41db3 100644 --- a/hdr/clock.h +++ b/hdr/clock.h @@ -33,7 +33,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *clock_hRcsId = - "$Id: clock.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif diff --git a/hdr/ddate.h b/hdr/date.h similarity index 94% rename from hdr/ddate.h rename to hdr/date.h index 7a96ba5e..4bfa8e78 100644 --- a/hdr/ddate.h +++ b/hdr/date.h @@ -1,6 +1,6 @@ /****************************************************************/ /* */ -/* ddate.h */ +/* date.h */ /* */ /* DOS General Date Structure */ /* */ @@ -33,7 +33,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *date_hRcsId = - "$Id: date.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif @@ -51,7 +51,7 @@ static BYTE *date_hRcsId = #define EPOCH_DAY 1 /* 1 for January 1 */ #define EPOCH_YEAR 1980 /* for Tues 1-1-80 epoch */ -typedef UWORD ddate; +typedef UWORD date; #endif diff --git a/hdr/dcb.h b/hdr/dcb.h index 26044fc1..13bbec04 100644 --- a/hdr/dcb.h +++ b/hdr/dcb.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *clock_hRcsId = - "$Id: dcb.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif @@ -80,8 +80,8 @@ struct dpb { 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 */ + CLUSTER dpb_xrootclst; /* starting cluster of root dir */ + CLUSTER dpb_xcluster; /* cluster # of first free */ /* -1 if not known */ #endif }; @@ -89,4 +89,3 @@ struct dpb { #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 index 5275d7ec..ae05d67c 100644 --- a/hdr/debug.h +++ b/hdr/debug.h @@ -44,16 +44,6 @@ #endif #endif - -/* assert macro */ -#ifdef DEBUG -VOID panic(BYTE * s); -#define assert(condition) (void)(!(condition)?panic(#condition),0:0) -#else -#define assert(condition) /* ((void)0) */ -#endif - - /* use to limit output to debug builds */ #ifdef DEBUG #ifdef DEBUG_PRINT_COMPORT @@ -76,7 +66,7 @@ VOID panic(BYTE * s); /* #define DEBUGIRQ */ /* show output related to moving kernel into HMA */ -#ifdef DEBUGHMA +#ifdef DEBUG #define HMAInitPrintf(x) DebugPrintf(x) #else #define HMAInitPrintf(x) @@ -127,39 +117,27 @@ VOID panic(BYTE * s); #endif /* debug truename */ -#ifdef DEBUG -#ifndef DEBUG_TRUENAME -#define DEBUG_TRUENAME -#endif -#endif +/* #define DEBUG_TRUENAME */ #ifdef DEBUG_TRUENAME #define tn_printf(x) DebugPrintf(x) #else #define tn_printf(x) #endif -/* debug task/process creation */ -#ifdef DEBUGTASK -#define ProcDbgPrintf(x) DebugPrintf(x) -#else -#define ProcDbgPrintf(x) -#endif - -/* ensure printf is prototyped */ +/* just to be sure printf is declared */ #if defined(DEBUG) || defined(DEBUGIRQ) || defined(DEBUGCFG) || \ defined(DEBUGDOSFNS) || defined(CHDIR_DEBUG) || defined(FIND_DEBUG) || \ - defined(DEBUGFATDIR) || defined(DEBUGFATFS) || \ - defined(FORCEPRINTF) + defined(DEBUGFATDIR) || defined(DEBUGFATFS) #ifndef DEBUG_NEED_PRINTF #define DEBUG_NEED_PRINTF #endif #endif #ifdef DEBUG_NEED_PRINTF -int VA_CDECL printf(CONST char * fmt, ...); +VOID VA_CDECL printf(CONST char FAR * fmt, ...); #ifdef DEBUG_PRINT_COMPORT -int VA_CDECL dbgc_printf(CONST char * fmt, ...); +VOID VA_CDECL dbgc_printf(CONST char FAR * fmt, ...); #endif #endif diff --git a/hdr/device.h b/hdr/device.h index 32905fc5..4cefb2f8 100644 --- a/hdr/device.h +++ b/hdr/device.h @@ -27,6 +27,12 @@ /* Cambridge, MA 02139, USA. */ /****************************************************************/ +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *device_hRcsId = + "$Id$"; +#endif +#endif /* * Status Word Bits @@ -150,15 +156,15 @@ typedef struct { UWORD bpb_nbyte; /* Bytes per Sector */ UBYTE bpb_nsector; /* Sectors per Allocation Unit */ UWORD bpb_nreserved; /* # Reserved Sectors */ - UBYTE bpb_nfat; /* # FATs */ + UBYTE bpb_nfat; /* # FAT's */ UWORD bpb_ndirent; /* # Root Directory entries */ - UWORD bpb_nsize; /* Total volume Size in sectors */ + 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; /* Total volume Size in sectors if*/ + ULONG bpb_huge; /* Size in sectors if */ /* bpb_nsize == 0 */ #ifdef WITHFAT32 ULONG bpb_xnfsect; /* FAT size in sectors if */ @@ -168,7 +174,7 @@ typedef struct { /* bits 6-4: reserved (0) */ /* bits 3-0: active FAT number */ UWORD bpb_xfsversion; /* filesystem version */ - ULONG bpb_xrootclst; /* starting cluster of root dir */ + CLUSTER bpb_xrootclst; /* starting cluster of root dir */ UWORD bpb_xfsinfosec; /* FS info sector number, */ /* 0xFFFF if unknown */ UWORD bpb_xbackupsec; /* backup boot sector number */ @@ -177,8 +183,7 @@ typedef struct { } bpb; #define N_RETRY 5 /* number of retries permitted */ - -#include "dsk.h" +#define SEC_SIZE 512 /* size of sector in bytes */ #define LBA_READ 0x4200 #define LBA_WRITE 0x4300 @@ -242,7 +247,7 @@ typedef struct ddtstruct { /* 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_CURBPBLOCK 0x004 /* current BPB locked ??? */ #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 */ @@ -253,7 +258,6 @@ typedef struct ddtstruct { /* freedos specific flag bits */ #define DF_LBA 0x400 #define DF_WRTVERIFY 0x800 -#define DF_DMA_TRANSPARENT 0x1000 /* DMA boundary errors are handled transparently */ /* typedef struct ddtstruct ddt;*/ @@ -486,7 +490,6 @@ extern request /* I/O Request packets */ /* dsk.c */ COUNT ASMCFUNC FAR blk_driver(rqptr rp); ddt * getddt(int dev); -COUNT writelabelBPB(char drive, const char *name); /* error.c */ COUNT char_error(request * rq, struct dhdr FAR * lpDevice); @@ -495,12 +498,7 @@ COUNT block_error(request * rq, COUNT nDrive, struct dhdr FAR * lpDevice, int mo 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 index e6da7eab..44c53271 100644 --- a/hdr/dirmatch.h +++ b/hdr/dirmatch.h @@ -31,24 +31,32 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *dirmatch_hRcsId = - "$Id: dirmatch.h 1415 2009-06-02 13:18:24Z bartoldeman $"; + "$Id$"; #endif #endif typedef struct { UBYTE dm_drive; BYTE dm_name_pat[FNAME_SIZE + FEXT_SIZE]; - UBYTE dm_attr_srch; + BYTE dm_attr_srch; /* !!! should be UBYTE --avb */ UWORD dm_entry; CLUSTER dm_dircluster; #ifndef WITHFAT32 UWORD reserved; #endif - UWORD reserved2; + + struct { + BITS f_dmod:1; /* directory has been modified */ + BITS f_droot:1; /* directory is the root */ + BITS f_dnew:1; /* fnode is new and needs fill */ + BITS f_ddir:1; /* fnode is assigned to dir */ + BITS f_filler:12; /* filler to avoid a bad bug */ + /* (feature?) in TC 2.01 */ + } dm_flags; /* file flags */ UBYTE dm_attr_fnd; /* found file attribute */ - dtime dm_time; /* file time */ - ddate dm_date; /* file date */ + 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 deleted file mode 100644 index 96cd257c..00000000 --- a/hdr/dsk.h +++ /dev/null @@ -1,31 +0,0 @@ -/****************************************************************/ -/* */ -/* 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 index 8ce3cf4e..1aba1b0f 100644 --- a/hdr/error.h +++ b/hdr/error.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *error_hRcsId = - "$Id: error.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif diff --git a/hdr/exe.h b/hdr/exe.h index 3c4866d1..cc434b26 100644 --- a/hdr/exe.h +++ b/hdr/exe.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *exe_hRcsId = - "$Id: exe.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif diff --git a/hdr/fat.h b/hdr/fat.h index e2dd16d0..8670bbc7 100644 --- a/hdr/fat.h +++ b/hdr/fat.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *fat_hRcsId = - "$Id: fat.h 1448 2009-06-16 21:45:17Z bartoldeman $"; + "$Id$"; #endif #endif @@ -105,8 +105,8 @@ struct dirent { UWORD dir_crdate; /* Creation date */ UWORD dir_accdate; /* Last access date */ UWORD dir_start_high; /* High word of the cluster */ - dtime dir_time; /* Time file created/updated */ - ddate dir_date; /* Date file created/updated */ + time dir_time; /* Time file created/updated */ + date dir_date; /* Date file created/updated */ UWORD dir_start; /* Starting cluster */ /* 1st available = 2 */ ULONG dir_size; /* File size in bytes */ @@ -131,18 +131,20 @@ struct lfn_entry { struct dpb; CLUSTER getdstart(struct dpb FAR *dpbp, struct dirent *dentry); void setdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value); +BOOL checkdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value); #else #define getdstart(dpbp, dentry) \ ((dentry)->dir_start) #define setdstart(dpbp, dentry, value) \ (((dentry)->dir_start) = (UWORD)(value)) +#define checkdstart(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) diff --git a/hdr/fcb.h b/hdr/fcb.h index be3d1b88..2d5f4493 100644 --- a/hdr/fcb.h +++ b/hdr/fcb.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *fcb_hRcsId = - "$Id: fcb.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif @@ -86,8 +86,8 @@ typedef struct { UWORD fcb_recsiz; /* Logical record size in bytes, */ /* default = 128 */ ULONG fcb_fsize; /* File size in bytes */ - ddate fcb_date; /* Date file created */ - dtime fcb_time; /* Time of last write */ + 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 */ diff --git a/hdr/file.h b/hdr/file.h index ad09f9ae..ec63ebd8 100644 --- a/hdr/file.h +++ b/hdr/file.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *file_hRcsId = - "$Id: file.h 831 2004-03-27 00:27:11Z bartoldeman $"; + "$Id$"; #endif #endif @@ -58,10 +58,8 @@ static BYTE *file_hRcsId = /* bits 2, 3 reserved */ /* bits 4, 5, 6 sharing modes */ -/* see PC Mag Nov 15, 1988 "Networked Database" p234 by Frank J Derfler Jr */ #define O_SHAREMASK 0x0070 /* mask to isolate shared bits */ -#define O_COMPAT 0x0000 /* default, compatibility mode */ #define O_DENYALL 0x0010 /* sharing bits */ #define O_DENYWRITE 0x0020 /* " " */ #define O_DENYREAD 0x0030 /* " " */ diff --git a/hdr/fnode.h b/hdr/fnode.h index 1e2face8..5803d4f4 100644 --- a/hdr/fnode.h +++ b/hdr/fnode.h @@ -31,27 +31,32 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *fnode_hRcsId = - "$Id: fnode.h 1432 2009-06-10 16:10:54Z bartoldeman $"; + "$Id$"; #endif #endif struct f_node { + UWORD f_count; /* number of uses of this file */ + COUNT f_mode; /* read, write, read-write, etc */ + 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*/ + UWORD f_diroff; /* offset/32 of the dir entry */ + CLUSTER f_dirstart; /* the starting cluster of dir */ /* 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 */ }; +#define F_DMOD 1 /* directory has been modified */ +#define F_DDIR 2 /* fnode is assigned to dir */ +#define F_DDATE 4 /* date set using setdate */ + typedef struct f_node *f_node_ptr; struct lfn_inode { diff --git a/hdr/kbd.h b/hdr/kbd.h index 2c13512c..10ef3392 100644 --- a/hdr/kbd.h +++ b/hdr/kbd.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *kbd_hRcsId = - "$Id: kbd.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif diff --git a/hdr/kconfig.h b/hdr/kconfig.h index 02c340ad..b6a4faed 100644 --- a/hdr/kconfig.h +++ b/hdr/kconfig.h @@ -21,29 +21,7 @@ ' hit any key to continue to boot from 'diskette or CD' wait ## seconds if no key hit, boot from HD - - Version_: only in kernel 2042 or higher, offline version identification - OemID: 0xFD for FreeDOS kernel, 0xDC for DosC kernel - Major: actual kernel version (not MS-DOS compatibility version), e.g. 2 - Revision: revision sequence, e.g. 42 for kernel 2042 - Release: 0 if released version, >0 for svn builds (e.g. svn revision #) - CheckDebugger: during initialization enable/disable check to stop in debugger if one is active - 0 = do not check (assume absent), - 1 = do check by running breakpoint, - 2 = assume present - - Verbose: amount of messages to display during initialization - -1 = quiet - 0 = normal - 1 = verbose - - PartitionMode: how to handle GPT and MBR partitions - bits 0-1: 01=GPT if found, 00=MBR if found, 11=Hybrid, GPT first then MBR, 10=Hybrid, MBR first then GPT - in hybrid mode, EE partitions ignored, drives assigned by GPT or MBR first based on hybrid type - bits 2-4: 001=mount ESP (usually FAT32) partition, 010=mount MS Basic partitions, 100=mount unknown partitions - 111=attempt to mount all paritions, 110=attempt to mount all but ESP partitions - bits 5-7: reserved, 0 else undefined behavior */ typedef struct _KernelConfig { char CONFIG[6]; /* "CONFIG" */ @@ -55,15 +33,4 @@ typedef struct _KernelConfig { unsigned char ForceLBA; unsigned char GlobalEnableLBAsupport; /* = 0 --> disable LBA support */ signed char BootHarddiskSeconds; - - /* for version 2042 and higher only */ - unsigned char Version_OemID; - unsigned char Version_Major; - unsigned short Version_Revision; - unsigned short Version_Release; - - /* for version 2044 and higher only */ - unsigned char CheckDebugger; - signed char Verbose; - unsigned char PartitionMode; } KernelConfig; diff --git a/hdr/lol.h b/hdr/lol.h index b18fa6f0..e12e539b 100644 --- a/hdr/lol.h +++ b/hdr/lol.h @@ -26,7 +26,8 @@ /* Boston, MA 02111-1307 USA. */ /****************************************************************/ -enum {LOC_CONV=0, LOC_HMA=1}; +#ifndef __LOL_H +#define __LOL_H /* 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) */ @@ -39,7 +40,7 @@ struct lol { 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 */ + unsigned short maxsecbytes; /* 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 */ @@ -55,7 +56,7 @@ struct lol { 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 char dwordmoves; /* 44 use dword moves (unused) */ 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 */ @@ -73,15 +74,17 @@ struct lol { 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 rev_number; /* 6e minor DOS version */ unsigned char version_flags; /* 6f DOS version flags */ - char *os_release; /* 70 near pointer to os_release string */ + struct f_node FAR *f_nodes; /* 70 pointer to the array */ + unsigned short f_nodes_cnt; /* 74 number of allocated f_nodes */ + char *os_release; /* 76 near pointer to os_release string */ + /* ANY ITEM BELOW THIS POINT MAY CHANGE */ #ifdef WIN31SUPPORT unsigned short winInstanced; /* WinInit called */ unsigned long winStartupInfo[4]; @@ -89,3 +92,4 @@ struct lol { #endif }; +#endif /* __LOL_H */ diff --git a/hdr/mcb.h b/hdr/mcb.h index 6fc47e5b..6ff077c2 100644 --- a/hdr/mcb.h +++ b/hdr/mcb.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *mcb_hRcsId = - "$Id: mcb.h 822 2004-03-25 00:20:20Z bartoldeman $"; + "$Id$"; #endif #endif diff --git a/hdr/network.h b/hdr/network.h index 7e33e5c3..dcb66f08 100644 --- a/hdr/network.h +++ b/hdr/network.h @@ -59,9 +59,6 @@ #define REM_PRINTREDIR 0x1125 #define REM_EXTOC 0x112e -/* Redirector extensions */ -#define REM_GETLARGESPACE 0x11a3 - struct rgds { UWORD r_spc; UWORD r_navc; diff --git a/hdr/nls.h b/hdr/nls.h index 7025c87e..1e9e4fa5 100644 --- a/hdr/nls.h +++ b/hdr/nls.h @@ -28,7 +28,7 @@ /****************************************************************/ /* one byte alignment */ -#include "algnbyte.h" +#include /* * Description of the organization of NLS information -- 2000/02/13 ska @@ -175,7 +175,7 @@ * * Performance tweaks: * When the system -- This word applies to the combination of kernel and - * any loaded MUX-14 extension � la NLSFUNC here. -- uppercases + * 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 @@ -356,9 +356,6 @@ struct CountrySpecificInfo { */ char CurrencyPrecision; /* = 2 # Currency precision */ char TimeFormat; /* = 0 # time format: 0/1: 12/24 houres */ - void FAR *CharMapFn; /* far pointer to user callable character mapping function */ - char DataSeparator[2]; /* ',' ASCIIZ value */ - /* 5 words reserved, should be 0 */ }; /* @@ -406,7 +403,7 @@ struct nlsExtCntryInfo { 0: 12 hours (append AM/PM) 1: 24 houres */ - intvec upCaseFct; /* far call to a function upcasing the + VOID(FAR * upCaseFct) (VOID); /* far call to a function upcasing the character in register AL */ char dataSep[2]; /* ASCIZ of separator in data records */ }; @@ -433,16 +430,12 @@ struct nlsPackage { /* the contents of one chain item of the UWORD yeschar; /* yes / no character DOS-65-23 */ UWORD nochar; unsigned numSubfct; /* number of supported sub-functions */ - struct nlsPointer nlsPointers[5]; /* may grow dynamically */ - struct nlsExtCntryInfo nlsExt; + struct nlsPointer nlsPointers[1]; /* grows dynamically */ }; struct nlsDBCS { /* The internal structure is unknown to me */ UWORD numEntries; - UWORD dbcsTbl[4]; /* I don't know max size but it should need - at least 3 words (6 bytes) - ({0x81,0x9f,0xe0,0xfc,0,0} for CP932-Japan) - -- lpproj 2014/10/27 */ + UWORD dbcsTbl[1]; }; struct nlsCharTbl { @@ -477,23 +470,20 @@ struct nlsInfoBlock { /* This block contains all information maybe tweaked by NLSFUNC */ UWORD sysCodePage; /* system code page */ unsigned flags; /* implementation flags */ -#ifdef __GNUC__ - /* need to initialize using explicit segment/offset */ - union { - struct { struct nlsPackage *off; char *seg; }; - struct nlsPackage FAR *p; - } actPkg, chain; - #define actPkg actPkg.p - #define chain chain.p -#else struct nlsPackage FAR *actPkg; /* current NLS package */ struct nlsPackage FAR *chain; /* first item of info chain -- hardcoded U.S.A./CP437 */ -#endif }; -extern struct nlsInfoBlock ASM nlsInfo; -extern struct nlsPackage DOSFAR ASM nlsPackageHardcoded; +extern struct nlsInfoBlock 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[]; /*********************************************************************** @@ -626,7 +616,7 @@ struct nlsCSys_loadPackage { }; /* standard alignment */ -#include "algndflt.h" +#include #ifdef DEBUG /* Enable debugging of NLS part */ diff --git a/hdr/pcb.h b/hdr/pcb.h index 79b3ea22..2405eba4 100644 --- a/hdr/pcb.h +++ b/hdr/pcb.h @@ -52,12 +52,12 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *pcb_hRcsId = - "$Id: pcb.h 1316 2007-05-15 17:48:47Z bartoldeman $"; + "$Id$"; #endif #endif /* Force one-byte alignment for all the internal structures, see above */ -#include "algnbyte.h" +#include /* */ /* interrupt handler structure definition */ /* */ @@ -87,6 +87,14 @@ typedef struct { 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; @@ -158,7 +166,15 @@ typedef struct { #define FLG_CARRY 0x0001 /* Allow default alignment from now on */ -#include "algndflt.h" +#include + +/* + * Invoke interrupt "intnr" with all registers from *pr loaded + * into the processor registers (except: SS, SP,& flags) + * On return, all processor registers are stored into *pr (including + * flags). + */ +void ASMCFUNC intr(int intnr, iregs * const pr); #endif diff --git a/hdr/portab.h b/hdr/portab.h index bc79aed5..7a0dd0ed 100644 --- a/hdr/portab.h +++ b/hdr/portab.h @@ -31,10 +31,12 @@ #ifdef MAIN #ifdef VERSION_STRINGS static char *portab_hRcsId = - "$Id: portab.h 1121 2005-03-15 15:25:08Z perditionc $"; + "$Id$"; #endif #endif +#include + /****************************************************************/ /* */ /* Machine dependant portable types. Note that this section is */ @@ -64,6 +66,14 @@ static char *portab_hRcsId = #define I86 #define CDECL cdecl #if __TURBOC__ > 0x202 +#if __TURBOC__ < 0x400 /* targeted to TC++ 1.0 which is 0x297 (3.1 is 0x410) */ +#pragma warn -pia /* possibly incorrect assignment */ +#pragma warn -sus /* suspicious pointer conversion */ +/* + * NOTE: The above enable TC++ to build the kernel, but it's not recommended + * for development. Use [Open]Watcom (the best!) or newer Borland compilers! + */ +#endif /* printf callers do the right thing for tc++ 1.01 but not tc 2.01 */ #define VA_CDECL #else @@ -73,11 +83,12 @@ static char *portab_hRcsId = void __int__(int); #ifndef FORSYS void __emit__(char, ...); -#define disable() __emit__(0xfa) -#define enable() __emit__(0xfb) +#define disable() __emit__(0xfa) /* cli; disable interrupts */ +#define enable() __emit__(0xfb) /* sti; enable interrupts */ +#define halt() __emit__(0xf4) /* hlt; halt until interrupt */ #endif -#elif defined(_MSC_VER) +#elif defined (_MSC_VER) #define I86 #define asm __asm @@ -89,6 +100,7 @@ void __emit__(char, ...); #define __int__(intno) asm int intno; #define disable() asm cli #define enable() asm sti +#define halt() asm hlt #define _CS getCS() static unsigned short __inline getCS(void) { @@ -102,14 +114,14 @@ static unsigned short __inline getSS(void) #elif defined(__WATCOMC__) /* don't know a better way */ -#if defined(_M_I86) - #define I86 #define __int__(intno) asm int intno; void disable(void); -#pragma aux disable = "cli" __modify __exact []; +#pragma aux disable = "cli" modify exact []; void enable(void); -#pragma aux enable = "sti" __modify __exact []; +#pragma aux enable = "sti" modify exact []; +void halt(void); +#pragma aux halt = "hlt" modify exact []; #define asm __asm #define far __far #define CDECL __cdecl @@ -117,22 +129,19 @@ void enable(void); #define PASCAL pascal #define _CS getCS() unsigned short getCS(void); -#pragma aux getCS = "mov dx,cs" __value [__dx] __modify __exact[__dx]; +#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 - +#pragma aux getSS = "mov dx,ss" value [dx] modify exact[dx]; /* enable Possible loss of precision warning for compatibility with Borland */ #pragma enable_message(130) +#if !defined(FORSYS) && !defined(EXEFLAT) && _M_IX86 >= 300 +#pragma aux default parm [ax dx cx] modify [ax dx es fs] /* min.unpacked size */ +/* #pragma aux default parm [ax dx] modify [ax bx cx dx es fs]min.packed size */ +#endif -#else - -/* workaround for building some utils with OpenWatcom (flat model) */ -#define MC68K - +#if _M_IX86 >= 300 || defined(M_I386) +#define I386 #endif #elif defined (_MYMC68K_COMILER_) @@ -140,44 +149,8 @@ unsigned short getSS(void); #define MC68K #elif defined(__GNUC__) - -#ifdef __FAR -#define I86 -#define STRINGIFY(x) #x -#define __int__(intno) asm volatile(STRINGIFY(int $##intno)) -static inline void disable(void) -{ - asm volatile("cli"); -} -static inline void enable(void) -{ - asm volatile("sti"); -} -#define far __far -#define CDECL __attribute__((cdecl)) -#define VA_CDECL -#define PASCAL - -#define _CS getCS() -static inline unsigned short getCS(void) -{ - unsigned short ret; - asm volatile("mov %%cs, %0" : "=r"(ret)); - return ret; -} - -#define _SS getSS() -static inline unsigned short getSS(void) -{ - unsigned short ret; - asm volatile("mov %%ss, %0" : "=r"(ret)); - return ret; -} -extern char DosDataSeg[]; -#else /* for warnings only ! */ #define MC68K -#endif #else #error Unknown compiler @@ -186,15 +159,11 @@ We might even deal with a pre-ANSI compiler. This will certainly not compile. #ifdef I86 #if _M_IX86 >= 300 || defined(M_I386) -#ifndef I386 #define I386 -#endif #elif _M_IX86 >= 100 || defined(M_I286) -#ifndef I186 #define I186 #endif #endif -#endif #ifdef MC68K #define far /* No far type */ @@ -215,12 +184,10 @@ We might even deal with a pre-ANSI compiler. This will certainly not compile. typedef __SIZE_TYPE__ size_t; #else #define CONST -#if !(defined(_SIZE_T) || defined(_SIZE_T_DEFINED) || defined(__SIZE_T_DEFINED)) typedef unsigned size_t; #endif #endif -#endif -#if defined(I86) && !defined(MC68K) +#ifdef I86 #define VOID void #define FAR far /* segment architecture */ #define NEAR near /* " " */ @@ -237,16 +204,7 @@ typedef unsigned size_t; as 'ASMCFUNC', and is (and will be ?-) cdecl */ #define ASMCFUNC CDECL #define ASMPASCAL PASCAL -#if defined(__GNUC__) -#define ASM -#else #define ASM ASMCFUNC -#endif - -/* variables that can be near or far: redefined in init-dat.h */ -#define DOSFAR -#define DOSTEXTFAR - /* */ /* Boolean type & definitions of TRUE and FALSE boolean values */ /* */ @@ -298,7 +256,7 @@ typedef unsigned short CLUSTER; #endif typedef unsigned short UNICODE; -#if defined(STATICS) || defined(__WATCOMC__) || defined(__GNUC__) +#if defined(STATICS) || defined(__WATCOMC__) #define STATIC static /* local calls inside module */ #else #define STATIC @@ -316,6 +274,19 @@ typedef signed long LONG; #define LONG long #endif +typedef UWORD ofs_t; +typedef UWORD seg_t; + +#define lonibble(v) (0x0f & (v)) +#define hinibble(v) (0xf0 & (v)) + +#if CHAR_BIT == 8 +# define lobyte(v) ((UBYTE)(v)) +#else +# define lobyte(v) ((UBYTE)(0xff & (v))) +#endif +#define hibyte(v) lobyte ((UWORD)(v) >> 8u) + #if USHRT_MAX == 0xFFFF # define loword(v) ((unsigned short)(v)) #else @@ -330,49 +301,41 @@ typedef signed long LONG; #ifdef I86 #ifndef MK_FP -#if defined(__WATCOMC__) +#if defined __WATCOMC__ #define MK_FP(seg,ofs) (((UWORD)(seg)):>((VOID *)(ofs))) -#elif defined(__TURBOC__) && (__TURBOC__ > 0x202) +#elif __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))) +#define MK_FP(seg,ofs) ((void FAR *)MK_ULONG(seg, 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 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 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))) +#define peekl(seg, ofs) (*(unsigned long far *)MK_FP(seg,ofs)) -#if defined(__TURBOC__) && (__TURBOC__ > 0x202) +#if __TURBOC__ > 0x202 #define FP_SEG(fp) ((unsigned)(void _seg *)(void far *)(fp)) #else -#define FP_SEG(fp) ((unsigned)((ULONG)(VOID FAR *)(fp)>>16)) +#define FP_SEG(fp) hiword ((ULONG)(VOID FAR *)(fp)) #endif -#if defined(__GNUC__) && defined(__BUILTIN_IA16_FP_OFF) -#define FP_OFF(fp) __builtin_ia16_FP_OFF(fp) -#else -#define FP_OFF(fp) ((unsigned)(fp)) -#endif +#define FP_OFF(fp) loword (fp) #endif #endif #ifdef MC68K -#define MK_FP(seg,ofs) ((VOID *)(&(((BYTE *)(size_t)(seg))[(ofs)]))) -#define FP_SEG(fp) (0) +#define MK_FP(seg,ofs) ((VOID *)&(((BYTE *)(size_t)(seg))[ofs])) +#define FP_SEG(fp) 0 #define FP_OFF(fp) ((size_t)(fp)) #endif -#if defined(__GNUC__) && defined(__FAR) -typedef VOID FAR *intvec; -#else typedef VOID (FAR ASMCFUNC * intvec) (void); -#endif #define MK_PTR(type,seg,ofs) ((type FAR*) MK_FP (seg, ofs)) #if __TURBOC__ > 0x202 @@ -387,10 +350,29 @@ typedef VOID (FAR ASMCFUNC * intvec) (void); unreferenced parameter 'x' and (hopefully) generates no code */ -#define UNREFERENCED_PARAMETER(x) (void)x; +#define UNREFERENCED_PARAMETER(x) (void)(x) #ifdef I86 /* commandline overflow - removing /DPROTO TE */ #define PROTO #endif -#define LENGTH(x) (sizeof(x)/sizeof(x[0])) +typedef const char CStr[], *PCStr; +typedef char Str[], *PStr; +typedef const void *CVP; +typedef const void FAR *CVFP; +typedef void FAR *VFP; + +#define LENGTH(x) (sizeof (x)/sizeof *(x)) +#define ENDOF(x) ((x) + LENGTH (x)) + +/* (unsigned) modulo arithmetics trick: a<=b<=c equal to b-a<=c-a */ +#define inrange(type,v,lo,hi) ((type)((v) - (lo)) <= (type)((hi) - (lo))) +#define _isdigit(c) inrange(UBYTE, c, '0', '9') +#define _islower(c) inrange(UBYTE, c, 'a', 'z') +#define _isupper(c) inrange(UBYTE, c, 'A', 'Z') + +/* Fast ASCII tolower/toupper */ +#define _fast_lower(ch) ((ch) | 0x20) +#define _fast_dolower(var) ((var) |= 0x20) +#define _fast_upper(ch) ((ch) & ~0x20) +#define _fast_doupper(var) ((var) &= ~0x20) diff --git a/hdr/process.h b/hdr/process.h index 9b63a839..3fca29e3 100644 --- a/hdr/process.h +++ b/hdr/process.h @@ -28,6 +28,12 @@ /* Cambridge, MA 02139, USA. */ /****************************************************************/ +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *process_hRcsId = + "$Id$"; +#endif +#endif /* Modes available as first argument to the spawnxx functions. */ @@ -59,16 +65,11 @@ 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 */ - intvec ps_reentry; /* 06 re-entry point */ + BYTE ps_fill1; /* 04 single char fill */ + /* CP/M-like entry point */ + 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 */ @@ -79,10 +80,10 @@ typedef struct { 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_dbcs_inputmode; /* 3c unused,see int21/6301h/6302h */ - UBYTE ps_truename; /* 3d unused,append truename flag int2f/B711h */ + 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 version to return on int21/30h, defaults to true version */ + 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 */ diff --git a/hdr/sft.h b/hdr/sft.h index 106b30ec..6a61a606 100644 --- a/hdr/sft.h +++ b/hdr/sft.h @@ -30,7 +30,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *sft_hRcsId = - "$Id: sft.h 1429 2009-06-09 18:50:03Z bartoldeman $"; + "$Id$"; #endif #endif @@ -56,33 +56,22 @@ typedef struct { 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 - dtime sft_time; /* 0d - File time */ - ddate 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 */ + WORD sft_stclust; /* 0b - Starting cluster */ + time sft_time; /* 0d - File time */ + date sft_date; /* 0f - File date */ + LONG sft_size; /* 11 - File size */ + LONG sft_posit; /* 15 - Current file position */ + WORD sft_relclust; /* 19 - File relative cluster */ + WORD sft_cuclust; /* 1b - File current cluster */ + WORD sft_dirdlust; /* 1d - Sector containing cluster */ + BYTE 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 + WORD sft_status; /* 35 - this sft status */ BYTE FAR *sft_ifsptr; /* 37 - pointer to IFS driver for file, 0000000h if native DOS */ -#endif } sft; /* SFT Table header definition */ @@ -115,8 +104,7 @@ typedef struct sfttbl { /* the following bits are file (block) unique */ #define SFT_FDATE 0x4000 /* File date set */ -#define SFT_FFIXEDMEDIA 0x0800 /* File on non-removable media - unused */ -#define SFT_FCLEAN 0x0040 /* File has not been written to */ +#define SFT_FDIRTY 0x0040 /* File has been written to */ #define SFT_FDMASK 0x003f /* File mask for drive no */ /* the following bits are device (char) unique */ @@ -130,7 +118,7 @@ typedef struct sfttbl { #define SFT_FCONOUT 0x0002 /* device is console output */ #define SFT_FCONIN 0x0001 /* device is console input */ -/* Convenience defines */ +/* Covienence defines */ #define sft_dcb sft_dcb_or_dev._sft_dcb #define sft_dev sft_dcb_or_dev._sft_dev @@ -138,7 +126,3 @@ typedef struct sfttbl { #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 index f4fcabbc..b002738d 100644 --- a/hdr/stacks.inc +++ b/hdr/stacks.inc @@ -25,7 +25,7 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: stacks.inc 1591 2011-05-06 01:46:55Z bartoldeman $ +; $Id$ ; ; @@ -135,124 +135,52 @@ irp_hi equ 26 ; error 1 2 3 %macro Protect386Registers 0 %endmacro - - %assign Size386Registers 0 - %macro RestoreSP 0 - mov sp, bp - %endmacro - %macro Restore386Registers 0 %endmacro -%ELSE - %ifdef WATCOM +%ELSE %macro Protect386Registers 0 + + %ifdef WATCOM push fs push gs - %endmacro - - %assign Size386Registers 4 - - %macro RestoreSP 0 - lea sp, [bp - Size386Registers] - %endmacro - - %macro Restore386Registers 0 - pop gs - pop fs - %endmacro - %else - - %macro Protect386Registers 0 push eax pop ax - %ifdef MSCL8 + %ifdef MSC push ecx pop cx - %else ;BC5 + %else ;BC push ebx pop bx %endif push edx pop dx - %endmacro - - %assign Size386Registers 6 + %endif - %macro RestoreSP 0 - lea sp, [bp - Size386Registers] %endmacro %macro Restore386Registers 0 + + %ifdef WATCOM + pop gs + pop fs + %else push dx pop edx - %ifdef MSCL8 + %ifdef MSC push cx pop ecx - %else ;BC5 + %else ;BC push bx pop ebx %endif push ax pop eax - %endmacro - %endif -%ENDIF -; macros to define stack arguments -; arg a, {b,4}, c -; defines a and c as "word" arguments and b as a "dword" argument -; for STDCALL defines .a as [bp+4], .b as [bp+6] and .c as [bp+10] -; for PASCAL defines .a as [bp+10], .b as [bp+6] and .c as [bp+4] -; -; popargs bx, {dx,ax}, cx pops these arguments of the stack (for PASCAL -; in reverse order). Here dx,ax is a dword argument dx:ax where dx is -; the high word. The caller is responsible for dealing with instruction -; pointer (ip) on the stack. - -%ifdef gcc -%define STDCALL -%else -%define PASCAL -%endif - -%macro definearg 1-2 2 - %xdefine .%1 bp+.argloc - %assign .argloc .argloc+%2 -%endmacro - -%macro arg 1-* - %assign .argloc 4 - %rep %0 - %ifdef PASCAL - %rotate -1 - %endif - definearg %1 - %ifdef STDCALL - %rotate 1 - %endif - %endrep -%endmacro - -%macro multipop 1-* - %rep %0 - %rotate -1 - pop %1 - %endrep -%endmacro + %endmacro -%macro popargs 1-* - %rep %0 - %ifdef PASCAL - %rotate -1 - %endif - multipop %1 - %ifdef STDCALL - %rotate 1 - %endif - %endrep -%endmacro +%ENDIF diff --git a/hdr/tail.h b/hdr/tail.h index 810a6bda..183f201f 100644 --- a/hdr/tail.h +++ b/hdr/tail.h @@ -31,7 +31,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *tail_hRcsId = - "$Id: tail.h 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #endif diff --git a/hdr/dtime.h b/hdr/time.h similarity index 93% rename from hdr/dtime.h rename to hdr/time.h index cf580744..050105a6 100644 --- a/hdr/dtime.h +++ b/hdr/time.h @@ -1,6 +1,6 @@ /****************************************************************/ /* */ -/* dtime.h */ +/* time.h */ /* */ /* DOS General Time Structure */ /* */ @@ -35,11 +35,11 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *time_hRcsId = - "$Id: time.h 942 2004-05-23 15:00:37Z bartoldeman $"; + "$Id$"; #endif #endif -typedef UWORD dtime; +typedef UWORD time; struct dostime { diff --git a/hdr/version.h b/hdr/version.h index 8dd36a3f..47d38f81 100644 --- a/hdr/version.h +++ b/hdr/version.h @@ -26,26 +26,29 @@ /* Cambridge, MA 02139, USA. */ /****************************************************************/ -/* The version the kernel reports as compatible with */ +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *date_hRcsId = + "$Id$"; +#endif +#endif + +/* This Kernel is at a min Dos Ver. 5.00 or 7.10 with FAT32 support */ #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 46 /* 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 "- GIT " +#define MAJOR_RELEASE 5 +#define MINOR_RELEASE 00 #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) +#define REV_NUMBER 0 +#define OEM_ID 0xfd /* FreeDos version */ +#define REVISION_MAJOR 1 +#define REVISION_MINOR 1 +#define REVISION_SEQ 37 +#define BUILD "2037" +#define SUB_BUILD "w-UNSTABLE" /* only use w=WorkInProgress for UNSTABLE branch */ +#define KERNEL_VERSION_STRING "1.1.37w" /*#REVISION_MAJOR "." #REVISION_MINOR "." #REVISION_SEQ */ +#define KERNEL_BUILD_STRING "2037w-UNSTABLE" /*#BUILD SUB_BUILD */ diff --git a/hdr/win.h b/hdr/win.h index 93a07574..cde08a5d 100644 --- a/hdr/win.h +++ b/hdr/win.h @@ -14,16 +14,9 @@ struct WinStartupInfo 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)*/ + ULONG instanceTable; /* far pointer to array of instance data */ }; extern struct WinStartupInfo winStartupInfo; -#if defined __GNUC__ -extern UWORD winseg1, winseg2, winseg3; -extern UBYTE markEndInstanceData; -extern struct lol FAR ASM DATASTART; -#endif - /* contains a list of offsets relative to DOS data segment of various internal variables. diff --git a/hdr/xstructs.h b/hdr/xstructs.h index f29bbe41..42d2ab7c 100644 --- a/hdr/xstructs.h +++ b/hdr/xstructs.h @@ -9,7 +9,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *XStructs_hRcsId = - "$Id: xstructs.h 1457 2009-06-26 20:00:41Z bartoldeman $"; + "$Id$"; #endif #endif @@ -64,19 +64,20 @@ struct xdpbforformat { } rebuilddpb; struct { - DWORD new; /* new active FAT/mirroring state, or -1 to get + DWORD newmirroring; /* 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 */ + DWORD oldmirroring; /* previous active FAT/mirroring state (as above) */ + UDWORD reserved[2]; + } setmirroring; + + struct { + DWORD newrootclst; /* set new root directory cluster, -1 - get current */ + DWORD oldrootclst; /* get previous root directory cluster */ UDWORD reserved[2]; - } setget; + } setroot; } xdff_f; }; diff --git a/kernel/apisupt.asm b/kernel/apisupt.asm index abc10c05..914fd6c8 100644 --- a/kernel/apisupt.asm +++ b/kernel/apisupt.asm @@ -24,7 +24,7 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: apisupt.asm 538 2003-03-12 22:43:53Z bartoldeman $ +; $Id$ ; %include "segs.inc" diff --git a/kernel/asmsupt.asm b/kernel/asmsupt.asm index d91f0a02..ab53290d 100644 --- a/kernel/asmsupt.asm +++ b/kernel/asmsupt.asm @@ -31,14 +31,9 @@ ; 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 $ +; $Id$ ; -; for OW on Linux: -%ifdef owlinux -%define WATCOM -%endif - %ifdef WATCOM %ifdef _INIT %define WATCOM_INIT ; no seperate init segment for watcom. @@ -48,7 +43,6 @@ %ifndef WATCOM_INIT %include "segs.inc" - %include "stacks.inc" %ifdef _INIT @@ -135,10 +129,9 @@ pascal_setup: cld mov bl,6 ; majority (4) wants that -arg arg1, arg2, arg3 - mov cx,[.arg3] ; majority (8) wants that (near and far) - mov si,[.arg2] ; majority (3) wants that (near) - mov di,[.arg1] ; majority (3) wants that (near) + 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 @@ -194,17 +187,14 @@ FMEMCPYBACK: FMEMCPY: call pascal_setup -arg {d,4}, {s,4}, n ; Get the repetition count, n preset above -%ifdef STDCALL - mov cx,[.n] -%endif + ; mov cx,[bp+4] ; Get the far source pointer, s - lds si,[.s] + lds si,[bp+6] ; Get the far destination pointer d - les di,[.d] + les di,[bp+10] mov bl,10 jmp short domemcpy @@ -217,17 +207,14 @@ arg {d,4}, {s,4}, n FMEMSET: call pascal_setup -arg {d,4}, ch, n ; Get the repetition count, n - preset above -%ifdef STDCALL - mov cx,[.n] -%endif + ; mov cx,[bp+4] ; Get the fill byte ch - mov ax,[.ch] + mov ax,[bp+6] ; Get the far source pointer, s - les di,[.d] + les di,[bp+8] mov bl,8 domemset: @@ -248,12 +235,11 @@ domemset: MEMSET: call pascal_setup -arg d, ch, n ; Get the repitition count, n - preset above ; mov cx,[bp+4] ; Get the char ch - mov ax, [.ch] + mov ax, [bp+6] ; Get the far source pointer, d - preset above ; mov di,[bp+8] @@ -286,20 +272,21 @@ pascal_return: ; fstrcpy (void FAR*dest, void FAR *src); +%ifndef _INIT global FSTRCPY FSTRCPY: call pascal_setup -arg {dest,4}, {src,4} ; Get the source pointer, ss - lds si,[.src] + lds si,[bp+4] ; and the destination pointer, d - les di,[.dest] + les di,[bp+8] mov bl,8 jmp short dostrcpy +%endif ;****** global STRCPY @@ -307,13 +294,11 @@ STRCPY: call pascal_setup -%ifdef PASCAL ; Get the source pointer, ss mov si,[bp+4] ; and the destination pointer, d mov di,[bp+6] -%endif mov bl,4 dostrcpy: @@ -327,6 +312,7 @@ strcpy_loop: jmp short pascal_return ;****************************************************************** +%ifndef _INIT global FSTRLEN FSTRLEN: call pascal_setup @@ -336,15 +322,14 @@ FSTRLEN: mov bl,4 jmp short dostrlen +%endif ;********************************************** global STRLEN STRLEN: call pascal_setup ; Get the source pointer, ss -%ifdef PASCAL mov di,[bp+4] -%endif mov bl,2 dostrlen: @@ -366,11 +351,8 @@ STRCHR: call pascal_setup ; Get the source pointer, ss -arg src, ch -%ifdef STDCALL ; preset above for PASCAL - mov cx,[.ch] - mov si,[.src] -%endif + ; mov cx,[bp+4] - preset above + ; mov si,[bp+6] - preset above mov bl,4 strchr_loop: @@ -401,12 +383,11 @@ strchr_found1: FSTRCHR: call pascal_setup -arg {src,4}, ch ; Get ch (preset above) ;mov cx, [bp+4] ;and the source pointer, src - lds si, [.src] + lds si, [bp+6] ;mov bl, 6 - preset above @@ -417,17 +398,14 @@ arg {src,4}, ch FMEMCHR: call pascal_setup -arg {src,4}, ch, n ; Get the length - preset above -%ifdef STDCALL - mov cx, [.n] -%endif + ; mov cx, [bp+4] ; and the search value - mov ax, [.ch] + mov ax, [bp+6] ; and the source pointer, ss - les di, [.src] + les di, [bp+8] mov bl, 8 @@ -443,24 +421,19 @@ arg {src,4}, ch, n FSTRCMP: call pascal_setup -arg {dest,4}, {src,4} ; Get the source pointer, ss - lds si,[.src] + lds si,[bp+4] ; and the destination pointer, d - les di,[.dest] + les di,[bp+8] - mov bl,8 - -%if 0 jmp short dostrcmp ;****** - global STRCMP -STRCMP: + global _strcmp +_strcmp: call pascal_setup - mov bl,4 ; Get the source pointer, ss ; mov si,[bp+4] @@ -470,11 +443,9 @@ STRCMP: xchg si,di dostrcmp: -%endif ; replace strncmp(s1,s2)--> ; strncmp(s1,s2,0xffff) mov cx,0xffff -%if 0 jmp short dostrncmp @@ -489,7 +460,6 @@ FSTRNCMP: ; and the destination pointer, d les di,[bp+8] mov cx,[bp+12] - mov bl,10 jmp short dostrncmp @@ -507,7 +477,6 @@ _strncmp: xchg si,di dostrncmp: -%endif jcxz strncmp_retzero strncmp_loop: @@ -525,17 +494,14 @@ strncmp_loop: FMEMCMP: call pascal_setup -arg {dest,4}, {src,4}, n ; the length - preset above -%ifdef STDCALL - mov cx, [.n] -%endif + ; mov cx, [bp+4] ; Get the source pointer, ss - les di,[.src] + les di,[bp+6] ; and the destination pointer, d - lds si,[.dest] + lds si,[bp+10] mov bl,10 diff --git a/kernel/blockio.c b/kernel/blockio.c index b74416b3..5dcae2dd 100644 --- a/kernel/blockio.c +++ b/kernel/blockio.c @@ -33,7 +33,7 @@ #ifdef VERSION_STRINGS static BYTE *blockioRcsId = - "$Id: blockio.c 1702 2012-02-04 08:46:16Z perditionc $"; + "$Id$"; #endif #define b_next(bp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), bp->b_next))) @@ -47,7 +47,7 @@ static BYTE *blockioRcsId = /************************************************************************/ /* #define DISPLAY_GETBLOCK */ -STATIC BOOL flush1(struct buffer FAR * bp); +STATIC VOID flush1(struct buffer FAR * bp); /* this searches the buffer list for the given disk/block. @@ -155,7 +155,7 @@ STATIC struct buffer FAR *searchblock(ULONG blkno, COUNT dsk) return bp; } -BOOL DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mode) +VOID DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mode) { struct buffer FAR *bp = firstbuf; @@ -176,8 +176,6 @@ BOOL DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mo bp = b_next(bp); } while (FP_OFF(bp) != FP_OFF(firstbuf)); - - return FALSE; } #if TOM @@ -226,8 +224,7 @@ struct buffer FAR *getblk(ULONG blkno, COUNT dsk, BOOL overwrite) /* 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; + flush1(bp); /* Fill the indicated disk buffer with the current track and sector */ @@ -259,106 +256,77 @@ VOID setinvld(REG COUNT dsk) 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) +VOID 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; + flush1(bp); bp = b_next(bp); } while (FP_OFF(bp) != FP_OFF(firstbuf)); - return ok; } /* */ /* Write one disk buffer */ /* */ -STATIC BOOL flush1(struct buffer FAR * bp) +STATIC VOID flush1(struct buffer FAR * bp) { - BOOL ok = TRUE; +/* All lines with changes on 9/4/00 by BER marked below */ + + UWORD result; /* BER 9/4/00 */ 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; + /* BER 9/4/00 */ + result = dskxfer(bp->b_unit, bp->b_blkno, bp->b_buffer, 1, DSKWRITE); if (bp->b_flag & BFR_FAT) { - b_copies = bp->b_copies; - b_offset = bp->b_offset; + UWORD b_copies = bp->b_copies; + ULONG blkno = bp->b_blkno; #ifdef WITHFAT32 + ULONG b_offset = bp->b_offset; if (b_offset == 0) /* FAT32 FS */ b_offset = bp->b_dpbp->dpb_xfatsize; +#else + UWORD b_offset = bp->b_offset; #endif - } - while (b_copies--) - { - if (dskxfer(bp->b_unit, blkno, bp->b_buffer, 1, DSKWRITE)) - ok = FALSE; - blkno += b_offset; + while (--b_copies > 0) + { + blkno += b_offset; + /* BER 9/4/00 */ + result = dskxfer(bp->b_unit, blkno, bp->b_buffer, 1, DSKWRITE); + } } } + else + result = 0; /* This negates any error code returned in result...BER */ + /* and 0 returned, if no errors occurred - tom */ bp->b_flag &= ~BFR_DIRTY; /* even if error, mark not dirty */ - if (!ok) /* otherwise system has trouble */ + if (result != 0) /* otherwise system has trouble */ bp->b_flag &= ~BFR_VALID; /* continuing. */ - return ok; } /* */ /* Write all disk buffers */ /* */ -BOOL flush(void) +VOID flush(VOID) { REG struct buffer FAR *bp = firstbuf; - REG BOOL ok; - ok = TRUE; do { - if (!flush1(bp)) - ok = FALSE; + flush1(bp); bp->b_flag &= ~BFR_VALID; bp = b_next(bp); } while (FP_OFF(bp) != FP_OFF(firstbuf)); - network_redirector(REM_FLUSHALL); - - return (ok); } /************************************************************************/ @@ -436,10 +404,10 @@ UWORD dskxfer(COUNT dsk, ULONG blkno, VOID FAR * buf, UWORD numblocks, { IoReqHdr.r_trans = deblock_buf; if (mode == DSKWRITE) - fmemcpy(deblock_buf, buf, dpbp->dpb_secsize); + fmemcpy(deblock_buf, buf, SEC_SIZE); execrh((request FAR *) & IoReqHdr, dpbp->dpb_device); if (mode == DSKREAD) - fmemcpy(buf, deblock_buf, dpbp->dpb_secsize); + fmemcpy(buf, deblock_buf, SEC_SIZE); } else { @@ -500,7 +468,7 @@ void AllocateHMASpace (size_t lowbuffer, size_t highbuffer) do { /* check if buffer intersects with requested area */ - if (FP_OFF(bp) <= highbuffer && FP_OFF(bp+1) > lowbuffer) + if (FP_OFF(bp) < highbuffer && FP_OFF(bp+1) > lowbuffer) { flush1(bp); /* unlink bp from buffer chain */ diff --git a/kernel/break.c b/kernel/break.c index c51f62c3..a8d3218d 100644 --- a/kernel/break.c +++ b/kernel/break.c @@ -30,11 +30,10 @@ #include "portab.h" #include "globals.h" #include "proto.h" -#include "debug.h" #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: break.c 885 2004-04-14 15:40:51Z bartoldeman $"; + "$Id$"; #endif #define CB_FLG *(UBYTE FAR*)MK_FP(0x0, 0x471) @@ -54,13 +53,13 @@ unsigned char ctrl_break_pressed(void) 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) + unsigned char c = 0; + if (ctrl_break_pressed() || + (c = (unsigned char)ndread(&syscon)) == CTL_C || + *pdev != syscon && (c = (unsigned char)ndread(pdev)) == CTL_C) + { handle_break(pdev, -1); + } return c; } @@ -77,7 +76,7 @@ unsigned char check_handle_break(struct dhdr FAR **pdev) void handle_break(struct dhdr FAR **pdev, int sft_out) { - char *buf = "^C\r\n"; + static char *buf = "^C\r\n"; CB_FLG &= ~CB_MSK; /* reset the ^Break flag */ con_flush(pdev); @@ -91,4 +90,3 @@ void handle_break(struct dhdr FAR **pdev, int sft_out) spawn_int23(); /* invoke user INT-23 and never come back */ } - diff --git a/kernel/chario.c b/kernel/chario.c index 6648acbc..9870c7c5 100644 --- a/kernel/chario.c +++ b/kernel/chario.c @@ -32,11 +32,10 @@ #ifdef VERSION_STRINGS static BYTE *charioRcsId = - "$Id: chario.c 1413 2009-06-01 13:41:03Z bartoldeman $"; + "$Id$"; #endif #include "globals.h" -#include "debug.h" STATIC int CharRequest(struct dhdr FAR **pdev, unsigned command) { @@ -74,7 +73,7 @@ long BinaryCharIO(struct dhdr FAR **pdev, size_t n, void FAR * bp, CharReqHdr.r_count = n; CharReqHdr.r_trans = bp; err = CharRequest(pdev, command); - } while (err == 1); + } while (err > 0); return err == SUCCESS ? (long)CharReqHdr.r_count : err; } @@ -97,9 +96,7 @@ STATIC void CharCmd(struct dhdr FAR **pdev, unsigned command) STATIC int Busy(struct dhdr FAR **pdev) { - CharCmd(pdev, C_NDREAD); - if (CharReqHdr.r_status & S_ERROR) - CharCmd(pdev, C_ISTAT); + CharCmd(pdev, C_ISTAT); return CharReqHdr.r_status & S_BUSY; } @@ -141,42 +138,15 @@ int ndread(struct dhdr FAR **pdev) /* 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(__GNUC__) - asm volatile("int $0x29":: "a"(chr):"bx"); -#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; + scr_pos = 0; else if (c == BS) { - if (scrpos > 0) - scrpos--; - } else if (c != LF && c != BELL) { - scrpos += count; - } - scr_pos = scrpos; + if (scr_pos > 0) + scr_pos--; + } else if (c != LF && c != BELL) + scr_pos += count; } STATIC int raw_get_char(struct dhdr FAR **pdev, BOOL check_break); @@ -195,9 +165,6 @@ long cooked_write(struct dhdr FAR **pdev, size_t n, char FAR *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 = ' '; @@ -213,7 +180,7 @@ long cooked_write(struct dhdr FAR **pdev, size_t n, char FAR *bp) if (PrinterEcho) DosWrite(STDPRN, 1, &c); if (fast_counter & 0x80) - fast_put_char(c); + put_console(c); else { err = CharIO(pdev, c, C_OUTPUT); @@ -257,16 +224,15 @@ void write_char_stdout(int c) #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) +STATIC VOID echo_char(int c, int sft_idx, unsigned i) { - int out = c; + local_buffer[i] = c; if (iscntrl(c) && c != HT && c != LF && c != CR) { write_char('^', sft_idx); - out += '@'; + c += '@'; } - write_char(out, sft_idx); - return c; + write_char(c, sft_idx); } STATIC void destr_bs(int sft_idx) @@ -297,11 +263,11 @@ long cooked_read(struct dhdr FAR **pdev, size_t n, char FAR *bp) return xfer; } -STATIC unsigned read_char_sft_dev(int sft_in, int sft_out, +STATIC unsigned char read_char_sft_dev(int sft_in, int sft_out, struct dhdr FAR **pdev, BOOL check_break) { - unsigned c; + unsigned char c; if (*pdev) { @@ -393,15 +359,13 @@ void read_line(int sft_in, int sft_out, keyboard FAR * kp) 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); + echo_char(kp->kb_buf[stored_pos++], sft_out, count++); break; case F2: @@ -427,7 +391,7 @@ void read_line(int sft_in, int sft_out, keyboard FAR * kp) 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); + echo_char(kp->kb_buf[stored_pos++], sft_out, count++); } stored_pos = new_pos; break; @@ -498,15 +462,12 @@ void read_line(int sft_in, int sft_out, keyboard FAR * kp) /* fall through */ default: - if (c >= 256) - break; if (count < size - 1 || c == CR) - local_buffer[count++] = echo_char(c, sft_out); + echo_char(c, sft_out, count++); else write_char(BELL, sft_out); if (stored_pos < stored_size && !insert) stored_pos++; - break; } first = FALSE; } while (c != CR); @@ -533,7 +494,8 @@ size_t read_line_handle(int sft_idx, size_t n, char FAR * bp) 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); + write_char(LF, sft_idx); + kb_buf.kb_buf[kb_buf.kb_count + 1] = LF; inputptr = kb_buf.kb_buf; if (*inputptr == CTL_Z) { diff --git a/kernel/config.c b/kernel/config.c index e3470f69..bb703385 100644 --- a/kernel/config.c +++ b/kernel/config.c @@ -32,301 +32,222 @@ #include "dyndata.h" #include "debug.h" +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id$"; +#endif -#define para2far(seg) ((mcb FAR *)MK_FP((seg), 0)) +#define testbit(v,bit) ((UBYTE)((v) >> (UBYTE)(bit)) & 1) -/** - 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]; -}; +static UBYTE MenuColor BSS_INIT(0); -/** Structure below holds the menu-strings */ -STATIC struct MenuSelector MenuStruct[MENULINESMAX] BSS_INIT({0}); +static unsigned screenwidth(void) +{ + return peek(0, 0x44a); +} -int nMenuLine BSS_INIT(0); -int MenuColor = -1; -extern char ASM kernel_command_line[256]; -extern int kernel_command_line_length; +static unsigned screenbottom(void) +{ + UBYTE row = peekb(0, 0x484); + if (row == 0) + row = 24; + return row; +} -STATIC void WriteMenuLine(struct MenuSelector *menu) +static unsigned screeny(void) { 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)); + r.BH = peekb(0, 0x462); /* active video page */ + r.AH = 0x03; /* get cursor pos */ + init_call_intr(0x10, &r); + return r.DH; +} - /* 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; +static void gotoxy(unsigned x, unsigned y) +{ + iregs r; + r.BH = peekb(0, 0x462); /* active video page */ + r.DL = x; + r.DH = y; + r.AH = 0x02; /* set cursor pos */ 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; +static void ClearScreenArea(UBYTE attr, unsigned x, unsigned y, unsigned w, unsigned h) +{ + iregs r; + r.BH = attr; + r.CL = x; r.DL = x + w - 1; + r.CH = y; r.DH = y + h - 1; + r.AX = 0x0600; /* clear rectangle */ init_call_intr(0x10, &r); - printf("%s", pText); + gotoxy(x, y); } -/* Deselect the previously selected line */ -STATIC void DeselectLastLine(void) +static void say(PCStr s) { - struct MenuSelector *menu; - for (menu = MenuStruct; menu < &MenuStruct[MENULINESMAX]; menu++) - { - if (menu->bSelected) - { - /* deselect it: */ - menu->bSelected = 0; - WriteMenuLine(menu); - break; - } - } + printf(s); } -STATIC void SelectLine(int MenuSelected) +static void say2(PCStr f, PCStr s) { - struct MenuSelector *menu; - - DeselectLastLine(); /* clear previous selection */ - menu = &MenuStruct[MenuSelected]; - menu->bSelected = 1; /* set selection flag for this one */ - WriteMenuLine(menu); + printf(f, s); } -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}); +static void clearrow(void) +{ + unsigned width; + say("\r"); + for (width = screenwidth(); --width;) + say(" "); + say("\r"); +} -static char FAR *envp = master_env; +static seg_t umb_base_start BSS_INIT(0); +static size_t ebda_size BSS_INIT(0); 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 */ + /* UBYTE cfgDosDataUmb; */ 0, + /* BYTE cfgBuffers; */ NUMBUFF, + /* UBYTE cfgFiles; */ NFILES, + /* UBYTE cfgFilesHigh; */ 0, + /* UBYTE cfgFcbs; */ NFCBS, + /* UBYTE cfgProtFcbs; */ 0, + /* char cfgShell[256]; */ "command.com /P /E:256", + /* UBYTE cfgLastdrive; */ NLAST, + /* UBYTE cfgLastdriveHigh; */ 0, + /* BYTE cfgStacks; */ NSTACKS, + /* BYTE cfgStacksHigh; */ 0, + /* UWORD cfgStackSize; */ STACKSIZE, + /* UBYTE cfgP_0_startmode; */ 0, /* load command.com (low by default) */ + /* unsigned ebda2move; */ 0, /* 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); +/* master_env copied over command line area in + DOS_PSP, thus its size limited to 128 bytes */ +static char master_env[128] = "PATH=."; + +STATIC seg_t base_seg BSS_INIT(0); +STATIC seg_t umb_base_seg BSS_INIT(0); +VFP 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}); - -#define MAX_CHAINS 5 -struct CfgFile { - COUNT nFileDesc; - COUNT nCfgLine; -} cfgFile[MAX_CHAINS] BSS_INIT({0}); -COUNT nCurChain BSS_INIT(0); -COUNT nFileDesc 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 CmdChain(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 unsigned nPass BSS_INIT(0); +static char configfile [] = "FDCONFIG.SYS"; +STATIC char szLine[256] BSS_INIT({0}); +STATIC char szBuf[256] BSS_INIT({0}); + +UBYTE askCommand BSS_INIT(0); + +static int MenuTimeout = -1; +static unsigned last_choice = 10; /* =non existing choice */ +static unsigned line_choices BSS_INIT(0); +static unsigned all_choices BSS_INIT(0); + +STATIC BOOL LoadDevice(PCStr, VFP top, int mode); +STATIC void CfgFailure(PCStr); STATIC VOID DoMenu(void); -STATIC VOID CfgMenuDefault(BYTE * pLine); -STATIC BYTE * skipwh(BYTE * s); -STATIC int iswh(unsigned char c); -STATIC BYTE * scan(BYTE * s, BYTE * d, int fMenuSelect); -STATIC BOOL isnum(char ch); -#if 0 -STATIC COUNT tolower(COUNT c); -#endif +STATIC PCStr skipwh(PCStr); +STATIC PCStr scanword(PCStr, PStr); +STATIC PCStr scanverb(PCStr, PStr); +#define isdigit(ch) ((UBYTE)((ch) - '0') <= 9) 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 PStr strupr(PStr); +static PStr strcat(PStr d, PCStr s); +STATIC void mcb_init(seg_t, size_t, BYTE type); +STATIC void mumcb_init(seg_t, size_t); +#define mcb_next(seg) ((seg) + MK_SEG_PTR(mcb, seg)->m_size + 1) + +STATIC PCStr GetNumArg(PCStr); +STATIC BOOL GetNumArg1(PCStr); +STATIC BOOL GetNumArg2(PCStr, int default2); +static void hintSkipAll(void); +static BOOL askSkipLine(void); +STATIC char strcasediff(PCStr, PCStr); +STATIC void LoadCountryInfoHardCoded(PCStr filename, int ccode, int cpage); 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 +STATIC void config_init_fnodes(int f_nodes_cnt); #define EOF 0x1a -STATIC struct table * LookUp(struct table *p, BYTE * token); +typedef void config_sys_func_t(PCStr); -typedef void config_sys_func_t(BYTE * pLine); +STATIC config_sys_func_t + CfgSwitches, + CfgMenuColor, CfgMenuDefault, CfgMenu, CfgMenuEsc, + CfgBreak, Config_Buffers, Country, Dosmem, DosData, + Fcbs, Files, FilesHigh, CfgLastdrive, CfgLastdriveHigh, + Numlock, CmdShell, CmdShellHigh, + Stacks, StacksHigh, CfgSwitchar, + sysScreenMode, sysVersion, SetAnyDos, + Device, DeviceHigh, CmdInstall, CmdInstallHigh, CmdSet; -struct table { - BYTE *entry; - signed char pass; - config_sys_func_t *func; -}; +STATIC struct table { + PCStr const entry; + UBYTE pass; + config_sys_func_t *const func; -STATIC struct table commands[] = { - /* first = switches! this one is special; some options will - always be ran, others depends on F5/F8 and ? processing */ - {"SWITCHES", 0, CfgSwitches}, +} commands [] = { - /* rem is never executed by locking out pass */ - {"REM", 0, CfgIgnore}, - {";", 0, CfgIgnore}, + /* this one is special since it checked for /N/F before F5/F8 and + asked for /K/E after menu; DoConfig() changes commands[0].pass */ + {"SWITCHES", 0, CfgSwitches}, - {"MENUCOLOR",0,CfgMenuColor}, + {"REM", 100, NULL}, + {"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}, - {"CHAIN", 2, CmdChain}, - {"SET", 2, CmdSet}, - - /* default action */ - {"", -1, CfgFailure} + {"MENU", 1, CfgMenu}, /* lines to print in pass 1 */ + {"ECHO", 3, CfgMenu}, /* lines to print in pass 3 */ + {"EECHO", 3, CfgMenuEsc}, /* modified ECHO (ea) */ + + {"BREAK", 2, CfgBreak}, + {"BUFFERS", 2, Config_Buffers}, + {"BUFFERSHIGH", 2, Config_Buffers}, /* currently dummy */ + {"COUNTRY", 2, Country}, + {"DOS", 2, Dosmem}, + {"DOSDATA", 2, DosData}, + {"FCBS", 2, Fcbs}, + {"FILES", 2, Files}, + {"FILESHIGH", 2, FilesHigh}, + {"LASTDRIVE", 2, CfgLastdrive}, + {"LASTDRIVEHIGH", 2, CfgLastdriveHigh}, + {"NUMLOCK", 2, Numlock}, + {"STACKS", 2, Stacks}, + {"STACKSHIGH", 2, StacksHigh}, + {"SWITCHAR", 2, CfgSwitchar}, + {"SCREEN", 2, sysScreenMode}, /* JPP */ + {"VERSION", 2, sysVersion}, /* JPP */ + {"ANYDOS", 2, SetAnyDos}, /* tom */ + + {"DEVICE", 3, Device}, + {"DEVICEHIGH", 3, DeviceHigh}, + + {"INSTALL", 4, CmdInstall}, + {"INSTALLHIGH", 4, CmdInstallHigh}, + {"SET", 4, CmdSet}, + {"SHELL", 4, CmdShell}, + {"SHELLHIGH", 4, CmdShellHigh}, }; -/* 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; -} +enum { HMA_NONE, /* do nothing */ + HMA_REQ, /* DOS=HIGH detected */ + HMA_DONE, /* Moved kernel to HMA */ +}; + +enum { UMB_NONE, /* do nothing */ + UMB_DONE, /* UMB initialized */ + UMB_REQ, /* DOS=UMB detected */ +}; -BYTE *pLineStart BSS_INIT(0); +enum {LOC_CONV=0, LOC_HMA=1}; /* dup in global.h */ -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 */ +static UBYTE HMAState BSS_INIT(HMA_NONE); +static UBYTE UmbState BSS_INIT(UMB_NONE); /* Do first time initialization. Store last so that we can reset it */ /* later. */ @@ -335,10 +256,17 @@ void PreConfig(void) /* Initialize the base memory pointers */ CfgDbgPrintf(("SDA located at 0x%p\n", internal_data)); + /* Begin by initializing our system buffers */ - /* DebugPrintf(("Preliminary %d buffers allocated at 0x%p\n", Config.cfgBuffers, buffers));*/ - - LoL->sfthead = MK_FP(FP_SEG(LoL), 0xcc); /* &(LoL->firstsftt) */ + + LoL->DPBp = + DynAlloc("DPBp", blk_dev.dh_name[0], sizeof(struct dpb)); + + /* Initialize the file table */ + CfgDbgPrintf(("Initializing fnodes\n")); + config_init_fnodes(Config.cfgFiles); + + LoL->sfthead = MK_PTR(struct sfttbl, FP_SEG(LoL), 0xcc); /* &(LoL->firstsftt) */ /* LoL->FCBp = (sfttbl FAR *)&FcbSft; */ /* LoL->FCBp = (sfttbl FAR *) KernelAlloc(sizeof(sftheader) @@ -348,23 +276,35 @@ void PreConfig(void) LoL->CDSp = KernelAlloc(sizeof(struct cds) * LoL->lastdrive, 'L', 0); + CfgDbgPrintf(("Preliminary:\n f_node 0x%p\n", LoL->f_nodes)); /* CfgDbgPrintf((" FCB table 0x%p\n",LoL->FCBp));*/ - CfgDbgPrintf((" sft table 0x%p\n", LoL->sfthead)); CfgDbgPrintf((" CDS table 0x%p\n", LoL->CDSp)); CfgDbgPrintf((" DPB table 0x%p\n", LoL->DPBp)); /* Done. Now initialize the MCB structure */ /* This next line is 8086 and 80x86 real mode specific */ - CfgDbgPrintf(("Preliminary allocation completed: top at %p\n", lpTop)); + CfgDbgPrintf(("Preliminary allocation completed: top at %p\n", lpTop)); + + /* initialize environment */ + fmemcpy(MK_PTR(char, DOS_PSP + 8, 0), master_env, sizeof(master_env)); } -/* Do second pass initialization: near allocation and MCBs */ -void PreConfig2(void) +static void KernelAllocSFT(sfttbl FAR *p, unsigned files, int high) { - struct sfttbl FAR *sp; + p = p->sftt_next = (sfttbl FAR *)KernelAlloc(sizeof(sftheader) + + files * sizeof(sft), 'F', high); + p->sftt_count = files; + p->sftt_next = (sfttbl FAR *)-1l; +} - /* initialize NEAR allocated things */ +#define EBDASEG 0x40e +#define RAMSIZE 0x413 +#define RAM_size() peek(0, RAMSIZE) +/* Do pre-drivers initialization: near allocation and MCBs */ +static void PreConfig3(void) +{ + /* initialize NEAR allocated things */ /* Initialize the base memory pointers from last time. */ /* if the kernel could be moved to HMA, everything behind the dynamic @@ -373,59 +313,67 @@ void PreConfig2(void) and allocation starts after the kernel. */ - base_seg = LoL->first_mcb = FP_SEG(AlignParagraph((BYTE FAR *) DynLast() + 0x0f)); - - if (Config.ebda2move) + size_t ram_top = RAM_size(); /* how much conventional RAM, kb */ + seg_t ebdaseg = peek(0, EBDASEG); + size_t ebdasz = peekb(ebdaseg, 0); + if (Config.ebda2move && ram_top * 64 == ebdaseg && ebdasz <= 63) { - ebda_size = ebdasize(); - if (ebda_size > Config.ebda2move) - ebda_size = Config.ebda2move; - ram_top += ebda_size / 1024; + ram_top += ebdasz; + ebdasz *= 1024u; + if (ebdasz > Config.ebda2move) + ebdasz = (Config.ebda2move + 15) & -16; + ebda_size = ebdasz; } /* We expect ram_top as Kbytes, so convert to paragraphs */ - mcb_init(base_seg, ram_top * 64 - LoL->first_mcb - 1, MCB_LAST); + base_seg = LoL->first_mcb = FP_SEG(alignNextPara(DynLast())); + mcb_init(base_seg, ram_top * 64 - base_seg, 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; + /* allocate space in low memory for 3 file handles + (SFT) in addition to 5 handles, builtin into LOL */ + KernelAllocSFT(LoL->sfthead, 3, 0); if (ebda_size) /* move the Extended BIOS Data Area from top of RAM here */ - movebda(ebda_size, FP_SEG(KernelAlloc(ebda_size, 'I', 0))); + { + seg_t new_seg = FP_SEG(KernelAlloc(ebda_size, 'I', 0)); + fmemcpy(MK_SEG_PTR(BYTE, new_seg), MK_SEG_PTR(const BYTE, ebdaseg), ebda_size); + poke(0, EBDASEG, new_seg); + poke(0, RAMSIZE, ram_top); + } -/* if (UmbState == 2) - umb_init(); -*/ + umb_init(); } -/* Do third pass initialization. */ -/* Also, run config.sys to load drivers. */ +/* Do last initialization. */ 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; + Config.cfgFilesHigh = + Config.cfgStacksHigh = + Config.cfgLastdriveHigh = 1; } /* compute lastdrive ... */ - LoL->lastdrive = Config.cfgLastdrive; - if (LoL->lastdrive < LoL->nblkdev) - LoL->lastdrive = LoL->nblkdev; + { + UBYTE drv = Config.cfgLastdrive; + if (drv < LoL->nblkdev) + drv = LoL->nblkdev; + LoL->lastdrive = drv; + } CfgDbgPrintf(("starting FAR allocations at %x\n", base_seg)); + /* Initialize the file table */ + config_init_fnodes(Config.cfgFiles); + /* Begin by initializing our system buffers */ /* dma_scratch = (BYTE FAR *) KernelAllocDma(BUFFERSIZE); */ - /* DebugPrintf(("DMA scratchpad allocated at 0x%p\n", dma_scratch)); */ + /* CfgDbgPrintf(("DMA scratchpad allocated at 0x%p\n", dma_scratch)); */ config_init_buffers(Config.cfgBuffers); @@ -433,23 +381,22 @@ void PostConfig(void) /* 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; + + /* allocate space for remaining file handles (SFT); 5 are + already builtin and 3 are allocated in PreConfig3() */ + KernelAllocSFT(LoL->sfthead->sftt_next, + Config.cfgFiles - 8, Config.cfgFilesHigh); LoL->CDSp = KernelAlloc(sizeof(struct cds) * LoL->lastdrive, 'L', Config.cfgLastdriveHigh); -/* CfgDbgPrintf((" FCB table 0x%p\n",LoL->FCBp));*/ - CfgDbgPrintf((" sft table 0x%p\n", LoL->sfthead->sftt_next)); + CfgDbgPrintf(("Final: \n f_node 0x%p\n", LoL->f_nodes)); +/* printf(" FCB table 0x%p\n",LoL->FCBp);*/ CfgDbgPrintf((" CDS table 0x%p\n", LoL->CDSp)); CfgDbgPrintf((" DPB table 0x%p\n", LoL->DPBp)); if (Config.cfgStacks) { - VOID FAR *stackBase = + void _seg *stackBase = KernelAlloc(Config.cfgStacks * Config.cfgStackSize, 'S', Config.cfgStacksHigh); init_stacks(stackBase, Config.cfgStacks, Config.cfgStackSize); @@ -463,17 +410,14 @@ void PostConfig(void) /* 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 (UmbState == UMB_DONE) + MK_SEG_PTR(mcb, 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); + register size_t hma_paras = (HMAFree + 15) / 16; + seg_t kernel_seg = allocmem(hma_paras); + mcb _seg *p = MK_SEG_PTR(mcb, kernel_seg - 1); p->m_name[0] = 'S'; p->m_name[1] = 'C'; @@ -481,674 +425,418 @@ VOID configDone(VOID) CfgDbgPrintf(("HMA not available, moving text to %x\n", kernel_seg)); MoveKernel(kernel_seg); - - kernel_seg += hma_paras + 1; - - CfgDbgPrintf(("kernel is low, start alloc at %x\n", kernel_seg)); + CfgDbgPrintf(("kernel is low, start alloc at %x\n", + kernel_seg + hma_paras + 1)); } /* 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; + CVFP xms_addr; + seg_t umb_seg; + size_t umb_size; - if (UMB_get_largest(xms_addr, &umb_seg, &umb_size)) + if (UmbState == UMB_REQ && + (xms_addr = DetectXMSDriver()) != NULL && + UMB_get_largest(xms_addr, &umb_seg, &umb_size)) { - UmbState = 1; + seg_t umb_furthest = umb_seg; + + /* SAFETY: new block may be too small or below memory top */ + seg_t base_top = RAM_size() * 64 - 1; + if (umb_size < 2 || umb_furthest <= base_top) + return; + + UmbState = UMB_DONE; /* reset root */ - /* Note: since device drivers can change what is considered top of memory (e.g. move XBDA) we must requery */ - ram_top = init_oem(); - LoL->uppermem_root = ram_top * 64 - 1; + LoL->uppermem_root = base_top; + umb_base_seg = umb_furthest; /* 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); + /* (it prefixes hole between UMBs) */ + MK_SEG_PTR(mcb, base_seg)->m_type = MCB_NORMAL; + MK_SEG_PTR(mcb, base_seg)->m_size--; + mumcb_init(base_top, umb_seg - base_top); /* 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; + mcb_init(umb_seg, umb_size, MCB_NORMAL); /* there can be more UMBs ! - this happens, if memory mapped devces are in between + this happens, if memory mapped devices 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_furthest < umb_seg) { - 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 + seg_t umb_hole = mcb_next(umb_furthest); + + /* SAFETY: new block may (1) be adjacent to old block, + (2) overlap it or (3) be inside. (2) and (3) are errors + and shouldn't happen, but handle them anyway. */ + if (umb_hole >= umb_seg) { - /* create link mcb (above) */ - mumcb_init(umb_seg + umb_size - 1, umb_next - umb_seg - umb_size); + size_t overlap = umb_hole - umb_seg; + if (overlap < umb_size) + /* join adjacent/overlapped new block to prev block */ + MK_SEG_PTR(mcb, umb_furthest)->m_size += umb_size - overlap; + continue; } - } - 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 - { + /* SAFETY: new block may be too small */ + if (umb_size < 2) + continue; + /* create link mcb (below) */ - mumcb_init(umb_prev, umb_seg - umb_prev - 1); + MK_SEG_PTR(mcb, umb_furthest)->m_size--; + umb_furthest = umb_seg; + umb_hole--; + mumcb_init(umb_hole, umb_seg - umb_hole); } + else /* umb_seg <= umb_furthest */ + { + seg_t umb_prev, umb_hole, umb_next, umb_cur_next; - if (umb_seg > umb_max) - umb_max = umb_seg; - } - para2far(umb_max)->m_size++; - para2far(umb_max)->m_type = MCB_LAST; - CfgDbgPrintf(("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; currently <= 2047 chars */ - 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); - -struct memdiskopt { - BYTE * name; - UWORD size; -}; - -/* preprocesses memdisk command line to allow simpler handling - { is replaced by unsigned offset to start of next config line - e.g. "{{HI{HI}{HI{HI" --> "13HI4HI}3HI3HI" - FreeDOS supports max 256 length config lines, memdisk 4 max command length 2047 -*/ -BYTE FAR * ProcessMemdiskLine(BYTE FAR *cLine) -{ - BYTE FAR *ptr; - BYTE FAR *sLine = cLine; - - /* skip everything until end of line or starting { */ - for (; *cLine && (*cLine != '{'); ++cLine) - ; - sLine = cLine; - - for (ptr = cLine; *cLine; ptr = cLine) - { - /* skip everything until end of line or starting { */ - for (++cLine; *cLine && (*cLine != '{'); ++cLine) - ; - - /* calc offset from previous { to next { or eol and replace previous { with offset */ - *ptr = (BYTE)(cLine - ptr); - } - - return sLine; -} - -/* Given a pointer to a memdisk command line and buffer will copy the next - config.sys equivalent line to pLine and return updated cLine. - Call repeatedly until end of string (*cLine == '\0'). - Each simulated line is indicated be enclosing the line in curly braces {} - with the end } optional - the next { will indicate end/beginning and - end of line. MEMDISK options may appear nearly anywhere on line and are - ignored - see memdisk_opts for list of recognized options. -*/ -BYTE FAR * GetNextMemdiskLine(BYTE FAR *cLine, BYTE *pLine) -{ - STATIC struct memdiskopt memdiskopts[] = { - {"initrd", 6}, {"BOOT_IMAGE", 10}, - {"floppy", 6}, {"harddisk", 8}, {"iso", 3}, - {"nopass", 6}, {"nopassany", 9}, - {"edd", 3}, {"noedd", 5} -/* - {"c", 1}, {"h", 1}, {"s", 1}, - {"raw", 3}, {"bigraw", 6}, {"int", 3}, {"safeint", 7} -*/ - }; - - int ws = TRUE; /* treat start of line same as if whitespace seen */ - BYTE FAR * mf = NULL; /* where last line split by memdisk option */ - BYTE FAR *ptr = cLine; /* start of current cfg line, where { was */ - BYTE FAR *sLine = cLine; - - /* exit early if already at end of command line */ - if (!*cLine) return cLine; - - /* point to start of next line; terminates current line if no } found before here */ - cLine += *cLine; - - /* restore original character we overwrite with offset, for next iteration of cfg file */ - *ptr = '{'; - - /* ASSERT ptr points to start of line { and cLine points to start of next line { (or eol)*/ - - /* copy chars to pLine buffer until } or start of next line */ - for (++ptr; (*ptr != '}') && (ptr < cLine); ++ptr) - { - /* if not in last {} then simply copy chars up to } (or next {) */ - if (*cLine) goto copy_char; + /* SAFETY: umb_seg may point into base memory */ + if (base_top >= umb_seg) + continue; - /* otherwise if last character was whitespace (or start of line) check for memdisk option to skip */ - if (ws) - { - int i; - for (i = 0; i < 9; ++i) - { - /* compare with option */ - if (fmemcmp(ptr, memdiskopts[i].name, memdiskopts[i].size) == 0) + /* find previous block */ + for (umb_hole = base_top;;) { - BYTE c = *(ptr + memdiskopts[i].size); - /* ensure character after is end of line, =, or whitespace */ - if (!c || (c == '=') || iswh(c)) - { - /* flag this line split */ - mf = ptr; - - /* matched option so point past it */ - ptr += memdiskopts[i].size; - - /* allow extra whitespace between option and = by skipping it */ - while (iswh(*ptr)) - ++ptr; - - /* if option has = value then skip it as well */ - if (*ptr == '=') - { - /* allow extra whitespace between = and value by skipping it */ - while (iswh(*ptr)) - ++ptr; - - /* skip past all characters after = */ - for (; (*ptr != '}') && (ptr < cLine) && !iswh(*ptr); ++ptr) - ; - } - - break; /* memdisk option found, no need to keep check rest in list */ - } + umb_next = mcb_next(umb_hole); + /* ASSUME umb_hole->m_type == 'M' && umb_hole->m_psp == 8 && + umb_next->m_type == 'M' && umb_next->m_psp != 8 && + umb_hole < umb_next <= umb_furthest */ + if (umb_seg <= umb_next) + break; + umb_prev = umb_next; + umb_hole = mcb_next(umb_next); } - } - } + /* NOW base_top == umb_hole < umb_seg <= umb_next || + base_top < umb_prev < umb_seg <= umb_next */ - if (ptr < cLine) - { - ws = iswh(*ptr); + /* SAFETY: new block may be inside previous block */ + umb_cur_next = umb_seg + umb_size; + if (umb_cur_next <= umb_hole) + continue; - /* allow replacing X=Y prior to memdisk options with X=Z after */ - /* on 1st pass if find a match we overwrite it with spaces */ - if (mf && (*ptr == '=')) - { - BYTE FAR *old=sLine, FAR *new; - /* check for = in command line */ - for (; old < mf; ++old) + /* SAFETY: umb_seg may point below hole, + so, use ">=" instead "==" */ + if (umb_hole + 1 >= umb_seg && umb_hole != base_top) + /* join adjacent/overlapped new block to prev block */ + umb_size = umb_cur_next - (umb_seg = umb_prev); + else { - for (; (*old != '=') && (old < mf); ++old) - ; - /* ASSERT ptr points to = after memdisk option and old points to = before memdisk option or mf */ - - /* compare backwards to see if same option */ - for (new = ptr; (old >= sLine) && ((*old & 0xCD) == (*new & 0xCD)); --old, --new) - { - if (iswh(*old) || iswh(*new)) break; - } - - /* if match found then overwrite, otherwise skip past the = */ - if (((old <= sLine) || iswh(*old)) && iswh(*new)) - { - /* match found so overwrite with spaces */ - for(++old; !iswh(*old) && (old < mf); ++old) - *old = ' '; - } - else - { - for (; (*old != '=') && (old < mf); ++old) - ; - } + /* SAFETY: new block may be too small */ + if (umb_size < 2 && umb_cur_next < umb_next) + continue; + /* adjust link mcb below */ + MK_SEG_PTR(mcb, umb_hole)->m_size = umb_seg - umb_hole - 1; } - } -copy_char: - *pLine = *ptr; - ++pLine; - } - } - *pLine = 0; - - /* return location to begin next scan from */ - return cLine; -} + /* SAFETY: new block may overlap next block, + so, use ">=" instead "==" */ + if (umb_cur_next >= umb_next) + { + /* join adjacent/overlapped next block to new block */ + if (umb_furthest == umb_next) + umb_furthest = umb_seg; + if (umb_base_seg == umb_next) + umb_base_seg = umb_seg; + umb_size = mcb_next(umb_next) - umb_seg; + } + else /* umb_cur_next < umb_next */ + { + /* create link mcb (above) */ + umb_size--, umb_cur_next--; + mumcb_init(umb_cur_next, umb_next - umb_cur_next); + } + } /* else */ -#endif + /* setup the real mcb for the devicehigh block */ + mcb_init(umb_seg, umb_size, MCB_NORMAL); + } /* while */ + MK_SEG_PTR(mcb, umb_furthest)->m_type = MCB_LAST; + umb_base_start = umb_base_seg; -static unsigned check_config_commandline(char ** pointer, char * cc, - char const * commandbuffer, char const * command); -static unsigned check_config_commandline(char ** pointer, char * cc, - char const * commandbuffer, char const * command) { - unsigned length = strlen(command); - if (memcmp(commandbuffer, command, length) == 0 - && (commandbuffer[length] == '\t' - || commandbuffer[length] == ' ' - || commandbuffer[length] == '=' - || commandbuffer[length] == 0)) { - for (cc += length; *cc == '\t' || *cc == ' '; ++cc); - if (*cc == '=') ++cc; - for (; *cc == '\t' || *cc == ' '; ++cc); - *pointer = cc; - return 1; - } - return 0; + DebugPrintf(("UMB Allocation completed: start at 0x%x\n", umb_base_seg)); + } /* if */ } +STATIC const struct table * LookUp(CStr token) +{ + const struct table *p = commands; + do + if (!strcasediff(p->entry, token)) + return p; + while (++p < ENDOF(commands)); + p = NULL; + return p; +} -VOID DoConfig(int nPass) +static void DoConfig_(void) { - BYTE *pLine; - BOOL bEof = FALSE; + int nFileDesc, done; -#ifdef MEMDISK_ARGS - /* check if MEMDISK used for LoL->BootDrive, if so check for special appended arguments */ - struct memdiskinfo FAR *mdsk = NULL; - BYTE FAR *cLine; - /* 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); - if (mdsk != NULL) - { - cLine = ProcessMemdiskLine(mdsk->cmdline); - } - } -#endif + if (askCommand & ASK_SKIPALL) + return; - if (nPass==0) + /* Check to see if we have a config.sys file. If not, just */ + /* exit since we don't force the user to have one. */ + /*strcpy (configfile, "FDCONFIG.SYS");*/ + if ((nFileDesc = open(configfile, 0)) < 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); - CfgDbgPrintf(("MEMDISK args:{%S}\n", mdsk->cmdline)); - } - else + CfgDbgPrintf(("%s not found\n", configfile)); + strcpy (configfile, "CONFIG.SYS"); + if ((nFileDesc = open(configfile, 0)) < 0) { - CfgDbgPrintf(("MEMDISK not detected!\n")); - } -#endif - } - - { - char * pp = kernel_command_line; - char * cc; - unsigned ii; - static char commandbuffer[256]; - char * end = &kernel_command_line[kernel_command_line_length]; - static char * configfile = ""; - static char * altconfigfile = "fdconfig.sys"; - static char * oldconfigfile = "config.sys"; - static struct { char ** pointer; char const * command; } - configcommands[] = { - { &configfile, "CONFIG" }, - { &altconfigfile, "ALTCONFIG" }, - { &oldconfigfile, "OLDCONFIG" }, - { NULL, NULL } - }; - for (; pp < end; pp += strlen(pp) + 1) { - for (cc = pp; *cc == '\t' || *cc == ' '; ++cc); - strcpy(commandbuffer, cc); - strupr(commandbuffer); - for (ii = 0; configcommands[ii].pointer != NULL; ++ii) - if (check_config_commandline(configcommands[ii].pointer, - cc, commandbuffer, configcommands[ii].command)) - break; - } - - /* 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). */ - for (ii = 0; configcommands[ii].pointer != NULL; ++ii) { - if (**configcommands[ii].pointer != '\0') { - if ((nFileDesc = open(*configcommands[ii].pointer, 0)) >= 0) { - CfgDbgPrintf(("Reading \"%s\"...\n", *configcommands[ii].pointer)); - break; - } else { - CfgDbgPrintf(("\"%s\" not found\n", *configcommands[ii].pointer)); - } - } - } - if (configcommands[ii].pointer == NULL) { - /* at this point no config file was found, may return early */ -#ifdef MEMDISK_ARGS - /* if memdisk in use then only assume end of file reached and proceed, else return early */ - if (mdsk != NULL) - bEof = TRUE; - else -#endif - return; + CfgDbgPrintf(("%s not found\n", configfile)); + return; } } - - nCfgLine = 0; /* keep track of which line in file for errors */ + CfgDbgPrintf(("Reading %s...\n", configfile)); /* 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 != NULL); nCfgLine++) -#else - for (; !bEof; nCfgLine++) -#endif + done = nCfgLine = 0; + do { - struct table *pEntry; - pLineStart = szLine; - -#ifdef MEMDISK_ARGS - if (!bEof) - { -#endif + PStr q; + PCStr p; + const struct table *pEntry; /* read in a single line, \n or ^Z terminated */ - - for (pLine = szLine;;) + nCfgLine++; + for (q = szLine;;) { - if (read(nFileDesc, pLine, 1) == 0) + /* if EOF already found, error reading, or EOF char read then we're done */ + if (read(nFileDesc, q, 1) != 1 || *q == EOF) { - bEof = TRUE; + done++; break; } - if (pLine >= szLine + sizeof(szLine) - 3) - { - CfgFailure(pLine); - printf("error - line overflow line %d \n", nCfgLine); + if (*q == '\n') /* end of line */ break; - } - if (*pLine == '\n' || *pLine == EOF) /* end of line */ - break; + if (*q != '\r') /* ignore CR */ + { + q++; + if (q >= szLine + sizeof szLine - 1) + { + /* *q = 0; */ /* static memory already zeroed */ + CfgFailure(q); + say("error - line overflow\n"); + break; + } + } + } /* for */ + *q = 0; /* terminate line - make ASCIIZ */ - if (*pLine != '\r') /* ignore CR */ - pLine++; - } + p = skipwh(szLine); + if (*p == '\0' || *p == ';') + continue; /* skip empty line and comment */ - *pLine = 0; -#ifdef MEMDISK_ARGS - } - else if (mdsk != NULL) + p = scanverb(p, szBuf); /* extract verb */ + pEntry = LookUp(szBuf); + if (pEntry == NULL) { - cLine = GetNextMemdiskLine(cLine, szLine); - /* if end of memdisk command line reached, flag done */ - if (!*cLine) - mdsk = NULL; - } -#endif - - if (bEof && nCurChain) { - struct CfgFile *cfg = &cfgFile[--nCurChain]; - close(nFileDesc); - bEof = FALSE; - nFileDesc = cfg->nFileDesc; - nCfgLine = cfg->nCfgLine; + if (nPass == 2) /* only at pass 2 (after menu)... */ + CfgFailure(p); /* ...say error for wrong verb */ continue; } - CfgDbgPrintf(("CONFIG=[%s]\n", szLine)); - - /* Skip leading white space and get verb. */ - pLine = scan(szLine, szBuf, 1); - - /* 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); - - /* should config command be executed on this pass? */ - if (pEntry->pass >= 0 && pEntry->pass != nPass) + if (nPass != pEntry->pass || + nPass > 1 && /* after menu: check "123?device=" */ + !testbit(line_choices, last_choice)) continue; - /* pass 0 always executed (rem Menu prompt switches) */ - if (nPass == 0) + if (pEntry->func != CfgMenu && pEntry->func != CfgMenuEsc) { - 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) + if (*p) { - CfgFailure(pLine); - continue; + if (*p != ' ' && *p != '\t' && *p != '=') + { + CfgFailure(p); + continue; + } + p = skipwh(p); + if (*p == '=') /* accept "device foo.sys" without '=' */ + p = skipwh(p + 1); } - pLine = skipwh(pLine); + if (nPass > 1 && askSkipLine()) /* after menu: processing "?" */ + continue; } - if ('=' == *pLine || pEntry->func == CfgMenu || pEntry->func == CfgMenuEsc) - pLine = skipwh(pLine+1); + if (*p == ' ' || *p == '\t') + p++; /* YES. DO IT */ - pEntry->func(pLine); - } - close(nFileDesc); + pEntry->func(p); + } while (!done && !(askCommand & ASK_SKIPALL)); - if (nPass == 0) - { - DoMenu(); - } + close(nFileDesc); + nPass++; } -STATIC struct table * LookUp(struct table *p, BYTE * token) +void DoConfig() { - while (p->entry[0] != '\0' && !strcaseequal(p->entry, token)) - ++p; - return p; + DoConfig_(); /* switches=/f/n, menucolor= */ + hintSkipAll(); + if (!(askCommand & ASK_SKIPALL)) + { + if (MenuColor) /* color defined? */ + ClearScreenArea(MenuColor, 0, 0, screenwidth(), screenbottom() + 1); + DoConfig_(); /* show MENU, find choices */ + if (all_choices) + { + if (!testbit(all_choices, last_choice)) + { + unsigned ac; + last_choice = 0; /* find lowest existing choice */ + for (ac = all_choices; !testbit(ac, 0); ac >>= 1) + last_choice++; + } + if ((all_choices - 1) & all_choices) /* more than one choice? */ + DoMenu(); + if (!(askCommand & ASK_SKIPALL)) + { + static char choice[] = "CONFIG=0"; + choice[7] = (UBYTE)'0' + last_choice; + CmdSet(choice); /* show choice in environment */ + } + } + commands[0].pass = 2; /* switches=/k/e at pass 2 */ + DoConfig_(); /* break=, files=, etc. */ + } + PreConfig3(); + DoConfig_(); /* device= */ } /* get BIOS key with timeout: - - timeout < 0: no timeout + timeout < 0: no timeout, remove returned key from keyboard buffer timeout = 0: poll only once - timeout > 0: timeout in seconds - + timeout > 0: timeout for poll in seconds return - 0xffff : no key hit - + 0 : no key hit (only for timeout >= 0) 0xHH.. : scancode in upper half 0x..LL : asciicode in lower half */ + #define GetBiosTime() peekl(0, 0x46c) -UWORD GetBiosKey(int timeout) +#define ESC 27 +#define K_F5 0x3F00 +#define K_F8 0x4200 +#define K_Left 0x4B00 +#define K_Right 0x4D00 +#define K_Up 0x4800 +#define K_Down 0x5000 + +unsigned GetBiosKey(int timeout) { iregs r; - - ULONG startTime = GetBiosTime(); - if (timeout >= 0) { + ULONG startTime = GetBiosTime(); do { - /* optionally HLT here - timer will IRQ even if no keypress */ - r.a.x = 0x0100; /* are there keys available ? */ + r.AH = 0x01; /* 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; - } + if (!(r.flags & FLG_ZERO)) + return r.AX; } while ((unsigned)(GetBiosTime() - startTime) < timeout * 18u); - return 0xffff; + return 0; } - /* 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; + /* key available or blocking wait (timeout < 0): fetch it */ + r.AH = 0x00; init_call_intr(0x16, &r); - return r.a.x; + return r.AX; } -STATIC BOOL SkipLine(char *pLine) +static void hintSkipAll(void) { - short key; - COUNT i; - signed char originalskipconfigseconds = InitKernelConfig.SkipConfigSeconds; - - if (originalskipconfigseconds >= 0) + int timeout = InitKernelConfig.SkipConfigSeconds; + if (timeout >= 0) { + unsigned key; - if (originalskipconfigseconds > 0) - printf("Press F8 to trace or F5 to skip CONFIG.SYS/AUTOEXEC.BAT"); - - key = GetBiosKey(originalskipconfigseconds); /* wait 2 seconds */ + if ((all_choices - 1) & all_choices) /* more than one choice? */ + timeout = 0; - InitKernelConfig.SkipConfigSeconds = -1; + if (timeout > 0) + say2("Press F8 to trace or F5 to skip %s/AUTOEXEC.BAT", configfile); + key = GetBiosKey(timeout); + clearrow(); /* clear hint line */ - if (key == 0x3f00) /* F5 */ + if (key == K_F8) /* F8 */ { - SkipAllConfig = TRUE; + askCommand |= ASK_TRACE; + GetBiosKey(-1); /* remove key from buffer */ } - else if (key == 0x4200) /* F8 */ + else if (key == K_F5) /* F5 */ { - singleStep = TRUE; + askCommand |= ASK_SKIPALL; + say2("Bypassing %s and AUTOEXEC.BAT files.\n", configfile); + GetBiosKey(-1); /* remove key from buffer */ } - - if (originalskipconfigseconds > 0) - 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; - - for (i = 0; i < nCurChain; i++) - printf(" "); - printf("%s[Y,N]?", pLine); +static BOOL askSkipLine(void) +{ + /* !device= never ask / ?device= always ask / device= ask if ASK_TRACE */ + /* "!device?=" will not be asked... */ + if ((askCommand & (ASK_NOASK | ASK_YESALL)) || /* "!" or Esc */ + !(askCommand & (ASK_ASK | ASK_TRACE))) /* not ("?" or trace) */ + return FALSE; /* do not skip, and do not ask either */ + say2("%s[Y,n]?", szLine); for (;;) { - key = GetBiosKey(-1); - - switch (toupper(key & 0x00ff)) + unsigned key = GetBiosKey(-1); /* wait keypress */ + if (key == K_F5) /* YES, you may hit F5 here, too */ + { + askCommand |= ASK_SKIPALL; + key = 'N'; + } + if (key == K_F8) /* F8 */ + key = ESC; + switch (toupper((UBYTE)key)) { case 'N': - printf("N\n"); + say("N\n"); return TRUE; - case 0x1b: /* don't know where documented - ESCAPE answers all following questions - with YES - */ - singleStep = FALSE; /* and fall through */ + case ESC: /* Esc answers all following questions YES */ + askCommand &= ~ASK_TRACE; + askCommand |= ASK_YESALL; + /* and fall through */ case '\r': case '\n': case 'Y': - printf("Y\n"); + say("Y\n"); return FALSE; - - } - - if (key == 0x3f00) /* YES, you may hit F5 here, too */ - { - printf("N\n"); - SkipAllConfig = TRUE; - return TRUE; } - } - + } /* for */ } +static int numarg BSS_INIT(0); + /* JPP - changed so will accept hex number. */ /* ea - changed to accept hex digits in hex numbers */ -STATIC char *GetNumArg(char *p, int *num) +STATIC PCStr GetNumArg(PCStr p) { static char digits[] = "0123456789ABCDEF"; unsigned char base = 10; @@ -1157,15 +845,15 @@ STATIC char *GetNumArg(char *p, int *num) /* look for NUMBER */ p = skipwh(p); - if (*p == '-') + if (!isdigit(*p)) { - p++; + if (*p != '-') + { + CfgFailure(p); + return NULL; + } sign = -1; - } - else if (!isnum(*p)) - { - CfgFailure(p); - return NULL; + p++; } for( ; *p; p++) @@ -1175,341 +863,274 @@ STATIC char *GetNumArg(char *p, int *num) base = 16; else { - char *q = strchr(digits, ch); + PCStr q = strchr(digits, ch); if (q == NULL) break; n = n * base + (q - digits); } } - *num = n * sign; + numarg = n * sign; return p; } -BYTE *GetStringArg(BYTE * pLine, BYTE * pszString) +STATIC BOOL isEOL(PCStr p) { - /* just return whatever string is there, including null */ - return scan(pLine, pszString, 0); + if (*p) /* garbage at line end? */ + { + CfgFailure(p); + return FALSE; + } + return TRUE; } -STATIC void Config_Buffers(BYTE * pLine) +/* Format: nnn EOL */ +STATIC BOOL GetNumArg1(PCStr p) { - COUNT nBuffers; - - /* Get the argument */ - if (GetNumArg(pLine, &nBuffers)) - Config.cfgBuffers = nBuffers; + p = GetNumArg(p); + if (p == NULL) + return FALSE; + return isEOL(skipwh(p)); } -STATIC void CfgBuffersHigh(BYTE * pLine) -{ - Config_Buffers(pLine); - if (InitKernelConfig.Verbose >= 0) printf("Note: BUFFERS will be in HMA or low RAM, not in UMB\n"); -} +static int numarg1 BSS_INIT(0); -/** - Set screen mode - rewritten to use init_call_intr() by RE / ICD -*/ -STATIC VOID sysScreenMode(BYTE * pLine) +/* Format: nnn [, nnn] EOL */ +STATIC BOOL GetNumArg2(PCStr p, int default2) { - iregs r; - COUNT nMode; - COUNT nFunc = 0x11; - - /* Get the argument */ - if (GetNumArg(pLine, &nMode) == (BYTE *) 0) - return; + p = GetNumArg(p); + if (p == NULL) + return FALSE; - if(nMode<0x10) - nFunc = 0; /* set lower screenmode */ - else if ((nMode != 0x11) && (nMode != 0x12) && (nMode != 0x14)) - return; /* do nothing; invalid screenmode */ + numarg1 = numarg; + numarg = default2; + p = skipwh(p); + if (*p == ',') + return GetNumArg1(p + 1); -/* 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); + return isEOL(p); } -STATIC VOID sysVersion(BYTE * pLine) +/* Format: BUFFERS [=] nnn [, nnn] */ +STATIC void Config_Buffers(PCStr p) { - 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; - - if (InitKernelConfig.Verbose >= 0) 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 */ - ((psp far *)MK_FP(DOS_PSP, 0))->ps_retdosver = (minor << 8) + major; + if (GetNumArg2(p, 0)) + Config.cfgBuffers = (UBYTE)numarg1; + /* Second argument (0..8 buffers for read-ahead) not supported */ } -STATIC VOID Files(BYTE * pLine) +/* Set screen mode - rewritten to use init_call_intr() by RE / ICD */ +/* Format: SCREEN [=] nnn */ +STATIC void sysScreenMode(PCStr p) { - COUNT nFiles; + if (GetNumArg1(p)) + { + unsigned mode = numarg; + if (mode >= 0x10) + { + /* Modes + 0x11 (17) 28 lines + 0x12 (18) 43/50 lines + 0x14 (20) 25 lines + */ + if (mode != 0x11 && mode != 0x12 && mode != 0x14) + return; /* do nothing; invalid screenmode */ + mode |= 0x1100; + } + { + iregs r; + r.BL = 0; /* block to load for AH=0x11 */ + r.AX = mode; /* set videomode */ + init_call_intr(0x10, &r); + } + } +} - /* Get the argument */ - if (GetNumArg(pLine, &nFiles) == (BYTE *) 0) +/* Format: VERSION [=] nn.nn */ +STATIC void sysVersion(PCStr p) +{ + int major; + p = GetNumArg(p); + major = numarg; + if (p == NULL || *p != '.' || !GetNumArg1(p + 1)) return; - /* Got the value, assign either default or new value */ - Config.cfgFiles = max(Config.cfgFiles, nFiles); - Config.cfgFilesHigh = 0; + printf("Changing reported version to %d.%d\n", + LoL->os_setver_major = (UBYTE)major, + LoL->os_setver_minor = (UBYTE)numarg); } -STATIC VOID FilesHigh(BYTE * pLine) +/* Format: FILES [=] nnn */ +/* Format: FILESHIGH [=] nnn */ +static void _Files(PCStr p, UBYTE high) { - Files(pLine); - Config.cfgFilesHigh = 1; + if (GetNumArg1(p)) + { + UBYTE nFiles = (UBYTE)numarg; + if (Config.cfgFiles < nFiles) + Config.cfgFiles = nFiles; + Config.cfgFilesHigh = high; + } } -STATIC VOID CfgLastdrive(BYTE * pLine) -{ - /* Format: LASTDRIVE = letter */ - BYTE drv; +STATIC void Files(PCStr p) { _Files(p, 0); } - pLine = skipwh(pLine); - drv = toupper(*pLine); +STATIC void FilesHigh(PCStr p) { _Files(p, 1); } - if (drv < 'A' || drv > 'Z') +/* Format: LASTDRIVE [=] letter */ +/* Format: LASTDRIVEHIGH [=] letter */ +static void _CfgLastdrive(PCStr p, UBYTE high) +{ + BYTE drv = toupper(*p); + if (drv < 'A' || drv > 'Z' || p[1]) { - CfgFailure(pLine); + /* no or wrong character or garbage at line end? */ + CfgFailure(p); 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; + drv -= 'A' - 1; /* Make real number */ + if (Config.cfgLastdrive < drv) + Config.cfgLastdrive = drv; + Config.cfgLastdriveHigh = high; } -/* - UmbState of confidence, 1 is sure, 2 maybe, 4 unknown and 0 no way. -*/ +STATIC void CfgLastdrive(PCStr p) { _CfgLastdrive(p, 0); } -STATIC VOID Dosmem(BYTE * pLine) -{ - BYTE *pTmp; - BYTE UMBwanted = FALSE; - - GetStringArg(pLine, szBuf); - strcpy(szBuf, pLine); - strupr(szBuf); +STATIC void CfgLastdriveHigh(PCStr p) { _CfgLastdrive(p, 1); } - /* printf("DOS called with %s\n", szBuf); */ - - for (pTmp = szBuf;;) +/* UmbState of confidence, UMB_DONE is sure, UMB_REQ maybe, UMB_NONE no way. + Transitions: UMB_NONE -> UMB_NONE/UMB_REQ depending on DOS=UMB, try init + (UMB_REQ -> UMB_DONE) after each driver load, as it could have been the + UMB driver. + If UMB really found, state UMB_DONE is reached and MCBs are adjusted. +*/ +/* opt = HIGH | UMB + Format: DOS [=] opt {, opt} +*/ +STATIC void Dosmem(PCStr p) +{ + UBYTE UMBwanted = UMB_NONE, HMAwanted = HMA_NONE; + for (;;) { - while (*pTmp == ' ' || *pTmp == '\t') - pTmp++; - - if (memcmp(pTmp, "UMB", 3) == 0) - { - UMBwanted = TRUE; - pTmp += 3; - } - if (memcmp(pTmp, "HIGH", 4) == 0) - { - HMAState = HMA_REQ; - pTmp += 4; - } - if (memcmp(pTmp, "LOW", 3) == 0) - { - HMAState = HMA_LOW; - pTmp += 3; - } - if (memcmp(pTmp, "NOUMB", 5) == 0) + PCStr q = scanword(p, szBuf); + if (!strcasediff(szBuf, "UMB")) + UMBwanted = UMB_REQ; + else if (!strcasediff(szBuf, "HIGH")) + HMAwanted = HMA_REQ; +/* else if (!strcasediff(szBuf, "CLAIMINIT")) + * INITDataSegmentClaimed = 0; + */ + else { - UMBwanted = FALSE; - pTmp += 5; + CfgFailure(p); + return; } -/* if (memcmp(pTmp, "CLAIMINIT",9) == 0) { INITDataSegmentClaimed = 0; pTmp += 9; }*/ - pTmp = skipwh(pTmp); - - if (*pTmp == '\0') - break; - if (*pTmp != ',') + p = skipwh(q); + if (*p != ',') { - CfgFailure(pLine + (pTmp - szBuf)); - break; + if (*p == '\0') + break; + CfgFailure(p); + return; } - pTmp++; - } + p++; + } /* for */ - if (UmbState == 0) + if (UmbState == UMB_NONE) { LoL->uppermem_link = 0; LoL->uppermem_root = 0xffff; - UmbState = UMBwanted ? 2 : 0; + UmbState = UMBwanted; } /* Check if HMA is available straight away */ - if (HMAState == HMA_REQ && MoveKernelToHMA()) - { - HMAState = HMA_DONE; - } + if (HMAwanted == HMA_REQ) + HMAState = MoveKernelToHMA() ? HMA_DONE : HMA_REQ; } -STATIC VOID DosData(BYTE * pLine) +/* Format: DOSDATA [=] UMB */ +STATIC void DosData(PCStr p) { - pLine = GetStringArg(pLine, szBuf); - strupr(szBuf); - - if (memcmp(szBuf, "UMB", 3) == 0) + if (!strcasediff(p, "UMB")) Config.cfgDosDataUmb = TRUE; + else + CfgFailure(p); } -STATIC VOID CfgSwitchar(BYTE * pLine) +/* Format: SWITCHAR [=] character */ +STATIC void CfgSwitchar(PCStr p) { - /* Format: SWITCHAR = character */ - - GetStringArg(pLine, szBuf); - init_switchar(*szBuf); + if (*p == '\0' || p[1]) + { + /* no character or garbage at line end */ + CfgFailure(p); + return; + } + init_switchar(*p); } -STATIC VOID CfgSwitches(BYTE * pLine) +/* Format: SWITCHES [=] { /K | /N | /F | /E[[:]nnn] } */ +STATIC void CfgSwitches(PCStr p) { - pLine = skipwh(pLine); - if (*pLine == '=') + do { - pLine = skipwh(pLine + 1); - } - while (*pLine) - { - if (*pLine == '/') { - pLine++; - switch(toupper(*pLine)) { + if (*p != '/') + { + if (nPass) + CfgFailure(p); + return; + } + switch(toupper(*++p)) + { case 'K': - if (commands[0].pass == 1) + if (nPass) kbdType = 0; /* force conv keyb */ + p++; break; case 'N': InitKernelConfig.SkipConfigSeconds = -1; + p++; break; case 'F': InitKernelConfig.SkipConfigSeconds = 0; + p++; 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 == '-'))) - { - pLine--; - break; - } - pLine = GetNumArg(pLine, &n) - 1; + /* Note that if there is no EBDA, this will have no effect */ + if (*++p == ':') + p++; /* skip optional separator */ + if (isdigit(*p)) + { + p = GetNumArg(p); + if (p == NULL) + return; /* 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) */ + if (nPass) + Config.ebda2move = numarg; } + break; default: - CfgFailure(pLine); - } - } else { - CfgFailure(pLine); - } - pLine = skipwh(pLine+1); - } - commands[0].pass = 1; + if (nPass) + CfgFailure(p); + return; + } /* switch */ + p = skipwh(p); + } while (*p); } -STATIC VOID Fcbs(BYTE * pLine) +/* Format: FCBS [=] totalFcbs [, protectedFcbs] */ +STATIC void Fcbs(PCStr p) { - /* Format: FCBS = totalFcbs [,protectedFcbs] */ - COUNT fcbs; - - if ((pLine = GetNumArg(pLine, &fcbs)) == 0) - return; - Config.cfgFcbs = fcbs; - - pLine = skipwh(pLine); - - if (*pLine == ',') + if (GetNumArg2(p, Config.cfgProtFcbs)) { - GetNumArg(++pLine, &fcbs); - Config.cfgProtFcbs = fcbs; + UBYTE fcbs = (UBYTE)numarg1, prot = (UBYTE)numarg; + Config.cfgFcbs = fcbs; + if (prot > fcbs) + prot = fcbs; + Config.cfgProtFcbs = prot; } - - 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(): @@ -1517,10 +1138,9 @@ STATIC VOID CfgKeyBuf(BYTE * pLine) * 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) + +STATIC void LoadCountryInfo(PCStr filename, int ccode, int cpage) { /* COUNTRY.SYS file data structures - see RBIL tables 2619-2622 */ @@ -1542,39 +1162,31 @@ STATIC BOOL LoadCountryInfo(char *filenam, UWORD ctryCode, UWORD codePage) ULONG offset; /* offset within file of subfunction data entry */ }; static struct { /* subfunction data */ - char signature[8]; /* \377CTYINFO|UCASE|LCASE|FUCASE|FCHAR|COLLATE|DBCS|YESNO */ + 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 */ - int idx; /* index of pointer in nls_hc.asm to be copied to */ + void FAR *p; /* pointer to data in nls_hc.asm to be copied to */ }; - static struct subf_tbl table[9] = { - {"\377 ", -1}, /* 0, unused */ - {"\377CTYINFO", 5}, /* 1 */ - {"\377UCASE ", 0}, /* 2 */ - {"\377LCASE ", -1}, /* 3, not supported [yet] */ - {"\377FUCASE ", 1}, /* 4 */ - {"\377FCHAR ", 2}, /* 5 */ - {"\377COLLATE", 3}, /* 6 */ - {"\377DBCS ", 4}, /* 7, not supported [yet] */ - {"\377YESNO ", -1} /* 35 */ + 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[9]; - static int entries, count; - int fd, i, subf_tbl_ndx; - char *filename = filenam == NULL ? "\\COUNTRY.SYS" : filenam; - BOOL rc = FALSE; - BYTE FAR *ptable; - void FAR *CharMapFn; + static struct subf_hdr hdr[8]; + int fd, entries, count, i; if ((fd = open(filename, 0)) < 0) { - if (filenam == NULL) - return !LoadCountryInfoHardCoded(ctryCode); printf("%s not found\n", filename); - return rc; + return; } if (read(fd, &header, sizeof(header)) != sizeof(header)) { @@ -1593,28 +1205,23 @@ err:printf("%s has invalid format\n", filename); { if (read(fd, &entry, sizeof(entry)) != sizeof(entry) || entry.length != 12) goto err; - if (entry.country != ctryCode || entry.codepage != codePage && codePage) + if (entry.country != ccode || entry.codepage != cpage && cpage) 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) + || read(fd, &hdr, sizeof(struct subf_hdr) * count) != sizeof(struct subf_hdr) * count) goto err; - - /* Note: we reuse i here as we only process 1 entry, goto after inner for ends outer for */ for (i = 0; i < count; i++) { if (hdr[i].length != 6) goto err; - subf_tbl_ndx = hdr[i].id; - if (subf_tbl_ndx == 3 || ((subf_tbl_ndx < 1 || subf_tbl_ndx > 7) && subf_tbl_ndx != 35)) + if (hdr[i].id < 1 || hdr[i].id > 6 || hdr[i].id == 3) continue; - if (subf_tbl_ndx == 35) - subf_tbl_ndx = 8; /* 0 through 7 match, but subfunction 35 is 9th entry in table[] */ if (lseek(fd, hdr[i].offset) == 0xffffffffL || read(fd, &subf_data, 10) != 10 - || memcmp(subf_data.signature, table[subf_tbl_ndx].sig, 8) && (hdr[i].id !=4 + || 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; @@ -1624,212 +1231,150 @@ err:printf("%s has invalid format\n", filename); != entry.country || ((struct CountrySpecificInfo *)subf_data.buffer)->CodePage != entry.codepage - && codePage) + && cpage) 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)); - CharMapFn = nlsCountryInfoHardcoded.C.CharMapFn; - } - if (hdr[i].id == 1) - ptable = (BYTE FAR *)&nlsPackageHardcoded.nlsExt.size; - else - ptable = nlsPackageHardcoded.nlsPointers[table[subf_tbl_ndx].idx].pointer; - if (hdr[i].id == 7) - { - if (subf_data.length == 0) - { - /* if DBCS table (in country.sys) is empty, clear internal table */ - *(DWORD *)(subf_data.buffer) = 0L; - fmemcpy(ptable, subf_data.buffer, 4); - } - else - { - fmemcpy(ptable + 2, subf_data.buffer, subf_data.length); - /* write length */ - *(UWORD *)(subf_data.buffer) = subf_data.length; - fmemcpy(ptable, subf_data.buffer, 2); - } - continue; - } - - /* for 0-7 we store COUNTRY.SYS data directly in buffer, but yes/no characters we store in nls package directly */ - if (hdr[i].id == 35) - { - fmemcpy(&nlsPackageHardcoded.yeschar, subf_data.buffer, 2); - fmemcpy(&nlsPackageHardcoded.nochar, subf_data.buffer + 2, 2); - } else { - fmemcpy(ptable + 2, subf_data.buffer, - /* skip length ^*/ subf_data.length); - if (hdr[i].id == 1) { - /* fixup user callable address in case we overwrote it */ - ((struct CountrySpecificInfo *)ptable)->CharMapFn = CharMapFn; - } } + 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); + printf("couldn't find info for country ID %u\n", ccode); ret: close(fd); - return rc; } -STATIC VOID Country(BYTE * pLine) +/* Format: COUNTRY [=] countryCode [, [codePage] [, filename]] */ +STATIC void Country(PCStr p) { - /* Format: COUNTRY = countryCode, [codePage], filename */ - COUNT ctryCode; - COUNT codePage = 0; - char *filename = NULL; + int ccode; + PCStr filename = "\\COUNTRY.SYS"; - if ((pLine = GetNumArg(pLine, &ctryCode)) == 0) - goto error; + p = GetNumArg(p); + if (p == NULL) + return; - pLine = skipwh(pLine); - if (*pLine == ',') + ccode = numarg; + numarg = 0; + p = skipwh(p); + if (*p == ',') { - pLine = skipwh(pLine + 1); - - if (*pLine != ',') - if ((pLine = GetNumArg(pLine, &codePage)) == 0) - goto error; - - pLine = skipwh(pLine); - if (*pLine == ',') + p = skipwh(p + 1); + if (*p != ',') { - GetStringArg(++pLine, szBuf); - filename = szBuf; + p = GetNumArg(p); + if (p == NULL) + return; + p = skipwh(p); } + if (*p == ',') + filename = p + 1; } - if (LoadCountryInfo(filename, ctryCode, codePage)) + if (*p && *p != ',') /* garbage at line end? */ + { + CfgFailure(p); return; + } -error: - CfgFailure(pLine); + LoadCountryInfo(filename, ccode, numarg); } -STATIC VOID Stacks(BYTE * pLine) +/* Format: STACKS [=] stacks [, stackSize] */ +/* Format: STACKSHIGH [=] stacks [, stackSize] */ +static void _Stacks(PCStr p, UBYTE high) { - COUNT stacks; - - /* Format: STACKS = stacks [, stackSize] */ - pLine = GetNumArg(pLine, &stacks); - Config.cfgStacks = stacks; - - pLine = skipwh(pLine); - - if (*pLine == ',') + if (GetNumArg2(p, Config.cfgStackSize)) { - GetNumArg(++pLine, &stacks); - Config.cfgStackSize = stacks; + UBYTE stacks = (UBYTE)numarg1; + UWORD sz = numarg; + if (stacks > 64) + stacks = 64; + if (sz < 32) + sz = 32; + if (sz > 512) + sz = 512; + Config.cfgStacks = stacks; + Config.cfgStackSize = sz; + Config.cfgStacksHigh = high; } - - 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 Stacks(PCStr p) { _Stacks(p, 0); } -STATIC VOID InitPgmHigh(BYTE * pLine) -{ - InitPgm(pLine); - Config.cfgP_0_startmode = 0x80; -} +STATIC void StacksHigh(PCStr p) { _Stacks(p, 1); } -STATIC VOID InitPgm(BYTE * pLine) +/* Format: SHELL [=] command */ +STATIC void CmdShell(PCStr p) { - 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; + /* assume strlen(p)+1 <= sizeof Config.cfgShell */ + strcpy(Config.cfgShell, p); } -STATIC VOID CfgBreak(BYTE * pLine) +/* Format: SHELLHIGH [=] command */ +STATIC void CmdShellHigh(PCStr p) { - /* Format: BREAK = (ON | OFF) */ - GetStringArg(pLine, szBuf); - break_ena = strcaseequal(szBuf, "OFF") ? 0 : 1; + Config.cfgP_0_startmode = 0x80; + /* assume strlen(p)+1 <= sizeof Config.cfgShell */ + strcpy(Config.cfgShell, p); } -STATIC VOID Numlock(BYTE * pLine) +/* Format: BREAK [=] (ON | OFF) */ +STATIC void CfgBreak(PCStr p) { - /* 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(); + if (!strcasediff(p, "ON")) + break_ena = 1; + else if (!strcasediff(p, "OFF")) + break_ena = 0; + else + CfgFailure(p); } -STATIC VOID DeviceHigh(BYTE * pLine) +/* Format: NUMLOCK [=] (ON | OFF) */ +STATIC void Numlock(PCStr p) { - 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); - } - } + UBYTE FAR *keyflags = MK_PTR(UBYTE, 0, 0x417); + if (!strcasediff(p, "ON")) + *keyflags |= 32; + else if (!strcasediff(p, "OFF")) + *keyflags &= ~32; else { - printf("UMBs unavailable!\n"); - LoadDevice(pLine, lpTop, FALSE); + CfgFailure(p); + return; } + keycheck(); +} + +/* Format: DEVICEHIGH [=] command */ +STATIC void DeviceHigh(PCStr p) +{ + if (UmbState != UMB_DONE || /* UMB not initialized? */ + LoadDevice(p, MK_SEG_PTR(void, mcb_next(umb_base_start)), TRUE) == DE_NOMEM) + Device(p); } -STATIC void Device(BYTE * pLine) +/* Format: DEVICE [=] command */ +STATIC void Device(PCStr p) { - LoadDevice(pLine, lpTop, FALSE); + LoadDevice(p, lpTop, FALSE); } -STATIC BOOL LoadDevice(BYTE * pLine, char FAR *top, COUNT mode) +STATIC BOOL LoadDevice(PCStr p, VFP top, int mode) { - exec_blk eb; - struct dhdr FAR *dhp; - struct dhdr FAR *next_dhp; - BOOL result; - seg base, start; + int ret; + seg_t base = base_seg; + seg_t start = LoL->first_mcb; if (mode) { base = umb_base_seg; - start = umb_start; - } - else - { - base = base_seg; - start = LoL->first_mcb; + start = umb_base_start; } if (base == start) @@ -1837,33 +1382,41 @@ STATIC BOOL LoadDevice(BYTE * pLine, char FAR *top, COUNT mode) base++; /* Get the device driver name */ - GetStringArg(pLine, szBuf); + { + PStr d = szBuf; + PCStr s = p; + for (; (UBYTE)*s > ' '; d++, s++) + *d = *s; + *d = '\0'; + } /* The driver is loaded at the top of allocated memory. */ /* The device driver is paragraph aligned. */ - eb.load.reloc = eb.load.load_seg = base; + { + exec_blk eb; + eb.load.reloc = eb.load.load_seg = base; - CfgDbgPrintf(("Loading device driver %s at segment %04x\n", szBuf, 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; + ret = init_DosExec(3, &eb, szBuf); + if (ret != SUCCESS) + { + CfgFailure(p); + return ret; + } } - strcpy(szBuf, pLine); + strcpy(szBuf, p); /* uppercase the device driver command */ - strupr(szBuf); + /* add \r\n to the command line */ + strcat(strupr(szBuf), " \r\n"); /* 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 */ @@ -1871,41 +1424,35 @@ STATIC BOOL LoadDevice(BYTE * pLine, char FAR *top, COUNT mode) /* 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; + ofs_t next = 0; + do + { + struct dhdr FAR *dhp = MK_PTR(struct dhdr, base, next); + /* init_device returns FALSE on SUCCESS, TRUE otherwise */ + ret = init_device(dhp, szBuf, mode, &top); + if (ret) break; + + next = 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; + } while (next != 0xffff); } - /* might have been the UMB driver or DOS=UMB */ - if (UmbState == 2) - umb_init(); + /* might have been the UMB driver -> try UMB initialization */ + umb_init(); - return result; + return ret; } -STATIC VOID CfgFailure(BYTE * pLine) +STATIC void CfgFailure(PCStr p) { - 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"); + printf("Error in %s line %d:\n" + "%s\n", configfile, nCfgLine, szLine); + gotoxy(p - szLine, screeny()); + say("^\n"); } struct submcb @@ -1917,46 +1464,43 @@ struct submcb char name[8]; }; -void FAR * KernelAllocPara(size_t nPara, char type, char *name, int mode) +void _seg * KernelAllocPara(size_t nPara, UBYTE type, CStr name, int mode) { - seg base, start; - struct submcb FAR *p; - - /* if no umb available force low allocation */ - if (UmbState != 1) - mode = 0; + seg_t base, start; + struct submcb _seg *p; - if (mode) + if (mode && UmbState == UMB_DONE) { base = umb_base_seg; - start = umb_start; + start = umb_base_start; } else { + mode = 0; base = base_seg; start = LoL->first_mcb; } /* create the special DOS data MCB if it doesn't exist yet */ - CfgDbgPrintf(("kernelallocpara: %x %x %x %c %d\n", start, base, nPara, type, mode)); + 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); + mcb _seg *p = MK_SEG_PTR(mcb, base); + mcb_init(++base, p->m_size, p->m_type); + mumcb_init(FP_SEG(p), 1); p->m_name[1] = 'D'; } nPara++; - mcb_init(base + nPara, para2far(base)->m_size - nPara, para2far(base)->m_type); - para2far(start)->m_size += nPara; + mcb_init(base + nPara, MK_SEG_PTR(mcb, base)->m_size - nPara + 1, + MK_SEG_PTR(mcb, base)->m_type); + MK_SEG_PTR(mcb, start)->m_size += nPara; - p = (struct submcb FAR *)para2far(base); + p = MK_SEG_PTR(struct submcb, base); p->type = type; p->start = FP_SEG(p)+1; - p->size = nPara-1; + p->size = nPara - 1; if (name) fmemcpy(p->name, name, 8); base += nPara; @@ -1964,25 +1508,26 @@ void FAR * KernelAllocPara(size_t nPara, char type, char *name, int mode) umb_base_seg = base; else base_seg = base; - return MK_FP(FP_SEG(p)+1, 0); + return MK_SEG_PTR(void, FP_SEG(p) + 1); } -void FAR * KernelAlloc(size_t nBytes, char type, int mode) +void _seg * KernelAlloc(size_t nBytes, UBYTE type, int mode) { - void FAR *p; - size_t nPara = (nBytes + 15)/16; + void _seg *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); + /* note: lpTop is already para-aligned */ + p = alignNextPara(lpTop = MK_FP(FP_SEG(lpTop) - nPara, FP_OFF(lpTop))); } else { p = KernelAllocPara(nPara, type, NULL, mode); } - fmemset(p, 0, nBytes); + + fmemset(p, 0x0, nBytes); return p; } @@ -1997,93 +1542,88 @@ STATIC BYTE FAR * KernelAllocDma(WORD bytes, char type) } #endif -STATIC void FAR * AlignParagraph(VOID FAR * lpPtr) +void _seg * alignNextPara(CVFP p) { - 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 */ + seg_t seg = FP_OFF(p); + if (seg) + seg = (seg - 1) / 16 + 1; + seg += FP_SEG(p); - /* and return an adddress adjusted to the nearest paragraph */ - /* boundary. */ - return MK_FP(uSegVal, 0); + /* return an address adjusted to the nearest paragraph boundary */ + return MK_SEG_PTR(void, seg); } #endif -STATIC int iswh(unsigned char c) +STATIC PCStr skipwh(PCStr s) { - return (c == '\r' || c == '\n' || c == '\t' || c == ' '); + s--; + do + s++; + while (*s == ' ' || *s == '\t'); + return s; } -STATIC BYTE * skipwh(BYTE * s) +STATIC PCStr scanword(PCStr s, PStr d) { - while (iswh(*s)) - ++s; + s = skipwh(s); + while (*s >= 'a' && *s <= 'z' || + *s >= 'A' && *s <= 'Z') + *d++ = *s++; + *d = '\0'; return s; } -STATIC BYTE * scan(BYTE * s, BYTE * d, int fMenuSelect) +STATIC PCStr scanverb(PCStr s, PStr d) { - askThisSingleCommand = FALSE; - DontAskThisSingleCommand = FALSE; - - s = skipwh(s); + askCommand &= ~(ASK_ASK | ASK_NOASK); + line_choices = 0xffff; /* statement in all menus */ - MenuLine = 0; + for (;; s++) + { + s = skipwh(s); - /* only check at beginning of line, ie when looking for - menu selection line applies to. Fixes issue where - value after = starts with number, eg shell=4dos */ - /* does the line start with "123?" */ + if (*s == '!') /* "!dos" ? */ + askCommand |= ASK_NOASK; - if (fMenuSelect && isnum(*s)) - { - unsigned numbers = 0; - for ( ; isnum(*s); s++) - numbers |= 1 << (*s -'0'); + else if (*s == '?') /* "?device" ? */ + askCommand |= ASK_ASK; - if (*s == '?') + else { - MenuLine = numbers; - Menus |= numbers; - s = skipwh(s+1); - } - } + UBYTE ch = *s - (UBYTE)'0'; + if (ch <= 9) /* "123?device" ? */ + { + PCStr p = s; + unsigned digits = 0; + do + { + digits |= 1 << ch; + ch = *++p - (UBYTE)'0'; + } while (ch <= 9); + if (*p != '?') + break; - /* !dos=high,umb ?? */ - if (*s == '!') - { - DontAskThisSingleCommand = TRUE; - s = skipwh(s+1); - } + s = p; + line_choices = digits; + all_choices |= digits; + } + else + break; + } /* else */ + } /* for */ + + s = scanword(s, d); - if (*s == ';') + if (*s == '?') /* "device?" ? */ { - /* semicolon is a synonym for rem */ - *d++ = *s++; + askCommand |= ASK_ASK; + 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) { @@ -2093,31 +1633,36 @@ STATIC char toupper(char c) } /* Convert string s to uppercase */ -STATIC VOID strupr(char *s) +static PStr strupr(PStr s) { - while (*s) { - *s = toupper(*s); - s++; + PStr d = s; + for (;; d++) + { + char ch = *d; + if (ch == '\0') + break; + *d = toupper(ch); } + return s; } /* The following code is 8086 dependant */ #if 1 /* ifdef KERNEL */ -STATIC VOID mcb_init_copy(UCOUNT seg, UWORD size, mcb *near_mcb) +STATIC void mcb_init_copy(seg_t seg, size_t size, mcb *near_mcb) { - near_mcb->m_size = size; - fmemcpy(MK_FP(seg, 0), near_mcb, sizeof(mcb)); + near_mcb->m_size = size - 1; + fmemcpy(MK_SEG_PTR(mcb, seg), near_mcb, sizeof(mcb)); } -STATIC VOID mcb_init(UCOUNT seg, UWORD size, BYTE type) +STATIC void mcb_init(seg_t seg, size_t 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 void mumcb_init(seg_t seg, size_t size) { static mcb near_mcb = { MCB_NORMAL, @@ -2129,20 +1674,22 @@ STATIC VOID mumcb_init(UCOUNT seg, UWORD size) } #endif -char *strcat(register char * d, register const char * s) +static PStr strcat(PStr d, PCStr s) { strcpy(d + strlen(d), s); return d; } /* compare two ASCII strings ignoring case */ -STATIC char strcaseequal(const char * d, const char * s) +STATIC char strcasediff(PCStr d, PCStr s) { - char ch; - while ((ch = toupper(*s++)) == toupper(*d++)) - if (ch == '\0') - return 1; - return 0; + while (toupper(*s) == toupper(*d)) + { + if (*s == '\0') + return 0; + s++, d++; + } + return 1; } /* @@ -2155,29 +1702,27 @@ 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 */ + /* 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 */ + if (wantedbuffers < 6) /* min 6 buffers */ wantedbuffers = 6; - if (wantedbuffers > 99) /* max 99 buffers */ + 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 */ + if (buffers < wantedbuffers) /* not less than requested */ buffers = wantedbuffers; LoL->nbuffers = buffers; LoL->inforecptr = &LoL->firstbuf; { size_t bytes = sizeof(struct buffer) * buffers; - pbuffer = HMAalloc(bytes); - - if (pbuffer == NULL) + if ((pbuffer = HMAalloc(bytes)) == NULL) { pbuffer = KernelAlloc(bytes, 'B', 0); if (HMAState == HMA_DONE) @@ -2186,15 +1731,16 @@ STATIC void config_init_buffers(int wantedbuffers) else { LoL->bufloc = LOC_HMA; - /* space in HMA beyond requested buffers available as user space */ + + /* space in HMA beyond requested buffers available as user space */ firstAvailableBuf = pbuffer + wantedbuffers; } } LoL->deblock_buf = DiskTransferBuffer; LoL->firstbuf = pbuffer; - CfgDbgPrintf(("init_buffers (size %u) at", sizeof(struct buffer))); - CfgDbgPrintf((" (%p)", LoL->firstbuf)); + DebugPrintf(("init_buffers (size %u) at (%p)", + sizeof(struct buffer), pbuffer)); buffers--; pbuffer->b_prev = FP_OFF(pbuffer + buffers); @@ -2205,603 +1751,410 @@ STATIC void config_init_buffers(int wantedbuffers) pbuffer->b_next = FP_OFF(pbuffer + 1); pbuffer++; pbuffer->b_prev = FP_OFF(pbuffer - 1); - } - while (--i); + } 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")); - CfgDbgPrintf((" done\n")); - - if (FP_SEG(pbuffer) == 0xffff) + if (FP_SEG(pbuffer) == /*HMASEG*/0xFFFF) { buffers++; - if (InitKernelConfig.Verbose >= 0) - { - printf("Kernel: allocated %d Diskbuffers = %u Bytes in HMA\n", + 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) +STATIC void config_init_fnodes(int f_nodes_cnt) { - UNREFERENCED_PARAMETER(pLine); - ReturnAnyDosVersionExpected = TRUE; + struct f_node FAR *p; + size_t bytes; + + /* number of allocated files */ + LoL->f_nodes_cnt = f_nodes_cnt; + bytes = f_nodes_cnt * sizeof(struct f_node); + + p = HMAalloc(bytes); + if (p == NULL) + p = KernelAlloc(bytes, 'F', 0); + LoL->f_nodes = p; } /* - 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) + Undocumented feature: + Format: ANYDOS [=] + will report to MSDOS programs just the version number + they expect. be careful with it! */ -STATIC VOID SetIdleHalt(BYTE * pLine) +STATIC void SetAnyDos(PCStr p) { - COUNT haltlevel; - if (GetNumArg(pLine, &haltlevel)) - HaltCpuWhileIdle = haltlevel; /* 0 for no HLT, 1..n more, -1 max */ + UNREFERENCED_PARAMETER(p); + ReturnAnyDosVersionExpected = TRUE; } -STATIC VOID CfgIgnore(BYTE * pLine) +/* Format: EECHO string */ +STATIC void CfgMenuEsc(PCStr p) { - UNREFERENCED_PARAMETER(pLine); + char ch; + do + { + ch = *p; p++; + if (ch == '\0') + ch = '\n'; + if (ch == '$') /* translate $ to ESC */ + ch = ESC; + printf("%c", ch); + } while (ch != '\n'); } /* - 'MENU'ing stuff - although it's worse then MSDOS's , its better then nothing + 'MENU'ing stuff + although it's worse then MSDOS's , its better then nothing + Menu selection bar struct: + x pos, y pos, string */ -STATIC void ClearScreen(unsigned char attr); -STATIC VOID CfgMenu(BYTE * pLine) +static struct MenuSelector { - int nLen; - BYTE *pNumber = pLine; + unsigned x, y; + UBYTE len; + char text[80]; +} MenuStruct[10] BSS_INIT({0}); - printf("%s\n",pLine); - if (MenuColor == -1) - return; - - pLine = skipwh(pLine); +static unsigned nextMenuRow BSS_INIT(0); - /* skip drawing characters in cp437, which is what we'll have - just after booting! */ - while ((unsigned char)*pLine >= 0xb0 && (unsigned char)*pLine < 0xe0) - pLine++; +/* Format: MENU string */ +/* Format: ECHO string */ +STATIC void CfgMenu(PCStr p) +{ + struct MenuSelector *menu; + UBYTE ch; + unsigned len; + int spaces; - pLine = skipwh(pLine); /* skip more whitespaces... */ + say2("%s\n", p); + nextMenuRow++; - /* now I'm expecting a number here if this is a menu-choice line. */ - if (isnum(pLine[0])) + /* find digit */ + for (len = 0;; p++, len++) { - 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 */ + ch = *p; + if (ch == '\0') + return; + ch -= (UBYTE)'0'; + if (ch <= 9) + break; } - nMenuLine++; + + menu = &MenuStruct[ch]; + menu->x = len; /* start position of digit */ + menu->y = nextMenuRow - 1; + + /* copy menu text (up to null or 10+ spaces) */ + len = 0; + do + { + ch = *p; + if (ch == '\0') + break; + menu->text[len] = ch; + p++, len++; + if (ch > ' ') + { + menu->len = len; + spaces = 11; + } + } while (--spaces && len < sizeof menu->text - 1); + menu->text[menu->len] = '\0'; } -STATIC VOID CfgMenuEsc(BYTE * pLine) +STATIC void SelectLine(unsigned i) { - BYTE * check; - for (check = pLine; check[0]; check++) - if (check[0] == '$') check[0] = 27; /* translate $ to ESC */ - printf("%s\n",pLine); + struct MenuSelector *menu = MenuStruct; + do + { + if (menu->len) + { + UBYTE attr = MenuColor; + if (i == 0) /* selected line? */ + /* swap colors and clear blinking attribute */ + attr = ((attr << 4) | (attr >> 4)) & 0x7f; + + /* redraw line */ + ClearScreenArea(attr, menu->x, menu->y, menu->len, 1); + say2("%s", menu->text); + } + menu++, i--; + } while (menu < ENDOF(MenuStruct)); } -STATIC VOID DoMenu(void) +static unsigned show_choices(unsigned choicey) { - iregs r; - int key = -1; - if (Menus == 0) - return; + unsigned x; + UBYTE i; - InitKernelConfig.SkipConfigSeconds = -1; - - if (MenuColor == -1) - Menus |= 1 << 0; /* '0' Menu always allowed */ - - nMenuLine+=2; /* use this to position "select menu" text (ypos): */ - - for (;;) + gotoxy(2, choicey); + say("Enter a choice: ["); + x = 19; /* =strlen(" Enter a choice: [") */ + i = 0; + do { - int i, j; - -RestartInput: - - if (MenuColor != -1) + if (testbit(all_choices, i)) { - 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 */ + if (i < last_choice) + x++; + printf("%c", (UBYTE)'0' + i); } + i++; + } while (i <= 9); + say("]"); + return x; +} - 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); +STATIC VOID DoMenu(void) +{ + unsigned choicey; + say("\n\n\n"); /* make sure there are 3 free lines */ + choicey = screeny() - 2; - if (MenuTimeout >= 0) - printf("- %d \b", MenuTimeout); - else - printf(" \b\b\b\b\b"); + gotoxy(0, screenbottom()); + say2("F5=Bypass startup files F8=Confirm each line of %s/AUTOEXEC.BAT", + configfile); - if (MenuColor != -1) - printf("\r\n\n "); - else - printf(" -"); + for (;;) + { + unsigned key; + UBYTE c; - printf(" Singlestepping (F8) is: %s \r", singleStep ? "ON " : "OFF"); + gotoxy(75, screenbottom()); + say(askCommand & ASK_TRACE ? "[Y]" : "[N]"); - key = GetBiosKey(MenuTimeout >= 0 ? 1 : -1); + if (MenuColor && nextMenuRow + 1 == choicey) + SelectLine(last_choice); /* invert color of selected line */ - if (key == -1) /* timeout, take default */ + if (MenuTimeout >= 0) { - if (MenuTimeout > 0) + show_choices(choicey); + printf(" Time remaining: %d ", MenuTimeout); + + gotoxy(show_choices(choicey), choicey); + key = GetBiosKey(1); /* poll keyboard 1 second */ + if (key == 0) { + if (MenuTimeout == 0) + break; /* timeout, take default */ MenuTimeout--; - goto RestartInput; + continue; } - 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(MenuSelected 10) + last_choice = 10;*/ + MenuTimeout = numarg; } - ClearScreen((bg << 4) | fg); -} - -/********************************************************************************* - National specific things. - this handles only Date/Time/Currency, and NOT codepage things. - Some may consider this a hack, but I like to see 24 Hour support. tom. -*********************************************************************************/ - -#define _DATE_MDY 0 /* mm/dd/yy */ -#define _DATE_DMY 1 /* dd.mm.yy */ -#define _DATE_YMD 2 /* yy/mm/dd */ - -#define _TIME_12 0 -#define _TIME_24 1 - -struct CountrySpecificInfoSmall { - short CountryID; /* = W1 W437 # Country ID */ - char DateFormat; /* Date format: 0/1/2: U.S.A./Europe/Japan */ - char CurrencyString[3]; /* '$' ,'EUR' */ - char ThousandSeparator; /* ',' # Thousand's separator */ - char DecimalPoint; /* '.' # Decimal point */ - char DateSeparator; /* '-' */ - char TimeSeparator; /* ':' */ - char CurrencyFormat; /* = 0 # Currency format (bit array) */ - char CurrencyPrecision; /* = 2 # Currency precision */ - char TimeFormat; /* = 0 # time format: 0/1: 12/24 houres */ -}; - -struct CountrySpecificInfoSmall specificCountriesSupported[] = { -#include "../country/kernel.tb1" -}; +} -STATIC int LoadCountryInfoHardCoded(COUNT ctryCode) +/* Format: MENUCOLOR [=] foreground [, background] */ +STATIC void CfgMenuColor(PCStr p) { - struct CountrySpecificInfoSmall *country; - - /* printf("cntry: %u, CP%u, file=\"%s\"\n", ctryCode, codePage, filename); */ - - - - for (country = specificCountriesSupported; - country < specificCountriesSupported + LENGTH(specificCountriesSupported); - country++) - { - if (country->CountryID == 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++) + if (GetNumArg2(p, 0)) { - printf("%u ", country->CountryID); + UBYTE attr = (UBYTE)((numarg << 4) | numarg1); + if (attr == 0) + attr = 0x07; /* white on black */ + MenuColor = attr; } - 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) +STATIC void free(seg_t seg) { - _CmdInstall(pLine,0x80); /* load high, if possible */ + iregs r; + r.ES = seg; + r.AH = 0x49; /* free memory */ + init_call_intr(0x21, &r); } -STATIC VOID CmdChain(BYTE * pLine) -{ - struct CfgFile *cfg; - int fd; - InstallPrintf(("CHAIN: %s\n", pLine)); - if (nCurChain >= MAX_CHAINS) { - CfgFailure(pLine); - return; - } - if ((fd = open(pLine, 0)) < 0) { - CfgFailure(pLine); - return; - } - cfg = &cfgFile[nCurChain++]; - cfg->nFileDesc = nFileDesc; - cfg->nCfgLine = nCfgLine; - nFileDesc = fd; - nCfgLine = 0; +/* set memory allocation strategy */ +STATIC void set_strategy(UBYTE strat) +{ + iregs r; + r.BL = strat; + r.AX = 0x5801; + init_call_intr(0x21, &r); } -STATIC VOID InstallExec(struct instCmds *icmd) +/* Format: INSTALL [=] command */ +/* Format: INSTALLHIGH [=] command */ +STATIC void _CmdInstall(PCStr p, int mode) { - BYTE filename[128], *args, *d, *cmd = icmd->buffer; + CommandTail args; + PStr pf; + unsigned len; exec_blk exb; - InstallPrintf(("installing %s\n",cmd)); - - cmd=skipwh(cmd); - - for (args = cmd, d = filename; ;args++,d++) + for (pf = szBuf;; p++, pf++) { - *d = *args; - if (*d <= 0x020 || *d == '/') + UBYTE ch = *p; + if (ch <= ' ' || ch == '/') break; + *pf = ch; } - *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; - + *pf = '\0'; - InstallPrintf(("cmd[%s] args [%u,%s]\n",filename,*args,args+1)); + len = strlen(p); + if (len > sizeof args.ctBuffer - 2) + len = sizeof args.ctBuffer - 2; /* trim too long line */ + args.ctCount = (UBYTE)len; + args.ctBuffer[len] = '\r'; + args.ctBuffer[len+1] = '\0'; + memcpy(args.ctBuffer, p, len); - if (init_DosExec(icmd->mode, &exb, filename) != SUCCESS) - { - CfgFailure(cmd); - } -} + set_strategy(mode); + exb.exec.env_seg = DOS_PSP + 8; + exb.exec.cmd_line = &args; + /*exb.exec.fcb_1 = exb.exec.fcb_2 = NULL;*/ /* unimportant */ -STATIC void free(seg segment) -{ - iregs r; + DebugPrintf(("cmd[%s] args [%u,%s]\n", szBuf, args.ctCount, args.ctBuffer)); - r.a.b.h = 0x49; /* free memory */ - r.es = segment; - init_call_intr(0x21, &r); + if (init_DosExec(mode, &exb, szBuf) != SUCCESS) + CfgFailure(p); } -/* set memory allocation strategy */ -STATIC void set_strategy(unsigned char strat) -{ - iregs r; +STATIC void CmdInstall(PCStr p) { _CmdInstall(p, 0); } - r.a.x = 0x5801; - r.b.b.l = strat; - init_call_intr(0x21, &r); -} +STATIC void CmdInstallHigh(PCStr p) { _CmdInstall(p, 0x80); } VOID DoInstall(void) { - int i; - unsigned short installMemory; - struct instCmds *cmd; + seg_t kernel; - 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 + /* grab memory for this install code: + we are executing somewhere at top of memory and 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); + kernel = allocmem(((unsigned)_init_end + ebda_size + 15) / 16); - InstallPrintf(("allocated memory at %x\n",installMemory)); + DebugPrintf(("Installing commands now (kernel at %X)\n", kernel)); + + DoConfig_(); - 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); + free(kernel); - InstallPrintf(("Done with installing commands\n")); - return; + DebugPrintf(("Done with installing commands\n")); } -STATIC BYTE far * searchvar(const BYTE * name, int length) -{ - BYTE far * pp = master_env; - do { - if (!fmemcmp(name, pp, length + 1)) { - return pp; - } - pp += fstrlen(pp) + 1; - } while (*pp); - return NULL; -} +/* master_env copied over command line area in + DOS_PSP, thus its size limited to 128 bytes */ +/* static char master_env[128] = "PATH=."; */ -STATIC void deletevar(BYTE far * pp) { - int variablelength; - if (NULL == pp) - return; - variablelength = fstrlen(pp) + 1; - fmemcpy(pp, pp + variablelength, (unsigned)(envp + 3 - (pp + variablelength))); - /* our fmemcpy always copies forwards */ - envp -= variablelength; - return; -} + /* !!! dirty hack: because bug in old FreeCOM, which wrongly + process empty environment in MS-DOS style, garbage empty + environment by dummy variable: --avb + */ +static PStr envp = master_env + 7; /* sizeof("PATH=.") + 1 zero */ -STATIC VOID CmdSet(BYTE *pLine) +/* Format: SET var = string */ +STATIC void CmdSet(PCStr p) { - pLine = GetStringArg(pLine, szBuf); - pLine = skipwh(pLine); /* scan() stops at the equal sign or space */ - if (*pLine == '=') /* equal sign is required */ + PStr q; + p = skipwh(scanword(p, szBuf)); + if (*p != '=') /* equal sign is required */ + { + CfgFailure(p); + return; + } + + /* environment variables must be uppercase */ + strcat(strupr(szBuf), "="); + + { + PStr pm = master_env; /* find duplication */ + for (q = pm; pm < envp; q = pm) + { + PCStr v = szBuf; + while (*v == *pm) /* compare variables */ + v++, pm++; + while (*++pm); /* find end of definition */ + pm++; + if (*v == '\0') /* variable found? */ + { + while (pm < envp) + *q++ = *pm++; /* remove duplication */ + break; + } + } /* for */ + } + + p = skipwh(p + 1); + if (*p) /* add new definition? */ { - int size, oldsize, namesize; - BYTE far * pp; - strupr(szBuf); /* all environment variables must be uppercase */ - namesize = strlen(szBuf); - strcat(szBuf, "="); - pp = searchvar(szBuf, namesize); - pLine = skipwh(++pLine); - strcat(szBuf, pLine); /* append the variable value (may include spaces) */ - size = strlen(szBuf); - if (size == namesize + 1) { - /* empty variable ? then just delete. (cannot fail) */ - deletevar(pp); + size_t sz = strlen(strcat(szBuf, p)) + 1; + + /* environment ends by empty ASCIIZ (one null character) */ + if (sz >= master_env + sizeof master_env - q) + { + CfgFailure(p); + say("Out of environment space\n"); return; } - if (pp) { - oldsize = fstrlen(pp) + 1; - } else { - oldsize = 0; - } - if (size < master_env + sizeof(master_env) - (envp - oldsize) - 1 - 2) - { /* must end with two consequtive zeros */ - deletevar(pp); /* now that there's enough space, actually delete */ - fstrcpy(envp, szBuf); - envp += size + 1; /* add next variables starting at the second zero */ - *envp = 0; - envp[1] = 0; - envp[2] = 0; - /* The word marker after last variable should not equal 1, - to indicate that there is no executable pathname following. */ - } - else - printf("Master environment is full - can't add \"%s\"\n", szBuf); + strcpy(q, szBuf); + q += sz; } - else - printf("Invalid SET command: \"%s\"\n", szBuf); + + envp = q; + *q = '\0'; /* "add" empty ASCIIZ string */ + fmemcpy(MK_PTR(char, DOS_PSP + 8, 0), master_env, q + 1 - master_env); } diff --git a/kernel/config.h b/kernel/config.h index 9dbd3066..f9404115 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -29,17 +29,16 @@ struct config { /* Configuration variables */ UBYTE cfgDosDataUmb; - BYTE cfgBuffers; /* number of buffers in the system */ + 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 */ + char cfgShell[256]; /* SHELL= line */ UBYTE cfgLastdrive; /* last drive */ UBYTE cfgLastdriveHigh; - BYTE cfgStacks; /* number of stacks */ - BYTE cfgStacksHigh; + 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 index 40a397c2..cf2fd1a3 100644 --- a/kernel/console.asm +++ b/kernel/console.asm @@ -161,8 +161,6 @@ CommonNdRdExit: ; *** tell if key waiting and return its ASCII if yes add ah,[cs:_kbdType] int 16h ; Get status, if zf=0 al=char jz ConNdRd4 ; Jump if no char available - or ax,ax ; Also check for ax=0 as apparently some - jz ConNdRd4 ; int16h handlers set ax=0 to indicate unsupported function call checke0 ; check for e0 scancode or ax,ax ; Zero ? jnz ConNdRd1 ; Jump if not zero @@ -226,8 +224,7 @@ ConWr1: loop ConWr1 ; Loop if more to output jmp _IOExit -global _CBreak ; int 0x1B handler -_CBreak: +CBreak: mov byte [cs:uScanCode],3 ; Put a ^C into the buffer IntRetn: iret @@ -266,14 +263,9 @@ _int29_handler: pop ax iret %IFDEF DEBUG_PRINT_COMPORT -%ifnum DEBUG_PRINT_COMPORT -%define DEBUG_USE_COMPORT DEBUG_PRINT_COMPORT -%else -%define DEBUG_USE_COMPORT 1 ; default to COM2 if not specified -%endif .comprint: push dx - mov dx, DEBUG_USE_COMPORT ; 0=COM1,1=COM2,2=COM3,3=COM4 + mov dx, 1 ; 0=COM1,1=COM2,2=COM3,3=COM4 mov ah, [cs:ASYNC_NEED_INIT] or ah,ah diff --git a/kernel/country.asm b/kernel/country.asm new file mode 100644 index 00000000..56764529 --- /dev/null +++ b/kernel/country.asm @@ -0,0 +1,4734 @@ +; 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$ + +; 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 162; 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 +__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 +_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,0," ",",",".",",",3,2,_24; Bulgaria Lucho +bg_872 cnf 359,872,DMY,0D0h,0EBh,0,0,0," ",",",".",",",3,2,_24; Bulgaria Lucho +bg_850 cnf 359,850,DMY,"B","G","L",0,0," ",",",".",",",3,2,_24; Bulgaria +bg_858 cnf 359,858,DMY,"B","G","L",0,0," ",",",".",",",3,2,_24; Bulgaria +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, 259, 250, 252, 252, 253, 254, 255 + +ucase_872 equ ucase_855 + +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_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 + +; 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 + +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 + +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 + +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 + +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 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 deleted file mode 100644 index 2197a7f7..00000000 --- a/kernel/cpu.asm +++ /dev/null @@ -1,90 +0,0 @@ -; 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 - ; NEC V20/V30 support 186 instructions but - ; do not mask the shift count like a 186. - ; based on https://hg.pushbx.org/ecm/ldebug/file/7f3440d5824d/source/init.asm#l3071 - ; which is based on http://www.textfiles.com/hamradio/v20_bug.txt - mov ax, sp ; we use stack to do test - mov cx, 0 ; after pop still 0 if 8088/8086 - push cx - inc cx ; after pop still 1 if NEC V20/V30 - ; next instructions may lock system if breakpoint or trace flag set - db 8Fh, 0C1h; pop r/m16 with operand cx on 808x, nop on NEC V20/V30 - mov sp, ax ; reset stack to known good state (pre push, optional pop) - or cx, cx ; cx is 0 if 808x, 1 if NEC - jz is808x ; if not NEC then goto test for 808x vs 8018x - mov bx, cx ; treat NEC V20/V30 as 8018x, i.e. return 1 - jmp short cleanup -is808x: - 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 index 312cbfa1..2fdc86cc 100644 --- a/kernel/dosfns.c +++ b/kernel/dosfns.c @@ -27,9 +27,14 @@ /****************************************************************/ #include "portab.h" +#include "debug.h" + +#ifdef VERSION_STRINGS +static BYTE *dosfnsRcsId = + "$Id$"; +#endif #include "globals.h" -#include "debug.h" /* /// Added for SHARE. - Ron Cemer */ @@ -42,7 +47,7 @@ BYTE share_installed = 0; code, so DOS simply negates this value and returns it in AX. */ extern int ASMPASCAL - share_open_check(const char FAR * filename, /* pointer to fully qualified filename */ + 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... */ @@ -82,13 +87,6 @@ extern int ASMPASCAL unsigned long len, /* length (in bytes) of region to lock or unlock */ int unlock); /* one to unlock; zero to lock */ - /* DOS calls this to see if share already has the file marked as open. - Returns: - 1 if open - 0 if not */ -extern int ASMPASCAL - share_is_file_open(const char far * filename); - /* /// End of additions for SHARE. - Ron Cemer */ STATIC int remote_lock_unlock(sft FAR *sftp, /* SFT for file */ @@ -96,51 +94,42 @@ STATIC int remote_lock_unlock(sft FAR *sftp, /* SFT for file */ unsigned long len, /* length (in bytes) of region to lock or unlock */ int unlock); /* one to unlock; zero to lock */ -struct cds FAR *get_cds_unvalidated(unsigned drive) +/* get current directory structure for drive + return NULL if the CDS is not valid or the + drive is not within range, on input drv is + 0 for default or 1=A,2=B,... +*/ +struct cds FAR *get_cds1(unsigned drv) { - if (drive >= lastdrive) - return NULL; - return &CDSp[drive]; + if (drv-- == 0) /* get default drive or convert to 0 = A:, 1 = B:, ... */ + drv = default_drive; + return get_cds(drv); } -/* 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) { - DebugPrintf(("%u >= %u\n", drive, lastdrive)); + if (drive >= lastdrive) return NULL; - } cdsp = &CDSp[drive]; flags = cdsp->cdsFlags; - DebugPrintf(("flags=%0x valid=%04x, join=%04x, net=%04x, DPB is NULL?%d\n", flags, flags & CDSVALID, flags & CDSJOINED, flags & CDSNETWDRV, (cdsp->cdsDpb == NULL)?0:1)); /* 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) + if ((flags & CDSVALID) == 0 || + (flags & CDSJOINED) != 0 || + (flags & CDSNETWDRV) == 0 && 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); + cdsp = get_cds(drive == 0 ? default_drive : drive - 1); if (cdsp == NULL) { @@ -159,6 +148,15 @@ struct dpb FAR * GetDriveDPB(UBYTE drive, COUNT * rc) } #endif +/* Construct dir-style filename for ASCIIZ 8.3 name */ +STATIC VOID DosGetFile(BYTE * lpszPath, BYTE FAR * lpszDosFileName) +{ + char fcbname[FNAME_SIZE + FEXT_SIZE]; + + ParseDosName(lpszPath, fcbname, FALSE); + fmemcpy(lpszDosFileName, fcbname, FNAME_SIZE + FEXT_SIZE); +} + int idx_to_sft_(int SftIndex) { /*called from below and int2f/ax=1216*/ @@ -275,7 +273,7 @@ long DosRWSft(int sft_idx, size_t n, void FAR * bp, int mode) /* Test for eof and exit */ /* immediately if it is */ - if (!(s->sft_flags & SFT_FEOF)) + if (!(s->sft_flags & SFT_FEOF) || (s->sft_flags & SFT_FNUL)) return 0; if (s->sft_flags & SFT_FCONIN) @@ -301,41 +299,50 @@ long DosRWSft(int sft_idx, size_t n, void FAR * bp, int mode) /* a block transfer */ /* /// Added for SHARE - Ron Cemer */ - if (IsShareInstalled(FALSE) && (s->sft_shroff >= 0)) + if (IsShareInstalled() && (s->sft_shroff >= 0)) { - /* sft_shroff is file_table index in share */ 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); + { + long XferCount = rwblock(s->sft_status, bp, n, mode); + if (XferCount < 0) + return XferCount; + if (mode == XFR_WRITE) + s->sft_size = dos_getfsize(s->sft_status); + s->sft_posit += XferCount; + return XferCount; + } } -COUNT SftSeek2(int sft_idx, LONG new_pos, unsigned mode, UDWORD * p_result) +int SftSeek(int sft_idx, LONG new_pos, unsigned mode) +{ + return _SftSeek(idx_to_sft(sft_idx), new_pos, mode); +} + +int _SftSeek(sft FAR *s, 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) + if (mode > SEEK_END) /* 2 */ 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 */ + if (s->sft_flags & SFT_FSHARED) { + if (mode == SEEK_CUR) + { + new_pos += s->sft_posit; + } + /* seek from end of file */ + else if (mode == SEEK_END) + { /* * RB list has it as Note: * this function is called by the DOS 3.1+ kernel, but only when seeking @@ -346,43 +353,33 @@ COUNT SftSeek2(int sft_idx, LONG new_pos, unsigned mode, UDWORD * p_result) * 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; + if (s->sft_mode & (O_DENYREAD | O_DENYNONE)) + new_pos = remote_lseek(s, new_pos); + else + new_pos += s->sft_size; + } + } + /* Do special return for character devices */ + else if (s->sft_flags & SFT_FDEVICE) + { + new_pos = 0; + } + else + { + if ((new_pos = dos_lseek(s->sft_status, new_pos, mode)) < 0) + return (int)new_pos; } s->sft_posit = new_pos; - *p_result = new_pos; return SUCCESS; } -COUNT SftSeek(int sft_idx, LONG new_pos, unsigned mode) -{ - UDWORD result; - return SftSeek2(sft_idx, new_pos, mode, &result); -} - -ULONG DosSeek(unsigned hndl, LONG new_pos, COUNT mode, int *rc) -{ - int sft_idx = get_sft_idx(hndl); - UDWORD result; - - /* Get the SFT block that contains the SFT */ - *rc = SftSeek2(sft_idx, new_pos, mode, &result); - if (*rc == SUCCESS) - return result; - 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); + return FP_OFF(r) == 0 ? DE_TOOMANY : r - q; } STATIC sft FAR *get_free_sft(COUNT * sft_idx) @@ -436,17 +433,6 @@ const char FAR *get_root(const char FAR * fname) return fname; } -STATIC void ConvertPathNameToFCBName(char *FCBName, const char *PathName) -{ - ConvertNameSZToName83(FCBName, (char *)FP_OFF(get_root(PathName))); - FCBName[FNAME_SIZE + FEXT_SIZE] = '\0'; -} - -STATIC void set_fcbname(void) -{ - ConvertPathNameToFCBName(DirEntBuffer.dir_name, PriPathName); -} - /* initialize SFT fields (for open/creat) for character devices */ STATIC int DeviceOpenSft(struct dhdr FAR *dhp, sft FAR *sftp) { @@ -521,13 +507,19 @@ long DosOpenSft(char FAR * fname, unsigned flags, unsigned attrib) result = truename(fname, PriPathName, CDS_MODE_CHECK_DEV_PATH); if (result < SUCCESS) + { + DFnsDbgPrintf(("DosOpenSft: truename failed\n")); return result; - - set_fcbname(); + } + else DFnsDbgPrintf(("DosOpenSft: truename succeeded\n")); /* now get a free system file table entry */ if ((sftp = get_free_sft(&sft_idx)) == (sft FAR *) - 1) + { + DFnsDbgPrintf(("DosOpenSft: file table full\n")); return DE_TOOMANY; + } + else DFnsDbgPrintf(("DosOpenSft: obtained sft entry\n")); fmemset(sftp, 0, sizeof(sft)); @@ -538,23 +530,14 @@ long DosOpenSft(char FAR * fname, unsigned flags, unsigned attrib) sftp->sft_shroff = -1; /* /// Added for SHARE - Ron Cemer */ sftp->sft_attrib = attrib = attrib | D_ARCHIVE; - /* check for a (local) device */ - DebugPrintf(("result for %Fs is %s%s%s%s",fname,(result & IS_DEVICE)?"device ":"X",(result & IS_NETWORK)?"network ":"N",(dhp = IsDevice(fname)) != NULL?"IsDevice!=NULL ":"=")); - if ((result & IS_DEVICE) && !(result & IS_NETWORK) && (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; - } + DFnsDbgPrintf(("DosOpenSft: mode=%02X, flags=%02X, attrib=%02X\n", \ + sftp->sft_mode, OpenMode, attrib)); if (result & IS_NETWORK) { int status; unsigned cmd; + DFnsDbgPrintf(("DosOpenSft: IS_NETWORK\n")); if ((flags & (O_TRUNC | O_CREAT)) == O_CREAT) attrib |= 0x100; @@ -583,51 +566,79 @@ long DosOpenSft(char FAR * fname, unsigned flags, unsigned attrib) return status; } - /* 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; + /* 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 + */ + DFnsDbgPrintf(("DosOpenSft: IS_DEVICE\n")); + if (rc < SUCCESS) + return rc; + return sft_idx; + } /* /// Added for SHARE. - Ron Cemer */ - if (IsShareInstalled(TRUE)) + if (IsShareInstalled()) { - DebugPrintf(("Share installed - open_check(%s)\n", PriPathName)); + DFnsDbgPrintf(("DosOpenSft: using SHARE\n")); if ((sftp->sft_shroff = share_open_check(PriPathName, cu_psp, flags & 0x03, (flags >> 4) & 0x07)) < 0) return sftp->sft_shroff; } - else - { - DebugPrintf(("Share NOT installed - open_check(%s)\n", PriPathName)); - } - + /* /// End of additions for SHARE. - Ron Cemer */ - sftp->sft_count++; - sftp->sft_flags = PriPathName[0] - 'A'; - result = dos_open(PriPathName, flags, attrib, sft_idx); - DebugPrintf(("dos_open(%s) returned %i\n", PriPathName, result)); - if (result < 0) + /* NEVER EVER allow directories to be created */ + /* ... though FCB's are weird :) */ + if (!(flags & O_FCB) && + (attrib & ~(D_RDONLY | D_HIDDEN | D_SYSTEM | D_ARCHIVE | D_VOLID))) + { + DFnsDbgPrintf(("DosOpenSft: invalid request\n")); + return DE_ACCESS; + } + + result = dos_open(PriPathName, flags, attrib); + DFnsDbgPrintf(("DosOpenSft: dos_open returned %02X\n", result)); + if (result >= 0) + { + int status = (int)(result >> 16); + if (status == S_OPENED) + { + sftp->sft_attrib = dos_getfattr_fd((COUNT)result); + /* Check permissions. -- JPP + (do not allow to open volume labels/directories) */ + if (sftp->sft_attrib & (D_DIR | D_VOLID)) + { + DFnsDbgPrintf(("DosOpenSft: closing, invalid attributes DIR|VOLID\n")); + dos_close((COUNT)result); + return DE_ACCESS; + } + sftp->sft_size = dos_getfsize((COUNT)result); + } + sftp->sft_status = (COUNT)result; + sftp->sft_flags = PriPathName[0] - 'A'; + sftp->sft_count += 1; + DosGetFile(PriPathName, sftp->sft_name); + dos_getftime(sftp->sft_status, + (date FAR *) & sftp->sft_date, + (time FAR *) & sftp->sft_time); + DFnsDbgPrintf(("DosOpenSft: returning %lu (decimal)\n", (sft_idx | ((long)status << 16)))); + return sft_idx | ((long)status << 16); + } + else { /* /// Added for SHARE *** CURLY BRACES ADDED ALSO!!! ***. - Ron Cemer */ - /* if we allocated a share slot above, but open failed, free slot */ - if (sftp->sft_shroff >= 0) /* SHARE installed status can't change since check above */ + if (IsShareInstalled()) { 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) @@ -699,16 +710,21 @@ COUNT DosForceDup(unsigned OldHandle, unsigned NewHandle) } /* 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; + if ((Sftp->sft_flags & (SFT_FDEVICE | SFT_FSHARED)) + || (Sftp->sft_status >= 0)) + { + p->ps_filetab[NewHandle] = p->ps_filetab[OldHandle]; + /* possible hazard: integer overflow ska*/ + Sftp->sft_count += 1; + return SUCCESS; + } + else + return DE_INVLDHNDL; } 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; @@ -719,10 +735,15 @@ COUNT DosCloseSft(int sft_idx, BOOL commitonly) */ if (sftp->sft_flags & SFT_FSHARED) { - /* DebugPrintf(("closing SFT %d = %p\n",sft_idx,sftp)); */ + /* printf("closing SFT %d = %p\n",sft_idx,sftp); */ return network_redirector_fp(commitonly ? REM_FLUSH: REM_CLOSE, sftp); } + /* now just drop the count if a device, else */ + /* call file system handler */ + if (!commitonly) + sftp->sft_count -= 1; + if (sftp->sft_flags & SFT_FDEVICE) { if (sftp->sft_dev->dh_attr & SFT_FOCRM) @@ -732,68 +753,62 @@ COUNT DosCloseSft(int sft_idx, BOOL commitonly) */ struct dhdr FAR *dev = sftp->sft_dev; if (BinaryCharIO(&dev, 0, MK_FP(0x0000, 0x0000), C_CLOSE) != SUCCESS) - return DE_INVLDHNDL; + return DE_ACCESS; } - /* 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; + if (commitonly || sftp->sft_count > 0) + return dos_commit(sftp->sft_status); /* /// Added for SHARE *** CURLY BRACES ADDED ALSO!!! ***. - Ron Cemer */ - if (sftp->sft_count == 1 && IsShareInstalled(TRUE)) + if (IsShareInstalled()) { 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; + return dos_close(sftp->sft_status); } 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; + COUNT ret; /* Get the SFT block that contains the SFT */ - return DosCloseSft(sft_idx, FALSE); + ret = DosCloseSft(get_sft_idx(hndl), FALSE); + if (ret != DE_INVLDHNDL && ret != DE_ACCESS) + p->ps_filetab[hndl] = 0xff; + return ret; } +/* get disk free space (in terms of free clusters and cluster size) + input: drive specifies which disk to obtain information about, + where 0=default, 1=A,2=B,... + navc, bps, and nc are pointers to uninitialized variables + used to hold the result, where + navc is count of available [free] clusters + bps is bytes per sector + nc is total number of clusters + returns the number of sectors per cluster or on error -1 + */ 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[5]; /* add space for SI, although it's unused here */ UWORD spc; - /* first check for valid drive */ - spc = -1; - cdsp = get_cds1(drive); - - if (cdsp == NULL) - return spc; + /* first check for valid drive */ + if ((cdsp = get_cds1(drive)) == NULL) + return -1; - current_ldt = cdsp; if (cdsp->cdsFlags & CDSNETWDRV) { + COUNT rg[4]; if (remote_getfree(cdsp, rg) != SUCCESS) - return spc; + return -1; /* for int21/ah=1c: Undoc DOS says, its not supported for @@ -802,21 +817,15 @@ UWORD DosGetFree(UBYTE drive, UWORD * navc, UWORD * bps, UWORD * nc) 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; + *bps = rg[2]; + *nc = rg[1]; + if (navc) + *navc = rg[3]; + return rg[0]; } - dpbp = cdsp->cdsDpb; - if (dpbp == NULL) - return spc; + if ((dpbp = cdsp->cdsDpb) == NULL) + return -1; if (navc == NULL) { @@ -824,25 +833,25 @@ UWORD DosGetFree(UBYTE drive, UWORD * navc, UWORD * bps, UWORD * nc) 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); + return -1; + + /* 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) + /* now tell fs to give us free cluster count */ + if (navc) nfree = dos_free(dpbp); + + /* we shift ntotal until it is equal to or below 0xfff6 */ while (ntotal > FAT_MAGIC16 && cluster_size < 0x8000) { cluster_size <<= 1; @@ -850,101 +859,63 @@ UWORD DosGetFree(UBYTE drive, UWORD * navc, UWORD * bps, UWORD * nc) 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; + *nc = ntotal > FAT_MAGIC16 ? FAT_MAGIC16 : (UWORD) ntotal; + if (navc) + *navc = nfree > FAT_MAGIC16 ? FAT_MAGIC16 : (UWORD) 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; + /* now tell fs to give us free cluster count */ + if (navc) + *navc = (UWORD) dos_free(dpbp); 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; + if (*nc > FAT_MAGIC16 / 2) + *nc = FAT_MAGIC16; + else + *nc <<= 1; + if (navc) + if (*navc > FAT_MAGIC16 / 2) + *navc = FAT_MAGIC16; + else + *navc <<= 1; } return spc; } #ifdef WITHFAT32 +/* network names like \\SERVER\C aren't supported yet */ #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[5]; + 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); + if (IS_SLASH(DriveString[0]) || !IS_SLASH(DriveString[2]) + || DriveString[1] != ':') + return DE_INVLDDRV; + + cdsp = get_cds(DosUpFChar(*DriveString) - 'A'); - /* - 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 */ + if (cdsp == NULL) return DE_INVLDDRV; if (cdsp->cdsFlags & CDSNETWDRV) { - /* Try redirector extension */ - if (remote_getfree_11a3(cdsp, rg) != SUCCESS) - { - /* Fallback */ - 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 /* Supports extension */ - { - UDWORD total, avail; - UDWORD bps, spc; - - bps = rg[4]; - spc = 1; - total = (((UDWORD)rg[0] << 16UL) | rg[1]); - avail = (((UDWORD)rg[2] << 16UL) | rg[3]); - - while (total > 0x00ffffffUL && spc < 128) { - spc *= 2; - avail /= 2; - total /= 2; - } - while (total > 0x00ffffffUL && bps < 32768UL) { - bps *= 2; - avail /= 2; - total /= 2; - } + if (remote_getfree(cdsp, rg) != SUCCESS) + return DE_INVLDDRV; - xfsp->xfs_secsize = bps; - xfsp->xfs_clussize = spc; - xfsp->xfs_totalclusters = total; - xfsp->xfs_freeclusters = avail; - } + xfsp->xfs_clussize = rg[0]; + xfsp->xfs_totalclusters = rg[1]; + xfsp->xfs_secsize = rg[2]; + xfsp->xfs_freeclusters = rg[3]; } else { @@ -953,7 +924,7 @@ COUNT DosGetExtFree(BYTE FAR * DriveString, struct xfreespace FAR * xfsp) return DE_INVLDDRV; xfsp->xfs_secsize = dpbp->dpb_secsize; xfsp->xfs_totalclusters = - (ISFAT32(dpbp) ? dpbp->dpb_xsize : dpbp->dpb_size) - 1; + (ISFAT32(dpbp) ? dpbp->dpb_xsize : dpbp->dpb_size); xfsp->xfs_freeclusters = dos_free(dpbp); xfsp->xfs_clussize = dpbp->dpb_clsmask + 1; } @@ -963,64 +934,80 @@ COUNT DosGetExtFree(BYTE FAR * DriveString, struct xfreespace FAR * xfsp) xfsp->xfs_freesectors = xfsp->xfs_freeclusters * xfsp->xfs_clussize; xfsp->xfs_datasize = sizeof(struct xfreespace); + fmemset(xfsp->xfs_reserved, 0, 8); + 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'; + BYTE *cp; + struct cds FAR *cdsp; - DebugPrintf(("CWD [%s]\n", path)); - if (truename(path, PriPathName, CDS_MODE_SKIP_PHYSICAL) < SUCCESS) + /* next - "log" in the drive */ + /* first check for valid drive */ + cdsp = get_cds(drive == 0 ? default_drive : drive - 1); + if (cdsp == NULL) return DE_INVLDDRV; - /* skip d:\ */ - fstrcpy(s, PriPathName + 3); + fmemcpy(&TempCDS, cdsp, sizeof(TempCDS)); + cp = TempCDS.cdsCurrentPath; + /* ensure termination of fstrcpy */ + cp[MAX_CDSPATH - 1] = '\0'; + + if ((TempCDS.cdsFlags & CDSNETWDRV) == 0) + { + /* dos_cd ensures that the path exists; if not, we + need to change to the root directory */ + int result = dos_cd(cp); + if (result == DE_PATHNOTFND) + cp[TempCDS.cdsBackslashOffset + 1] = + cdsp->cdsCurrentPath[TempCDS.cdsBackslashOffset + 1] = '\0'; + else if (result < SUCCESS) + return result; + } + + cp += TempCDS.cdsBackslashOffset; + if (*cp == '\0') + s[0] = '\0'; + else + fstrcpy(s, cp + 1); + return SUCCESS; } COUNT DosChangeDir(BYTE FAR * s) { COUNT result; + BYTE FAR *p; + + /* don't do wildcard CHDIR --TE */ + for (p = s; *p; p++) + if (*p == '*' || *p == '?') + return DE_PATHNOTFND; -#if defined(CHDIR_DEBUG) - DebugPrintf(("DosChangeDir: %Fs\n", s)); -#endif result = truename(s, PriPathName, CDS_MODE_CHECK_DEV_PATH); if (result < SUCCESS) { -#if defined(CHDIR_DEBUG) - DebugPrintf(("truename error: 0x%04x\n", result)); -#endif - return DE_PATHNOTFND; + return result; } - set_fcbname(); - if ((FP_OFF(current_ldt) != 0xFFFF) && (strlen(PriPathName) >= sizeof(current_ldt->cdsCurrentPath))) return DE_PATHNOTFND; #if defined(CHDIR_DEBUG) - DebugPrintf(("Remote Chdir: n='%Fs' p='%s\n", s, PriPathName)); + 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) - DebugPrintf(("status = %04x, new_path='%Fs'\n", result, current_ldt->cdsCurrentPath)); + printf("status = %04x, new_path='%Fs'\n", result, cdsd->cdsCurrentPath); #endif - /* on error result should be negative, on success for network call value - should be ignored as some redirectors e.g. Lantastic return count on success */ - if (result < SUCCESS) + if (result != SUCCESS) return result; /* Copy the path to the current directory @@ -1029,6 +1016,7 @@ COUNT DosChangeDir(BYTE FAR * s) 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); @@ -1038,34 +1026,29 @@ COUNT DosChangeDir(BYTE FAR * s) return SUCCESS; } -STATIC int pop_dmp(int rc, dmatch FAR * dmp) +STATIC int pop_dmp(int rc, dmatch FAR * save_dta) { - dta = dmp; + dta = save_dta; 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); + fmemcpy(save_dta, &sda_tmp_dm, 21 /*offsetof(save_dta->dm_attr_fnd)*/ ); + save_dta->dm_attr_fnd = SearchDir.dir_attrib; + save_dta->dm_time = SearchDir.dir_time; + save_dta->dm_date = SearchDir.dir_date; + save_dta->dm_size = SearchDir.dir_size; + ConvertName83ToNameSZ(save_dta->dm_name, SearchDir.dir_name); } return rc; } -COUNT DosFindFirst(UCOUNT attr, BYTE FAR * name) +COUNT DosFindFirst(UCOUNT attr, const char FAR * name) { - int rc; - register dmatch FAR *dmp = dta; - - DebugPrintf(("DosFindFirst(%Fs, 0x%04x)\n", name, attr)); - rc = truename(name, PriPathName, - CDS_MODE_CHECK_DEV_PATH | CDS_MODE_ALLOW_WILDCARDS); + dmatch FAR *save_dta = dta; + int rc = truename(name, PriPathName, + CDS_MODE_CHECK_DEV_PATH | CDS_MODE_ALLOW_WILDCARDS); if (rc < SUCCESS) return rc; - set_fcbname(); - /* /// Added code here to do matching against device names. DOS findfirst will match exact device names if the filename portion (excluding the extension) contains @@ -1077,7 +1060,7 @@ COUNT DosFindFirst(UCOUNT attr, BYTE FAR * name) SAttr = (BYTE) attr; #if defined(FIND_DEBUG) - DebugPrintf(("Remote Find: n='%Fs\n", PriPathName)); + printf("Remote Find: n='%Fs\n", PriPathName); #endif dta = &sda_tmp_dm; @@ -1085,34 +1068,36 @@ COUNT DosFindFirst(UCOUNT attr, BYTE FAR * name) if (rc & IS_NETWORK) rc = network_redirector_fp(REM_FINDFIRST, current_ldt); - else if (rc & IS_DEVICE && !(attr & D_VOLID)) /* DEVICE can't be a volume label */ + 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); + p = (const char *)get_root(PriPathName); for (i = 0; i < FNAME_SIZE && *p && *p != '.'; i++) SearchDir.dir_name[i] = *p++; + for (; i < FNAME_SIZE + FEXT_SIZE; i++) + SearchDir.dir_name[i] = ' '; rc = SUCCESS; /* /// End of additions. - Ron Cemer ; heavily edited - Bart Oldeman */ } else rc = dos_findfirst(attr, PriPathName); - return pop_dmp(rc, dmp); + return pop_dmp(rc, save_dta); } COUNT DosFindNext(void) { - COUNT rc; - register dmatch FAR *dmp = dta; + dmatch FAR *save_dta = dta; + + /* findnext will always fail on a device name or volume id */ + if (save_dta->dm_attr_fnd & (D_DEVICE | D_VOLID)) + return DE_NFILES; /* * The new version of SHSUCDX 1.0 looks at the dm_drive byte to @@ -1132,24 +1117,16 @@ COUNT DosFindNext(void) * (12h, DE_NFILES) */ #if 0 - DebugPrintf(("findnext: %d\n", dmp->dm_drive)); + printf("findnext: %d\n", save_dta->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_drive & 0x80) && sda_tmp_dm.dm_entry == 0xffff)) - return DE_NFILES; - + fmemcpy(dta = &sda_tmp_dm, save_dta, 21 /*offsetof(save_dta->dm_attr_fnd)*/ ); 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); + return pop_dmp(sda_tmp_dm.dm_drive & 0x80 + ? network_redirector_fp(REM_FINDNEXT, &sda_tmp_dm) + : dos_findnext(), save_dta); } -COUNT DosGetFtime(COUNT hndl, ddate * dp, dtime * tp) +COUNT DosGetFtime(COUNT hndl, date * dp, time * tp) { sft FAR *s; /*sfttbl FAR *sp;*/ @@ -1158,12 +1135,19 @@ COUNT DosGetFtime(COUNT hndl, ddate * dp, dtime * tp) if (FP_OFF(s = get_sft(hndl)) == (size_t) - 1) return DE_INVLDHNDL; - *dp = s->sft_date; - *tp = s->sft_time; - return SUCCESS; + /* If SFT entry refers to a device, return the date and time of opening */ + if (s->sft_flags & (SFT_FDEVICE | SFT_FSHARED)) + { + *dp = s->sft_date; + *tp = s->sft_time; + return SUCCESS; + } + + /* call file system handler */ + return dos_getftime(s->sft_status, dp, tp); } -COUNT DosSetFtimeSft(int sft_idx, ddate dp, dtime tp) +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); @@ -1179,7 +1163,11 @@ COUNT DosSetFtimeSft(int sft_idx, ddate dp, dtime tp) s->sft_date = dp; s->sft_time = tp; - return SUCCESS; + if (s->sft_flags & SFT_FSHARED) + return SUCCESS; + + /* call file system handler */ + return dos_setftime(s->sft_status, dp, tp); } COUNT DosGetFattr(BYTE FAR * name) @@ -1202,14 +1190,40 @@ COUNT DosGetFattr(BYTE FAR * name) if (PriPathName[3] == '\0') return 0x10; - set_fcbname(); - if (result & IS_NETWORK) return network_redirector(REM_GETATTRZ); if (result & IS_DEVICE) return DE_FILENOTFND; +/* /// Use truename()'s result, which we already have in PriPathName. + I copy it to tmp_name because PriPathName is global and seems + to get trashed somewhere in transit. + The reason for using truename()'s result is that dos_?etfattr() + are very low-level functions and don't handle full path expansion + or cleanup, such as converting "c:\a\b\.\c\.." to "C:\A\B". + - Ron Cemer +*/ +/* + memcpy(SecPathName,PriPathName,sizeof(SecPathName)); + return dos_getfattr(SecPathName, attrp); +*/ + /* no longer true. dos_getfattr() is + A) intelligent (uses dos_open) anyway + B) there are some problems with MAX_PARSE, i.e. if PATH ~= 64 + and TRUENAME adds a C:, which leeds to trouble. + + the problem was discovered, when VC did something like + + fd = DosOpen(filename,...) + jc can't_copy_dialog; + + attr = DosGetAttrib(filename); + jc can't_copy_dialog; + and suddenly, the filehandle stays open + shit. + tom + */ return dos_getfattr(PriPathName); } @@ -1224,25 +1238,23 @@ COUNT DosSetFattr(BYTE FAR * name, UWORD attrp) if (result < SUCCESS) return result; - set_fcbname(); - if (result & IS_NETWORK) return remote_setfattr(attrp); if (result & IS_DEVICE) return DE_FILENOTFND; - DebugPrintf(("DosSetFattr(%s)\n", name)); - 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); - } +/* /// Use truename()'s result, which we already have in PriPathName. + I copy it to tmp_name because PriPathName is global and seems + to get trashed somewhere in transit. + - Ron Cemer +*/ +/* + memcpy(SecPathName,PriPathName,sizeof(SecPathName)); + return dos_setfattr(SecPathName, attrp); + + see DosGetAttr() +*/ return dos_setfattr(PriPathName, attrp); } @@ -1264,17 +1276,12 @@ COUNT DosDelete(BYTE FAR * path, int attrib) if (result < SUCCESS) return result; - set_fcbname(); - if (result & IS_NETWORK) return network_redirector(REM_DELETE); if (result & IS_DEVICE) return DE_FILENOTFND; - if (IsShareInstalled(TRUE) && share_is_file_open(PriPathName)) - return DE_ACCESS; - return dos_delete(PriPathName, attrib); } @@ -1287,9 +1294,6 @@ COUNT DosRenameTrue(BYTE * path1, BYTE * path2, int attrib) if (FP_OFF(current_ldt) == 0xFFFF || (current_ldt->cdsFlags & CDSNETWDRV)) return network_redirector(REM_RENAME); - if (IsShareInstalled(TRUE) && share_is_file_open(path1)) - return DE_ACCESS; - return dos_rename(path1, path2, attrib); } @@ -1308,8 +1312,6 @@ COUNT DosRename(BYTE FAR * path1, BYTE FAR * path2) if (result < SUCCESS) return result; - set_fcbname(); - if ((result & (IS_NETWORK | IS_DEVICE)) == IS_DEVICE) return DE_FILENOTFND; @@ -1324,8 +1326,6 @@ COUNT DosMkRmdir(const char FAR * dir, int action) if (result < SUCCESS) return result; - set_fcbname(); - if (result & IS_NETWORK) return network_redirector(action == 0x39 ? REM_MKDIR : REM_RMDIR); @@ -1349,7 +1349,7 @@ COUNT DosLockUnlock(COUNT hndl, LONG pos, LONG len, COUNT unlock) return remote_lock_unlock(s, pos, len, unlock); /* Invalid function unless SHARE is installed or remote. */ - if (!IsShareInstalled(FALSE)) + if (!IsShareInstalled()) return DE_INVLDFUNC; /* Lock violation if this SFT entry does not support locking. */ @@ -1401,7 +1401,6 @@ struct dhdr FAR *IsDevice(const char FAR * fname) ((*froot=='.') && ((*(froot+1)=='\0') || (*(froot+2)=='\0' && *(froot+1)=='.'))) ) { - DebugPrintf(("root is blank\n")); return NULL; } @@ -1412,11 +1411,9 @@ struct dhdr FAR *IsDevice(const char FAR * fname) if (!(dhp->dh_attr & ATTR_CHAR)) /* if this is block device, skip */ continue; - DebugPrintf(("checking filename\n")); for (i = 0; i < FNAME_SIZE; i++) { unsigned char c1 = (unsigned char)froot[i]; - DebugPrintf(("%c",c1)); /* ignore extensions and handle filenames shorter than FNAME_SIZE */ if (c1 == '.' || c1 == '\0') { @@ -1433,29 +1430,21 @@ struct dhdr FAR *IsDevice(const char FAR * fname) break; } - DebugPrintf(("\ni=%d\n", i)); /* if found a match then return device header */ if (i == FNAME_SIZE) return dhp; } - DebugPrintf(("Not device\n")); 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) +BOOL IsShareInstalled(void) { extern unsigned char ASMPASCAL share_check(void); - /*DebugPrintf(("Share_check at %p and share_installed at %p\n", (void far *)&share_check, (void far *)&share_installed));*/ - if (recheck == FALSE) - return share_installed; - if (share_check() == 0xff) + if (!share_installed && share_check() == 0xff) share_installed = TRUE; - else - share_installed = FALSE; return share_installed; } @@ -1469,10 +1458,7 @@ COUNT DosTruename(const char FAR *src, char FAR *dest) */ COUNT rc = truename(src, PriPathName, CDS_MODE_ALLOW_WILDCARDS); if (rc >= SUCCESS) - { fstrcpy(dest, PriPathName); - set_fcbname(); - } return rc; } diff --git a/kernel/dosidle.asm b/kernel/dosidle.asm index 9c21e63a..aa5326d6 100644 --- a/kernel/dosidle.asm +++ b/kernel/dosidle.asm @@ -34,32 +34,17 @@ PSP_USERSS equ 30h segment HMA_TEXT global _DosIdle_int - global _DosIdle_hlt - extern _InDOS - extern _cu_psp - extern _MachineId - extern critical_sp - extern _user_r - ; variables as the following are "part of" module inthndlr.c - ; because of the define MAIN before include globals.h there! - extern _HaltCpuWhileIdle - extern _DGROUP_ + + extern _InDOS:wrt DGROUP + extern _cu_psp:wrt DGROUP + extern _MachineId:wrt DGROUP + extern critical_sp:wrt DGROUP + extern _user_r: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 @@ -91,6 +76,3 @@ Do_DosI: pop ax ret -; segment _DATA ; belongs to DGROUP -; whatever db whatever - diff --git a/kernel/dosnames.c b/kernel/dosnames.c new file mode 100644 index 00000000..c474d7df --- /dev/null +++ b/kernel/dosnames.c @@ -0,0 +1,128 @@ +/****************************************************************/ +/* */ +/* dosnames.c */ +/* DOS-C */ +/* */ +/* Generic parsing functions for file name specifications */ +/* */ +/* 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 *dosnamesRcsId = + "$Id$"; +#endif + +#include "globals.h" + +const char _DirWildNameChars[] = "*?./\\\"[]:|<>+=;,"; + +STATIC BOOL charOK(const char *s, const char c) +{ + return (UBYTE)c >= ' ' && !strchr(s, c); +} + +/* + MSD durring an FindFirst search string looks like this; + (*), & (.) == Current directory *.* + (\) == Root directory *.* + (..) == Back one directory *.* + + This always has a "truename" as input, so we may do some shortcuts + + returns number of characters in the directory component (up to the + last backslash, including d:) or negative if error + */ +int ParseDosName(const char *filename, char *fcbname, BOOL bAllowWildcards) +{ + int nDirCnt, nFileCnt, nExtCnt; + const char *lpszLclDir, *lpszLclFile, *lpszLclExt; + + /* Initialize the users data fields */ + nDirCnt = nFileCnt = nExtCnt = 0; + + /* NB: this code assumes ASCII */ + + /* Now see how long a directory component we have. */ + lpszLclDir = lpszLclFile = filename; + filename += 2; + + while (charOK(_DirWildNameChars + 5, *filename)) + if (*filename++ == '\\') + lpszLclFile = filename; + nDirCnt = lpszLclFile - lpszLclDir; + + /* Parse out the file name portion. */ + filename = lpszLclFile; + while (charOK(bAllowWildcards ? _DirWildNameChars + 2 + : _DirWildNameChars, *filename)) + { + ++nFileCnt; + ++filename; + } + + if (nFileCnt == 0) + { + if (bAllowWildcards && *filename == '\0' && + (nDirCnt == 3 || filename[-1] != '\\')) + /* D:\ or D:\DOS but not D:\DOS\ */ + return DE_NFILES; + return DE_PATHNOTFND; + } + + /* Now we have pointers set to the directory portion and the */ + /* file portion. Now determine the existance of an extension. */ + lpszLclExt = filename; + if ('.' == *filename) + { + lpszLclExt = ++filename; + while (*filename) + { + if (charOK(bAllowWildcards ? _DirWildNameChars + 2 + : _DirWildNameChars, *filename)) + { + ++nExtCnt; + ++filename; + } + else + { + return DE_FILENOTFND; + } + } + } + else if (*filename) + return DE_FILENOTFND; + + /* Finally copy whatever the user wants extracted to the user's */ + /* buffers. */ + memset(fcbname, ' ', FNAME_SIZE + FEXT_SIZE); + memcpy(fcbname, lpszLclFile, nFileCnt); + memcpy(&fcbname[FNAME_SIZE], lpszLclExt, nExtCnt); + + /* Clean up before leaving */ + + return nDirCnt; +} + diff --git a/kernel/dsk.c b/kernel/dsk.c index 9703f3ee..a3bb21ae 100644 --- a/kernel/dsk.c +++ b/kernel/dsk.c @@ -27,47 +27,40 @@ #include "portab.h" #include "globals.h" #include "dyndata.h" +#include "debug.h" #ifdef VERSION_STRINGS static BYTE *dskRcsId = - "$Id: dsk.c 1702 2012-02-04 08:46:16Z perditionc $"; + "$Id$"; #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); +void ASMPASCAL fl_readkey(void); +int ASMPASCAL fl_reset(UBYTE drive); +int ASMPASCAL fl_diskchanged(UBYTE drive); +int ASMPASCAL fl_setdisktype(UBYTE drive, WORD type); +int ASMPASCAL fl_setmediatype(UBYTE drive, WORD tracks, WORD sectors); +int ASMPASCAL fl_read (UBYTE drive, WORD, WORD, WORD, WORD, void FAR *); +int ASMPASCAL fl_write (UBYTE drive, WORD, WORD, WORD, WORD, void FAR *); +int ASMPASCAL fl_verify(UBYTE drive, WORD, WORD, WORD, WORD, void FAR *); +int ASMPASCAL fl_format(UBYTE drive, WORD, WORD, WORD, WORD, void FAR *); +int ASMPASCAL fl_lba_ReadWrite(UBYTE drive, WORD mode, + struct _bios_LBA_address_packet FAR *); #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] +#pragma aux (pascal) fl_readkey modify exact [ax] +#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 dx bx] +#pragma aux (pascal) fl_setmediatype modify exact [ax cx dx bx es] +#pragma aux (pascal) fl_read modify exact [ax cx dx bx es] +#pragma aux (pascal) fl_write modify exact [ax cx dx bx es] +#pragma aux (pascal) fl_format modify exact [ax cx dx bx es] +#pragma aux (pascal) fl_verify modify exact [ax cx dx bx es] +#pragma aux (pascal) fl_lba_ReadWrite modify exact [ax 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 */ + ULONG LBA_address, unsigned total, UWORD FAR * transferred); #define LBA_READ 0x4200 #define LBA_WRITE 0x4300 @@ -81,7 +74,7 @@ UWORD LBA_WRITE_VERIFY = 0x4302; this is certainly true, if located somewhere at 0xf+1000 and must hold already during BOOT time */ -UBYTE DiskTransferBuffer[MAX_SEC_SIZE]; +UBYTE DiskTransferBuffer[1 * SEC_SIZE]; struct FS_info { ULONG serialno; @@ -94,74 +87,64 @@ extern struct DynS ASM Dyn; /*TE - array access functions */ ddt *getddt(int dev) { - return &(((ddt *) Dyn.Buffer)[dev]); + return (ddt*)Dyn.Buffer + dev; } -STATIC VOID tmark(ddt *pddt) -{ - pddt->ddt_fh.ddt_lasttime = ReadPCClock(); -} +#define getddt0() ((ddt*)Dyn.Buffer) + +#define tmark(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 N_PART 4 /* number of partitions per partition table */ #define PARTOFF 0x1be -#ifdef PROTO -typedef WORD dsk_proc(rqptr rq, ddt * pddt); -#else -typedef WORD dsk_proc(); -#endif +typedef WORD dsk_proc(rqptr, ddt*); STATIC dsk_proc mediachk, bldbpb, blockio, IoctlQueblk, Genblkdev, Getlogdev, Setlogdev, blk_Open, blk_Close, - blk_Media, blk_noerr, blk_nondr, blk_error; + blk_Media, blk_noerr, blk_nondr; -STATIC WORD getbpb(ddt * pddt); -#ifdef PROTO +STATIC WORD getbpb(ddt*); STATIC WORD dskerr(COUNT); -#else -STATIC WORD dskerr(); -#endif /* */ /* the function dispatch table */ /* */ -static dsk_proc * const dispatch[NENTRY] = +static dsk_proc * const dispatch [] = { - /* 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 */ + /* disk init is done in initdisk.c, so this should never be called */ + NULL, /* 0x00 Initialize */ + mediachk, /* 0x01 Media Check */ + bldbpb, /* 0x02 Build BPB */ + NULL, /* 0x03 Ioctl In */ + blockio, /* 0x04 Input (Read) */ + blk_nondr, /* 0x05 Non-destructive Read */ + blk_noerr, /* 0x06 Input Status */ + blk_noerr, /* 0x07 Input Flush */ + blockio, /* 0x08 Output (Write) */ + blockio, /* 0x09 Output with verify */ + blk_noerr, /* 0x0A Output Status */ + blk_noerr, /* 0x0B Output Flush */ + NULL, /* 0x0C Ioctl Out */ + blk_Open, /* 0x0D Device Open */ + blk_Close, /* 0x0E Device Close */ + blk_Media, /* 0x0F Removable Media */ + blk_noerr, /* 0x10 Output till busy */ + NULL, /* 0x11 undefined */ + NULL, /* 0x12 undefined */ + Genblkdev, /* 0x13 Generic Ioctl Call */ + NULL, /* 0x14 undefined */ + NULL, /* 0x15 undefined */ + NULL, /* 0x16 undefined */ + Getlogdev, /* 0x17 Get Logical Device */ + Setlogdev, /* 0x18 Set Logical Device */ + IoctlQueblk /* 0x19 Ioctl Query */ }; #define hd(x) ((x) & DF_FIXED) @@ -170,68 +153,61 @@ static dsk_proc * const dispatch[NENTRY] = /* F U N C T I O N S --------------------------------------------------- */ /* ----------------------------------------------------------------------- */ -COUNT ASMCFUNC FAR blk_driver(rqptr rp) +int 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) + if (rp->r_command >= LENGTH (dispatch)) + return failure(E_FAILURE); /* general failure */ { - return failure(E_FAILURE); /* general failure */ + dsk_proc *const proc = dispatch [rp->r_command]; + if (proc == NULL) + { + rp->r_count = 0; + return failure(E_FAILURE); /* general failure */ + } + if (rp->r_unit >= blk_dev.dh_name[0]) + return failure(E_UNIT); + return proc (rp, getddt(rp->r_unit)); } - 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 char template_string[] = + "\nInsert diskette for drive :: and press any key when ready\n\n"; +/* 012345678901234567890123456^ */ +#define DRIVE_POS 27 STATIC WORD play_dj(ddt * pddt) { + UBYTE i; + ddt *pddt2; + + if ((pddt->ddt_descflags & (DF_MULTLOG | DF_CURLOG)) != DF_MULTLOG) + return M_NOT_CHANGED; + /* play the DJ ... */ - if ((pddt->ddt_descflags & (DF_MULTLOG | DF_CURLOG)) == DF_MULTLOG) + pddt2 = getddt0() - 1; + i = blk_dev.dh_name[0] + 1; + do { - int i; - ddt *pddt2 = getddt(0); - for (i = 0; i < blk_dev.dh_name[0]; i++, pddt2++) + pddt2++, i--; + if (i == 0) { - 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); + put_string("Error in the DJ mechanism!\n"); /* should not happen! */ + return M_CHANGED; } - return M_CHANGED; - } - return M_NOT_CHANGED; + } while (pddt->ddt_driveno != pddt2->ddt_driveno || + (~pddt2->ddt_descflags & (DF_MULTLOG | DF_CURLOG))); + + template_string[DRIVE_POS] = 'A' + pddt->ddt_logdriveno; + put_string(template_string); + fl_readkey(); + pddt2->ddt_descflags &= ~DF_CURLOG; + pddt->ddt_descflags |= DF_CURLOG; + pokeb(0, 0x504, pddt->ddt_logdriveno); + return M_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; @@ -241,15 +217,22 @@ STATIC WORD diskchange(ddt * pddt) if (pddt->ddt_descflags & DF_CHANGELINE) /* if we can detect a change ... */ { - if ((result = fl_diskchanged(pddt->ddt_driveno)) == 1) + int ret = fl_diskchanged(pddt->ddt_driveno); + if (ret == 1) + { /* check if it has changed... */ return M_CHANGED; - else if (result == 0) + } + if (ret == 0) + { return M_NOT_CHANGED; + } } /* can not detect or error... */ - return tdelay(pddt, 37ul) ? M_DONT_KNOW : M_NOT_CHANGED; + if (tdelay(pddt, 37)) + return M_DONT_KNOW; + return M_NOT_CHANGED; } STATIC WORD mediachk(rqptr rp, ddt * pddt) @@ -263,21 +246,17 @@ STATIC WORD mediachk(rqptr rp, ddt * pddt) else if (pddt->ddt_descflags & DF_DISKCHANGE) { pddt->ddt_descflags &= ~DF_DISKCHANGE; - rp->r_mcretcode = M_DONT_KNOW; + rp->r_mcretcode = M_DONT_KNOW; /* media_check() treats as M_CHANGED but tries flushing buffers 1st */ } - else + else if ((rp->r_mcretcode = diskchange(pddt)) == M_DONT_KNOW) { - 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; - } + /* don't know but can check serial number ... */ + ULONG serialno = pddt->ddt_serialno; + int ret = getbpb(pddt); + if (ret) + return ret; + if (serialno != pddt->ddt_serialno) + rp->r_mcretcode = M_CHANGED; } return S_DONE; } @@ -285,13 +264,10 @@ STATIC WORD mediachk(rqptr rp, ddt * pddt) /* * Read Write Sector Zero or Hard Drive Dos Bpb */ -STATIC WORD RWzero(ddt * pddt, UWORD mode) +STATIC int RWzero(ddt * pddt, UWORD mode) { UWORD done; - - return LBA_Transfer(pddt, mode, - (UBYTE FAR *) DiskTransferBuffer, - pddt->ddt_offset, 1, &done); + return LBA_Transfer(pddt, mode, DiskTransferBuffer, 0, 1, &done); } /* @@ -300,36 +276,32 @@ STATIC WORD RWzero(ddt * pddt, UWORD mode) */ 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++) + UBYTE unit = 0; + if (pddt->ddt_descflags & DF_MULTLOG) { - if (pddt->ddt_driveno == pddt2->ddt_driveno && - (pddt2->ddt_descflags & (DF_MULTLOG | DF_CURLOG)) == - (DF_MULTLOG | DF_CURLOG)) - break; + ddt *pddt2 = getddt0() - 1; + do + pddt2++, unit++; + while (unit < blk_dev.dh_name[0] && + (pddt->ddt_driveno != pddt2->ddt_driveno || + (~pddt2->ddt_descflags & (DF_MULTLOG | DF_CURLOG)))); } - - rp->r_unit = i+1; + rp->r_unit = unit; return S_DONE; } STATIC WORD Setlogdev(rqptr rp, ddt * pddt) { - unsigned char unit = rp->r_unit; + UBYTE unit = rp->r_unit + 1; 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; + if (rp->r_unit) + { + getddt(rp->r_unit - 1)->ddt_descflags &= ~DF_CURLOG; + pddt->ddt_descflags |= DF_CURLOG; + /* UNDOCUMENTED: MS-DOS sets r_unit field both for */ + /* 0x17 (Getlogdev()) and 0x18 (Setlogdev()) functions. */ + rp->r_unit = unit; + } return S_DONE; } @@ -363,48 +335,42 @@ STATIC WORD blk_Media(rqptr rp, ddt * pddt) if (hd(pddt->ddt_descflags)) return S_BUSY | S_DONE; /* Hard Drive */ - else - return S_DONE; /* Floppy */ + 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; + /* 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]); + { + int ret = RWzero(pddt, LBA_READ); + if (ret) + return ret; + } - if (DiskTransferBuffer[0x1fe] != 0x55 - || DiskTransferBuffer[0x1ff] != 0xaa || pbpbarray->bpb_nbyte % 512) + if (getword(DiskTransferBuffer + 0x1fe) != 0xaa55 || + getword(DiskTransferBuffer + BT_BPB) != 512) /* bpb_nbyte */ { /* copy default bpb to be sure that there is no bogus data */ - memcpy(pbpbarray, &pddt->ddt_defbpb, sizeof(bpb)); - return 0; + memcpy(&pddt->ddt_bpb, &pddt->ddt_defbpb, sizeof pddt->ddt_bpb); + return S_DONE; } - pddt->ddt_descflags &= ~DF_NOACCESS; /* set drive to accessible */ + pddt->ddt_descflags &= ~DF_NOACCESS; /* set drive to accessible */ /*TE ~ 200 bytes*/ - memcpy(pbpbarray, &DiskTransferBuffer[BT_BPB], sizeof(bpb)); + memcpy(&pddt->ddt_bpb, DiskTransferBuffer + BT_BPB, sizeof pddt->ddt_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) { + if (memcmp(DiskTransferBuffer + 0x36, "FAT16", 5) == 0 || + memcmp(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. @@ -413,71 +379,62 @@ STATIC WORD getbpb(ddt * pddt) */ { struct FS_info *fs = (struct FS_info *)&DiskTransferBuffer[0x27]; - register BYTE extended_BPB_signature; #ifdef WITHFAT32 - if (pbpbarray->bpb_nfsect == 0) + if (pddt->ddt_bpb.bpb_nfsect == 0) { /* FAT32 boot sector */ fs = (struct FS_info *)&DiskTransferBuffer[0x43]; - /* Extended BPB signature, offset differs for FAT32 vs FAT12/16 */ - extended_BPB_signature = DiskTransferBuffer[0x42]; } - else #endif - extended_BPB_signature = DiskTransferBuffer[0x26]; - - /* 0x29 is usual signature value for serial#,vol label,& fstype; - 0x28 older EBPB signature indicating only serial# is valid */ - if ((extended_BPB_signature == 0x29) || (extended_BPB_signature == 0x28)) - { - pddt->ddt_serialno = getlong(&fs->serialno); - } else { - /* short BPB, no serial # available */ - pddt->ddt_serialno = 0; - } - if (extended_BPB_signature == 0x29) - { - fmemcpy(pddt->ddt_volume, fs->volume, sizeof fs->volume); - fmemcpy(pddt->ddt_fstype, fs->fstype, sizeof fs->fstype); - } else { - /* earlier extended BPB or short BPB, fields not available */ - fmemcpy(pddt->ddt_volume, "NO NAME ", 11); - fmemcpy(pddt->ddt_fstype, "FAT?? ", 8); - } + 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); + printf("BPB_NBYTE = %04x\n" + "BPB_NSECTOR = %02x\n" + "BPB_NRESERVED = %04x\n" + "BPB_NFAT = %02x\n" + "BPB_NDIRENT = %04x\n" + "BPB_NSIZE = %04x\n" + "BPB_MDESC = %02x\n" + "BPB_NFSECT = %04x\n", + pddt->ddt_bpb.bpb_nbyte, + pddt->ddt_bpb.bpb_nsector, + pddt->ddt_bpb.bpb_nreserved, + pddt->ddt_bpb.bpb_nfat, + pddt->ddt_bpb.bpb_ndirent, + pddt->ddt_bpb.bpb_nsize, + pddt->ddt_bpb.bpb_mdesc, + pddt->ddt_bpb.bpb_nfsect); #endif - count = - pbpbarray->bpb_nsize == 0 ? - pbpbarray->bpb_huge : pbpbarray->bpb_nsize; - secs_per_cyl = pbpbarray->bpb_nheads * pbpbarray->bpb_nsecs; + tmark(pddt); - 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); + unsigned secs_per_cyl = pddt->ddt_bpb.bpb_nheads * pddt->ddt_bpb.bpb_nsecs; + if (secs_per_cyl == 0) + return failure(E_FAILURE); - tmark(pddt); + /* this field is problematic for partitions > 65535 cylinders, + in general > 512 GiB. However: we are not using it ourselves. */ + { + unsigned nsize = pddt->ddt_bpb.bpb_nsize; + pddt->ddt_ncyl = (UWORD)(((nsize ? nsize : pddt->ddt_bpb.bpb_huge) - 1) + / secs_per_cyl) + 1; + } + } #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); + printf("BPB_NSECS = %04x\n" + "BPB_NHEADS = %04x\n" + "BPB_HIDDEN = %08lx\n" + "BPB_HUGE = %08lx\n", + pddt->ddt_bpb.bpb_nsecs, + pddt->ddt_bpb.bpb_nheads, + pddt->ddt_bpb.bpb_hidden, + pddt->ddt_bpb.bpb_huge); #endif return 0; @@ -485,11 +442,9 @@ STATIC WORD getbpb(ddt * pddt) STATIC WORD bldbpb(rqptr rp, ddt * pddt) { - WORD result; - - if ((result = getbpb(pddt)) != 0) - return result; - + int ret = getbpb(pddt); + if (ret) + return ret; rp->r_bpptr = &pddt->ddt_bpb; return S_DONE; } @@ -499,63 +454,44 @@ STATIC WORD IoctlQueblk(rqptr rp, ddt * pddt) UNREFERENCED_PARAMETER(pddt); #ifdef WITHFAT32 - if (rp->r_cat == 8 || rp->r_cat == 0x48) + if ((UBYTE)(~0x40 & rp->r_cat) != 8 || /* 0x08,0x48 */ #else - if (rp->r_cat == 8) + 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); + (rp->r_fun != 0x60 && + (UBYTE)(~0x21 & rp->r_fun) != 0x46)) /* 0x46,0x47,0x66,0x67 */ + return failure(E_CMD); + return S_DONE; } -/* read/write block with CHS based off start of drive's partition */ 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); -} - -/* read/write block with CHS based off start of disk drive is on */ -STATIC COUNT GenblockioAbs(ddt * pddt, UWORD mode, WORD head, WORD track, - WORD sector, WORD count, VOID FAR * buffer) -{ - UWORD transferred; + UWORD done; - /* apparently sector is ZERO, not ONE based !!! */ + /* apparently here 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 + - sector, count, &transferred); + ((ULONG) track * pddt->ddt_bpb.bpb_nheads + + head) * pddt->ddt_bpb.bpb_nsecs + sector, + count, &done); } STATIC WORD Genblkdev(rqptr rp, ddt * pddt) { - int ret; unsigned descflags = pddt->ddt_descflags; #ifdef WITHFAT32 - int extended = 0; + unsigned copy_size = sizeof (bpb); - if (rp->r_cat == 0x48) - extended = 1; - else -#endif + if (rp->r_cat != 0x48) + { + if (rp->r_cat != 8) + return failure(E_CMD); + copy_size = BPB_SIZEOF; + } +#else if (rp->r_cat != 8) return failure(E_CMD); +#endif switch (rp->r_fun) { @@ -565,80 +501,68 @@ STATIC WORD Genblkdev(rqptr rp, ddt * pddt) bpb *pbpb; pddt->ddt_type = gblp->gbio_devtype; - pddt->ddt_descflags = (descflags & ~3) | (gblp->gbio_devattrib & 3) - | (DF_DPCHANGED | DF_REFORMAT); + 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; + pbpb = (gblp->gbio_spcfunbit & 1) ? &pddt->ddt_bpb : &pddt->ddt_defbpb; #ifdef WITHFAT32 - fmemcpy(pbpb, &gblp->gbio_bpb, - extended ? sizeof(gblp->gbio_bpb) : BPB_SIZEOF); + fmemcpy(pbpb, &gblp->gbio_bpb, copy_size); #else fmemcpy(pbpb, &gblp->gbio_bpb, sizeof(gblp->gbio_bpb)); #endif - /*pbpb->bpb_nsector = gblp->gbio_nsecs; */ + /*pbpb->bpb_nsector = gblp->gbio_nsecs;*/ break; } - case 0x41: /* write track - CHS is absolute not relative to partition start */ + case 0x41: /* write track */ { struct gblkrw FAR *rw = rp->r_rw; - ret = GenblockioAbs(pddt, LBA_WRITE, rw->gbrw_head, rw->gbrw_cyl, - rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); - if (ret != 0) - return dskerr(ret); + int ret = Genblockio(pddt, LBA_WRITE, rw->gbrw_head, rw->gbrw_cyl, + rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); + if (ret) + return ret; + break; } - break; case 0x42: /* format/verify track */ { struct gblkfv FAR *fv = rp->r_fv; - COUNT tracks; - struct thst { - UBYTE track, head, sector, type; - } *addrfield, afentry; + int ret; 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; + fv->gbfv_spcfunbit = 1; /* "not supported by bios" */ + break; } - if (descflags & DF_DPCHANGED) + + /* first try newer setmediatype function */ + if ((descflags & DF_DPCHANGED) && + (ret = fl_setmediatype(pddt->ddt_driveno, pddt->ddt_ncyl, + pddt->ddt_bpb.bpb_nsecs)) != 0) { - /* 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); + return failure(E_NOTFND); /*dskerr(0xc)*/ } - else if (ret == 0x80) + if (ret == 0x80 || + (fv->gbfv_spcfunbit & 1) && + (ret = fl_read(pddt->ddt_driveno, 0, 0, 1, 1, + DiskTransferBuffer)) != 0) { - fv->gbfv_spcfunbit = 3; /* no disk in drive */ + fv->gbfv_spcfunbit = 3; /* no disk in drive */ return dskerr(ret); } - else if (ret != 0) - /* otherwise, setdisktype */ + /* 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; + unsigned tracks = pddt->ddt_ncyl; + unsigned secs = pddt->ddt_bpb.bpb_nsecs; + UBYTE type = pddt->ddt_type + 1; if (!(tracks == 40 && (secs == 9 || secs == 8) && type < 3)) { /* type 3: 1.2M disk in 1.2M drive */ @@ -651,152 +575,152 @@ STATIC WORD Genblkdev(rqptr rp, ddt * pddt) { /* specified tracks, sectors/track not allowed for drive */ fv->gbfv_spcfunbit = 2; - return dskerr(0xc); + return failure(E_NOTFND); /*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); + fv->gbfv_spcfunbit = 0; /* success */ + break; } - afentry.head++; - if (afentry.head >= pddt->ddt_bpb.bpb_nheads) + { - afentry.head = 0; - afentry.track++; + unsigned cyl = fv->gbfv_cyl; + unsigned head = fv->gbfv_head; + unsigned tracks = fv->gbfv_spcfunbit & 2 ? fv->gbfv_ntracks : 1; + + for (; tracks; tracks--) + { + if (cyl >= pddt->ddt_ncyl) /* ??? remove --avb */ + return failure(E_FAILURE); + { + struct thst { + UBYTE cyl, head, sector, type; + } *addrfield = (struct thst *)DiskTransferBuffer; + unsigned sector = 0; + do + { + sector++; + addrfield->type = 2; /* 512 byte sectors */ + addrfield->cyl = cyl; + addrfield->head = head; + addrfield->sector = sector; + addrfield++; + } while (sector < pddt->ddt_bpb.bpb_nsecs); + } + { + int ret = Genblockio(pddt, LBA_FORMAT, head, cyl, 0, + pddt->ddt_bpb.bpb_nsecs, DiskTransferBuffer); + if (ret) + return ret; + } + if (++head >= pddt->ddt_bpb.bpb_nheads) + { + head = 0; + cyl++; + } + } } - } + fv->gbfv_spcfunbit >>= 1; /* move bit 1 to bit 0 */ + } /* 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); + int ret = Genblockio(pddt, LBA_VERIFY, fv->gbfv_head, fv->gbfv_cyl, 0, + (fv->gbfv_spcfunbit & 1) + ? fv->gbfv_ntracks * pddt->ddt_defbpb.bpb_nsecs + : pddt->ddt_defbpb.bpb_nsecs, + DiskTransferBuffer); + /* !!! ret should be analyzed to fill fv->gbfv_spcfunbit by + 1=function not supported by BIOS + 2=specified tracks, sector/track not allowed for drive + 3=no disk in drive + --avb + */ + if (ret) + return ret; fv->gbfv_spcfunbit = 0; /* success */ + break; } - break; case 0x46: /* set volume serial number */ { - struct Gioc_media FAR *gioc = rp->r_gioc; struct FS_info *fs; - BYTE extended_BPB_signature; - - ret = getbpb(pddt); - if (ret != 0) - return (ret); - - extended_BPB_signature = - DiskTransferBuffer[(pddt->ddt_bpb.bpb_nfsect != 0 ? 0x26 : 0x42)]; - /* return error if media lacks extended BPB with serial # */ - if ((extended_BPB_signature != 0x29) && (extended_BPB_signature != 0x28)) - return failure(E_MEDIA); - - /* otherwise, store serial # in extended BPB */ - fs = (struct FS_info *)&DiskTransferBuffer - [(pddt->ddt_bpb.bpb_nfsect != 0 ? 0x27 : 0x43)]; - fs->serialno = gioc->ioc_serialno; - pddt->ddt_serialno = fs->serialno; - - /* And volume name if BPB supports it */ - if (extended_BPB_signature == 0x29) - { - fmemcpy(fs->volume, gioc->ioc_volume, 11); - fmemcpy(pddt->ddt_volume, fs->volume, 11); - } - + int ret = getbpb(pddt); + if (ret) + return ret; + fs = (struct FS_info *)(pddt->ddt_bpb.bpb_nfsect + ? DiskTransferBuffer + 0x27 + : DiskTransferBuffer + 0x43); + pddt->ddt_serialno = fs->serialno = rp->r_gioc->ioc_serialno; ret = RWzero(pddt, LBA_WRITE); - if (ret != 0) - return (dskerr(ret)); + if (ret) + return ret; + break; } - 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); - } + pddt->ddt_descflags |= DF_NOACCESS; + if (rp->r_ai->AI_Flag) + pddt->ddt_descflags &= ~DF_NOACCESS; break; case 0x60: /* get device parameters */ { struct gblkio FAR *gblp = rp->r_io; bpb *pbpb; + DebugPrintf(("get params entry: spec=%X, type=%X, devattr=%X\n", gblp->gbio_spcfunbit,pddt->ddt_type,descflags)); + 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; + pbpb = (gblp->gbio_spcfunbit & 1) ? &pddt->ddt_bpb : &pddt->ddt_defbpb; + /* Note: last 6 bytes of standard BPB may not be copied for + 0x60 when rp->r_cat==8 in some versions of DOS eg MSDOS5,see rbil */ #ifdef WITHFAT32 - fmemcpy(&gblp->gbio_bpb, pbpb, - extended ? sizeof(gblp->gbio_bpb) : BPB_SIZEOF); + if (rp->r_cat == 0x08) copy_size -= 6; + fmemcpy(&gblp->gbio_bpb, pbpb, copy_size); #else - fmemcpy(&gblp->gbio_bpb, pbpb, sizeof(gblp->gbio_bpb)); + fmemcpy(&gblp->gbio_bpb, pbpb, sizeof(gblp->gbio_bpb)-6); #endif - /*gblp->gbio_nsecs = pbpb->bpb_nsector; */ + /*gblp->gbio_nsecs = pbpb->bpb_nsector;*/ + DebugPrintf(("get params dev spec=%X, type=%X, attrib=%X, media=%X, ncyl=%X\n", + gblp->gbio_spcfunbit, gblp->gbio_devtype, gblp->gbio_devattrib, gblp->gbio_media, gblp->gbio_ncyl)); break; } - case 0x61: /* read track - CHS is absolute on disk not relative to start of partition */ + case 0x61: /* read track */ { struct gblkrw FAR *rw = rp->r_rw; - ret = GenblockioAbs(pddt, LBA_READ, rw->gbrw_head, rw->gbrw_cyl, - rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); - if (ret != 0) - return dskerr(ret); + int ret; + DebugPrintf(("read track: head=%X, cyl=%X, sect=%X, nsecs=%X\n", rw->gbrw_head, rw->gbrw_cyl,rw->gbrw_sector, rw->gbrw_nsecs)); + /*int*/ ret = Genblockio(pddt, LBA_READ, rw->gbrw_head, rw->gbrw_cyl, + rw->gbrw_sector, rw->gbrw_nsecs, rw->gbrw_buffer); + if (ret) + return ret; + break; } - break; case 0x66: /* get volume serial number */ { - struct Gioc_media FAR *gioc = rp->r_gioc; + struct Gioc_media FAR *gioc; + int ret = getbpb(pddt); + if (ret) + return ret; - ret = getbpb(pddt); - if (ret != 0) - return (ret); - - /* Note: getbpb() will initialize extended BPB fields with default values */ + gioc = rp->r_gioc; gioc->ioc_serialno = pddt->ddt_serialno; - fmemcpy(gioc->ioc_volume, pddt->ddt_volume, 11); - fmemcpy(gioc->ioc_fstype, pddt->ddt_fstype, 8); + fmemcpy(gioc->ioc_volume, pddt->ddt_volume, sizeof gioc->ioc_volume); + fmemcpy(gioc->ioc_fstype, pddt->ddt_fstype, sizeof gioc->ioc_fstype); + break; } - break; case 0x67: /* get access flag */ - { - struct Access_info FAR *ai = rp->r_ai; - ai->AI_Flag = descflags & DF_NOACCESS ? 0 : 1; /* bit 9 */ - } + rp->r_ai->AI_Flag = (UBYTE)~(descflags / DF_NOACCESS) & 1; /* bit 9 */ break; default: return failure(E_CMD); @@ -806,12 +730,8 @@ STATIC WORD Genblkdev(rqptr rp, ddt * pddt) STATIC WORD blockio(rqptr rp, ddt * pddt) { - ULONG start, size; - WORD ret; - UWORD done; - + ULONG start; int action; - bpb *pbpb; switch (rp->r_command) { @@ -833,35 +753,24 @@ STATIC WORD blockio(rqptr rp, ddt * pddt) 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; + const bpb *pbpb = hd(pddt->ddt_descflags) ? &pddt->ddt_defbpb : &pddt->ddt_bpb; + ULONG size = (pbpb->bpb_nsize ? pbpb->bpb_nsize : pbpb->bpb_huge); + if (start >= size || rp->r_count > size - start) + 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); + UWORD done; + int ret = LBA_Transfer(pddt, action, rp->r_trans, + start, rp->r_count, &done); + rp->r_count = done; + if (ret) + return 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); @@ -878,13 +787,9 @@ STATIC WORD dskerr(COUNT code) { 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); + return S_ERROR | E_NOTRDY; /* failure(E_NOTRDY); at least on the + INT25 route, 0x8002 is returned */ + return failure(E_CMD); case 3: /* write protect */ return failure(E_WRPRT); @@ -892,14 +797,15 @@ STATIC WORD dskerr(COUNT code) default: if (code & 0x80) /* time-out */ return failure(E_NOTRDY); - else if (code & 0x40) /* seek error */ + if (code & 0x40) /* seek error */ return failure(E_SEEK); - else if (code & 0x10) /* CRC error */ + if (code & 0x10) /* CRC error */ return failure(E_CRC); - else if (code & 0x04) + if (code & 0x04) return failure(E_NOTFND); - else - return failure(E_FAILURE); + + case 2: /* address mark not found - general failure */ + return failure(E_FAILURE); } } @@ -907,34 +813,22 @@ STATIC WORD dskerr(COUNT code) translate LBA sectors into CHS addressing */ -STATIC int LBA_to_CHS(ULONG LBA_address, struct CHS *chs, const ddt * pddt, - const bpb ** ppbpb) +STATIC void LBA_to_CHS(ULONG LBA_address, struct CHS FAR *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) + const bpb *p = hd(pddt->ddt_descflags) ? &pddt->ddt_defbpb : &pddt->ddt_bpb; + unsigned hs = p->bpb_nsecs * p->bpb_nheads; + chs->Cylinder = 0xffffu; + if (hs > hiword(LBA_address)) /* LBA_address < hs * 0x10000ul */ { -#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 = (unsigned)(LBA_address / hs); + hs = (unsigned)(LBA_address % hs); + chs->Head = hs / p->bpb_nsecs; + chs->Sector = hs % p->bpb_nsecs + 1; } - - chs->Cylinder = (UWORD)LBA_address; - chs->Head = hsrem / pbpb->bpb_nsecs; - chs->Sector = hsrem % pbpb->bpb_nsecs + 1; - *ppbpb = pbpb; - return 0; } /* Test for 64K boundary crossing and return count small */ @@ -944,8 +838,8 @@ 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); + 0xffff / SEC_SIZE : + (UWORD)(-dma_off) / SEC_SIZE); return min(count, sectors_to_dma_boundary); } @@ -960,43 +854,22 @@ STATIC unsigned DMA_max_transfer(void FAR * buffer, unsigned count) 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 - + crossing track boundaries (necessary for some BIOS's) 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) + UWORD FAR * 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; @@ -1006,175 +879,114 @@ STATIC int LBA_Transfer(ddt * pddt, UWORD mode, VOID FAR * buffer, if (!hd(pddt->ddt_descflags)) { - UBYTE FAR *int1e_ptr = (UBYTE FAR *)getvec(0x1e); - unsigned char nsecs = (unsigned char)(pddt->ddt_bpb.bpb_nsecs); - + UBYTE FAR *int1e_ptr = (UBYTE FAR *)getvec(0x1e); + UBYTE nsecs = (UBYTE)pddt->ddt_bpb.bpb_nsecs; if (int1e_ptr[4] != nsecs) { int1e_ptr[4] = nsecs; - fl_reset(driveno); + fl_reset(pddt->ddt_driveno); } } - -/* + + LBA_address += pddt->ddt_offset; +/* 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; + return failure(E_CMD); // dskerr(1) } */ buffer = adjust_far(buffer); - for (; totaltodo != 0;) + while (totaltodo) { - count = totaltodo; - if ((pddt->ddt_descflags & DF_DMA_TRANSPARENT) == 0) - { - /* avoid overflowing 64K DMA boundary - for drives that don't handle this transparently */ - count = DMA_max_transfer(buffer, totaltodo); - } + int num_retries; + /* avoid overflowing 64K DMA boundary */ + void FAR *transfer_address = buffer; + unsigned 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; + fmemcpy(DiskTransferBuffer, buffer, 512); } - for (num_retries = 0; num_retries < N_RETRY; num_retries++) + for (num_retries = N_RETRY;;) { - if ((pddt->ddt_descflags & DF_LBA) && mode != LBA_FORMAT) + unsigned error_code; + if (mode != LBA_FORMAT && (pddt->ddt_descflags & DF_LBA)) { + UWORD m; + static struct _bios_LBA_address_packet dap = { + 16, 0, 0, 0, 0, 0, 0 + }; dap.number_of_blocks = count; - dap.buffer_address = transfer_address; - + dap.block_address = LBA_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 + m = mode; + if (mode == LBA_WRITE_VERIFY && !(pddt->ddt_descflags & DF_WRTVERIFY)) { /* verify requested, but not supported */ - error_code = - fl_lba_ReadWrite(driveno, LBA_WRITE, &dap); - + error_code = fl_lba_ReadWrite(pddt->ddt_driveno, LBA_WRITE, &dap); if (error_code == 0) { - error_code = - fl_lba_ReadWrite(driveno, LBA_VERIFY, &dap); + m = LBA_VERIFY; + error_code = fl_lba_ReadWrite(pddt->ddt_driveno, m, &dap); } } + else + error_code = fl_lba_ReadWrite(pddt->ddt_driveno, m, &dap); } else { /* transfer data, using old bios functions */ - const bpb *pbpb; - if (LBA_to_CHS(LBA_address, &chs, pddt, &pbpb)) - return 1; - - /* avoid overflow at end of track */ - - if (chs.Sector + count > (unsigned)pbpb->bpb_nsecs + 1) + struct CHS chs; + LBA_to_CHS(LBA_address, &chs, pddt); + if (chs.Cylinder > 1023u) { - count = pbpb->bpb_nsecs + 1 - chs.Sector; +#ifdef DEBUG + printf("IO error: cylinder (%u) > 1023\n", chs.Cylinder); +#else + put_string("IO error: cylinder > 1023\n"); +#endif + return failure(E_CMD); /*dskerr(1)*/ } + /* avoid overflow at end of track */ + if (count > pddt->ddt_bpb.bpb_nsecs + 1 - chs.Sector) + 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); - + mode == LBA_FORMAT ? fl_format : fl_write) + (pddt->ddt_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, + error_code = fl_verify(pddt->ddt_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; - } + fl_reset(pddt->ddt_driveno); + if (--num_retries == 0) + return dskerr(error_code); + } /* end of retries */ /* copy to user buffer if nesessary */ if (transfer_address == DiskTransferBuffer && (mode & 0xff00) == (LBA_READ & 0xff00)) - { - fmemcpy(buffer, DiskTransferBuffer, bytes_sector); - } + fmemcpy(buffer, DiskTransferBuffer, 512); *transferred += count; LBA_address += count; totaltodo -= count; - buffer = adjust_far((char FAR *)buffer + count * bytes_sector); + buffer = adjust_far((char FAR *)buffer + count * 512u); } - return (error_code); -} - - -COUNT writelabelBPB(char drive, const char *name) -{ - ddt *pddt = getddt(drive - 'A'); - struct FS_info *fs; - int offset; - WORD ret; - - ret = getbpb(pddt); - if (ret != 0) - return ret; - - if (DiskTransferBuffer[0x26] == 0x29 && - pddt->ddt_bpb.bpb_nfsect != 0) /* BPB v4.1 */ - offset = 0x27; - else if (DiskTransferBuffer[0x42] == 0x29 && - pddt->ddt_bpb.bpb_nfsect == 0) /* BPB v7 long */ - offset = 0x43; - else - return -1; - - /* store volume name */ - fs = (struct FS_info *)&DiskTransferBuffer[offset]; - ConvertNameSZToName83(fs->volume, name); - - ret = RWzero(pddt, LBA_WRITE); - if (ret != 0) - return ret; - return 0; } - - - -/* - * 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 index e980a2c4..ff474bfd 100644 --- a/kernel/dyndata.h +++ b/kernel/dyndata.h @@ -9,7 +9,13 @@ moveable and Dyn.Buffer resizable, but not before */ +#ifdef DEBUG void far *DynAlloc(char *what, unsigned num, unsigned size); +#else +void far *_DynAlloc(unsigned num, unsigned size); +#define DynAlloc(what, num, size) (_DynAlloc((num), (size))) +#endif + void far *DynLast(void); void DynFree(void *ptr); diff --git a/kernel/dyninit.c b/kernel/dyninit.c index c0285018..0461e556 100644 --- a/kernel/dyninit.c +++ b/kernel/dyninit.c @@ -19,7 +19,7 @@ kernel layout: 02610H 0F40EH 0CDFFH HMA_TEXT HMA - FCBs, f_nodes, buffers,... + FCB's, f_nodes, buffers,... drivers @@ -38,31 +38,27 @@ kernel layout: #include "portab.h" #include "init-mod.h" #include "dyndata.h" - -#if defined(DEBUG) -#define DebugPrintf(x) printf x -#else -#define DebugPrintf(x) -#endif +#include "debug.h" /*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 +#ifdef DEBUG void far *DynAlloc(char *what, unsigned num, unsigned size) +#else +void far *_DynAlloc(unsigned num, unsigned size) +#endif { 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); @@ -81,11 +77,13 @@ void far *DynAlloc(char *what, unsigned num, unsigned size) 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() { diff --git a/kernel/entry.asm b/kernel/entry.asm index ebceaad9..1e388353 100644 --- a/kernel/entry.asm +++ b/kernel/entry.asm @@ -25,37 +25,32 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: entry.asm 1701 2012-01-16 22:06:21Z perditionc $ +; $Id$ ; - %include "segs.inc" + %include "segs.inc" %include "stacks.inc" -segment HMA_TEXT +segment HMA_TEXT extern _int21_syscall extern _int21_service extern _int2526_handler - extern _error_tos - extern _char_api_tos - extern _disk_api_tos - extern _user_r - extern _ErrorMode - extern _InDOS - extern _term_type - extern _abort_progress -%IFDEF WIN31SUPPORT - extern _winInstanced -%ENDIF ; WIN31SUPPORT - extern _cu_psp - extern _MachineId - extern critical_sp + 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 - extern int21regs_off + extern int21regs_seg:wrt DGROUP + extern int21regs_off:wrt DGROUP - extern _Int21AX + extern _Int21AX:wrt DGROUP - extern _DGROUP_ + extern _DGROUP_ global reloc_call_cpm_entry global reloc_call_int20_handler @@ -70,17 +65,9 @@ segment HMA_TEXT ; 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. +; This one is a strange one. The call is to psp:0005h but it returns to the +; function after the call. What we do is convert it to a normal call and +; fudge the stack to look like an int 21h call. ; reloc_call_cpm_entry: ; Stack is: @@ -88,7 +75,10 @@ reloc_call_cpm_entry: ; psp seg ; 000ah ; - add sp, byte 2 ; remove unneeded far return offset 0ah + push bp ; trash old return address + mov bp,sp + xchg bp,[2+bp] + pop bp pushf ; start setting up int 21h stack ; ; now stack is @@ -117,43 +107,43 @@ reloc_call_cpm_entry: ; psp seg (alias .COM cs) ; return offset ; - cmp cl,024h ; restrict calls to functions 0-24h - ja cpm_error + cmp cl,024h + jbe 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 + iret ; ; interrupt zero divide handler: -; print a message 'Interrupt divide by zero' +; print a message 'Divide error' ; Terminate the current process ; ; VOID INRPT far ; int20_handler(iregs UserRegs) ; -print_hex: mov cl, 12 +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 + 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_error_message db 0dh,0ah,'Divide error, stack:',0dh,0ah,0 global reloc_call_int0_handler reloc_call_int0_handler: - mov si,divide_by_zero_message + mov si,divide_error_message zero_message_loop: mov al, [cs:si] @@ -169,27 +159,27 @@ zero_message_loop: 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 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 - + call print_hex + mov al, ' ' + int 10h + inc si + inc si + cmp si, 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 + 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 @@ -199,31 +189,6 @@ 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 ; @@ -241,10 +206,35 @@ reloc_call_int20_handler: ; int21_handler(iregs UserRegs) ; reloc_call_int21_handler: - cmp ah,25h - je int21_func25 - cmp ah,35h - je int21_func35 +;%define OEMHANDLER ; enable OEM hook, mostly OEM DOS 2.x, maybe through OEM 6.x +%ifdef OEMHANDLER + extern _OemHook21 + ; When defined and set (!= ffff:ffffh) invoke installed + ; int 21h handler for ah=f9h through ffh + ; with all registers preserved, callee must perform the iret + cmp ah, 0f9h ; if a normal int21 call, proceed + jb skip_oemhndlr ; as quickly as possible + ; we need all registers preserved but also + ; access to the hook address, so we copy locally + ; 1st (while performing check for valid address) + ; then do the jmp + push ds + push dx + mov dx,[cs:_DGROUP_] + mov ds,dx + cmp word [_OemHook21], -1 + je no_oemhndlr + cmp word [_OemHook21+2], -1 + je no_oemhndlr + pop dx + pop ds + jmp far [ds:_OemHook21] ; invoke OEM handler (no return) +;local_hookaddr dd 0 +no_oemhndlr: + pop dx + pop ds +skip_oemhndlr: +%endif ;OEMHANDLER ; ; Create the stack frame for C call. This is done to ; preserve machine state and provide a C structure for @@ -260,19 +250,23 @@ reloc_call_int21_handler: sti PUSH$ALL mov bp,sp + Protect386Registers ; ; 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: mov dx,[cs:_DGROUP_] mov ds,dx - mov byte [_term_type], 0 ; reset termination type -int21_reentry: ; entered here from int 24h abort, ds = dx => DGROUP - Protect386Registers + + 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 @@ -281,8 +275,8 @@ int21_reentry: ; entered here from int 24h abort, ds = dx => DGROUP jne int21_1 int21_user: -%IFNDEF WIN31SUPPORT - call end_dos_crit_sect +%IFNDEF WIN31SUPPORT ; begin critical section + call dos_crit_sect %ENDIF ; NOT WIN31SUPPORT push ss @@ -292,29 +286,6 @@ int21_user: pop cx jmp short int21_ret -int21_func25: - push es - push bx - xor bx,bx - mov es,bx - mov bl,al - shl bx,1 - shl bx,1 - mov [es:bx],dx - mov [es:bx+2],ds - pop bx - pop es - iret - -int21_func35: - xor bx,bx - mov es,bx - mov bl,al - shl bx,1 - shl bx,1 - les bx,[es:bx] - iret - ; ; normal entry, use one of our 4 stacks ; @@ -334,7 +305,7 @@ int21_1: ; I don't know who needs that, but ... (TE) ; mov word [_user_r+2],ss - mov word [_user_r],bp ; store and init + mov word [_user_r],bp ; store and init ; ; Decide which stack to run on. @@ -373,7 +344,10 @@ int21_2: %IFDEF WIN31SUPPORT ; begin critical section ; should be called as needed, but we just ; mark the whole int21 api as critical - call begin_dos_crit_sect + push ax + mov ax, 8001h ; Enter Critical Section + int 2ah + pop ax %ENDIF ; WIN31SUPPORT inc byte [_InDOS] mov cx,_char_api_tos @@ -387,8 +361,8 @@ int21_2: jbe int21_normalentry int21_3: -%IFNDEF WIN31SUPPORT - call end_dos_crit_sect +%IFNDEF WIN31SUPPORT ; begin critical section + call dos_crit_sect %ENDIF ; NOT WIN31SUPPORT mov cx,_disk_api_tos @@ -408,10 +382,12 @@ int21_normalentry: push bp call _int21_service -int21_exit: -%IFDEF WIN31SUPPORT - call end_dos_crit_sect ; release all critical sections +int21_exit: dec byte [_InDOS] +%IFDEF WIN31SUPPORT ; end critical section + call dos_crit_sect ; release all critical sections %if 0 + ; should be called as needed, but we just + ; mark the whole int21 api as critical push ax mov ax, 8101h ; Leave Critical Section int 2ah @@ -419,10 +395,6 @@ int21_exit: %endif %ENDIF ; WIN31SUPPORT - ; tiny chance DOS re-entered between clearing InDOS and restoring user stack, - ; so we disable interrupts until user stack restored; see SF bug# 215 - cli - dec byte [_InDOS] ; ; Recover registers from system call. Registers and flags ; were modified by the system call. @@ -433,42 +405,31 @@ int21_exit_nodec: pop bp ; get back user stack pop si - global _int21_iret -_int21_iret: +%if XCPU >= 386 +%ifdef WATCOM + sub bp, 4 ; for fs and gs only +%else + sub bp, 6 ; high parts of eax, ebx or ecx, edx +%endif +%endif + cli mov ss,si - RestoreSP + mov sp,bp int21_ret: Restore386Registers - POP$ALL + POP$ALL ; ; ... and return. ; iret -%IFDEF WIN31SUPPORT -; -; begin DOS Critical Section 1 -; -; -begin_dos_crit_sect: - ; we only enable critical sections if Windows is active - ; we currently use winInstanced, but may need to use separate patchable location - cmp word [_winInstanced], 0 - jz skip_crit_sect - push ax - mov ax, 8001h ; Enter Critical Section - int 2ah - pop ax -skip_crit_sect: - ret -%ENDIF ; WIN31SUPPORT ; ; end Dos Critical Section 0 thur 7 ; ; -end_dos_crit_sect: +dos_crit_sect: mov [_Int21AX],ax ; needed! push ax ; This must be here!!! mov ah,82h ; re-enrty sake before disk stack @@ -537,8 +498,8 @@ int2526: Protect386Registers - push dx - push cx ; save user stack + push dx + push cx ; save user stack push dx ; SS:SP -> user stack push cx @@ -546,8 +507,8 @@ int2526: call _int2526_handler add sp, byte 6 - pop cx - pop dx ; restore user stack + pop cx + pop dx ; restore user stack Restore386Registers @@ -613,8 +574,6 @@ CritErr05: mov bp,sp push si push di - Protect386Registers - ; ; Get parameters ; @@ -622,11 +581,10 @@ CritErr05: 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 + ; make bp:si point to dev header ; mov si,word [bp+10] ; lpDevice Offset - mov cx,word [bp+12] ; lpDevice segment + mov bp,word [bp+12] ; lpDevice segment ; ; Now save real ss:sp and retry info in internal stack ; @@ -648,11 +606,8 @@ CritErr05: ; ; switch to user's stack ; - mov bp,[es:PSP_USERSP] mov ss,[es:PSP_USERSS] - RestoreSP - Restore386Registers - mov bp,cx + mov sp,[es:PSP_USERSP] ; ; and call critical error handler ; @@ -663,13 +618,6 @@ CritErr05: ; cld cli - Protect386Registers - ; ecm: The extended stack frame must be restored here - ; in case the response isn't Abort. The int 21h handler - ; will expect the extended stack frame to be still - ; intact, but the stack written by the int 24h (even - ; only the int instruction) will have overwritten it. - mov bp, [cs:_DGROUP_] mov ds,bp mov ss,bp @@ -683,13 +631,7 @@ CritErr05: pop word [es:PSP_USERSP] pop word [es:PSP_USERSS] mov bp, sp - mov ah, byte [bp + 4 + 4 + Size386Registers] - ; restore old AH from nFlags - ; ecm: One 4 is the displacement of nFlags from the - ; usual bp, the other 4 accounts for the si and di - ; on the stack, the Size386Registers is added to - ; skip the fs and gs (OpenWatcom 386 build) or high - ; words that are a part of the stack frame, if any. + mov ah, byte [bp+4+4] ; restore old AH from nFlags sti ; Enable interrupts ; ; clear flags @@ -732,8 +674,6 @@ CritErr30: CritErrExit: xor ah,ah ; clear out top for return - - Restore386Registers pop di pop si pop bp @@ -743,28 +683,18 @@ CritErrExit: ; Abort processing. ; CritErrAbort: - test byte [_abort_progress], -1 - mov al, FAIL - jnz CritErrExit -%if 0 mov ax,[_cu_psp] mov es,ax cmp ax,[es:PSP_PARENT] mov al,FAIL jz CritErrExit - ; ecm: This check is done by (E)DR-DOS, but not MS-DOS. - ; Therefore, disable it and terminate the self-parented - ; process here like any other. -%endif cli - mov ax,word [_user_r+2] ;Get frame + mov bp,word [_user_r+2] ;Get frame + mov ss,bp mov bp,word [_user_r] - mov ss,ax mov sp,bp mov byte [_ErrorMode],1 ; flag abort mov ax,4C00h mov [bp+reg_ax],ax sti - mov byte [_term_type], 2 ; set int 24h abort error - mov dx, ds jmp int21_reentry ; restart the system call diff --git a/kernel/error.c b/kernel/error.c index 035312b1..84332fda 100644 --- a/kernel/error.c +++ b/kernel/error.c @@ -27,20 +27,24 @@ /****************************************************************/ #include "portab.h" -#include "globals.h" -#include "debug.h" +#ifdef VERSION_STRINGS +static BYTE *errorRcsId = + "$Id$"; +#endif + +#include "globals.h" #ifdef DEBUG /* error registers */ VOID dump(void) { - DebugPrintf(("Register Dump [AH = %02x CS:IP = %04x:%04x FLAGS = %04x]\n", - error_regs.AH, error_regs.CS, error_regs.IP, error_regs.FLAGS)); - DebugPrintf(("AX:%04x BX:%04x CX:%04x DX:%04x\n", - error_regs.AX, error_regs.BX, error_regs.CX, error_regs.DX)); - DebugPrintf(("SI:%04x DI:%04x DS:%04x ES:%04x\n", - error_regs.SI, error_regs.DI, error_regs.DS, error_regs.ES)); + 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 diff --git a/kernel/execrh.asm b/kernel/execrh.asm index ae4541f9..87ce4c9c 100644 --- a/kernel/execrh.asm +++ b/kernel/execrh.asm @@ -25,11 +25,10 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: execrh.asm 1184 2006-05-20 20:49:59Z mceric $ +; $Id$ ; %include "segs.inc" - %include "stacks.inc" segment HMA_TEXT ; EXECRH @@ -51,29 +50,25 @@ segment HMA_TEXT push si push ds ; sp=bp-8 -arg {rhp,4}, {dhp,4} - lds si,[.dhp] ; ds:si = device header - les bx,[.rhp] ; es:bx = request header + lds si,[bp+4] ; ds:si = device header + les bx,[bp+8] ; es:bx = request header mov ax, [si+6] ; construct strategy address - mov [.dhp], ax + mov [bp+4], ax push si ; the bloody fucking RTSND.DOS push di ; driver destroys SI,DI (tom 14.2.03) - call far[.dhp] ; call far the strategy + 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 [.dhp],ax ; construct interrupt address - call far[.dhp] ; call far the interrupt - - ; Restore386Registers ; less stack load and better performance... + mov ax,[si+8] ; construct 'interrupt' address + mov [bp+4],ax ; construct interrupt address + call far[bp+4] ; call far the interrupt sti ; damm driver turn off ints cld ; has gone backwards diff --git a/kernel/fatdir.c b/kernel/fatdir.c index 6dbe8fe8..c7c98dd5 100644 --- a/kernel/fatdir.c +++ b/kernel/fatdir.c @@ -31,6 +31,10 @@ #include "globals.h" #include "debug.h" +#ifdef VERSION_STRINGS +static BYTE *fatdirRcsId = + "$Id$"; +#endif /* Description. * Initialize a fnode so that it will point to the directory with @@ -39,10 +43,8 @@ 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_flags = F_DDIR; + fnp->f_diroff = 0; fnp->f_offset = 0l; fnp->f_cluster_offset = 0; @@ -52,20 +54,38 @@ VOID dir_init_fnode(f_node_ptr fnp, CLUSTER dirstart) if (ISFAT32(fnp->f_dpb)) dirstart = fnp->f_dpb->dpb_xrootclst; #endif - fnp->f_cluster = fnp->f_dmp->dm_dircluster = dirstart; + fnp->f_cluster = fnp->f_dirstart = dirstart; } -f_node_ptr dir_open(register const char *dirname, BOOL split, f_node_ptr fnp) +f_node_ptr dir_open(register const char *dirname) { + f_node_ptr fnp; int i; - char *fcbname; + char fcbname[FNAME_SIZE + FEXT_SIZE]; + + FDirDbgPrintf(("dir_open: trying to open %s\n", dirname)); + + /* Allocate an fnode if possible - error return (0) if not. */ + if ((fnp = get_f_node()) == (f_node_ptr) 0) + { + FDirDbgPrintf(("dir_open: failed to get f_node\n")); + return (f_node_ptr) 0; + } + + /* Force the fnode into read-write mode */ + fnp->f_mode = RDWR; /* 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() */ + if (media_check(fnp->f_dpb) < 0) + { + FDirDbgPrintf(("dir_open: media_check failed\n")); + release_f_node(fnp); + return (f_node_ptr) 0; + } /* Walk the directory tree to find the starting cluster */ /* */ @@ -77,30 +97,32 @@ f_node_ptr dir_open(register const char *dirname, BOOL split, f_node_ptr fnp) -- 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 \ */ + /* skip all path seperators */ + while (*dirname == '\\') + ++dirname; + /* don't continue if we're at the end */ if (*dirname == '\0') break; /* Convert the name into an absolute name for */ /* comparison... */ - dirname = ConvertNameSZToName83(fcbname, dirname); + memset(fcbname, ' ', FNAME_SIZE + FEXT_SIZE); - /* do not continue if we split the filename off and are */ - /* at the end */ - if (split && *dirname == '\0') - break; + 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; + } /* Now search through the directory to */ /* find the entry... */ @@ -114,11 +136,13 @@ f_node_ptr dir_open(register const char *dirname, BOOL split, f_node_ptr fnp) i = TRUE; break; } - fnp->f_dmp->dm_entry++; + fnp->f_diroff++; } if (!i || !(fnp->f_dir.dir_attrib & D_DIR)) { + FDirDbgPrintf(("dir_open: no match found, returning failure\n")); + release_f_node(fnp); return (f_node_ptr) 0; } else @@ -126,9 +150,9 @@ f_node_ptr dir_open(register const char *dirname, BOOL split, f_node_ptr fnp) /* make certain we've moved off */ /* root */ dir_init_fnode(fnp, getdstart(fnp->f_dpb, &fnp->f_dir)); - fnp->f_dmp->dm_entry = 0; } } + FDirDbgPrintf(("dir_open: returning, ok\n")); return fnp; } @@ -139,11 +163,24 @@ STATIC void swap_deleted(char *name) name[0] ^= EXT_DELETED - DELETED; /* 0xe0 */ } +STATIC struct buffer FAR *getblock_from_off(f_node_ptr fnp, unsigned secsize) +{ + /* Compute the block within the cluster and the */ + /* offset within the block. */ + unsigned sector; + + sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; + + /* Get the block we need from cache */ + return getblock(clus2phys(fnp->f_cluster, fnp->f_dpb) + sector, + fnp->f_dpb->dpb_unit); +} + /* 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 + * The fnp->f_diroff always corresponds to the directory entry * which has been read. * Return value. * 1 - all OK, directory entry having been read is not empty. @@ -155,66 +192,79 @@ 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) + if (fnp->f_diroff >= 65535U) + { + FDirDbgPrintf(("dir_read: exceed dir entry count\n")); 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,*/ + /* dirent portion of the fnode, clear the f_dmod bit and leave, */ /* but only for root directories */ - if (fnp->f_dmp->dm_dircluster == 0) + if (fnp->f_dirstart == 0) { - if (entry >= fnp->f_dpb->dpb_dirents) + if (fnp->f_diroff >= fnp->f_dpb->dpb_dirents) + { + FDirDbgPrintf(("dir_read: end of dir\n")); return DE_SEEK; + } - fnp->f_dirsector = entry / (secsize / DIRENT_SIZE) + - fnp->f_dpb->dpb_dirstrt; + bp = getblock(fnp->f_diroff / (secsize / DIRENT_SIZE) + + fnp->f_dpb->dpb_dirstrt, fnp->f_dpb->dpb_unit); +#ifdef DISPLAY_GETBLOCK + printf("DIR (dir_read)\n"); +#endif } else { /* Do a "seek" to the directory position */ - fnp->f_offset = entry * (ULONG)DIRENT_SIZE; + fnp->f_offset = fnp->f_diroff * (ULONG)DIRENT_SIZE; /* Search through the FAT to find the block */ /* that this entry is in. */ +#ifdef DISPLAY_GETBLOCK + printf("dir_read: "); +#endif if (map_cluster(fnp, XFR_READ) != SUCCESS) + { + DebugPrintf(("dir_read: map_cluster failed\n")); 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); - + bp = getblock_from_off(fnp, secsize); #ifdef DISPLAY_GETBLOCK - printf("DIR (dir_read)\n"); + printf("DIR (dir_read)\n"); #endif + } /* Now that we have the block for our entry, get the */ /* directory entry. */ if (bp == NULL) + { + FDirDbgPrintf(("dir_read: invalid block\n")); 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); + getdirent((BYTE FAR *) & bp-> + b_buffer[(fnp->f_diroff * DIRENT_SIZE) % fnp->f_dpb->dpb_secsize], + &fnp->f_dir); swap_deleted(fnp->f_dir.dir_name); + /* Update the fnode's directory info */ + fnp->f_flags &= ~F_DMOD; + /* and for efficiency, stop when we hit the first */ /* unused entry. */ /* either returns 1 or 0 */ + FDirDbgPrintf(("dir_read: dir_name is %11s\n", fnp->f_dir.dir_name)); return (fnp->f_dir.dir_name[0] != '\0'); } @@ -227,55 +277,100 @@ COUNT dir_read(REG f_node_ptr fnp) * TRUE - all OK. * FALSE - error occured (fnode is released). */ -BOOL dir_write_update(REG f_node_ptr fnp, BOOL update) +#ifndef IPL +BOOL dir_write(REG f_node_ptr fnp) { struct buffer FAR *bp; - UBYTE FAR *vp; + REG UWORD secsize = fnp->f_dpb->dpb_secsize; + + if (!(fnp->f_flags & F_DDIR)) + return FALSE; /* Update the entry if it was modified by a write or create... */ - if (!update || (fnp->f_flags & (SFT_FCLEAN|SFT_FDATE)) != SFT_FCLEAN) + if (fnp->f_flags & F_DMOD) { - 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; - + /* Root is a consecutive set of blocks, so handling is */ + /* simple. */ + if (fnp->f_dirstart == 0) + { + bp = getblock(fnp->f_diroff / (secsize / DIRENT_SIZE) + + fnp->f_dpb->dpb_dirstrt, + fnp->f_dpb->dpb_unit); #ifdef DISPLAY_GETBLOCK - printf("DIR (dir_write)\n"); + printf("DIR (dir_write)\n"); #endif + } - swap_deleted(fnp->f_dir.dir_name); + /* All other directories are just files. The only */ + /* special handling is resetting the offset so that we */ + /* can continually update the same directory entry. */ + else + { - vp = &bp->b_buffer[fnp->f_diridx * DIRENT_SIZE]; + /* Do a "seek" to the directory position */ + /* and convert the fnode to a directory fnode. */ + fnp->f_offset = fnp->f_diroff * (ULONG)DIRENT_SIZE; + fnp->f_cluster = fnp->f_dirstart; + fnp->f_cluster_offset = 0; - 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); + /* Search through the FAT to find the block */ + /* that this entry is in. */ +#ifdef DISPLAY_GETBLOCK + printf("dir_write: "); +#endif + if (map_cluster(fnp, XFR_READ) != SUCCESS) + { + release_f_node(fnp); + return FALSE; + } + + bp = getblock_from_off(fnp, secsize); + bp->b_flag &= ~(BFR_DATA | BFR_FAT); + bp->b_flag |= BFR_DIR | BFR_VALID; +#ifdef DISPLAY_GETBLOCK + printf("DIR (dir_write)\n"); #endif - fputlong(&vp[DIR_SIZE], fnp->f_dir.dir_size); } - else + + /* Now that we have a block, transfer the directory */ + /* entry into the block. */ + if (bp == NULL) { - putdirent(&fnp->f_dir, vp); + release_f_node(fnp); + return FALSE; } swap_deleted(fnp->f_dir.dir_name); + putdirent(&fnp->f_dir, &bp->b_buffer[(fnp->f_diroff * DIRENT_SIZE) % + fnp->f_dpb->dpb_secsize]); + + 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); + return TRUE; +} +#endif + +VOID dir_close(REG f_node_ptr fnp) +{ + /* Test for invalid f_nodes */ + if (fnp == NULL || !(fnp->f_flags & F_DDIR)) + return; + +#ifndef IPL + /* Write out the entry */ + dir_write(fnp); + +#endif + /* Clear buffers after release */ + /* hazard: no error checking! */ + flush_buffers(fnp->f_dpb->dpb_unit); + + /* and release this instance of the fnode */ + release_f_node(fnp); } #ifndef IPL @@ -283,24 +378,25 @@ COUNT dos_findfirst(UCOUNT attr, BYTE * name) { REG f_node_ptr fnp; REG dmatch *dmp = &sda_tmp_dm; + REG COUNT i; /* 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 */ + /* but never close). Since we don't want to lose fnodes 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; + /* current directory, do a seek and read, then close the fnode. */ - /* 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; + /* Parse out the file name */ + i = ParseDosName(name, SearchDir.dir_name, TRUE); + if (i < SUCCESS) + return i; +/* + printf("\nff %s", Tname); + printf("ff %s", fcbname); +*/ /* Now search through the directory to find the entry... */ @@ -308,19 +404,66 @@ COUNT dos_findfirst(UCOUNT attr, BYTE * name) /* 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*/ + /* RBIL: ignore ReaDONLY and ARCHIVE bits */ /* 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); + if ((attr & ~(D_RDONLY | D_ARCHIVE))==D_VOLID) + i = 3; + else + attr &= ~D_VOLID; /* ignore volume mask */ + + /* Now open this directory so that we can read the */ + /* fnode entry and do a match on it. */ + +/* printf("dir_open %s\n", szDirName);*/ + { + char tmp = name[i]; + name[i] = '\0'; + if ((fnp = dir_open(name)) == NULL) + return DE_PATHNOTFND; + name[i] = tmp; + } + + /* Now initialize the dirmatch structure. */ - /* Now further initialize the dirmatch structure. */ dmp->dm_drive = name[0] - 'A'; dmp->dm_attr_srch = attr; - DebugPrintf(("dos_findfirst: %s (calling dos_findnext())\n", name)); - return dos_findnext(); + /* Copy the raw pattern from our data segment to the DTA. */ + fmemcpy(dmp->dm_name_pat, SearchDir.dir_name, FNAME_SIZE + FEXT_SIZE); + + if ((attr & D_VOLID)==D_VOLID) /* search for VOL label ignore RDONLY & ARCHIVE */ + { + /* Now do the search */ + while (dir_read(fnp) == 1) + { + /* Test the attribute and return first found */ + if ((fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE)) == D_VOLID && + fnp->f_dir.dir_name[0] != DELETED) + { + dmp->dm_dircluster = fnp->f_dirstart; /* TE */ + memcpy(&SearchDir, &fnp->f_dir, sizeof(struct dirent)); + FDirDbgPrintf(("dos_findfirst: %11s\n", fnp->f_dir.dir_name)); + + dir_close(fnp); + return SUCCESS; + } + fnp->f_diroff++; + } + + /* Now that we've done our failed search, close it and */ + /* return an error. */ + dir_close(fnp); + return DE_NFILES; + } + /* Otherwise just do a normal find next */ + else + { + dmp->dm_entry = 0; + dmp->dm_dircluster = fnp->f_dirstart; + dir_close(fnp); + return dos_findnext(); + } } /* @@ -335,61 +478,62 @@ COUNT dos_findfirst(UCOUNT attr, BYTE * name) COUNT dos_findnext(void) { REG f_node_ptr fnp; - REG dmatch *dmp; + REG dmatch *dmp = &sda_tmp_dm; + + /* Allocate an fnode if possible - error return (0) if not. */ + if ((fnp = get_f_node()) == (f_node_ptr) 0) + { + return DE_NFILES; + } + + memset(fnp, 0, sizeof(*fnp)); + + /* Force the fnode into read-write mode */ + fnp->f_mode = RDWR; /* 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) + { + release_f_node(fnp); return DE_NFILES; + } dir_init_fnode(fnp, dmp->dm_dircluster); /* Search through the directory to find the entry, but do a */ /* seek first. */ + fnp->f_diroff = dmp->dm_entry; + /* 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)) - { - /* + ++fnp->f_diroff; + if (fnp->f_dir.dir_name[0] != '\0' && fnp->f_dir.dir_name[0] != DELETED && + !(fnp->f_dir.dir_attrib & D_VOLID) && + 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; - } + files are returned. RdOnly + Archive bits are ignored + */ + /* Test the attribute as the final step */ + !(~dmp->dm_attr_srch & (D_DIR|D_SYSTEM|D_HIDDEN) & fnp->f_dir.dir_attrib)) + { + /* If found, transfer it to the dmatch structure */ + dmp->dm_dircluster = fnp->f_dirstart; + memcpy(&SearchDir, &fnp->f_dir, sizeof(struct dirent)); + /* return the result */ + release_f_node(fnp); + return SUCCESS; } } - - - DebugPrintf(("dos_findnext: %11s\n", fnp->f_dir.dir_name)); + FDirDbgPrintf(("dos_findnext: %11s\n", fnp->f_dir.dir_name)); /* return the result */ + release_f_node(fnp); + return DE_NFILES; } #endif @@ -405,74 +549,22 @@ COUNT dos_findnext(void) 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 = FNAME_SIZE; --loop >= 0 && destSZ[loop] == ' '; ) + ; + destSZ += ++loop; + if (*srcFCBName != '.') /* not for ".", ".." */ { - - for (loop = FEXT_SIZE; --loop >= 0;) - { - if (srcFCBName[loop] != ' ') - break; - } - if (loop >= 0) + srcFCBName += FNAME_SIZE; + for (loop = FEXT_SIZE; --loop >= 0 && srcFCBName[loop] == ' '; ) + ; + if (++loop > 0) { *destSZ++ = '.'; - fmemcpy(destSZ, srcFCBName, loop + 1); - destSZ += loop + 1; + fmemcpy(destSZ, srcFCBName, loop); + destSZ += loop; } } *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 index a4028da6..8737555e 100644 --- a/kernel/fatfs.c +++ b/kernel/fatfs.c @@ -31,29 +31,32 @@ #include "globals.h" #include "debug.h" +#ifdef VERSION_STRINGS +BYTE *RcsId = "$Id$"; +#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); +f_node_ptr xlt_fd(COUNT); +STATIC void save_far_f_node(f_node_ptr fnp); +STATIC f_node_ptr get_near_f_node(void); +STATIC f_node_ptr split_path(char *, char *); +BOOL find_fname(f_node_ptr, char *, int); + /* /// Added - Ron Cemer */ +STATIC void merge_file_changes(f_node_ptr fnp, int collect); /* /// 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 int is_same_file(f_node_ptr fnp1, f_node_ptr fnp2); + /* /// Added - Ron Cemer */ +STATIC void copy_file_changes(f_node_ptr src, f_node_ptr dst); +BOOL find_free(f_node_ptr); +STATIC int alloc_find_free(f_node_ptr fnp, char *path, char *fcbname); STATIC VOID wipe_out(f_node_ptr); -STATIC CLUSTER extend(f_node_ptr); -STATIC COUNT extend_dir(f_node_ptr); +CLUSTER extend(f_node_ptr); +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 dtime time_encode(struct dostime *t) -{ - return (t->hour << 11) | (t->minute << 5) | (t->second >> 1); -} +STATIC VOID shrink_file(f_node_ptr fnp); #ifdef WITHFAT32 CLUSTER getdstart(struct dpb FAR *dpbp, struct dirent *dentry) @@ -69,6 +72,14 @@ void setdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value) if (ISFAT32(dpbp)) dentry->dir_start_high = (UWORD)(value >> 16); } + +BOOL checkdstart(struct dpb FAR *dpbp, struct dirent *dentry, CLUSTER value) +{ + if (!ISFAT32(dpbp)) + return dentry->dir_start == (UWORD)value; + return (dentry->dir_start == (UWORD)value && + dentry->dir_start_high == (UWORD)(value >> 16)); +} #endif ULONG clus2phys(CLUSTER cl_no, struct dpb FAR * dpbp) @@ -90,7 +101,7 @@ struct dpb FAR *get_dpb(COUNT dsk) return cdsp->cdsDpb; } -/* initialize directory entry (creation/access stamps 0 as per MS-DOS 7.10) */ +/* initialize directory entry */ STATIC void init_direntry(struct dirent *dentry, unsigned attrib, CLUSTER cluster, char *name) { @@ -101,7 +112,6 @@ STATIC void init_direntry(struct dirent *dentry, unsigned attrib, #endif dentry->dir_start = (UWORD)cluster; dentry->dir_attrib = (UBYTE)attrib; - /* set create and last modified time & date */ dentry->dir_crtime = dentry->dir_time = dos_gettime(); dentry->dir_crdate = dentry->dir_date = dos_getdate(); } @@ -119,29 +129,42 @@ STATIC void init_direntry(struct dirent *dentry, unsigned attrib, /* 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) +long dos_open(char *path, unsigned flags, unsigned attrib) { - REG f_node_ptr fnp = sft_to_fnode(fd); - /* FDPP has special handling for volume name here, - (they can coexist with files/directories) - writelabelBPB(drive,label); - */ - int status = find_fname(path, D_ALL | attrib, fnp); + REG f_node_ptr fnp; + char fcbname[FNAME_SIZE + FEXT_SIZE]; + int status = S_OPENED; + + /* First test the flags to see if the user has passed a valid */ + /* file mode... */ + if ((flags & O_ACCMODE) > 2) + return DE_INVLDACC; + + /* next, split the passed dir into components (i.e. - path to */ + /* new directory and name of new directory. */ + if ((fnp = split_path(path, fcbname)) == NULL) + { + FatFSDbgPrintf(("dos_open: splitpath(\"%s\", \"%11s\") failed.\n", path, fcbname)); + return DE_PATHNOTFND; + } /* Check that we don't have a duplicate name, so if we */ /* find one, truncate it (O_CREAT). */ - if (status == SUCCESS) + if (find_fname(fnp, fcbname, D_ALL | attrib)) { - unsigned char dir_attrib = fnp->f_dir.dir_attrib; + FatFSDbgPrintf(("dos_open: filename match found\n")); 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)) + if ((fnp->f_dir.dir_attrib & (D_RDONLY | D_DIR | D_VOLID)) + || (fnp->f_dir.dir_attrib & ~D_ARCHIVE & ~attrib)) + { + dir_close(fnp); return DE_ACCESS; - + } + /* Release the existing files FAT and set the */ /* length to zero, effectively truncating the */ /* file to zero. */ @@ -151,25 +174,27 @@ int dos_open(char *path, unsigned flags, unsigned attrib, int fd) 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)) + if ((flags & O_FCB) && (fnp->f_dir.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))) + /* Check permissions. -- JPP */ + if ((fnp->f_dir.dir_attrib & D_RDONLY) && + ((flags & O_ACCMODE) != O_RDONLY)) + { + dir_close(fnp); return DE_ACCESS; - status = S_OPENED; + } } else { + dir_close(fnp); return DE_FILEEXISTS; } } - else if (status == DE_FILENOTFND && (flags & O_CREAT)) + else if (flags & O_CREAT) { - int ret = alloc_find_free(fnp, path); + int ret = alloc_find_free(fnp, path, fcbname); + FatFSDbgPrintf(("dos_open: create\n")); if (ret != SUCCESS) return ret; status = S_CREATED; @@ -178,31 +203,47 @@ int dos_open(char *path, unsigned flags, unsigned attrib, int fd) { /* open: If we can't find the file, just return a not */ /* found error. */ - return status; + dir_close(fnp); + FatFSDbgPrintf(("dos_open: file not found\n")); + return DE_FILENOTFND; + } + + /* Set the fnode to the desired mode */ + /* Updating the directory entry first. */ + fnp->f_mode = flags & O_ACCMODE; + + if (status != S_OPENED) + { + init_direntry(&fnp->f_dir, attrib, FREE, fcbname); + fnp->f_flags = F_DMOD | F_DDIR; + if (!dir_write(fnp)) + { + release_f_node(fnp); + return DE_ACCESS; + } } /* 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; + fnp->f_cluster = FREE; + setdstart(fnp->f_dpb, &fnp->f_dir, FREE); + fnp->f_cluster_offset = 0; } + fnp->f_flags = 0; + if (status != S_OPENED) + fnp->f_flags = F_DMOD; + 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); + fnp->f_cluster_offset = 0; - fnode_to_sft(fnp); - return status; + save_far_f_node(fnp); + return xlt_fnp(fnp) | ((long)status << 16); } BOOL fcmp_wild(const char * s1, const char * s2, unsigned n) @@ -215,12 +256,20 @@ BOOL fcmp_wild(const char * s1, const char * s2, unsigned n) COUNT dos_close(COUNT fd) { + f_node_ptr fnp; + /* Translate the fd into a useful pointer */ - f_node_ptr fnp = sft_to_fnode(fd); + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return DE_INVLDHNDL; - if (!(fnp->f_flags & SFT_FCLEAN)) + if (fnp->f_flags & F_DMOD) { - if (!(fnp->f_flags & SFT_FDATE)) + if (!(fnp->f_flags & F_DDATE)) { fnp->f_dir.dir_time = dos_gettime(); fnp->f_dir.dir_date = dos_getdate(); @@ -228,18 +277,52 @@ COUNT dos_close(COUNT fd) merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ } - fnp->f_sft_idx = 0xff; + fnp->f_flags |= F_DDIR; - return dir_write_update(fnp, TRUE) ? SUCCESS : DE_INVLDHNDL; + dir_close(fnp); + return SUCCESS; +} + +COUNT dos_commit(COUNT fd) +{ + f_node_ptr fnp, fnp2; + + /* Translate the fd into a useful pointer */ + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return DE_INVLDHNDL; + fnp2 = get_f_node(); + if (fnp2 == (f_node_ptr) 0) + { + release_near_f_node(fnp); + return DE_INVLDHNDL; + } + + /* a copy of the fnode is closed meaning that the directory info + is updated etc, but we keep our old info */ + memcpy(fnp2, fnp, sizeof(*fnp)); + save_far_f_node(fnp2); + release_near_f_node(fnp); + return dos_close(xlt_fnp(fnp2)); } /* */ /* split a path into it's component directory and file name */ /* */ -f_node_ptr split_path(const char * path, f_node_ptr fnp) +f_node_ptr split_path(char * path, char * fcbname) { - /* check if the path ends in a backslash */ - if (path[strlen(path) - 1] == '\\') + REG f_node_ptr fnp; + + /* Start off by parsing out the components. */ + int dirlength = ParseDosName(path, fcbname, FALSE); + FatFSDbgPrintf(("split_path: dirlen=%i, path=\"%s\", fcbname=\"%11s\"\n", \ + dirlength, path, fcbname)); + + if (dirlength < SUCCESS) return (f_node_ptr) 0; /* 11/29/99 jt @@ -256,19 +339,47 @@ f_node_ptr split_path(const char * path, f_node_ptr fnp) #ifdef DEBUG if (get_cds(path[0]-'A')->cdsFlags & CDSNETWDRV) { - printf("split path called for redirected file: `%s'\n", path); + printf("split path called for redirected file: `%11s'\n", + fcbname); return (f_node_ptr) 0; } #endif /* Translate the path into a useful pointer */ - return dir_open(path, TRUE, fnp); + { + char tmp = path[dirlength]; + path[dirlength] = '\0'; + fnp = dir_open(path); + path[dirlength] = tmp; + } + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit... */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0 || fnp->f_count <= 0) + { + FatFSDbgPrintf(("split_path: failing, fnp is %sNULL, f_count=%i\n", \ + (fnp==(f_node_ptr)0)?"":"NOT", \ + (fnp==(f_node_ptr)0)?123:fnp->f_count)); + dir_close(fnp); + return (f_node_ptr) 0; + } + + FatFSDbgPrintf(("split_path: success\n")); + return fnp; } /* checks whether directory part of path exists */ BOOL dir_exists(char * path) { - return split_path(path, &fnode[0]) != NULL; + REG f_node_ptr fnp; + char fcbname[FNAME_SIZE + FEXT_SIZE]; + + if ((fnp = split_path(path, fcbname)) == NULL) + return FALSE; + + dir_close(fnp); + return TRUE; } BOOL fcbmatch(const char *fcbname1, const char *fcbname2) @@ -276,23 +387,18 @@ 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) +STATIC BOOL find_fname(f_node_ptr fnp, char *fcbname, int attr) { - /* 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) + if (fcbmatch(fnp->f_dir.dir_name, fcbname) && (fnp->f_dir.dir_attrib & ~(D_RDONLY | D_ARCHIVE | attr)) == 0) { - return SUCCESS; + return TRUE; } - fnp->f_dmp->dm_entry++; + fnp->f_diroff++; } - return DE_FILENOTFND; + return FALSE; } /* Description. @@ -300,35 +406,40 @@ STATIC int find_fname(const char *path, int attr, f_node_ptr fnp) * pointed by fnp, fnode isn't modified (I hope). * Return value. * SUCCESS - completed successfully. - * DE_ACCESS - error occurred, fnode is released. + * DE_BLKINVLD - error occured, 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; + unsigned original_diroff = fnp->f_diroff; while (TRUE) { - if (fnp->f_dmp->dm_entry == 0) + if (fnp->f_diroff == 0) break; - fnp->f_dmp->dm_entry--; - if (dir_read(fnp) <= 0) - return DE_ACCESS; + fnp->f_diroff--; + if (dir_read(fnp) <= 0) { + dir_close(fnp); + return DE_BLKINVLD; + } 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_flags |= F_DMOD; + if (!dir_write(fnp)) return DE_BLKINVLD; + } + fnp->f_diroff = original_diroff; + if (dir_read(fnp) <= 0) { + dir_close(fnp); + return DE_BLKINVLD; } - 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 + /* If more than one f_node 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 @@ -336,67 +447,58 @@ COUNT remove_lfn_entries(f_node_ptr fnp) 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) +STATIC void merge_file_changes(f_node_ptr fnp, int collect) { - int i, j; - sft FAR *sftp; - sfttbl FAR *sp; + f_node_ptr fnp2; + int i, fd; - if (!IsShareInstalled(FALSE)) - return SUCCESS; + if (!IsShareInstalled()) + return; - i = 0; - for (sp = sfthead; sp != (sfttbl FAR *) - 1; sp = sp->sftt_next) + fd = xlt_fnp(fnp); + fnp2 = get_near_f_node(); + for (i = 0; i < f_nodes_cnt; i++) { - for(j = sp->sftt_count, sftp = sp->sftt_table; --j >= 0; sftp++, i++) + fmemcpy(fnp2, &f_nodes[i], sizeof(*fnp2)); + if ((fnp != (f_node_ptr) 0) + && (i != fd) + && (fnp->f_count > 0) && (is_same_file(fnp, fnp2))) { - 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) { - 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 + f_node which refers to this file. */ + if (fnp2->f_mode != RDONLY) { - /* 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; + memcpy(&fnp->f_dir, &fnp2->f_dir, sizeof(struct dirent)); + break; } } + else + { + /* We just made changes to this file, so we are + distributing these changes to the other f_nodes + which refer to this file. */ + memcpy(&fnp2->f_dir, &fnp->f_dir, sizeof(struct dirent)); + fmemcpy(&f_nodes[i], fnp2, sizeof(*fnp2)); + } } } - return SUCCESS; + release_near_f_node(fnp2); } -void dos_merge_file_changes(int fd) + /* /// Added - Ron Cemer */ +STATIC int is_same_file(f_node_ptr fnp1, f_node_ptr fnp2) { - merge_file_changes(sft_to_fnode(fd), FALSE); + return + (fnp1->f_dpb->dpb_unit == fnp2->f_dpb->dpb_unit) + && (fnp1->f_dpb->dpb_subunit == fnp2->f_dpb->dpb_subunit) + && (fcbmatch(fnp1->f_dir.dir_name, fnp2->f_dir.dir_name)) + && ((fnp1->f_dir.dir_attrib & D_VOLID) == 0) + && ((fnp2->f_dir.dir_attrib & D_VOLID) == 0) + && (fnp1->f_diroff == fnp2->f_diroff) + && (fnp1->f_dirstart == fnp2->f_dirstart) + && (fnp1->f_dpb == fnp2->f_dpb); } STATIC COUNT delete_dir_entry(f_node_ptr fnp) @@ -415,8 +517,8 @@ STATIC COUNT delete_dir_entry(f_node_ptr fnp) /* The directory has been modified, so set the */ /* bit before closing it, allowing it to be */ /* updated */ - if (!dir_write(fnp)) - return DE_ACCESS; + fnp->f_flags |= F_DMOD; + dir_close(fnp); /* SUCCESSful completion, return it */ return SUCCESS; @@ -424,81 +526,127 @@ STATIC COUNT delete_dir_entry(f_node_ptr fnp) COUNT dos_delete(BYTE * path, int attrib) { - REG f_node_ptr fnp = &fnode[0]; + REG f_node_ptr fnp; + char fcbname[FNAME_SIZE + FEXT_SIZE]; + + /* first split the passed dir into components (i.e. - */ + /* path to new directory and name of new directory */ + if ((fnp = split_path(path, fcbname)) == NULL) + { + return DE_PATHNOTFND; + } /* 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) + if (find_fname(fnp, fcbname, attrib)) { /* 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)) + { + dir_close(fnp); return DE_ACCESS; + } return delete_dir_entry(fnp); } else + { /* No such file, return the error */ - return ret; + dir_close(fnp); + return DE_FILENOTFND; + } } COUNT dos_rmdir(BYTE * path) { REG f_node_ptr fnp; + REG f_node_ptr fnp1; + BOOL found; + char fcbname[FNAME_SIZE + FEXT_SIZE]; /* 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) + /* next, split the passed dir into components (i.e. - */ + /* path to new directory and name of new directory */ + if ((fnp = split_path(path, fcbname)) == NULL) + { return DE_PATHNOTFND; + } - /* Directories may have attributes, but if other than 'archive' */ - /* or 'read only' then deny i.e. do not allow (SYSTEM|HIDDEN) */ - /* directory to be deleted. */ - if (fnp->f_dir.dir_attrib & ~(D_DIR | D_RDONLY | D_ARCHIVE)) - return DE_ACCESS; + /* Check that we don't have a duplicate name, so if we */ + /* find one, it's an error. */ + if (find_fname(fnp, fcbname, D_ALL)) + { + /* Check if it's really a directory */ + if (!(fnp->f_dir.dir_attrib & D_DIR)) + { + dir_close(fnp); + 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; + /* Check that the directory is empty. Only the */ + /* "." and ".." are permissable. */ + fnp->f_flags &= ~F_DMOD; + fnp1 = dir_open(path); + if (fnp1 == NULL) + { + dir_close(fnp); + return DE_ACCESS; + } + + dir_read(fnp1); + if (fnp1->f_dir.dir_name[0] != '.' || fnp1->f_dir.dir_name[1] != ' ') + { + dir_close(fnp); + 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; + fnp1->f_diroff++; + dir_read(fnp1); + if (fnp1->f_dir.dir_name[0] != '.' || fnp1->f_dir.dir_name[1] != '.') + { + dir_close(fnp); + 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) - { + /* Now search through the directory and make certain */ + /* that there are no entries. */ + found = FALSE; + fnp1->f_diroff++; + while (dir_read(fnp1) == 1) + { + if (fnp1->f_dir.dir_name[0] == '\0') + break; + if (fnp1->f_dir.dir_name[0] != DELETED + && fnp1->f_dir.dir_attrib != D_LFN) + { + found = TRUE; + break; + } + fnp1->f_diroff++; + } + + dir_close(fnp1); /* If anything was found, exit with an error. */ - if (fnp->f_dir.dir_name[0] != DELETED && fnp->f_dir.dir_attrib != D_LFN) + if (found) + { + dir_close(fnp); return DE_ACCESS; - fnp->f_dmp->dm_entry++; + } + return delete_dir_entry(fnp); + } + else + { + /* No such file, return the error */ + dir_close(fnp); + return DE_FILENOTFND; } - - /* 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) @@ -506,63 +654,70 @@ COUNT dos_rename(BYTE * path1, BYTE * path2, int attrib) REG f_node_ptr fnp1; REG f_node_ptr fnp2; COUNT ret; - char *fcbname; + char fcbname[FNAME_SIZE + FEXT_SIZE]; /* 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; + /* first split the passed target into compnents (i.e. - path to */ + /* new file name and name of new file name */ + if ((fnp2 = split_path(path2, fcbname)) == NULL) + { + return DE_PATHNOTFND; + } /* 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) + if (find_fname(fnp2, fcbname, attrib)) { - /* rename in the same directory: change the directory entry in-place */ - fnp2 = fnp1; - if ((ret = remove_lfn_entries(fnp1)) < 0) - return ret; + dir_close(fnp2); + return DE_ACCESS; } - 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; + /* next split the passed source into compnents (i.e. - path to */ + /* old file name and name of old file name */ + if ((fnp1 = split_path(path1, fcbname)) == NULL) + { + dir_close(fnp2); + return DE_PATHNOTFND; + } - if ((ret = remove_lfn_entries(fnp1)) < 0) - return ret; + if (!find_fname(fnp1, fcbname, attrib)) + { + /* No such file, return the error */ + dir_close(fnp1); + dir_close(fnp2); + return DE_FILENOTFND; + } - /* init fnode for new file name to match old file name */ - memcpy(&fnp2->f_dir, &fnp1->f_dir, sizeof(struct dirent)); + ret = alloc_find_free(fnp2, path2, fcbname); + if (ret != SUCCESS) { + dir_close(fnp1); + return ret; + } - /* Ok, so we can delete this one. Save the file info. */ - *(fnp1->f_dir.dir_name) = DELETED; + if ((ret = remove_lfn_entries(fnp1)) < 0) + return ret; - if (!dir_write(fnp1)) - return DE_ACCESS; - } + memcpy(&fnp2->f_dir, &fnp1->f_dir, sizeof(struct dirent)); /* put the fnode's name into the directory. */ memcpy(fnp2->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE); + /* The directory has been modified, so set the bit before */ + /* closing it, allowing it to be updated. */ + fnp1->f_flags = fnp2->f_flags = F_DMOD | F_DDIR; + + /* Ok, so we can delete this one. Save the file info. */ + *(fnp1->f_dir.dir_name) = DELETED; + + dir_close(fnp1); + dir_close(fnp2); + /* SUCCESSful completion, return it */ - return dir_write(fnp2) ? SUCCESS : DE_ACCESS; + return SUCCESS; } /* */ @@ -575,18 +730,17 @@ STATIC VOID wipe_out_clusters(struct dpb FAR * dpbp, CLUSTER st) /* 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 */ + while (st != LONG_LAST_CLUSTER) { /* get the next cluster pointed to */ next = next_cluster(dpbp, st); /* just exit if a damaged file system exists */ - if (next <= 1) + if (next == FREE || next == 1) return; /* zap the FAT pointed to */ - if (link_fat(dpbp, st, FREE) != SUCCESS) /* nonfree->free */ - return; /* better abort on error */ + link_fat(dpbp, st, FREE); /* and the start of free space pointer */ #ifdef WITHFAT32 @@ -597,7 +751,7 @@ STATIC VOID wipe_out_clusters(struct dpb FAR * dpbp, CLUSTER st) } else #endif - if ((dpbp->dpb_cluster == UNKNCLUSTER) || (dpbp->dpb_cluster > (UWORD)st)) + if ((dpbp->dpb_cluster == UNKNCLUSTER) || (dpbp->dpb_cluster > st)) dpbp->dpb_cluster = (UWORD)st; /* and just follow the linked list */ @@ -609,16 +763,14 @@ STATIC VOID wipe_out_clusters(struct dpb FAR * dpbp, CLUSTER st) #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... */ + if (fnp && !checkdstart(fnp->f_dpb, &fnp->f_dir, FREE)) + wipe_out_clusters(fnp->f_dpb, getdstart(fnp->f_dpb, &fnp->f_dir)); } STATIC BOOL find_free(f_node_ptr fnp) @@ -629,17 +781,19 @@ STATIC BOOL find_free(f_node_ptr fnp) { if (fnp->f_dir.dir_name[0] == DELETED) return TRUE; - fnp->f_dmp->dm_entry++; + fnp->f_diroff++; } return rc >= 0; } -/* alloc_find_free: resets the directory */ -/* Then finds a spare directory entry and if not */ +/* alloc_find_free: resets the directory by a close followed by */ +/* an open. 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) +STATIC int alloc_find_free(f_node_ptr fnp, char *path, char *fcbname) { - fnp = split_path(path, fnp); + fnp->f_flags &= ~F_DMOD; + dir_close(fnp); + fnp = split_path(path, fcbname); /* Get a free f_node pointer so that we can use */ /* it in building the new file. */ @@ -647,8 +801,10 @@ STATIC int alloc_find_free(f_node_ptr fnp, char *path) /* find an empty slot, we need to abort. */ if (find_free(fnp) == 0) { - if (fnp->f_dmp->dm_dircluster == 0) + if (fnp->f_dirstart == 0) { + fnp->f_flags &= ~F_DMOD; + dir_close(fnp); return DE_TOOMANY; } else @@ -668,27 +824,129 @@ STATIC int alloc_find_free(f_node_ptr fnp, char *path) /* */ /* dos_getdate for the file date */ /* */ -ddate dos_getdate(void) +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); + /* Convert to FAT date format: yyyy yyym mmmd dddd (yyyyyyy=year-1980) */ + return ((dd.year - 1980) << 9) | (dd.month << 5) | dd.monthday; } /* */ /* dos_gettime for the file time */ /* */ -dtime dos_gettime(void) +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); + /* Convert to FAT time format: hhhh hmmm mmmd dddd (d = double second) */ + return (dt.hour << 11) | (dt.minute << 5) | (dt.second >> 1); +} + +/* */ +/* dos_getftime for the file time */ +/* */ +COUNT dos_getftime(COUNT fd, date FAR * dp, time FAR * tp) +{ + f_node_ptr fnp; + + /* Translate the fd into an fnode pointer, since all internal */ + /* operations are achieved through fnodes. */ + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return DE_INVLDHNDL; + + /* Get the date and time from the fnode and return */ + *dp = fnp->f_dir.dir_date; + *tp = fnp->f_dir.dir_time; + + release_near_f_node(fnp); + return SUCCESS; +} + +/* */ +/* dos_setftime for the file time */ +/* */ +COUNT dos_setftime(COUNT fd, date dp, time tp) +{ + f_node_ptr fnp; + + /* Translate the fd into an fnode pointer, since all internal */ + /* operations are achieved through fnodes. */ + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return DE_INVLDHNDL; + + /* Set the date and time from the fnode and return */ + fnp->f_dir.dir_date = dp; + fnp->f_dir.dir_time = tp; + /* mark file as modified and set this date upon closing */ + fnp->f_flags |= F_DMOD | F_DDATE; + + save_far_f_node(fnp); + return SUCCESS; +} + +/* */ +/* dos_getfsize for the file time */ +/* */ +ULONG dos_getfsize(COUNT fd) +{ + f_node_ptr fnp; + + /* Translate the fd into an fnode pointer, since all internal */ + /* operations are achieved through fnodes. */ + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return (ULONG)-1l; + + /* Return the file size */ + release_near_f_node(fnp); + return fnp->f_dir.dir_size; +} + +/* */ +/* dos_setfsize for the file time */ +/* */ +BOOL dos_setfsize(COUNT fd, LONG size) +{ + f_node_ptr fnp; + + /* Translate the fd into an fnode pointer, since all internal */ + /* operations are achieved through fnodes. */ + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return FALSE; + + /* Change the file size */ + fnp->f_dir.dir_size = size; + + merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ + save_far_f_node(fnp); + + return TRUE; } /* */ @@ -696,7 +954,7 @@ dtime dos_gettime(void) /* */ STATIC CLUSTER find_fat_free(f_node_ptr fnp) { - REG CLUSTER idx, size, cluster; + REG CLUSTER idx, size; struct dpb FAR *dpbp = fnp->f_dpb; #ifdef DISPLAY_GETBLOCK @@ -721,68 +979,37 @@ STATIC CLUSTER find_fat_free(f_node_ptr fnp) /* Search the FAT table looking for the first free */ /* entry. */ - cluster = idx; - for (;;) + for (; idx <= size; idx++) { -#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; + dpbp->dpb_xcluster = idx; + if (idx > size) + { + /* No empty clusters, disk is FULL! */ + dpbp->dpb_xcluster = UNKNCLUSTER; + idx = LONG_LAST_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++) + dpbp->dpb_cluster = (UWORD)idx; + if ((UWORD)idx > (UWORD)size) { - 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 */ + /* No empty clusters, disk is FULL! */ + dpbp->dpb_cluster = UNKNCLUSTER; + idx = LONG_LAST_CLUSTER; } - return SUCCESS; + /* return the free entry */ + return idx; } /* */ @@ -792,8 +1019,19 @@ STATIC int clear_dir(f_node_ptr fnp, CLUSTER cluster) COUNT dos_mkdir(BYTE * dir) { REG f_node_ptr fnp; + REG COUNT idx; + struct buffer FAR *bp; + struct dpb FAR *dpbp; CLUSTER free_fat, parent; COUNT ret; + char fcbname[FNAME_SIZE + FEXT_SIZE]; + + /* first split the passed dir into components (i.e. - */ + /* path to new directory and name of new directory */ + if ((fnp = split_path(dir, fcbname)) == NULL) + { + return DE_PATHNOTFND; + } /* check that the resulting combined path does not exceed the 67 MAX_CDSPATH limit. this leads to problems: @@ -804,18 +1042,22 @@ COUNT dos_mkdir(BYTE * dir) is lost forever */ if (strlen(dir) >= MAX_CDSPATH) /* dir is already output of "truename" */ + { + dir_close(fnp); 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; + if (find_fname(fnp, fcbname, D_ALL)) + { + dir_close(fnp); + return DE_ACCESS; + } - parent = fnp->f_dmp->dm_dircluster; + parent = fnp->f_dirstart; - ret = alloc_find_free(fnp, dir); + ret = alloc_find_free(fnp, dir, fcbname); if (ret != SUCCESS) return ret; @@ -828,59 +1070,92 @@ COUNT dos_mkdir(BYTE * dir) /* No empty clusters, disk is FULL! Translate into a */ /* useful error message. */ if (free_fat == LONG_LAST_CLUSTER) + { + dir_close(fnp); return DE_HNDLDSKFULL; + } - init_direntry(&fnp->f_dir, D_DIR, free_fat, fnp->f_dmp->dm_name_pat); + /* Set the fnode to the desired mode */ + fnp->f_mode = WRONLY; - /* 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 */ + init_direntry(&fnp->f_dir, D_DIR, free_fat, fcbname); - /* clean out the new directory */ - ret = clear_dir(fnp, free_fat); - if (ret != SUCCESS) - return ret; + fnp->f_flags = F_DMOD | F_DDIR; - /* Write the new directory entry */ - if (!dir_write(fnp)) - return DE_ACCESS; + fnp->f_offset = 0l; - /* Craft the new directory. Note that if we're in a new */ - /* directory just under the root, ".." pointer is 0. */ + /* Mark the cluster in the FAT as used */ + dpbp = fnp->f_dpb; + link_fat(dpbp, free_fat, LONG_LAST_CLUSTER); - dir_init_fnode(fnp, free_fat); - fnp->f_dmp->dm_entry = 0; - find_free(fnp); + /* Craft the new directory. Note that if we're in a new */ + /* directory just under the root, ".." pointer is 0. */ + /* as we are overwriting it completely, don't read first */ + bp = getblockOver(clus2phys(free_fat, dpbp), dpbp->dpb_unit); +#ifdef DISPLAY_GETBLOCK + printf("FAT (dos_mkdir)\n"); +#endif + if (bp == NULL) + { + dir_close(fnp); + return DE_BLKINVLD; + } /* Create the "." entry */ - init_direntry(&fnp->f_dir, D_DIR, free_fat, ". "); + init_direntry(&DirEntBuffer, D_DIR, free_fat, ". "); /* And put it out */ - if (!dir_write(fnp)) - return DE_ACCESS; + putdirent(&DirEntBuffer, bp->b_buffer); /* create the ".." entry */ - if (!find_free(fnp) && ((ret = extend_dir(fnp)) != SUCCESS)) - return ret; + DirEntBuffer.dir_name[1] = '.'; #ifdef WITHFAT32 - if (ISFAT32(fnp->f_dpb) && parent == fnp->f_dpb->dpb_xrootclst) + if (ISFAT32(dpbp) && parent == dpbp->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] = '.'; + setdstart(dpbp, &DirEntBuffer, parent); /* and put it out */ - if (!dir_write(fnp)) - return DE_ACCESS; + putdirent(&DirEntBuffer, &bp->b_buffer[DIRENT_SIZE]); + + /* fill the rest of the block with zeros */ + fmemset(&bp->b_buffer[2 * DIRENT_SIZE], 0, BUFFERSIZE - 2 * DIRENT_SIZE); + + /* Mark the block to be written out */ + bp->b_flag |= BFR_DIRTY | BFR_VALID; + + /* clear out the rest of the blocks in the cluster */ + for (idx = 1; idx <= dpbp->dpb_clsmask; idx++) + { + + /* as we are overwriting it completely, don't read first */ + bp = getblockOver(clus2phys(getdstart(dpbp, &fnp->f_dir), dpbp) + idx, + dpbp->dpb_unit); +#ifdef DISPLAY_GETBLOCK + printf("DIR (dos_mkdir)\n"); +#endif + if (bp == NULL) + { + dir_close(fnp); + return DE_BLKINVLD; + } + fmemset(bp->b_buffer, 0, BUFFERSIZE); + bp->b_flag |= BFR_DIRTY | BFR_VALID | BFR_UNCACHE; /* need not be cached */ + } + + /* flush the drive buffers so that all info is written */ + /* hazard: no error checking! */ + flush_buffers(dpbp->dpb_unit); + + /* Close the directory so that the entry is updated */ + fnp->f_flags |= F_DMOD; + dir_close(fnp); 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; @@ -893,49 +1168,62 @@ STATIC CLUSTER extend(f_node_ptr fnp) 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 */ + /* Now that we've found a free FAT entry, mark it as the last */ + /* entry and save. */ + if (fnp->f_cluster == FREE) + setdstart(fnp->f_dpb, &fnp->f_dir, free_fat); 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 */ - } + link_fat(fnp->f_dpb, fnp->f_cluster, free_fat); + link_fat(fnp->f_dpb, free_fat, LONG_LAST_CLUSTER); + /* Mark the directory so that the entry is updated */ + fnp->f_flags |= F_DMOD; return free_fat; } STATIC COUNT extend_dir(f_node_ptr fnp) { - int ret; + REG COUNT idx; + CLUSTER cluster = extend(fnp); if (cluster == LONG_LAST_CLUSTER) + { + dir_close(fnp); return DE_HNDLDSKFULL; + } - ret = clear_dir(fnp, cluster); - if (ret != SUCCESS) - return ret; + /* clear out the blocks in the cluster */ + for (idx = 0; idx <= fnp->f_dpb->dpb_clsmask; idx++) + { + REG 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 (extend_dir)\n"); +#endif + if (bp == NULL) + { + dir_close(fnp); + return DE_BLKINVLD; + } + 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 */ + } if (!find_free(fnp)) + { + dir_close(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; + /* hazard: no error checking! */ + flush_buffers(fnp->f_dpb->dpb_unit); return SUCCESS; @@ -944,7 +1232,7 @@ STATIC COUNT extend_dir(f_node_ptr fnp) /* 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 + * a file or a directory depending whether fnp->f_ddir is FALSE or TRUE * 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 @@ -993,10 +1281,8 @@ COUNT map_cluster(REG f_node_ptr fnp, COUNT mode) 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 : + fnp->f_cluster = (fnp->f_flags & F_DDIR) ? fnp->f_dirstart : getdstart(fnp->f_dpb, &fnp->f_dir); fnp->f_cluster_offset = 0; } @@ -1012,7 +1298,7 @@ COUNT map_cluster(REG f_node_ptr fnp, COUNT mode) { /* 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 */ + if (cluster == 1) return DE_SEEK; /* If this is a read and the next is a LAST_CLUSTER, */ @@ -1042,13 +1328,13 @@ COUNT map_cluster(REG f_node_ptr fnp, COUNT mode) } /* extends a file from f_dir.dir_size to f_offset */ -/* Proper OSes write zeros in between, but DOS just adds */ +/* Proper OS's 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, BOOL emptywrite) +STATIC COUNT dos_extend(f_node_ptr fnp) { #ifdef WRITEZEROS struct buffer FAR *bp; @@ -1068,39 +1354,8 @@ STATIC COUNT dos_extend(f_node_ptr fnp, BOOL emptywrite) while (count > 0) #endif { - BOOL special = 0; - if (emptywrite -#ifdef WRITEZEROS - && fnp->f_offset != 0 -#else - /* f_offset != 0 always true here */ -#endif - && ((fnp->f_offset & - (((ULONG)fnp->f_dpb->dpb_secsize - << fnp->f_dpb->dpb_shftcnt) - 1) - ) - == 0) - ) { - special = 1; - -- fnp->f_offset; - } - if (map_cluster(fnp, XFR_WRITE) != SUCCESS) { - if (special) ++ fnp->f_offset; - if (fnp->f_cluster != FREE) { - /* ecm: write size if couldn't satisfy full request, - but at least one cluster is allocated. */ - fnp->f_dir.dir_size = - (((ULONG)fnp->f_cluster_offset + 1) - /* at 0 we have incremented to 1, having allocated the second - cluster, so + 1 for the then-total size. */ - * (ULONG)fnp->f_dpb->dpb_secsize) - << - fnp->f_dpb->dpb_shftcnt; - merge_file_changes(fnp, FALSE); - } + if (map_cluster(fnp, XFR_WRITE) != SUCCESS) return DE_HNDLDSKFULL; - } - if (special) ++ fnp->f_offset; #ifdef WRITEZEROS /* Compute the block within the cluster and the offset */ @@ -1110,39 +1365,18 @@ STATIC COUNT dos_extend(f_node_ptr fnp, BOOL emptywrite) #ifdef DSK_DEBUG printf("write %d links; dir offset %ld, cluster %d\n", - fnp->f_count, fnp->f_dmp->dm_entry, fnp->f_cluster); + fnp->f_count, fnp->f_diroff, 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); - } + bp = getblk(clus2phys(fnp->f_cluster, fnp->f_dpb) + sector, + fnp->f_dpb->dpb_unit, boff == 0 && xfr_cnt == secsize); if (bp == NULL) { - if (fnp->f_cluster != FREE) { - /* ecm: write size if couldn't satisfy full request, - but at least one cluster is allocated. */ - fnp->f_dir.dir_size = - (((ULONG)fnp->f_cluster_offset + 1) - /* at 0 we have incremented to 1, having allocated the second - cluster, so + 1 for the then-total size. */ - * (ULONG)fnp->f_dpb->dpb_secsize) - << - fnp->f_dpb->dpb_shftcnt; - merge_file_changes(fnp, FALSE); - } - return DE_ACCESS; + return DE_BLKINVLD; } /* set a block to zero */ @@ -1233,9 +1467,7 @@ STATIC COUNT dos_extend(f_node_ptr fnp, BOOL emptywrite) 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 f_node_ptr fnp; REG struct buffer FAR *bp; UCOUNT xfr_cnt = 0; UCOUNT ret_cnt = 0; @@ -1250,30 +1482,29 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) fd, FP_SEG(buffer), FP_OFF(buffer), count); } #endif + /* Translate the fd into an fnode pointer, since all internal */ + /* operations are achieved through fnodes. */ + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + { + return 0; + } 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); + fnp->f_flags |= F_DMOD; /* mark file as modified */ + fnp->f_flags &= ~F_DDATE; /* set date not valid any more */ - if (dos_extend(fnp, count == 0) != SUCCESS) + if (dos_extend(fnp) != SUCCESS) { - /* ecm: control flow may end up here if CX = 0000h and - the extending failed to allocate a cluster - behind the last needed. in this case, our - return here of 0 happens to be correct and - indicates the extension succeeded. */ - fnode_to_sft(fnp); + save_far_f_node(fnp); return 0; } - /* ecm: if CX = 0000h and seek was on a cluster boundary > size, - the dos_extend call will have allocated one cluster - too many. this is truncated later without problems. - but does this aid fragmentation maybe ? - if CX > 0000h then we want to write to the cluster - anyway, so extending to the cluster that starts at - the boundary is desired. */ } /* Test that we are really about to do a data transfer. If the */ @@ -1294,32 +1525,12 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) 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? */ + shrink_file(fnp); } - fnode_to_sft(fnp); + save_far_f_node(fnp); return 0; } - /* prevent overwriting beginning of file when write exceeds 4GB, - i.e. when overflow of offset occurs, return error on write */ - if (fnp->f_offset + count < fnp->f_offset) /* unsigned overflow */ - { - if (mode == XFR_WRITE) - { -#if 1 /* we fail write call even if could partially succeed */ - /* can't extend beyond 4G so return '0 byte written, DISK_FULL */ - return DE_HNDLDSKFULL; -#else - /* truncate request to max size can write */ - ULONG max_count = (ULONG)-1 - fnp->f_offset; - count = (max_count >= (UCOUNT)-1)?(UCOUNT)-1:(UCOUNT)max_count; -#endif - } - /* else XFR_READ should end automatically at EOF */ - } - /* The variable secsize will be used later. */ secsize = fnp->f_dpb->dpb_secsize; @@ -1333,9 +1544,10 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) unsigned sector, boff; /* Do an EOF test and return whatever was transferred */ - if (mode == XFR_READ && fnp->f_offset >= fnp->f_dir.dir_size) + /* but only for regular files. */ + if (mode == XFR_READ && !(fnp->f_flags & F_DDIR) && (fnp->f_offset >= fnp->f_dir.dir_size)) { - fnode_to_sft(fnp); + save_far_f_node(fnp); return ret_cnt; } @@ -1366,7 +1578,7 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) #endif if (map_cluster(fnp, mode) != SUCCESS) { - fnode_to_sft(fnp); + save_far_f_node(fnp); return ret_cnt; } if (mode == XFR_WRITE) @@ -1383,44 +1595,38 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) /* see comments above */ - if (boff == 0) /* complete sectors only */ + if (!(fnp->f_flags & F_DDIR) && /* don't experiment with directories yet */ + boff == 0) /* complete sectors only */ { static ULONG startoffset; UCOUNT sectors_to_xfer, sectors_wanted; startoffset = fnp->f_offset; - sectors_wanted = to_xfer; + sectors_wanted = (UCOUNT)(fnp->f_dir.dir_size - fnp->f_offset); /* 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); - + if (mode != XFR_READ || to_xfer <= sectors_wanted) + sectors_wanted = to_xfer; 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); + for (sectors_to_xfer = -sector; ; ) + { + 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; - fnp->f_offset += sectors_to_xfer * secsize; + if (sectors_to_xfer >= sectors_wanted) + break; - 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; @@ -1437,7 +1643,7 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) mode == XFR_READ ? DSKREAD : DSKWRITE)) { fnp->f_offset = startoffset; - fnode_to_sft(fnp); + save_far_f_node(fnp); return DE_ACCESS; } @@ -1449,7 +1655,7 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) #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); + fnp->f_count, fnp->f_diroff, fnp->f_cluster, mode); #endif /* Get the block we need from cache */ @@ -1462,7 +1668,7 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) #endif if (bp == NULL) /* (struct buffer *)0 --> DS:0 !! */ { - fnode_to_sft(fnp); + save_far_f_node(fnp); return ret_cnt; } @@ -1472,7 +1678,7 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) /* 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) + if (!(fnp->f_flags & F_DDIR) && mode == XFR_READ) xfr_cnt = (UWORD) min(xfr_cnt, fnp->f_dir.dir_size - fnp->f_offset); /* transfer a block */ @@ -1515,17 +1721,61 @@ long rwblock(COUNT fd, VOID FAR * buffer, UCOUNT count, int mode) merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */ } } - fnode_to_sft(fnp); + save_far_f_node(fnp); return ret_cnt; } +/* Position the file pointer to the desired offset */ +/* Returns a long current offset or a negative error code */ +LONG dos_lseek(COUNT fd, LONG foffset, COUNT origin) +{ + REG f_node_ptr fnp; + + /* Translate the fd into a useful pointer */ + + fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + + if (fnp == (f_node_ptr) 0) + return (LONG) DE_INVLDHNDL; + + /* now do the actual lseek adjustment to the file poitner */ + switch (origin) + { + /* offset from beginning of file */ + case SEEK_SET: + fnp->f_offset = (ULONG) foffset; + break; + + /* offset from current location */ + case SEEK_CUR: + fnp->f_offset += foffset; + break; + + /* offset from eof */ + case SEEK_END: + fnp->f_offset = fnp->f_dir.dir_size + foffset; + break; + + /* default to an invalid function */ + default: + release_near_f_node(fnp); + return (LONG) DE_INVLDFUNC; + } + save_far_f_node(fnp); + return fnp->f_offset; +} + /* 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; + REG CLUSTER cnt = 0; CLUSTER max_cluster = dpbp->dpb_size; #ifdef WITHFAT32 @@ -1537,30 +1787,14 @@ CLUSTER dos_free(struct dpb FAR * dpbp) } else #endif - if (dpbp->dpb_nfreeclst != UNKNCLSTFREE) + /* only for testing, limit returning cached entry to FAT32, ie always recalc */ + if (/* ISFAT32(dpbp) && */(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; - } + if (next_cluster(dpbp, i) == 0) ++cnt; - } } #ifdef WITHFAT32 if (ISFAT32(dpbp)) @@ -1578,63 +1812,130 @@ CLUSTER dos_free(struct dpb FAR * dpbp) int dos_cd(char * PathName) { f_node_ptr fnp; - struct cds FAR *cdsp; + struct cds FAR *cdsp = get_cds(PathName[0] - 'A'); + + if ((media_check(cdsp->cdsDpb) < 0)) + return DE_INVLDDRV; /* now test for its existance. If it doesn't, return an error. */ - if ((fnp = dir_open(PathName, FALSE, &fnode[0])) == NULL) + if ((fnp = dir_open(PathName)) == 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; + cdsp->cdsStrtClst = (UWORD)fnp->f_dirstart; + dir_close(fnp); return SUCCESS; } #endif +/* try to allocate a near f_node */ +/* (there are just two of them, in the SDA) */ +f_node_ptr get_near_f_node(void) +{ + f_node_ptr fnp = fnode; + DDebugPrintf(("get_near_f_node: fnp is %p\n", fnp)); + if (fnp->f_count && (++fnp)->f_count) + panic("more than two near fnodes requested at the same time!\n"); + fnp->f_count++; + DDebugPrintf(("got near fnode, fnp->f_count=%i\n", fnp->f_count)); + return fnp; +} + +/* Try to allocate an f_node from the available files array */ +f_node_ptr get_f_node(void) +{ + REG int i; + f_node_ptr fnp = get_near_f_node(); + + if (fnp != (f_node_ptr)0) + { + FatFSDbgPrintf(("get_f_node: &f_nodes[0]=%p, f_nodes_cnt=%i\n", (void far *)&f_nodes, f_nodes_cnt)); + for (i = 0; i < f_nodes_cnt; i++) + { + if (f_nodes[i].f_count == 0) + { + ++f_nodes[i].f_count; + fnode_fd[fnp - fnode] = i; + FatFSDbgPrintf(("f_nodes[%i].f_count=%i, fnode_fd[%i]=%i\n", \ + i, f_nodes[i].f_count, (fnp-fnode), i)); + return fnp; + } + } + release_near_f_node(fnp); + FatFSDbgPrintf(("get_f_node: failure finding free entry in f_nodes[]\n")); + } + else FatFSDbgPrintf(("get_f_node: get_near_fnode() failed, returned NULL\n")); + return (f_node_ptr) 0; +} + +VOID release_f_node(f_node_ptr fnp) +{ + struct f_node FAR *fp = &f_nodes[xlt_fnp(fnp)]; + + FatFSDbgPrintf(("release_f_node: fp->f_count=%i\n", fp->f_count)); + + if (fp->f_count > 0) + --fp->f_count; + else + fp->f_count = 0; + release_near_f_node(fnp); +} + #ifndef IPL +COUNT dos_getfattr_fd(COUNT fd) +{ + f_node_ptr fnp = xlt_fd(fd); + + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + if (fnp == (f_node_ptr) 0) + return DE_TOOMANY; + + release_near_f_node(fnp); + return fnp->f_dir.dir_attrib; +} + 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 result, fd; + + fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0); + if (fd < SUCCESS) + return fd; + + result = dos_getfattr_fd(fd); + dos_close(fd); + return result; } COUNT dos_setfattr(BYTE * name, UWORD attrp) { + COUNT fd; 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) + /* JPP-If user tries to set VOLID or DIR bits, return error */ + if ((attrp & (D_VOLID | D_DIR | 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; + fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0); + if (fd < SUCCESS) + return fd; + fnp = xlt_fd(fd); + /* 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; + fnp->f_flags |= F_DMOD | F_DDATE; + merge_file_changes(fnp, FALSE); + save_far_f_node(fnp); + dos_close(fd); + return SUCCESS; } #endif @@ -1659,17 +1960,13 @@ VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp) bpb sbpb; fmemcpy(&sbpb, bpbp, sizeof(sbpb)); - if (sbpb.bpb_nsector == 0) { - shftcnt = 8; - } else { - for (shftcnt = 0; (sbpb.bpb_nsector >> shftcnt) > 1; shftcnt++) - ; - } + 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) & 0xFF; + 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; @@ -1711,9 +2008,7 @@ ckok:; : 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; @@ -1772,97 +2067,90 @@ COUNT media_check(REG struct dpb FAR * dpbp) return DE_INVLDDRV; /* First test if anyone has changed the removable media */ + DDebugPrintf(("do media check...\n")); ret = rqblockio(C_MEDIACHK, dpbp); if (ret < SUCCESS) + { + FatFSDbgPrintf(("media_check: failed\n")); return ret; + } + DDebugPrintf(("mcr=%s, dpb_flags=%04xh\n", (MediaReqHdr.r_mcretcode==1)?"none":"possible", dpbp->dpb_flags)); switch (MediaReqHdr.r_mcretcode | dpbp->dpb_flags) { case M_NOT_CHANGED: /* It was definitely not changed, so ignore it */ + DDebugPrintf(("media_check: no change\n")); 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; + /* hazard: no error checking! */ + DDebugPrintf(("media_check: unknown\n")); + flush_buffers(dpbp->dpb_unit); /* If it definitely changed, don't know (falls through) */ /* or has been changed, rebuild the bpb. */ - /* case M_CHANGED: */ + /* case M_CHANGED: */ default: + DDebugPrintf(("media_check: assumming changed\n")); setinvld(dpbp->dpb_unit); ret = rqblockio(C_BLDBPB, dpbp); if (ret < SUCCESS) + { + DebugPrintf(("media_check: build BPB failed\n")); 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)); + ISFAT32(dpbp) || FP_SEG(dpbp) == FP_SEG(&os_major)); #else bpb_to_dpb(MediaReqHdr.r_bpptr, dpbp); #endif + DDebugPrintf(("media_check: returning ok\n")); return SUCCESS; } } -/* copy the SFT fd into the first near fnode */ -STATIC f_node_ptr sft_to_fnode(int fd) +/* allocate a near fnode and copy the far fd fnode to it */ +f_node_ptr xlt_fd(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; + f_node_ptr fnp = (f_node_ptr) 0; - 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 + /* If the fd was invalid because it was out of range or the */ + /* requested file was not open, tell the caller and exit */ + /* note: an invalid fd is indicated by a 0 return */ + FatFSDbgPrintf(("xlt_fd: fd(%i) ?< f_nodes_cnt(%i)\n", fd, f_nodes_cnt)); + if (fd < f_nodes_cnt) + { + fnp = get_near_f_node(); + if (fnp != (f_node_ptr)0) + { + fmemcpy(fnp, &f_nodes[fd], sizeof(*fnp)); + FatFSDbgPrintf(("xlt_fd: fnp->f_count=%i, fnp-fnode=%i\n", fnp->f_count, (fnp-fnode))); + if (fnp->f_count <= 0) + { + release_near_f_node(fnp); + fnp = (f_node_ptr) 0; + } else + { + fnode_fd[fnp - fnode] = fd; + FatFSDbgPrintf(("xlt_fd: success\n")); + } + } + else FatFSDbgPrintf(("xlt_fd: get_near_f_node failed\n")); + } return fnp; } -STATIC void fnode_to_sft(f_node_ptr fnp) +/* copy a near fnode to the corresponding far one and release it */ +STATIC void save_far_f_node(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 + FatFSDbgPrintf(("save_far_f_node: copying near fnode to far one\n")); + fmemcpy(&f_nodes[xlt_fnp(fnp)], fnp, sizeof(*fnp)); + release_near_f_node(fnp); } /* TE @@ -1880,28 +2168,26 @@ STATIC void fnode_to_sft(f_node_ptr fnp) Apps tested (VB ISAM); BO: confirmation??? */ -STATIC int shrink_file(f_node_ptr fnp) +STATIC VOID shrink_file(f_node_ptr fnp) { ULONG lastoffset = fnp->f_offset; /* has to be saved */ - CLUSTER last, next, st; + CLUSTER next, st; struct dpb FAR *dpbp = fnp->f_dpb; - int ret = DE_ACCESS; + + fnp->f_offset = fnp->f_dir.dir_size; /* end of file */ 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 */ + next = next_cluster(dpbp, st); - if (next <= 1) /* 1/error or 0/FREE chain points into the void */ + if (next == 1) /* error */ goto done; /* Loop from start until either a FREE entry is */ @@ -1909,32 +2195,24 @@ STATIC int shrink_file(f_node_ptr fnp) /* last cluster is encountered. */ /* zap the FAT pointed to */ - if (fnp->f_dir.dir_size == 0) /* file shrinks to size 0 */ + if (fnp->f_dir.dir_size == 0) { fnp->f_cluster = FREE; - setdstart(dpbp, &fnp->f_dir, FREE); /* file no longer has start cluster */ - last = FREE; + setdstart(dpbp, &fnp->f_dir, FREE); + link_fat(dpbp, st, 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 (next == LONG_LAST_CLUSTER) /* nothing to do */ + goto done; + link_fat(dpbp, st, LONG_LAST_CLUSTER); } - 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; + wipe_out_clusters(dpbp, next); done: fnp->f_offset = lastoffset; /* has to be restored */ - return ret; + } /* diff --git a/kernel/fattab.c b/kernel/fattab.c index 12e1a2bd..07a02e41 100644 --- a/kernel/fattab.c +++ b/kernel/fattab.c @@ -31,7 +31,7 @@ #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: fattab.c 1631 2011-06-13 16:27:34Z bartoldeman $"; + "$Id$"; #endif /************************************************************************/ @@ -44,27 +44,8 @@ static BYTE *RcsId = 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) @@ -73,7 +54,7 @@ struct buffer FAR *getFATblock(struct dpb FAR * dpbp, CLUSTER clussec) 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 */ + bp->b_offset = dpbp->dpb_fatsize; #ifdef WITHFAT32 if (ISFAT32(dpbp)) { @@ -81,8 +62,6 @@ struct buffer FAR *getFATblock(struct dpb FAR * dpbp, CLUSTER clussec) bp->b_copies = 1; } #endif - } else { - clusterMessage("I/O: 0x",clussec); } return bp; } @@ -92,25 +71,14 @@ 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; + dpbp->dpb_xnfreeclst = fip->fi_nfreeclst; + dpbp->dpb_xcluster = fip->fi_cluster; } void write_fsinfo(struct dpb FAR * dpbp) @@ -118,19 +86,11 @@ 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; + bp->b_flag |= BFR_VALID | BFR_DIRTY; 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; } @@ -138,10 +98,10 @@ void write_fsinfo(struct dpb FAR * dpbp) /* */ /* 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 */ +/* There are two kinds of FAT's, 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: */ +/* of UWORD's. The 12 bit FAT is difficult, because it packs 3 */ +/* FAT entries into two BYTE's. These are packed as follows: */ /* */ /* 0x0003 0x0004 0x0005 0x0006 0x0007 0x0008 0x0009 ... */ /* */ @@ -152,19 +112,13 @@ void write_fsinfo(struct dpb FAR * dpbp) /* 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; + unsigned secdiv; + unsigned char wasfree = 0; CLUSTER clussec = Cluster1; CLUSTER max_cluster = dpbp->dpb_size; @@ -173,17 +127,14 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, max_cluster = dpbp->dpb_xsize; #endif - if (clussec <= 1 || clussec > max_cluster) /* try to read out of range? */ + if (clussec <= 1 || clussec > max_cluster) { - 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 */ + put_string("run CHKDSK: trying to access invalid cluster 0x"); +#ifdef WITHFAT32 + put_unsigned((unsigned)(clussec >> 16), 16, 4); +#endif + put_unsigned((unsigned)(clussec & 0xffffu), 16, 4); + put_console('\n'); return 1; } @@ -220,13 +171,12 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, /* Get the block that this cluster is in */ bp = getFATblock(dpbp, clussec); - if (bp == NULL) { + if (bp == NULL) return 1; /* the only error code possible here */ - } if (ISFAT12(dpbp)) { - REG UBYTE FAR *fbp0; REG UBYTE FAR * fbp1; + REG UBYTE FAR *fbp0, FAR * fbp1; struct buffer FAR * bp1; unsigned cluster, cluster2; @@ -250,7 +200,7 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, if (bp1 == 0) return 1; /* the only error code possible here */ - if (Cluster2 != READ_CLUSTER) + if ((unsigned)Cluster2 != READ_CLUSTER) bp1->b_flag |= BFR_DIRTY | BFR_VALID; fbp1 = &bp1->b_buffer[0]; @@ -275,11 +225,8 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, return LONG_BAD; return cluster; } - - wasfree = 0; if (cluster == FREE) - wasfree = 1; - + wasfree++; cluster = res; } @@ -288,7 +235,7 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, cluster2 = (unsigned)Cluster2 & 0x0fff; /* Now pack the value in */ - if ((unsigned)Cluster1 & 0x01) + if (Cluster1 & 0x01) { cluster &= 0x000f; cluster2 <<= 4; @@ -319,9 +266,8 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, /* 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; + wasfree++; } #ifdef WITHFAT32 else if (ISFAT32(dpbp)) @@ -339,15 +285,12 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, /* 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; + wasfree++; } #endif - else { - put_string("Bad DPB!\n"); /* FAT1x size field > 65525U (see fat.h) */ + else return 1; - } /* update the free space count */ bp->b_flag |= BFR_DIRTY | BFR_VALID; @@ -355,9 +298,9 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, { int adjust = 0; if (!wasfree) - adjust = 1; + adjust++; else if (Cluster2 != FREE) - adjust = -1; + adjust--; #ifdef WITHFAT32 if (ISFAT32(dpbp) && dpbp->dpb_xnfreeclst != XUNKNCLSTFREE) { @@ -374,40 +317,10 @@ CLUSTER link_fat(struct dpb FAR * dpbp, CLUSTER Cluster1, 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. */ +/* Given the disk parameters, and a cluster number, this function + looks at the FAT, and returns the next cluster in the clain. */ 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; + return link_fat(dpbp, ClusterNum, READ_CLUSTER); } -/* 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 index a2ddba95..576aec7d 100644 --- a/kernel/fcbfns.c +++ b/kernel/fcbfns.c @@ -31,7 +31,7 @@ #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: fcbfns.c 1405 2009-05-26 20:44:44Z bartoldeman $"; + "$Id$"; #endif #define FCB_SUCCESS 0 @@ -47,38 +47,33 @@ 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(":;,=+ \t", *lpFileName) != NULL) -#define TestFieldSeps(lpFileName) ((unsigned char)*lpFileName <= ' ' || strchr("/\\\"[]<>|.:;,=+\t", *lpFileName) != NULL) +#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) +UBYTE FAR *FatGetDrvData(UBYTE drive, UBYTE * pspc, UWORD * bps, UWORD * nc) { - static BYTE mdb; - UWORD spc; + /* get the data available from dpb */ + UWORD spc = DosGetFree(drive, NULL, bps, nc); + if ((*pspc = lobyte(spc)) == 0xff) + return NULL; - /* get the data available from dpb */ - spc = DosGetFree(drive, NULL, bps, nc); - if (spc != 0xffff) + if (drive-- == 0) /* 0 = A:, 1 = B:, ... */ + drive = default_drive; + + /* Point to the media desctriptor for this drive */ { - 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); - } + struct dpb FAR *dpbp; + if ((dpbp = get_dpb(drive)) != NULL) + return &dpbp->dpb_mdb; + } + + { + static UBYTE mdb = 0; + return &mdb; } - return NULL; } -#define PARSE_SKIP_LEAD_SEP 0x01 +#define PARSE_SEP_STOP 0x01 #define PARSE_DFLT_DRIVE 0x02 #define PARSE_BLNK_FNAME 0x04 #define PARSE_BLNK_FEXT 0x08 @@ -88,16 +83,31 @@ BYTE FAR *FatGetDrvData(UBYTE drive, UBYTE * pspc, UWORD * bps, UWORD * nc) #define PARSE_RET_BADDRIVE 0xff #ifndef IPL -UWORD FcbParseFname(UBYTE *wTestMode, const BYTE FAR * lpFileName, fcb FAR * lpFcb) +ofs_t FcbParseFname(UBYTE *wTestMode, const char FAR * lpFileName, fcb FAR * lpFcb) { - WORD wRetCodeDrive = FALSE, wRetCodeName = FALSE, wRetCodeExt = FALSE; + WORD wRetCodeName = FALSE, wRetCodeExt = FALSE; /* pjv -- ExtFcbToFcb? */ - - /* skip leading separators if requested */ - if (*wTestMode & PARSE_SKIP_LEAD_SEP) + /* Start out with some simple stuff first. Check if we are */ + /* going to use a default drive specificaton. */ + if (!(*wTestMode & PARSE_DFLT_DRIVE)) + lpFcb->fcb_drive = FDFLT_DRIVE; + if (!(*wTestMode & PARSE_BLNK_FNAME)) { - while (TestCmnSeps(lpFileName)) + fmemset(lpFcb->fcb_fname, ' ', FNAME_SIZE); + } + if (!(*wTestMode & PARSE_BLNK_FEXT)) + { + fmemset(lpFcb->fcb_fext, ' ', FEXT_SIZE); + } + + /* Undocumented behavior, set record number & record size to 0 */ + lpFcb->fcb_cublock = lpFcb->fcb_recsiz = 0; + + if (!(*wTestMode & PARSE_SEP_STOP)) + { + lpFileName = ParseSkipWh(lpFileName); + if (TestCmnSeps(lpFileName)) ++lpFileName; } @@ -105,39 +115,19 @@ UWORD FcbParseFname(UBYTE *wTestMode, const BYTE FAR * lpFileName, fcb FAR * lpF lpFileName = ParseSkipWh(lpFileName); /* Now check for drive specification */ - /* If drive specified, set to it otherwise */ - /* set to default drive unless leave as-is requested */ - - /* Undocumented behavior: should keep parsing even if drive */ - /* specification is invalid -- tkchia 20220715 */ - /* drive specification can refer to an invalid drive, but must */ - /* not itself be a file name delimiter! -- tkchia 20220716 */ - if (!TestFieldSeps(lpFileName) && *(lpFileName + 1) == ':') + if (*(lpFileName + 1) == ':') { /* non-portable construct to be changed */ REG UBYTE Drive = DosUpFChar(*lpFileName) - 'A'; - if (get_cds(Drive) == NULL) - wRetCodeDrive = TRUE; + if (Drive >= lastdrive) + { + *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 */ - /* per MS-DOS Encyclopedia pp269 no other FCB fields modified */ - /* except zeroing current block and record size fields */ - 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 '..' */ @@ -165,11 +155,8 @@ UWORD FcbParseFname(UBYTE *wTestMode, const BYTE FAR * lpFileName, fcb FAR * lpF GetNameField(++lpFileName, (BYTE FAR *) lpFcb->fcb_fext, FEXT_SIZE, (BOOL *) & wRetCodeExt); - if (wRetCodeDrive) - *wTestMode = PARSE_RET_BADDRIVE; - else if (wRetCodeName | wRetCodeExt) - *wTestMode = PARSE_RET_WILD; - else + *wTestMode = PARSE_RET_WILD; + if (!(wRetCodeName | wRetCodeExt)) *wTestMode = PARSE_RET_NOWILD; return FP_OFF(lpFileName); } @@ -181,6 +168,33 @@ const BYTE FAR * ParseSkipWh(const BYTE FAR * 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) @@ -191,7 +205,8 @@ const BYTE FAR * GetNameField(const BYTE FAR * lpFileName, BYTE FAR * lpDestFiel while (*lpFileName != '\0' && !TestFieldSeps(lpFileName) && nIndex < nFieldSize) { - /* convert * into multiple ? for remaining length of field */ + if (*lpFileName == ' ') + break; if (*lpFileName == '*') { *pbWildCard = TRUE; @@ -199,11 +214,8 @@ const BYTE FAR * GetNameField(const BYTE FAR * lpFileName, BYTE FAR * lpDestFiel ++lpFileName; break; } - /* include ? as-is but flag for return purposes wildcard used */ if (*lpFileName == '?') *pbWildCard = TRUE; - - /* store uppercased character, and advance to next char */ *lpDestField++ = DosUpFChar(*lpFileName++); ++nIndex; } @@ -238,7 +250,6 @@ UBYTE FcbReadWrite(xfcb FAR * lpXfcb, UCOUNT recno, int mode) /* Convert to fcb if necessary */ lpFcb = ExtFcbToFcb(lpXfcb); - recsiz = lpFcb->fcb_recsiz; bigsize = (ULONG)recsiz * recno; if (bigsize > 0xffff) @@ -380,20 +391,7 @@ UBYTE FcbRandomIO(xfcb FAR * lpXfcb, int mode) 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) -*/ +/* merged fcbOpen and FcbCreate - saves ~200 byte */ UBYTE FcbOpen(xfcb FAR * lpXfcb, unsigned flags) { sft FAR *sftp; @@ -417,11 +415,8 @@ UBYTE FcbOpen(xfcb FAR * lpXfcb, unsigned flags) 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 */ @@ -517,8 +512,6 @@ UBYTE FcbDelete(xfcb FAR * lpXfcb) UBYTE FcbRename(xfcb FAR * lpXfcb) { - BYTE buf[FNAME_SIZE + FEXT_SIZE]; - BOOL bWildCard; rfcb FAR *lpRenameFcb; COUNT FcbDrive; UBYTE result = FCB_SUCCESS; @@ -526,10 +519,7 @@ UBYTE FcbRename(xfcb FAR * lpXfcb) /* Build a traditional DOS file name */ lpRenameFcb = (rfcb FAR *) CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); - /* expand wildcards in dest */ - GetNameField(lpRenameFcb->renNewName, buf, FNAME_SIZE, &bWildCard); - GetNameField(lpRenameFcb->renNewExtent, buf + FNAME_SIZE, FEXT_SIZE, &bWildCard); - + /* check for a device */ if (IsDevice(SecPathName)) { @@ -538,7 +528,7 @@ UBYTE FcbRename(xfcb FAR * lpXfcb) else { dmatch Dmatch; - COUNT rc; + COUNT result; wAttr = (lpXfcb->xfcb_flag == 0xff ? lpXfcb->xfcb_attrib : D_ALL); dta = &Dmatch; @@ -549,33 +539,33 @@ UBYTE FcbRename(xfcb FAR * lpXfcb) else do { /* 'A:' + '.' + '\0' */ - BYTE loc_szBuffer[2 + FNAME_SIZE + 1 + FEXT_SIZE + 1]; + char loc_szBuffer[2 + FNAME_SIZE + 1 + FEXT_SIZE + 1]; fcb LocalFcb; BYTE *pToName; const BYTE FAR *pFromPattern = Dmatch.dm_name; - const char *pToPattern = buf; int i; - UBYTE mode = 0; - FcbParseFname(&mode, pFromPattern, &LocalFcb); + loc_szBuffer [0] = 0; /* dummy place */ + FcbParseFname((UBYTE*)loc_szBuffer, 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 (*pToPattern != '?') - *pToName = *pToPattern; - pToName++; - pToPattern++; + if (*pFromPattern != '?') + *pToName = *pFromPattern; + pToName++; + pFromPattern++; } SecPathName[0] = 'A' + FcbDrive - 1; SecPathName[1] = ':'; strcpy(&SecPathName[2], Dmatch.dm_name); - rc = truename(SecPathName, PriPathName, 0); + result = truename(SecPathName, PriPathName, 0); - if (rc < SUCCESS || (rc & IS_DEVICE)) + if (result < SUCCESS || (result & IS_DEVICE)) { result = FCB_ERROR; break; @@ -583,8 +573,8 @@ UBYTE FcbRename(xfcb FAR * lpXfcb) /* now to build a dos name again */ LocalFcb.fcb_drive = FcbDrive; FcbNameInit(&LocalFcb, loc_szBuffer, &FcbDrive); - rc = truename(loc_szBuffer, SecPathName, 0); - if (rc < SUCCESS || (rc & (IS_NETWORK|IS_DEVICE)) == IS_DEVICE + result = truename(loc_szBuffer, SecPathName, 0); + if (result < SUCCESS || (result & (IS_NETWORK|IS_DEVICE)) == IS_DEVICE || DosRenameTrue(PriPathName, SecPathName, wAttr) != SUCCESS) { result = FCB_ERROR; @@ -620,7 +610,7 @@ UBYTE FcbClose(xfcb FAR * lpXfcb) /* 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); + dos_setfsize(s->sft_status, lpFcb->fcb_fsize); DosSetFtimeSft(lpFcb->fcb_sftno, lpFcb->fcb_date, lpFcb->fcb_time); if ((CritErrCode = -DosCloseSft(lpFcb->fcb_sftno, FALSE)) == SUCCESS) { @@ -641,6 +631,10 @@ VOID FcbCloseAll() DosCloseSft(idx, FALSE); } +/* TE suggest, that there was not enough space on stack for + Dmatch in FcbFindFirstNext() --avb */ +static dmatch Dmatch; + UBYTE FcbFindFirstNext(xfcb FAR * lpXfcb, BOOL First) { void FAR *orig_dta = dta; @@ -655,20 +649,17 @@ UBYTE FcbFindFirstNext(xfcb FAR * lpXfcb, BOOL First) /* Next initialze local variables by moving them from the fcb */ lpFcb = CommonFcbInit(lpXfcb, SecPathName, &FcbDrive); - if (First) - { - /* Reconstruct the dirmatch structure from the fcb */ - Dmatch.dm_drive = lpFcb->fcb_sftno; + /* 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); + 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; + Dmatch.dm_attr_srch = wAttr; + Dmatch.dm_entry = lpFcb->fcb_strtclst; + Dmatch.dm_dircluster = lpFcb->fcb_dirclst; - wAttr = D_ALL; - } + wAttr = D_ALL; if ((xfcb FAR *) lpFcb != lpXfcb) { @@ -705,4 +696,3 @@ UBYTE FcbFindFirstNext(xfcb FAR * lpXfcb, BOOL First) return FCB_SUCCESS; } #endif - diff --git a/kernel/globals.h b/kernel/globals.h index 14d0b5c7..2696ab8d 100644 --- a/kernel/globals.h +++ b/kernel/globals.h @@ -27,18 +27,21 @@ /* Cambridge, MA 02139, USA. */ /****************************************************************/ +#ifndef __GLOBALS_H +#define __GLOBALS_H + #ifdef VERSION_STRINGS #ifdef MAIN static BYTE *Globals_hRcsId = - "$Id: globals.h 1705 2012-02-07 08:10:33Z perditionc $"; + "$Id$"; #endif #endif #include "device.h" #include "mcb.h" #include "pcb.h" -#include "ddate.h" -#include "dtime.h" +#include "date.h" +#include "time.h" #include "fat.h" #include "fcb.h" #include "tail.h" @@ -46,8 +49,8 @@ static BYTE *Globals_hRcsId = #include "sft.h" #include "cds.h" #include "exe.h" -#include "dirmatch.h" #include "fnode.h" +#include "dirmatch.h" #include "file.h" #include "clock.h" #include "kbd.h" @@ -156,17 +159,19 @@ typedef BYTE *UPMAP; /* */ /* External Assembly variables */ /* */ -extern struct dhdr FAR ASM clk_dev; /* Clock device driver */ -extern struct dhdr FAR ASM con_dev; /* Console device driver */ -extern struct dhdr FAR ASM prn_dev; /* Generic printer device driver */ -extern struct dhdr FAR ASM aux_dev; /* Generic aux device driver */ -extern struct dhdr FAR ASM blk_dev; /* Block device (Disk) driver */ +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 */ -extern BYTE FAR _HMATextStart[]; /* first byte of HMAable CODE area */ -extern BYTE FAR _HMATextEnd[]; /* and the last byte of it */ +extern BYTE FAR _InitTextStart; /* first available byte of ram */ +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 */ @@ -201,7 +206,7 @@ GLOBAL WORD bDumpRdWrParms #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" + "(C) Copyright 1995-2001 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" @@ -211,7 +216,11 @@ GLOBAL BYTE copyright[] = GLOBAL const BYTE ASM os_release[] #ifdef MAIN - = KERNEL_VERSION_STRING +#if 0 + = "DOS-C version %d.%d Beta %d [FreeDOS Release] (Build %d).\n" +#endif + = "FreeDOS kernel version " KERNEL_VERSION_STRING + " (Build " KERNEL_BUILD_STRING ", " __DATE__ ")\n" #if 0 "For technical information and description of the DOS-C operating system\n\ consult \"FreeDOS Kernel\" by Pat Villani, published by Miller\n\ @@ -222,22 +231,23 @@ Freeman Publishing, Lawrence KS, USA (ISBN 0-87930-436-7).\n\ ; /* 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 */ +/* KERNAL.ASM AND MUST NOT BE CHANGED. DO NOT CHANGE ORDER BECAUSE THEY */ +/* ARE DOCUMENTED AS UNDOCUMENTED (?) AND HAVE MANY PROGRAMS AND TSR'S */ /* 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 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 */ -extern struct dhdr FAR * ASM syscon;/* console device */ -extern WORD ASM maxsecsize; /* largest sector size in use (can use) */ +extern struct dhdr +FAR * ASM clock, /* CLOCK$ device */ + FAR * ASM syscon; /* console device */ +extern WORD ASM maxbksize; /* Number of Drives in system */ extern struct buffer FAR *ASM firstbuf; /* head of buffers linked list */ enum {LOC_CONV=0, LOC_HMA=1}; @@ -268,8 +278,6 @@ extern BYTE ASM ErrorMode, /* Critical error flag */ ASM CritErrClass, ASM VgaSet, ASM njoined; /* number of joined devices */ -extern VOID FAR * ASM setverPtr; /* Pointer to SETVER list */ - extern UWORD ASM Int21AX; extern COUNT ASM CritErrCode; extern BYTE FAR * ASM CritErrDev; @@ -302,13 +310,11 @@ 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 term_type, /* 0 normal, 1 ^C, 2 int 24h, 3 TSR */ - ASM abort_progress, /* set during process termination */ + 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) */ @@ -327,14 +333,13 @@ extern BYTE ASM verify_ena, /* verify enabled flag */ 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 UBYTE DiskTransferBuffer[SEC_SIZE]; extern struct cds ASM TempCDS; @@ -348,6 +353,9 @@ GLOBAL WORD dump_regs; /* dump registers of bad call */ #endif +extern struct f_node FAR * ASM f_nodes; /* pointer to the array */ +extern UWORD ASM f_nodes_cnt; /* number of allocated f_nodes */ + /* */ /* Function prototypes - automatically generated */ /* */ @@ -355,8 +363,7 @@ GLOBAL WORD dump_regs; /* dump registers of bad call */ /* Process related functions - not under automatic generation. */ /* Typically, these are in ".asm" files. */ -VOID ASMCFUNC FAR cpm_entry(VOID) -/*INRPT FAR handle_break(VOID) */ ; +VOID ASMCFUNC FAR cpm_entry(VOID); COUNT ASMCFUNC CriticalError(COUNT nFlag, COUNT nDrive, COUNT nError, struct dhdr FAR * lpDevice); @@ -366,16 +373,15 @@ VOID ASMCFUNC FAR CharMapSrvc(VOID); 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] +#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 /* */ @@ -411,20 +417,14 @@ void setvec(unsigned char intno, intvec vector); /* ^Break handling */ #ifdef __WATCOMC__ -#pragma aux (__cdecl) spawn_int23 __aborts; +#pragma aux (cdecl) spawn_int23 aborts; #endif void ASMCFUNC spawn_int23(void); /* procsupt.asm */ -void ASMCFUNC DosIdle_hlt(void); /* dosidle.asm */ - -GLOBAL BYTE ASM 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 BYTE ReturnAnyDosVersionExpected; + GLOBAL struct f_node fnode[2]; +GLOBAL int fnode_fd[2]; + +#endif /* __GLOBALS_H */ + diff --git a/kernel/init-dat.h b/kernel/init-dat.h index 126dc46c..cda5e055 100644 --- a/kernel/init-dat.h +++ b/kernel/init-dat.h @@ -1,6 +1,3 @@ -#undef DOSFAR -#undef DOSTEXTFAR - /* Included by initialisation functions */ #if _MSC_VER != 0 @@ -23,11 +20,6 @@ extern __segment DosTextSeg; #define DOSFAR FAR #define DOSTEXTFAR FAR -#elif defined(__GNUC__) - -#define DOSFAR FAR -#define DOSTEXTFAR FAR - #elif !defined(I86) #define DOSFAR diff --git a/kernel/init-mod.h b/kernel/init-mod.h index 538b8508..3eca8484 100644 --- a/kernel/init-mod.h +++ b/kernel/init-mod.h @@ -2,11 +2,12 @@ #define IN_INIT_MOD #include "version.h" -#include "ddate.h" -#include "dtime.h" +#include "date.h" +#include "time.h" #include "mcb.h" #include "sft.h" #include "fat.h" +#include "fnode.h" #include "file.h" #include "cds.h" #include "device.h" @@ -16,12 +17,12 @@ #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 "nls.h" #include "kconfig.h" @@ -38,7 +39,7 @@ #define BSS_INIT(x) #endif -extern struct _KernelConfig ASM InitKernelConfig; +extern struct _KernelConfig InitKernelConfig; /* * Functions in `INIT_TEXT' may need to call functions in `_TEXT'. The entry @@ -57,16 +58,13 @@ extern struct _KernelConfig ASM InitKernelConfig; #define memset init_memset #define strchr init_strchr #define strcpy init_strcpy -#define fstrcpy init_fstrcpy #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); @@ -76,7 +74,6 @@ 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); -VOID ASMPASCAL fstrcpy(char FAR *d, const char FAR *s); size_t ASMPASCAL strlen(const char *s); size_t ASMPASCAL fstrlen(const char FAR *s); char * ASMPASCAL strchr(const char *s, int ch); @@ -84,18 +81,17 @@ 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) 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) memcmp modify nomemory +#pragma aux (pascal_ax) fmemcmp modify nomemory #pragma aux (pascal_ax) strcpy -#pragma aux (pascal_ax) fstrcpy -#pragma aux (pascal_ax) strlen __modify __nomemory -#pragma aux (pascal_ax) fstrlen __modify __nomemory -#pragma aux (__pascal) strchr __modify __exact [__ax __dx] __nomemory +#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 @@ -128,50 +124,36 @@ intvec getvec(unsigned char intno); /* config.c */ extern struct config Config; VOID PreConfig(VOID); -VOID PreConfig2(VOID); -VOID DoConfig(int pass); +void DoConfig(void); 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); +#ifdef I86 +void _seg * alignNextPara(CVFP); +#else +#define alignNextPara(x) ((const VOID *)x) +#endif +void _seg * KernelAlloc(size_t nBytes, UBYTE type, int mode); +void _seg * KernelAllocPara(size_t nPara, UBYTE type, CStr name, int mode); void DoInstall(void); -UWORD GetBiosKey(int timeout); +unsigned 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); + +int ASMPASCAL UMB_get_largest(CVFP driverAddress, seg_t *, size_t *); #ifdef __WATCOMC__ -#pragma aux (__pascal) UMB_get_largest __modify __exact [__ax __bx __cx __dx] +# 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); +VFP HMAalloc(COUNT bytesToAllocate); /* 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); @@ -179,24 +161,24 @@ 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_DosExec(int mode, exec_blk *, CStr); 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] +#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 */ @@ -204,10 +186,13 @@ 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 int13_handler(void); +/* VOID ASMCFUNC FAR int19_handler(void); */ VOID ASMCFUNC FAR int20_handler(void); VOID ASMCFUNC FAR int21_handler(void); VOID ASMCFUNC FAR int22_handler(void); @@ -222,26 +207,27 @@ VOID ASMCFUNC FAR int2f_handler(void); VOID ASMCFUNC FAR cpm_entry(void); /* kernel.asm */ -#ifdef __GNUC__ -VOID ASMCFUNC init_call_p_0(struct config FAR *Config) FAR __attribute__((noreturn)); -#else -VOID ASMCFUNC FAR init_call_p_0(struct config FAR *Config); /* P_0, actually */ + +void ASMCFUNC FAR init_call_p_0(const struct config FAR *); /* P_0, actually */ +#ifdef __WATCOMC__ +# pragma aux (cdecl) init_call_p_0 aborts #endif /* 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); + +void ASMCFUNC FreeDOSmain(void); +BOOL init_device(struct dhdr FAR *, PCStr cmdLine, int mode, VFP *top); +#ifdef __WATCOMC__ +# pragma aux (cdecl) FreeDOSmain aborts +#endif /* prf.c */ -int VA_CDECL init_printf(CONST char * fmt, ...); -int VA_CDECL init_sprintf(char * buff, CONST char * fmt, ...); + +VOID VA_CDECL init_printf(const char FAR * fmt, ...); +VOID VA_CDECL init_sprintf(char FAR * buff, const char FAR * fmt, ...); /* procsupt.asm */ VOID ASMCFUNC FAR got_cbreak(void); -/* console.asm */ -VOID ASMCFUNC FAR CBreak(void); /* initclk.c */ extern void Init_clk_driver(void); @@ -251,39 +237,34 @@ 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 VFP 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 FAR ASM master_env[128]; -extern struct lol FAR *LoL; +enum { ASK_ASK = 0x01, /* ?device= device?= */ + ASK_NOASK = 0x02, /* !files= */ + ASK_TRACE = 0x04, /* F8 processing */ + ASK_SKIPALL = 0x08, /* F5 processing */ + ASK_YESALL = 0x10, /* Esc while trace */ +}; + +extern UBYTE askCommand; + +extern struct lol FAR * const LoL; extern struct dhdr DOSTEXTFAR ASM blk_dev; /* Block device (Disk) driver */ extern struct buffer FAR *DOSFAR firstAvailableBuf; /* first 'available' buffer */ -extern struct lol FAR ASM DATASTART; - -extern BYTE DOSFAR ASM _HMATextAvailable; /* first byte of available CODE area */ -extern BYTE FAR ASM _HMATextStart[]; /* first byte of HMAable CODE area */ -extern BYTE FAR ASM _HMATextEnd[]; -extern BYTE DOSFAR ASM break_ena; /* break enabled flag */ -extern BYTE DOSFAR ASM _InitTextStart[]; /* first available byte of ram */ -extern BYTE DOSFAR ASM _InitTextEnd[]; -extern BYTE DOSFAR ASM ReturnAnyDosVersionExpected; -extern BYTE DOSFAR ASM HaltCpuWhileIdle; - -extern BYTE DOSFAR ASM internal_data[]; -extern unsigned char DOSTEXTFAR ASM kbdType; - -extern struct { - char ThisIsAConstantOne; - short TableSize; - - struct CountrySpecificInfo C; - -} DOSFAR ASM nlsCountryInfoHardcoded; +extern struct lol ASM FAR DATASTART; +extern intvec ASM FAR SAVEDIVLST; + +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 _InitTextStart, /* first available byte of ram */ + DOSFAR ReturnAnyDosVersionExpected; + +extern BYTE FAR ASM internal_data[]; +extern unsigned char FAR ASM kbdType; /* data shared between DSK.C and INITDISK.C @@ -291,16 +272,10 @@ extern struct { 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 */ +extern char DOSFAR DiskTransferBuffer[SEC_SIZE]; /* in dsk.c */ struct RelocationTable { UBYTE jmpFar; @@ -318,26 +293,21 @@ struct RelocatedEntry { UWORD jmpSegment; }; -extern struct RelocationTable DOSFAR ASM _HMARelocationTableStart[]; -extern struct RelocationTable DOSFAR ASM _HMARelocationTableEnd[]; +extern struct RelocationTable + DOSFAR ASM _HMARelocationTableStart[], + DOSFAR ASM _HMARelocationTableEnd[]; extern void FAR *DOSFAR ASM XMSDriverAddress; -extern UBYTE DOSFAR ASM XMS_Enable_Patch; -#ifdef __GNUC__ -extern VOID ASMPASCAL _EnableA20(VOID) FAR; -extern VOID ASMPASCAL _DisableA20(VOID) FAR; -#else extern VOID ASMPASCAL FAR _EnableA20(VOID); extern VOID ASMPASCAL FAR _DisableA20(VOID); -#endif 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] +#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 @@ -346,4 +316,3 @@ ULONG ASMCFUNC FAR MULULUL(ULONG mul1, ULONG mul2); /* MULtiply ULong by ULo 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 index 8dce0729..0780843f 100644 --- a/kernel/initclk.c +++ b/kernel/initclk.c @@ -31,7 +31,7 @@ #ifdef VERSION_STRINGS static char *RcsId = - "$Id: initclk.c 1359 2008-03-09 16:11:10Z mceric $"; + "$Id$"; #endif /* */ @@ -58,8 +58,6 @@ void Init_clk_driver(void) 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); diff --git a/kernel/initdisk.c b/kernel/initdisk.c index 0ec93db0..5b4523b7 100644 --- a/kernel/initdisk.c +++ b/kernel/initdisk.c @@ -25,13 +25,14 @@ /****************************************************************/ #include "portab.h" -#include "debug.h" #include "init-mod.h" #include "dyndata.h" +#ifdef VERSION_STRINGS +static BYTE *dskRcsId = + "$Id$"; +#endif -#define FLOPPY_SEC_SIZE 512u /* common sector size */ - -UBYTE InitDiskTransferBuffer[MAX_SEC_SIZE] BSS_INIT({0}); +UBYTE InitDiskTransferBuffer[SEC_SIZE] BSS_INIT({0}); COUNT nUnits BSS_INIT(0); /* @@ -67,7 +68,7 @@ COUNT nUnits BSS_INIT(0); * * d) using intr(intno, ®s) method. * - * why not? + * whynot's * * a) this is my personal favorite, combining the best aof all worlds. * TURBO-C does support inline assembly, but only by using TASM, @@ -92,7 +93,7 @@ COUNT nUnits BSS_INIT(0); * 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. + * and scince it's the only portable method, I opted for it. * * e) and all this is my private opinion. tom ehlert. * @@ -148,6 +149,8 @@ COUNT nUnits BSS_INIT(0); * CHS or LBA, strengthening its role as a rescue environment. */ +#include "debug.h" + #define LBA_to_CHS init_LBA_to_CHS /* @@ -173,13 +176,13 @@ COUNT nUnits BSS_INIT(0); #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 * + * 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 FAT12MAX (FAT_MAGIC-6) +#define FAT16MAX (FAT_MAGIC16-6) +#define FAT32MAX (FAT_MAGIC32-6) #define IsExtPartition(parttyp) ((parttyp) == EXTENDED || \ (parttyp) == EXTENDED_LBA ) @@ -255,7 +258,7 @@ COUNT init_readdasd(UBYTE drive) regs.a.b.h = 0x15; regs.d.b.l = drive; init_call_intr(0x13, ®s); - if ((regs.flags & 1) == 0) + if ((regs.flags & FLG_CARRY) == 0) switch (regs.a.b.h) { case 2: @@ -270,7 +273,7 @@ typedef struct { UWORD bpb_nbyte; /* Bytes per Sector */ UBYTE bpb_nsector; /* Sectors per Allocation Unit */ UWORD bpb_nreserved; /* # Reserved Sectors */ - UBYTE bpb_nfat; /* # FATs */ + UBYTE bpb_nfat; /* # FAT's */ UWORD bpb_ndirent; /* # Root Directory entries */ UWORD bpb_nsize; /* Size in sectors */ UBYTE bpb_mdesc; /* MEDIA Descriptor Byte */ @@ -281,11 +284,11 @@ typedef struct { 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 */ + {SEC_SIZE, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2}, /* FD360 5.25 DS */ + {SEC_SIZE, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2}, /* FD1200 5.25 HD */ + {SEC_SIZE, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2}, /* FD720 3.5 LD */ + {SEC_SIZE, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2}, /* FD1440 3.5 HD */ + {SEC_SIZE, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2} /* FD2880 3.5 ED */ }; COUNT init_getdriveparm(UBYTE drive, bpb * pbpbarray) @@ -297,9 +300,10 @@ COUNT init_getdriveparm(UBYTE drive, bpb * pbpbarray) return 5; regs.a.b.h = 0x08; regs.d.b.l = drive; + /* Note: RBIL suggests setting ES:DI to 0:0 to guard against BIOS bugs */ init_call_intr(0x13, ®s); type = regs.b.b.l - 1; - if (regs.flags & 1) + if (regs.flags & FLG_CARRY) 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 */ @@ -322,25 +326,10 @@ COUNT init_getdriveparm(UBYTE drive, bpb * pbpbarray) /* 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 + copied and pasted from dsk.c! */ -void init_LBA_to_CHS(struct CHS *chs, ULONG LBA_address, +void LBA_to_CHS(struct CHS *chs, ULONG LBA_address, struct DriveParamS *driveparam) { unsigned hs = driveparam->chs.Sector * driveparam->chs.Head; @@ -356,7 +345,14 @@ void init_LBA_to_CHS(struct CHS *chs, ULONG LBA_address, void printCHS(char *title, struct CHS *chs) { /* has no fixed size for head/sect: is often 1/1 in our context */ - if (InitKernelConfig.Verbose >= 0) printf("%s%4u-%u-%u", title, chs->Cylinder, chs->Head, chs->Sector); + printf("%s%4u-%u-%u", title, chs->Cylinder, chs->Head, chs->Sector); +} + +STATIC VOID printStartEnd(struct CHS *chs, struct CHS *end) +{ + printCHS(" start ", chs); + printCHS(", end ", end); + printf("\n"); } /* @@ -368,7 +364,10 @@ void printCHS(char *title, struct CHS *chs) */ /* Compute ceil(a/b) */ -#define cdiv(a, b) (((a) + (b) - 1) / (b)) +STATIC UWORD cdiv(ULONG a, UWORD b) +{ + return (UWORD)((a + b - 1) / b); +} /* calculates FAT data: code adapted by Bart Oldeman from mkdosfs from the Linux dosfstools: @@ -377,70 +376,130 @@ void printCHS(char *title, struct CHS *chs) 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) { + UBYTE maxclustsize; 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) + defbpb->bpb_nfat = 2; + if (FileSystem == FAT32 || FileSystem == FAT32_LBA) + { + defbpb->bpb_ndirent = 0; + defbpb->bpb_nreserved = 0x20; + } + else { - 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); + defbpb->bpb_ndirent = 512; + defbpb->bpb_nreserved = 1; + } + fatdata = + NumSectors - cdiv(defbpb->bpb_ndirent * DIRENT_SIZE, + defbpb->bpb_nbyte) - defbpb->bpb_nreserved; + maxclustsize = 128; #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) */ + if (FileSystem != FAT12) + DebugPrintf(("%ld sectors for FAT+data, starting with %d sectors/cluster\n", fatdata, defbpb->bpb_nsector)); +#endif + switch (FileSystem) + { + + case FAT12: + case FAT12_LBA: { - unsigned clust = (fatdat - 2 * defbpb->bpb_nfsect) / NSECTORFAT12; - unsigned maxclust = (defbpb->bpb_nfsect * 2 * FLOPPY_SEC_SIZE) / 3; + unsigned fatdat, fatlength, clust, maxclust; + /* in DOS, FAT12 defaults to 4096kb (8 sector) - clusters. */ + defbpb->bpb_nsector = 8; + /* 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*defbpb->bpb_nsector" is for the reserved first two FAT entries */ + fatlength = cdiv(fatdat + 2 * defbpb->bpb_nsector, + defbpb->bpb_nbyte * 2 * defbpb->bpb_nsector / 3 + defbpb->bpb_nfat); + /* 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 = + (fatdat - defbpb->bpb_nfat * fatlength) / defbpb->bpb_nsector; + maxclust = (fatlength * 2 * defbpb->bpb_nbyte) / 3; if (maxclust > FAT12MAX) maxclust = FAT12MAX; - printf("FAT12: #clu=%u, fatlength=%u, maxclu=%u, limit=%u\n", - clust, defbpb->bpb_nfsect, maxclust, FAT12MAX); + DebugPrintf(("FAT12: #clu=%u, fatlength=%u, maxclu=%u, limit=%u\n", + clust, fatlength, maxclust, FAT12MAX)); if (clust > maxclust - 2) { clust = maxclust - 2; - printf("FAT12: too many clusters: setting to maxclu-2\n"); + DebugPrintf(("FAT12: too many clusters: setting to maxclu-2\n")); } + defbpb->bpb_nfsect = fatlength; + memcpy(pddt->ddt_fstype, MSDOS_FAT12_SIGN, 8); + break; + } + case FAT16SMALL: + case FAT16LARGE: + case FAT16_LBA: + { + unsigned fatlength; + unsigned long clust, maxclust; + /* 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; + do + { + DebugPrintf(("Trying with %d sectors/cluster:\n", + defbpb->bpb_nsector)); + + fatlength = cdiv(fatdata + 2 * defbpb->bpb_nsector, + defbpb->bpb_nbyte * defbpb->bpb_nsector / 2 + defbpb->bpb_nfat); + /* 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 - defbpb->bpb_nfat * fatlength) / defbpb->bpb_nsector; + maxclust = ((unsigned long)fatlength * defbpb->bpb_nbyte) / 2; + if (maxclust > FAT16MAX) + maxclust = FAT16MAX; + DebugPrintf(("FAT16: #clu=%lu, fatlen=%u, maxclu=%lu, limit=%u\n", + clust, fatlength, maxclust, FAT_MAGIC16)); + if (clust > maxclust - 2) + { + DebugPrintf(("FAT16: too many clusters\n")); + clust = 0; + } + else if (clust <= FAT_MAGIC) + { + /* The <= 4086 avoids that the filesystem will be misdetected as having a + * 12 bit FAT. */ + DebugPrintf(("FAT16: would be misdetected as FAT12\n")); + clust = 0; + } + if (clust) + break; + defbpb->bpb_nsector <<= 1; + } + while (defbpb->bpb_nsector && defbpb->bpb_nsector <= maxclustsize); + defbpb->bpb_nfsect = fatlength; + memcpy(pddt->ddt_fstype, MSDOS_FAT16_SIGN, 8); + break; } -#endif - memcpy(pddt->ddt_fstype, MSDOS_FAT12_SIGN, 8); - } - else - { /* FAT16/FAT32 */ - CLUSTER fatlength, maxcl; - unsigned long clust, maxclust, rest; - unsigned fatentpersec; - unsigned divisor; - #ifdef WITHFAT32 - if (FileSystem == FAT32 || FileSystem == FAT32_LBA) + case FAT32: + case FAT32_LBA: { + unsigned long fatlength, clust, maxclust; + /* For FAT32, use the cluster size table described in the FAT spec: * http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf */ @@ -455,66 +514,30 @@ VOID CalculateFATData(ddt * pddt, ULONG NumSectors, UBYTE FileSystem) 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; /* how many 32bit FAT values fit in a default 512 byte sector */ - 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; /* how many 16bit FAT values fit in a default 512 byte sector */ - maxcl = FAT16MAX; - } - - DebugPrintf(("%lu sectors for FAT+data, starting with %u sectors/cluster\n", fatdata, defbpb->bpb_nsector)); - do - { - DebugPrintf(("Trying with %u sectors/cluster:\n", defbpb->bpb_nsector)); - divisor = fatentpersec * defbpb->bpb_nsector + NFAT; /* # of fat entries per cluster + 2 */ - rest = (unsigned)(fatdata % divisor); - fatlength = (CLUSTER)(fatdata / divisor); - fatlength += (CLUSTER)((2 * defbpb->bpb_nsector + divisor + rest - 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, (ULONG)fatlength, maxclust, (ULONG)maxcl)); - if (clust > maxclust - 2) - { - clust = 0; - DebugPrintf(("FAT: too many clusters\n")); - } - else if (clust <= FAT_MAGIC) + do { - /* 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; + fatlength = cdiv(fatdata + 2 * defbpb->bpb_nsector, + defbpb->bpb_nbyte * defbpb->bpb_nsector / 4 + defbpb->bpb_nfat); + /* 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 - defbpb->bpb_nfat * fatlength) / defbpb->bpb_nsector; + maxclust = (fatlength * defbpb->bpb_nbyte) / 4; + if (maxclust > FAT32MAX) + maxclust = FAT32MAX; + DebugPrintf(("FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n", + clust, fatlength, maxclust, FAT32MAX)); + if (clust > maxclust - 2) + { + clust = 0; + DebugPrintf(("FAT32: too many clusters\n")); + } + if (clust) + break; + defbpb->bpb_nsector <<= 1; } - if (clust) - break; - defbpb->bpb_nsector <<= 1; - } - while (defbpb->bpb_nsector && defbpb->bpb_nsector <= MAXCLUSTSIZE); -#ifdef WITHFAT32 - if (FileSystem == FAT32 || FileSystem == FAT32_LBA) - { + while (defbpb->bpb_nsector && defbpb->bpb_nsector <= maxclustsize); defbpb->bpb_nfsect = 0; defbpb->bpb_xnfsect = fatlength; /* set up additional FAT32 fields */ @@ -524,13 +547,9 @@ VOID CalculateFATData(ddt * pddt, ULONG NumSectors, UBYTE FileSystem) defbpb->bpb_xfsinfosec = 1; defbpb->bpb_xbackupsec = 6; memcpy(pddt->ddt_fstype, MSDOS_FAT32_SIGN, 8); + break; } - else #endif - { - defbpb->bpb_nfsect = (UWORD)fatlength; - memcpy(pddt->ddt_fstype, MSDOS_FAT16_SIGN, 8); - } } pddt->ddt_fstype[8] = '\0'; } @@ -567,15 +586,18 @@ void DosDefinePartition(struct DriveParamS *driveParam, /* Turn off 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 || IsLBAPartition(pEntry->FileSystem) || ExtLBAForce)) + 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)); +#ifdef DEBUG + if (pddt->ddt_descflags & DF_LBA) + DebugPrintf(("LBA enabled for drive %c:\n", 'A' + nUnits)); +#endif pddt->ddt_offset = StartSector; - pddt->ddt_defbpb.bpb_nbyte = FLOPPY_SEC_SIZE; + pddt->ddt_defbpb.bpb_nbyte = SEC_SIZE; pddt->ddt_defbpb.bpb_mdesc = 0xf8; pddt->ddt_defbpb.bpb_nheads = driveParam->chs.Head; pddt->ddt_defbpb.bpb_nsecs = driveParam->chs.Sector; @@ -585,14 +607,13 @@ void DosDefinePartition(struct DriveParamS *driveParam, pddt->ddt_defbpb.bpb_huge = pEntry->NumSect; if (pEntry->NumSect <= 0xffff) { - pddt->ddt_defbpb.bpb_nsize = (UWORD) (pEntry->NumSect); + pddt->ddt_defbpb.bpb_nsize = loword (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; @@ -631,51 +652,49 @@ void DosDefinePartition(struct DriveParamS *driveParam, } /* Get the parameters of the hard disk */ -STATIC int LBA_Get_Drive_Parameters(int drive, struct DriveParamS *driveParam, int firstPass) +STATIC int LBA_Get_Drive_Parameters(int drive, struct DriveParamS *driveParam) { iregs regs; struct _bios_LBA_disk_parameterS lba_bios_parameters; - if (firstPass && (InitKernelConfig.Verbose >= 1)) - printf("Checking for LBA support in BIOS for drive %02x\n", drive); + ExtLBAForce = FALSE; memset(driveParam, 0, sizeof *driveParam); drive |= 0x80; - /* use CHS if LBA support is not enabled by kernel configuration */ + /* for tests - disable LBA support, + even if exists */ if (!InitKernelConfig.GlobalEnableLBAsupport) { - if (firstPass && (InitKernelConfig.Verbose >= 1)) printf("LBA support disabled.\n"); goto StandardBios; } /* check for LBA support */ regs.b.x = 0x55aa; regs.a.b.h = 0x41; regs.d.b.l = drive; - regs.ds = 0x40; - /* ds = 40h is to work around a Xi8088 ROM-BIOS bug, - refer to https://github.com/FDOS/kernel/issues/156 - and https://www.bttr-software.de/forum/forum_entry.php?id=21275 */ - regs.flags = FLG_CARRY; /* ensure carry is set to force error if unsupported */ init_call_intr(0x13, ®s); - if ((regs.flags & FLG_CARRY) || regs.b.x != 0xaa55 || !(regs.c.x & 0x01)) + if (regs.b.x != 0xaa55 || (regs.flags & FLG_CARRY)) { - /* error conditions: - carry set or BX != 0xaa55 => no EDD spec compatible BIOS (LBA extensions not supported) - CX bit 1 is set if BIOS supports fixed disk subset (Disk Address Packet [DAP] subset), - or clear if fixed disk access subset not supported by LBA extensions - */ 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.b.h < 0x21) - LBA_WRITE_VERIFY = 0x4301; /* may be problematic if INT13 is hooked by - different controllers / drivers */ + if (regs.a.x < 0x2100) + LBA_WRITE_VERIFY = 0x4301; - /* query disk size and DMA handling, geometry is queried later by INT13,08 */ memset(&lba_bios_parameters, 0, sizeof(lba_bios_parameters)); lba_bios_parameters.size = sizeof(lba_bios_parameters); @@ -685,104 +704,74 @@ STATIC int LBA_Get_Drive_Parameters(int drive, struct DriveParamS *driveParam, i regs.d.b.l = drive; init_call_intr(0x13, ®s); + /* error or DMA boundary errors not handled transparently */ if (regs.flags & FLG_CARRY) { - /* carry flag set indicates failed LBA disk parameter query */ goto StandardBios; } + /* verify maximum settings, we can't handle more */ + if (lba_bios_parameters.heads > 0xffff || lba_bios_parameters.sectors > 0xffff || - (lba_bios_parameters.totalSect == 0 && - lba_bios_parameters.totalSectHigh == 0)) + lba_bios_parameters.totalSectHigh != 0) { - if (firstPass) - { - printf("Suspicious LBA disk parameters, reverting to CHS access:\n"); - printf(" drive %02x, heads=%lu, sectors=%lu, total=0x%lx-%08lx\n", + 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; } - /* restrict disk size to 2TB, because we can not handle more */ - if (lba_bios_parameters.totalSectHigh == 0) - { - driveParam->total_sectors = lba_bios_parameters.totalSect; - } - else - { - if (firstPass) printf("Drive %02x is too large to handle, restricted to 2TB\n", drive); - driveParam->total_sectors = 0xffffffffUL; - } + driveParam->total_sectors = lba_bios_parameters.totalSect; - /* if we arrive here, mark drive as LBA capable */ + /* if we arrive here, success */ driveParam->descflags = DF_LBA; if (lba_bios_parameters.information & 8) driveParam->descflags |= DF_WRTVERIFY; - - if (lba_bios_parameters.information & 1) - { - /* DMA boundary errors are handled transparently */ - driveParam->descflags |= DF_DMA_TRANSPARENT; - } -StandardBios: /* get disk geometry, and if LBA is not enabled, also size */ - if (firstPass && (InitKernelConfig.Verbose >= 1)) - printf("Retrieving CHS values for drive\n"); +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) - { + if (regs.flags & FLG_CARRY) 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; + driveParam->chs.Head = (regs.d.x >> 8) + 1; + driveParam->chs.Sector = (regs.c.x & 0x3f); + driveParam->chs.Cylinder = (regs.c.x >> 8) | ((regs.c.x & 0xc0) << 2); if (driveParam->chs.Sector == 0) { /* happens e.g. with Bochs 1.x if no harddisk defined */ driveParam->chs.Sector = 63; /* avoid division by zero...! */ - if (firstPass && (InitKernelConfig.Verbose >= 0)) - printf("BIOS reported 0 sectors/track, assuming 63!\n"); + printf("BIOS reported 0 sectors/track, assuming 63!\n"); } if (!(driveParam->descflags & DF_LBA)) { driveParam->total_sectors = - (ULONG)driveParam->chs.Cylinder + min(driveParam->chs.Cylinder, 1023) * driveParam->chs.Head * driveParam->chs.Sector; } driveParam->driveno = drive; - DebugPrintf(("drive %02Xh total: C = %u, H = %u, S = %u,", + DebugPrintf(("drive parameters %02x - %04lu-%u-%u", drive, driveParam->chs.Cylinder, driveParam->chs.Head, driveParam->chs.Sector)); DebugPrintf((" total size %luMB\n\n", driveParam->total_sectors / 2048)); - return driveParam->driveno; - - ErrorReturn: - /* to avoid division by zero later, use some sane defaults */ - driveParam->total_sectors = 0; - driveParam->chs.Head = 16; - driveParam->chs.Sector = 63; - return 0; + + return driveParam->driveno; } /* @@ -825,72 +814,43 @@ BOOL ConvPartTableEntryToIntern(struct PartTableEntry * pEntry, 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) +STATIC void warning_suspect(char *partitionName, struct CHS *chs, + struct CHS *pEntry_chs) { - if (!InitKernelConfig.ForceLBA) + if (pEntry_chs->Cylinder != (chs->Cylinder & 0x3FF) + || pEntry_chs->Head != chs->Head + || pEntry_chs->Sector != chs->Sector) { - if (InitKernelConfig.Verbose >= 0) - { - printf("WARNING: using suspect partition %s FS %02x:", partitionName, fs); - printCHS(" with calculated values ", chs); - printCHS(" instead of ", pEntry_chs); - printf("\n"); - } + printf("WARNING: %s", partitionName); + printCHS(" has CHS=", chs); + printCHS(", not ", pEntry_chs); + printf("\n"); + memcpy(pEntry_chs, chs, sizeof(struct CHS)); } - memcpy(pEntry_chs, chs, sizeof(struct CHS)); } -BOOL ScanForPrimaryPartitions(struct DriveParamS * driveParam, int scan_type, +int 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]; + char partitionName[28]; 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) + if (partitionsToIgnore & (1 << i) + || scan_type == SCAN_PRIMARYBOOT && !pEntry->Bootable + || !IsFATPartition(pEntry->FileSystem)) continue; partitionStart = startSector + pEntry->RelSect; - if (!IsFATPartition(pEntry->FileSystem)) - { - continue; - } - - if (extendedPartNo) - sprintf(partitionName, "Ext:%d", extendedPartNo); - else - sprintf(partitionName, "Pri:%d", i + 1); + sprintf(partitionName, "partition %s:%d FS %02x", + extendedPartNo ? "Ext" : "Pri", + extendedPartNo ? extendedPartNo : i + 1, + pEntry->FileSystem); /* some sanity checks, that partition @@ -899,58 +859,37 @@ BOOL ScanForPrimaryPartitions(struct DriveParamS * driveParam, int scan_type, 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) + /* some FDISK's enter for partitions + > 8 GB cyl = 1022 or 1023, other (cyl&1023) */ - - if (is_suspect(&chs, &pEntry->Begin)) + if (!IsLBAPartition(pEntry->FileSystem)) { - print_warning_suspect(partitionName, pEntry->FileSystem, &chs, - &pEntry->Begin); + warning_suspect(partitionName, &chs, &pEntry->Begin); + warning_suspect(partitionName, &end, &pEntry->End); } - - if (is_suspect(&end, &pEntry->End)) + if (pEntry->NumSect == 0) { - if (pEntry->NumSect == 0) - { - printf("Not using partition %s with 0 sectors\n", partitionName); - continue; - } - print_warning_suspect(partitionName, pEntry->FileSystem, &end, - &pEntry->End); + printf("Not using %s with 0 sectors\n", partitionName); + continue; } - if (chs.Cylinder > 1023 || end.Cylinder > 1023) { - /* if partition exceeds bounds of CHS addressing but LBA is not supported then skip partition */ 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"); - + printf("Can't use LBA %s without LBA support", partitionName); + printStartEnd(&chs, &end); continue; } - /* if partition exceeds bounds of CHS addressing and we can use LBA - but partition type indicates to use CHS then print warning - and force internal filesystem indicator to enable LBA - */ - if (!(InitKernelConfig.ForceLBA || IsLBAPartition(pEntry->FileSystem) || ExtLBAForce)) + if (!InitKernelConfig.ForceLBA && !ExtLBAForce + && !IsLBAPartition(pEntry->FileSystem)) { printf - ("WARNING: Partition ID does not suggest LBA - part %s FS %02x.\n" + ("WARNING: %s is not LBA\n" "Please run FDISK to correct this - using LBA to access partition.\n", - partitionName, pEntry->FileSystem); - - printCHS(" start ", &chs); - printCHS(", end ", &end); - printf("\n"); + partitionName); + printStartEnd(&chs, &end); pEntry->FileSystem = (pEntry->FileSystem == FAT12 ? FAT12_LBA : pEntry->FileSystem == FAT32 ? FAT32_LBA : /* pEntry->FileSystem == FAT16 ? */ @@ -959,11 +898,9 @@ BOOL ScanForPrimaryPartitions(struct DriveParamS * driveParam, int scan_type, /* 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"); + printf("found and using LBA %s", + partitionName); + printStartEnd(&chs, &end); #endif } @@ -977,17 +914,12 @@ BOOL ScanForPrimaryPartitions(struct DriveParamS * driveParam, int scan_type, extendedPartNo, i); if (scan_type == SCAN_PRIMARYBOOT || scan_type == SCAN_PRIMARY) - { - return partitionsToIgnore; - } + break; } - return partitionsToIgnore; } -void BIOS_drive_reset(unsigned drive); - -int Read1LBASector(struct DriveParamS *driveParam, unsigned drive, +BOOL Read1LBASector(struct DriveParamS *driveParam, unsigned drive, ULONG LBA_address, void * buffer) { static struct _bios_LBA_address_packet dap = { @@ -1004,31 +936,17 @@ int Read1LBASector(struct DriveParamS *driveParam, unsigned drive, #if 0 if (LBA_address >= driveParam->total_sectors) { - printf("LBA-Transfer error : address overflow = %lu, > %lu total sectors\n", - LBA_address, driveParam->total_sectors); + printf("LBA-Transfer error : address overflow = %lu > %lu max\n", + LBA_address + 1, driveParam->total_sectors); return 1; } #endif for (num_retries = 0; num_retries < N_RETRY; num_retries++) { - if (InitKernelConfig.Verbose >= 1) - { - printf("retry# %i sector %lu\n", num_retries, LBA_address); - } - 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))) + if (driveParam->descflags & DF_LBA) { - if (InitKernelConfig.Verbose >= 1) printf("LBA mode\n"); dap.number_of_blocks = 1; dap.buffer_address = buffer; dap.block_address_high = 0; /* clear high part */ @@ -1041,12 +959,12 @@ int Read1LBASector(struct DriveParamS *driveParam, unsigned drive, } else { /* transfer data, using old bios functions */ - if (InitKernelConfig.Verbose >= 1) printf("CHS mode\n"); + LBA_to_CHS(&chs, LBA_address, driveParam); /* avoid overflow at end of track */ if (chs.Cylinder > 1023) { - printf("LBA-Transfer error : address = %lu, cylinder %u > 1023\n", LBA_address, chs.Cylinder); + printf("LBA-Transfer error : cylinder %u > 1023\n", chs.Cylinder); return 1; } @@ -1060,17 +978,25 @@ int Read1LBASector(struct DriveParamS *driveParam, unsigned drive, } /* end of retries */ init_call_intr(0x13, ®s); if ((regs.flags & FLG_CARRY) == 0) - break; - BIOS_drive_reset(driveParam->driveno); + return 0; + regs.a.b.h = 0xD; + init_call_intr(0x13, ®s); /* reset hard disk */ } - - return regs.flags & FLG_CARRY ? 1 : 0; + return 1; } /* Load the Partition Tables and get information on all drives */ +/* If scanType != SCAN_EXTENDED then we return with the + lower four bits set (valid partition, drive added) or clear + (unhandled or invalid) for each partition entry in the + partition table, or 0 when scanType == SCAN_EXTENDED. + If we are unable to obtain the disk parameters for drive, + then we return -1 (usually means BIOS returned a count + higher than drives that exists; ISOLINUX may do this and + from RBIL may occur in some BIOSes). + */ int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) { - /* note: error messages are only printed on first call, where (scanType==SCAN_PRIMARYBOOT) */ struct PartTableEntry PTable[4]; ULONG RelSectorOffset; @@ -1085,17 +1011,15 @@ int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) /* 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,(scanType==SCAN_PRIMARYBOOT))) + if (!LBA_Get_Drive_Parameters(drive, &driveParam)) { - printf("can't get drive parameters for drive %02x\n", drive); - return PartitionsToIgnore; + if (scanType == SCAN_PRIMARYBOOT) /* only display 1st time through */ + printf("can't get drive parameters for drive %02x\n", drive); + return -1; } RelSectorOffset = 0; /* boot sector */ ExtendedPartitionOffset = 0; /* not found yet */ - ExtLBAForce = 0; /* initially we are not dealing with partitions - within a type 0x0E LBA extended partition, - so we do not enforce LBA access by now */ /* Read the Primary Partition Table. */ @@ -1107,7 +1031,7 @@ int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) if (Read1LBASector (&driveParam, drive, RelSectorOffset, InitDiskTransferBuffer)) { - printf("Error reading partition table drive %02Xh sector %lu", drive, + printf("Error reading partition table drive %02x sector %lu", drive, RelSectorOffset); return PartitionsToIgnore; } @@ -1122,7 +1046,10 @@ int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) if (++strangeHardwareLoop < 3) goto strange_restart; - if (scanType==SCAN_PRIMARYBOOT) printf("illegal partition table - drive %02x sector %lu\n", drive, + if (scanType == SCAN_PRIMARYBOOT) /* only display 1st time through */ + printf("corrupt or unpartitioned drive %02x\n", drive); + else if (RelSectorOffset /* && (scanType == SCAN_EXTENDED) */) + printf("illegal extended partition table - drive %02x sector %lu\n", drive, RelSectorOffset); return PartitionsToIgnore; } @@ -1152,10 +1079,10 @@ int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) { RelSectorOffset = ExtendedPartitionOffset + PTable[iPart].RelSect; - if (ExtendedPartitionOffset == 0) /* first extended in chain? */ + if (ExtendedPartitionOffset == 0) { ExtendedPartitionOffset = PTable[iPart].RelSect; - /* grand parent LBA -> all children and grandchildren LBA */ + /* grand parent LBA -> all children and grandchildren LBA */ ExtLBAForce = (PTable[iPart].FileSystem == EXTENDED_LBA); } @@ -1174,6 +1101,9 @@ int ProcessDisk(int scanType, unsigned drive, int PartitionsToIgnore) return PartitionsToIgnore; } + +/* query BIOS for number of hard disks + */ int BIOS_nrdrives(void) { iregs regs; @@ -1182,7 +1112,7 @@ int BIOS_nrdrives(void) regs.d.b.l = 0x80; init_call_intr(0x13, ®s); - if (regs.flags & 1) + if (regs.flags & FLG_CARRY) { printf("no hard disks detected\n"); return 0; @@ -1191,16 +1121,6 @@ int BIOS_nrdrives(void) 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: @@ -1237,7 +1157,9 @@ 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. +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 @@ -1291,34 +1213,63 @@ 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) +/* initializes a ddt and stores for later retrieval */ +STATIC void create_ddt(ddt *pddt, int Unit, int driveno, int type, int ncyl, int flags, void *defbpb, int bpbsize) { 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_type = type; + pddt->ddt_ncyl = ncyl; + pddt->ddt_descflags = flags; pddt->ddt_offset = 0; - pddt->ddt_serialno = 0x12345678l; - memcpy(&pddt->ddt_bpb, &pddt->ddt_defbpb, sizeof(bpb)); + memcpy(&pddt->ddt_bpb, defbpb, bpbsize); push_ddt(pddt); } -void ReadAllPartitionTables(void) -{ - UBYTE foundPartitions[MAX_HARD_DRIVE]; +/* initializes a ddt for a drive that is assumed to not exist, + e.g. the fake ddt for floppies (A: & B:) on floppyless systems + */ +#define fake_ddt(pddt, Unit) create_ddt(pddt, Unit, \ + 0xFF, /* usually invalid BIOS drive # */ \ + 0x04, /* 2.88MB floppy, since usually for non-existant floppy */ \ + 80, \ + DF_NOACCESS, \ + &floppy_bpbs[4], sizeof(floppy_bpb) \ +) + +/* initializes ddt for a drive (logical or physical) assumed to exist */ +#define make_ddt(pddt, Unit, driveno, flags) create_ddt(pddt, Unit, \ + driveno, \ + init_getdriveparm(driveno, &(pddt)->ddt_defbpb), \ + ( ((pddt)->ddt_type & 7) ? 80 : 40 ), \ + ( init_readdasd(driveno) | flags ), \ + &(pddt)->ddt_defbpb, sizeof(bpb) \ +) + +/* disk initialization: returns number of units */ +COUNT dsk_init() +{ + static UBYTE foundPartitions[MAX_HARD_DRIVE] = {0}; int HardDrive; int nHardDisk; ddt nddt; static iregs regs; + printf(" - InitDisk\r"); + +#if defined DEBUG && !defined DEBUG_PRINT_COMPORT + { + regs.a.x = 0x1112; /* select 43 line mode - more space for partinfo */ + regs.b.x = 0; + init_call_intr(0x10, ®s); + } +#endif + /* 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; @@ -1326,44 +1277,34 @@ void ReadAllPartitionTables(void) 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)) + if (regs.AL & 1) /* at least one floppy drive installed */ { - /* floppy drives installed and a B: drive */ - make_ddt(&nddt, 1, 1, 0); + make_ddt(&nddt, 0, 0, 0); + if (regs.AL & 0xC0) /* more than one floppy */ + make_ddt(&nddt, 1, 1, 0); /* real B: drive */ + else + make_ddt(&nddt, 1, 0, DF_MULTLOG); /* phantom B: drive */ } else { - /* set up the DJ method : multiple logical drives */ - make_ddt(&nddt, 1, 0, DF_MULTLOG); + fake_ddt(&nddt, 0); + fake_ddt(&nddt, 1); } /* Initial number of disk units */ nUnits = 2; nHardDisk = BIOS_nrdrives(); - if (nHardDisk > LENGTH(foundPartitions)) - nHardDisk = LENGTH(foundPartitions); + if (nHardDisk > MAX_HARD_DRIVE) + nHardDisk = MAX_HARD_DRIVE; 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) { - if (InitKernelConfig.Verbose >= 1) printf("Drive Letter Assignment - DOS order\n"); + /* printf("Drive Letter Assignment - DOS order\n"); */ /* Process primary partition table 1 partition only */ for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) @@ -1375,6 +1316,9 @@ void ReadAllPartitionTables(void) foundPartitions[HardDrive] = ProcessDisk(SCAN_PRIMARY, HardDrive, 0); } + /* ignore last drive if can't get info about it; can't use anyway */ + if ((nHardDisk>1) && (foundPartitions[nHardDisk-1]==(UBYTE)-1)) + nHardDisk--; /* Process extended partition table */ for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) @@ -1390,16 +1334,14 @@ void ReadAllPartitionTables(void) } else { - UBYTE bootdrv = peekb(0,0x5e0); - - if (InitKernelConfig.Verbose >= 1) printf("Drive Letter Assignment - sorted by drive\n"); + /* 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, 0) && - driveParam.driveno == bootdrv) + if (LBA_Get_Drive_Parameters(HardDrive, &driveParam) && + driveParam.driveno == peekb(0,0x5e0)) { foundPartitions[HardDrive] = ProcessDisk(SCAN_PRIMARYBOOT, HardDrive, 0); @@ -1418,6 +1360,9 @@ void ReadAllPartitionTables(void) foundPartitions[HardDrive] = ProcessDisk(SCAN_PRIMARY, HardDrive, 0); } + /* ignore last drive if can't get info about it; can't use anyway */ + if ((nHardDisk>1) && (foundPartitions[nHardDisk-1]==(UBYTE)-1)) + nHardDisk--; /* Process extended partition table */ ProcessDisk(SCAN_EXTENDED, HardDrive, 0); @@ -1426,38 +1371,6 @@ void ReadAllPartitionTables(void) ProcessDisk(SCAN_PRIMARY2, HardDrive, foundPartitions[HardDrive]); } } - - if (InitKernelConfig.Verbose >= 0) - { - unsigned foundPartitionsCount = 0; - /* Tell user if no valid partitions found on any hard drive */ - for (HardDrive = 0; HardDrive < nHardDisk; HardDrive++) - { - foundPartitionsCount += foundPartitions[HardDrive]; - } - /* printf("Found %i partitions\n", foundPartitionsCount); */ - if (!foundPartitionsCount) printf("No supported partitions found.\n"); - } -} - -/* disk initialization: returns number of units */ -COUNT dsk_init() -{ - if (InitKernelConfig.Verbose >= 1) printf("\nInitDisk\n"); - -#if defined(DEBUG) && !defined(DOSEMU) && !defined(DEBUG_PRINT_COMPORT) - { - 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 index 0e1c7d2d..3afc67d3 100644 --- a/kernel/inithma.c +++ b/kernel/inithma.c @@ -65,10 +65,11 @@ #include "portab.h" #include "init-mod.h" +#include "debug.h" #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: inithma.c 956 2004-05-24 17:07:04Z bartoldeman $"; + "$Id$"; #endif BYTE DosLoadedInHMA BSS_INIT(FALSE); /* set to TRUE if loaded HIGH */ @@ -78,7 +79,7 @@ UWORD HMAFree BSS_INIT(0); /* first byte in HMA not yet used */ STATIC void InstallVDISK(void); #ifdef DEBUG -#if defined(__TURBOC__) || defined(__GNUC__) +#ifdef __TURBOC__ #define int3() __int__(3); #else void int3() @@ -90,12 +91,6 @@ void int3() #define int3() #endif -#ifdef DEBUG -#define HMAInitPrintf(x) printf x -#else -#define HMAInitPrintf(x) -#endif - #ifdef DEBUG VOID hdump(BYTE FAR * p) { @@ -179,7 +174,6 @@ int MoveKernelToHMA() return FALSE; XMSDriverAddress = xms_addr; - XMS_Enable_Patch = 0x90; /* must be set after XMSDriverAddress */ #ifdef DEBUG /* A) for debugging purpose, suppress this, @@ -225,12 +219,33 @@ int MoveKernelToHMA() DosLoadedInHMA = TRUE; } - /* - on finalize, will install a VDISK - */ + 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 - InstallVDISK(); + so: we install this after all drivers have been loaded + */ + { + static struct { /* Boot sector 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 Sectors; + BYTE dummy4; + } VDISK_BOOT_SECTOR = { + {0xcf,' ',' '}, + {"VDISK"}, + {" "}, 512, + {"FDOS "}, 128, /* 128 * 512 = 64K */ + ' ' + }; + fmemcpy(MK_FP(0xffff, 0x0010), &VDISK_BOOT_SECTOR, + sizeof(VDISK_BOOT_SECTOR)); + *(WORD FAR *) MK_FP(0xffff, 0x002e) = 1024 + 64; + } /* report the fact we are running high through int 21, ax=3306 */ LoL->version_flags |= 0x10; @@ -239,43 +254,6 @@ int MoveKernelToHMA() } -/* - 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 @@ -305,7 +283,6 @@ VOID FAR * HMAalloc(COUNT bytesToAllocate) unsigned CurrentKernelSegment = 0; -/* relocate segment with HMA_TEXT code group */ void MoveKernel(unsigned NewKernelSegment) { UBYTE FAR *HMADest; @@ -313,11 +290,11 @@ void MoveKernel(unsigned NewKernelSegment) unsigned len; unsigned jmpseg = CurrentKernelSegment; - /* if the first time called, initialize to end of HMA_TEXT code group segment */ + /* on 1st call use original link time (unrelocated) TGROUP segment */ if (CurrentKernelSegment == 0) CurrentKernelSegment = FP_SEG(_HMATextEnd); - /* if already relocated into HMA, nothing to do */ + /* if already relocated to HMA, then ignore move request */ if (CurrentKernelSegment == 0xffff) return; @@ -327,8 +304,6 @@ void MoveKernel(unsigned NewKernelSegment) len = (FP_OFF(_HMATextEnd) | 0x000f) - (FP_OFF(_HMATextStart) & 0xfff0); - /* HMA doesn't start until a paragraph into 0xffff segment */ - /* HMA begins with VDISK header to mark area is used */ if (NewKernelSegment == 0xffff) { HMASource += HMAOFFSET; @@ -358,8 +333,7 @@ void MoveKernel(unsigned NewKernelSegment) style table */ - struct RelocationTable FAR *rp; - struct RelocationTable rtemp; + struct RelocationTable FAR *rp, rtemp; /* verify, that all entries are valid */ @@ -375,7 +349,8 @@ void MoveKernel(unsigned NewKernelSegment) FP_OFF(_HMARelocationTableStart)) / sizeof(struct RelocationTable)); int3(); - goto errorReturn; + for (;;) + ; } } @@ -409,9 +384,5 @@ void MoveKernel(unsigned NewKernelSegment) } CurrentKernelSegment = NewKernelSegment; - return; - -errorReturn: - for (;;) ; } diff --git a/kernel/initoem.c b/kernel/initoem.c index 2b0b0fab..e69de29b 100644 --- a/kernel/initoem.c +++ b/kernel/initoem.c @@ -1,73 +0,0 @@ -/****************************************************************/ -/* */ -/* 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 index 3e9462b8..75b33331 100644 --- a/kernel/int2f.asm +++ b/kernel/int2f.asm @@ -25,62 +25,14 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: int2f.asm 1591 2011-05-06 01:46:55Z bartoldeman $ +; $Id$ ; - %include "segs.inc" + %include "segs.inc" %include "stacks.inc" -; macro to switch to an internal stack (if necessary), set DS == SS == DGROUP, -; and push the old SS:SP onto the internal stack -; -; destroys AX, SI, BP; turns on IRQs -; -; int2f does not really need to switch to a separate stack for MS-DOS -; compatibility; this is mainly to work around the C code's assumption -; that SS == DGROUP -; -; TODO: remove the need for this hackery -- tkchia -%macro SwitchToInt2fStack 0 - mov ax,[cs:_DGROUP_] - mov ds,ax - mov si,ss - mov bp,sp - cmp ax,si - jz %%already - cli - mov ss,ax - extern int2f_stk_top - mov sp,int2f_stk_top - sti -%%already: -; well, GCC does not currently clobber function parameters passed on the -; stack; but just in case it decides to do that in the future, we push _two_ -; copies of the old SS:SP: -; - the second copy can be passed as a pointer parameter to a C function -; - the first copy is used to actually restore the user stack later - push si - push bp - push si - push bp -%endmacro - -; macro to switch back from an internal stack, i.e. undo SwitchToInt2fStack -; -; destroys BP; turns on IRQs -- tkchia -%macro DoneInt2fStack 0 - pop bp - pop bp - pop bp - cli - pop ss - mov sp,bp - sti -%endmacro - segment HMA_TEXT - extern _cu_psp - extern _HaltCpuWhileIdle + extern _cu_psp:wrt DGROUP extern _syscall_MUX14 extern _DGROUP_ @@ -101,27 +53,7 @@ Int2f2: 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 +Int2f3: cmp ah,12h je IntDosCal ; Dos Internal calls cmp ah,13h @@ -153,19 +85,12 @@ Check4Share: jne Int2f?iret ; yes, do installation check Int2f?14: ;; MUX-14 -- NLSFUNC API ;; all functions are passed to syscall_MUX14 - ;; Note: this is the kernel's default NLS handlers, if made it - ;; here then no other program (e.g. NLSFUNC) hooked int 2F/14 - ;; and handled request (either none loaded or choose not to) push bp ; Preserve BP later on - Protect386Registers PUSH$ALL - SwitchToInt2fStack call _syscall_MUX14 - DoneInt2fStack 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 @@ -181,19 +106,19 @@ Int2f?iret: ; DRIVER.SYS calls - now only 0803. DriverSysCal: - extern _Dyn + extern _Dyn:wrt DGROUP cmp al, 3 - jne IntDosCal ; pass other calls through + 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 +; also handle Windows' DOS notification hooks ;********************************************************************** IntDosCal: - ; set up register structure + ; set up register frame ;struct int2f12regs ;{ ; [space for 386 regs] @@ -214,6 +139,28 @@ IntDosCal: cld +%IFDEF WIN31SUPPORT ; switch to local stack, no reentrancy support + extern mux2F_stk_top:wrt DGROUP + cli + ; setup, initialize copy + mov si, sp ; ds:si = ss:sp (user stack) + mov ax, ss + mov ds, ax + mov di, mux2F_stk_top-30 ; es:di = local stack-copied chunk + mov es, [cs:_DGROUP_] ; [-X == -(2*cx below+4) ] + mov cx, 13 ; how many words to copy over + ; setup, store original stack pointer + mov [es:di+28], si ; store ss:sp + mov [es:di+26], ds + ; actually switch to local stack + mov ax, es + mov ss, ax + mov sp, di + ; copy over stack data to local stack + rep movsw + sti +%ENDIF ; WIN31SUPPORT + %if XCPU >= 386 %ifdef WATCOM mov si,fs @@ -223,10 +170,9 @@ IntDosCal: %endif %endif - SwitchToInt2fStack + mov ds,[cs:_DGROUP_] extern _int2F_12_handler call _int2F_12_handler - DoneInt2fStack %if XCPU >= 386 %ifdef WATCOM @@ -237,6 +183,24 @@ IntDosCal: %endif %endif +%IFDEF WIN31SUPPORT ; switch back to user stack + cli + ; setup, initialize copy + mov si, sp ; ds:si = ss:sp (local stack) + mov ax, ss + mov ds, ax + mov di, [ds:si+28] ; restore original ss:sp + mov es, [ds:si+26] + mov cx, 13 ; how many words to copy over + ; actually switch to user stack + mov ax, es + mov ss, ax + mov sp, di + ; copy over stack data to user stack + rep movsw + sti +%ENDIF ; WIN31SUPPORT + pop es pop ds pop di @@ -253,7 +217,6 @@ IntDosCal: SHARE_CHECK: mov ax, 0x1000 int 0x2f - test ax, "US" ; Uninstallable SHARE signature ret ; DOS calls this to see if it's okay to open the file. @@ -262,7 +225,7 @@ SHARE_CHECK: ; 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(const char FAR * filename, +; STATIC int share_open_check(char * filename, ; /* pointer to fully qualified filename */ ; unsigned short pspseg, ; /* psp segment address of owner process */ @@ -271,17 +234,16 @@ SHARE_CHECK: ; int sharemode) /* SHARE_COMPAT, etc... */ global SHARE_OPEN_CHECK SHARE_OPEN_CHECK: - push ds - pop es ; save ds - mov di, si ; save si + mov es, si ; save si pop ax ; return address - popargs {ds,si},bx,cx,dx; filename,pspseg,openmode,sharemode; + 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, di ; restore si - push es - pop ds ; restore ds + mov si, es ; restore si ret ; DOS calls this to record the fact that it has successfully @@ -322,13 +284,12 @@ share_common: mov bp, sp push si push di -arg pspseg, fileno, {ofs,4}, {len,4}, allowcriter - mov bx, [.pspseg] ; pspseg - mov cx, [.fileno] ; fileno - mov si, [.ofs+2] ; high word of ofs - mov di, [.ofs] ; low word of ofs - les dx, [.len] ; len - or ax, [.allowcriter] ; allowcriter/unlock + 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 @@ -350,25 +311,6 @@ SHARE_LOCK_UNLOCK: mov ax,0x10a4 jmp short share_common -; DOS calls this to see if share already has the file marked as open. -; Returns: -; 1 if open -; 0 if not -; STATIC WORD share_is_file_open(const char far *filename) /* pointer to fully qualified filename */ - global SHARE_IS_FILE_OPEN -SHARE_IS_FILE_OPEN: - mov si, ds - mov es, si ; save ds - pop ax ; save return address - pop si ; filename - pop ds ; SEG filename - push ax ; restore return address - mov ax, 0x10a6 - int 0x2f ; returns ax - mov si, es ; restore ds - mov ds, si - ret - ; Int 2F Multipurpose Remote System Calls ; ; added by James Tabor jimtabor@infohwy.com @@ -385,7 +327,7 @@ remote_lseek: ; arg is a pointer to the long seek value ; "fall through" remote_getfattr: - stc ; assume unsupported/failed unless carry clear on return + clc ; set to succeed int 2fh jc ret_neg_ax jmp short ret_int2f @@ -404,8 +346,10 @@ remote_lock_unlock: global NETWORK_REDIRECTOR_MX NETWORK_REDIRECTOR_MX: pop bx ; ret address - popargs ax,{es,dx},cx ; cmd (ax), seg:off s - ; stack value (arg); cx in remote_rw + 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 @@ -431,16 +375,13 @@ call_int2f: push cx ; arg cmp al, 0ch je remote_getfree - cmp al, 0xa3 - je remote_getfree cmp al, 1eh je remote_print_doredir cmp al, 1fh je remote_print_doredir int2f_call: - xor cx, cx ; default to success error code but - stc ; assume unsupported/failed unless carry clear on return + xor cx, cx ; set to succeed; clear carry and CX int 2fh pop bx jnc ret_set_ax_to_cx @@ -465,7 +406,7 @@ remote_print_doredir: ; di points to an lregs structure mov si,[di+8] lds di,[di+0xa] - stc ; assume unsupported/failed unless carry clear on return + clc ; set to succeed int 2fh pop bx ; restore stack and ds=ss push ss @@ -476,7 +417,7 @@ ret_set_ax_to_carry: ; carry => -1 else 0 (SUCCESS) jmp short ret_int2f remote_getfree: - stc ; assume unsupported/failed unless carry clear on return + clc ; set to succeed int 2fh pop di ; retrieve pushed pointer arg jc ret_set_ax_to_carry @@ -484,11 +425,10 @@ remote_getfree: mov [di+2],bx mov [di+4],cx mov [di+6],dx - mov [di+8],si ; for REM_GETLARGEFREE, unused on REM_GETFREE jmp short ret_set_ax_to_carry remote_rw: - stc ; assume unsupported/failed unless carry clear on return + clc ; set to succeed int 2fh jc ret_min_dx_ax xor dx, dx ; dx:ax := dx:cx = bytes read @@ -505,50 +445,40 @@ qremote_fn: remote_process_end: ; Terminate process mov ds, [_cu_psp] int2f_restore_ds: - stc ; assume unsupported/failed unless carry clear on return + 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 - 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 +; extern UWORD ASMCFUNC call_nls(UWORD subfct, struct nlsInfoBlock *nlsinfo, +; UWORD bp, UWORD cp, UWORD cntry, UWORD bufsize, UWORD FAR *buf, UWORD *id); + + global _call_nls +_call_nls: push bp mov bp, sp push si push di - mov si, _nlsInfo ; nlsinfo - les di, [bp + 4] ; buf + mov al, [bp + 4] ; subfct + mov ah, 0x14 + mov si, [bp + 6] ; nlsinfo + mov bx, [bp + 10] ; cp + mov dx, [bp + 12] ; cntry + mov cx, [bp + 14] ; bufsize + les di, [bp + 16] ; buf + push bp mov bp, [bp + 8] ; bp int 0x2f - mov dx, bx ; return id in high word + pop bp + mov bp, [bp + 20] ; store id (in SS:) unless it's NULL + or bp, bp + jz nostore + mov [bp], bx +nostore: 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 ; @@ -573,23 +503,22 @@ FLOPPY_CHANGE: ; 00h successful ; 80h function not implemented ; B0h only a smaller UMB is available -; B1h no UMBs are available +; B1h no UMB's are available ; B2h UMB segment number is invalid ; segment INIT_TEXT ; int ASMPASCAL UMB_get_largest(void FAR * driverAddress, ; UCOUNT * seg, UCOUNT * size); -arg {driverAddress,4}, argseg, size - global UMB_GET_LARGEST + 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 [.driverAddress] ; Call the driver + mov ax,1000h ; get the umb's + call far [bp+8] ; Call the driver ; ; bl = 0xB0 and ax = 0 so do it again. @@ -601,7 +530,7 @@ UMB_GET_LARGEST: je umbt_error mov ax,1000h ; dx set with largest size - call far [.driverAddress] ; Call the driver + call far [bp+8] ; Call the driver cmp ax,1 jne umbt_error @@ -609,10 +538,10 @@ UMB_GET_LARGEST: ; and the size mov cx,bx ; *seg = segment - mov bx, [.argseg] + mov bx, [bp+6] mov [bx],cx - mov bx, [.size] ; *size = size + mov bx, [bp+4] ; *size = size mov [bx],dx umbt_ret: diff --git a/kernel/inthndlr.c b/kernel/inthndlr.c index ea45e240..369cae8f 100644 --- a/kernel/inthndlr.c +++ b/kernel/inthndlr.c @@ -31,12 +31,12 @@ #include "portab.h" #include "globals.h" #include "nls.h" -#include "win.h" #include "debug.h" + #ifdef VERSION_STRINGS BYTE *RcsId = - "$Id: inthndlr.c 1709 2012-02-08 02:13:49Z perditionc $"; + "$Id$"; #endif #ifdef TSC @@ -61,58 +61,38 @@ struct HugeSectorBlock { BYTE FAR *buf; }; +#ifdef WIN31SUPPORT +#include "win.h" /* Structures used for Windows compatibility */ +#endif /* WIN31SUPPORT */ + + /* 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 +/* this here works on the users stack !! and only very few functions are allowed */ - -/* TODO: really, really make sure that this function works properly */ -/* even when SS != DGROUP (some changes to the compiler (!) may be */ -/* necessary). Currently, between Turbo C++, gcc-ia16, & Open Watcom, */ -/* it seems only Watcom has explicit support for calling near-data */ -/* functions with SS != DGROUP. The code for this function happens to */ -/* to compile under gcc-ia16 to correctly-behaving code _for now_. But */ -/* it will be better to be able to guarantee this. -- tkchia 20191207 */ - -/* Update: I added experimental SS != DGROUP support, and a __seg_ss */ -/* address space qualifier, to gcc-ia16 around January 2020. This */ -/* function now uses these if available. In particular, the iregs *irp */ -/* structure will always be on the stack, so (as far as the calling */ -/* convention permits) the function can treat the irp pointer as a */ -/* 16-bit pointer relative to SS. -- tkchia 20200417 */ -#if defined __GNUC__ && defined __IA16_FEATURE_ATTRIBUTE_NO_ASSUME_SS_DATA -__attribute__((no_assume_ss_data)) -VOID ASMCFUNC int21_syscall(iregs __seg_ss * irp, ...) -#else VOID ASMCFUNC int21_syscall(iregs FAR * irp) -#endif { Int21AX = irp->AX; switch (irp->AH) { - /* Set Interrupt Vector - now implemented in entry.asm */ -#if 0 + /* Set Interrupt Vector */ case 0x25: setvec(irp->AL, (intvec)MK_FP(irp->DS, irp->DX)); break; -#endif - /* DosVars - get/set dos variables */ - case 0x33: + case 0x33: /* DosVars - get/set dos variables */ switch (irp->AL) { - /* Set Ctrl-C flag; returns dl = break_ena */ - case 0x01: + case 0x01: /* Set Ctrl-C flag */ break_ena = irp->DL & 1; /* fall through so DL only low bit (as in MS-DOS) */ - /* Get Ctrl-C flag */ - case 0x00: + case 0x00: /* Get Ctrl-C flag */ irp->DL = break_ena; break; - case 0x02: /* andrew schulman: get/set extended control break */ + case 0x02: /* andrew schulman: get/set extended control break */ { UBYTE tmp = break_ena; break_ena = irp->DL & 1; @@ -129,7 +109,7 @@ VOID ASMCFUNC int21_syscall(iregs FAR * irp) case 0x06: irp->BL = os_major; irp->BH = os_minor; - irp->DL = 0; /* lower 3 bits revision #, remaining should be 0 */ + irp->DL = rev_number; irp->DH = version_flags; /* bit3:runs in ROM,bit 4: runs in HMA */ break; @@ -140,53 +120,32 @@ VOID ASMCFUNC int21_syscall(iregs FAR * irp) irp->AL = 0xff; break; - /* the remaining are FreeDOS extensions */ - - /* return CPU family */ - case 0xfa: - irp->AL = CPULevel; - break; - -#if 0 /* unknown if used / usage */ - case 0xfb: -#endif - -#if 1 /* duplicates DOS 4 int 2F/122Fh, but used by CALLVER */ - /* set FreeDOS returned version for int 21.30 from BX */ - case 0xfc: - os_setver_major = irp->BL; - os_setver_minor = irp->BH; - break; -#endif + /* set FreeDOS returned version for int 21.30 from BX */ + case 0xfc: /* 0xfc ... 0xff are FreeDOS extensions */ + os_setver_major = irp->BL; + os_setver_minor = irp->BH; + break; /* Toggle DOS-C rdwrblock trace dump */ #ifdef DEBUG case 0xfd: bDumpRdWrParms = !bDumpRdWrParms; break; -#endif /* Toggle DOS-C syscall trace dump */ -#ifdef DEBUG case 0xfe: bDumpRegs = !bDumpRegs; - irp->AX = bDumpRegs; break; #endif /* Get DOS-C release string pointer */ case 0xff: -#if !defined __GNUC__ || defined __IA16_FEATURE_ATTRIBUTE_NO_ASSUME_SS_DATA irp->DX = FP_SEG(os_release); -#else /* TODO: remove this hacky SS != DGROUP workaround --tkchia 20191207 */ - asm volatile("movw %%ds, %0" : "=g" (irp->DX)); -#endif irp->AX = FP_OFF(os_release); } break; - /* Get Interrupt Vector - now implemented in entry.asm */ -#if 0 + /* Get Interrupt Vector */ case 0x35: { intvec p = getvec(irp->AL); @@ -194,7 +153,6 @@ VOID ASMCFUNC int21_syscall(iregs FAR * irp) irp->BX = FP_OFF(p); break; } -#endif /* Set PSP */ case 0x50: @@ -217,7 +175,7 @@ VOID ASMCFUNC int21_syscall(iregs FAR * irp) int int21_fat32(lregs *r) { COUNT rc; - + switch (r->AL) { /* Get extended drive parameter block */ @@ -225,7 +183,7 @@ int int21_fat32(lregs *r) { struct dpb FAR *dpb; struct xdpbdata FAR *xddp; - + if (r->CX < sizeof(struct xdpbdata)) return DE_INVLDBUF; @@ -236,12 +194,12 @@ int int21_fat32(lregs *r) /* 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); @@ -261,13 +219,15 @@ int int21_fat32(lregs *r) case 0x03: { struct xfreespace FAR *xfsp = MK_FP(r->ES, r->DI); - + if (r->CX < sizeof(struct xfreespace)) return DE_INVLDBUF; rc = DosGetExtFree(MK_FP(r->DS, r->DX), xfsp); if (rc != SUCCESS) return rc; + xfsp->xfs_datasize = sizeof(struct xfreespace); + xfsp->xfs_version.actual = 0; break; } /* Set DPB to use for formatting */ @@ -282,22 +242,26 @@ int int21_fat32(lregs *r) 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 (nfreeclst == 1 || cluster == 1) + return DE_INVLDPARM; + if (ISFAT32(dpb)) { if ((dpb->dpb_xfsinfosec == 0xffff - && (nfreeclst != 0 || cluster != 0)) - || nfreeclst == 1 || nfreeclst > dpb->dpb_xsize - || cluster == 1 || cluster > dpb->dpb_xsize) + && (nfreeclst || cluster)) + || nfreeclst > dpb->dpb_xsize + || cluster > dpb->dpb_xsize) { return DE_INVLDPARM; } @@ -307,8 +271,8 @@ int int21_fat32(lregs *r) } else { - if ((unsigned)nfreeclst == 1 || (unsigned)nfreeclst > dpb->dpb_size || - (unsigned)cluster == 1 || (unsigned)cluster > dpb->dpb_size) + if ((unsigned)nfreeclst > dpb->dpb_size || + (unsigned)cluster > dpb->dpb_size) { return DE_INVLDPARM; } @@ -329,51 +293,61 @@ int int21_fat32(lregs *r) /* 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)) + struct buffer FAR *bp; + bpb FAR *bpbp; + DWORD newmirroring = + xdffp->xdff_f.setmirroring.newmirroring; + + if (newmirroring != -1 + && (ISFAT32(dpb) + && (newmirroring & ~(0xf | 0x80)))) + { return DE_INVLDPARM; - - value = xdffp->xdff_f.setget.new; - if ((UWORD) xdffp->xdff_function == 0x03) + } + xdffp->xdff_f.setmirroring.oldmirroring = + (ISFAT32(dpb) ? dpb->dpb_xflags : 0); + if (newmirroring != -1 && ISFAT32(dpb)) { - /* FAT mirroring */ - if (value != 0xFFFFFFFFUL && (value & ~(0xf | 0x80))) - return DE_INVLDPARM; - xdffp->xdff_f.setget.old = dpb->dpb_xflags; + bp = getblock(1, dpb->dpb_unit); + bp->b_flag &= ~(BFR_DATA | BFR_DIR | BFR_FAT); + bp->b_flag |= BFR_VALID | BFR_DIRTY; + bpbp = (bpb FAR *) & bp->b_buffer[BT_BPB]; + bpbp->bpb_xflags = (UWORD)newmirroring; } - else + goto rebuild_dpb; + } + case 0x04: + { + struct buffer FAR *bp; + bpb FAR *bpbp; + DWORD rootclst = xdffp->xdff_f.setroot.newrootclst; + if (!ISFAT32(dpb) + || (rootclst != -1 + && (rootclst == 1 + || (ULONG)rootclst > dpb->dpb_xsize))) { - /* root cluster */ - if (value != 0xFFFFFFFFUL && (value < 2 || value > dpb->dpb_xsize)) - return DE_INVLDPARM; - xdffp->xdff_f.setget.old = dpb->dpb_xrootclst; + return DE_INVLDPARM; } - if (value != 0xFFFFFFFFUL) + xdffp->xdff_f.setroot.oldrootclst = dpb->dpb_xrootclst; + if (rootclst != -1) { - bpb FAR *bpbp; - struct buffer FAR *bp = getblock(1, dpb->dpb_unit); + 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; + bpbp->bpb_xrootclst = rootclst; } goto rebuild_dpb; } - default: - return DE_INVLDFUNC; } - + break; } /* Extended absolute disk read/write */ @@ -383,30 +357,29 @@ int int21_fat32(lregs *r) 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)) + + if (r->CX != 0xffff || ((r->SI & 1) == 0 && r->SI != 0) + || (r->SI & ~0x6001)) { return DE_INVLDPARM; } - + if (r->DL > lastdrive || r->DL == 0) return -0x207; - - if ((r->SI & 1) == 0) /* while uncommon, reads CAN have type hints */ + + if (r->SI == 0) mode = DSKREADINT25; else mode = DSKWRITEINT26; - + r->AX = dskxfer(r->DL - 1, SectorBlock->blkno, SectorBlock->buf, SectorBlock->nblks, mode); - + if (mode == DSKWRITEINT26) - if (r->AX == 0) + if (r->AX <= 0) setinvld(r->DL - 1); - + if (r->AX > 0) return -0x20c; break; @@ -423,7 +396,6 @@ VOID ASMCFUNC int21_service(iregs FAR * r) COUNT rc; long lrc; lregs lr; /* 8 local registers (ax, bx, cx, dx, si, di, ds, es) */ - psp FAR *psp = MK_FP(cu_psp, 0); #define FP_DS_DX (MK_FP(lr.DS, lr.DX)) #define FP_ES_DI (MK_FP(lr.ES, lr.DI)) @@ -431,7 +403,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) #define CLEAR_CARRY_FLAG() r->FLAGS &= ~FLG_CARRY #define SET_CARRY_FLAG() r->FLAGS |= FLG_CARRY - psp->ps_stack = (BYTE FAR *) r; + ((psp FAR *) MK_FP(cu_psp, 0))->ps_stack = (BYTE FAR *) r; fmemcpy(&lr, r, sizeof(lregs) - 4); lr.DS = r->DS; @@ -443,7 +415,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) if (bDumpRegs) { fmemcpy(&error_regs, user_r, sizeof(iregs)); - DebugPrintf(("System call (21h): %02x\n", user_r->AX)); + printf("System call (21h): %04x\n", user_r->AX); dump_regs = TRUE; dump(); } @@ -451,6 +423,9 @@ VOID ASMCFUNC int21_service(iregs FAR * r) 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) || +#ifdef WITHFAT32 + lr.AH == 0x73 || +#endif lr.AH == 0x6c) { CLEAR_CARRY_FLAG(); @@ -459,23 +434,28 @@ VOID ASMCFUNC int21_service(iregs FAR * r) } /* 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 - */ + /* We force clear the near fnodes, + On a normal int21h entry these are unused, so should already + be clear, thus this code is effectively redundant. + However when re-entering int21h, such as a device driver + (e.g. shsufdrv), the fnodes may contain the values of the + in progress call; as long as the driver/tsr causing the + reentrancey saves and restores the SDA across the call then + any changes we do (ie clearing these) should go unnoticed + and if the cause of the reentrancy does not save/restore the + SDA then the caller should expected the unexpected. + Failure to do this will at a minimal result in the extra + output indicating fnodes not 0 (and possibly clearing at end + of call) when the re-entered int21h call completes, but could + result in the re-entered call to fail with no free near fnodes + if both are already in use by the original int21h call (?bug 1879?). + See also PATCH TE 5 jul 04 explanation at end + */ if (/*ErrorMode && */lr.AH > 0x0c && lr.AH != 0x30 && lr.AH != 0x59) { /*if (ErrorMode)*/ ErrorMode = 0; + fnode[0].f_count = 0; /* don't panic - THEY ARE unused !! */ + fnode[1].f_count = 0; } /* Check for Ctrl-Break */ if (break_ena || (lr.AH >= 1 && lr.AH <= 5) || (lr.AH >= 8 && lr.AH <= 0x0b)) @@ -486,7 +466,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) { /* int 21h common error handler */ case 0x64: - goto error_invalid; + goto error_invalid; /* case 0x00: --> Simulate a DOS-4C-00 */ @@ -644,7 +624,6 @@ VOID ASMCFUNC int21_service(iregs FAR * r) default: #ifdef DEBUG printf("Unsupported INT21 AH = 0x%x, AL = 0x%x.\n", lr.AH, lr.AL); -#endif /* Fall through. */ /* CP/M compatibility functions */ @@ -656,6 +635,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) case 0x61: #endif case 0x6b: +#endif lr.AL = 0; break; @@ -676,18 +656,12 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* 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 */ - } + { + UBYTE FAR *p = FatGetDrvData(lr.DL, &lr.AL, &lr.CX, &lr.DX); + lr.DS = FP_SEG(p); + lr.BX = FP_OFF(p); break; + } /* Get default DPB */ /* case 0x1f: see case 0x32 */ @@ -763,38 +737,34 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Get DTA */ case 0x2f: - lr.BX = FP_OFF(dta); lr.ES = FP_SEG(dta); + lr.BX = FP_OFF(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.AX = psp->ps_retdosver; - lr.BL = REVISION_SEQ; - lr.CX = 0; /* do not set this to a serial number! - 32RTM won't like non-zero values */ + lr.AL = os_setver_major; + lr.AH = os_setver_minor; + lr.BX = (OEM_ID << 8) | REVISION_SEQ; + lr.CX = 0; /* serial number must be 0 or buggy 32RTM thrashes stack! */ if (ReturnAnyDosVersionExpected) { - /* TE for testing purpose only and NOT + /* TE for testing purpose only and NOT to be documented: return programs, who ask for version == XX.YY - exactly this 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 */ + if (retp[0] == 0x3d) /* cmp ax, xxyy */ { - lr.AL = retp[1]; - lr.AH = retp[2]; + lr.AX = *(UWORD FAR *)&retp[1]; } +#if TOM /* Disable the much rarer case to save code size. The only MS-DOS + * utility featuring it is DOSKEY, and FreeCom almost replaces it + */ 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 */ @@ -802,17 +772,16 @@ VOID ASMCFUNC int21_service(iregs FAR * r) lr.AL = retp[4]; lr.AH = retp[3]; } - +#endif } - } - - break; + break; /* Keep Program (Terminate and stay resident) */ case 0x31: DosMemChange(cu_psp, lr.DX < 6 ? 6 : lr.DX, 0); return_code = lr.AL | 0x300; - term_type = 3; /* ecm: TSR terminate */ + DDebugPrintf(("ErrorLevel kernel returns is %x(==%x|0x300)\n", (unsigned)return_code, (unsigned)lr.AL)); + tsr = TRUE; return_user(); break; @@ -825,14 +794,14 @@ VOID ASMCFUNC int21_service(iregs FAR * r) { 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! */ + /* hazard: no error checking! */ flush_buffers(dpb->dpb_unit); dpb->dpb_flags = M_CHANGED; /* force flush and reread of drive BPB/DPB */ @@ -853,13 +822,13 @@ VOID ASMCFUNC int21_service(iregs FAR * r) break; /* - case 0x33: + case 0x33: see int21_syscall */ /* Get InDOS flag */ case 0x34: - lr.BX = FP_OFF(&InDOS); lr.ES = FP_SEG(&InDOS); + lr.BX = FP_OFF(&InDOS); break; /* Get Interrupt Vector */ @@ -894,28 +863,18 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Get/Set Country Info */ case 0x38: { - UWORD cntry = lr.AL; - - if (cntry == 0xff) - cntry = lr.BX; - + UWORD ccode = lr.AL != 0xFF ? lr.AL : lr.BX; if (0xffff == lr.DX) { /* Set Country Code */ - rc = DosSetCountry(cntry); + rc = DosSetCountry(ccode); } else { - if (cntry == 0) - cntry--; /* Get Country Information */ - rc = DosGetCountryInformation(cntry, FP_DS_DX); + rc = DosGetCountryInformation(ccode ? ccode : NLS_DEFAULT, FP_DS_DX); if (rc >= SUCCESS) - { - if (cntry == (UWORD) - 1) - cntry = nlsInfo.actPkg->cntry; - lr.AX = lr.BX = cntry; - } + lr.BX = ccode ? ccode : nlsPackageHardcoded.cntry; } goto short_check; } @@ -964,15 +923,15 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Dos Seek */ case 0x42: - if (lr.AL > 2) - goto error_invalid; - lrc = DosSeek(lr.BX, (LONG)MK_ULONG(lr.CX, lr.DX), lr.AL, &rc); - if (rc == SUCCESS) + { + sft FAR *s = get_sft(lr.BX); + if ((rc = _SftSeek(s, MK_ULONG(lr.CX, lr.DX), lr.AL)) >= SUCCESS) { - lr.DX = (UWORD)(lrc >> 16); - lr.AX = (UWORD) lrc; + lr.DX = hiword (s->sft_posit); + lr.AX = loword (s->sft_posit); } goto short_check; + } /* Get/Set File Attributes */ case 0x43: @@ -989,33 +948,6 @@ VOID ASMCFUNC int21_service(iregs FAR * r) 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.CL); - 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; } @@ -1082,7 +1014,8 @@ VOID ASMCFUNC int21_service(iregs FAR * r) #if 0 if (cu_psp == lr.ES) { - psp->ps_size = lr.BX + cu_psp; + psp FAR *p = MK_FP(cu_psp, 0); + p->ps_size = lr.BX + cu_psp; } #endif if (DosMemCheck() != SUCCESS) @@ -1105,12 +1038,22 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* End Program */ case 0x4c: - if (break_flg) { + if (((psp FAR *)MK_FP(cu_psp, 0))->ps_parent == cu_psp) + break; + tsr = FALSE; + rc = 0; + if (ErrorMode) + { + ErrorMode = FALSE; + rc = 0x200; + } + else if (break_flg) + { break_flg = FALSE; - term_type = 1; + rc = 0x100; } - rc = term_type << 8; return_code = lr.AL | rc; + DDebugPrintf(("ErrorLevel kernel returns is %x\n", (unsigned)return_code)); if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC @@ -1122,6 +1065,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Get Child-program Return Value */ case 0x4d: lr.AX = return_code; + DDebugPrintf(("Child ErrorLevel kernel returns is %x(==%x)\n", (unsigned)return_code, (unsigned)lr.AX)); /* needs to be cleared (RBIL) */ return_code = 0; break; @@ -1142,15 +1086,15 @@ VOID ASMCFUNC int21_service(iregs FAR * r) lr.AX = 0; goto short_check; /* - case 0x50: + case 0x50: case 0x51: see int21_syscall */ /* ************UNDOCUMENTED************************************* */ /* Get List of Lists */ case 0x52: - lr.BX = FP_OFF(&DPBp); lr.ES = FP_SEG(&DPBp); + lr.BX = FP_OFF(&DPBp); break; case 0x53: @@ -1172,8 +1116,6 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Dos Create New Psp & set p_size */ case 0x55: child_psp(lr.DX, cu_psp, lr.SI); - /* copy command line from the parent (required for some device loaders) */ - fmemcpy(MK_FP(lr.DX, 0x80), MK_FP(cu_psp, 0x80), 128); cu_psp = lr.DX; break; @@ -1194,8 +1136,8 @@ VOID ASMCFUNC int21_service(iregs FAR * r) case 0x01: rc = DosSetFtime((COUNT) lr.BX, /* Handle */ - (ddate) lr.DX, /* FileDate */ - (dtime) lr.CX); /* FileTime */ + (date) lr.DX, /* FileDate */ + (time) lr.CX); /* FileTime */ break; default: @@ -1208,8 +1150,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) switch (lr.AL) { case 0x00: - lr.AL = mem_access_mode; - lr.AH = 0; + lr.AX = mem_access_mode; break; case 0x01: @@ -1224,7 +1165,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) break; case 0x03: - if (uppermem_root != 0xffff) /* always error if not exists */ + if (uppermem_root != 0xffff) /* always error if not exists */ { DosUmbLink(lr.BX); break; @@ -1244,11 +1185,11 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* Get Extended Error */ case 0x59: lr.AX = CritErrCode; + lr.ES = FP_SEG(CritErrDev); + lr.DI = FP_OFF(CritErrDev); lr.CH = CritErrLocus; lr.BH = CritErrClass; lr.BL = CritErrAction; - lr.DI = FP_OFF(CritErrDev); - lr.ES = FP_SEG(CritErrDev); break; /* Create Temporary File */ @@ -1294,19 +1235,18 @@ VOID ASMCFUNC int21_service(iregs FAR * r) case 0x09: rc = remote_printredir(lr.DX, Int21AX); CLEAR_CARRY_FLAG(); - if (rc != SUCCESS) - goto error_exit; - break; + goto short_check; /* 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; + lregs er; + fmemcpy(&er, FP_DS_DX, sizeof(er)); + CritErrCode = er.AX; + CritErrDev = MK_FP(er.ES, er.DI); + CritErrLocus = er.CH; + CritErrClass = er.BH; + CritErrAction = er.BL; CLEAR_CARRY_FLAG(); break; } @@ -1335,12 +1275,12 @@ VOID ASMCFUNC int21_service(iregs FAR * r) break; case 0x5f: - if (lr.AL == 7 || lr.AL == 8) + if (inrange(UBYTE, lr.AL, 7, 8)) { if (lr.DL < lastdrive) { struct cds FAR *cdsp = CDSp + lr.DL; - if (FP_OFF(cdsp->cdsDpb)) /* letter of physical drive? */ + if (FP_OFF(cdsp->cdsDpb)) /* letter of physical drive? */ { cdsp->cdsFlags &= ~CDSPHYSDRV; if (lr.AL == 7) @@ -1351,23 +1291,20 @@ VOID ASMCFUNC int21_service(iregs FAR * r) 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 */ + r->AX = rc; + if (rc != SUCCESS) { - 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; + SET_CARRY_FLAG(); + CritErrCode = rc; /* Maybe set */ } + 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 @@ -1391,7 +1328,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) break; #endif - /* UNDOCUMENTED: return current psp + /* UNDOCUMENTED: return current psp case 0x62: is in int21_syscall lr.BX = cu_psp; break; @@ -1401,29 +1338,21 @@ VOID ASMCFUNC int21_service(iregs FAR * r) case 0x63: { VOID FAR *p; + + if (lr.AL == 0) { + p = DosGetDBCS(); + lr.DS = FP_SEG(p); + lr.SI = FP_OFF(p); + } + else + lr.AL = 0; + #if 0 /* not really supported, but will pass. */ lr.AL = 0x00; /*jpp: according to interrupt list */ - /*Bart: fails for PQDI and WATCOM utilities: + /*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) + 2; - 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; } /* @@ -1454,7 +1383,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) DosUpFString(FP_DS_DX); break; case 0x23: /* check Yes/No response */ - lr.AX = DosYesNo(lr.DL); + lr.AX = DosYesNo(lr.DX); break; default: #ifdef NLS_DEBUG @@ -1542,148 +1471,13 @@ VOID ASMCFUNC int21_service(iregs FAR * r) /* case 0x6d and above not implemented : see default; return AL=0 */ #ifdef WITHFAT32 - /* LFN API */ + /* LFN functions - fail with "function not supported" error code */ case 0x71: - switch (lr.AL) - { -#ifdef WITHLFNAPI - /* Win95 LFN - reset drive */ - case 0x0d: - /* Win95 LFN - make directory */ - case 0x39: - /* Win95 LFN - remove directory */ - case 0x3a: - /* Win95 LFN - change directory */ - case 0x3b: - /* Win95 LFN - delete file */ - case 0x41: - /* Win95 LFN - extended get/set file attributes */ - case 0x43: - /* Win95 LFN - get current directory */ - case 0x47: - /* Win95 LFN - find first file */ - case 0x4e: - /* Win95 LFN - find next file */ - case 0xa2: /* internal - same as 0x4f */ - case 0x4f: { - goto unsupp; - } - /* Win95 LFN - rename file */ - case 0x56: - /* Win95 LFN - canonicalize file name/path */ - case 0x60: { - switch (lr.CL) - { - /* truename - canonicalize path, accepts short/long/or combination as input and may return combined short/long name */ - case 0x00: { - } - /* get canonical short (8.3) name or path, truename that accepts long name and returns short name */ - case 0x01: { - } - /* get canonical long name or path, truename that accepts short name and returns long name */ - case 0x02: { - } - default: - goto unsupp; - } - } - /* Win95 LFN - create or open file */ - case 0xa9: /* for real-mode servers only, AX is _global_ file handle on return */ - case 0x6c: { - goto unsupp; - } - /* Win95 LFN - get volume information */ - case 0xa0: - /* Win95 LFN - find file close */ - case 0xa1: { -lfn_findclose: - goto unsupp; - } -#if 0 - /* Win95 LFN - internal use ??? */ - case 0xa3: - case 0xa4: - case 0xa5: - goto unsupp; -#endif -#endif - /* EDR-DOS LFN - Long LSEEK - SET CURRENT 64-bit FILE POSITION */ - case 0x42: - /* Win95 LFN - get file info by handle */ - case 0xa6: { - /* only passed to redirector supported for now */ - iregs saved_r; - sft FAR *s; - unsigned char idx; - - if (lr.BX >= psp->ps_maxfiles) - { - rc = DE_INVLDHNDL; - goto error_exit; - } - idx = psp->ps_filetab[lr.BX]; - s = idx_to_sft(idx); - if (s == (sft FAR *)-1) - { - rc = DE_INVLDHNDL; - goto error_exit; - } - if (!(s->sft_flags & SFT_FSHARED)) { - if (lr.AL != 0x42) { - goto unsupp; /* unsupported on local fs yet */ - } - } - /* call to redirector */ - fmemcpy(&saved_r, r, sizeof(saved_r)); - r->ES = FP_SEG(s); - r->DI = FP_OFF(s); - r->flags |= FLG_CARRY; - r->AH = 0x11; - call_intr(0x2f, r); - if (!(r->flags & FLG_CARRY)) { - r->ES = saved_r.ES; - r->DI = saved_r.DI; - goto real_exit; - } - /* carry still set - unhandled */ - fmemcpy(r, &saved_r, sizeof(saved_r)); - goto unsupp; - } -#ifdef WITHLFNAPI - /* Win95 LFN - Win95 64 UTC file time to/from DOS date and time (local timezone) */ - case 0xa7: { - /* Note: valid input range limited to Jan 1, 1980 to Dec 31, 2107 */ - switch (lr.BL) - { - /* from Win95 UTC to DOS date/time */ - case 0x00: { - } - /* from DOS date/time to Win95 UTC */ - case 0x01: { - } - default: - goto unsupp; - } - } - /* Win95 LFN - generate short filename */ - case 0xa8: - /* Win95 LFN - subst */ - case 0xaa: { - goto unsupp; - } -#endif - default: - goto unsupp; - } -#ifdef WITHLFNAPI - /* Win95 beta LFN - find close */ - case 0x72: goto lfn_findclose; -#endif + 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 @@ -1704,7 +1498,7 @@ VOID ASMCFUNC int21_service(iregs FAR * r) break; /* Setup LFN inode */ case 0x03: - rc = lfn_setup_inode(lr.BX, MK_ULONG(lr.CX, lr.DX), MK_ULONG(lr.SI,lr.DI)); + rc = lfn_setup_inode(lr.BX, ((ULONG)lr.CX << 16) | lr.DX, ((ULONG)lr.SI << 16) | lr.DI); break; /* Create LFN entries */ case 0x04: @@ -1728,13 +1522,6 @@ VOID ASMCFUNC int21_service(iregs FAR * r) #endif } goto exit_dispatch; -#ifdef WITHFAT32 -unsupp: - { - lr.AL = 00; - goto error_carry; - } -#endif long_check: if (lrc >= SUCCESS) { @@ -1755,11 +1542,36 @@ VOID ASMCFUNC int21_service(iregs FAR * r) error_carry: SET_CARRY_FLAG(); exit_dispatch: - fmemcpy(r, &lr, sizeof(lregs) - 4); /* copy lr -> r but exclude flags */ + fmemcpy(r, &lr, sizeof(lregs) - 4); r->DS = lr.DS; r->ES = lr.ES; real_exit:; + /* PATCH !! TE 5 JUL 04 + 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 + + a) now the alloc()'ed fnode[0] never gets free()'ed + b) errormode NEVER gets set back to 0 unyil exit() + + I have NO idea how real DOS handles this; + the appended patch cures the worst symptoms + */ + if (fnode[0].f_count != 0 || + fnode[1].f_count != 0 ) + { + if (ErrorMode == 0) + put_string("near_fnodes not 0"); /* panic ?? */ + fnode[0].f_count = 0; /* don't panic - THEY ARE unused !! */ + fnode[1].f_count = 0; + } + /* PATCH !! END TE 5 JUL 04 */ + #ifdef DEBUG if (bDumpRegs) { @@ -1778,7 +1590,7 @@ 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) { - term_type = 1; + tsr = FALSE; return_mode = 1; return_code = -1; mod_sto(CTL_C); @@ -1797,8 +1609,8 @@ struct int25regs { UWORD flags, ip, cs; }; -/* - this function is called from an assembler wrapper function +/* + this function is called from an assembler wrapper function */ VOID ASMCFUNC int2526_handler(WORD mode, struct int25regs FAR * r) { @@ -1806,34 +1618,25 @@ VOID ASMCFUNC int2526_handler(WORD mode, struct int25regs FAR * r) UWORD nblks; BYTE FAR *buf; UBYTE drv; - struct dpb FAR *dpbp; if (mode == 0x26) mode = DSKWRITEINT26; else mode = DSKREADINT25; - drv = r->ax & 0x7f; /* according to RBIL, some programs may try with */ - /* high bit of AL set, so mask it together with AH */ - /* otherwise we might access a non-existing unit */ - - dpbp = get_dpb(drv); + drv = r->ax; - if (drv >= lastdrive || dpbp == NULL) + if (drv >= lastdrive) { r->ax = 0x201; SET_CARRY_FLAG(); return; } - nblks = r->cx; - blkno = r->dx; - #ifdef WITHFAT32 { - /* if reading / writing block other than bootsecter, - prevent using INT25,26 on initialized FAT32 */ - if ((blkno != 0) && ISFAT32(dpbp) && (dpbp->dpb_xfatsize != 0)) + struct dpb FAR *dpbp = get_dpb(drv); + if (dpbp != NULL && ISFAT32(dpbp)) { r->ax = 0x207; SET_CARRY_FLAG(); @@ -1842,6 +1645,9 @@ VOID ASMCFUNC int2526_handler(WORD mode, struct int25regs FAR * r) } #endif + nblks = r->cx; + blkno = r->dx; + buf = MK_FP(r->ds, r->bx); if (nblks == 0xFFFF) @@ -1854,8 +1660,6 @@ VOID ASMCFUNC int2526_handler(WORD mode, struct int25regs FAR * r) InDOS++; - if (mode == DSKWRITEINT26) - DeleteBlockInBufferCache(blkno, blkno, drv, XFR_WRITE); r->ax = dskxfer(drv, blkno, buf, nblks, mode); CLEAR_CARRY_FLAG(); @@ -1890,9 +1694,10 @@ STATIC VOID StartTrace(VOID) } #endif -/* this function is called from an assembler wrapper function - and serves the internal dos calls - int2f/12xx and int2f/4a01,4a02. +/* 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__ @@ -1911,60 +1716,36 @@ struct int2f12regs { UWORD di, si, bp; xreg b, d, c, a; UWORD ip, cs, flags; - UWORD callerARG1; /* used if called from INT2F/12 */ + xreg callerARG1; /* used if called from INT2F/12 */ }; -extern intvec FAR ASM BIOSInt13; -extern intvec FAR ASM UserInt13; -extern intvec FAR ASM BIOSInt19; +extern intvec BIOSInt13, UserInt13, BIOSInt19; /* WARNING: modifications in `r' are used outside of int2F_12_handler() * On input r.AX==0x12xx, 0x4A01 or 0x4A02 - * also handle Windows' DOS notification hooks, r.AH==0x16 and r.AH==0x13 - * along with DRIVER.SYS/DRIVPARAM r.AH=0x08 calls + * also handle Windows' DOS notification hooks, r.AH==0x16 */ -VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) +VOID ASMCFUNC int2F_12_handler(struct int2f12regs r) { COUNT rc; long lrc; - UWORD requestedsize; - -#define r (*pr) - - r.FLAGS &= ~FLG_CARRY; /* assume success, ensure carry clear */ if (r.AH == 0x4a) { - size_t size = 0, offs = 0xffff, realoffs; /* defaults for no alloc */ + size_t size = 0, offs = 0xffff; r.ES = offs; if (FP_SEG(firstAvailableBuf) == offs) /* HMA present? */ { - realoffs = FP_OFF(firstAvailableBuf); - if (realoffs <= 0xFFF0) { /* if any free (not yet exthausted) */ - offs = realoffs; - offs += 15; - offs &= ~ 15; /* annoying: buffers may be unaligned */ - size = - offs; /* bx + di = 10000h */ - if (r.AL == 0x02) /* allocate HMA space */ - { - requestedsize = (r.BX + 15) & ~ 15; /* align to paragraph */ - if (requestedsize < r.BX || - requestedsize > size) { /* overflow or OOM */ - size = 0; - offs = 0xffff; /* requested more than we have */ - } else { - UWORD alignment = offs - realoffs; - size = (UWORD)requestedsize; /* return rounded size */ - AllocateHMASpace(realoffs, offs + size - 1); /* ! realoffs */ - if ( ((UDWORD)offs + (UDWORD)size) == 0x10000UL ) { - firstAvailableBuf = MK_FP(0xFFFF, 0xFFFF); /* exhausted */ - } else { - firstAvailableBuf += size + alignment; /* advance free pointer */ - } - } - } + 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; @@ -1989,28 +1770,11 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) { /* default: unhandled requests pass through unchanged */ case 0x0: /* is Windows active */ - { - if (winInstanced) - { - r.AL = (winStartupInfo.winver >> 8) & 0xFF; /* winmajor */ - r.AH = winStartupInfo.winver & 0xFF; /* winminor */ - } - /* return AX unchanged if Windows not active */ - break; - } /* 0x0 */ case 0x0A: /* identify Windows version */ { -#if 0 /* windows should answer this? if active, otherwise return not active */ - if (winInstanced) - { - r.AX = 0 /* call supported */ - r.BX = winStartupInfo.winver; /* BH=winmajor, BL=winminor */ - r.CX = 2; /* mode (0002h = standard, 0003h = enhanced) */ - } -#endif /* return AX unchanged if Windows not active */ break; - } /* 0x0A */ + } /* 0x0, 0x0A */ case 0x03: /* Windows Get Instance Data */ { /* This should only be called if AX=1607h/BX=15h is not supported. */ @@ -2034,15 +1798,10 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) set to memory manager calling point to disable V86 ES:BX is 0000:0000, set to startup structure */ - /* r.CX = 0x0; ** redundant and could be set nonzero by another hooked program */ + r.CX = 0x0; /* it is ok to load Windows, give it a shot anyway :-) */ r.es = FP_SEG(&winStartupInfo); r.BX = FP_OFF(&winStartupInfo); winStartupInfo.winver = r.di; /* match what caller says it is */ -#if defined __GNUC__ - winseg1 = FP_SEG(&winStartupInfo); - winseg2 = FP_SEG(&DATASTART); - winseg3 = FP_OFF(&markEndInstanceData); -#endif winInstanced = 1; /* internal flag marking Windows is active */ DebugPrintf(("Win startup\n")); break; @@ -2128,7 +1887,7 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) 0004h: device driver chain 0008h: Swappable Data Area */ - r.DX = 0xA2AB; /* on succes DX:AX set to A2AB:B97Ch */ + r.DX = 0xA2AB; /* on succes DS:AX set to A2AB:B97Ch */ r.AX = 0xB97C; r.BX = 0; /* a zero here tells Windows to instance everything */ break; @@ -2140,7 +1899,7 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) else return BX:CX size in bytes allocated to driver and DX:AX set to A2AB:B97Ch */ mcb FAR *smcb = MK_PTR(mcb, (r.ES-1), 0); /* para before is possibly submcb segment */ - /* drivers always start a seg:0 (DI==0), so if not then either + /* drivers always start a seg:0 (DI==0), so if not then either not device driver or duplicate (ie device driver file loaded is of multi-driver variety; multiple device drivers in same file, whose memory was allocated as a single chunk) @@ -2186,7 +1945,8 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) case 0x80: /* Win Release Time-slice */ { /* This function is generally only called in idle loops */ - DosIdle_hlt(); + enable(); /* sti; enable interrupts */ + halt(); /* hlt; halt until interrupt */ r.AX = 0; /* DebugPrintf(("Release Time Slice\n")); */ break; @@ -2238,299 +1998,38 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) #endif return; } - else if (r.AH == 0x08) /* DRIVER.SYS / DRIVPARAM */ + /* else (r.AH == 0x12) */ + + switch (r.AL) { - switch (r.AL) - { case 0x00: /* installation check */ - r.AL = 0xff; /* installed, 0=not installed */ + r.AL = 0xff; break; - case 0x01: /* add new block device */ - /* TODO, see push_ddt() */ + case 0x03: /* get DOS data segment */ + r.DS = FP_SEG(&nul_dev); break; - case 0x02: /* execute device driver request */ - /* TODO */ + case 0x06: /* invoke critical error */ + /* code, drive number, error, device header */ + r.AL = CriticalError(r.callerARG1.b.h, + (r.callerARG1.b.h & EFLG_CHAR) + ? 0 : r.callerARG1.b.l, + r.DI, MK_FP(r.BP, r.SI)); break; - /* Note: see in2f.asm where this is handled */ - case 0x03: /* get drive data table */ - r.DS = FP_SEG(&nul_dev); - r.DI = FP_OFF(getddt(0)); - break; - } + case 0x08: /* decrease SFT reference count */ + { + sft FAR *p = MK_FP(r.ES, r.DI); - return; - } - /* else (r.AH == 0x12) DOS internal functions */ + r.AX = p->sft_count; - switch (r.AL) - { - case 0x00: - /* Installation check for INT 2Fh/AH=12h internal DOS services. - * Input: AX=1200h. - * Output: AL=FFh (internal INT 2Fh/AH=12h multiplex handler installed/present). - */ - r.AL = 0xff; + if (--p->sft_count == 0) + --p->sft_count; + } break; -#if 0 - case 0x01: - /* Close current file (internal SFT-level close). - * Input: ES:DI -> SFT entry to close. - * Output: CF=0 on success; CF=1, AX=error code on failure. - * - * Decrement SFT.sft_count at ES:DI. If it reaches zero, flush - * dirty buffers for the file, update the directory entry - * (time/date/size) if the file is dirty, then mark the SFT free - * (sft_count = 0xFFFF). For character devices, issue a C_CLOSE - * driver request if refcount hit zero. Caller has already resolved - * handle -> SFT; this is the kernel-internal tail of INT 21h/3Eh. - * NOTE: do NOT decrement InDOS here; caller manages that. - */ - goto not_implemented; -#endif - - case 0x02: - /* Get interrupt vector (internal, avoids INT 21h/35h). - * Input: CL = interrupt number. - * Output: ES:BX = current handler address (far ptr from IVT at 0000:CL*4). - * CF=0. - * No state is modified. Equivalent to INT 21h/AH=35h but callable - * from within the kernel without re-entering INT 21h. - * - * Note: not used by FreeDOS kernel - */ - { - UBYTE FAR * p = (UBYTE FAR *)getvec(r.CL); - r.ES = FP_SEG(p); - r.BX = FP_OFF(p); - break; - } - - case 0x03: - /* Get DOS data segment (internal kernel data segment pointer). - * Input: none. - * Output: DS = segment of DOS DGROUP (kernel data segment). - * - * Returns the segment of the DOS kernel data area by loading DS - * with the segment of the NUL device header, which resides at the - * start of the DOS data segment. Used internally so code running - * outside DGROUP can locate kernel variables and tables. - */ - r.DS = FP_SEG(&nul_dev); - break; - - case 0x04: - /* Normalize path separator / DBCS lead-byte check. - * Input: character to test passed on stack - * Output: If AL is '/' (2Fh), '\' (5Ch), or the current SWITCHAR: - * AL = '\' (5Ch), ZF=1. - * If AL is a DBCS lead byte (per DBCS table): - * AL unchanged, ZF=0, DL=1 (flag: skip next byte). - * Otherwise: - * AL unchanged, ZF=0, DL=0. - * - * Allows the DOS path parser to canonicalize separators while - * guarding against misinterpreting the trail byte of a DBCS - * two-byte character as a path separator. Check DBCS lead-byte - * ranges from the DBCS table (see INT 21h/AH=63h / DBCS_TAB). - * - * Note: not used by FreeDOS kernel - */ - { - unsigned char c = r.callerARG1 & 0xFF; - - /* --- separator check first (takes priority over DBCS) --- */ - if (c == '/' || c == '\\' || c == (unsigned char)switchar) - { - r.AL = '\\'; /* canonicalize to backslash */ - r.FLAGS |= FLG_ZERO; /* ZF=1 */ - r.DL = 0; - } else - { - /* --- DBCS lead-byte check --- */ - BOOL nlsIsDBCS(UBYTE ch); /* only used here and in nls.c */ - r.DL = (nlsIsDBCS(c))?1:0; - /* AL unchanged */ - r.FLAGS &= ~FLG_ZERO; /* ZF=0 */ - } - - break; - } - - case 0x05: - /* Output character to standard output (kernel-internal). - * Input: AL = character to write. - * Output: none (AL preserved by convention). - * - * Write AL to STDOUT (JFT[1] of current PSP) via the DOS - * character-output path, with CTRL-C/CTRL-BREAK checking. - * Equivalent to INT 21h/AH=02h but does NOT increment InDOS, - * making it safe to call from within the kernel. May trap to - * INT 23h on break. Modifies: flags; AL preserved. - * - * Note: not used by FreeDOS kernel - */ - { - check_handle_break(&syscon); - write_char_stdout(r.AL); - break; - } - - case 0x06: - /* Invoke critical error handler (INT 24h) with explicit parameters. - * Input: callerARG1 high byte = error type/flags (EFLG_CHAR etc.); - * callerARG1 low byte = drive number (if not char device); - * DI = DOS error code; - * BP:SI = far pointer to device header. - * Output: AL = user response (0=ignore, 1=retry, 2=abort, 3=fail). - * - * Directly invokes CriticalError() with the supplied drive number, - * error code, and device header pointer. The EFLG_CHAR bit in the - * high byte of callerARG1 selects drive 0 (character device) vs. - * the low-byte drive number (block device). Differs from 0x0A in - * that all parameters are supplied explicitly by the caller rather - * than being derived from the current drive and stack. - * Modifies: AL. - */ - - /* 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; - -#if 0 - case 0x07: - /* Make disk buffer most-recently used (move to MRU head of LRU chain). - * Input: DS:BX -> buffer header in the DOS buffer cache chain. - * Output: CF=0. No registers modified except flags. - * - * Unlink the buffer header at DS:BX from its current position in - * the doubly-linked LRU chain and relink it at the MRU (head) end. - * The chain anchor is at DOS_DATA buf_head. Buffer header layout - * (DOS 4.x): +00h next ptr (WORD), +02h prev ptr, +04h drive - * (FFh=free), +05h flags (dirty=40h, FAT=10h, dir=08h), - * +06h sector number (DWORD), +0Ah DPB ptr. - * NOTE: 0x0F performs the same operation but with pointer in DS:DI. - */ - goto not_implemented; -#endif - - case 0x08: - /* Decrease SFT reference count (without closing). - * Input: ES:DI -> SFT entry. - * Output: AX = original (pre-decrement) sft_count value. - * - * Reads the current sft_count from the SFT entry at ES:DI into AX, - * then decrements sft_count. If the decremented value reaches zero - * it is decremented once more (wrapping to 0xFFFF) to mark the SFT - * as free, matching the DOS convention that 0xFFFF means unused. - * Unlike 0x01 this does NOT flush buffers, update the directory - * entry, or issue a device-driver close; it is a raw refcount - * adjustment used during handle duplication and inheritance cleanup. - * Modifies: AX, ES:DI->sft_count. - */ - { - sft FAR *p = MK_FP(r.ES, r.DI); - - r.AX = p->sft_count; - - if (--p->sft_count == 0) - --p->sft_count; - - break; - } - -#if 0 - case 0x09: - /* Flush and free disk buffer (write-back and release). - * Input: DS:BX -> buffer header. - * Output: CF=0 on success; CF=1, AX=DOS error code on write failure. - * - * If the buffer's dirty flag (bit 40h of flags byte) is set, write - * the buffer's sector back to disk via the driver for the drive in - * header+04h. If this is a FAT buffer (flag bit 10h) and the DPB - * indicates multiple FAT copies, also write mirror FAT sectors - * (one write per additional FAT, offset by sectors-per-FAT each). - * After writing, clear the dirty flag. Then mark the buffer free - * by setting the drive byte (header+04h) to FFh. Do NOT relink in - * the LRU chain here; caller uses 0x07/0x0F for that. - */ - goto not_implemented; -#endif - - case 0x0a: - /* Perform critical error using current drive context (INT 24h). - * Input: callerARG1 = DOS error code (passed on stack by caller); - * default_drive = current default drive number. - * Output: AL = user response (0=ignore, 1=retry, 2=abort, 3=fail). - * CF=1 normally; CF=0 if AL=1 (retry requested). - * - * Invokes CriticalError() using the current default drive and its - * associated DPB device header, with the error code taken from the - * caller's stack argument. Differs from 0x06 in that drive number - * and device header are derived from the current drive context - * rather than being passed explicitly. Sets CF on return; clears - * CF only if the user chose retry (AL=1). - */ - /* code, drive number, error, device header */ - r.AL = CriticalError(0x38, /* ignore/retry/fail - based on RBIL possible return values */ - default_drive, - r.callerARG1, /* error, from RBIL passed on stack */ - CDSp[(WORD)default_drive].cdsDpb->dpb_device); - r.FLAGS |= FLG_CARRY; - if (r.AL == 1) r.FLAGS &= ~FLG_CARRY; /* carry clear if should retry */ - break; - - case 0x0b: - /* Handle sharing violation (conditionally invoke INT 24h). - * Input: ES:DI -> SFT entry for the previously-opened conflicting file; - * callerARG1 = DOS error code (on stack). - * Output: AX = 0x0020 (sharing violation error code); - * CF=1 normally; CF=0 if retry was chosen (AL=1 from INT 24h). - * - * Examines the conflicting SFT's open mode. If the file was opened - * via FCB (O_FCB set) or in compatibility mode without NOINHERIT, - * invokes CriticalError() (INT 24h) to give the user a chance to - * retry. Otherwise returns immediately with CF set and AX=0x0020. - * CF is cleared only if CriticalError returns AL=1 (retry). - * Always sets AX=0x0020 (DE_SHARE) on return regardless of path taken. - */ - { - /* ES:DI = SFT for previous open of file */ - sft FAR *sftp = MK_FP(r.ES, r.DI); - /* default to don't retry, ie fail/abort/etc other than retry */ - r.FLAGS |= FLG_CARRY; - /* from RBIL if SFT for FCB or compatibility mode without NOINHERIT call int24h */ - if ((sftp->sft_mode & O_FCB) || !(sftp->sft_mode & (O_SHAREMASK | O_NOINHERIT))) - { - r.AL = CriticalError(0x38, /* ignore/retry/fail - ??? */ - default_drive, - r.callerARG1, /* error, from RBIL passed on stack */ - CDSp[(WORD)default_drive].cdsDpb->dpb_device); - /* clear carry if should retry */ - if (r.AL == 1) r.FLAGS &= ~FLG_CARRY; - } - r.AX = 0x20; /* error sharing violation */ - } - break; - - case 0x0c: - /* Perform device-open and set SFT owner PSP (open notification). - * Input: lpCurSft -> current SFT entry (global, set before call). - * Output: none; CF not modified. - * - * If the SFT entry refers to a character device (SFT_FDEVICE set), - * issues a C_OPEN request to the device driver via execrh() so the - * driver can perform any per-open initialization. Regardless of - * device type, records the current PSP segment (cu_psp) in the - * SFT's sft_psp field to establish ownership. Called during file - * open processing after the SFT has been allocated and filled in. - * Modifies: lpCurSft->sft_psp; device driver internal state if char device. - */ + case 0x0c: /* perform "device open" for device, set owner for FCB */ if (lpCurSft->sft_flags & SFT_FDEVICE) { @@ -2547,79 +2046,13 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) lpCurSft->sft_psp = cu_psp; break; - case 0x0d: - /* Get current DOS date and time (packed internal format). - * Input: none. - * Output: AX = packed date word (as returned by dos_getdate()); - * DX = packed time word (as returned by dos_gettime()). - * - * Retrieves the current system date and time in the DOS internal - * packed format. AX receives the date (year/month/day encoded) and - * DX receives the time (hours/minutes/seconds encoded). This is the - * kernel-internal equivalent of INT 21h/AH=2Ah+2Ch combined into a - * single call, used by file-stamping code inside the kernel. - */ + case 0x0d: /* get dos date/time */ r.AX = dos_getdate(); r.DX = dos_gettime(); break; -#if 0 - case 0x0e: - /* Mark all disk buffers unreferenced (clear LRU referenced bits). - * Input: none. - * Output: CF=0. No registers modified except flags (internally - * uses AX/BX/ES but must restore them). - * - * Walk the entire buffer cache chain from head to tail. On each - * buffer header, clear the "referenced" / "recently-touched" bit - * (implementation-defined bit in the flags byte used by the LRU - * refill pass). This prepares for a subsequent 0x10 scan to find - * a victim buffer. Called before the buffer-allocation sweep. - */ - goto not_implemented; - - case 0x0f: - /* Make buffer most recently used (pointer in DS:DI). - * Input: DS:DI -> buffer header. - * Output: CF=0. No registers modified except flags. - * - * Identical in effect to 0x07 (relink header to MRU head of the - * doubly-linked LRU chain), but the buffer pointer is passed in - * DI rather than BX. Both subfunctions coexist because different - * internal callers use different register conventions. - * See 0x07 for buffer header layout details. - */ - goto not_implemented; - - case 0x10: - /* Find unreferenced disk buffer (LRU victim selection). - * Input: none (chain walked from LRU tail toward MRU head). - * Output: DS:DI -> chosen buffer header; ZF=0 if found, ZF=1 if none. - * - * Scan the buffer chain from the LRU (tail) end forward. Return - * the first header whose drive byte == FFh (free) OR whose - * "referenced" bit is clear (see 0x0E). If no such buffer exists - * return with ZF=1 so the caller can flush one explicitly. - * Modifies: DI, flags; DS may be set to DOS DGROUP on return. - * NOTE: call 0x0E first to clear referenced bits before calling - * this function, otherwise all in-use buffers may appear referenced. - */ - goto not_implemented; -#endif - - case 0x11: - /* Normalize ASCIIZ filename (uppercase and convert path separators). - * Input: DS:SI -> source ASCIIZ filename string. - * ES:DI -> destination buffer for normalized string. - * Output: ES:DI buffer filled with normalized, NUL-terminated string. - * - * Copies the source string to the destination, converting lowercase - * ASCII letters (a-z) to uppercase (A-Z) and forward slashes ('/') - * to backslashes ('\'). Processes until and including the NUL - * terminator. - * NOTE: DBCS characters are not specially handled in this implementation. - */ + case 0x11: /* normalise ASCIIZ filename */ { char c; char FAR *s = MK_FP(r.DS, r.SI); @@ -2640,379 +2073,79 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) break; } - case 0x12: - /* Get length of ASCIIZ string at ES:DI. - * Input: ES:DI -> NUL-terminated string. - * Output: CX = length of string including the NUL terminator byte - * - * See also 0x25 which performs the same operation on DS:SI. - */ + case 0x12: /* get length of asciiz string */ r.CX = fstrlen(MK_FP(r.ES, r.DI)) + 1; break; - - case 0x13: - /* Uppercase a single character (ASCII, kernel-internal). - * Input: character in callerARG1 low byte (pushed on stack by caller). - * Output: AL = uppercased character. - * - * Reads the character from callerARG1 (the value pushed on the - * caller's stack before the INT 2Fh), converts lowercase ASCII - * letters (a-z) to uppercase (A-Z), and returns the result in AL. - * NOTE: 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 0x14: - /* Compare two far pointers for exact equality (does not normalize addresses). - * Input: DS:SI = first far pointer; ES:DI = second far pointer. - * Output: ZF=1 if DS==ES and SI==DI (equal); ZF=0 otherwise. - * CF=0. No other registers modified. - * - * Note: not used by FreeDOS kernel; may be used by MSDOS - * used by Lantastic - */ - { - if ((r.DS == r.ES) && (r.SI == r.DI)) { - r.FLAGS |= FLG_ZERO; - } else { - r.FLAGS &= ~FLG_ZERO; - } - - break; - } -#if 0 - case 0x15: - /* Flush (write-back) a single dirty disk buffer. - * Input: DS:DI -> buffer header (some refs ES:DI; use DS:DI per RBIL). - * Output: CF=0 on success; CF=1, AX=DOS error code on write failure. - * - * If the buffer's dirty flag (bit 40h of flags byte) is set, write - * the sector back via the driver for the drive in header+04h. If - * this is a FAT buffer (flag bit 10h) and the DPB indicates multiple - * FAT copies, also write each mirror FAT sector (offset by - * sectors-per-FAT per copy). Clear the dirty flag after a successful - * write. Do NOT mark the buffer free (drive byte unchanged); that is - * done by 0x09. Do NOT relink in the LRU chain. - */ - goto not_implemented; -#endif + case 0x13: /* uppercase character */ + { + /* for now, ASCII only because nls.c cannot handle DS!=SS */ + UBYTE ch = r.callerARG1.b.l; + if (_islower(ch)) + ch -= (UBYTE)('a' - 'A'); + r.AL = ch; + break; + } case 0x16: - /* Get address of SFT entry by system file number (used by NET.EXE). - * Input: BX = system file table entry number (SFN, as returned - * by INT 2Fh/AX=1220h). - * Output: On success: ES:DI -> SFT entry; BX = relative entry index - * within its SFT block; CF=0. - * On failure: CF=1 (invalid SFN). - * - * Walks the SFT chain via idx_to_sft_() to locate the SFT entry - * corresponding to the given system file number. Returns both the - * far pointer to the entry (in ES:DI, also stored in lpCurSft) and - * the relative index within the SFT block (in BX). Used by network - * redirectors (NET.EXE) to obtain direct access to an SFT entry - * given a previously-obtained SFN. See also 0x30 (find by SFN, - * Windows 95 variant). - */ + /* 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) - goto error_carry; - + { + 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 (CDS) for a drive (used by NET.EXE). - * Input: callerARG1 low byte = drive number (0=A:, 1=B:, ...) pushed - * on stack by caller (e.g. "push 2" for C:). - * Output: On success: DS:SI -> CDS entry for the drive; CF=0. - * On failure: CF=1 (invalid or out-of-range drive number). - * - * Used by network redirectors to obtain the CDS for a drive without - * going through the full validation path. A secondary use is - * to determine sizeof(CDS entry) from the returned pointer. - * - 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 - */ - { - struct cds FAR *cdsp = get_cds_unvalidated(r.callerARG1 & 0xff); - - if (cdsp == NULL) - goto error_carry; - + 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) + */ + { + const struct cds FAR *cdsp; + if ((cdsp = get_cds(r.callerARG1.b.l)) == NULL) + { + r.FLAGS |= FLG_CARRY; + break; + } r.DS = FP_SEG(cdsp); r.SI = FP_OFF(cdsp); + r.FLAGS &= ~FLG_CARRY; break; - } + } - case 0x18: - /* Get pointer to caller's saved register frame (user_r). - * Input: none. - * Output: DS:SI -> user_r (the iregs structure saved on INT 21h entry - * containing the calling program's register state). - * - * Returns a far pointer to the global user_r register save area in - * DS:SI. This allows internal DOS code and network redirectors to - * inspect or modify the register values that will be restored to the - * caller when the current INT 21h call returns. Used by SHARE and - * network components that need to patch return values after the fact. - */ + case 0x18: /* get caller's registers */ r.DS = FP_SEG(user_r); r.SI = FP_OFF(user_r); break; - case 0x19: - /* Set default drive (internal, validates against LASTDRIVE). - * Input: AL = drive number (0=A:, 1=B:, ...). - * Output: On success: AL = LASTDRIVE count (number of valid drives), - * CF=0. - * On invalid drive: CF=1, AX=000Fh (invalid drive). - * - * Validate AL against lastdrive. If valid, set the DOS internal - * current-drive byte to AL and update the internal current-CDS - * pointer to CDS_array + AL * sizeof(struct cds). Then trigger a - * media check / DPB build for the new drive. Return the total - * number of valid drives in AL. - * - * Note: not used by FreeDOS kernel - */ - { - UBYTE drv = r.AL; + case 0x1b: /* #days in February - valid until 2099. */ - if (drv >= lastdrive || get_cds_unvalidated(drv) == NULL) - { - r.AX = -DE_INVLDDRV; /* AX = 0x000F */ - goto error_carry; - } - r.AL = DosSelectDrv(drv); - - break; - } - - case 0x1a: - /* Get drive number from file path (parse leading drive letter). - * Input: DS:SI -> ASCIZ path or drive-letter string (e.g. "C:\..."). - * Output: AL = 0 if no explicit drive letter (default drive used). - * AL = 1..26 for explicit A:..Z:. - * AL = 0FFh if invalid/unrecognized drive letter. - * CF=0 always (errors expressed via AL=FFh). - * - * Note: used by Lantastic when trying to map a drive - */ - { - char FAR *p = MK_FP(r.DS, r.SI); - unsigned char c = p[0]; - - if (!c || p[1] != ':') /* "" or path without X: drive letter */ - { - r.AL = 0; /* no drive letter present, use default */ - } - else - { - c |= 0x20; /* map to lower case if letter */ - if (c >= 'a' && c <= 'z') - { - r.AL = c - 'a' + 1; /* 'A'->1, 'B'->2, ... 'Z'->26 */ - r.SI += 2; /* RBIL says DS:SI returns path without - drive letter, suggests MSDOS just - uses DS:SI incrementing as it parses */ - } - else - { - r.AL = 0xff; /* out of range, invalid drive letter */ - } - } - - break; - } - - case 0x1b: - /* Return number of days in February for a given year (leap year check). - * Input: CL = year modulo 4 (low 2 bits used; CL & 3 == 0 means leap year). - * Output: AL = 29 if leap year (CL & 3 == 0); AL = 28 otherwise. - * - * Tests the low two bits of CL. If both are zero the year is divisible - * by 4 and is treated as a leap year (29 days). Otherwise returns 28. - * NOTE: this simple test is only valid until 2099; the century-year - * exception (years divisible by 100 but not 400 are not leap years) - * is not handled, but is irrelevant within the DOS epoch. - */ r.AL = (r.CL & 3) ? 28 : 29; break; -#if 0 /* unlikely to be used */ - case 0x1c: - /* Checksum memory block (16-bit running sum with carry fold). - * Input: DS:SI -> start of buffer; CX = byte count; - * DX = initial checksum seed (usually 0). - * Output: DX = updated checksum; SI advanced by CX; CX = 0. - * - * Used during init to checksum device-driver images. - * NOTE: differs from 0x1D which uses a plain 8-bit truncated sum. - */ - { - UWORD FAR *p = MK_FP(r.DS, r.SI); - UWORD sum = r.DX; - UWORD count = r.CX; - UWORD words = count >> 1; /* number of full word pairs */ - - while (words--) - { - UWORD prev = sum; - sum += *p++; - if (sum < prev) /* carry out: fold back in (ones-complement style) */ - sum++; - } - - if (count & 1) /* odd trailing byte: zero-extend to word */ - { - UWORD prev = sum; - sum += (UWORD)*((UBYTE FAR *)p); - if (sum < prev) - sum++; - } - - r.DX = sum; - r.SI += count; /* advance SI by original byte count */ - r.CX = 0; - - break; - } - - case 0x1d: - /* Sum memory block (8-bit truncated running sum, no carry fold). - * Input: DS:SI -> buffer; CX = byte count. - * Output: AL = 8-bit sum (truncated, carry ignored); - * SI advanced by CX; CX = 0. - * - * Differs from 0x1C which uses a 16-bit carry-folded sum. - * Note: not used by FreeDOS kernel - */ - { - UBYTE FAR *p = MK_FP(r.DS, r.SI); - UBYTE sum = r.AL; - UWORD count = r.CX; - - r.SI += count; /* advance SI before count is consumed */ - while (count--) - sum += *p++; - - r.AL = sum; - r.CX = 0; - - break; - } -#endif - - case 0x1e: - /* Compare ASCIIZ filenames for equivalence (case-insensitive, ASCII range only). - * Input: DS:SI -> first ASCIIZ filename - * ES:DI -> second ASCIIZ filename - * Output: ZF=1 if filenames equivalent; ZF=0 if not equivalent. - * - * Note: not used by FreeDOS kernel - */ - { - const char FAR *s1 = MK_FP(r.DS, r.SI); - const char FAR *s2 = MK_FP(r.ES, r.DI); - char c1, c2; - - do { - c1 = *s1++; - c2 = *s2++; - if (c1 >= 'a' && c1 <= 'z') c1 -= 'a' - 'A'; - if (c2 >= 'a' && c2 <= 'z') c2 -= 'a' - 'A'; - } while (c1 && c1 == c2); - - if (c1 == c2) - r.FLAGS |= FLG_ZERO; /* ZF=1: equivalent */ - else - r.FLAGS &= ~FLG_ZERO; /* ZF=0: not equivalent */ - - break; - } - - case 0x1f: - /* Build a temporary Current Directory Structure for a drive letter. - * Input: callerARG1 low byte = drive letter ASCII ('A'..'Z' or 'a'..'z') - * pushed on stack by caller. - * Output: On success: ES:DI -> TempCDS (filled-in temporary CDS); CF=0. - * On failure: CF=1 (invalid letter or drive out of range). - * - * Fills TempCDS with a minimal CDS: path set to "X:\", DPB pointer - * and flags copied from the real CDS if the drive is active - * (CDSPHYSDRV only, no other flags inherited), or NULL/0 if inactive. - * Start cluster and parameter fields set to 0xFFFF. - */ - { - /* the drive is passed as ASCII letter ('A'-'z'), not a number (1-26), - * so masks to lower 5 bits and adjusts from 1 based to 0 based. - */ - int drv = (r.callerARG1 & 0x1f) - 1; - struct cds FAR *cdsp; - #if 0 - if ((unsigned)drv >= nblkdev) /* if drv < 0 or exceeds # of block devices */ - goto error_carry; - #endif - - cdsp = get_cds_unvalidated(drv); - if (cdsp == NULL) - goto error_carry; - - memset(&TempCDS, 0, sizeof(TempCDS)); - strcpy(TempCDS.cdsCurrentPath, "?:\\"); - *TempCDS.cdsCurrentPath = (BYTE)(r.callerARG1 & 0xff); - TempCDS.cdsBackslashOffset = 2; - if (cdsp->cdsFlags) - { - TempCDS.cdsDpb = cdsp->cdsDpb; - TempCDS.cdsFlags = CDSPHYSDRV; /* don't inherit CDS flags */ - } - else - { - TempCDS.cdsDpb = NULL; - TempCDS.cdsFlags = 0; - } - TempCDS.cdsStrtClst = 0xffff; - TempCDS.cdsParam = 0xffff; - TempCDS.cdsUserData = 0xffff; - r.CX = sizeof(TempCDS); - r.ES = FP_SEG(&TempCDS); - r.DI = FP_OFF(&TempCDS); - break; - } - - case 0x20: - /* Get Job File Table (JFT) entry pointer for a handle. - * Input: BX = file handle (index into current PSP's JFT). - * Output: On success: ES:DI -> JFT byte entry (ps_filetab[BX]); - * CF=0. - * On failure: AL = negated DE_INVLDHNDL; CF=1. - * - * Validates BX against ps_maxfiles in the current PSP. If valid, - * returns a far pointer to the JFT byte at ps_filetab[BX] in ES:DI. - * The JFT byte contains the SFN (system file number) that maps this - * handle to an SFT entry. Used by network redirectors and internal - * code that need to directly read or modify the JFT without going - * through the full handle-resolution path. - */ + case 0x20: /* get job file table entry */ { psp FAR *p = MK_FP(cu_psp, 0); unsigned char FAR *idx; @@ -3020,244 +2153,87 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) if (r.BX >= p->ps_maxfiles) { r.AL = -DE_INVLDHNDL; - goto error_carry; + 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; } + break; - case 0x21: - /* Canonicalize (truename) a file path (internal wrapper for INT 21h/60h). - * Input: DS:SI -> source ASCIIZ path (possibly relative, with '/', etc.). - * ES:DI -> destination buffer for canonical ASCIIZ path. - * Output: ES:DI buffer filled with fully qualified canonical path. - * CF and AX set by DosTruename() on error. - * - * Calls DosTruename() to resolve the source path to a fully qualified, - * normalized absolute path in the destination buffer. Handles drive - * letters, relative paths, '.' and '..' components, and '/' -> '\' - * conversion. This is the kernel-internal equivalent of INT 21h/AH=60h - * (TRUENAME), used by internal callers that already have DS:SI and - * ES:DI set up rather than going through the full INT 21h dispatch. - */ - rc = DosTruename(MK_FP(r.DS, r.SI), MK_FP(r.ES, r.DI)); - r.AX = rc; - goto short_check; + case 0x21: /* truename */ - case 0x22: - /* Set extended error information (inject error state for INT 21h/59h). - * Input: DS:SI -> 4-byte (minimum) error block: - * +00h WORD = extended error code (see INT 21h/AH=59h). - * +02h BYTE = error class. - * +03h BYTE = suggested action. - * +04h BYTE = locus (some callers supply 5 bytes). - * Output: CF=0. - * - * Copy the fields from DS:SI into the DOS-internal extended-error - * state variables (CritErrCode, CritErrClass, CritErrAction, - * CritErrLocus) that are returned by INT 21h/AH=59h. Used by - * network redirectors and TSRs to inject a specific error to be - * reported to the next INT 21h caller. Equivalent in purpose to - * INT 21h/AH=5Dh/AL=0Ah but reached via the internal 2F/12 path. - */ - goto not_implemented; + DosTruename(MK_FP(r.DS, r.SI), MK_FP(r.ES, r.DI)); - case 0x23: - /* Check if a name refers to a character device. - * Input: DirEntBuffer.dir_name = 11-byte FCB-format filename to test - * (set as a side-effect of a preceding directory search). - * Output: On success (is a device): BH = device attribute word low byte - * (dh_attr of the device header); CF=0. - * On failure (not a device): CF=1. - * - * Calls IsDevice() with the name from DirEntBuffer.dir_name. If a - * matching device header is found in the device chain, returns its - * attribute byte in BH and clears CF. If no match, sets CF. Used - * during open/create processing to distinguish character devices - * from disk files before allocating an SFT entry. - */ + break; + + case 0x23: /* check if character device */ { struct dhdr FAR *dhp; dhp = IsDevice((BYTE FAR *) DirEntBuffer.dir_name); - if (dhp == NULL) goto error_carry; + + if (dhp == NULL) + { + r.FLAGS |= FLG_CARRY; + break; + } r.BH = dhp->dh_attr; + r.FLAGS &= ~FLG_CARRY; } break; - case 0x24: - /* Set sharing retry delay and retry count (SHARE internals). - * Input: CX = delay loop count (outer retry delay iterations). - * DX = retry count (number of retries before giving up). - * Output: CF=0. - * - * Store CX into the DOS-internal SharingDelay word and DX into - * the SharingRetries word in DGROUP. These values are consulted - * by the sharing-violation retry loop in file open and lock - * operations (the same values set by INT 21h/AH=44h/CX=440Bh - * at the public API level). Both words live in the DOS data - * segment. - */ - goto not_implemented; + case 0x25: /* get length of asciiz string */ - case 0x25: - /* Get length of ASCIIZ string at DS:SI. - * Input: DS:SI -> NUL-terminated string. - * Output: CX = length of string including the NUL terminator byte - * - * Identical in behavior to 0x12 but operates on DS:SI rather than ES:DI, - */ r.CX = fstrlen(MK_FP(r.DS, r.SI)) + 1; break; - case 0x26: - /* Open file (internal wrapper for DosOpen, legacy compatibility mode). - * Input: DS:DX -> ASCIIZ filename to open. - * CL = open mode flags (O_RDONLY / O_WRONLY / O_RDWR etc.). - * Output: On success: AX = file handle (SFN); CF=0. - * On failure: AX = DOS error code; CF=1. - * - * Clears CF and CritErrCode, then calls DosOpen() with O_LEGACY|O_OPEN - * combined with the mode flags from CL. The attribute parameter is 0. - * Result is checked via long_check: on success AX = handle; on failure - * AX = error code and CF set. This is the kernel-internal open used by - * code that needs to open a file without going through INT 21h/3Dh. - * Modifies: AX, FLAGS, CritErrCode. - */ + 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 by handle (internal wrapper for DosClose). - * Input: BX = file handle to close. - * Output: CF=0 on success; CF=1, AX=error code on failure. - * - * Clears CF and CritErrCode, then calls DosClose() with the handle - * in BX. Result is checked via short_check: on success CF remains - * clear; on failure AX = error code and CF is set. This is the - * kernel-internal close used by code that needs to close a handle - * without going through INT 21h/3Eh. - * Modifies: AX, FLAGS, CritErrCode. - */ + case 0x27: /* close file */ + r.FLAGS &= ~FLG_CARRY; CritErrCode = SUCCESS; rc = DosClose(r.BX); goto short_check; -#ifdef WITHFAT32 -#ifdef WITHLFNAPI - case 0x42: - /* 64-bit move file pointer (LFN/FAT32 extended seek). - * Input: DS:DX -> 64-bit file position (UDWORD[2], little-endian); - * CL = seek method (0=from start, 1=from current, 2=from end); - * BX = file handle. - * Output: Same as 0x28 on success: DX:AX = new 32-bit file position; CF=0. - * On failure: AX = error code; CF=1. - * - * Only the lower 32 bits of the file position are supported. - */ - { - /* r.(DS:DX) points to 64-bit file position instead of r.(CX:DX) being 32-bit file position */ - UDWORD FAR *filepos = MK_FP(r.DS, r.DX); - if (*(filepos+1) != 0) /* we currently only handle lower 32 bits, upper 32 bits must be 0 */ - goto error_invalid; - r.BP = 0x4200 + r.CL; - r.CX = hiword(*filepos); - r.DX = loword(*filepos); - /* fall through to 32-bit move file pointer (0x28) */ - } -#endif -#endif - case 0x28: - /* Move file pointer / seek (internal wrapper for DosSeek). - * Input: BX = file handle; - * CX:DX = 32-bit signed offset (CX=high word, DX=low word); - * BP = seek method biased: 0x4200=from start, 0x4201=from current, - * 0x4202=from end (BP value passed by internal callers). - * Output: On success: DX:AX = new 32-bit file position; CF=0. - * On failure: AX = error code; CF=1. - * - * Validates BP is in range 0x4200..0x4202; if not, jumps to error_invalid. - * Calls DosSeek() with handle BX, offset MK_ULONG(CX,DX), and method - * BP & 0xFF. On success, splits the returned position into DX (high) and - * AX (low). NOTE: RBIL documents that MS-DOS sets a dummy stack frame - * pointer and moves BP to AX before calling; FreeDOS does not replicate - * that internal mechanism but achieves the same observable result. - * Modifies: AX, DX, FLAGS, CritErrCode. - */ + 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; + sft FAR *s = get_sft(r.BX); + if ((rc = _SftSeek(s, MK_ULONG(r.CX, r.DX), r.BP & 0xff)) >= SUCCESS) + { + r.DX = hiword (s->sft_posit); + r.AX = loword (s->sft_posit); + } } goto short_check; - case 0x29: - /* Read from file (internal wrapper for DosRead). - * Input: BX = file handle; - * CX = number of bytes to read; - * DS:DX -> destination buffer. - * Output: On success: AX = number of bytes actually read; CF=0. - * On failure: AX = DOS error code; CF=1. - * - * Clears CritErrCode, then calls DosRead() with handle BX, - * count CX, and buffer DS:DX. Result is checked via long_check: - * on success AX = bytes read (may be less than CX at EOF); on - * failure AX = error code and CF set. Kernel-internal equivalent - * of INT 21h/AH=3Fh without the full INT 21h dispatch overhead. - * Modifies: AX, FLAGS, CritErrCode. - */ + 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 entry point (stub; FASTOPEN not implemented). - * Input: ES:DI -> FASTOPEN handler entry point (FAR); BX = 0 to install, - * nonzero to uninstall. (Per PC-DOS 4 FASTOPEN convention.) - * Output: CF=0. - * - * In a full implementation, stores ES:DI into the DOS-internal - * FastOpen_Entry FAR pointer (or zeros it if BX != 0), enabling the - * DOS name-lookup path to call through to a FASTOPEN directory cache - * before going to disk. FreeDOS currently does nothing here; the - * function simply clears CF and returns, making FASTOPEN installs - * silently succeed without effect. - */ + case 0x2a: /* Set FastOpen but does nothing. */ + r.FLAGS &= ~FLG_CARRY; break; - case 0x2b: - /* Device I/O Control (internal wrapper for DosDevIOctl). - * Input: BP = IOCTL function code (0x4400..0x44FF, i.e. INT 21h/44xx); - * BX = file handle or drive number; - * CX = category/function or count; - * DX = data or buffer offset; - * DS:SI -> input buffer (for some subfunctions); - * ES:DI -> output buffer (for some subfunctions). - * Output: CF=0 on success (output registers set by DosDevIOctl); - * CF=1, AX=error code on failure. - * - * Validates BP is in range 0x4400..0x44FF; if not, jumps to error_invalid. - * Copies all relevant registers into a local lregs structure with AX=BP - * (so DosDevIOctl sees the correct AH=44h, AL=subfunction), then calls - * DosDevIOctl(). On failure, sets AX to the negated error code, updates - * CritErrCode for non-device/access errors, and jumps to error_carry. - * This is the kernel-internal IOCTL path used by internal callers. - * Modifies: AX, FLAGS, CritErrCode; output registers per subfunction. - */ + case 0x2b: /* Device I/O Control */ if (r.BP < 0x4400 || r.BP > 0x44ff) goto error_invalid; { @@ -3280,119 +2256,43 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) goto error_carry; } break; - - case 0x2c: - /* Get pointer to second device driver in chain (skip NUL device). - * Input: none. - * Output: BX:AX = far pointer (segment:offset) to the header of the - * second device driver in the device chain (i.e. nul_dev.dh_next), - * skipping the NUL device which is always first. - * - * Used by utilities such as Zip drive handlers that need to walk the - * device chain starting from the second entry. - */ + + 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 (last critical error code). - * Input: none. - * Output: AX = CritErrCode (the DOS extended error code from the most - * recent critical error or failed DOS call). - * - * Returns the current value of the global CritErrCode variable in AX. - * This is the kernel-internal equivalent of the error-code portion of - * INT 21h/AH=59h (Get Extended Error), used by internal callers that - * only need the error code without the full class/action/locus detail. - * CritErrCode is set by failed DOS calls and by the critical error - * handler; it is cleared at the start of most INT 21h functions. - */ + case 0x2d: /* Get Extended Error Code */ r.AX = CritErrCode; - break; - - case 0x2e: - /* Get or set error table addresses (ignored; stub for MS compatibility). - * Input: DL = subfunction (00h=get, 01h=set, 02h..05h select table); - * ES:DI -> new table pointer (for set subfunctions). - * Output: ES:DI -> requested table pointer (for get subfunctions); CF=0. - * - * In a full implementation, reads or writes entries in the DOS-internal - * error-message table-pointer array (four FAR pointers used by the - * message-retrieval code that formats INT 21h/AH=59h descriptions). - * FreeDOS currently ignores all subfunctions and returns immediately. - * NOTE: MS DEBUG calls this with DS != DOSDS - */ + /* fall through only to re-use break */ + case 0x2e: /* GET or SET error table addresse - ignored + called by MS debug with DS != DOSDS, printf + doesn't work!! */ break; case 0x2f: - /* Set DOS version returned by INT 21h/AH=30h for all processes. - * Input: DX = new version to set (DL=major, DH=minor), or DX=0 - * to reset to the emulated true DOS version. - * Output: none. - * Modifies: os_setver_major, os_setver_minor. - * - * If DX is nonzero, sets os_setver_major = DL and os_setver_minor = DH, - * causing INT 21h/AH=30h to return the specified version to all callers. - * If DX is zero, resets os_setver_major/minor back to os_major/os_minor - * (the kernel's true version). This duplicates the behavior of DOS 4 - * INT 2Fh/AX=122Fh and is also accessible via INT 21h/AH=33h/AL=FCh. - * Used by version-faking utilities (e.g. SETVER equivalents). - */ - if (r.DX) /* set returned version from DX */ + if (r.DX) { os_setver_major = r.DL; os_setver_minor = r.DH; } - else /* set returned version from emulated true DOS version */ + else { os_setver_major = os_major; os_setver_minor = os_minor; } break; -#if 0 - case 0x30: - /* Windows 95: Find SFT entry by system file number (SFN). - * Input: BX = system file number (SFN, i.e. the raw index value - * stored in PSP.JFT[handle], NOT the handle itself). - * Output: On success: ES:DI -> SFT entry; CF=0. - * On failure: CF=1, AX=0006h (invalid handle). - * - * Walk the SFT chain (anchor at SysVars+04h: link->count->entries). - * Count down through each SFT block until the cumulative entry - * index matches BX. This is equivalent to 0x16 but selected by - * raw SFN rather than by JFT handle, bypassing the PSP/JFT - * indirection layer. Used by Windows 95 kernel internals. - */ - goto not_implemented; - - case 0x31: - /* Windows 95: Set/clear "report Windows presence to DOS programs" flag. - * Input: DX = 0000h to enable Windows load (valid for one time only, - * added in Windows 95 OSR2 to protect FAT32 from - * the earlier Windows 95 versions); - * DX = 0001h to clear (hide Windows from INT 2Fh/AX=1600h); - * DX = 0002h to set (report Windows present). - * Output: AX = 0, CF = 0 on success, AX = 1, CF = 1 on error. - * - * Store the low bit of BX into a DOS-internal byte flag - * (WinReportFlag). This flag gates the response of the - * INT 2Fh/AX=1600h Windows enhanced-mode installation check: - * when clear, 1600h returns AL=0 (not present); when set, it - * returns the Windows version. Return the previous value in AX. - */ - goto not_implemented; -#endif - default: if (r.AL <= 0x31) { -not_implemented: put_string("unimplemented internal dos function INT2F/12"); put_unsigned(r.AL, 16, 2); put_string("\n"); - goto error_carry; + r.FLAGS |= FLG_CARRY; } } return; @@ -3415,10 +2315,93 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr) CritErrCode = r.AX; /* Maybe set */ error_carry: r.FLAGS |= FLG_CARRY; +} -#undef r + +/* how registers pushed on stack prior to calling int wrapper function, + when returns these are then popped off, so any changes to these + will effectively set the returned value in these registers + */ +struct intXXregs { +#ifdef I386 + /* preserved 386+ only registers, compiler specific */ +#endif + UWORD es, ds; + UWORD di, si, bp; + xreg b, d, c, a; + UWORD intreq; /* which interrupt filter request for */ + UWORD flags; /* flags duplicated, one pushed by int call ignored */ + xreg param; + UWORD ip, cs , oflags; + /* top item of int caller's stack, possibly additional params */ +}; + + +/* additional processing for various wrapped/filtered interrupts + WARNING: this function also called during kernel init phase + -- int 13h + filter for BIOS int13h support, only called on int13h error + for ms-dos compatibility this should at minimal + watch for disk-change notification and set internal status + (may be called multiple times in row when BIOS reports same + change multiple times, ie delays clearing disk change status) + TODO: move DMA bounday check from int25/26 to here + Note: use stored user (usually BIOS) hooked int13 handler + -- int 19h + clean up prior to a warm reboot + for ms compatibility this should at a minimal + restore original (or indicated as original) BIOS int13h handler + and any others that may be hooked (including this one) + if himem loaded clear high memory area (clear vdisk signature so himem loads) + */ +VOID ASMCFUNC intXX_filter(struct intXXregs r) +{ + DebugPrintf(("int %02xh filter\n", r.intreq)); + switch(r.intreq) + { + case 0x19: /* reboot via bootstrap */ + { + setvec(0x13, BIOSInt13); + setvec(0x19, BIOSInt19); + + /* clear vdisk signature if kernel loaded in hma */ + if (version_flags & 0x10) + fmemset(MK_FP(0xffff, 0x0010),0,512); + break; + } + case 0x13: /* error with disk handler */ + { + DebugPrintf(("disk error %i [ah=%x] (drive %x)\n", r.a.b.h, r.param.b.h, r.param.b.l)); + DebugPrintf(("bx==(%x) cx==(%x) dx==(%x)\n", r.BX, r.CX, r.DX)); + /* currently just marks floppy as changed on disk change error */ + if ((r.a.b.h == 0x06) && (r.param.b.l < 0x80)) /* diskchange and is it a floppy? */ + { + register int i; + + /* mark floppy as changed */ + for(i=0; i < blk_dev.dh_name[0]; i++) + { + ddt *pddt = getddt(i); + if (pddt->ddt_driveno == r.param.b.l) + { + DebugPrintf(("ddt[%i] match, flags=%04x\n", i, pddt->ddt_descflags)); + if ((pddt->ddt_descflags & DF_CHANGELINE) && /* drive must have changeline support */ + (pddt->ddt_descflags & DF_CURBPBLOCK)) /* and BPB not currently locked (in-use) */ + pddt->ddt_descflags |= DF_DISKCHANGE; + /* or get dpb pointer from ddt and set dpbp->dpb_flags = M_CHANGED; */ + } + } + } + break; + } + default: + DebugPrintf(("INT_ERROR!\n")); + break; + } } + + /* * 2000/09/04 Brian Reifsnyder * Modified interrupts 0x25 & 0x26 to return more accurate error codes. diff --git a/kernel/intr.asm b/kernel/intr.asm index 8fcbc3aa..1b966dac 100644 --- a/kernel/intr.asm +++ b/kernel/intr.asm @@ -26,9 +26,8 @@ ; %include "segs.inc" - %include "stacks.inc" -%macro INTR 1 +%macro INTR 0 push bp ; Standard C entry mov bp,sp @@ -41,18 +40,12 @@ push es %endif push ds - pushf -arg nr, {rp,%1} - mov ax, [.nr] ; interrupt number + mov ax, [bp+6] ; interrupt number mov [cs:%%intr_1-1], al jmp short %%intr_2 ; flush the instruction cache -%%intr_2: -%if %1 == 4 - lds bx, [.rp] ; regpack structure FAR -%else - mov bx, [.rp] ; regpack structure -%endif +%%intr_2 mov bx, [bp+4] ; regpack structure + mov ax, [bx] mov cx, [bx+4] mov dx, [bx+6] mov si, [bx+8] @@ -60,9 +53,6 @@ arg nr, {rp,%1} mov bp, [bx+12] push word [bx+14] ; ds mov es, [bx+16] - mov ah, byte [bx+22] ; flags - sahf - mov ax, [bx] mov bx, [bx+2] pop ds int 0 @@ -72,33 +62,23 @@ arg nr, {rp,%1} push ds push bx mov bx, sp -%if %1 == 4 -%ifdef WATCOM - lds bx, [ss:bx+(14+8)+4] ; FAR address of REGPACK, pascal convention -%else - lds bx, [ss:bx+14+.rp-bp] ; FAR address of REGPACK, SP=BX + skip saved registers (14) + -%endif -%else - mov ds, [ss:bx+8] + mov ds, [ss:bx+6] %ifdef WATCOM - mov bx, [ss:bx+26] ; NEAR address of REGPACK, pascal convention + mov bx, [ss:bx+24] ; address of REGPACK %else - mov bx, [ss:bx+14+.rp-bp] ; NEAR address of REGPACK -%endif + mov bx, [ss:bx+16] ; address of REGPACK %endif mov [bx], ax - pop word [bx+2] ; bx + 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] ; ds + pop word [bx+14] mov [bx+16], es - pop word [bx+22] ; flags + pop word [bx+22] - ; restore all registers to values from INTR entry - popf pop ds %ifdef WATCOM pop es @@ -109,74 +89,75 @@ arg nr, {rp,%1} pop di pop si pop bp + ret 4 %endmacro segment HMA_TEXT ; -; void ASMPASCAL call_intr(WORD nr, struct REGPACK FAR *rp) +; int ASMPASCAL res_DosExec(int mode, exec_blk * ep, const char * lp); ; - global CALL_INTR -CALL_INTR: - INTR 4 ; rp is far, DWORD argument - ret 6 - -;; COUNT ASMPASCAL res_DosExec(COUNT mode, exec_blk * ep, BYTE * lp) global RES_DOSEXEC RES_DOSEXEC: pop es ; ret address - popargs ax,bx,dx ; mode, exec block, filename + 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: + sbb dx,dx ; CF=0? + and ax,dx ; then ax=0, else ax=error code ret -;; UCOUNT ASMPASCAL res_read(int fd, void *buf, UCOUNT count); +; +; unsigned ASMPASCAL res_read(int fd, void *buf, unsigned count); +; global RES_READ RES_READ: pop ax ; ret address - popargs bx,dx,cx ; fd, buf, count + 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: + sbb dx,dx ; CF=1? + or ax,dx ; then ax=-1, else ax=bytes read ret segment INIT_TEXT ; -; void init_call_intr(nr, rp) -; REG int nr -; REG struct REGPACK *rp +; unsigned ASMPASCAL init_call_intr(int nr, iregs * rp); ; global INIT_CALL_INTR INIT_CALL_INTR: - INTR 2 ; rp is near, WORD argument - ret 4 + INTR ; -; int init_call_XMScall( (WORD FAR * driverAddress)(), WORD AX, WORD DX) +; int ASMPASCAL init_call_XMScall(void FAR * driverAddress, UWORD ax, UWORD dx); ; ; this calls HIMEM.SYS ; global INIT_CALL_XMSCALL INIT_CALL_XMSCALL: pop bx ; ret address - popargs {es,cx},ax,dx + 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) + +; +; void FAR * ASMPASCAL DetectXMSDriver(VOID); +; global DETECTXMSDRIVER DETECTXMSDRIVER: mov ax, 4300h @@ -184,8 +165,8 @@ DETECTXMSDRIVER: cmp al, 80h je detected - xor ax, ax - xor dx, dx + xor ax,ax + cwd ret detected: @@ -200,30 +181,38 @@ detected: pop es ret +; +; void ASMPASCAL keycheck(void); +; global KEYCHECK KEYCHECK: mov ah, 1 int 16h ret -;; int open(const char *pathname, int flags); +; +; int ASMPASCAL open(const char *pathname, int flags); +; global INIT_DOSOPEN INIT_DOSOPEN: ;; init calling DOS through ints: pop bx ; ret address - popargs dx,ax ; pathname, flags + 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: + jnc common_ret ; CF=1? + sbb ax,ax ; then ax=-1, else ax unchanged +common_ret: ret -;; int close(int fd); +; +; int ASMPASCAL close(int fd); +; global CLOSE CLOSE: pop ax ; ret address @@ -232,41 +221,52 @@ CLOSE: mov ah, 3eh jmp short common_int21 -;; UCOUNT read(int fd, void *buf, UCOUNT count); +; +; unsigned ASMPASCAL read(int fd, void *buf, unsigned count); +; global READ READ: pop ax ; ret address - popargs bx,dx,cx ; fd,buf,count + 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); +; +; int ASMPASCAL dup2(int oldfd, int newfd); +; global DUP2 DUP2: pop ax ; ret address - popargs bx,cx ; oldfd,newfd + 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 - popargs bx,{cx,dx} ; fd, position high:low + 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 + 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) +; +; void ASMPASCAL init_PSPSet(seg psp_seg); +; global INIT_PSPSET INIT_PSPSET: pop ax ; ret address @@ -276,22 +276,27 @@ INIT_PSPSET: int 21h ret -;; COUNT init_DosExec(COUNT mode, exec_blk * ep, BYTE * lp) +; +; int ASMPASCAL init_DosExec(int mode, exec_blk * ep, const char * lp); +; global INIT_DOSEXEC INIT_DOSEXEC: pop es ; ret address - popargs ax,bx,dx ; mode, exec block, filename + 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: + sbb dx,dx ; CF=0? + and ax,dx ; then ax=0, else ax=error code ret -;; int init_setdrive(int drive) +; +; int ASMPASCAL init_setdrive(int drive); +; global INIT_SETDRIVE INIT_SETDRIVE: mov ah, 0x0e @@ -302,7 +307,9 @@ common_dl_int21: int 21h ret -;; int init_switchar(int char) +; +; int ASMPASCAL init_switchar(int chr); +; global INIT_SWITCHAR INIT_SWITCHAR: mov ax, 0x3701 @@ -318,15 +325,18 @@ ALLOCMEM: push ax ; ret address mov ah, 48h int 21h - sbb bx, bx ; carry=1 -> ax=-1 - or ax, bx ; segment + sbb bx,bx ; CF=1? + or ax,bx ; then ax=-1, else ax=segment ret -;; void set_DTA(void far *dta) +; +; void ASMPASCAL set_DTA(void far *dta); +; global SET_DTA SET_DTA: pop ax ; ret address - popargs {bx,dx} ; seg:off(dta) + pop bx ; seg(dta) + pop dx ; off(dta) push ax ; ret address mov ah, 1ah push ds diff --git a/kernel/intwrap.asm b/kernel/intwrap.asm new file mode 100644 index 00000000..4f20ad2d --- /dev/null +++ b/kernel/intwrap.asm @@ -0,0 +1,160 @@ +; +; File: +; intwrap.asm +; Description: +; support for hooking misc interrupts +; BIOS disk interrupt support code +; warm boot support code +; +; Copyright (c) 2005 +; 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 "segs.inc" + %include "stacks.inc" + +segment HMA_TEXT + extern _DGROUP_ + + ; defined in kernel.asm + extern _UserInt13 ; actual BIOS int13 disk handler used by kernel + extern _BIOSInt19 ; original int19 (reboot) + + +; receives int 13h request, invokes original handler, +; but passes to C routine in inthndr.c on error +; this lets successful calls proceed with minimal overhead +; while allowing us to handle errors, store disk change, ... + + global reloc_call_int13_handler +reloc_call_int13_handler: + cli ; disable other interrupts for now + stc ; force error unless BIOS clears + push dx ; store BIOS drive # for error handling usage + +;TODO FIX this alters DS which is used by some subfunctions!!! + push ds ; get segment of kernel DATA + mov ds, [cs:_DGROUP_] + pushf ; simulate int call so returns back here (flags+cs:ip on stack) + call far [ds:_UserInt13] + pop ds ; restore ds + + jc int13err ; test if error, if not return to caller + +int13iret: + inc sp ; clean up stack + inc sp + retf 2 ; return to caller leaving flags asis + +int13err: + pushf ; don't mess up flags + + cmp ah, 06h ; disk changed + je int13wrap + + ; add check for other errors here, such as DMA issues + + popf + jmp int13iret ; pass error asis back to user + + +int13wrap: +%IF XCPU < 186 + push bp + push bp + mov bp, sp + mov [bp+2], word 13h ; do the push 0x13 onto stack + pop bp ; clean up stack frame (leaving just 0x13 pushed on stack) +%ELSE + push 13h ; the 186+ way to push a constant on the stack +%ENDIF + + ; at this point stack has initial flags, called cs,ip, initial dx, + ; flags returned from int13 call, and value 13h + ; fall through to intWrapCall to invoke C handler + + +; assumes interrupt # and single word param already pushed on stack +; pushes all registers on stack +; calls C handler +; restores registers (replacing value if changed by C code) +; pops int# and param off stack +; returns via iret +intWrapCall: + ; set up register frame + push ax + push cx + push dx + push bx + push bp + push si + push di + push ds + push es + + cld + + Protect386Registers ; ensure 386+ registers possibly modified by kernel safe + + mov ds,[cs:_DGROUP_] + push ds ; mov es, ds + pop es + extern _intXX_filter + call _intXX_filter + + Restore386Registers + + pop es + pop ds + pop di + pop si + pop bp + pop bx + pop dx + pop cx + pop ax + + add sp, 2 ; pop int# off stack + popf ; restore flags + inc sp ; pop param off stack (without altering flags) + inc sp + retf 2 ; iret but ignore pushed flags + + + +%IF 0 +; receives int 19h request, resets various int values, +; clears hma if in use, and finally invokes original handler, + + global reloc_call_int19_handler +reloc_call_int19_handler: + + mov ds, [cs:_DGROUP_] + lds ax,[_BIOSInt19] ; iret calls original handler, doesn't return + add sp, 4 ; so pop callers return address off stack + push ds ; and replace with address of original handler + push ax + push ax ; param, ignored + pushf ; flags, ignored + mov ax, 19h ; handler for int 19h + push ax + jmp intWrapCall +%ENDIF diff --git a/kernel/io.asm b/kernel/io.asm index 216933ad..32d13afb 100644 --- a/kernel/io.asm +++ b/kernel/io.asm @@ -31,18 +31,18 @@ %include "segs.inc" %include "stacks.inc" - extern ConTable - extern LptTable - extern ComTable - extern uPrtNo - extern CommonNdRdExit -;!! extern _NumFloppies - extern blk_stk_top - extern clk_stk_top + 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 + extern _TEXT_DGROUP:wrt LGROUP ;--------------------------------------------------- ; @@ -212,7 +212,6 @@ uUnitNumber dw 0 ; at any time. The request is stored into memory in the one and only ; location available for that purpose. ; - global GenStrategy GenStrategy: mov word [cs:_ReqPktPtr],bx mov word [cs:_ReqPktPtr+2],es @@ -501,12 +500,12 @@ GetUnitNum: blk_driver_params: dw blk_stk_top dw _reloc_call_blk_driver - dw DGROUP + dw seg _reloc_call_blk_driver clk_driver_params: dw clk_stk_top dw _reloc_call_clk_driver - dw DGROUP + dw seg _reloc_call_clk_driver ; clock device interrupt clk_entry: diff --git a/kernel/io.inc b/kernel/io.inc index 43235875..5ab1984d 100644 --- a/kernel/io.inc +++ b/kernel/io.inc @@ -49,12 +49,12 @@ %define E_FAILURE 12 ; General Failure - extern _IOExit - extern _IOSuccess - extern _IOErrorExit - extern _IOErrCnt - extern _IODone - extern _IOCommandError - extern GetUnitNum - extern _ReqPktPtr + 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 index bfaa64a6..c5bcb1f1 100644 --- a/kernel/ioctl.c +++ b/kernel/ioctl.c @@ -28,11 +28,10 @@ #include "portab.h" #include "globals.h" -#include "debug.h" #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: ioctl.c 1427 2009-06-09 12:23:14Z bartoldeman $"; + "$Id$"; #endif /* @@ -55,40 +54,57 @@ static BYTE *RcsId = */ -/* 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) +COUNT DosDevIOctl(lregs * r) { - struct dhdr FAR *dev; + static UBYTE cmds [] = { + 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, + }; + static UWORD required_attr [] = { + 0, 0, + /* 0x02 */ ATTR_IOCTL, + /* 0x03 */ ATTR_IOCTL, + /* 0x04 */ ATTR_IOCTL, + /* 0x05 */ ATTR_IOCTL, + 0, 0, + /* 0x08 */ ATTR_EXCALLS, + 0, 0, 0, + /* 0x0c */ ATTR_GENIOCTL, + /* 0x0d */ ATTR_GENIOCTL, + /* 0x0e */ ATTR_GENIOCTL, + /* 0x0f */ ATTR_GENIOCTL, + /* 0x10 */ ATTR_QRYIOCTL, + /* 0x11 */ ATTR_QRYIOCTL, + }; - if (r->AL > 0x11) - return DE_INVLDFUNC; + sft FAR *s; + struct dhdr FAR *dev; + struct dpb FAR *dpbp; + unsigned attr, flags; + UBYTE cmd, unit; switch (r->AL) { + default: /* 0x12+ */ + return DE_INVLDFUNC; + case 0x0b: - /* skip, it's a special case. */ - NetDelay = r->CX; - if (r->DX) + if (r->DX) /* skip, it's a special case */ NetRetry = r->DX; + NetDelay = r->CX; return SUCCESS; case 0x00: @@ -100,31 +116,98 @@ int DosDevIOctl(lregs * r) 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) + if ((s = get_sft(r->BX)) == (sft FAR *)-1) return DE_INVLDHNDL; - flags = s->sft_flags; + dev = s->sft_dev; + attr = dev->dh_attr; + break; + + case 0x0d: + /* NOTE: CX checked before check if get_dpb()->dpb_device->dh_attr + contains ATTR_GENIOCTL bit set + */ + if ((r->CX & ~0x4021) == 0x084A) + { /* 084A/484A, 084B/484B, 086A/486A, 086B/486B */ + r->AX = 0; /* (lock/unlock logical/physical volume) */ + return SUCCESS; /* simulate success for MS-DOS 7+ SCANDISK etc. --LG */ + } + + case 0x04: + case 0x05: + case 0x08: + case 0x09: + case 0x0e: + case 0x0f: + case 0x11: +/* + Line below 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 + */ +/* changed to use default drive if drive=0. --JPP */ +/* Fixed it. --JT */ + +#define NDN_HACK +#ifdef NDN_HACK +/* NDN feeds the actual ASCII drive letter to this function */ + unit = (r->BL & 0x1f) - 1; +#else + unit = r->BL - 1; +#endif + if (unit == 0xff) + unit = default_drive; + + if ((dpbp = get_dpb(unit)) == NULL) + { + if (r->AL != 0x09) + return DE_INVLDDRV; + attr = ATTR_REMOTE; + } + else + { + dev = dpbp->dpb_device; + attr = dev->dh_attr; + } + } /* switch */ + + /* required_attr[] may be zero and in this case attr ignored */ + if (~attr & required_attr [r->AL]) + return DE_INVLDFUNC; - switch (r->AL) - { - case 0x00: + /* commonly used, shouldn't harm to do front up */ + CharReqHdr.r_command = cmd = cmds [r->AL]; + if (cmd == C_GENIOCTL || cmd == C_IOCTLQRY) + { + 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_unit = dpbp->dpb_subunit; + CharReqHdr.r_status = 0; + + switch (r->AL) + { + case 0x00: /* Get the flags from the SFT */ - r->AX = flags & 0xff; + r->DX = flags; if (flags & SFT_FDEVICE) - r->AX |= (s->sft_dev->dh_attr & 0xff00); - /* else: files/networks return 0 in AH/DH */ + r->DH = attr >> 8; /* Undocumented result, Ax = Dx seen using Pcwatch */ - r->DX = r->AX; - return SUCCESS; + r->AX = r->DX; + break; - case 0x01: - /* sft_flags is a file, return an error because you */ + case 0x01: /* can't set the status of a file. */ if (!(flags & SFT_FDEVICE)) return DE_INVLDFUNC; @@ -134,152 +217,88 @@ int DosDevIOctl(lregs * r) 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; + /* Undocumented: AL should get the old value */ + r->AL = (UBYTE)flags; + break; - case 0x0a: + 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; - } + r->AX = 0; /* ??? RBIL doesn't says that AX changed --avb */ + 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. + case 0x06: + if (!(flags & SFT_FDEVICE)) + { + r->AL = s->sft_posit >= s->sft_size ? (UBYTE)0 : (UBYTE)0xFF; + break; + } + /* fall through */ - -SRM - */ -/* JPP - changed to use default drive if drive=0 */ -/* JT Fixed it */ + case 0x07: + if (!(flags & SFT_FDEVICE)) + { + r->AL = 0; + break; + } + /* fall through */ - /* 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 != 8 && r->AL != 9) - return DE_INVLDDRV; - dev = NULL; - attr = ATTR_REMOTE; - } + case 0x02: + case 0x03: + case 0x0c: + case 0x10: + if (!(flags & SFT_FDEVICE)) + return DE_INVLDFUNC; + CharReqHdr.r_unit = 0; /* ??? not used for devices --avb */ + goto execrequest; - switch (r->AL) - { - case 0x08: - { - struct cds FAR *cdsp = get_cds1(r->BL & 0x1f); - if (cdsp == NULL) - return DE_INVLDDRV; - if (cdsp->cdsFlags & CDSNETWDRV) - return DE_INVLDFUNC; - r->AX = (dpbp->dpb_flags == M_DONT_KNOW); - return SUCCESS; - } - case 0x09: + 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); + const struct cds FAR *cdsp = get_cds(unit); 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, 0x0e, 0x0f, 0x11 */ + r->AX = S_DONE | S_BUSY; /* ??? S_* values only for driver interface; + RBIL doesn't says that AX changed --avb */ 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); + case 0x04: + case 0x05: + case 0x08: + case 0x0d: + case 0x11: + execrequest: + execrh(&CharReqHdr, dev); + if (CharReqHdr.r_status & S_ERROR) + { + CritErrCode = (CharReqHdr.r_status & S_MASK) + 0x13; + return DE_DEVICE; + } - 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) & 1u; + else /* 0x0c, 0x0d, 0x10, 0x11 */ + r->AX = CharReqHdr.r_status; + break; - 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; + case 0x0e: + default: /* 0x0f */ + execrh(&CharReqHdr, dev); + if (CharReqHdr.r_status & S_ERROR) + { + CritErrCode = (CharReqHdr.r_status & S_MASK) + 0x13; + return DE_ACCESS; + } + r->AL = CharReqHdr.r_unit; + } /* switch */ return SUCCESS; } diff --git a/kernel/irqstack.asm b/kernel/irqstack.asm index a283a012..fd55d3bc 100644 --- a/kernel/irqstack.asm +++ b/kernel/irqstack.asm @@ -24,95 +24,88 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: irqstack.asm 1567 2011-04-09 02:03:20Z bartoldeman $ +; $Id$ ; ; 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 +segment _LOWTEXT +global _old_vectors +_old_vectors times 16 dd 0 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 +irq_0: push bx + mov bx, 0 * 4 + jmp short general_irq_service + +irq_1: push bx + mov bx, 1 * 4 + jmp short general_irq_service + +irq_2: push bx + mov bx, 2 * 4 + jmp short general_irq_service + +irq_3: push bx + mov bx, 3 * 4 + jmp short general_irq_service + +irq_4: push bx + mov bx, 4 * 4 + jmp short general_irq_service + +irq_5: push bx + mov bx, 5 * 4 + jmp short general_irq_service + +irq_6: push bx + mov bx, 6 * 4 + jmp short general_irq_service + +irq_7: push bx + mov bx, 7 * 4 + jmp short general_irq_service + +irq_08: push bx + mov bx, 8 * 4 + jmp short general_irq_service + +irq_09: push bx + mov bx, 9 * 4 + jmp short general_irq_service + +irq_0a: push bx + mov bx, 0ah * 4 + jmp short general_irq_service + +irq_0b: push bx + mov bx, 0bh * 4 + jmp short general_irq_service + +irq_0c: push bx + mov bx, 0ch * 4 + jmp short general_irq_service + +irq_0d: push bx + mov bx, 0dh * 4 + jmp short general_irq_service + +irq_0e: push bx + mov bx, 0eh * 4 + jmp short general_irq_service + +irq_0f: push bx + mov bx, 0fh * 4 +; jmp short general_irq_service 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 @@ -137,7 +130,7 @@ common_irq: sub [stack_top], ax pushf - call far word [bx] + call far word [_old_vectors+bx] cli add [stack_top], ax @@ -148,16 +141,19 @@ common_irq: mov ss, dx ; switch back to old stack mov sp, ax -return: pop ds ; restore registers and 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 + call far word [_old_vectors+bx] + pop ds + pop ax + pop dx + pop bx + iret segment INIT_TEXT @@ -165,9 +161,6 @@ 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 @@ -176,9 +169,8 @@ _init_stacks: push si - mov ax,LGROUP + mov ax,_LOWTEXT mov ds,ax - mov es,ax mov bx, [bp+4] mov dx, [bp+6] @@ -191,22 +183,31 @@ _init_stacks: mul cx add ax, bx - ; stack_top = stack_size * nStacks + stack_seg:stack_offs - mov [stack_top], ax + 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 + mov ax, _LOWTEXT + mov es, ax + + mov di, _old_vectors + mov si, 8 * 4 + mov cx, 10h + rep movsw + + mov si, 70h * 4 + mov cx, 10h + rep movsw + + push ds + pop es + + mov di, 8 * 4 + mov dx, 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 + mov di, 70h * 4 call set_vect pop si @@ -215,32 +216,16 @@ _init_stacks: 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 + mov cx, 8 +set_next: mov ax, dx cli - mov [si-4], dx ; set new vector - mov [si-2], es + stosw + mov ax, _LOWTEXT + stosw sti - - add dx, bp - lea di, [di+bp-4] ; update di, compensating for movsw - loop set_vect + add dx, irq_1 - irq_0 + loop set_next ret diff --git a/kernel/kernel.asm b/kernel/kernel.asm index 657dfbd8..c2c2f705 100644 --- a/kernel/kernel.asm +++ b/kernel/kernel.asm @@ -25,39 +25,34 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: kernel.asm 1705 2012-02-07 08:10:33Z perditionc $ +; $Id$ ; %include "segs.inc" - %include "stacks.inc" %include "ludivmul.inc" -segment PSP +segment PSP - extern _ReqPktPtr + 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 -;************************************************************ +;************************************************************ -%ifidn __OUTPUT_FORMAT__, obj ..start: -%endif -bootloadunit: ; (byte of short jump re-used) -entry: +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: -config_signature: db 'CONFIG' ; constant dw configend-configstart; size of config area ; to be checked !!! @@ -71,36 +66,14 @@ ForceLBA db 0 ; GlobalEnableLBAsupport db 1 ; BootHarddiskSeconds db 0 ; -; The following VERSION resource must be keep in sync with VERSION.H -Version_OemID db 0xFD ; OEM_ID -Version_Major db 2 -Version_Revision dw 43 ; REVISION_SEQ -Version_Release dw 1 ; 0=release build, >0=svn# - -CheckDebugger: db 0 ; 0 = no check, 1 = check, 2 = assume present -Verbose db 0 ; -1 = quiet, 0 = normal, 1 = verbose - -PartitionMode db 0x1f ; bits 0-1: 01=GPT if found, 00=MBR if found, 11=Hybrid, GPT first then MBR, 10=Hybrid, MBR first then GPT - ; in hybrid mode, EE partitions ignored, drives assigned by GPT or MBR first based on hybrid type - ; bits 2-4: 001=mount ESP (usually FAT32) partition, 010=mount MS Basic partitions, 100=mount unknown partitions - ; 111=attempt to mount all paritions, 110=attempt to mount all but ESP partitions - ; bits 5-7: reserved, 0 else undefined behavior - configend: -kernel_config_size: equ configend - config_signature - ; must be below-or-equal the size of struct _KernelConfig - ; in the file kconfig.h ! - times (32 - 4) - ($ - $$) db 0 -bootloadstack: dd 0 - - -;************************************************************ +;************************************************************ ; KERNEL CONFIGURATION AREA END -;************************************************************ +;************************************************************ -;************************************************************ +;************************************************************ ; KERNEL real entry (at ~60:20) ; ; moves the INIT part of kernel.sys to high memory (~9000:0) @@ -108,25 +81,11 @@ bootloadstack: dd 0 ; to aid debugging, some '123' messages are output ; this area is discardable and used as temporary PSP for the ; init sequence -;************************************************************ +;************************************************************ - cpu 8086 ; (keep initial entry compatible) -global realentry realentry: ; execution continues here - push cs - pop ds - xor di, di - mov byte [di + bootloadunit - $$], bl - push bp - mov word [di + bootloadstack - $$], sp - mov word [di + bootloadstack + 2 - $$], ss - jmp entry_common - - - times 0C0h - ($ - $$) nop ; magic offset (used by exeflat) -entry_common: -%ifndef QUIET + push ax push bx pushf @@ -136,46 +95,20 @@ entry_common: popf pop bx pop ax -%endif - - push cs - pop ds - jmp IGROUP:kernel_start -beyond_entry: times 256-(beyond_entry-entry) db 0 + jmp far kernel_start +beyond_entry: resb 256-(beyond_entry-entry) ; scratch area for data (DOS_PSP) -_master_env equ $ - 128 -global _master_env segment INIT_TEXT -%ifdef TEST_FILL_INIT_TEXT - %macro step 0 - %if _LFSR & 1 - %assign _LFSR (_LFSR >> 1) ^ 0x80200003 - %else - %assign _LFSR (_LFSR >> 1) - %endif - %endmacro - - align 16 - %assign _LFSR 1 - %rep 1024 * 8 - dd _LFSR - step - %endrep -%endif + extern _FreeDOSmain - extern _FreeDOSmain - extern _query_cpu - ; ; kernel start-up ; kernel_start: - cld -%ifndef QUIET push bx pushf mov ax, 0e32h ; '2' Tracecode - kernel entered @@ -183,111 +116,64 @@ kernel_start: int 010h popf pop bx -%endif - -extern _kernel_command_line - - ; INP: ds => entry section, with CONFIG block - ; and compressed entry help data - ; (actually always used now) -initialise_command_line_buffer: - mov dx, I_GROUP - mov es, dx - - mov bl, [bootloadunit] - lds si, [bootloadstack] ; -> original ss:sp - 2 - lea ax, [si + 2] ; ax = original sp - mov si, word [si] ; si = original bp - - ; Note that the kernel command line buffer in - ; the init data segment is pre-initialised to - ; hold 0x00 0xFF in the first two bytes. This - ; is used to indicate no command line present, - ; as opposed to an empty command line which - ; will hold 0x00 0x00. - ; If any of the branches to .none are taken then - ; the buffer is not modified so it retains the - ; 0x00 0xFF contents. - cmp si, 114h ; buffer fits below ss:bp ? - jb .none ; no --> - cmp word [si - 14h], "CL" ; signature passed to us ? - jne .none ; no --> - lea si, [si - 114h] ; -> command line buffer - cmp ax, si ; stack top starts below-or-equal buffer ? - ja .none ; no --> - mov di, _kernel_command_line ; our buffer - mov cx, 255 - xor ax, ax - push di - rep movsb ; copy up to 255 bytes - stosb ; truncate - pop di - mov ch, 1 ; cx = 256 - repne scasb ; scan for terminator - rep stosb ; clear remainder of buffer - ; (make sure we do not have 0x00 0xFF - ; even if the command line given is - ; actually the empty string) -.none: - - cli - mov ss, dx - 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 + INITSIZE - mov cl,4 - shr dx,cl - sub ax,dx - mov es,ax - mov dx,INITTEXTSIZE ; 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,__HMATextEnd ; para aligned - shr dx,cl + 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 + add ax,dx %endif - mov ds,ax - mov si,-2 + INITSIZE; 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 + __HMATextEnd - 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 + 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 + 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 -%ifndef QUIET push bx pushf mov ax, 0e33h ; '3' Tracecode - kernel entered @@ -295,194 +181,64 @@ cont: ; Now set up call frame int 010h popf pop bx -%endif - mov byte [_BootDrive],bl ; tell where we came from + mov byte [_BootDrive],bl ; tell where we came from -;!! int 11h -;!! mov cl,6 -;!! shr al,cl -;!! inc al +;!! int 11h +;!! mov cl,6 +;!! shr al,cl +;!! inc al ;!! mov byte [_NumFloppies],al ; and how many + + mov ax,ss + mov ds,ax + mov es,ax + jmp _FreeDOSmain - call _query_cpu -%if XCPU != 86 - %if XCPU < 186 || (XCPU % 100) != 86 || (XCPU / 100) > 9 - %fatal Unknown CPU level defined - %endif - cmp al, (XCPU / 100) - jb cpu_abort ; if CPU not supported --> - cpu XCPU -%endif - mov [_CPULevel], al - -initialise_kernel_config: -extern _InitKernelConfig - - mov ax, ss ; => init data segment - mov si, 60h - mov ds, si ; => entry section - mov si, _LowKernelConfig ; -> our CONFIG block - mov es, ax ; => init data segment - mov di, _InitKernelConfig ; -> init's CONFIG block buffer - mov cx, kernel_config_size / 2 ; size that we support - rep movsw ; copy it over -%if kernel_config_size & 1 - movsb ; allow odd size -%endif - mov ds, ax ; => init data segment - -check_debugger_present: -extern _debugger_present - - mov al, 1 ; assume debugger present - cmp byte [di - kernel_config_size + (CheckDebugger - config_signature)], 1 - ja .skip_ints_00_06 ; 2 means assume present - jb .absent ; 0 means assume absent - clc ; 1 means check - int3 ; break to debugger - jc .skip_ints_00_06 - ; The debugger should set CY here to indicate its - ; presence. The flag set is checked later to skip - ; overwriting the interrupt vectors 00h, 01h, 03h, - ; and 06h. This logic is taken from lDOS init. -.absent: - xor ax, ax ; no debugger present -.skip_ints_00_06: - mov byte [_debugger_present], al - - jmp _FreeDOSmain - -%if XCPU != 86 - cpu 8086 - -cpu_abort: - mov ah, 0Fh - int 10h ; get video mode, bh = active page - - call .first ; print string that follows (address pushed by call) - -%define LOADNAME "FreeDOS" - db 13,10 ; (to emit a blank line after the tracecodes) - db 13,10 - db LOADNAME, " load error: An 80", '0'+(XCPU / 100) - db "86 processor or higher is required by this build.",13,10 - db "To use ", LOADNAME, " on this processor please" - db " obtain a compatible build.",13,10 - db 13,10 - db "Press any key to reboot.",13,10 - db 0 - -.display: - mov ah, 0Eh - mov bl, 07h ; page in bh, bl = colour for some modes - int 10h ; write character (may change bp!) - - db 0A8h ; [test al,imm8] skip "pop si" [=imm8] after the first iteration -.first: - pop si ; (first iteration only) get message address from stack - cs lodsb ; get character - test al, al ; zero ? - jnz .display ; no, display and get next character --> - - xor ax, ax - xor dx, dx - int 13h ; reset floppy disks - xor ax, ax - mov dl, 80h - int 13h ; reset hard disks - - ; this "test ax, imm16" opcode is used to - db 0A9h ; skip "sti" \ "hlt" [=imm16] during first iteration -.wait: - sti - hlt ; idle while waiting for keystroke - mov ah, 01h - int 16h ; get keystroke - jz .wait ; none available, loop --> - - mov ah, 00h - int 16h ; remove keystroke from buffer - - int 19h ; reboot - jmp short $ ; (in case it returns, which it shouldn't) - - cpu XCPU -%endif ; XCPU != 86 - - -segment INIT_TEXT_END - - -;************************************************************ +segment INIT_TEXT_END + + +;************************************************************ ; KERNEL CODE AREA END ; the NUL device -;************************************************************ +;************************************************************ -segment CONST +segment CONST ; ; NUL device strategy ; - global _nul_strtgy - extern GenStrategy + global _nul_strtgy _nul_strtgy: - jmp LGROUP:GenStrategy + mov word [cs:_ReqPktPtr],bx ;save rq headr + mov word [cs:_ReqPktPtr+2],es + retf ; ; NUL device interrupt ; - global _nul_intr + global _nul_intr _nul_intr: push es push bx - mov bx,LGROUP - mov es,bx - les bx,[es:_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: + les bx,[cs:_ReqPktPtr] ;es:bx--> rqheadr 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 - ; used by int13 handler and get/set via int 2f/13h - global _BIOSInt13 ; BIOS provided disk handler - global _UserInt13 ; actual disk handler used by kernel - db 13h -_BIOSInt13: dd 0 - db 15h - dd 0 - ; used for cleanup on reboot - global _BIOSInt19 - db 19h -_BIOSInt19: dd 0 - db 1Bh - dd 0 - ; default to using BIOS provided disk handler - db 13h -_UserInt13: dd 0 - ; floppy parameter table global _int1e_table _int1e_table: times 0eh db 0 -;************************************************************ +;************************************************************ ; KERNEL FIXED DATA AREA -;************************************************************ +;************************************************************ -segment _FIXED_DATA +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 @@ -500,11 +256,14 @@ dos_data db 0 global _NetBios _NetBios dw 0 ; NetBios Number - times (26h - 0ch - ($ - DATASTART)) db 0 + times (26h - 12h - ($ - 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 +; MANY MULTIPLEX PROGRAMS AND TSR'S ACCESSING THEM + global _OemHook21 +_OemHook21 dd -1 ;-0012 OEM fn handler (int21/f8h) + dw 0 ;-000e offset from DOS CS of int21 ret global _NetRetry _NetRetry dw 3 ;-000c network retry count global _NetDelay @@ -519,30 +278,34 @@ _first_mcb dw 0 ;-0002 Start of user memory global MARK0026H ; A reference seems to indicate that this should start at offset 26h. MARK0026H equ $ -_DPBp dd -1 ; 0000 First drive Parameter Block +_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,LGROUP ; 000c console device - global _maxsecsize -_maxsecsize dw 512 ; 0010 maximum bytes/sector of any block device - dd 0 ; 0012 pointer to buffers info structure +_syscon dw _con_dev,seg _con_dev ; 000c console device + global _maxbksize +_maxbksize dw 512 ; 0010 maximum bytes/sector of any block device + global _inforecptr +_inforecptr 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 + ; unused for DOS 5+ global _nblkdev _nblkdev db 0 ; 0020 number of block devices + ; should match # of DPBs global _lastdrive _lastdrive db 0 ; 0021 value of last drive + ; ie max logical drives, should match # of CDSs global _nul_dev _nul_dev: ; 0022 device chain root - extern _con_dev - dw _con_dev, LGROUP + 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 @@ -550,9 +313,8 @@ _nul_dev: ; 0022 device chain root db 'NUL ' global _njoined _njoined db 0 ; 0034 number of joined devices - dw 0 ; 0035 DOS 4 near pointer to special names (always zero in DOS 5) [setver precursor] - global _setverPtr -_setverPtr dw 0,0 ; 0037 setver list (far pointer, set by setver driver) + 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 @@ -561,99 +323,90 @@ _LoL_nbuffers dw 1 ; 003F number of buffers 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 ... +%IF XCPU < 386 + db 0 ; 0044 cpu type (1 if >=386) +%ELSE + db 1 ; 0044 cpu type (1 if >=386) +%ENDIF dw 0 ; 0045 Extended memory in KBytes -buf_info: - global _firstbuf +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 + global _bufloc _bufloc db 0 ; 0053 00=conv 01=HMA - global _deblock_buf + 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 + db 0, 0FFh, 0 ; 005D int24fail,memstrat,a20count 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 + ; required by program being EXECed global _uppermem_root -_uppermem_root dw 0ffffh ; 0066 dmd_upper_root (usually 9fff) +_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 - + 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 + global _rev_number +_rev_number db 0 + global _version_flags +_version_flags db 0 + global _f_nodes +_f_nodes dd 0 + global _f_nodes_cnt +_f_nodes_cnt dw 0 + global os_release + extern _os_release +os_release dw _os_release + +;; any FreeDOS variable below this point are subject to relocation. +;; variables above should not change (unless necessary) as +;; programs may make use of them (even though they should NOT!) %IFDEF WIN31SUPPORT - global _winStartupInfo, _winInstanced + 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 - %ifnidni __OUTPUT_FORMAT__, elf dw instance_table,seg instance_table ; array of instance data - %else - dw instance_table ; array of instance data -global _winseg1 -_winseg1: dw 0 - %endif instance_table: ; should include stacks, Win may auto determine SDA region ; we simply include whole DOS data segment - %ifnidni __OUTPUT_FORMAT__, elf - dw seg _DATASTART, 0 ; [SEG:OFF] address of region's base - dw _markEndInstanceData wrt seg _DATASTART ; size in bytes - %else -global _winseg2 -_winseg2: dw 0 - dw 0 ; [SEG:OFF] address of region's base -global _winseg3 -_winseg3: dw 0 ; size in bytes - %endif + dw seg _DATASTART, 0 ; [?linear?] address of region's base +; dw 0, 0;seg _DATASTART ; [?linear?] 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 + 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 _CritPatch ; offset of to array of offsets to patch + 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 can just point this - ; to an empty table + ; 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 @@ -667,8 +420,8 @@ _firstsftt: dd -1 ; link to next dw 5 ; count times 5*59 db 0 ; reserve space for the 5 sft entries - db 0 ; pad byte so next value on even boundary - + db 0 ; pad byte so next value on even boundary + ; 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 @@ -692,7 +445,7 @@ _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??) +; this byte is used for TAB's global _scr_pos _scr_pos db 0 ; Current Cursor Column global _switchar @@ -735,15 +488,13 @@ _net_name db ' ' ;-27 - 15 Character Network Name global _return_code global _internal_data -; ensure offset of critical patch table remains fixed, some programs hard code offset - times (0315h - ($ - DATASTART)) db 0 global _CritPatch -_CritPatch dw 0 ;-11 zero list of patched critical - dw 0 ; section variables - dw 0 ; DOS puts 0d0ch here but some - dw 0 ; progs really write to that addr. - dw 0 ;-03 - critical patch list terminator - db 90h ;-01 - unused, NOP pad byte +_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 @@ -796,7 +547,6 @@ _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 - global _abort_progress _abort_progress db 0 ; 39 - abort in progress global _CharReqHdr _CharReqHdr: @@ -839,12 +589,8 @@ _Server_Call db 0 ;252 - Server call Func 5D sub 0 ; Pad to 05CCh times (25ch - ($ - _internal_data)) db 0 - global _term_type ; used by break and critical error -_term_type db 0 ;25C - handlers during termination - ; ecm: 00h = normal terminate, - ; 01h = control-c terminate, - ; 02h = critical error abort, - ; 03h = TSR terminate + 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?? @@ -853,40 +599,30 @@ 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 ; i.e. points stack frame (SS:SP) with user registers when int21h called +int21regs_seg dw 0 global critical_sp -critical_sp dw 0 ;268 - critical error internal stack, store SP during int24h +critical_sp dw 0 ;268 - critical error internal stack global current_ddsc -current_ddsc times 2 dw 0 ;26A - pointer to DPB for ??? - -diskbuf_seg dw 0 ;26E - segment of disk buffer - dd 0 ;270 - saving partial cluster number??? - see https://faydoc.tripod.com/structures/16/1690.htm - dw 0 - dw 0 ;276 - temp word - db 0 ;278 - media id returned by AH=1Bh,1Ch - db 0 ;279 - unused +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 - point to device header if filename is character 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 (ThisCDS in published MSDOS sources) +_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 - dw 0 ;28C - temp file handler - dd 0 ;28E - pointer to JFT entry (for file being opened) in process handle table - ; Pad to 05b2h + ; 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 - dw 0ffffh ; 296 - 0xffff or offset of last component in filename ; Pad to 05ceh times (2aeh - ($ - _internal_data)) db 0 @@ -899,15 +635,15 @@ _current_filepos times 2 dw 0 ;2AE - current offset in file ;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 ; store DS,BX on entry to int21h (ie caller's values) + 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 (see offset 264h) +prev_int21regs_off dw 0 ;2D0 - pointer to prev int 21 frame prev_int21regs_seg dw 0 - ; Pad to 05fdh, 2D4 through 2E4 used for int21h/ax=6C00h + ; Pad to 05fdh times (2ddh - ($ - _internal_data)) db 0 global _ext_open_action global _ext_open_attrib @@ -915,25 +651,38 @@ prev_int21regs_seg dw 0 _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 -open_filename dd 0 ;2E3 pointer to filename to open (see ax=6C00h) + + + +; these 3 placed here so init code and int wrapper can easily access +; holds pointers to actual disk handler routines and interrupt +; vectors that we try to restore before a warm reboot + global _SAVEDIVLST +_SAVEDIVLST: + ; used by int13 handler and get/set via int 2f/13h + global _BIOSInt13 + global _UserInt13 +_BIOSInt13 dd 0 ; used to restore int13 on reboot (see int19 wrapper) +_UserInt13 dd 0 ; actual disk handler used by kernel + global _BIOSInt19 +_BIOSInt19 dd 0 ; original int19 + ; Pad to 0620h times (300h - ($ - _internal_data)) db 0 + global _szNames +_szNames: +;; times 11 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 - + global _FcbSearchBuffer ; during FCB search 1st/next use bottom +_FcbSearchBuffer: ; of error stack as scratch buffer +; times 43 db 0 ; - only used during int 21 call ; stacks are made to initialize to no-ops so that high-water ; testing can be performed - times STACK_SIZE*2-($-apistk_bottom) db 0x90 - ; critical error stack 331 bytes?, disk stack 384 bytes, character i/o 384 bytes - ;300 - Error Processing Stack + + global apistk_bottom +apistk_bottom: + times STACK_SIZE dw 0x9090 ;300 - Error Processing Stack global _error_tos _error_tos: times STACK_SIZE dw 0x9090 ;480 - Disk Function Stack @@ -943,32 +692,22 @@ _disk_api_tos: global _char_api_tos _char_api_tos: apistk_top: - db 0 ;780 device driver look-ahead (printer), see ah=64h + db 0 ; 780 ??? _VolChange db 0 ;781 - volume change _VirtOpen db 0 ;782 - virtual open flag - ; 783h to 788h are fastseek drive, 1st cluster, logical cluster, returned logical cluster - ; 78Ah dw ? temp location of SYSINIT - ; controlled variables end at offset 78Ch so pad to end times (78ch - ($ - _internal_data)) db 0 -; MSDOS 7.1+ with FAT32 SDA extended - ;78Ch - 47 bytes of ??? - times (7bbh - ($ - _internal_data)) db 0 -absrdwrflg db 0 ;7bbh - 0=int 25h/26h absolute read/write, 1=int 21h/ax=7305h - times 12 dw 0 ;7bch to 7d2h, high word of 32bit values, see offsets 0x 2a2, 29c, 2bc, 29a, 276, 244, & registers ebx,edx,edi,ecx - times 3 dw 0 ; ??? - ; ; end of controlled variables ; -segment _BSS +segment _BSS ;!! global _NumFloppies -;!!_NumFloppies resw 1 -;!!intr_dos_stk resw 1 -;!!intr_dos_seg resw 1 +;!!_NumFloppies resw 1 +;!!intr_dos_stk resw 1 +;!!intr_dos_seg resw 1 ; mark front and end of bss area to clear @@ -986,25 +725,27 @@ __ib_end: init_tos: ; the last paragraph of conventional memory might become an MCB resb 16 - global __init_end + global __init_end __init_end: init_end: -segment _DATA +segment _DATA ; blockdev private stack global blk_stk_top - times 256 dw 0 + times 192 dw 0 blk_stk_top: ; clockdev private stack global clk_stk_top - times 128 dw 0 + times 64 dw 0 clk_stk_top: -; int2fh private stack - global int2f_stk_top +%IFDEF WIN31SUPPORT +; mux2F private stack + global mux2F_stk_top times 128 dw 0 -int2f_stk_top: +mux2F_stk_top: +%ENDIF ; WIN31SUPPORT ; Dynamic data: ; member of the DOS DATA GROUP @@ -1029,10 +770,8 @@ segment DYN_DATA global _Dyn _Dyn: DynAllocated dw 0 - ;times DynAllocated db ? ; allocated at runtime, need to add DynAllocated to _markEndInstanceData -global _markEndInstanceData -_markEndInstanceData: ; mark end of DOS data seg we say needs instancing +markEndInstanceData: ; mark end of DOS data seg we say needs instancing segment ID_B @@ -1043,20 +782,17 @@ segment ID_E __INIT_DATA_END: -segment INIT_TEXT_START +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 +segment HMA_TEXT_START global __HMATextAvailable -__HMATextAvailable: +__HMATextAvailable global __HMATextStart __HMATextStart: @@ -1071,48 +807,25 @@ begin_hma: db 0 ; to minimize relocations - global _DGROUP_ -_DGROUP_ dw DGROUP + global _DGROUP_ +_DGROUP_ dw DGROUP %ifdef WATCOM ; 32 bit multiplication + division global __U4M __U4M: - LMULU + LMULU global __U4D __U4D: LDIVMODU %endif -%ifdef gcc -%macro ULONG_HELPERS 1 -global %1udivsi3 -%1udivsi3: call %1ldivmodu - ret 8 - -global %1umodsi3 -%1umodsi3: call %1ldivmodu - mov dx, cx - mov ax, bx - ret 8 - -%1ldivmodu: LDIVMODU - -global %1ashlsi3 -%1ashlsi3: LSHLU - -global %1lshrsi3 -%1lshrsi3: LSHRU -%endmacro - ULONG_HELPERS ___ -%endif - - times 0xd0 - ($-begin_hma) db 0 - ; reserve space for far jump to cp/m routine - times 5 db 0 + resb 0xd0 - ($-begin_hma) + ; reserve space for far jump to cp/m routine + resb 5 ;End of HMA segment -segment HMA_TEXT_END +segment HMA_TEXT_END global __HMATextEnd __HMATextEnd: ; and c version @@ -1121,20 +834,20 @@ __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) nobits stack +segment _STACK class=STACK stack -segment CONST +segment CONST ; dummy interrupt return handlers - global _int22_handler + global _int22_handler global _int28_handler global _int2a_handler global _empty_handler -_int22_handler: +_int22_handler: _int28_handler: _int2a_handler: _empty_handler: @@ -1143,12 +856,24 @@ _empty_handler: global _initforceEnableA20 initforceEnableA20: - call near forceEnableA20 - retf + call near forceEnableA20 + retf global __HMARelocationTableStart __HMARelocationTableStart: + global _int13_handler + extern reloc_call_int13_handler +_int13_handler: jmp 0:reloc_call_int13_handler + call near forceEnableA20 + +%IF 0 + global _int19_handler + extern reloc_call_int19_handler +_int19_handler: jmp 0:reloc_call_int19_handler + call near forceEnableA20 +%ENDIF + global _int2f_handler extern reloc_call_int2f_handler _int2f_handler: jmp 0:reloc_call_int2f_handler @@ -1190,11 +915,6 @@ _int0_handler: jmp 0:reloc_call_int0_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 @@ -1236,20 +956,17 @@ __HMARelocationTableEnd: ; 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: - - global _XMS_Enable_Patch -_XMS_Enable_Patch: ; SMC: patch to nop (90h) to enable use of XMS - retf - +UsingXMSdriver: push bx - call 0:0 ; (immediate far address patched) - global _XMSDriverAddress -_XMSDriverAddress: equ $ - 4 ; XMS driver, if detected + call far [cs:_XMSDriverAddress] pop bx retf @@ -1258,6 +975,8 @@ _DISABLEA20: mov ah,6 jmp short UsingXMSdriver +dslowmem dw 0 +eshighmem dw 0ffffh global forceEnableA20 forceEnableA20: @@ -1265,55 +984,67 @@ forceEnableA20: push ds push es push ax - push si - push di - push cx - pushf - cld - -.retry: - xor si, si ; = 0000h - mov ds, si ; => low memory (IVT) - dec si ; = FFFFh - mov es, si ; => HMA at offset 10h - inc si ; back to 0, -> IVT entry 0 and 1 - mov di, 10h ; -> HMA, or wrapping around to 0:0 - mov cx, 4 - repe cmpsw ; compare up to 4 words - je .enable - -.success: - popf - pop cx - pop di - pop si - pop ax - pop es - pop ds - retn + +forceEnableA20retry: + mov ds, [cs:dslowmem] + mov es, [cs:eshighmem] + + mov ax, [ds:00000h] + cmp ax, [es:00010h] + jne forceEnableA20success -.enable: - ; ok, we have to enable A20 (at least seems so) - push cs ; make far call stack frame - call _ENABLEA20 - jmp short .retry + 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 +global _ExecUserDisableA20 + _ExecUserDisableA20: - push ax - push cs ; make far call stack frame - call _DISABLEA20 ; (no-op if not in HMA, patched otherwise) + + cmp word [cs:_XMSDriverAddress],0 + jne NeedToDisable + cmp word [cs:_XMSDriverAddress+2],0 + je noNeedToDisable +NeedToDisable: + push ax + call far _DISABLEA20 pop ax - iret +noNeedToDisable: + iret +; ; Default Int 24h handler -- always returns fail ; so we have not to relocate it (now) ; @@ -1334,7 +1065,3 @@ _TEXT_DGROUP dw DGROUP segment INIT_TEXT global _INIT_DGROUP _INIT_DGROUP dw DGROUP - -%ifdef gcc - ULONG_HELPERS _init_ -%endif diff --git a/kernel/kernel.cfg b/kernel/kernel.cfg deleted file mode 100644 index 38d5ef57..00000000 --- a/kernel/kernel.cfg +++ /dev/null @@ -1,14 +0,0 @@ --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/kernel.ld b/kernel/kernel.ld deleted file mode 100755 index 7b45b430..00000000 --- a/kernel/kernel.ld +++ /dev/null @@ -1,196 +0,0 @@ -/* Linker script for DOS executables with separate data and text segments. - Partly derived from dos-exe-small.ld in newlib-ia16 and elks-separate.ld. */ - -OUTPUT_FORMAT(binary) - -DOS_PSP = 0x60; -MEMOFS = DOS_PSP * 16 - SIZEOF(.msdos_mz_hdr); - -/* these GROUPs play the same role as GROUPS (segments) in OMF */ -PGROUP = (MEMOFS + LOADADDR(.ptext)) / 16; -LGROUP = (MEMOFS + LOADADDR(.ltext)) / 16; -DGROUP = (MEMOFS + LOADADDR(.data)) / 16; -_DosDataSeg = DGROUP; -TGROUP = (MEMOFS + LOADADDR(.text)) / 16; -IGROUP = (MEMOFS + LOADADDR(.itext)) / 16; -I_GROUP = (MEMOFS + LOADADDR(.idata)) / 16; - -INITSIZE = SIZEOF(.itext) + SIZEOF(.idata) + SIZEOF(.ibss); - -SECTIONS - { - /* Fabricate a .exe header here. Although libbfd does have an - "i386msdos" back-end which produces an "MZ" exe header, it cannot do - certain things (yet). */ - .msdos_mz_hdr : { - /* Signature. */ - SHORT (0x5a4d) - /* Bytes in last 512-byte page. */ - SHORT (LOADADDR (.ibss) % 512) - /* Total number of 512-byte pages. */ - SHORT (ALIGN(LOADADDR (.ibss), 512) / 512) - /* Relocation entries. */ - SHORT ((__msdos_mz_rel_end - __msdos_mz_rel_start) / 4) - /* Header size in paragraphs. */ - SHORT (SIZEOF(.msdos_mz_hdr) / 16) - /* Minimum extra paragraphs. */ - SHORT (ALIGN(SIZEOF (.ibss) + SIZEOF(.istack), 16) / 16) - /* Maximum extra paragraphs. */ - SHORT (0xffff) - /* Initial %ss. */ - SHORT (LOADADDR (.istack) / 16 ) - /* Initial %sp. */ - SHORT (LOADADDR (.istack) % 16 + SIZEOF(.istack)) - /* Padding for Checksum (unused) and initial cs:ip (0:0) */ - . = 0x18; - /* Relocation table offset. */ - SHORT (. + 4) - /* Overlay number */ - SHORT (0) - /* Relocations */ - HIDDEN (__msdos_mz_rel_start = .); - *(.msdos_mz_reloc .msdos_mz_reloc.*) - HIDDEN (__msdos_mz_rel_end = .); - /* Padding */ - . = ALIGN (16); - } - - /* Target PSP section. */ - .ptext 0 : AT (SIZEOF(.msdos_mz_hdr)) { - *(PSP) - } - - /* Target low data+text sections. */ - .ltext 0 : AT (LOADADDR(.ptext) + SIZEOF(.ptext)) { - *(_IRQTEXT) - *(_LOWTEXT) - *(_IO_TEXT) - *(_IO_FIXED_DATA) - } - - /* Target data sections. */ - .data 0 : AT (ALIGN(LOADADDR(.ltext) + SIZEOF(.ltext), 16)) { - *(_FIXED_DATA) - *(_BSS) - *(EXCLUDE_FILE (config.obj iasmsupt.obj *init*.obj iprf.obj main.obj) .bss) - *(_DATA) - *(EXCLUDE_FILE (config.obj iasmsupt.obj *init*.obj iprf.obj main.obj) .data) - *(_DATAEND) - *(CONST) - *(CONST2) - *(EXCLUDE_FILE (config.obj iasmsupt.obj *init*.obj iprf.obj main.obj) .rodata) - *(EXCLUDE_FILE (config.obj iasmsupt.obj *init*.obj iprf.obj main.obj) .rodata.*) - *(DYN_DATA) - ASSERT(. <= 0xfff8, - "Error: too large for a small-model .exe file."); - } - - /* Target text sections. */ - .text 0 : AT (ALIGN(LOADADDR(.data) + SIZEOF(.data), 16)) { - *(HMA_TEXT_START) - *(HMA_TEXT) - _call_intr = CALL_INTR; - _res_DosExec = RES_DOSEXEC; - _res_read = RES_READ; - _strlen = STRLEN; - _fstrlen = FSTRLEN; - _strlen = STRLEN; - _fstrcmp = FSTRCMP; - _strchr = STRCHR; - _fstrchr = FSTRCHR; - _fmemchr = FMEMCHR; - _strcpy = STRCPY; - _fmemcpy = FMEMCPY; - _fstrcpy = FSTRCPY; - _memcpy = MEMCPY; - _fmemset = FMEMSET; - _memset = MEMSET; - _memcmp = MEMCMP; - _fmemcmp = FMEMCMP; - _network_redirector_mx = NETWORK_REDIRECTOR_MX; - _execrh = EXECRH; - _share_check = SHARE_CHECK; - _share_open_check = SHARE_OPEN_CHECK; - _share_close_file = SHARE_CLOSE_FILE; - _share_access_check = SHARE_ACCESS_CHECK; - _share_lock_unlock = SHARE_LOCK_UNLOCK; - _share_is_file_open = SHARE_IS_FILE_OPEN; - _call_nls = CALL_NLS; - _fl_reset = FL_RESET; - _fl_diskchanged = FL_DISKCHANGED; - _fl_format = FL_FORMAT; - _fl_read = FL_READ; - _fl_write = FL_WRITE; - _fl_verify = FL_VERIFY; - _fl_setdisktype = FL_SETDISKTYPE; - _fl_setmediatype = FL_SETMEDIATYPE; - _fl_readkey = FL_READKEY; - _fl_lba_ReadWrite = FL_LBA_READWRITE; - _floppy_change = FLOPPY_CHANGE; - _ReadPCClock = READPCCLOCK; - _WritePCClock = WRITEPCCLOCK; - _WriteATClock = WRITEATCLOCK; - *(EXCLUDE_FILE (config.obj iasmsupt.obj *init*.obj iprf.obj main.obj) .text) - *(HMA_TEXT_END) - ASSERT(. <= 0x10000, - "Error: too large for a small-model .exe file."); - } - - /* Target init text sections. */ - .itext 0 : AT (LOADADDR(.text) + SIZEOF(.text)) { - *(INIT_TEXT_START) - *(INIT_TEXT) - _init_execrh = INIT_EXECRH; - _init_memset = INIT_MEMSET; - _init_fmemset = INIT_FMEMSET; - _init_memcmp = INIT_MEMCMP; - _init_fmemcmp = INIT_FMEMCMP; - _init_memcpy = INIT_MEMCPY; - _init_fmemcpy = INIT_FMEMCPY; - _init_strcpy = INIT_STRCPY; - _init_fstrcpy = INIT_FSTRCPY; - _init_strlen = INIT_STRLEN; - _init_fstrlen = INIT_FSTRLEN; - _init_strchr = INIT_STRCHR; - _UMB_get_largest = UMB_GET_LARGEST; - _init_call_intr = INIT_CALL_INTR; - _read = READ; - _init_DosOpen = INIT_DOSOPEN; - _close = CLOSE; - _dup2 = DUP2; - _lseek = LSEEK; - _allocmem = ALLOCMEM; - _init_PSPSet = INIT_PSPSET; - _init_DosExec = INIT_DOSEXEC; - _init_setdrive = INIT_SETDRIVE; - _init_switchar = INIT_SWITCHAR; - _keycheck = KEYCHECK; - _set_DTA = SET_DTA; - _DetectXMSDriver = DETECTXMSDRIVER; - _init_call_XMScall = INIT_CALL_XMSCALL; - __EnableA20 = _ENABLEA20; - __DisableA20 = _DISABLEA20; - *(.text) - *(INIT_TEXT_END) - ASSERT(. <= 0x10000, - "Error: too large for a small-model .exe file."); - } - - /* Target init data sections. */ - .idata 0 : AT (LOADADDR(.itext) + SIZEOF(.itext)) { - *(ID_B) - *(.data) - *(.rodata) *(.rodata.*) - *(ID_E) - } - .ibss (NOLOAD) : AT (LOADADDR(.idata) + SIZEOF(.idata)) { - *(IB_B) - *(.bss) - *(IB_E) - } - .istack 0 (NOLOAD) : AT (LOADADDR(.ibss) + SIZEOF(.ibss)) { - *(_STACK) - . = 0x1000; - } - /DISCARD/ : { *(.*) } - } diff --git a/kernel/lfnapi.c b/kernel/lfnapi.c index 928f16b2..b56fc05d 100644 --- a/kernel/lfnapi.c +++ b/kernel/lfnapi.c @@ -11,7 +11,7 @@ #ifdef VERSION_STRINGS static BYTE *lfnaidRcsId = - "$Id: lfnapi.c 1389 2009-05-20 18:13:37Z bartoldeman $"; + "$Id$"; #endif #ifdef WITHLFNAPI @@ -50,7 +50,7 @@ VOID unicode_to_lfn(UNICODE FAR **name, struct lfn_entry FAR *lep); */ COUNT lfn_allocate_inode(VOID) { - f_node_ptr fnp = get_f_node(&fnode[0]); + f_node_ptr fnp = get_f_node(); struct dpb FAR *dpbp; COUNT handle; if (fnp == 0) return LHE_NOFREEHNDL; @@ -105,7 +105,7 @@ COUNT lfn_free_inode(COUNT handle) * Return value. * SUCCESS, LHE_INVLDHNDL */ -COUNT lfn_setup_inode(COUNT handle, ULONG dirstart, ULONG diroff) +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; diff --git a/kernel/ludivmul.inc b/kernel/ludivmul.inc index a4176297..966d2715 100644 --- a/kernel/ludivmul.inc +++ b/kernel/ludivmul.inc @@ -1,21 +1,26 @@ -; this one adapted from elks, http://elks.sourceforge.net -; multiply cx:bx * dx:ax, result in dx:ax +; this one adapted from elks, http://elks.sourceforge.net +; multiply cx:bx * dx:ax, result in dx:ax +; optimized by Arkady Belousov: +; dx:ax * cx:bx +; = xh:xl * yh:yl +; = xh:xl*yh*w + xh:xl*yl +; = [xh*yh*w*w +] (xl*yh + xh*yl)*w + xl*yl %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 + push cx + push si + xchg si,ax ; si=xl (XCHG instead MOV) + xchg ax,dx ; ax=xh (XCHG instead MOV) + mul bx ; dx:ax=xh*yl (forget dx) + xchg cx,ax ; cx=low(xh*yl), ax=yh + mul si ; dx:ax=xl*yh (forget dx) + add cx,ax ; cx=low(xl*yh+xh*yl) + xchg ax,si ; ax=xl (XCHG instead MOV) + mul bx ; dx:ax=xl*yl + add dx,cx + pop si + pop cx ret %endmacro @@ -25,117 +30,111 @@ %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 +; ...bugfixed and optimized by Arkady Belousov. + +; This macro divides two unsigned long numbers, the dividend and the divisor ; resulting in a quotient and a remainder. ; ; input: -; dx:ax = dividend -; cx:bx = divisor -; +; dx:ax = dividend (x=xh:xl) +; cx:bx = divisor (y=yh:yl) ; output: -; dx:ax = quotient of division of dividend by divisor -; cx:bx = remainder of division of dividend by divisor -; +; dx:ax = quotient of division of dividend by divisor (q=x/y) +; cx:bx = remainder of division of dividend by divisor (r=x%y) ; destroys: ; flags ; -%ifdef STDCALL - push bp - mov bp, sp - mov ax, [bp+6] - mov dx, [bp+8] - mov bx, [bp+10] - mov cx, [bp+12] - pop bp -%endif +%if XCPU < 386 + + jcxz %%div3216 ; cx=0 -> divisor < 2^16 - test cx, cx ; divisor > 2^16-1 ? - jnz %%big_divisor ; yes, divisor > 2^16-1 - cmp dx, bx ; only one division needed ? (cx = 0) - jb %%one_div ; yes, one division sufficient + push si ; save temp + push di ; variables + + push dx ; save + push ax ; dividend x + mov si,bx ; si=yl + mov di,cx ; di:si=cx:bx=y + +%%shift_loop: + shr dx,1 ; shift both + rcr ax,1 ; divisor and + shr cx,1 ; and dividend + rcr bx,1 ; right by 1 bit (rcr preserves ZF) + jnz %%shift_loop ; until zero in cx (divisor < 2^16) + div bx ; ax=quotient q, di:si=y + mov cx,ax ; cx=q + mul di ; dx:ax=q*yh (forget dx) + xchg bx,ax ; bx=low(q*yh) (XCHG instead MOV) + mov ax,cx ; ax=q + mul si ; dx:ax=q*yl + add dx,bx ; dx:ax=q*y, cx=q - 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 ax - xchg ax, cx ; cx = quotient-hi, ax =dividend-lo + pop bx ; bx=xl + sub bx,ax ; bx=xl-low(q*y) + xchg ax,cx ; ax=q (XCHG instead MOV) + pop cx ; cx=xh + sbb cx,dx ; cx:bx=x-q*y=remainder r, ax=q -%%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) + jae %%div_done ; if remainder < 0 + add bx,si + adc cx,di ; correct remainder (r+=y) + dec ax ; and quotient (q-=1) +%%div_done: + xor dx,dx ; dx:ax=0:q=q + + pop di ; restore temp + pop si ; variables 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:si and cx:bx -%%shift_loop: - shr dx, 1 ; shift both - rcr ax, 1 ; dividend - shr cx, 1 ; and divisor - rcr bx, 1 ; right by 1 bit - jnz %%shift_loop ; loop if di non-zero (rcr does not touch ZF) - div bx ; compute quotient dx:ax>>x / cx:bx>>x (stored in ax; remainder in dx not used) - pop bx ; get dividend lo-word - mov cx, ax ; save quotient - mul di ; quotient * divisor hi-word (low only) - pop dx ; dividend high - sub dx,ax ; dividend high - divisor high * quotient, no overflow (carry/borrow) possible here - push dx ; save dividend high - mov ax, cx ; ax=quotient - mul si ; quotient * divisor lo-word - sub bx, ax ; dividend-lo - (quot.*divisor-lo)-lo - mov ax, cx ; get quotient - pop cx ; restore dividend hi-word - sbb cx, dx ; subtract (divisor-lo * quot.)-hi from dividend-hi - sbb dx, dx ; 0 if remainder > 0, else FFFFFFFFh - and si, dx ; nothing to add - and di, dx ; back if remainder positive di:si := di:si(cx:bx) & dx:dx - add bx, si ; correct remainder cx:bx += di:si - adc cx, di ; and - add ax, dx ; quotient if necessary ax += dx - xor dx, dx ; clear hi-word of quot (ax<=FFFFh) dx := 0 - pop di ; restore temp - pop si ; variables +; dx:ax=x, bx=y, cx=0 +; x=xh:xl=xh*w+xl=[xh/y]*y*w+xh%y*w+xl=[xh/y]*y*w+xt +; w=2^16, xh=x/w, xl=x%w, xt=xh%y*w+xl +; remainder = x%y = xt%y +; quotient = [x/y] = [xh/y]*w+xt/y + +%%div3216: + cmp dx,bx ; xh < y ? + jb %%one_div ; yes, one division sufficient + + xchg cx,ax ; ax=0, cx=xl + xchg ax,dx ; dx:ax=0:xh, cx=xl + div bx ; ax=xh/y, dx=xh%y, cx=xl + xchg ax,cx ; dx:ax=xh%y*w+xl=xt, cx=xh/y + +%%one_div: + div bx ; ax=xt/y, dx=xt%d=x%d, cx=xh/y + mov bx,dx ; bx=x%d + mov dx,cx ; dx:ax=xh/y*w+xt/y=x/y + xor cx,cx ; cx:bx=x%d ret -%endmacro +%else ; XCPU >= 386 (Svilen Stoianov and Luchezar Georgiev, Varna, Bulgaria) -%macro LSHLU 0 - pop bx - popargs {dx,ax},cx - push bx - jcxz %%ret -%%loop: shl ax, 1 - rcl dx, 1 - loop %%loop -%%ret: ret -%endmacro + push eax ; save eax.high + pop ax + push edx ; save edx.high + push ax + pop eax ; eax=x + push ecx ; save ecx.high + push bx + pop ecx ; ecx=y + + xor edx,edx + div ecx ; eax=q, edx=r -%macro LSHRU 0 - pop bx - popargs {dx,ax},cx - push bx - jcxz %%ret -%%loop: shr dx, 1 - rcr ax, 1 - loop %%loop -%%ret: ret + push edx + pop bx + pop ecx ; restore ecx.high, cx:bx=r + push eax + pop ax + pop edx ; restore edx.high, dx:ax=q + push ax + pop eax ; restore eax.high + ret + +%endif %endmacro diff --git a/kernel/main.c b/kernel/main.c index 0966cfe4..28883e8a 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -32,25 +32,36 @@ #include "dyndata.h" #include "debug.h" +#ifdef VERSION_STRINGS +static BYTE *mainRcsId = + "$Id$"; +#endif + +/* The Holy Copyright Message. Do NOT remove it or you'll be cursed forever! */ + +#define COPYRIGHT \ +"Copyright 1995-2005 Pasquale Villani and The FreeDOS Project.\n" \ +"NO WARRANTY. Licensed under the GNU General Public License version 2.\n\n" -static char copyright[] = - "(C) Copyright 1995-2023 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 init_internal_devices(void); STATIC VOID update_dcb(struct dhdr FAR *); STATIC VOID init_kernel(VOID); +STATIC VOID do_fixup(VOID); STATIC VOID signon(VOID); -STATIC VOID kernel(VOID); +STATIC VOID init_shell(VOID); STATIC VOID FsConfig(VOID); STATIC VOID InitPrinters(VOID); STATIC VOID InitSerialPorts(VOID); STATIC void CheckContinueBootFromHarddisk(void); STATIC void setup_int_vectors(void); +#define setup_fastprint_hook() setvec(0x29, int29_handler) /* required for printf! */ + + +void setvec(unsigned char intno, intvec vector); + #ifdef _MSC_VER BYTE _acrtused = 0; @@ -62,21 +73,11 @@ __segment DosTextSeg = 0; #endif -struct lol FAR *LoL = &DATASTART; - -struct _KernelConfig ASM InitKernelConfig = { -1 }; -char ASM kernel_command_line[256] = { 0, -1 }; /* special none value */ -int kernel_command_line_length BSS_INIT(0); -UBYTE ASM debugger_present = 0xFF; /* initialised in kernel.asm - do NOT set 0 here or compiler may - move it into bss that we zero out */ +struct lol FAR * const LoL = &DATASTART; +intvec FAR * const savedIVs = &SAVEDIVLST; -VOID ASMCFUNC FreeDOSmain(void) +void ASMCFUNC FreeDOSmain(void) { - unsigned char drv; - unsigned char FAR *p; - char * pp; - #ifdef _MSC_VER extern FAR prn_dev; DosDataSeg = (__segment) & DATASTART; @@ -92,136 +93,106 @@ VOID ASMCFUNC FreeDOSmain(void) at 50:e0 */ - drv = LoL->BootDrive + 1; - p = MK_FP(0, 0x5e0); { - *p = drv - 1; /* compatibility with older kernels */ - } + UBYTE drv; + UBYTE FAR *p = MK_PTR(UBYTE, 0, 0x5e2); + if (fmemcmp(p, "CONFIG", 6) == 0) /* UPXed */ + drv = p[-2]; /* stored there by stub from exeflat.c */ - if (drv >= 0x80) - drv = 3; /* C: */ - LoL->BootDrive = drv; + /* !!! stub, added by exeflat.c for UPXed kernel, should store + boot drive# in the CONFIG-block, not outside (below) it. --avb */ - /* install DOS API and other interrupt service routines, basic kernel functionality works */ - setup_int_vectors(); + else + { + drv = LoL->BootDrive; -#ifdef DEBUG - /* printf must go after setup_int_vectors call */ - if (kernel_command_line[0] == 0 && kernel_command_line[1] == (char)-1) { - printf("\nKERNEL: Command line is not specified.\n"); - } else { - printf("\nKERNEL: Command line is \"%s\"\n", kernel_command_line); - } -#endif + /* !!! kernel.asm should store boot drive# from BL into + LowKernelConfig instead LoL->BootDrive. --avb */ - kernel_command_line_length = strlen(kernel_command_line); - for (pp = kernel_command_line; *pp; ++pp) { - if (*pp == ';') { - *pp = 0; + p[-2] = drv; /* used in initdisk.c */ + + /* !!! initdisk.c:ReadAllPartitionTables() should get boot drive# + from InitKernelConfig, not at fixed address 0:5e0. --avb */ + + p = (UBYTE FAR*)&LowKernelConfig; } + + /* !!! boot drive# should be get from InitKernelConfig after + copying there FAR memory (from 0:5e0 or LowKernelConfig). --avb */ + + drv++; /* A:=1, B:=2 */ + if (drv > 0x80) + drv = 3; /* C: */ + LoL->BootDrive = drv; + + fmemcpy(&InitKernelConfig, p, sizeof InitKernelConfig); } - /* check if booting from floppy/CD */ + /* printfs won't work until int29, fast console output hook is installed */ + setup_fastprint_hook(); + + /* check if booting from CD before we hook too many interrupts */ CheckContinueBootFromHarddisk(); /* display copyright info and kernel emulation status */ signon(); - /* 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 + /* finish initial HMA segment relocation (move up until DOS=HIGH known) */ + do_fixup(); - DoInstall(); + /* install DOS API and other interrupt service routines, basic kernel functionality works */ + setup_int_vectors(); - kernel(); -} + /* initialize all internal variables, process CONFIG.SYS, load drivers, etc */ + init_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); - } + init_shell(); + init_call_p_0(&Config); /* execute process 0 (the shell) */ } STATIC void PSPInit(void) { - psp far *p = MK_FP(DOS_PSP, 0); - - /* Clear out new psp first */ - fmemset(p, 0, sizeof(psp)); - /* high half is used as environment */ - - /* 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; + psp _seg *p = MK_SEG_PTR(psp, DOS_PSP); + + fmemset(p, 0, sizeof(psp)); /* Clear out new psp first */ + + /* initialize all entries and exits */ + p->ps_exit = 0x20cd; /* CP/M-like exit point: */ + /* INT 20 opcode */ + /* CP/M-like entry point: */ + p->ps_farcall = 0x9a; /* FAR CALL opcode... */ + p->ps_reentry = MK_FP(0, 0x30 * 4); /* ...entry address */ + p->ps_unix[0] = 0xcd; /* unix style call: */ + p->ps_unix[1] = 0x21; /* INT 21/RETF opcodes */ 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; - - /* default system version for int21/ah=30 */ - p->ps_retdosver = (LoL->os_setver_minor << 8) + LoL->os_setver_major; - - /* 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); - - /* do not modify command line tail, used as environment */ + /* parent-child relationships */ + /*p->ps_parent = 0;*/ /* parent psp segment */ + p->ps_prevpsp = (VFP)-1l; /* previous psp address */ + + /* Environment and memory useage parameters */ + /*p->ps_size = 0;*/ /* segment of memory beyond */ + /* memory allocated to program */ + /*p->ps_environ = 0;*/ /* environment paragraph */ + + /*p->ps_isv22 = NULL;*/ /* terminate handler */ + /*p->ps_isv23 = NULL;*/ /* break handler */ + /*p->ps_isv24 = NULL;*/ /* critical error handler */ + + /*p->ps_stack = NULL;*/ /* user stack pointer - int 21 */ + + /* File System parameters */ + p->ps_maxfiles = sizeof p->ps_files; /* size of file table */ + fmemset(p->ps_filetab = p->ps_files, 0xff, sizeof p->ps_files); + + /*p->ps_fcb1.fcb_drive = 0;*/ /* 1st command line argument */ + /*fmemset(p->ps_fcb1.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE);*/ + /*p->ps_fcb2.fcb_drive = 0;*/ /* 2nd command line argument */ + /*fmemset(p->ps_fcb2.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE);*/ + + /* this area reused for master environment */ + /*p->ps_cmd.ctCount = 0;*/ /* local command line */ + /*p->ps_cmd.ctBuffer[0] = '\r';*/ /* command tail */ } #ifndef __WATCOMC__ @@ -243,6 +214,30 @@ void setvec(unsigned char intno, intvec vector) } #endif + +/* ensures int vectors we may need to restore are saved */ +STATIC VOID save_int_vectors(VOID) +{ + /* we create far pointers otherwise compiler sets value + in initial data segment (IDATA) which does us no good. + */ + extern intvec BIOSInt13, UserInt13, BIOSInt19; /* in kernel.asm */ + intvec FAR *pBIOSInt13, FAR *pUserInt13, FAR *pBIOSInt19; + + pBIOSInt13 = MK_FP(FP_SEG(savedIVs), FP_OFF(savedIVs)); + pUserInt13 = pBIOSInt13 + 1; + pBIOSInt19 = pBIOSInt13 + 2; + + /* store for later use by our replacement int13handler */ + *pBIOSInt13 = getvec(0x13); /* save original BIOS int 0x13 handler */ + *pUserInt13 = *pBIOSInt13; /* default to it for user int 0x13 handler */ + *pBIOSInt19 = getvec(0x19); /* save reboot handler so we can clean up a little */ + + DDebugPrintf(("\n")); /* force anything printed to start on next line after BS */ + DDebugPrintf(("BIOSInt13(at %p) is %p\n", pBIOSInt13, *pBIOSInt13)); + DDebugPrintf(("BIOSInt19(at %p) is %p\n", pBIOSInt19, *pBIOSInt19)); +} + STATIC void setup_int_vectors(void) { static struct vec @@ -252,11 +247,14 @@ STATIC void setup_int_vectors(void) } vectors[] = { /* all of these are in the DOS DS */ - { 0x80 | 0x0, FP_OFF(int0_handler) }, /* zero divide */ - { 0x80 | 0x1, FP_OFF(empty_handler) }, /* single step */ - { 0x80 | 0x3, FP_OFF(empty_handler) }, /* debug breakpoint */ - { 0x80 | 0x6, FP_OFF(int6_handler) }, /* invalid opcode */ + { 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 */ +/* { 0x13, FP_OFF(int13_handler) }, *//* BIOS disk filter */ +#if 0 { 0x19, FP_OFF(int19_handler) }, /* BIOS bootstrap loader, vdisk */ +#endif { 0x20, FP_OFF(int20_handler) }, { 0x21, FP_OFF(int21_handler) }, /* primary DOS API */ { 0x22, FP_OFF(int22_handler) }, @@ -269,20 +267,15 @@ STATIC void setup_int_vectors(void) { 0x2f, FP_OFF(int2f_handler) } /* multiplex int */ }; struct vec *pvec; - struct lowvec FAR *plvec; int i; - /* save current int vectors so can restore on reboot and call original directly */ - for (plvec = intvec_table; plvec < intvec_table + 6; plvec++) - plvec->isv = getvec(plvec->intno); + save_int_vectors(); /* install default handlers */ for (i = 0x23; i <= 0x3f; i++) - setvec(i, empty_handler); /* note: int 31h segment should be DOS DS */ - HaltCpuWhileIdle = 0; - for (pvec = vectors; pvec < vectors + (sizeof vectors/sizeof *pvec); pvec++) - if ((pvec->intno & 0x80) == 0 || debugger_present == 0) - setvec(pvec->intno & 0x7F, (intvec)MK_FP(FP_SEG(empty_handler), pvec->handleroff)); + setvec(i, empty_handler); + for (pvec = vectors; pvec < ENDOF(vectors); 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); @@ -291,24 +284,28 @@ STATIC void setup_int_vectors(void) setvec(0x29, int29_handler); /* required for printf! */ } -STATIC void init_kernel(void) +#ifdef DEBUGIRQ +extern short old_vectors; +STATIC void printIRQvectors(void) { - COUNT i; - - LoL->os_setver_major = LoL->os_major = MAJOR_RELEASE; - LoL->os_setver_minor = LoL->os_minor = MINOR_RELEASE; + int i,c=0; + short FAR *pv = MK_FP(0x70 /* ??? */, (short)&old_vectors); + printf("Original IRQ1-16 Int vectors: %x:%x\n", FP_SEG(pv), FP_OFF(pv)); + for (i = 0; i < 16; i++, pv+=2) + { + printf("(%x)%04X:%04X ", i, *pv, *(pv+1)); + c = (c+1)%6; + if (c==0) printf("\n"); + } + printf("\n"); +} +#endif - /* Init oem hook - returns memory size in KB */ - ram_top = init_oem(); - - /* Note: HMA_TEXT and init code already moved higher in - conventional memory by startup code, however, we still - need to adjust any references to new location. So use - current CS as that is where we were moved to and perform - any fixups needed. Note this will also re-copy the - HMA_TEXT segment, so be sure not to overwrite it prior - to the MoveKernel() call. Kernel moved to around 8F??:0000 - */ +STATIC void do_fixup(void) +{ + /* move kernel to high conventional RAM, just below the init code */ + /* Note: kernel.asm actually moves and jumps here, but MoveKernel + must still be called to do the necessary segment fixups */ #ifdef __WATCOMC__ lpTop = MK_FP(_CS, 0); #else @@ -316,14 +313,28 @@ STATIC void init_kernel(void) #endif MoveKernel(FP_SEG(lpTop)); + /* lpTop should be para-aligned */ + /* Note: during init time (before our MCB chain established) + KernelAlloc returns a para aligned chunk just below last + chunk allocated, lpTop. I.e. lpTop is top of free conv memory + */ lpTop = MK_FP(FP_SEG(lpTop) - 0xfff, 0xfff0); +} + +STATIC void init_kernel(void) +{ + COUNT i; + + LoL->os_setver_major = LoL->os_major = MAJOR_RELEASE; + LoL->os_setver_minor = LoL->os_minor = MINOR_RELEASE; + LoL->rev_number = REVISION_SEQ; /* Initialize IO subsystem */ - InitIO(); + init_internal_devices(); InitPrinters(); InitSerialPorts(); - init_PSPSet(DOS_PSP); + init_PSPSet(DOS_PSP); /* LoL->_cu_psp = DOS_PSP; */ set_DTA(MK_FP(DOS_PSP, 0x80)); PSPInit(); @@ -335,10 +346,6 @@ STATIC void init_kernel(void) /* use largest possible value for the initial CDS */ LoL->lastdrive = 26; - /* init_device((struct dhdr FAR *)&blk_dev, NULL, 0, &ram_top); */ - /* WARNING: dsk_init() must be called prior to update_dcb() to ensure - _Dyn (start of Dynamic memory block) is the start of drive data table (see getddt() in dsk.c) - */ blk_dev.dh_name[0] = dsk_init(); PreConfig(); @@ -351,14 +358,7 @@ STATIC void init_kernel(void) 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); - + DoConfig(); /* Close all (device) files */ for (i = 0; i < 20; i++) @@ -367,12 +367,17 @@ STATIC void init_kernel(void) /* and do final buffer allocation. */ PostConfig(); +#ifdef DEBUGIRQ + /* displayed stored IRQ vectors, should be original values */ + printIRQvectors(); +#endif + /* Init the file system one more time */ FsConfig(); - + configDone(); - InitializeAllBPBs(); + DoInstall(); } STATIC VOID FsConfig(VOID) @@ -384,24 +389,20 @@ STATIC VOID FsConfig(VOID) 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->cdsCurrentPath[0] = 'A' + i; + pcds_table->cdsCurrentPath[1] = ':'; + pcds_table->cdsCurrentPath[2] = '\\'; + pcds_table->cdsCurrentPath[3] = '\0'; + pcds_table->cdsFlags = 0; + if (i < LoL->nblkdev && (LONG) dpb != -1l) { 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->cdsUserData = 0xffff; + pcds_table->cdsStoreUData = 0xffff; pcds_table->cdsJoinOffset = 2; } @@ -436,18 +437,7 @@ STATIC VOID FsConfig(VOID) STATIC VOID signon() { - if (InitKernelConfig.Verbose < 0) - { -#ifdef CUSTOM_BRANDING - printf("\n" CUSTOM_BRANDING "\n\n"); -#else - printf("\n%S\n\n", MK_FP(FP_SEG(LoL), FP_OFF(LoL->os_release))); -#endif - } else { -#ifdef CUSTOM_BRANDING - printf("\n" CUSTOM_BRANDING "\n\n%s", copyright); -#else - printf("\n%S" + printf("\r%S" "Kernel compatibility %d.%d - " #if defined(__BORLANDC__) "BORLANDC" @@ -464,175 +454,106 @@ STATIC VOID signon() generate some bullshit error here, as the compiler should be known #endif #if defined (I386) - " - 80386 CPU required" + " - i386 CPU required" #elif defined (I186) " - 80186 CPU required" -#else - " - 808x compatible" #endif #ifdef WITHFAT32 " - FAT32 support" #endif - "\n\n%s", + "\n\n" COPYRIGHT, MK_FP(FP_SEG(LoL), FP_OFF(LoL->os_release)), - MAJOR_RELEASE, MINOR_RELEASE, copyright); -#endif - } + MAJOR_RELEASE, MINOR_RELEASE); } -STATIC void kernel() +STATIC void init_shell() { - CommandTail Cmd; - - if (master_env[0] == '\0') /* some shells panic on empty master env. */ - fmemcpy(master_env, "PATH=.\0\0\0\0", sizeof("PATH=.\0\0\0\0")); - - /* 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) + /* if stepping CONFIG.SYS (F5/F8), tell COMMAND.COM about it */ + /* (insert /D, /Y as first argument) */ + if (askCommand & (ASK_TRACE | ASK_SKIPALL)) { - char *insertString = NULL; + PStr p = Config.cfgShell - 1; /* find end of command name */ - if (singleStep) - insertString = " /Y"; /* single step AUTOEXEC */ + /* too long line -> truncate it to make space for "/Y \0" */ + Config.cfgShell[sizeof Config.cfgShell - 4] = '\0'; - if (SkipAllConfig) - insertString = " /D"; /* disable AUTOEXEC */ + do p++; while ((UBYTE)*p > ' ' && *p != '/'); - if (insertString) - { + if (*p == ' ' || *p == '\t') + p++; /* place option after space */ - /* insert /D, /Y as first argument */ - char *p, *q; - - for (p = Cmd.ctBuffer; p < &Cmd.ctBuffer[Cmd.ctCount]; p++) + { + PStr q = p; + while (*q++); /* find end of command line */ + /* shift tail to right by 3 to make room for option */ + do { - 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; + q--; + q[3] = q[0]; + } while (q > p); } + + p[0] = '/', p[1] = 'Y', p[2] = ' '; /* single step AUTOEXEC */ + if (askCommand & ASK_SKIPALL) + p[1] = 'D'; /* disable AUTOEXEC */ } - init_call_p_0(&Config); /* go execute process 0 (the shell) */ } -/* check for a block device and update device control block */ +/* 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; - - /* printf("nblkdev = %i\n", LoL->nblkdev); */ - - /* if no units, nothing to do, ensure at least 1 unit for rest of logic */ - if (nunits == 0) return; - - /* allocate memory for new device control blocks, insert into chain [at end], and update our pointer to new end */ - if ( LoL->first_mcb ) { - dpb = (struct dpb FAR *)KernelAlloc(nunits * sizeof(struct dpb), 'E', Config.cfgDosDataUmb); - } - else { - dpb = DynAlloc("DPBp", blk_dev.dh_name[0], sizeof(struct dpb)); - } + int nunits = dhp->dh_name[0]; + struct dpb FAR *dpb = LoL->DPBp; - /* find end of dpb chain or initialize root if needed */ - if (LoL->nblkdev == 0) - { - /* update root pointer to new end (our just allocated block) */ - LoL->DPBp = dpb; - } - else + /* if we have already chained to at least block driver, + then find last DPB in list, reserve some space in + unused (top of convential) memory, and link it in. + */ + if (LoL->nblkdev) { - struct dpb FAR *tmp_dpb; - /* find current end of dpb chain by following next pointers to end */ - for (tmp_dpb = LoL->DPBp; (ULONG) tmp_dpb->dpb_next != 0xffffffffl; tmp_dpb = tmp_dpb->dpb_next) - ; - /* insert into chain [at end] */ - tmp_dpb->dpb_next = dpb; + while ((LONG) dpb->dpb_next != -1l) + dpb = dpb->dpb_next; + dpb = dpb->dpb_next = + KernelAlloc(nunits * sizeof(struct dpb), 'E', Config.cfgDosDataUmb); } - /* dpb points to last block, one just allocated */ - - for (Index = 0; Index < nunits; Index++) - { - /* printf("processing unit %i of %i nunits\n", Index, nunits); */ - dpb->dpb_next = dpb + 1; /* memory allocated as array, so next is just next element */ - 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)) + + { + int i = 0; + do { - LoL->CDSp[LoL->nblkdev].cdsDpb = dpb; - LoL->CDSp[LoL->nblkdev].cdsFlags = CDSPHYSDRV; - } - - ++dpb; /* dbp = dbp->dpb_next; */ - ++LoL->nblkdev; + dpb->dpb_next = dpb + 1; + dpb->dpb_unit = LoL->nblkdev; + if (LoL->nblkdev < LoL->lastdrive && LoL->CDSp) + { + LoL->CDSp[LoL->nblkdev].cdsDpb = dpb; + LoL->CDSp[LoL->nblkdev].cdsFlags = CDSPHYSDRV; + } + LoL->nblkdev++; + dpb->dpb_subunit = i; + dpb->dpb_device = dhp; + dpb->dpb_flags = M_CHANGED; + dpb++; + i++; + } while (i < nunits); } - /* note that always at least 1 valid dpb due to above early exit if nunits==0 */ - (dpb - 1)->dpb_next = (void FAR *)0xFFFFFFFFl; - - /* printf("processed %i nunits\n", nunits); */ + (dpb - 1)->dpb_next = (VFP)-1l; } -/* If cmdLine is NULL, this is an internal driver */ - -BOOL init_device(struct dhdr FAR * dhp, char *cmdLine, COUNT mode, - char FAR **r_top) +/* If r_top is NULL, this is an internal driver */ +BOOL init_device(struct dhdr FAR * dhp, PCStr cmdLine, int mode, VFP *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_endaddr = r_top ? *r_top : lpTop; + rq.r_bpbptr = (VFP)cmdLine; rq.r_firstunit = LoL->nblkdev; - execrh((request FAR *) & rq, dhp); + execrh(&rq, dhp); /* * Added needed Error handle @@ -640,9 +561,10 @@ BOOL init_device(struct dhdr FAR * dhp, char *cmdLine, COUNT mode, if ((rq.r_status & (S_ERROR | S_DONE)) == S_ERROR) return TRUE; - if (cmdLine) + if (r_top) { /* Don't link in device drivers which do not take up memory */ + /* ie device drivers that fail to load and return top==CS:0 */ if (rq.r_endaddr == (BYTE FAR *) dhp) return TRUE; @@ -662,8 +584,35 @@ BOOL init_device(struct dhdr FAR * dhp, char *cmdLine, COUNT mode, 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); + char name[8]; + PCStr q; + { + UBYTE ch; + PCStr p = cmdLine; + q = p; /* position after path */ + do /* find driver name after path */ + { + ch = *p; + p++; + if (ch == ':' || ch == '\\' || ch == '/') + q = p; + } while (ch > ' '); + } + { + int i = 0; + do /* extract driver name */ + { + UBYTE ch = *q; + if (ch <= ' ' || ch == '.') + ch = '\0'; /* copy name, without extension */ + name[i] = ch; + if (ch == '\0') + break; + i++, q++; + } while (i < sizeof name); + } + KernelAllocPara(FP_SEG(alignNextPara(rq.r_endaddr)) - FP_SEG(dhp), + 'D', name, mode); } /* Another fix for multisegmented device drivers: */ @@ -673,10 +622,11 @@ BOOL init_device(struct dhdr FAR * dhp, char *cmdLine, COUNT mode, /* last INIT call which will then be passed as the end address */ /* for the next INIT call. */ - *r_top = (char FAR *)rq.r_endaddr; + *r_top = rq.r_endaddr; } - if (!(dhp->dh_attr & ATTR_CHAR) && (rq.r_nunits != 0)) + /* if block device (not character) and unit count is nonzero */ + if (!(dhp->dh_attr & ATTR_CHAR) && rq.r_nunits) { dhp->dh_name[0] = rq.r_nunits; update_dcb(dhp); @@ -690,28 +640,21 @@ BOOL init_device(struct dhdr FAR * dhp, char *cmdLine, COUNT mode, return FALSE; } -STATIC void InitIO(void) +STATIC void init_internal_devices(void) { struct dhdr far *device = &LoL->nul_dev; /* Initialize driver chain */ do { - init_device(device, NULL, 0, &lpTop); + /* ??? is cmdLine "\n" for internal devices required? --avb */ + init_device(device, "\n", 0, NULL); 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 :-) @@ -752,14 +695,14 @@ STATIC VOID InitSerialPorts(VOID) } /***************************************************************** - 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 + 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) @@ -768,83 +711,46 @@ STATIC int EmulatedDriveStatus(int drive,char statusOnly) 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; + r.AH = 0x4b; /* bootable CDROM - get status */ + r.AL = statusOnly; + r.DL = (char)drive; + r.SI = (int)buffer; + init_call_intr(0x13, &r); + return r.FLAGS & 1; /* carry flag */ } STATIC void CheckContinueBootFromHarddisk(void) { - char *bootedFrom = "Floppy/CD"; - iregs r; - int key; - - if (InitKernelConfig.BootHarddiskSeconds == 0) + if (InitKernelConfig.BootHarddiskSeconds <= 0 /* feature disabled */ + || LoL->BootDrive >= 3 && EmulatedDriveStatus(0x80,1)) /* booted from HD */ 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\nTo boot from hard disk, press 'H' or wait %d seconds\n" + "To boot from floppy/CD, press any other key NOW!\n", + InitKernelConfig.BootHarddiskSeconds); - 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') + if (GetBiosKey(InitKernelConfig.BootHarddiskSeconds)) { - /* user has hit a key, continue to boot from floppy/CD */ - printf("\n"); - return; + unsigned key = GetBiosKey(-1); /* remove key from buffer */ + if ((UBYTE)key != 'h' && (UBYTE)key != 'H') + /* user has hit a key, continue to boot from floppy/CD */ + 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); - { -#if __GNUC__ - asm volatile("jmp $0,$0x7c00"); -#else - void (far *reboot)(void) = (void (far*)(void)) MK_FP(0x0,0x7c00); - - (*reboot)(); -#endif + iregs r; + r.AX = 0x0201; + r.CX = 0x0001; + r.DX = 0x0080; + r.BX = 0x7c00; + r.ES = 0; + init_call_intr(0x13, &r); } + + /* now jump and run */ + ((void (far*)(void)) MK_FP(0,0x7c00))(); /* jump to boot sector */ } diff --git a/kernel/makefile b/kernel/makefile index 8768820c..28b87d76 100644 --- a/kernel/makefile +++ b/kernel/makefile @@ -1,133 +1,114 @@ # -# Makefile for kernel.sys (originally for Borland C/C++ 3.1) +# makefile for kernel.sys +# +# $Id$ # !include "../mkfiles/generic.mak" -LIBS=..$(DIRSEP)lib$(DIRSEP)device.lib ..$(DIRSEP)lib$(DIRSEP)libm.lib +LIBS=..\lib\device.lib ..\lib\libm.lib HDR=../hdr/ -# *List Macros* +# 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 -OBJS8=initdisk.obj initclk.obj cpu.obj -OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(OBJS6) $(OBJS7) $(OBJS8) - -# *Explicit Rules* - -production: ../bin/$(TARGET).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 - -kernel.sys: kernel.exe ../utils/exeflat.exe ../utils/upxentry.bin ../utils/upxdevic.bin exeflat.rsp - ..$(DIRSEP)utils$(DIRSEP)exeflat.exe kernel.exe kernel.sys $(LOADSEG) @exeflat.rsp - -kernel.exe: $(TARGET).lnk $(OBJS) $(LIBS) - $(LINK) @$(TARGET).lnk; +# Order of linking is important: first kernel.asm, last INIT code. +OBJS1=kernel.obj entry.obj intr.obj irqstack.obj apisupt.obj io.obj console.obj +OBJS2=printer.obj serial.obj dosidle.obj execrh.obj asmsupt.obj int2f.obj \ +nlssupt.obj intwrap.obj +OBJS3=nls_hc.obj procsupt.obj dsk.obj error.obj blockio.obj chario.obj break.obj +OBJS4=fatfs.obj fatdir.obj fattab.obj dosfns.obj fcbfns.obj inthndlr.obj +OBJS5=ioctl.obj memmgr.obj task.obj newstuff.obj dosnames.obj nls.obj +OBJS6=prf.obj network.obj sysclk.obj lfnapi.obj systime.obj initclk.obj +OBJS7=initdisk.obj inithma.obj main.obj config.obj iprf.obj dyninit.obj \ +iasmsupt.obj +OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(OBJS6) $(OBJS7) -clobber: clean - -$(RM) kernel.exe kernel.sys status.me +# Explicit Rules ####################################################### -clean: - -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.cod *.err *.lnk *.rsp +all: ..\bin\$(TARGET).sys ..\bin\country.sys + +..\bin\$(TARGET).sys: $(TARGET).lnk $(OBJS) $(LIBS) ..\utils\exeflat.exe + $(LINK) @$(TARGET).lnk; + ..\utils\exeflat kernel.exe $*.sys $(LOADSEG) -S0x10 -S0x8B + copy $*.sys ..\bin\kernel.sys + +..\bin\country.sys: country.asm + $(NASM) -o $*.sys country.asm # 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 - -# -S to avoid showing expected relocations -# 0x10 & 0x78 or 0x79 depending on compilation options -exeflat.rsp: makefile - -$(RM) exeflat.rsp - $(ECHOTO) exeflat.rsp -S0x10 - $(ECHOTO) exeflat.rsp -S0x78 - $(ECHOTO) exeflat.rsp -S0x79 - $(ECHOTO) exeflat.rsp -E..$(DIRSEP)utils$(DIRSEP)upxentry.bin - $(ECHOTO) exeflat.rsp -D..$(DIRSEP)utils$(DIRSEP)upxdevic.bin - $(ECHOTO) exeflat.rsp $(UPXOPT) - $(ECHOTO) exeflat.rsp $(XUPX) - -$(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 $(OBJS8) - $(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 +# inability of Turbo `make' 2.0 to perform command line redirection. --ror4 + +ECHOTO=..\utils\echoto + +$(TARGET).lnk: $(DEPENDS) *.cfg + -$(RM) *.lnk *.obj + $(ECHOTO) $*.lnk $(OBJS1)+ + $(ECHOTO) $*.lnk $(OBJS2)+ + $(ECHOTO) $*.lnk $(OBJS3)+ + $(ECHOTO) $*.lnk $(OBJS4)+ + $(ECHOTO) $*.lnk $(OBJS5)+ + $(ECHOTO) $*.lnk $(OBJS6)+ + $(ECHOTO) $*.lnk $(OBJS7) + $(ECHOTO) $*.lnk kernel + $(ECHOTO) $*.lnk ..\bin\$* + $(ECHOTO) $*.lnk $(LIBS) + +# Individual File Dependencies ######################################### + +apisupt.obj: apisupt.asm segs.inc +asmsupt.obj: asmsupt.asm segs.inc +console.obj: console.asm io.inc +dosidle.obj: dosidle.asm segs.inc +entry.obj: entry.asm segs.inc $(HDR)stacks.inc +execrh.obj: execrh.asm segs.inc +int2f.obj: int2f.asm segs.inc $(HDR)stacks.inc +intwrap.obj: intwrap.asm segs.inc $(HDR)stacks.inc +intr.obj: intr.asm segs.inc +io.obj: io.asm segs.inc $(HDR)stacks.inc +irqstack.obj: irqstack.asm segs.inc +kernel.obj: kernel.asm segs.inc ludivmul.inc +nls_hc.obj: nls_hc.asm segs.inc +nlssupt.obj: nlssupt.asm segs.inc $(HDR)stacks.inc +printer.obj: printer.asm io.inc +procsupt.obj: procsupt.asm segs.inc $(HDR)stacks.inc +serial.obj: serial.asm io.inc HDRS=\ - $(HDR)portab.h $(HDR)device.h $(HDR)mcb.h $(HDR)pcb.h \ - $(HDR)fat.h $(HDR)fcb.h $(HDR)tail.h $(HDR)dtime.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)portab.h $(HDR)device.h $(HDR)mcb.h $(HDR)pcb.h $(HDR)lol.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 +blockio.obj: blockio.c $(HEADERS) +break.obj: break.c $(HEADERS) +chario.obj: chario.c $(HEADERS) +dosfns.obj: dosfns.c $(HEADERS) +dosnames.obj: dosnames.c $(HEADERS) +dsk.obj: dsk.c $(HEADERS) +error.obj: error.c $(HEADERS) +fatdir.obj: fatdir.c $(HEADERS) +fatfs.obj: fatfs.c $(HEADERS) +fattab.obj: fattab.c $(HEADERS) +fcbfns.obj: fcbfns.c $(HEADERS) +inthndlr.obj: inthndlr.c $(HEADERS) +ioctl.obj: ioctl.c $(HEADERS) +lfnapi.obj: lfnapi.c $(HEADERS) +memmgr.obj: memmgr.c $(HEADERS) +misc.obj: misc.c $(HEADERS) +network.obj: network.c $(HEADERS) +newstuff.obj: newstuff.c $(HEADERS) +nls.obj: nls.c $(HEADERS) +prf.obj: prf.c $(HDR)portab.h +strings.obj: strings.c +sysclk.obj: sysclk.c $(HEADERS) +syspack.obj: syspack.c $(HEADERS) +systime.obj: systime.c $(HEADERS) +task.obj: task.c $(HEADERS) # now the funny stuff :-) # Files in the INIT segment @@ -135,39 +116,49 @@ task.obj: task.c $(HEADERS) $(TARGET).lnk # 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 +config.obj: config.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -initoem.obj: initoem.c $(INITHEADERS) $(TARGET).lnk - $(CC) $(INITCFLAGS) $*.c - $(INITPATCH) $*.obj +dyninit.obj: dyninit.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -main.obj: main.c $(INITHEADERS) $(TARGET).lnk - $(CC) $(INITCFLAGS) $*.c - $(INITPATCH) $*.obj +initclk.obj: initclk.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -inithma.obj: inithma.c $(INITHEADERS) $(TARGET).lnk - $(CC) $(INITCFLAGS) $*.c - $(INITPATCH) $*.obj +initdisk.obj: initdisk.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -dyninit.obj: dyninit.c $(INITHEADERS) $(TARGET).lnk - $(CC) $(INITCFLAGS) $*.c - $(INITPATCH) $*.obj +inithma.obj: inithma.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -initdisk.obj: initdisk.c $(INITHEADERS) $(TARGET).lnk - $(CC) $(INITCFLAGS) $*.c - $(INITPATCH) $*.obj +initoem.obj: initoem.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -initclk.obj: initclk.c $(INITHEADERS) $(TARGET).lnk - $(CC) $(INITCFLAGS) $*.c - $(INITPATCH) $*.obj +main.obj: main.c $(INITHEADERS) + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj -#the string functions for INIT_TEXT -iasmsupt.obj: asmsupt.asm $(TARGET).lnk - $(NASM) -D$(COMPILER) -D_INIT -f obj $(NASMFLAGS) -o iasmsupt.obj asmsupt.asm +# the string functions for INIT_TEXT + +iasmsupt.obj: asmsupt.asm + $(NASM) $(NASMFLAGS) -D_INIT asmsupt.asm -o$*.obj + +# the printf for INIT_TEXT - yet another special case, this file includes prf.c + +iprf.obj: iprf.c prf.c $(HDR)portab.h + $(CC) $(INITCFLAGS) $*.c + $(INITPATCH) $*.obj + +######################################################################## + +clean: + -$(RM) *.bak *.cod *.crf *.err *.lnk *.lst *.map *.obj *.xrf -#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 +clobber: clean + -$(RM) kernel.exe status.me diff --git a/kernel/memdisk.asm b/kernel/memdisk.asm deleted file mode 100644 index fb76e643..00000000 --- a/kernel/memdisk.asm +++ /dev/null @@ -1,79 +0,0 @@ -; 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 index ffe0b816..e692e799 100644 --- a/kernel/memmgr.c +++ b/kernel/memmgr.c @@ -31,17 +31,17 @@ #ifdef VERSION_STRING static BYTE *memmgrRcsId = - "$Id: memmgr.c 1338 2007-07-20 20:52:33Z mceric $"; + "$Id$"; #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) && \ +#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 mcbFreeable(mcb) \ + ((mcb)->m_type == MCB_NORMAL || (mcb)->m_type == MCB_LAST) #define para2far(seg) (mcb FAR *)MK_FP((seg) , 0) @@ -61,17 +61,18 @@ STATIC COUNT joinMCBs(seg para) while (p->m_type == MCB_NORMAL) { q = nxtMCB(p); - if (!mcbFree(q)) - break; if (!mcbValid(q)) return DE_MCBDESTRY; + if (!mcbFree(q)) + break; /* 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 */ +#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" */ + q->m_size = 0xffff; /* mark the now unlinked MCB as "fake" */ #endif } @@ -125,7 +126,7 @@ COUNT DosMemAlloc(UWORD size, COUNT mode, seg *para, UWORD *asize) /* Hack to the Umb Region direct for now. Save time and program space. */ - if ((uppermem_link & 1) && uppermem_root != 0xffff) + if (uppermem_link && uppermem_root != 0xffff) { COUNT tmpmode = (mode == LARGEST ? mem_access_mode : mode); if ((mode != LARGEST || size == 0xffff) && @@ -153,9 +154,9 @@ COUNT DosMemAlloc(UWORD size, COUNT mode, seg *para, UWORD *asize) /* 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: + /* case LAST_FIT: */ /* search for last possible */ + /* case LAST_FIT_U: */ + /* case LAST_FIT_UO: */ default: foundSeg = p; break; @@ -195,7 +196,7 @@ COUNT DosMemAlloc(UWORD size, COUNT mode, seg *para, UWORD *asize) if (!foundSeg || !foundSeg->m_size) { /* no block to fullfill the request */ if ((mode != LARGEST) && (mode & FIRST_FIT_U) && - (uppermem_link & 1) && uppermem_root != 0xffff) + uppermem_link && uppermem_root != 0xffff) { mode &= ~FIRST_FIT_U; goto searchAgain; @@ -295,15 +296,11 @@ COUNT DosMemFree(UWORD para) p = para2far(para); /* check for corruption */ - if (!mcbFreeable(p)) /* does not have to be valid, freeable is enough */ + if (!mcbFreeable(p)) /* does not have to be valid, freeable is enough */ return DE_INVLDMCB; - /* ignore double free */ - if (mcbFree(p)) - return SUCCESS; - /* Mark the mcb as free so that we can later */ - /* merge with other surrounding free MCBs */ + /* merge with other surrounding free mcb's */ p->m_psp = FREE_PSP; fmemset(p->m_name, '\0', 8); @@ -315,14 +312,12 @@ COUNT DosMemFree(UWORD para) * para is the segment of the data portion of the block rather than * the segment of the MCB itself. * - * Resize on an unallocated block is allowed and makes it allocated. - * * 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; mcb FAR * q; + REG mcb FAR *p, FAR * q; /* Initialize */ p = para2far(para - 1); /* pointer to MCB */ @@ -362,16 +357,11 @@ COUNT DosMemChange(UWORD para, UWORD size, UWORD * maxSize) p->m_type = MCB_NORMAL; /* Mark the mcb as free so that we can later */ - /* merge with other surrounding free MCBs */ + /* merge with other surrounding free mcb's */ q->m_psp = FREE_PSP; - - /* Alone in the Dark game accesses the free area after realloc. - * It will crash with the below memset() - disable to match MS-DOS. */ -#if 0 fmemset(q->m_name, '\0', 8); -#endif - /* try to join q with the free MCBs following it if possible */ + /* try to join q with the free mcb's following it if possible */ if (joinMCBs(FP_SEG(q)) != SUCCESS) return DE_MCBDESTRY; } @@ -418,7 +408,7 @@ COUNT DosMemCheck(void) COUNT FreeProcessMem(UWORD ps) { mcb FAR *p; - BYTE oldumbstate = uppermem_link & 1; + BYTE oldumbstate = uppermem_link; /* link in upper memory to free those , too */ DosUmbLink(1); @@ -481,7 +471,7 @@ void DosUmbLink(unsigned n) return; p = para2far(first_mcb); - if (n > 1 || (uppermem_link & 1) == n) + if (n > 1 || uppermem_link == n) return; while (FP_SEG(p) != uppermem_root && p->m_type != MCB_LAST) { diff --git a/kernel/misc.c b/kernel/misc.c index 58007c50..248c0baf 100644 --- a/kernel/misc.c +++ b/kernel/misc.c @@ -30,7 +30,7 @@ #ifdef VERSION_STRINGS static BYTE *miscRcsId = - "$Id: misc.c 653 2003-08-09 09:35:18Z bartoldeman $"; + "$Id$"; #endif #include "globals.h" diff --git a/kernel/msc.cfg b/kernel/msc.cfg new file mode 100644 index 00000000..af2a42c5 --- /dev/null +++ b/kernel/msc.cfg @@ -0,0 +1,5 @@ +-batch -nologo -WX +-Zlp1 +-f- -Osb1V4e -Gsry +-Fc +-I..\hdr diff --git a/kernel/network.c b/kernel/network.c index 8e9e3c85..a29e6ac3 100644 --- a/kernel/network.c +++ b/kernel/network.c @@ -32,7 +32,7 @@ #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: network.c 895 2004-04-21 17:40:12Z bartoldeman $"; + "$Id$"; #endif /* see RBIL D-2152 and D-215D06 before attempting diff --git a/kernel/newstuff.c b/kernel/newstuff.c index fa7302c2..05c9513b 100644 --- a/kernel/newstuff.c +++ b/kernel/newstuff.c @@ -25,8 +25,17 @@ /* Cambridge, MA 02139, USA. */ /****************************************************************/ +#ifdef VERSION_STRINGS +static BYTE *mainRcsId = + "$Id$"; +#endif + #include "portab.h" #include "globals.h" + +#ifdef DEBUG +#define DEBUG_TRUENAME +#endif #include "debug.h" /* @@ -39,27 +48,20 @@ int SetJFTSize(UWORD nHandles) psp FAR *ppsp = MK_FP(cu_psp, 0); UBYTE FAR *newtab; - if (nHandles <= ppsp->ps_maxfiles) + 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_filetab = newtab; } - - 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; } @@ -72,10 +74,8 @@ long DosMkTmp(BYTE FAR * pathname, UWORD attr) 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++ = '\\'; - } + if (ptmp == pathname || (ptmp[-1] != '\\' && ptmp[-1] != '/')) + *ptmp++ = '\\'; ptmp[8] = '\0'; randvar = ((unsigned long)dos_getdate() << 16) | dos_gettime(); @@ -87,12 +87,6 @@ long DosMkTmp(BYTE FAR * pathname, UWORD attr) 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); @@ -100,7 +94,6 @@ long DosMkTmp(BYTE FAR * pathname, UWORD attr) return rc; } - #define drLetterToNr(dr) ((unsigned char)((dr) - 'A')) /* Convert an uppercased drive letter into the drive index */ #define drNrToLetter(dr) ((dr) + 'A') @@ -178,10 +171,7 @@ long DosMkTmp(BYTE FAR * pathname, UWORD attr) */ -#define PATH_ERROR() \ - fstrchr(src, '/') == 0 && fstrchr(src, '\\') == 0 \ - ? DE_FILENOTFND \ - : DE_PATHNOTFND +#define PATH_ERROR goto errRet #define PATHLEN 128 @@ -232,28 +222,71 @@ long DosMkTmp(BYTE FAR * pathname, UWORD attr) #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) return PATH_ERROR(); /* path too long */ \ + if (p >= dest + SFTMAX) PATH_ERROR; /* path too long */ \ *p++ = c; \ } +/* helper for truename: parses either name or extension */ +STATIC int parse_name_ext(int i, const char FAR **src, char **cp, char *dest) +{ + int retval = SUCCESS; + char *p = *cp; + char c; + + while(1) switch(c=*(*src)++) + { + case '.': + retval |= PNE_DOT; + /* fall through */ + case '/': + case '\\': + case '\0': + *cp = p; + return retval; + case '*': + retval |= PNE_WILDCARD; + /* register the wildcard, even if no '?' is appended */ + if (i) do + { + addChar('?'); + } while(--i); + /** Alternative implementation: + if (i) + { + if (dest + SFTMAX - *p < i) + PATH_ERROR; + fmemset(p, '?', i); + p += i; + } **/ + break; + case '?': + retval |= PNE_WILDCARD; + /* fall through */ + default: + if (i) { /* name length in limits */ + --i; + addChar(c); + } + } + + errRet: + return -1; +} + COUNT truename(const char FAR * src, char * dest, COUNT mode) { COUNT i; struct dhdr FAR *dhp; const char FAR *froot; COUNT result; - unsigned state; + int gotAnyWildcards = 0; struct cds FAR *cdsEntry; char *p = dest; /* dynamic pointer into dest */ char *rootPos; char src0; + enum { DONT_ADD, ADD, ADD_UNLESS_LAST } addSep; tn_printf(("truename(%S)\n", src)); @@ -266,13 +299,6 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) if (src0 == '\0') return DE_FILENOTFND; - /* Was a drive letter provided? If not then use current drive */ - if (src[1] == ':') - result = drLetterToNr(DosUpFChar(src0)); - else - result = default_drive; - - /* check for network'd device or path */ if (src0 == '\\' && src[1] == '\\') { const char FAR *unc_src = src; /* Flag UNC paths and short circuit processing. Set current LDT */ @@ -289,137 +315,52 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) /* 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; + + tn_printf(("CDS entry: #%u @%p (%u) '%S'\n", result, cdsEntry, + cdsEntry->cdsBackslashOffset, cdsEntry->cdsCurrentPath)); + /* is the current_ldt thing necessary for compatibly?? + -- 2001/09/03 ska*/ + current_ldt = cdsEntry; + if (cdsEntry->cdsFlags & CDSNETWDRV) + result |= IS_NETWORK; + + dhp = IsDevice(src); + if (dhp) + result |= IS_DEVICE; /* Try if the Network redirector wants to do it */ - /* via Qualify Remote Filename call & validate results */ - assert(sizeof(PriPathName)>=12); /* dest is always pointer to PriPathName or SecPathName */ - memset(dest, 0, 12); /* so we can verify redirector set result value */ + 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') + if (QRemote_Fn(dest, src) == SUCCESS && dest[0] != '\0') { - tn_printf(("QRemoteFn() returned: \"%s\"\n", dest)); + tn_printf(("QRemoteFn() returned: \"%S\"\n", dest)); #ifdef DEBUG_TRUENAME if (strlen(dest) >= SFTMAX) panic("Truename: QRemote_Fn() overflowed output buffer"); #endif - /* don't flag devices such as Z:/NUL as NETWORK devices, - where Z: is a network mapped drive, but do flag redirected - devices such as LPT# for Lantastic - */ if (dest[2] == '/' && (result & IS_DEVICE)) result &= ~IS_NETWORK; - else - result |= IS_NETWORK; -#ifdef DEBUG_TRUENAME - tn_printf(("Truename: result=%04x\n", result)); -#endif return result; } - /* Redirector interface failed (or skipped) --> proceed with local mapper */ - - dhp = IsDevice(src); - - /* Note: [older] redirectors may not provide Int 2Fh API and instead simply wrap Int 21h calls - so above callout to redirector may fail but still be a redirected (mapped) drive that is invalid to us. - - When given a character device, Truename or Open allows device name to be prefixed by invalid - drive letter and\or optional \DEV\ directory prefix, however any other directory including - root path (\) will always return error. However, if drive is valid, then for character - devices any path may be provided for truename but not findfirst [which path must be valid]. - For example: - CON will use default drive and assuming default is X: then same as X:CON - X:CON and X:\DEV\CON will succeed regardless if X: is valid or not - - If X: is a valid drive then returns proper path for drive (X:/CON or \\remote\path\CON respectively) - If X: is not a valid drive then if no path (not even root \ path) or path exactly \DEV\ will - succeed and use dummy path of P:/CON (always P: apparently for dummy CDS), or if any path than \DEV\ - will fail. - - X:\CON and X:\path\CON will always succeed if X: is a valid drive even if path does not exists - If X: is a valid drive then returns provided path for drive (X:/CON or \\remote\path\CON respectively). - */ - - /* determine if valid drive */ - cdsEntry = get_cds(result); - - /* is this a character device (dhp != NULL)? if so check special cases - if cdsEntry is not NULL then valid drive, so any path acceptable for character device - */ - if (dhp && (cdsEntry == NULL)) - { - /* determine if drive letter provided (we know at least 1 character long) */ - const char FAR *s = src+1; - const char FAR *hasSlash; - - if (*s == ':') s++; else s--; /* skip drive (X:) if provided */ - /* s points to start of device name or path, just past optional drive letter */ - - /* determine if path provided, any \ or / characters indicate path including root */ - hasSlash = fstrchr(s, '\\'); - if (hasSlash == NULL) hasSlash = fstrchr(s, '/'); - - if (hasSlash != NULL) { - /* only \DEV\ (with leading \) or /DEV/ for path portion allowed since drive is invalid */ - tn_printf(("-->%Fs<--\n", s)); - if ((*s == '\\') || (*s == '/')) { - unsigned char c[6]; - unsigned x; - c[0]= *(++s) & 0xDF; /* get uppercase next character */ - c[1]= *(++s) & 0xDF; - c[2]= *(++s) & 0xDF; - c[3]= *(++s); - if (c[3]=='\\') c[3]='/'; - s++; /* s now points to start of device name */ - c[4]= '\0'; - x = fstrcmp((char *)c, "DEV/"); - tn_printf(("comparing %s to %s == %d\n", c, "DEV/", x)); - if (x != 0) goto invalid_path; - tn_printf(("ok\n")); - } else { - /* there is a / or \ but not at beginning so must be a path, which is invalid for device */ - goto invalid_path; - } - } /* else { just devicename or X:devicename, drive even default need not be valid to us (mapped drive with invalid CDS) } */ - - /* we have a character device with invalid drive - instead of using CDS of current drive follow MS-DOS convention of returning drive P: for invalid drive. - */ - result = 'P' - 'A'; /* return drive P: */ - /* cdsEntry = get_cds_unvalidated(result); * WARNING: may point past valid memory! if result >= lastdrive */ - cdsEntry = (struct cds FAR *)MK_FP(-1,-1); - tn_printf(("No CDS using entry P: #%u\n", result)); - fmemset(&TempCDS, 0, sizeof(TempCDS)); - fstrcpy(TempCDS.cdsCurrentPath, s); /* just device name no path or drive letter */ - tn_printf(("cds=%s\n", TempCDS.cdsCurrentPath)); - } - - - /* Note: on redirected drives cdsEntry may not be NULL but with dhp==NULL, so must check network redir prior to here */ - if (cdsEntry == NULL) - { -invalid_path: - return DE_PATHNOTFND; - } else { - if (cdsEntry != (struct cds FAR *)MK_FP(-1,-1)) - fmemcpy(&TempCDS, cdsEntry, sizeof(TempCDS)); - } - current_ldt = cdsEntry; /* update current_ldt for compatibility, stored in LOL */ - tn_printf(("CDS entry: #%u @%p (%u) '%s'\n", result, cdsEntry, - TempCDS.cdsBackslashOffset, TempCDS.cdsCurrentPath)); - if (TempCDS.cdsFlags & CDSNETWDRV) - result |= IS_NETWORK; - - if (dhp) - result |= IS_DEVICE; - /* Redirector interface failed --> proceed with local mapper */ dest[0] = drNrToLetter(result & 0x1f); dest[1] = ':'; - /* Do we have a drive? if so skip over it */ - if (src[1] == ':') src += 2; + /* Do we have a drive? */ + if (src[1] == ':') + src += 2; /* Code repoff from dosfns.c @@ -431,7 +372,6 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) if (result & IS_DEVICE) { froot = get_root(src); - /* was devicename or dev\devicename passed in [after stripping optional X:/] */ if (froot == src || froot == src + 5) { if (froot == src + 5) @@ -456,7 +396,6 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) src = froot; } } - tn_printf(("DEVICE: dest=%s, src=%Fs\n", dest, (char far *)src)); } /* Make fully-qualified logical path */ @@ -466,59 +405,32 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) 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 ((cdsEntry != (struct cds FAR *)MK_FP(-1,-1)) && ((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)); + tn_printf(("SUBSTing from: %S\n", cdsEntry->cdsCurrentPath)); /* 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) + fmemcpy(dest, cdsEntry->cdsCurrentPath, cdsEntry->cdsBackslashOffset); + if (cdsEntry->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); + rootPos = p = dest + current_ldt->cdsBackslashOffset; + *p = '\\'; /* force backslash! */ } - if (p[0] == '\0') - p[1] = p[0]; - p[0] = '\\'; /* force backslash! */ - + p++; + if (DosGetCuDir((UBYTE)((result & 0x1f) + 1), p) < 0) + return DE_PATHNOTFND; if (*src != '\\' && *src != '/') p += strlen(p); else /* skip the absolute path marker */ @@ -528,108 +440,97 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) } /* append the path specified in src */ + addSep = ADD; /* add separator */ - state = 0; while(*src) { /* New segment. If any wildcards in previous segment(s), this is an invalid path. */ - if (state & PNE_WILDCARD) + if (gotAnyWildcards) 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 == '.') - { - int dots = 1; - /* special directory component */ - ++src; - if (*src == '.') /* skip the second dot */ - { - ++src; - dots++; - } - if (*src == '/' || *src == '\\' || *src == '\0') - { - --p; /* backup the backslash */ - if (dots == 2) + switch(*src++) + { + case '/': + case '\\': /* skip multiple separators (duplicated slashes) */ + addSep = ADD; + break; + case '.': /* special directory component */ + switch(*src) { - /* ".." entry */ - /* remove last path component */ - while(*--p != '\\') - if (p <= rootPos) /* already on root */ - return DE_PATHNOTFND; + case '/': + case '\\': + case '\0': + /* current path -> ignore */ + addSep = ADD_UNLESS_LAST; + /* If (/ or \) && no ++src + --> addSep = ADD next turn */ + continue; /* next char */ + case '.': /* maybe ".." entry */ + switch(src[1]) + { + case '/': + case '\\': + case '\0': + /* remove last path component */ + while(*--p != '\\') + if (p <= rootPos) /* already on root */ + return DE_PATHNOTFND; + /* the separator was removed -> add it again */ + ++src; /* skip the second dot */ + /* If / or \, next turn will find them and + assign addSep = ADD */ + addSep = ADD_UNLESS_LAST; + continue; /* next char */ + } } - continue; /* next char */ - } - - /* ill-formed .* or ..* entries => return error */ - /* The error is either PATHNOTFND or FILENOTFND - depending on if it is not the last component */ - return PATH_ERROR(); - } - - /* 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); + + /* 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; + default: /* normal component */ + if (addSep != DONT_ADD) + { /* append backslash */ + addChar(*rootPos); + addSep = DONT_ADD; } - /** 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 */ - return PATH_ERROR(); + + /* append component in 8.3 convention */ + --src; + /* first character skipped in switch() */ + i = parse_name_ext(FNAME_SIZE, &src, &p, dest); + if (i == -1) + PATH_ERROR; + if (i & PNE_WILDCARD) + gotAnyWildcards = TRUE; /* 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)) return PATH_ERROR(); - addChar(c); - } + if ((i & PNE_DOT) && *src != '/' && *src != '\\') + { + if (*src == '\0') + continue; + /* we arrive here only when an extension-dot has been found */ + addChar('.'); + i = parse_name_ext(FEXT_SIZE, &src, &p, dest); + if (i == -1 || i & PNE_DOT) /* multiple dots are ill-formed */ + PATH_ERROR; + if (i & PNE_WILDCARD) + gotAnyWildcards = TRUE; + } + --src; /* terminator or separator was skipped */ + break; } - /* *** end of parse name and extension *** */ } - if (state & PNE_WILDCARD && !(mode & CDS_MODE_ALLOW_WILDCARDS)) + if (gotAnyWildcards && !(mode & CDS_MODE_ALLOW_WILDCARDS)) return DE_PATHNOTFND; - if (p == dest + 2) + if (addSep == ADD || p == dest + 2) { - /* we must always add a seperator if dest = "c:" */ + /* MS DOS preserves a trailing '\\', so an access to "C:\\DOS\\" + or "CDS.C\\" fails. */ + /* But don't add the separator, if the last component was ".." */ + /* we must also add a seperator if dest = "c:" */ addChar('\\'); } @@ -670,12 +571,12 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) { strcpy(dest + 2, dest + j); } - result = (result & 0xffe0) | i; /* tweak drive letter (JOIN) */ + result = (result & 0xffe0) | i; current_ldt = cdsp; result &= ~IS_NETWORK; if (cdsp->cdsFlags & CDSNETWDRV) result |= IS_NETWORK; - tn_printf(("JOINed path: \"%s\"\n", dest)); + tn_printf(("JOINed path: \"%S\"\n", dest)); return result; } } @@ -686,15 +587,6 @@ COUNT truename(const char FAR * src, char * dest, COUNT mode) 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; } @@ -732,13 +624,13 @@ 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 +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: OUT: 1123: orig buffer: C:\INTRSPY\SPY_INT.BAT 1123: IN: int.??? [FAIL 0001] 1123: OUT: C:\INTRSPY @@ -752,11 +644,11 @@ more report.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: IN: abcöflkgsxkf [FAIL 0001] 1123: OUT: C:\TOOL\INT.COM -1123: orig buffer: abcöflkgsxkf +1123: orig buffer: abcöflkgsxkf 1123: IN: C:\INTRSPY\SPY_INT.BAT [FAIL 0001] -1123: OUT: C:\INTRSPY\ABCÖFLKG +1123: OUT: C:\INTRSPY\ABCÖFLKG 1123: orig buffer: C:\INTRSPY\SPY_INT.BAT 1123: IN: cmdspy.??? [FAIL 0001] 1123: OUT: C:\INTRSPY @@ -778,7 +670,7 @@ 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) +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(() diff --git a/kernel/nls.c b/kernel/nls.c index 667e7d80..6173d378 100644 --- a/kernel/nls.c +++ b/kernel/nls.c @@ -36,12 +36,11 @@ #include "portab.h" #include "globals.h" #include "pcb.h" -#include "nls.h" -#include "debug.h" +#include #ifdef VERSION_STRINGS static BYTE *RcsId = - "$Id: nls.c 1491 2009-07-18 20:48:44Z bartoldeman $"; + "$Id$"; #endif #ifdef NLS_DEBUG @@ -56,7 +55,7 @@ static BYTE *RcsId = #endif #endif -struct nlsInfoBlock ASM nlsInfo = { +struct nlsInfoBlock nlsInfo = { (char FAR *)0 /* filename to COUNTRY.SYS */ , 437 /* system code page */ /* Implementation flags */ @@ -67,13 +66,8 @@ struct nlsInfoBlock ASM nlsInfo = { #ifdef NLS_REORDER_POINTERS | NLS_CODE_REORDER_POINTERS #endif -#ifdef __GNUC__ - , {.seg=DosDataSeg, .off=&nlsPackageHardcoded} /* hardcoded first package */ - , {.seg=DosDataSeg, .off=&nlsPackageHardcoded} /* first item in chain */ -#else , &nlsPackageHardcoded /* hardcoded first package */ , &nlsPackageHardcoded /* first item in chain */ -#endif }; /* getTableX return the pointer to the X'th table; X==subfct */ @@ -99,29 +93,28 @@ struct nlsInfoBlock ASM nlsInfo = { ***** MUX calling functions **************************************** ********************************************************************/ -#ifdef __GNUC__ -#define call_nls(a,b,c,d,e,f) call_nls(f,e,d,c,b,a) -#endif -extern long ASMPASCAL call_nls(UWORD, VOID FAR *, UWORD, UWORD, UWORD, UWORD); +extern int ASMCFUNC call_nls(UWORD, struct nlsInfoBlock *, UWORD, UWORD, UWORD, + UWORD, void FAR *, 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) +STATIC COUNT muxGo(int subfct, UWORD bp, UWORD cp, UWORD cntry, UWORD bufsize, + void FAR *buf, UWORD *id) { - long ret; + int 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)); + ret = call_nls(subfct, &nlsInfo, bp, cp, cntry, bufsize, buf, id); + log(("NLS: muxGo(): return value = %d\n", ret)); return ret; } /* * Call NLSFUNC to load the NLS package */ -STATIC COUNT muxLoadPkg(int subfct, UWORD cp, UWORD cntry) +COUNT muxLoadPkg(int subfct, UWORD cp, UWORD cntry) { - long ret; + UWORD id; /* on stack, call_nls in int2f.asm takes care of this + * if DS != SS */ /* 0x1400 == not installed, ok to install */ /* 0x1401 == not installed, not ok to install */ @@ -134,18 +127,19 @@ STATIC COUNT muxLoadPkg(int subfct, UWORD cp, UWORD cntry) /* 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. + NLSFUNC ID. If not NULL, call_nls will set *id = BX on return. + Note: &id should be the pointer offset addressable via SS (SS:BP == &id) */ - ret = muxGo(0, 0, NLS_FREEDOS_NLSFUNC_VERSION, 0, NLS_FREEDOS_NLSFUNC_ID, 0); - if ((int)ret != 0x14ff) + if (muxGo(0, 0, NLS_FREEDOS_NLSFUNC_VERSION, 0, NLS_FREEDOS_NLSFUNC_ID, 0, + (UWORD *)&id) != 0x14ff) return DE_FILENOTFND; /* No NLSFUNC --> no load */ - if ((int)(ret >> 16) != NLS_FREEDOS_NLSFUNC_ID) /* FreeDOS NLSFUNC will return */ + if (id != 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); + return muxGo(subfct, 0, cp, cntry, 0, 0, 0); } STATIC int muxBufGo(int subfct, int bp, UWORD cp, UWORD cntry, @@ -154,7 +148,7 @@ STATIC int muxBufGo(int subfct, int bp, UWORD cp, UWORD cntry, 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); + return muxGo(subfct, bp, cp, cntry, bufsize, buf, 0); } #define mux65(s,cp,cc,bs,b) muxBufGo(2, (s), (cp), (cc), (bs), (b)) @@ -386,16 +380,7 @@ 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); } @@ -442,11 +427,11 @@ STATIC VOID xUpMem(struct nlsPackage FAR * nls, VOID FAR * str, muxBufGo(NLSFUNC_UPMEM, 0, nls->cp, nls->cntry, len, str); } -BOOL nlsIsDBCS(UBYTE ch) +STATIC BOOL nlsIsDBCS(UBYTE ch) { if (ch < 128) - return FALSE; /* No leadbyte is smaller than that */ + return FALSE; /* No leadbyte is smaller than that */ { UWORD FAR *t= ((struct nlsDBCS FAR*)getTable7(nlsInfo.actPkg))->dbcsTbl; @@ -566,7 +551,7 @@ VOID DosUpFString(char FAR * str) 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 */ + 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)); @@ -657,12 +642,7 @@ VOID FAR *DosGetDBCS(void) ***** MUX-14 API *************************************************** ********************************************************************/ -/* This is the kernel's default NLSFUNC multiplex int 2F/14 (MUX-14) - handling. If made it here then no other program has hooked MUX-14 - and handled request -- either none loaded or choose to pass request - on. - - Registers: +/* Registers: AH == 14 AL == subfunction BX == codepage @@ -673,54 +653,60 @@ VOID FAR *DosGetDBCS(void) Return value: AL register to be returned if AL == 0, Carry must be cleared, otherwise set */ -UWORD ASMCFUNC syscall_MUX14(iregs FAR *pr) +UWORD ASMCFUNC syscall_MUX14(DIRECT_IREGS) { struct nlsPackage FAR *nls; /* addressed NLS package */ - log(("NLS: MUX14(): subfct=%x, cp=%u, cntry=%u\n", pr->AL, pr->BX, pr->DX)); + 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(pr->BX, pr->DX)) == NULL) + if ((nls = searchPackage(BX, DX)) == NULL) return DE_INVLDFUNC; /* no such package */ log(("NLS: MUX14(): NLS pkg found\n")); - switch (pr->AL) + switch (AL) { case NLSFUNC_INSTALL_CHECK: - pr->BX = NLS_FREEDOS_NLSFUNC_ID; + BX = NLS_FREEDOS_NLSFUNC_ID; return SUCCESS; /* kernel just simulates default functions */ case NLSFUNC_DOS38: - return nlsGetData(nls, NLS_DOS_38, MK_FP(pr->ES, pr->DI), 34); + return nlsGetData(nls, NLS_DOS_38, MK_FP(ES, DI), 34); case NLSFUNC_GETDATA: - return nlsGetData(nls, pr->BP, MK_FP(pr->ES, pr->DI), pr->CX); + return nlsGetData(nls, BP, MK_FP(ES, DI), CX); case NLSFUNC_DRDOS_GETDATA: /* Does not pass buffer length */ - return nlsGetData(nls, pr->CL, MK_FP(pr->ES, pr->DI), 512); + 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, pr->CX); + return nlsYesNo(nls, CX); case NLSFUNC_UPMEM: - nlsUpMem(nls, MK_FP(pr->ES, pr->DI), pr->CX); + 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=\"", pr->CX, - pr->ES, pr->DI)); - for (j = 0, p = MK_FP(pr->ES, pr->DI); j < pr->CX; ++j) + 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(pr->ES, pr->DI), pr->CX); + nlsFUpMem(nls, MK_FP(ES, DI), CX); return SUCCESS; } - log(("NLS: MUX14(): Invalid function %x\n", pr->AL)); + log(("NLS: MUX14(): Invalid function %x\n", AL)); return DE_INVLDFUNC; /* no such function */ } diff --git a/kernel/nls_hc.asm b/kernel/nls_hc.asm index f95ccc09..e59c5a65 100644 --- a/kernel/nls_hc.asm +++ b/kernel/nls_hc.asm @@ -14,17 +14,15 @@ _nlsPackageHardcoded: DB 000h, 000h, 000h, 000h, 001h, 000h, 0b5h, 001h DB 00fh, 000h, 059h, 000h, 04eh, 000h, 006h, 000h DB 002h - DW ?table2, DGROUP + DW ?table2, SEG ?table2 DB 004h - DW ?table4, DGROUP + DW ?table4, SEG ?table4 DB 005h - DW ?table5, DGROUP + DW ?table5, SEG ?table5 DB 006h - DW ?table6, DGROUP + DW ?table6, SEG ?table6 DB 007h - DW ?table7, DGROUP - GLOBAL _nlsCountryInfoHardcoded -_nlsCountryInfoHardcoded: + DW ?table7, SEG ?table7 DB 001h GLOBAL _nlsCntryInfoHardcoded _nlsCntryInfoHardcoded: @@ -32,8 +30,8 @@ _nlsCntryInfoHardcoded: 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 - DW _CharMapSrvc, DGROUP +extern _CharMapSrvc:wrt DGROUP + DW _CharMapSrvc, SEG _CharMapSrvc DB 02ch, 000h GLOBAL _hcTablesStart _hcTablesStart: @@ -122,7 +120,9 @@ _nlsCollHardcoded: GLOBAL _nlsDBCSHardcoded _nlsDBCSHardcoded: ?table7: - DB 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h - DB 000h, 000h + DB 000h, 000h, 000h, 000h GLOBAL _hcTablesEnd _hcTablesEnd: + + +END diff --git a/kernel/nls_load.c b/kernel/nls_load.c deleted file mode 100644 index 0d338bb3..00000000 --- a/kernel/nls_load.c +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************/ -/* */ -/* 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 index a87ed637..bd375b6e 100644 --- a/kernel/nlssupt.asm +++ b/kernel/nlssupt.asm @@ -24,7 +24,7 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: nlssupt.asm 971 2004-05-30 19:31:07Z bartoldeman $ +; $Id$ ; diff --git a/kernel/prf.c b/kernel/prf.c index baa01f0e..83f051a1 100644 --- a/kernel/prf.c +++ b/kernel/prf.c @@ -27,27 +27,26 @@ /****************************************************************/ #include "portab.h" +#include "debug.h" #ifdef FORSYS -#ifdef __GNUC__ -#include -#else #include -#endif #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 */ +#ifdef VERSION_STRINGS +static BYTE *prfRcsId = + "$Id$"; +#endif /* special console output routine */ /*#define DOSEMU */ @@ -62,7 +61,7 @@ void put_console(int c) if (buff_offset >= MAX_BUFSIZE) { buff_offset = 0; - DebugPrintf(("Printf buffer overflow!\n")); + printf("Printf buffer overflow!\n"); } if (c == '\n') { @@ -73,12 +72,6 @@ void put_console(int c) _DX = FP_OFF(buff); _AX = 0x13; __int__(0xe6); -#elif defined(__GNUC__) - asm volatile( - "int $0xe6\n" - : /* outputs */ - : /* inputs */ "a"(0x13), "e"(FP_SEG(buff)), "d"(FP_OFF(buff)) - ); #elif defined(I86) asm { @@ -99,13 +92,13 @@ void put_console(int c) #else #ifdef __WATCOMC__ void int29(char c); -#pragma aux int29 = "int 0x29" __parm [__al] __modify __exact [__bx]; +#pragma aux int29 = "int 0x29" parm [al] modify exact [bx]; #ifdef DEBUG_PRINT_COMPORT void fastComPrint(char c); #pragma aux fastComPrint = \ "mov bx, 0xFD05" \ - "int 0x29" __parm [__al] __modify __exact [__bx]; + "int 0x29" parm [al] modify exact [bx]; #endif #endif @@ -125,8 +118,6 @@ void put_console(int c) #if defined DEBUG_PRINT_COMPORT fastComPrint(c); #endif -#elif defined(__GNUC__) - asm volatile("int $0x29" : : "a"(c) : "bx"); #elif defined(I86) __asm { @@ -140,26 +131,19 @@ void put_console(int c) #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; +typedef char FAR *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_arg(arg, type) (((type FAR *)(arg+=sizeof(type)))[-1]) #define va_end(arg) #endif -static BYTE SSFAR *charp = 0; +static BYTE FAR *charp = 0; STATIC VOID handle_char(COUNT); -STATIC void ltob(LONG, BYTE SSFAR *, COUNT); -STATIC void do_printf(const char *, REG va_list); +STATIC void do_printf(const char FAR *, va_list); +VOID VA_CDECL printf(const char FAR * fmt, ...); /* special handler to switch between sprintf and printf */ STATIC VOID handle_char(COUNT c) @@ -168,80 +152,28 @@ STATIC VOID handle_char(COUNT c) put_console(c); else #ifdef DEBUG_PRINT_COMPORT - if (charp == (BYTE SSFAR *)-1) + if (charp == (BYTE FAR *)-1) fastComPrint(c); else #endif *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; - BYTE 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, ...) +VOID VA_CDECL printf(CONST BYTE FAR *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, ...) +VOID VA_CDECL sprintf(char FAR * buff, CONST BYTE FAR * fmt, ...) { va_list arg; @@ -249,28 +181,23 @@ int VA_CDECL sprintf(char * buff, CONST char * fmt, ...) charp = buff; do_printf(fmt, arg); handle_char('\0'); - return 0; } #ifdef DEBUG_PRINT_COMPORT -int dbgc_printf(CONST char * fmt, ...) +VOID dbgc_printf(CONST BYTE FAR * fmt, ...) { va_list arg; - va_start(arg, fmt); - charp = (BYTE SSFAR *)-1; + charp = (BYTE FAR *)-1; do_printf(fmt, arg); - handle_char('\0'); - return 0; } #endif -STATIC void do_printf(CONST BYTE * fmt, va_list arg) +STATIC void do_printf(CONST BYTE FAR * fmt, va_list arg) { int base, size; - BYTE s[13]; /* long enough for a 32-bit octal number string with sign */ - BYTE flags; - BYTE FAR *p; + char s[13]; /* long enough for a 32-bit octal number string with sign */ + char flags, FAR *p; for (;*fmt != '\0'; fmt++) { @@ -324,8 +251,8 @@ STATIC void do_printf(CONST BYTE * fmt, va_list arg) case 'p': { UWORD w0 = va_arg(arg, unsigned); - char SSFAR *tmp = charp; - fsprintf(s, "%04x:%04x", va_arg(arg, unsigned), w0); + char FAR *tmp = charp; + sprintf(s, "%04x:%04x", va_arg(arg, unsigned), w0); p = s; charp = tmp; break; @@ -361,23 +288,42 @@ STATIC void do_printf(CONST BYTE * fmt, va_list arg) lprt: { - long currentArg; + long n; + ULONG u; + BOOL minus = FALSE; + BYTE FAR *t = s + sizeof(s) - 1; + if (flags & LONGARG) - currentArg = va_arg(arg, long); + n = va_arg(arg, long); else { - currentArg = va_arg(arg, int); + n = va_arg(arg, int); if (base >= 0) - currentArg = (long)(unsigned)currentArg; + n = (long)(unsigned)n; } - ltob(currentArg, s, base); - p = s; + /* convert a long integer to a string in any base (2-16) */ + u = n; + if (base < 0) /* signals signed conversion */ + { + base = -base; + if (n < 0) + { + u = -n; + minus++; + } + } + *t = '\0'; /* terminate the number string */ + do /* generate digits in reverse order */ + *--t = "0123456789ABCDEF"[(UWORD)(u % base)]; + while ((u /= base) > 0); + if (minus) + *--t = '-'; + p = t; } break; default: handle_char('?'); - case '%': handle_char(*fmt); continue; @@ -404,11 +350,10 @@ STATIC void do_printf(CONST BYTE * fmt, va_list arg) } va_end(arg); } - #endif #if !defined(FORSYS) && !defined(_INIT) -extern void put_string(const char *); +extern void put_string(const char FAR *); extern void put_unsigned(unsigned, int, int); void hexd(char *title, UBYTE FAR * p, COUNT numBytes) @@ -428,7 +373,7 @@ void hexd(char *title, UBYTE FAR * p, COUNT numBytes) { 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'); @@ -438,22 +383,18 @@ void hexd(char *title, UBYTE FAR * p, COUNT numBytes) /* put_unsigned -- print unsigned int in base 2--16 */ void put_unsigned(unsigned n, int base, int width) { - char s[6]; - int i; + char s[6]; /* CAUTION: width must be [0..5] and is not checked! */ - for (i = 0; i < width; i++) + s[width] = '\0'; /* terminate the number string */ + while (--width >= 0) { /* generate digits in reverse order */ - s[i] = "0123456789abcdef"[(UWORD) (n % base)]; + s[width] = "0123456789ABCDEF"[n % base]; n /= base; } - - while(i != 0) - { /* print digits in reverse order */ - put_console(s[--i]); - } + put_string(s); } -void put_string(const char *s) +void put_string(const char FAR *s) { while(*s != '\0') put_console(*s++); @@ -463,24 +404,19 @@ void put_string(const char *s) #ifdef TEST /* - this testprogram verifies that the strings are printed correctly - ( or the way, I expect them to print) - - compile like (note -DTEST !) + 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 + c:\tc\tcc -DTEST -Ihdr kernel\prf.c + + and run. If strings are wrong, the program will wait for a key */ -#include +#include #include -void cso(char c) -{ - putchar(c); -} - struct { char *should; char *format; @@ -563,8 +499,8 @@ void test(char *should, char *format, unsigned lowint, unsigned highint) if (strcmp(b, should)) { - printf("\nhit ENTER\n"); - getchar(); + printf("\nhit a key\n"); + getch(); } } diff --git a/kernel/printer.asm b/kernel/printer.asm index 142a8b24..c979323b 100644 --- a/kernel/printer.asm +++ b/kernel/printer.asm @@ -220,7 +220,7 @@ PrtGnIoctl3: ; ; original implementation didn't print at all - on my machine,LPT2 ; -; maybe this one is not much better either, +; maybe this one's not much better either, ; but should print a little bit ; ; the status bits = AH diff --git a/kernel/procsupt.asm b/kernel/procsupt.asm index 3b0fcbd9..6fc3352a 100644 --- a/kernel/procsupt.asm +++ b/kernel/procsupt.asm @@ -25,17 +25,16 @@ ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; -; $Id: procsupt.asm 1591 2011-05-06 01:46:55Z bartoldeman $ +; $Id$ ; %include "segs.inc" - extern _user_r + extern _user_r:wrt DGROUP - extern _break_flg ; break detected flag - extern _term_type - extern _int21_handler ; far call system services + extern _break_flg:wrt DGROUP ; break detected flag + extern _int21_handler:wrt DGROUP ; far call system services %include "stacks.inc" @@ -48,34 +47,27 @@ segment HMA_TEXT ; ; void exec_user(iregs far *irp, int disable_a20) ; - global _exec_user + global _exec_user _exec_user: - -; PUSH$ALL -; mov ds,[_DGROUP_] -; cld -; -; -; - pop ax ; return address (unused) - - pop bp ; irp (user ss:sp) - pop si +%ifndef WATCOM +; exec_user declared with attribute `aborts' + pop ax ; return address (unused) +%endif + pop ax ; irp (user ss:sp) + pop dx pop cx ; disable A20? - or cx,cx - jz do_iret - cli - mov ss,si - mov sp,bp ; set-up user stack + mov ss,dx + mov sp,ax ; set-up user stack sti ; + or cx,cx POP$ALL + jz do_iret extern _ExecUserDisableA20 - jmp DGROUP:_ExecUserDisableA20 + jmp far _ExecUserDisableA20 do_iret: - extern _int21_iret - jmp _int21_iret + iret segment _LOWTEXT @@ -131,7 +123,6 @@ _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. @@ -148,38 +139,108 @@ _spawn_int23: ; this patch helps FreeDos to survive CtrlC, ; but should clearly be done somehow else. mov ss, [_user_r+2] - RestoreSP + mov sp, [_user_r] sti ; get all the user registers back - Restore386Registers POP$ALL - ; stack should now match entry to int21h - - ; we need to call int 23h and be able to determine - ; on return if done via iret or [stc] retf - ; Note: formally we constructed int 23h call on stack - ; but some programs such as Invisible Lan redirector - ; save return address of int 23h call and later check - ; it match int 23h opcode, which if done on stack no - ; no longer matches (as stack space likely reused) - - ; save current stack pointer so we can compare - mov [cs:old_sp], sp - ; clear carry - ; note we ignore, but formally set on return meant abort program - clc - ; invoke user int 23h - int 23h - - ; if old_sp == sp then continue (iret or retf 2 return) - ; else if old_sp == sp-2 then abort (retf 0 return) - cmp [cs:old_sp], sp - je ??int23_respawn - -??int23_abort: + ;; 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 @@ -187,23 +248,13 @@ _spawn_int23: push ds ;; we need DGROUP mov ds, [cs:_DGROUP_] inc byte [_break_flg] - mov byte [_term_type], 1 - ; ecm: This is overwritten in the int 21h handler, - ; but is passed from the int 23h caller to the - ; terminate code in MS-DOS by writing this. - ; For us, break_flg is used in function 4Ch to - ; re-set term_type to 1 later. pop ds xor ah, ah ;; clear ah --> perform DOS-00 --> terminate ??int23_respawn: - jmp DGROUP:_int21_handler - -; stores sp prior to int 23h call -; note: we assume int 23h call not invoked while int 23h call in progress -; value only matters between for duration of above set, int, cmp sequence -old_sp dw 0 + pop bp ;; Restore the original register + jmp far _int21_handler ; ; interrupt enable and disable routines @@ -224,10 +275,13 @@ old_sp dw 0 ; prepare to call process 0 (the shell) from P_0() in C - global reloc_call_p_0 + global reloc_call_p_0 reloc_call_p_0: +%ifndef WATCOM +; reloc_call_p_0 declared with attribute `aborts' pop ax ; return address (32-bit, unused) pop ax +%endif pop ax ; fetch parameter 0 (32-bit) from the old stack pop dx mov ds,[cs:_DGROUP_] @@ -237,4 +291,9 @@ reloc_call_p_0: sti push dx ; pass parameter 0 onto the new stack push ax - call _P_0 ; no return, allow parameter fetch from C +%ifndef WATCOM + call _P_0 ; no return, allow parameter fetch from C +%else +; P_0 declared with attribute `aborts' + jmp _P_0 ; no return, allow parameter fetch from C +%endif diff --git a/kernel/proto.h b/kernel/proto.h index a4c6abfa..c66567a5 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -29,7 +29,7 @@ #ifdef MAIN #ifdef VERSION_STRINGS static BYTE *Proto_hRcsId = - "$Id: proto.h 1491 2009-07-18 20:48:44Z bartoldeman $"; + "$Id$"; #endif #endif @@ -38,11 +38,10 @@ 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); +VOID flush_buffers(REG COUNT dsk); +VOID flush(void); BOOL fill(REG struct buffer FAR * bp, ULONG blkno, COUNT dsk); -BOOL DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mode); +VOID 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); @@ -54,7 +53,7 @@ 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; +#pragma aux handle_break aborts; #endif /* chario.c */ @@ -77,8 +76,12 @@ long cooked_write(struct dhdr FAR **pdev, size_t n, char FAR *bp); sft FAR *get_sft(UCOUNT); /* dosfns.c */ + +#define SEEK_SET 0u +#define SEEK_CUR 1u +#define SEEK_END 2u + 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); @@ -88,7 +91,7 @@ void BinarySftIO(int sft_idx, void *bp, int 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); +int _SftSeek(sft FAR*, LONG new_pos, unsigned mode); long DosOpen(char FAR * fname, unsigned flags, unsigned attrib); COUNT CloneHandle(unsigned hndl); long DosDup(unsigned Handle); @@ -100,10 +103,10 @@ COUNT DosCloseSft(int sft_idx, BOOL commitonly); 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 DosFindFirst(UCOUNT attr, const char FAR * name); COUNT DosFindNext(void); -COUNT DosGetFtime(COUNT hndl, ddate * dp, dtime * tp); -COUNT DosSetFtimeSft(int sft_idx, ddate dp, dtime tp); +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); @@ -113,74 +116,89 @@ 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); +BOOL IsShareInstalled(void); 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_unvalidated(unsigned dsk); -struct cds FAR *get_cds(unsigned dsk); -struct cds FAR *get_cds1(unsigned dsk); +struct cds FAR *get_cds1(unsigned drv); +struct cds FAR *get_cds(unsigned drv); COUNT DosTruename(const char FAR * src, char FAR * dest); -/* dosidle.asm */ +/*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 [] +#pragma aux (cdecl) DosIdle_int modify exact [] #endif +/* dosnames.c */ +int ParseDosName(const char *, char *, BOOL); + /* error.c */ + VOID dump(void); VOID panic(BYTE * s); VOID fatal(BYTE * err_msg); +#ifdef __WATCOMC__ +# pragma aux panic aborts +# pragma aux fatal aborts +#endif /* 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); +f_node_ptr dir_open(const char *dirname); 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) +BOOL dir_write(REG f_node_ptr fnp); +VOID dir_close(REG f_node_ptr fnp); 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); +int FileName83Length(BYTE * filename83); /* 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); +long dos_open(char * path, unsigned flag, unsigned attrib); 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_commit(COUNT fd); COUNT dos_delete(BYTE * path, int attrib); COUNT dos_rmdir(BYTE * path); COUNT dos_rename(BYTE * path1, BYTE * path2, int attrib); -ddate dos_getdate(void); -dtime dos_gettime(void); +date dos_getdate(void); +time dos_gettime(void); +COUNT dos_getftime(COUNT fd, date FAR * dp, time FAR * tp); +COUNT dos_setftime(COUNT fd, date dp, time tp); +ULONG dos_getfsize(COUNT fd); +BOOL dos_setfsize(COUNT fd, LONG size); 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); +LONG dos_lseek(COUNT fd, LONG foffset, COUNT origin); 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); +VOID trim_path(BYTE FAR * s); int dos_cd(char * PathName); +f_node_ptr get_f_node(void); +VOID release_f_node(f_node_ptr fnp); +#define release_near_f_node(fnp) ((fnp)->f_count = 0) +COUNT dos_getfattr_fd(COUNT fd); 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); +/* translate the f_node pointer into an fd */ +#define xlt_fnp(fnp) (fnode_fd[(fnp) - fnode]) struct dhdr FAR * select_unit(COUNT drive); -void dos_merge_file_changes(int fd); /* fattab.c */ void read_fsinfo(struct dpb FAR * dpbp); @@ -188,7 +206,6 @@ 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); @@ -197,9 +214,8 @@ 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); +UBYTE FAR *FatGetDrvData(UBYTE drive, UBYTE * spc, UWORD * bps, UWORD * nc); +ofs_t FcbParseFname(UBYTE *wTestMode, const char FAR * lpFileName, fcb FAR * lpFcb); const BYTE FAR *ParseSkipWh(const BYTE FAR * lpFileName); BOOL TestCmnSeps(BYTE FAR * lpFileName); BOOL TestFieldSeps(BYTE FAR * lpFileName); @@ -218,23 +234,20 @@ void FcbCloseAll(void); UBYTE FcbFindFirstNext(xfcb FAR * lpXfcb, BOOL First); /* intr.asm */ -UWORD ASMPASCAL call_intr(WORD nr, iregs FAR * rp); -COUNT ASMPASCAL res_DosExec(COUNT mode, exec_blk * ep, BYTE * lp); -UCOUNT ASMPASCAL res_read(int fd, void *buf, UCOUNT count); + +int ASMPASCAL res_DosExec(int mode, exec_blk *, PCStr); +unsigned ASMPASCAL res_read(int fd, void *buf, unsigned count); #ifdef __WATCOMC__ -#pragma aux (__pascal) call_intr __modify __exact [__ax] -#pragma aux (__pascal) res_DosExec __modify __exact [__ax __bx __dx __es] -#pragma aux (__pascal) res_read __modify __exact [__ax __bx __cx __dx] +# 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); + +VFP adjust_far(CVFP); COUNT DosMemAlloc(UWORD size, COUNT mode, seg * para, UWORD * asize); COUNT DosMemLargest(UWORD * size); COUNT DosMemFree(UWORD para); @@ -250,7 +263,7 @@ VOID mcb_print(mcb FAR * mcbp); COUNT lfn_allocate_inode(VOID); COUNT lfn_free_inode(COUNT handle); -COUNT lfn_setup_inode(COUNT handle, ULONG dirstart, ULONG diroff); +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); @@ -279,16 +292,16 @@ COUNT DosSetCountry(UWORD cntry); COUNT DosGetCodepage(UWORD * actCP, UWORD * sysCP); COUNT DosSetCodepage(UWORD actCP, UWORD sysCP); VOID FAR *DosGetDBCS(void); -UWORD ASMCFUNC syscall_MUX14(iregs FAR *); +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, ...); +VOID VA_CDECL printf(const char FAR* fmt, ...); +VOID VA_CDECL sprintf(char FAR * buff, const char FAR* 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_string(const char FAR *s); void put_console(int); /* strings.c */ @@ -318,26 +331,27 @@ int /*ASMCFUNC*/ ASMPASCAL fmemcmp(const void FAR *m1, const void FAR *m2, size_ #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) 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) 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 +#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); +COUNT ByteToBcd(COUNT x); LONG WordToBcd(BYTE * x, UWORD * mon, UWORD * day, UWORD * yr); /* syspack.c */ @@ -359,12 +373,15 @@ 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); + +void new_psp(seg_t para, seg_t cur_psp); +void child_psp(seg_t para, seg_t cur_psp, seg_t beyond); +void return_user(void); COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp); ULONG SftGetFsize(int sft_idx); -VOID InitPSP(VOID); +#ifdef __WATCOMC__ +# pragma aux return_user aborts +#endif /* newstuff.c */ int SetJFTSize(UWORD nHandles); @@ -377,18 +394,20 @@ 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_getfree_11a3(s,d) (int)network_redirector_mx(REM_GETLARGESPACE, 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) -/* local (near) address of s pushed on stack, where s is far (segment:offset) of argument */ #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); + +void ASMCFUNC exec_user(iregs FAR *, int disable_a20); +#ifdef __WATCOMC__ +# pragma aux (cdecl) exec_user aborts +#endif /* new by TE */ @@ -400,5 +419,4 @@ VOID ASMCFUNC exec_user(iregs FAR * irp, int disable_a20); ASSERT_CONST( (BYTE FAR *)x->fcb_ext - (BYTE FAR *)x->fcbname == 8) */ -#define ASSERT_CONST(x) { typedef struct { char _xx[x ? 1 : -1]; } xx ; } - +#define ASSERT_CONST(x) { typedef struct { char _[(x) ? 1 : -1]; } _; } diff --git a/kernel/segs.inc b/kernel/segs.inc index 6dd65833..5e88c19c 100644 --- a/kernel/segs.inc +++ b/kernel/segs.inc @@ -38,86 +38,60 @@ CPU XCPU %endif %endif -; for OW on Linux: -%ifdef owlinux -%define WATCOM -%endif - -%ifidn __OUTPUT_FORMAT__, obj group PGROUP PSP -group LGROUP _IRQTEXT _LOWTEXT _IO_TEXT _IO_FIXED_DATA _TEXT +group LGROUP _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 -%define IGROUP TGROUP 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 -%define class(x) class=x -%define nobits -%define exec -%define INITSIZE init_end wrt INIT_TEXT -%define INITTEXTSIZE __INIT_DATA_START wrt INIT_TEXT - -%else ; using ELF - -BITS 16 -; groups are defined in the linker script kernel.ld -extern PGROUP -extern DGROUP -extern LGROUP -extern TGROUP -extern IGROUP -extern I_GROUP -%define class(x) -%define stack -extern INITSIZE -%define INITTEXTSIZE __InitTextEnd +segment PSP class=PSP +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 +%ifdef MSC +segment CONST class=CONST align=2 +%else +segment CONST class=DATA align=2 %endif - -segment PSP class(PSP) -segment _IRQTEXT class(LCODE) exec -segment _LOWTEXT class(LCODE) exec -segment _IO_TEXT class(LCODE) exec -segment _IO_FIXED_DATA class(LCODE) align=2 -segment _TEXT class(LCODE) exec -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 +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) exec -segment HMA_TEXT_END class(CODE) align=16 -segment INIT_TEXT_START class(CODE) align=16 -segment INIT_TEXT class(CODE) exec -segment INIT_TEXT_END class(CODE) align=16 +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 +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 nobits -segment IB class(IB) align=2 nobits -segment IB_E class(IB) align=2 nobits +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 index 436b180a..914bf5f7 100644 --- a/kernel/serial.asm +++ b/kernel/serial.asm @@ -40,7 +40,7 @@ ComTable db 0Ah dw _IOCommandError dw ComRead dw ComNdRead - dw ComInStat + dw _IOExit dw ComInpFlush dw ComWrite dw ComWrite @@ -50,7 +50,7 @@ ComTable db 0Ah segment _IO_TEXT - extern CommonNdRdExit + extern CommonNdRdExit:wrt LGROUP ComRead: jcxz ComRd3 @@ -62,8 +62,7 @@ ComRead: ComRd1: call BiosRdCom or ah,ah ; timeout? - ;js ComRd1 ; yes, try again - js _IOErrCnt ; yes, fail to avoid looping forever + js ComRd1 ; yes, try again ComRd2: stosb loop ComRd1 @@ -85,18 +84,6 @@ 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 @@ -104,17 +91,17 @@ ComNdRead: or al,al jnz ComNdRd1 call ComRdStatus - test ah,1 ; char waiting + test ah,1 + jz ComNdRtn + test al,20h 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 + jmp CommonNdRdExit ComNdRtn: - jmp _IODone ; return "busy" + jmp _IODone ComOutStat: @@ -123,7 +110,7 @@ ComOutStat: jz ComNdRtn test ah,20h jz ComNdRtn - jmp _IOExit ; return "ready" + jmp _IOExit ComRdStatus: diff --git a/kernel/strings.c b/kernel/strings.c index e13a1f26..8ec16dec 100644 --- a/kernel/strings.c +++ b/kernel/strings.c @@ -30,7 +30,7 @@ #ifdef VERSION_STRINGS static BYTE *stringsRcsId = - "$Id: strings.c 653 2003-08-09 09:35:18Z bartoldeman $"; + "$Id$"; #endif #ifndef I86 diff --git a/kernel/sysclk.c b/kernel/sysclk.c index 67df7b2b..457551dc 100644 --- a/kernel/sysclk.c +++ b/kernel/sysclk.c @@ -31,7 +31,7 @@ #ifdef VERSION_STRINGS static char *RcsId = - "$Id: sysclk.c 681 2003-09-09 17:32:20Z bartoldeman $"; + "$Id$"; #endif /* */ diff --git a/kernel/syspack.c b/kernel/syspack.c index 9676a1c1..c1a91248 100644 --- a/kernel/syspack.c +++ b/kernel/syspack.c @@ -32,7 +32,7 @@ #ifdef VERSION_STRINGS static BYTE *syspackRcsId = - "$Id: syspack.c 485 2002-12-09 00:17:15Z bartoldeman $"; + "$Id$"; #endif #ifdef NONNATIVE diff --git a/kernel/systime.c b/kernel/systime.c index 3c8c035b..e84bc0ea 100644 --- a/kernel/systime.c +++ b/kernel/systime.c @@ -27,13 +27,13 @@ /****************************************************************/ #include "portab.h" -#include "dtime.h" -#include "ddate.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 $"; + "$Id$"; #endif const UWORD days[2][13] = { diff --git a/kernel/task.c b/kernel/task.c index 1f31b926..35e37ae9 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -30,9 +30,10 @@ #include "globals.h" #include "debug.h" - - -#define toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) + ('A' - 'a') : (c)) +#ifdef VERSION_STRINGS +static BYTE *RcsId = + "$Id$"; +#endif #define LOADNGO 0 #define LOAD 1 @@ -47,6 +48,7 @@ #define ExeHeader (*(exe_header *)(SecPathName + 0)) #define TempExeBlock (*(exec_blk *)(SecPathName + sizeof(exe_header))) #define Shell (SecPathName + sizeof(exe_header) + sizeof(exec_blk)) +#define sizeofShell (sizeof 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 @@ -54,20 +56,17 @@ #endif #endif -#define CHUNK 32256 -#define MAXENV 32768u -#define ENV_KEEPFREE 0x83 /* keep unallocated by environment variables */ - /* The '65' added to nEnvSize does not cover the additional stuff: - + 2 bytes: number of strings - + 80h bytes: maximum absolute filename - + 1 byte: '\0' - -- 1999/04/21 ska */ +#define CHUNK 32256u /* =8000h-512; this value allows to combine + in one int value negative error codes + and positive read counters + */ +#define MAXENV 32768u /* maximum environment size */ intvec getvec(unsigned char intno) { intvec iv; disable(); - iv = *(intvec FAR *)MK_FP(0,4 * (intno)); + iv = *MK_PTR(intvec, 0, 4 * intno); enable(); return iv; } @@ -75,331 +74,323 @@ intvec getvec(unsigned char intno) void setvec(unsigned char intno, intvec vector) { disable(); - *(intvec FAR *)MK_FP(0,4 * intno) = vector; + *MK_PTR(intvec, 0, 4 * intno) = vector; enable(); } ULONG SftGetFsize(int sft_idx) { - sft FAR *s = idx_to_sft(sft_idx); + const 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 WORD SetverCompareFilename(BYTE FAR *m1, BYTE FAR *m2, COUNT c) -{ - while (c--) + /* If SFT entry refers to a device, return the date and time of opening */ + if (s->sft_flags & (SFT_FDEVICE | SFT_FSHARED)) { - if (toupper(*m1) != toupper(*m2)) - { - return *m1 - *m2; - } - - m1 = m1 + 1; m2 = m2 + 1; + return s->sft_size; } - return 0; + /* call file system handler */ + return dos_getfsize(s->sft_status); } -STATIC UWORD SetverGetVersion(BYTE FAR *table, BYTE FAR *name) +/* create a new environment for the process */ +STATIC int ChildEnv(seg_t env_seg, seg_t *penv_seg, const char far *path) { - BYTE FAR *len; - COUNT nlen; - - if ((table != NULL) && (name != NULL)) - { - nlen = fstrlen(name); + size_t env_sz, path_sz; + int rc; - while (*(len = table) != 0) - { - if ((*len == nlen) && (SetverCompareFilename(name, table + 1, *len) == 0)) - { - return *((UWORD FAR *)(table + *len + 1)); - } + /* Every process requires an environment because of argv[0] + -- 1999/04/21 ska + */ - table = table + *len + 3; - } - } + /* make complete pathname */ + if ((rc = truename(path, PriPathName, CDS_MODE_SKIP_PHYSICAL)) < SUCCESS) + return rc; - return 0; -} + /* get parent's environment if exec.env_seg == 0 */ + if (env_seg == 0) + env_seg = MK_SEG_PTR(const psp, cu_psp)->ps_environ; -/* allocate memory for and copy current process env to child environment - returns segment of env MCB (not env block itself) in pChildEnvSeg - */ -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); - *pChildEnvSeg = 0; /* initialize to invalid value, prevent free'ing random address on errors by callers of ChildEnv */ - - /* create a new environment for the process */ - /* copy parent's environment if exec.env_seg == 0 */ - - ProcDbgPrintf(("ChildEnv: environment block is %u, using %s\n", exp->exec.env_seg, (exp->exec.env_seg)?"exec_blk":"parent_blk")); - 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 */ + /* count size of environment */ + path_sz = strlen(PriPathName) + 5; + env_sz = 0; + if (env_seg && *MK_PTR(const char, env_seg, 0)) { - *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++) + do { - /* Test env size and abort if greater than max */ - if (nEnvSize >= MAXENV - ENV_KEEPFREE) + env_sz++; + if (env_sz + path_sz > MAXENV) return DE_INVLDENV; - - /* loop until first double terminator '\0\0' found */ - if (*(UWORD FAR *) (pSrc + nEnvSize) == 0) - break; - } - nEnvSize += 2; /* account for trailing \0\0 */ + } while (*MK_PTR(const UWORD, env_seg, env_sz)); } - /* allocate enough space for env + path (rounding up to nearest para) - Note: we must allocate at least 1 paragraph (16 bytes) for empty environment - + ENV_KEEPFREE for argv[0] (program name) - */ - /* ProcDbgPrintf(("PriPathName is %lu bytes\n", sizeof(PriPathName))); */ - assert(sizeof(PriPathName)+3==ENV_KEEPFREE); - if ((RetCode = DosMemAlloc((nEnvSize + ENV_KEEPFREE + 15)/16, - mem_access_mode, pChildEnvSeg, - NULL /*(UWORD FAR *) MaxEnvSize ska */ )) < 0) + /* allocate space for env + path */ { - ProcDbgPrintf(("Error alloc Env space\n")); - return RetCode; + UWORD tmp; + if ((rc = DosMemAlloc((env_sz + path_sz + 15) / 16, + mem_access_mode, penv_seg, &tmp)) != SUCCESS) + return rc; } - pDest = MK_FP(*pChildEnvSeg + 1, 0); /* skip past MCB and set pDest to start of env block */ - - /* 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; + seg_t dst_seg = *penv_seg + 1; + + /* environment contains: + - 0 or more ASCIIZ strings (with variable definitions); + - empty ASCIIZ string (one null character); + - 16-bit counter (usually 1); + - ASCIIZ string with path. + */ + /* UNDOCUMENTED: with none variables before empty ASCIIZ string, + environment should get additional null character (ie. empty + environment contains two null characters). --avb + */ + fmemcpy(MK_SEG_PTR(char, dst_seg), MK_SEG_PTR(const char, env_seg), env_sz); + *MK_PTR(UWORD, dst_seg, env_sz) = 0; + *MK_PTR(UWORD, dst_seg, env_sz + 2) = 1; + fstrcpy(MK_PTR(char, dst_seg, env_sz + 4), PriPathName); } - 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) +#ifdef DEBUG { - ProcDbgPrintf(("Failed to get truename for env argv0\n")); - return RetCode; - } - ProcDbgPrintf(("ChildEnv for [%s]\n", PriPathName)); - 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 */ + seg_t dst_seg = *penv_seg + 1; + int i; + DebugPrintf(("ChildEnv. env seg=0x%02x\n", dst_seg)); + if (dst_seg) + { + const char FAR*p = MK_PTR(const char, dst_seg, 0); + /* loop through ASCIIZ env variables */ + if (*p) + while (*p) + { + DebugPrintf(("[")); + for (; *p; p++) + if (*p == ' ') DebugPrintf(("")); + else DebugPrintf(("%c", *p)); + DebugPrintf(("]\n")); + p++; + } + else + p++; /* even empty env must have 1 ("") ASCIIZ string */ + /* may be followed by empty string (just \0), 16bit count, ASCIIZ argv[0] */ + DebugPrintf(("End of Env marker = 0x%02x (should be 0)\n", *p)); + DebugPrintf(("argv[0] present = %u\n", *MK_PTR(UWORD, dst_seg, env_sz + 2))); + p+=3; /* skip 16bit count and point to argv[0] */ + if (*p) + { + for (i = 0; p[i] && (i < 127); i++) + DebugPrintf(("%c", p[i])); + DebugPrintf(("\n")); + } + else + DebugPrintf(("No program name (argv[0]) supplied\n")); + } + } +#endif + return SUCCESS; } -/* The following code is 8086 dependant */ -void new_psp(seg para, seg cur_psp) +/* The following code is 8086 dependant */ +void new_psp(seg_t para, seg_t 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); - /* RBIL is wrong on zeroing parent_psp, and in fact some - * progs (Alpha Waves game, https://github.com/stsp/fdpp/issues/112) - * won't work if its zeroed. */ -#if 0 - /* parent psp segment set to 0 (see RBIL int21/ah=26) */ - p->ps_parent = 0; -#endif - /* default system version for int21/ah=30 */ - p->ps_retdosver = (os_setver_minor << 8) + os_setver_major; + psp _seg *p = MK_SEG_PTR(psp, para); + + fmemcpy(p, MK_SEG_PTR(psp, cur_psp), sizeof(psp)); + + /* initialize all entries and exits */ + p->ps_exit = 0x20cd; /* CP/M-like exit point: */ + /* INT 20 opcode */ + /* CP/M-like entry point: */ + p->ps_farcall = 0x9a; /* FAR CALL opcode... */ + p->ps_reentry = MK_FP(0xf01d,0xfef0); /* ...entry address */ + + /* entry address should point to 0:c0 (INT 30 vector), but + low word of ps_reentry should also contain "size of first + segment for .COM file" while preserving the far call; + in MS-DOS this is F01D:FEF0 --avb */ + + p->ps_unix[0] = 0xcd; /* unix style call: */ + p->ps_unix[1] = 0x21; /* INT 21/RETF opcodes */ + p->ps_unix[2] = 0xcb; + + /* parent-child relationships */ + p->ps_prevpsp = (VFP)-1l; /* previous psp address */ + + p->ps_isv22 = getvec(0x22); /* terminate handler */ + p->ps_isv23 = getvec(0x23); /* break handler */ + p->ps_isv24 = getvec(0x24); /* critical error handler */ + + /* File System parameters */ + p->ps_maxfiles = sizeof p->ps_files; /* size of file table */ + p->ps_filetab = p->ps_files; /* file table address */ } -void child_psp(seg para, seg cur_psp, int psize) +/* !!! cur_psp always equal to cu_psp --avb */ +void child_psp(seg_t para, seg_t cur_psp, seg_t beyond) { - psp FAR *p = MK_FP(para, 0); - psp FAR *q = MK_FP(cur_psp, 0); - int i; + psp _seg *p; new_psp(para, cur_psp); + p = MK_SEG_PTR(psp, para); - /* 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 */ + /* parent-child relationships */ + p->ps_parent = cu_psp; /* parent psp segment */ + + /* Environment and memory useage parameters */ + p->ps_size = beyond; /* segment of memory beyond */ + /* memory allocated to program */ + + /* File System parameters */ + { + psp _seg *q = MK_SEG_PTR(psp, cur_psp); + int i; + /* clone the file table, 0xff=unused */ + for (i = 0; i < sizeof p->ps_files; i++) + p->ps_files[i] = CloneHandle(i) != SUCCESS ? 0xff : q->ps_filetab[i]; + } } -STATIC UWORD patchPSP(UWORD pspseg, UWORD envseg, exec_blk FAR * exb, - BYTE FAR * fnam) +STATIC void makePSP(seg_t pspseg, seg_t envseg, size_t asize, const char FAR * path) { - psp FAR *psp; - mcb FAR *pspmcb; - int i; - BYTE FAR *np; - UWORD fakever; - - 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) + psp _seg *p = MK_SEG_PTR(psp, pspseg); + mcb _seg *pspmcb = MK_SEG_PTR(mcb, FP_SEG(p) - 1); + + /* identify the mcb as this functions' */ + pspmcb->m_psp = FP_SEG(p); + + /* copy the file name less extension into MCB */ { - fmemcpy(&psp->ps_fcb1, exb->exec.fcb_1, 16); - fmemcpy(&psp->ps_fcb2, exb->exec.fcb_2, 16); + const char FAR *np; + int i; + for (np = path;;) /* find program name after path */ + { + char ch = *path; + if (ch == '\0') + break; + path++; + if (ch == ':' || ch == '\\' || ch == '/') + np = path; /* remember position after path */ + } + i = 0; + do /* extract program name */ + { + UBYTE ch = *np; + if (ch == '.' || ch == '\0') + { + pspmcb->m_name[i] = '\0'; + break; + } + if (ch >= 'a' && ch <= 'z') + ch -= (UBYTE)('a' - 'A'); + pspmcb->m_name[i] = ch; /* copy name, without extension */ + i++, np++; + } while (i < 8); } - /* identify the mcb as this functions' */ - pspmcb->m_psp = pspseg; - /* Patch in environment segment, if present, also adjust its MCB */ + setvec(0x22, (intvec)MK_FP(user_r->CS, user_r->IP)); + child_psp(FP_SEG(p), cu_psp, FP_SEG(p) + asize); + + /* Patch in env segment, if present, also adjust its MCB */ if (envseg) { - ((mcb FAR *) MK_FP(envseg, 0))->m_psp = pspseg; + MK_SEG_PTR(mcb, envseg)->m_psp = FP_SEG(p); envseg++; } - psp->ps_environ = envseg; + p->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++) +static void load_transfer(seg_t ds, exec_blk *ep, int mode) +{ + UWORD fcbcode; + psp _seg *p = MK_SEG_PTR(psp, ds); { - pspmcb->m_name[i] = toupper(np[i]); + psp _seg *q = MK_SEG_PTR(psp, cu_psp); + p->ps_parent = FP_SEG(q); + p->ps_prevpsp = q; + q->ps_stack = (BYTE FAR *)user_r; } - if (i < 8) - pspmcb->m_name[i] = '\0'; + user_r->FLAGS &= ~FLG_CARRY; - if ((fakever = SetverGetVersion(setverPtr, np)) != 0) + cu_psp = FP_SEG(p); + /* process dta */ + dta = &p->ps_cmd; + + /* complete the psp by adding the command line and FCBs */ + /* UNDOCUMENTED: MS-DOS copies sizeof(CommandTail) bytes without + checking memory contents and fixing wrong (>7Fh) length field; + FCBs also copied without checking address validness --avb + */ + fmemcpy(&p->ps_fcb1, ep->exec.fcb_1, 12); /* drive+name+ext */ + fmemcpy(&p->ps_fcb2, ep->exec.fcb_2, 12); + fmemcpy(&p->ps_cmd, ep->exec.cmd_line, sizeof(CommandTail)); + + /* AX value to be passed based on FCB values */ + fcbcode = (get_cds1(p->ps_fcb1.fcb_drive) ? 0 : 0xff) | + (get_cds1(p->ps_fcb2.fcb_drive) ? 0 : 0xff00); + +#ifdef DEBUG { - psp->ps_retdosver = fakever; + int i, ctCount=ep->exec.cmd_line->ctCount; + /* display full command line */ + if (ctCount > 127) + { + DebugPrintf(("load_transfer. CommantTail=%d count exceeds 127\n", ctCount)); + ctCount = 127; + } + DebugPrintf(("load_transfer. CommandTail is:\n")); + /* use loop in case tail not '\0' terminated */ + if (ctCount) + { + for (i=0; i < ctCount; i++) + if (ep->exec.cmd_line->ctBuffer[i] == ' ') + DebugPrintf(("")); + else + DebugPrintf(("%c", ep->exec.cmd_line->ctBuffer[i])); + DebugPrintf(("\n")); + } + else + DebugPrintf(("\n")); } +#endif - /* 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)); - + iregs FAR *irp = (iregs FAR *)ep->exec.stack - 1; + /* 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->AX = + irp->BX = fcbcode; + irp->DX = + irp->ES = + irp->DS = FP_SEG(p); + irp->CS = FP_SEG(ep->exec.start_addr); + irp->SI = + irp->IP = FP_OFF(ep->exec.start_addr); + irp->DI = FP_OFF(ep->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!!!"); */ + + /* We should never be here + panic("KERNEL RETURNED!!!"); */ } + /* mode == LOAD */ - exp->exec.stack -= 2; - *((UWORD FAR *)(exp->exec.stack)) = fcbcode; - return SUCCESS; + ep->exec.stack -= sizeof(UWORD); + *(UWORD FAR *)ep->exec.stack = fcbcode; } /* Now find out how many paragraphs are available @@ -462,10 +453,8 @@ STATIC int ExecMemAlloc(UWORD size, seg *para, UWORD *asize) COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) { UWORD mem; - UWORD env, asize = 0; - - { - UWORD com_size; + UWORD env, asize; + UWORD com_size; { ULONG com_size_long = SftGetFsize(fd); /* maximally 64k - 256 bytes stack - @@ -482,26 +471,18 @@ COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) if (mode & 0x80) { mem_access_mode |= 0x80; - DosUmbLink(1); /* link in UMBs */ + DosUmbLink(1); /* link in UMB's */ } - rc = ChildEnv(exp, &env, namep); - #if DEBUG - if (rc != SUCCESS) { ProcDbgPrintf(("Failed to create ChildEnv\n")); } - #endif - /* 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 ((rc = ChildEnv(exp->exec.env_seg, &env, namep)) == SUCCESS) + { + if ((rc = ExecMemLargest(&asize, com_size)) != SUCCESS || + /* Allocate our memory and pass back any errors */ + (rc = ExecMemAlloc(asize, &mem, &asize)) != SUCCESS) + DosMemFree(env); + } if (mode & 0x80) { @@ -513,45 +494,27 @@ COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) if (rc != SUCCESS) return rc; +#ifdef DEBUG + DebugPrintf(("DosComLoader. Loading '%S' at %04x\n", namep, mem)); +#endif ++mem; } - else - mem = exp->load.load_seg; - } - ProcDbgPrintf(("DosComLoader. Loading '%S' at %04x\n", namep, mem)); /* 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); + /* MS DOS always only loads the very first 64KB - sizeof(psp) bytes. + -- 1999/04/21 ska */ /* read everything, but at most 64K - sizeof(PSP) */ - /* lpproj: some device drivers (not exe) are larger than 0xff00bytes... */ - DosRWSft(fd, (mode == OVERLAY) ? 0xfffeU : 0xff00U, sp, XFR_READ); + /* !!! should be added check for reading success --avb */ + DosRWSft(fd, 0xff00, mode == OVERLAY /* memory already allocated */ + ? MK_FP(exp->load.load_seg, 0) + : MK_FP(mem, sizeof(psp)), XFR_READ); DosCloseSft(fd, FALSE); - } - if (mode == OVERLAY) - return SUCCESS; - + if (mode != OVERLAY) { - 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); + makePSP(mem, env, asize, namep); /* set asize to end of segment */ if (asize > 0x1000) asize = 0x1000; @@ -561,91 +524,73 @@ COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) /* 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); + MK_SEG_PTR(psp, mem)->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); + *MK_PTR(UWORD, mem, asize) = 0; + load_transfer(mem, exp, mode); } return SUCCESS; } -VOID return_user(void) +void return_user(void) { - psp FAR *p; psp FAR * q; - REG COUNT i; - iregs FAR *irp; -/* long j;*/ - /* restore parent */ - p = MK_FP(cu_psp, 0); + psp _seg *p = MK_SEG_PTR(psp, cu_psp); /* When process returns - restore the isv */ setvec(0x22, p->ps_isv22); setvec(0x23, p->ps_isv23); setvec(0x24, p->ps_isv24); - abort_progress = -1; - /* 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 (term_type != 3 && p->ps_parent != cu_psp) + if (!tsr) { + REG COUNT i; network_redirector(REM_CLOSEALL); for (i = 0; i < p->ps_maxfiles; i++) { DosClose(i); } FcbCloseAll(); - FreeProcessMem(cu_psp); + FreeProcessMem(FP_SEG(p)); } - cu_psp = p->ps_parent; - q = MK_FP(cu_psp, 0); - - abort_progress = 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 */ + { + iregs FAR *irp = (iregs FAR *)MK_SEG_PTR(psp, cu_psp = p->ps_parent)->ps_stack; + irp->CS = FP_SEG(p->ps_isv22); + irp->IP = FP_OFF(p->ps_isv22); - if (InDOS) - --InDOS; - exec_user((iregs FAR *) q->ps_stack, 0); + if (InDOS) + --InDOS; + exec_user(irp, 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; + UWORD mem, env, start_seg, asize; + 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 + /* First scale the size and remove the offset */ 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; + image_size = ExeHeader.exPages * 32 - 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 */ + /* 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 */ if ((mode & 0x7f) != OVERLAY) { @@ -653,78 +598,51 @@ COUNT DosExeLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) 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; - - /* Some ancient NE programs set exMinAlloc to 0xffff to signify - that they should not be run as normal MZ programs at all. Check - for this and similar conditions. -- 2019/11/05 tkchia */ - if (exe_size < image_size) - return DE_NOMEM; - /* Clone the environement and create a memory arena */ if (mode & 0x80) { - DosUmbLink(1); /* link in UMBs */ + DosUmbLink(1); /* link in UMB's */ mem_access_mode |= 0x80; } - rc = ChildEnv(exp, &env, namep); - #if DEBUG - if (rc != SUCCESS) { ProcDbgPrintf(("Failed to create ChildEnv\n")); } - #endif - - if (rc == SUCCESS) + if ((rc = ChildEnv(exp->exec.env_seg, &env, namep)) == SUCCESS) + { + image_size += sizeof(psp) / 16; /*TE 03/20/01 */ /* 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 ((rc = ExecMemLargest(&asize, image_size + ExeHeader.exMinAlloc)) == SUCCESS) + { + unsigned max_size = image_size + ExeHeader.exMaxAlloc; + /* second test is for overflow (avoiding longs) -- + exMaxAlloc can be high */ + if (max_size > asize || max_size < image_size || + /* 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 */ + (ExeHeader.exMinAlloc | ExeHeader.exMaxAlloc) == 0) + max_size = asize; + /* Allocate our memory and pass back any errors */ + rc = ExecMemAlloc(max_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 */ - ProcDbgPrintf(("DosExeLoader. Loading '%S' at %04x\n", namep, mem)); - +#ifdef DEBUG + DebugPrintf(("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 */ @@ -733,75 +651,57 @@ COUNT DosExeLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) { if (mode != OVERLAY) { - DosMemFree(--mem); + DosMemFree(mem); DosMemFree(env); } return DE_INVLDDATA; } /* create the start seg for later computations */ - start_seg = mem; - exe_size = image_size; + start_seg = exp->load.load_seg; 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); - + start_seg = mem + 1 + sizeof(psp) / 16; + if ((ExeHeader.exMinAlloc | ExeHeader.exMaxAlloc) == 0) /* then the image should be placed as high as possible */ - start_seg += mp->m_size - image_size; - } + start_seg += MK_SEG_PTR(const mcb, mem)->m_size - image_size; + image_size -= sizeof(psp) / 16; } - } /* read in the image in 32256 chunks */ { - int nBytesRead, toRead = CHUNK; - seg sp = start_seg; - - while (1) + seg_t sp = start_seg; + do { - 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) + int toRead = CHUNK; + if (image_size < CHUNK/16) + { + toRead = image_size*16; + image_size = CHUNK/16; + } + if ((int)DosRWSft(fd, toRead, MK_FP(sp, 0), XFR_READ) < toRead) break; sp += CHUNK/16; - exe_size -= CHUNK/16; - } + } while (image_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++) + /* relocate the image for new segment */ + SftSeek(fd, ExeHeader.exRelocTable, 0); + { + unsigned i; + for (i = ExeHeader.exRelocItems; i; i--) { - if (DosRWSft - (fd, sizeof(reloc), (VOID FAR *) & reloc[0], XFR_READ) != sizeof(reloc)) + UWORD reloc[2]; + if (DosRWSft(fd, sizeof reloc, reloc, XFR_READ) != sizeof reloc) { if (mode != OVERLAY) { - DosMemFree(--mem); + 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; - } + *MK_PTR(seg_t, reloc[1] + start_seg, reloc[0]) += start_seg; } } @@ -809,24 +709,17 @@ COUNT DosExeLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd) DosCloseSft(fd, FALSE); /* exit here for overlay */ - if (mode == OVERLAY) - return SUCCESS; - + if (mode != OVERLAY) { - 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); + mem++; + makePSP(mem, env, asize, 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); + load_transfer(mem, exp, mode); } return SUCCESS; } @@ -854,7 +747,7 @@ COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp) return DE_FILENOTFND; } - rc = (int)DosRWSft(fd, sizeof(exe_header), (BYTE FAR *)&ExeHeader, XFR_READ); + rc = (int)DosRWSft(fd, sizeof(exe_header), &ExeHeader, XFR_READ); if (rc == sizeof(exe_header) && (ExeHeader.exSignature == MAGIC || ExeHeader.exSignature == OLD_MAGIC)) @@ -864,8 +757,6 @@ COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp) else if (rc != 0) { rc = DosComLoader(lp, &TempExeBlock, mode, fd); - } else { - rc = DE_INVLDFMT; } DosCloseSft(fd, FALSE); @@ -879,44 +770,65 @@ COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp) #include "config.h" /* config structure definition */ /* start process 0 (the shell) */ -VOID ASMCFUNC P_0(struct config FAR *Config) +void ASMCFUNC P_0(const struct config FAR *); +#ifdef __WATCOMC__ +# pragma aux (cdecl) P_0 aborts +#endif + +void ASMCFUNC P_0(const 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! */ + int mode = Config->cfgP_0_startmode; + + const char FAR *p = MK_PTR(const char, FP_SEG(Config), Config->cfgShell); + PStr endp = Shell; + while ((*endp = *p++) != '\0' && + ++endp < Shell + sizeofShell - 4); /* 4 for 0,ctCount and "\r\0" */ + + 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; + PStr tailp = Shell - 1; + + *endp = '\r', endp[1] = '\0'; /* terminate command line */ + endp += 2; + + /* find end of command name */ + do tailp++; while ((UBYTE)*tailp > ' ' && *tailp != '/'); + + /* shift tail to right by 2 to make room for '\0' and ctCount */ + { + PStr p = endp; + do + { + p--; + p[2] = p[0]; + } while (p > tailp); + } + + /* terminate name */ + *tailp = '\0'; + + /* init length of command line tail (ctCount field) */ + tailp++; + *tailp = (UBYTE)(endp - tailp - 1); /* without "\r\0" */ + + { + exec_blk exb; + exb.exec.env_seg = DOS_PSP + 8; + exb.exec.cmd_line = (CommandTail *)tailp; + /*exb.exec.fcb_1 = exb.exec.fcb_2 = NULL;*/ /* unimportant */ + #ifdef DEBUG - DebugPrintf(("Process 0 starting: %s%s\n\n", Shell, tailp + 2)); + DebugPrintf(("Process 0 starting: %s%s\n\n", Shell, tailp + 1)); #endif - res_DosExec(mode, &exb, Shell); - put_string("Bad or missing Command Interpreter: "); /* failure _or_ exit */ + res_DosExec(mode, &exb, Shell); + } + + /* failure or exit */ + put_string("\nBad or missing Command Interpreter\n" + "Enter the full shell command line:\n"); 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 */ + *endp = '\n'; /* replace "\r\0" by "\n\0" */ + put_string(++tailp); + endp = Shell + res_read(STDIN, Shell, sizeofShell) - 2; /* exclude "\r\n" */ } } diff --git a/kernel/tci.cfg b/kernel/tci.cfg new file mode 100644 index 00000000..946e7946 --- /dev/null +++ b/kernel/tci.cfg @@ -0,0 +1,7 @@ +-zCINIT_TEXT +-zRID +-zTID +-zSI_GROUP +-zDIB +-zBIB +-zGI_GROUP diff --git a/kernel/turboc.cfg b/kernel/turboc.cfg index f07a6c1c..413e8f77 100644 --- a/kernel/turboc.cfg +++ b/kernel/turboc.cfg @@ -1,15 +1,11 @@ --f- --ff- --O --Z -d +-f- -k- --vi- --wpro --weas --wpre --w --g1 --I..\hdr +-O -Z -p --v- -I. -D__STDC__=0 -DKERNEL -DI86 -DPROTO -DASMSUPT +-v- +-w -g1 +-I..\hdr +-DI86 + +-zCHMA_TEXT diff --git a/kernel/wc.cfg b/kernel/wc.cfg new file mode 100644 index 00000000..53e3092a --- /dev/null +++ b/kernel/wc.cfg @@ -0,0 +1,9 @@ +-e5 -we -wx +-j +-os -s +-r -zgf -zff +-zq -zl -zp1 +-d1 +-I..\hdr + +-ntHMA_TEXT diff --git a/kernel/wci.cfg b/kernel/wci.cfg new file mode 100644 index 00000000..0559116a --- /dev/null +++ b/kernel/wci.cfg @@ -0,0 +1,11 @@ +-e5 -we -wx +-j +-os -s +-r -zgf -zff +-zq -zl -zp1 +-d1 +-I..\hdr + +-ntINIT_TEXT +-gTGROUP +-ndI diff --git a/lib/makefile b/lib/makefile index c9a4ce68..9dbb4de7 100644 --- a/lib/makefile +++ b/lib/makefile @@ -1,24 +1,26 @@ # # makefile for libm.lib # -# $Id: makefile 688 2003-09-15 10:46:24Z bartoldeman $ +# $Id$ # - !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 +all: libm.lib +libm.lib: $(CLIB) $(DEPENDS) + -$(RM) $*.lib + $(LIBUTIL) $(CLIB) $(MATH_EXTRACT)$(LIBTERM) + $(COMSPEC) /c for %i in (*.obj) do ..\utils\patchobj CODE=LCODE %i + $(LIBUTIL) $* $(MATH_INSERT)$(LIBTERM) + -$(RM) *.obj -clobber: clean - -$(RM) status.me +######################################################################## clean: - -$(RM) *.obj *.bak libm.lib + -$(RM) *.bak *.cod *.crf *.err *.las *.lst *.map *.obj *.xrf +clobber: clean + -$(RM) libm.lib status.me diff --git a/makefile b/makefile index fd3e58bd..2cc1e694 100644 --- a/makefile +++ b/makefile @@ -1,16 +1,5 @@ -# 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" -# On Windows, use config.mak, and -# "mingw32-make all", "mingw32-make clean", or "mingw32-make clobber" - -default: - @echo On DOS, please type build, clean, or clobber. - @echo On Linux, please type make all, make clean, or make clobber. - @echo On Windows, please type mingw32-make all, mingw32-make clean, or - @echo mingw32-make clobber. - -build: +#just in case somebody likes make better than build... +all: build bin\kwc8616.sys: @@ -19,130 +8,42 @@ bin\kwc8616.sys: bin\kwc8632.sys: build -r wc 86 fat32 -# use as follows: wmake -ms zip VERSION=2029 +#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 + zip -9 -r -k source/ke$(VERSION)src.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 +BINLIST1 = doc bin/kernel.sys bin/sys.com bin/command.com bin/config.sys +BINLIST2 = 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 docs\*.txt doc + copy docs\*.cvs doc + copy docs\copying doc + copy docs\*.lsm doc + del doc\build.txt + del doc\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 + zip -9 -r -k ../ke$(VERSION)_16.zip $(BINLIST1) + zip -9 -r -k ../ke$(VERSION)_16.zip $(BINLIST2) + utils\rmfiles doc\*.txt doc\*.cvs doc\*.lsm doc\copying 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 docs\*.txt doc + copy docs\*.cvs doc + copy docs\copying doc + copy docs\*.lsm doc + del doc\build.txt + del doc\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 + zip -9 -r -k ../ke$(VERSION)_32.zip $(BINLIST1) + zip -9 -r -k ../ke$(VERSION)_32.zip $(BINLIST2) + utils\rmfiles doc\*.txt doc\*.cvs doc\*.lsm doc\copying rmdir doc zip: zip_src zipfat16 zipfat32 -#Linux part -#defaults: override using config.mak -export - -ifeq ($(OS),Windows_NT) -BUILDENV ?= windows -DIRSEP=\ -CP=copy -else -BUILDENV ?= linux -DIRSEP=/ -CP=cp -endif - -ifeq ($(BUILDENV),windows) -COMPILER=owwin -TEST_F=type >nul 2>nul -TOUCH=wtouch -else -COMPILER=owlinux -TEST_F=test -f -TOUCH=touch -ifndef WATCOM - WATCOM=$(HOME)/watcom - PATH:=$(WATCOM)/binl:$(PATH) -endif -endif - -XCPU=86 -XFAT=32 -XUPX=upx --8086 --best -XNASM=nasm -ifeq ($(COMPILER),gcc) -MAKE=make -MAKEADJUST=for i in utils lib drivers boot sys kernel setver; do sed 's@!include "\(.*\)"@include ../mkfiles/gcc.mak@' < $$i/makefile > $$i/GNUmakefile; done -MAKEREMOVE=for i in utils lib drivers boot sys kernel setver; do rm -f $$i/GNUmakefile; done -XLINK=ia16-elf-gcc -else -MAKE=wmake -ms -h -MAKEADJUST= -MAKEREMOVE= -XLINK=wlink -endif -#ALLCFLAGS=-DDEBUG - --include config.mak -ifdef XUPX - UPXOPT=-U -endif - -all: - $(MAKEADJUST) - 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 - cd country && $(MAKE) DIRSEP=$(DIRSEP) CP=$(CP) production - cd setver && $(MAKE) production - $(MAKEREMOVE) - -clean: - $(MAKEADJUST) - 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 country && $(MAKE) clean - cd setver && $(MAKE) clean - $(MAKEREMOVE) - -clobber: - $(MAKEADJUST) - 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 country && $(MAKE) clobber - cd setver && $(MAKE) clobber - $(MAKEREMOVE) diff --git a/mkfiles/bc.mak b/mkfiles/bc.mak new file mode 100644 index 00000000..51d0cbd5 --- /dev/null +++ b/mkfiles/bc.mak @@ -0,0 +1,10 @@ +# +# BC.MAK - kernel compiler options for Borland C++ +# + +!include "..\mkfiles\tcpp.mak" + +TARGET=KBC + +CC=$(BINPATH)\bcc -c +CL=$(BINPATH)\bcc diff --git a/mkfiles/bc3.mak b/mkfiles/bc3.mak deleted file mode 100644 index 833317a9..00000000 --- a/mkfiles/bc3.mak +++ /dev/null @@ -1,53 +0,0 @@ -# -# BC3.MAK - kernel copiler options for Borland C 3.1 -# - -# Use these for Borland C 3.1 - -COMPILERPATH=$(BC3_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=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/bc5.mak b/mkfiles/bc5.mak deleted file mode 100644 index 559438e6..00000000 --- a/mkfiles/bc5.mak +++ /dev/null @@ -1,53 +0,0 @@ -# -# 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/gcc.mak b/mkfiles/gcc.mak deleted file mode 100644 index abc09de5..00000000 --- a/mkfiles/gcc.mak +++ /dev/null @@ -1,84 +0,0 @@ -# -# GCC.MAK - kernel compiler options for ia16-elf-gcc -# - -#********************************************************************** -#* TARGET : we create a %TARGET%.sys file -#* TARGETOPT : options, handled down to the compiler -#********************************************************************** - -TARGET=kgc$(XCPU)$(XFAT) -TARGETOPT=-march=i8086 - -ifeq ($(XCPU),186) -TARGETOPT=march=i80186 -ALLCFLAGS+=-DI186 -endif -ifeq ($(XCPU),386) -TARGETOPT=-march=i80286 -ALLCFLAGS+=-DI386 -endif - -ifeq ($(XFAT),32) -ALLCFLAGS+=-DWITHFAT32 -NASMFLAGS+=-DWITHFAT32 -endif - -NASM=$(XNASM) -NASMFLAGS+=-i../hdr/ -DXCPU=$(XCPU) -felf - -CC=ia16-elf-gcc -c -CL=ia16-elf-gcc -INCLUDEPATH=. - -LIBUTIL=ar crs -LIBPLUS= -LIBTERM= - -TINY=-mcmodel=tiny -CFLAGST=-Os -fno-strict-aliasing -fpack-struct -fcall-used-es -Wno-pointer-to-int-cast -Wno-pragmas -Wno-array-bounds -Werror -o $@ -CFLAGSC= - -# -# heavy stuff - building -# -# -mcmodel=small small memory model (small code/small data) -# -Os -> favor code size over execution time in optimizations -# -fno-strict-aliasing don't assume strict aliasing rules -# -fleading-underscore underscores leading field for DOS compiler compat -# -fno-common no "common" variables, just BSS for uninitialized data -# -fpack-struct pack structure members -# -ffreestanding don't assume any headers -# -fcall-used-es es clobbered in function calls -# -mrtd use stdcall calling convention -# -Wno-pointer-to-int-cast do not warn about FP_OFF -# -Wno-pragmas do not warn about #pragma pack -# -Werror treat all warnings as errors -# -mfar-function-if-far-return-type treat `int __far f ();' as a far function - -ALLCFLAGS+=-I../hdr $(TARGETOPT) -mcmodel=small -fleading-underscore -fno-common -fpack-struct -ffreestanding -fcall-used-es -mrtd -Wno-pointer-to-int-cast -Wno-pragmas -Werror -Os -fno-strict-aliasing -mfar-function-if-far-return-type -INITCFLAGS=$(ALLCFLAGS) -o $@ -CFLAGS=$(ALLCFLAGS) -o $@ - -DIRSEP=/ -RM=rm -f -CP=cp -ECHOTO=echo>> -ifeq ($(LOADSEG)0, 0) -LOADSEG=0x60 -endif - -INITPATCH=ia16-elf-objcopy --redefine-sym ___umodsi3=_init_umodsi3 --redefine-sym ___udivsi3=_init_udivsi3 --redefine-sym ___ashlsi3=_init_ashlsi3 --redefine-sym ___lshrsi3=_init_lshrsi3 --redefine-sym _printf=_init_printf --redefine-sym _sprintf=_init_sprintf --redefine-sym _execrh=_init_execrh --redefine-sym _memcpy=_init_memcpy --redefine-sym _fmemcpy=_init_fmemcpy --redefine-sym _fmemset=_init_fmemset --redefine-sym _fmemcmp=_init_fmemcmp --redefine-sym _memcmp=_init_memcmp --redefine-sym _memset=_init_memset --redefine-sym _strchr=_init_strchr --redefine-sym _strcpy=_init_strcpy --redefine-sym _fstrcpy=_init_fstrcpy --redefine-sym _strlen=_init_strlen --redefine-sym _fstrlen=_init_fstrlen --redefine-sym _open=_init_DosOpen -CLDEF=1 -CLT=gcc -Wall -I../hdr -o $@ -CLC=$(CLT) -LINK=$(XLINK) -Tkernel.ld -nostdlib -Wl,-Map,kernel.map -o kernel.exe $(OBJS) -Wl,--whole-archive ../drivers/device.lib -Wl,--no-whole-archive \# - -.SUFFIXES: .obj .asm - -# *Implicit Rules* -.asm.obj : - $(NASM) -D$(COMPILER) $(NASMFLAGS) -o $@ $< - -.c.obj : - $(CC) $(CFLAGS) $*.c diff --git a/mkfiles/generic.mak b/mkfiles/generic.mak index e0c0487f..9fe65f1a 100644 --- a/mkfiles/generic.mak +++ b/mkfiles/generic.mak @@ -1,58 +1,63 @@ # These are generic definitions -#********************************************************************** -#* TARGET : we create a %TARGET%.sys file -#* TARGETOPT : options, handled down to the compiler -#********************************************************************** - -TARGETOPT=-1- +# TARGET : we create a $(TARGET).sys file +!if $(XCPU)0 == 0 +XCPU=86 +!endif +CPUOPT= !if $(XCPU) == 186 -TARGETOPT=-1 -ALLCFLAGS=$(ALLCFLAGS) -DI186 +CPUOPT=-1 !endif !if $(XCPU) == 386 -TARGETOPT=-3 -ALLCFLAGS=$(ALLCFLAGS) -DI386 +CPUOPT=-3 +!endif +# extension, if compiler supports it, specify compiler switch in XCPU_EX and set XCPU to 386 +!if $(XCPU_EX)0 != 0 +XCPU=386 +CPUOPT=$(XCPU_EX) !endif +!if $(XFAT)0 == 0 +XFAT=32 +!endif !if $(XFAT) == 32 -ALLCFLAGS=$(ALLCFLAGS) -DWITHFAT32 -NASMFLAGS=$(NASMFLAGS) -DWITHFAT32 +ALLCFLAGS=-DWITHFAT32 $(ALLCFLAGS) +NASMFLAGS=-DWITHFAT32 $(NASMFLAGS) !endif -NASM=$(XNASM) -NASMFLAGS = $(NASMFLAGS) -i../hdr/ -DXCPU=$(XCPU) - -LINK=$(XLINK) +NASMFLAGS=-fobj -i../hdr/ -D$(COMPILER) -DXCPU=$(XCPU) $(NASMFLAGS) +#BINPATH=$(BASE)\bin +INCLUDEPATH=$(BASE)\include +LIBPATH=$(BASE)\lib 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 +!include "..\mkfiles\$(COMPILER).mak" TARGET=$(TARGET)$(XCPU)$(XFAT) +INITCFLAGS=$(INITCFLAGS) $(ALLCFLAGS) +CFLAGS=$(CFLAGS) $(ALLCFLAGS) +RM=..\utils\rmfiles +DEPENDS=makefile ..\*.bat ..\mkfiles\*.* + +# Implicit Rules ####################################################### + +.asm.obj: + $(NASM) $(NASMFLAGS) $< -.asm.obj : - $(NASM) -D$(COMPILER) -f obj $(NASMFLAGS) $*.asm +.c.obj: + $(CC) $(CFLAGS) $< -# *Implicit Rules* -.c.obj : - $(CC) $(CFLAGS) $*.c +.cpp.obj: + $(CC) $(CFLAGS) $< -.cpp.obj : - $(CC) $(CFLAGS) $*.cpp +.c.com: + $(CL) $(CFLAGST) $< +.c.exe: + $(CL) $(CFLAGSC) $< diff --git a/mkfiles/msc.mak b/mkfiles/msc.mak new file mode 100644 index 00000000..a3044e14 --- /dev/null +++ b/mkfiles/msc.mak @@ -0,0 +1,31 @@ +# +# MSC.MAK - kernel compiler options for MS VC 1.5x (MS CL 8.x) +# + +TARGET=KMS + +CC=$(BINPATH)\cl -batch -nologo -c +CL=$(BINPATH)\cl -batch -nologo + +# used for building the library + +CLIB=$(LIBPATH)\slibce.lib +MATH_EXTRACT=*aflmul *aFlshl *aFNauldi *aFulrem *aFulshr *aFuldiv *aFlrem *aFldiv *aFNaulsh +MATH_INSERT =+aflmul +aFlshl +aFNauldi +aFulrem +aFulshr +aFuldiv +aFlrem +aFldiv +aFNaulsh + +# + +!if $(XCPU) == 186 +CPUOPT=-G1 +!endif +!if $(XCPU) == 386 +CPUOPT=-G3 +!endif + +ALLCFLAGS=@msc.cfg -I$(INCLUDEPATH) $(CPUOPT) $(ALLCFLAGS) +INITCFLAGS=-NTINIT_TEXT +CFLAGS =-NTHMA_TEXT +INITPATCH=..\utils\patchobj _DATA=IDATA DATA=ID BSS=ID DGROUP=I_GROUP CONST=IC + +CFLAGST=-I..\hdr -I$(INCLUDEPATH) /Fm /AT /Os /Zp1 +CFLAGSC=-I..\hdr -I$(INCLUDEPATH) /Fm /AL /Os /Zp1 diff --git a/mkfiles/mscl8.mak b/mkfiles/mscl8.mak deleted file mode 100644 index 5a75545c..00000000 --- a/mkfiles/mscl8.mak +++ /dev/null @@ -1,47 +0,0 @@ -# -# 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 *aFNaulsh *aFNauldi *aFulrem *aFulshr *aFuldiv *aFlrem *aFldiv -MATH_INSERT= +aflmul +aFlshl +aFNaulsh +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 deleted file mode 100644 index 0cf9f789..00000000 --- a/mkfiles/owlinux.mak +++ /dev/null @@ -1,19 +0,0 @@ -# -# WATCOM.MAK - kernel compiler options for Open Watcom on Linux (cross-compile) -# - -# Get definitions from watcom.mak, then override -include "../mkfiles/watcom.mak" - -DIRSEP=/ -CC=$(CC) -fo=.obj -CL=$(CL) -fo=.obj -INCLUDEPATH=$(COMPILERPATH)/h -RM=rm -f -CP=cp -ECHOTO=echo>> -INITPATCH=@echo > /dev/null -CLDEF=1 -CLT=wcl386 -zq -fo=.obj -bcl=linux -I../hdr -fe=$@ -I$(COMPILERPATH)/lh -CLC=$(CLT) -XLINK=$(XLINK) debug all format dos opt quiet,symfile,map,statics,verbose F { $(OBJS) } L ../lib/device.lib N kernel.exe $# diff --git a/mkfiles/owwin.mak b/mkfiles/owwin.mak deleted file mode 100644 index a0db6db4..00000000 --- a/mkfiles/owwin.mak +++ /dev/null @@ -1,20 +0,0 @@ -# -# WATCOM.MAK - kernel compiler options for Open Watcom on Windows (cross-compile) -# - -# Get definitions from watcom.mak, then override -include "../mkfiles/watcom.mak" - -DIRSEP=\ - -INCLUDEPATH=$(COMPILERPATH)\h -#RM=del 2>nul -#CP=copy -#ECHOTO=echo>> -#INITPATCH=@echo > nul -CLDEF=1 -CLT=wcl386 -zq -bcl=nt -I..\hdr -fe=$@ -I$(COMPILERPATH)\h -I$(COMPILERPATH)\h\nt -CLC=$(CLT) -NASMFLAGS=-DWATCOM $(NASMFLAGS) -#linker arguments are passed via response file, so don't modify XLINK -#XLINK=$(XLINK) debug all format dos opt quiet,symfile,map,statics,verbose F { $(OBJS) } L ..$(DIRSEP)lib$(DIRSEP)device.lib N kernel.exe $# diff --git a/mkfiles/tc.mak b/mkfiles/tc.mak new file mode 100644 index 00000000..d8bc5c04 --- /dev/null +++ b/mkfiles/tc.mak @@ -0,0 +1,14 @@ +# +# TC.MAK - kernel compiler options for Turbo C 2.01 +# + +!include "..\mkfiles\tcpp.mak" + +TARGET=KTC + +MATH_EXTRACT=*LDIV *LXMUL *LURSH *LLSH *LRSH +MATH_INSERT =+LDIV +LXMUL +LURSH +LLSH +LRSH + +# TCC doesn't support responce file + +INITCFLAGS=-zCINIT_TEXT -zRID -zTID -zSI_GROUP -zDIB -zBIB -zGI_GROUP diff --git a/mkfiles/tc2.mak b/mkfiles/tc2.mak deleted file mode 100644 index e9427d95..00000000 --- a/mkfiles/tc2.mak +++ /dev/null @@ -1,53 +0,0 @@ -# -# 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 deleted file mode 100644 index 781a327f..00000000 --- a/mkfiles/tc3.mak +++ /dev/null @@ -1,53 +0,0 @@ -# -# 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/tcpp.mak b/mkfiles/tcpp.mak new file mode 100644 index 00000000..643fd151 --- /dev/null +++ b/mkfiles/tcpp.mak @@ -0,0 +1,42 @@ +# +# TCPP.MAK - kernel compiler options for Turbo C++ 1.01 +# + +TARGET=KTP + +CC=$(BINPATH)\tcc -c +CL=$(BINPATH)\tcc + +# used for building the library + +CLIB=$(LIBPATH)\cs.lib +MATH_EXTRACT=*H_LDIV *H_LLSH *H_LURSH *F_LXMUL +MATH_INSERT =+H_LDIV +H_LLSH +H_LURSH +F_LXMUL + +# +# Compiler options for Turbo/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" + +# +# Common options specified in turboc.cfg instead ALLCFLAGS +# + +ALLCFLAGS=-I..\hdr;$(INCLUDEPATH) $(CPUOPT) $(ALLCFLAGS) +INITCFLAGS=@tci.cfg + +CFLAGST=-I..\hdr;$(INCLUDEPATH) -L$(LIBPATH) -mt -lt +CFLAGSC=-I..\hdr;$(INCLUDEPATH) -L$(LIBPATH) -mc diff --git a/mkfiles/tcpp3.mak b/mkfiles/tcpp3.mak new file mode 100644 index 00000000..1df46c6b --- /dev/null +++ b/mkfiles/tcpp3.mak @@ -0,0 +1,7 @@ +# +# TCPP3.MAK - kernel compiler options for Turbo C++ 3.0 +# + +!include "..\mkfiles\tcpp.mak" + +TARGET=KT3 diff --git a/mkfiles/turbocpp.mak b/mkfiles/turbocpp.mak deleted file mode 100644 index 8bedf47d..00000000 --- a/mkfiles/turbocpp.mak +++ /dev/null @@ -1,53 +0,0 @@ -# -# 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 index e901e271..772593bc 100644 --- a/mkfiles/watcom.mak +++ b/mkfiles/watcom.mak @@ -1,67 +1,50 @@ # -# WATCOM.MAK - kernel copiler options for WATCOM C 11.0c +# WATCOM.MAK - kernel compiler options for WATCOM C/OpenWatcom # -# Use these for WATCOM 11.0c -COMPILERPATH=$(WATCOM) -CC=*wcc -zq -CL=wcl -zq -INCLUDEPATH=$(COMPILERPATH)\H -INCLUDE=$(COMPILERPATH)\h -EDPATH=$(COMPILERPATH)\EDDAT +TARGET=KWC -!if $(XCPU) != 186 -!if $(XCPU) != 386 -TARGETOPT=-0 -!endif -!endif +INCLUDEPATH=$(BASE)\h +LIBPATH=$(BASE)\lib286 -LIBPATH=$(COMPILERPATH)\lib286 -LIBUTIL=wlib -q -LIBPLUS= -LIBTERM= - -TINY=-mt -CFLAGST=-zp1-os-s-we-e3-wx-bt=DOS -CFLAGSC=-mc-zp1-os-s-we-e3-wx-bt=DOS - -TARGET=kwc +CC=$(BINPATH)\wcc +CL=$(BINPATH)\wcl # used for building the library -CLIB=$(COMPILERPATH)\lib286\dos\clibm.lib - -# we use our own ones, which override these ones when linking. -# - -MATH_EXTRACT= -MATH_INSERT= - +CLIB=$(LIBPATH)\dos\clibm.lib +MATH_EXTRACT=*i4m +MATH_INSERT =+i4m # -# heavy stuff - building +# Compiler options for Watcom +# --------------------------- # # -e= set limit on number of error messages +# -w= set warning level number +# -we treat all warnings as errors +# -zq operate quietly +# +# -j change char default from unsigned to signed # -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 +# -s remove stack overflow checks # -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 +# -zu SS!=DGROUP # -# -3 optimization for 386 - given in CONFIG.MAK, not here +# -3 optimization for 386 - given in $(CPUOPT) +# -g= set code group name +# -nc= set code class name +# -nd= set data segment name +# -nm= set module name +# -nt= set name of text segment # -ALLCFLAGS=-I..$(DIRSEP)hdr $(TARGETOPT) $(ALLCFLAGS) -os-s-e5-j-zl-zp1-wx-we-zgf-zff-r -INITCFLAGS=$(ALLCFLAGS)-ntINIT_TEXT-gTGROUP-ndI -CFLAGS=$(ALLCFLAGS)-ntHMA_TEXT +ALLCFLAGS=-I$(INCLUDEPATH) $(CPUOPT)$(ALLCFLAGS) +INITCFLAGS=@wci.cfg +CFLAGS =@wc.cfg +CFLAGST=-I..\hdr;$(INCLUDEPATH) -e3-we-wx-zq-os-s-zp1-mt +CFLAGSC=-I..\hdr;$(INCLUDEPATH) -e3-we-wx-zq-os-s-zp1-mc diff --git a/setver/makefile b/setver/makefile deleted file mode 100644 index 6a2200b2..00000000 --- a/setver/makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# makefile for setver.sys -# - -!include "../mkfiles/generic.mak" - - -production: setver.sys - -setver.sys: setver.asm - $(NASM) -o ..$(DIRSEP)bin$(DIRSEP)setver.sys setver.asm - -clobber: clean - -clean: - -$(RM) *.obj *.map *.lst *.err - diff --git a/setver/setver.asm b/setver/setver.asm deleted file mode 100644 index fd16e067..00000000 --- a/setver/setver.asm +++ /dev/null @@ -1,82 +0,0 @@ -; -; Initially written by Ricardo Hanke -; Released under the terms of the GNU General Public License. -; See the file 'COPYING' in the main directory for details. -; -; This driver loads the list of special programs into memory. -; - -section .text - - -COMMAND equ 2 -STATUS equ 3 -DRIVEREND equ 14 - -FAKETABLE equ 37h - - -header dw -1, -1 - dw 1000000000000000b - dw strategy - dw interrupt - db "SETVERXX" - - dw signature - -paramblock dd 0 - - -strategy: mov [cs:paramblock + 0], bx - mov [cs:paramblock + 2], es - retf - - -interrupt: push ax - push bx - push di - push es - pushf - - les di, [paramblock] - mov bl, [es:di + COMMAND] - cmp bl, 0 - jne error - - mov ax, table - add ax, [length] - - mov word [es:di + DRIVEREND + 0], ax - mov word [es:di + DRIVEREND + 2], cs - - mov ah, 52h - int 21h - - mov word [es:bx + FAKETABLE + 0], table - mov word [es:bx + FAKETABLE + 2], cs - - xor ax, ax - jmp exit - -error: mov ax, 8003h - -exit: or ax, 0100h - mov [es:di + STATUS], ax - - popf - pop es - pop di - pop bx - pop ax - - retf - - -signature db 'SDIR' -length dw 1 - -table: - ;db 11, "SHOWVER.EXE", 5, 00 - ;db 12, "BUGGYPRG.EXE", 3, 31 - - db 0 diff --git a/share b/share deleted file mode 160000 index 47f3d425..00000000 --- a/share +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 47f3d42527256fa46a00fe84cdb46d90f2e66f50 diff --git a/share/share.c b/share/share.c new file mode 100644 index 00000000..46777d4d --- /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 00000000..dbb7a1eb --- /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 index d752327b..eb70f4a1 100644 --- a/sys/bin2c.c +++ b/sys/bin2c.c @@ -9,7 +9,7 @@ int main(int argc, char **argv) if (argc < 4) { fprintf(stderr, - "Usage: bin2c \n"); + "Usage: bin2c \n"); return 1; } diff --git a/sys/fdkrncfg.c b/sys/fdkrncfg.c index c35a0afa..0f37481e 100644 --- a/sys/fdkrncfg.c +++ b/sys/fdkrncfg.c @@ -13,25 +13,21 @@ * merged into SYS by tom ehlert * ***************************************************************************/ -char VERSION[] = "v1.05"; +/* 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 -#ifndef __GNUC__ #include -#endif #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, ...); - -#if defined(__WATCOMC__) +extern int VA_CDECL printf(const char FAR * fmt, ...); +extern int VA_CDECL sprintf(char FAR * buff, const char FAR * fmt, ...); + +#ifdef __WATCOMC__ unsigned _dos_close(int handle); #define close _dos_close #define SEEK_SET 0 @@ -43,20 +39,12 @@ 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]; + parm [bx] [dx cx] [ax] \ + value [dx ax]; -#elif defined(__GNUC__) -#include -#include -#define memicmp strncasecmp -#define O_BINARY 0 #else #include -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -/* #include */ +#include #endif #define FAR far @@ -93,10 +81,7 @@ void showUsage(void) 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" - " CheckDebugger=0|1|2\n" - " Verbose=0|1\n" - ); + " BootHarddiskSeconds=0|seconds to wait\n"); } /* simply reads in current configuration values, exiting program @@ -134,22 +119,6 @@ int readConfigSettings(int kfile, char *kfilename, KernelConfig * cfg) exit(1); } - /* check if config settings old UPX header and adjust - original UPX header incorrectly set size value to 19, - a while back this was fixed and if we ran across a kernel - with the wrong value we would update it to 14. Another bug, - the correct value is 6 (possibly 5 if kernel old enough, but - we can safely ignore the 'u' value for BootHarddiskSeconds - as it won't be used if the kernel doesn't support that option. - The "corrected size" incorrectly included the 8 bytes of the CONFIG - header ['C','O','N','F','I','G' + WORD ConfigSize ]. - 14 was never valid for a released kernel, so we can safely - assume 13 is valid, 15-18 is valid, and >= 20 valid but - that a value of 14 or 19 should really be 6. - */ - if ((cfg->ConfigSize == 19) || (cfg->ConfigSize == 14)) - cfg->ConfigSize = 6; /* ignore 'nused87654321' */ - return 1; } @@ -175,51 +144,38 @@ void displayConfigSettings(KernelConfig * cfg) { /* print known options and current value - only if available */ - /* show kernel version if available, read only, no option to modify */ - if (cfg->ConfigSize >= 12) - { - printf - ("%s kernel %s (build %d.%d OEM:%02X)\n", - (cfg->Version_OemID == 0xFD)?"FreeDOS":"DOS-C", - cfg->Version_Release?"Nightly":"Release", - cfg->Version_Major, - cfg->Version_Revision, - cfg->Version_OemID - ); - } - if (cfg->ConfigSize >= 1) { printf - ("DLASORT=0x%02X Sort disks by drive order: *0=no, 1=yes\n", + ("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", + ("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", + ("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", + ("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", + ("GLOBALENABLELBASUPPORT=0x%02X Enable LBA support: *1=yes, 0=no\n", cfg->GlobalEnableLBAsupport); } @@ -230,27 +186,6 @@ void displayConfigSettings(KernelConfig * cfg) cfg->BootHarddiskSeconds); } - if (cfg->ConfigSize >= 13) - { - printf - ("CheckDebugger=%d : *0=no, 1=check, 2=assume\n", - cfg->CheckDebugger); - } - - if (cfg->ConfigSize >= 14) - { - printf - ("Verbose=%d : -1=quiet, *0=normal, 1=verbose\n", - cfg->Verbose); - } - - if (cfg->ConfigSize >= 15) - { - printf - ("PartitionMode=0x%02X How GPT or hybrid GPT/MBR partitions used\n", - cfg->PartitionMode); - } - #if 0 /* we assume that SYS is as current as the kernel */ /* Print value any options added that are unknown as hex dump */ @@ -409,7 +344,6 @@ 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 readonly = 0; /* flag indicates kernel was opened read-only */ int argstart, i; char *cptr; char *argptr; @@ -417,7 +351,7 @@ int FDKrnConfigMain(int argc, char **argv) printf("FreeDOS Kernel Configuration %s\n", VERSION); /* 1st go through and just process arguments (help/filename/etc) */ - for (i = 1; i < argc; i++) + for (i = 2; i < argc; i++) { argptr = argv[i]; @@ -438,10 +372,6 @@ int FDKrnConfigMain(int argc, char **argv) exit(1); } } - else if (memicmp(argptr, "CONFIG", 6) == 0) - { - /* ignore */ - } } argstart = 2; @@ -466,14 +396,7 @@ int FDKrnConfigMain(int argc, char **argv) kfile = open(kfilename, O_RDWR | O_BINARY); if (kfile < 0) - { - /* attempt to open read only to allow viewing options */ - kfile = open(kfilename, O_RDONLY | O_BINARY); - readonly = 1; - - if (kfile < 0) - printf("Error: unable to open kernel file <%s>\n", kfilename), exit(1); - } + 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); @@ -518,16 +441,6 @@ int FDKrnConfigMain(int argc, char **argv) setSByteOption(&(cfg.BootHarddiskSeconds), cptr, 0, 127, &updates, "BootHarddiskSeconds"); } - else if (memicmp(argptr, "CheckDebugger", 5) == 0) - { - setByteOption(&(cfg.CheckDebugger), - cptr, 2, &updates, "CheckDebugger"); - } - else if (memicmp(argptr, "VERBOSE", 3) == 0) - { - setSByteOption(&(cfg.Verbose), - cptr, -1, 1, &updates, "VERBOSE"); - } else { illegal_arg: @@ -537,16 +450,8 @@ int FDKrnConfigMain(int argc, char **argv) } } - /* warn user if attempt to modify read-only file */ - if (updates && readonly) - { - printf("Kernel %s opened read-only, changes ignored!\n", kfilename); - /* reload current settings, ignore newly requested ones */ - readConfigSettings(kfile, kfilename, &cfg); - } - /* write out new config values if modified */ - if (updates && !readonly) + if (updates) { /* update it */ if (writeConfigSettings(kfile, &cfg)) diff --git a/sys/makefile b/sys/makefile index 5e64bec4..93f5799b 100644 --- a/sys/makefile +++ b/sys/makefile @@ -1,66 +1,47 @@ # -# makefile for bin2c.exe and sys.com +# makefile for bin2c.com and sys.com # -# $Id: makefile 1482 2009-07-11 16:59:43Z perditionc $ +# $Id$ # !include "../mkfiles/generic.mak" -CFLAGS = -I$(INCLUDEPATH) -I..$(DIRSEP)hdr -DFORSYS -DWITHFAT32 $(CFLAGST) -NASMFLAGS = -DSYS=1 +SYS_C=sys.c fdkrncfg.c ..\kernel\prf.c talloc.c +DEPENDS=$(DEPENDS) *.cfg -# *List Macros* +######################################################################## -SYS_EXE_dependencies = \ - sys.obj \ - fdkrncfg.obj \ - prf.obj \ - talloc.obj +all: bin2c.com ..\bin\sys.com -# *Explicit Rules* -production: bin2c.exe ../bin/sys.com +bin2c.com: bin2c.c $(DEPENDS) -bin2c.exe: bin2c.c - $(CLC) bin2c.c +fat12com.h: ..\boot\fat12.bin bin2c.com + bin2c ..\boot\fat12.bin $*.h $* -../bin/sys.com: sys.com - $(CP) sys.com ..$(DIRSEP)bin +fat16com.h: ..\boot\fat16.bin bin2c.com + bin2c ..\boot\fat16.bin $*.h $* -fat12com.h: ../boot/fat12com.bin bin2c.exe - .$(DIRSEP)bin2c.exe ../boot/fat12com.bin fat12com.h fat12com +fat32chs.h: ..\boot\fat32chs.bin bin2c.com + bin2c ..\boot\$*.bin $*.h $* -fat16com.h: ../boot/fat16com.bin bin2c.exe - .$(DIRSEP)bin2c.exe ../boot/fat16com.bin fat16com.h fat16com +fat32lba.h: ..\boot\fat32lba.bin bin2c.com + bin2c ..\boot\$*.bin $*.h $* -fat32chs.h: ../boot/fat32chs.bin bin2c.exe - .$(DIRSEP)bin2c.exe ../boot/fat32chs.bin fat32chs.h fat32chs +oemfat12.h: ..\boot\oemfat12.bin bin2c.com + bin2c ..\boot\$*.bin $*.h $* -fat32lba.h: ../boot/fat32lba.bin bin2c.exe - .$(DIRSEP)bin2c.exe ../boot/fat32lba.bin fat32lba.h fat32lba +oemfat16.h: ..\boot\oemfat16.bin bin2c.com + bin2c ..\boot\$*.bin $*.h $* -oemfat12.h: ../boot/oemfat12.bin bin2c.exe - .$(DIRSEP)bin2c.exe ../boot/oemfat12.bin oemfat12.h oemfat12 +..\bin\sys.com: $(SYS_C) ..\hdr\*.h fat12com.h fat16com.h fat32chs.h fat32lba.h oemfat12.h oemfat16.h + $(CL) $(CFLAGST) -DFORSYS -DWITHFAT32 $(SYS_C) + copy sys.com ..\bin + del sys.com -oemfat16.h: ../boot/oemfat16.bin bin2c.exe - .$(DIRSEP)bin2c.exe ../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.exe 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 + -$(RM) *.bak *.cod *.crf *.err *.las *.lst *.map *.obj *.xrf +clobber: clean + -$(RM) bin2c.com fat*.h oem*.h status.me diff --git a/sys/sys.c b/sys/sys.c index 6e79b2da..0c2b1882 100644 --- a/sys/sys.c +++ b/sys/sys.c @@ -26,20 +26,30 @@ ***************************************************************/ -/* #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 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.6f" -#define SYS_NAME "DOS System Installer " +#define SYS_VERSION "v3.6c" +#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 -#ifndef __GNUC__ #include -#endif #include -#ifndef __GNUC__ #include #include #ifdef __TURBOC__ @@ -47,7 +57,6 @@ #else #include #endif -#endif #include #ifdef __TURBOC__ #include @@ -58,16 +67,16 @@ #include "device.h" #include "dcb.h" #include "xstructs.h" -#include "ddate.h" -#include "dtime.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, ...); +extern int VA_CDECL printf(const char FAR * fmt, ...); +extern int VA_CDECL sprintf(char FAR * buff, const char FAR * fmt, ...); #include "fat12com.h" #include "fat16com.h" @@ -82,150 +91,7 @@ extern int VA_CDECL sprintf(char * buff, CONST char * fmt, ...); #ifndef __WATCOMC__ -#ifdef __GNUC__ -#include -#include -#include -#include -#define O_BINARY 0 -#define stricmp strcasecmp -#define memicmp strncasecmp -union REGS { - struct { - unsigned char al, ah, bl, bh, cl, ch, dl, dh; - } h; - struct { - unsigned short ax, bx, cx, dx, si, di, cflag; - } x; -}; -struct SREGS { - unsigned short ds, es; -}; -struct _diskfree_t { - unsigned short avail_clusters, sectors_per_cluster, bytes_per_sector; -}; - -int int86x(int ivec, union REGS *in, union REGS *out, struct SREGS *s) -{ - /* must save sp for int25/26 */ - asm("mov %7, %%cs:(1f+1); jmp 0f; 0:" - "mov %%di, %%dx; mov %%sp, %%di;" - "push %%di; push %%di;" - /* push twice to work both for int 25h/26h and int 21h */ - "1:int $0x00; pop %%di; pop %%di;" - /* second pop always reads the correct SP value. - the first pop may read the FL left on stack. */ - "mov %%di, %%sp; sbb %0, %0" : - "=r"(out->x.cflag), - "=a"(out->x.ax), "=b"(out->x.bx), "=c"(out->x.cx), "=d"(out->x.dx), - "=e"(s->es), "=Rds"(s->ds) : - "q"((unsigned char)ivec), "a"(in->x.ax), "b"(in->x.bx), - "c"(in->x.cx), "D"(in->x.dx), "S"(in->x.si), "e"(s->es), - "Rds"(s->ds) - : - "cc", "memory"); - return out->x.ax; -} - -int int86(int ivec, union REGS *in, union REGS *out) -{ - struct SREGS sr = {0,}; - return int86x(ivec, in, out, &sr); -} - -int intdos(union REGS *in, union REGS *out) -{ - return int86(0x21, in, out); -} - -int intdosx(union REGS *in, union REGS *out, struct SREGS *s) -{ - asm("push %%ds; mov %%bx, %%ds; int $0x21; pop %%ds; sbb %0, %0": - "=r"(out->x.cflag), "=a"(out->x.ax) : - "a"(in->x.ax), "c"(in->x.cx), "d"(in->x.dx), - "D"(in->x.di), "S"(in->x.si), "b"(s->ds), "e"(s->es) : - "cc", "memory"); - return out->x.ax; -} - -unsigned _dos_allocmem(unsigned size, unsigned *seg) -{ - union REGS in, out; - in.h.ah = 0x48; - in.x.bx = size; - unsigned ret = intdos(&in, &out); - if (!out.x.cflag) - { - *seg = ret; - ret = 0; - } - return ret; -} - -unsigned _dos_freemem(unsigned seg) -{ - union REGS in, out; - struct SREGS s; - in.h.ah = 0x49; - s.es = seg; - return intdosx(&in, &out, &s); -} - -unsigned int _dos_getdiskfree(unsigned int drive, - struct _diskfree_t *diskspace) -{ - union REGS in, out; - in.x.ax = 0x3600; - in.x.dx = drive; - unsigned ret = intdos(&in, &out); - diskspace->avail_clusters = out.x.bx; - diskspace->sectors_per_cluster = out.x.dx; - diskspace->bytes_per_sector = out.x.cx; - return ret; -} - -long filelength(int fhandle) -{ - long ret = lseek(fhandle, 0, SEEK_END); - lseek(fhandle, 0, SEEK_SET); - return ret; -} - -struct find_t { - char reserved[21]; - unsigned char attrib; - unsigned short wr_time; - unsigned short wr_date; - unsigned long size; - char filename[13]; -}; -#define _A_NORMAL 0x00 -#define _A_HIDDEN 0x02 -#define _A_SYSTEM 0x04 - -int _dos_findfirst(const char *file_name, unsigned int attr, - struct find_t *find_tbuf) -{ - union REGS in, out; - struct SREGS sr; - in.h.ah = 0x1A; /* set DTA */ - in.x.dx = FP_OFF(find_tbuf); - sr.ds = FP_SEG(find_tbuf); - intdosx(&in, &out, &sr); - in.h.ah = 0x4e; - in.x.dx = FP_OFF(file_name); - in.x.cx = attr; - sr.ds = FP_SEG(file_name); - intdosx(&in, &out, &sr); - if (out.x.cflag) - return out.x.ax; - /* memcpy(find_tbuf, (void *)0x80, sizeof(*find_tbuf)); */ - /* did set DTA to find_tbuf prior */ - return 0; -} -#else #include -#endif /* returns current DOS drive, A=0, B=1,C=2, ... */ #ifdef __TURBOC__ @@ -248,7 +114,7 @@ unsigned getcurdrive(void); "mov ah, 0x19" \ "int 0x21" \ "xor ah, ah" \ - __value [__ax]; + value [ax]; long filelength(int __handle); @@ -265,9 +131,9 @@ long filelength(int __handle); "int 0x21" \ "pop dx" \ "pop ax" \ - __parm [__bx] \ - __modify [__cx] \ - __value [__dx __ax]; + parm [bx] \ + modify [cx] \ + value [dx ax]; extern int unlink(const char *pathname); @@ -300,9 +166,7 @@ int write(int fd, const void *buf, unsigned count) } #define close _dos_close -#endif -#if defined(__WATCOMC__) || defined(__GNUC__) int stat(const char *file_name, struct stat *statbuf) { struct find_t find_tbuf; @@ -312,9 +176,7 @@ int stat(const char *file_name, struct stat *statbuf) /* statbuf->st_attr = (ULONG)find_tbuf.attrib; */ return ret; } -#endif -#ifdef __WATCOMC__ /* 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) @@ -339,7 +201,6 @@ char *getenv(const char *name) } #endif - BYTE pgm[] = "SYS"; #define SEC_SIZE 512 @@ -403,7 +264,6 @@ struct bootsectortype32 { * globals needed by put_boot & check_space */ enum {FAT12 = 12, FAT16 = 16, FAT32 = 32} fs; /* file system type */ -unsigned smallfat32; /* static */ struct xfreespace x; /* we make this static to be 0 by default - this avoids FAT misdetections */ @@ -441,15 +301,16 @@ typedef struct 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 - /* EDR-DOS */ { "DRBIO.SYS", "DRDOS.SYS", 0x70, 1, 1 }, - /* EDR-DOS */ { "EDRPACK.SYS", NULL, 0x60, 1, 0 }, - /* EDR-DOS */ { "EDRDOS.COM", NULL, 0x60, 1, 0 }, - /* OSS MS-DOS */ { "LMSPACK.SYS", NULL, 0x60, 1, 0 }, - /* OSS MS-DOS */ { "LMSDOS.COM", NULL, 0x60, 1, 0 }, - /* OpenDOS */ { "IBMBIO.COM", "IBMDOS.COM", /*0x70:*/0x70, 1, 1 }, +#endif #ifdef WITHOEMCOMPATBS - /* PC-DOS */ { "IBMBIO.COM", "IBMDOS.COM", /*0x70:*/0x0, 0, 6138 }, + /* 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 }, @@ -459,33 +320,34 @@ DOSBootFiles 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 /* DRBIO, DRDOS version of EDR kernel */ -#define OEM_LEDRPACK 2 /* lDOS drload version of EDR kernel */ -#define OEM_LEDR 3 /* lDOS iniload version of EDR kernel */ -#define OEM_LMSPACK 4 /* lDOS drload version of MS-DOS kernel */ -#define OEM_LMS 5 /* lDOS iniload version of MS-DOS kernel */ -#define OEM_OPENDOS 6 /* old IBMBIO, IBMDOS compatible DR-DOS versions */ +#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 7 /* use PC-DOS compatible boot sector and names */ -#define OEM_MS 8 /* use PC-DOS compatible BS with MS names */ -#define OEM_W9x 9 /* use PC-DOS compatible BS with MS names */ -#define OEM_RX 10 /* use PC-DOS compatible BS with Rx names */ +#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 */ #endif CONST char * msgDOS[DOSFLAVORS] = { /* order should match above items */ - "\n", /* In standard FreeDOS mode, don't print anything special */ - "Enhanced DR-DOS 7.01.07+ mode (DRBIO.SYS and DRDOS.SYS)\n", - "Enhanced DR-DOS mode (EDRPACK.SYS, lDOS drload)\n", - "Enhanced DR-DOS mode (EDRDOS.COM, lDOS iniload)\n", - "OSS MS-DOS mode (LMSPACK.SYS, lDOS drload)\n", - "OSS MS-DOS mode (LMSDOS.COM, lDOS iniload)\n", - "Novell DOS 7, Caldera OpenDOS, DR-DOS 7.02 - 7.03, 7.01.01 - 7.01.06 mode\n", + "\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, DR DOS 5 - Novell DOS 7 mode\n", - "MS-DOS mode\n", - "Win9x DOS mode\n", - "RxDOS mode\n", + "PC-DOS compatibility mode\n", + "MS-DOS compatibility mode\n", + "Win9x DOS compatibility mode\n", #endif }; @@ -504,20 +366,19 @@ typedef struct SYSOptions { 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(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filename); +BOOL copy(const BYTE *source, COUNT drive, const BYTE * filename); void showHelpAndExit(void) { printf( - "Usage: %s [source] drive: [bootsect] [{option}]\n" + "Usage: \n" + "%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" @@ -527,26 +388,19 @@ void showHelpAndExit(void) " /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 FreeDOS settings\n" - " /OEM:EDR Enhanced DR-DOS (DRBIO.SYS and DRDOS.SYS)\n" - " /OEM:LEDRPACK Enhanced DR-DOS (EDRPACK.SYS, lDOS drload)\n" - " /OEM:LEDR Enhanced DR-DOS (EDRDOS.COM, lDOS iniload)\n" - " /OEM:LMSPACK OSS MS-DOS (LMSPACK.SYS, lDOS drload)\n" - " /OEM:LMS OSS MS-DOS (LMSDOS.COM, lDOS iniload)\n" - " /OEM:OPENDOS Caldera OpenDOS 7.01 (and Novell DOS 7),\n" - " DR-DOS 7.02 - 7.03, 7.01.01 - 7.01.06\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 PC-DOS, DR DOS 5 - Novell DOS 7\n" - " /OEM:MS MS-DOS\n" - " /OEM:W9x MS Win9x DOS\n" + " /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" + " /FORCEDRV: force use of drive # set in bs instead of BIOS boot value\n" " /NOBAKBS : skips copying boot sector to backup bs, FAT32 only else ignored\n" #ifdef FDCONFIG "%s CONFIG /help\n" @@ -591,11 +445,6 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) { 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) { @@ -624,18 +473,10 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) argp++; /* point to DR/PC/MS that follows */ if (memicmp(argp, "AUTO", 4) == 0) opts->flavor = OEM_AUTO; - else if (memicmp(argp, "LEDRPACK", 8) == 0) - opts->flavor = OEM_LEDRPACK; - else if (memicmp(argp, "LEDR", 4) == 0) - opts->flavor = OEM_LEDR; else if (memicmp(argp, "EDR", 3) == 0) opts->flavor = OEM_EDR; - else if (memicmp(argp, "LMSPACK", 7) == 0) - opts->flavor = OEM_LMSPACK; - else if (memicmp(argp, "LMS", 3) == 0) - opts->flavor = OEM_LMS; - else if (memicmp(argp, "OPENDOS", 7) == 0) - opts->flavor = OEM_OPENDOS; + else if (memicmp(argp, "DR", 2) == 0) + opts->flavor = OEM_DR; #ifdef WITHOEMCOMPATBS else if (memicmp(argp, "PC", 2) == 0) opts->flavor = OEM_PC; @@ -643,8 +484,6 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) 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; @@ -660,44 +499,10 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) showHelpAndExit(); } } - /* override auto options */ - else if (memicmp(argp, "FORCE", 5) == 0) + /* force use of drive # set in bs instead of BIOS boot value */ + else if (memicmp(argp, "FORCEDRV", 8) == 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(); - } + opts->ignoreBIOS = 1; } /* skips copying boot sector to backup bs, FAT32 only else ignored */ else if (memicmp(argp, "NOBAKBS", 7) == 0) @@ -765,39 +570,10 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) { drivearg = argno; /* either source or destination drive */ } - else if (!srcarg /* && drivearg */ && !opts->bsFile) + else if (!srcarg /* && drivearg */) { - /* 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; - } - } + srcarg = drivearg; /* set source path */ + drivearg = argno; /* set destination drive */ } else if (!opts->bsFile /* && srcarg && drivearg */) { @@ -805,7 +581,6 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) } else /* if (opts->bsFile && srcarg && drivearg) */ { - EXITBADARG: printf("%s: invalid argument %s\n", pgm, argv[argno]); showHelpAndExit(); } @@ -829,12 +604,10 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) sprintf(opts->srcDrive, "%c:", 'A' + getcurdrive()); if (srcarg) { - int slen; + int slen; /* set source path, reserving room to append filename */ - if ( (argv[srcarg][1] == ':') || ((argv[srcarg][0]=='\\') && (argv[srcarg][1] == '\\')) ) + 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); @@ -907,7 +680,14 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) } /* if unable to determine DOS, assume FreeDOS */ - if (opts->flavor == OEM_AUTO) opts->flavor = OEM_FD; + 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; @@ -917,17 +697,13 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) 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) + 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 */ @@ -987,6 +763,8 @@ 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) { @@ -996,22 +774,15 @@ int main(int argc, char **argv) initOptions(argc, argv, &opts); - if (opts.verbose) { - printf(SYS_NAME SYS_VERSION ", " __DATE__ "\n"); - printf(msgDOS[opts.flavor]); - } - - if (opts.verbose) - printf("Processing boot sector...\n"); + printf("Processing boot sector...\n"); put_boot(&opts); if (opts.copyKernel) { - if (opts.verbose) - printf("Now copying system files...\n"); + printf("Now copying system files...\n"); sprintf(srcFile, "%s%s", opts.srcDrive, (opts.fnKernel)?opts.fnKernel:opts.kernel.kernel); - if (!copy(&opts, srcFile, opts.dstDrive, opts.kernel.kernel)) + if (!copy(srcFile, opts.dstDrive, opts.kernel.kernel)) { printf("%s: cannot copy \"%s\"\n", pgm, srcFile); exit(1); @@ -1020,7 +791,7 @@ int main(int argc, char **argv) if (opts.kernel.dos) { sprintf(srcFile, "%s%s", opts.srcDrive, opts.kernel.dos); - if (!copy(&opts, srcFile, opts.dstDrive, opts.kernel.dos) && opts.kernel.minsize) + if (!copy(srcFile, opts.dstDrive, opts.kernel.dos) && opts.kernel.minsize) { printf("%s: cannot copy \"%s\"\n", pgm, srcFile); exit(1); @@ -1030,17 +801,16 @@ int main(int argc, char **argv) if (opts.copyShell) { - if (opts.verbose) - printf("Copying shell (command interpreter)...\n"); + 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(&opts, srcFile, opts.dstDrive, "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(&opts, comspec, opts.dstDrive, "COMMAND.COM")) + 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); @@ -1048,9 +818,7 @@ int main(int argc, char **argv) } /* copy shell */ } - if (opts.verbose) - printf("\n"); - printf("System transferred.\n\n"); + printf("\nSystem transferred.\n"); return 0; } @@ -1093,9 +861,9 @@ int absread(int DosDrive, int nsects, int foo, void *diskReadPacket); "sbb ax, ax" \ "popf" \ "pop bp" \ - __parm [__ax] [__cx] [__dx] [__bx] \ - __modify [__si __di] \ - __value [__ax]; + parm [ax] [cx] [dx] [bx] \ + modify [si di] \ + value [ax]; int abswrite(int DosDrive, int nsects, int foo, void *diskReadPacket); #pragma aux abswrite = \ @@ -1104,9 +872,9 @@ int abswrite(int DosDrive, int nsects, int foo, void *diskReadPacket); "sbb ax, ax" \ "popf" \ "pop bp" \ - __parm [__ax] [__cx] [__dx] [__bx] \ - __modify [__si __di] \ - __value [__ax]; + parm [ax] [cx] [dx] [bx] \ + modify [si di] \ + value [ax]; int fat32readwrite(int DosDrive, void *diskReadPacket, unsigned intno); #pragma aux fat32readwrite = \ @@ -1114,51 +882,49 @@ int fat32readwrite(int DosDrive, void *diskReadPacket, unsigned intno); "mov cx, 0xffff" \ "int 0x21" \ "sbb ax, ax" \ - __parm [__dx] [__bx] [__si] \ - __modify [__cx __dx __si] \ - __value [__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" \ + "mov ah, 0xd" \ "int 0x21" \ "mov ah,0x32" \ "int 0x21" \ "pop ds" \ - __parm [__dx] \ - __modify [__ax __bx]; + 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]; + 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! */ + value [ax] \ + parm [bx] [cx] [dx]; /* BH must be 0 for lock! */ #else #ifndef __TURBOC__ -int int2526readwrite(int DosDrive, void *diskReadPacket, unsigned intno) +int2526readwrite(int DosDrive, void *diskReadPacket, unsigned intno) { union REGS regs; - struct SREGS sregs; regs.h.al = (BYTE) DosDrive; regs.x.bx = (short)diskReadPacket; regs.x.cx = 0xffff; - sregs.ds = FP_SEG(diskReadPacket); - int86x(intno, ®s, ®s, &sregs); + int86(intno, ®s, ®s); return regs.x.cflag; } @@ -1174,16 +940,14 @@ int2526readwrite(DosDrive, diskReadPacket, 0x26) int fat32readwrite(int DosDrive, void *diskReadPacket, unsigned intno) { union REGS regs; - struct SREGS sregs; regs.x.ax = 0x7305; regs.h.dl = DosDrive; regs.x.bx = (short)diskReadPacket; regs.x.cx = 0xffff; regs.x.si = intno; - sregs.ds = FP_SEG(diskReadPacket); - int86x(0x21, ®s, ®s, &sregs); - + intdos(®s, ®s); + return regs.x.cflag; } /* fat32readwrite */ @@ -1258,8 +1022,8 @@ unsigned getextdrivespace(void far *drivename, void *buf, unsigned buf_size); "stc" \ "int 0x21" \ "sbb ax, ax" \ - __parm [__es __dx] [__di] [__cx] \ - __value [__ax]; + parm [es dx] [di] [cx] \ + value [ax]; #else /* !defined __WATCOMC__ */ @@ -1293,53 +1057,42 @@ BOOL haveLBA(void); /* return TRUE if we have LBA BIOS, FALSE otherwise */ "mov ax, 0x4100" /* IBM/MS Int 13h Extensions - installation check */ \ "mov bx, 0x55AA" \ "mov dl, 0x80" \ - "push ds" \ - "mov cx, 0x40" \ - "mov ds, cx" \ "int 0x13" \ - "pop ds" \ "xor ax, ax" \ "cmp bx, 0xAA55" \ "jne quit" \ "and cx, 1" \ "xchg cx, ax" \ "quit:" \ - __modify [__bx __cx __dx] \ - __value [__ax]; + modify [bx cx dx] \ + value [ax]; #else BOOL haveLBA(void) { union REGS r; - struct SREGS sr; r.x.ax = 0x4100; r.x.bx = 0x55AA; r.h.dl = 0x80; - sr.ds = 0x40; - /* ds = 40h is to work around a Xi8088 ROM-BIOS bug, - refer to https://github.com/FDOS/kernel/issues/156 - and https://www.bttr-software.de/forum/forum_entry.php?id=21275 */ - int86x(0x13, &r, &r, &sr); + 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) + struct bootsectortype *oldboot) { /* 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); - } +#ifdef DEBUG + 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); +#endif oldboot->bsSecPerTrack = default_bpb->bsSecPerTrack; oldboot->bsHeads = default_bpb->bsHeads; @@ -1474,16 +1227,17 @@ void dumpBS(const char *bsFile, int drive) 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]; + static unsigned char oldboot[SEC_SIZE], newboot[SEC_SIZE]; + static unsigned char 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'); - } +#ifdef DEBUG + printf("Reading old bootsector from drive %c:\n", opts->dstDrive + 'A'); +#endif /* lock drive */ generic_block_ioctl(opts->dstDrive + 1, 0x84a, NULL); @@ -1509,7 +1263,7 @@ void put_boot(SYSOptions *opts) saveBS(opts->bsFileOrig, oldboot); } - bs = (struct bootsectortype *)oldboot; + bs = (struct bootsectortype *)&oldboot; if (bs->bsBytesPerSec != SEC_SIZE) { @@ -1532,26 +1286,14 @@ void put_boot(SYSOptions *opts) totalSectors = bs32->bsSectors ? bs32->bsSectors : bs32->bsHugeSectors; dataSectors = totalSectors - bs32->bsResSectors - (bs32->bsFATs * fatSize) - rootDirSectors; - clusters = dataSectors / (((bs32->bsSecPerClust - 1) & 0xFF) + 1); - - if (bs32->bsFATsecs == 0) { - if (clusters >= 0xFFFfff5UL) { /* FAT32 has 28 significant bits */ - printf("Too many clusters (%lXh) for FAT32 file system!\n", clusters); - exit(1); - } + clusters = dataSectors / bs32->bsSecPerClust; + + if (clusters < FAT_MAGIC) /* < 4085 */ + fs = FAT12; + else if (clusters < FAT_MAGIC16) /* < 65525 */ + fs = FAT16; + else fs = FAT32; - if (clusters < FAT_MAGIC16) - smallfat32 = 1; - } else { - if (clusters < FAT_MAGIC) /* < 4085 */ - fs = FAT12; - else if (clusters < FAT_MAGIC16) /* < 65525 */ - fs = FAT16; - else { - printf("Too many clusters (%lXh) for non-FAT32 file system!\n", clusters); - exit(1); - } - } } /* bit 0 set if function to use current BPB, clear if Device @@ -1563,12 +1305,11 @@ void put_boot(SYSOptions *opts) if (fs == FAT32) { - if (opts->verbose) - printf("FAT type: FAT32%s\n", smallfat32 ? " (small)" : ""); + 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); + correct_bpb((struct bootsectortype *)(default_bpb + 7 - 11), bs); #ifdef WITHFAT32 /* copy one of the FAT32 boot sectors */ if (!opts->kernel.stdbs) /* MS/PC DOS compatible BS requested */ @@ -1577,12 +1318,8 @@ void put_boot(SYSOptions *opts) "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); + + memcpy(newboot, haveLBA() ? fat32lba : fat32chs, SEC_SIZE); #else printf("SYS hasn't been compiled with FAT32 support.\n" "Consider using -DWITHFAT32 option.\n"); @@ -1591,44 +1328,14 @@ void put_boot(SYSOptions *opts) } else { /* copy the FAT12/16 CHS+LBA boot sector */ - if (opts->verbose) - printf("FAT type: FAT1%c\n", fs + '0' - 10); + 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); + correct_bpb((struct bootsectortype *)(default_bpb + 7 - 11), bs); 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 !!! */ - { - /* magic offset: LBA detection */ - unsigned offset; - offset = (fs == FAT16) ? 0x178 : 0x17B; - - 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: Internal error: FAT1%c LBA detect unexpected content\n", - pgm, fs == FAT12 ? '2' : '6'); - exit(1); - } - } } else { @@ -1649,22 +1356,21 @@ void put_boot(SYSOptions *opts) #endif memcpy(&newboot[SBOFFSET], &oldboot[SBOFFSET], SBSIZE); - bs = (struct bootsectortype *)newboot; + 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 */ + memcpy(bs->OemName, "FRDOS4.1", 8); #ifdef WITHFAT32 if (fs == FAT32) { - bs32 = (struct bootsectortype32 *)newboot; + bs32 = (struct bootsectortype32 *)&newboot; /* ensure appears valid, if not then force valid */ if ((bs32->bsBackupBoot < 1) || (bs32->bsBackupBoot > bs32->bsResSectors)) { - if (opts->verbose) + #ifdef DEBUG printf("BPB appears to have invalid backup boot sector #, forcing to default.\n"); + #endif bs32->bsBackupBoot = 0x6; /* ensure set, 6 is MS defined bs size */ } bs32->bsDriveNumber = opts->defBootDrive; @@ -1680,14 +1386,8 @@ void put_boot(SYSOptions *opts) */ if (opts->kernel.stdbs) { - /* magic offset: loadsegoff_60 */ - int defaultload = *(int *)(&newboot[0x78]); - if (defaultload != 0x60 && defaultload != 0x70) { - printf("%s: Internal error: FAT32 load seg unexpected content\n", pgm); - exit(1); - } - *(int *)(&newboot[0x78]) = opts->kernel.loadaddr; - bsBiosMovOff = 0x82; /* magic offset: mov byte [bp + 40h], dl */ + ((int *)newboot)[0x78/sizeof(int)] = opts->kernel.loadaddr; + bsBiosMovOff = 0x82; } else /* compatible bs */ { @@ -1726,68 +1426,47 @@ void put_boot(SYSOptions *opts) */ if (opts->kernel.stdbs) { - /* magic offset: loadsegoff_60 */ - int defaultload = *(int *)(&newboot[0x5C]); - if (defaultload != 0x60 && defaultload != 0x70) { - printf("%s: Internal error: FAT1%c load seg unexpected content\n", - pgm, fs == FAT12 ? '2' : '6'); - exit(1); - } /* this sets the segment we load the kernel to, default is 0x60:0 */ - *(int *)(&newboot[0x5C]) = opts->kernel.loadaddr; - bsBiosMovOff = 0x66; /* magic offset: mov byte [bp + 24h], dl */ + ((int *)newboot)[0x5c/sizeof(int)] = opts->kernel.loadaddr; + bsBiosMovOff = 0x66; } else { - int defaultload; /* load segment hard coded to 0x70 in oem compatible boot sector, */ /* this however changes the offset jumped to default 0x70:0 */ - if (fs == FAT12) { - /* magic offset: jmp LOADSEG:xxxxh */ - defaultload = *(int *)(&newboot[0x11A]); - *(int *)(&newboot[0x11A]) = opts->kernel.loadaddr; - } else { - /* magic offset: jmp LOADSEG:xxxxh */ - defaultload = *(int *)(&newboot[0x118]); - *(int *)(&newboot[0x118]) = opts->kernel.loadaddr; - } - if (defaultload != 0x0 && defaultload != 0x200) { - printf("%s: Internal error: OEM FAT1%c load ofs unexpected content\n", - pgm, fs == FAT12 ? '2' : '6'); - exit(1); - } - bsBiosMovOff = 0x4F; /* magic offset: mov byte [bp + 24h], dl */ + if (fs == FAT12) + ((int *)newboot)[0x11c/sizeof(int)] = opts->kernel.loadaddr; + else + ((int *)newboot)[0x119/sizeof(int)] = opts->kernel.loadaddr; + bsBiosMovOff = 0x4F; } } - if ( (newboot[bsBiosMovOff]==0x88) && (newboot[bsBiosMovOff+1]==0x56) ) + if (opts->ignoreBIOS) { - 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: Internal error: Unit save unexpected content\n", pgm); - exit(1); + else + { + printf("%s : fat boot sector does not match expected layout\n", pgm); + exit(1); + } } - if (opts->verbose) /* display information about filesystem */ - { +#ifdef DEBUG /* add an option to display this on user request? */ 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); - } - +#endif { int i = 0; - /* magic offset: (first) kernel filename */ memset(&newboot[0x1f1], ' ', 11); while (opts->kernel.kernel[i] && opts->kernel.kernel[i] != '.') { @@ -1808,15 +1487,14 @@ void put_boot(SYSOptions *opts) } } - 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 DEBUG + /* 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); +#endif #ifdef DDEBUG printf("\nNew Boot Sector:\n"); @@ -1844,7 +1522,7 @@ void put_boot(SYSOptions *opts) */ if ((fs == FAT32) && !opts->skipBakBSCopy) { - bs32 = (struct bootsectortype32 *)newboot; + bs32 = (struct bootsectortype32 *)&newboot; #ifdef DEBUG printf("writing backup bootsector to sector %d\n", bs32->bsBackupBoot); #endif @@ -1859,8 +1537,9 @@ void put_boot(SYSOptions *opts) if (opts->bsFile != NULL) { - if (opts->verbose) - printf("writing new bootsector to file %s\n", opts->bsFile); +#ifdef DEBUG + printf("writing new bootsector to file %s\n", opts->bsFile); +#endif saveBS(opts->bsFile, newboot); } /* if write boot sector to file*/ @@ -1908,16 +1587,15 @@ 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) + if (allocmem((unsigned)((memsize+15)>>4), theseg)==-1) #else - if (_dos_allocmem((unsigned)((memsize+15)>>4), &dseg)!=0) + unsigned dseg; + if (_dos_allocmem((unsigned)((memsize+15)>>4), &dseg)==0) + *theseg = (UWORD)dseg; #endif - return -1; /* failed to allocate memory */ - - *theseg = (UWORD)dseg; - return 0; /* success */ + return 0; /* success */ + return -1; /* failed to allocate memory */ } #ifdef __TURBOC__ #define dos_freemem freemem @@ -1926,7 +1604,7 @@ int alloc_dos_mem(ULONG memsize, UWORD *theseg) #endif /* copies file (path+filename specified by srcFile) to drive:\filename */ -BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filename) +BOOL copy(const BYTE *source, COUNT drive, const BYTE * filename) { static BYTE src[SYS_MAXPATH]; static BYTE dest[SYS_MAXPATH]; @@ -1934,26 +1612,14 @@ BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filena 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 - - if (opts->verbose) - printf("Copying %s...\n", source); + printf("Copying %s...\n", source); truename(src, source); sprintf(dest, "%c:\\%s", 'A' + drive, filename); if (stricmp(src, dest) == 0) { - if (opts->verbose) - printf("%s: source and destination are identical: skipping \"%s\"\n", - pgm, source); + printf("%s: source and destination are identical: skipping \"%s\"\n", + pgm, source); return TRUE; } @@ -1963,17 +1629,11 @@ BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filena 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; + exit(1); } if ((fdout = @@ -2001,7 +1661,7 @@ BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filena { ULONG filesize; UWORD theseg; - BYTE far *buffer; BYTE far *bufptr; + BYTE far *buffer, far *bufptr; UWORD offs; unsigned chunk_size; @@ -2010,7 +1670,7 @@ BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filena if (alloc_dos_mem(filesize, &theseg)!=0) { printf("Not enough memory to buffer %lu bytes for %s\n", filesize, source); - return FALSE; + return NULL; } bufptr = buffer = MK_FP(theseg, 0); @@ -2066,13 +1726,23 @@ BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filena } #endif + { #if defined __WATCOMC__ || defined _MSC_VER /* || defined __BORLANDC__ */ - _dos_setftime(fdout, date, time); +#if defined(__WATCOMC__) && __WATCOMC__ < 1280 + unsigned short date, time; +#else + unsigned date, time; +#endif + _dos_getftime(fdin, &date, &time); + _dos_setftime(fdout, date, time); #elif defined __TURBOC__ - setftime(fdout, &ftime); + struct ftime ftime; + getftime(fdin, &ftime); + setftime(fdout, &ftime); #endif + } - /* reduce disk swap on single drives, close file on drive last accessed 1st */ + close(fdin); close(fdout); #ifdef __SOME_OTHER_COMPILER__ @@ -2086,11 +1756,7 @@ BOOL copy(SYSOptions *opts, const BYTE *source, COUNT drive, const BYTE * filena }; #endif - /* and close input file, usually same drive as next action will access */ - close(fdin); - - if (opts->verbose) - printf("%lu Bytes transferred\n", copied); + printf("%lu Bytes transferred\n", copied); return TRUE; } /* copy */ diff --git a/sys/talloc.c b/sys/talloc.c index e68d1919..5b7b64a7 100644 --- a/sys/talloc.c +++ b/sys/talloc.c @@ -33,12 +33,6 @@ extern unsigned __brklvl; #ifdef __GNUC__ #include -static inline int brk(void *addr) -{ - char *brklvl = sbrk(0); - int *res = sbrk((char *)addr - brklvl); - return (res == (void *)-1) ? -1 : 0; -} #endif #define BUSY (sizeof(size_t)-1) /* Bit set if memory block in use*/ diff --git a/sys/turboc.cfg b/sys/turboc.cfg new file mode 100644 index 00000000..84faa4cc --- /dev/null +++ b/sys/turboc.cfg @@ -0,0 +1,7 @@ +-d +-f- +-k- +-O -Z +-v- +-w -g1 +-I..\hdr diff --git a/test/bootimg/a.asm b/test/bootimg/a.asm deleted file mode 100644 index 53e5df43..00000000 --- a/test/bootimg/a.asm +++ /dev/null @@ -1,23 +0,0 @@ - -%if 0 - -Create test data in NASM - 2022, by C. Masloch - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - -%ifndef SIZE - %define SIZE 512*16 -%endif -%ifndef CONTENT - %define CONTENT "a" -%endif - -times SIZE db CONTENT diff --git a/test/bootimg/bootimg.asm b/test/bootimg/bootimg.asm deleted file mode 100644 index 628cd528..00000000 --- a/test/bootimg/bootimg.asm +++ /dev/null @@ -1,1865 +0,0 @@ - -%if 0 - -Create a boot image file (default: 1440 KiB diskette) in NASM - 2019, by C. Masloch - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - -%if 0 - -_PAYLOADFILE must be defined to a list of names and/or keywords. -The filenames and keywords are separated by commas. - -Filenames are accepted as tokens or strings. A plain filename that -does not belong to a preceeding keyword is taken as a file to add -to the image in the image's current directory. The entire name is -interpreted as a source pathname, passed to the incbin directive -in full, which in turn searches NASM's working directory and the -directories specified to NASM with -I switches. The last component -of the name, after the last slash or backslash, is converted into -allcaps and taken as the target filename. - -Keywords are accepted only as (non-string) tokens. The available -keywords are: - -::empty Ignored. Can be used to create an image without files. - -::chdir Change into subdirectory. May be followed by a .. - (dotdot) keyword to back out of a directory. - Otherwise, the filename of the subdirectory to - create (relative to the current directory), - as a string, is expected in the next list item. - -::fragment Followed by number of fragments, followed by length - (in number of clusters) of each fragment. Note that - if the file is shorter than the sum of fragment - lengths plus 1 cluster then it will have NUL bytes - appended so as to make sure the last cluster contains - one byte, and all prior clusters are full. - -::fragmentsame Followed by number of fragments, followed by one value - that specifies the length of all the fragments. - -::nextfragment Places next fragment of a fragmented file. At the - end of the image all remaining fragments are placed. - (The exact order that fragments appear in is not yet - fixed; only the first fragment is certain.) - -::nextfragments Followed by number of fragments to place. Places the - next fragments of fragmented files. The number is - allowed to be higher than the amount of fragments - that remain to be placed; this is handled the same - as if that exact amount was specified. - -::rename Followed by source pathname, then a target filename. - -::fill Followed by length, byte value, target filename. - -::endfill Followed by length, byte value, target filename. - Filename is written to the directory as usual. - The FAT chain is allocated after all other - non-::endfill files however. Additionally, if the - byte value is zero, the chain is allocated after - all non-zero-value ::endfill files. If _FULL=0 - then the zero-value ::endfill data will not be - written at all, only the FAT entries are allocated. - If the value is given as 256 this is treated as - zero but not handled specifically to make use of - _FILL=0 like it is for the literal value 0. - -::attrib Followed by attribute byte value. Sets what - attributes to use for the following directory - entries. ATTR_DIRECTORY and ATTR_VOLLABEL are - invalid to use for this. The _ATTRIB def is - used to set the initial default. - The valid values are: ATTR_READONLY, - ATTR_HIDDEN, ATTR_SYSTEM, ATTR_ARCHIVE, and - any combination of those. - -::date Followed by numeric date value, eg 20110308. - The _FILEDATE def is used to set the initial - default. If _USE_FILE_DATETIME is set, this - defaults to NASM's __DATE_NUM__, else it - defaults to 1980_00_00. - -::time Followed by numeric time value, eg 113842. - The _FILETIME def is used to set the initial - default. If _USE_FILE_DATETIME is set, this - defaults to NASM's __TIME_NUM__, else it - defaults to 0. - -::setdirdatetime Special case: Set root directory - datetime to current setting, instead - of using default _FILEDATE _FILETIME. - (Only affects subdir dotdot entries.) - -File and directory names are checked for duplicates. If a -string like ::chdir,'foo',::chdir,..,::chdir,'foo' is used, -the subdirectory will be detected as a duplicate. That is, -it is not valid to create/enter the same subdirectory twice. - -The order of the files' directory entries and cluster chains in -the file system is determined by the order they were specified -in the list. Particularly, in FAT12 and FAT16 images, the first -two files specified will be placed consecutively at the start -of the data area, which may be necessary for some loaders. -As this is not known to be required by any FAT32 loaders, -the FAT32 root directory counts as the first file. - -Files and directories are always written into a single run of -clusters each, that is, there is no fragmentation. - -Some things are not supported yet: - -* A volume label directory entry. - -* Automatic choice of a volume serial number. - -* Long file names. - -* Boot sector loaders that are not exactly 512 bytes long. - -* Automatic calculation of some parameters such as SPF. - - -A directory is always terminated with one or more directory -entries that are filled with all-zeros. - -If _BOOTPATCHFILE is specified (not the empty quoted string), -then it is used with incbin to extract the boot loader's -jump instruction (3 bytes) and the boot code that's to be -placed after the BPBN (size depends on FAT type). The (E)BPB, -including BPBN, is then created by this script to match the -filesystem that is being written. - -Else, if _BOOTFILE is specified (not the empty quoted string), -it is expected that the (E)BPB of that boot sector matches -the file system parameters specified to the bootimg.asm file. -If _BOOTFILE equals "" then a proper (E)BPB is created, -along with a default loader (which aborts with an error). -If _BOOTJUMPFILE and _BOOTCODEFILE are specified but -_BOOTFILE is not then these files are used to initialise the -first 512 bytes of the boot sector(s), excepting the (E)BPB. -The size of the jump file has to match 3 bytes or 11 bytes. -The size of the code file has to match the amount of bytes -remaining after the BPBN fields to fill up 512 bytes, or two -bytes less (for an 0AA55h signature), or four bytes less -(for an 0AA55_0000h signature). - -If the FAT type is FAT32 and _FSINFO is set, then the def -_BOOTINFOFILE can be specified. If it is defined to the quoted -string "::bootpatchfile" then the FSIBOOT loader is extracted -from the file specified in _BOOTPATCHFILE, for 484 bytes that -start at offset 512 in the file. It is expected that the first -4 bytes of this area contain the FSINFO signature "RRaA". - -Otherwise, if a file is specified as _BOOTINFOFILE (not the -empty quoted string) that file must be exactly 484 bytes long. -The first four bytes should again contain the FSINFO signature -reading "RRaA". - -Otherwise the 480-bytes FSIBOOT area is zero-filled. - - -=== Examples - -Empty default (90mm 1440 KiB FAT12 diskette) image: - -nasm bootimg.asm -I ../lmacros/ -o bootimg.img -D_PAYLOADFILE=::empty - - -A FAT16 image with some fragmented data files, -and automatic calculation of a large enougn or -too large FAT: - -nasm a.asm -o a.bin -nasm a.asm -o b.bin -DCONTENT="'b'" -nasm a.asm -o minus.bin -DCONTENT=-1 -nasm bootimg.asm -o bootimg.img -I ../lmacros/ \ - -D_BPE=16 -D_SPC=1 -D_SPI=$(( 1024 * 2 * 32 )) \ - -D_SPF=$(( (1024 * 2 * 32 / 1 * 2 + 511) / 512 )) \ - -D_NUMROOT=512 -D_ALIGNDATA \ - -D_PAYLOADFILE=::fragmentsame,15,1,a.bin,\ -::fragmentsame,7,1,b.bin,\ -::nextfragments,1024,minus.bin - - -lDOS boot tests can also specify a custom _PAYLOADFILE def: - -./test.sh diskette -D_PAYLOADFILE="::fragmentsame,3,1,testwrit.sys,\ -result.txt,::nextfragment,::chdir,dir,::nextfragment,::rename,result.txt,result2" - - -A FAT32 image in an MBR partition, with a FAT32+FSIBOOT loader -read at build time, and some files loaded into it: - -nasm bootimg.asm \ - -D_WARN_DEFAULT_OFF=1 -D_WARN_TOOMANYFAT=0 -D_WARN_ALIGNDATA=0 \ - -D_MBR -D_ALIGNDATA -D_CHS_HEADS=8 -D_CHS_SECTORS=8 \ - -D_MBR_PART_TYPE=ptFAT32 \ - -D_BPE=32 -D_SPC=1 -D_SPI=69632 -D_SPF=544 -D_NUMROOT=224 \ - -o hdimage.img -l hdimage.lst \ - -D_PAYLOADFILE=testwrit.sys,result.txt,::chdir,dir \ - -D_BOOTPATCHFILE="'boot32tw.bin'" -D_UNIT=80h \ - -I ../lmacros/ \ - -D_BOOTINFOFILE=::bootpatchfile -D_MBRPATCHFILE=oldmbr.bin - - -A FAT32 image with auto-calculated FAT size, depicting some -uses of attributes and filetimes, wrapped into a dosemu2 -image of an MBR-partitioned unit: - -nasm -D_ATTRIB=ATTR_SYSTEM -I ../lmacros/ \ - bootimg.asm -D_BPS=512 \ - -D_PAYLOADFILE=::empty,::rename,"'test.dat'",test.bin,\ -::time,030826,::setdirdatetime,::time,012638,\ -::attrib,ATTR_HIDDEN+ATTR_READONLY+ATTR_SYSTEM,\ -"'test.dat'",::chdir,testdir,"'test.dat'" \ - -D_BPE=32 -D_SPI="(34 * 2 * 1024)" \ - -D_SPF="((_SPI / _SPC * _BPE / 8 + _BPS - 1) / _BPS)" \ - -D_SPC=1 -D_CHS_HEADS=8 -D_CHS_SECTORS=8 \ - -D_MBR -D_MBR_DOSEMU_IMAGE_HEADER \ - -D_BOOTPATCHFILE="'boot32tw.bin'" -D_BOOTINFOFILE="'::bootpatchfile'" \ - -D_USE_FILE_DATETIME=1 -o part.img && mdir -i part.img@@80s -a ::. - -%endif - - -%include "lmacros3.mac" - - defaulting - sectalign off - - numdef SPI, 2880 ; sectors per image - numdef BPS, 512 ; bytes per sector - numdef SPC, 1 ; sectors per cluster - numdef SPF, 9 ; sectors per FAT - numdef BPE, 12 ; bits per entry - numdef FSINFO, 1 ; (only if FAT32) include an FSINFO sector - numdef BACKUP, 1 ; (only if FAT32) include a boot sector backup - numdef FSI_INIT_FREE, 1 ; initialise FSINFO amount free clusters - numdef NUMFATS, 2 ; number of FATs - numdef NUMROOT, 224 ; number of root directory entries -%assign _SP512 (512 + _BPS - 1) / _BPS -; (512 + 32 - 1) / 32 = 16 -; (512 + 64 - 1) / 64 = 8 -; (512 + 512 - 1) / 512 = 1 -; (512 + 1024 - 1) / 1024 = 1 - numdef NUMRESERVED, _SP512 - ; number of reserved sectors -%if _BPE == 32 && (_FSINFO || _BACKUP) - numdef NUMRESERVED, _SP512 * 16 - ; number of reserved sectors -%endif - numdef ALIGNDATA, 0, 16 ; align data to this sector boundary - ; (done by increasing _NUMRESERVED) - numdef FILLROOT, 1 - numdef WARN_TOOMANYFAT, 1 - numdef WARN_ALIGNDATA, 1 - numdef WARN_FILLROOT, 1 - numdef WARN_SMALL32, 1 - numdef WARN_DEFAULT_OFF, 0 -%if _WARN_DEFAULT_OFF - numdef WARN_TOOMANYFAT, 0 - numdef WARN_ALIGNDATA, 0 - numdef WARN_FILLROOT, 0 - numdef WARN_SMALL32, 0 -%endif - numdef ERROR_SMALL32, 1 - numdef MEDIAID, 0F0h ; media ID - numdef EOF, 15 ; suffix of EOF entry marker - - numdef UNIT, 0 ; load unit in BPB - numdef CHS_SECTORS, 18 ; CHS geometry field for sectors - numdef CHS_HEADS, 2 ; CHS geometry field for heads - numdef HIDDEN, 0 ; number of hidden sectors - - strdef BOOTPATCHFILE, "" - strdef BOOTFILE, "" - strdef BOOTJUMPFILE, "" - strdef BOOTCODEFILE, "" - strdef BOOTINFOFILE, "" - gendef PAYLOADFILE, "" - gendef MAP, "" - - strdef OEM_NAME, " lDOS" - strdef OEM_NAME_FILL, '_' - strdef DEFAULT_LABEL, "NO NAME" - numdef VOLUMEID, 0 - numdef ATTRIB, 0 - numdef FILEDATE, 1980_00_00 - numdef FILETIME, 0 - numdef USE_FILE_DATETIME, 0 -%if _USE_FILE_DATETIME - numdef FILEDATE, __DATE_NUM__ - numdef FILETIME, __TIME_NUM__ -%endif - - numdef MBR, 0 - strdef MBRPATCHFILE, "" - strdef MBRCODEFILE, "" - gendef MBR_PART_TYPE, fat %+ _BPE - numdef MBR_DOSEMU_IMAGE_HEADER, 0 - numdef MBR_GAP_SIZE_SECTORS, 0, 2048 - numdef MBR_GAP_SIZE_CYLINDERS, 1 - numdef MBR_ADD_GAP_TO_HIDDEN, 1 - numdef MBR_ADD_GAP_TO_ALIGN, 1 - - - numdef FULL, 1 - numdef ZEROBYTES_RESB, 1 - numdef ZEROBYTES_MAX, 4000_0000h - ; Using the resb trick to zero takes about 1/40th - ; the time of using times (for a 512 MiB image). -%if _ZEROBYTES_RESB - %imacro zerobytes 1.nolist -%if %1 < 0 - %error Negative count given to zerobytes -%else -[warning -zeroing] -[warning -other] - %rep (%1) / (_ZEROBYTES_MAX) - resb (_ZEROBYTES_MAX) - %endrep - resb (%1) % (_ZEROBYTES_MAX) -[warning *other] -[warning *zeroing] -%endif - %endmacro -%else - %imacro zerobytes 1.nolist -%if %1 < 0 - %error Negative count given to zerobytes -%else - %rep (%1) / (_ZEROBYTES_MAX) - times (_ZEROBYTES_MAX) db 0 - %endrep - times (%1) % (_ZEROBYTES_MAX) db 0 -%endif - %endmacro -%endif - - - numdef FILLBYTES_MAX, 4000_0000h - %imacro fillbytes 2.nolist -%ifn %2 - zerobytes %1 -%else - %rep (%1) / (_FILLBYTES_MAX) - times (_FILLBYTES_MAX) db %2 - %endrep - times (%1) % (_FILLBYTES_MAX) db %2 -%endif - %endmacro - - - %imacro zerobytes_if_full 1.nolist -%if _FULL -zerobytes %1 -%endif - %endmacro - - -ptEmpty: equ 0 -ptFAT12: equ 1 -ptFAT16_16BIT_CHS: equ 4 -ptExtendedCHS: equ 5 -ptFAT16_CHS: equ 6 -ptFAT32_CHS: equ 0Bh -ptFAT32: equ 0Ch -ptFAT16: equ 0Eh -ptExtended: equ 0Fh -ptLinux: equ 83h -ptExtendedLinux: equ 85h - -%if _MBR - %if _MBR_GAP_SIZE_SECTORS == 0 - %if _MBR_GAP_SIZE_CYLINDERS == 0 - %error Invalid gap size specified - %else - %assign _MBR_GAP_SIZE_SECTORS _MBR_GAP_SIZE_CYLINDERS * _CHS_HEADS * _CHS_SECTORS - %endif - %endif - %if _MBR_ADD_GAP_TO_HIDDEN - %assign _HIDDEN _HIDDEN + _MBR_GAP_SIZE_SECTORS - %endif - %ifidni _MBR_PART_TYPE, fat12 - %assign _MBR_PART_TYPE ptFAT12 - %elifidni _MBR_PART_TYPE, fat16_16bit_chs - %assign _MBR_PART_TYPE ptFAT16_16BIT_CHS - %elifidni _MBR_PART_TYPE, fat16_chs - %assign _MBR_PART_TYPE ptFAT16_CHS - %elifidni _MBR_PART_TYPE, fat32_chs - %assign _MBR_PART_TYPE ptFAT32_CHS - %elifidni _MBR_PART_TYPE, fat32 - %assign _MBR_PART_TYPE ptFAT32 - %elifidni _MBR_PART_TYPE, fat16 - %assign _MBR_PART_TYPE ptFAT16 - %endif - %assign _MBR_PART_TYPE _MBR_PART_TYPE - %ifnnum _MBR_PART_TYPE - %error Invalid partition type specified - %endif - %if _MBR_PART_TYPE == 0 - %error Invalid partition type specified - %endif -%endif - -%ifnidn _MAP, "" - [map all _MAP] -%endif - -%ifidn _PAYLOADFILE, "" - %error No payload files specified! -%endif - - -%if _BPE == 12 -%elif _BPE == 16 -%elif _BPE == 32 -%else - %error Invalid BPE (_BPE) -%endif - -%if _BPE != 32 - %if _FILLROOT - %assign ii (_NUMROOT + _BPS / 32 - 1) & ~(_BPS / 32 - 1) - %if _WARN_FILLROOT && ii != _NUMROOT - %warning Expanding root to ii entries to fill last sector - %endif - %assign _NUMROOT ii - %endif - %assign ROOTSECTORS (_NUMROOT * 32 + _BPS - 1) / _BPS -%else - %assign ROOTSECTORS 0 -%endif -%assign FATSECTORS _NUMFATS * _SPF - -%if _ALIGNDATA - %assign ii 0 - %if _MBR && _MBR_ADD_GAP_TO_ALIGN - %assign ii ii + _MBR_GAP_SIZE_SECTORS - %endif - %assign ii ii + _NUMRESERVED + ROOTSECTORS + FATSECTORS - %assign ii (ii + (_ALIGNDATA)) % (_ALIGNDATA) - %assign ii ((_ALIGNDATA) - ii) % (_ALIGNDATA) - %if ii - %if _WARN_ALIGNDATA - %warning Adding ii reserved sectors for %[_ALIGNDATA]-sector alignment - %endif - %endif - %assign _NUMRESERVED _NUMRESERVED + ii -%endif - -%assign DATASECTORS (_SPI - _NUMRESERVED - FATSECTORS - ROOTSECTORS) -%assign DATACLUSTERS (DATASECTORS / _SPC) -%assign NUMENTRIES _SPF * _BPS * 8 / _BPE -%assign NUMSECTORS _SPF -%assign NUMNEEDED (DATACLUSTERS + 2) -%assign SECNEEDED (NUMNEEDED * _BPE / 8 + _BPS - 1) / _BPS -%if NUMENTRIES < NUMNEEDED - %error Too few FAT sectors specified \ - (NUMENTRIES entries (NUMSECTORS sectors), NUMNEEDED needed (SECNEEDED sectors)) -%elif NUMENTRIES >= (NUMNEEDED + _BPS * 8 / _BPE) - %if _WARN_TOOMANYFAT - %warning Too many FAT sectors specified \ - (NUMENTRIES entries (NUMSECTORS sectors), NUMNEEDED needed (SECNEEDED sectors)) - %endif -%endif - -%macro detectionerror 1-2.nolist 0 - %assign len 8 - %assign ii 0 - %assign sum 0 - %define string "" - %rep len - %assign shift ((len - 1 - ii) * 4) - %assign digit (DATACLUSTERS >> shift) & 15 - %assign sum sum + digit - %if sum - %substr digit "0123456789ABCDEF" digit + 1 - %strcat string string,digit - %endif - %assign ii ii + 1 - %endrep - %ifn sum - %define string "0" - %endif - %deftok string string - %if %2 && !_ERROR_SMALL32 - %if _WARN_SMALL32 - %warning FAT would be detected %1 (%[DATACLUSTERS] = %[string]h clusters) - %endif - %else - %error FAT would be detected %1 (%[DATACLUSTERS] = %[string]h clusters) - %endif -%endmacro - -%if (DATACLUSTERS + 2) > 0FFF0h - %if _BPE == 12 || _BPE == 16 - detectionerror as FAT32 - %endif -%elif (DATACLUSTERS + 2) > 0FF0h - %if _BPE == 12 - detectionerror as FAT16 - %endif -%endif -%if (DATACLUSTERS + 2) < 1000h - %if _BPE == 16 - detectionerror as FAT12 - %endif - %if _BPE == 32 - detectionerror as FAT12, 1 - %endif -%elif (DATACLUSTERS + 2) < 10000h - %if _BPE == 32 - detectionerror as FAT16, 1 - %endif -%endif - -%if _EOF < 8 || _EOF > 15 - %error Invalid EOF value (_EOF) -%endif - -%if _BPE != 32 - %assign MAXENTRY (1 << _BPE) - 1 -%else - %assign MAXENTRY (1 << 28) - 1 -%endif -%assign EOFSTARTENTRY MAXENTRY - 7 -%assign EOFENDENTRY MAXENTRY -%assign BADENTRY MAXENTRY - 8 -%assign EOFENTRY MAXENTRY - 15 + _EOF - - - struc PARTINFO_CHS_TUPLE -pictHead: resb 1 -pictSectorLow6: -pictCylinderHigh2: resb 1 -pictCylinderLow8: resb 1 - endstruc - - %macro chs_tuple 1.nolist -%assign %%sector (%1) % _CHS_SECTORS -%assign %%i (%1) / _CHS_SECTORS -%assign %%head %%i % _CHS_HEADS -%assign %%cylinder %%i / _CHS_HEADS -%if %%cylinder >= 1024 - %assign %%cylinder 1023 -%endif - istruc PARTINFO_CHS_TUPLE -at pictHead, db %%head -at pictSectorLow6 -at pictCylinderHigh2, db (%%sector + 1) | ((%%cylinder >> (8 - 6)) & 0C0h) -at pictCylinderLow8, db (%%cylinder & 0FFh) - iend - %endmacro - - struc PARTINFO -piBoot: resb 1 -piStartCHS: resb 3 ; PARTINFO_CHS_TUPLE -piType: resb 1 -piEndCHS: resb 3 ; PARTINFO_CHS_TUPLE -piStart: resd 1 -piLength: resd 1 - endstruc - - struc BS -bsJump: resb 3 -bsOEM: resb 8 -bsBPB: - endstruc - - struc EBPB ; BPB sec -bpbBytesPerSector: resw 1 ; offset 00h 0Bh -bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh -bpbReservedSectors: resw 1 ; offset 03h 0Eh -bpbNumFATs: resb 1 ; offset 05h 10h -bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32 -bpbTotalSectors: resw 1 ; offset 08h 13h -bpbMediaID: resb 1 ; offset 0Ah 15h -bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32 -bpbCHSSectors: resw 1 ; offset 0Dh 18h -bpbCHSHeads: resw 1 ; offset 0Fh 1Ah -bpbHiddenSectors: resd 1 ; offset 11h 1Ch -bpbTotalSectorsLarge: resd 1 ; offset 15h 20h -bpbNew: ; offset 19h 24h - -ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h -ebpbFSFlags: resw 1 ; offset 1Dh 28h -ebpbFSVersion: resw 1 ; offset 1Fh 2Ah -ebpbRootCluster: resd 1 ; offset 21h 2Ch -ebpbFSINFOSector: resw 1 ; offset 25h 30h -ebpbBackupSector: resw 1 ; offset 27h 32h -ebpbReserved: resb 12 ; offset 29h 34h -ebpbNew: ; offset 35h 40h - endstruc - - struc BPBN ; ofs B16 S16 B32 S32 -bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h - resb 1 ; 01h 1Ah 25h 36h 41h -bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN -bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h -bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h -bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h - endstruc ; 1Ah 33h 3Eh 4Fh 5Ah - - struc DIRENTRY -deName: resb 8 -deExt: resb 3 -deAttrib: resb 1 - resb 8 -deClusterHigh: resw 1 -deTime: resw 1 -deDate: resw 1 -deClusterLow: resw 1 -deSize: resd 1 - endstruc - -ATTR_READONLY equ 1 -ATTR_HIDDEN equ 2 -ATTR_SYSTEM equ 4 -ATTR_VOLLABEL equ 8 -ATTR_DIRECTORY equ 10h -ATTR_ARCHIVE equ 20h - - struc DOSEMU_IMAGE_HEADER -; This structure is parsed when determining the geometry for -; a hard disk image. It is documented in the dosemu2 sources at: -; https://github.com/dosemu2/dosemu2/blob/f41c0f267fec/src/include/disks.h#L132 -dihSig: resb 7 ; "DOSEMU",0 or 0Eh,"DEXE" -dihCHSHeads: resd 1 ; (note the misalignment for these) -dihCHSSectors: resd 1 -dihCHSCylinders:resd 1 -dihHeaderSize: resd 1 -dihDummy: resb 1 -dihDEXEFlags: resd 1 - endstruc -dih_our_size: equ 8192 ; (16 * 512) - - %imacro checkattrib 0 -%if _ATTRIB & (ATTR_VOLLABEL | ATTR_DIRECTORY) - %error Invalid attribute: _ATTRIB -%endif - %endmacro - checkattrib - - %imacro convertdatetime 0 -%push -%assign %$year _FILEDATE / 1_00_00 -%assign %$month _FILEDATE / 1_00 % 100 -%assign %$day _FILEDATE % 100 -%if %$year < 1980 - %assign _FATFILEDATE 0 << 9 | 1 << 5 | 1 -%elif (%$year - 1980) >= 128 - %assign _FATFILEDATE 127 << 9 | 12 << 5 | 31 -%else - %assign _FATFILEDATE (%$year - 1980) << 9 | %$month << 5 | %$day -%endif -%assign %$hour _FILETIME / 1_00_00 -%assign %$minute _FILETIME / 1_00 % 100 -%assign %$second _FILETIME % 100 -%assign _FATFILETIME %$hour << 11 | %$minute << 5 | %$second >> 1 -%pop - %endmacro - convertdatetime - - -%define STARTSFOLLOWS start=0 - -%if _MBR -CYLINDERS equ (_MBR_GAP_SIZE_SECTORS + _SPI + _CHS_HEADS * _CHS_SECTORS - 1) \ - / (_CHS_HEADS * _CHS_SECTORS) - - - %if _MBR_DOSEMU_IMAGE_HEADER - addsection dosemu_image_header, STARTSFOLLOWS - %define STARTSFOLLOWS follows=dosemu_image_header - istruc DOSEMU_IMAGE_HEADER -at dihSig, asciz "DOSEMU" -at dihCHSHeads, dd _CHS_HEADS -at dihCHSSectors, dd _CHS_SECTORS -at dihCHSCylinders, dd CYLINDERS -at dihHeaderSize, dd dih_our_size - iend - times dih_our_size - ($ - $$) db 0 - %endif - - - addsection mbr, STARTSFOLLOWS vstart=7C00h - %define STARTSFOLLOWS follows=mbr - -mbr_start: - %ifnidn _MBRPATCHFILE, "" - incbin _MBRPATCHFILE, 0, 512 - 2 - 4 * 16 - %elifnidn _MBRCODEFILE, "" - incbin _MBRCODEFILE - %else - cli - cld - xor ax, ax - mov es, ax - mov ds, ax - mov ss, ax - mov sp, 7C00h - sti - mov si, mbr_message -@@: - lodsb - test al, al - jz @F - mov ah, 0Eh - mov bh, [462h] - mov bl, 7 - int 10h - jmp @B - -@@: - xor ax, ax - int 13h - xor ax, ax - int 16h - int 19h - -mbr_message: - db "Unable to boot, MBR loader not written.",13,10 - db 13,10 - db "Press any key to reboot.",13,10 - db 0 - %endif - - times (512 - 2 - 4 * 16) - ($ - $$) db 0 - -%assign TOTAL_MBR_SECTORS CYLINDERS * _CHS_HEADS * _CHS_SECTORS -mbr_partition_table: - istruc PARTINFO -at piBoot, db 80h ; active primary partition -at piStartCHS - chs_tuple _MBR_GAP_SIZE_SECTORS -at piType, db _MBR_PART_TYPE -at piEndCHS - chs_tuple (TOTAL_MBR_SECTORS - 1) -at piStart, dd _MBR_GAP_SIZE_SECTORS -at piLength, dd TOTAL_MBR_SECTORS - _MBR_GAP_SIZE_SECTORS - iend - - times (512 - 2) - ($ - $$) db 0 -mbr_signature: - dw 0AA55h - align _BPS, db 0 - - - addsection gap, STARTSFOLLOWS - %define STARTSFOLLOWS follows=gap - - zerobytes (_MBR_GAP_SIZE_SECTORS - 1) * _BPS -%endif - - - %imacro emit_boot 2 - addsection %1_boot, STARTSFOLLOWS vstart=7C00h - %define STARTSFOLLOWS follows=%1_boot - -%1_boot_start: -%ifnidn _BOOTPATCHFILE, "" - %assign USEBOOTFILE 0 -%elifnidn _BOOTFILE, "" - %assign USEBOOTFILE 1 -%else - %assign USEBOOTFILE 0 -%endif - -%if USEBOOTFILE - incbin _BOOTFILE -%else - %ifnidn _BOOTPATCHFILE, "" - incbin _BOOTPATCHFILE, 0, 3 - %elifnidn _BOOTJUMPFILE, "" - incbin _BOOTJUMPFILE - %else - jmp strict short %1_boot_after_bpb - nop - %endif - %if ($ - $$) == bsOEM -%1_oem_id: ; offset 03h (03) - fill 8,_OEM_NAME_FILL,db _OEM_NAME - %endif - %if ($ - $$) != bsBPB - %error Invalid boot jump file length, must be 11 or 3 - %endif -%1_bytes_per_sector: ; offset 0Bh (11) - dw _BPS -%1_sectors_per_cluster: ; offset 0Dh (13) - db _SPC & 255 -%1_num_reserved_sectors:; offset 0Eh (14) - dw _NUMRESERVED -%1_num_fats: ; offset 10h (16) - db _NUMFATS -%1_num_root_dir_ents: ; offset 11h (17) -%if _BPE != 32 - dw _NUMROOT -%else - dw 0 -%endif -%1_total_sectors: ; offset 13h (19) -%if _SPI < 1_0000h - dw _SPI -%else - dw 0 -%endif -%1_media_id: ; offset 15h (21) - db _MEDIAID -%1_sectors_per_fat: ; offset 16h (22) -%if _BPE != 32 - dw _SPF -%else - dw 0 -%endif -%1_sectors_per_track: ; offset 18h (24) - dw _CHS_SECTORS -%1_heads: ; offset 1Ah (26) - dw _CHS_HEADS -%1_hidden_sectors: ; offset 1Ch (28) - dd _HIDDEN -%1_total_sectors_large: ; offset 20h (32) -%if _SPI >= 1_0000h - dd _SPI -%else - dd 0 -%endif - -; Extended BPB ; offset 24h (36) - -%if _BPE == 32 -%1_sectors_per_fat_large: - ; offset 24h (36) - dd _SPF -%1_fsflags: ; offset 28h (40) - dw 0 -%1_fsversion: ; offset 2Ah (42) - dw 0 -%1_root_cluster: ; offset 2Ch (44) - dd rootcluster -%1_fsinfo_sector: ; offset 30h (48) -%if _FSINFO - dw (%1_fsinfo - %1_boot_start) / _BPS -%else - dw 0 -%endif -%1_backup_sector: ; offset 32h (50) -%if _BACKUP - dw (_boot_end_2 - _boot_start) / _BPS -%else - dw 0 -%endif - - times 12 db 0 ; offset 34h (52) reserved - -; Extended BPB ; offset 40h (64) -%endif - -%1_boot_unit: db _UNIT - db 0 -%1_ext_bpb_signature: db 29h -%1_serial_number: dd _VOLUMEID -%1_volume_label: fill 11,32,db _DEFAULT_LABEL -%1_filesystem_identifier: -%if _BPE == 12 - fill 8,32,db "FAT12" -%elif _BPE == 16 - fill 8,32,db "FAT16" -%elif _BPE == 32 - fill 8,32,db "FAT32" -%else - %error Invalid BPE -%endif - - -%1_boot_after_bpb: - %ifnidn _BOOTPATCHFILE, "" - incbin _BOOTPATCHFILE, ($ - $$), 512 - 2 - ($ - $$) - %elifnidn _BOOTCODEFILE, "" - incbin _BOOTCODEFILE - %else - cli - cld - xor ax, ax - mov es, ax - mov ds, ax - mov ss, ax - mov sp, 7C00h - sti - mov si, %1_boot_message -@@: - lodsb - test al, al - jz @F - mov ah, 0Eh - mov bh, [462h] - mov bl, 7 - int 10h - jmp @B - -@@: - xor ax, ax - int 13h - xor ax, ax - int 16h - int 19h - -%1_boot_message: - db "Unable to boot, loader not written.",13,10 - db 13,10 - db "Press any key to reboot.",13,10 - db 0 - - times 508 - ($ - $$) db 0 - %endif -%endif -%if ($ - $$) == 508 - dw 0 -%endif -%if ($ - $$) == 510 - dw 0AA55h -%endif -%1_boot_end: - -%if (%1_boot_end - %1_boot_start) != 512 - %ifnidn _BOOTFILE, "" - %error Boot file has wrong size, must be 512, 510, or 508 - %elifnidn _BOOTCODEFILE, "" - %assign numberexpected1 512 - (%1_boot_after_bpb - $$) - %assign numberexpected2 numberexpected1 - 2 - %assign numberexpected3 numberexpected1 - 4 - %error Boot code file has wrong size, must be numberexpected1, numberexpected2, or numberexpected3 - %else - %error Internal error, default boot sector loader has wrong size - %endif -%endif -%if _BPS > 512 - _fill _BPS - 4, 0, %1_boot_start - dd 0AA55_0000h -%endif - -%if _BPE == 32 && _FSINFO -%1_fsinfo: - istruc FSINFO - %ifnidn _BOOTINFOFILE, "" - %ifidni _BOOTINFOFILE, "::bootpatchfile" - incbin _BOOTPATCHFILE, 512, 484 - %else - incbin _BOOTINFOFILE - %endif - %else -at FSINFO.signature1 - dd "RRaA" -at FSINFO.reserved1 - _fill 480 + 4, 0, %1_fsinfo - %endif - %if $ - %1_fsinfo != FSINFO.signature2 - %error Boot info file has wrong size - %endif -at FSINFO.signature2 - dd "rrAa" -at FSINFO.numberfree -%if _FSI_INIT_FREE && %2 - dd DATACLUSTERS - USEDCLUSTERS -%else - dd -1 ; number of free clusters -%endif -at FSINFO.nextfree - dd -1 ; first free cluster -at FSINFO.reserved2 - times 3 dd 0 -at FSINFO.signature3 - dd 0_AA55_0000h - iend - %if _BPS > 512 - times (_BPS - 512 - 4) db 0 - dd 0_AA55_0000h - %endif -%endif - -%if _BACKUP && _BPE == 32 - %if _BPS < 512 - zerobytes (6 * 512) - ($ - $$) - %else - zerobytes (6 * _BPS) - ($ - $$) - %endif -%endif -%1_boot_end_2: -%assign bootused bootused + ($ - $$) - - %endmacro - - - struc FSINFO ; FAT32 FSINFO sector layout -.signature1: resd 1 ; 41615252h ("RRaA") for valid FSINFO -.reserved1: ; former unused, initialized to zero by FORMAT -.fsiboot: resb 480 ; now used for FSIBOOT -.signature2: resd 1 ; 61417272h ("rrAa") for valid FSINFO -.numberfree: resd 1 ; FSINFO: number of free clusters or -1 -.nextfree: resd 1 ; FSINFO: first free cluster or -1 -.reserved2: resd 3 ; unused, initialized to zero by FORMAT -.signature3: resd 1 ; AA550000h for valid FSINFO or FSIBOOT - endstruc - -%assign bootused 0 - emit_boot ,1 -%if _BACKUP && _BPE == 32 - emit_boot backup,0 -%endif - zerobytes (_NUMRESERVED * _BPS) - bootused - - - addsection fat, STARTSFOLLOWS align=_BPS - - - ; %1 = name for the equ to receive the start cluster, - ; _start_cluster will be appended - ; also name for the equ from which to read end entry, - ; _chain_end will be appended - ; %2 = how many clusters/entries to allocate - ; (if zero, %1_start_cluster equ will be zero) - %macro addfatchain 2.nolist -%xdefine FATCHAINS FATCHAINS,%1,%2 - %endmacro -%define FATCHAINS secondentry,1 -secondentry_chain_end equ EOFENTRY - - - addsection fixed_root, follows=fat align=_BPS - - - ; %1 = directory name ("" if is root) - ; %2 = data section name to use - ; %3 = data section name of dir to write to (none if is root) - ; %$parentcluster = data cluster number of parent dir (0 if root is parent) - ; %$parentattrib = attrib of parent dir (0 if root is parent) - ; %$parentfiletime = file time of parent dir - ; %$parentfiledate = file date of parent dir - %macro incdir 3.nolist - usesection %2 -%2 %+ _start: -%ifnidni %1, "" - istruc DIRENTRY -at deName, fill 8,32,db "." -at deExt, fill 3,32,db 32 -at deAttrib, db ATTR_DIRECTORY | _ATTRIB -at deClusterHigh, dw %%dir_start_cluster >> 16 -at deTime, dw _FATFILETIME -at deDate, dw _FATFILEDATE -at deClusterLow, dw %%dir_start_cluster & 0FFFFh -at deSize, dd 0 - iend - istruc DIRENTRY -at deName, fill 8,32,db ".." -at deExt, fill 3,32,db 32 -at deAttrib, db ATTR_DIRECTORY | %$$parentattrib -at deClusterHigh, dw %$$parentcluster >> 16 -at deTime, dw %$$parentfiletime -at deDate, dw %$$parentfiledate -at deClusterLow, dw %$$parentcluster & 0FFFFh -at deSize, dd 0 - iend -%endif - -%%dir_chain_end equ EOFENTRY -%xdefine CHAINLIST CHAINLIST,%%dir - -%ifnidni %3, none - -%define string %1 -%ifnstr string - %defstr string string -%endif - parsename %1, 1 - - usesection %3 - istruc DIRENTRY -at deName, fill 8,32,db %$$name -at deExt, fill 3,32,db %$$ext -at deAttrib, db ATTR_DIRECTORY | _ATTRIB -at deClusterHigh, dw %%dir_start_cluster >> 16 -at deTime, dw _FATFILETIME -at deDate, dw _FATFILEDATE -at deClusterLow, dw %%dir_start_cluster & 0FFFFh -at deSize, dd 0 - iend -%else - rootcluster equ %%dir_start_cluster -%endif -%2 %+ _start_cluster equ %%dir_start_cluster - %endmacro - - - ; %1 = source pathname - ; %2 = offset behind data already read - ; %3 = fixed, 0 - ; %4 = size of fragment in amount clusters, nonzero - ; %5 only defined if more fragments to follow - ; - ; Recreates the FRAGMENTLIST smacro by defining - ; it to 0 then appending %5 and subsequent - ; parameters, if any. - ; Sets FRAGMENTOFFSET to the next offset after - ; the data possibly read in by this mmacro. - ; If the file is shorter, this mmacro will fill - ; the space with appended NUL bytes to use up - ; the specified amount clusters. - %macro incbinpart 4-*.nolist -%%start: -incbin %1, %2, %4 * _BPS * _SPC -%assign FRAGMENTOFFSET %2 + %4 * _BPS * _SPC -%define FRAGMENTLIST 0 -%rotate 4 -%rep %0 - 4 - %xdefine FRAGMENTLIST FRAGMENTLIST, %1 - %rotate 1 -%endrep -%if ($ - %%start) < %4 * _BPS * _SPC - %assign TAIL %4 * _BPS * _SPC - ($ - %%start) - %warning File %1 is shorter than expected, appending TAIL NUL bytes - times TAIL db 0 -%endif - %endmacro - - - %macro nextfragment 6-*.nolist - usesection %1 -%1 %+ _start: -%3_chain_end equ %%fragment_start_cluster - ; equate prior fragment's end entry to start of this fragment -%xdefine %%sourcename %4 ; source pathname to read from -%xdefine %%offset %5 ; offset to -> after already read data -%xdefine %%oldfragmentlist FRAGMENTLIST - ; if we have one preserve the new FRAGMENTLIST -%xdefine FRAGMENTLIST %6 ; set up our remaining as the current list - - ; In this mmacro we eat the next fragment to allocate. - ; %1 = section name, %2 = "none" token, %3 = fragment - ; identifier for prior fragment (macro-local name), - ; %4 = pathname, %5 = file offset, %6 = FRAGMENTLIST - ; (which starts with 0 and may have embedded commas). - ; So %7 and up are the parameters of the subsequent - ; fragment, if any, in groups of four. -%define NEXTFRAGMENTS none ; reset the list to a none token -%rotate 6 ; rotate past the section name, none, - ; and all four of our current fragment -%assign COUNTER 1 -%rep %0 - 6 ; repeat for all remaining parameters - %if COUNTER % 4 - %xdefine NEXTFRAGMENTS NEXTFRAGMENTS, %1 - ; append this parameter - %else - %xdefine NEXTFRAGMENTS NEXTFRAGMENTS, {%1} - ; this is a FRAGMENTLIST, so we make - ; sure to pass along curly braces - %endif - %rotate 1 ; next parameter - %assign COUNTER COUNTER + 1 -%endrep ; note: rotated 6 + %0 - 6 times equals - ; %0 times, all back to the beginning - - %ifidn FRAGMENTLIST, 0 ; if no further fragment -%%start: - incbin %%sourcename, %%offset ; include remaining data -%%fragment_chain_end equ EOFENTRY - ; tell FAT cnain allocation to end after this -%if ($ - %%start) == 0 - %warning File %%sourcename is shorter than expected, appending a NUL byte - db 0 ; for proper FAT chain size mustn't be zero -%endif -%3_next_size equ ($ - %1 %+ _start) - ; communicate to prior fragment what its - ; next size (ie, this fragment's) is - %else - incbinpart %%sourcename, %%offset, FRAGMENTLIST - ; incbin a part, specified by this mmacro's - ; %4, and re-create FRAGMENTLIST -%xdefine NEXTFRAGMENTS \ - NEXTFRAGMENTS, %%fragment, %%sourcename, FRAGMENTOFFSET, \ - {FRAGMENTLIST} ; remember at the end of NEXTFRAGMENTS list -%define FRAGMENTLIST 0 ; reset FRAGMENTLIST -%3_next_size equ ($ - %1 %+ _start) + %%fragment_next_size - ; communicate to prior fragment what its - ; next size (ie, this fragment's) is - ; this includes the size of the fragment - ; that's subsequent to this one, so it - ; includes this fragment and all the - ; fragments that are still to come. - %endif - -%xdefine CHAINLIST CHAINLIST,%%fragment - ; remember base name for this fragment's chain - -%xdefine FRAGMENTLIST %%oldfragmentlist - ; preserve current FRAGMENTLIST for new file - %endmacro - - - ; %1 = source filename, may include a directory - ; (the directory is used to locate - ; the file on the host system) - ; %2 = target filename, may include a directory - ; (directory is stripped, base name is - ; used in all-caps to store to the image) - ; %3 = data section name to use - ; %4 = data section name of directory to write to - ; %5 = nonzero if filling data - ; %6 = size of data to fill - ; %7 = value to fill - ; isrename = nonzero if ::rename - ; isfill = nonzero if ::fill - %macro incfile 4-7.nolist 0 - usesection %3 -%3 %+ _start: -%if %5 - fillbytes %6, %7 -%%fragment_chain_end equ EOFENTRY -%%filesize equ ($ - %3 %+ _start) -%else - %define string %1 - %ifnstr string - %defstr string string - %endif - %xdefine %%sourcename string - %ifidn FRAGMENTLIST, 0 - incbin %%sourcename -%%fragment_chain_end equ EOFENTRY -%%filesize equ ($ - %3 %+ _start) - %else - incbinpart %%sourcename, 0, FRAGMENTLIST -%xdefine NEXTFRAGMENTS \ - NEXTFRAGMENTS, %%fragment, %%sourcename, FRAGMENTOFFSET, \ - {FRAGMENTLIST} -%define FRAGMENTLIST 0 -%%filesize equ ($ - %3 %+ _start) + %%fragment_next_size - %endif -%endif - -%xdefine CHAINLIST CHAINLIST,%%fragment - -%define string %2 -%ifnstr string - %defstr string string -%endif - parsename %2, !!(isrename || isfill) - - usesection %4 - istruc DIRENTRY -at deName, fill 8,32,db %$$name -at deExt, fill 3,32,db %$$ext -at deAttrib, db _ATTRIB -at deClusterHigh, dw %%fragment_start_cluster >> 16 -at deTime, dw _FATFILETIME -at deDate, dw _FATFILEDATE -at deClusterLow, dw %%fragment_start_cluster & 0FFFFh -at deSize, dd %%filesize - iend - %endmacro - - - ; %1 = filename - ; %2 = data section name of directory to write to - ; %3 = fill length - ; %4 = fill value - %imacro incendfill 4.nolist -%if %4 - %if %4 == 256 - %xdefine LISTENDFILL LISTENDFILL, %%file, %3, 0 - %else - %xdefine LISTENDFILL LISTENDFILL, %%file, %3, %4 - %endif -%else - %xdefine LISTENDFILLZEROS LISTENDFILLZEROS, %%file, %3, %4 -%endif - -%define string %1 -%ifnstr string - %defstr string string -%endif - parsename %1, 1 - - usesection %2 - istruc DIRENTRY -at deName, fill 8,32,db %$$name -at deExt, fill 3,32,db %$$ext -at deAttrib, db _ATTRIB -at deClusterHigh, dw %%file_start_cluster >> 16 -at deTime, dw _FATFILETIME -at deDate, dw _FATFILEDATE -at deClusterLow, dw %%file_start_cluster & 0FFFFh -at deSize, dd %3 - iend - %endmacro - - - ; %1 = filename, with directory as on host side - ; string = stringified filename, still with host path - ; %2 = if slash disallowed in pathname - ; returns result in %$name, %$ext, and %$namelist - %macro parsename 1-2.nolist 0 -%strlen length string -%assign ii 1 -%rep length - %substr cc string length - ii + 1 - %ifidn cc,"/" - %if %2 - %if ischdir - %error Subsubdirectory not supported, use ::chdir twice - %elif isrename - %error Subdirectory not supported in ::rename target - %elif isfill - %error Subdirectory not supported in ::fill target - %else - %error Subdirectory not supported - %endif - %endif - %substr string string length -ii + 2, -1 - %exitrep - %endif - %ifidn cc,"\" - %if %2 - %if ischdir - %error Subsubdirectory not supported, use ::chdir twice - %elif isrename - %error Subdirectory not supported in ::rename target - %elif isfill - %error Subdirectory not supported in ::fill target - %else - %error Subdirectory not supported - %endif - %endif - %substr string string length -ii + 2, -1 - %exitrep - %endif - %assign ii ii + 1 -%endrep -%strlen length string -%assign ii 1 -%define %$name "" -%define %$ext "" -%assign dotyet 0 -%rep length - %substr cc string ii - %assign ii ii + 1 - %if cc >= 'a' && cc <= 'z' - %substr cc "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (cc - 'a' + 1) - %endif - %ifn dotyet - %ifidn cc,"." - %assign dotyet 1 - %else - %strlen ll %$name - %if ll >= 8 - %error Too long name part in %1 - %exitrep - %endif - checkchar %1,cc - %strcat %$name %$name,cc - %endif - %else - %strlen ll %$ext - %if ll >= 3 - %error Too long ext part in %1 - %exitrep - %else - checkchar %1,cc,"." - %strcat %$ext %$ext,cc - %endif - %endif -%endrep -%ifidn %$name,"" - %error Invalid empty name part in %1 -%endif - - addnametonamelist %$namelist - %endmacro - - %macro checkchar 2-3.nolist 0 -%if %2 <= ' ' || %2 >= 128 || \ - %2 == '/' || %2 == '\' || \ - %2 == '"' || %2 == %3 - %error Invalid character (%2) in name (%1) -%endif - %endmacro - - ; %$name = (string) filename part, 1 to 8 characters, all caps - ; %$ext = (string) file extension part, 0 to 3 characters, all caps - ; %3 = first saved name part in name list - ; %4 = first saved extension part in name list - ; %5, %6 = next filename in name list - ; %$namelist = name list (pairs of name parts, extension parts) - %macro addnametonamelist 2-*.nolist -%ifnidn %1, "" - %error Expected first list entry to be empty -%elifnidn %2, "" - %error Expected first list entry to be empty -%elif %0 & 1 - %error Expected list to contain even number of entries -%endif -%rotate 2 -%rep (%0 - 2) / 2 - %ifidn %1, %$name - %ifidn %2, %$ext - %error Duplicate filename %$name %+ . %+ %$ext in directory %$dirname - %exitrep - %endif - %endif - %rotate 2 -%endrep -%xdefine %$namelist %$namelist, %$name, %$ext - %endmacro - - - %macro setup_a_section 0.nolist - addsection data %+ filescount, follows= %+ ff vstart=0 - %xdefine ff data %+ filescount - %assign filescount filescount + 1 - %endmacro - - -%define DIRLIST none -%define CHAINLIST none -%define FRAGMENTLIST 0 -%define NEXTFRAGMENTS none -%define LISTENDFILL none, none, none -%define LISTENDFILLZEROS none, none, none - %macro multiincfile 1-*.nolist -%assign filescount 0 -%define ff fixed_root -%assign chainindex 0 -%assign ischdir 0 -%assign isfragment 0 -%assign isfragmentsame 0 -%assign isnextfragments 0 -%assign isrename 0 -%assign isfill 0 -%assign isattrib 0 -%assign isdatetime 0 -%assign isdate 0 -%assign istime 0 -%push ROOT -%define %$namelist "", "" -%define %$dirname "/" -%if _BPE == 32 - setup_a_section ; add a section for root directory - incdir "", data %+ chainindex, none - %xdefine nextdir data %+ chainindex - %xdefine DIRLIST DIRLIST,nextdir - %xdefine %$parent nextdir -; %xdefine %$parentcluster %$parent %+ _start_cluster - %define %$parentcluster 0 - %assign chainindex chainindex + 1 -%else - %define %$parent fixed_root - %define %$parentcluster 0 -%endif -%assign %$parentattrib 0 -%assign %$parentfiletime _FATFILETIME -%assign %$parentfiledate _FATFILEDATE -%rep %0 - %if ischdir - %ifidni %1, .. - %ifctx ROOT - %error Cannot back out over root - %else - %pop - %endif - %else - setup_a_section ; add a section for a directory - incdir %1, data %+ chainindex, %$parent - %push SUB - %define %$namelist "", "" - %strcat %$dirname %$$dirname, %$$name, ".", %$$ext, "/" - %xdefine nextdir data %+ chainindex - %xdefine DIRLIST DIRLIST,nextdir - %xdefine %$parent nextdir - %xdefine %$parentcluster %$parent %+ _start_cluster - %assign %$parentattrib _ATTRIB - %assign %$parentfiletime _FATFILETIME - %assign %$parentfiledate _FATFILEDATE - %assign chainindex chainindex + 1 - %endif - %assign ischdir 0 - %elif isfragment == -1 - %assign isfragment %1 - %elif isfragment == -2 - %assign isfragmentsame %1 - %assign isfragment 0 - %elif isfragment - %ifn %1 - %error Zero clusters fragment is invalid - %endif - %assign ONEFRAGMENT %1 - %xdefine FRAGMENTLIST FRAGMENTLIST, ONEFRAGMENT - %assign isfragment isfragment - 1 - %elif isfragmentsame - %ifn %1 - %error Zero clusters fragment is invalid - %endif - %assign ONEFRAGMENT %1 - %rep isfragmentsame - %xdefine FRAGMENTLIST FRAGMENTLIST, ONEFRAGMENT - %endrep - %assign isfragmentsame 0 - %elif isnextfragments - %rep %1 - %ifidn NEXTFRAGMENTS, none - %exitrep - %else - setup_a_section ; add a section for next data fragment - nextfragment data %+ chainindex, NEXTFRAGMENTS - %assign chainindex chainindex + 1 - %endif - %endrep - %assign isnextfragments 0 - %elif isrename == 1 - %xdefine renamesource %1 - %assign isrename 2 - %elif isrename == 2 - setup_a_section ; add a section for a file - incfile renamesource, %1, data %+ chainindex, %$parent - %assign chainindex chainindex + 1 - %assign isrename 0 - %elif isfill == 1 || isfill == 4 - %xdefine filllength %1 - %assign isfill isfill + 1 - %elif isfill == 2 || isfill == 5 - %xdefine fillvalue %1 - %assign isfill isfill + 1 - %elif isfill == 3 - setup_a_section ; add a section for a file - incfile "", %1, data %+ chainindex, %$parent, 1, filllength, fillvalue - %assign chainindex chainindex + 1 - %assign isfill 0 - %elif isfill == 6 - incendfill %1, %$parent, filllength, fillvalue - %assign isfill 0 - %elif isattrib - %assign _ATTRIB %1 - checkattrib - %assign isattrib 0 - %elif isdatetime == 1 - %assign _FILEDATE %1 - %assign isdatetime 2 - %elif isdatetime == 2 - %assign _FILETIME %1 - convertdatetime - %assign isdatetime 0 - %elif isdate - %assign _FILEDATE %1 - convertdatetime - %assign isdate 0 - %elif istime - %assign _FILETIME %1 - convertdatetime - %assign istime 0 - %elifidni %1, ::chdir - %assign ischdir 1 - %elifidni %1, ::fragment - %assign isfragment -1 - %elifidni %1, ::fragmentsame - %assign isfragment -2 - %elifidni %1, ::nextfragment - %ifidn NEXTFRAGMENTS, none - %error No next fragments to write - %endif - setup_a_section ; add a section for next data fragment - nextfragment data %+ chainindex, NEXTFRAGMENTS - %assign chainindex chainindex + 1 - %elifidni %1, ::nextfragments - %assign isnextfragments 1 - %elifidni %1, ::rename - %assign isrename 1 - %elifidni %1, ::fill - %assign isfill 1 - %elifidni %1, ::endfill - %assign isfill 4 - %elifidni %1, ::attrib - %assign isattrib 1 - %elifidni %1, ::datetime - %assign isdatetime 1 - %elifidni %1, ::date - %assign isdate 1 - %elifidni %1, ::time - %assign istime 1 - %elifidni %1, ::setdirdatetime - %assign %$parentfiletime _FATFILETIME - %assign %$parentfiledate _FATFILEDATE - %elifnidni %1, ::empty - %ifidn %1, "" - %error Invalid filename - %elifempty %1 - %error Invalid filename - %else - setup_a_section ; add a section for a file - incfile %1, %1, data %+ chainindex, %$parent - %assign chainindex chainindex + 1 - %endif - %endif - %rotate 1 -%endrep -%if ischdir - %error No directory to create specified -%endif -%if isfragment - %error No fragment list specified -%endif -%if isfragmentsame - %error No fragment size specified -%endif -%if isnextfragments - %error No amount of fragments specified -%endif -%if isrename == 1 - %error No rename source specified -%endif -%if isrename == 2 - %error No rename target specified -%endif -%if isfill == 1 || isfill == 4 - %error No fill length specified -%endif -%if isfill == 2 || isfill == 5 - %error No fill value specified -%endif -%if isfill == 3 || isfill == 6 - %error No fill target specified -%endif -%if isattrib - %error No attributes value specified -%endif -%if isdatetime == 1 - %error No datetime date value specified -%endif -%if isdatetime == 2 - %error No datetime time value specified -%endif -%if isdate - %error No date value specified -%endif -%if istime - %error No time value specified -%endif -%rep 1024 - %ifctx ROOT - %exitrep - %else - %pop - %endif -%endrep -%pop - %endmacro - multiincfile _PAYLOADFILE - - %rep 1024 - %ifidn NEXTFRAGMENTS, none - %exitrep - %else - setup_a_section ; add a section for next data fragment - nextfragment data %+ chainindex, NEXTFRAGMENTS - %assign chainindex chainindex + 1 - %endif - %endrep - - %macro extenddirectories 1-*.nolist -%ifnidni %1, none - %error Expected a none entry to start dir list -%endif -%rotate 1 -%rep %0 - 1 - usesection %1 - times 32 db 0 - ; Insure at least one entry. Makes things - ; easier to handle for the loader too. - ; (Can depend on a zero-filled entry - ; that terminates the directory.) - %rotate 1 -%endrep - %endmacro - - extenddirectories DIRLIST - - - %macro allocatechains 1-*.nolist -%ifnidni %1, none - %error Expected a none entry to start chain list -%endif -%rotate 1 -%assign ii 0 -%rep %0 - 1 - usesection data %+ ii - align _BPS * _SPC, db 0 - %assign clusters ($ - data %+ ii %+ _start) / (_BPS * _SPC) - addfatchain %1,clusters - %assign ii ii + 1 - %rotate 1 -%endrep - %endmacro - - %macro allocateendfill 3-*.nolist -%ifnidni %1, none - %error Expected a none entry to start chain list -%endif -%if %0 % 3 - %error Expected an amount of chain list entries divisible by 3 -%endif - ; ii as left from allocatechains -%rep (%0 - 3) / 3 - %rotate 3 - setup_a_section - usesection data %+ ii -data %+ ii %+ _start: - %if isendfillzeros - ; zerobytes_if_full (%2 + _BPS * _SPC - 1) & ~(_BPS * _SPC - 1) - zerobytes_if_full %2 - %else - fillbytes %2, %3 - %endif - align _BPS * _SPC, db 0 - %assign clusters (%2 + _BPS * _SPC - 1) / (_BPS * _SPC) - %assign data_used data_used + (clusters * _BPS * _SPC) - addfatchain %1,clusters -%1_chain_end equ EOFENTRY - %assign ii ii + 1 -%endrep - %endmacro - - allocatechains CHAINLIST - -%assign data_used 0 -%assign ii 0 -%rep filescount - usesection data %+ ii - align _BPS * _SPC, db 0 -data %+ ii %+ _end: - %assign data_used data_used \ - + (data %+ ii %+ _end - data %+ ii %+ _start) - %assign ii ii + 1 -%endrep - -%assign isendfillzeros 0 - allocateendfill LISTENDFILL -%assign isendfillzeros 1 - allocateendfill LISTENDFILLZEROS - addsection empty, follows= %+ ff vstart=0 - - - usesection fixed_root -%if _BPE != 32 - times 32 db 0 -%endif - zerobytes ROOTSECTORS * _BPS - ($ - $$) - - -USEDCLUSTERS equ data_used / (_BPS * _SPC) - usesection empty -%if data_used > (DATASECTORS * _BPS) - %error Too much data used -%endif - zerobytes_if_full DATASECTORS * _BPS - data_used - - -%if _MBR - addsection partition_end_padding, follows=empty - zerobytes_if_full (CYLINDERS * _CHS_HEADS * _CHS_SECTORS \ - - _MBR_GAP_SIZE_SECTORS - _SPI) \ - * _BPS -%endif - - -%if _BPE == 12 - %macro dumpfatentry 1.nolist -%ifempty EVENENTRY - %xdefine EVENENTRY %1 -%else - db (EVENENTRY) & 0FFh - db ((EVENENTRY) >> 8) \ - | (((%1) & 0Fh) << 4) - db ((%1) >> 4) - %define EVENENTRY -%endif - %endmacro -%elif _BPE == 16 - %define dumpfatentry dw -%elif _BPE == 32 - %define dumpfatentry dd -%else - %error Invalid bpe -%endif - - %macro expandfatchains 2-*.nolist -%define EVENENTRY -dumpfatentry (_MEDIAID | (MAXENTRY - 15)) - ; first entry has media ID byte -%assign ii 1 ; first entry is at index 0, - ; next is index 1 -%rep %0 / 2 ; for each pair - %if %2 - %1_start_cluster equ ii ; equ for chain start cluster - %rep %2 - 1 ; as many as are non-end entries - %assign ii ii + 1 - dumpfatentry ii ; link to next cluster - %endrep - %assign ii ii + 1 - dumpfatentry %1_chain_end ; end of contiguous chain entry - %else - %1_start_cluster equ 0 ; empty chain, start cluster is 0 - %endif - %rotate 2 ; rotate to next pair -%endrep -%ifnempty EVENENTRY - ; dumpfatentry 0 - dw EVENENTRY - %if 0 - -Edge case result with dumpfatentry 0 here: - -bootimg$ nasm bootimg.asm \ - -D_PAYLOADFILE=::endfill,"(_SPI - 1 - 1 - 1) * 512",0,zeros.bin \ - -I ../lmacros/ -D_FULL=0 -D_BPE=12 -D_SPI=342 -D_SPF="1" \ - -D_NUMFATS=1 -D_NUMROOT=16 -bootimg.asm:1201: error: Negative count given to zerobytes -bootimg.asm:1205: error: Internal error in FAT filling - -Correct behaviour with dw EVENENTRY: - -bootimg$ nasm bootimg.asm \ - -D_PAYLOADFILE=::endfill,"(_SPI - 1 - 1 - 1) * 512",0,zeros.bin \ - -I ../lmacros/ -D_FULL=0 -D_BPE=12 -D_SPI=342 -D_SPF="1" \ - -D_NUMFATS=1 -D_NUMROOT=16 - -Correctly rejecting too small FAT: - -bootimg$ time nasm bootimg.asm \ - -D_PAYLOADFILE=::endfill,"(_SPI - 1 - 1 - 1) * 512",0,zeros.bin \ - -I ../lmacros/ -D_FULL=0 -D_BPE=12 -D_SPI=343 -D_SPF="1" \ - -D_NUMFATS=1 -D_NUMROOT=16 -bootimg.asm:272: error: Too few FAT sectors specified (341 entries, 342 needed) -bootimg.asm:1221: error: Negative count given to zerobytes -bootimg.asm:1225: error: Internal error in FAT filling - - %endif -%endif - %endmacro - - usesection fat -%assign jj 0 -%rep _NUMFATS -fat%[jj]: - expandfatchains FATCHAINS - zerobytes _SPF * _BPS - ($ - fat%[jj]) -%assign jj jj+1 -%endrep -%if FATSECTORS * _BPS - ($ - $$) - %error Internal error in FAT filling -%endif diff --git a/test/cfg.sh b/test/cfg.sh deleted file mode 100755 index dce2978b..00000000 --- a/test/cfg.sh +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash - -# Usage of the works is permitted provided that this -# instrument is retained with the works, so that any entity -# that uses the works is notified of this instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -# If you want to override configuration without the -# hassle of having to exclude differences in this file -# (cfg.sh) from the SCM, you may provide ovr.sh. -# The meaning of this line allows you to copy cfg.sh -# to serve as a template for ovr.sh without changes. -[ -f ovr.sh ] && [[ "${BASH_SOURCE[0]##*/}" != ovr.sh ]] && . ovr.sh - -# As the below only are set if no value is provided -# yet, any value can be overridden from the shell. -[ -z "$LMACROS_DIR" ] && LMACROS_DIR=lmacros/ -[ -z "$LDOSBOOT_DIR" ] && LDOSBOOT_DIR=ldosboot/ -[ -z "$BOOTIMG_DIR" ] && BOOTIMG_DIR=bootimg/ - -[ -z "$QEMU" ] && QEMU=qemu-system-i386 -[ -z "$NASM" ] && NASM=nasm diff --git a/test/ldosboot/boot.asm b/test/ldosboot/boot.asm deleted file mode 100644 index 7f74821c..00000000 --- a/test/ldosboot/boot.asm +++ /dev/null @@ -1,2082 +0,0 @@ - -%if 0 - -File system boot sector loader code for FAT12 or FAT16 - -Adapted from 2002-11-26 fatboot.zip/fat12.asm, - released as public domain by Chris Giese - -Public domain by C. Masloch, 2012 - -%endif - - -%include "lmacros2.mac" - -%ifndef _MAP -%elifempty _MAP -%else ; defined non-empty, str or non-str - [map all _MAP] -%endif - - defaulting - - numdef FAT16, 0 ; 0 = FAT12, 1 = FAT16 - strdef OEM_NAME, " lDOS" - strdef OEM_NAME_FILL, '_' - strdef DEFAULT_LABEL, "lDOS" - numdef VOLUMEID, 0 - - strdef LOAD_NAME, "LDOS" - strdef LOAD_EXT, "COM" ; name of file to load - numdef LOAD_ADR, 02000h ; where to load - numdef LOAD_MIN_PARA, paras(4096) - numdef LOAD_NON_FAT, 0, 2048 ; use FAT-less loading (value is amount bytes) - numdef EXEC_SEG_ADJ, 0 ; how far cs will be from _LOAD_ADR - numdef EXEC_OFS, 400h ; what value ip will be - numdef CHECKOFFSET, 1020 - numdef CHECKVALUE, "lD" - numdef LOAD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere) - numdef ADD_SEARCH, 0 ; whether to search second file - strdef ADD_NAME, "" - strdef ADD_EXT, "" ; name of second file to search - numdef ADD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere) - numdef CHECK_ATTRIB, 0 ; check attribute for LFN, label, directory - numdef ATTRIB_SAVE, _CHECK_ATTRIB - - gendef _ADR_DIRBUF, end -start+7C00h ; 07E00h - gendef _ADR_FATBUF, end -start+7C00h ; 07E00h - - numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) - numdef QUERY_GEOMETRY_DISABLED, 0 - numdef USE_PART_INFO, 1 ; use ds:si-> partition info from MBR, if any - numdef USE_PART_INFO_DISABLED, 0 - numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl - numdef RPL, 1 ; support RPL and do not overwrite it - numdef RPL_GRACE_AREA, 130 * 1024 - ; alternative RPL support, - ; assume RPL fits in this area - numdef CHS, 1 ; support CHS (if it fits) - numdef LBA, 1 ; support LBA (if available) - numdef LBA_33_BIT, 1 ; support 33-bit LBA - numdef LBA_CHECK_NO_33, 1 ; else: check that LBA doesn't carry - - numdef RELOCATE, 0 ; relocate the loader to top of memory - numdef SET_BL_UNIT, 0 ; if to pass unit in bl as well - numdef SET_DL_UNIT, 0 ; if to pass unit in dl - numdef SET_AXBX_DATA, 0 ; if to pass first data sector in ax:bx - numdef SET_DSSI_DPT, 0 ; if to pass DPT address in ds:si - numdef PUSH_DPT, 0 ; if to push DPT address - numdef MEMORY_CONTINUE, 1 ; if to just execute when memory full - numdef SET_DI_CLUSTER, 0 ; if to pass first load file cluster in di - numdef DIRBUF_500, 0 ; if to load root dir sector(s) to 0:500h - numdef DIR_ENTRY_500, 0 ; if to copy directory entry to 0:500h - numdef DIR_ENTRY_520, 0 ; if to copy next directory entry to 0:520h - numdef TURN_OFF_FLOPPY, 0 ; if to turn off floppy motor after loading - numdef DATASTART_HIDDEN,0 ; if to add hidden sectors to data_start - numdef LBA_SET_TYPE, 0 ; if to set third byte to LBA partition type - numdef SET_LOAD_SEG, 1 ; if to set load_seg (word [ss:bp - 6]) - numdef SET_FAT_SEG, 1 ; if to set fat_seg (word [ss:bp - 8]) - numdef SET_FAT_SEG_NORMAL, 1 ; do not use aggressive optimisation - numdef SET_CLUSTER, 1 ; if to set first_cluster (word [ss:bp - 16]) - numdef ZERO_ES, 0 ; if to set es = 0 before jump - numdef ZERO_DS, 0 ; if to set ds = 0 before jump - - numdef FIX_SECTOR_SIZE, 0 ; fix sector size (0 = disable, else = sector size) - numdef FIX_SECTOR_SIZE_SKIP_CHECK, 0 ; don't check sector size - numdef FIX_CLUSTER_SIZE, 0 ; fix cluster size - numdef FIX_CLUSTER_SIZE_SKIP_CHECK, 0 ; don't check cluster size - numdef NO_LIMIT, 0 ; allow using more memory than a boot sector - ; also will not write 0AA55h signature! - numdef WARN_PART_SIZE, 0 - - numdef LBA_SKIP_CHECK, 1 ; don't use proper LBA extensions check - numdef LBA_SKIP_CY, 1 ; skip check: set up CY before 13.42 - numdef LBA_SKIP_ANY, 0 ; skip check: try CHS on any error - incdef _LBA_SKIP_ANY, LBA_SKIP_CY - numdef LBA_RETRY, 0 ; retry LBA reads one time - numdef CHS_RETRY, 1 ; retry CHS reads one time - numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times - ; (value of the def is used as count) - numdef CHS_RETRY_NORMAL,1 ; do not use aggressive optimisation - numdef RETRY_RESET, 1 ; call reset disk system 13.00 on retries - - numdef MEDIAID, 0F0h ; media ID - numdef UNIT, 0 ; load unit in BPB - numdef CHS_SECTORS, 18 ; CHS geometry field for sectors - numdef CHS_HEADS, 2 ; CHS geometry field for heads - numdef HIDDEN, 0 ; number of hidden sectors - numdef SPI, 2880 ; sectors per image - numdef BPS, 512 ; bytes per sector - numdef SPC, 1 ; sectors per cluster - numdef SPF, 9 ; sectors per FAT - numdef NUMFATS, 2 ; number of FATs - numdef NUMROOT, 224 ; number of root directory entries - numdef NUMRESERVED, 1 ; number of reserved sectors - -%if _FAT16 - ; Unlike the 1440 KiB diskette image defaults for the FAT12 - ; loader we just fill the FAT16 BPB with zeros by default. - numdef MEDIAID, 0 ; media ID - numdef UNIT, 0 ; load unit in BPB - numdef CHS_SECTORS, 0 ; CHS geometry field for sectors - numdef CHS_HEADS, 0 ; CHS geometry field for heads - numdef HIDDEN, 0 ; number of hidden sectors - numdef SPI, 0 ; sectors per image - numdef BPS, 0 ; bytes per sector - numdef SPC, 0 ; sectors per cluster - numdef SPF, 0 ; sectors per FAT - numdef NUMFATS, 0 ; number of FATs - numdef NUMROOT, 0 ; number of root directory entries - numdef NUMRESERVED, 0 ; number of reserved sectors -%endif - -%if _DIRBUF_500 - gendef _ADR_DIRBUF, 500h -%endif - - - numdef COMPAT_FREEDOS, 0 ; partial FreeDOS load compatibility - numdef COMPAT_IBM, 0 ; partial IBMDOS load compatibility - numdef COMPAT_MS7, 0 ; partial MS-DOS 7 load compatibility - numdef COMPAT_MS6, 0 ; partial MS-DOS 6 load compatibility - numdef COMPAT_LDOS, 0 ; lDOS load compatibility - numdef COMPAT_KERNEL7E, 0 ; kernel at 0:7E00h load compatibility - -%if (!!_COMPAT_FREEDOS + !!_COMPAT_IBM + \ - !!_COMPAT_MS7 + !!_COMPAT_MS6 + \ - !!_COMPAT_LDOS + !!_COMPAT_KERNEL7E) > 1 - %error At most one set must be selected. -%endif - -%if _COMPAT_FREEDOS - strdef LOAD_NAME, "KERNEL" - strdef LOAD_EXT, "SYS" - numdef LOAD_ADR, 00600h - numdef LOAD_MIN_PARA, paras(512) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 0 - - numdef CHECKVALUE, 0 - numdef SET_LOAD_SEG, 0 - numdef SET_FAT_SEG, 0 - numdef SET_CLUSTER, 0 - - numdef SET_BL_UNIT, 1 - numdef MEMORY_CONTINUE, 0 - numdef RELOCATE, 1 - ; The FreeDOS load protocol mandates that the entire file be loaded. -%endif - -%if _COMPAT_IBM - strdef LOAD_NAME, "IBMBIO" - strdef LOAD_EXT, "COM" - numdef LOAD_ADR, 00700h - numdef LOAD_MIN_PARA, paras(512) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 0 - numdef LOAD_DIR_SEG, 50h - numdef ADD_SEARCH, 1 - strdef ADD_NAME, "IBMDOS" - strdef ADD_EXT, "COM" - numdef ADD_DIR_SEG, 52h - ; Note: The IBMBIO.COM directory entry must be stored at - ; 0:500h, and the IBMDOS.COM directory entry at 0:520h. - - numdef CHECKVALUE, 0 - numdef SET_LOAD_SEG, 0 - numdef SET_FAT_SEG, 0 - numdef SET_CLUSTER, 0 - - numdef SET_DL_UNIT, 1 - numdef MEMORY_CONTINUE, 1 - ; 3 sectors * 512 BpS should suffice. We load into 700h--7A00h, - ; ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB). - numdef SET_AXBX_DATA, 1 - numdef DATASTART_HIDDEN,1 - numdef SET_DSSI_DPT, 1 - numdef PUSH_DPT, 1 -%endif - -%if _COMPAT_MS7 - strdef LOAD_NAME, "IO" - strdef LOAD_EXT, "SYS" - numdef LOAD_ADR, 00700h - numdef LOAD_MIN_PARA, paras(1024) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 200h - - numdef CHECKVALUE, 0 - numdef SET_LOAD_SEG, 0 - numdef SET_FAT_SEG, 0 - numdef SET_CLUSTER, 0 - - numdef SET_DL_UNIT, 1 - numdef SET_DSSI_DPT, 0 - numdef PUSH_DPT, 1 - numdef MEMORY_CONTINUE, 1 - ; 4 sectors * 512 BpS should suffice. We load into 700h--7A00h, - ; ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB). - numdef SET_DI_CLUSTER, 1 - numdef DATASTART_HIDDEN,1 - numdef LBA_SET_TYPE, 1 -%endif - -%if _COMPAT_MS6 - strdef LOAD_NAME, "IO" - strdef LOAD_EXT, "SYS" - numdef LOAD_ADR, 00700h - numdef LOAD_MIN_PARA, paras(512) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 0 - numdef LOAD_DIR_SEG, 50h - numdef ADD_SEARCH, 1 - strdef ADD_NAME, "MSDOS" - strdef ADD_EXT, "SYS" - numdef ADD_DIR_SEG, 52h - ; Note: The IO.SYS directory entry must be stored at - ; 0:500h, and the MSDOS.SYS directory entry at 0:520h. - - numdef CHECKVALUE, 0 - numdef SET_LOAD_SEG, 0 - numdef SET_FAT_SEG, 0 - numdef SET_CLUSTER, 0 - - numdef SET_DL_UNIT, 1 - numdef MEMORY_CONTINUE, 1 - ; 3 sectors * 512 BpS should suffice. We load into 700h--7A00h, - ; ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB). - numdef SET_AXBX_DATA, 1 - numdef DATASTART_HIDDEN,1 - numdef SET_DSSI_DPT, 1 - numdef PUSH_DPT, 1 -%endif - -%if _COMPAT_LDOS - strdef LOAD_NAME, "LDOS" - strdef LOAD_EXT, "COM" - numdef LOAD_ADR, 02000h - numdef LOAD_MIN_PARA, paras(4096) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 400h - numdef CHECKOFFSET, 1020 - numdef CHECKVALUE, "lD" - - numdef SET_DL_UNIT, 0 - numdef SET_CLUSTER, 1 - numdef SET_FAT_SEG, 1 - numdef SET_LOAD_SEG, 1 - numdef MEMORY_CONTINUE, 1 - numdef DATASTART_HIDDEN,0 -%endif - -%if _COMPAT_KERNEL7E - strdef OEM_NAME, "KERNEL7E" - strdef LOAD_NAME, "KERNEL7E" - strdef LOAD_EXT, "BIN" - numdef LOAD_ADR, 07E00h - numdef LOAD_MIN_PARA, paras(512) - numdef EXEC_SEG_ADJ, -7E0h - numdef EXEC_OFS, 7E00h - numdef CHECKVALUE, 0 - - numdef SET_DL_UNIT, 1 - numdef SET_BL_UNIT, 0 - numdef SET_CLUSTER, 0 - numdef SET_FAT_SEG, 0 - numdef SET_LOAD_SEG, 0 - numdef MEMORY_CONTINUE, 0 - numdef DATASTART_HIDDEN,0 - - gendef _ADR_FATBUF, 4000h - gendef _ADR_DIRBUF, 4000h - numdef RPL, 0 - numdef ZERO_ES, 1 -%endif - - -%if 0 - -Notes about partial load compatibilities - -* FreeDOS: - * Relocates to an address other than 27A00h (1FE0h:7C00h) - * A lot of options between _USE_PART_INFO, _QUERY_GEOMETRY, _CHS, _LBA, - and/or _RPL need to be disabled to make the loader fit -* IBMDOS: -* MS-DOS 6: - * Does not actually relocate DPT, just provide its address - * A lot of options between _USE_PART_INFO, _QUERY_GEOMETRY, _CHS, - and/or _LBA need to be disabled to make the loader fit -* MS-DOS 7: - * Does not actually relocate DPT, just provide its address - * Does not contain message table used by loader - -%endif - -%if _SET_BL_UNIT && _SET_AXBX_DATA - %error Cannot select both of these options! -%endif - -%if _DIR_ENTRY_520 - %assign _DIR_ENTRY_500 1 -%endif - -%if _DIRBUF_500 && _ADD_SEARCH - %error Cannot select both of these options! -%endif - -%if _ADD_SEARCH - %if _LOAD_DIR_SEG == 0 || _ADD_DIR_SEG == 0 - %error Assuming dir segs should be set if add search set - %endif -%endif - -%if _RPL - %assign _RPL_GRACE_AREA 0 -%endif - - -%assign LOADLIMIT 0A0000h -%assign POSITION 07C00h - -%if _FIX_SECTOR_SIZE - %assign i 5 - %rep 13-5 - %if (1 << i) != (_FIX_SECTOR_SIZE) - %assign i i+1 - %endif - %endrep - %if (1 << i) != (_FIX_SECTOR_SIZE) - %error Invalid sector size _FIX_SECTOR_SIZE - %endif -%endif - -%if _FIX_CLUSTER_SIZE - %if _FIX_CLUSTER_SIZE > 256 - %error Invalid cluster size _FIX_CLUSTER_SIZE - %endif - %assign i 0 - %rep 8-0 - %if (1 << i) != (_FIX_CLUSTER_SIZE) - %assign i i+1 - %endif - %endrep - %if (1 << i) != (_FIX_CLUSTER_SIZE) - %warning Non-power-of-two cluster size _FIX_CLUSTER_SIZE - %endif -%endif - - -; 512-byte stack (minus the variables). -ADR_STACK_LOW equ 7C00h - 200h ; 07A00h - -%if _DIRBUF_500 - gendef _ADR_DIRBUF, 500h -%elif _RELOCATE - gendef _ADR_DIRBUF, _LOAD_ADR -%endif - -; one-sector directory buffer. Assumes sectors are no larger than 8 KiB -ADR_DIRBUF equ __ADR_DIRBUF - -%if ! _RELOCATE -; this used to be a two-sector FAT buffer -- two sectors because FAT12 -; entries are 12 bits and may straddle a sector boundary. -; however, with the FAT12 loaded completely, the buffer only needs to hold -; one 8 KiB sector, two 4 KiB sectors, three 2 KiB sectors, six 1 KiB sectors, -; or twelve 512 byte sectors. -; this shares its area with the directory buffer as they -; are not simultaneously used. (if not _DIRBUF_500.) -ADR_FATBUF equ __ADR_FATBUF -%endif - -; start of unused memory after loader: -ADR_END equ end -start+7C00h -%if ! _RELOCATE - %if (ADR_FATBUF + 8192) > ADR_END - ADR_FREE_FROM equ (ADR_FATBUF + 8192) ; 09E00h - %else - ADR_FREE_FROM equ ADR_END ; 07E00h - %endif - -; end of unused memory before loader: - %if ADR_FATBUF < ADR_STACK_LOW -ADR_FREE_UNTIL equ ADR_FATBUF - %else -ADR_FREE_UNTIL equ ADR_STACK_LOW - %endif - - %if ((ADR_FATBUF + 8192 - 1) & ~0FFFFh) != (ADR_FATBUF & ~0FFFFh) - %warning Possibly crossing 64 KiB boundary while reading FAT - %endif -%endif - -%if ((ADR_DIRBUF + 8192 - 1) & ~0FFFFh) != (ADR_DIRBUF & ~0FFFFh) - %warning Possibly crossing 64 KiB boundary while reading directory -%endif - -%if _RELOCATE - ADR_FREE_FROM equ 0 ; make next conditional true - ADR_FREE_UNTIL equ 0 -%endif -%if _LOAD_ADR >= ADR_FREE_FROM - ; If reading on a sector size boundary, no crossing can occur. - ; Check for all possible sector sizes (32 B to 8 KiB). If one - ; of them fails display a warning, including the minimum size. - %assign SECSIZECHECK 32 - %assign EXITREP 0 - %rep 256 - %ifn EXITREP - %if _LOAD_ADR & (SECSIZECHECK - 1) - %warning Possibly crossing 64 KiB boundary while reading file (sector size >= SECSIZECHECK) - %assign EXITREP 1 - %exitrep - %endif - %if SECSIZECHECK == 8192 - %assign EXITREP 1 - %exitrep - %endif - %assign SECSIZECHECK SECSIZECHECK * 2 - %endif - %endrep -%else - ; If loading below the boot sector, address 1_0000h is never reached. -%endif - - -%if (_LOAD_ADR & 0Fh) - %error Load address must be on a paragraph boundary -%endif - -%if _LOAD_ADR > LOADLIMIT - %error Load address must be in LMA -%elif _LOAD_ADR < 00500h - %error Load address must not overlap IVT or BDA -%endif - -%if ! _RELOCATE - %if _LOAD_ADR > (POSITION-512) && _LOAD_ADR < (POSITION+512) - %error Load address must not overlap loader - %endif - - %if ADR_FATBUF > LOADLIMIT - %error FAT buffer address must be in LMA - %elif ADR_FATBUF < 00500h - %error FAT buffer address must not overlap IVT or BDA - %elif (ADR_FATBUF + 8192) > (POSITION-512) && ADR_FATBUF < (POSITION+512) - %error FAT buffer address must not overlap loader - %endif -%endif - -%if ADR_DIRBUF > LOADLIMIT - %error Dir buffer address must be in LMA -%elif ADR_DIRBUF < 00500h - %error Dir buffer address must not overlap IVT or BDA -%elif (ADR_DIRBUF + 8192) > (POSITION-512) && ADR_DIRBUF < (POSITION+512) - %error Dir buffer address must not overlap loader at initial position -%endif - -%if ((_EXEC_SEG_ADJ<<4)+_EXEC_OFS) < 0 - %error Execution address must be in loaded file -%elif ((_EXEC_SEG_ADJ<<4)+_EXEC_OFS+_LOAD_ADR) > LOADLIMIT - %error Execution address must be in LMA -%endif - -%if (_EXEC_OFS & ~0FFFFh) - %error Execution offset must fit into 16 bits -%endif - -%if (_EXEC_SEG_ADJ > 0FFFFh || _EXEC_SEG_ADJ < -0FFFFh) - %error Execution segment adjustment must fit into 16 bits -%endif - - -%if !_CHS && _QUERY_GEOMETRY - %warning No CHS support but querying geometry anyway -%endif - -%if !_CHS && !_LBA - %error Either CHS or LBA or both must be enabled -%endif - - -%if 0 - -There is some logic inside MS-DOS's hard disk partition initialisation -code that sets up several requirements for us to fulfil. Otherwise, -it will not accept the information given in the BPB (using default -information based on the length as specified by MBR/EPBR instead) or -make the whole file system inaccessible except for formatting. Both of -those are undesirable of course. Some/all(?) checks are documented on -pages 601,602 in "DOS Internals", Geoff Chappell 1994, as follows: - -* First three bytes contain either "jmp sho xx\ nop" or "jmp ne xx". -* Media descriptor field >= 0F0h. -* Bytes per sector field == 512. -* Sectors per cluster field a power of 2 (1,2,4,8,16,32,64,128). -* OEM name "version" (last three to four characters) - * must be "20.?", "10.?" (? = wildcard), but no other with "0.?", - * otherwise, must be "2.0", or - * 2nd-to-last,3rd-to-last character codes together > "3.", or - * those == "3.", last character code > "0" - -To stay compatible to those, display a warning here if the name -itself would disqualify our boot sector already. - -%endif - -%push -%strlen %$len _OEM_NAME_FILL -%if %$len != 1 - %error Specified OEM name fill must be 1 character -%endif -%strlen %$len _OEM_NAME -%define %$nam _OEM_NAME -%if %$len > 8 - %error Specified OEM name is too long -%else - %assign %$warn 0 - %rep 8 - %$len - %strcat %$nam %$nam,_OEM_NAME_FILL - %endrep - %substr %$prefix %$nam 5 ; "wvxyZa.b", get "Z" - %substr %$major %$nam 6,7 ; "wvxyzA.b", get "A." - %substr %$minor %$nam 8 ; "wvxyza.B", get "B" - %if %$major == "0." - %ifn %$prefix == "1" || %$prefix == "2" - %assign %$warn 1 - %endif - %elifn %$major == "2." && %$minor == "0" - %if %$major < "3." - %assign %$warn 1 - %elif %$major == "3." && %$minor < "1" - %assign %$warn 1 - %endif - %endif - %if %$warn - %warning Specified OEM name fails MS-DOS's validation - %endif -%endif -%pop - - - struc DIRENTRY -deName: resb 8 -deExt: resb 3 -deAttrib: resb 1 - resb 8 -deClusterHigh: resw 1 -deTime: resw 1 -deDate: resw 1 -deClusterLow: resw 1 -deSize: resd 1 - endstruc - -ATTR_READONLY equ 1 -ATTR_HIDDEN equ 2 -ATTR_SYSTEM equ 4 -ATTR_VOLLABEL equ 8 -ATTR_DIRECTORY equ 10h -ATTR_ARCHIVE equ 20h - - -; use byte-offset addressing from BP for smaller code -%define VAR(x) ((x) - start) + bp - - - cpu 8086 -; bootsector loaded at address 07C00h, addressable using 0000h:7C00h - org POSITION -start: - - -%define _LASTVARIABLE start - %macro nextvariable 2-3.nolist -%1 equ (_LASTVARIABLE - %2) -%define _LASTVARIABLE %1 -%ifidn %3, relocatestart - %define _RELOCATESTART %1 -%elifempty %3 -%else - %error Invalid third parameter -%endif - %endmacro - -; Variables - -; (dword) sector where the first cluster's data starts - nextvariable data_start, 4 - -; (word) current load segment (points behind last loaded data) - nextvariable load_seg, 2 - -; (word) segment of FAT buffer -; for FAT12 this holds the entire FAT -; for FAT16 this holds the sector given by wo[fat_sector] -; for FAT32 this holds the sector given by dwo[fat_sector] - nextvariable fat_seg, 2 - -; (word for FAT16) currently loaded sector-in-FAT, -1 if none - nextvariable fat_sector, 4 - -; (word for FAT12/FAT16) first cluster of load file - nextvariable first_cluster, 4, relocatestart - -ADR_STACK_START equ _LASTVARIABLE -start+POSITION - -%ifn _FIX_SECTOR_SIZE -; (word) number of 16-byte paragraphs per sector - nextvariable para_per_sector, 2, relocatestart -%endif - -%assign DIRSEARCHSTACK_CL_FIRST 0 -%assign DIRSEARCHSTACK_CL_SECOND 0 -%assign PLACEHOLDER 0 - - %if _ATTRIB_SAVE && ! (_ADD_SEARCH || _LOAD_DIR_SEG) - %if _LASTVARIABLE == start - 12h - %assign DIRSEARCHSTACK_CL_FIRST 1 - %elif _LASTVARIABLE == start - 10h - %assign DIRSEARCHSTACK_CL_SECOND 1 - %endif - %ifn _DIR_ENTRY_500 -; three words left on the stack after directory search - nextvariable dirsearchstack, 6, relocatestart - %else -; two words left on the stack after directory search - nextvariable dirsearchstack, 4, relocatestart - %endif - %elifn !_RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL - %if _LASTVARIABLE == start - 12h - nextvariable cmdline_signature_placeholder, 2, relocatestart - %assign PLACEHOLDER 1 - %elif _LASTVARIABLE == start - 10h - %if _PUSH_DPT - nextvariable cmdline_signature_placeholder, 4, relocatestart - %assign PLACEHOLDER 2 - ; In this case, part of the original DPT pointer may - ; overlap the CL signature word. Therefore allocate - ; two placeholder words to insure no CL match. - %else - ; In this case the last_available_sector variable - ; will be at word [ss:bp - 12h] (or none) and the - ; stack pointer will be equal to bp - 12h (or - 10h) - ; at handover time. Thus no placeholder is needed. - %endif - %else - %error Placeholder not placed - %endif - ; This stack slot is used to insure that - ; the "CL" signature is not present at this - ; location. If not relocate and load address - ; is below loader then the next variable - ; (last_available_sector) will always receive - ; a value < 7C0h so cannot hold "CL". - ; If _ATTRIB_SAVE is in use and neither the - ; _ADD_SEARCH nor the _LOAD_DIR_SEG options - ; are set, the first word of dirsearchstack - ; will be at word [ss:bp - 14h]. - %endif - -%ifn ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE -; (word) segment of last available memory for sector - nextvariable last_available_sector, 2 -%else - %if _LASTVARIABLE == start - 12h - nextvariable cmdline_signature_placeholder, 2, relocatestart - %assign PLACEHOLDER 1 - %elif _LASTVARIABLE == start - 10h - %if _PUSH_DPT - nextvariable cmdline_signature_placeholder, 4, relocatestart - %assign PLACEHOLDER 2 - %endif - %endif -%endif - -lowest_variable equ _LASTVARIABLE - - - jmp strict short skip_bpb -%if !_CHS && _LBA_SET_TYPE - db 0Eh ; LBA-enabled FAT16 FS partition type -%else - nop ; default: no LBA -%endif - - -; BIOS Parameter Block (BPB) -; -; Installation will use the BPB already present in your file system. -; These values must be initialised when installing the loader. -; -; The values shown here work only with 1440 KiB disks (CHS=80:2:18) - -oem_id: ; offset 03h (03) - not used by this code - fill 8,_OEM_NAME_FILL,db _OEM_NAME -bytes_per_sector: ; offset 0Bh (11) - refer to _FIX_SECTOR_SIZE ! - dw _BPS -sectors_per_cluster: ; offset 0Dh (13) - refer to _FIX_CLUSTER_SIZE ! - db _SPC & 255 -fat_start: -num_reserved_sectors: ; offset 0Eh (14) - dw _NUMRESERVED -num_fats: ; offset 10h (16) - db _NUMFATS -num_root_dir_ents: ; offset 11h (17) - dw _NUMROOT -total_sectors: ; offset 13h (19) - not used by this code -%if _SPI < 1_0000h - dw _SPI -%else - dw 0 -%endif -media_id: ; offset 15h (21) - not used by this code - db _MEDIAID -sectors_per_fat: ; offset 16h (22) - dw _SPF -sectors_per_track: ; offset 18h (24) - dw _CHS_SECTORS -heads: ; offset 1Ah (26) - dw _CHS_HEADS -hidden_sectors: ; offset 1Ch (28) - dd _HIDDEN -total_sectors_large: ; offset 20h (32) - not used by this code -%if _SPI >= 1_0000h - dd _SPI -%else - dd 0 -%endif - -; Extended BPB - -boot_unit: db _UNIT - db 0 -ext_bpb_signature: db 29h -serial_number: dd _VOLUMEID -volume_label: fill 11,32,db _DEFAULT_LABEL -filesystem_identifier: fill 8,32,db "FAT1",'2'+4*!!_FAT16 - - -; Initialised data - -load_name: - fill 8,32,db _LOAD_NAME - fill 3,32,db _LOAD_EXT -%if _ADD_SEARCH -add_name: - fill 8,32,db _ADD_NAME - fill 3,32,db _ADD_EXT - - ; align 2 - ; This happens to be aligned anyway. But even if - ; it didn't, we'd rather save that byte than use - ; it to align these fields. So comment this out. -dirseg: - dw _ADD_DIR_SEG -%endif - - - numdef TMPINC, 0 - -%if _TMPINC - [list -] -%endif - %imacro errorhandler 0 -%if _TMPINC - %include "error.tmp" - [list -] -%else -; === error.tmp === -error_start: - -read_sector.err: - mov al, 'R' ; Disk 'R'ead error -%if ! _MEMORY_CONTINUE || _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM - db __TEST_IMM16 ; (skip mov) -error_filetoobig: -error_memory: - mov al,'M' ; Not enough 'M'emory -%endif - -error: -%if _RELOCATE - mov bx, 7 - mov ds, bx - mov bh, [462h - 70h] -%else - mov bh, [462h] - mov bl, 7 -%endif - mov ah, 0Eh - int 10h ; display character - mov al, 07h - int 10h ; beep! - - xor ax, ax ; await key pressed - int 16h - - int 19h ; re-start the boot process - -%if _WARN_PART_SIZE - %assign num $ - error_start - %warning error size is num bytes -%endif -; === eof === -%endif -%if _TMPINC - [list +] -%endif - %endmacro - - - %imacro readhandler 0 -%if _TMPINC - %include "read.tmp" - [list -] -%else -; === read.tmp === -read_sector_start: - ; INP: dx:ax = sector - ; OUT: only if successful - ; dx:ax = incremented - ; bx => behind read sector - ; es = ADR_FATBUF>>4 = ADR_DIRBUF>>4 - ; CHG: - -%if ! _RELOCATE - %if ADR_DIRBUF == ADR_FATBUF -read_sector_dirbuf: - %endif - %if _FAT16 && ! _LOAD_NON_FAT -read_sector_fatbuf: - %endif - %if (ADR_DIRBUF == ADR_FATBUF) || (_FAT16 && ! _LOAD_NON_FAT) - mov bx, ADR_FATBUF>>4 - %if _FAT16 && _SET_FAT_SEG && ! _LOAD_NON_FAT - mov word [VAR(fat_seg)], bx - ; Optimisation: Set FAT buffer segment here where - ; we have it ready in a register, instead of - ; wasting a word immediate on it. If the FAT is - ; never read then we do not need to set the - ; variable anyway, only the sector variable has - ; to contain a -1 to indicate it's uninitialised. - ; If we get here from read_sector_dirbuf we will - ; also initialise this variable but that does not - ; cause any problems. - %endif - %endif -%endif - - ; Read a sector using Int13.02 or Int13.42 - ; - ; INP: dx:ax = sector number within partition - ; bx => buffer - ; (_LBA) ds = ss - ; OUT: If unable to read, - ; ! jumps to error instead of returning - ; If sector has been read, - ; dx:ax = next sector number (has been incremented) - ; bx => next buffer (bx = es+word[para_per_sector]) - ; es = input bx - ; CHG: - -read_sector: - push dx - push cx - push ax - push si - - mov es, bx ; => buffer - -; DX:AX==LBA sector number -; add partition start (= number of hidden sectors) - add ax,[VAR(hidden_sectors + 0)] - adc dx,[VAR(hidden_sectors + 2)] - %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33 - jc .err - %endif -%if _LBA ; +70 bytes (with CHS, +63 bytes without CHS) - %if _LBA_33_BIT - sbb si, si ; -1 if was CY, 0 else - neg si ; 1 if was CY, 0 else - %endif - xor cx, cx - push cx ; highest word = 0 - %if _LBA_33_BIT - push si ; bit 32 = 1 if operating in 33-bit space - %else - push cx ; second highest word = 0 - %endif - push dx - push ax ; = qword sector number - push bx - push cx ; bx => buffer - inc cx - push cx ; word number of sectors to read - mov cl, 10h - push cx ; word size of disk address packet - mov si, sp ; ds:si -> disk address packet (on stack) - - %if _LBA_SKIP_CHECK ; -14 bytes - mov dl, [VAR(boot_unit)] - %else - mov ah, 41h - mov dl, [VAR(boot_unit)] - mov bx, 55AAh - stc - int 13h ; 13.41.bx=55AA extensions installation check - jc .no_lba - cmp bx, 0AA55h - jne .no_lba - shr cl, 1 ; support bitmap bit 0 - jnc .no_lba - %endif - -%if _LBA_RETRY - %if _LBA_SKIP_CHECK && _LBA_SKIP_CY - stc - %endif - mov ah, 42h - int 13h ; 13.42 extensions read - jnc .lba_done - - %if _RETRY_RESET - xor ax, ax - int 13h ; reset disk - %endif - - ; have to reset the LBAPACKET's lpCount, as the handler may - ; set it to "the number of blocks successfully transferred". - ; (in any case, the high byte is still zero.) - mov byte [si + 2], 1 -%endif - - %if _LBA_SKIP_CHECK && _LBA_SKIP_CY - stc - %endif - mov ah, 42h - int 13h - %if _LBA_SKIP_CHECK && _CHS - %if _LBA_SKIP_ANY - jc .no_lba - %else - jc .lba_check_error_1 - %endif - %else -.cy_err: - jc .lba_error - %endif - -.lba_done: -%if _CHS && _LBA_SET_TYPE - mov byte [bp + 2], 0Eh ; LBA-enabled FAT16 FS partition type -%endif - add sp, 10h -%if _CHS - jmp short .done -%endif - -.lba_error: equ .err - - %if !_CHS -.no_lba: equ .err - %else - %if _LBA_SKIP_CHECK - %if ! _LBA_SKIP_ANY -.lba_check_error_1: - cmp ah, 1 ; invalid function? - jne .lba_error ; no, other error --> - ; try CHS instead - %endif -.cy_err: equ .err - %endif -.no_lba: - add sp, 8 - pop cx ; cx = low word of sector - pop ax - pop dx ; dx:ax = middle two words of sector - ; Here dx <= 1 if _LBA_33_BIT, else zero. - ; If dx is nonzero then the CHS calculation - ; should fail. If CHS sectors is equal to 1 - ; (very unusual) then the div may fail. Else, - ; we will detect a cylinder > 1023 eventually. - pop si ; discard highest word of qword - %endif -%endif - -%if !_LBA -.cy_err: equ .err -%endif - -%if _CHS ; +70 bytes -; dx:ax = LBA sector number, (if _LBA) cx = 0 -; divide by number of sectors per track to get sector number -; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability -; Use two-step 32:16 divide to avoid overflow - %if !_LBA - xchg cx, ax ; cx = low word of sector, clobbers ax - xchg ax, dx ; ax = high word of sector, clobbers dx - xor dx, dx ; dx:ax = high word of sector - %else - ; from the .no_lba popping we already have: - ; cx = low word of sector - ; dx:ax = high word of sector - %endif - div word [VAR(sectors_per_track)] - xchg cx,ax - div word [VAR(sectors_per_track)] - xchg cx,dx - -; DX:AX=quotient, CX=remainder=sector (S) - 1 -; divide quotient by number of heads - xchg bx, ax ; bx = low word of quotient, clobbers ax - xchg ax, dx ; ax = high word of quotient, clobbers dx - xor dx, dx ; dx = 0 - div word [VAR(heads)] - ; ax = high / heads, dx = high % heads - xchg bx, ax ; bx = high / heads, ax = low quotient - div word [VAR(heads)] - -; bx:ax=quotient=cylinder (C), dx=remainder=head (H) -; move variables into registers for INT 13h AH=02h - mov dh, dl ; dh = head - inc cx ; cl5:0 = sector - xchg ch, al ; ch = cylinder 7:0, al = 0 - shr ax, 1 - shr ax, 1 ; al7:6 = cylinder 9:8 - ; bx has bits set iff it's > 0, indicating a cylinder >= 65536. - or bl, bh ; collect set bits from bh - or cl, al ; cl7:6 = cylinder 9:8 - ; ah has bits set iff it was >= 4, indicating a cylinder >= 1024. - or bl, ah ; collect set bits from ah - mov dl,[VAR(boot_unit)] ; dl = drive -.nz_err: - jnz .err ; error if cylinder >= 1024 --> - ; ! bx = 0 (for 13.02 call) - -; we call INT 13h AH=02h once for each sector. Multi-sector reads -; may fail if we cross a track or 64K boundary -%if _CHS_RETRY_REPEAT - mov si, _CHS_RETRY_REPEAT + 1 - %if _CHS_RETRY_NORMAL && _RETRY_RESET - db __TEST_IMM16 ; (skip int 13h) -.loop_chs_retry_repeat: - int 13h ; reset disk - %elif _RETRY_RESET -.loop_chs_retry_repeat: - xor ax, ax - int 13h ; reset disk - %else -.loop_chs_retry_repeat: - %endif - dec si ; another attempt ? - js .nz_err ; no --> - mov ax, 0201h - int 13h ; read one sector - %if _CHS_RETRY_NORMAL && _RETRY_RESET - mov ax, bx ; ax = 0 - %endif - jc .loop_chs_retry_repeat - ; fall through to .done -%else - mov ax, 0201h - %if _CHS_RETRY - %if _RETRY_RESET - ; In this case we cannot store to the stack and - ; pop the value at the right moment for both - ; cases of the "jnc .done" branch. So use the - ; original code to re-init ax to 0201h. - int 13h ; read one sector - jnc .done -; reset drive - xor ax, ax - int 13h - mov ax, 0201h - %else - push ax - int 13h ; read one sector - pop ax ; restore ax = 0201h - jnc .done - %endif - %endif -; try read again - int 13h - %if _LBA_SKIP_CHECK - inc bx - jc .nz_err - %else - jc .cy_err - %endif -%endif - -%endif ; _CHS - -.done: -; increment segment - mov bx, es -%if _FIX_SECTOR_SIZE - add bx, _FIX_SECTOR_SIZE >> 4 -%else - add bx, [VAR(para_per_sector)] -%endif - - pop si - pop ax - pop cx - pop dx -; increment LBA sector number - inc ax - jne @F - inc dx -@@: - - retn - -%if _WARN_PART_SIZE - %assign num $ - read_sector_start - %warning read_sector size is num bytes -%endif -; === eof === -%endif -%if _TMPINC - [list +] -%endif - %endmacro -%if _TMPINC - [list +] -%endif - -%if _WARN_PART_SIZE - %assign num $ - start - %warning BPB + data size is num bytes -%endif - - -; Code - -skip_bpb: - cli - cld - xor cx, cx - mov bp, start ; magic bytes - checked by instsect - mov ss, cx - mov sp, ADR_STACK_START -%if _USE_AUTO_UNIT - mov [VAR(boot_unit)], dl; magic bytes - checked by instsect -%else - mov dl, [VAR(boot_unit)]; magic bytes - checked by instsect -%endif - - ; Note: es is left uninitialised here until the first call to - ; read_sector if the below conditional is false. -%if _USE_PART_INFO ; +19 bytes - mov es, cx -; Note: Award Medallion BIOS v6.0 (ASUS MED 2001 ACPI BIOS Revision 1009) -; loads from a floppy disk drive with ds:si = 0F000h:0A92Dh -> -; FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected -; as a valid partition table entry by this handling. Therefore, we -; only accept partition information when booting from a hard disk now. - - ; start of magic byte sequence for instsect - test dl, dl ; floppy ? - jns @F ; don't attempt detection --> -; Check whether an MBR left us partition information. -; byte[ds:si] bit 7 means active and must be set if valid. - cmp byte [si], cl ; flags for xx-00h (result is xx), SF = bit 7 - jns @F ; xx < 80h, ie info invalid --> -; byte[ds:si+4] is the file system type. Check for valid one. - cmp byte [si+4], cl ; is it zero? - je @F ; yes, info invalid --> -; Info valid, trust their hidden sectors over hardcoded. -; Assume the movsw instructions won't run with si = FFFFh. - mov di, hidden_sectors ; -> BPB field - add si, 8 ; -> partition start sector in info - %if _USE_PART_INFO_DISABLED - nop - nop ; size has to match enabled code - %else - movsw - movsw ; overwrite BPB field with value from info - %endif -@@: - ; end of magic byte sequence for instsect -%endif - mov ds, cx - sti - - -%if _QUERY_GEOMETRY ; +27 bytes - - ; start of magic byte sequence for instsect -; test dl, dl ; floppy? -; jns @F ; don't attempt query, might fail --> - ; Note that while the original PC BIOS doesn't support this function - ; (for its diskettes), it does properly return the error code 01h. - ; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1) - mov ah, 08h - ; xor cx, cx ; initialise cl to 0 - ; Already from prologue cx = 0. - stc ; initialise to CY - %if _QUERY_GEOMETRY_DISABLED - nop - nop ; size has to match enabled code - %else - int 13h ; query drive geometry - %endif - jc @F ; apparently failed --> - and cx, 3Fh ; get sectors - jz @F ; invalid (S is 1-based), don't use --> - mov [VAR(sectors_per_track)], cx - mov cl, dh ; cx = maximum head number - inc cx ; cx = number of heads (H is 0-based) - mov [VAR(heads)], cx -@@: - ; end of magic byte sequence for instsect -%endif - -%if _FIX_SECTOR_SIZE - %if !_FIX_SECTOR_SIZE_SKIP_CHECK - cmp word [VAR(bytes_per_sector)], _FIX_SECTOR_SIZE - mov al, 'S' - jne error - %endif - mov bx, _FIX_SECTOR_SIZE >> 5 - %if _FIX_CLUSTER_SIZE - %if !_FIX_CLUSTER_SIZE_SKIP_CHECK - cmp byte [VAR(sectors_per_cluster)], _FIX_CLUSTER_SIZE & 0FFh - mov al, 'C' - jne error - %endif - %endif - mov ch, 0 ; ! ch = 0 -%else -; 16-byte paragraphs per sector - mov bx,[VAR(bytes_per_sector)] - mov cx,4 ; ! ch = 0 - shr bx,cl - %if _FIX_CLUSTER_SIZE - %if !_FIX_CLUSTER_SIZE_SKIP_CHECK - cmp byte [VAR(sectors_per_cluster)], _FIX_CLUSTER_SIZE & 0FFh - mov al, 'C' - jne error - %endif - %else - ; ! ch = 0 - %endif - push bx ; push into word [VAR(para_per_sector)] - -; 32-byte FAT directory entries per sector - shr bx, 1 ; /2 = 32-byte entries per sector -%endif - -%if _WARN_PART_SIZE - %assign num $ - skip_bpb - %warning init size is num bytes -%endif - - -dirsearch_start: - -; number of sectors used for root directory (store in CX) - mov si, [VAR(num_root_dir_ents)] - mov ax, bx - ; The ax value here is the last value of bx, which is set - ; by the shr instruction. Therefore, it cannot be higher - ; than 7FFFh, so this cwd instruction always zeros dx. - cwd - dec ax ; rounding up - add ax, si ; from BPB - adc dx, dx ; account for overflow (dx was zero) - div bx ; get number of root sectors - xchg ax, cx ; cx = number of root secs, ! ah = 0 - -; first sector of root directory - mov al,[VAR(num_fats)] ; ! ah = 0, hence ax = number of FATs - mul word [VAR(sectors_per_fat)] - add ax,[VAR(num_reserved_sectors)] - adc dl, dh ; account for overflow (dh was and is 0) - - xor di, di - -; first sector of disk data area: - add cx, ax - adc di, dx - mov [VAR(data_start)], cx - mov [VAR(data_start+2)], di - -next_dir_search: -%if _ADD_SEARCH - push dx - push ax - push si -%endif - -; Scan root directory for file. We don't bother to check for deleted -; entries (E5h) or entries that mark the end of the directory (00h). - ; number of root entries in si here -next_sect: - mov cx, bx ; entries per sector as loop counter -%if ! _RELOCATE - %if ADR_DIRBUF == ADR_FATBUF - call read_sector_dirbuf - %else - mov bx, ADR_DIRBUF>>4 - call read_sector - %endif -%else - mov bx, ADR_DIRBUF>>4 - call read_sector -%endif - mov bx, cx ; restore bx for next iteration later - - xor di, di ; es:di-> first entry in this sector -next_ent: - %if DIRSEARCHSTACK_CL_FIRST - push cx ; first dirsearchstack word = entries-in-sector - push si ; other: entries total - %else - push si - push cx ; second dirsearchstack word = entries-in-sector - %endif - push di ; dirsearchstack -%if _CHECK_ATTRIB && ! _ATTRIB_SAVE - test byte [es:di + deAttrib], ATTR_DIRECTORY | ATTR_VOLLABEL - jnz @F ; directory, label, or LFN entry --> (NZ) -%endif -%if _ADD_SEARCH - mov si, add_name -filename equ $ - 2 ; SMC to update to load_name later -%else - mov si, load_name ; ds:si-> name to match -%endif - mov cx, 11 ; length of padded 8.3 FAT filename - repe cmpsb ; check entry -%if _ATTRIB_SAVE - %if _CHECK_ATTRIB - jnz @F - ; deAttrib == 11, right after the 11-byte name - test byte [es:di], ATTR_DIRECTORY | ATTR_VOLLABEL - ; directory, label, or LFN entry ? - %endif - jz found_it ; found entry --> -%endif -@@: - pop di - %if DIRSEARCHSTACK_CL_FIRST - pop si - pop cx ; pop from dirsearchstack - %else - pop cx - pop si ; pop from dirsearchstack - %endif - lea di, [di + DIRENTRY_size] -%if ! _ATTRIB_SAVE - jz found_it ; found entry --> -%endif - - dec si ; count down entire root's entries - loopnz next_ent ; count down sector's entries (jumps iff si >0 && cx >0) - jnz next_sect ; (jumps iff si >0 && cx ==0) - ; ends up here iff si ==0 - ; ie all root entries checked unsuccessfully -%if 0 - -qemu prior to 2020-08 has a bug which affects the above -conditionals. The bug is that if NZ is set (like when the -branch to the label found_it is not taken) and then another -instruction sets ZR (like the dec si at the end of the root -directory) and then loopnz is used which sets cx to zero -then after the loopnz FL will be NZ leading to the jnz branch -to be taken. Eventually the entire load unit is traversed and -qemu returns error 01h when trying to read past the end of -the unit (at least for 1440 KiB diskettes). - -The bug can be worked around in two ways as done by lDebug: - -https://hg.pushbx.org/ecm/ldebug/rev/c95e2955bbca - -https://hg.pushbx.org/ecm/ldebug/rev/c84047f15d9c - -However, both cost a few bytes each. Therefore the proper -fix is considered to be updating qemu. Error behaviour occurs -when a file is not found. In an unlikely case, another sector -in the data area may hold a match for the searched entry. -Otherwise, the read eventually fails and the loader aborts -with an R error (instead of the expected F error). - -Reference: https://bugs.launchpad.net/qemu/+bug/1888165 - -%endif - - mov al,'F' ; File not 'F'ound - jmp error - -found_it: -%if _ADD_SEARCH || _LOAD_DIR_SEG - %if _ATTRIB_SAVE - pop di ; es:di -> dir entry (pop from dirsearchstack) - %endif - mov cx, 32 - mov ax, _LOAD_DIR_SEG - %if ! _ATTRIB_SAVE - sub di, cx ; es:di -> dir entry - %endif - %if _ADD_SEARCH - xchg ax, word [VAR(dirseg)] - %endif - push ds - mov si, di - push di - push es - pop ds ; ds:si -> dir entry - mov es, ax - xor di, di ; es:di -> destination - rep movsb ; store dir entry - push ds - pop es - pop di ; restore es:di -> dir entry - pop ds - %if _ADD_SEARCH -%if ((load_name - start) & 0FF00h) == ((add_name - start) & 0FF00h) - mov byte [VAR(filename)], (load_name - start + 7C00h) & 255 -%else - mov word [VAR(filename)], load_name -%endif - ; update name to second iteration's -%if (_LOAD_DIR_SEG & 255) != (_ADD_DIR_SEG & 255) - cmp al, _ADD_DIR_SEG & 255 -%elif (_LOAD_DIR_SEG) != (_ADD_DIR_SEG) - cmp ax, _ADD_DIR_SEG ; was first iteration ? -%else - %error Must not store directory entries to same segment -%endif - %if _ATTRIB_SAVE - pop si ; discard cx/si - pop si ; discard si/cx (dirsearchstack) - %endif - pop si - pop ax - pop dx ; restore root start and count - ; (bx still holds entries per sector) - je next_dir_search ; jump to search load file next --> - %endif - times PLACEHOLDER push bx - ; push into cmdline_signature_placeholder - %if _RELOCATE - push word [es:di + deClusterLow] - ; (word on stack) = first cluster number - %endif -%else - %if _DIR_ENTRY_500 ; +24 bytes, probably - mov cx, 32 - %if _ATTRIB_SAVE - pop si ; es:si -> dir entry (pop from dirsearchstack) - %else - xchg si, di - sub si, cx - %endif - push ds - push es - push es - pop ds ; ds:si -> directory entry - xor ax, ax - mov es, ax - mov di, 500h ; es:di -> 0:500h - %if _DIR_ENTRY_520 - rep movsw ; move to here (two directory entries) - %else - rep movsb ; move to here - %endif - pop es - pop ds - xchg si, di ; es:di -> behind (second) directory entry - %endif - times PLACEHOLDER push bx - ; push into cmdline_signature_placeholder - ; Push the entries per sector value into this - ; stack slot to ensure that it does not hold "CL". - %if _RELOCATE - %if _DIR_ENTRY_500 || !_ATTRIB_SAVE - push word [es:di + deClusterLow - DIRENTRY_size \ - - (DIRENTRY_size * !!_DIR_ENTRY_520)] - ; (word on stack) = first cluster number - %else - push word [es:di + deClusterLow - (deName + 11)] - ; (word on stack) = first cluster number - %endif - %endif -%endif - -%if _WARN_PART_SIZE - %assign num $ - dirsearch_start - %warning dirsearch size is num bytes -%endif - - -%if _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM -memory_start: -; Get conventional memory size and store it - int 12h - mov cl, 6 - shl ax, cl - %if _RPL ; +31 bytes - xchg dx, ax - lds si, [4 * 2Fh] - add si, 3 - lodsb - cmp al, 'R' - jne .no_rpl - lodsb - cmp al, 'P' - jne .no_rpl - lodsb - cmp al, 'L' - jne .no_rpl - mov ax, 4A06h - int 2Fh -.no_rpl: - push ss - pop ds - xchg ax, dx - %endif - %if _RELOCATE - %if _LOAD_NON_FAT - sub ax, (_RPL_GRACE_AREA + 20 * 1024 \ - + 512 + 7C00h) >> 4 - %else - sub ax, (_RPL_GRACE_AREA + 20 * 1024 \ - + 8192 + (8192-16) + 512 + 7C00h) >> 4 - %endif - ; RPL grace area preserved for RPL - ; 20 KiB: reserved for iniload - ; 8 KiB: FAT buffer - ; 8 KiB - 16 B: to allow rounding down FAT buffer position - ; 512: sector - ; 7C00h: stack and to allow addressing with 7C00h in bp - ; - ; Note also that by addressing the stack and sector - ; with bp at 7C00h, and insuring this subtraction doesn't - ; underflow, makes sure that we do not overwrite the IVT or - ; BDA. (However, we assume that ax is at least 60h or so.) - ; - ; The FAT buffer segment is masked so that the actual buffer - ; is stored on an 8 KiB boundary. This is to ensure that - ; the buffer doesn't possibly cross a 64 KiB DMA boundary. - jc .error_memory_j_CY - cmp ax, (end -start+7C00h - ADR_STACK_LOW + 15) >> 4 - ; This check is to ensure that the start of the destination - ; for the relocation (stack, sector) is - ; above-or-equal the end of the source for the relocation. - ; That is, to avoid overwriting any of the source with the - ; string move instruction (which for simplicity is always UP). -.error_memory_j_CY: - jb error_memory - %if ! _LOAD_NON_FAT - mov bx, ((8192 - 16) + 512 + 7C00h)>>4 - add bx, ax -; this is like calculating the following for the bx value: -; ((LMA_top - 20 KiB - 8 KiB - (8 KiB - 16 B) - 512 - 7C00h) + \ -; ((8 KiB - 16 B) + 512 + 7C00h))>>4 -; == (LMA_top - 20 KiB - 8 KiB)>>4 - and bx, ~ ((8192>>4) - 1) - mov word [VAR(fat_seg)], bx - %endif - - mov di, relocated - push ax - push di ; -> relocation target label relocated - ; (We cannot use a near call here to push the target IP - ; because we do not control whether the ROM-BIOS loader - ; entered us at 0:7C00h or 7C0h:0. So we need to create - ; the correct offset manually here.) - - mov es, ax ; => destination - mov si, sp ; ds:si = ss:_RELOCATESTART - 2 - 4 - mov di, si ; es:di -> destination for stack low - mov cx, (end - (_RELOCATESTART - 2 - 4)) >> 1 - ; end is the top of used memory - ; _RELOCATESTART is the lowest filled stack frame slot - ; 2 is for the first cluster word on the stack - ; 4 is for the additional slots taken by the return address - rep movsw ; relocate stack, sector - retf ; jump to relocated code - -%if _WARN_PART_SIZE - %assign num $ - memory_start - %warning memory size is num bytes -%endif - - - readhandler - - errorhandler - - -relocated: - mov ss, ax - mov ds, ax ; relocate these - add ax, (ADR_STACK_LOW) >> 4 ; (rounding down) => behind available - - pop si - %else - sub ax, (_RPL_GRACE_AREA + 20 * 1024) >> 4 - ; RPL grace area, plus - ; 20 KiB reserved for iniload - jb error_memory - %endif -%elif _LOAD_ADR < ADR_FREE_UNTIL - %if !_FIX_SECTOR_SIZE - mov ax, ADR_FREE_UNTIL >> 4 ; rounding *down* - %endif -%else - %error Load address within used memory -%endif -%if ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE - ; user of last_available_sector will hardcode the value! -%else - %if _FIX_SECTOR_SIZE - sub ax, _FIX_SECTOR_SIZE >> 4 - %else - sub ax, [VAR(para_per_sector)] - %endif - push ax ; push into word [VAR(last_available_sector)] -%endif - -read_fat_start: -; get starting cluster of file -%if ! _RELOCATE - %if _ADD_SEARCH || _LOAD_DIR_SEG - mov si,[es:di + deClusterLow] - %elif _ATTRIB_SAVE && ! _DIR_ENTRY_500 - mov si,[es:di - deAttrib + deClusterLow] - %else - mov si,[es:di + deClusterLow - DIRENTRY_size \ - - (DIRENTRY_size * !!_DIR_ENTRY_520)] - %endif -%endif -%if _SET_CLUSTER - mov word [VAR(first_cluster)], si -%endif -%if _SET_DI_CLUSTER - push si ; remember cluster for later -%endif - -%if !_FAT16 && !_LOAD_NON_FAT -; Load the entire FAT into memory. This is easily feasible for FAT12, -; as the FAT can only contain at most 4096 entries. -; (The exact condition should be "at most 4087 entries", or with a -; specific FF7h semantic, "at most 4088 entries"; the more reliable -; and portable alternative would be "at most 4080 entries".) -; Thus, no more than 6 KiB need to be read, even though the FAT size -; as indicated by word[sectors_per_fat] could be much higher. The -; first loop condition below is to correctly handle the latter case. -; (Sector size is assumed to be a power of two between 32 and 8192 -; bytes, inclusive. An 8 KiB buffer is necessary if the sector size -; is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB -; of memory instead of only the relevant 6 KiB. This is always true -; if the sector size is 8 KiB, and with 4 KiB sector size it is true -; iff word[sectors_per_fat] is higher than one.) - mov di, 6 << 10 ; maximum size of FAT12 to load - mov cx, [VAR(sectors_per_fat)] - ; maximum size of this FS's FAT -%if ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && !_FIX_SECTOR_SIZE - ; Under these conditions, ax here is - ; below ADR_FREE_UNTIL >> 4 so the - ; following cwd instruction zeros dx. - cwd -%else - xor dx, dx -%endif - mov ax, [VAR(fat_start)]; = first FAT sector - %if _RELOCATE - ; bx already = FAT buffer segment here - %else - mov bx, ADR_FATBUF>>4 - %if _SET_FAT_SEG - mov word [VAR(fat_seg)], bx - %endif - %endif -@@: - call read_sector ; read next FAT sector -%if _FIX_SECTOR_SIZE - sub di, _FIX_SECTOR_SIZE -%else - sub di, [VAR(bytes_per_sector)] -%endif - ; di = bytes still left to read - jbe @F ; if none --> - ; (jbe means jump if CF || ZF) - loop @B ; if any FAT sector still remains --> -@@: ; one of the limits reached; FAT read -%endif - - mov bx, _LOAD_ADR>>4 ; => load address -%if _FAT16 && !_LOAD_NON_FAT - mov di, -1 ; = no FAT sector read yet - %if _SET_FAT_SEG && _SET_FAT_SEG_NORMAL - ; This is not strictly needed because a FAT sector is - ; read in any case, initialising this variable later. - mov word [VAR(fat_sector)], di - %endif -%endif -%if _LOAD_NON_FAT - %if _SET_FAT_SEG - %if _FAT16 - or word [VAR(fat_sector)], -1 - %else - and word [VAR(fat_seg)], 0 - %endif - %endif -%endif - -next_cluster: -; convert 16-bit cluster value (in SI) to 32-bit LBA sector value (in DX:AX) -; and get next cluster in SI - - - ; Converts cluster number to sector number - ; and finds next cluster in chain - ; - ; INP: si = valid cluster number - ; (!_FAT16) [ADR_FATBUF] = entire FAT as read from FS - ; (_FAT16) di = currently buffered FAT sector, -1 if none - ; OUT: If unable to read a FAT sector, - ; ! jumps to error instead of returning - ; If everything is okay, - ; si = next cluster number (or EOC value) - ; dx:ax = sector number - ; (_FAT16) di = currently buffered FAT sector - ; CHG: cx - -%if ! _LOAD_NON_FAT -; prepare to load entry from FAT - -%if _FAT16 - push si ; preserve cluster number for later - -; Multiply cluster number by 2. - xchg ax, si - ; xor dx, dx ; dx:ax = entry to load (0..FFF6h) - ; add ax, ax - ; adc dx, dx ; dx:ax = byte offset into FAT (0..131052) - cwd ; dx = FFFFh if ax >= 8000h, else = 0 - add ax, ax ; ax = (2 * ax) & FFFFh - neg dx ; dx = 1 if 2 * ax overflowed, else = 0 - -; Divide by sector size to split dx:ax into the remainder as the byte offset -; into the FAT sector, and quotient as the sector offset into the FAT. - div word [VAR(bytes_per_sector)] - mov si, dx ; = byte offset in sector - ; dx = byte offset into sector (0..8190) - ; ax = sector offset into FAT (0..4095) - -; quotient in AX is FAT sector. -; check the FAT buffer to see if this sector is already loaded -; (simple disk cache; speeds things up a little -- -; actually, it speeds things up a lot) - cmp ax, di - je @F - mov di, ax - %if _SET_FAT_SEG - mov word [VAR(fat_sector)], ax - %endif - -; read the target FAT sector. - push bx - ; As noted above, the sector offset in ax here is - ; 0..4095 (ie, 4 Ki S * 32 B/S = 128 KiB of FAT data), - ; therefore this cwd instruction always zeros dx. - cwd - add ax, [VAR(fat_start)] - adc dx, dx ; (account for overflow) - %if _RELOCATE - mov bx, word [VAR(fat_seg)] - call read_sector - %else - call read_sector_fatbuf - %endif - pop bx -@@: - -; get 16 bits from FAT - es lodsw - xchg ax, si - pop ax ; restore cluster number -%else -; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2, -; so multiply cluster number by 3 first, then divide by 2. - mov ax, si ; = cluster number (up to 12 bits set) - ; (remember cluster number in ax) - shl si, 1 ; = 2n (up to 13 bits set) - add si, ax ; = 2n+n = 3n (up to 14 bits set) - shr si, 1 ; si = byte offset into FAT (0..6129) - ; CF = whether to use high 12 bits - %if _RELOCATE - mov es, word [VAR(fat_seg)] - ; es lodsw - ; xchg ax, si - mov si, word [es:si] - %else -; Use the calculated byte offset as an offset into the FAT -; buffer, which holds all of the FAT's relevant data. - ; lea si, [ADR_FATBUF + si] - ; -> 16-bit word in FAT to load -; get 16 bits from FAT - ; lodsw - ; xchg ax, si - mov si, [ADR_FATBUF + si] - ; = 16-bit word in FAT to load - %endif - - mov cl, 4 - jc @F ; iff CY after shift --> - shl si, cl ; shift up iff even entry -@@: - shr si, cl ; shift down (clears top 4 bits) - - ; (ax holds cluster number) -%endif - -%else ; _LOAD_NON_FAT - mov di, _LOAD_NON_FAT - mov al, [VAR(sectors_per_cluster)] - dec ax - mov ah, 0 - inc ax - mov cx, ax - mul word [VAR(bytes_per_sector)] - test dx, dx - jnz @F - cmp ax, di - mov al, 'N' - jb error -@@: - xchg ax, si -%endif -; adjust cluster number to make it 0-based - dec ax - dec ax - -%if ! _LOAD_NON_FAT -%if _FIX_CLUSTER_SIZE - mov cx, _FIX_CLUSTER_SIZE -%else -; adjusted sectors per cluster -; decode EDR-DOS's special value 0 meaning 256 - mov cl, [VAR(sectors_per_cluster)] - dec cx - mov ch, 0 - inc cx -%endif -%endif - -; convert from clusters to sectors - mul cx - add ax, [VAR(data_start)] - adc dx, [VAR(data_start)+2] - ; dx:ax = sector number - -; xxx - this will always load an entire cluster (e.g. 64 sectors), -; even if the file is shorter than this -@@: - %if ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE - cmp bx, (ADR_FREE_UNTIL >> 4) - (_FIX_SECTOR_SIZE >> 4) - %else - cmp bx, [VAR(last_available_sector)] - %endif -%if _MEMORY_CONTINUE - ja @F -%else - ja error_filetoobig -%endif -%if _FAT16 && ! _LOAD_NON_FAT - push es ; (must preserve ADR_FATBUF reference) -%endif - call read_sector -%if _FAT16 && ! _LOAD_NON_FAT - pop es -%endif -%if _SET_LOAD_SEG - mov [VAR(load_seg)], bx ; => after last read data -%endif -%if _LOAD_NON_FAT - sub di, word [VAR(bytes_per_sector)] - ja @B -%else - loop @B - -%if _FAT16 -; FFF7h: bad cluster -; FFF8h-FFFFh: end of cluster chain - cmp si, 0FFF7h -%else -; 0FF7h: bad cluster -; 0FF8h-0FFFh: end of cluster chain - cmp si, 0FF7h -%endif - jb next_cluster -%endif ; _LOAD_NON_FAT -@@: - -%if _WARN_PART_SIZE - %assign num $ - read_fat_start - %warning read_fat size is num bytes -%endif - - -finish_start: -%if _LOAD_MIN_PARA - %if ((_LOAD_ADR >> 4) + _LOAD_MIN_PARA) & 255 == 0 - ; If the value is divisible by 256 we can compare only the - ; high byte for the same CF result: NC iff bx >= limit. - cmp bh, ((_LOAD_ADR >> 4) + _LOAD_MIN_PARA) >> 8 - %else - cmp bx, (_LOAD_ADR >> 4) + _LOAD_MIN_PARA - %endif - mov al, 'E' - jb error -%endif - -%if _TURN_OFF_FLOPPY -; turn off floppy motor - mov dx,3F2h - mov al,0 - out dx,al -%endif - -; Set-up registers for and jump to loaded file -; Already: ss:bp-> boot sector containing BPB -%if _CHECKVALUE -CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET - %if ! _RELOCATE && CHECKLINEAR <= (64 * 1024 - 2) - cmp word [CHECKLINEAR], _CHECKVALUE - %else - mov ax, CHECKLINEAR >> 4 - mov es, ax - cmp word [es:CHECKLINEAR & 15], _CHECKVALUE - %endif - mov al, 'V' ; check 'V'alue mismatch - jne error -%endif -%if _SET_DL_UNIT - mov dl, [VAR(boot_unit)]; set dl to unit -%endif -%if _SET_DI_CLUSTER && (_PUSH_DPT || _SET_DSSI_DPT) - pop cx -%endif -%if _DATASTART_HIDDEN - mov bx, [VAR(hidden_sectors + 0)] - mov ax, [VAR(hidden_sectors + 2)] - add word [VAR(data_start + 0)], bx - adc word [VAR(data_start + 2)], ax -%endif -%if _SET_BL_UNIT - %if _SET_DL_UNIT - mov bl, dl ; set bl to unit, too - %else - mov bl, [VAR(boot_unit)]; set bl to unit - %endif -%endif -%if _PUSH_DPT || _SET_DSSI_DPT - %ifn _SET_DSSI_DPT ; (implying that only _PUSH_DPT is set) - %if _RELOCATE - xor ax, ax - mov es, ax - mov di, 1Eh * 4 - les si, [es:di] - push es - push si - push ax - push di - %else - mov di, 1Eh*4 - les si, [di] ; -> original (also current) DPT - push es - push si ; original (also current) DPT address - push ss - push di ; 0000h:0078h (address of 1Eh IVT entry) - %endif - %else - %if _RELOCATE - xor ax, ax - mov ds, ax - %endif - mov di, 1Eh*4 - lds si, [di] ; -> original (also current) DPT - %if _PUSH_DPT - push ds - push si ; original (also current) DPT address - %if _RELOCATE - push ax - push di - %else - push ss - push di ; 0000h:0078h (address of 1Eh IVT entry) - %endif - %endif - %endif -%else - %if _RELOCATE && (_ZERO_ES || _ZERO_DS) - xor ax, ax - %endif -%endif -%if _RELOCATE - %if _ZERO_ES - mov es, ax - %endif - %if _ZERO_DS - mov ds, ax - %endif -%endif - -%if _SET_AXBX_DATA - mov bx, [VAR(data_start)] - mov ax, [VAR(data_start+2)] -%endif -%if _SET_DI_CLUSTER - %if _PUSH_DPT || _SET_DSSI_DPT - mov di, cx - %else - pop di - %endif -%endif -%if ! _RELOCATE - %if _ZERO_ES - push ss - pop es - %endif -%endif - ; ss:bp-> boot sector with BPB - jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS - - -%if _WARN_PART_SIZE - %assign num $ - finish_start - %warning finish size is num bytes -%endif - - -%if ! _RELOCATE - errorhandler - - readhandler -%endif - - -%if !_NO_LIMIT -available: - _fill 508,38,start - -signatures: - dw 0 -; 2-byte magic bootsector signature - dw 0AA55h - -%assign num signatures-available -%assign fatbits 12 -%if _FAT16 - %assign fatbits 16 -%endif -%warning FAT%[fatbits]: num bytes still available. -%endif - -end: diff --git a/test/ldosboot/boot32.asm b/test/ldosboot/boot32.asm deleted file mode 100644 index a922c70c..00000000 --- a/test/ldosboot/boot32.asm +++ /dev/null @@ -1,1820 +0,0 @@ - -%if 0 - -File system boot sector loader code for FAT32 - -Adapted from 2002-11-26 fatboot.zip/fat12.asm, - released as public domain by Chris Giese - -Public domain by C. Masloch, 2012 - -%endif - - -%include "lmacros2.mac" - -%ifndef _MAP -%elifempty _MAP -%else ; defined non-empty, str or non-str - [map all _MAP] -%endif - - defaulting - - strdef OEM_NAME, " lDOS" - strdef OEM_NAME_FILL, '_' - strdef DEFAULT_LABEL, "lDOS" - numdef VOLUMEID, 0 - strdef FSIBOOTNAME, "FSIBOOT4" - ; used to set experimental name - ; strdef FSIBOOTNAME, "FSIBEX02" - - strdef LOAD_NAME, "LDOS" - strdef LOAD_EXT, "COM" ; name of file to load - numdef LOAD_ADR, 02000h ; where to load - numdef LOAD_MIN_PARA, paras(1536) - numdef EXEC_SEG_ADJ, 0 ; how far cs will be from _LOAD_ADR - numdef EXEC_OFS, 400h ; what value ip will be - numdef CHECKOFFSET, 1020 - numdef CHECKVALUE, "lD" - numdef LOAD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere) - numdef ADD_SEARCH, 0 ; whether to search second file - strdef ADD_NAME, "" - strdef ADD_EXT, "" ; name of second file to search - numdef ADD_DIR_SEG, 0 ; => where to store dir entry (0 if nowhere) - - numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) - numdef QUERY_GEOMETRY_DISABLED, 0 - numdef USE_PART_INFO, 1 ; use ds:si-> partition info from MBR, if any - numdef USE_PART_INFO_DISABLED, 0 - numdef USE_AUTO_UNIT, 1 ; use unit passed from ROM-BIOS in dl - numdef RPL, 1 ; support RPL and do not overwrite it - numdef CHS, 1 ; support CHS (if it fits) - numdef LBA, 1 ; support LBA (if available) - numdef LBA_33_BIT, 1 ; support 33-bit LBA - numdef LBA_CHECK_NO_33, 1 ; else: check that LBA doesn't carry - - numdef RELOCATE, 0 ; relocate the loader to top of memory - numdef SET_DL_UNIT, 0 ; if to pass unit in dl - numdef SET_BL_UNIT, 0 ; if to pass unit in bl as well - numdef SET_AXBX_DATA, 0 ; if to pass first data sector in ax:bx - numdef SET_DSSI_DPT, 0 ; if to pass DPT address in ds:si - numdef PUSH_DPT, 0 ; if to push DPT address - numdef MEMORY_CONTINUE, 1 ; if to just execute when memory full - numdef SET_SIDI_CLUSTER,0 ; if to pass first load file cluster in si:di - numdef TURN_OFF_FLOPPY, 0 ; if to turn off floppy motor after loading - numdef DATASTART_HIDDEN,0 ; if to add hidden sectors to data_start - numdef LBA_SET_TYPE, 0 ; if to set third byte to LBA partition type - numdef SET_LOAD_SEG, 1 ; if to set load_seg (word [ss:bp - 6]) - numdef SET_FAT_SEG, 1 ; if to set fat_seg (word [ss:bp - 8]) - numdef SET_CLUSTER, 1 ; if to set first_cluster (dword [ss:bp - 16]) - numdef ZERO_ES, 0 ; if to set es = 0 before jump - numdef ZERO_DS, 0 ; if to set ds = 0 before jump - - numdef FIX_SECTOR_SIZE, 0 ; fix sector size (0 = disable, else = sector size) - numdef FIX_SECTOR_SIZE_SKIP_CHECK, 0 ; don't check sector size - numdef FIX_CLUSTER_SIZE, 0 ; fix cluster size - numdef FIX_CLUSTER_SIZE_SKIP_CHECK, 0 ; don't check cluster size - numdef NO_LIMIT, 0 ; allow using more memory than a boot sector - ; also will not write 0AA55h signature! - numdef WARN_PART_SIZE, 0 - - numdef LBA_SKIP_CHECK, 1 ; don't use proper LBA extensions check - numdef LBA_SKIP_CY, 1 ; skip check: set up CY before 13.42 - numdef LBA_SKIP_ANY, 0 ; skip check: try CHS on any error - incdef _LBA_SKIP_ANY, LBA_SKIP_CY - numdef LBA_RETRY, 0 ; retry LBA reads one time - numdef CHS_RETRY, 1 ; retry CHS reads one time - numdef CHS_RETRY_REPEAT,16 ; retry CHS reads multiple times - ; (value of the def is used as count) - numdef CHS_RETRY_NORMAL,1 ; do not use aggressive optimisation - numdef RETRY_RESET, 1 ; call reset disk system 13.00 on retries - - ; Unlike the 1440 KiB diskette image defaults for the FAT12 - ; loader we just fill the BPB with zeros by default. - numdef MEDIAID, 0 ; media ID - numdef UNIT, 0 ; load unit in BPB - numdef CHS_SECTORS, 0 ; CHS geometry field for sectors - numdef CHS_HEADS, 0 ; CHS geometry field for heads - numdef HIDDEN, 0 ; number of hidden sectors - numdef SPI, 0 ; sectors per image - numdef BPS, 0 ; bytes per sector - numdef SPC, 0 ; sectors per cluster - numdef SPF, 0 ; sectors per FAT - numdef SECTOR_FSINFO, 0 ; FSINFO sector - numdef SECTOR_BACKUP, 0 ; backup boot sector - numdef CLUSTER_ROOT, 0 ; root directory first cluster - numdef NUMFATS, 0 ; number of FATs - numdef NUMRESERVED, 0 ; number of reserved sectors - - numdef COMPAT_FREEDOS, 0 ; partial FreeDOS load compatibility - numdef COMPAT_IBM, 0 ; partial IBMDOS load compatibility - numdef COMPAT_MS7, 0 ; partial MS-DOS 7 load compatibility - numdef COMPAT_LDOS, 0 ; lDOS load compatibility - -%if (!!_COMPAT_FREEDOS + !!_COMPAT_IBM + !!_COMPAT_MS7 + !!_COMPAT_LDOS) > 1 - %error At most one set must be selected. -%endif - -%if _COMPAT_FREEDOS - strdef LOAD_NAME, "KERNEL" - strdef LOAD_EXT, "SYS" - numdef LOAD_ADR, 00600h - numdef LOAD_MIN_PARA, paras(512) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 0 - numdef CHECKVALUE, 0 - - numdef SET_BL_UNIT, 1 - numdef MEMORY_CONTINUE, 0 - numdef RELOCATE, 1 - ; The FreeDOS load protocol mandates that the entire file be loaded. -%endif - -%if _COMPAT_IBM - strdef LOAD_NAME, "IBMBIO" - strdef LOAD_EXT, "COM" - numdef LOAD_ADR, 00700h - numdef LOAD_MIN_PARA, paras(512) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 0 - numdef CHECKVALUE, 0 - numdef LOAD_DIR_SEG, 50h - numdef ADD_SEARCH, 1 - strdef ADD_NAME, "IBMDOS" - strdef ADD_EXT, "COM" - numdef ADD_DIR_SEG, 52h - ; Note: The IBMBIO.COM directory entry must be stored at - ; 0:500h, and the IBMDOS.COM directory entry at 0:520h. - - numdef SET_DL_UNIT, 1 - numdef MEMORY_CONTINUE, 1 - ; 3 sectors * 512 BpS should suffice. We load into 700h--7A00h, - ; ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB). - numdef SET_AXBX_DATA, 1 - numdef DATASTART_HIDDEN,1 - numdef SET_DSSI_DPT, 1 - numdef PUSH_DPT, 1 -%endif - -%if _COMPAT_MS7 - strdef LOAD_NAME, "IO" - strdef LOAD_EXT, "SYS" - numdef LOAD_ADR, 00700h - numdef LOAD_MIN_PARA, paras(1024) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 200h - numdef CHECKVALUE, 0 - - numdef SET_DL_UNIT, 1 - numdef SET_DSSI_DPT, 0 - numdef PUSH_DPT, 1 - numdef MEMORY_CONTINUE, 1 - ; 4 sectors * 512 BpS should suffice. We load into 700h--7A00h, - ; ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB). - numdef SET_SIDI_CLUSTER,1 - numdef DATASTART_HIDDEN,1 - numdef LBA_SET_TYPE, 1 -%endif - -%if _COMPAT_LDOS - strdef LOAD_NAME, "LDOS" - strdef LOAD_EXT, "COM" - numdef LOAD_ADR, 02000h - numdef LOAD_MIN_PARA, paras(1536) - numdef EXEC_SEG_ADJ, 0 - numdef EXEC_OFS, 400h - numdef CHECKOFFSET, 1020 - numdef CHECKVALUE, "lD" - - numdef SET_DL_UNIT, 0 - numdef SET_CLUSTER, 1 - numdef SET_FAT_SEG, 1 - numdef SET_LOAD_SEG, 1 - numdef MEMORY_CONTINUE, 1 - numdef DATASTART_HIDDEN,0 -%endif - -%if 0 - -Notes about partial load compatibilities - -* FreeDOS: - * Relocates to an address other than 27A00h (1FE0h:7C00h) -* IBMDOS: - * Does not actually relocate DPT, just provide its address -* MS-DOS 7: - * Does not actually relocate DPT, just provide its address - * Does not contain message table used by loader - -%endif - -%if _SET_BL_UNIT && _SET_AXBX_DATA - %error Cannot select both of these options! -%endif - - -%assign LOADLIMIT 0A0000h -%assign POSITION 07C00h - -%if _FIX_SECTOR_SIZE - %assign i 5 - %rep 13-5 - %if (1 << i) != (_FIX_SECTOR_SIZE) - %assign i i+1 - %endif - %endrep - %if (1 << i) != (_FIX_SECTOR_SIZE) - %error Invalid sector size _FIX_SECTOR_SIZE - %endif -%endif - -%if _FIX_CLUSTER_SIZE - %if _FIX_CLUSTER_SIZE > 256 - %error Invalid cluster size _FIX_CLUSTER_SIZE - %endif - %assign i 0 - %rep 8-0 - %if (1 << i) != (_FIX_CLUSTER_SIZE) - %assign i i+1 - %endif - %endrep - %if (1 << i) != (_FIX_CLUSTER_SIZE) - %warning Non-power-of-two cluster size _FIX_CLUSTER_SIZE - %endif -%endif - - -%if (_LOAD_ADR & 0Fh) - %error Load address must be on a paragraph boundary -%endif - -%if _LOAD_ADR > LOADLIMIT - %error Load address must be in LMA -%elif _LOAD_ADR < 00500h - %error Load address must not overlap IVT or BDA -%endif -%if ! _RELOCATE - %if _LOAD_ADR > (POSITION-512) && _LOAD_ADR < (POSITION+1024) - %error Load address must not overlap loader - %endif -%endif - -%if ((_EXEC_SEG_ADJ<<4)+_EXEC_OFS) < 0 - %error Execution address must be in loaded file -%elif ((_EXEC_SEG_ADJ<<4)+_EXEC_OFS+_LOAD_ADR) > LOADLIMIT - %error Execution address must be in LMA -%endif - -%if (_EXEC_OFS & ~0FFFFh) - %error Execution offset must fit into 16 bits -%endif - -%if (_EXEC_SEG_ADJ > 0FFFFh || _EXEC_SEG_ADJ < -0FFFFh) - %error Execution segment adjustment must fit into 16 bits -%endif - - -%if !_CHS && _QUERY_GEOMETRY - %warning No CHS support but querying geometry anyway -%endif - -%if !_CHS && !_LBA - %error Either CHS or LBA or both must be enabled -%endif - - -%if 0 - -There is some logic inside MS-DOS's hard disk partition initialisation -code that sets up several requirements for us to fulfil. Otherwise, -it will not accept the information given in the BPB (using default -information based on the length as specified by MBR/EPBR instead) or -make the whole file system inaccessible except for formatting. Both of -those are undesirable of course. Some/all(?) checks are documented on -pages 601,602 in "DOS Internals", Geoff Chappell 1994, as follows: - -* First three bytes contain either "jmp sho xx\ nop" or "jmp ne xx". -* Media descriptor field >= 0F0h. -* Bytes per sector field == 512. -* Sectors per cluster field a power of 2 (1,2,4,8,16,32,64,128). -* OEM name "version" (last three to four characters) - * must be "20.?", "10.?" (? = wildcard), but no other with "0.?", - * otherwise, must be "2.0", or - * 2nd-to-last,3rd-to-last character codes together > "3.", or - * those == "3.", last character code > "0" - -To stay compatible to those, display a warning here if the name -itself would disqualify our boot sector already. - -%endif - -%push -%strlen %$len _OEM_NAME_FILL -%if %$len != 1 - %error Specified OEM name fill must be 1 character -%endif -%strlen %$len _OEM_NAME -%define %$nam _OEM_NAME -%if %$len > 8 - %error Specified OEM name is too long -%else - %assign %$warn 0 - %rep 8 - %$len - %strcat %$nam %$nam,_OEM_NAME_FILL - %endrep - %substr %$prefix %$nam 5 ; "wvxyZa.b", get "Z" - %substr %$major %$nam 6,7 ; "wvxyzA.b", get "A." - %substr %$minor %$nam 8 ; "wvxyza.B", get "B" - %if %$major == "0." - %ifn %$prefix == "1" || %$prefix == "2" - %assign %$warn 1 - %endif - %elifn %$major == "2." && %$minor == "0" - %if %$major < "3." - %assign %$warn 1 - %elif %$major == "3." && %$minor < "1" - %assign %$warn 1 - %endif - %endif - %if %$warn - %warning Specified OEM name fails MS-DOS's validation - %endif -%endif -%pop - -; 512-byte stack (minus the variables). -ADR_STACK_LOW equ 7C00h - 200h ; 07A00h - -ADR_FSIBOOT equ end -start+7C00h ; 07E00h - -%define _AFTER (ADR_FSIBOOT + 512) -%if _RELOCATE - ; dynamic allocation of FAT buffer -%else - %if _LOAD_ADR < 7C00h - ADR_FATBUF equ _AFTER - %define _AFTER (ADR_FATBUF + 8192) - %else - ADR_FATBUF equ 2000h - %endif -%endif - -%if _ADD_SEARCH - %if _RELOCATE - ; dynamic allocation of dir buffer - %elif _LOAD_ADR < 7C00h - ADR_DIRBUF equ _AFTER - %define _AFTER (ADR_DIRBUF + 8192) - %else - ADR_DIRBUF equ 4000h - %endif -%else - %if _RELOCATE - ADR_DIRBUF equ _LOAD_ADR ; 00600h - %elif _LOAD_ADR < 7C00h - ; one-sector directory buffer. Assumes sectors are no larger than 8 KiB - ADR_DIRBUF equ _AFTER ; 0A000h - %define _AFTER (ADR_DIRBUF + 8192) - %else - ADR_DIRBUF equ 4000h - %endif -%endif -ADR_FREE equ _AFTER ; 08000h - -%if ! _RELOCATE - %if ((ADR_FATBUF + 8192 - 1) & ~0FFFFh) != (ADR_FATBUF & ~0FFFFh) - %warning Possibly crossing 64 KiB boundary while reading FAT - %endif -%endif - -%ifn _RELOCATE && _ADD_SEARCH - %if ((ADR_DIRBUF + 8192 - 1) & ~0FFFFh) != (ADR_DIRBUF & ~0FFFFh) - %warning Possibly crossing 64 KiB boundary while reading directory - %endif -%endif - -%if _LOAD_ADR >= ADR_FREE || _RELOCATE - ; If reading on a sector size boundary, no crossing can occur. - ; Check for all possible sector sizes (32 B to 8 KiB). If one - ; of them fails display a warning, including the minimum size. - %assign SECSIZECHECK 32 - %assign EXITREP 0 - %rep 256 - %ifn EXITREP - %if _LOAD_ADR & (SECSIZECHECK - 1) - %warning Possibly crossing 64 KiB boundary while reading file (sector size >= SECSIZECHECK) - %assign EXITREP 1 - %exitrep - %endif - %if SECSIZECHECK == 8192 - %assign EXITREP 1 - %exitrep - %endif - %assign SECSIZECHECK SECSIZECHECK * 2 - %endif - %endrep -%else - ; If loading below the boot sector, address 1_0000h is never reached. -%endif - - - struc FSINFO ; FAT32 FSINFO sector layout -.signature1: resd 1 ; 41615252h ("RRaA") for valid FSINFO -.reserved1: ; former unused, initialized to zero by FORMAT -.fsiboot: resb 480 ; now used for FSIBOOT -.signature2: resd 1 ; 61417272h ("rrAa") for valid FSINFO -.numberfree: resd 1 ; FSINFO: number of free clusters or -1 -.nextfree: resd 1 ; FSINFO: first free cluster or -1 -.reserved2: resd 3 ; unused, initialized to zero by FORMAT -.signature3: resd 1 ; AA550000h for valid FSINFO or FSIBOOT - endstruc - - struc FSIBOOTG ; FSIBOOT general layout -.signature: resq 1 ; 8 bytes that identify the FSIBOOT type -.fsicode: resb 470 ; 470 bytes FSIBOOT type specific data or code -.dirsearch: resw 1 ; 1 word -> directory search entrypoint - endstruc - - struc DIRENTRY -deName: resb 8 -deExt: resb 3 -deAttrib: resb 1 -dePlusSize: resb 1 - resb 7 -deClusterHigh: resw 1 -deTime: resw 1 -deDate: resw 1 -deClusterLow: resw 1 -deSize: resd 1 - endstruc - -ATTR_READONLY equ 1 -ATTR_HIDDEN equ 2 -ATTR_SYSTEM equ 4 -ATTR_VOLLABEL equ 8 -ATTR_DIRECTORY equ 10h -ATTR_ARCHIVE equ 20h - - -; use byte-offset addressing from BP for smaller code -%define VAR(x) ((x) - start) + bp - - - cpu 8086 -; bootsector loaded at address 07C00h, addressable using 0000h:7C00h - org POSITION -start: - - -%define _LASTVARIABLE start - %macro nextvariable 2.nolist -%1 equ (_LASTVARIABLE - %2) -%define _LASTVARIABLE %1 - %endmacro - -; Variables - -; (dword) sector where the first cluster's data starts - nextvariable data_start, 4 - -; (word) current load segment (points behind last loaded data) - nextvariable load_seg, 2 - -; (word) segment of FAT buffer -; for FAT12 this holds the entire FAT -; for FAT16 this holds the sector given by wo[fat_sector] -; for FAT32 this holds the sector given by dwo[fat_sector] - nextvariable fat_seg, 2 - -; (dword for FAT32) currently loaded sector-in-FAT, -1 if none - nextvariable fat_sector, 4 - -; (dword for FAT32) first cluster of load file - nextvariable first_cluster, 4 - -ADR_STACK_START equ _LASTVARIABLE -start+POSITION - -; (word) number of 16-byte paragraphs per sector - nextvariable para_per_sector, 2 - -; (word) number of 32-byte directory entries per sector - nextvariable entries_per_sector, 2 - -; (word) segment of last available memory for sector - nextvariable last_available_sector, 2 - -; (word) actual sectors per cluster - nextvariable adj_sectors_per_cluster, 2 - -; (word) paragraphs left to read - nextvariable paras_left, 2 - -lowest_variable equ _LASTVARIABLE - - - jmp strict short skip_bpb -%if !_CHS && _LBA_SET_TYPE - db 0Ch ; LBA-enabled FAT32 FS partition type -%else - nop ; default: no LBA -%endif - - -; BIOS Parameter Block (BPB) -; -; Installation will use the BPB already present in your file system. -; These values must be initialised when installing the loader. - -oem_id: ; offset 03h (03) - not used by this code - fill 8,_OEM_NAME_FILL,db _OEM_NAME -bytes_per_sector: ; offset 0Bh (11) - refer to _FIX_SECTOR_SIZE ! - dw _BPS -sectors_per_cluster: ; offset 0Dh (13) - refer to _FIX_CLUSTER_SIZE ! - db _SPC & 255 -fat_start: -num_reserved_sectors: ; offset 0Eh (14) - dw _NUMRESERVED -num_fats: ; offset 10h (16) - db _NUMFATS -num_root_dir_ents: ; offset 11h (17) - dw 0 -total_sectors: ; offset 13h (19) - not used by this code -%if _SPI < 1_0000h - dw _SPI -%else - dw 0 -%endif -media_id: ; offset 15h (21) - not used by this code - db _MEDIAID -sectors_per_fat: ; offset 16h (22) - dw 0 -sectors_per_track: ; offset 18h (24) - dw _CHS_SECTORS -heads: ; offset 1Ah (26) - dw _CHS_HEADS -hidden_sectors: ; offset 1Ch (28) - dd _HIDDEN -total_sectors_large: ; offset 20h (32) - not used by this code -%if _SPI >= 1_0000h - dd _SPI -%else - dd 0 -%endif - -sectors_per_fat_large: ; offset 24h (36) - dd _SPF -fsflags: ; offset 28h (40) - dw 0 -fsversion: ; offset 2Ah (42) - dw 0 -root_cluster: ; offset 2Ch (44) - dd _CLUSTER_ROOT -fsinfo_sector: ; offset 30h (48) - dw _SECTOR_FSINFO -backup_sector: ; offset 32h (50) - dw _SECTOR_BACKUP - - times 12 db 0 ; offset 34h (52) reserved - -; Extended BPB ; offset 40h (64) - -boot_unit: db _UNIT - db 0 -ext_bpb_signature: db 29h -serial_number: dd _VOLUMEID -volume_label: fill 11,32,db _DEFAULT_LABEL -filesystem_identifier: fill 8,32,db "FAT32" - - -; Initialised data - - align 2 -fsiboot_table: ; this table is used by the FSIBOOT stage -.error: dw error - ; INP: al = error condition letter - ; ('B' = bad chain / FS error, 'F' = file not found, - ; 'R' = disk read error, 'M' = not enough memory, - ; 'E' = not enough data in file) -.success: dw load_finish - ; INP: dword [ss:sp] = first cluster - ; Note: The first cluster dword is always filled in - ; by FSIBOOT; the option _SET_SIDI_CLUSTER only - ; affects usage in the primary loader. -%if _MEMORY_CONTINUE -.memory_full: dw load_finish_mc - ; INP: al = error condition letter ('M'), - ; dword [ss:sp] = current cluster number, - ; dword [ss:sp + 4] = first cluster, refer to .success -%else -.memory_full: dw error - ; refer to previous .memory_full comment -%endif -.read_sector: dw read_sector - ; INP: dx:ax = sector number within partition, - ; bx => buffer, (_LBA) ds = ss - ; OUT: dx:ax incremented, bx => incremented, - ; es = input bx, does not return if error occurred - ; CHG: none -%if _RELOCATE && _ADD_SEARCH -.dirbuf: dw 8192 >> 4 - ; initialised to segment displacement from FAT buffer -%else -.dirbuf: dw ADR_DIRBUF>>4 - ; => directory sector buffer (one sector) -%endif -.writedirentry: dw writedirentry.loaddir - ; INP: es:bx -> found dir entry in dir sector buffer - ; si:di = loaded sector-in-FAT - ; CHG: ax, cx, dx - ; STT: ss:bp -> boot sector - ; ds = ss - ; UP - ; OUT: directory entry copied if so desired - ; (is a no-op if not to copy dir entry) -.filename: dw .load_name - ; -> name to search -.minpara: dw _LOAD_MIN_PARA -.loadseg: dw _LOAD_ADR>>4 - ; => where to load - -.load_name: ; = blank-padded 11-byte filename to search for - fill 8,32,db _LOAD_NAME - fill 3,32,db _LOAD_EXT - -fsiboot_name: - fill 8, 32, db _FSIBOOTNAME - -%if _WARN_PART_SIZE - %assign num $ - start - %warning BPB + data size is num bytes -%endif - - -; Code - - ; Note that this may be entered with cs:ip = 07C0h:0 ! -skip_bpb: - cli - cld - xor cx, cx - mov bp, start ; magic bytes - checked by instsect - mov ss, cx - mov sp, ADR_STACK_START -%if _USE_AUTO_UNIT - mov [VAR(boot_unit)], dl; magic bytes - checked by instsect -%else - mov dl, [VAR(boot_unit)]; magic bytes - checked by instsect -%endif - - ; Note: es is left uninitialised here until the first call to - ; read_sector if the below conditional is false. -%if _USE_PART_INFO ; +19 bytes - mov es, cx -; Note: Award Medallion BIOS v6.0 (ASUS MED 2001 ACPI BIOS Revision 1009) -; loads from a floppy disk drive with ds:si = 0F000h:0A92Dh -> -; FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected -; as a valid partition table entry by this handling. Therefore, we -; only accept partition information when booting from a hard disk now. - - ; start of magic byte sequence for instsect - test dl, dl ; floppy ? - jns @F ; don't attempt detection --> -; Check whether an MBR left us partition information. -; byte[ds:si] bit 7 means active and must be set if valid. - cmp byte [si], cl ; flags for xx-00h (result is xx), SF = bit 7 - jns @F ; xx < 80h, ie info invalid --> -; byte[ds:si+4] is the file system type. Check for valid one. - cmp byte [si+4], cl ; is it zero? - je @F ; yes, info invalid --> -; Info valid, trust their hidden sectors over hardcoded. -; Assume the movsw instructions won't run with si = FFFFh. - mov di, hidden_sectors ; -> BPB field - add si, 8 ; -> partition start sector in info - %if _USE_PART_INFO_DISABLED - nop - nop ; size has to match enabled code - %else - movsw - movsw ; overwrite BPB field with value from info - %endif -@@: - ; end of magic byte sequence for instsect -%endif - mov ds, cx - sti - - -%if _QUERY_GEOMETRY ; +27 bytes - - ; start of magic byte sequence for instsect -; test dl, dl ; floppy? -; jns @F ; don't attempt query, might fail --> - ; Note that while the original PC BIOS doesn't support this function - ; (for its diskettes), it does properly return the error code 01h. - ; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1) - mov ah, 08h - ; xor cx, cx ; initialise cl to 0 - ; Already from prologue cx = 0. - stc ; initialise to CY - %if _QUERY_GEOMETRY_DISABLED - nop - nop ; size has to match enabled code - %else - int 13h ; query drive geometry - %endif - jc @F ; apparently failed --> - and cx, 3Fh ; get sectors - jz @F ; invalid (S is 1-based), don't use --> - mov [VAR(sectors_per_track)], cx - mov cl, dh ; cx = maximum head number - inc cx ; cx = number of heads (H is 0-based) - mov [VAR(heads)], cx -@@: - ; end of magic byte sequence for instsect -%endif - - -; 16-byte paragraphs per sector - mov ax, [VAR(bytes_per_sector)] - mov cl, 4 - shr ax, cl - push ax ; push into word [VAR(para_per_sector)] - -; 32-byte FAT directory entries per sector - shr ax, 1 ; /2 = 32-byte entries per sector - push ax ; push into word [VAR(entries_per_sector)] - -load_fsiboot: - cmp ax, 1024 >> 5 ; sector size is at least 1 KiB (large) ? - jae .loaded ; already loaded as part of the boot sector --> - - ; If this code runs, then ax was below 1024 >> 5, - ; therefore this cwd instruction always zeros dx. - cwd - - mov ax, [VAR(fsinfo_sector)] -; inc ax -; jz error_fsiboot ; was FFFFh, invalid --> -; dec ax - ; FFFFh always fails the < num_reserved_sectors check - test ax, ax - jz @F ; is 0 ? invalid --> (ZR, NC) - cmp ax, [VAR(num_reserved_sectors)] -@@: ; (ZR, NC if ax == 0) - jae error_fsiboot ; (jump if NC) - ; dx:ax = FSINFO sector (dx = 0 from cwd) - mov cx, 512 - mov bx, ADR_FSIBOOT >> 4 -@@: - call read_sector - sub cx, [VAR(bytes_per_sector)] - ja @B ; read 512 bytes --> - -.loaded: - push ds - pop es - mov di, fsiboot.signature - mov si, fsiboot_name - mov cx, 4 ; size of fsiboot_name - repe cmpsw - jne error_fsiboot - ; Note that now es:di -> fsiboot.start - -%if _LOAD_ADR >= ADR_FREE || _RELOCATE -; Get conventional memory size and store it - int 12h - mov cl, 6 - shl ax, cl - %if _RPL ; +33 bytes - xchg dx, ax - lds si, [4 * 2Fh] - add si, 3 - lodsb - cmp al, 'R' - jne .no_rpl - lodsb - cmp al, 'P' - jne .no_rpl - lodsb - cmp al, 'L' - jne .no_rpl - mov ax, 4A06h - int 2Fh -.no_rpl: - push ss - pop ds - xchg ax, dx - %endif - %if _RELOCATE - %if _ADD_SEARCH - sub ax, (20 * 1024 + 8192 + 8192 + (8192-16) + 1024 + 7C00h) >> 4 - %else - sub ax, (20 * 1024 + 8192 + (8192-16) + 1024 + 7C00h) >> 4 - %endif - ; 20 KiB: reserved for iniload - ; 8 KiB: dir buffer (only if _ADD_SEARCH) - ; 8 KiB: FAT buffer - ; 8 KiB - 16 B: to allow rounding down position of buffers - ; 1 KiB: sector + FSIBOOT - ; 7C00h: stack and to allow addressing with 7C00h in bp - ; - ; Note also that by addressing the stack and sector and FSIBOOT - ; with bp at 7C00h, and insuring this subtraction doesn't - ; underflow, makes sure that we do not overwrite the IVT or - ; BDA. (However, we assume that ax is at least 60h or so.) - ; - ; The FAT buffer segment is masked so that the actual buffer - ; is stored on an 8 KiB boundary. This is to ensure that - ; the buffer doesn't possibly cross a 64 KiB DMA boundary. - jc error_fsiboot - cmp ax, (end_after_fsiboot -start+7C00h - ADR_STACK_LOW + 15) >> 4 - ; This check is to ensure that the start of the destination - ; for the relocation (stack, sector, FSIBOOT) is - ; above-or-equal the end of the source for the relocation. - ; That is, to avoid overwriting any of the source with the - ; string move instruction (which for simplicity is always UP). - jb error_fsiboot - - ; With _RELOCATE enabled, the FAT buffer segment - ; is fixed up by the primary loader here before - ; FSIBOOT is executed. - mov bx, ((8192 - 16) + 1024 + 7C00h)>>4 -; bx is initialised to the value -; ((8192 - 16) + 1024 + 7C00h)>>4 -; so this is like calculating the following for its value: -; ((LMA_top - 20 KiB - 8 KiB - 8 KiB{AS} - (8 KiB - 16 B) - 1 KiB - 7C00h) + \ -; ((8 KiB - 16 B) + 1 KiB + 7C00h))>>4 -; == (LMA_top - 20 KiB - 8 KiB - 8 KiB{AS})>>4 -; {AS} = only if _ADD_SEARCH - add bx, ax - and bx, ~ ((8192>>4) - 1) ; => FAT sector buffer (one sector) - %if _ADD_SEARCH -; .dirbuf is initialised to 8192 >> 4 - add word [VAR(fsiboot_table.dirbuf)], bx - ; => dir sector buffer (one sector) - %endif - - push ax - push di ; -> reloc destination of fsiboot.start - - mov es, ax ; => destination - mov si, sp ; ds:si = ss:entries_per_sector - 4 - mov di, si ; es:di -> destination for stack low - mov cx, (end_after_fsiboot - (entries_per_sector - 4)) >> 1 - ; end_after_fsiboot is the top of used memory - ; entries_per_sector is the lowest filled stack frame slot - ; 4 is for the additional slots taken by the return address - rep movsw ; relocate stack, sector, and FSIBOOT - mov ss, ax - mov ds, ax ; relocate these - add ax, (ADR_STACK_LOW) >> 4 ; (rounding down) => behind available - - retf ; jump to relocated FSIBOOT - %else - sub ax, (20 * 1024) >> 4 ; 20 KiB reserved for iniload - jc error_fsiboot - mov bx, ADR_FATBUF >> 4 ; => FAT sector buffer (one sector) - push es - push di ; -> fsiboot.start - retf - ; Do a far return here to ensure that cs is zero. - %endif -%elif _LOAD_ADR < ADR_STACK_LOW - mov ax, (ADR_STACK_LOW >> 4) - mov bx, ADR_FATBUF >> 4 ; => FAT sector buffer (one sector) - push es - push di ; -> fsiboot.start - retf - ; Do a far return here to ensure that cs is zero. -%else - %error Load address within used memory -%endif - - -%if _WARN_PART_SIZE - %assign num $ - skip_bpb - %warning init size is num bytes -%endif - - -finish_start: - ; INP: es:bx -> found dir entry in dir sector buffer - ; si:di = loaded sector-in-FAT - ; CHG: ax, cx, dx - ; STT: ss:bp -> boot sector - ; ds = ss - ; UP - ; OUT: directory entry copied if so desired - ; (is a no-op if not to copy dir entry) -writedirentry: -%if _LOAD_DIR_SEG -.loaddir: - mov ax, _LOAD_DIR_SEG -%else -.loaddir: equ read_sector.retn -%endif -%if _LOAD_DIR_SEG || (_ADD_DIR_SEG && _ADD_SEARCH) - ; INP: ax => where to store directory entry -.ax: - push ds - push si - push di - push es - pop ds - mov si, bx ; ds:si -> directory entry - mov cx, DIRENTRY_size >> 1 - mov es, ax - xor di, di ; es:di -> where to store directory entry - rep movsw ; move to here (one directory entry) - push ds - pop es ; es:bx -> dir entry in dir sector buffer - pop di - pop si - pop ds - retn -%endif - - -%if _MEMORY_CONTINUE -load_finish_mc: - pop bx - pop cx -%endif -load_finish: - -%if _ADD_SEARCH - mov word [VAR(fsiboot_table.filename)], add_name - call near word [dirsearch_entrypoint] - %if _ADD_DIR_SEG - mov ax, _ADD_DIR_SEG - call writedirentry.ax - %endif -%endif - -%if _TURN_OFF_FLOPPY -; turn off floppy motor - mov dx,3F2h - mov al,0 - out dx,al -%endif - -; Set-up registers for and jump to loaded file -; Already: ss:bp-> boot sector containing BPB -%if _CHECKVALUE -CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET - %if CHECKLINEAR <= (64 * 1024 - 2) && ! _RELOCATE - cmp word [CHECKLINEAR], _CHECKVALUE - %else - mov ax, CHECKLINEAR >> 4 - mov es, ax - cmp word [es:CHECKLINEAR & 15], _CHECKVALUE - %endif - mov al, 'V' ; check 'V'alue mismatch - jne error -%endif -%if _SET_SIDI_CLUSTER && (_PUSH_DPT || _SET_DSSI_DPT) - pop cx - pop dx -%endif -%if _PUSH_DPT || _SET_DSSI_DPT - %ifn _SET_DSSI_DPT ; (implying that only _PUSH_DPT is set) - %if _RELOCATE - xor ax, ax - mov es, ax ; => IVT - mov di, 1Eh*4 - les si, [es:di] ; -> original (also current) DPT - push es - push si ; original (also current) DPT address - push ax - push di ; 0000h:0078h (address of 1Eh IVT entry) - %else - ; If not _RELOCATE, ds = 0000h (=> IVT) - mov di, 1Eh*4 - les si, [di] ; -> original (also current) DPT - push es - push si ; original (also current) DPT address - ; If not _RELOCATE, ss = 0000h (=> IVT) - push ss - push di ; 0000h:0078h (address of 1Eh IVT entry) - %endif - %else - %if _RELOCATE - xor ax, ax - mov ds, ax ; => IVT - %endif - ; If not _RELOCATE, ds = 0000h (=> IVT) - mov di, 1Eh*4 - lds si, [di] ; -> original (also current) DPT - %if _PUSH_DPT - push ds - push si ; original (also current) DPT address - %if _RELOCATE - push ax - push di ; 0000h:0078h (address of 1Eh IVT entry) - %else - ; If not _RELOCATE, ss = 0000h (=> IVT) - push ss - push di ; 0000h:0078h (address of 1Eh IVT entry) - %endif - %endif - %endif -%endif -%if _ZERO_ES || _ZERO_DS - %if _RELOCATE - %ifn _PUSH_DPT || _SET_DSSI_DPT - xor ax, ax - %endif - %if _ZERO_ES - mov es, ax - %endif - %if _ZERO_DS - mov ds, ax - %endif - %else - %if _ZERO_ES - push ss - pop es - %endif - %if _ZERO_DS && _SET_DSSI_DPT - push ss - pop ds - %endif - %endif -%endif -%if _DATASTART_HIDDEN - mov bx, [VAR(hidden_sectors + 0)] - mov ax, [VAR(hidden_sectors + 2)] - add word [VAR(data_start + 0)], bx - adc word [VAR(data_start + 2)], ax -%endif -%if _SET_AXBX_DATA - mov bx, [VAR(data_start)] - mov ax, [VAR(data_start+2)] -%endif -%if _SET_SIDI_CLUSTER - %if _SET_DSSI_DPT - %error Cannot select both of these. - %endif - %if _PUSH_DPT || _SET_DSSI_DPT - mov di, cx - mov si, dx - %else - pop di - pop si - %endif -%endif -%if _SET_DL_UNIT - mov dl, [VAR(boot_unit)]; set dl to unit - %if _SET_BL_UNIT - mov bl, dl ; set bl to unit, too - %endif -%elif _SET_BL_UNIT - mov bl, [VAR(boot_unit)]; set bl to unit -%endif - ; ss:bp-> boot sector with BPB - jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS - -%if _WARN_PART_SIZE - %assign num $ - finish_start - %warning finish size is num bytes -%endif - - -error_start: - -error_fsiboot: - mov al,'I' - - db __TEST_IMM16 ; (skip mov) -read_sector.err: - mov al, 'R' ; Disk 'R'ead error - -error: -%if _RELOCATE - mov bx, 7 - mov ds, bx - mov bh, [462h - 70h] -%else - mov bh, [462h] - mov bl, 7 -%endif - mov ah, 0Eh - int 10h ; display character - mov al, 07h - int 10h ; beep! - - xor ax, ax ; await key pressed - int 16h - - int 19h ; re-start the boot process - -%if _WARN_PART_SIZE - %assign num $ - error_start - %warning error size is num bytes -%endif - - - ; Read a sector using Int13.02 or Int13.42 - ; - ; INP: dx:ax = sector number within partition - ; bx => buffer - ; (_LBA) ds = ss - ; OUT: If unable to read, - ; ! jumps to error instead of returning - ; If sector has been read, - ; dx:ax = next sector number (has been incremented) - ; bx => next buffer (bx = es+word[para_per_sector]) - ; es = input bx - ; CHG: - -read_sector: - push dx - push cx - push ax - push si - - mov es, bx ; => buffer - -; DX:AX==LBA sector number -; add partition start (= number of hidden sectors) - add ax,[VAR(hidden_sectors + 0)] - adc dx,[VAR(hidden_sectors + 2)] - %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33 - jc .err - %endif -%if _LBA ; +70 bytes (with CHS, +63 bytes without CHS) - %if _LBA_33_BIT - sbb si, si ; -1 if was CY, 0 else - neg si ; 1 if was CY, 0 else - %endif - xor cx, cx - push cx ; highest word = 0 - %if _LBA_33_BIT - push si ; bit 32 = 1 if operating in 33-bit space - %else - push cx ; second highest word = 0 - %endif - push dx - push ax ; = qword sector number - push bx - push cx ; bx => buffer - inc cx - push cx ; word number of sectors to read - mov cl, 10h - push cx ; word size of disk address packet - mov si, sp ; ds:si -> disk address packet (on stack) - - %if _LBA_SKIP_CHECK ; -14 bytes - mov dl, [VAR(boot_unit)] - %else - mov ah, 41h - mov dl, [VAR(boot_unit)] - mov bx, 55AAh - stc - int 13h ; 13.41.bx=55AA extensions installation check - jc .no_lba - cmp bx, 0AA55h - jne .no_lba - shr cl, 1 ; support bitmap bit 0 - jnc .no_lba - %endif - -%if _LBA_RETRY - %if _LBA_SKIP_CHECK && _LBA_SKIP_CY - stc - %endif - mov ah, 42h - int 13h ; 13.42 extensions read - jnc .lba_done - - %if _RETRY_RESET - xor ax, ax - int 13h ; reset disk - %endif - - ; have to reset the LBAPACKET's lpCount, as the handler may - ; set it to "the number of blocks successfully transferred". - ; (in any case, the high byte is still zero.) - mov byte [si + 2], 1 -%endif - - %if _LBA_SKIP_CHECK && _LBA_SKIP_CY - stc - %endif - mov ah, 42h - int 13h - %if _LBA_SKIP_CHECK && _CHS - %if _LBA_SKIP_ANY - jc .no_lba -.err_CY: equ .err -.err_2: equ .err - %else - jnc .lba_done - cmp ah, 1 ; invalid function? - je .no_lba ; try CHS instead --> -.err_CY: -.err_2: - jmp .lba_error - %endif - %else -.err_CY: - jc .lba_error -.err_2: equ .err - %endif - -.lba_done: -%if _CHS && _LBA_SET_TYPE - mov byte [bp + 2], 0Ch ; LBA-enabled FAT32 FS partition type -%endif - add sp, 10h -%if _CHS - jmp short .done -%endif - -.lba_error: equ .err - - %if !_CHS -.no_lba: equ .err - %else -.no_lba: - add sp, 8 - pop cx ; cx = low word of sector - pop ax - pop dx ; dx:ax = middle two words of sector - ; Here dx <= 1 if _LBA_33_BIT, else zero. - ; If dx is nonzero then the CHS calculation - ; should fail. If CHS sectors is equal to 1 - ; (very unusual) then the div may fail. Else, - ; we will detect a cylinder > 1023 eventually. - pop si ; discard highest word of qword - %endif -%else -.err_2: equ .err -%endif - -%if _CHS ; +70 bytes -; dx:ax = LBA sector number, (if _LBA) cx = 0 -; divide by number of sectors per track to get sector number -; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability -; Use two-step 32:16 divide to avoid overflow - %if !_LBA - xchg cx, ax ; cx = low word of sector, clobbers ax - xchg ax, dx ; ax = high word of sector, clobbers dx - xor dx, dx ; dx:ax = high word of sector - %else - ; from the .no_lba popping we already have: - ; cx = low word of sector - ; dx:ax = high word of sector - %endif - div word [VAR(sectors_per_track)] - xchg cx,ax - div word [VAR(sectors_per_track)] - xchg cx,dx - -; DX:AX=quotient, CX=remainder=sector (S) - 1 -; divide quotient by number of heads - xchg bx, ax ; bx = low word of quotient, clobbers ax - xchg ax, dx ; ax = high word of quotient, clobbers dx - xor dx, dx ; dx = 0 - div word [VAR(heads)] - ; ax = high / heads, dx = high % heads - xchg bx, ax ; bx = high / heads, ax = low quotient - div word [VAR(heads)] - -; bx:ax=quotient=cylinder (C), dx=remainder=head (H) -; move variables into registers for INT 13h AH=02h - mov dh, dl ; dh = head - inc cx ; cl5:0 = sector - xchg ch, al ; ch = cylinder 7:0, al = 0 - shr ax, 1 - shr ax, 1 ; al7:6 = cylinder 9:8 - ; bx has bits set iff it's > 0, indicating a cylinder >= 65536. - or bl, bh ; collect set bits from bh - or cl, al ; cl7:6 = cylinder 9:8 - ; ah has bits set iff it was >= 4, indicating a cylinder >= 1024. - or bl, ah ; collect set bits from ah - mov dl,[VAR(boot_unit)] ; dl = drive -.nz_err: - jnz .err_2 ; error if cylinder >= 1024 --> - ; ! bx = 0 (for 13.02 call) - -; we call INT 13h AH=02h once for each sector. Multi-sector reads -; may fail if we cross a track or 64K boundary -%if _CHS_RETRY_REPEAT - mov si, _CHS_RETRY_REPEAT + 1 - %if _CHS_RETRY_NORMAL && _RETRY_RESET - db __TEST_IMM16 ; (skip int 13h) -.loop_chs_retry_repeat: - int 13h ; reset disk - %elif _RETRY_RESET -.loop_chs_retry_repeat: - xor ax, ax - int 13h ; reset disk - %else -.loop_chs_retry_repeat: - %endif - dec si ; another attempt ? - js .nz_err ; no --> - mov ax, 0201h - int 13h ; read one sector - %if _CHS_RETRY_NORMAL && _RETRY_RESET - mov ax, bx ; ax = 0 - %endif - jc .loop_chs_retry_repeat - ; fall through to .done -%else - mov ax, 0201h - %if _CHS_RETRY - %if _RETRY_RESET - ; In this case we cannot store to the stack and - ; pop the value at the right moment for both - ; cases of the "jnc .done" branch. So use the - ; original code to re-init ax to 0201h. - int 13h ; read one sector - jnc .done -; reset drive - xor ax, ax - int 13h - mov ax, 0201h - %else - push ax - int 13h ; read one sector - pop ax ; restore ax = 0201h - jnc .done - %endif - %endif -; try read again - int 13h - jc .err_CY -%endif -%if ! _LBA -.err_CY: equ .err -%endif - -%endif ; _CHS - -.done: -; increment segment - mov bx, es -%if _FIX_SECTOR_SIZE - add bx, _FIX_SECTOR_SIZE >> 4 -%else - add bx, [VAR(para_per_sector)] -%endif - - pop si - pop ax - pop cx - pop dx -; increment LBA sector number - inc ax - jne @F - inc dx -@@: - -.retn: - retn - -%if _WARN_PART_SIZE - %assign num $ - read_sector - %warning read_sector size is num bytes -%endif - - -%if _ADD_SEARCH -add_name: ; = blank-padded 11-byte filename to search for - fill 8,32,db _ADD_NAME - fill 3,32,db _ADD_EXT -%endif - - -%if !_NO_LIMIT -available: - _fill 508,38,start - -signatures: - dw 0 -; 2-byte magic bootsector signature - dw 0AA55h - -%assign num signatures-available -%warning FAT32: num bytes still available. -%else ; for testing - align 4 -signatures: - dw 0 -; 2-byte magic bootsector signature - dw 0AA55h -%endif - - align 16, nop -end: - -fsiboot: - dd "RRaA" -.signature: - fill 8, 32, db _FSIBOOTNAME - -%if ($ - .signature) != 8 - %error Unexpected name size -%endif -.start: - ; INP: ax => after last segment to be used for loading - ; bx => FAT buffer (8 KiB) - ; ss:bp -> boot sector, with EBPB - ; dwo [ss:bp - 4] = data_start (uninit) - ; wo [ss:bp - 6] = load_seg (uninit) - ; wo [ss:bp - 8] = fat_seg (uninit) - ; dwo [ss:bp - 12] = fat_sector (uninit) - ; dwo [ss:bp - 16] = first_cluster (uninit) - ; wo [ss:bp - 18] = para_per_sector - ; wo [ss:bp - 20] = entries_per_sector - ; ss:sp = ss:bp - 20 - ; (Note: The following stack frame entries are currently - ; only used by FSIBOOT itself, so they may be - ; considered implementation detail instead of - ; part of the FSIBOOT protocol.) - ; wo [ss:bp - 22] = last_available_sector (uninit) - ; wo [ss:bp - 24] = adj_sectors_per_cluster (uninit) - ; wo [ss:bp - 26] = paras_left (uninit) - ; Stack layout has to match! - ; ss = ds - ; ss:bp + ((11 + ebpbNew + BPBN_size + 1) & ~1) - ; = ss:fsiboot_table, refer to its comments - ; cs set to address jump table offsets in fsiboot_table - ; ds set to address fsiboot_table.load_name - ; OUT: Jumps to fsiboot_table.error if error occurs: - ; al = error condition letter - ; Else: - ; data_start (within partition) initialised - ; load_seg => behind last loaded data - ; fat_seg initialised (from bx) - ; fat_sector initialised - ; (-1 initially, loaded sector-in-FAT later) - ; first_cluster initialised - ; last_available_sector initialised - ; (from input ax minus word [para_per_sector]) - ; adj_sectors_per_cluster initialised (from BPB) - ; paras_left initialised - ; Jumps to fsiboot_table.success if loaded entirely: - ; dword [ss:sp] = first cluster - ; Jumps to fsiboot_table.memory_full if loaded partially: - ; al = error condition letter ('M') - ; dword [ss:sp] = current cluster number - ; dword [ss:sp + 4] = first cluster - - mov word [VAR(fat_seg)], bx ; initialise => FAT buffer - - sub ax, word [VAR(para_per_sector)] - jc .CY_fsiboot_error_badchain - push ax ; push into word [VAR(last_available_sector)] - - mov bx, word [VAR(fsiboot_table.loadseg)] - mov word [VAR(load_seg)], bx ; initialise => load address - cmp ax, bx - jb .CY_fsiboot_error_badchain - -; adjusted sectors per cluster (store in a word, -; and decode EDR-DOS's special value 0 meaning 256) - mov al, [VAR(sectors_per_cluster)] - dec ax - mov ah, 0 - inc ax - push ax ; push into word [VAR(adj_sectors_per_cluster)] - dec ax ; ! ah = 0 - mov al,[VAR(num_fats)] ; ! ah = 0, hence ax = number of FATs - push ax - mul word [VAR(sectors_per_fat_large)] - ; ax = low word SpF*nF - ; dx = high word - xchg bx, ax - xchg cx, dx - ; cx:bx = first mul - pop ax - mul word [VAR(sectors_per_fat_large + 2)] - ; ax = high word adjust - ; dx = third word - test dx, dx - stc - jnz .CY_fsiboot_error_badchain - ; dx = zero - xchg dx, ax - ; dx = high word adjust - ; ax = zero - add dx, cx - jc .CY_fsiboot_error_badchain - ; dx:bx = result - xchg ax, bx - ; dx:ax = result - ; bx = zero - - add ax,[VAR(num_reserved_sectors)] - adc dx, bx ; bx is zero here -.CY_fsiboot_error_badchain: - jc ..@CY_2_fsiboot_error_badchain - -; first sector of disk data area: - mov [VAR(data_start)], ax - mov [VAR(data_start+2)], dx - - mov di, -1 - mov si, di - mov word [VAR(fat_sector + 2)], si - mov word [VAR(fat_sector + 0)], di - call dirsearch - - -found_load_file: - call near word [VAR(fsiboot_table.writedirentry)] - -; get starting cluster of file - push word [es:bx + deClusterHigh] - push word [es:bx + deClusterLow] - - ; check FAT+ size bits - test byte [es:bx + dePlusSize], 0E7h - ; test whether bits 7-5 and 2-0 NZ -; https://web.archive.org/web/20150219123449/http://www.fdos.org/kernel/fatplus.txt - jnz .large_file ; yes, clamp to maximum paras --> - mov ax, [es:bx + deSize + 2] - mov bx, [es:bx + deSize] - ; ax:bx = file size (non-FAT+) - - mov cx, [VAR(bytes_per_sector)] - dec cx ; BpS - 1 - add bx, cx - adc ax, 0 ; large ? - jc .large_file ; yes, clamp to maximum paras --> - - not cx ; ~ (BpS - 1) - and bx, cx ; mask to limit to rounded-up sector - ; (this also rounds up paragraphs) - mov cx, 4 -@@: - shr ax, 1 - rcr bx, 1 - loop @B - ; ax:bx = size in paragraphs - ; bx = size in paragraphs if < 1_0000h - test ax, ax ; > 0FFFFh paras ? - jz @F ; no, take actual size --> -.large_file: - mov bx, 0FFFFh ; cx = clamp size to 0FFFFh paras -@@: - call check_enough.in_bx ; (CHG ax) - - pop ax - pop dx ; dx:ax = first cluster - - push bx ; push into word [VAR(paras_left)] - - mov word [VAR(first_cluster + 0)], ax - mov word [VAR(first_cluster + 2)], dx - push dx - push ax ; remember cluster for later - - call check_clust -..@CY_2_fsiboot_error_badchain: - jc ..@CY_3_fsiboot_error_badchain - -next_load_cluster: - push dx - push ax ; preserve cluster number for later - call clust_to_first_sector - ; dx:ax = first sector of cluster - ; cx = adjusted sectors per cluster - -; xxx - this will always load an entire cluster (e.g. 64 sectors), -; even if the file is shorter than this -@@: - mov bx, [VAR(load_seg)] ; => where to read next sector - cmp bx, [VAR(last_available_sector)] - jbe @F - call check_enough - mov al, 'M' ; (! _MEMORY_CONTINUE: error code) - jmp near word [VAR(fsiboot_table.memory_full)] - -@@: - call near word [VAR(fsiboot_table.read_sector)] - mov [VAR(load_seg)], bx ; => after last read data - - mov bx, [VAR(para_per_sector)] - sub word [VAR(paras_left)], bx - jbe @F ; read enough --> - - loop @BB - pop ax - pop dx - - call clust_next - jnc next_load_cluster - inc ax - inc ax - test al, 8 ; set in 0FFF_FFF8h--0FFF_FFFFh, - ; clear in 0, 1, and 0FFF_FFF7h - jz fsiboot_error_badchain - db __TEST_IMM16 -@@: - pop bx - pop cx - call check_enough - jmp near word [VAR(fsiboot_table.success)] - - -dirsearch: - mov ax, [VAR(root_cluster)] - mov dx, [VAR(root_cluster + 2)] - call check_clust -..@CY_3_fsiboot_error_badchain: - jc fsiboot_error_badchain - -next_root_clust: - push dx - push ax - call clust_to_first_sector - ; dx:ax = first sector of cluster - ; cx = adjusted sectors per cluster -next_root_sect: - push cx - mov cx, [VAR(entries_per_sector)] - -; Scan root directory for file. We don't bother to check for deleted -; entries (E5h) or entries that mark the end of the directory (00h). - mov bx, [VAR(fsiboot_table.dirbuf)] - call near word [VAR(fsiboot_table.read_sector)] - - push di - xor di, di ; es:di-> first entry in this sector -next_ent: - test byte [es:di + deAttrib], ATTR_DIRECTORY | ATTR_VOLLABEL - jnz @F ; directory, label, or LFN entry --> (NZ) - push si - push di - push cx - mov si, [VAR(fsiboot_table.filename)] - ; ds:si-> name to match - mov cx, 11 ; length of padded 8.3 FAT filename - repe cmpsb ; check entry - pop cx - pop di - pop si -@@: ; ZR = match, NZ = mismatch - je found_it ; found entry --> - lea di, [di + DIRENTRY_size] - - loop next_ent ; count down sector's entries (jumps iff cx >0) - pop di - pop cx - loop next_root_sect - pop ax - pop dx - call clust_next - jnc next_root_clust -file_not_found: - mov al, 'F' - db __TEST_IMM16 -fsiboot_error_badchain: - mov al, 'B' - -fsiboot_error: - jmp near word [VAR(fsiboot_table.error)] - - - ; INP: dx:ax = cluster - 2 (0-based cluster) - ; OUT: dx:ax = first sector of that cluster - ; cx = adjusted sectors per cluster - ; CHG: bx -clust_to_first_sector: - mov cx, word [VAR(adj_sectors_per_cluster)] - push dx - mul cx - xchg bx, ax - pop ax - push dx - mul cx - test dx, dx - jnz fsiboot_error_badchain - xchg dx, ax - pop ax - add dx, ax - jc ..@CY_fsiboot_error_badchain - xchg ax, bx - - add ax, [VAR(data_start)] - adc dx, [VAR(data_start + 2)] -..@CY_fsiboot_error_badchain: - jc fsiboot_error_badchain - ; dx:ax = first sector in cluster - retn - - -check_enough: - mov bx, [VAR(load_seg)] - ; => behind last read sector - sub bx, word [VAR(fsiboot_table.loadseg)] -.in_bx: - cmp bx, word [VAR(fsiboot_table.minpara)] - mov al, 'E' - jb fsiboot_error - retn - - -found_it: - ; es:di -> dir entry in dir sector buffer - mov bx, di - pop di ; restore si:di = loaded FAT sector - pop cx ; (discard sectors per cluster counter) - pop cx - pop cx ; (discard current cluster number) - ; es:bx -> dir entry - retn - - - ; INP: dx:ax = cluster (0-based) - ; si:di = loaded FAT sector, -1 if none - ; OUT: CY if no next cluster - ; NC if next cluster found - ; dx:ax = next cluster value (0-based) - ; si:di = loaded FAT sector - ; CHG: cx, bx, es -clust_next: - add ax, 2 - adc dx, 0 - - add ax, ax - adc dx, dx - add ax, ax - adc dx, dx ; * 4 = byte offset into FAT (0--4000_0000h) - push ax - xchg ax, dx - xor dx, dx ; dx:ax = high word - div word [VAR(bytes_per_sector)] - xchg bx, ax ; bx = result high word, clobbers ax - pop ax ; dx = remainder, ax = low word - div word [VAR(bytes_per_sector)] - xchg dx, bx ; dx:ax = result, bx = remainder - ; dx:ax = sector offset into FAT (0--200_0000h) - ; bx = byte offset into FAT sector (0--8190) - cmp dx, si - jne @F ; read sector - cmp ax, di - je @FF ; sector is already buffered -@@: - mov si, dx - mov di, ax - mov word [VAR(fat_sector + 2)], dx - mov word [VAR(fat_sector + 0)], ax - - push bx - add ax, [VAR(fat_start)] - adc dx, 0 - mov bx, [VAR(fat_seg)] - call near word [VAR(fsiboot_table.read_sector)] - pop bx -@@: - mov es, [VAR(fat_seg)] - mov ax, [es:bx] - mov dx, [es:bx + 2] - - ; INP: dx:ax = cluster value, 2-based - ; OUT: dx:ax -= 2 (makes it 0-based) - ; CY iff invalid cluster -check_clust: - and dh, 0Fh - sub ax, 2 - sbb dx, 0 - cmp dx, 0FFFh - jb @F ; CY here means valid ...- - cmp ax, 0FFF7h - 2 -@@: ; -... or if NC first, CY here also - cmc ; NC if valid - retn - - -fsinfo_available: - _fill 480 + 4 - 2,38,fsiboot - -%assign num $-fsinfo_available -%warning FSINFO: num bytes still available. - - - ; INP: si:di = loaded sector-in-FAT - ; word [fsiboot_table.filename] -> 8.3 filename - ; CHG: ax, cx, dx - ; OUT: si:di updated, if so - ; es:bx -> found directory entry - ; jumps to error handler if an error occurs - ; STT: stack variables as set up by main FSIBOOT entry -dirsearch_entrypoint: - dw dirsearch - - dd "rrAa" - dd -1 ; number of free clusters - dd -1 ; first free cluster - times 3 dd 0 ; FSINFO.reserved2 - dd 0_AA55_0000h ; FSINFO.signature3 - -end_after_fsiboot: -%if $ - fsiboot != 512 - %error Wrong FSIBOOT layout -%endif diff --git a/test/ldosboot/doc/ldosboot.src b/test/ldosboot/doc/ldosboot.src deleted file mode 100644 index e153818a..00000000 --- a/test/ldosboot/doc/ldosboot.src +++ /dev/null @@ -1,459 +0,0 @@ -\cfg{chapter}{Section} - -\cfg{text-filename}{ldosboot.txt} -\cfg{text-chapter-numeric}{true} -\cfg{text-indent-preamble}{false} -\cfg{text-quotes}{"}{"} -\cfg{text-indent}{4} -\cfg{text-width}{72} - -\cfg{html-chapter-numeric}{true} -\cfg{html-suppress-address}{true} -\cfg{html-single-filename}{ldosboot.htm} -\cfg{html-leaf-level}{0} -\cfg{html-template-fragment}{%k}{%b} -\cfg{html-head-end}{} -\cfg{html-heading-hashtag-links}{true} - -\cfg{pdf-filename}{ldosboot.pdf} - -\cfg{ps-filename}{ldosboot.ps} - -\cfg{info-filename}{ldosboot.info} - -\cfg{chm-filename}{ldosboot.chm} - -\cfg{winhelp-filename}{ldosboot.hlp} - -\cfg{man-filename}{ldosboot.7} -\cfg{man-identity}{ldosboot}{7}{2020}{}{C. Masloch} - -\title lDOS boot documentation - -\copyright 2020 by C. Masloch. -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -This document has been compiled on \date{%Y-%m-%d}. - - -\C{protocols} lDOS boot protocols - - -\H{protocol-sector-iniload} Sector to iniload protocol - -The iniload kernel is loaded to an arbitrary segment. -The segment must be at least 60h. -Common choices are 60h, 70h, and 200h. -At least 1536 bytes of the file must be loaded. -Current loaders will load at least 8192 bytes -if the file is as large or larger than that. -The entrypoint is found by applying no segment adjustment (0) -and choosing the offset 400h (1024). - - -\S{protocol-sector-iniload-file} File properties - -The file must be at least 4096 bytes long. -This is now required, beyond the former lower bound of 1536 bytes, -to support an optimisation of the FAT12 and FAT16 boot sector loaders. -The lDebug loader and the FAT32+FSIBOOT loader currently retain the 1536 bytes limit. - -The file may allow multi-use as a flat .COM format executable, -flat .SYS format device driver, or MZ .EXE format executable -and/or device driver. -It is also valid to append arbitrary sized data such as a .ZIP archive. - -The file needs to be placed in the root directory for the boot sector loaders. -The lDebug loader allows to load a file -from any subdirectory and this is also allowed. -The file may be fragmented in any part. -The file data may be located anywhere in the file system. -The supported cluster sizes should be between 32 Bytes and 2 MiB, inclusive. -The sector size should be between 32 Bytes and 8 KiB, inclusive. - - -\S{protocol-sector-iniload-signatures} Signatures - -At offset 1020 (3FCh) there is the signature \cq{lD}. -Behind that there are two bytes with printable non-blank ASCII codepoints. -Currently the following signatures are defined: - -\dt \cq{lDOS} - -\dd lDOS kernel (not yet in use) - -\dt \cq{lDRx} - -\dd RxDOS kernel - -\dt \cq{lDFD} - -\dd FreeDOS kernel wrapped in iniload (fdkernpl.asm) - -\dt \cq{lDeb} - -\dd lDebug - -\dt \cq{lDDb} - -\dd lDDebug (debuggable lDebug) - -\dt \cq{lDbC} - -\dd lCDebug (conditionally debuggable lDebug) - -\dt \cq{lDTP} - -\dd lDOS test payload kernel (testpl.asm) - -\dt \cq{lDTW} - -\dd lDOS test result writer kernel (testwrit.asm) - - -\S{protocol-sector-iniload-lsv} Load Stack Variables (LSV) - -Under this protocol, the pointer \cq{ss:bp} is passed. -It points to a boot sector with (E)BPB. -\cq{bp} must be even for compatibility with older iniload (before 2023-March). -The stack pointer must be at most \cq{bp - 10h}. -Below the pointed to location there live the Load Stack Variables. -These follow this structure: - -\c struc LOADSTACKVARS, -10h -\c lsvFirstCluster: resd 1 -\c lsvFATSector: resd 1 -\c lsvFATSeg: resw 1 -\c lsvLoadSeg: resw 1 -\c lsvDataStart: resd 1 -\c endstruc - -\dt lsvFirstCluster - -\dd (FAT12, FAT16) Low word gives starting cluster of file. -High word uninitialised. - -\dd (FAT32) Dword gives starting cluster of file. - -\dd (else) Should be zero. - -\dt lsvFATSector - -\dd (FAT16) Low word gives loaded sector-in-FAT. --1 if none loaded yet. -High word uninitialised. - -\dd (FAT32) Dword gives loaded sector-in-FAT. --1 if none loaded yet. - -\dd (FAT12, else) Unused. - -\dt lsvFATSeg - -\dd (FAT16, FAT32) Word gives segment of FAT buffer -if word/dword [lsvFATSector] != -1. - -\dd (FAT12) Word gives segment of FAT buffer. -Zero if none. -Otherwise, buffer holds entire FAT data, up to 6 KiB. - -\dt lsvLoadSeg - -\dd Word points to segment beyond last loaded paragraph. -Allows iniload to determine how much of it is already loaded. - -\dt lsvDataStart - -\dd Dword gives sector-in-partition of first cluster's data. - - -An LSV extension allows to pass a command line to the kernel. -The base pointer must be at least \cq{114h} then. -The stack pointer must be at most \cq{bp - 114h} then. -This follows the structure like this: - -\c lsvclSignature equ "CL" -\c lsvclBufferLength equ 256 -\c -\c struc LSVCMDLINE, LOADSTACKVARS - lsvclBufferLength - 4 -\c lsvCommandLine: -\c .start: resb lsvclBufferLength -\c .signature: resw 1 -\c lsvExtra: resw 1 -\c endstruc - -\dt lsvCommandLine.start - -\dd Command line buffer. Contains zero-terminated command line string. - -\dt lsvCommandLine.signature - -\dd Contains the signature value \cq{CL} if command line is given. - -\dt lsvExtra - -\dd Used internally by iniload. -Space for this must be reserved when passing a command line. - -If no command line is passed then either the stack pointer -must be \cq{bp - 10h}, or \cq{bp - 12h}, or -the word in the lsvCommandLine.signature variable -(\cw{word [ss:bp - 14h]}) -must not equal the string \cq{CL}. - -\b dosemu2's RxDOS.3 support sets \cq{sp = bp - 10h} - -\b ldosboot boot.asm (FAT12/FAT16) loader -makes sure not to pass the variable with the content "CL". -Refer to placeholder and DIRSEARCHSTACK_CL_FIRST uses in the source. - -\b ldosboot boot32.asm (FAT32) loader -uses the variable for an \q{entries per sector} value -which is always a power of two and always below-or-equal 100h. - -\b lDebug with protocol options \cw{cmdline=0 push_dpt=0} -sets \cq{sp = bp - 10h} - - -\S{protocol-sector-iniload-memory} Memory map - -The initial loader part that is loaded must be loaded -at above or equal to linear 00600h. -The FAT buffer segment (if used) must also be stored -at above or equal to linear 00600h. -The stack (which should extend at least 512 bytes below \cq{ss:bp}) -and boot sector (pointed to by \cq{ss:bp}, at least 512 bytes length) -should also be stored at above or equal to linear 00600h. - -There is an additional memory area, -the Low Memory Area top reservation, -which should be unused by the load protocol at handoff time -but be at least 20 KiB in size. -It is located below the usable Low Memory Area top. -That is, directly below the EBDA, RPL-reserved memory, video memory, -or otherwise UMA. -This area is reserved in order to facilitate initial loader operation. - -None of the memory areas may overlap. -This does not include the FAT buffer in case it is uninitialised. - - -\S{protocol-sector-iniload-loadname} Load filename in the boot sector - -The boot sector may be expected to contain a valid -8.3 format (blank-padded FCB) filename -in the area of the boot sector starting behind the (E)BPB, -extending up to below the boot sector signature word with value AA55h -(at offset 510 in the boot sector). -This name should not contain blanks other than trailing in the -file name portion or trailing in the file extension portion. -It should consist of printable ASCII codepoints. -That is, byte values between 20h and 7Eh inclusive. -It should not consist of eleven times the same byte value. -Additional FAT Short File Name restrictions may be assumed. - -Although a loader should not depend on this for crucial operation, -it may want to detect the kernel name it was presumably loaded from -for informational or optional purposes. -The canonical implementation of this is currently the function -\cq{findname} in the \cw{testpl.asm} test payload kernel. -It is found within -\W{https://hg.pushbx.org/ecm/ldosboot/file/e0c17723f953/testpl.asm#l668}{the ldosboot repo}. -This handling is based on the function of the same name -\W{https://hg.pushbx.org/ecm/instsect/file/53e4327aacd6/instsect.asm#l2442}{in the instsect application}. - - -\S{protocol-sector-iniload-patch} Query patch support - -The ldosboot repo includes a patch Script for lDebug (.sld) file -which allows to patch the initial loader stage. -The patches concern handling of the CHS geometry detection, -and whether LBA or CHS access is used. -There are several legacy patch sites in which patch.sld -can directly patch the initial loader's code. - -However, the preferred way is to find the query patch sequence. -It should appear within the first 1536 bytes, -that is within the part of the initial loader that must be loaded. -This is the sequence: - -\c 8A5640 mov dl, byte [bp + 40h] -\c B8xxyy mov ax, yyxxh -\c 84D2 test dl, dl -\c 7902 jns @F -\c 86C4 xchg al, ah -\c @@: - -The immediate word of the \cw{mov ax} instruction is to be patched. -The sequence should be scanned for without regard as to what -the current contents of this word are. - -The following flag values are used: - -\b 01h Force CHS access, do not detect LBA support with 13.41 - -\b 02h Force LBA access, do not detect LBA support with 13.41 - -\b 04h Force use of BPB's CHS geometry, do not detect with 13.08 - -\b 80h Used by lDebug. If this value is set for the load unit, -then lDebug will make use of the other flags set up for that unit. -The corresponding flags will be saved in lDebug's load_unit_flags. -This affects only the load unit (LD in lDebug terminology), -which suffices to pass commands in the startup Script for lDebug. - -The flag 01h takes precedence over 02h if both are set. - -The low byte (xxh) is used in case the loader loads -from a diskette unit, that is a unit number below 80h. -The high byte (yyh) is used otherwise, in case the loader loads -from a hard disk unit, that is a unit number above-or-equal 80h. - - -\H{protocol-iniload-payload} Iniload to payload protocol - -The payload is loaded to an arbitrary segment. -The segment must be at least 60h. -The entire payload must be loaded. -The size of the payload is determined at iniload build time. -The entrypoint is found by applying a segment adjustment -and choosing an offset. -The segment adjustment is specified at iniload build time -by the numeric define \cw{_EXEC_SEGMENT} (default 0), -and the offset by the define \cw{_EXEC_OFFSET} (default 0). - - -\S{protocol-iniload-payload-ebpb} Extended BIO Parameter Block (EBPB) - -Above the LSV, \cw{ss:bp} points to an EBPB and surrrounding boot sector. -Note that this is always a FAT32-style EBPB. -If the filesystem that is loaded from is not FAT32, -and is therefore FAT16 or FAT12, -then the FAT16/FAT12 BPBN structure is moved up. -It is placed where the FAT32 BPBN is usually expected. -In this case, the entire boot sector contents behind the BPBN -are also moved up by the size of the FAT32-specific fields. -The FAT32-specific fields are filled with zeros, -except for the FAT32 \q{sectors per FAT} field. -It is filled with the contents of the FAT16/FAT12 -\q{sectors per FAT} field. - - -\S{protocol-iniload-payload-lsv} Load Stack Variables (LSV) - -Refer to \k{protocol-sector-iniload-lsv}. - - -\S{protocol-iniload-payload-ld} Load Data 1 (LD) - -Below the LSV, iniload passes the LOADDATA (1) structure. - -\c struc LOADDATA, LOADSTACKVARS - 10h -\c ldMemoryTop: resw 1 -\c ldLoadTop: resw 1 -\c ldSectorSeg: resw 1 -\c ldFATType: resb 1 -\c ldHasLBA: resb 1 -\c ldClusterSize: resw 1 -\c ldParaPerSector:resw 1 -\c ldLoadingSeg: -\c ldQueryPatchValue: -\c resw 1 -\c ldLoadUntilSeg: resw 1 -\c endstruc - -\dt ldMemoryTop - -\dd Word. Segment pointer to behind usable memory. -Points at the first of the EBDA, RPL-reserved memory, or -video memory or otherwise UMA. -Indicates how much memory may be used by a typical kernel. -(lDebug detects the EBDA to move that below where it installs.) - -\dt ldLoadTop - -\dd Word. Segment pointer to lowest lDOS boot memory in use. -All memory between linear 600h and the segment indicated here -is usable by the payload. -Only the payload itself is stored in this area. -The other buffers, stack, and structures passed by iniload -must live above this segment. - -\dt ldSectorSeg - -\dd Word. Segment pointer to an 8 KiB transfer buffer. -It is insured that this buffer does not cross a 64 KiB boundary. -This may be needed by some disk units. -The buffer is not initialised to anything generally. - -\dt ldFATType - -\dd Byte. Indicates length of FAT entry in bits. -12 indicates FAT12, 16 FAT16, 32 FAT32. -It is planned to allow zero for non-FAT filesystems. - -\dt ldHasLBA - -\dd Byte. Only least significant bit used. -Bit on indicates LBA extensions available for the load disk unit. -Bit off indicates LBA extensions not available. - -\dt ldClusterSize - -\dd Word. Contains amount of sectors per cluster. -Unlike the byte field for the same purpose in the BPB, -this field can encode 256 (EDR-DOS compatible) without any masking. -May be given as zero for non-FAT filesystems. - -\dt ldParaPerSector - -\dd Word. Contains amount of paragraphs per sector. -Must be a power of two between 2 (32 B/s) and 200h (8192 B/s). -May be given as zero for non-FAT filesystems. - -\dt ldLoadingSeg - -\dd Word. Internally used by iniload. -Available for re-use by payload. -However, ldQueryPatchValue re-uses the same field. - -\dt ldQueryPatchValue - -\dd Word. Passes the query patch value from the initial loader. -This provides an opportunity to patch a well-known site -in the initial loader to change its behaviour in some ways. -Near the end of its operation, the initial loader -passes along this value in this variable for the next stage to use. - -\dt ldLoadUntilSeg - -\dd Word. Internally used by iniload. -Available for re-use by payload. - - -\S{protocol-iniload-payload-lcl} Load Command Line (LCL) - -Below the LOADDATA structure, iniload passes the LOADCMDLINE structure. - -\c lsvclBufferLength equ 256 -\c -\c struc LOADCMDLINE, LOADDATA - lsvclBufferLength -\c ldCommandLine: -\c .start: resb lsvclBufferLength -\c endstruc - -This buffer is always initialised to an ASCIZ string. -At most 255 bytes may be initialised to string data. -At most the 256th byte is a zero. - -If the first word of the buffer is equal to 0FF00h, -that is there is an empty command line -the terminator of which is followed by a byte with the value 0FFh, -then no command line was passed to iniload. -Currently lDebug can pass a command line to iniload when -loading with its lDOS, RxDOS.2, RxDOS.3, or FreeDOS protocols. -When iniload is loaded as a Multiboot1 or Multiboot2 specification kernel, -it is also assumed that a command line can be passed. diff --git a/test/ldosboot/doc/mak.sh b/test/ldosboot/doc/mak.sh deleted file mode 100755 index f65e02d5..00000000 --- a/test/ldosboot/doc/mak.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -# Usage of the works is permitted provided that this -# instrument is retained with the works, so that any entity -# that uses the works is notified of this instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -echo -ne "\\U Source Control Revision ID\n\nhg $(hg id -i), from commit on at $(hg log -r . --template="{date|isodatesec}\n")\n\nIf this is in ecm's repository, you can find it at \\W{https://hg.pushbx.org/ecm/ldosboot/rev/$(hg log -r . --template "{node|short}")}{https://hg.pushbx.org/ecm/ldosboot/rev/$(hg log -r . --template "{node|short}")}\n" > screvid.src -halibut --precise ldosboot.src screvid.src --html --text --pdf diff --git a/test/ldosboot/fdkernpl.asm b/test/ldosboot/fdkernpl.asm deleted file mode 100644 index f75cf68a..00000000 --- a/test/ldosboot/fdkernpl.asm +++ /dev/null @@ -1,246 +0,0 @@ - -%if 0 - -Loader adjustment to load FreeDOS kernel - by C. Masloch, 2017 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - -%include "lmacros3.mac" - - struc BS -bsJump: resb 3 -bsOEM: resb 8 -bsBPB: - endstruc - - struc EBPB ; BPB sec -bpbBytesPerSector: resw 1 ; offset 00h 0Bh -bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh -bpbReservedSectors: resw 1 ; offset 03h 0Eh -bpbNumFATs: resb 1 ; offset 05h 10h -bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32 -bpbTotalSectors: resw 1 ; offset 08h 13h -bpbMediaID: resb 1 ; offset 0Ah 15h -bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32 -bpbCHSSectors: resw 1 ; offset 0Dh 18h -bpbCHSHeads: resw 1 ; offset 0Fh 1Ah -bpbHiddenSectors: resd 1 ; offset 11h 1Ch -bpbTotalSectorsLarge: resd 1 ; offset 15h 20h -bpbNew: ; offset 19h 24h - -ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h -ebpbFSFlags: resw 1 ; offset 1Dh 28h -ebpbFSVersion: resw 1 ; offset 1Fh 2Ah -ebpbRootCluster: resd 1 ; offset 21h 2Ch -ebpbFSINFOSector: resw 1 ; offset 25h 30h -ebpbBackupSector: resw 1 ; offset 27h 32h -ebpbReserved: resb 12 ; offset 29h 34h -ebpbNew: ; offset 35h 40h - endstruc - - struc BPBN ; ofs B16 S16 B32 S32 -bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h - resb 1 ; 01h 1Ah 25h 36h 41h -bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN -bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h -bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h -bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h - endstruc ; 1Ah 33h 3Eh 4Fh 5Ah - - -%ifndef _MAP -%elifempty _MAP -%else ; defined non-empty, str or non-str - [map all _MAP] -%endif - - strdef PAYLOAD_FILE, "KERNEL.SYS" - - - struc LOADSTACKVARS, -10h -lsvFirstCluster: resd 1 -lsvFATSector: resd 1 -lsvFATSeg: resw 1 -lsvLoadSeg: resw 1 -lsvDataStart: resd 1 - endstruc - - -lsvclSignature equ "CL" -lsvclBufferLength equ 256 - - struc LOADDATA, LOADSTACKVARS - 10h -ldMemoryTop: resw 1 -ldLoadTop: resw 1 -ldSectorSeg: resw 1 -ldFATType: resb 1 -ldHasLBA: resb 1 -ldClusterSize: resw 1 -ldParaPerSector:resw 1 -ldLoadingSeg: ; word -lsvCommandLine: ; word -.start: equ $ - lsvclBufferLength -.signature: resw 1 -ldLoadUntilSeg: ; word -lsvExtra: ; word -.partition: resb 1 ; byte -.flags: resb 1 ; byte - endstruc - -lsvefNoDataStart equ 1 -lsvefPartitionNumber equ 2 - - struc LOADCMDLINE, LOADDATA - lsvclBufferLength -ldCommandLine: -.start: resb lsvclBufferLength - endstruc - - - cpu 8086 - org 0 - addsection ENTRY, start=0 vstart=0 -entry: - - mov ax, cs - add ax, entry_size_p + payload_size_p - xor bx, bx - push ax - push bx - retf - - align 16 - endarea entry - - - addsection PAYLOAD, follows=ENTRY -payload: -realpayload: - incbin _PAYLOAD_FILE - align 16, db 38 - endarea realpayload - - - addsection STACKRELOCATE, follows=PAYLOAD vstart=0 -stackrelocate: - - mov ax, 60h + payload_size_p - mov es, ax - xor di, di - xor si, si - lea cx, [ bp + 512 ] - rep movsb - mov ds, ax - mov si, bp - xor di, di - cmp word [ds:bp + ldCommandLine], 0FF00h - je @F - lea si, [bp + ldCommandLine + lsvclBufferLength - 2] - lea di, [bp + lsvCommandLine.start + lsvclBufferLength - 2] - mov cx, words(lsvclBufferLength) -%if words(lsvclBufferLength) <= 20 - %error AMD erratum 109 workaround needed -%endif - std - rep movsw - cld - lea si, [bp + lsvCommandLine.start] - mov di, lsvclSignature -@@: - cli - mov ss, ax - mov sp, si - mov word [bp + lsvCommandLine.signature], di - ; Note that this access uses the new ss. - ; Also note: If no command line is passed, - ; si will equal bp. That means the word - ; written here is technically below sp, - ; that is it belongs to the unused stack. - ; This does not cause any problems however. - ; It hardens the next load stage against - ; accidentally expecting a command line if - ; it does not check the offsets properly. - sti - - jmp 60h:0 - - align 16 - endarea stackrelocate - -payload_size equ realpayload_size + stackrelocate_size - endarea payload, 1 - - - addsection RELOCATE, follows=STACKRELOCATE vstart=0 -relocate: - mov bx, 1000h - mov ax, 60h - mov es, ax - mov cx, payload_size_p - mov ax, cs - sub ax, cx - mov ds, ax - xor si, si - xor di, di - - mov ax, cx - cmp ax, bx - jbe @F - mov cx, bx -@@: - sub ax, cx - shl cx, 1 - shl cx, 1 - shl cx, 1 - rep movsw - -@@: - mov dx, es - add dx, bx - mov es, dx ; next segment - - mov dx, ds - add dx, bx - mov ds, dx ; next segment - - sub ax, bx ; = how much to relocate after this round - mov cx, 1000h << 3 ; in case another full 64 KiB to relocate - jae @F ; another full 64 KiB to relocate --> - add ax, bx ; restore - shl ax, 1 - shl ax, 1 - shl ax, 1 ; convert paragraphs to words - mov cx, ax ; that many words - xor ax, ax ; no more to relocate after this round - -@@: - xor si, si - xor di, di - rep movsw ; relocate next chunk - test ax, ax ; another round needed? - jnz @BB ; yes --> - ; ax = 0 - - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - mov bl, dl - - push ss - pop ds - cmp word [bp + bsBPB + bpbSectorsPerFAT], ax - je @F - push ss - pop es - lea si, [bp + bsBPB + ebpbNew] - lea di, [bp + bsBPB + bpbNew] - mov cx, (512 - bsBPB - bpbNew + 1) >> 1 - rep movsw -@@: - - jmp 60h + realpayload_size_p:0 diff --git a/test/ldosboot/iniload.asm b/test/ldosboot/iniload.asm deleted file mode 100644 index 309490c6..00000000 --- a/test/ldosboot/iniload.asm +++ /dev/null @@ -1,2544 +0,0 @@ - -%if 0 - -Loader for finishing file system booting - by C. Masloch, 2017 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - -%assign __lMACROS1_MAC__DEBUG_DEFAULTS 1 -%include "lmacros3.mac" - numdef DEBUG5 -%idefine d5 _d 5, - - struc BS -bsJump: resb 3 -bsOEM: resb 8 -bsBPB: - endstruc - - struc EBPB ; BPB sec -bpbBytesPerSector: resw 1 ; offset 00h 0Bh -bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh -bpbReservedSectors: resw 1 ; offset 03h 0Eh -bpbNumFATs: resb 1 ; offset 05h 10h -bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32 -bpbTotalSectors: resw 1 ; offset 08h 13h -bpbMediaID: resb 1 ; offset 0Ah 15h -bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32 -bpbCHSSectors: resw 1 ; offset 0Dh 18h -bpbCHSHeads: resw 1 ; offset 0Fh 1Ah -bpbHiddenSectors: resd 1 ; offset 11h 1Ch -bpbTotalSectorsLarge: resd 1 ; offset 15h 20h -bpbNew: ; offset 19h 24h - -ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h -ebpbFSFlags: resw 1 ; offset 1Dh 28h -ebpbFSVersion: resw 1 ; offset 1Fh 2Ah -ebpbRootCluster: resd 1 ; offset 21h 2Ch -ebpbFSINFOSector: resw 1 ; offset 25h 30h -ebpbBackupSector: resw 1 ; offset 27h 32h -ebpbReserved: resb 12 ; offset 29h 34h -ebpbNew: ; offset 35h 40h - endstruc - - struc BPBN ; ofs B16 S16 B32 S32 -bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h - resb 1 ; 01h 1Ah 25h 36h 41h -bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN -bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h -bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h -bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h - endstruc ; 1Ah 33h 3Eh 4Fh 5Ah - - struc LOADSTACKVARS, -10h -lsvFirstCluster: resd 1 -lsvFATSector: resd 1 -lsvFATSeg: resw 1 -lsvLoadSeg: resw 1 -lsvDataStart: resd 1 - endstruc - -lsvclSignature equ "CL" -lsvclBufferLength equ 256 - - struc LOADDATA, LOADSTACKVARS - 10h -ldMemoryTop: resw 1 -ldLoadTop: resw 1 -ldSectorSeg: resw 1 -ldFATType: resb 1 -ldHasLBA: resb 1 -ldClusterSize: resw 1 -ldParaPerSector:resw 1 -ldLoadingSeg: ; word -ldQueryPatchValue: ; word -lsvCommandLine: ; word -.start: equ $ - lsvclBufferLength -.signature: resw 1 -ldLoadUntilSeg: ; word -lsvExtra: ; word -.partition: resb 1 ; byte -.flags: resb 1 ; byte - endstruc - -lsvefNoDataStart equ 1 -lsvefPartitionNumber equ 2 - - struc LOADCMDLINE, LOADDATA - lsvclBufferLength -ldCommandLine: -.start: resb lsvclBufferLength - endstruc - - struc LBAPACKET -lpSize: resw 1 -lpCount: resw 1 -lpBuffer: resd 1 -lpSector: resq 1 - endstruc - - struc PARTINFO -piBoot: resb 1 -piStartCHS: resb 3 -piType: resb 1 -piEndCHS: resb 3 -piStart: resd 1 -piLength: resd 1 - endstruc - -ptEmpty: equ 0 -ptFAT12: equ 1 -ptFAT16_16BIT_CHS: equ 4 -ptExtendedCHS: equ 5 -ptFAT16_CHS: equ 6 -ptFAT32_CHS: equ 0Bh -ptFAT32: equ 0Ch -ptFAT16: equ 0Eh -ptExtended: equ 0Fh -ptLinux: equ 83h -ptExtendedLinux: equ 85h - - -query_no_geometry equ 4 -query_no_chs equ 2 -query_no_lba equ 1 -query_fd_multiplier equ 1 -query_hd_multiplier equ 256 -query_all_multiplier equ query_fd_multiplier + query_hd_multiplier - - -%ifndef _MAP -%elifempty _MAP -%else ; defined non-empty, str or non-str - [map all _MAP] -%endif - - defaulting - - numdef QUERY_PATCH, 1 ; use new style patch of CHS/LBA/geometry - numdef QUERY_DEFAULT, 0 - numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) - numdef RPL, 1 ; support RPL and do not overwrite it - numdef CHS, 1 ; support CHS (if it fits) - numdef LBA, 1 ; support LBA (if available) - numdef LBA_33_BIT, 1 ; support 33-bit LBA - numdef LBA_CHECK_NO_33, 1 ; else: check that LBA doesn't carry - numdef MULTIBOOT1, 1 ; use Multiboot specification loader - numdef MULTIBOOT2, 1 ; use Multiboot2 specification loader - numdef LSVEXTRA, 1 ; use lsvExtra field - ; (needed if to use partition scanner) - - numdef LBA_SKIP_CHECK, 0 ; don't use proper LBA extensions check - numdef LBA_RETRY, 1 ; retry LBA reads - numdef CHS_RETRY, 1 ; retry CHS reads - numdef STACKSIZE, 2048 -%if _STACKSIZE < 256 - %error Too small stack size -%elif _STACKSIZE > 3 * 1024 - ; Note that we use 8 KiB for SectorSeg, 8 KiB for FATSeg, - ; 512 bytes + (ebpbNew - bpbNew) for the boot sector, - ; and a few paragraphs left for MCBs and headers. As the - ; protocol is implemented with a 20 KiB reserved area (below - ; EBDA / RPL / end of low memory), this results in a maximum - ; stack size around 3 KiB (substantially below 4 KiB). - %error Too large stack size -%endif - numdef CHECKSUM, 0 ; include checksumming of kernel image -%if _CHECKSUM - %include "inicheck.mac" -%endif - - numdef PADDING, 0 - strdef PAYLOAD_FILE, "lDOSLOAD.BIN" - numdef EXEC_OFFSET, 0 - numdef EXEC_SEGMENT, 0 - strdef INILOAD_SIGNATURE, "XX" - - numdef IMAGE_EXE, 0 - numdef IMAGE_EXE_CS, -16 ; relative-segment for CS - numdef IMAGE_EXE_IP, 256 +64 ; value for IP - ; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0. - numdef IMAGE_EXE_SS, -16 ; relative-segment for SS - numdef IMAGE_EXE_SP, 0FFFEh ; value for SP (0 underflows) - numdef IMAGE_EXE_AUTO_STACK, 0, 2048 ; allocate stack behind image - numdef IMAGE_EXE_MIN, 65536 ; how much to allocate for the process -%ifndef _IMAGE_EXE_MIN_CALC - %define _IMAGE_EXE_MIN_CALC \ - (((_IMAGE_EXE_MIN \ - - (payload.actual_end - payload) \ - - 256 \ - + _IMAGE_EXE_AUTO_STACK) + 15) & ~15) -%endif - numdef IMAGE_EXE_MAX, -1 - - numdef SECOND_PAYLOAD_EXE, 0 - numdef SECOND_PAYLOAD_EXE_CS, -16 - numdef SECOND_PAYLOAD_EXE_IP, 256 +64 - numdef SECOND_PAYLOAD_EXE_SS, -16 - numdef SECOND_PAYLOAD_EXE_SP, 0FFFEh - numdef SECOND_PAYLOAD_EXE_AUTO_STACK, 0, 2048 - numdef SECOND_PAYLOAD_EXE_MIN, 65536 -%ifndef _SECOND_PAYLOAD_EXE_MIN_CALC - %define _SECOND_PAYLOAD_EXE_MIN_CALC \ - (((_SECOND_PAYLOAD_EXE_MIN \ - - (second_payload.actual_end - second_payload) \ - - 256 \ - + _SECOND_PAYLOAD_EXE_AUTO_STACK) + 15) & ~15) -%endif - numdef SECOND_PAYLOAD_EXE_MAX, -1 - strdef SECOND_PAYLOAD_FILE, "lDOSEXEC.COM" - - - strdef INILOAD_CFG, "" -%ifnidn _INILOAD_CFG, "" - %include _INILOAD_CFG -%endif - - -%if _IMAGE_EXE && _SECOND_PAYLOAD_EXE - %error Cannot use both of these. -%endif - -%push -%define %$string _INILOAD_SIGNATURE -%strlen %$length %$string -%if %$length != 2 - %error Invalid signature -%endif -%substr %$letter %$string 1 -%if %$letter <= 32 || %$letter >= 127 - %error Invalid signature -%endif -%substr %$letter %$string 2 -%if %$letter <= 32 || %$letter >= 127 - %error Invalid signature -%endif -%pop - - - cpu 8086 - org 0 -start: - db "MZ" ; exeSignature - ; dec bp, pop dx - jmp strict short ms6_entry ; exeExtraBytes - ; db 0EBh, 16h ; dw 16EBh -%if _IMAGE_EXE - ; For now hardcoded to carry a .COM-like executable. - ; Note: With _IMAGE_EXE_AUTO_STACK, the - ; stack segment will be behind the image. - dw (payload.end - $$ + 511) / 512 ; exePages - dw 0 ; exeRelocItems - dw (payload -$$+0) >> 4 ; exeHeaderSize - dw (_IMAGE_EXE_MIN_CALC + 15) >> 4 ; exeMinAlloc -%if _IMAGE_EXE_MAX - dw _IMAGE_EXE_MAX ; exeMaxAlloc -%else - dw (_IMAGE_EXE_MIN_CALC + 15) >> 4 ; exeMaxAlloc -%endif -%if _IMAGE_EXE_AUTO_STACK - dw ((payload.actual_end - payload) \ - + _IMAGE_EXE_MIN_CALC \ - - _IMAGE_EXE_AUTO_STACK + 15) >> 4 ; exeInitSS - ; ss: payload size minus 512 (conservative, assume DOS - ; treats bogus exeExtraBytes as below 512 bytes.) - ; + exeMinAlloc - ; - auto stack size - dw _IMAGE_EXE_AUTO_STACK ; exeInitSP - ; sp = auto stack size (eg 800h) -%else - dw _IMAGE_EXE_SS ; exeInitSS - dw _IMAGE_EXE_SP ; exeInitSP -%endif - dw 0 ; exeChecksum - dw _IMAGE_EXE_IP, _IMAGE_EXE_CS ; exeInitCSIP - dw 0 ; exeRelocTable -%elif _SECOND_PAYLOAD_EXE - ; For now hardcoded to carry a .COM-like executable. - ; Note: With _SECOND_PAYLOAD_EXE_AUTO_STACK, the - ; stack segment will be behind the image. - dw (second_payload.end - $$ + 511) / 512 ; exePages - dw 0 ; exeRelocItems - dw (second_payload -$$+0) >> 4 ; exeHeaderSize - dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4 ; exeMinAlloc -%if _SECOND_PAYLOAD_EXE_MAX - dw _SECOND_PAYLOAD_EXE_MAX ; exeMaxAlloc -%else - dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4 ; exeMaxAlloc -%endif -%if _SECOND_PAYLOAD_EXE_AUTO_STACK - dw ((second_payload.actual_end - second_payload) \ - + _SECOND_PAYLOAD_EXE_MIN_CALC \ - - _SECOND_PAYLOAD_EXE_AUTO_STACK + 15) >> 4 ; exeInitSS - dw _SECOND_PAYLOAD_EXE_AUTO_STACK ; exeInitSP -%else - dw _SECOND_PAYLOAD_EXE_SS ; exeInitSS - dw _SECOND_PAYLOAD_EXE_SP ; exeInitSP -%endif - dw 0 ; exeChecksum - dw _SECOND_PAYLOAD_EXE_IP, _SECOND_PAYLOAD_EXE_CS ; exeInitCSIP - dw 0 ; exeRelocTable -%else - dw -1 ; exePages - dw 0 ; exeRelocItems - dw 0 ; exeHeaderSize - dw -1 ; exeMinAlloc - dw -1 ; exeMaxAlloc - dw -16, 0 ; exeInitSS, exeInitSP - dw 0 ; exeChecksum - dw 100h, -16 ; exeInitCSIP - dw 0 ; exeRelocTable -%endif - -ms6_entry: - ; This is the MS-DOS 6 / IBMDOS compatible entry point. - ; Note that this supports FAT32 for PC-DOS 7.10! - ; cs:ip = 70h:0 - ; ax:bx = first data sector of first cluster, - ; including hidden sectors - ; 0:7C00h-> boot sector with BPB, - ; load unit field set, hidden sectors set - ; (actually boot unit in dl; because the "MZ" signature - ; destroys dl we assume it's in the BPB too) - ; Either: - ; dword [ss:sp] = 0:78h = 1Eh * 4 (IVT entry of int 1Eh) - ; dword [ss:sp + 4] = old int 1Eh address - ; Or: - ; ds:si = old int 1Eh address - ; 0:500h-> directory entry for BIO file - cli - cld - push dx - inc bp ; undo signature instructions - -d3 call d3_display_two_characters -d3 test ax, "00" - - mov cx, cs - cmp cx, 60h - jne @F -.freedos_or_msdos1_com_entry: - jmp freedos_or_msdos1_com_entry -@@: - -; xor cx, cx -;; test dx, dx -;; jnz @FF - ; Actual DOS will always put a zero word on top of - ; the stack. But when the debugger loads us as - ; a flat format binary it may set up another - ; stack segment or not initialise the stack slot. - ; (So as to avoid corrupting the binary.) - ; The offset check should suffice anyway. - call @F -@@: - pop cx - sub cx, @B ; cx == 0 iff entered at offset 0 - jne .freedos_or_msdos1_com_entry -@@: - ; cx = 0 - - ; Note: It has been observed that some IBMBIO.COM / IO.SYS - ; boot sector loaders pass the int 1Eh address on the - ; stack (like MS-DOS 7 loading does). So we detect - ; whether the first dword (far pointer to IVT entry) - ; matches and then assume that the second dword has - ; the original int 1Eh address. Else, ds:si is used. - mov di, 1Eh * 4 ; -> IVT entry of int 1Eh - cmp dx, di ; int 1Eh address on stack ? - jne .dssi ; no --> - mov bp, sp - cmp word [bp + 2], cx ; segment 0 in next word ? - jne .dssi ; no --> - pop si - pop ds ; discard - pop si - pop ds ; get old int 1Eh address from stack -.dssi: - jmp ms6_continue1 - - -error: - push cs - pop ds - mov si, msg.error - call disp_error - pop si - call disp_error - xor ax, ax - int 16h - int 19h - - -disp_error.loop: - mov ah, 0Eh - mov bx, 7 - ; push bp - ; (call may change bp, but it is not used here any longer.) - int 10h - ; pop bp -disp_error: - lodsb - test al, al - jnz .loop - retn - - -query_geometry: -%if _QUERY_GEOMETRY || !_LBA_SKIP_CHECK - ; magic bytes start - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - ; magic bytes - %if _QUERY_PATCH - mov ax, _QUERY_DEFAULT ; magic bytes, checked by patch script -..@query_patch_site equ $ - 2 - test dl, dl ; hard disk unit ? - jns @F ; no --> - xchg al, ah ; get high byte into al - ; magic bytes end -@@: - %endif -%endif - -%if _QUERY_GEOMETRY ; +30 bytes - %if !_LBA_SKIP_CHECK - push dx - %if _QUERY_PATCH - push ax - %endif - %endif - - %if _QUERY_PATCH - test al, 4 ; don't query geometry ? - jnz @F ; yes --> - %endif - -; test dl, dl ; floppy? -; jns @F ; don't attempt query, might fail --> - ; Note that while the original PC BIOS doesn't support this function - ; (for its diskettes), it does properly return the error code 01h. - ; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1) - mov ah, 08h - xor cx, cx ; initialise cl to 0 - stc ; initialise to CY - int 13h ; query drive geometry - jc @F ; apparently failed --> - and cx, 3Fh ; get sectors - jz @F ; invalid (S is 1-based), don't use --> - mov [bp + bsBPB + bpbCHSSectors], cx - mov cl, dh ; cx = maximum head number - inc cx ; cx = number of heads (H is 0-based) - mov [bp + bsBPB + bpbCHSHeads], cx -@@: -%endif - -%if !_LBA_SKIP_CHECK - %if _QUERY_GEOMETRY - %if _QUERY_PATCH - pop ax ; restore query patch flags in al - %endif - pop dx ; restore unit number in dl - %endif - %if _QUERY_PATCH - shr al, 1 ; CY if force CHS - jc @F ; if so --> - and al, 1 ; force LBA ? - jnz .done_lba ; yes --> - %endif - mov ah, 41h - mov bx, 55AAh - stc - int 13h ; 13.41.bx=55AA extensions installation check -@@: - mov al, 0 ; zero in case of no LBA support - jc .no_lba - cmp bx, 0AA55h - jne .no_lba - shr cl, 1 ; support bitmap bit 0 - jnc .no_lba - inc ax ; al = 1 to indicate LBA support -.no_lba: -.done_lba: - mov byte [bp + ldHasLBA], al -%else - mov byte [bp + ldHasLBA], 0 -%endif - -%if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK - retn -%endif - - - ; Read a sector using Int13.02 or Int13.42 - ; - ; INP: dx:ax = sector number within partition - ; bx:0-> buffer - ; (_LBA) ds = ss - ; OUT: If unable to read, - ; ! jumps to error instead of returning - ; If sector has been read, - ; dx:ax = next sector number (has been incremented) - ; bx:0-> next buffer (bx = es+word[para_per_sector]) - ; es = input bx - ; CHG: - - ; STT: ds = ss - ; - ; Note: If error 09h (data boundary error) is returned, - ; the read is done into the ldSectorSeg buffer, - ; then copied into the user buffer. -read_sector: - push dx - push cx - push ax - push si - - mov es, bx - -; DX:AX==LBA sector number -; add partition start (= number of hidden sectors) - add ax,[bp + bsBPB + bpbHiddenSectors + 0] - adc dx,[bp + bsBPB + bpbHiddenSectors + 2] - - %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33 - jc .err_CY_2 - %if !_LBA -.err_CY_2: equ .err_CY_1 - %endif - %endif -%if _LBA ; +70 bytes (with CHS, +63 bytes without CHS) - %if _LBA_33_BIT - sbb si, si ; -1 if was CY, 0 else - neg si ; 1 if was CY, 0 else - %endif - xor cx, cx ; cx = 0 (needed if jumping to .no_lba_checked) - %if !_LBA_SKIP_CHECK - test byte [bp + ldHasLBA], 1 - jz .no_lba_checked - %endif - push cx - %if _LBA_33_BIT - push si ; bit 32 = 1 if operating in 33-bit space - %else - push cx ; second highest word = 0 - %endif - push dx - push ax ; qword sector number (lpSector) - push bx - push cx ; bx:0 -> buffer (lpBuffer) - inc cx - push cx ; word number of sectors to read (lpCount) - mov cl, 10h - push cx ; word size of disk address packet (lpSize) - mov si, sp ; ds:si -> disk address packet (on stack) - - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - mov ah, 42h ; 13.42 extensions read -%if _LBA_RETRY - call .int13_retry -%else - call .int13_preserve_lpcount -%endif - jnc .lba_done - -%if _LBA_SKIP_CHECK - cmp ah, 1 ; invalid function? - je .no_lba_skip ; try CHS instead --> -%endif - cmp ah, 9 ; data boundary error? - jne .lba_error - - ; push word [si + 4 + 0] - push es ; => user buffer - mov es, word [bp + ldSectorSeg] - mov word [si + 4 + 2], es - ; and word [si + 4 + 0], byte 0 - - mov ah, 42h -%if _LBA_RETRY - call .int13_retry -%else - int 13h - ; (don't need .int13_preserve_lpcount as no further call) -%endif -.err_CY_2: - jc .err_CY_1 -%ifn _CHS -.err_CY_1: equ .err -%endif - - pop es - ; pop cx - add sp, 10h - jmp .sectorseg_helper_then_done - -.lba_done: - add sp, 10h - jmp short .done - -.lba_error: equ .err - - %if !_CHS -.no_lba_skip: equ .err -.no_lba_checked: equ .err - %elif _LBA_SKIP_CHECK -.no_lba_skip: - add sp, 8 - pop ax - pop dx - %if _LBA_33_BIT - pop si - pop cx ; cx = 0 (needed as input for next cwd instruction) - test si, si - mov si, sp ; si == sp - %else - pop cx - pop cx - ; si == sp - 16 - %endif - %else -.no_lba_checked: - %if _LBA_33_BIT - test si, si - %endif - mov si, sp ; si == sp - %endif -%endif - -%if _CHS ; +70 bytes - %if _LBA && _LBA_33_BIT - jnz .err_NZ_2 - %endif -; dx:ax = LBA sector number, (if _LBA) cx = 0 -; divide by number of sectors per track to get sector number -; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability -; Use two-step 32:16 divide to avoid overflow - %if !_LBA - xchg cx, ax ; cx = low word of sector, clobbers ax - xchg ax, dx ; ax = high word of sector, clobbers dx - xor dx, dx ; dx:ax = high word of sector - %else - xchg cx, ax ; cx = low word of sector, ax = 0 - push dx ; stack = high word of sector - cwd ; dx = 0 (because ax was 0) - pop ax ; ax = high word of sector - ; dx:ax = high word of sector - %endif - div word [bp + bsBPB + bpbCHSSectors] - xchg cx,ax - div word [bp + bsBPB + bpbCHSSectors] - xchg cx,dx - -; DX:AX=quotient, CX=remainder=sector (S) - 1 -; divide quotient by number of heads - xchg bx, ax ; bx = low word of quotient, clobbers ax - xchg ax, dx ; ax = high word of quotient, clobbers dx - xor dx, dx ; dx = 0 - div word [bp + bsBPB + bpbCHSHeads] - ; ax = high / heads, dx = high % heads - xchg bx, ax ; bx = high / heads, ax = low quotient - div word [bp + bsBPB + bpbCHSHeads] - -; bx:ax=quotient=cylinder (C), dx=remainder=head (H) -; move variables into registers for INT 13h AH=02h - mov dh, dl ; dh = head - inc cx ; cl5:0 = sector - xchg ch, al ; ch = cylinder 7:0, al = 0 - shr ax, 1 - shr ax, 1 ; al7:6 = cylinder 9:8 - ; bx has bits set iff it's > 0, indicating a cylinder >= 65536. - or bl, bh ; collect set bits from bh - or cl, al ; cl7:6 = cylinder 9:8 - ; ah has bits set iff it was >= 4, indicating a cylinder >= 1024. - or bl, ah ; collect set bits from ah - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - ; dl = drive -.err_NZ_2: - jnz .err_NZ_1 ; error if cylinder >= 1024 --> - ; ! bx = 0 (for 13.02 call) - -; we call INT 13h AH=02h once for each sector. Multi-sector reads -; may fail if we cross a track or 64K boundary - - mov ax, 0201h ; read one sector -%if _CHS_RETRY - call .int13_retry -%else - int 13h -%endif - jnc .done - - cmp ah, 9 ; data boundary error? -.err_NZ_1: - jne .err - - push es ; user buffer - mov es, word [bp + ldSectorSeg] - - mov ax, 0201h -%if _CHS_RETRY - call .int13_retry -%else - int 13h -%endif -.err_CY_1: - jnc .sectorseg_helper_es -%endif ; _CHS -.err: -error_diskaccess: equ $ - call error - db "Disk read error.", 0 - - -%if _CHS -.sectorseg_helper_es: - pop es -%endif - -.sectorseg_helper_then_done: - xor si, si - mov ds, word [bp + ldSectorSeg] - push di - ; mov di, cx - xor di, di - mov cx, word [bp + bsBPB + bpbBytesPerSector] - rep movsb - pop di - - push ss - pop ds - -.done: -; increment segment - mov bx, es - add bx, word [bp + ldParaPerSector] - - pop si - pop ax - pop cx - pop dx -.increment_sector_number: -; increment LBA sector number - inc ax - jne @F - inc dx -@@: - retn - - -%if (_LBA && _LBA_RETRY) || (_CHS && _CHS_RETRY) -.int13_retry: - push ax -%if _LBA - call .int13_preserve_lpcount -%else - int 13h ; first try -%endif - jnc @F ; NC, success on first attempt --> - -; reset drive - xor ax, ax - int 13h - jnc @FF ; NC, reset succeeded --> - ; CY, reset failed, error in ah - -@@: ; NC or CY, stack has function number - inc sp - inc sp ; discard word on stack, preserve CF - retn - -@@: -; try read again - pop ax ; restore function number -%if ! _LBA - int 13h ; retry, CF error status, ah error number - retn -%endif ; else: fall through to .int13_preserve_lpcount -%endif - -%if _LBA - ; have to reset the LBAPACKET's lpCount, as the handler may - ; set it to "the number of blocks successfully transferred". - - ; hack: si points into unclaimed stack space - ; when this is called from the CHS handler. - ; this should not cause any issues however. - ; actually, if !_LBA_SKIP_CHECK, then si is set - ; to point to claimed stack space. also legal. -.int13_preserve_lpcount: - push word [si + lpCount] - int 13h - pop word [si + lpCount] - retn -%endif - - -error_shortfile: - call error - db "File is too short.", 0 - -error_badchain: - call error - db "Bad cluster chain.", 0 - -error_badclusters: - call error - db "Bad amount of clusters.", 0 - -error_outofmemory: - call error - db "Out of memory.", 0 - -%assign num 512-($-$$) -%if num >= 3 -%assign num num - 3 - %warning num bytes in front of ms7_entry - _fill 512 - 3,38,start -error_outofmemory_j1: - jmp error_outofmemory -%else -error_outofmemory_j1: equ error_outofmemory - %warning num bytes in front of ms7_entry -%endif - _fill 512,38,start -ms7_entry: - ; This is the MS-DOS 7 compatible entry point. - ; Supports FAT32 too. - ; cs:ip = 70h:200h - ; (si:)di = first cluster of load file - ; dwo [ss:bp - 4] = first data sector (with hidden sectors) - ; dwo [ss:sp] = 0:78h (IVT entry of int 1Eh) - ; dwo [ss:sp + 4] = old int 1Eh address - ; ss:bp -> boot sector with (E)BPB, - ; load unit field set, hidden sectors set - inc dx - dec dx ; "BJ" signature (apparently not about FAT32 support) - - jmp .continue ; jump to handler above 600h (sector loads 800h bytes) - -.ms6_common: ; cx = 0 - mov ax, 70h + ((3 * 512) >> 4) ; MS6 entry has 3 sectors loaded - ; (and is always segment 70h) - -.continue2_set_extra_and_empty_cmdline: ; cx = 0, ax => behind loaded -%if _LSVEXTRA - mov word [bp + lsvExtra], cx -%endif - mov word [bp + lsvCommandLine], cx -.continue2: ; cx = 0, ax => behind loaded - mov word [bp + lsvLoadSeg], ax - - mov word [bp + lsvFATSeg], cx ; initialise to zero (for FAT12) - dec cx - mov word [bp + lsvFATSector + 0], cx - mov word [bp + lsvFATSector + 2], cx ; initialise to -1 - - ; Actually it seems that the MS-DOS 7 loaders load 4 sectors - ; instead of only three (as the MS-DOS 6 loaders do). - ; We use this to store specific handling in that last sector. - - jmp ldos_entry.ms7_common - -msg: -.error: db "Load error: ", 0 - - -finish_continue: - mov bx, cs - add ax, bx ; = cs + rounded up length - sub ax, word [bp + ldLoadTop] ; = paras to move down - jbe short finish_load - - mov cx, word [bp + lsvLoadSeg] - ; => after end of loaded data - sub word [bp + lsvLoadSeg], ax - ; relocate this pointer already - neg ax - add ax, bx ; ax = cs - paras to move down - ; want to relocate cs to this - jnc short error_outofmemory_j1 - mov di, relocate_to - push ax - push di ; dword on stack: relocate_to - cmp ax, 60h + 1 - jb short error_outofmemory_j1 - push ax ; word on stack => where to relocate to - dec ax ; one less to allow relocator - mov es, ax - - -finish_relocation: - xor di, di ; es:di -> where to put relocator - - push es - push di ; dword on stack: relocator destination - - mov ds, bx ; ds => unrelocated cs - mov si, relocator ; ds:si -> relocator -relocator_size equ relocator.end - relocator -%rep (relocator_size + 1) / 2 - movsw ; place relocator -%endrep -%if relocator_size > 16 - %error Relocator is too large -%endif - xor di, di ; word [ss:sp+4]:di -> where to relocate to - xor si, si ; ds:si = cs:0 - - ; cx => after end of loaded data - sub cx, bx ; length of currently loaded fragment - mov bx, 1000h - mov ax, cx - cmp ax, bx ; > 64 KiB ? - jbe @F - mov cx, bx ; first relocate the first 64 KiB -@@: - sub ax, cx ; how much to relocate later - shl cx, 1 - shl cx, 1 - shl cx, 1 ; how much to relocate first, - ; << 3 == convert paragraphs to words - retf ; jump to relocator - - - ; ds => first chunk of to be relocated data - ; es => first chunk of relocated data - ; bx = 1000h (64 KiB >> 4) - ; ax = number of paragraphs after first chunk (in next chunk) -relocate_to: -@@: - mov dx, es - add dx, bx - mov es, dx ; next segment - - mov dx, ds - add dx, bx - mov ds, dx ; next segment - - sub ax, bx ; = how much to relocate after this round - mov cx, 1000h << 3 ; in case another full 64 KiB to relocate - jae @F ; another full 64 KiB to relocate --> - add ax, bx ; restore - shl ax, 1 - shl ax, 1 - shl ax, 1 ; convert paragraphs to words - xchg cx, ax ; cx = that many words - xor ax, ax ; no more to relocate after this round - -@@: - xor si, si - xor di, di - rep movsw ; relocate next chunk - test ax, ax ; another round needed? - jnz @BB ; yes --> - - push ss - pop ds - - ; ds = ss - ; cs = low enough to complete load - ; lsvLoadSeg => after last loaded fragment - ; ldLoadTop => after last available memory - ; ldParaPerSector = initialised - ; word [ss:sp] = payload.actual_end in paras -finish_load: - pop ax - mov bx, cs - add ax, bx - mov word [bp + ldLoadUntilSeg], ax - ; ldLoadUntilSeg => after last to-be-loaded paragraph - - mov bx, word [bp + lsvLoadSeg] - cmp bx, ax - jae short loaded_all_if_ae ; (for FreeDOS entrypoint) already loaded --> - - mov word [bp + ldLoadingSeg], cs - - mov ax, [bp + lsvFirstCluster] - mov dx, [bp + lsvFirstCluster + 2] - mov di, [bp + lsvFATSector] - mov si, [bp + lsvFATSector + 2] - call check_clust - jc short error_badchain_j - -skip_next_clust: - push dx - push ax - call clust_to_first_sector -skip_next_sect: - mov bx, [bp + ldLoadingSeg] - cmp bx, [bp + ldLoadUntilSeg] - jae loaded_all.2stack - - add bx, [bp + ldParaPerSector] - ; bx += paras per sector - cmp bx, [bp + lsvLoadSeg] - ja skipped_all - ; emulate read_sector: - call read_sector.increment_sector_number - ; dx:ax += 1 - mov [bp + ldLoadingSeg], bx - - loop skip_next_sect - pop ax - pop dx - call clust_next - jnc skip_next_clust -end_of_chain: - inc ax - inc ax - test al, 8 ; set in 0FFF_FFF8h--0FFF_FFFFh, - ; clear in 0, 1, and 0FFF_FFF7h - jz short error_badchain_j - mov bx, [bp + ldLoadingSeg] - cmp bx, [bp + ldLoadUntilSeg] -loaded_all_if_ae: - jae loaded_all - jmp error_shortfile - - -skipped_all: - sub bx, [bp + ldParaPerSector] - ; restore bx => next sector to read - call read_sector - ; we can depend on the fact that at least - ; up to end was already loaded, so this - ; (successful) read_sector call loaded - ; at least 32 bytes starting at end. - ; therefore, we can put part of the - ; remaining handler into these 32 bytes. - jmp skipped_all_continue - - -error_badchain_j: - jmp error_badchain - - - ; ds => first chunk of to be relocated data - ; word [ss:sp] => first chunk of relocation destination - ; cx = number of words in first chunk -relocator: - pop es ; => where to relocate to - rep movsw - retf ; jump to relocated relocate_to -.end: - - - ; INP: dx:ax = cluster - 2 (0-based cluster) - ; OUT: dx:ax = first sector of that cluster - ; cx = adjusted sectors per cluster - ; CHG: bx -clust_to_first_sector: - mov cx, word [bp + ldClusterSize] - push dx - mul cx - xchg bx, ax - pop ax - push dx - mul cx - test dx, dx - jnz short error_badchain_j - xchg dx, ax - pop ax - add dx, ax -.cy_error_badchain: - jc short error_badchain_j - xchg ax, bx - - add ax, [bp + lsvDataStart] - adc dx, [bp + lsvDataStart + 2] - jc short .cy_error_badchain - ; dx:ax = first sector in cluster - retn - - - ; INP: dx:ax = cluster (0-based) - ; si:di = loaded FAT sector, -1 if none - ; OUT: CY if no next cluster - ; NC if next cluster found - ; dx:ax = next cluster value (0-based) - ; si:di = loaded FAT sector - ; CHG: cx, bx -clust_next: - add ax, 2 - adc dx, 0 - - push es - cmp byte [bp + ldFATType], 16 - je .fat16 - ja .fat32 - -.fat12: -; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2, -; so multiply cluster number by 3 first, then divide by 2. - ; ax = cluster number (up to 12 bits set) - mov dx, ax - shl ax, 1 ; = 2n (up to 13 bits set) - add ax, dx ; = 2n+n = 3n (up to 14 bits set) - shr ax, 1 ; ax = byte offset into FAT (0..6129) - ; CF = whether to use high 12 bits - sbb cx, cx ; = -1 iff CY, else 0 - -; Use the calculated byte offset as an offset into the FAT -; buffer, which holds all of the FAT's relevant data. - mov es, [bp + lsvFATSeg] - xchg bx, ax ; bx -> 16-bit word in FAT to load - -; get 16 bits from FAT - mov ax, [es:bx] - - and cl, 4 ; = 4 iff CY after shift, else 0 - shr ax, cl ; shift down iff odd entry, else unchanged - and ax, 0FFFh ; insure it's only 12 bits - jmp short .gotvalue_zero_dx - -.fat32: - ; * 4 = byte offset into FAT (0--4000_0000h) - add ax, ax - adc dx, dx -.fat16: - ; * 2 = byte offset into FAT (0--2_0000h) - add ax, ax - adc dx, dx - - push ax - xchg ax, dx - xor dx, dx ; dx:ax = high word - div word [bp + bsBPB + bpbBytesPerSector] - xchg bx, ax ; bx = high word / divisor - pop ax ; dx = remainder, ax = low word - div word [bp + bsBPB + bpbBytesPerSector] - xchg dx, bx ; dx:ax = result, bx = remainder - ; dx:ax = sector offset into FAT (0--200_0000h) - ; bx = byte offset into FAT sector (0--8190) - cmp dx, si - jne @F ; read sector - cmp ax, di - je @FF ; sector is already buffered -@@: - mov si, dx - mov di, ax - mov word [bp + lsvFATSector + 2], dx - mov word [bp + lsvFATSector + 0], ax - - push bx - add ax, [bp + bsBPB + bpbReservedSectors] - adc dx, 0 - mov bx, [bp + lsvFATSeg] - call read_sector - pop bx -@@: - mov es, [bp + lsvFATSeg] - mov dx, [es:bx + 2] - mov ax, [es:bx] ; dx:ax = FAT32 entry - - cmp byte [bp + ldFATType], 16 ; is it FAT32 ? - jne @F ; yes --> -.gotvalue_zero_dx: - xor dx, dx ; no, clear high word -@@: - pop es - - ; INP: dx:ax = cluster value, 2-based - ; OUT: dx:ax -= 2 (makes it 0-based) - ; CY iff invalid cluster -check_clust: - and dh, 0Fh - sub ax, 2 - sbb dx, 0 - - cmp byte [bp + ldFATType], 16 - ja .fat32 - je .fat16 - -.fat12: - cmp ax, 0FF7h - 2 - jmp short .common - -.fat32: - cmp dx, 0FFFh - jb @F ; CY here means valid ...- - -.fat16: - cmp ax, 0FFF7h - 2 -@@: ; -... or if NC first, CY here also -.common: - cmc ; NC if valid - retn - - -ms6_continue1: - mov es, cx ; cx = 0 - mov bp, 7C00h ; 0:bp -> boot sector with BPB - - mov word [es:di], si - mov word [es:di + 2], ds ; restore old int 1Eh address - - mov ss, cx ; = 0 - mov sp, 7C00h + lsvCommandLine - - push word [es:500h + 20] - push word [es:500h + 26] - pop word [bp + lsvFirstCluster + 0] - pop word [bp + lsvFirstCluster + 2] - - sub bx, word [bp + bsBPB + bpbHiddenSectors + 0] - sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2] - mov word [bp + lsvDataStart + 0], bx - mov word [bp + lsvDataStart + 2], ax - jmp ms7_entry.ms6_common ; passing cx = 0 - - -%assign num 1020-($-$$) -%warning num bytes in front of ldos_entry - _fill 1020,38,start - dw "lD" ; always this signature (word [1020] == 446Ch) - dw _INILOAD_SIGNATURE - ; two printable non-blank ASCII characters - ; (ie both bytes in the range 21h..7Eh) - ; Rx = RxDOS kernel - ; FD = FreeDOS kernel - ; TP = TestPL - ; (lD)eb = lDebug - ; (lD)Db = lDDebug -%if ($ - $$) != 1024 - %error Invalid signature -%endif -ldos_entry: - cli - cld - - ; ip = 400h - ; cs = arbitrary; typically 60h, 70h, or 200h - ; dwo [ss:bp - 4] = first data sector (without hidden sectors) - ; wo [ss:bp - 6] = load_seg, => after last loaded data - ; wo [ss:bp - 8] = fat_seg, 0 if invalid - ; initialised to 0 by MS-DOS 6, 7, FreeDOS entrypoints - ; fat_sector is not used for FAT12 ! - ; wo [ss:bp - 12] = fat_sector, -1 if none (FAT16) - ; dwo [ss:bp - 12] = fat_sector, -1 if none (FAT32) - ; initialised to -1 by MS-DOS 6, 7, FreeDOS entrypoints - ; wo [ss:bp - 16] = first_cluster (FAT16, FAT12) - ; dwo [ss:bp - 16] = first_cluster (FAT32) - ; initialised to 0 by FreeDOS entrypoint - ; - ; Extension 1: - ; lsvExtra (word [ss:bp - 18]) may be set, - ; not sure about interface yet. allows - ; to not initialise data start, or to specify - ; a partition number instead of offset - ; - ; Extension 2: - ; word [ss:bp - 20] = signature "CL" if valid - ; bp >= 20 + 256 if valid - ; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string - - xor ax, ax - push ax ; push into lsvExtra if sp -> LSV -%if _LSVEXTRA - mov word [bp + lsvExtra], ax - ; byte [ss:bp - 18] = partition number - ; byte [ss:bp - 17] = flags for initialisation -%endif - push ax ; push into lsvCommandLine if sp -> LSV - -.ms7_common: - mov ax, cs - mov cx, word [bp + lsvLoadSeg] - sub cx, ax - cmp cx, (end -$$+0) >> 4 - jae @F -error_notfullyloaded: - call error - db "Initial loader not fully loaded.", 0 -@@: - - mov bx, (payload.actual_end -$$+0 +15) >> 4 - cmp cx, bx - jbe @F - add bx, ax - mov word [bp + lsvLoadSeg], bx -@@: - -init_memory: -; Get conventional memory size and store it - int 12h - mov cl, 6 - shl ax, cl -%if _RPL - xor si, si - xchg dx, ax - mov ds, si - lds si, [4 * 2Fh] - add si, 3 - lodsb - cmp al, 'R' - jne .no_rpl - lodsb - cmp al, 'P' - jne .no_rpl - lodsb - cmp al, 'L' - jne .no_rpl - mov ax, 4A06h - int 2Fh -.no_rpl: - xchg ax, dx -%endif - push ax - ; sub ax, 32 >> 4 ; make space for two MCBs: top MCB, RPL MCB - dec ax - dec ax - mov cx, ax - sub ax, (8192 + 16) >> 4 - dec cx ; => last paragraph of higher buffer (16-byte trailer) - mov dx, ax ; => first paragraph of higher buffer - mov bx, cx - and dh, 0F0h ; 64 KiB chunk of first paragraph of higher buffer - and bh, 0F0h ; 64 KiB chunk of last paragraph of higher buffer - cmp bh, dh ; in same chunk? - mov bx, ax - je .gotsectorseg ; yes, use higher buffer as sector buffer -> - ; bx = use higher buffer as FAT buffer - inc bx ; => 8 KiB buffer (no 16-byte trailer) - sub ax, (8192 + 32) >> 4 - ; 32 = leave space for higher buffer MCB + header - ; +16 from the above calcs for 16-byte trailer - mov cx, ax ; use lower buffer as sector buffer - jmp short .gotsegs - -.gotsectorseg: - ; ax = use higher buffer as sector buffer - sub bx, (8192 + 32) >> 4 ; use lower buffer as FAT buffer - ; 32 = leave space for higher buffer MCB + header - mov cx, bx - ; ax = sector seg - ; bx = FAT seg - ; cx = the lower of the two -.gotsegs: - sub cx, (+_STACKSIZE -LOADCMDLINE + 512 + (ebpbNew - bpbNew) + 32 + 15) >> 4 - ; +_STACKSIZE = stack space - ; -LOADCMDLINE = load cmd line + data + lsv space - ; 512 = boot sector (allows finding filename) - ; (ebpbNew - bpbNew) = additional space for BPBN moving - ; 32 = leave space for lower buffer MCB + header - ; cx = stack seg - - dec cx ; leave space for stack + BPB buffer MCB - cmp cx, word [bp + lsvLoadSeg] - jnb @F -.error_outofmemory: - jmp error_outofmemory -@@: - - push ax - mov dx, ss - mov ax, bp - add ax, 512 + 15 - jnc @F - mov ax, 1_0000h >> 1 - db __TEST_IMM16 ; (skip one shr) -@@: - shr ax, 1 - shr ax, 1 - shr ax, 1 - shr ax, 1 - add dx, ax - cmp dx, cx - ja .error_outofmemory - - ; note that the next conditional doesn't jump for lsvFATSeg = 0 - mov dx, word [bp + lsvFATSeg] - add dx, (8192) >> 4 - cmp dx, cx - ja .error_outofmemory - pop ax - - pop dx ; top of memory (=> start of RPL, EBDA, video memory) - inc cx ; => stack + BPB buffer - push ss - pop ds - mov es, cx - push cx ; top of memory below buffers - push ax ; => sector seg - - xor cx, cx - lea si, [bp + lsvCommandLine.start] - cmp bp, si ; can have command line ? - ; (also makes sure movsw and lodsw never run - ; with si = 0FFFFh which'd cause a fault.) - jb .no_cmdline - - mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start - ; -> cmd line target - mov cl, (LOADCMDLINE_size + 1) >> 1 - rep movsw ; copy cmd line -%if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature - %error Unexpected structure layout -%endif - lodsw - cmp ax, lsvclSignature - je @F ; if command line given --> -.no_cmdline: - mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl - ; truncate as if empty line given - dec cx ; cl = 0FFh -@@: - mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start \ - + fromwords(words(LOADCMDLINE_size)) - 1 ], cl - ; remember whether command line given - ; = 0 if given (also truncates if too long) - ; = 0FFh if not given - - ; si happens to be already correct here if we didn't - ; branch to .no_cmdline, however make sure to set - ; it here to support this case. - lea si, [bp + lsvExtra] - ; ds:si -> lsv + BPB - mov di, _STACKSIZE - LOADCMDLINE + lsvExtra - ; es:di -> where to place lsv - mov cx, (- lsvExtra + 512 + 1) >> 1 - rep movsw ; copy lsv (including lsvExtra) and BPB - xor ax, ax - mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1 - rep stosw ; initialise area behind sector (left so for FAT32) - pop ax - pop cx - mov ss, cx - mov sp, _STACKSIZE - ; -> above end of stack space - mov bp, _STACKSIZE - LOADCMDLINE - ; -> BPB, above end of lsv - dec cx ; => space for stack + BPB buffer MCB - sti - - ; ax => sector buffer - ; bx => FAT buffer - ; cx => above end of memory available for load - ; dx => above end of memory used by us - mov word [bp + ldMemoryTop], dx - mov word [bp + ldLoadTop], cx - mov word [bp + ldSectorSeg], ax - - mov ds, word [bp + lsvFATSeg] - xor si, si ; ds:si -> FAT buffer - mov es, bx - xor di, di ; es:di -> where to move - mov cx, 8192 >> 1 - rep movsw - mov word [bp + lsvFATSeg], bx - - push ds ; to check for word [lsvFATSeg] == zero later on - - push ss - pop es - push ss - pop ds - - mov bx, [bp + bsBPB + bpbSectorsPerFAT] - test bx, bx - jz .is_fat32 - - ; lea si, [bp + 510] ; -> last source word - mov si, _STACKSIZE - LOADCMDLINE + 510 - lea di, [si + (ebpbNew - bpbNew)] ; -> last dest word - mov cx, (512 - bsBPB - bpbNew + 1) >> 1 - ; move sector up, except common BPB start part -%if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20 - %fatal Need AMD erratum 109 workaround -%endif - std ; AMD erratum 109 handling not needed - rep movsw - cld - - mov word [bp + lsvFirstCluster + 2], cx - mov word [bp + lsvFATSector + 2], cx - - mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx - mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx - mov word [bp + bsBPB + ebpbFSFlags], cx - ; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved: - ; uninitialised here (initialised by loaded_all later) -.is_fat32: -%if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK - call query_geometry - ; The ebpbNew BPBN needs to be initialised - ; to use this function. It must be called - ; before using read_sector (used by the FAT12 - ; FAT loader, or by finish_load later). -%endif - -%if _LSVEXTRA - test byte [bp + lsvExtra.flags], -1 - jz @F - - mov cx, cs - mov ax, word [bp + lsvLoadSeg] - sub ax, cx - cmp ax, (end_of_handle_lsv_extra_flags + 15 -$$+0) >> 4 - jb error_notfullyloaded - - call handle_lsv_extra_flags -@@: -%endif - -; adjusted sectors per cluster (store in a word, -; and decode EDR-DOS's special value 0 meaning 256) - mov al, [bp + bsBPB + bpbSectorsPerCluster] - dec ax - mov ah, 0 - inc ax - mov [bp + ldClusterSize], ax - -; 16-byte paragraphs per sector - mov ax, [bp + bsBPB + bpbBytesPerSector] - mov cl, 4 - shr ax, cl - mov [bp + ldParaPerSector], ax - -; total sectors - ; After the prior shr instruction, ax is < 8000h, - ; so the following cwd always zeros dx. - cwd - mov ax, [bp + bsBPB + bpbTotalSectors] - test ax, ax - jnz @F - mov dx, [bp + bsBPB + bpbTotalSectorsLarge + 2] - mov ax, [bp + bsBPB + bpbTotalSectorsLarge] - - ; fall through and let it overwrite the field with the - ; already current contents. saves a jump. -@@: - mov [bp + bsBPB + bpbTotalSectorsLarge + 2], dx - mov [bp + bsBPB + bpbTotalSectorsLarge], ax - - ; dx:ax = total sectors - - cmp word [bp + bsBPB + bpbSectorsPerFAT], 0 - mov byte [bp + ldFATType], 32 - je .got_fat_type - - ; dx:ax = total amount of sectors - sub ax, word [bp + lsvDataStart] - sbb dx, word [bp + lsvDataStart + 2] - - ; dx:ax = total amount of data sectors - mov bx, ax - xchg ax, dx - xor dx, dx - div word [bp + ldClusterSize] - xchg bx, ax - div word [bp + ldClusterSize] - ; bx:ax = quotient, dx = remainder - ; bx:ax = number of clusters - test bx, bx - jz @F -.badclusters: - jmp error_badclusters - -@@: - cmp ax, 0FFF7h - 2 - ja .badclusters - shr byte [bp + ldFATType], 1 ; = 16 - cmp ax, 0FF7h - 2 - ja .got_fat_type - - mov byte [bp + ldFATType], 12 - pop ax - test ax, ax - jnz .got_fat12 - -; lsvFATSeg was zero! This means the FAT isn't loaded yet. - -; Load the entire FAT into memory. This is easily feasible for FAT12, -; as the FAT can only contain at most 4096 entries. -; (The exact condition should be "at most 4087 entries", or with a -; specific FF7h semantic, "at most 4088 entries"; the more reliable -; and portable alternative would be "at most 4080 entries".) -; Thus, no more than 6 KiB need to be read, even though the FAT size -; as indicated by word[sectors_per_fat] could be much higher. The -; first loop condition below is to correctly handle the latter case. -; (Sector size is assumed to be a power of two between 32 and 8192 -; bytes, inclusive. An 8 KiB buffer is necessary if the sector size -; is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB -; of memory instead of only the relevant 6 KiB. This is always true -; if the sector size is 8 KiB, and with 4 KiB sector size it is true -; iff word[sectors_per_fat] is higher than one.) - mov di, 6 << 10 ; maximum size of FAT12 to load - mov cx, [bp + bsBPB + bpbSectorsPerFAT] - ; maximum size of this FS's FAT - ; If we're here, then ax = 0 (jnz jumped if not), - ; so this cwd always zeros dx. - cwd - mov ax, [bp + bsBPB + bpbReservedSectors]; = first FAT sector - mov bx, [bp + lsvFATSeg] -@@: - call read_sector ; read next FAT sector - sub di, [bp + bsBPB + bpbBytesPerSector] - ; di = bytes still left to read - jbe @F ; if none --> - ; (jbe means jump if CF || ZF) - loop @B ; if any FAT sector still remains --> -@@: ; one of the limits reached; FAT read - -.got_fat12: - db __TEST_IMM8 ; skip pop ax -.got_fat_type: - pop ax - - mov ax, (payload.actual_end -$$+0 +15) >> 4 - push ax - ; on stack: payload.actual_end in paragraphs - mov bx, [bp + ldParaPerSector] - dec bx ; para per sector - 1 - add ax, bx ; round up - not bx ; ~ (para per sector - 1) - and ax, bx ; rounded up, - ; ((payload.actual_end -$$+0 +15) >> 4 + pps - 1) & ~ (pps - 1) - - jmp finish_continue - - -%assign num 1024+512-($-$$) -%warning num bytes in front of end - _fill 1024+512,38,start -end: - - -load_next_clust: - push dx - push ax - call clust_to_first_sector -load_next_sect: - mov bx, [bp + ldLoadingSeg] - cmp bx, [bp + ldLoadUntilSeg] - jae loaded_all.2stack_j - - call read_sector -skipped_all_continue: - mov [bp + ldLoadingSeg], bx - loop load_next_sect - pop ax - pop dx - call clust_next - jnc load_next_clust - jmp end_of_chain - -%if ($ - end) > 32 - %error load_next part exceeds end+32 -%endif - - ; if we jump to here, then the whole file has - ; been loaded, so this jump doesn't have to - ; stay in the 32 bytes after the end label. -loaded_all.2stack_j: - jmp loaded_all.2stack - - -ms7_entry.continue: - cli - cld - pop bx - pop es - pop word [es:bx] - pop word [es:bx + 2] - - lea bx, [bp + lsvCommandLine] - cmp sp, bx - jbe @F - mov sp, bx -@@: - mov word [bp + lsvFirstCluster + 0], di - mov word [bp + lsvFirstCluster + 2], si - - mov ax, word [bp + bsBPB + bpbHiddenSectors + 0] - mov dx, word [bp + bsBPB + bpbHiddenSectors + 2] - sub word [bp + lsvDataStart + 0], ax - sbb word [bp + lsvDataStart + 2], dx - - mov ax, cs - add ax, (4 * 512) >> 4 ; MS7 entry has 4 sectors loaded - xor cx, cx ; cx = 0 - jmp ms7_entry.continue2_set_extra_and_empty_cmdline - - -%assign num 2046-($-$$) -%warning num bytes in front of end2 - _fill 2046,38,start - dw "MS" ; signature of MS-DOS 7 load - align 16, db 38 -end2: - - - ; This handling is in the second header part, - ; behind the needed part to finish loading. - ; It is only used when the file is completely loaded. -loaded_all.2stack: - pop ax - pop ax -loaded_all: - mov ax, word [bp + bsBPB + bpbSectorsPerFAT] - test ax, ax - jz .fat32 - - xor ax, ax - push ss - pop es - lea di, [bp + bsBPB + ebpbFSFlags] - mov cx, (EBPB_size - ebpbFSFlags) / 2 - rep stosw - ; initialise ebpbFSFlags (reinit), ebpbFSVersion, - ; ebpbRootCluster, ebpbFSINFOSector, ebpbBackupSector, - ; ebpbReserved - -.fat32: - -%if _CHECKSUM - push cs - pop ds - - mov si, checksumheader - mov cx, CHECKSUMHEADER_size / 2 - xor bx, bx -@@: - cmp si, ..@checksumfield - lodsw - jne @F - xor ax, ax -@@: - add bx, ax - loop @BB - - test bx, bx - jnz error_header_checksum_failed - - testopt [..@checksumtype], 8000h - jnz @F - - call checksum_crc16_6_paragraphs_start_cs - int3 - - push cs - pop ds - - cmp ax, word [..@checksumfield] - jne error_data_checksum_failed -..@data_checksum_ignore_failure_debugger: -@@: -%endif - - push ss - pop es - lea di, [bp + ldCommandLine.start] - mov cx, lsvclBufferLength - xor ax, ax - push word [bp + ldCommandLine.start + lsvclBufferLength - 1] - ; get sentinel (whether command line given) - repne scasb ; scan for terminator - pop ax ; al = 0FFh if no command line given - ; al = 0 else - rep stosb ; clear remainder of buffer - -%if _QUERY_PATCH - mov ax, word [cs:..@query_patch_site] -%else - mov ax, _QUERY_DEFAULT -%endif - mov word [bp + ldQueryPatchValue], ax - - mov ax, cs - add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT - push ax -%if _EXEC_OFFSET - mov ax, _EXEC_OFFSET -%else - xor ax, ax -%endif - push ax - ; cs:ip = xxxxh:_EXEC_OFFSET - ; entire payload loaded (payload -- payload.actual_end) - ; LOADSTACKVARS and LOADDATA and EBPB and ebpbNew BPBN set - ; LOADCMDLINE set (ASCIZ, up to 255 bytes + 1 byte terminator) - ; word [ldCommandLine.start] = 0FF00h if had invalid signature - retf - - -%if _CHECKSUM -error_header_checksum_failed: - call error - db "Header checksum failed.", 0 - -error_data_checksum_failed: - stc - int3 - jnc ..@data_checksum_ignore_failure_debugger - call error - db "Data checksum failed.", 0 -%endif - - -freedos_or_msdos1_com_entry: - call @F -@@: - pop cx - cmp cx, @B - jne msdos1_com_entry - -freedos_entry: - ; This is the FreeDOS compatible entry point. - ; Supports FAT32 too. - ; cs:ip = 60h:0 - ; whole load file loaded - ; first cluster of load file: not given! - ; first data sector: not given! - ; int 1Eh not modified, original address: not given! - ; bl = load unit (not used by us) - ; ss:bp -> boot sector with (E)BPB, - ; load unit field set, hidden sectors set - ; (usually at 1FE0h:7C00h) - ; NEW: word [ss:bp - 14h] = "CL" to indicate command line - ; then ss:bp - 114h -> 256 byte ASCIZ string - - lea bx, [bp + lsvCommandLine.start] - ; ss:bx -> command line buffer, if any - cmp bp, - lsvCommandLine.start - ; enough data below bp to hold buffer ? - jb @F ; no --> - cmp sp, bx ; sp below-or-equal would-be buffer ? - jbe .canbevalid ; yes, can be valid --> (and word access valid) -@@: - cmp bp, - lsvCommandLine.signature - ; enough data below bp to hold our lsv ? - jae @F ; yes --> - test bp, 1 ; valid to access even-aligned words ? - jnz .error ; maybe not --> -@@: - and word [bp + lsvCommandLine.signature], 0 - ; invalidate signature -.canbevalid: - cmp word [bp + lsvCommandLine.signature], "CL" - ; valid signature ? - je @F ; yes, keep bx pointing at buffer - - lea bx, [bp + lsvCommandLine.signature] - ; no, ss:bx -> lsv with signature -@@: - cmp sp, bx ; sp below-or-equal needed stack frame ? - jbe @F ; yes --> - and bl, ~1 ; make even-aligned stack (rounding down) - mov sp, bx ; change sp -@@: - - -d3 call d3_display_two_characters -d3 test ax, "F0" - - xor cx, cx - mov word [bp + lsvFirstCluster + 0], cx - mov word [bp + lsvFirstCluster + 2], cx - -%if _LSVEXTRA - mov word [bp + lsvExtra], lsvefNoDataStart << 8 -%else - call calculate_data_start -%endif -.multiboot_entry: - mov ax, cs - add ax, (payload.actual_end -$$+0 +15) >> 4 - ; Multiboot1/2 and FreeDOS have whole image - xor cx, cx ; cx = 0 - jmp ms7_entry.continue2 - - -.error: - call error - asciz "Invalid base pointer in FreeDOS entrypoint." - - -%if _LSVEXTRA -handle_lsv_extra_flags: - test byte [bp + lsvExtra.flags], lsvefPartitionNumber - jz @F - call parse_partition_number -@@: - test byte [bp + lsvExtra.flags], lsvefNoDataStart - jz @F - call calculate_data_start -@@: - retn - - -parse_partition_number: - xor ax, ax - mov word [bp + bsBPB + bpbHiddenSectors], ax - mov word [bp + bsBPB + bpbHiddenSectors + 2], ax - cmp byte [bp + bsBPB + ebpbNew + bpbnBootUnit], -1 - jne @F - mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], 80h - mov word [bp + bsBPB + bpbCHSSectors], ax - mov word [bp + bsBPB + bpbCHSHeads], ax - call query_geometry -@@: - - %if !_LBA_SKIP_CHECK - test byte [bp + ldHasLBA], 1 - jnz @F - %endif - - mov ax, word [bp + bsBPB + bpbCHSSectors] - mov dx, word [bp + bsBPB + bpbCHSHeads] - - ; following is from lDebug 0c0930773929 boot.asm - overridedef DEBUG5, 0 -%define load_unit (bp + bsBPB + ebpbNew + bpbnBootUnit) -%define load_sectorsize (bp + bsBPB + bpbBytesPerSector) -%define load_sectorsizepara (bp + ldParaPerSector) - - test ax, ax - jz .invalid_sectors - cmp ax, 63 - ja .invalid_sectors - test dx, dx - jz .invalid_heads - cmp dx, 100h - ja .invalid_heads -@@: - - mov ax, word [bp + ldSectorSeg] ; ax => sector seg - dec ax ; ax => sector seg - 16 - mov es, ax - xor ax, ax - mov bx, 16 - -d5 call d5dumpregs -d5 call d5message -d5 asciz 13,10,"In query_geometry 0",13,10 - - mov di, bx - mov cx, (8192 + 2) >> 1 - ; es:bx -> auxbuff, es:di = same - rep stosw ; fill buffer, di -> behind (auxbuff+8192+2) - mov ax, 0201h ; read sector, 1 sector - inc cx ; sector 1 (1-based!), cylinder 0 (0-based) - mov dh, 0 ; head 0 (0-based) - mov dl, [load_unit] - stc - call .int13_retry - jc .access_error - - std ; _AMD_ERRATUM_109_WORKAROUND does not apply - mov word [es:bx - 2], 5E5Eh ; may overwrite last 2 bytes at line_out_end - scasw ; -> auxbuff+8192 (at last word to sca) -d5 call d5dumpregs -d5 call d5message -d5 asciz 13,10,"In query_geometry 1",13,10 - mov cx, (8192 + 2) >> 1 - xor ax, ax - repe scasw - add di, 4 ; di -> first differing byte (from top) - cld - push di - - mov di, bx - mov cx, (8192 + 2) >> 1 - dec ax ; = FFFFh - rep stosw - - mov ax, 0201h - inc cx - mov dh, 0 - mov dl, [load_unit] - stc - call .int13_retry - jc .access_error - - std ; _AMD_ERRATUM_109_WORKAROUND does not apply - scasw ; di -> auxbuff+8192 (last word to sca) -d5 call d5dumpregs -d5 call d5message -d5 asciz 13,10,"In query_geometry 2",13,10 - pop dx - mov ax, -1 - mov cx, (8192 + 2) >> 1 - repe scasw -%if 0 -AAAB - ^ - sca B, match - ^ - sca B, mismatch - ^ - stop -%endif - add di, 4 ; di -> first differing byte (from top) - cld - -%if 0 -0000000000000 -AAAAAAAA00000 - ^ -FFFFFFFFFFFFF -AAAAAAAA00FFF - ^ -%endif - cmp dx, di ; choose the higher one - jae @F - mov dx, di -@@: - sub dx, bx ; dx = sector size - -d5 call d5dumpregs -d5 call d5message -d5 asciz 13,10,"In query_geometry 3",13,10 - - cmp dx, 8192 + 2 - jae .sector_too_large - mov ax, 32 - cmp dx, ax - jb .sector_too_small -@@: - cmp dx, ax - je .got_match - cmp ax, 8192 - jae .sector_not_power - shl ax, 1 - jmp @B - -.got_match: - mov word [load_sectorsize], ax - mov cl, 4 - shr ax, cl - mov word [load_sectorsizepara], ax - - resetdef - - - push cs - pop ds - push cs - pop es - - mov cx, .per_partition - call scan_partitions - - mov di, partition_offset - mov dx, word [di + 2] - mov ax, word [di] - - cmp ax, -1 - jne @F - cmp dx, -1 - jne @F - - push ss - pop es - mov di, bp - xor ax, ax - mov cx, 512 / 2 + (((ebpbNew - bpbNew + 15) & ~15) >> 1) - push word [bp + bsBPB + ebpbNew + bpbnBootUnit] - push word [bp + bsBPB + bpbCHSSectors] - push word [bp + bsBPB + bpbCHSHeads] - rep stosw - pop word [bp + bsBPB + bpbCHSHeads] - pop word [bp + bsBPB + bpbCHSSectors] - pop bx - mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl - mov word [bp + bsBPB + bpbHiddenSectors], dx - mov word [bp + bsBPB + bpbHiddenSectors + 2], dx - - jmp .invalid_return - - -@@: - push dx - push ax - mov bx, [bp + ldSectorSeg] - call read_ae_512_bytes - push es - pop ds - xor si, si - push ss - pop es - mov di, bp - mov cx, 512 / 2 - - pop ax - pop dx - - push word [bp + bsBPB + ebpbNew + bpbnBootUnit] - push word [bp + bsBPB + bpbCHSSectors] - push word [bp + bsBPB + bpbCHSHeads] - - - rep movsw - - push ax - xor ax, ax - mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1 - rep stosw ; initialise area behind sector (left so for FAT32) - pop ax - - - pop word [bp + bsBPB + bpbCHSHeads] - pop word [bp + bsBPB + bpbCHSSectors] - mov word [bp + bsBPB + bpbHiddenSectors], ax - mov word [bp + bsBPB + bpbHiddenSectors + 2], dx - - - push ss - pop ds - push ss - pop es - - mov bx, [bp + bsBPB + bpbSectorsPerFAT] - test bx, bx - jz .not_fat32 - - lea si, [bp + 510] ; -> last source word - lea di, [si + (ebpbNew - bpbNew)] ; -> last dest word - mov cx, (512 - bsBPB - bpbNew + 1) >> 1 - ; move sector up, except common BPB start part -%if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20 - %fatal Need AMD erratum 109 workaround -%endif - std ; AMD erratum 109 handling not needed - rep movsw - cld - - mov word [bp + lsvFirstCluster + 2], cx - mov word [bp + lsvFATSector + 2], cx - - mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx - mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx - mov word [bp + bsBPB + ebpbFSFlags], cx - ; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved: - ; uninitialised here (initialised by loaded_all later) -.not_fat32: - - pop bx - mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl - - mov ah, lsvefNoDataStart - mov al, byte [cs:partition_type] - cmp al, ptFAT12 - je @F - cmp al, ptFAT16_16BIT_CHS - je @F - cmp al, ptFAT16_CHS - je @F - cmp al, ptFAT32_CHS - je @F - cmp al, ptFAT32 - je @F - cmp al, ptFAT16 - je @F - -.invalid_return: - xor ax, ax - mov word [bp + lsvDataStart], ax - mov word [bp + lsvDataStart + 2], ax -@@: - mov byte [bp + lsvExtra.flags], ah - -%if _CHECKSUM - push cs - pop es - mov di, scanparttab_variables_start - mov cx, scanparttab_variables_length_w - xor ax, ax - rep stosw ; clear variables for eventual checksum - dec ax - mov di, partition_offset - stosw - stosw ; reset this variable too -%endif - - push ss - pop es - push ss - pop ds - retn - - -.per_partition: - push cx - push si - push di - push bx - - mov ax, [es:si + piStart] - mov dx, [es:si + piStart + 2] - add ax, [ss:bx + di - 8] - adc dx, [ss:bx + di - 8 + 2] ; = partition start - - mov cx, -1 - mov di, partition_offset - cmp word [di], cx ; first one encountered ? - jne @F - cmp word [di + 2], cx - jne @F ; no --> - mov cl, byte [es:si + piType] - mov byte [di - partition_offset + partition_type], cl - ; save type - mov word [di], ax - mov word [di + 2], dx ; yes, save offset -@@: - - mov cl, byte [load_current_partition] - ; which one ? - cmp cl, byte [bp + lsvExtra.partition] - jne @F ; not the sought one - - mov cl, byte [es:si + piType] - mov byte [di - partition_offset + partition_type], cl - ; save type - mov word [di], ax - mov word [di + 2], dx ; save offset - - pop bx ; bx = base - mov sp, bx ; reset sp - pop ax ; pop dummy bp - retn ; return to caller - -@@: ; not yet found, continue - pop bx - pop di - pop si - pop cx - retn - - -.int13_retry: - pushf - push ax - int 13h ; first try - jnc @F ; NC, success on first attempt --> - -; reset drive - xor ax, ax - int 13h - jc @F ; CY, reset failed, error in ah --> - -; try read again - pop ax ; restore function number - popf - int 13h ; retry, CF error status, ah error number - retn - -@@: ; NC or CY, stack has function number - inc sp - inc sp - inc sp - inc sp ; discard two words on stack, preserve CF - retn - - -.access_error: - jmp error_diskaccess - -.sector_too_large: -.sector_too_small: -.sector_not_power: - call error - asciz "Invalid sector size." - -.invalid_sectors: -.invalid_heads: - call error - asciz "Invalid geometry." - -scan_logical.got_partition_cycle: - call error - asciz "Partition cycle detected." - -scan_logical.error_too_many_partitions: - call error - asciz "Too many partitions detected." - -read_partition_table.signature_fail: - call error - asciz "Invalid partition table detected." - - - ; INP: dx:ax = first sector - ; bx:0 -> buffer - ; OUT: dx:ax = sector number after last read - ; es = input bx - ; bx:0 -> buffer after last written - ; CHG: - -read_ae_512_bytes: - push ds - push cx - push bx - push ss - pop ds - mov cx, 512 -.loop: - call read_sector - sub cx, word [bp + bsBPB + bpbBytesPerSector] - ja .loop - pop es - pop cx - pop ds - retn - - -%assign _PARTITION_TABLE_IN_CS 1 -%assign _BOOTCMD_FAIL_ERROR 0 -%define _SCANPTAB_PREFIX -%define _SCANPTAB_DEBUG4_PREFIX - overridedef DEBUG4, 0 -%include "scanptab.asm" - resetdef - - - align 16 -scanparttab_variables_start: -partition_table: - times 16 * 4 db 0 -.end: - -partition_offset: - dd -1 - -load_partition_cycle: - dw 0 -load_current_partition: - db 0 -partition_type: - db 0 - - align 2 -scanparttab_variables_length_w: equ ($ - scanparttab_variables_start) / 2 -%endif - - - ; INP: ss:bp -> BPB - ; ss:bp - LOADSTACKVARS -> lsv - ; OUT: lsvDataStart set - ; CHG: ax, bx, cx, dx, si, di -calculate_data_start: - xor cx, cx ; ! ch = 0 - - ; Although this currently is unused, we calculate the - ; first data sector (including root directory size) - ; here to complete the LOADSTACKVARS. - -; 32-byte FAT directory entries per sector - mov ax, [bp + bsBPB + bpbBytesPerSector] - mov cl, 5 ; ! ch = 0 - shr ax, cl - -; number of sectors used for root directory (store in CX) - ; After the prior shr instruction, ax is always < 8000h, - ; so this cwd instruction always zeros dx. - cwd - mov si, [bp + bsBPB + bpbNumRootDirEnts] ; (0 iff FAT32) - mov bx, ax - dec ax ; rounding up - js .error_badchain ; if >= 8000h (ie, 0FFFFh while bx = 0) - add ax, si ; from BPB - adc dx, dx ; account for overflow (dx was zero) - div bx ; get number of root sectors - xchg ax, cx ; cx = number of root secs, ! ah = 0 - - push cx ; number of root secs -; first sector of root directory - mov al, [bp + bsBPB + bpbNumFATs] - ; ! ah = 0, hence ax = number of FATs - mov cx, word [bp + bsBPB + bpbSectorsPerFAT] - xor di, di ; di:cx = sectors per FAT - ; iff FAT12, FAT16 - test cx, cx ; is FAT32 ? - jnz @F ; no --> - mov cx, word [bp + bsBPB + ebpbSectorsPerFATLarge] - mov di, word [bp + bsBPB + ebpbSectorsPerFATLarge + 2] ; for FAT32 -@@: - push ax - mul cx - ; ax = low word SpF*nF - ; dx = high word - xchg bx, ax - xchg cx, dx - ; cx:bx = first mul - pop ax - mul di - ; ax = high word adjust - ; dx = third word - test dx, dx - jnz .error_badchain - xchg dx, ax - ; dx = high word adjust - add dx, cx - ; dx:bx = result - xchg ax, bx - ; dx:ax = result - jc .error_badchain - - add ax, [bp + bsBPB + bpbReservedSectors] - adc dx, byte 0 - jc .error_badchain - - pop cx ; number of root sectors - xor di, di - -; first sector of disk data area: - add cx, ax - adc di, dx - mov [bp + lsvDataStart], cx - mov [bp + lsvDataStart + 2], di - - retn - -.error_badchain: - jmp error_badchain - - -end_of_handle_lsv_extra_flags: - - -%if _CHECKSUM -CHECKSUM_SIZE_P equ (payload.actual_end - $$ + 0) / 16 - - overridedef STANDALONE, 0 - %include "inicheck.asm" - resetdef - - align 16 -checksumheader: - istruc CHECKSUMHEADER -at cshSignature, dw "CS" -at cshLengthBytesStructure, dw CHECKSUMHEADER_size -at cshOffsetStructure, dw paras(checksumheader - $$ + 0) -at cshChecksumStructure, dw \ - 10000h-(("CS" + CHECKSUMHEADER_size \ - + paras(checksumheader - $$ + 0) \ - + 8106h + CHECKSUM_SIZE_P \ - + 0 + 0) & 0FFFFh) -at cshTypeChecksum -..@checksumtype: dw 8106h -at cshAmountParagraphsData, dw CHECKSUM_SIZE_P -at cshChecksumData -..@checksumfield: dw 0 -at cshReserved, dw 0 - iend -%endif - -%if _MULTIBOOT1 || _MULTIBOOT2 - %include "multboot.asm" -%endif - - -%if _DEBUG3 - ; INP: word [cs:ip + 1] = two characters to display - ; (second one may be NUL to skip) - ; OUT: - - ; CHG: - -d3_display_two_characters: - lframe near - lenter - push ax - push bx - mov bx, word [bp + ?frame_ip] - mov ax, [cs:bx + 1] - - push ax - call d3_disp_al - pop ax - - xchg al, ah - test al, al - jz @F - - call d3_disp_al -@@: - - pop bx - pop ax - lleave - lret - - ; INP: al = to display - ; CHG: ax, bx -d3_disp_al: - push bp - mov ah, 0Eh - mov bx, 7 - int 10h - pop bp - retn -%endif - - -msdos1_com_entry: - mov dx, .msg + 100h - mov ah, 09h - int 21h - int 20h - -.msg: - ascic "86-DOS version 1 not supported, aborting.",13,10 - - - align 16, db 38 -payload: - incbin _PAYLOAD_FILE - align 16, db 38 -.actual_end: -%if _IMAGE_EXE - align 512, db 38 ; until end of page - times 512 db 38 ; a full additional page, - ; this is for the bogus exeExtraBytes - ; Note that the pages start counting within the EXE header! - ; Thus alignment to the file-level page boundary is correct. -%endif -.end: - - -%if _SECOND_PAYLOAD_EXE - align 16, db 38 -second_payload: - incbin _SECOND_PAYLOAD_FILE - align 16, db 38 -.actual_end: - align 512, db 38 - times 512 db 38 -.end: -%endif - -%if ($ - start) < 4096 - _fill 4096, 38, start ; fill to new minimum limit -%endif - -%if _PADDING - %if ($ - $$) > _PADDING - %warning No padding needed - %else - times _PADDING - ($ - $$) db 0 - %endif -%endif diff --git a/test/ldosboot/kernshim.asm b/test/ldosboot/kernshim.asm deleted file mode 100644 index 60803cf5..00000000 --- a/test/ldosboot/kernshim.asm +++ /dev/null @@ -1,58 +0,0 @@ - -%if 0 - -FreeDOS kernel executable MZ header shim - by C. Masloch, 2022 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - -%include "lmacros2.mac" - - defaulting - - strdef FILE, "" -%ifidn _FILE,"" - %fatal Has to specify a file! -%endif - - - org 0 -header: - db "MZ" ; exeSignature - dw (payload.end - $$) % 512 ; exeExtraBytes - dw (payload.end - $$ + 511) / 512 ; exePages - dw 0 ; exeRelocItems - dw (payload -$$+0) >> 4 ; exeHeaderSize - dw 0 ; exeMinAlloc - dw -1 ; exeMaxAlloc - dw (payload.end + 15 - payload) / 16 ; exeInitSS - dw 512 ; exeInitSP - dw 0 ; exeChecksum - dw 0, 0 ; exeInitCSIP - dw 0 ; exeRelocTable - endarea header - - - align 16, db 0 -payload: - jmp strict short entry - db "CONFIG" - dw 1 - db -1 - - times 32 - ($ - payload) db 0 -entry: equ $ - jmp entry_common - - times 0xC0 - ($ - payload) nop -entry_common: equ $ - - incbin _FILE -.actual_end: -.end: diff --git a/test/ldosboot/multboot.asm b/test/ldosboot/multboot.asm deleted file mode 100644 index e0e41347..00000000 --- a/test/ldosboot/multboot.asm +++ /dev/null @@ -1,566 +0,0 @@ - -%if 0 - -Multiboot header and loader - 2008--2019 by C. Masloch - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - -%macro mbootchecksummed 1-2.nolist 1BADB002h - dd %2 ; signature - dd %1 ; flags - dd -((%2+%1) & 0FFFF_FFFFh) - ; checksum: dword sum of these three = 0 -%endmacro - -%macro mboot2checksummed 0-1.nolist 0E852_50D6h - dd %1 ; signature - dd 0 ; platform (i386) - dd mboot2_header_end - mboot2_header - ; size of header, including header tags - dd -((%1 + (mboot2_header_end - mboot2_header))) & 0FFFF_FFFFh - ; checksum -%endmacro - - -MULTIBOOT_CMDLINE_LENGTH equ lsvclBufferLength - -MULTIBOOT_BASE equ (1024+64)*1024 ; one paragraph above the HMA -MULTIBOOT_END equ MULTIBOOT_BASE + (payload.actual_end - $$ + 0) -MULTIBOOT_BSS_END equ MULTIBOOT_END \ - + fromdwords(dwords(MULTIBOOT_CMDLINE_LENGTH)) -MULTIBOOT_TARGET_SEGMENT equ 200h -MULTIBOOT_TARGET equ MULTIBOOT_TARGET_SEGMENT << 4 -MULTIBOOT_BPB equ MULTIBOOT_TARGET - 512 - 16 -MULTIBOOT_CMDLINE_START equ MULTIBOOT_BPB + lsvCommandLine.start -MULTIBOOT_STACK_TOP equ MULTIBOOT_CMDLINE_START - -%if _MULTIBOOT1 - ; Multiboot header - ; must be dword aligned and in first 8 KiB! - align 4, db 0 -mbootheader: - mbootchecksummed 00010000h - ; flags: provides info where to load image - dd MULTIBOOT_BASE + mbootheader ; load address of header - dd MULTIBOOT_BASE ; load address - dd MULTIBOOT_END ; load area end (0 = load whole file) - dd MULTIBOOT_BSS_END ; uninitialised area end (0 = none) - dd MULTIBOOT_BASE + mbootentry ; entry point -%endif - -%if _MULTIBOOT2 - ; Multiboot2 header - ; qword (64-bit) aligned and in first 32 KiB - align 8, db 0 -mboot2_header: - mboot2checksummed -mboot2_tag_information_request: -.: -.type: dw 1 -.flags: dw 0 -.size: dd .end - . - dd 1 ; command line - dd 5 ; ROM-BIOS boot device -.end: - align 8, db 0 -mboot2_tag_addresses: -.: -.type: dw 2 -.flags: dw 0 -.size: dd .end - . - dd MULTIBOOT_BASE + mboot2_header - ; load address of header - dd MULTIBOOT_BASE ; load address - dd MULTIBOOT_END ; load area end (0 = load whole file) - dd MULTIBOOT_BSS_END ; uninitialised area end (0 = none) -.end: - align 8, db 0 -mboot2_tag_entrypoint: -.: -.type: dw 3 -.flags: dw 0 -.size: dd .end - . - dd MULTIBOOT_BASE + mboot2entry ; entry point -.end: - align 8, db 0 -mboot2_tag_end: -.: -.type: dw 0 -.flags: dw 0 -.size: dd .end - . -.end: -mboot2_header_end: -%endif - - -%unmacro mbootchecksummed 1-2.nolist 1BADB002h -%unmacro mboot2checksummed 0-1.nolist 0E85250D6h - -%if ($-$$) > 8192 - %fatal Multiboot header must be in the first 8 KiB -%endif - - struc MBI -mbiFlags: resd 1 - resb 8 -mbiBootDevice: resd 1 -mbiCmdLine: resd 1 -mbiModuleCount: resd 1 -mbiModuleTable: resd 1 - ; (More data follows but none which seems useful.) - endstruc - -[cpu 386] -[bits 32] - - numdef MULTIBOOT_CHECKS, 1 - numdef MULTIBOOT_DEBUG, 0 - numdef MULTIBOOT_HALT, 0 - numdef MULTIBOOT_PROGRESS, 0 - - - %if _MULTIBOOT_CHECKS || _MULTIBOOT_HALT -mbootentry.halt: -mboot2entry.halt: - ; Unfortunately, as the environment is unknown, we can only - ; literally halt here, as we don't know how to do I/O. - cli -@@: - hlt - jmp short @B - %endif - -%if _MULTIBOOT1 - ; INP: eax = 2BADB002h - ; ebx-> multiboot info structure - ; STT: loaded and executed according to Multiboot header, ie - ; loaded at MULTIBOOT_BASE - ; eip = MULTIBOOT_BASE+mbootentry - ; in PM32 with paging disabled - ; CPL 0 - ; cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors - ; DI - ; ! stack not set up - ; ! GDT might not be set up - ; ! IDT might not be set up - ; A20 on - ; - ; Note: Although A20 is on, HMA access without an XMM - ; to manage it might be undesirable. Multiboot - ; also doesn't tell us whether and if so then - ; how we can switch A20. -mbootentry: - %if _MULTIBOOT_HALT - jmp .halt - %endif - %if _MULTIBOOT_CHECKS -[bits 16] - test ax, 0 ; (test eax if in 32-bit segment) - jmp short .halt ; (skipped if in 32-bit segment) -[bits 32] - cmp eax, 2BADB002h ; signature ? - jne short .halt ; no --> - smsw eax - rol eax, 1 ; 2 = protection, 1 = paging - and al, 3 ; mask off others - cmp al, 2 ; PE but not PG ? - jne short .halt ; no --> - mov eax, cs - and al, 3 ; CPL 0 ? - jnz short .halt ; no --> - %endif - - %if _MULTIBOOT_PROGRESS - mov ebp, 0B8000h + 2 * 80 * 20 - mov word [ebp], 5000h | '1' - inc ebp - inc ebp - %endif - - ; prepare this and that - or edx, -1 - ; locate boot drive in Multiboot info structure - test byte [ ebx + mbiFlags ], 2 ; boot device info valid ? - jz @F - mov eax, [ ebx + mbiBootDevice ]; get the info - rol eax, 16 - xchg al, ah - mov edx, eax ; dl = boot load unit (or 0FFh), - ; dh = partition (or 0FFh) - ; (edxh = subpartition numbers) -@@: - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | '2' - inc ebp - inc ebp - %endif - - xor eax, eax - mov edi, MULTIBOOT_END - mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4 - test byte [ ebx + mbiFlags ], 4 ; command line valid ? - jz @F - mov esi, [ ebx + mbiCmdLine ] - rep movsd - mov byte [ edi - 1 ], 0 ; insure it is terminated - ; (this may truncate the line) -@@: - rep stosd - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | '3' - inc ebp - inc ebp - %endif - - %if _MULTIBOOT2 - jmp multiboot_1_2_common - %endif -%endif - -%if _MULTIBOOT2 - ; INP: eax = 36D7_6289h - ; ebx-> multiboot2 info structure - ; STT: loaded and executed according to Multiboot2 header, ie - ; loaded at MULTIBOOT_BASE - ; eip = MULTIBOOT_BASE+mboot2entry - ; in PM32 with paging disabled - ; CPL 0 - ; cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors - ; DI - ; ! stack not set up - ; ! GDT might not be set up - ; ! IDT might not be set up - ; A20 on - ; - ; Note: Although A20 is on, HMA access without an XMM - ; to manage it might be undesirable. Multiboot - ; also doesn't tell us whether and if so then - ; how we can switch A20. -mboot2entry: - %if _MULTIBOOT_HALT - jmp .halt - %endif - %if _MULTIBOOT_CHECKS -[bits 16] - test ax, 0 ; (test eax if in 32-bit segment) - jmp short .halt ; (skipped if in 32-bit segment) -[bits 32] - cmp eax, 36D7_6289h ; signature ? - jne .halt ; no --> - smsw eax - rol eax, 1 ; 2 = protection, 1 = paging - and al, 3 ; mask off others - cmp al, 2 ; PE but not PG ? - jne .halt ; no --> - mov eax, cs - and al, 3 ; CPL 0 ? - jnz .halt ; no --> - %endif - - %if _MULTIBOOT_PROGRESS - mov ebp, 0B8000h + 2 * 80 * 20 - mov word [ebp], 5000h | 'A' - inc ebp - inc ebp - %endif - - or edx, -1 ; initialise boot partition info - - xor eax, eax - mov edi, MULTIBOOT_END - mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4 - rep stosd ; initialise command line buffer - - add ebx, 8 ; skip fixed header (size, reserved) -.tags_loop: - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'B' - inc ebp - inc ebp - %endif - - mov eax, dword [ebx] - test eax, eax ; end of tags ? - jz .tags_end ; yes --> - - cmp eax, 1 - je .cmdline - - cmp eax, 5 - je .partition - -.tags_next: - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'C' - inc ebp - inc ebp - %endif - - add ebx, dword [ebx + 4] - ; -> after end of tag - ; (at padding or next tag) - add ebx, 7 - and ebx, ~7 ; skip any padding - jmp .tags_loop - -.cmdline: - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'D' - inc ebp - inc ebp - %endif - - lea esi, [ebx + 8] - mov edi, MULTIBOOT_END - mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4 - rep movsd ; copy command line - mov byte [ edi - 1 ], 0 - ; insure it is terminated - ; (this may truncate the line) - jmp .tags_next - -.partition: - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'E' - inc ebp - inc ebp - %endif - - mov eax, dword [ebx + 8] - cmp eax, 100h - jae @F - mov dl, al ; get ROM-BIOS unit -@@: - - mov eax, dword [ebx + 12] - cmp eax, 100h - jae @F - mov dh, al ; get partition number (0 = first primary) -@@: - jmp .tags_next - -.tags_end: - xor eax, eax - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'F' - inc ebp - inc ebp - %endif - -%endif - -multiboot_1_2_common: - mov esp, MULTIBOOT_STACK_TOP ; set a valid stack, at 8 KiB - ; (also required by 86M entry later) - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 's' - inc ebp - inc ebp - %endif - - ; A20 is on. set up some things - xor ecx, ecx - mov edi, 1024*1024 - mov cl, 10h ; (ecx = 10h) - rep stosd ; clear this area so A20 tests succeed -; The above writes to 10_0000h..10_003Fh, leaving edi = 10_0040h - mov al, 0C0h ; (eax = C0h) - mov byte [ edi-40h+eax ], 0EAh - mov [ edi-40h+eax+1 ], eax ; write jump for CP/M entry hack here -; The above writes to 10_00C0h..10_00C4h - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 't' - inc ebp - inc ebp - %endif - - ; relocate image to a good location, 2000h - mov esi, MULTIBOOT_BASE ; -> iniload image - mov edi, MULTIBOOT_TARGET - mov ecx, (payload.actual_end - $$ + 0 + 3) / 4 - rep movsd - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'u' - inc ebp - inc ebp - %endif - -MULTIBOOT_ESI_AFTER equ MULTIBOOT_BASE + (payload.actual_end - $$ + 0 + 3) / 4 * 4 -%if MULTIBOOT_ESI_AFTER != MULTIBOOT_END - mov esi, MULTIBOOT_END -%endif - mov edi, MULTIBOOT_CMDLINE_START - mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4 - rep movsd - - %if _MULTIBOOT_PROGRESS - mov word [ebp], 5000h | 'v' - inc ebp - inc ebp - %endif - - ; now back to real mode - o32 lgdt [ MULTIBOOT_BASE+mbootgdtdesc ] - ; set our GDT - mov ax, 10h - mov ds, ax - mov es, ax - mov ss, ax - mov fs, ax - mov gs, ax ; set 64 KiB segment limits - o32 push byte 0 - o32 popf ; reset all flags - jmp 08h:.pm16 ; use 16-bit selector - -[bits 16] - ; now really switch to real mode - ; (already executing relocated code) -.pm16: - mov eax, cr0 - dec ax - mov cr0, eax ; clear PE bit - - jmp dword MULTIBOOT_TARGET_SEGMENT:.rm ; reload cs - - ; Set up registers and the environment for - ; the kernel entry point. It doesn't need initialised - ; segment registers but we'll initialise them in case - ; they still contain selector content. -.rm: - ; some sources indicate we should set the IDT - o32 lidt [cs:mbootidtdesc] ; set IDT to RM IVT - xor ax, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - ; (cs should be = 200h now, need no far jump) - ; cs = 200h, ip = mboot_86m_entry - ; ds = es = fs = gs = ss = 0 - ; sp = 2000h - 512 - 16 + lsvCommandLine.start - ; dl = boot unit (or -1) - ; dh = boot partition (0..3 = primary, 4+ = logical, or -1) - - mov bp, MULTIBOOT_BPB ; -> pseudo BPB - mov di, MULTIBOOT_BPB + lsvCommandLine.signature - mov ax, lsvclSignature - stosw ; store signature - mov cx, (- (lsvCommandLine.signature + 2) + 512 + 3) / 4 - xor eax, eax - rep stosd ; clear - ; lsvFirstCluster = 0 (same as for FreeDOS entrypoint) - ; bsBPB + bpbHiddenSectors = 0 (invalid or unpartitioned) - ; bsBPB + bpbCHSSectors = 0 - ; bsBPB + bpbCHSHeads = 0 - - inc ax - mov dword [bp + lsvDataStart], eax - ; lsvDataStart = 1 (placeholder) -__CPU__ - mov word [bp + bsBPB + bpbNumRootDirEnts], ax - mov word [bp + bsBPB + bpbSectorsPerFAT], ax - ; do not detect as FAT32 - mov byte [bp + bsBPB + bpbSectorsPerCluster], al - mov word [bp + bsBPB + bpbBytesPerSector], 512 - mov word [bp + bsBPB + bpbTotalSectors], 8192 - ; 1 C/s * 8 Ki sectors = 8 Ki clusters, detect as FAT16 - ; that is, do not load FAT at all (would load a FAT12) - - mov byte [bp + bsBPB + bpbNew + bpbnBootUnit], dl - ; set boot load unit - -%if _LSVEXTRA - %if _MULTIBOOT_DEBUG - mov ax, dx - call mb_disp_ax_hex - %endif - xchg dl, dh ; dl = Multiboot spec partition number - ; (0..3 primary, 4+ logical, -1 invalid) - inc dx ; 0 invalid, 1..4 primary, 5+ logical - mov dh, lsvefPartitionNumber - mov word [bp + lsvExtra], dx -%endif - jmp freedos_entry.multiboot_entry - - -%if _MULTIBOOT_DEBUG -mb_disp_ax_hex: ; ax - xchg al,ah - call mb_disp_al_hex ; display former ah - xchg al,ah ; and fall trough for al -mb_disp_al_hex: ; al - push cx - mov cl,4 - ror al,cl - call mb_disp_al_lownibble_hex ; display former high-nibble - rol al,cl - pop cx - ; and fall trough for low-nibble -mb_disp_al_lownibble_hex: - push ax ; save ax for call return - and al,00001111b ; high nibble must be zero - add al,'0' ; if number is 0-9, now it's the correct character - cmp al,'9' - jna .decimalnum ; if we get decimal number with this, ok --> - add al,7 ; otherwise, add 7 and we are inside our alphabet - .decimalnum: - call mb_disp_al - pop ax - retn - -mb_disp_al: - push ax - push bx - push bp - mov ah, 0Eh - mov bx, 7 - int 10h - pop bp - pop bx - pop ax - retn -%endif - - - align 16, db 0 -mbootgdt: - dw 0,0 - db 0,0,0,0 - - ; selector 8: 16-bit real mode CS - ; base = 00002000h, limit 0FFFFh (1 B Granularity), present - ; type = 16-bit code execute/read only/conforming, DPL = 0 - dw 0FFFFh,MULTIBOOT_TARGET - db 0,9Eh,0,0 - - ; selector 10h: 16-bit real mode DS - ; base = 00000000h, limit 0FFFFh (1 B Granularity), present - ; type = 16-bit data read/write, DPL = 0 - dw 0FFFFh,0 - db 0,92h,0,0 - endarea mbootgdt - -mbootgdtdesc: - dw mbootgdt_size-1 ; limit - dd MULTIBOOT_BASE+mbootgdt ; address - -mbootidtdesc: - dw 400h-1 ; limit - dd 0 ; address (86M IVT) diff --git a/test/ldosboot/patch.sld b/test/ldosboot/patch.sld deleted file mode 100644 index 09796c87..00000000 --- a/test/ldosboot/patch.sld +++ /dev/null @@ -1,210 +0,0 @@ -@goto :help - -Patch iniload script - by C. Masloch, 2021 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - - -@:help -; Available patches: -; -; :patch_iniload_no_query_geometry (new or old style) -; :patch_iniload_no_lba (new or old style) -; :patch_iniload_no_query_geometry_old (old style) -; :patch_iniload_no_lba_old (old style) -; :patch_iniload_no_chs (new style only) -; :patch_iniload_detect_lba (new style only) -; :patch_iniload_detect_geometry (new style only) -; -; Inputs: vef = nonzero to debug -; cs:ve7 -> iniload -; Output: vee = nonzero if error -; iniload patched if successful -; Change: ve0 to vef, src, sro, aao, stack -; -; :query_patch_iniload (new style) -; -; Input: ve8 = what to set for new style query patch -; 0 = default, -1 = none (do old style patch) -; ve9 = what to clear for new style query patch -; Requires lDebug release 3 or later -@goto :eof - - -:query_patch_iniload -@if not (vef) then r ysf |= C000 -@:query_patch_common -r ve0 word (sp - 100) -a ss:ve0 - mov dl, byte [bp + 40] - mov ax, 0 - . -r ve1 := aao - 2 -r vec := ve1 - ve0 -s cs:ve7 l #1536 range ss:ve0 l vec -if (src == 0 && vee == -1) then goto :eof -if not (src) then goto :query_patch_error -a ss:ve0 - test dl, dl - jns (ve0 + 6) - db 86,C4 ; xchg al, ah - . -if (word [srs:sro + vec + 2] != word [ss:ve0 + 0]) then goto :query_patch_error -if (word [srs:sro + vec + 4] != word [ss:ve0 + 2]) then goto :query_patch_error -if (word [srs:sro + vec + 6] != word [ss:ve0 + 4]) then goto :query_patch_error -if not (ve8 or ve9) then goto :query_patch_found -r word [srs:sro + vec] or:= ve8 -r word [srs:sro + vec] and:= ~ve9 -:query_patch_success -r ve8 := 0 -r ve9 := 0 -r vee := 0 -r ysf &= ~C000 -; Patched successfully (new style) -@goto :eof - -:query_patch_found -r ve8 := 0 -r ve9 := 0 -r vee := 0 -r ysf &= ~C000 -; Patch site found, no patch requested (new style) -@goto :eof - -:query_patch_error -r ve8 := 0 -r ve9 := 0 -r vee := 1 -r ysf &= ~C000 -; Patch failed (new style) -@goto :eof - - -:patch_iniload_no_query_geometry -@if not (vef) then r ysf |= C000 -r vee := -1 -r ve8 := 404 -r ve9 := 0 -y :query_patch_common -@if not (vee == -1) then goto :eof - -:patch_iniload_no_query_geometry_old -@if not (vef) then r ysf |= C000 -r ve0 word (sp - 100) -a ss:ve0 - mov ah, 08 - xor cx, cx - stc - int 13 - jc (ve0) - . -r ve1 := aao - 1 -r vec := ve1 - ve0 -s cs:ve7 l #1536 range ss:ve0 l vec -if not (src) then goto :error -r word [srs:sro + vec - 3] := 9090 -goto :success - - -:patch_iniload_no_lba -@if not (vef) then r ysf |= C000 -r vee := -1 -r ve8 := 101 -r ve9 := 0 -y :query_patch_common -@if not (vee == -1) then goto :eof - -:patch_iniload_no_lba_old -@if not (vef) then r ysf |= C000 -r ve0 word (sp - 100) -a ss:ve0 - mov ah, 41 - mov dl, byte [bp + 40] - mov bx, 55AA - stc - int 13 - mov al, 0 - jc (ve0) - . -r ve1 := aao - 1 -r vec := ve1 - ve0 -s cs:ve7 l #1536 range ss:ve0 l vec -if (src) then goto :patch_iniload_no_lba.success -a ss:ve0 - mov ah, 41 - pop dx - mov bx, 55AA - stc - int 13 - mov al, 0 - jc (ve0) - . -r ve1 := aao - 1 -r vec := ve1 - ve0 -s cs:ve7 l #1536 range ss:ve0 l vec -if (src) then goto :patch_iniload_no_lba.success -a ss:ve0 - mov ah, 41 - mov bx, 55AA - stc - int 13 - mov al, 0 - jc (ve0) - . -r ve1 := aao - 1 -r vec := ve1 - ve0 -s cs:ve7 l #1536 range ss:ve0 l vec -if not (src) then goto :error - -:patch_iniload_no_lba.success -r word [srs:sro + vec - 5] := 9090 -goto :success - -:success -r ve8 := 0 -r ve9 := 0 -r vee := 0 -r ysf &= ~C000 -; Patched successfully -@goto :eof - - -:patch_iniload_no_chs -@if not (vef) then r ysf |= C000 -r vee := -1 -r ve9 := 0 -r ve8 := 202 -y :query_patch_common -@if not (vee == -1) then goto :eof -goto :error - -:patch_iniload_detect_lba -@if not (vef) then r ysf |= C000 -r vee := -1 -r ve8 := 0 -r ve9 := 303 -y :query_patch_common -@if not (vee == -1) then goto :eof -goto :error - -:patch_iniload_detect_geometry -@if not (vef) then r ysf |= C000 -r vee := -1 -r ve8 := 0 -r ve9 := 404 -y :query_patch_common -@if not (vee == -1) then goto :eof -goto :error - -:error -r ve8 := 0 -r ve9 := 0 -r vee := 1 -r ysf &= ~C000 -; Patch failed -@goto :eof diff --git a/test/ldosboot/test/cfg.sh b/test/ldosboot/test/cfg.sh deleted file mode 100644 index d8979f21..00000000 --- a/test/ldosboot/test/cfg.sh +++ /dev/null @@ -1,39 +0,0 @@ -#! /bin/bash - -# Usage of the works is permitted provided that this -# instrument is retained with the works, so that any entity -# that uses the works is notified of this instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -# If you want to override configuration without the -# hassle of having to exclude differences in this file -# (cfg.sh) from the SCM, you may provide ovr.sh. -# The meaning of this line allows you to copy cfg.sh -# to serve as a template for ovr.sh without changes. -[ -f ovr.sh ] && [[ "${BASH_SOURCE[0]##*/}" != ovr.sh ]] && . ovr.sh - -# As the below only are set if no value is provided -# yet, any value can be overridden from the shell. -[ -z "$LMACROS_DIR" ] && LMACROS_DIR=../../lmacros/ -[ -z "$LDOSBOOT_DIR" ] && LDOSBOOT_DIR=../ -[ -z "$SCANPTAB_DIR" ] && SCANPTAB_DIR=../../scanptab/ -[ -z "$INICHECK_DIR" ] && INICHECK_DIR=../../crc16-t/ -[ -z "$BOOTIMG_DIR" ] && BOOTIMG_DIR=../../bootimg/ -[ -z "$LDEBUG_DIR" ] && LDEBUG_DIR=../../ldebug/bin/ -[ -z "$LDOSMBR_DIR" ] && LDOSMBR_DIR=../../ldosmbr/ -[ -z "$INSTSECT_DIR" ] && INSTSECT_DIR=../../instsect/ - -[ -z "$DOSEMU" ] && DOSEMU=dosemu -[ -z "$QEMU" ] && QEMU=qemu-system-i386 -[ -z "$DEFAULT_MACHINE" ] && DEFAULT_MACHINE=dosemu -[ -z "$SENDKEYS" ] && SENDKEYS=sendkeys -[ -z "$BOOT_KERNEL" ] && BOOT_KERNEL=~/.dosemu/drive_c/kernel.sys -[ -z "$BOOT_COMMAND" ] && BOOT_COMMAND=~/.dosemu/drive_c/command.com -[ -z "$BOOT_PROTOCOL" ] && BOOT_PROTOCOL=FREEDOS -[ -z "$BOOT_OPTIONS" ] && BOOT_OPTIONS=" " -[ -z "$MKTMPINC" ] && MKTMPINC=mktmpinc.pl -[ -z "$NASM" ] && NASM=nasm -[ -z "$CHECKSUM" ] && CHECKSUM="${INICHECK_DIR%/}"/iniload/checksum - -[ -z "$use_build_inicheck" ] && use_build_inicheck=0 diff --git a/test/ldosboot/test/quit.asm b/test/ldosboot/test/quit.asm deleted file mode 100644 index b12b156a..00000000 --- a/test/ldosboot/test/quit.asm +++ /dev/null @@ -1,60 +0,0 @@ - -%if 0 - -Shut down machine - by C. Masloch, 2020 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - - cpu 8086 - org 256 -quit: - int3 - - mov ax, 0F000h - mov es, ax - mov di, 0FFF5h - mov si, msg.dosemudate - mov cx, 4 - repe cmpsw ; running in DosEmu? - jne .quit_not_dosemu - - xor bx, bx - mov ax, -1 - int 0E6h ; dosemu quit - -.quit_not_dosemu: - -; from https://stackoverflow.com/a/5240330/738287 - mov ax, 5301h - xor bx, bx - int 15h ; connect to APM API - - mov ax, 530Eh - xor bx, bx - mov cx, 0102h - int 15h ; set APM version to 1.02 - - mov ax, 5307h - mov bx, 1 - mov cx, 3 - int 15h ; shut down system - - mov dx, msg.failed - mov ah, 09h - int 21h - mov ax, 4C00h - int 21h - - - align 4 -msg: -.dosemudate: db "02/25/93" -.failed: db "Quit failed.",13,10,36 diff --git a/test/ldosboot/test/run.sh b/test/ldosboot/test/run.sh deleted file mode 100755 index d958e631..00000000 --- a/test/ldosboot/test/run.sh +++ /dev/null @@ -1,20 +0,0 @@ -#! /bin/bash - -# Usage of the works is permitted provided that this -# instrument is retained with the works, so that any entity -# that uses the works is notified of this instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -testrunname="fat12 default: " \ - ./test.sh diskette -testrunname="fat12 direct: " \ - ./test.sh diskette direct -testrunname="fat12 hdimage: " \ - ./test.sh hdimage -testrunname="fat12 16spc 20MiB: " \ - ./test.sh hdimage aligndata bpe 12 spc 16 mib 20 nr 512 -testrunname="fat16 4spc 32MiB: " \ - ./test.sh hdimage aligndata bpe 16 spc 4 mib 32 nr 512 -testrunname="fat32 1spc 34MiB: " \ - ./test.sh hdimage aligndata bpe 32 spc 1 mib 34 diff --git a/test/ldosboot/test/test.sh b/test/ldosboot/test/test.sh deleted file mode 100755 index 6d225b37..00000000 --- a/test/ldosboot/test/test.sh +++ /dev/null @@ -1,524 +0,0 @@ -#! /bin/bash - -# Usage of the works is permitted provided that this -# instrument is retained with the works, so that any entity -# that uses the works is notified of this instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -if [[ "$1" != selfcall ]] -then - setsid -w "$0" selfcall "$@" - exit $? -fi -shift - -. cfg.sh - -if [ -n "$LMACROS_DIR" ]; then { - options_i_lmacros=-I"${LMACROS_DIR%/}"/ -} fi - -if [ -n "$LDOSBOOT_DIR" ]; then { - options_i_ldosboot=-I"${LDOSBOOT_DIR%/}"/ -} fi - -if [ -n "$SCANPTAB_DIR" ]; then { - options_i_scanptab=-I"${SCANPTAB_DIR%/}"/ -} fi - -if [ -n "$BOOTIMG_DIR" ]; then { - options_i_bootimg=-I"${BOOTIMG_DIR%/}"/ -} fi - -if [ -n "$LDEBUG_DIR" ]; then { - options_i_ldebug=-I"${LDEBUG_DIR%/}"/ -} fi - -if [ -n "$LDOSMBR_DIR" ]; then { - options_i_ldosmbr=-I"${LDOSMBR_DIR%/}"/ -} fi - -if [ -n "$INSTSECT_DIR" ]; then { - options_i_instsect=-I"${INSTSECT_DIR%/}"/ -} fi - -direct=0 -options_dosemu_direct="-A" -bpe=12 -spc=1 -spi=2880 -nr=224 -pitype="" -chsheads=8 -chssectors=8 - -((debug)) && echo DEFAULT_MACHINE="$DEFAULT_MACHINE" parameters="$@" -machine="$DEFAULT_MACHINE" -if [[ "$1" == dosemu ]] -then - machine="$1" - shift -elif [[ "$1" == qemu ]] -then - machine="$1" - shift -fi - -driveletters=( {C..Z} ) -unitletters=( {a..z} ) -dosemu=0 -qemu=0 -if [[ "$machine" == dosemu ]] -then - dosemu=1 - if [ -z "$dosemu_drives" ] || [ "$dosemu_drives" == test ] - then - # Depending on the dosemu2 configuration, dosemu may - # set up 2, 3, or 4 system drives. To support all - # these cases, the variable dosemu_drives may now - # be set to indicate the amount of drives. - # If it is not set or set to "test" we do a bit of - # magic detection: Run dosemu -E lredir and count - # the amount of redirections displayed. Also check - # that all of the redirections are on the expected - # drives, starting with C:. - # We assume that each of the system drives corresponds - # to its own ROM-BIOS unit. - # Discussed here: https://github.com/dosemu2/dosemu2/discussions/1456 - driveslist="$("$DOSEMU" -dumb -quiet -E lredir -te 2> /dev/null < /dev/null | - sed -re '/^about to execute|^current drive redirections/Id' )" - dosemu_drives="$(echo "$driveslist" | wc -l)" - for checkdrivenumber in $(seq 0 "$((dosemu_drives - 1))") - do - driveletter="${driveletters[checkdrivenumber]}" - if ! echo "$driveslist" | grep -Eiq "^$driveletter:" - then - echo "Error: Drive $driveletter: not found in lredir list" >&2 - exit 1 - fi - done - fi - ((debug)) && echo "Drive ${driveletters[dosemu_drives]}:" -elif [[ "$machine" == qemu ]] -then - qemu=1 - dosemu_drives=0 -else - echo "Error: invalid machine \"$machine\" selected" >&2 - exit 1 -fi - -if [[ "$1" == hdimage ]] -then - shift - options_hdimage="-D_MBR" - if ((dosemu)) - then - options_hdimage="$options_hdimage -D_MBR_DOSEMU_IMAGE_HEADER" - fi - dosemu_category="disk" - dosemu_device="hdimage" - dosemu_drive="${driveletters[dosemu_drives]}:" - qemu_switch="-hda" - name="hdimage" - bootfile="" - unit="$(printf "%03Xh" "$((0x80 + $dosemu_drives))")" - options_ldebug_unit="hd${unitletters[dosemu_drives]}" - diskette=0 - if [[ "$1" == direct ]] - then - shift - # output of the following command is either: - # 1. "CPU set to 486", followed by the sign ons for dosemu, FreeDOS, - # and config.sys and autoexec.bat output, then executing "exitemu" - # (if -C4 switch is not supported, parsed as -C -4). - # 2. Only the dosemu sign on with the error message as follows: - # "ERROR: Drive G not defined, can't boot!" (execution aborted). - if ((dosemu)) && "$DOSEMU" -dumb -E exitemu -C4 < /dev/null 2>&1 | grep "CPU set to 486" > /dev/null - then - echo "Error: dosemu lacks support for -C4 switch" >&2 - exit 1 - fi - options_dosemu_direct="-C$dosemu_drives" - unit=80h - direct=1 - fi - if ((qemu)) - then - unit=80h - options_ldebug_unit="hda" - fi - ((debug)) && echo "unit=\"$unit\"" - while true - do - if [[ "$1" == bpe && -n "$2" ]] - then - ((bpe="$2")) - if (($?)) || [[ "$bpe" != 32 && "$bpe" != 16 && "$bpe" != 12 ]] - then - echo "Error: Invalid bpe \"$2\" given, expected 12, 16, 32" >&2 - exit 1 - fi - shift - shift - elif [[ "$1" == spc && -n "$2" ]] - then - ((spc="($2)")) - (($?)) && exit $? - shift - shift - elif [[ "$1" == mib && -n "$2" ]] - then - ((spi="(($2) * 1024 * 2)")) - (($?)) && exit $? - shift - shift - elif [[ "$1" == spi && -n "$2" ]] - then - ((spi="($2)")) - (($?)) && exit $? - shift - shift - elif [[ "$1" == nr && -n "$2" ]] - then - ((nr="($2)")) - (($?)) && exit $? - shift - shift - elif [[ "$1" == pitype && -n "$2" ]] - then - pitype="$2" - shift - shift - elif [[ "$1" == aligndata ]] - then - options_hdimage="$options_hdimage -D_ALIGNDATA" - shift - elif [[ "$1" == chsheads && -n "$2" ]] - then - ((chsheads="($2)")) - (($?)) && exit $? - shift - shift - elif [[ "$1" == chssectors && -n "$2" ]] - then - ((chssectors="($2)")) - (($?)) && exit $? - shift - shift - else - break - fi - done - if ((qemu && chsheads > 16)) - then - echo "Warning: qemu autodetection requires CHS heads <= 16" >&2 - fi - if ((dosemu)) - then - options_mcopy_offset="@@$((16 + chsheads * chssectors))s" - else - options_mcopy_offset="@@$((chsheads * chssectors))s" - fi - options_hdimage="$options_hdimage -D_CHS_HEADS=$chsheads -D_CHS_SECTORS=$chssectors" -elif [[ "$1" == diskette ]] -then - shift - options_hdimage="" - dosemu_category="floppy" - dosemu_device="device" - dosemu_drive="A:" - qemu_switch="-fdb" - name="diskette" - bootfile="boot${bpe}tw.bin" - unit=01h - options_ldebug_unit="fdb" - options_mcopy_offset="" - diskette=1 - if [[ "$1" == direct ]] - then - shift - qemu_switch="-fda" - unit=00h - direct=1 - fi -else - echo "Error: Invalid disk type \"$1\" specified , must be hdimage or diskette" >&2 - exit 1 -fi - -if [[ "$bpe" == 32 ]] -then - if [[ -z "$pitype" ]] - then - pitype=ptFAT32 - fi - bootname=boot32 -else - if [[ -z "$pitype" ]] - then - if [[ "$bpe" == 16 ]] - then - pitype=ptFAT16 - else - pitype=ptFAT12 - fi - fi - bootname=boot -fi - -echo -ne 'failure\r\n' > result.txt - -TMPINC="" -if command -v "$MKTMPINC" &> /dev/null -then - TMPINC="-D_TMPINC" -fi -if [[ -n "$TMPINC" ]] -then - "$MKTMPINC" "${LDOSBOOT_DIR%/}"/$bootname.asm > /dev/null -fi - "$NASM" "${LDOSBOOT_DIR%/}"/$bootname.asm -w-user \ - $TMPINC \ - -D_LOAD_NAME="'TESTWRIT'" -D_LOAD_EXT="'SYS'" -D_FAT$bpe \ - -D_UNIT=$unit \ - "$@" \ - "$options_i_lmacros" \ - -D_MAP=boot${bpe}tw.map -l boot${bpe}tw.lst -o boot${bpe}tw.bin && - "$NASM" "${LDOSBOOT_DIR%/}"/testwrit.asm \ - "$options_i_lmacros" \ - -o testwrit.bin -l testwrit.lst && - "$NASM" "${LDOSBOOT_DIR%/}"/iniload.asm -w-user \ - "$options_i_ldosboot" \ - "$options_i_lmacros" \ - "$options_i_scanptab" \ - -D_PADDING='(48 * 1024)' \ - -D_PAYLOAD_FILE="'testwrit.bin'" -o testwrit.sys -l testwrin.lst \ - -D_INILOAD_SIGNATURE='"TW"' && - "$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \ - -D_WARN_DEFAULT_OFF=1 \ - -D_WARN_TOOMANYFAT=0 -D_WARN_ALIGNDATA=0 \ - $options_hdimage -D_MBR_PART_TYPE="$pitype" \ - -D_BPE="$bpe" -D_SPC="$spc" -D_SPI="$spi" \ - -D_SPF="$(( (spi / spc * bpe / 8 + 511) / 512 ))" \ - -D_NUMROOT="$nr" \ - -D_MAP=$name.map -o $name.img -l $name.lst \ - -D_PAYLOADFILE="testwrit.sys,result.txt,::chdir,dir" \ - -D_BOOTFILE="'$bootfile'" \ - -D_UNIT=$unit \ - "$@" \ - -I ./ \ - "$options_i_lmacros" \ - "$options_i_bootimg" -(($?)) && exit $? -if [[ -n "$TMPINC" ]] -then - rm -f *.tmp -fi - -pgid="$(ps -o pgid= $$)" -function handle_timeout_process() { - stty sane - ((debug)) && ps -e -o pgid=,comm=,pid= | grep -E "^\s*$pgid " - pidlist="$(ps -e -o pgid=,comm=,pid= | - grep -E "^\s*$pgid " | - grep -Ev " (bash|test.sh|ps|grep) ")" - pidlist="$(echo "$pidlist" | - sed -re 's/^\s+//g' | - tr -s " " | cut -d" " -f 3)" - if [[ -n "$pidlist" ]] - then - ((debug)) && ps $pidlist - kill $pidlist - fi -} - -if ((! diskette)) -then - if ((dosemu)) - then - seekmbr=8192 - else - seekmbr=0 - fi - "$NASM" "${LDOSMBR_DIR%/}"/oldmbr.asm -w-user \ - "$options_i_ldosmbr" \ - "$options_i_lmacros" \ - -o oldmbr.bin && - dd if=oldmbr.bin of=hdimage.img seek="$seekmbr" bs=1 count=440 conv=notrunc status=none - (($?)) && exit $? - - "$NASM" "${INSTSECT_DIR%/}"/instsect.asm \ - -w-macro-params-legacy \ - -I ./ \ - "$options_i_instsect" \ - "$options_i_lmacros" \ - -D_FAT12=0 -D_FAT16=0 -D_FAT32=0 -D_FAT$bpe=1 \ - -D_PAYLOAD_FAT$bpe="'boot${bpe}tw.bin'" \ - -o inst${bpe}tw.com -l inst${bpe}tw.lst -D_MAP=inst${bpe}tw.map - (($?)) && exit $? - if ((dosemu)) - then - timeout --foreground 10 "$DOSEMU" \ - -I "$dosemu_category { $dosemu_device $name.img }" \ - -dumb -quiet > result.log 2>&1 -K "$PWD" \ - -E "inst${bpe}tw.com $dosemu_drive" < /dev/null - rc=$? - handle_timeout_process - if ((rc)) - then - if ((rc == 124)) - then - echo "Error: instsect run timed out" >&2 - fi - cat result.log - exit 1 - fi - # && "$DOSEMU" -I "..." -dumb -K "$PWD" -E dirg.bat; - elif ((qemu)) - then - cp -aL "$BOOT_KERNEL" "${BOOT_KERNEL##*/}" - cp -aL "$BOOT_COMMAND" "${BOOT_COMMAND##*/}" - echo -ne "@echo off\r\ninst${bpe}tw.com C:\r\nquit.com\r\n" > autoexec.bat -if [[ -n "$TMPINC" ]] -then - "$MKTMPINC" "${LDOSBOOT_DIR%/}"/boot.asm > /dev/null -fi - "$NASM" quit.asm \ - "$options_i_lmacros" \ - -o quit.com && - "$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \ - "$options_i_lmacros" \ - $TMPINC \ - -D_COMPAT_"$BOOT_PROTOCOL"=1 \ - -D_LBA=0 -D_USE_PART_INFO=0 -D_QUERY_GEOMETRY=0 \ - $BOOT_OPTIONS \ - -D_MAP=bootinst.map -l bootinst.lst -o bootinst.bin && - "$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \ - -I ./ \ - "$options_i_ldebug" \ - "$options_i_bootimg" \ - "$options_i_lmacros" \ - -o diskinst.img -l diskinst.lst \ - -D_PAYLOADFILE="${BOOT_KERNEL##*/},${BOOT_COMMAND##*/},autoexec.bat,inst${bpe}tw.com,quit.com" \ - -D_BOOTFILE="'bootinst.bin'" - (($?)) && exit $? -if [[ -n "$TMPINC" ]] -then - rm -f *.tmp -fi - timeout --foreground 10 "$QEMU" -fda diskinst.img "$qemu_switch" "$name".img -boot order=a -display none 2> /dev/null - rc=$? - handle_timeout_process - if ((rc == 124)) - then - echo "Error: instsect run timed out" >&2 - exit 1 - fi - fi -fi - -if ((! direct)) -then -if [[ -n "$TMPINC" ]] -then - "$MKTMPINC" "${LDOSBOOT_DIR%/}"/boot.asm > /dev/null -fi - "$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \ - "$options_i_lmacros" \ - $TMPINC \ - -D_LOAD_NAME="'LDEBUG'" -D_LOAD_EXT="'COM'" \ - -D_MAP=boot12db.map -l boot12db.lst -o boot12db.bin && - "$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \ - -I ./ \ - "$options_i_ldebug" \ - "$options_i_bootimg" \ - "$options_i_lmacros" \ - -o diskldbg.img -l diskldbg.lst \ - -D_PAYLOADFILE="ldebug.com" -D_BOOTFILE="'boot12db.bin'" - (($?)) && exit $? -if [[ -n "$TMPINC" ]] -then - rm -f *.tmp -fi - - if ((dosemu)) - then - timeout --foreground 10 "$DOSEMU" -input \ - "$(echo -ne "boot $options_ldebug_unit"'\rif (rc) then boot quit\rq\r')" \ - -I "floppy { device diskldbg.img }" \ - -I "$dosemu_category { $dosemu_device $name.img }" \ - -A -dumb 2> result.err > result.log < /dev/null - elif ((qemu)) - then - ( (sleep 2; "$SENDKEYS" "boot $options_ldebug_unitif (rc) then boot quitq" | socat - UNIX-CONNECT:qemu-monitor > /dev/null ) & > /dev/null) - timeout --foreground 10 "$QEMU" -fda diskldbg.img "$qemu_switch" "$name".img -boot order=a -monitor unix:qemu-monitor,server,nowait -display none 2> /dev/null - fi -else - if ((dosemu)) - then - timeout --foreground 10 "$DOSEMU" \ - -I "$dosemu_category { $dosemu_device $name.img }" \ - "$options_dosemu_direct" -dumb 2> result.err > result.log < /dev/null - elif ((qemu)) - then - timeout --foreground 10 "$QEMU" "$qemu_switch" "$name".img -display none 2> /dev/null - fi -fi - -rc=$? -handle_timeout_process -if ((rc == 124)) -then - echo "${testrunname}timeout" -fi -if [[ "$(mtype -t -i $name.img$options_mcopy_offset ::RESULT.TXT 2> /dev/null)" == success ]] -then - echo "${testrunname}success" -elif ((dosemu)) -then - echo "${testrunname}failure, log contains:" - if [ ! -s result.log ] - then - echo "Result log file empty, dosemu error?" - fi - cat result.log | perl -e ' - my %errorlookup = ( - V => "Check value mismatch", - F => "File not found", - E => "Not enough file data", - R => "Disk read error", - B => "Bad chain / bad FS", - M => "Out of memory", - I => "FSIBOOT error", - S => "Fix sector size mismatch", - C => "Fix cluster size mismatch", - N => "Non-FAT load needs larger cluster size", - ); - my $empty = 1; - while (<>) { - next if $empty and /^\s*$/; - next if /^(dosemu2 2|Configured: |Please test against)/; - next if /^(Get the latest code|Submit Bugs via|Ask for help in)/; - next if /^(This program comes with|This is free software,)/; - $empty = 0; - if (/^([A-Z])\x7/ and defined $errorlookup{$1}) { - s/^(.).//; - print "lDOS boot error condition letter \"$1\" = $errorlookup{$1}\n"; - s/[\x7\n]//g; - s/^\s*$//; - next if /^(dosemu2 2|Configured: |Please test against)/; - next if /^(Get the latest code|Submit Bugs via|Ask for help in)/; - next if /^(This program comes with|This is free software,)/; - print; - print "\n" unless /^$/; - } else { - s/[\x7\n]//g; - print; - print "\n"; - }; - };' -else - echo "${testrunname}failure" -fi diff --git a/test/ldosboot/testpl.asm b/test/ldosboot/testpl.asm deleted file mode 100644 index b202b1bd..00000000 --- a/test/ldosboot/testpl.asm +++ /dev/null @@ -1,871 +0,0 @@ - -%if 0 - -Loader test payload - by C. Masloch, 2017 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - -%include "lmacros2.mac" - - numdef LARGE, 1 - numdef PADDING, 0 - - struc BS -bsJump: resb 3 -bsOEM: resb 8 -bsBPB: - endstruc - - struc EBPB ; BPB sec -bpbBytesPerSector: resw 1 ; offset 00h 0Bh -bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh -bpbReservedSectors: resw 1 ; offset 03h 0Eh -bpbNumFATs: resb 1 ; offset 05h 10h -bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32 -bpbTotalSectors: resw 1 ; offset 08h 13h -bpbMediaID: resb 1 ; offset 0Ah 15h -bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32 -bpbCHSSectors: resw 1 ; offset 0Dh 18h -bpbCHSHeads: resw 1 ; offset 0Fh 1Ah -bpbHiddenSectors: resd 1 ; offset 11h 1Ch -bpbTotalSectorsLarge: resd 1 ; offset 15h 20h -bpbNew: ; offset 19h 24h - -ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h -ebpbFSFlags: resw 1 ; offset 1Dh 28h -ebpbFSVersion: resw 1 ; offset 1Fh 2Ah -ebpbRootCluster: resd 1 ; offset 21h 2Ch -ebpbFSINFOSector: resw 1 ; offset 25h 30h -ebpbBackupSector: resw 1 ; offset 27h 32h -ebpbReserved: resb 12 ; offset 29h 34h -ebpbNew: ; offset 35h 40h - endstruc - - struc BPBN ; ofs B16 S16 B32 S32 -bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h - resb 1 ; 01h 1Ah 25h 36h 41h -bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN -bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h -bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h -bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h - endstruc ; 1Ah 33h 3Eh 4Fh 5Ah - - struc LOADSTACKVARS, -10h -lsvFirstCluster: resd 1 -lsvFATSector: resd 1 -lsvFATSeg: resw 1 -lsvLoadSeg: resw 1 -lsvDataStart: resd 1 - endstruc - -lsvclSignature equ "CL" -lsvclBufferLength equ 256 - - struc LOADDATA, LOADSTACKVARS - 10h -ldMemoryTop: resw 1 -ldLoadTop: resw 1 -ldSectorSeg: resw 1 -ldFATType: resb 1 -ldHasLBA: resb 1 -ldClusterSize: resw 1 -ldParaPerSector:resw 1 -ldLoadingSeg: ; word -lsvCommandLine: ; word -.start: equ $ - lsvclBufferLength -.signature: resw 1 -ldLoadUntilSeg: ; word -lsvExtra: ; word -.partition: resb 1 ; byte -.flags: resb 1 ; byte - endstruc - -lsvefNoDataStart equ 1 -lsvefPartitionNumber equ 2 - - struc LOADCMDLINE, LOADDATA - lsvclBufferLength -ldCommandLine: -.start: resb lsvclBufferLength - endstruc - - -%ifndef _MAP -%elifempty _MAP -%else ; defined non-empty, str or non-str - [map all _MAP] -%endif - - cpu 8086 - org 0 -payload: - ; The device header is of a fixed format. - ; For our purposes, the 4-byte code for - ; each the strategy entry and the - ; interrupt entry is part of this format. - ; (DOS may read the attributes or entrypoint - ; offsets before calling either, so the - ; inicomp stage needs to recreate in its - ; entrypoints part exactly what we have here.) -device_header: -.next: - fill 2, -1, jmp strict short j_zero_entrypoint - dw -1 -.attributes: - dw 8000h ; character device -.strategy: - dw .strategy_entry ; -> strategy entry -.interrupt: - dw .interrupt_entry ; -> interrupt entry -.name: - fill 8, 32, db "TESTPL$$" ; character device name -.strategy_entry: - fill 4, 90h, jmp device_entrypoint -.interrupt_entry: - fill 4, 90h, retf - - -j_zero_entrypoint: - jmp zero_entrypoint - - - nop - align 32, nop -kernel_entrypoint: - ; cs:ip = load seg : 32 here -%if ($ - $$) != 32 - %error Wrong kernel mode entrypoint -%endif - - ; S0 +28 - pushf ; +26 - push ax ; +24 - push cs ; +22 - call .push_ip -.push_ip: - pop ax - sub ax, .push_ip - kernel_entrypoint - push ax ; +20 IP - -common_entrypoint: - push es ; +18 ES - push bx ; +16 BX - cmp word [cs:signature], 2638h - je sig1_valid - jmp sig_invalid - - align 64, nop -dos_exe_entrypoint: - ; cs:ip = PSP : 256 + 64 here - ; - ; Code must be position independent enough. -%if ($ - $$) != 64 - %error Wrong EXE mode entrypoint -%endif - - ; S0 +28 - pushf ; +26 - push ax ; +24 - push cs ; +22 - call .push_ip -.push_ip: - pop ax - sub ax, .push_ip - dos_exe_entrypoint - push ax ; +20 IP - -dos_com_entrypoint: - mov byte [cs:100h + loadmode], 1 - mov ax, cs - add ax, 10h ; simulate kernel loading - push ax -jump_common_entrypoint: - mov ax, common_entrypoint - push ax - retf ; jump to cs + 10h : common_entrypoint - - -zero_entrypoint: - ; S0 +28 - pushf ; +26 - push ax ; +24 - push cs ; +22 - call .push_ip -.push_ip: - pop ax - sub ax, .push_ip - push ax ; +20 IP - - cmp word [cs:0], 20CDh - jne @F - cmp ax, 100h - je dos_com_entrypoint -@@: - - push cx - mov cl, 4 - shr ax, cl - mov cx, cs - add ax, cx - pop cx - push ax - jmp jump_common_entrypoint - - -device_entrypoint: - pushf - push ax - push cs - call .push_ip -.push_ip: - pop ax - sub ax, .push_ip - device_header.strategy_entry - push ax - mov byte [cs:loadmode], 2 - mov word [cs:dev_sp], sp - mov word [cs:dev_exit], dev_exit.1 - jmp common_entrypoint - - -sig_invalid: - call error - db "Signature invalid.", 0 - -sig1_valid: - push ds - push bx - mov bx, cs - add bx, (signature2 -$$+0) >> 4 - mov ds, bx - cmp word [(signature2 -$$+0) & 0Fh], 2638h - pop bx - pop ds - jne sig_invalid - jmp sig_valid - -msg: -.error: db "Test payload error: ", 0 -.test: db "Test payload loaded.", 13, 10, 0 - -.psp_and_size_before: asciz "PSP at " -.psp_and_size_between: asciz "h, size of memory block is " -.psp_and_size_after: asciz "h paragraphs.",13,10 -.cmdline.kern.none: asciz "No kernel command line given!",13,10 -.cmdline_before.kern: asciz "Kernel command line = ",'"' -.cmdline_before.app: asciz "Application command line = ",'"' -.cmdline_before.device: asciz "Device command line = ",'"' -.cmdline_after: asciz '"',13,10 - - align 4 -.foundname: - times 8+1+3+1 db 0 - ; buffer for base name (8) + dot (1) + ext (3) + NUL (1) - align 2 -.foundname_none: - asciz "(None)" -.foundname_none_size: equ $ - .foundname_none - align 2 -.names: - dw .name_first, 0 - dw .name_second, 0 - dw .name_third, 0 - dw .name_fourth, 0 - dw 0 -.name_first: asciz "1st name" -.name_second: asciz "2nd name" -.name_third: asciz "3rd name" -.name_fourth: asciz "4th name" -.name_before: asciz ": " -.name_quote: asciz '"' -.name_after: asciz 13,10 - - align 4 -dev_request_header: - dd 0 -loadmode: dw 0 ; 0 = loaded as boot payload, - ; 1 = loaded as DOS application, - ; 2 = loaded as DOS device driver -dev_sp: dw 0 -dev_exit: dw 0 -.1: - mov sp, word [cs:dev_sp] - jmp .common_1 - -.2: mov sp, word [cs:dev_sp] - jmp .common_2 - -.common_2: - pop ax ; ss - pop ds - pop ax ; sp - pop bp - pop di - pop si - pop dx - pop cx - -.common_1: - pop bx ; bx - pop es ; es - pop ax ; (IP) - pop ax ; (CS) - pop ax ; ax - mov word [es:bx + 3], 8103h - ; error, done, error code: unknown command - popf ; flags - retf ; far return to DOS - - -error: - push cs - pop ds - mov si, msg.error - call disp_msg - pop si - call disp_msg - test byte [cs:loadmode], 2 - jz .dos_or_bios - jmp near [cs:dev_exit] - -.dos_or_bios: - test byte [cs:loadmode], 1 - jz .bios - - mov ax, 4C01h - int 21h - -.bios: - xor ax, ax - int 16h - int 19h - -disp_msg_asciz: - push ds - push si - push ax - push cs - pop ds - mov si, dx - call disp_msg - pop ax - pop si - pop ds - retn - -disp_msg: -@@: - lodsb - test al, al - jz @F - call disp_al - jmp short @B - -disp_al: - push ax - push bx - push dx - push bp - test byte [cs:loadmode], 1 | 2 - jz .bios - - mov dl, al - mov ah, 02h - int 21h - jmp .common - -.bios: - mov ah, 0Eh - mov bx, 7 - int 10h - -.common: - pop bp - pop dx - pop bx - pop ax -@@: - retn - -disp_msg_length: - push cx - jcxz .ret -.loop: - lodsb - call disp_al - loop .loop -.ret: - pop cx - retn - - -sig_valid: - ; S0 +28 -; pushf ; +26 -; push ax ; +24 -; push cs ; +22 -; call .push_ip -;.push_ip: -; pop ax -; sub ax, .push_ip -; push ax ; +20 IP -; push es ; +18 -; push bx ; +16 - sti - cld - push cx ; +14 - push dx ; +12 - push si ; +10 - push di ; +8 - push bp ; +6 - mov ax, sp - add ax, 22 - push ax ; +4 SP - push ds ; +2 - push ss ; +0 - - test byte [cs:loadmode], 2 - jz @F - - mov word [cs:dev_sp], sp - mov word [cs:dev_exit], dev_exit.2 - mov word [cs:dev_request_header], bx - mov word [cs:dev_request_header + 2], es - - cmp byte [es:bx + 2], 0 ; command code 0 (init) ? - jne dev_exit.2 ; else immediately return --> - - mov byte [es:bx + 13], 0 ; number of units = 0 - mov word [es:bx + 14 + 2], cs - and word [es:bx + 14], 0 ; -> after end of memory to allocate - or word [cs:device_header.next], -1 - ; fill in offset of device header link -@@: - - mov si, sp - push ss - pop ds - mov di, table - push cs - pop es -loop_table: - mov bx, [es:di + 0] - mov al, 32 - call disp_al - mov ax, [es:di + 2] - call disp_al - xchg al, ah - call disp_al - cmp bx, -1 - je @F - mov al, '=' - call disp_al - mov ax, [si + bx] - call disp_ax_hex -@@: - add di, 4 - cmp di, table.end - jb loop_table - -listnames: - test byte [cs:loadmode], 1 | 2 - jnz .skip - - mov bx, msg.names - push ss - pop ds - lea si, [bp + bsBPB + ebpbNew + BPBN_size] - mov cx, (512 - (bsBPB + ebpbNew + BPBN_size)) - 2 - ; -2 = AA55h sig - cmp word [bp + bsBPB + bpbSectorsPerFAT], 0 - je @F - mov cx, (512 + (ebpbNew - bpbNew) - (bsBPB + ebpbNew + BPBN_size)) - 2 -@@: -.nextname: - call findname - lahf - mov dx, [cs:bx] - call disp_msg_asciz - mov dx, msg.name_before - call disp_msg_asciz - sahf - jc @F ; skip quote if no name --> - mov dx, msg.name_quote - call disp_msg_asciz -@@: - mov dx, msg.foundname - call disp_msg_asciz - sahf - jc @F ; skip quote if no name --> - mov dx, msg.name_quote - call disp_msg_asciz -@@: - mov dx, msg.name_after - call disp_msg_asciz - sahf - mov ax, 0 - jc @F ; set to zero if no name --> - lea ax, [si - 11] ; -> name in buffer -@@: - mov word [cs:bx + 2], ax ; -> name in buffer, or 0 - add bx, 4 - cmp word [cs:bx], 0 - jne .nextname - -.skip: - - push cs - pop ds - mov si, msg.test - call disp_msg - - test byte [cs:loadmode], 1 - jz .skip_psp_dos - - mov si, msg.psp_and_size_before - call disp_msg - mov ah, 51h - int 21h - mov ax, bx - call disp_ax_hex - mov si, msg.psp_and_size_between - call disp_msg - dec bx - mov es, bx - mov ax, word [es:3] - call disp_ax_hex - mov si, msg.psp_and_size_after - call disp_msg - - - mov si, msg.cmdline_before.app - call disp_msg - - mov ah, 51h - int 21h - mov ds, bx - mov si, 81h - xor cx, cx - mov cl, byte [si - 1] - call disp_msg_length - - push cs - pop ds - mov si, msg.cmdline_after - call disp_msg - - jmp .after_cmdline - -.skip_psp_dos: - test byte [cs:loadmode], 2 - jz .skip_device - - mov si, msg.cmdline_before.device - call disp_msg - - les bx, [cs:dev_request_header] - les di, [es:bx + 18] - push es - pop ds - mov si, di - - ; Writing MS-DOS Device Drivers, second edition, page 349 - ; specifies the following as to the command line termination: - ; "Note that the DEVICE= command string is terminated by an - ; Ah when there are no arguments. When there are arguments, - ; the string is terminated with the following sequence: - ; 0h, Dh, Ah." - db __TEST_IMM8 -@@: - inc di - cmp byte [di], 0 - je @F - cmp byte [di], 13 - je @F - cmp byte [di], 10 - jne @B -@@: ; di -> at terminator - sub di, si - mov cx, di - call disp_msg_length - - push cs - pop ds - mov si, msg.cmdline_after - call disp_msg - - jmp .after_cmdline - -.skip_device: - mov si, msg.cmdline.kern.none - cmp word [bp + ldCommandLine], 0FF00h - je .no_kernel_cmdline - - mov si, msg.cmdline_before.kern - call disp_msg - - push ss - pop ds - lea si, [bp + ldCommandLine] - call disp_msg - - push cs - pop ds - mov si, msg.cmdline_after -.no_kernel_cmdline: - call disp_msg - -.after_cmdline: - int3 - - test byte [cs:loadmode], 2 - jz .dos_or_bios - - jmp near [cs:dev_exit] - -.dos_or_bios: - test byte [cs:loadmode], 1 - jz .bios - - mov ax, 4C00h - int 21h - -.bios: - xor ax, ax - int 16h - int 19h - - -disp_ax_hex: ; ax - xchg al,ah - call disp_al_hex ; display former ah - xchg al,ah ; and fall trough for al -disp_al_hex: ; al - push cx - mov cl,4 - ror al,cl - call disp_al_lownibble_hex ; display former high-nibble - rol al,cl - pop cx - ; and fall trough for low-nibble -disp_al_lownibble_hex: - push ax ; save ax for call return - and al,00001111b ; high nibble must be zero - add al,'0' ; if number is 0-9, now it's the correct character - cmp al,'9' - jna .decimalnum ; if we get decimal number with this, ok --> - add al,7 ; otherwise, add 7 and we are inside our alphabet - .decimalnum: - call disp_al - pop ax - retn - - - ; INP: ds:si -> first byte to check for name - ; cx = number of bytes left - ; OUT: (8+1+3+1)bytes[es:msg.foundname] = found name, - ; converted to 8.3 ASCIZ format, - ; "(None)" if none - ; CY if no filename found, - ; si = INP:si + INP:cx - ; cx = 0 - ; NC if filename found, - ; ds:si -> byte behind the name, thus ds:(si-11)-> name - ; cx = number of bytes left - ; CHG: di, ax -findname: -.: - cmp cx, 11 ; enough for another name ? - jb .none ; no --> - ; (cx == 0 jumps here too) -.check: - push cx - push si - mov cx, 11 - lodsb - mov ah, al ; check for same char in all 11 places - cmp al, 32 ; first character must not be blank - je .check_fail ; if it is --> -; cmp al, 5 ; first character may be 05h to indicate 0E5h -; je .check_pass - db __TEST_IMM8 ; (skip lodsb) -.check_loop_same: - lodsb - cmp ah, al - jne .check_loop_differs - call .check_character - jc .check_fail - loop .check_loop_same - ; if we arrive here, all characters (while valid) are the - ; same character repeated 11 times. we disallow this in case - ; that the padding character is an allowed one (eg '&' 26h). -.check_fail: - pop si - pop cx - dec cx ; lessen the counter - inc si ; -> next position to check - jmp . - -.check_character: - cmp al, 32 - jb .check_character_fail - cmp al, 127 -; je .check_character_fail - jae .check_character_fail - ; note: with all characters >= 128 allowed, - ; we get false positives in our sectors. - cmp al, '.' - je .check_character_fail - cmp al, '/' - je .check_character_fail - cmp al, '\' - je .check_character_fail - cmp al, 'a' - jb .check_character_pass - cmp al, 'z' - ja .check_character_pass -.check_character_fail: - stc - retn - -.check_character_pass: - clc - retn - -.check_loop: - lodsb -.check_loop_differs: - call .check_character - jc .check_fail -.check_pass: - loop .check_loop - - pop ax ; (discard si) - sub si, 11 ; -> at name - - call convert_name_to_asciz - ; si -> behind name - pop cx - sub cx, 11 ; lessen the counter - clc - retn - -.none: - add si, cx - mov di, msg.foundname - push si - push ds - push cs - pop ds - mov si, msg.foundname_none - mov cx, (msg.foundname_none_size + 1) >> 1 - rep movsw - pop ds - pop si - xor cx, cx - stc - retn - - - ; INP: ds:si -> 11-byte blank-padded name - ; es:msg.foundname -> (8+1+3+1)-byte buffer - ; OUT: ds:si -> behind 11-byte blank-padded name - ; es:msg.foundname filled - ; CHG: cx, di, ax -convert_name_to_asciz: - mov di, msg.foundname - mov cx, 8 - rep movsb ; copy over base name, si -> extension - cmp byte [es:di - 8], 05h ; is it 05h ? - jne @F ; no --> - mov byte [es:di - 8], 0E5h ; yes, convert to 0E5h -@@: - - db __TEST_IMM8 ; (skip dec) -@@: - dec di ; decrement -> at previous trailing blank - cmp byte [es:di - 1], 32 ; trailing blank ? - je @B ; yes --> - - mov al, '.' - stosb ; store dot (if needed) - mov cl, 3 - rep movsb ; copy over extension, si -> behind name - - db __TEST_IMM8 ; (skip dec) -@@: - dec di ; decrement -> at previous trailing blank - cmp byte [es:di - 1], 32 ; trailing blank ? - je @B ; yes --> - - cmp byte [es:di - 1], '.' ; trailing dot ? (only occurs if all-blank ext) - jne @F ; no --> - dec di ; -> at the dot -@@: - mov al, 0 - stosb ; store filename terminator - retn - - - align 4 -table: - dw +0, "SS" - dw +6, "BP" - dw +4, "SP" - dw +22, "CS" - dw +20, "IP" - dw +26, "FL" - db -1, -1, 13,10 - dw +2, "DS" - dw +10, "SI" - dw +18, "ES" - dw +8, "DI" - db -1, -1, 13,10 - dw +24, "AX" - dw +16, "BX" - dw +14, "CX" - dw +12, "DX" - db -1, -1, 13,10 - dw +28, "S0" - dw +30, "S1" - dw +32, "S2" - dw +34, "S3" - dw +36, "S4" - dw +38, "S5" - dw +40, "S6" - dw +42, "S7" - db -1, -1, 13,10 - dw +44, "S8" - dw +46, "S9" - dw +48, "SA" - dw +50, "SB" - dw +52, "SC" - dw +54, "SD" - dw +56, "SE" - dw +58, "SF" - db -1, -1, 13,10 -.end: - - -signature: - dw 2638h - align 16, db 0 - -%if _LARGE - times 64 * 1024 db 0 -%endif - -signature2: - dw 2638h - -%if _PADDING - %if ($ - $$) > _PADDING - %warning No padding needed - %else - times _PADDING - ($ - $$) db 0 - %endif -%endif diff --git a/test/ldosboot/testwrit.asm b/test/ldosboot/testwrit.asm deleted file mode 100644 index 6d60458f..00000000 --- a/test/ldosboot/testwrit.asm +++ /dev/null @@ -1,1030 +0,0 @@ - -%if 0 - -Write success indicator after file system booting - by C. Masloch, 2020 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - -%assign __lMACROS1_MAC__DEBUG_DEFAULTS 1 -%include "lmacros3.mac" - - struc BS -bsJump: resb 3 -bsOEM: resb 8 -bsBPB: - endstruc - - struc EBPB ; BPB sec -bpbBytesPerSector: resw 1 ; offset 00h 0Bh -bpbSectorsPerCluster: resb 1 ; offset 02h 0Dh -bpbReservedSectors: resw 1 ; offset 03h 0Eh -bpbNumFATs: resb 1 ; offset 05h 10h -bpbNumRootDirEnts: resw 1 ; offset 06h 11h -- 0 for FAT32 -bpbTotalSectors: resw 1 ; offset 08h 13h -bpbMediaID: resb 1 ; offset 0Ah 15h -bpbSectorsPerFAT: resw 1 ; offset 0Bh 16h -- 0 for FAT32 -bpbCHSSectors: resw 1 ; offset 0Dh 18h -bpbCHSHeads: resw 1 ; offset 0Fh 1Ah -bpbHiddenSectors: resd 1 ; offset 11h 1Ch -bpbTotalSectorsLarge: resd 1 ; offset 15h 20h -bpbNew: ; offset 19h 24h - -ebpbSectorsPerFATLarge: resd 1 ; offset 19h 24h -ebpbFSFlags: resw 1 ; offset 1Dh 28h -ebpbFSVersion: resw 1 ; offset 1Fh 2Ah -ebpbRootCluster: resd 1 ; offset 21h 2Ch -ebpbFSINFOSector: resw 1 ; offset 25h 30h -ebpbBackupSector: resw 1 ; offset 27h 32h -ebpbReserved: resb 12 ; offset 29h 34h -ebpbNew: ; offset 35h 40h - endstruc - - struc BPBN ; ofs B16 S16 B32 S32 -bpbnBootUnit: resb 1 ; 00h 19h 24h 35h 40h - resb 1 ; 01h 1Ah 25h 36h 41h -bpbnExtBPBSignature: resb 1 ; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN -bpbnSerialNumber: resd 1 ; 03h 1Ch 27h 38h 43h -bpbnVolumeLabel: resb 11 ; 07h 20h 2Bh 3Ch 47h -bpbnFilesystemID: resb 8 ; 12h 2Bh 36h 47h 52h - endstruc ; 1Ah 33h 3Eh 4Fh 5Ah - - struc LOADSTACKVARS, -10h -lsvFirstCluster: resd 1 -lsvFATSector: resd 1 -lsvFATSeg: resw 1 -lsvLoadSeg: resw 1 -lsvDataStart: resd 1 - endstruc - -lsvclSignature equ "CL" -lsvclBufferLength equ 256 - - struc LOADDATA, LOADSTACKVARS - 10h -ldMemoryTop: resw 1 -ldLoadTop: resw 1 -ldSectorSeg: resw 1 -ldFATType: resb 1 -ldHasLBA: resb 1 -ldClusterSize: resw 1 -ldParaPerSector:resw 1 -ldLoadingSeg: resw 1 -ldLoadUntilSeg: resw 1 - endstruc - - struc LOADCMDLINE, LOADDATA - lsvclBufferLength -ldCommandLine: -.start: resb lsvclBufferLength - endstruc - - struc LBAPACKET -lpSize: resw 1 -lpCount: resw 1 -lpBuffer: resd 1 -lpSector: resq 1 - endstruc - - struc DIRENTRY -deName: resb 8 -deExt: resb 3 -deAttrib: resb 1 - resb 8 -deClusterHigh: resw 1 -deTime: resw 1 -deDate: resw 1 -deClusterLow: resw 1 -deSize: resd 1 - endstruc - -ATTR_READONLY equ 1 -ATTR_HIDDEN equ 2 -ATTR_SYSTEM equ 4 -ATTR_VOLLABEL equ 8 -ATTR_DIRECTORY equ 10h -ATTR_ARCHIVE equ 20h - - -%ifndef _MAP -%elifempty _MAP -%else ; defined non-empty, str or non-str - [map all _MAP] -%endif - - defaulting - - numdef QUERY_GEOMETRY, 1 ; query geometry via 13.08 (for CHS access) - numdef CHS, 1 ; support CHS (if it fits) - numdef LBA, 1 ; support LBA (if available) - numdef LBA_33_BIT, 1 ; support 33-bit LBA - numdef LBA_CHECK_NO_33, 1 ; else: check that LBA doesn't carry - numdef LBA_SKIP_CHECK, 0 ; don't use proper LBA extensions check - numdef LBA_RETRY, 1 ; retry LBA reads - numdef CHS_RETRY, 1 ; retry CHS reads - - numdef PADDING, 0 - strdef FILE_NAME, "RESULT" - strdef FILE_EXT, "TXT" ; name of file to write - strdef FILE_SUCCESS_MSG,"success" - - - cpu 8086 - org 0 -start: - push ss - pop ds - mov word [cs:dirsp], sp - - mov ax, cs - cmp ax, 200h + 200h ; loaded high ? - mov dx, 200h ; yes, use low buffer - jae @F - add ax, paras(end - $$) ; => behind used load image - mov dx, ax - neg ax ; - behind used - add ax, word [bp + ldLoadTop] ; top - used = length of free - cmp ax, 200h ; enough ? - jb error_outofmemory ; no --> - ; (For simplicity we do not attempt to relocate our load image.) -@@: - mov word [cs:dirbuf], dx - -%if _QUERY_GEOMETRY || !_LBA_SKIP_CHECK - call query_geometry - ; The ebpbNew BPBN needs to be initialised - ; to use this function. It must be called - ; before using read_sector. -%endif - - cmp byte [bp + ldFATType], 16 - ja search32 - cmp byte [bp + ldFATType], 0 - ja search1216 - call error - asciz "Unknown file system (ldFATType = 0)." - -search1216: - xor cx, cx - mov bx, word [bp + ldParaPerSector] - shr bx, 1 ; = entries per sector - -; number of sectors used for root directory (store in CX) - mov si, [bp + bsBPB + bpbNumRootDirEnts] - mov ax, bx - ; The ax value here is the last value of bx, which is set - ; by the shr instruction. Therefore, it cannot be higher - ; than 7FFFh, so this cwd instruction always zeros dx. - cwd - dec ax ; rounding up - add ax, si ; from BPB - adc dx, dx ; account for overflow (dx was zero) - div bx ; get number of root sectors - xchg ax, cx ; cx = number of root secs, ! ah = 0 - -; first sector of root directory - mov al, [bp + bsBPB + bpbNumFATs]; ! ah = 0, hence ax = number of FATs - mul word [bp + bsBPB + bpbSectorsPerFAT] - add ax, [bp + bsBPB + bpbReservedSectors] - adc dl, dh ; account for overflow (dh was and is 0) - -; Scan root directory for file. We don't bother to check for deleted -; entries (E5h) or entries that mark the end of the directory (00h). - ; number of root entries in si here -.next_sect: - mov cx, bx ; entries per sector as loop counter - call read_sector_to_dirbuf - mov bx, cx ; restore bx for next iteration later - - xor di, di ; es:di-> first entry in this sector -.next_ent: - call check_entry - dec si ; count down entire root's entries - loopnz .next_ent ; count down sector's entries (jumps iff si >0 && cx >0) - jnz .next_sect ; (jumps iff si >0 && cx ==0) - ; ends up here iff si ==0 - ; ie all root entries checked unsuccessfully - jmp error_filenotfound - - -search32: - mov ax, [bp + bsBPB + ebpbRootCluster] - mov dx, [bp + bsBPB + ebpbRootCluster + 2] - mov si, word [bp + lsvFATSector + 2] - mov di, word [bp + lsvFATSector] - call check_clust - jc error_filenotfound - -.next_root_clust: - call clust_to_first_sector - push cx - push bx - mov cx, [bp + ldClusterSize] -.next_root_sect: - push cx - mov cx, [bp + ldParaPerSector] - shr cx, 1 - -; Scan root directory for file. We don't bother to check for deleted -; entries (E5h) or entries that mark the end of the directory (00h). - call read_sector_to_dirbuf - - push di - xor di, di ; es:di-> first entry in this sector -.next_ent: - call check_entry - loop .next_ent ; count down sector's entries (jumps iff cx >0) - pop di - pop cx - loop .next_root_sect - pop bx - pop cx - call clust_next - jnc .next_root_clust - jmp error_filenotfound - - -read_sector_to_dirbuf: - mov bx, word [cs:dirbuf] - mov word [cs:dirsec], ax - mov word [cs:dirsec + 2], dx - jmp read_sector - -check_entry: - test byte [es:di + deAttrib], ATTR_DIRECTORY | ATTR_VOLLABEL - jnz @F ; directory, label, or LFN entry --> (NZ) - push si - push di - push cx - push ds - push cs - pop ds - mov si, msg.filename ; ds:si-> name to match - mov cx, 11 ; length of padded 8.3 FAT filename - repe cmpsb ; check entry - pop ds - pop cx - pop di - pop si -@@: ; ZR = match, NZ = mismatch - je found_it ; found entry --> - lea di, [di + DIRENTRY_size] - retn - -found_it: - mov sp, word [cs:dirsp] - mov word [cs:dirofs], di - - cmp word [es:di + deSize], 0 - jne @F - cmp word [es:di + deSize + 2], 0 - jne @F - -error_emptyfile: equ $ - call error - asciz "File is empty." - -@@: -; get starting cluster of file - mov ax, [es:di + deClusterLow] - mov dx, [es:di + deClusterHigh] ; dx:ax = first cluster - cmp byte [bp + ldFATType], 16 - ja @F - xor dx, dx -@@: - - mov di, [bp + lsvFATSector] - mov si, [bp + lsvFATSector + 2] - call check_clust - jc error_emptyfile - - call clust_to_first_sector - mov bx, cs - add bx, paras(filbuf - $$) - call write_sector - - mov es, word [cs:dirbuf] - mov bx, word [cs:dirofs] - mov word [es:bx + deSize], filbuf.size - and word [es:bx + deSize + 2], 0 - mov bx, es - mov ax, word [cs:dirsec] - mov dx, word [cs:dirsec + 2] - call write_sector - - push cs - pop ds - mov si, msg.success - call disp_error - -quit: - int3 - - mov ax, 0F000h - mov es, ax - push cs - pop ds ; avoid "repe cs cmpsw" (8086 bug) - mov di, 0FFF5h - mov si, msg.dosemudate - mov cx, 4 - repe cmpsw ; running in DosEmu? - jne .quit_not_dosemu - - xor bx, bx - mov ax, -1 - int 0E6h ; dosemu quit - -.quit_not_dosemu: - -; from https://stackoverflow.com/a/5240330/738287 - mov ax, 5301h - xor bx, bx - int 15h ; connect to APM API - - mov ax, 530Eh - xor bx, bx - mov cx, 0102h - int 15h ; set APM version to 1.02 - - mov ax, 5307h - mov bx, 1 - mov cx, 3 - int 15h ; shut down system - - ; setopt [cs:quitrecurse], 1 - call error - asciz "Quit failed." - - -error: - push cs - pop ds - mov si, msg.error - call disp_error - pop si - call disp_error - mov si, msg.error.trailer - call disp_error -%if 0 - testopt [cs:quitrecurse], 1 - jz quit -%endif - int3 - xor ax, ax - int 16h - int 19h - -disp_error: -.: - lodsb - test al, al - jz .ret - mov ah, 0Eh - mov bx, 7 - push bp - ; (call may change bp) - int 10h - pop bp - jmp short . - - - align 4 -dirsec: dd 0 -dirofs: dw 0 -dirbuf: dw 0 -dirsp: dw 0 -; quitrecurse: db 0 - -msg: -.error: asciz "Load error: " -.success: db "Test writer loaded successfully. Quitting the machine." -.error.trailer: asciz 13,10 -.filename: fill 8, 32, db _FILE_NAME - fill 3, 32, db _FILE_EXT - align 4 -.dosemudate: db "02/25/93" - - align 16, db 38 -filbuf: -.: - db _FILE_SUCCESS_MSG,13,10 -.size: equ $ - . -%if .size > 32 - %error File success message is too long -%endif - _fill 8192, 38, . - - -query_geometry: -%if _QUERY_GEOMETRY ; +30 bytes - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - %if !_LBA_SKIP_CHECK - push dx - %endif -; test dl, dl ; floppy? -; jns @F ; don't attempt query, might fail --> - ; Note that while the original PC BIOS doesn't support this function - ; (for its diskettes), it does properly return the error code 01h. - ; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1) - mov ah, 08h - xor cx, cx ; initialise cl to 0 - stc ; initialise to CY - int 13h ; query drive geometry - jc @F ; apparently failed --> - and cx, 3Fh ; get sectors - jz @F ; invalid (S is 1-based), don't use --> - mov [bp + bsBPB + bpbCHSSectors], cx - mov cl, dh ; cx = maximum head number - inc cx ; cx = number of heads (H is 0-based) - mov [bp + bsBPB + bpbCHSHeads], cx -@@: -%endif - -%if !_LBA_SKIP_CHECK - mov ah, 41h - %if _QUERY_GEOMETRY - pop dx - %else - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - %endif - mov bx, 55AAh - stc - int 13h ; 13.41.bx=55AA extensions installation check - mov al, 0 ; zero in case of no LBA support - jc .no_lba - cmp bx, 0AA55h - jne .no_lba - test cl, 1 ; support bitmap bit 0 - jz .no_lba - inc ax ; al = 1 to indicate LBA support -.no_lba: - mov byte [bp + ldHasLBA], al -%endif - -%if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK -disp_error.ret: - retn -%endif - - - ; Read a sector using Int13.02 or Int13.42 - ; - ; INP: dx:ax = sector number within partition - ; bx:0-> buffer - ; (_LBA) ds = ss - ; OUT: If unable to read, - ; ! jumps to error instead of returning - ; If sector has been read, - ; dx:ax = next sector number (has been incremented) - ; bx:0-> next buffer (bx = es+word[para_per_sector]) - ; es = input bx - ; CHG: - - ; STT: ds = ss - ; - ; Note: If error 09h (data boundary error) is returned, - ; the read is done into the ldSectorSeg buffer, - ; then copied into the user buffer. -read_sector: - clropt [bp + ldHasLBA], 2 - jmp @F - -write_sector: - setopt [bp + ldHasLBA], 2 -@@: - - push dx - push cx - push ax - push si - - mov es, bx - -; DX:AX==LBA sector number -; add partition start (= number of hidden sectors) - add ax,[bp + bsBPB + bpbHiddenSectors + 0] - adc dx,[bp + bsBPB + bpbHiddenSectors + 2] - - %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33 - jc .err_CY - %endif -%if _LBA ; +70 bytes (with CHS, +63 bytes without CHS) - %if _LBA_33_BIT - sbb si, si ; -1 if was CY, 0 else - neg si ; 1 if was CY, 0 else - %endif - xor cx, cx ; cx = 0 (needed if jumping to .no_lba_checked) - %if !_LBA_SKIP_CHECK - test byte [bp + ldHasLBA], 1 - jz .no_lba_checked - %endif - push cx - %if _LBA_33_BIT - push si ; bit 32 = 1 if operating in 33-bit space - %else - push cx ; second highest word = 0 - %endif - push dx - push ax ; qword sector number (lpSector) - push bx - push cx ; bx:0 -> buffer (lpBuffer) - inc cx - push cx ; word number of sectors to read (lpCount) - mov cl, 10h - push cx ; word size of disk address packet (lpSize) - mov si, sp ; ds:si -> disk address packet (on stack) - - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - call .get_ah_3_write_2_read - or ah, 40h ; 42h extensions read or 43h extensions write -%if _LBA_RETRY - call .int13_retry -%else - call .int13_preserve_lpcount -%endif - jnc .lba_done - -%if _LBA_SKIP_CHECK - cmp ah, 1 ; invalid function? - je .no_lba_skip ; try CHS instead --> -%endif - cmp ah, 9 ; data boundary error? - jne .lba_error - - testopt [bp + ldHasLBA], 2 - jz @F - - ; es => user buffer - push es - call .sectorseg_helper_write - mov word [si + 4 + 2], es ; => sector buffer - mov ah, 43h -%if _LBA_RETRY - call .int13_retry -%else - int 13h - ; (don't need .int13_preserve_lpcount as no further call) -%endif - pop es ; ! restore es => user buffer - jc .lba_error - jmp .lba_done - -@@: - ; push word [si + 4 + 0] - push es ; => user buffer - mov es, word [bp + ldSectorSeg] - mov word [si + 4 + 2], es - ; => sector buffer - ; and word [si + 4 + 0], byte 0 - - mov ah, 42h -%if _LBA_RETRY - call .int13_retry -%else - int 13h - ; (don't need .int13_preserve_lpcount as no further call) -%endif - jc .lba_error - - pop es ; => user buffer - ; pop cx - call .sectorseg_helper_read - -.lba_done: - add sp, 10h - jmp short .done - -.lba_error: equ .err - - %if !_CHS -.no_lba_skip: equ .err -.no_lba_checked: equ .err - %elif _LBA_SKIP_CHECK -.no_lba_skip: - ; si == sp - add sp, 8 - pop ax - pop dx - %if _LBA_33_BIT - pop si - pop cx ; cx = 0 (needed as input for next cwd instruction) - test si, si - mov si, sp ; si == sp - %else - pop cx - pop cx - ; si == sp - 16 - %endif - %else -.no_lba_checked: - %if _LBA_33_BIT - test si, si - %endif - mov si, sp ; si == sp - %endif -%endif - -%if _CHS ; +70 bytes - %if _LBA && _LBA_33_BIT - jnz .err - %endif -; dx:ax = LBA sector number, (if _LBA) cx = 0 -; divide by number of sectors per track to get sector number -; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability -; Use two-step 32:16 divide to avoid overflow - %if !_LBA - xchg cx, ax ; cx = low word of sector, clobbers ax - xchg ax, dx ; ax = high word of sector, clobbers dx - xor dx, dx ; dx:ax = high word of sector - %else - xchg cx, ax ; cx = low word of sector, ax = 0 - push dx ; stack = high word of sector - cwd ; dx = 0 (because ax was 0) - pop ax ; ax = high word of sector - ; dx:ax = high word of sector - %endif - div word [bp + bsBPB + bpbCHSSectors] - xchg cx,ax - div word [bp + bsBPB + bpbCHSSectors] - xchg cx,dx - -; DX:AX=quotient, CX=remainder=sector (S) - 1 -; divide quotient by number of heads - xchg bx, ax ; bx = low word of quotient, clobbers ax - xchg ax, dx ; ax = high word of quotient, clobbers dx - xor dx, dx ; dx = 0 - div word [bp + bsBPB + bpbCHSHeads] - ; ax = high / heads, dx = high % heads - xchg bx, ax ; bx = high / heads, ax = low quotient - div word [bp + bsBPB + bpbCHSHeads] - -; bx:ax=quotient=cylinder (C), dx=remainder=head (H) -; move variables into registers for INT 13h AH=02h - mov dh, dl ; dh = head - inc cx ; cl5:0 = sector - xchg ch, al ; ch = cylinder 7:0, al = 0 - shr ax, 1 - shr ax, 1 ; al7:6 = cylinder 9:8 - ; bx has bits set iff it's > 0, indicating a cylinder >= 65536. - or bl, bh ; collect set bits from bh - or cl, al ; cl7:6 = cylinder 9:8 - ; ah has bits set iff it was >= 4, indicating a cylinder >= 1024. - or bl, ah ; collect set bits from ah - mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit] - ; dl = drive - jnz .err ; error if cylinder >= 1024 --> - ; ! bx = 0 (for 13.02 call) - -; we call INT 13h AH=02h once for each sector. Multi-sector reads -; may fail if we cross a track or 64K boundary - - call .get_ah_3_write_2_read - mov al, 01h ; access one sector - -%if _CHS_RETRY - call .int13_retry -%else - int 13h -%endif - jnc .done - - cmp ah, 9 ; data boundary error? - jne .err - - testopt [bp + ldHasLBA], 2 - jz @F - - push es ; user buffer - call .sectorseg_helper_write - mov ax, 0301h -%if _LBA_RETRY - call .int13_retry -%else - int 13h -%endif - jc .err - pop es - jmp .done - -@@: - push es ; user buffer - mov es, word [bp + ldSectorSeg] - - mov ax, 0201h -%if _CHS_RETRY - call .int13_retry -%else - int 13h -%endif - jc .err - - pop es - call .sectorseg_helper_read -%endif ; _CHS - -.done: -; increment segment - mov bx, es - add bx, word [bp + ldParaPerSector] - - pop si - pop ax - pop cx - pop dx -; increment LBA sector number - inc ax - jne @F - inc dx -@@: - retn - - -%if (_LBA && _LBA_RETRY) || (_CHS && _CHS_RETRY) -.int13_retry: - push ax -%if _LBA - call .int13_preserve_lpcount -%else - int 13h ; first try -%endif - jnc @F ; NC, success on first attempt --> - -; reset drive - xor ax, ax - int 13h - jnc @FF ; NC, reset succeeded --> - ; CY, reset failed, error in ah - -@@: ; NC or CY, stack has function number - inc sp - inc sp ; discard word on stack, preserve CF - retn - -@@: -; try read again - pop ax ; restore function number -%if ! _LBA - int 13h ; retry, CF error status, ah error number - retn -%endif ; else: fall through to .int13_preserve_lpcount -%endif - -%if _LBA - ; have to reset the LBAPACKET's lpCount, as the handler may - ; set it to "the number of blocks successfully transferred". - - ; hack: si points into unclaimed stack space - ; when this is called from the CHS handler. - ; this should not cause any issues however. - ; actually, if !_LBA_SKIP_CHECK, then si is set - ; to point to claimed stack space. also legal. -.int13_preserve_lpcount: - push word [si + lpCount] - int 13h - pop word [si + lpCount] - retn -%endif - - ; INP: word [bp + ldSectorSeg] => source buffer with read data - ; es => destination buffer - ; CHG: si, cx - ; OUT: ss = ds - ; data copied to destination buffer - ; STT: UP -.sectorseg_helper_read: - xor si, si - mov ds, word [bp + ldSectorSeg] - push di - ; mov di, cx - xor di, di - mov cx, word [bp + bsBPB + bpbBytesPerSector] - rep movsb - pop di - - push ss - pop ds - retn - - ; INP: es => source buffer with data to read - ; word [bp + ldSectorSeg] => destination buffer - ; CHG: - - ; OUT: ss = ds - ; es => destination buffer - ; data copied to destination buffer - ; STT: UP -.sectorseg_helper_write: - push es - pop ds - push si - push di - push cx - xor di, di - mov es, word [bp + ldSectorSeg] - xor si, si - mov cx, word [bp + bsBPB + bpbBytesPerSector] - rep movsb - pop cx - pop di - pop si - - push ss - pop ds - retn - -.get_ah_3_write_2_read: - mov ah, 02h ; read - testopt [bp + ldHasLBA], 2 - jz @F - mov ah, 03h ; write -@@: - retn - -.err: -error_diskaccess: - testopt [bp + ldHasLBA], 2 - jz @F - call error - db "Disk write error.", 0 - -@@: - call error - db "Disk read error.", 0 - -error_badchain: - call error - db "Bad cluster chain.", 0 - -error_badclusters: - call error - db "Bad amount of clusters.", 0 - -error_outofmemory: - call error - db "Out of memory.", 0 - -error_filenotfound: - call error - db "File not found.", 0 - - - ; INP: dx:ax = cluster - 2 (0-based cluster) - ; OUT: cx:bx = input dx:ax - ; dx:ax = first sector of that cluster - ; CHG: - -clust_to_first_sector: - push dx - push ax - push dx - mul word [bp + ldClusterSize] - xchg bx, ax - xchg cx, dx - pop ax - mul word [bp + ldClusterSize] - test dx, dx - jnz short error_badchain - xchg dx, ax - add dx, cx -.cy_error_badchain: - jc short error_badchain - xchg ax, bx - - add ax, [bp + lsvDataStart] - adc dx, [bp + lsvDataStart + 2] - jc short .cy_error_badchain - ; dx:ax = first sector in cluster - pop bx - pop cx ; cx:bx = cluster - retn - - - ; INP: cx:bx = cluster (0-based) - ; si:di = loaded FAT sector, -1 if none - ; OUT: CY if no next cluster - ; NC if next cluster found, - ; dx:ax = next cluster value (0-based) - ; si:di = loaded FAT sector - ; CHG: cx, bx -clust_next: - mov ax, bx - mov dx, cx - add ax, 2 - adc dx, 0 - - push es - cmp byte [bp + ldFATType], 16 - je .fat16 - ja .fat32 - -.fat12: -; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2, -; so multiply cluster number by 3 first, then divide by 2. - ; ax = cluster number (up to 12 bits set) - mov dx, ax - shl ax, 1 ; = 2n (up to 13 bits set) - add ax, dx ; = 2n+n = 3n (up to 14 bits set) - shr ax, 1 ; ax = byte offset into FAT (0..6129) - ; CF = whether to use high 12 bits - sbb cx, cx ; = -1 iff CY, else 0 - -; Use the calculated byte offset as an offset into the FAT -; buffer, which holds all of the FAT's relevant data. - mov es, [bp + lsvFATSeg] - xchg bx, ax ; bx -> 16-bit word in FAT to load - -; get 16 bits from FAT - mov ax, [es:bx] - - and cl, 4 ; = 4 iff CY after shift, else 0 - shr ax, cl ; shift down iff odd entry, else unchanged - and ax, 0FFFh ; insure it's only 12 bits - jmp short .gotvalue_zero_dx - -.fat32: - ; * 4 = byte offset into FAT (0--4000_0000h) - add ax, ax - adc dx, dx -.fat16: - ; * 2 = byte offset into FAT (0--2_0000h) - add ax, ax - adc dx, dx - - push ax - xchg ax, dx - xor dx, dx ; dx:ax = high word - div word [bp + bsBPB + bpbBytesPerSector] - xchg bx, ax ; bx = high word / divisor - pop ax ; dx = remainder, ax = low word - div word [bp + bsBPB + bpbBytesPerSector] - xchg dx, bx ; dx:ax = result, bx = remainder - ; dx:ax = sector offset into FAT (0--200_0000h) - ; bx = byte offset into FAT sector (0--8190) - cmp dx, si - jne @F ; read sector - cmp ax, di - je @FF ; sector is already buffered -@@: - mov si, dx - mov di, ax - mov word [bp + lsvFATSector + 2], dx - mov word [bp + lsvFATSector + 0], ax - - push bx - add ax, [bp + bsBPB + bpbReservedSectors] - adc dx, 0 - mov bx, [bp + lsvFATSeg] - call read_sector - pop bx -@@: - mov es, [bp + lsvFATSeg] - mov dx, [es:bx + 2] - mov ax, [es:bx] ; dx:ax = FAT32 entry - - cmp byte [bp + ldFATType], 16 ; is it FAT32 ? - jne @F ; yes --> -.gotvalue_zero_dx: - xor dx, dx ; no, clear high word -@@: - pop es - - ; INP: dx:ax = cluster value, 2-based - ; OUT: dx:ax -= 2 (makes it 0-based) - ; CY iff invalid cluster -check_clust: - and dh, 0Fh - sub ax, 2 - sbb dx, 0 - - cmp byte [bp + ldFATType], 16 - ja .fat32 - je .fat16 - -.fat12: - cmp ax, 0FF7h - 2 - jmp short .common - -.fat32: - cmp dx, 0FFFh - jb @F ; CY here means valid ...- - -.fat16: - cmp ax, 0FFF7h - 2 -@@: ; -... or if NC first, CY here also -.common: - cmc ; NC if valid - retn - - - align 16, db 38 -end: - -%if _PADDING - %if ($ - $$) > _PADDING - %warning No padding needed - %else - times _PADDING - ($ - $$) db 0 - %endif -%endif diff --git a/test/lmacros/jn_warn.mac b/test/lmacros/jn_warn.mac deleted file mode 100644 index 4deb70fb..00000000 --- a/test/lmacros/jn_warn.mac +++ /dev/null @@ -1,304 +0,0 @@ -[list -] -%if 0 - -Warn for near jumps -Public Domain by C. Masloch, 2018 - -%endif - -%ifndef __JN_WARN_MAC__ -%assign __JN_WARN_MAC__ 1 - - %imacro jz 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnz 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro je 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jne 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jc 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnc 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jb 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnb 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro ja 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jna 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jae 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnae 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jbe 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnbe 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - - %imacro js 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jns 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - %imacro jo 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jno 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - %imacro jp 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnp 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - - %imacro jl 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnl 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jg 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jng 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jge 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnge 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jle 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - %imacro jnle 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - - %imacro jecxz 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - %imacro jcxz 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - - - %imacro jmp 1.nolist -%%start: - %? %1 -%%end: -%assign %%length %%end - %%start -%if %%length > 2 && %%length < 5 - %warning __FILE__ __LINE__ %? %1 %%length -%endif - %endmacro - -%endif -[list +] diff --git a/test/lmacros/lmacros1.mac b/test/lmacros/lmacros1.mac deleted file mode 100644 index fa3fa1ea..00000000 --- a/test/lmacros/lmacros1.mac +++ /dev/null @@ -1,1106 +0,0 @@ -[list -] -%if 0 - -NASM macro collection -Public Domain by C. Masloch, 2008-2012 -Intended for 86 Mode programs. - -%endif - -%ifndef __lMACROS1_MAC__ -%assign __lMACROS1_MAC__ 1 - -%if !!2 - 1 - %error Unary operator ! returns values > 1. Adjust all sources. -%endif - -%idefine by byte -%idefine wo word -%idefine dwo dword - -%idefine b byte -%idefine w word -%idefine d dword - -%idefine s short -%idefine sho short - -%idefine n near -%idefine ne near - -%idefine f far - - - ; Bind major and minor version byte to version word or - ; version word with exchanged bytes. -%idefine ver(major,minor) ( ((major)&0FFh)<<8|((minor)&0FFh) ) -%idefine verx(major,minor) ( ((minor)&0FFh)<<8|((major)&0FFh) ) - - ; Macros for table creation -%define count(start,stop) stop-start+1 -%define range(start,stop) (start),count(start,stop) ; generates two comma-separated values - - ; Work with 4-byte dates -%define date4b(y,m,d) (((y)&0FFFFh)<<16|((m)&0FFh)<<8|((d)&0FFh)) ; create 4-byte date -%define year4bd(d) (((d)>>16)&0FFFFh) ; get year from 4-byte date -%define month4bd(d) (((d)>>8)&0FFh) ; get month from 4-byte date -%define day4bd(d) ((d)&0FFh) ; get day from 4-byte date - ; The 4-byte date stores the year 0-65535 in the high word, - ; followed by the month 0-255 in the high byte (of the low - ; word) and the day 0-255 in the low byte. - - - ; Write numbers as decimal digits into a string -%define _1digits_nocheck(d) (((d)% 10)+'0') -%xdefine _2digits_nocheck(d) _1digits_nocheck((d)/10),_1digits_nocheck(d) -%xdefine _3digits_nocheck(d) _1digits_nocheck((d)/100),_2digits_nocheck(d) -%xdefine _4digits_nocheck(d) _1digits_nocheck((d)/1000),_3digits_nocheck(d) -%xdefine _5digits_nocheck(d) _1digits_nocheck((d)/10000),_4digits_nocheck(d) -%xdefine _1digits(d) (!!(d/10)*(1<<32)+ _1digits_nocheck(d)) -%xdefine _2digits(d) _1digits((d)/ 10),_1digits_nocheck(d) -%xdefine _3digits(d) _1digits((d)/ 100),_2digits_nocheck(d) -%xdefine _4digits(d) _1digits((d)/ 1000),_3digits_nocheck(d) -%xdefine _5digits(d) _1digits((d)/10000),_4digits_nocheck(d) - - ; Write number as decimal digits into a string, - ; and automagically determine how many digits to use. - ; The input number is a critical expression to NASM. - ; - ; %1 = number to write - ; %2 = minimal number of digits, 0..5. defaults to 1 - ; (setting it to 0 with a number of 0 writes nothing) -%macro _autodigits 1-2.nolist 1 -%if %2 > 5 - %error Minimal number of digits 6 or more: %2 -%endif -%if (%1) >= 100000 - %error Number has to use 6 or more digits: %1 -%elif (%1) >= 10000 || %2 == 5 - db _5digits(%1) -%elif (%1) >= 1000 || %2 == 4 - db _4digits(%1) -%elif (%1) >= 100 || %2 == 3 - db _3digits(%1) -%elif (%1) >= 10 || %2 == 2 - db _2digits(%1) -%elif (%1) >= 1 || %2 == 1 - db _1digits(%1) -%endif -%endmacro - - ; %1 = name of single-line macro to set. will be prefixed by underscore - ; %2 = number to write - ; %3 = minimal number of digits, 0..5. defaults to 1 - ; (setting it to 0 with a number of 0 defines macro to "") -%macro _autodigitsdef 2-3.nolist 1 -%if %3 > 5 - %error Minimal number of digits 6 or more: %3 -%endif -%if (%2) >= 100000 - %error Number has to use 6 or more digits: %2 -%elif (%2) >= 10000 || %3 == 5 -%define _%1 %[_5digits(%2)] -%elif (%2) >= 1000 || %3 == 4 -%define _%1 %[_4digits(%2)] -%elif (%2) >= 100 || %3 == 3 -%define _%1 %[_3digits(%2)] -%elif (%2) >= 10 || %3 == 2 -%define _%1 %[_2digits(%2)] -%elif (%2) >= 1 || %3 == 1 -%define _%1 %[_1digits(%2)] -%elif -%define _%1 "" -%endif -%endmacro - - ; Write numbers as hexadecimal digits into a string -%define _1digitshex_nocheck(h) ( ((h)& 0Fh) + '0' + ('A'-'9'-1)*(((h)& 0Fh)/10) ) -%xdefine _2digitshex_nocheck(h) _1digitshex_nocheck((h)>> 4),_1digitshex_nocheck(h) -%xdefine _3digitshex_nocheck(h) _1digitshex_nocheck((h)>> 8),_2digitshex_nocheck(h) -%xdefine _4digitshex_nocheck(h) _1digitshex_nocheck((h)>>12),_3digitshex_nocheck(h) -%xdefine _5digitshex_nocheck(h) _1digitshex_nocheck((h)>>16),_4digitshex_nocheck(h) -%xdefine _6digitshex_nocheck(h) _1digitshex_nocheck((h)>>20),_5digitshex_nocheck(h) -%xdefine _7digitshex_nocheck(h) _1digitshex_nocheck((h)>>24),_6digitshex_nocheck(h) -%xdefine _8digitshex_nocheck(h) _1digitshex_nocheck((h)>>28),_7digitshex_nocheck(h) -%xdefine _1digitshex(h) (!!(h&~0Fh)*(1<<32)+ _1digitshex_nocheck(h)) -%xdefine _2digitshex(h) _1digitshex((h)>> 4),_1digitshex_nocheck(h) -%xdefine _3digitshex(h) _1digitshex((h)>> 8),_2digitshex_nocheck(h) -%xdefine _4digitshex(h) _1digitshex((h)>>12),_3digitshex_nocheck(h) -%xdefine _5digitshex(h) _1digitshex((h)>>16),_4digitshex_nocheck(h) -%xdefine _6digitshex(h) _1digitshex((h)>>20),_5digitshex_nocheck(h) -%xdefine _7digitshex(h) _1digitshex((h)>>24),_6digitshex_nocheck(h) -%xdefine _8digitshex(h) _1digitshex((h)>>28),_7digitshex_nocheck(h) - -%xdefine _5digitssephex(h) _1digitshex((h)>>16),"_",_4digitshex_nocheck(h) -%xdefine _6digitssephex(h) _2digitshex((h)>>16),"_",_4digitshex_nocheck(h) -%xdefine _7digitssephex(h) _3digitshex((h)>>16),"_",_4digitshex_nocheck(h) -%xdefine _8digitssephex(h) _4digitshex((h)>>16),"_",_4digitshex_nocheck(h) - - -%macro _appenddigitstrdef 2.nolist -%substr %%ii "0123456789ABCDEF" (%2) + 1 -%strcat _%1 _%1,%%ii -%endmacro - - ; %1 = name of single-line macro to set. will be prefixed by underscore - ; %2 = number to write - ; %3 = minimal number of digits, 0..5. defaults to 1 - ; (setting it to 0 with a number of 0 defines macro to "") -%macro _autodigitsstrdef 2-3.nolist 1 -%if %3 > 5 - %error Minimal number of digits 6 or more: %3 -%endif -%define _%1 "" -%if (%2) >= 100000 - %error Number has to use 6 or more digits: %2 -%endif -%if (%2) >= 10000 || %3 >= 5 -_appenddigitstrdef %1, %2 / 10000 % 10 -%endif -%if (%2) >= 1000 || %3 >= 4 -_appenddigitstrdef %1, %2 / 1000 % 10 -%endif -%if (%2) >= 100 || %3 >= 3 -_appenddigitstrdef %1, %2 / 100 % 10 -%endif -%if (%2) >= 10 || %3 >= 2 -_appenddigitstrdef %1, %2 / 10 % 10 -%endif -%if (%2) >= 1 || %3 >= 1 -_appenddigitstrdef %1, %2 / 1 % 10 -%endif -%endmacro - - ; %1 = name of single-line macro to set. will be prefixed by underscore - ; %2 = number to write - ; %3 = minimal number of hexits, 0..8. defaults to 1 - ; (setting it to 0 with a number of 0 defines macro to "") -%macro _autohexitsstrdef 2-3.nolist 1 -%if %3 > 8 - %error Minimal number of hexits 9 or more: %3 -%endif -%define _%1 "" -%if (%2) >= 1_0000_0000h - %error Number has to use 9 or more hexits: %2 -%endif -%if (%2) >= 1000_0000h || %3 >= 8 -_appenddigitstrdef %1, (%2 >> (7 * 4)) & 0Fh -%endif -%if (%2) >= 100_0000h || %3 >= 7 -_appenddigitstrdef %1, (%2 >> (6 * 4)) & 0Fh -%endif -%if (%2) >= 10_0000h || %3 >= 6 -_appenddigitstrdef %1, (%2 >> (5 * 4)) & 0Fh -%endif -%if (%2) >= 1_0000h || %3 >= 5 -_appenddigitstrdef %1, (%2 >> (4 * 4)) & 0Fh -%endif -%if (%2) >= 1000h || %3 >= 4 -_appenddigitstrdef %1, (%2 >> (3 * 4)) & 0Fh -%endif -%if (%2) >= 100h || %3 >= 3 -_appenddigitstrdef %1, (%2 >> (2 * 4)) & 0Fh -%endif -%if (%2) >= 10h || %3 >= 2 -_appenddigitstrdef %1, (%2 >> (1 * 4)) & 0Fh -%endif -%if (%2) >= 1h || %3 >= 1 -_appenddigitstrdef %1, (%2 >> (0 * 4)) & 0Fh -%endif -%endmacro - - - ; Compute required words/dwords/qwords/paragraphs/pages/KiB of known byte size (rounds up if necessary) -%idefine bytes(b) (b) -%idefine words(b) ((b)+1>>1) -%idefine dwords(b) ((b)+3>>2) -%idefine qwords(b) ((b)+7>>3) -%idefine paragraphs(b) ((b)+15>>4) -%idefine paras(b) ((b)+15>>4) -%idefine pages(b) ((b)+511>>9) -%idefine kib(b) ((b)+1023>>10) - - ; Compute required bytes of known word/dword/qword/paragraph/page/KiB size -%idefine frombytes(b) (b) -%idefine fromwords(w) ((w)<<1) -%idefine fromdwords(d) ((d)<<2) -%idefine fromqwords(q) ((q)<<3) -%idefine fromparagraphs(p) ((p)<<4) -%idefine fromparas(p) ((p)<<4) -%idefine frompages(p) ((p)<<9) -%idefine fromkib(k) ((k)<<10) - - - ; Compute relative address - ; - ; address: which address is referenced - ; fixup: how many bytes are added to get the absolute address -%define __REL__(address,fixup) ((address)-(fixup)) -%xdefine __REL8__(address,fixup) __REL__(address,fixup) -%xdefine __REL8__(address) __REL__(address,$+1) ; for __JMP_REL8 (db) -%xdefine __REL16__(address,fixup) __REL__(address,fixup) -%xdefine __REL16__(address) __REL__(address,$+2); for __JMP_REL16 (dw) - - ; Values of some opcodes -%define __JMP_REL8 0EBh -%define __JMP_REL16 0E9h -%define __JMP_FAR 0EAh -%define __CALL_REL16 0E8h -%define __CALL_FAR 9Ah -%define __NOP 90h -%define __TEST_IMM8 0A8h ; changes flags, NC -%define __TEST_IMM16 0A9h ; changes flags, NC - ; Longer NOPs require two bytes, like a short jump does. - ; However they execute faster than unconditional jumps. - ; This one reads random data in the stack segment. - ; (Search for better ones.) -%define __TEST_OFS16_IMM8 0F6h,86h ; changes flags, NC - - ; Remove the following macros if already found in other files -%unimacro asciz 0-1+.nolist -%unimacro ascii 0-1+.nolist -%unmacro _ascii_prefix_suffix 2-3+.nolist -%undef ascii -%undef asciz -%undef ascic -%undef asciiline -%undef ascizline -%undef ascicline -%unimacro verdef 4.nolist -%unimacro numdef 1-3.nolist -%unimacro strdef 3.nolist -%unimacro incdef 2-4.nolist -%unimacro _incdef 2-4.nolist -%unimacro incdef 2-*.nolist -%unimacro excdef 2-*.nolist -%unimacro comment 0-*.nolist -%unimacro commentif 2.nolist -%unimacro commentifn 2.nolist -%unimacro fixme 0-1+.nolist -%unimacro noparam 0-1+.nolist -%unimacro noparamnamed 1-2+.nolist -%unimacro assignif 3-4.nolist -%unimacro assignifn 3-4.nolist -%unimacro cpu 1+.nolist ; removes NASM's standard macro -%unimacro selcpu 0.nolist -%unimacro cpufailmsg 0-2+.nolist -%unimacro check186 0-1.nolist -%unimacro check286 0-1.nolist -%unimacro check386 0-1.nolist -%unimacro check186 0-3.nolist -%unimacro check286 0-3.nolist -%unimacro check386 0-3.nolist -%unimacro checkcpu 1.nolist -%unimacro _d 2.nolist -%unimacro d0out 0-3.nolist -%unimacro endarea 1-2.nolist -%unimacro struc 1.nolist ; removes NASM's standard macro -%unimacro struc 1-2.nolist -%unimacro endstruc 0.nolist ; removes NASM's standard macro -%unimacro endstruc 0-1.nolist -%unimacro istruc 1.nolist ; removes NASM's standard macro -%unimacro at 1-2+.nolist ; removes NASM's standard macro -%unimacro iend 0.nolist ; removes NASM's standard macro -%unimacro fill 2-3+.nolist -%unimacro _fill 3.nolist -%unimacro pad 2-3+.nolist -%unimacro _pad 3.nolist -%unimacro alignd 2-3+.nolist - - - -%if __NASM_VERSION_ID__ >= (2 * 100_0000h + 15 * 1_0000h) - %pragma preproc sane_empty_expansion true -%endif - - ; String prefixed and/or suffixed with sequence(s) - ; - ; %1 = prefix - ; %2 = suffix - ; %3+ = Optional string - %macro _ascii_prefix_suffix 2-3+.nolist - db %1 -%ifnempty %3 - db %3 -%endif - db %2 - %endmacro - -%idefine ascii _ascii_prefix_suffix "","", -%idefine asciz _ascii_prefix_suffix "",0, -%idefine ascic _ascii_prefix_suffix "",36, -%idefine asciiline _ascii_prefix_suffix "",{13,10}, -%idefine ascizline _ascii_prefix_suffix "",{13,10,0}, -%idefine ascicline _ascii_prefix_suffix "",{13,10,36}, - - ; Counted string - ; - ; %1 = data type of count - ; %2+ = optional string - %imacro _counted 2+.nolist -%push - %ifnempty %2 - _strlen %2 - %1 %$len - db %2 - %else - %1 0 - %endif -%pop - %endmacro - %idefine counted _counted db, - %idefine countedb _counted db, - %idefine countedw _counted dw, - - %imacro _strlen 1-*.nolist -%assign %$len 0 -%rep %0 - %ifstr %1 - %strlen %$addlen %1 - %assign %$len %$len+%$addlen - %elifnempty %1 - %assign %$len %$len+1 - %endif - %rotate 1 -%endrep - %endmacro - - - ; Define version information. - ; - ; %1 = Base name of single-line macros - ; %2 = Additional letter for base name of single-line macros - ; %3 = Major version - ; %4 = Minor version - ; - ; Created single-line macros: - ; %1_VER%2 = version word, high byte = major version - ; %1_VER%2_X = version word (bytes exchanged), high byte = minor version - ; %1_VER%2_MAJ = Major version number byte - ; %1_VER%2_MIN = Minor version number byte - ; %1_VER%2_STR = Up to 7 character version string (maximal "255.255") - %imacro verdef 4.nolist -%assign %1_VER%2_MAJ %3 -%assign %1_VER%2_MIN %4 -%assign %1_VER%2 ver(%3,%4) -%assign %1_VER%2_X verx(%3,%4) -%push - %defstr %$maj %3 - %defstr %$min %4 - %strlen %$length %$min - %if %$length < 2 - %strcat %$min '0', %$min ; one digit low numbers padded to two digits - %endif - %strcat %1_VER%2_STR %$maj, '.', %$min -%pop - %endmacro - - ; Define a numeric definition for conditional assembly - ; - ; Instead of: - ; %ifdef DEFINE - ; use: - ; %if _DEFINE - ; - ; %1 = Definition name. Will get an additional underscore prefix - ; %2 = Value to assign if not defined (defaults to 0) - ; %3 = Value to assign if defined, but empty (defaults to 1) - %imacro numdef 1-3.nolist 0,1 -%ifnum __DEFAULTED_%1 - %if __lMACROS1_MAC__DEFAULTING && __DEFAULTED_%1 - %undef _%1 ; cause defaulting to take effect again - %if __DEFAULTED_%1 == 2 ; defaulted to third parameter? - %define _%1 ; cause alternative defaulting to take effect again - %endif - %endif -%endif -%ifdef _%1 - %ifempty _%1 - %if __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED - %if __lMACROS1_MAC__SHOW_EXPLICIT_DEFAULT || __lMACROS1_MAC__SHOW_EXPLICIT - %defstr WARNINGMESSAGE %1 - %strcat WARNINGMESSAGE "define _",WARNINGMESSAGE," set empty explicitly" - %warning WARNINGMESSAGE - %endif - %endif - %assign _%1 %3 ; i.e. "-d_DEFINE" option on NASM's command line - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 2 ; note alternative defaulting occurred - %endif - %else - %if __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED - %if __lMACROS1_MAC__SHOW_EXPLICIT_VALUE || __lMACROS1_MAC__SHOW_EXPLICIT - %defstr WARNINGMESSAGE %1 - %strcat WARNINGMESSAGE "define _",WARNINGMESSAGE," set explicitly" - %warning WARNINGMESSAGE - %endif - %endif - %endif ; (if option was "-d_DEFINE=0", it's left as zero) - %if __lMACROS1_MAC__DEFAULTING - %ifnnum __DEFAULTED_%1 - %assign __DEFAULTED_%1 0 ; note no defaulting occurred - %endif - %endif -%else ; If not defined (no option on NASM's command line) - %assign _%1 %2 ; then assign to zero - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 1 ; note defaulting occurred - %endif -%endif - %endmacro - - - ; Define a generic definition for conditional assembly - ; - ; %1 = Definition name. Will get an additional underscore prefix - ; %2 = What to define as if not defined (defaults to empty) - ; %3 = What to define as if defined, but empty (defaults to empty) - %imacro gendef 1-3.nolist -%ifnum __DEFAULTED_%1 - %if __lMACROS1_MAC__DEFAULTING && __DEFAULTED_%1 - %undef _%1 ; cause defaulting to take effect again - %if __DEFAULTED_%1 == 2 ; defaulted to third parameter? - %define _%1 ; cause alternative defaulting to take effect again - %endif - %endif -%endif -%ifdef _%1 - %ifempty _%1 - %if __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED - %if __lMACROS1_MAC__SHOW_EXPLICIT_DEFAULT || __lMACROS1_MAC__SHOW_EXPLICIT - %defstr WARNINGMESSAGE %1 - %strcat WARNINGMESSAGE "define _",WARNINGMESSAGE," set empty explicitly" - %warning WARNINGMESSAGE - %endif - %endif - %define _%1 %3 ; i.e. "-d_DEFINE" option on NASM's command line - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 2 ; note alternative defaulting occurred - %endif - %else - %if __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED - %if __lMACROS1_MAC__SHOW_EXPLICIT_VALUE || __lMACROS1_MAC__SHOW_EXPLICIT - %defstr WARNINGMESSAGE %1 - %strcat WARNINGMESSAGE "define _",WARNINGMESSAGE," set explicitly" - %warning WARNINGMESSAGE - %endif - %endif - %endif ; (if option was "-d_DEFINE=0", it's left as zero) - %if __lMACROS1_MAC__DEFAULTING - %ifnnum __DEFAULTED_%1 - %assign __DEFAULTED_%1 0 ; note no defaulting occurred - %endif - %endif -%else ; If not defined (no option on NASM's command line) - %define _%1 %2 ; then define to default - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 1 ; note defaulting occurred - %endif -%endif - %endmacro - - -;; %macro __help_strdef_stringify 3+.nolist -;;%xdefine _%1 %2%3%2 -;; %endmacro - - ; Define a string definition - ; - ; %1 = Definition name. Will get an additional underscore prefix - ; %2 = Value to assign if not defined - ; %3 = Value to assign if defined, but no string (if not given, %2) - ; - ; Using braces { and } is useful for %2 and %3 - %imacro strdef 2-3.nolist -%ifnum __DEFAULTED_%1 - %if __lMACROS1_MAC__DEFAULTING && __DEFAULTED_%1 - %undef _%1 ; cause defaulting to take effect again - %if __DEFAULTED_%1 == 2 ; defaulted to third parameter? - %define _%1 ; cause alternative defaulting to take effect again - %endif - %endif -%endif -%ifdef _%1 - %ifempty _%1 - %if __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED - %if __lMACROS1_MAC__SHOW_EXPLICIT_DEFAULT || __lMACROS1_MAC__SHOW_EXPLICIT - %defstr WARNINGMESSAGE %1 - %strcat WARNINGMESSAGE "define _",WARNINGMESSAGE," set empty explicitly" - %warning WARNINGMESSAGE - %endif - %endif - %if %0 >= 3 - %define _%1 %3 ; i.e. "-d_DEFINE" option on NASM's command line - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 2 ; note alternative defaulting occurred - %endif - %else - %define _%1 %2 - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 1 ; note defaulting occurred - %endif - %endif - %else - %if __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED - %if __lMACROS1_MAC__SHOW_EXPLICIT_VALUE || __lMACROS1_MAC__SHOW_EXPLICIT - %defstr WARNINGMESSAGE %1 - %strcat WARNINGMESSAGE "define _",WARNINGMESSAGE," set explicitly" - %warning WARNINGMESSAGE - %endif - %endif - %ifnstr _%1 -; refer to http://stackoverflow.com/questions/15650276/nasm-convert-integer-to-string-using-preprocessor - %defstr _%1 _%1 -; %define %%quot " -; %define %%stringify(x) %%quot %+ x %+ %%quot -; %xdefine _%1 %%stringify(_%1) -;; __help_strdef_stringify %1, ", _%1 - ; issue: leading and trailing blanks are deleted out of the string. - ; workaround: quote the content so that it's a string already. - ; ie this may need nasm source.asm -D_"' content '" - %endif - %endif ; (if option was "-d_DEFINE='FOO'", it's left as 'FOO') -%else ; If not defined (no option on NASM's command line) - %define _%1 %2 ; - %if __lMACROS1_MAC__DEFAULTING - %assign __DEFAULTED_%1 1 ; note defaulting occurred - %endif -%endif - %endmacro - - ; Include definitions if a condition is met - ; - ; %1 = condition - ; %2-* = included definition name, without underscore prefix - %imacro incdef 2-*.nolist - %if %1 ; if true - %rep (%0 - 1) -%rotate 1 -%assign _%1 1 ; set any included to true - %endrep - %endif - %endmacro - - ; Exclude definitions if a condition is met - ; - ; %1 = condition - ; %2-* = excluded definition name, without underscore prefix - %imacro excdef 2-*.nolist - %if %1 ; if true - %rep (%0 - 1) -%rotate 1 -%assign _%1 0 ; set any excluded to false - %endrep - %endif - %endmacro - - %imacro overridedef 1-2.nolist 0 -%push OVERRIDE -%ifdef _%1 - %assign %$defined 1 -%else - %assign %$defined 0 -%endif -%xdefine %$prior _%1 -%xdefine %$defaulted __DEFAULTED_%1 -%define %$name %1 -%assign _%1 %2 -%assign __DEFAULTED_%1 0 - %endmacro - - %imacro resetdef 0-1.nolist -%ifnctx OVERRIDE - %error Wrong context -%endif -%if %0 - %ifnidn %1, %$name - %error Wrong usage of resetdef - %endif -%endif -%xdefine _%[%$name] %$prior -%xdefine __DEFAULTED_%[%$name] %$defaulted -%ifn %$defined - %undef _%[%$name] -%endif -%pop - %endmacro - - -%assign __lMACROS1_MAC__DEFAULTING 0 - %imacro defaulting 0-1.nolist 1 -%ifidni %1,toggle - %assign __lMACROS1_MAC__DEFAULTING !__lMACROS1_MAC__DEFAULTING -%else - %assign __lMACROS1_MAC__DEFAULTING !!(%1) -%endif - %endmacro - -%assign __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED 0 - numdef _lMACROS1_MAC__SHOW_EXPLICIT - numdef _lMACROS1_MAC__SHOW_EXPLICIT_DEFAULT - numdef _lMACROS1_MAC__SHOW_EXPLICIT_VALUE -%assign __lMACROS1_MAC__SHOW_EXPLICIT__INITIALISED 1 - - numdef _lMACROS1_MAC__CPU_DEFAULTS -%if __lMACROS1_MAC__CPU_DEFAULTS - numdef 186 ; 186 opcodes allowed - numdef 386 ; 386 opcodes allowed - incdef _386,186 ; excluding 186 opcodes on 386+ seems not useful -%endif - - numdef _lMACROS1_MAC__DEBUG_DEFAULTS -%if __lMACROS1_MAC__DEBUG_DEFAULTS - numdef DEBUG ; all of the debugging levels - incdef _DEBUG,DEBUG0,DEBUG1,DEBUG2,DEBUG3,DEBUG4 - numdef DEBUG0 ; 1st level debug - numdef DEBUG1 ; 2nd level debug - numdef DEBUG2 ; 3rd level debug - numdef DEBUG3 ; 4th level debug - numdef DEBUG4 ; 5th level debug - ; Note: All specific debug levels are independent. - ; What each debug level does is program-specific. -%endif - - - ; Automatically select CPU depending on definitions - ; - ; Use "hardwired" cpu directives instead in source files that - ; don't include code for multiple CPU generations. - %imacro selcpu 0.nolist -%if _386 - cpu 386 -%elif _186 - cpu 186 -%else - cpu 8086 -%endif - %endmacro - - ; Write a message stating what CPU type is required. - ; - ; %1 = Part of message before numerical CPU identifier (Defaults to "") - ; %2 = Part of message after numerical CPU identifier (Defaults to ASCIZ " CPU required") - ; - ; Using braces { and } is useful - ; - ; No data is generated if assembling for 8086 - %imacro cpufailmsg 0-2+.nolist "",{" CPU required",0} -%if _386 - db %1, "386", %2 -%elif _186 - db %1, "186", %2 -%endif - %endmacro - - ; Check if required CPU is available - ; - ; The code uses cx, ax and comparison flags. - ; - ; %1 = Code to execute if CPU requirement not meet - %imacro checkcpu 1.nolist -%if _386 -%%checkcpu: check386 -.fail: - %1 -.pass: -%elif _186 -%%checkcpu: check186 -.fail: - %1 -.pass: -%endif - %endmacro - - ; Check for 186+ CPU - ; - ; %1 = true if .fail follows (jump to .pass), - ; false if .pass follows (jump to .fail) - ; Default true - ; %2 = label to jump to if 186+ CPU - ; Default .pass - ; %3 = label to jump to if no 186+ CPU - ; Default .fail - %imacro check186 0-3 1 .pass .fail - mov cx, 1_0010_0001b ; Shift count's bit 0 and 5 are set; shift data is 1 - shl ch, cl ; 186+ limits shift count to five bits (0-4): resulting - ; ch is 10b on 186+; 0 on 8086 (actual result overflows) -%if %1 - jnz %2 ; 186+ --> -%else - jz %3 ; 8086 --> -%endif - %endmacro - - ; Check for 286+ CPU - ; - ; %1 = true if .fail follows (jump to .pass), - ; false if .pass follows (jump to .fail) - ; Default true - ; %2 = label to jump to if 286+ CPU - ; Default .pass - ; %3 = label to jump to if no 286+ CPU - ; Default .fail - - %imacro check286 0-3 1 .pass .fail - push sp - pop ax - cmp ax, sp ; 286+ pushes original sp value -%if %1 - je %2 ; 286+ --> -%else - jne %3 ; 8086 or 186 --> -%endif - %endmacro - - ; Check for 386+ CPU - ; - ; %1 = true if .fail follows (jump to .pass), - ; false if .pass follows (jump to .fail) - ; Default true - ; %2 = label to jump to if 386+ CPU - ; Default .pass - ; %3 = label to jump to if no 386+ CPU - ; Default .fail - %imacro check386 0-3 1 .pass .fail - check286 0, {%2}, {%3} ; branches to .fail if 8086 or 186 --> -[cpu 286] - pushf - push wo 0111_0000_0000_0000b - popf ; set bits 12-14 of FLAGS ("push imm16" instruction 186+) - pushf - pop ax ; get what was in FLAGS - popf ; restore original flags - test ax, 0111_0000_0000_0000b ; 386+ leaves what we pushed; 286 clears bits 12-14 in - ; Real Mode (Bits 12-14 are used in Protected Mode only) -__CPU__ -%if %1 - jnz %2 ; 386+ --> -%else - jz %3 ; 286 --> -%endif - %endmacro - - ; Instruction if specified level debug definition true - ; - ; %1 = Level of requested debug definition - ; %2 = Instruction - %imacro _d 2+.nolist -%if _DEBUG%1 - %2 -%endif - %endmacro - - ; Instruction if xth level debug definition true - ; - ; %1+ = Instruction -%idefine d0 _d 0, -%idefine d1 _d 1, -%idefine d2 _d 2, -%idefine d3 _d 3, -%idefine d4 _d 4, - - ; Breakpoint if xth level debug definition true -%idefine dbp _d, __DEBUG_BP__ -%idefine d0bp d0 __DEBUG0_BP__ -%idefine d1bp d1 __DEBUG1_BP__ -%idefine d2bp d2 __DEBUG2_BP__ -%idefine d3bp d3 __DEBUG3_BP__ -%idefine d4bp d4 __DEBUG4_BP__ -%idefine dd0bp _d,{d0bp} -%idefine dd1bp _d,{d1bp} -%idefine dd2bp _d,{d2bp} -%idefine dd3bp _d,{d3bp} -%idefine dd4bp _d,{d4bp} - - ; Breakpoint instructions for all debug levels - ; - ; "call ...", "int1", "int3" are useful single-instruction breakpoints -%define __DEBUG_BP__ int3 -%define __DEBUG0_BP__ int3 -%define __DEBUG1_BP__ int3 -%define __DEBUG2_BP__ int3 -%define __DEBUG3_BP__ int3 -%define __DEBUG4_BP__ int3 - - ; Print number if 1st level debug definition true - ; - ; %1 = Number to display (in range 0-255) - ; %2 = Override call for "call __DEBUG0_DISPALDEC__" - ; %3 = Override call for "call __DEBUG0_DISPAL__" - ; - ; The calls have to preserve all registers except ax. - %macro d0out 0-3.nolist -,call __DEBUG0_DISPALDEC__,call __DEBUG0_DISPAL__ -%if _DEBUG0 - push ax -%ifnidn %1,- - mov al, %1 - %2 -%endif - mov al, '.' - %3 - pop ax -%endif - %endmacro - - ; cpu macro replacement - ; - ; __CPU__ = like __SECT__ (that is, use [cpu ...] and switch back with __CPU__) - %imacro cpu 1+.nolist -%define __CPU__ [cpu %1] -__CPU__ - %endmacro - - ; Define size of area - ; - ; %1 = Starting label of area - ; %2 = if true, use already defined label %1_size (for - ; use with NASM's struc and endstruc); default is false - ; - ; Provided labels: %1_size (byte), %1_size_b (same), - ; %1_size_w (words), %1_size_d (dwords), %1_size_q - ; (qwords), %1_size_p (paragraphs), %1_size_pg (pages), - ; %1_size_ki (KiB). - %imacro endarea 1-2.nolist 0 -%ifn %2 -%1_size equ $ - %1 -%endif -%1_size_b equ %1_size -%1_size_w equ %1_size+1 >>1 -%1_size_d equ %1_size+3 >>2 -%1_size_q equ %1_size+7 >>3 -%1_size_p equ %1_size+15 >>4 -%1_size_pg equ %1_size+511 >>9 -%1_size_ki equ %1_size+1023 >>10 - %endmacro - - ; The following macros replace NASM's standard struc macros. - ; They add support for non-zero starting offsets of structures - ; (optional %2 of struc is starting offset) and creating endarea's - ; various size definitions with endstruc (if optional %1 of endstruc - ; is true). -%imacro struc 1-2.nolist 0 -%push -%define %$strucname %1 -[absolute %2] -%$strucname: -%endmacro -%imacro endstruc 0-1.nolist 0 -%if %1 -endarea %$strucname -%else -%{$strucname}_size equ ($-%$strucname) -%endif -%pop -__SECT__ -%endmacro - -%imacro istruc 1.nolist -%push -%define %$strucname %1 -%$strucstart: -%endmacro -%imacro at 1-2+.nolist - times (%1-%$strucname)-($-%$strucstart) db 0 - %2 -%endmacro -%imacro iend 0.nolist - times %{$strucname}_size-($-%$strucstart) db 0 -%pop -%endmacro - - - %imacro checkeven 1.nolist -%ifnnum %1 - %error Number expected -%endif -%if %1 & 1 - %error Even value expected -%endif - %endmacro - - ; Fill data to specified byte size (specify data) - ; - ; %1 = Byte size to fill - ; %2 = Fill byte (eg 0, 90h, 32) - ; %3 = Actual instruction to place before filling (optional) - %imacro fill 2-3+.nolist -%%data: - %3 ; Actual data if given, else expands to nothing - _fill %1,%2,%%data - %endmacro - - - ; Fill data to specified byte size (specify start label of data) - ; - ; %1 = Byte size to fill - ; %2 = Fill byte (eg 0, 90h, 32) - ; %3 = Start label of data - %imacro _fill 3.nolist -%if %1 < 0 ; hu? - %error _fill: size is negative -%elif $-(%3) < 0 ; should generate a phase error anyway. however - %error _fill: start label must not be behind filling -%elif (%1)-$+(%3) < 0 ; times would also throw an error then ("TIMES value x is negative") - %error _fill: data too large, exceeds size ; but showing a more specific message won't hurt -%endif - times (%1)-$+(%3) db %2 ; Fill with fill byte to given size - %endmacro - - - ; Pad data to specified byte boundary (specify data) - ; - ; Does _not_ pad relative to the section start but relative to the start of the data. Use - ; NASM's align (or alignd below) to pad (cough, cough... align) if you don't want that. - ; - ; %1 = Byte boundary - ; %2 = Pad byte (eg 0, 90h, 32) - ; %3 = Actual instruction to place before padding (optional, else macro creates nothing) - %imacro pad 2-3+.nolist -%%data: - %3 ; Actual data if given, else expands to nothing - _pad %1,%2,%%data - %endmacro - - - ; Pad data to specified byte boundary (specify start label of data) - ; - ; Does _not_ pad relative to the section start but relative to the start of the data. Use - ; NASM's align (or alignd below) to pad (cough, cough... align) if don't you want that. - ; - ; %1 = Byte boundary - ; %2 = Pad byte (eg 0, 90h, 32) - ; %3 = Start label of data (if it equals $, no padding is created) - %imacro _pad 3.nolist -%if %1 < 0 ; hu? - %error _pad: boundary is negative -%elifn %1 - %error _pad: boundary is zero -%elif $-%3 < 0 ; should generate a phase error anyway. however - %error _pad: start label must not be behind padding -%endif - -%push - %assign %$size $-%3 ; size of data - %assign %$count 0 - %rep %1 ; must be at the boundary then - %ifn (%$count + %$size) % %1 ; if ( !((paddedcount + size) modulo boundary) ) - %exitrep ; then { we're done } - %endif - %assign %$count %$count+1 ; else keep counting - %endrep - %if %$count >= %1 ; if loop end caused by %endrep - %error pad: an unknown error occured - %endif - times (%$count-1) db %2 ; put this data for the assembler. but in _one_ line -%pop - %endmacro - - - ; Similar to pad but using align: - ; - ; %1 = Byte boundary (relative from the section start) - ; %2 = Align byte (eg 0, 90h, 32) - ; %3 = Actual instruction to place before aligning (optional, else macro still aligns!) - %imacro alignd 2-3+.nolist - %3 -%if %1 < 0 ; hu? - %error alignd: boundary is negative -%elifn %1 - %error alignd: boundary is zero -%else - align %1,db %2 -%endif - %endmacro - - - ; Comment a line out - ; - ; Purpose: In front of instructions that are only to be created if - ; an expressions results in true, place a valid single-line - ; macro name. Then use the commentif (or commentifn) macro - ; below to create a single-line macro from an expression. - ; - ; This will use the macro "comment" so the instructions won't - ; assemble if the expression doesn't result in true. (Or - ; if the expression doesn't result in false, in case of - ; commentifn.) Else the single-line macro gets defined to - ; nothing causing the instructions to assemble. This "comment" - ; macro is required because you can't define a single-line - ; macro to the value of semicolon (";") with the preprocessor - ; for obvious reasons. (It will think a real comment starts - ; with the semicolon ;) - %imacro comment 0-*.nolist - %endmacro - - - ; Specify a single-line macro for above comment macro purpose - ; - ; %1 = expression (gets placed after %if) - ; %2 = single-line macro (gets underscore prefix) - %imacro commentif 2.nolist -%if %1 -%define _%2 comment ; define it to invoke comment -%else -%define _%2 ; define it to a zero string -%endif - %endmacro - - - ; Like commentif, but expression gets placed after %ifn - %imacro commentifn 2.nolist -%ifn %1 -%define _%2 comment ; define it to invoke comment -%else -%define _%2 ; define it to a zero string -%endif - %endmacro - - - ; Aborts assembling if found anywhere within source - %imacro fixme 0-1+.nolist -%error %1 - %endmacro - - - ; Comment a line out but make sure there are no parameters - %imacro noparam 0-1+.nolist -%if %0 - %error Must not have parameters. -%endif - %endmacro - - - ; Like noparam, except %1 is a message to display - %imacro noparamnamed 1-2+.nolist -%ifnempty %2 - %error %1: Must not have parameters. -%endif - %endmacro - - - ; Assign a single-line macro to an value if a condition matches, else zero - ; - ; %1 = expression (gets placed after %if) - ; %2 = single-line macro (gets underscore prefix) - ; %3 = value if condition matches - ; %4 = value if condition doesn't match (default: 0) - %imacro assignif 3-4.nolist 0 -%if %1 -%assign _%2 %3 -%else -%assign _%2 %4 -%endif - %endmacro - - - ; Like assignif, but expression gets placed after %ifn - %imacro assignifn 3-4.nolist 0 -%ifn %1 -%assign _%2 %3 -%else -%assign _%2 %4 -%endif - %endmacro - -%endif -[list +] diff --git a/test/lmacros/lmacros2.mac b/test/lmacros/lmacros2.mac deleted file mode 100644 index a6a6c836..00000000 --- a/test/lmacros/lmacros2.mac +++ /dev/null @@ -1,1263 +0,0 @@ -[list -] -%if 0 - -Extensions to NASM macro collection -Public Domain by C. Masloch, 2011-2012 -Intended for 86 Mode programs. - -%endif - -%ifndef __lMACROS2_MAC__ -%assign __lMACROS2_MAC__ 1 - -%include "lmacros1.mac" -[list -] - -%ifdef _186 - %ifnum _186 ; if appears like it is available: - numdef _lframe__use_186_def, 1 ; then default to use it - %endif -%endif - numdef _lframe__use_186_def ; use _186 to determine whether 186 available - numdef _lframe__force_186 ; regardless the above: assume 186 available - %assign __lframe__override_force_8086 0; regardless the above: temporarily stay 8086-compatible - - ; Initiate stack frame definition. - ; %1 Type of frame for parameter processing. - ; What this really means is only how large the return - ; address and other things between bp and the last - ; parameter are. - ; Default: none - ; Accepted: none, near (or 2), far (or 4), int (or 6), - ; positive even numbers - ; Notice: lret's auto %1 observes near/far/int here. - ; %2 Nesting type of frame. - ; Default: normal - ; Accepted: normal, nested, inner - ; - ; A nested frame pushes and sets bp anew. That means that - ; the labels of the outside frame are not usable. - ; An inner frame modifies sp but not bp. The outer frame's - ; variables may be accessed from within the inner frame. - ; A normal frame is neither a nested nor an inner frame. -%imacro lframe 0-2.nolist none,normal -%ifdef lsizeparameters - %undef lsizeparameters -%endif -%ifdef __lframe__autoret - %undef __lframe__autoret -%endif - -%ifidni %2, normal -%elifidni %2, nested -%elifidni %2, inner -%else - %fatal Invalid frame nesting type specified: %2 -%endif - -%ifctx LFRAME - %fatal Already inside lframe, must end previous with lenter -%elifctx LENTER - %ifidni %2, normal - %fatal Still inside lenter, must end previous with lleave - %endif -%elifctx LENTEREARLY - %ifidni %2, normal - %fatal Still inside lenter, must end previous with lleave - %endif -%endif -%ifnctx LENTER - %ifnidni %2, normal - %fatal Not inside lenter, cannot use nested or inner frame - %endif -%endif -%push LFRAME - -%assign %$bits __BITS__ -%if %$bits == 16 - %assign %$base_size 2 - %assign %$near_offset 2 - %assign %$far_offset 4 - %assign %$int_offset 6 -%elif %$bits == 32 - %assign %$base_size 4 - %assign %$near_offset 4 - %assign %$far_offset 8 - %assign %$int_offset 12 -%elif %$bits == 64 - %assign %$base_size 8 - %assign %$near_offset 8 - %assign %$far_offset 16 - %assign %$int_offset 24 -%else - %fatal Unknown BITS specified: %$bits -%endif - -%assign %$inner 0 -%ifidni %2, inner - %assign %$inner 1 -%endif -%assign %$nested 0 -%ifidni %2, nested - %assign %$nested 1 -%endif - -%define %$autoret -%ifidni %1,none -%elifidni %1,- -%elifidni %1,near - %define %$autoret near - %assign %$parofs %$near_offset -%elifidni %1,far - %define %$autoret far - %assign %$parofs %$far_offset -%elifidni %1,int - %define %$autoret int - %assign %$parofs %$int_offset -%elifnum %1 - %if %1 < 0 - %fatal Invalid frame type specified (negative): %1 - %endif - %if %1 & 1 - %fatal Invalid frame type specified (odd): %1 - %endif - %assign %$parofs %1 -%else - %fatal Invalid frame type specified: %1 -%endif -%ifdef %$parofs - %assign %$alignofs %$parofs + %$base_size -%endif -%assign %$pars_size 0 -%assign %$pars_return_size 0 -%define %$parlist -%define %$labellist empty,empty,empty -%assign %$ofs 0 -%assign %$enter 0 -%assign %$req 0 -%assign %$usereq 0 -%assign %$emit 1 - -%assign %$restore_frame_ofs 0 -%if %$inner - %assign %$ofs %$$ofs - %assign %$restore_frame_ofs %$$ofs -%endif -%assign %$pars_inner_size 0 -%endmacro - - ; Indicate that the stack frame set-up should not - ; actually write any code (is not required) if no - ; parameters or variables are registered. - ; Note that if no variables or parameters are - ; registered before lenter, and this is used, then it - ; is an error to register variables after lenter. - ; As a workaround, do not use this then, or additionally - ; use lframe_needotherwise (effectively overriding this). - ; - ; This must be placed before lenter. -%imacro lframe_needonlyregistered 0.nolist -%ifnctx LFRAME - %fatal Must use lframe first -%endif -%assign %$usereq 1 -%endmacro - - ; Indicate that the stack frame set-up is necessary, - ; even if no parameters or variables are registered. - ; - ; This must be placed before lenter. -%imacro lframe_needotherwise 0.nolist -%ifnctx LFRAME - %fatal Must use lframe first -%endif -%assign %$req 1 -%endmacro - -%macro __lvar_check_duplicate_label 3-*.nolist -%if %0 % 3 - %fatal Expected number of parameters that is a multiple of three -%endif -%rep (%0 / 3) - 1 - %ifidn %1, %$newlabel - %fatal Duplicate label: %1 - %endif - %rotate 3 -%endrep -%endmacro - -%macro __lvar_list_label 1.nolist -%define %$newlabel %1 -__lvar_check_duplicate_label %$labellist -%ifdef ?%1 - %xdefine %$labellist %1,defined,?%1,%$labellist -%else - %xdefine %$labellist %1,undefined,,%$labellist -%endif -%endmacro - -%macro __lvar_define_var 2.nolist -__lvar_list_label %1 -%assign ?%1 %2 -._%$lframe_?%1: equ %2 -%endmacro - - ; Define a stack frame variable. - ; %1 Type or size of variable. - ; Accepted: byte (1), word (2), dword (4), numeric - ; %2 Name of variable. A question mark is prepended. - ; - ; Variables registered before lenter are accounted for - ; in the code lenter generates, ie uninitialised space - ; is automatically allocated for them on the stack. - ; Variables registered after lenter are not automatically - ; allocated, you must manually either push data onto the - ; stack (possibly with desired initial values) or adjust - ; sp to allocate space for them on the stack. - ; Defining variables after "lleave code" is untested and - ; potentially has unexpected results. -%imacro lvar 2.nolist -%ifctx LENTER - %ifn %$enter - %fatal lenter did not set up stack frame - %endif -%elifctx LENTEREARLY -%elifnctx LFRAME - %fatal Must use lframe first -%endif -%ifidni %1,byte - %assign %$varsize 1 -%elifidni %1,word - %assign %$varsize 2 -%elifidni %1,dword - %assign %$varsize 4 -%elifidni %1,qword - %assign %$varsize 8 -%else - ; Previously we checked with %elifnum here that the parameter - ; is numeric. That turned out not to be what we want in - ; https://hg.pushbx.org/ecm/inicomp/file/dc376b09985e/exodecr.asm#l153 - ; In that case we used lequ as a workaround but it really - ; should be allowed directly as lvar size specification. - ; Therefore, we give the parameter to %assign and let it fail - ; in case the expression doesn't result in a scalar number. - %assign %$varsize %1 -%endif -%assign %$ofs %$ofs-%$varsize -__lvar_define_var %2, %$ofs -%assign %$req 1 -%assign %$hadvar 1 -%endmacro - - ; Define a stack frame parameter. - ; %1 Type or size of parameter. - ; Accepted: byte (1), word (2), dword (4), numeric - ; %2 Name of parameter. A question mark is prepended. - ; - ; Parameters must be registered before lenter, as lenter - ; contains the mechanism to automatically calculate the - ; final offsets. This is necessary to allow registering - ; parameters in the same order they have to be pushed - ; onto the stack by the caller. -%imacro lpar 2.nolist -%ifnctx LFRAME - %fatal Must use lframe first -%endif -%ifndef %$parofs - %fatal Specified no frame type with lframe -%endif -%ifdef %$hadvar - %fatal lpar must occur before any lvar - ; This is for lframe inner-type frames - ; which modify %$ofs in lpar. -%endif -%ifidni %1,byte - %assign %$varsize 1 -%elifidni %1,word - %assign %$varsize 2 -%elifidni %1,dword - %assign %$varsize 4 -%elifidni %1,qword - %assign %$varsize 8 -%elifnum %1 - %assign %$varsize %1 -%else - %fatal Invalid type specified: %1 -%endif -__lvar_list_label %2 -%assign %$pars_size %$pars_size+%$varsize -%ifempty %$parlist - %xdefine %$parlist %$varsize,%2 -%else - %xdefine %$parlist %$parlist,%$varsize,%2 -%endif -%assign %$req 1 -%if %$inner - %assign %$pars_inner_size %$pars_inner_size + %$varsize - %assign %$ofs %$ofs - %$varsize -%endif -%endmacro - - ; Note to return all prior defined stack frame parameters. - ; This simply subtracts the current length of parameters - ; from the length that is to be popped off the stack by lret. - ; - ; This is sort of a hack. May incorrectly handle cases of - ; byte (or otherwise odd-sized) parameters. -%imacro lpar_return 0.nolist -%ifnctx LFRAME - %fatal Must use lframe first -%endif -%ifndef %$parofs - %fatal Specified no frame type with lframe -%endif -%ifempty %$parlist - %fatal Specified no parameters with lpar -%endif -%ifn %$pars_size - %fatal Specified no parameters with lpar -%endif -%assign %$pars_return_size %$pars_size -%assign %$req 1 -%endmacro - - ; Define a stack frame equ. - ; %1 Numeric value to assign to this equ. - ; %2 Name of equ. A question mark is prepended. - ; - ; The equ's lifetime is the same as the frame's, just like - ; for lvar and lpar labels. (All are internally defines.) -%imacro lequ 2.nolist -%ifctx LENTER -%elifctx LENTEREARLY -%elifnctx LFRAME - %fatal Must use lframe first -%endif -__lvar_define_var %2, %1 -%endmacro - - ; Define an alignment variable. - ; %1 What boundary to align to. Default is 16. - ; %2 Space to add to align. Default is 0. - ; - ; It is assumed that the call instruction that - ; called the current function had the stack - ; aligned to at least the same boundary. - ; The second parameter specifies the size of - ; any parameters that we want to push before - ; doing a call next. The alignment is chosen - ; so that the call instruction will get the - ; aligned stack. - ; Sets %$alignment to the size of the variable - ; defined for aligning, 0 if none. If not 0, - ; the variable ?align_X_Y is defined where X - ; is a decimal number indicating the size of - ; all prior variables plus r/e/bp on stack - ; plus the size set for the frame type, and - ; Y is the decimal number of the %2 parameter. - ; This can only be used if the lframe had a - ; frame type other than "none". - ; If a variable is defined then lreserve or - ; another space reservation method must be - ; used to actually allocate space for the - ; created variable and thus align the stack. -%imacro lalign 0-2.nolist 16, 0 -%ifctx LENTER -%elifctx LENTEREARLY -%elifnctx LFRAME - %fatal Must use lframe first -%endif -%ifndef %$parofs - %fatal Specified no frame type with lframe -%endif -%assign %$alignbase %$alignofs - %$ofs -%assign %$alignadjust %2 -%assign %$alignment (%1 - ((%$alignbase + %$alignadjust) % %1)) % %1 -%if %$alignment - lvar %$alignment, align_ %+ %$alignbase %+ _ %+ %$alignadjust -%endif -%endmacro - - ; Create a defined stack frame. - ; This sets up bp and reserves stack space for all defined - ; variables. It also defines the labels for parameters. - ; If no variables or parameters were registered until now, - ; and lframe_needonlyregistered has been used (without - ; overriding it by using lframe_needotherwise), then it is - ; assumed that no more variables will be registered after - ; this and that the stack frame is unnecessary. It will - ; thus not be created. lenter and lleave will consequently - ; not create any code. - ; Defines %$lsizeparameters to be the even number of bytes - ; all parameters take up, and %$lsizevariables to be the - ; even number of bytes all variables take up. - ; The code created by this does not change any flags, as it - ; uses either (one or two) "push ax" or "lea sp, [bp - x]" - ; or "enter x, 0" to reserve the stack space. - ; - ; "lenter early" can be used to write only the initial - ; "push bp" \ "mov bp, sp" sequence. Then variables are - ; defined with lvar as usual. However, these variables - ; can *optionally* be initialised by pushing into them - ; (similarly to lvar variables defined after lenter). - ; Finally, a "lenter" acts as the default lenter does, - ; and reserves stack space for all yet defined lvar - ; variables. This is always done using "lea sp, [bp - x]" - ; so it doesn't matter how many of the variables were - ; already initialised by pushing into them. -%imacro lenter 0-1.nolist -%ifctx LENTEREARLY -%elifnctx LFRAME - %fatal Must use lframe first -%endif -%ifidni %1,early - %ifctx LENTEREARLY - %fatal Cannot use lenter early twice - %endif - %repl LENTEREARLY - %assign %$req 1 - %assign %$early 1 - %assign %$wasearly 0 -%elifempty %1 - %assign %$wasearly 0 - %ifctx LENTEREARLY - %assign %$wasearly 1 - %endif - %assign %$early 0 - %repl LENTER -%else - %fatal Invalid parameter: %1 -%endif -%assign %$lsizevariables (-%$ofs+1 - (- %$restore_frame_ofs) - %$pars_inner_size )&~1 -%ifn %$usereq - %assign %$req 1 -%endif -%assign %$enter_emitted 0 -%if %$req - %assign %$enter 1 - %assign %$186 0 - %if %$early || %$wasearly - %elif __lframe__override_force_8086 - %elif __lframe__force_186 - %assign %$186 1 - %elif __lframe__use_186_def - %assign %$186 _186 - %endif - %if %$186 && %$ofs && (! %$inner) && %$emit - enter %$lsizevariables, 0 - %assign %$enter_emitted 1 - %endif -%ifnidn %$bits,__BITS__ - %fatal BITS of lframe (%$bits) differs from current: __BITS__ -%endif -%if %$bits == 16 -%ifn %$inner -%ifn %$wasearly - __lvar_define_var frame_bp, 0 - %ifidni %$autoret, near - __lvar_define_var frame_ip, 2 - %elifidni %$autoret, far - __lvar_define_var frame_ip, 2 - __lvar_define_var frame_cs, 4 - %elifidni %$autoret, int - __lvar_define_var frame_ip, 2 - __lvar_define_var frame_cs, 4 - __lvar_define_var frame_fl, 6 - %endif -%endif -%endif - %if %$emit - %ifn %$enter_emitted - %ifn %$inner - %ifn %$wasearly - push bp - mov bp, sp - %endif - %endif - %ifn %$early - %if %$ofs - %if %$wasearly == 0 && (%$lsizevariables) == 0 - %elif %$wasearly == 0 && (%$lsizevariables) == 2 - push ax - %elif %$wasearly == 0 && (%$lsizevariables) == 4 - push ax - push ax - %else - lea sp, [bp + %$restore_frame_ofs - (%$lsizevariables + %$pars_inner_size)] - %endif - %endif - %endif - %endif - %endif -%elif %$bits == 32 -%ifn %$inner -%ifn %$wasearly - __lvar_define_var frame_ebp, 0 - %ifidni %$autoret, near - __lvar_define_var frame_eip, 4 - %elifidni %$autoret, far - __lvar_define_var frame_eip, 4 - __lvar_define_var frame_cs, 8 - %elifidni %$autoret, int - __lvar_define_var frame_eip, 4 - __lvar_define_var frame_cs, 8 - __lvar_define_var frame_efl, 12 - %endif -%endif -%endif - %if %$emit - %ifn %$enter_emitted - %ifn %$inner - %ifn %$wasearly - push ebp - mov ebp, esp - %endif - %endif - %ifn %$early - %if %$ofs - %if %$wasearly == 0 && (%$lsizevariables) == 0 - %elif %$wasearly == 0 && (%$lsizevariables) == 2 - push ax - %elif %$wasearly == 0 && (%$lsizevariables) == 4 - push eax - %elif %$wasearly == 0 && (%$lsizevariables) == 8 - push eax - push eax - %else - lea esp, [ebp + %$restore_frame_ofs - (%$lsizevariables + %$pars_inner_size)] - %endif - %endif - %endif - %endif - %endif -%elif %$bits == 64 -%ifn %$inner -%ifn %$wasearly - __lvar_define_var frame_rbp, 0 - %ifidni %$autoret, near - __lvar_define_var frame_rip, 8 - %elifidni %$autoret, far - __lvar_define_var frame_rip, 8 - __lvar_define_var frame_cs, 16 - %elifidni %$autoret, int - __lvar_define_var frame_rip, 8 - __lvar_define_var frame_cs, 16 - __lvar_define_var frame_rfl, 24 - %endif -%endif -%endif - %if %$emit - %ifn %$enter_emitted - %ifn %$inner - %ifn %$wasearly - push rbp - mov rbp, rsp - %endif - %endif - %ifn %$early - %if %$ofs - %if %$wasearly == 0 && (%$lsizevariables) == 0 - %elif %$wasearly == 0 && (%$lsizevariables) == 2 - push ax - %elif %$wasearly == 0 && (%$lsizevariables) == 8 - push rax - %else - lea rsp, [rbp + %$restore_frame_ofs - (%$lsizevariables + %$pars_inner_size)] - %endif - %endif - %endif - %endif - %endif -%else - %fatal Unknown BITS specified: %$bits -%endif -%ifn %$wasearly - ._%$lenter: -%endif -%endif -%ifn %$wasearly - %assign %$lsizeparameters (%$pars_size+1)&~1 - __lenter_parse_parlist %$parlist -%endif -%endmacro - -%macro __lenter_parse_parlist 0-*.nolist -%if %0 & 1 - %fatal Expected even number of macro parameters! -%endif -%rep %0 >> 1 -%assign %$pars_size %$pars_size - %1 -%if %$inner -%assign ?%2 (%$pars_size + %$parofs + %$restore_frame_ofs - %$pars_inner_size) -._%$lframe_?%2: equ (%$pars_size + %$parofs + %$restore_frame_ofs - %$pars_inner_size) -%else -%assign ?%2 (%$pars_size + %$parofs + %$base_size) -._%$lframe_?%2: equ (%$pars_size + %$parofs + %$base_size) -%endif -%rotate 2 -%endrep -%endmacro - - ; Reserve stack space for prior lvar variables. - ; - ; This is used after lenter and reserves the stack space - ; for all yet defined variables, including those defined - ; after the lenter usage (which aren't reserved space for - ; by lenter itself). - ; - ; "lenter early \ lvar a \ lenter \ lvar b" is equivalent - ; to "lenter \ lvar a \ lreserve \ lvar b". - ; - ; lreserve can be used multiple times. It always uses - ; "lea sp, [bp - x]" to reserve space, so the space will - ; always be equal to the already defined variables. - ; - ; Warning: Using lreserve after having pushed additional - ; data, beyond the defined variables, will discard that - ; data from the stack as sp is reset. -%imacro lreserve 0.nolist -%ifnctx LENTER - %fatal Must use lenter first -%endif -%ifn %$enter - %fatal lenter did not set up stack frame -%endif -%assign %$lsizevariables (-%$ofs+1)&~1 -%ifnidn %$bits,__BITS__ - %fatal BITS of lframe (%$bits) differs from current: __BITS__ -%endif -%if %$emit -%if %$bits == 16 - %if %$ofs - lea sp, [bp - %$lsizevariables] - %endif -%elif %$bits == 32 - %if %$ofs - lea esp, [ebp - %$lsizevariables] - %endif -%elif %$bits == 64 - %if %$ofs - lea rsp, [rbp - %$lsizevariables] - %endif -%else - %fatal Unknown BITS specified: %$bits -%endif -%endif -%endmacro - - -%imacro ldup 0.nolist -%ifnctx LENTER - %fatal Must use lenter first -%endif -%ifn %$nested - %fatal ldup only valid in nested frame in normal frame -%endif -%if %$$inner - %fatal ldup only valid in nested frame in normal frame -%endif -%if %$enter != %$$enter - %fatal Failed ldup (enter) -%endif -%ifnempty %$autoret - %ifnidn %$autoret, %$$autoret - %fatal Failed ldup (autoret) - %endif -%else - %ifnempty %$$autoret - %fatal Failed ldup (autoret one empty) - %endif -%endif -%if %$parofs != %$$parofs - %fatal Failed ldup (parofs) -%endif -%if %$bits != %$$bits - %fatal Failed ldup (bits) -%endif -%if %$pars_return_size != %$$pars_return_size - %fatal Failed ldup (pars_return_size) -%endif -__ldup_count newparlist, %$parlist -__ldup_count oldparlist, %$$parlist -%if %$count_newparlist != %$count_oldparlist - %fatal Failed ldup (count_*parlist) -%endif -__ldup_check_parlist %$$parlist -__ldup_count newlabellist, %$labellist -__ldup_count oldlabellist, %$$labellist -%if %$count_newlabellist != %$count_oldlabellist - %fatal Failed ldup (count_*labellist) -%endif -__ldup_check_labellist %$$labellist -%endmacro - -%macro __ldup_count 1-*.nolist -%assign %$count_%[%1] %0 - 1 -%endmacro - -%macro __ldup_check_parlist 0-*.nolist -%assign %$ii 0 -%rep %0 - %define %$check %1 - __ldup_check_single %$ii + 1,%$parlist - %assign %$ii %$ii + 1 - %rotate 1 -%endrep -%endmacro - -%macro __ldup_check_labellist 3-*.nolist -%assign %$ii 0 -%rep (%0 / 3) - 1 - %define %$check %1 - __ldup_check_single %$ii + 1,%$labellist - %xdefine %$check ?%1 - __ldup_check_single %$ii + 1 + 2,%$labellist - %assign %$ii %$ii + 3 - %rotate 3 -%endrep -%endmacro - -%macro __ldup_check_single 1-*.nolist -%rotate %1 -%ifnidn %1, %$check - ; The following is a workaround for older versions of NASM. - ; Refer to https://bugzilla.nasm.us/show_bug.cgi?id=3392628 - %ifnnum %1 - %fatal Failed ldup (check single: 1 1=%1 check=%$check) - %elifnnum %$check - %fatal Failed ldup (check single: 2 1=%1 check=%$check) - %elifn %1 == %$check - %fatal Failed ldup (check single: 3 1=%1 check=%$check) - %endif -%endif -%endmacro - - -%imacro lemit 0-1.nolist on -%ifctx LENTER -%elifctx LENTEREARLY -%elifnctx LFRAME - %fatal Must use lframe first -%endif -%ifidni %1,on - %assign %$emit 1 -%elifidni %1,off - %assign %$emit 0 -%else - %assign %$emit !! %1 -%endif -%endmacro - - -%imacro lifemit 1+.nolist -%ifctx LENTER -%elifctx LENTEREARLY -%elifnctx LFRAME - %fatal Must use lframe first -%endif -%if %$emit - %1 -%endif -%endmacro - - - ; Remove a created stack frame. - ; This restores bp if it was altered to access variables or - ; parameters. It also restores sp from bp if sp was altered - ; to allocate space to variables. - ; The code created by this does not change any flags, as it - ; uses only "mov sp, bp" and "pop bp", or "leave". - ; This undefines all labels that were defined for variables - ; and parameters in this stack frame, to prevent accidental - ; usage of these labels later. - ; lsizeparameters is defined as the (even) number of bytes - ; that all parameters use on the stack. (This is zero if no - ; parameters have been registered.) - ; No return instruction is written by this macro; you may use - ; lret or place the appropriate instruction(s) manually. - ; If none of lframe_needonlyregistered,needotherwise have - ; been used, and no variables or parameters at all have been - ; registered (regardless whether before or after lenter), - ; then this will stop with an error. - ; %1 Specifies whether to write the stack frame removal - ; code or to remove the macros' context. This allows - ; writing the code multiple times. - ; Default: code+ctx - ; Accepted: code+ctx (or ), code, ctx - ; %2 Specifies whether to always restore sp. - ; Default: optimiserestoresp - ; Accepted: optimiserestoresp (or ), forcerestoresp -%imacro lleave 0-2.nolist -%ifnctx LENTER - %fatal Must use lenter first -%endif -%ifidni %1,code -%elifidni %1,ctx -%elifidni %1,code+ctx -%elifempty %1 -%else - %fatal Invalid parameter specified: %1 -%endif -%ifidni %2,forcerestoresp -%elifidni %2,optimizerestoresp -%elifidni %2,optimiserestoresp -%elifempty %2 -%else - %fatal Invalid second parameter specified: %2 -%endif - %ifnidni %1,ctx -%ifn %$inner -%if %$enter - %ifn %$req - %fatal lframe apparently unnecessary - ; Note that to fix this, you either have to remove - ; the lframe usage altogether, or employ one of those: - ; * lframe_needonlyregistered - ; * lframe_needotherwise - ; See the descriptions of those. - %endif - %assign %$186 0 - %if __lframe__override_force_8086 - %elif __lframe__force_186 - %assign %$186 1 - %elif __lframe__use_186_def - %assign %$186 _186 - %endif - %ifn %$ofs - %ifnidni %2,forcerestoresp - %assign %$186 0 - %endif - %endif -%if %$emit - %if %$186 - leave - %else -%ifnidn %$bits,__BITS__ - %fatal BITS of lframe (%$bits) differs from current: __BITS__ -%endif -%if %$bits == 16 - %if %$ofs - mov sp, bp - %elifidni %2,forcerestoresp - mov sp, bp - %endif - pop bp -%elif %$bits == 32 - %if %$ofs - mov esp, ebp - %elifidni %2,forcerestoresp - mov esp, ebp - %endif - pop ebp -%elif %$bits == 64 - %if %$ofs - mov rsp, rbp - %elifidni %2,forcerestoresp - mov rsp, rbp - %endif - pop rbp -%else - %fatal Unknown BITS specified: %$bits -%endif - %endif -%endif -%else - %if %$ofs - %fatal No stack frame was created - %elifidni %2,forcerestoresp - %fatal No stack frame was created - %endif -%endif -%endif -%if %$inner -%ifnidn %$bits,__BITS__ - %fatal BITS of lframe (%$bits) differs from current: __BITS__ -%endif -%if %$emit -%if %$bits == 16 - lea sp, [bp + %$restore_frame_ofs - %$pars_return_size] -%elif %$bits == 32 - lea esp, [ebp + %$restore_frame_ofs - %$pars_return_size] -%elif %$bits == 64 - lea rsp, [rbp + %$restore_frame_ofs - %$pars_return_size] -%else - %fatal Unknown BITS specified: %$bits -%endif -%endif -%endif - %else -%ifnempty %2 - %fatal Invalid to specify second parameter -%endif - %endif -%ifdef %$parofs - %assign lsizeparameters %$lsizeparameters - %$pars_return_size -%endif -%xdefine __lframe__autoret %$autoret - %ifnidni %1,code -._%$lleave: -__lleave_undefine_labels %$labellist -%pop - %endif -%endmacro - -%macro __lleave_undefine_labels 3-*.nolist -%if %0 % 3 - %fatal Expected number of parameters that is a multiple of three -%endif -%rep (%0 / 3) - 1 - %ifidn %2, undefined - %undef ?%1 - %elifidn %2, defined - %define ?%1 %3 - %else - %fatal Expected parameter to be 'defined' or 'undefined' but is %2 - %endif - %rotate 3 -%endrep -%endmacro - - ; Place matching return instruction. - ; This uses lsizeparameters, if it has been set by - ; lleave, as the size of all parameters on the - ; caller's stack frame. - ; This generally must be used after using lleave. - ; This may be used any number of times. - ; %1 Specifies type of return. - ; Default: auto - ; Accepted: auto, near, far, int - ; Notice: auto will use lframe's %1 only if it was - ; one of near, far, int. Otherwise, auto - ; (including the default) is an error! - ; %2 Specifies an adjustment to remove either more - ; or less than all the registered parameters - ; from the caller's stack frame. - ; Default: 0 - ; Accepted: even numbers, including negatives. - ; Must be at least -lsizeparameters! - ; Notice: The sum of lsizeparameters and %2 - ; must be 0 for type int (ie iret). - ; - ; Note: As this is usually used after the lframe's - ; context is already popped, the lemit - ; setting does not affect this macro. -%imacro lret 0-2.nolist auto,0 -%ifctx LFRAME - %fatal Must use lenter first -%elifctx LENTEREARLY - %fatal Must use lenter first -%endif -; Do not check specifically for ctx LENTER here! -; Usually, lleave already popped the ctx. -%push - %define %$type %1 - %ifidni %$type,- - %define %$type auto - %endif - %ifempty %$type - %define %$type auto - %endif - %ifidni %$type,auto - %ifdef __lframe__autoret - %ifnempty __lframe__autoret - %define %$type __lframe__autoret - %endif - %endif - %endif - %ifidni %$type,near - %define %$inst retn - %elifidni %$type,far - %define %$inst retf - %elifidni %$type,int - %define %$inst iret - %else - %fatal Invalid type specified: %1 - %endif - %if %2 & 1 - %fatal Invalid adjustment %2, is odd - %endif - %assign %$remov %2 - %ifnum lsizeparameters - %assign %$remov %$remov+lsizeparameters - %endif - %if %$remov < 0 - %fatal Invalid adjustment %2, sum is negative - %endif - %ifn %$remov - %define %$remov - %endif - %$inst %$remov -%pop -%endmacro - - - -%unimacro @@ 1+.nolist -%unimacro @@ 0-1+.nolist - - ; Core macro implementing anonymous local labels that behave - ; similarly to (but not exactly the same way as) MS MASM's. - ; It shifts @FFFF..@BBBB by one and then invents a new label - ; name for @FFFF. The invented names contain incrementing - ; numbers to insure they are unique, and all start with ..@ - ; to avoid interfering with NASM's named local labels. - ; - ; Provided (cap-insensitive) smacros: - ; @FFFF (or @F4) Forward reference to fourth @@ - ; @FFF (or @F3) Forward reference to third @@ - ; @FF (or @F2) Forward reference to second @@ - ; @F (or @F1) Forward reference to next @@ - ; @B (or @B1) Backward reference to previous @@ - ; @BB (or @B2) Backward reference to second @@ - ; @BBB (or @B3) Backward reference to third @@ - ; @BBBB (or @B4) Backward reference to fourth @@ - ; (It is recommended to seldom use anything but @F and @B.) - ; Internally used (cap-sensitive) smacro: - ; __@@_seq Incremented by @S, initialised to 0 - ; by including this file. This gives - ; the first number of invented names. - ; __@@_num Incremented by @@, initialised to 4 - ; by including this file as well as - ; by @S. This gives the second number - ; of invented names. (Note that the - ; current value is always what @@ - ; will invent for the new @FFFF; thus - ; eg the current @F refers to a name - ; that was invented with the current - ; value less four. Consequently the - ; first @@ defines a label whose name - ; contains a 0 as the second number.) - ; Invented names, full form: - ; ..@.@@.%[__@@_seq].%[__@@_num] - ; eg ..@.@@.0.0, ..@.@@.0.1, etc; ..@.@@.1.0, etc - ; - ; Note that as NASM has no procedure concept, the @@ labels - ; of logically distinct code sequences aren't automatically - ; reset, that is an @F near the end of one code sequence - ; whose intended target @@ erroneously wasn't placed will - ; jump to the next placed @@ after the code sequence. - ; To work around that, manually place @S (start sequence for - ; @@ labels) between logically distinct code sequences. For - ; more strict checks, put @I (invalidate @@ references) - ; whereever a logically distinct code sequence ends, and - ; @S whereever a logically distinct code sequence begins. - ; (This disallows any @@ references outside such marked - ; code sequences.) - - ; This - ; will cause all erroneous @@ forward references in front - ; of it and all erroneous @@ backward references behind it - ; to refer to undefined labels. - ; The former will have a (regular) positive second number in - ; the referenced label name, while the latter will have a - ; (special) negative second number -4..-1 in the referenced - ; label name. The line on which the error occurs is the - ; line with the erroneous reference. - %macro __@@_next 0-1.nolist 1 -%if _@@_check && ! __@@_in_seq - %if _@@_check == 1 - %warning "not in a sequence" - %else - %error "not in a sequence" - %endif -%endif - %rep %1 -%ixdefine @BBBB @BBB -%ixdefine @BBB @BB -%ixdefine @BB @B -%ixdefine @B @F -%ixdefine @F @FF -%ixdefine @FF @FFF -%ixdefine @FFF @FFFF -%idefine @FFFF ..@.@@.%[__@@_seq].%[__@@_num] -%ixdefine @B4 @BBBB -%ixdefine @B3 @BBB -%ixdefine @B2 @BB -%ixdefine @B1 @B -%ixdefine @F1 @F -%ixdefine @F2 @FF -%ixdefine @F3 @FFF -%ixdefine @F4 @FFFF - -%assign __@@_num __@@_num+1 - %endrep - %endmacro - - ; This macro defines an anonymous local label (optionally - ; writing any kind of code afterwards) - ; then it calls the above macro to shift the pre-invented - ; names and invent a new one for @FFFF. - ; Note that smacros inside following code if any are - ; expanded by NASM's preprocessor before processing mmacros - ; hence "@@: jmp @F" is equivalent to "@@: jmp $". - ; (If correct label missing colon warning behaviour wasn't - ; wanted, then the implementation could be simpler. Hmm.) - %macro @@ 0.nolist -@F -__@@_next - %endmacro - ; "@@", label alone on line missing colon warning. - %macro @@ 1+.nolist -%ifidn %1,: -@F %+ : -__@@_next -%else - %push - %defstr %$str %1 - %substr %$colon %$str 1 - %ifidn %$colon,':' - %substr %$str %$str 2,-1 - %deftok %$str %$str -@F %+ : -__@@_next -%$str - %else -@F times 0 nop -__@@_next -%1 - %endif - %pop -%endif - %endmacro - ; "@@ :", (trivial) no label-missing-colon warnings. - ; "@@ nop", label missing colon warning; the "times 0 nop" - ; part is necessary so that this warning isn't 'promoted' - ; to the label alone on line missing colon warning. - ; "@@ : nop", no label-missing-colon warnings. - ; Not handled like actual label: following "instruction" is - ; allowed to be a directive, another label, or even an - ; mmacro usage like @@ itself. Hmmm... allows eg "@@: @@:" - ; to define two @@ labels at once. May be useful. - - numdef @@_check, 0 ; 0 = none, 1 = warn, else = error - numdef @@_start, 1 ; 0 = omit @S, else = do @S - - ; Only invalidate outstanding @@ forward references. - %imacro @FI 0.nolist -%assign __@@_num_inv __@@_num_inv+1 -%idefine @FFFF ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%assign __@@_num_inv __@@_num_inv+1 -%idefine @FFF ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%assign __@@_num_inv __@@_num_inv+1 -%idefine @FF ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%assign __@@_num_inv __@@_num_inv+1 -%idefine @F ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%ixdefine @F4 @FFFF -%ixdefine @F3 @FFF -%ixdefine @F2 @FF -%ixdefine @F1 @F - %endmacro - - ; Only invalidate @@ backward references. - %imacro @BI 0.nolist -%assign __@@_num_inv __@@_num_inv+1 -%idefine @B ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%assign __@@_num_inv __@@_num_inv+1 -%idefine @BB ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%assign __@@_num_inv __@@_num_inv+1 -%idefine @BBB ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%assign __@@_num_inv __@@_num_inv+1 -%idefine @BBBB ..@.@@.%[__@@_seq].inv.%[__@@_num_inv] -%ixdefine @B4 @BBBB -%ixdefine @B3 @BBB -%ixdefine @B2 @BB -%ixdefine @B1 @B - %endmacro - - ; Invalidate all references. - ; The sequence flag is reset, unless non-zero %1 is given. - %imacro @I 0-1.nolist 0 -%if __@@_in_seq && %1 - %assign __@@_in_seq 1 -%else - %assign __@@_in_seq 0 -%endif -@FI -@BI - %endmacro - - ; Invalidate outstanding @@ forward references (by causing - ; them to ultimately refer to undefined labels) then invent - ; four new names for @BBBB..@B that are invalid (ie would - ; ultimately refer to undefined labels) then invent four - ; new names for @F..@FFFF that can be defined by @@. - ; Note that __@@_next successfully passes along whatever - ; @F..@FFFF are initialised to when this macro is used; - ; even if they aren't initialised at all (in that case - ; their names are passed along!). No error conditions are - ; caused there, and all of these passed names are discarded - ; by @BI. - ; As __@@_num is initialised to -4, at the end of this - ; macro's processing the @@ backward references @BBBB..@B - ; refer to names ending in -4..-1 (which are to be left - ; undefined) and the @@ forward references @F..@FFFF refer - ; to ..@.@@.%[__@@_seq].0..3 (which can be defined by @@). - %imacro @S 0-1.nolist _@@_check -%if %1 && __@@_in_seq - %if %1 == 1 - %warning "already in a sequence" - %else - %error "already in a sequence" - %endif -%endif - -%assign __@@_seq __@@_seq+1 -%assign __@@_num 0 -%assign __@@_num_inv 0 -%assign __@@_in_seq 1 - -__@@_next 4 -@BI - %endmacro - -%ifnnum __@@_in_seq - %assign __@@_in_seq 0 -%endif -%ifnnum __@@_seq - %assign __@@_seq 0 - %assign __@@_num 0 - %assign __@@_num_inv 0 -%endif -%ifnnum __@@_num - %assign __@@_num 0 -%endif -%ifnnum __@@_num_inv - %assign __@@_num_inv 0 -%endif -%if _@@_start - @S -%endif - - - %imacro checklframeend 0 -%ifctx LFRAME - %fatal Still inside lframe! -%elifctx LENTER - %fatal Still inside lenter! -%elifctx LENTEREARLY - %fatal Still inside lenter! -%endif - %endmacro - - - %imacro _struc_at 2-3+.nolist -%if %1 - %if (%2 - ($ - %$strucname)) != 0 - %if %1 == 1 - %error Not at that offset! - %else - %warning Not at that offset! - %endif - %endif -%endif - resb %2 - ($ - %$strucname) -%3 - %endmacro - -%idefine struc_at _struc_at 0, -%idefine exact_struc_at _struc_at 1, -%idefine warn_struc_at _struc_at 2, - - -%endif -[list +] diff --git a/test/lmacros/lmacros3.mac b/test/lmacros/lmacros3.mac deleted file mode 100644 index be1174e6..00000000 --- a/test/lmacros/lmacros3.mac +++ /dev/null @@ -1,139 +0,0 @@ -[list -] -%if 0 - -Extensions to NASM macro collection -Public Domain by C. Masloch, 2019 -Intended for 86 Mode programs. - -%endif - -%ifndef __lMACROS3_MAC__ -%assign __lMACROS3_MAC__ 1 - -%include "lmacros2.mac" -[list -] - - - ; This macro is used to generate byte or word access to specific - ; bits of a dword variable. - ; %1 = token: if "~", bit value will be negated after checking - ; %2 = instruction - ; %3 = variable, in the form "[address]" without size specification - ; %4 = bit value(s) to access - ; %5 = bool: disable word access warning, defaults to 0 - ; If the value in %4 has bits set in different bytes so that - ; a single 8- or 16-bit instruction cannot access all the bits, - ; an error is displayed. This insures that the macro only has - ; to generate one instruction, as a 32-bit access on 16-bit - ; CPUs requires multiple instructions. This workaround code - ; needs to be written specifically then, or the flags have to - ; be re-ordered to allow the access. -%macro _opt 4-5.nolist 0 -%push -%defstr %$adr %3 -%strlen %$len %$adr -%substr %$tf %$adr 1 -%substr %$tb %$adr %$len -%substr %$adr %$adr 2,-2 -%deftok %$adr %$adr -%%num: equ %4 -%assign %$num %%num -%ifnidn %$tf,"[" - %error Invalid memory access syntax -%elifnidn %$tb,"]" - %error Invalid memory access syntax -%elifn %$num - %error Bit value is zero! Check code. -%elifn (%$num) & ~0FFh - %2 byte [%$adr], %1(%$num) -%elifn (%$num) & ~0FF00h - %2 byte [%$adr+1], %1((%$num)>>8) -%elifn (%$num) & ~0FF0000h - %2 byte [%$adr+2], %1((%$num)>>16) -%elifn (%$num) & ~0FF000000h - %2 byte [%$adr+3], %1((%$num)>>24) -%elifn (%$num) & ~0FFFFh - %ifn %5 - %warning Macro generated word access - %endif - %2 word [%$adr], %1(%$num) -%elifn (%$num) & ~0FFFF00h - %ifn %5 - %warning Macro generated word access - %endif - %2 word [%$adr+1], %1((%$num)>>8) -%elifn (%$num) & ~0FFFF0000h - %ifn %5 - %warning Macro generated word access - %endif - %2 word [%$adr+2], %1((%$num)>>16) -%else - %error Unsupported macro usage, requires dword: - %ifempty %1 - %error %2 dword [%$adr], %$num - %else - %error %2 dword [%$adr], %1(%$num) - %endif -%endif -%pop -%endmacro - - ; User forms for above macro. - ; %1 = variable, in the form "[address]" without size specification - ; %2 = bit value(s) to access - ; %3 = bool: disable word access warning, defaults to 0 - ; testopt tests the specified bits (using a "test" instruction) and - ; leaves a meaningful result in ZF, as well as NC. - ; clropt clears the specified bits (using an "and" instruction with - ; the negated value) and leaves NC, but a random ZF. - ; setopt sets the specified bits (using an "or" instruction) and - ; leaves NC, NZ. - ; xoropt toggles the specified bits (using a "xor" instruction) and - ; leaves NC, but a random ZF. -%idefine testopt _opt ,test, -%idefine clropt _opt ~,and, -%idefine setopt _opt ,or, -%idefine xoropt _opt ,xor, - - - %imacro addsection 1-2.nolist -%ifdef _SECTION_ADDED_%1 - %error Section %1 already added -%endif - section %1 %2 -%define _SECTION_ADDED_%1 1 - usesection %1 - %endmacro - - %imacro usesection 1-2.nolist 0 -%ifndef _SECTION_ADDED_%1 - %error Section %1 not yet added -%endif -%if %2 -%define _CURRENT_SECTION - [section %1] -%else -%xdefine _CURRENT_SECTION %1 - section %1 -%endif - %endmacro - - - %macro subcpu 1.nolist -%push SUBCPU -%xdefine %$CPU_PREV __CPU__ - cpu %1 - %endmacro - - %macro subcpureset 0.nolist -%ifnctx SUBCPU - %error Wrong context -%endif -%xdefine __CPU__ %$CPU_PREV -%pop -__CPU__ - %endmacro - - -%endif -[list +] diff --git a/test/lmacros/tests/000.asm b/test/lmacros/tests/000.asm deleted file mode 100644 index 9b74e6a2..00000000 --- a/test/lmacros/tests/000.asm +++ /dev/null @@ -1,68 +0,0 @@ - -%assign _@@_check 2 -%assign _@@_start 0 -%include "lmacros2.mac" - -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: @S - jmp @F - nop - nop -@@: - -;%fatal 1>@F1< 2>@F2< 3>@F3< 4>@F4< - jz @F - nop - nop -@@: - - jnz @F - nop - nop -@@: - - call @F - nop -@@: - -exit: - mov ax, 4C00h - int 21h - align 16 - -second: @S 0 - jmp @F - nop - nop -@@: - -;%fatal 1>@F1< 2>@F2< 3>@F3< 4>@F4< - jz @F - nop - nop -@@: - - jnz @F - nop - nop -@@: - - call @F - nop -@@: - jmp exit - align 16 - - jmp @B - jmp @BB - jmp @B3 - jmp @B4 - diff --git a/test/lmacros/tests/001.asm b/test/lmacros/tests/001.asm deleted file mode 100644 index 147b3022..00000000 --- a/test/lmacros/tests/001.asm +++ /dev/null @@ -1,32 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun1 - - mov ax, 4C00h - int 21h -%endif - -fun1: - lframe near - lvar word, foo - lvar word, bar - lenter - lvar word, quux - push ax - - lleave - lret diff --git a/test/lmacros/tests/002.asm b/test/lmacros/tests/002.asm deleted file mode 100644 index 68a3039e..00000000 --- a/test/lmacros/tests/002.asm +++ /dev/null @@ -1,37 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - push ax - call fun2 - - mov ax, 4C00h - int 21h -%endif - -fun2: - lframe near - lpar word, alpha - lvar word, foo - lvar word, bar - lenter - lvar word, quux - push ax - - mov word [bp + ?foo], 0F00h - mov dx, word [bp + ?alpha] - - lleave - lret diff --git a/test/lmacros/tests/003.asm b/test/lmacros/tests/003.asm deleted file mode 100644 index 2ecc7ad9..00000000 --- a/test/lmacros/tests/003.asm +++ /dev/null @@ -1,40 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - push bx - push cx - call fun3 - pop bx - - mov ax, 4C00h - int 21h -%endif - -fun3: - lframe near - lpar word, beta - lpar_return - lpar word, alpha - lvar word, foo - lvar word, bar - lenter - lvar word, quux - push ax - - mov word [bp + ?beta], 0BE7Ah - - lleave - lret diff --git a/test/lmacros/tests/004.asm b/test/lmacros/tests/004.asm deleted file mode 100644 index b7fbf8df..00000000 --- a/test/lmacros/tests/004.asm +++ /dev/null @@ -1,34 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun4 - - mov ax, 4C00h - int 21h -%endif - -fun4: - lframe near - lenter early - lvar word, foo - push bx - lvar word, bar - lenter - lvar word, quux - push ax - - lleave - lret diff --git a/test/lmacros/tests/005.asm b/test/lmacros/tests/005.asm deleted file mode 100644 index 1888f0aa..00000000 --- a/test/lmacros/tests/005.asm +++ /dev/null @@ -1,34 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun5 - - mov ax, 4C00h - int 21h -%endif - -fun5: - lframe near - lenter - lvar word, foo - push bx - lvar word, bar - lreserve - lvar word, quux - push ax - - lleave - lret diff --git a/test/lmacros/tests/006.asm b/test/lmacros/tests/006.asm deleted file mode 100644 index c3fc5628..00000000 --- a/test/lmacros/tests/006.asm +++ /dev/null @@ -1,43 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun6 - - mov ax, 4C00h - int 21h -%endif - -fun6: - lframe near - lvar word, foo - lvar word, bar - lenter - - mov word [bp + ?foo], ax - - lframe 0, nested - lvar word, qux - lvar word, foo - lenter - - mov word [bp + ?foo], bx - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/007.asm b/test/lmacros/tests/007.asm deleted file mode 100644 index 63b23274..00000000 --- a/test/lmacros/tests/007.asm +++ /dev/null @@ -1,44 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun7 - - mov ax, 4C00h - int 21h -%endif - -fun7: - lframe near - lvar word, foo - lvar word, bar - lenter - - mov word [bp + ?foo], ax - - lframe 0, inner - lvar word, qux - lvar word, foo - lenter - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/008.asm b/test/lmacros/tests/008.asm deleted file mode 100644 index a0c181f7..00000000 --- a/test/lmacros/tests/008.asm +++ /dev/null @@ -1,51 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun8 - - mov ax, 4C00h - int 21h -%endif - -fun8: - lframe near - lvar word, foo - lvar word, bar - lenter - - mov word [bp + ?foo], ax - - push cs - push si - - lframe 0, inner - lpar word, segment - lpar word, offset - lvar word, qux - lvar word, foo - lenter - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?segment] - mov dx, word [bp + ?offset] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/009.asm b/test/lmacros/tests/009.asm deleted file mode 100644 index 1c6fc857..00000000 --- a/test/lmacros/tests/009.asm +++ /dev/null @@ -1,52 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun9 - - mov ax, 4C00h - int 21h -%endif - -fun9: - lframe near - lvar word, foo - lvar word, bar - lenter - - mov word [bp + ?foo], ax - - push cs - push si - - lframe 0, inner - lpar word, segment - lpar word, offset - lvar word, qux - lvar word, foo - lvar word, xyzzy - lenter - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?segment] - mov dx, word [bp + ?offset] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/010.asm b/test/lmacros/tests/010.asm deleted file mode 100644 index be873e14..00000000 --- a/test/lmacros/tests/010.asm +++ /dev/null @@ -1,49 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun10 - - mov ax, 4C00h - int 21h -%endif - -fun10: - lframe near - lvar word, foo - lvar word, bar - lenter - - mov word [bp + ?foo], ax - - push cs - push si - - lframe 0, inner - lpar word, segment - lpar word, offset - lenter - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?segment] - mov dx, word [bp + ?offset] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/011.asm b/test/lmacros/tests/011.asm deleted file mode 100644 index 90fa57ef..00000000 --- a/test/lmacros/tests/011.asm +++ /dev/null @@ -1,50 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun11 - - mov ax, 4C00h - int 21h -%endif - -fun11: - lframe near - lvar word, foo - lvar word, bar - lenter - - mov word [bp + ?foo], ax - - push cs - push si - - lframe 0, inner - lpar word, segment - lpar_return - lpar word, offset - lenter - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?segment] - mov dx, word [bp + ?offset] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/012.asm b/test/lmacros/tests/012.asm deleted file mode 100644 index 165712dc..00000000 --- a/test/lmacros/tests/012.asm +++ /dev/null @@ -1,48 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun12 - - mov ax, 4C00h - int 21h -%endif - -fun12: - lframe near - lvar word, foo - lvar word, bar - lenter - lvar word, baz - push bx - - mov word [bp + ?foo], ax - - lframe 0, inner - lvar word, quux - lvar word, foo - lenter - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?quux] - mov dx, word [bp + ?baz] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/013.asm b/test/lmacros/tests/013.asm deleted file mode 100644 index fa7a584a..00000000 --- a/test/lmacros/tests/013.asm +++ /dev/null @@ -1,49 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun13 - - mov ax, 4C00h - int 21h -%endif - -fun13: - lframe near - lvar word, foo - lvar word, bar - lenter - lvar word, baz - push bx - - mov word [bp + ?foo], ax - - lframe 0, inner - lenter - lvar word, quux - lvar word, foo - lreserve - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?quux] - mov dx, word [bp + ?baz] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/014.asm b/test/lmacros/tests/014.asm deleted file mode 100644 index f7d32e6e..00000000 --- a/test/lmacros/tests/014.asm +++ /dev/null @@ -1,56 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun14 - - mov ax, 4C00h - int 21h -%endif - -fun14: - lframe near - lvar word, foo - lvar word, bar - lenter - lvar word, baz - push bx - - mov word [bp + ?foo], ax - - push cs - push si - lframe 0, inner - lpar word, alpha - lpar word, beta - lpar_return - lenter - lvar word, quux - lvar word, foo - lreserve - - mov word [bp + ?foo], bx - mov ax, word [bp + ?bar] - mov bx, word [bp + ?quux] - mov dx, word [bp + ?baz] - mov si, word [bp + ?beta] - inc word [bp + ?alpha] - - lleave - - mov ax, word [bp + ?foo] - - lleave - lret diff --git a/test/lmacros/tests/015.asm b/test/lmacros/tests/015.asm deleted file mode 100644 index 2b2ba140..00000000 --- a/test/lmacros/tests/015.asm +++ /dev/null @@ -1,70 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - push ax - call fun15 - - mov ax, 4C00h - int 21h -%endif - -fun15: -.1: - lframe near - lpar word, alpha - lvar word, foo - lvar word, bar - lenter - lvar word, baz - push bx - jmp .common - -.2: -%ifdef FAIL3 -bits 32 -%endif -%ifdef FAIL4 - lframe far, nested -%else - lframe near, nested -%endif - lpar word, alpha -%ifdef FAIL2 - lpar_return -%endif - lvar word, foo -%ifdef FAIL5 - lvar word, foobar -%else - lvar word, bar -%endif -%ifdef FAIL1 - lvar word, quux -%endif - lenter - lvar word, baz - push bx - - ldup - - lleave ctx - -.common: - mov dx, word [bp + ?alpha] - mov word [bp + ?foo], ax - - lleave - lret diff --git a/test/lmacros/tests/016.asm b/test/lmacros/tests/016.asm deleted file mode 100644 index bdcb6fff..00000000 --- a/test/lmacros/tests/016.asm +++ /dev/null @@ -1,64 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - xor ax, ax - push ax - call fun16 - mov ax, 1 - push bx - call fun16 - - mov ax, 4C00h - int 21h -%endif - -fun16: - mov bx, 0B3B3h - mov dx, 0D3D3h - lframe near - lpar word, alpha - lvar word, foo - lvar word, bar - lenter - test ax, ax - jnz .handler2 - -.handler1: - lvar word, quux - push cx - mov dx, word [bp + ?alpha] - mov word [bp + ?foo], ax - add ax, word [bp + ?quux] - - lleave - lret - -.handler2: - lframe near - lemit off - lpar word, alpha - lvar word, foo - lvar word, bar - lenter - lemit - lvar word, baz - push dx - - mov bx, word [bp + ?alpha] - mov word [bp + ?foo], ax - - lleave - lret diff --git a/test/lmacros/tests/017.asm b/test/lmacros/tests/017.asm deleted file mode 100644 index e83081ed..00000000 --- a/test/lmacros/tests/017.asm +++ /dev/null @@ -1,60 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - mov cx, 1234h - xor ax, ax - push ax - call fun17 - - mov ax, 4C00h - int 21h -%endif - -fun17: - lframe near - lpar word, alpha - lvar word, foo - lvar word, bar - lenter ; push bp \ mov bp, sp \ push ax \ push ax - - lvar word, quux - push cx ; push cx - lvar word, baz - lvar dword, xyzzy - lreserve ; lea sp, [bp - 0Ch] - mov dx, word [bp + ?alpha] - ; [bp + 4] - mov word [bp + ?foo], ax - ; [bp - 2] - add ax, word [bp + ?quux] - ; [bp - 6] - mov word [bp + ?xyzzy], dx - ; [bp - 0Ch] - - lframe 0, inner - lvar word, e - lvar word, f - lvar word, g - lenter ; lea sp, [bp - 12h] - lvar word, h - push ax ; push ax - lvar dword, i - lreserve ; lea sp, [bp - 18h] - - lleave ; lea sp, [bp - 0Ch] - - lleave ; mov sp, bp \ pop bp - lret ; retn 2 diff --git a/test/lmacros/tests/018.asm b/test/lmacros/tests/018.asm deleted file mode 100644 index df281c7b..00000000 --- a/test/lmacros/tests/018.asm +++ /dev/null @@ -1,36 +0,0 @@ - -%include "lmacros2.mac" - - numdef STANDALONE, 1 - -%if _STANDALONE -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun18 - - mov ax, 4C00h - int 21h -%endif - -fun18: - lframe near - lequ 16 * 3, 16tablesize - lvar ?16tablesize, firsttable - lvar fromparas(paras(26)), secondtable - lenter ; push bp \ mov bp, sp \ lea sp, [bp - 50h] - - lea si, [bp + ?firsttable] - ; lea si, [bp - 30h] - lea di, [bp + ?secondtable] - ; lea di, [bp - 50h] - - lleave ; mov sp, bp \ pop bp - lret ; retn diff --git a/test/lmacros/tests/019.asm b/test/lmacros/tests/019.asm deleted file mode 100644 index 536ac0e4..00000000 --- a/test/lmacros/tests/019.asm +++ /dev/null @@ -1,26 +0,0 @@ -%define _@@_check -%assign _@@_start 0 -%include "lmacros2.mac" - -@S - nop -@@: - nop - jmp @F - nop - nop - jmp @B - -@@: - nop - nop -@I - - nop - nop -@S -@@: - nop - nop - jmp @B -@I diff --git a/test/lmacros/tests/test.sh b/test/lmacros/tests/test.sh deleted file mode 100755 index 55418ca7..00000000 --- a/test/lmacros/tests/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#! /bin/bash - -echo -ne "" > "$1.lst" -[ -z "$NASM" ] && NASM=nasm -"$NASM" "$1.asm" -D_MAP="$1.map" -l "$1.lst" -f bin -o "$@" -I ../ -cat "$1.lst" -ndisasm "$1" - diff --git a/test/lmacros/tests/test2.asm b/test/lmacros/tests/test2.asm deleted file mode 100644 index 06be0e9c..00000000 --- a/test/lmacros/tests/test2.asm +++ /dev/null @@ -1,51 +0,0 @@ - -%include "lmacros2.mac" - -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 256 - sectalign off - section lCode start=256 align=1 - -start: - call fun1 - push ax - call fun2 - push bx - push cx - call fun3 - pop bx - call fun4 - call fun5 - call fun6 - call fun7 - call fun8 - call fun9 - call fun10 - call fun11 - call fun12 - call fun13 - call fun14 - - mov ax, 4C00h - int 21h - - overridedef STANDALONE, 0 -%include "001.asm" -%include "002.asm" -%include "003.asm" -%include "004.asm" -%include "005.asm" -%include "006.asm" -%include "007.asm" -%include "008.asm" -%include "009.asm" -%include "010.asm" -%include "011.asm" -%include "012.asm" -%include "013.asm" -%include "014.asm" - resetdef diff --git a/test/lmacros/tests/testalig.asm b/test/lmacros/tests/testalig.asm deleted file mode 100644 index fd3f697e..00000000 --- a/test/lmacros/tests/testalig.asm +++ /dev/null @@ -1,88 +0,0 @@ - -%include "lmacros2.mac" - -%ifdef _MAP -[map symbols brief _MAP] -%endif - - cpu 8086 - org 100h -start: - and sp, ~15 - call fun - mov word [first], ax - - sub sp, 16 - 4 - mov cx, 3 - mov dx, 4 - push cx - push dx - call fun2 - pop ax - - mov word [fifth], ax - - mov ax, 4C00h - int 21h - -fun: - lframe near - lenter - lvar word, foo - lalign 16 -%ifn %$alignment - %error Should need alignment -%endif -%if %$alignment != 10 - %error Should need 10-byte alignment -%endif - lreserve - lalign 16 -%if %$alignment - %error Should not need alignment -%endif - lalign 8 -%if %$alignment - %error Should not need alignment -%endif - mov ax, 1 - test sp, 15 - jz @F - neg ax -@@: - lleave - lret - - -fun2: - lframe near - lpar word, gamma - lpar_return - lpar word, delta - lenter - mov ax, [bp + ?gamma] - mov word [third], ax - mov ax, [bp + ?delta] - mov word [fourth], ax - mov word [bp + ?gamma], 5 - - lalign 16 -%ifn %$alignment - %error Should need alignment -%endif -%if %$alignment != 12 - %error Should need 12-byte alignment -%endif - lreserve - call fun - mov word [second], ax - - lleave - lret - - align 256 -first: dw 0 -second: dw 0 -third: dw 0 -fourth: dw 0 -fifth: dw 0 diff --git a/test/lmacros/tests/testmap.sh b/test/lmacros/tests/testmap.sh deleted file mode 100755 index 487abe59..00000000 --- a/test/lmacros/tests/testmap.sh +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/bash - -echo -ne "" > "$1.lst" -[ -z "$NASM" ] && NASM=nasm -"$NASM" "$1.asm" -D_MAP="$1.map" -l "$1.lst" -f bin -o "$@" -I ../ -cat "$1.lst" -cat "$1.map" diff --git a/test/lmacros/tests/testpar.asm b/test/lmacros/tests/testpar.asm deleted file mode 100644 index 08c3ae7c..00000000 --- a/test/lmacros/tests/testpar.asm +++ /dev/null @@ -1,58 +0,0 @@ - -%include "lmacros2.mac" - - cpu 8086 - org 100h -start: - mov ax, 1 - mov bx, 2 - push ax - push bx - call fun - - mov cx, 3 - mov dx, 4 - push cx - push dx - call fun2 - pop ax - - mov word [fifth], ax - - mov ax, 4C00h - int 21h - -fun: - lframe near - lpar word, alpha - lpar word, beta - lenter - mov ax, [bp + ?alpha] - mov word [first], ax - mov ax, [bp + ?beta] - mov word [second], ax - lleave - lret - - -fun2: - lframe near - lpar word, gamma - lpar_return - lpar word, delta - lenter - mov ax, [bp + ?gamma] - mov word [third], ax - mov ax, [bp + ?delta] - mov word [fourth], ax - mov word [bp + ?gamma], 5 - lleave - lret - - align 256 -first: dw 0 -second: dw 0 -third: dw 0 -fourth: dw 0 -fifth: dw 0 - diff --git a/test/lmacros/tests/testsat.asm b/test/lmacros/tests/testsat.asm deleted file mode 100644 index d11bf73f..00000000 --- a/test/lmacros/tests/testsat.asm +++ /dev/null @@ -1,18 +0,0 @@ -%include "lmacros2.mac" - - [map all testsat.map] - cpu 8086 - org 0 - -struc TESTSTRUC - resb 1 -struc_at 1, at_1: resb 3 -struc_at 4, at_4: - resw 1 -exact_struc_at 6 -at_6: resb 1 -struc_at 32 -at_32: resb 10 -warn_struc_at 64 -at_64: resb 1 -endstruc diff --git a/test/test.asm b/test/test.asm deleted file mode 100644 index e0ff7b4d..00000000 --- a/test/test.asm +++ /dev/null @@ -1,164 +0,0 @@ - -%if 0 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - -%include "lmacros3.mac" - - cpu 8086 - org 256 -start: - mov ah, 3Ch - xor cx, cx - mov dx, filename - int 21h - mov dx, msg.creating - jc error.nofile - xchg bx, ax - mov ah, 40h - mov dx, buffer - mov cx, buffer.size - int 21h - mov dx, msg.writing - jc error - cmp ax, cx - mov dx, msg.full - jne error - mov ah, 3Eh - int 21h - xor ax, ax - jmp quit - -error: - mov ah, 3Eh - int 21h -.nofile: - push ax - mov ah, 09h - int 21h - pop ax - call disp_ax_hex - mov al, 13 - call disp_al - mov al, 10 - call disp_al - mov ax, -1 - jmp quit - - - ; INP: al = character to display - ; CHG: - - ; STT: ds, es don't care -disp_al: - push ax - push dx - xchg ax, dx - mov ah, 02h - int 21h - pop dx - pop ax - retn - - - ; Display number in ax hexadecimal, always 4 digits - ; - ; INP: ax = number - ; OUT: displayed using disp_al - ; CHG: none -disp_ax_hex: - xchg al, ah - call disp_al_hex - xchg al, ah -disp_al_hex: - push cx - mov cl, 4 - rol al, cl - call disp_al_nybble_hex - rol al, cl - pop cx -disp_al_nybble_hex: - push ax - and al, 0Fh - add al, '0' - cmp al, '9' - jbe @F - add al, -'9' -1 +'A' -@@: - call disp_al - pop ax - retn - - -%if 0 - -Shut down machine - by C. Masloch, 2020 - -Usage of the works is permitted provided that this -instrument is retained with the works, so that any entity -that uses the works is notified of this instrument. - -DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -%endif - - - cpu 8086 - ; org 256 -quit: - int3 - - mov ax, 0F000h - mov es, ax - mov di, 0FFF5h - mov si, msg.dosemudate - mov cx, 4 - repe cmpsw ; running in DosEmu? - jne .quit_not_dosemu - - xor bx, bx - mov ax, -1 - int 0E6h ; dosemu quit - -.quit_not_dosemu: - -; from https://stackoverflow.com/a/5240330/738287 - mov ax, 5301h - xor bx, bx - int 15h ; connect to APM API - - mov ax, 530Eh - xor bx, bx - mov cx, 0102h - int 15h ; set APM version to 1.02 - - mov ax, 5307h - mov bx, 1 - mov cx, 3 - int 15h ; shut down system - - mov dx, msg.failed - mov ah, 09h - int 21h - mov ax, 4C00h - int 21h - - - align 4 -msg: -.dosemudate: db "02/25/93" -.failed: db "Quit failed.",13,10,36 -.creating: ascic "Creating failed, code=" -.writing: ascic "Writing failed, code=" -.full: ascic "Writing failed, full. AX=" -filename: - asciz "result.txt" -buffer: -.: db "success" -.size: equ $ - . diff --git a/test/test.sh b/test/test.sh deleted file mode 100755 index 507b570c..00000000 --- a/test/test.sh +++ /dev/null @@ -1,154 +0,0 @@ -#! /bin/bash - -# Usage of the works is permitted provided that this -# instrument is retained with the works, so that any entity -# that uses the works is notified of this instrument. -# -# DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. - -if [[ "$1" != selfcall ]] -then - setsid -w "$0" selfcall "$@" - exit $? -fi -shift - -. cfg.sh - -if [ -n "$LMACROS_DIR" ]; then { - options_i_lmacros=-I"${LMACROS_DIR%/}"/ -} fi - -if [ -n "$LDOSBOOT_DIR" ]; then { - options_i_ldosboot=-I"${LDOSBOOT_DIR%/}"/ -} fi - -if [ -n "$SCANPTAB_DIR" ]; then { - options_i_scanptab=-I"${SCANPTAB_DIR%/}"/ -} fi - -if [ -n "$BOOTIMG_DIR" ]; then { - options_i_bootimg=-I"${BOOTIMG_DIR%/}"/ -} fi - -if [ -n "$LDEBUG_DIR" ]; then { - options_i_ldebug=-I"${LDEBUG_DIR%/}"/ -} fi - -if [ -n "$LDOSMBR_DIR" ]; then { - options_i_ldosmbr=-I"${LDOSMBR_DIR%/}"/ -} fi - -if [ -n "$INSTSECT_DIR" ]; then { - options_i_instsect=-I"${INSTSECT_DIR%/}"/ -} fi - -direct=1 -bpe=12 -spc=1 -spi=2880 -nr=224 -pitype="" - -machine="qemu" -qemu=1 - - options_hdimage="" - options_mcopy_offset="" - diskette=1 - qemu_switch="-fda" - unit=00h - direct=1 - if [[ -z "$pitype" ]] - then - if [[ "$bpe" == 16 ]] - then - pitype=ptFAT16 - else - pitype=ptFAT12 - fi - fi - -echo -ne 'shell=test.com\r\n' > fdconfig.sys -echo -ne 'failure\r\n' > result.txt -if [[ -z "$1" || -z "$2" || -z "$3" ]] -then - echo Error, missing parameters. 1=KERNELPATHNAME, 2=DISKETTE, 3=BOOT - exit 1 -fi -KERNELPATHNAME="$1" -DISKETTE="$2" -BOOT="$3" -testrunname="$4" -shift -shift -shift -shift - -"$NASM" "test.asm" \ - "$options_i_lmacros" \ - -o test.com && -"$NASM" "${LDOSBOOT_DIR%/}"/boot.asm -w-user \ - "$options_i_lmacros" \ - -D_COMPAT_FREEDOS=1 \ - -D_LBA=0 -D_USE_PART_INFO=0 -D_QUERY_GEOMETRY=0 \ - -D_MAP=boot.map \ - -D_FAT$bpe -D_UNIT=$unit \ - "$@" \ - -l "$BOOT".lst \ - -o "$BOOT".bin && -"$NASM" "${BOOTIMG_DIR%/}"/bootimg.asm \ - -I ./ \ - "$options_i_bootimg" \ - "$options_i_lmacros" \ - -D_PAYLOADFILE="::rename,'$KERNELPATHNAME',KERNEL.SYS,fdconfig.sys,test.com,result.txt" \ - -D_BOOTPATCHFILE="'$BOOT.bin'" \ - -D_WARN_DEFAULT_OFF=1 \ - -D_WARN_TOOMANYFAT=0 -D_WARN_ALIGNDATA=0 \ - $options_hdimage -D_MBR_PART_TYPE="$pitype" \ - -D_BPE="$bpe" -D_SPC="$spc" -D_SPI="$spi" \ - -D_SPF="$(( (spi / spc * bpe / 8 + 511) / 512 ))" \ - -D_NUMROOT="$nr" \ - -o "$DISKETTE".img -l "$DISKETTE".lst \ - -D_UNIT=$unit \ - "$@" -(($?)) && exit $? - -pgid="$(ps -o pgid= $$)" -function handle_timeout_process() { - stty sane 2> /dev/null > /dev/null - # The stty sane command in the CI environment shows: - # - # 'standard input': Inappropriate ioctl for device - # - # It is probably safe to ignore. - ((debug)) && ps -e -o pgid=,comm=,pid= | grep -E "^\s*$pgid " - pidlist="$(ps -e -o pgid=,comm=,pid= | - grep -E "^\s*$pgid " | - grep -Ev " (bash|test.sh|ps|grep) ")" - pidlist="$(echo "$pidlist" | - sed -re 's/^\s+//g' | - tr -s " " | cut -d" " -f 3)" - if [[ -n "$pidlist" ]] - then - ((debug)) && ps $pidlist - kill $pidlist - fi -} -timeout --foreground 10 "$QEMU" "$qemu_switch" "$DISKETTE".img -display none 2> /dev/null - -rc=$? -handle_timeout_process -if ((rc == 124)) -then - echo "${testrunname}timeout" - exit 124 -fi -if [[ "$(mtype -t -i $DISKETTE.img$options_mcopy_offset ::RESULT.TXT 2> /dev/null)" == success ]] -then - echo "${testrunname}success" - exit 0 -else - echo "${testrunname}failure" - exit 1 -fi diff --git a/tests/absread/absread.c b/tests/absread/absread.c deleted file mode 100644 index ec9ef0ee..00000000 --- a/tests/absread/absread.c +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include - -typedef unsigned long uint32_t; -typedef unsigned short uint16_t; -typedef unsigned char uint8_t; - -void die(char *msg) -{ - printf("%s\n", msg); - exit(1); -} - -/* Both traditional DOS and FAT32 DOS return this structure, but - FAT32 return a lot more data, so make sure we have plenty of space */ -struct deviceparams { - uint8_t specfunc; - uint8_t devtype; - uint16_t devattr; - uint16_t cylinders; - uint8_t mediatype; - uint16_t bytespersec; - uint8_t secperclust; - uint16_t ressectors; - uint8_t fats; - uint16_t rootdirents; - uint16_t sectors; - uint8_t media; - uint16_t fatsecs; - uint16_t secpertrack; - uint16_t heads; - uint32_t hiddensecs; - uint32_t hugesectors; - uint8_t lotsofpadding[224]; -}; - -void get_partition_offset(int drive) -{ - static struct deviceparams dp; - int err=0; - - printf("Getting drive info: int21h function 440Dh subfunction 0860h\n"); - - dp.specfunc = 1; /* Get current information */ - - __asm { - mov ax, 0x440d - mov bx, drive - mov cx, 0x0860 - mov dx, offset dp - int 0x21 - mov ax, 0 - adc ax, 0 - mov err, ax - } - - if (!err) - { - printf("Partition Offset = %02lXh [c=%02u,h=%02u,s=%2u]\n", dp.hiddensecs, dp.cylinders, dp.heads, dp.secpertrack); - printf("FAT32 version 4860h to compare\n"); - } - else - printf("Original version failed, checking FAT32 version using 4860h\n"); - - __asm { - mov ax, 0x440d - mov bx, drive - mov cx, 0x4860 - mov dx, offset dp - int 0x21 - mov ax, 0 - adc ax, 0 - mov err, ax - } - - if (!err) - { - printf("Partition Offset = %02lXh\n", dp.hiddensecs); - return; - } - else - printf("FAT32 version failed.\n"); -} - -struct rwblock { - uint8_t special; - uint16_t head; - uint16_t cylinder; - uint16_t firstsector; - uint16_t sectors; - uint16_t bufferoffset; - uint16_t bufferseg; -}; - -static struct rwblock mbr = { - .special = 0, - .head = 0, - .cylinder = 0, /* 5265, 3fh */ - .firstsector = 0, /* MS-DOS, unlike the BIOS, zero-base sectors */ - .sectors = 1, - .bufferoffset = 0, - .bufferseg = 0 -}; - - -void read_mbr(int drive, const void *buf) -{ - uint8_t err=0; - uint16_t ds_seg=0; - - //printf("read_mbr(%c:,%p)", 'a'+drive-1, buf); - - mbr.bufferoffset = (unsigned short)buf; - __asm { - push ds - pop ax - mov ds_seg, ax - } - mbr.bufferseg = ds_seg; - //printf("DS = %04Xh\n", ds_seg); - - __asm { - mov ax, 0x440d - mov bx, drive - mov cx, 0x0861 - mov dx, offset mbr - int 0x21 - mov ax, 0 - adc ax, 0 - mov err, al - } - - if (!err) { - //printf("Success reading MBR\n\n"); - return; - } - - __asm { - mov ax, 0x440d - mov bx, drive - mov cx, 0x4861 - mov dx, offset mbr - int 0x21 - mov ax, 0 - adc ax, 0 - mov err, al - } - - if (!err) { - //printf("Success reading FAT32 MBR\n\n"); - return; - } - - printf("mbr read error"); -} - -int main(int argc, char *argv[]) -{ - unsigned int c,h,s; - static uint8_t buf[1024]; - unsigned drive = (unsigned)(argv[1][0]); /* a=1,b=2,... */ - drive = drive-'a'+1; - printf("Query drive %c:\n", 'a'+drive-1); - - get_partition_offset(drive); - - read_mbr(drive, buf); - printf("MBR: %02Xh %02Xh %02Xh %02Xh %02Xh %02Xh %02Xh %02Xh\n", - ((const uint8_t *)buf)[0], - ((const uint8_t *)buf)[1], - ((const uint8_t *)buf)[2], - ((const uint8_t *)buf)[3], - ((const uint8_t *)buf)[4], - ((const uint8_t *)buf)[5], - ((const uint8_t *)buf)[6], - ((const uint8_t *)buf)[7]); - - printf("Finding drive\n"); - for (c = 1024; c <= 5265; c++) { - for (h = 0; h < 255; h++) - for (s = 0; s <= 63; s++) - { - mbr.cylinder = c; - mbr.head =h; - mbr.sectors=s; - read_mbr(drive, buf); - if (buf[0] != 0) { - printf("Found at %u,%u,%u\n", c,h,s); - - printf("MBR: %02Xh %02Xh %02Xh %02Xh %02Xh %02Xh %02Xh %02Xh\n", - ((const uint8_t *)buf)[0], - ((const uint8_t *)buf)[1], - ((const uint8_t *)buf)[2], - ((const uint8_t *)buf)[3], - ((const uint8_t *)buf)[4], - ((const uint8_t *)buf)[5], - ((const uint8_t *)buf)[6], - ((const uint8_t *)buf)[7]); - - exit(0); - } - } - printf("c=%u,", c); fflush(NULL); - } - - return 0; -} diff --git a/tests/absread/build.bat b/tests/absread/build.bat deleted file mode 100644 index 3c643e66..00000000 --- a/tests/absread/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -wcl -e3-we-wx-zq-os-s-zp1-mt-bt=DOS absread.c diff --git a/tests/fcb_rename/build.bat b/tests/fcb_rename/build.bat deleted file mode 100644 index 28e95c0e..00000000 --- a/tests/fcb_rename/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -wcl -e3-we-wx-zq-os-s-zp1-ms-bt=DOS fcb_ren.c diff --git a/tests/fcb_rename/fcb_ren.c b/tests/fcb_rename/fcb_ren.c deleted file mode 100644 index a65705aa..00000000 --- a/tests/fcb_rename/fcb_ren.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - based on tests from andrewbird - https://github.com/dosemu2/fdpp/pull/42#issuecomment-446309983 - - test 1 - fn1 = "*" - fe1 = "in" - fn2 = "*" - fe2 = "out" - create the following files "one.in", "two.in", "three.in", "four.in", "five.in", "none.ctl" - Run test: - check "one.out, "two.out", "three.out", "four.out", "five.out", "none.ctl" are present - - test 2 - fn1 = "a*" - fe1 = "*" - fn2 = "b*" - fe2 = "out" - create "aone.in", "atwo.in", "athree.in", "afour.in", "afive.in", "xnone.ctl" - Run test: - check "bone.out", "btwo.out", "bthree.out", "bfour.out", "bfive.out", "xnone.ctl" are present - - test 3 - fn1 = "abc0??" - fe1 = "*" - fn2 = "???6*" - fe2 = "*" - create "abc001.txt", "abc002.txt", "abc003.txt", "abc004.txt", "abc005.txt", "abc010.txt", "xbc007.txt" - Run test: - check "abc601.txt", "abc602.txt", "abc603.txt", "abc604.txt", "abc605.txt", "abc610.txt", "xbc007.txt" are present - - test 4 - fn1 = "abc*" - fe1 = "htm" - fn2 = "*" - fe2 = "??" - create "abc001.htm", "abc002.htm", "abc003.htm", "abc004.htm", "abc005.htm", "abc010.htm", "xbc007.htm" -Run test: - check "abc001.ht", "abc002.ht", "abc003.ht", "abc004.ht", "abc005.ht", "abc010.ht", "xbc007.htm" are present -*/ - -#include -#include -#include -#include - -#define FCB_RENAME 0x17 - -#define FAILURE 0 -#define SUCCESS (!FAILURE) - -typedef unsigned char UBYTE; -typedef char BYTE; - -#define FNAME_SIZE 8 /* limit on file name */ -#define FEXT_SIZE 3 /* limit on extension */ - -#define FDFLT_DRIVE 0 /* default drive */ - -/* #pragma pack(1) assumed */ -struct fcb { - UBYTE fcb_drive; /* Drive number 0=default, 1=A, etc */ - BYTE old_fname[FNAME_SIZE]; /* File name */ - BYTE old_fext[FEXT_SIZE]; /* File name Extension */ - BYTE padding[5]; - BYTE new_fname[FNAME_SIZE]; /* File name */ - BYTE new_fext[FEXT_SIZE]; /* File name Extension */ - BYTE reserved[9]; -}; - - -/* copies s to buffer right padding up to len with spaces */ -void set_field(char *buffer, const char *s, int len) -{ - char *buf, *end; - memset(buffer, ' ', len); - for (buf=buffer, end = buffer+len; (*s != '\0') && (buf < end); buf++, s++) - { - *buf = *s; - } -} - -/* performs fcb rename - returns handle to open device or -1 on error - */ -int fcb_rename(const char *old_fname, const char *old_fext, - const char *new_fname, const char *new_fext) -{ - union REGS regs; - struct SREGS sregs; - struct fcb _fcb; - - printf("FCB rename %s.%s to %s.%s\n", old_fname, old_fext, new_fname, new_fext); - - memset(&_fcb, ' ', sizeof(struct fcb)); - _fcb.fcb_drive = FDFLT_DRIVE; - set_field(&(_fcb.old_fname), old_fname, FNAME_SIZE); - set_field(&(_fcb.old_fext), old_fext, FEXT_SIZE); - set_field(&(_fcb.new_fname), new_fname, FNAME_SIZE); - set_field(&(_fcb.new_fext), new_fext, FEXT_SIZE); - - - regs.h.ah = FCB_RENAME; - regs.h.al = 0; - regs.x.dx = FP_OFF((void far *)&_fcb); - sregs.ds = FP_SEG((void far *)&_fcb); - intdosx(®s, ®s, &sregs); - - if (regs.h.al == 0) return SUCCESS; - /* al == 0xFF on failure */ - /* printf("fcb rename call returned failure\n"); */ - return FAILURE; -} - -/* returns SUCCESS if file exists, else FAILURE */ -int file_exists(const char *filename) -{ - FILE *f; - f = fopen(filename, "r"); - if (f == NULL) return FAILURE; - fclose(f); - return SUCCESS; -} - -/* returns SUCCESS if file successfully created, else FAILURE */ -int create_file(const char *filename) -{ - FILE *f; - /* printf("creating %s\n", filename); */ - f = fopen(filename, "w"); - if (f == NULL) return FAILURE; - fclose(f); - if (!file_exists(filename)) return FAILURE; - return SUCCESS; -} - -/* delete test files (either original names or renamed version */ -void delete_files_test_1() -{ - remove("one.in"); - remove("two.in"); - remove("three.in"); - remove("four.in"); - remove("five.in"); - remove("none.ctl"); - remove("one.out"); - remove("two.out"); - remove("three.out"); - remove("four.out"); - remove("five.out"); -} -void delete_files_test_2() -{ - remove("aone.in"); - remove("atwo.in"); - remove("athree.in"); - remove("afour.in"); - remove("afive.in"); - remove("xnone.ctl"); - remove("bone.out"); - remove("btwo.out"); - remove("bthree.out"); - remove("bfour.out"); - remove("bfive.out"); -} -void delete_files_test_3() -{ - remove("abc001.txt"); - remove("abc002.txt"); - remove("abc003.txt"); - remove("abc004.txt"); - remove("abc005.txt"); - remove("abc010.txt"); - remove("xbc007.txt"); - remove("abc601.txt"); - remove("abc602.txt"); - remove("abc603.txt"); - remove("abc604.txt"); - remove("abc605.txt"); - remove("abc610.txt"); -} -void delete_files_test_4() -{ - remove("abc001.htm"); - remove("abc002.htm"); - remove("abc003.htm"); - remove("abc004.htm"); - remove("abc005.htm"); - remove("abc010.htm"); - remove("xbc007.htm"); - remove("abc001.ht"); - remove("abc002.ht"); - remove("abc003.ht"); - remove("abc004.ht"); - remove("abc005.ht"); - remove("abc010.ht"); -} - -/* create needed test files */ -int setup_test_1() -{ - /* ensure new files don't exist */ - delete_files_test_1(); - - if (!create_file("one.in")) return FAILURE; - if (!create_file("two.in")) return FAILURE; - if (!create_file("three.in")) return FAILURE; - if (!create_file("four.in")) return FAILURE; - if (!create_file("five.in")) return FAILURE; - if (!create_file("none.ctl")) return FAILURE; - - return SUCCESS; -} -int setup_test_2() -{ - /* ensure new files don't exist */ - delete_files_test_2(); - - if (!create_file("aone.in")) return FAILURE; - if (!create_file("atwo.in")) return FAILURE; - if (!create_file("athree.in")) return FAILURE; - if (!create_file("afour.in")) return FAILURE; - if (!create_file("afive.in")) return FAILURE; - if (!create_file("xnone.ctl")) return FAILURE; - - return SUCCESS; -} -int setup_test_3() -{ - /* ensure new files don't exist */ - delete_files_test_3(); - - if (!create_file("abc001.txt")) return FAILURE; - if (!create_file("abc002.txt")) return FAILURE; - if (!create_file("abc003.txt")) return FAILURE; - if (!create_file("abc004.txt")) return FAILURE; - if (!create_file("abc005.txt")) return FAILURE; - if (!create_file("abc010.txt")) return FAILURE; - if (!create_file("xbc007.txt")) return FAILURE; - if (!create_file("xbc007.htm")) return FAILURE; - - return SUCCESS; -} -int setup_test_4() -{ - /* ensure new files don't exist */ - delete_files_test_4(); - - if (!create_file("abc001.htm")) return FAILURE; - if (!create_file("abc002.htm")) return FAILURE; - if (!create_file("abc003.htm")) return FAILURE; - if (!create_file("abc004.htm")) return FAILURE; - if (!create_file("abc005.htm")) return FAILURE; - if (!create_file("abc010.htm")) return FAILURE; - if (!create_file("xbc007.htm")) return FAILURE; - - return SUCCESS; -} - -/* attempt fcb rename and verify files changed */ -int test_1() -{ - int status = FAILURE; - setup_test_1(); - - if (!fcb_rename("*","in", "*","out")) goto failure; - if (!file_exists("one.out")) goto failure; - if (!file_exists("two.out")) goto failure; - if (!file_exists("three.out")) goto failure; - if (!file_exists("four.out")) goto failure; - if (!file_exists("five.out")) goto failure; - if (!file_exists("none.ctl")) goto failure; - - status = SUCCESS; -failure: - delete_files_test_1(); - return status; -} - -int test_2() -{ - int status = FAILURE; - setup_test_2(); - - if (!fcb_rename("a*","*", "b*","out")) goto failure; - if (!file_exists("bone.out")) goto failure; - if (!file_exists("btwo.out")) goto failure; - if (!file_exists("bthree.out")) goto failure; - if (!file_exists("bfour.out")) goto failure; - if (!file_exists("bfive.out")) goto failure; - if (!file_exists("xnone.ctl")) goto failure; - - status = SUCCESS; -failure: - delete_files_test_2(); - return status; -} - -int test_3() -{ - int status = FAILURE; - setup_test_3(); - - if (!fcb_rename("abc0??","*", "???6*","*")) goto failure; - if (!file_exists("abc601.txt")) goto failure; - if (!file_exists("abc602.txt")) goto failure; - if (!file_exists("abc603.txt")) goto failure; - if (!file_exists("abc604.txt")) goto failure; - if (!file_exists("abc605.txt")) goto failure; - if (!file_exists("abc610.txt")) goto failure; - if (!file_exists("xbc007.txt")) goto failure; - - status = SUCCESS; -failure: - delete_files_test_3(); - return status; -} - -int test_4() -{ - int status = FAILURE; - setup_test_4(); - - if (!fcb_rename("abc*","htm", "*","??")) goto failure; - if (!file_exists("abc001.ht")) goto failure; - if (!file_exists("abc002.ht")) goto failure; - if (!file_exists("abc003.ht")) goto failure; - if (!file_exists("abc004.ht")) goto failure; - if (!file_exists("abc005.ht")) goto failure; - if (!file_exists("abc010.ht")) goto failure; - if (!file_exists("xbc007.htm")) goto failure; - - status = SUCCESS; -failure: - delete_files_test_4(); - return status; -} - - -int main(int argc, char *argv[]) -{ - int error_code = 0; - - if (test_1()) { printf("SUCCESS\n"); } else { printf("FAILURE\n"); error_code |= 0x01; } - if (test_2()) { printf("SUCCESS\n"); } else { printf("FAILURE\n"); error_code |= 0x02; } - if (test_3()) { printf("SUCCESS\n"); } else { printf("FAILURE\n"); error_code |= 0x04; } - if (test_4()) { printf("SUCCESS\n"); } else { printf("FAILURE\n"); error_code |= 0x08; } - - return error_code; -} diff --git a/tests/greatest.h b/tests/greatest.h deleted file mode 100644 index af0c0537..00000000 --- a/tests/greatest.h +++ /dev/null @@ -1,1266 +0,0 @@ -/* - * Copyright (c) 2011-2021 Scott Vokes - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef GREATEST_H -#define GREATEST_H - -#if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) -extern "C" { -#endif - -/* 1.5.0 */ -#define GREATEST_VERSION_MAJOR 1 -#define GREATEST_VERSION_MINOR 5 -#define GREATEST_VERSION_PATCH 0 - -/* A unit testing system for C, contained in 1 file. - * It doesn't use dynamic allocation or depend on anything - * beyond ANSI C89. - * - * An up-to-date version can be found at: - * https://github.com/silentbicycle/greatest/ - */ - - -/********************************************************************* - * Minimal test runner template - *********************************************************************/ -#if 0 - -#include "greatest.h" - -TEST foo_should_foo(void) { - PASS(); -} - -static void setup_cb(void *data) { - printf("setup callback for each test case\n"); -} - -static void teardown_cb(void *data) { - printf("teardown callback for each test case\n"); -} - -SUITE(suite) { - /* Optional setup/teardown callbacks which will be run before/after - * every test case. If using a test suite, they will be cleared when - * the suite finishes. */ - SET_SETUP(setup_cb, voidp_to_callback_data); - SET_TEARDOWN(teardown_cb, voidp_to_callback_data); - - RUN_TEST(foo_should_foo); -} - -/* Add definitions that need to be in the test runner's main file. */ -GREATEST_MAIN_DEFS(); - -/* Set up, run suite(s) of tests, report pass/fail/skip stats. */ -int run_tests(void) { - GREATEST_INIT(); /* init. greatest internals */ - /* List of suites to run (if any). */ - RUN_SUITE(suite); - - /* Tests can also be run directly, without using test suites. */ - RUN_TEST(foo_should_foo); - - GREATEST_PRINT_REPORT(); /* display results */ - return greatest_all_passed(); -} - -/* main(), for a standalone command-line test runner. - * This replaces run_tests above, and adds command line option - * handling and exiting with a pass/fail status. */ -int main(int argc, char **argv) { - GREATEST_MAIN_BEGIN(); /* init & parse command-line args */ - RUN_SUITE(suite); - GREATEST_MAIN_END(); /* display results */ -} - -#endif -/*********************************************************************/ - - -#include -#include -#include -#include - -/*********** - * Options * - ***********/ - -/* Default column width for non-verbose output. */ -#ifndef GREATEST_DEFAULT_WIDTH -#define GREATEST_DEFAULT_WIDTH 72 -#endif - -/* FILE *, for test logging. */ -#ifndef GREATEST_STDOUT -#define GREATEST_STDOUT stdout -#endif - -/* Remove GREATEST_ prefix from most commonly used symbols? */ -#ifndef GREATEST_USE_ABBREVS -#define GREATEST_USE_ABBREVS 1 -#endif - -/* Set to 0 to disable all use of setjmp/longjmp. */ -#ifndef GREATEST_USE_LONGJMP -#define GREATEST_USE_LONGJMP 0 -#endif - -/* Make it possible to replace fprintf with another - * function with the same interface. */ -#ifndef GREATEST_FPRINTF -#define GREATEST_FPRINTF fprintf -#endif - -#if GREATEST_USE_LONGJMP -#include -#endif - -/* Set to 0 to disable all use of time.h / clock(). */ -#ifndef GREATEST_USE_TIME -#define GREATEST_USE_TIME 1 -#endif - -#if GREATEST_USE_TIME -#include -#endif - -/* Floating point type, for ASSERT_IN_RANGE. */ -#ifndef GREATEST_FLOAT -#define GREATEST_FLOAT double -#define GREATEST_FLOAT_FMT "%g" -#endif - -/* Size of buffer for test name + optional '_' separator and suffix */ -#ifndef GREATEST_TESTNAME_BUF_SIZE -#define GREATEST_TESTNAME_BUF_SIZE 128 -#endif - - -/********* - * Types * - *********/ - -/* Info for the current running suite. */ -typedef struct greatest_suite_info { - unsigned int tests_run; - unsigned int passed; - unsigned int failed; - unsigned int skipped; - -#if GREATEST_USE_TIME - /* timers, pre/post running suite and individual tests */ - clock_t pre_suite; - clock_t post_suite; - clock_t pre_test; - clock_t post_test; -#endif -} greatest_suite_info; - -/* Type for a suite function. */ -typedef void greatest_suite_cb(void); - -/* Types for setup/teardown callbacks. If non-NULL, these will be run - * and passed the pointer to their additional data. */ -typedef void greatest_setup_cb(void *udata); -typedef void greatest_teardown_cb(void *udata); - -/* Type for an equality comparison between two pointers of the same type. - * Should return non-0 if equal, otherwise 0. - * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ -typedef int greatest_equal_cb(const void *expd, const void *got, void *udata); - -/* Type for a callback that prints a value pointed to by T. - * Return value has the same meaning as printf's. - * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ -typedef int greatest_printf_cb(const void *t, void *udata); - -/* Callbacks for an arbitrary type; needed for type-specific - * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ -typedef struct greatest_type_info { - greatest_equal_cb *equal; - greatest_printf_cb *print; -} greatest_type_info; - -typedef struct greatest_memory_cmp_env { - const unsigned char *exp; - const unsigned char *got; - size_t size; -} greatest_memory_cmp_env; - -/* Callbacks for string and raw memory types. */ -extern greatest_type_info greatest_type_info_string; -extern greatest_type_info greatest_type_info_memory; - -typedef enum { - GREATEST_FLAG_FIRST_FAIL = 0x01, - GREATEST_FLAG_LIST_ONLY = 0x02, - GREATEST_FLAG_ABORT_ON_FAIL = 0x04 -} greatest_flag_t; - -/* Internal state for a PRNG, used to shuffle test order. */ -struct greatest_prng { - unsigned char random_order; /* use random ordering? */ - unsigned char initialized; /* is random ordering initialized? */ - unsigned char pad_0[6]; - unsigned long state; /* PRNG state */ - unsigned long count; /* how many tests, this pass */ - unsigned long count_ceil; /* total number of tests */ - unsigned long count_run; /* total tests run */ - unsigned long a; /* LCG multiplier */ - unsigned long c; /* LCG increment */ - unsigned long m; /* LCG modulus, based on count_ceil */ -}; - -/* Struct containing all test runner state. */ -typedef struct greatest_run_info { - unsigned char flags; - unsigned char verbosity; - unsigned char running_test; /* guard for nested RUN_TEST calls */ - unsigned char exact_name_match; - - unsigned int tests_run; /* total test count */ - - /* currently running test suite */ - greatest_suite_info suite; - - /* overall pass/fail/skip counts */ - unsigned int passed; - unsigned int failed; - unsigned int skipped; - unsigned int assertions; - - /* info to print about the most recent failure */ - unsigned int fail_line; - unsigned int pad_1; - const char *fail_file; - const char *msg; - - /* current setup/teardown hooks and userdata */ - greatest_setup_cb *setup; - void *setup_udata; - greatest_teardown_cb *teardown; - void *teardown_udata; - - /* formatting info for ".....s...F"-style output */ - unsigned int col; - unsigned int width; - - /* only run a specific suite or test */ - const char *suite_filter; - const char *test_filter; - const char *test_exclude; - const char *name_suffix; /* print suffix with test name */ - char name_buf[GREATEST_TESTNAME_BUF_SIZE]; - - struct greatest_prng prng[2]; /* 0: suites, 1: tests */ - -#if GREATEST_USE_TIME - /* overall timers */ - clock_t begin; - clock_t end; -#endif - -#if GREATEST_USE_LONGJMP - int pad_jmp_buf; - unsigned char pad_2[4]; - jmp_buf jump_dest; -#endif -} greatest_run_info; - -struct greatest_report_t { - /* overall pass/fail/skip counts */ - unsigned int passed; - unsigned int failed; - unsigned int skipped; - unsigned int assertions; -}; - -/* Global var for the current testing context. - * Initialized by GREATEST_MAIN_DEFS(). */ -extern greatest_run_info greatest_info; - -/* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ -typedef const char *greatest_enum_str_fun(int value); - - -/********************** - * Exported functions * - **********************/ - -/* These are used internally by greatest macros. */ -int greatest_test_pre(const char *name); -void greatest_test_post(int res); -int greatest_do_assert_equal_t(const void *expd, const void *got, - greatest_type_info *type_info, void *udata); -void greatest_prng_init_first_pass(int id); -int greatest_prng_init_second_pass(int id, unsigned long seed); -void greatest_prng_step(int id); - -/* These are part of the public greatest API. */ -void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); -void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); -void GREATEST_INIT(void); -void GREATEST_PRINT_REPORT(void); -int greatest_all_passed(void); -void greatest_set_suite_filter(const char *filter); -void greatest_set_test_filter(const char *filter); -void greatest_set_test_exclude(const char *filter); -void greatest_set_exact_name_match(void); -void greatest_stop_at_first_fail(void); -void greatest_abort_on_fail(void); -void greatest_list_only(void); -void greatest_get_report(struct greatest_report_t *report); -unsigned int greatest_get_verbosity(void); -void greatest_set_verbosity(unsigned int verbosity); -void greatest_set_flag(greatest_flag_t flag); -void greatest_set_test_suffix(const char *suffix); - - -/******************** -* Language Support * -********************/ - -/* If __VA_ARGS__ (C99) is supported, allow parametric testing -* without needing to manually manage the argument struct. */ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L) || \ - (defined(_MSC_VER) && _MSC_VER >= 1800) -#define GREATEST_VA_ARGS -#endif - - -/********** - * Macros * - **********/ - -/* Define a suite. (The duplication is intentional -- it eliminates - * a warning from -Wmissing-declarations.) */ -#define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) - -/* Declare a suite, provided by another compilation unit. */ -#define GREATEST_SUITE_EXTERN(NAME) void NAME(void) - -/* Start defining a test function. - * The arguments are not included, to allow parametric testing. */ -#define GREATEST_TEST static enum greatest_test_res - -/* PASS/FAIL/SKIP result from a test. Used internally. */ -typedef enum greatest_test_res { - GREATEST_TEST_RES_PASS = 0, - GREATEST_TEST_RES_FAIL = -1, - GREATEST_TEST_RES_SKIP = 1 -} greatest_test_res; - -/* Run a suite. */ -#define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) - -/* Run a test in the current suite. */ -#define GREATEST_RUN_TEST(TEST) \ - do { \ - if (greatest_test_pre(#TEST) == 1) { \ - enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ - if (res == GREATEST_TEST_RES_PASS) { \ - res = TEST(); \ - } \ - greatest_test_post(res); \ - } \ - } while (0) - -/* Ignore a test, don't warn about it being unused. */ -#define GREATEST_IGNORE_TEST(TEST) (void)TEST - -/* Run a test in the current suite with one void * argument, - * which can be a pointer to a struct with multiple arguments. */ -#define GREATEST_RUN_TEST1(TEST, ENV) \ - do { \ - if (greatest_test_pre(#TEST) == 1) { \ - enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ - if (res == GREATEST_TEST_RES_PASS) { \ - res = TEST(ENV); \ - } \ - greatest_test_post(res); \ - } \ - } while (0) - -#ifdef GREATEST_VA_ARGS -#define GREATEST_RUN_TESTp(TEST, ...) \ - do { \ - if (greatest_test_pre(#TEST) == 1) { \ - enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ - if (res == GREATEST_TEST_RES_PASS) { \ - res = TEST(__VA_ARGS__); \ - } \ - greatest_test_post(res); \ - } \ - } while (0) -#endif - - -/* Check if the test runner is in verbose mode. */ -#define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0) -#define GREATEST_LIST_ONLY() \ - (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) -#define GREATEST_FIRST_FAIL() \ - (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) -#define GREATEST_ABORT_ON_FAIL() \ - (greatest_info.flags & GREATEST_FLAG_ABORT_ON_FAIL) -#define GREATEST_FAILURE_ABORT() \ - (GREATEST_FIRST_FAIL() && \ - (greatest_info.suite.failed > 0 || greatest_info.failed > 0)) - -/* Message-less forms of tests defined below. */ -#define GREATEST_PASS() GREATEST_PASSm(NULL) -#define GREATEST_FAIL() GREATEST_FAILm(NULL) -#define GREATEST_SKIP() GREATEST_SKIPm(NULL) -#define GREATEST_ASSERT(COND) \ - GREATEST_ASSERTm(#COND, COND) -#define GREATEST_ASSERT_OR_LONGJMP(COND) \ - GREATEST_ASSERT_OR_LONGJMPm(#COND, COND) -#define GREATEST_ASSERT_FALSE(COND) \ - GREATEST_ASSERT_FALSEm(#COND, COND) -#define GREATEST_ASSERT_EQ(EXP, GOT) \ - GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) -#define GREATEST_ASSERT_NEQ(EXP, GOT) \ - GREATEST_ASSERT_NEQm(#EXP " == " #GOT, EXP, GOT) -#define GREATEST_ASSERT_GT(EXP, GOT) \ - GREATEST_ASSERT_GTm(#EXP " <= " #GOT, EXP, GOT) -#define GREATEST_ASSERT_GTE(EXP, GOT) \ - GREATEST_ASSERT_GTEm(#EXP " < " #GOT, EXP, GOT) -#define GREATEST_ASSERT_LT(EXP, GOT) \ - GREATEST_ASSERT_LTm(#EXP " >= " #GOT, EXP, GOT) -#define GREATEST_ASSERT_LTE(EXP, GOT) \ - GREATEST_ASSERT_LTEm(#EXP " > " #GOT, EXP, GOT) -#define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ - GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT) -#define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ - GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL) -#define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ - GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA) -#define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ - GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT) -#define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ - GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) -#define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ - GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) -#define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ - GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) - -/* The following forms take an additional message argument first, - * to be displayed by the test runner. */ - -/* Fail if a condition is not true, with message. */ -#define GREATEST_ASSERTm(MSG, COND) \ - do { \ - greatest_info.assertions++; \ - if (!(COND)) { GREATEST_FAILm(MSG); } \ - } while (0) - -/* Fail if a condition is not true, longjmping out of test. */ -#define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ - do { \ - greatest_info.assertions++; \ - if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); } \ - } while (0) - -/* Fail if a condition is not false, with message. */ -#define GREATEST_ASSERT_FALSEm(MSG, COND) \ - do { \ - greatest_info.assertions++; \ - if ((COND)) { GREATEST_FAILm(MSG); } \ - } while (0) - -/* Internal macro for relational assertions */ -#define GREATEST__REL(REL, MSG, EXP, GOT) \ - do { \ - greatest_info.assertions++; \ - if (!((EXP) REL (GOT))) { GREATEST_FAILm(MSG); } \ - } while (0) - -/* Fail if EXP is not ==, !=, >, <, >=, or <= to GOT. */ -#define GREATEST_ASSERT_EQm(MSG,E,G) GREATEST__REL(==, MSG,E,G) -#define GREATEST_ASSERT_NEQm(MSG,E,G) GREATEST__REL(!=, MSG,E,G) -#define GREATEST_ASSERT_GTm(MSG,E,G) GREATEST__REL(>, MSG,E,G) -#define GREATEST_ASSERT_GTEm(MSG,E,G) GREATEST__REL(>=, MSG,E,G) -#define GREATEST_ASSERT_LTm(MSG,E,G) GREATEST__REL(<, MSG,E,G) -#define GREATEST_ASSERT_LTEm(MSG,E,G) GREATEST__REL(<=, MSG,E,G) - -/* Fail if EXP != GOT (equality comparison by ==). - * Warning: FMT, EXP, and GOT will be evaluated more - * than once on failure. */ -#define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ - do { \ - greatest_info.assertions++; \ - if ((EXP) != (GOT)) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ - GREATEST_FPRINTF(GREATEST_STDOUT, FMT, EXP); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ - GREATEST_FPRINTF(GREATEST_STDOUT, FMT, GOT); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - GREATEST_FAILm(MSG); \ - } \ - } while (0) - -/* Fail if EXP is not equal to GOT, printing enum IDs. */ -#define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ - do { \ - int greatest_EXP = (int)(EXP); \ - int greatest_GOT = (int)(GOT); \ - greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ - if (greatest_EXP != greatest_GOT) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: %s", \ - greatest_ENUM_STR(greatest_EXP)); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: %s\n", \ - greatest_ENUM_STR(greatest_GOT)); \ - GREATEST_FAILm(MSG); \ - } \ - } while (0) \ - -/* Fail if GOT not in range of EXP +|- TOL. */ -#define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ - do { \ - GREATEST_FLOAT greatest_EXP = (EXP); \ - GREATEST_FLOAT greatest_GOT = (GOT); \ - GREATEST_FLOAT greatest_TOL = (TOL); \ - greatest_info.assertions++; \ - if ((greatest_EXP > greatest_GOT && \ - greatest_EXP - greatest_GOT > greatest_TOL) || \ - (greatest_EXP < greatest_GOT && \ - greatest_GOT - greatest_EXP > greatest_TOL)) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "\nExpected: " GREATEST_FLOAT_FMT \ - " +/- " GREATEST_FLOAT_FMT \ - "\n Got: " GREATEST_FLOAT_FMT \ - "\n", \ - greatest_EXP, greatest_TOL, greatest_GOT); \ - GREATEST_FAILm(MSG); \ - } \ - } while (0) - -/* Fail if EXP is not equal to GOT, according to strcmp. */ -#define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ - do { \ - GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ - &greatest_type_info_string, NULL); \ - } while (0) \ - -/* Fail if EXP is not equal to GOT, according to strncmp. */ -#define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ - do { \ - size_t size = SIZE; \ - GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ - &greatest_type_info_string, &size); \ - } while (0) \ - -/* Fail if EXP is not equal to GOT, according to memcmp. */ -#define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ - do { \ - greatest_memory_cmp_env env; \ - env.exp = (const unsigned char *)EXP; \ - env.got = (const unsigned char *)GOT; \ - env.size = SIZE; \ - GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got, \ - &greatest_type_info_memory, &env); \ - } while (0) \ - -/* Fail if EXP is not equal to GOT, according to a comparison - * callback in TYPE_INFO. If they are not equal, optionally use a - * print callback in TYPE_INFO to print them. */ -#define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ - do { \ - greatest_type_info *type_info = (TYPE_INFO); \ - greatest_info.assertions++; \ - if (!greatest_do_assert_equal_t(EXP, GOT, \ - type_info, UDATA)) { \ - if (type_info == NULL || type_info->equal == NULL) { \ - GREATEST_FAILm("type_info->equal callback missing!"); \ - } else { \ - GREATEST_FAILm(MSG); \ - } \ - } \ - } while (0) \ - -/* Pass. */ -#define GREATEST_PASSm(MSG) \ - do { \ - greatest_info.msg = MSG; \ - return GREATEST_TEST_RES_PASS; \ - } while (0) - -/* Fail. */ -#define GREATEST_FAILm(MSG) \ - do { \ - greatest_info.fail_file = __FILE__; \ - greatest_info.fail_line = __LINE__; \ - greatest_info.msg = MSG; \ - if (GREATEST_ABORT_ON_FAIL()) { abort(); } \ - return GREATEST_TEST_RES_FAIL; \ - } while (0) - -/* Optional GREATEST_FAILm variant that longjmps. */ -#if GREATEST_USE_LONGJMP -#define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL) -#define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ - do { \ - greatest_info.fail_file = __FILE__; \ - greatest_info.fail_line = __LINE__; \ - greatest_info.msg = MSG; \ - longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ - } while (0) -#endif - -/* Skip the current test. */ -#define GREATEST_SKIPm(MSG) \ - do { \ - greatest_info.msg = MSG; \ - return GREATEST_TEST_RES_SKIP; \ - } while (0) - -/* Check the result of a subfunction using ASSERT, etc. */ -#define GREATEST_CHECK_CALL(RES) \ - do { \ - enum greatest_test_res greatest_RES = RES; \ - if (greatest_RES != GREATEST_TEST_RES_PASS) { \ - return greatest_RES; \ - } \ - } while (0) \ - -#if GREATEST_USE_TIME -#define GREATEST_SET_TIME(NAME) \ - NAME = clock(); \ - if (NAME == (clock_t) -1) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "clock error: %s\n", #NAME); \ - exit(EXIT_FAILURE); \ - } - -#define GREATEST_CLOCK_DIFF(C1, C2) \ - GREATEST_FPRINTF(GREATEST_STDOUT, " (%lu ticks, %.3f sec)", \ - (long unsigned int) (C2) - (long unsigned int)(C1), \ - (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) -#else -#define GREATEST_SET_TIME(UNUSED) -#define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2) -#endif - -#if GREATEST_USE_LONGJMP -#define GREATEST_SAVE_CONTEXT() \ - /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call * \ - * so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ - ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) -#else -#define GREATEST_SAVE_CONTEXT() \ - /*a no-op, since setjmp/longjmp aren't being used */ \ - GREATEST_TEST_RES_PASS -#endif - -/* Run every suite / test function run within BODY in pseudo-random - * order, seeded by SEED. (The top 3 bits of the seed are ignored.) - * - * This should be called like: - * GREATEST_SHUFFLE_TESTS(seed, { - * GREATEST_RUN_TEST(some_test); - * GREATEST_RUN_TEST(some_other_test); - * GREATEST_RUN_TEST(yet_another_test); - * }); - * - * Note that the body of the second argument will be evaluated - * multiple times. */ -#define GREATEST_SHUFFLE_SUITES(SD, BODY) GREATEST_SHUFFLE(0, SD, BODY) -#define GREATEST_SHUFFLE_TESTS(SD, BODY) GREATEST_SHUFFLE(1, SD, BODY) -#define GREATEST_SHUFFLE(ID, SD, BODY) \ - do { \ - struct greatest_prng *prng = &greatest_info.prng[ID]; \ - greatest_prng_init_first_pass(ID); \ - do { \ - prng->count = 0; \ - if (prng->initialized) { greatest_prng_step(ID); } \ - BODY; \ - if (!prng->initialized) { \ - if (!greatest_prng_init_second_pass(ID, SD)) { break; } \ - } else if (prng->count_run == prng->count_ceil) { \ - break; \ - } \ - } while (!GREATEST_FAILURE_ABORT()); \ - prng->count_run = prng->random_order = prng->initialized = 0; \ - } while(0) - -/* Include several function definitions in the main test file. */ -#define GREATEST_MAIN_DEFS() \ - \ -/* Is FILTER a subset of NAME? */ \ -static int greatest_name_match(const char *name, const char *filter, \ - int res_if_none) { \ - size_t offset = 0; \ - size_t filter_len = filter ? strlen(filter) : 0; \ - if (filter_len == 0) { return res_if_none; } /* no filter */ \ - if (greatest_info.exact_name_match && strlen(name) != filter_len) { \ - return 0; /* ignore substring matches */ \ - } \ - while (name[offset] != '\0') { \ - if (name[offset] == filter[0]) { \ - if (0 == strncmp(&name[offset], filter, filter_len)) { \ - return 1; \ - } \ - } \ - offset++; \ - } \ - \ - return 0; \ -} \ - \ -static void greatest_buffer_test_name(const char *name) { \ - struct greatest_run_info *g = &greatest_info; \ - size_t len = strlen(name), size = sizeof(g->name_buf); \ - memset(g->name_buf, 0x00, size); \ - (void)strncat(g->name_buf, name, size - 1); \ - if (g->name_suffix && (len + 1 < size)) { \ - g->name_buf[len] = '_'; \ - strncat(&g->name_buf[len+1], g->name_suffix, size-(len+2)); \ - } \ -} \ - \ -/* Before running a test, check the name filtering and \ - * test shuffling state, if applicable, and then call setup hooks. */ \ -int greatest_test_pre(const char *name) { \ - struct greatest_run_info *g = &greatest_info; \ - int match; \ - greatest_buffer_test_name(name); \ - match = greatest_name_match(g->name_buf, g->test_filter, 1) && \ - !greatest_name_match(g->name_buf, g->test_exclude, 0); \ - if (GREATEST_LIST_ONLY()) { /* just listing test names */ \ - if (match) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, " %s\n", g->name_buf); \ - } \ - goto clear; \ - } \ - if (match && (!GREATEST_FIRST_FAIL() || g->suite.failed == 0)) { \ - struct greatest_prng *p = &g->prng[1]; \ - if (p->random_order) { \ - p->count++; \ - if (!p->initialized || ((p->count - 1) != p->state)) { \ - goto clear; /* don't run this test yet */ \ - } \ - } \ - if (g->running_test) { \ - fprintf(stderr, "Error: Test run inside another test.\n"); \ - return 0; \ - } \ - GREATEST_SET_TIME(g->suite.pre_test); \ - if (g->setup) { g->setup(g->setup_udata); } \ - p->count_run++; \ - g->running_test = 1; \ - return 1; /* test should be run */ \ - } else { \ - goto clear; /* skipped */ \ - } \ -clear: \ - g->name_suffix = NULL; \ - return 0; \ -} \ - \ -static void greatest_do_pass(void) { \ - struct greatest_run_info *g = &greatest_info; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "PASS %s: %s", \ - g->name_buf, g->msg ? g->msg : ""); \ - } else { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "."); \ - } \ - g->suite.passed++; \ -} \ - \ -static void greatest_do_fail(void) { \ - struct greatest_run_info *g = &greatest_info; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "FAIL %s: %s (%s:%u)", g->name_buf, \ - g->msg ? g->msg : "", g->fail_file, g->fail_line); \ - } else { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "F"); \ - g->col++; /* add linebreak if in line of '.'s */ \ - if (g->col != 0) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - g->col = 0; \ - } \ - GREATEST_FPRINTF(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n", \ - g->name_buf, g->msg ? g->msg : "", \ - g->fail_file, g->fail_line); \ - } \ - g->suite.failed++; \ -} \ - \ -static void greatest_do_skip(void) { \ - struct greatest_run_info *g = &greatest_info; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "SKIP %s: %s", \ - g->name_buf, g->msg ? g->msg : ""); \ - } else { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "s"); \ - } \ - g->suite.skipped++; \ -} \ - \ -void greatest_test_post(int res) { \ - GREATEST_SET_TIME(greatest_info.suite.post_test); \ - if (greatest_info.teardown) { \ - void *udata = greatest_info.teardown_udata; \ - greatest_info.teardown(udata); \ - } \ - \ - greatest_info.running_test = 0; \ - if (res <= GREATEST_TEST_RES_FAIL) { \ - greatest_do_fail(); \ - } else if (res >= GREATEST_TEST_RES_SKIP) { \ - greatest_do_skip(); \ - } else if (res == GREATEST_TEST_RES_PASS) { \ - greatest_do_pass(); \ - } \ - greatest_info.name_suffix = NULL; \ - greatest_info.suite.tests_run++; \ - greatest_info.col++; \ - if (GREATEST_IS_VERBOSE()) { \ - GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ - greatest_info.suite.post_test); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - } else if (greatest_info.col % greatest_info.width == 0) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - greatest_info.col = 0; \ - } \ - fflush(GREATEST_STDOUT); \ -} \ - \ -static void report_suite(void) { \ - if (greatest_info.suite.tests_run > 0) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "\n%u test%s - %u passed, %u failed, %u skipped", \ - greatest_info.suite.tests_run, \ - greatest_info.suite.tests_run == 1 ? "" : "s", \ - greatest_info.suite.passed, \ - greatest_info.suite.failed, \ - greatest_info.suite.skipped); \ - GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ - greatest_info.suite.post_suite); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - } \ -} \ - \ -static void update_counts_and_reset_suite(void) { \ - greatest_info.setup = NULL; \ - greatest_info.setup_udata = NULL; \ - greatest_info.teardown = NULL; \ - greatest_info.teardown_udata = NULL; \ - greatest_info.passed += greatest_info.suite.passed; \ - greatest_info.failed += greatest_info.suite.failed; \ - greatest_info.skipped += greatest_info.suite.skipped; \ - greatest_info.tests_run += greatest_info.suite.tests_run; \ - memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ - greatest_info.col = 0; \ -} \ - \ -static int greatest_suite_pre(const char *suite_name) { \ - struct greatest_prng *p = &greatest_info.prng[0]; \ - if (!greatest_name_match(suite_name, greatest_info.suite_filter, 1) \ - || (GREATEST_FAILURE_ABORT())) { return 0; } \ - if (p->random_order) { \ - p->count++; \ - if (!p->initialized || ((p->count - 1) != p->state)) { \ - return 0; /* don't run this suite yet */ \ - } \ - } \ - p->count_run++; \ - update_counts_and_reset_suite(); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ - GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ - return 1; \ -} \ - \ -static void greatest_suite_post(void) { \ - GREATEST_SET_TIME(greatest_info.suite.post_suite); \ - report_suite(); \ -} \ - \ -static void greatest_run_suite(greatest_suite_cb *suite_cb, \ - const char *suite_name) { \ - if (greatest_suite_pre(suite_name)) { \ - suite_cb(); \ - greatest_suite_post(); \ - } \ -} \ - \ -int greatest_do_assert_equal_t(const void *expd, const void *got, \ - greatest_type_info *type_info, void *udata) { \ - int eq = 0; \ - if (type_info == NULL || type_info->equal == NULL) { return 0; } \ - eq = type_info->equal(expd, got, udata); \ - if (!eq) { \ - if (type_info->print != NULL) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ - (void)type_info->print(expd, udata); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ - (void)type_info->print(got, udata); \ - GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ - } \ - } \ - return eq; \ -} \ - \ -static void greatest_usage(const char *name) { \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ - " -h, --help print this Help\n" \ - " -l List suites and tests, then exit (dry run)\n" \ - " -f Stop runner after first failure\n" \ - " -a Abort on first failure (implies -f)\n" \ - " -v Verbose output\n" \ - " -s SUITE only run suites containing substring SUITE\n" \ - " -t TEST only run tests containing substring TEST\n" \ - " -e only run exact name match for -s or -t\n" \ - " -x EXCLUDE exclude tests containing substring EXCLUDE\n", \ - name); \ -} \ - \ -static void greatest_parse_options(int argc, char **argv) { \ - int i = 0; \ - for (i = 1; i < argc; i++) { \ - if (argv[i][0] == '-') { \ - char f = argv[i][1]; \ - if ((f == 's' || f == 't' || f == 'x') && argc <= i + 1) { \ - greatest_usage(argv[0]); exit(EXIT_FAILURE); \ - } \ - switch (f) { \ - case 's': /* suite name filter */ \ - greatest_set_suite_filter(argv[i + 1]); i++; break; \ - case 't': /* test name filter */ \ - greatest_set_test_filter(argv[i + 1]); i++; break; \ - case 'x': /* test name exclusion */ \ - greatest_set_test_exclude(argv[i + 1]); i++; break; \ - case 'e': /* exact name match */ \ - greatest_set_exact_name_match(); break; \ - case 'f': /* first fail flag */ \ - greatest_stop_at_first_fail(); break; \ - case 'a': /* abort() on fail flag */ \ - greatest_abort_on_fail(); break; \ - case 'l': /* list only (dry run) */ \ - greatest_list_only(); break; \ - case 'v': /* first fail flag */ \ - greatest_info.verbosity++; break; \ - case 'h': /* help */ \ - greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ - default: \ - case '-': \ - if (0 == strncmp("--help", argv[i], 6)) { \ - greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ - } else if (0 == strcmp("--", argv[i])) { \ - return; /* ignore following arguments */ \ - } \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Unknown argument '%s'\n", argv[i]); \ - greatest_usage(argv[0]); \ - exit(EXIT_FAILURE); \ - } \ - } \ - } \ -} \ - \ -int greatest_all_passed(void) { return (greatest_info.failed == 0); } \ - \ -void greatest_set_test_filter(const char *filter) { \ - greatest_info.test_filter = filter; \ -} \ - \ -void greatest_set_test_exclude(const char *filter) { \ - greatest_info.test_exclude = filter; \ -} \ - \ -void greatest_set_suite_filter(const char *filter) { \ - greatest_info.suite_filter = filter; \ -} \ - \ -void greatest_set_exact_name_match(void) { \ - greatest_info.exact_name_match = 1; \ -} \ - \ -void greatest_stop_at_first_fail(void) { \ - greatest_set_flag(GREATEST_FLAG_FIRST_FAIL); \ -} \ - \ -void greatest_abort_on_fail(void) { \ - greatest_set_flag(GREATEST_FLAG_ABORT_ON_FAIL); \ -} \ - \ -void greatest_list_only(void) { \ - greatest_set_flag(GREATEST_FLAG_LIST_ONLY); \ -} \ - \ -void greatest_get_report(struct greatest_report_t *report) { \ - if (report) { \ - report->passed = greatest_info.passed; \ - report->failed = greatest_info.failed; \ - report->skipped = greatest_info.skipped; \ - report->assertions = greatest_info.assertions; \ - } \ -} \ - \ -unsigned int greatest_get_verbosity(void) { \ - return greatest_info.verbosity; \ -} \ - \ -void greatest_set_verbosity(unsigned int verbosity) { \ - greatest_info.verbosity = (unsigned char)verbosity; \ -} \ - \ -void greatest_set_flag(greatest_flag_t flag) { \ - greatest_info.flags = (unsigned char)(greatest_info.flags | flag); \ -} \ - \ -void greatest_set_test_suffix(const char *suffix) { \ - greatest_info.name_suffix = suffix; \ -} \ - \ -void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ - greatest_info.setup = cb; \ - greatest_info.setup_udata = udata; \ -} \ - \ -void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) { \ - greatest_info.teardown = cb; \ - greatest_info.teardown_udata = udata; \ -} \ - \ -static int greatest_string_equal_cb(const void *expd, const void *got, \ - void *udata) { \ - size_t *size = (size_t *)udata; \ - return (size != NULL \ - ? (0 == strncmp((const char *)expd, (const char *)got, *size)) \ - : (0 == strcmp((const char *)expd, (const char *)got))); \ -} \ - \ -static int greatest_string_printf_cb(const void *t, void *udata) { \ - (void)udata; /* note: does not check \0 termination. */ \ - return GREATEST_FPRINTF(GREATEST_STDOUT, "%s", (const char *)t); \ -} \ - \ -greatest_type_info greatest_type_info_string = { \ - greatest_string_equal_cb, greatest_string_printf_cb, \ -}; \ - \ -static int greatest_memory_equal_cb(const void *expd, const void *got, \ - void *udata) { \ - greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ - return (0 == memcmp(expd, got, env->size)); \ -} \ - \ -/* Hexdump raw memory, with differences highlighted */ \ -static int greatest_memory_printf_cb(const void *t, void *udata) { \ - greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ - const unsigned char *buf = (const unsigned char *)t; \ - unsigned char diff_mark = ' '; \ - FILE *out = GREATEST_STDOUT; \ - size_t i, line_i, line_len = 0; \ - int len = 0; /* format hexdump with differences highlighted */ \ - for (i = 0; i < env->size; i+= line_len) { \ - diff_mark = ' '; \ - line_len = env->size - i; \ - if (line_len > 16) { line_len = 16; } \ - for (line_i = i; line_i < i + line_len; line_i++) { \ - if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X'; \ - } \ - len += GREATEST_FPRINTF(out, "\n%04x %c ", \ - (unsigned int)i, diff_mark); \ - for (line_i = i; line_i < i + line_len; line_i++) { \ - int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ - len += GREATEST_FPRINTF(out, "%02x%c", \ - buf[line_i], m ? ' ' : '<'); \ - } \ - for (line_i = 0; line_i < 16 - line_len; line_i++) { \ - len += GREATEST_FPRINTF(out, " "); \ - } \ - GREATEST_FPRINTF(out, " "); \ - for (line_i = i; line_i < i + line_len; line_i++) { \ - unsigned char c = buf[line_i]; \ - len += GREATEST_FPRINTF(out, "%c", isprint(c) ? c : '.'); \ - } \ - } \ - len += GREATEST_FPRINTF(out, "\n"); \ - return len; \ -} \ - \ -void greatest_prng_init_first_pass(int id) { \ - greatest_info.prng[id].random_order = 1; \ - greatest_info.prng[id].count_run = 0; \ -} \ - \ -int greatest_prng_init_second_pass(int id, unsigned long seed) { \ - struct greatest_prng *p = &greatest_info.prng[id]; \ - if (p->count == 0) { return 0; } \ - p->count_ceil = p->count; \ - for (p->m = 1; p->m < p->count; p->m <<= 1) {} \ - p->state = seed & 0x1fffffff; /* only use lower 29 bits */ \ - p->a = 4LU * p->state; /* to avoid overflow when */ \ - p->a = (p->a ? p->a : 4) | 1; /* multiplied by 4 */ \ - p->c = 2147483647; /* and so p->c ((2 ** 31) - 1) is */ \ - p->initialized = 1; /* always relatively prime to p->a. */ \ - fprintf(stderr, "init_second_pass: a %lu, c %lu, state %lu\n", \ - p->a, p->c, p->state); \ - return 1; \ -} \ - \ -/* Step the pseudorandom number generator until its state reaches \ - * another test ID between 0 and the test count. \ - * This use a linear congruential pseudorandom number generator, \ - * with the power-of-two ceiling of the test count as the modulus, the \ - * masked seed as the multiplier, and a prime as the increment. For \ - * each generated value < the test count, run the corresponding test. \ - * This will visit all IDs 0 <= X < mod once before repeating, \ - * with a starting position chosen based on the initial seed. \ - * For details, see: Knuth, The Art of Computer Programming \ - * Volume. 2, section 3.2.1. */ \ -void greatest_prng_step(int id) { \ - struct greatest_prng *p = &greatest_info.prng[id]; \ - do { \ - p->state = ((p->a * p->state) + p->c) & (p->m - 1); \ - } while (p->state >= p->count_ceil); \ -} \ - \ -void GREATEST_INIT(void) { \ - /* Suppress unused function warning if features aren't used */ \ - (void)greatest_run_suite; \ - (void)greatest_parse_options; \ - (void)greatest_prng_step; \ - (void)greatest_prng_init_first_pass; \ - (void)greatest_prng_init_second_pass; \ - (void)greatest_set_test_suffix; \ - \ - memset(&greatest_info, 0, sizeof(greatest_info)); \ - greatest_info.width = GREATEST_DEFAULT_WIDTH; \ - GREATEST_SET_TIME(greatest_info.begin); \ -} \ - \ -/* Report passes, failures, skipped tests, the number of \ - * assertions, and the overall run time. */ \ -void GREATEST_PRINT_REPORT(void) { \ - if (!GREATEST_LIST_ONLY()) { \ - update_counts_and_reset_suite(); \ - GREATEST_SET_TIME(greatest_info.end); \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "\nTotal: %u test%s", \ - greatest_info.tests_run, \ - greatest_info.tests_run == 1 ? "" : "s"); \ - GREATEST_CLOCK_DIFF(greatest_info.begin, \ - greatest_info.end); \ - GREATEST_FPRINTF(GREATEST_STDOUT, ", %u assertion%s\n", \ - greatest_info.assertions, \ - greatest_info.assertions == 1 ? "" : "s"); \ - GREATEST_FPRINTF(GREATEST_STDOUT, \ - "Pass: %u, fail: %u, skip: %u.\n", \ - greatest_info.passed, \ - greatest_info.failed, greatest_info.skipped); \ - } \ -} \ - \ -greatest_type_info greatest_type_info_memory = { \ - greatest_memory_equal_cb, greatest_memory_printf_cb, \ -}; \ - \ -greatest_run_info greatest_info - -/* Handle command-line arguments, etc. */ -#define GREATEST_MAIN_BEGIN() \ - do { \ - GREATEST_INIT(); \ - greatest_parse_options(argc, argv); \ - } while (0) - -/* Report results, exit with exit status based on results. */ -#define GREATEST_MAIN_END() \ - do { \ - GREATEST_PRINT_REPORT(); \ - return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ - } while (0) - -/* Make abbreviations without the GREATEST_ prefix for the - * most commonly used symbols. */ -#if GREATEST_USE_ABBREVS -#define TEST GREATEST_TEST -#define SUITE GREATEST_SUITE -#define SUITE_EXTERN GREATEST_SUITE_EXTERN -#define RUN_TEST GREATEST_RUN_TEST -#define RUN_TEST1 GREATEST_RUN_TEST1 -#define RUN_SUITE GREATEST_RUN_SUITE -#define IGNORE_TEST GREATEST_IGNORE_TEST -#define ASSERT GREATEST_ASSERT -#define ASSERTm GREATEST_ASSERTm -#define ASSERT_FALSE GREATEST_ASSERT_FALSE -#define ASSERT_EQ GREATEST_ASSERT_EQ -#define ASSERT_NEQ GREATEST_ASSERT_NEQ -#define ASSERT_GT GREATEST_ASSERT_GT -#define ASSERT_GTE GREATEST_ASSERT_GTE -#define ASSERT_LT GREATEST_ASSERT_LT -#define ASSERT_LTE GREATEST_ASSERT_LTE -#define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT -#define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE -#define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T -#define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ -#define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ -#define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ -#define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ -#define ASSERT_FALSEm GREATEST_ASSERT_FALSEm -#define ASSERT_EQm GREATEST_ASSERT_EQm -#define ASSERT_NEQm GREATEST_ASSERT_NEQm -#define ASSERT_GTm GREATEST_ASSERT_GTm -#define ASSERT_GTEm GREATEST_ASSERT_GTEm -#define ASSERT_LTm GREATEST_ASSERT_LTm -#define ASSERT_LTEm GREATEST_ASSERT_LTEm -#define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm -#define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm -#define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm -#define ASSERT_STR_EQm GREATEST_ASSERT_STR_EQm -#define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm -#define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm -#define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm -#define PASS GREATEST_PASS -#define FAIL GREATEST_FAIL -#define SKIP GREATEST_SKIP -#define PASSm GREATEST_PASSm -#define FAILm GREATEST_FAILm -#define SKIPm GREATEST_SKIPm -#define SET_SETUP GREATEST_SET_SETUP_CB -#define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB -#define CHECK_CALL GREATEST_CHECK_CALL -#define SHUFFLE_TESTS GREATEST_SHUFFLE_TESTS -#define SHUFFLE_SUITES GREATEST_SHUFFLE_SUITES - -#ifdef GREATEST_VA_ARGS -#define RUN_TESTp GREATEST_RUN_TESTp -#endif - -#if GREATEST_USE_LONGJMP -#define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP -#define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm -#define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP -#define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm -#endif - -#endif /* USE_ABBREVS */ - -#if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) -} -#endif - -#endif diff --git a/tests/int2f-12/Makefile b/tests/int2f-12/Makefile deleted file mode 100644 index a3f34065..00000000 --- a/tests/int2f-12/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -# Makefile for INT 2F / AH=12h tests -# Open Watcom 16-bit, real-mode DOS, small memory model -# -# Directory layout assumed: -# tests/ -# greatest.h -# testlib.h -# testlib.c -# int2f-12/ -# tNNNN.c -# Makefile <- this file -# -# Usage: -# wmake build all .exe files -# wmake clean remove generated files -# wmake ref run all tests in reference mode (writes *.ref) -# wmake test run all tests in test mode (writes *.tst) - -CC = wcl -CFLAGS = -zq -q -ms -k4096 -INCLUDES= -i=.. -TESTLIB = ../testlib.c -DEPS = ../testlib.c ../testlib.h ../greatest.h - -# List of test executables (add new ones here as you implement them) -EXES = t121f.com t121f.exe t1203.exe t1204.exe t1211.exe t1212.exe t1213.exe t1214.exe t121a.exe t121c.exe t121d.exe t1225.exe - -all: $(EXES) - -# Implicit suffix rule: any .c -> .exe in this directory -# wmake uses this when no explicit rule exists for a target -.c.exe: $(DEPS) .AUTODEPEND - $(CC) $(CFLAGS) $(INCLUDES) $[*.c $(TESTLIB) - -# MSDOS requires SS=DOSSTACK so we need to build special version, FD kernel does not need SS=DOSSTACK so use .exe version -t121f.com: - $(CC) -zq -q -mt -fpc $(INCLUDES) -dUSEDOSSTACK t121f.c $(TESTLIB) - del testlib.obj - - -# Reference mode: run on MS-DOS to generate golden .ref files -ref: $(EXES) - for %f in ($(EXES)) do %f ref - -# Test mode: compare against .ref files, write .tst -test: $(EXES) - for %f in ($(EXES)) do %f test - -clean: .SYMBOLIC - @if exist *.obj del *.obj - @if exist *.map del *.map - @if exist *.err del *.err - -clobber: clean .SYMBOLIC - @if exist *.exe del *.exe - @if exist *.ref del *.ref - @if exist *.tst del *.tst - @if exist *.txt del *.txt - @if exist *.out del *.out diff --git a/tests/int2f-12/RUNTEST.BAT b/tests/int2f-12/RUNTEST.BAT deleted file mode 100644 index 177823cc..00000000 --- a/tests/int2f-12/RUNTEST.BAT +++ /dev/null @@ -1,14 +0,0 @@ -@ECHO OFF -ECHO Running test %1 -%1 ref > %2.txt -REM above create a .REF and .TXT file -%1 test > %2.out -IF [%ERRORLEVEL%]==1 GOTO failed -ECHO Success (all tests passed) -GOTO done -REM above creates a .TST and .OUT file -REM 1st arg is test.exe 2nd arg is function -:failed -ECHO at least one test failed -:done - diff --git a/tests/int2f-12/t1203.c b/tests/int2f-12/t1203.c deleted file mode 100644 index 58541b6a..00000000 --- a/tests/int2f-12/t1203.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * t1203.c -- INT 2Fh / AX=1203h GET DOS DATA SEGMENT - * - * Expected: ES = DOS internal data segment - * No register changes other than ES (and possibly AX) - */ -#include "../greatest.h" -#include "../testlib.h" - -const char * g_tbasename = "1203"; - -TEST test_1203(void) -{ - PROBE p; - memset(&p, 0, sizeof(p)); - p.before.ax = 0x1203; - /* No special input registers needed for this subfunction */ - - probe_int2f(&p); - - /* Record result -- actual assertion is the diff, not a hard value, - but we can sanity-check that ES is nonzero (DOS is loaded) */ - print_probe_verbose(&p, "GET_DOS_DATA_SEG", -1); - - ASSERT_FALSE(p.after.es == 0); /* ES must point somewhere */ - PASS(); -} - -SUITE(suite) -{ - test_1203(); -} diff --git a/tests/int2f-12/t1204.c b/tests/int2f-12/t1204.c deleted file mode 100644 index 24373dc1..00000000 --- a/tests/int2f-12/t1204.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * t1204.c -- INT 2Fh / AX=1204h NORMALIZE PATH SEPARATOR - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1204.html): - * AX = 1204h - * STACK: WORD character to normalize - * Return: AL = normalized character ('/' -> '\', others unchanged) - * ZF set if character is a path separator ('\', '/', or SWITCHAR) - * STACK unchanged - * - * NOTE ON CALLING CONVENTION: - * This function is unique among INT 2Fh/12xx subfunctions: the input - * character is passed as a WORD pushed onto the stack BEFORE the INT 2Fh, - * not in any register. - * - * Care registers: - * AL -- normalized character (CARE_AL) - * ZF -- set iff path separator (CARE_ZF) - * All other output registers are don't-cares. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 1204.ref, verbose stdout - * default / test TEST: read 1204.ref, run all cases, write 1204.tst - * - * Build: - * wcl -zq -q -ms -i=.. t1204.c ..\testlib.c - * - * Usage: - * T1204 ref (reference mode, writes 1204.ref) - * T1204 test (test mode, reads 1204.ref, writes 1204.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - - -const char *g_tbasename = "1204"; /* declared by test e.g. "1204" */ - - -/* ---- - * We care about AL (normalized char) and ZF (separator flag). - * All other output registers are don't-cares. - * ---- */ -#define CARE_1204 (CARE_AL | CARE_FLAGS) - - -/* ------------------------------------------------------------------ */ -/* Helper: fill a PROBE for recording purposes. */ -/* after.ax low byte = AL result; after.flags = FLAGS result. */ -/* ------------------------------------------------------------------ */ -static void setup_1204(PROBE *p, unsigned char ch) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x1204; - p->before.cx = (unsigned short)ch; /* input char stored in CX for log */ - p->value = (unsigned short)ch; -} - -/* ------------------------------------------------------------------ */ -/* Core test runner for one character. */ -/* ------------------------------------------------------------------ */ -static int run_char_case(const char *name, unsigned char ch) -{ - PROBE p; - - setup_1204(&p, ch); - - if (g_ref_mode) { - printf("INPUT: ch=0x%02X ('%c')\n", - (unsigned)ch, - (ch >= 0x20 && ch < 0x7F) ? (char)ch : '.' - ); - } - - return run_case(name, &p, CARE_1204, NULL); -} - -/* ------------------------------------------------------------------ */ -/* Test suites */ -/* ------------------------------------------------------------------ */ - -/* - * Path separator characters: '/', '\', and the default SWITCHAR '/'. - * All must return AL='\' (5Ch) and ZF=1. - */ -TEST test_separators(void) -{ - char name[TC_NAME_MAX]; - - /* Forward slash -- must be converted to backslash, ZF=1 */ - sprintf(name, "1204_fwdslash"); - ASSERT(run_char_case(name, '/')); - - /* Backslash -- already canonical, ZF=1 */ - sprintf(name, "1204_backslash"); - ASSERT(run_char_case(name, '\\')); - - PASS(); -} - -/* - * Non-separator printable ASCII characters: AL unchanged, ZF=0. - */ -TEST test_non_separators(void) -{ - char name[TC_NAME_MAX]; - unsigned int ch; - - /* Letters */ - sprintf(name, "1204_letter_A"); - ASSERT(run_char_case(name, 'A')); - sprintf(name, "1204_letter_a"); - ASSERT(run_char_case(name, 'a')); - sprintf(name, "1204_letter_Z"); - ASSERT(run_char_case(name, 'Z')); - sprintf(name, "1204_letter_z"); - ASSERT(run_char_case(name, 'z')); - - /* Digits */ - sprintf(name, "1204_digit_0"); - ASSERT(run_char_case(name, '0')); - sprintf(name, "1204_digit_9"); - ASSERT(run_char_case(name, '9')); - - /* Common filename chars */ - sprintf(name, "1204_dot"); - ASSERT(run_char_case(name, '.')); - sprintf(name, "1204_colon"); - ASSERT(run_char_case(name, ':')); - sprintf(name, "1204_space"); - ASSERT(run_char_case(name, ' ')); - sprintf(name, "1204_underscore"); - ASSERT(run_char_case(name, '_')); - sprintf(name, "1204_dash"); - ASSERT(run_char_case(name, '-')); - sprintf(name, "1204_tilde"); - ASSERT(run_char_case(name, '~')); - sprintf(name, "1204_bang"); - ASSERT(run_char_case(name, '!')); - sprintf(name, "1204_hash"); - ASSERT(run_char_case(name, '#')); - sprintf(name, "1204_dollar"); - ASSERT(run_char_case(name, '$')); - sprintf(name, "1204_percent"); - ASSERT(run_char_case(name, '%')); - sprintf(name, "1204_ampersand"); - ASSERT(run_char_case(name, '&')); - sprintf(name, "1204_at"); - ASSERT(run_char_case(name, '@')); - - /* -All- printable ASCII except '/' and '\' */ - /* *** we only print some to avoid excessive tests */ - for (ch = 0x20; ch <= 0x7E; ch+=3) { - if (ch == '/' || ch == '\\') - continue; - sprintf(name, "1204_ascii_0x%02X", ch); - ASSERT(run_char_case(name, (unsigned char)ch)); - } - - PASS(); -} - -/* - * Control characters and NUL: AL unchanged, ZF=0. - */ -TEST test_control_chars(void) -{ - char name[TC_NAME_MAX]; - - sprintf(name, "1204_nul"); - ASSERT(run_char_case(name, 0x00)); - - sprintf(name, "1204_ctrl_01"); - ASSERT(run_char_case(name, 0x01)); - - sprintf(name, "1204_ctrl_1A_EOF"); /* Ctrl-Z / EOF */ - ASSERT(run_char_case(name, 0x1A)); - - sprintf(name, "1204_ctrl_1B_ESC"); /* ESC */ - ASSERT(run_char_case(name, 0x1B)); - - sprintf(name, "1204_ctrl_1F"); - ASSERT(run_char_case(name, 0x1F)); - - sprintf(name, "1204_del_7F"); - ASSERT(run_char_case(name, 0x7F)); - - PASS(); -} - -/* - * High-byte characters (0x80..0xFF): AL unchanged, ZF=0. - * These are DOS codepage characters; none are path separators. - */ -TEST test_high_bytes(void) -{ - char name[TC_NAME_MAX]; - unsigned int ch; - - /* Spot-check a few */ - sprintf(name, "1204_high_80"); - ASSERT(run_char_case(name, 0x80)); - - sprintf(name, "1204_high_FE"); - ASSERT(run_char_case(name, 0xFE)); - - sprintf(name, "1204_high_FF"); - ASSERT(run_char_case(name, 0xFF)); - - /* Sweep 0x80..0xFF */ - /* *** we only print some to avoid excess tests */ - for (ch = 0x80; ch <= 0xFF; ch+=3) { - sprintf(name, "1204_high_0x%02X", ch); - ASSERT(run_char_case(name, (unsigned char)ch)); - } - - PASS(); -} - -/* - * Boundary: characters immediately adjacent to '/' (0x2F) and '\' (0x5C). - */ -TEST test_adjacent_to_separators(void) -{ - char name[TC_NAME_MAX]; - - sprintf(name, "1204_before_fwdslash"); /* 0x2E = '.' */ - ASSERT(run_char_case(name, 0x2E)); - - sprintf(name, "1204_after_fwdslash"); /* 0x30 = '0' */ - ASSERT(run_char_case(name, 0x30)); - - sprintf(name, "1204_before_backslash"); /* 0x5B = '[' */ - ASSERT(run_char_case(name, 0x5B)); - - sprintf(name, "1204_after_backslash"); /* 0x5D = ']' */ - ASSERT(run_char_case(name, 0x5D)); - - PASS(); -} - -/* ------------------------------------------------------------------ */ -/* Suite -- called in main to run tests */ -/* ------------------------------------------------------------------ */ - -SUITE(suite) -{ - RUN_TEST(test_separators); - RUN_TEST(test_non_separators); - RUN_TEST(test_control_chars); - RUN_TEST(test_high_bytes); - RUN_TEST(test_adjacent_to_separators); -} diff --git a/tests/int2f-12/t1211.c b/tests/int2f-12/t1211.c deleted file mode 100644 index 103d1627..00000000 --- a/tests/int2f-12/t1211.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * t1211.c -- INT 2Fh / AX=1211h NORMALIZE ASCIZ FILENAME - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1211.html): - * AX = 1211h - * DS:SI -> ASCIZ filename to normalize (source) - * ES:DI -> buffer for normalized filename (destination) - * Return: destination buffer filled with uppercased filename, - * forward slashes '/' converted to backslashes '\', - * NUL terminator copied. - * No register return value (AX, BX, CX, DX, SI, DI, DS, ES, FLAGS - * are all don't-cares). - * - * FreeDOS inthndlr.c case 0x11: - * Copies DS:SI -> ES:DI, converting a-z -> A-Z and '/' -> '\', - * until and including the NUL terminator. - * - * Care: - * No register return value is defined; CARE_NONE for registers. - * The output is entirely in the destination buffer. - * run_case() records/compares the destination buffer via the - * "B" lines in the .ref file -- the reference system writes what - * the DOS actually produced; test mode compares against that. - * This avoids any local re-implementation of the normalization logic. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 1211.ref, verbose stdout - * default / test TEST: read 1211.ref, run all cases, write 1211.tst - * - * Build: - * wcl -zq -q -ms -i=.. t1211.c ..\testlib.c - * - * Usage: - * T1211 ref (reference mode, writes 1211.ref) - * T1211 test (test mode, reads 1211.ref, writes 1211.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "1211"; - -/* ---- - * No register return value is defined for 1211h, only buffer. - * ---- */ -#define CARE_1211 (CARE_BUF) - -/* ---- - * Buffer sizes. - * Source and destination are kept in separate static buffers. - * We test strings up to 260 chars (MAX_PATH). - * ---- */ -#define MAX_STR_LEN 260 -#define BUF_SIZE (MAX_STR_LEN + 2) /* +2: NUL + sentinel byte */ - -static char g_src[BUF_SIZE]; /* source string passed in DS:SI */ -static char g_dst[BUF_SIZE]; /* destination buffer at ES:DI */ - -/* ---- - * Helper: set up a PROBE for AX=1211h. - * DS:SI -> g_src (source) - * ES:DI -> g_dst (destination) - * DS is explicitly set because it carries a real far pointer (DS:SI). - * ---- */ -static void setup_1211(PROBE *p, unsigned char *src_ptr, unsigned char *dst_ptr, unsigned short buf_len) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x1211; - p->before.ds = FP_SEG(src_ptr); /* DS:SI -> source */ - p->before.si = FP_OFF(src_ptr); - p->before.es = FP_SEG(dst_ptr); /* ES:DI -> dest */ - p->before.di = FP_OFF(dst_ptr); - p->buffer = (unsigned char far *)dst_ptr; - p->bufsize = buf_len; -} - -/* ---- - * Core helper: run one test case via run_case(). - * label -- unique test name suffix (prefixed with "1211_") - * src -- input string (copied into g_src) - * - * In reference mode: calls the DOS, records destination buffer to .ref. - * In test mode: calls the DOS, compares destination buffer to .ref. - * - * Also checks the sentinel byte after g_dst[len] is unchanged (no overrun). - * ---- */ -static int run_norm_case(const char *label, const char *src) -{ - PROBE p; - char name[TC_NAME_MAX]; - unsigned short srclen; - - /* Prepare source */ - strncpy(g_src, src, MAX_STR_LEN); - g_src[MAX_STR_LEN] = '\0'; - srclen = (unsigned short)strlen(g_src); - - /* Poison destination so we can detect partial writes */ - memset(g_dst, 0xCC, sizeof(g_dst)); - g_dst[BUF_SIZE - 1] = '\xAA'; /* sentinel */ - - setup_1211(&p, g_src, g_dst, srclen+1); - - sprintf(name, "1211_%s", label); - - if (g_ref_mode) - printf("INPUT: \"%s\"\n", g_src); - - /* run_case() handles probe + ref_write + ref_write_buf (ref mode) - * or probe + tst_compare + tst_compare_buf (test mode). - * buf_len = srclen + 1 to include the NUL terminator. */ - if (!run_case(name, &p, CARE_1211, NULL)) - return 0; - - if (g_ref_mode) - printf("OUTPUT: \"%s\"\n", g_dst); - - /* Verify sentinel not overwritten (both modes) */ - if ((unsigned char)g_dst[BUF_SIZE - 1] != 0xAA) { - printf("FAIL %s (sentinel overwritten)\n", name); - return 0; - } - - return 1; -} - -/* ------------------------------------------------------------------ */ -/* Test suites */ -/* ------------------------------------------------------------------ */ - -/* - * Empty string: NUL is the only byte; destination must contain NUL only. - */ -TEST test_empty(void) -{ - ASSERT(run_norm_case("empty", "")); - PASS(); -} - -/* - * Already-uppercase filenames: output must equal input exactly. - */ -TEST test_already_upper(void) -{ - ASSERT(run_norm_case("upper_simple", "FILENAME.EXT")); - ASSERT(run_norm_case("upper_path", "C:\\DIR\\FILE.TXT")); - ASSERT(run_norm_case("upper_root", "\\")); - ASSERT(run_norm_case("upper_dot", ".")); - ASSERT(run_norm_case("upper_dotdot", "..")); - ASSERT(run_norm_case("upper_drive", "C:")); - ASSERT(run_norm_case("upper_drive_rel", "C:FOO")); - ASSERT(run_norm_case("upper_wildcard", "*.*")); - ASSERT(run_norm_case("upper_wildcard2", "?.?")); - PASS(); -} - -/* - * Lowercase letters: must be uppercased. - */ -TEST test_lowercase(void) -{ - ASSERT(run_norm_case("lower_simple", "filename.ext")); - ASSERT(run_norm_case("lower_mixed", "FileName.Ext")); - ASSERT(run_norm_case("lower_all_az", "abcdefghijklmnopqrstuvwxyz")); - ASSERT(run_norm_case("lower_path", "c:\\dir\\file.txt")); - ASSERT(run_norm_case("lower_drive_rel", "c:foo")); - ASSERT(run_norm_case("lower_deep", "a\\b\\c\\d\\e\\f\\g.txt")); - ASSERT(run_norm_case("lower_single_a", "a")); - ASSERT(run_norm_case("lower_single_z", "z")); - PASS(); -} - -/* - * Forward-slash conversion: '/' must become '\'. - */ -TEST test_slash_conversion(void) -{ - ASSERT(run_norm_case("slash_only", "/")); - ASSERT(run_norm_case("slash_double", "//")); - ASSERT(run_norm_case("slash_path", "dir/file.txt")); - ASSERT(run_norm_case("slash_mixed", "a/b\\c/d")); - ASSERT(run_norm_case("slash_leading", "/dir/file")); - ASSERT(run_norm_case("slash_trailing", "dir/")); - ASSERT(run_norm_case("slash_drive", "c:/dir/file.txt")); - ASSERT(run_norm_case("slash_all", "a/b/c/d/e/f/g")); - PASS(); -} - -/* - * Combined: lowercase + forward slashes together. - */ -TEST test_combined(void) -{ - ASSERT(run_norm_case("combo_simple", "c:/dir/file.txt")); - ASSERT(run_norm_case("combo_deep", "c:/users/foo/bar/baz.txt")); - ASSERT(run_norm_case("combo_mixed", "C:/Dir/File.Txt")); - ASSERT(run_norm_case("combo_all_lower", "abcdefghijklmnopqrstuvwxyz/xyz")); - ASSERT(run_norm_case("combo_83", "c:/progra~1/myapp.exe")); - PASS(); -} - -/* - * Characters that must pass through unchanged: - * digits, punctuation, high bytes, control chars (except '/' and a-z). - */ -TEST test_passthrough(void) -{ - /* Digits */ - ASSERT(run_norm_case("pass_digits", "0123456789")); - - /* Punctuation that is NOT '/' */ - ASSERT(run_norm_case("pass_punct", "!@#$%^&*()-_=+[]{}|;:',.<>?`~")); - - /* Backslash already canonical */ - ASSERT(run_norm_case("pass_backslash", "\\")); - - /* Space */ - ASSERT(run_norm_case("pass_space", "A B C")); - - /* High bytes (DOS codepage chars) -- must be copied unchanged */ - ASSERT(run_norm_case("pass_high_80", "\x80")); - ASSERT(run_norm_case("pass_high_fe", "\xFE")); - ASSERT(run_norm_case("pass_high_ff", "\xFF")); - ASSERT(run_norm_case("pass_high_mix", - "\x80\x90\xA0\xB0\xC0\xD0\xE0\xF0")); - - /* Control characters (non-NUL) */ - ASSERT(run_norm_case("pass_ctrl_01", "\x01")); - ASSERT(run_norm_case("pass_ctrl_1a", "\x1A")); /* Ctrl-Z */ - ASSERT(run_norm_case("pass_ctrl_1b", "\x1B")); /* ESC */ - ASSERT(run_norm_case("pass_ctrl_1f", "\x1F")); - - PASS(); -} - -/* - * Boundary: characters immediately adjacent to 'a' (0x61), 'z' (0x7A), - * and '/' (0x2F) to confirm the range checks are tight. - */ -TEST test_boundary_chars(void) -{ - /* 0x60 = '`' -- just below 'a', must NOT be uppercased */ - ASSERT(run_norm_case("bound_backtick", "`")); - - /* 0x7B = '{' -- just above 'z', must NOT be uppercased */ - ASSERT(run_norm_case("bound_lbrace", "{")); - - /* 0x2E = '.' -- just below '/', must NOT become '\' */ - ASSERT(run_norm_case("bound_dot", ".")); - - /* 0x30 = '0' -- just above '/', must NOT become '\' */ - ASSERT(run_norm_case("bound_zero", "0")); - - /* 0x5B = '[' -- just below '\' (0x5C), must pass through */ - ASSERT(run_norm_case("bound_lbracket", "[")); - - /* 0x5D = ']' -- just above '\' (0x5C), must pass through */ - ASSERT(run_norm_case("bound_rbracket", "]")); - - PASS(); -} - -/* - * Typical DOS path forms. - */ -TEST test_dos_paths(void) -{ - ASSERT(run_norm_case("path_root_only", "\\")); - ASSERT(run_norm_case("path_drive_root", "C:\\")); - ASSERT(run_norm_case("path_abs", - "C:\\WINDOWS\\SYSTEM32\\CMD.EXE")); - ASSERT(run_norm_case("path_rel", "DIR\\FILE.TXT")); - ASSERT(run_norm_case("path_dotdot", "..\\..\\FILE.TXT")); - ASSERT(run_norm_case("path_trailing_bs", "C:\\DIR\\")); - ASSERT(run_norm_case("path_unc_like", "\\\\SERVER\\SHARE\\FILE")); - ASSERT(run_norm_case("path_spaces", "C:\\MY DOCS\\FILE.TXT")); - ASSERT(run_norm_case("path_83_upper", "C:\\PROGRA~1\\MYAPP.EXE")); - ASSERT(run_norm_case("path_83_lower", "c:\\progra~1\\myapp.exe")); - ASSERT(run_norm_case("path_mixed_slash", "c:/windows/system32/cmd.exe")); - PASS(); -} - -/* - * Alignment: source and destination at various byte offsets within - * their respective buffers, to catch word-alignment assumptions. - */ -TEST test_alignment(void) -{ - static char src_aligned[BUF_SIZE + 8]; - static char dst_aligned[BUF_SIZE + 8]; - PROBE p; - char name[TC_NAME_MAX]; - unsigned int off; - const char *base = "abcdef/GHIJKL"; - unsigned short baselen; - - baselen = (unsigned short)strlen(base); - - for (off = 0; off <= 7; off++) { - char *src_ptr = src_aligned + off; - char *dst_ptr = dst_aligned + off; - - strcpy(src_ptr, base); - memset(dst_ptr, 0xCC, (unsigned short)(baselen + 2)); - - setup_1211(&p, src_ptr, dst_ptr, baselen+1); - - sprintf(name, "1211_align_off%u", off); - - if (g_ref_mode) - printf("INPUT (off=%u): \"%s\"\n", off, base); - - ASSERT(run_case(name, &p, CARE_1211, NULL)); - } - - PASS(); -} - -/* - * Source == destination (in-place normalization). - * RBIL does not forbid src==dst; FreeDOS reads one byte then writes it, - * so in-place is safe. - */ -TEST test_inplace(void) -{ - PROBE p; - const char *src = "c:/dir/file.txt"; - unsigned short srclen; - - strncpy(g_src, src, MAX_STR_LEN); - g_src[MAX_STR_LEN] = '\0'; - srclen = (unsigned short)strlen(g_src); - - setup_1211(&p, g_src, g_src, srclen+1); - - if (g_ref_mode) - printf("INPUT (in-place): \"%s\"\n", src); - - ASSERT(run_case("1211_inplace", &p, CARE_1211, NULL)); - - PASS(); -} - -/* - * Single-character strings for every printable ASCII value. - * Verifies the per-character transformation table is correct. - */ -TEST test_single_chars(void) -{ - char name[TC_NAME_MAX]; - unsigned int ch; - char src[2]; - - src[1] = '\0'; - for (ch = 0x01; ch <= 0x7E; ch++) { - src[0] = (char)ch; - sprintf(name, "char_0x%02X", ch); - ASSERT(run_norm_case(name, src)); - } - - /* A few high bytes */ - src[0] = (char)0x80; ASSERT(run_norm_case("char_0x80", src)); - src[0] = (char)0xA0; ASSERT(run_norm_case("char_0xA0", src)); - src[0] = (char)0xFF; ASSERT(run_norm_case("char_0xFF", src)); - - PASS(); -} - -/* ------------------------------------------------------------------ */ -/* Suite */ -/* ------------------------------------------------------------------ */ - -SUITE(suite) -{ - RUN_TEST(test_empty); - RUN_TEST(test_already_upper); - RUN_TEST(test_lowercase); - RUN_TEST(test_slash_conversion); - RUN_TEST(test_combined); - RUN_TEST(test_passthrough); - RUN_TEST(test_boundary_chars); - RUN_TEST(test_dos_paths); - RUN_TEST(test_alignment); - RUN_TEST(test_inplace); - RUN_TEST(test_single_chars); -} diff --git a/tests/int2f-12/t1212.c b/tests/int2f-12/t1212.c deleted file mode 100644 index e9c07c3a..00000000 --- a/tests/int2f-12/t1212.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * t1212.c -- INT 2Fh / AX=1212h GET LENGTH OF ASCIZ STRING - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1212.html): - * AX = 1212h - * ES:DI -> ASCIZ string - * Return: CX = length of string (not counting NUL terminator) - * - * All other registers (AX, BX, DX, SI, DS, ES, FLAGS) are don't-cares - * for pass/fail purposes; they are recorded in the .ref file but marked - * "????" so they do not affect test results on other DOS versions. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 1212.ref, verbose stdout - * default / test TEST: read 1212.ref, run all cases, write 1212.tst - * - * Build: - * wcl -zq -q -ms -i=.. t1212.c ..\testlib.c - * - * Usage: - * T1212 ref (reference mode, writes 1212.ref) - * T1212 test (test mode, reads 1212.ref, writes 1212.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "1212"; - - -/* ----------------------------------------------------------------------- - * We only care about CX on return (the string length). - * All other output registers are don't-cares. - * --------------------------------------------------------------------- */ -#define CARE_1212 (CARE_CX) - -/* ----------------------------------------------------------------------- - * Maximum string length we will test. - * DOS path buffers are 260 bytes; we go a bit beyond to probe limits. - * 513 bytes = 512-char string + NUL. - * --------------------------------------------------------------------- */ -#define MAX_STR_LEN 512 -#define BUF_SIZE (MAX_STR_LEN + 1) - -/* Static buffer -- avoids stack overflow in small model */ -static char g_strbuf[BUF_SIZE]; - -/* ----------------------------------------------------------------------- - * Helper: set up a PROBE for AX=1212h with ES:DI -> string s - * --------------------------------------------------------------------- */ -static void setup_1212(PROBE *p, const char far *s, unsigned short max_buf_len) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x1212; - p->before.es = FP_SEG(s); - p->before.di = FP_OFF(s); - /* All other input regs zero -- they are not used by this subfunction */ - p->before.ds = FP_SEG(p); /* DS must be a valid segment */ - p->buffer = (unsigned char far *)s; - /* Dump at most 32 bytes of the string for the verbose log */ - p->bufsize = (unsigned short)(_fstrlen(s) < max_buf_len ? _fstrlen(s) + 1 : max_buf_len); -} - -/* ----------------------------------------------------------------------- - * Helper: run one length-based test case - * --------------------------------------------------------------------- */ -static int run_len_case(unsigned short len) -{ - PROBE p; - char name[TC_NAME_MAX]; /* big enough for test name and a number */ - - build_test_string(g_strbuf, len); - setup_1212(&p, g_strbuf, 32); - - sprintf(name, "1212_len_%u", (unsigned)len); - - /* In verbose/reference mode, print the input string length */ - if (g_ref_mode) { - printf("INPUT: len=%u str=\"", (unsigned)len); - if (len <= 32) - printf("%s", g_strbuf); - else - printf("%.32s...", g_strbuf); - printf("\"\n"); - } - - return run_case(name, &p, CARE_1212, NULL); -} - -/* ----------------------------------------------------------------------- - * Helper: run one literal string test case - * --------------------------------------------------------------------- */ -static int run_lit_case(const char *label, const char *lit) -{ - PROBE p; - char name[TC_NAME_MAX]; /* big enough for name, shouldn't exceed 80 column line */ - - /* Copy literal into g_strbuf so it is in a known near segment */ - strncpy(g_strbuf, lit, BUF_SIZE - 1); - g_strbuf[BUF_SIZE - 1] = '\0'; - - setup_1212(&p, g_strbuf, 32); - - sprintf(name, "1212_%s", label); - - if (g_ref_mode) { - printf("INPUT: literal=\"%s\"\n", g_strbuf); - } - - return run_case(name, &p, CARE_1212, NULL); -} - -/* ----------------------------------------------------------------------- - * Test suites - * --------------------------------------------------------------------- */ - -/* - * Required lengths from the spec: - * 0, 1, 2, 3, 64, 128, 256, 260, 512 - */ -TEST test_required_lengths(void) -{ - ASSERT(run_len_case(0)); - ASSERT(run_len_case(1)); - ASSERT(run_len_case(2)); - ASSERT(run_len_case(3)); - ASSERT(run_len_case(64)); - ASSERT(run_len_case(128)); - ASSERT(run_len_case(256)); - ASSERT(run_len_case(260)); - ASSERT(run_len_case(512)); - PASS(); -} - -/* - * Boundary lengths: one below and one above each power-of-two and - * DOS-significant boundary. - */ -TEST test_boundary_lengths(void) -{ - ASSERT(run_len_case(4)); /* just above 3 */ - ASSERT(run_len_case(7)); /* 8 - 1 */ - ASSERT(run_len_case(8)); - ASSERT(run_len_case(9)); /* 8 + 1 */ - ASSERT(run_len_case(63)); /* 64 - 1 */ - ASSERT(run_len_case(65)); /* 64 + 1 */ - ASSERT(run_len_case(127)); /* 128 - 1 */ - ASSERT(run_len_case(129)); /* 128 + 1 */ - ASSERT(run_len_case(255)); /* 256 - 1 */ - ASSERT(run_len_case(257)); /* 256 + 1 */ - ASSERT(run_len_case(259)); /* MAX_PATH - 1 */ - ASSERT(run_len_case(261)); /* MAX_PATH + 1 */ - ASSERT(run_len_case(511)); /* 512 - 1 */ - PASS(); -} - -/* - * Literal corner-case strings that exercise specific DOS path semantics. - */ -TEST test_literal_cases(void) -{ - /* Empty string: length must be 0 */ - ASSERT(run_lit_case("empty", "")); - - /* Single characters */ - ASSERT(run_lit_case("dot", ".")); - ASSERT(run_lit_case("dotdot", "..")); - ASSERT(run_lit_case("backslash", "\\")); - ASSERT(run_lit_case("fwdslash", "/")); - ASSERT(run_lit_case("colon", ":")); - ASSERT(run_lit_case("space", " ")); - ASSERT(run_lit_case("nul_like_ctrl", "\x01")); /* non-NUL ctrl char */ - - /* Drive-letter forms */ - ASSERT(run_lit_case("drive_only", "C:")); - ASSERT(run_lit_case("drive_root", "C:\\")); - ASSERT(run_lit_case("drive_rel", "C:FOO")); - - /* Path forms */ - ASSERT(run_lit_case("root_only", "\\")); - ASSERT(run_lit_case("trailing_bslash", "ABC\\")); - ASSERT(run_lit_case("mixed_slashes", "A/B\\C/D")); - ASSERT(run_lit_case("deep_path", "A\\B\\C\\D\\E\\F\\G")); - ASSERT(run_lit_case("spaces_inside", "A B C D")); - ASSERT(run_lit_case("three_spaces", " ")); - - /* Wildcard characters (not path separators, but common in DOS) */ - ASSERT(run_lit_case("wildcard_star", "*.*")); - ASSERT(run_lit_case("wildcard_q", "?.?")); - - /* 8.3 filename */ - ASSERT(run_lit_case("filename_83", "FILENAME.EXT")); - - /* All printable ASCII (length 94) */ - ASSERT(run_lit_case("printable_ascii", - " !\"#$%&'()*+,-./0123456789:;<=>?@" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" - "abcdefghijklmnopqrstuvwxyz{|}~")); - - /* High-byte characters (DOS codepage chars, not NUL) */ - ASSERT(run_lit_case("high_byte_80", "\x80")); - ASSERT(run_lit_case("high_byte_fe", "\xFE")); - ASSERT(run_lit_case("high_byte_ff", "\xFF")); - - PASS(); -} - -/* - * Alignment corner cases: string starting at various offsets within - * g_strbuf to catch any word-alignment assumptions in the DOS kernel. - */ -TEST test_alignment_cases(void) -{ - PROBE p; - char name[TC_NAME_MAX]; /* big enough for name and a number */ - unsigned int offset; - - /* Test offsets 0..7 with a 16-char string */ - for (offset = 0; offset <= 7; offset++) { - char far *s; - - build_test_string(g_strbuf, 16); - s = (char far *)(g_strbuf + offset); - - setup_1212(&p, s, 17); - - sprintf(name, "1212_align_off%u", offset); - - if (g_ref_mode) - printf("INPUT: offset=%u str=\"%.16s\"\n", offset, s); - - ASSERT(run_case(name, &p, CARE_1212, NULL)); - } - - PASS(); -} - -/* - * Repeated-NUL / embedded-NUL: the function should stop at the FIRST NUL. - * We manually construct strings with a NUL in the middle. - * Expected CX = position of first NUL. - */ -TEST test_embedded_nul(void) -{ - PROBE p; - - /* "ABC\0DEF" -- length should be 3, not 7 */ - memcpy(g_strbuf, "ABC\x00" "DEF", 8); - - setup_1212(&p, g_strbuf, 8); - - if (g_ref_mode) - printf("INPUT: \"ABCDEF\" (embedded NUL at offset 3)\n"); - - ASSERT(run_case("1212_embedded_nul", &p, CARE_1212, NULL)); - - PASS(); -} - -/* ----------------------------------------------------------------------- - * Suite - * --------------------------------------------------------------------- */ - -SUITE(suite) -{ - RUN_TEST(test_required_lengths); - RUN_TEST(test_boundary_lengths); - RUN_TEST(test_literal_cases); - RUN_TEST(test_alignment_cases); - RUN_TEST(test_embedded_nul); -} diff --git a/tests/int2f-12/t1213.c b/tests/int2f-12/t1213.c deleted file mode 100644 index bcd694cd..00000000 --- a/tests/int2f-12/t1213.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * t1213.c -- INT 2Fh / AX=1213h UPPERCASE CHARACTER - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1213.html): - * AX = 1213h - * STACK: WORD containing character to uppercase (low byte used) - * Return: AL = uppercased character - * a-z (0x61..0x7A) -> A-Z (0x41..0x5A) - * all other byte values returned unchanged - * - * NOTE ON CALLING CONVENTION: - * Like AX=1204h, the input character is passed as a WORD pushed onto - * the stack BEFORE INT 2Fh, not in any register. The PROBE.value - * field carries this word; probe_int2f() pushes it before the INT. - * - * Care registers: - * AL -- uppercased character (CARE_AL) - * All other output registers are don't-cares. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 1213.ref, verbose stdout - * default / test TEST: read 1213.ref, run all cases, write 1213.tst - * - * Build: - * wcl -zq -q -ms -i=.. t1213.c ..\testlib.c - * - * Usage: - * T1213 ref (reference mode, writes 1213.ref) - * T1213 test (test mode, reads 1213.ref, writes 1213.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "1213"; - -/* ---- - * We only care about AL on return (the uppercased character). - * All other output registers are don't-cares. - * ---- */ -#define CARE_1213 (CARE_AL) - -/* ---- - * Helper: set up a PROBE for AX=1213h. - * The input character is passed via p->value (pushed on stack before INT 2Fh). - * ---- */ -static void setup_1213(PROBE *p, unsigned char ch) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x1213; - p->before.cx = (unsigned short)ch; /* store in CX for verbose log only */ - p->value = (unsigned short)ch; /* actual input: pushed on stack */ -} - -/* ---- - * Core helper: run one character test case. - * ---- */ -static int run_char_case(const char *name, unsigned char ch) -{ - PROBE p; - - setup_1213(&p, ch); - - if (g_ref_mode) { - printf("INPUT: ch=0x%02X ('%c')\n", - (unsigned)ch, - (ch >= 0x20 && ch < 0x7F) ? (char)ch : '.'); - } - - return run_case(name, &p, CARE_1213, NULL); -} - -/* ---- */ -/* Test suites */ -/* ---- */ - -/* - * Lowercase letters a..z: each must be uppercased to A..Z. - */ -TEST test_lowercase_letters(void) -{ - char name[TC_NAME_MAX]; - int i; - - for (i = 0; i < 26; i++) { - unsigned char ch = (unsigned char)('a' + i); - sprintf(name, "1213_lower_%c", ch); - ASSERT(run_char_case(name, ch)); - } - - PASS(); -} - -/* - * Uppercase letters A..Z: must be returned unchanged. - */ -TEST test_uppercase_letters(void) -{ - char name[TC_NAME_MAX]; - int i; - - for (i = 0; i < 26; i++) { - unsigned char ch = (unsigned char)('A' + i); - sprintf(name, "1213_upper_%c", ch); - ASSERT(run_char_case(name, ch)); - } - - PASS(); -} - -/* - * Digits 0..9: must be returned unchanged. - */ -TEST test_digits(void) -{ - char name[TC_NAME_MAX]; - int i; - - for (i = 0; i <= 9; i++) { - unsigned char ch = (unsigned char)('0' + i); - sprintf(name, "1213_digit_%c", ch); - ASSERT(run_char_case(name, ch)); - } - - PASS(); -} - -/* - * Boundary characters immediately adjacent to the a-z range. - * 0x60 = '`' (just below 'a' 0x61) -- must NOT be uppercased. - * 0x7B = '{' (just above 'z' 0x7A) -- must NOT be uppercased. - * 0x40 = '@' (just below 'A' 0x41) -- must pass through unchanged. - * 0x5B = '[' (just above 'Z' 0x5A) -- must pass through unchanged. - */ -TEST test_boundary_chars(void) -{ - ASSERT(run_char_case("1213_backtick", 0x60)); /* just below 'a' */ - ASSERT(run_char_case("1213_lbrace", 0x7B)); /* just above 'z' */ - ASSERT(run_char_case("1213_at", 0x40)); /* just below 'A' */ - ASSERT(run_char_case("1213_lbracket", 0x5B)); /* just above 'Z' */ - ASSERT(run_char_case("1213_rbracket", 0x5D)); /* 'Z'+3 */ - ASSERT(run_char_case("1213_underscore", 0x5F)); /* 'Z'+5 */ - PASS(); -} - -/* - * Punctuation and special printable ASCII (not letters or digits): - * all must be returned unchanged. - */ -TEST test_punctuation(void) -{ - ASSERT(run_char_case("1213_space", ' ')); - ASSERT(run_char_case("1213_bang", '!')); - ASSERT(run_char_case("1213_hash", '#')); - ASSERT(run_char_case("1213_dollar", '$')); - ASSERT(run_char_case("1213_percent", '%')); - ASSERT(run_char_case("1213_ampersand", '&')); - ASSERT(run_char_case("1213_star", '*')); - ASSERT(run_char_case("1213_plus", '+')); - ASSERT(run_char_case("1213_comma", ',')); - ASSERT(run_char_case("1213_minus", '-')); - ASSERT(run_char_case("1213_dot", '.')); - ASSERT(run_char_case("1213_fwdslash", '/')); - ASSERT(run_char_case("1213_colon", ':')); - ASSERT(run_char_case("1213_semicolon", ';')); - ASSERT(run_char_case("1213_lt", '<')); - ASSERT(run_char_case("1213_eq", '=')); - ASSERT(run_char_case("1213_gt", '>')); - ASSERT(run_char_case("1213_question", '?')); - ASSERT(run_char_case("1213_backslash", '\\')); - ASSERT(run_char_case("1213_caret", '^')); - ASSERT(run_char_case("1213_tilde", '~')); - ASSERT(run_char_case("1213_del", 0x7F)); - PASS(); -} - -/* - * Control characters (0x00..0x1F): must be returned unchanged. - */ -TEST test_control_chars(void) -{ - char name[TC_NAME_MAX]; - unsigned int ch; - - for (ch = 0x00; ch <= 0x1F; ch++) { - sprintf(name, "1213_ctrl_0x%02X", ch); - ASSERT(run_char_case(name, (unsigned char)ch)); - } - - PASS(); -} - -/* - * High-byte characters (0x80..0xFF): must be returned unchanged. - * These are DOS codepage characters; none are in the a-z ASCII range. - * Sweep every third value to keep the test count manageable. - */ -TEST test_high_bytes(void) -{ - char name[TC_NAME_MAX]; - unsigned int ch; - - /* Spot-check boundaries */ - ASSERT(run_char_case("1213_high_80", 0x80)); - ASSERT(run_char_case("1213_high_81", 0x81)); - ASSERT(run_char_case("1213_high_FE", 0xFE)); - ASSERT(run_char_case("1213_high_FF", 0xFF)); - - /* Sweep 0x82..0xFD every 3rd byte */ - for (ch = 0x82; ch <= 0xFD; ch += 3) { - sprintf(name, "1213_high_0x%02X", ch); - ASSERT(run_char_case(name, (unsigned char)ch)); - } - - PASS(); -} - -/* - * Full sweep of all 256 byte values. - * Verifies the complete transformation table in one pass. - * Every third value is tested to keep the .ref file compact. - */ -TEST test_full_sweep(void) -{ - char name[TC_NAME_MAX]; - unsigned int ch; - - for (ch = 0x00; ch <= 0xFF; ch += 3) { - sprintf(name, "1213_sweep_0x%02X", ch); - ASSERT(run_char_case(name, (unsigned char)ch)); - } - - PASS(); -} - -/* ---- */ -/* Suite */ -/* ---- */ - -SUITE(suite) -{ - RUN_TEST(test_lowercase_letters); - RUN_TEST(test_uppercase_letters); - RUN_TEST(test_digits); - RUN_TEST(test_boundary_chars); - RUN_TEST(test_punctuation); - RUN_TEST(test_control_chars); - RUN_TEST(test_high_bytes); - RUN_TEST(test_full_sweep); -} diff --git a/tests/int2f-12/t1214.c b/tests/int2f-12/t1214.c deleted file mode 100644 index cf3ce78f..00000000 --- a/tests/int2f-12/t1214.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * t1214.c -- INT 2Fh / AX=1214h COMPARE FAR POINTERS - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1214.html): - * AX = 1214h - * DS:SI = first far pointer - * ES:DI = second far pointer - * Return: ZF=1 if DS==ES and SI==DI (pointers are equal) - * ZF=0 if DS!=ES or SI!=DI (pointers are not equal) - * CF=0 always - * No other registers modified. - * - * Note: comparison is on the raw segment:offset pairs as stored, NOT - * on normalised linear addresses. Two pointers that address the same - * physical byte but have different segment:offset representations are - * considered NOT equal. - * - * Care registers: - * FLAGS -- ZF and CF (CARE_FLAGS) - * All other output registers are don't-cares. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 1214.ref, verbose stdout - * default / test TEST: read 1214.ref, run all cases, write 1214.tst - * - * Build: - * wcl -zq -q -ms -i=.. t1214.c ..\testlib.c - * - * Usage: - * T1214 ref (reference mode, writes 1214.ref) - * T1214 test (test mode, reads 1214.ref, writes 1214.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "1214"; - -/* ---- - * We only care about FLAGS on return (ZF and CF). - * All other output registers are don't-cares. - * ---- */ -#define CARE_1214 (CARE_FLAGS) - -/* ---- - * Helper: set up a PROBE for AX=1214h. - * DS:SI = first pointer (seg1:off1) - * ES:DI = second pointer (seg2:off2) - * ---- */ -static void setup_1214(PROBE *p, - unsigned short seg1, unsigned short off1, - unsigned short seg2, unsigned short off2) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x1214; - p->before.ds = seg1; - p->before.si = off1; - p->before.es = seg2; - p->before.di = off2; -} - -/* ---- - * Core helper: run one comparison test case. - * ---- */ -static int run_cmp_case(const char *name, - unsigned short seg1, unsigned short off1, - unsigned short seg2, unsigned short off2) -{ - PROBE p; - - setup_1214(&p, seg1, off1, seg2, off2); - - if (g_ref_mode) { - printf("INPUT: ptr1=%04X:%04X ptr2=%04X:%04X\n", - seg1, off1, seg2, off2); - } - - return run_case(name, &p, CARE_1214, NULL); -} - -/* ---- */ -/* Test suites */ -/* ---- */ - -/* - * Equal pointers: same segment AND same offset. - * ZF must be set (1), CF must be clear (0). - */ -TEST test_equal_pointers(void) -{ - /* Both zero */ - ASSERT(run_cmp_case("1214_eq_zero_zero", 0x0000, 0x0000, 0x0000, 0x0000)); - - /* Typical DOS data segment values */ - ASSERT(run_cmp_case("1214_eq_0070_0000", 0x0070, 0x0000, 0x0070, 0x0000)); - ASSERT(run_cmp_case("1214_eq_1234_5678", 0x1234, 0x5678, 0x1234, 0x5678)); - - /* Maximum values */ - ASSERT(run_cmp_case("1214_eq_FFFF_FFFF", 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF)); - ASSERT(run_cmp_case("1214_eq_FFFF_0000", 0xFFFF, 0x0000, 0xFFFF, 0x0000)); - ASSERT(run_cmp_case("1214_eq_0000_FFFF", 0x0000, 0xFFFF, 0x0000, 0xFFFF)); - - /* Segment = 0, various offsets */ - ASSERT(run_cmp_case("1214_eq_0000_0001", 0x0000, 0x0001, 0x0000, 0x0001)); - ASSERT(run_cmp_case("1214_eq_0000_8000", 0x0000, 0x8000, 0x0000, 0x8000)); - - /* Offset = 0, various segments */ - ASSERT(run_cmp_case("1214_eq_8000_0000", 0x8000, 0x0000, 0x8000, 0x0000)); - - /* Pointer to our own code segment (self-referential) */ - ASSERT(run_cmp_case("1214_eq_self", - FP_SEG(run_cmp_case), FP_OFF(run_cmp_case), - FP_SEG(run_cmp_case), FP_OFF(run_cmp_case))); - - PASS(); -} - -/* - * Unequal pointers: segment differs, offset same. - * ZF must be clear (0). - */ -TEST test_unequal_seg_only(void) -{ - ASSERT(run_cmp_case("1214_ne_seg_0001_vs_0002", 0x0001, 0x0000, 0x0002, 0x0000)); - ASSERT(run_cmp_case("1214_ne_seg_0000_vs_0001", 0x0000, 0x1234, 0x0001, 0x1234)); - ASSERT(run_cmp_case("1214_ne_seg_1234_vs_5678", 0x1234, 0xABCD, 0x5678, 0xABCD)); - ASSERT(run_cmp_case("1214_ne_seg_FFFE_vs_FFFF", 0xFFFE, 0x0000, 0xFFFF, 0x0000)); - ASSERT(run_cmp_case("1214_ne_seg_0000_vs_FFFF", 0x0000, 0x0000, 0xFFFF, 0x0000)); - PASS(); -} - -/* - * Unequal pointers: offset differs, segment same. - * ZF must be clear (0). - */ -TEST test_unequal_off_only(void) -{ - ASSERT(run_cmp_case("1214_ne_off_0000_vs_0001", 0x1000, 0x0000, 0x1000, 0x0001)); - ASSERT(run_cmp_case("1214_ne_off_0001_vs_0000", 0x1000, 0x0001, 0x1000, 0x0000)); - ASSERT(run_cmp_case("1214_ne_off_1234_vs_5678", 0xABCD, 0x1234, 0xABCD, 0x5678)); - ASSERT(run_cmp_case("1214_ne_off_FFFE_vs_FFFF", 0x0000, 0xFFFE, 0x0000, 0xFFFF)); - ASSERT(run_cmp_case("1214_ne_off_0000_vs_FFFF", 0x0000, 0x0000, 0x0000, 0xFFFF)); - PASS(); -} - -/* - * Unequal pointers: both segment and offset differ. - * ZF must be clear (0). - */ -TEST test_unequal_both(void) -{ - ASSERT(run_cmp_case("1214_ne_both_0001_0001_vs_0002_0002", - 0x0001, 0x0001, 0x0002, 0x0002)); - ASSERT(run_cmp_case("1214_ne_both_1234_5678_vs_ABCD_EF01", - 0x1234, 0x5678, 0xABCD, 0xEF01)); - ASSERT(run_cmp_case("1214_ne_both_0000_0000_vs_FFFF_FFFF", - 0x0000, 0x0000, 0xFFFF, 0xFFFF)); - ASSERT(run_cmp_case("1214_ne_both_FFFF_FFFF_vs_0000_0000", - 0xFFFF, 0xFFFF, 0x0000, 0x0000)); - PASS(); -} - -/* - * Aliased pointers: different segment:offset pairs that address the - * same physical byte (e.g. 0x1000:0x0010 == 0x1001:0x0000 == linear 0x10010). - * The function compares raw pairs, so ZF must be CLEAR (not equal). - * This confirms the function does NOT normalise before comparing. - */ -TEST test_aliased_not_equal(void) -{ - /* 0x1000:0x0010 vs 0x1001:0x0000 -- same linear address, different pairs */ - ASSERT(run_cmp_case("1214_alias_1000_0010_vs_1001_0000", - 0x1000, 0x0010, 0x1001, 0x0000)); - - /* 0x0000:0x0100 vs 0x0010:0x0000 -- same linear address 0x100 */ - ASSERT(run_cmp_case("1214_alias_0000_0100_vs_0010_0000", - 0x0000, 0x0100, 0x0010, 0x0000)); - - /* 0xF000:0x1000 vs 0xF001:0x0FF0 -- same linear address 0xF1000 */ - ASSERT(run_cmp_case("1214_alias_F000_1000_vs_F001_0FF0", - 0xF000, 0x1000, 0xF001, 0x0FF0)); - - PASS(); -} - -/* - * Symmetry: swap ptr1 and ptr2 for a selection of unequal pairs. - * The result (ZF=0) must be the same regardless of argument order. - */ -TEST test_symmetry(void) -{ - /* Forward */ - ASSERT(run_cmp_case("1214_sym_fwd_1234_5678", - 0x1234, 0x5678, 0xABCD, 0xEF01)); - /* Reversed */ - ASSERT(run_cmp_case("1214_sym_rev_1234_5678", - 0xABCD, 0xEF01, 0x1234, 0x5678)); - - /* Forward */ - ASSERT(run_cmp_case("1214_sym_fwd_0000_FFFF", - 0x0000, 0x0000, 0x0000, 0xFFFF)); - /* Reversed */ - ASSERT(run_cmp_case("1214_sym_rev_0000_FFFF", - 0x0000, 0xFFFF, 0x0000, 0x0000)); - - PASS(); -} - -/* - * Null pointer (0000:0000) compared against itself and against non-null. - */ -TEST test_null_pointer(void) -{ - /* NULL == NULL */ - ASSERT(run_cmp_case("1214_null_eq_null", - 0x0000, 0x0000, 0x0000, 0x0000)); - - /* NULL != non-null (segment differs) */ - ASSERT(run_cmp_case("1214_null_ne_seg", - 0x0000, 0x0000, 0x0001, 0x0000)); - - /* NULL != non-null (offset differs) */ - ASSERT(run_cmp_case("1214_null_ne_off", - 0x0000, 0x0000, 0x0000, 0x0001)); - - PASS(); -} - -/* ---- */ -/* Suite */ -/* ---- */ - -SUITE(suite) -{ - RUN_TEST(test_equal_pointers); - RUN_TEST(test_unequal_seg_only); - RUN_TEST(test_unequal_off_only); - RUN_TEST(test_unequal_both); - RUN_TEST(test_aliased_not_equal); - RUN_TEST(test_symmetry); - RUN_TEST(test_null_pointer); -} diff --git a/tests/int2f-12/t121a.c b/tests/int2f-12/t121a.c deleted file mode 100644 index 1674f352..00000000 --- a/tests/int2f-12/t121a.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * t121a.c -- INT 2Fh / AX=121Ah GET DRIVE NUMBER FROM PATH - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f121a.html): - * AX = 121Ah - * DS:SI -> ASCIZ path string (e.g. "C:\DIR\FILE.TXT" or "C:FOO") - * Return: AL = drive number (0=A:, 1=B:, 2=C:, ..., 25=Z:) - * AL = FFh if no drive letter present or drive letter invalid - * CF = 0 always (errors expressed via AL=FFh, not carry) - * - * Logic (from FreeDOS inthndlr.c case 0x1a): - * Examine DS:SI[0] and DS:SI[1]. - * If DS:SI[1] == ':': - * Uppercase DS:SI[0]; if in 'A'..'Z', return AL = char - 'A'. - * Otherwise return AL = FFh. - * Else (no colon at offset 1): - * Return AL = FFh. - * CF is never set. - * - * Care registers: - * AL -- drive number or FFh (CARE_AL) - * All other output registers are don't-cares. - * ** from RBIL DS:SI may be incremented by 2 - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 121a.ref, verbose stdout - * default / test TEST: read 121a.ref, run all cases, write 121a.tst - * - * Build: - * wcl -zq -q -ms -i=.. t121a.c ..\testlib.c - * - * Usage: - * T121A ref (reference mode, writes 121a.ref) - * T121A test (test mode, reads 121a.ref, writes 121a.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "121a"; - -/* ---- - * We only care about AL on return (drive number or FFh). - * CF is always clear; all other output registers are don't-cares. - * ---- */ -#define CARE_121A (CARE_AL) - -/* ---- - * Maximum path length we will test. - * ---- */ -#define MAX_PATH_LEN 260 -#define BUF_SIZE (MAX_PATH_LEN + 2) - -/* Static buffer -- avoids stack overflow in small model */ -static char g_pathbuf[BUF_SIZE]; - -/* ---- - * Helper: set up a PROBE for AX=121Ah with DS:SI -> path string s. - * ---- */ -static void setup_121a(PROBE *p, const char *s, signed short bufsize) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x121A; - p->before.ds = FP_SEG(s); - p->before.si = FP_OFF(s); - p->buffer = (unsigned char far *)s; - if (bufsize > 0) /* use strlen or bufsize, whichever is smaller */ - { - p->bufsize = (unsigned short)(strlen(s) < bufsize ? strlen(s) + 1 : bufsize); /* only track first bufsize bytes */ - } else /* use exactly bufsize even if garbage */ - { - bufsize *= -1; - p->bufsize = bufsize; /* only track first bufsize bytes */ - } -} - -/* ---- - * Core helper: run one test case. - * label -- unique suffix (prefixed with "121a_") - * path -- input string (copied into g_pathbuf) - * ---- */ -static int run_path_case(const char *label, const char *path) -{ - PROBE p; - char name[TC_NAME_MAX]; - - strncpy(g_pathbuf, path, MAX_PATH_LEN); - g_pathbuf[MAX_PATH_LEN] = '\0'; - - setup_121a(&p, g_pathbuf, 3); - - sprintf(name, "121a_%s", label); - - if (g_ref_mode) - printf("INPUT: \"%s\"\n", g_pathbuf); - - return run_case(name, &p, CARE_121A, NULL); -} - -/* ---- - * Test suites - * ---- */ - -/* - * Valid drive letters A:..Z: as the leading two characters. - * Each must return AL = drive_index (0..25). - * Tests both uppercase and lowercase drive letters. - */ -TEST test_valid_drives(void) -{ - char label[32]; - char path[4]; - int i; - - /* Uppercase A:..Z: with no path after the colon */ - for (i = 0; i < 26; i++) { - path[0] = (char)('A' + i); - path[1] = ':'; - path[2] = '\0'; - sprintf(label, "upper_%c_bare", 'A' + i); - ASSERT(run_path_case(label, path)); - } - - /* Lowercase a:..z: -- must be treated identically (uppercased internally) */ - for (i = 0; i < 26; i++) { - path[0] = (char)('a' + i); - path[1] = ':'; - path[2] = '\0'; - sprintf(label, "lower_%c_bare", 'a' + i); - ASSERT(run_path_case(label, path)); - } - - PASS(); -} - -/* - * Valid drive letters followed by typical path suffixes. - * The drive number returned must still be correct regardless of what - * follows the colon. - */ -TEST test_valid_drives_with_paths(void) -{ - /* Absolute paths */ - ASSERT(run_path_case("c_abs", "C:\\DIR\\FILE.TXT")); - ASSERT(run_path_case("c_root", "C:\\")); - ASSERT(run_path_case("c_root_only", "C:")); - ASSERT(run_path_case("a_abs", "A:\\COMMAND.COM")); - ASSERT(run_path_case("z_abs", "Z:\\UTIL\\TOOL.EXE")); - - /* Relative paths (drive-relative, no leading backslash) */ - ASSERT(run_path_case("c_rel", "C:FOO.TXT")); - ASSERT(run_path_case("c_rel_dir", "C:DIR\\FILE")); - ASSERT(run_path_case("d_rel", "D:SUBDIR\\DATA.DAT")); - - /* Lowercase drive with path */ - ASSERT(run_path_case("c_lower_abs", "c:\\windows\\system32\\cmd.exe")); - ASSERT(run_path_case("c_lower_rel", "c:foo\\bar.txt")); - - /* Drive followed by forward slash (non-canonical but valid input) */ - ASSERT(run_path_case("c_fwdslash", "C:/DIR/FILE.TXT")); - - /* Drive followed by dot-dot */ - ASSERT(run_path_case("c_dotdot", "C:..\\PARENT")); - - /* Drive followed by wildcard */ - ASSERT(run_path_case("c_wildcard", "C:*.*")); - - /* Long path */ - ASSERT(run_path_case("c_long", - "C:\\LONGDIR\\SUBDIR\\ANOTHER\\DEEP\\PATH\\FILE.TXT")); - - PASS(); -} - -/* - * No drive letter: strings that do NOT have ':' at offset 1. - * All must return AL = FFh. - */ -TEST test_no_drive_letter(void) -{ - /* Relative paths with no drive prefix */ - ASSERT(run_path_case("rel_simple", "FILE.TXT")); - ASSERT(run_path_case("rel_dir", "DIR\\FILE.TXT")); - ASSERT(run_path_case("rel_dotdot", "..\\FILE.TXT")); - ASSERT(run_path_case("rel_dot", ".\\FILE.TXT")); - - /* Absolute paths with no drive (root-relative) */ - ASSERT(run_path_case("abs_root", "\\DIR\\FILE.TXT")); - ASSERT(run_path_case("abs_root_only","\\")); - - /* UNC-like paths */ - ASSERT(run_path_case("unc", "\\\\SERVER\\SHARE\\FILE")); - - /* Single character (no room for ':' at offset 1) */ - ASSERT(run_path_case("single_A", "A")); - ASSERT(run_path_case("single_slash", "\\")); - ASSERT(run_path_case("single_dot", ".")); - - /* Empty string */ - ASSERT(run_path_case("empty", "")); - - /* Colon NOT at offset 1 */ - ASSERT(run_path_case("colon_at_0", ":something")); /* ':' at [0] */ - ASSERT(run_path_case("colon_at_2", "AB:CD")); /* ':' at [2] */ - ASSERT(run_path_case("colon_at_3", "ABC:DEF")); /* ':' at [3] */ - - /* Digit before colon -- not a valid drive letter */ - ASSERT(run_path_case("digit_colon", "1:FILE")); - ASSERT(run_path_case("zero_colon", "0:FILE")); - ASSERT(run_path_case("nine_colon", "9:FILE")); - - PASS(); -} - -/* - * Invalid characters before the colon: non-alpha characters at [0] - * with ':' at [1]. Must return AL = FFh. - */ -TEST test_invalid_drive_chars(void) -{ - char label[32]; - char path[4]; - unsigned int ch; - - path[1] = ':'; - path[2] = '\0'; - - /* Digits 0..9 */ - for (ch = '0'; ch <= '9'; ch++) { - path[0] = (char)ch; - sprintf(label, "digit_0x%02X", ch); - ASSERT(run_path_case(label, path)); - } - - /* Punctuation and special chars that are not letters */ - /* Spot-check a representative set */ - path[0] = '!'; ASSERT(run_path_case("bang_colon", path)); - path[0] = '@'; ASSERT(run_path_case("at_colon", path)); - path[0] = '['; ASSERT(run_path_case("lbracket_colon", path)); /* 0x5B, just above 'Z' */ - path[0] = '`'; ASSERT(run_path_case("backtick_colon", path)); /* 0x60, just below 'a' */ - path[0] = '{'; ASSERT(run_path_case("lbrace_colon", path)); /* 0x7B, just above 'z' */ - path[0] = ' '; ASSERT(run_path_case("space_colon", path)); - path[0] = '\t'; ASSERT(run_path_case("tab_colon", path)); - path[0] = '\0'; ASSERT(run_path_case("nul_colon", path)); /* empty string effectively */ - path[0] = (char)0x80; ASSERT(run_path_case("high80_colon", path)); - path[0] = (char)0xFF; ASSERT(run_path_case("highFF_colon", path)); - - PASS(); -} - -/* - * Boundary: characters immediately adjacent to 'A'/'Z' and 'a'/'z'. - * Confirms the alpha range check is tight. - */ -TEST test_boundary_drive_chars(void) -{ - char path[4]; - - path[1] = ':'; - path[2] = '\0'; - - /* 0x40 = '@' -- just below 'A' (0x41), must be invalid */ - path[0] = '@'; - ASSERT(run_path_case("below_A", path)); - - /* 'A' = 0x41 -- valid */ - path[0] = 'A'; - ASSERT(run_path_case("at_A", path)); - - /* 'Z' = 0x5A -- valid */ - path[0] = 'Z'; - ASSERT(run_path_case("at_Z", path)); - - /* 0x5B = '[' -- just above 'Z', must be invalid */ - path[0] = '['; - ASSERT(run_path_case("above_Z", path)); - - /* 0x60 = '`' -- just below 'a' (0x61), must be invalid */ - path[0] = '`'; - ASSERT(run_path_case("below_a", path)); - - /* 'a' = 0x61 -- valid (lowercase, uppercased to 'A') */ - path[0] = 'a'; - ASSERT(run_path_case("at_a", path)); - - /* 'z' = 0x7A -- valid (lowercase, uppercased to 'Z') */ - path[0] = 'z'; - ASSERT(run_path_case("at_z", path)); - - /* 0x7B = '{' -- just above 'z', must be invalid */ - path[0] = '{'; - ASSERT(run_path_case("above_z", path)); - - PASS(); -} - -/* - * Alignment: path string starting at various byte offsets within - * g_pathbuf to catch any word-alignment assumptions in the DOS kernel. - */ -TEST test_alignment(void) -{ - static char aligned_buf[BUF_SIZE + 8]; - PROBE p; - char name[TC_NAME_MAX]; - unsigned int off; - - for (off = 0; off <= 7; off++) { - char *s = aligned_buf + off; - - /* Use "C:\FILE" as a representative path with a valid drive */ - strcpy(s, "C:\\FILE.TXT"); - setup_121a(&p, s, BUF_SIZE); - - sprintf(name, "121a_align_valid_off%u", off); - if (g_ref_mode) - printf("INPUT (off=%u, valid): \"%s\"\n", off, s); - ASSERT(run_case(name, &p, CARE_121A, NULL)); - - /* Also test a no-drive path at each offset */ - strcpy(s, "NODRV.TXT"); - setup_121a(&p, s, BUF_SIZE); - - sprintf(name, "121a_align_nodrv_off%u", off); - if (g_ref_mode) - printf("INPUT (off=%u, no-drive): \"%s\"\n", off, s); - ASSERT(run_case(name, &p, CARE_121A, NULL)); - } - - PASS(); -} - -/* - * Colon at offset 1 but with NUL at offset 0 (degenerate: empty string - * with a colon embedded). Behaviour is implementation-defined but must - * not crash; we record whatever the DOS returns. - */ -TEST test_degenerate(void) -{ - PROBE p; - - /* "\0:" -- NUL then colon */ - g_pathbuf[0] = '\0'; - g_pathbuf[1] = ':'; - g_pathbuf[2] = '\0'; - - setup_121a(&p, g_pathbuf, 3); - - if (g_ref_mode) - printf("INPUT: NUL-colon degenerate\n"); - - ASSERT(run_case("121a_nul_colon", &p, CARE_121A, NULL)); - - /* " :" -- two spaces then colon (space is not alpha) */ - g_pathbuf[0] = ' '; - g_pathbuf[1] = ':'; - g_pathbuf[2] = '\0'; - - setup_121a(&p, g_pathbuf, 3); - - if (g_ref_mode) - printf("INPUT: space-colon degenerate\n"); - - ASSERT(run_case("121a_space_colon", &p, CARE_121A, NULL)); - - PASS(); -} - -/* ---- - * Suite - * ---- */ - -SUITE(suite) -{ - RUN_TEST(test_valid_drives); - RUN_TEST(test_valid_drives_with_paths); - RUN_TEST(test_no_drive_letter); - RUN_TEST(test_invalid_drive_chars); - RUN_TEST(test_boundary_drive_chars); - RUN_TEST(test_alignment); - RUN_TEST(test_degenerate); -} diff --git a/tests/int2f-12/t121c.c b/tests/int2f-12/t121c.c deleted file mode 100644 index a1a846f1..00000000 --- a/tests/int2f-12/t121c.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * t121c.c -- INT 2Fh / AX=121Ch CHECKSUM MEMORY BLOCK - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f121c.html): - * AX = 121Ch - * DS:SI -> start of buffer - * CX = byte count (0 = no bytes processed) - * DX = initial checksum (seed) - * Return: DX = 16-bit carry-folded running checksum - * SI = original SI + CX (advanced past the buffer) - * CX = 0 - * All other registers (AX, BX, DI, DS, ES, FLAGS) are don't-cares. - * - * Algorithm (16-bit carry-folded sum): - * For each byte B at DS:SI: - * DX += (unsigned 16-bit) B - * if carry: DX += 1 (fold carry back into sum) - * SI++; CX-- - * Repeat until CX == 0. - * - * This is an end-around carry (ones-complement) accumulation, identical - * to the IP/ICMP checksum inner loop. It differs from AX=121Dh which - * uses a plain 8-bit truncated sum with no carry fold. - * - * Care registers: - * DX -- final checksum (CARE_DX) - * SI -- advanced by CX (CARE_SI) - * CX -- must be 0 (CARE_CX) - * All other output registers are don't-cares. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 121c.ref, verbose stdout - * default / test TEST: read 121c.ref, run all cases, write 121c.tst - * - * Build: - * wcl -zq -q -ms -i=.. t121c.c ..\testlib.c - * - * Usage: - * T121C ref (reference mode, writes 121c.ref) - * T121C test (test mode, reads 121c.ref, writes 121c.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "121c"; - -/* ---- - * We care about DX (checksum), SI (advanced pointer), and CX (must be 0). - * All other output registers are don't-cares. - * ---- */ -#define CARE_121C (CARE_DX | CARE_SI | CARE_CX) - -/* ---- - * Maximum buffer size for tests. - * ---- */ -#define MAX_BUF 512 -#define BUF_SIZE (MAX_BUF + 2) /* +2: sentinel bytes */ - -/* Static buffer -- avoids stack overflow in small model */ -static unsigned char g_buf[BUF_SIZE]; - -/* ---- - * Helper: set up a PROBE for AX=121Ch. - * DS:SI -> buf (start of data) - * CX = count - * DX = initial checksum seed - * ---- */ -static void setup_121c(PROBE *p, - const unsigned char *buf, - unsigned short count, - unsigned short seed) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x121C; - p->before.ds = FP_SEG(buf); - p->before.si = FP_OFF(buf); - p->before.cx = count; - p->before.dx = seed; - /* buffer tracking: record the input bytes for verbose log only */ - p->buffer = (unsigned char far *)buf; - p->bufsize = (count < 32) ? count : 32; -} - -/* ---- - * Core helper: run one checksum test case. - * ---- */ -static int run_cksum_case(const char *name, - const unsigned char *buf, - unsigned short count, - unsigned short seed) -{ - PROBE p; - - setup_121c(&p, buf, count, seed); - - if (g_ref_mode) { - printf("INPUT: count=%u seed=0x%04X buf[0..%u]:", - count, seed, (count < 8 ? count : 8) - 1); - { - unsigned short i; - unsigned short show = (count < 8) ? count : 8; - for (i = 0; i < show; i++) - printf(" %02X", buf[i]); - if (count > 8) printf(" ..."); - } - printf("\n"); - } - - return run_case(name, &p, CARE_121C, NULL); -} - -/* ---- */ -/* Test suites */ -/* ---- */ - -/* - * Zero-length buffer: CX=0 on entry. - * DX must equal the seed (no bytes processed), SI unchanged, CX=0. - */ -TEST test_zero_length(void) -{ - /* seed=0 */ - ASSERT(run_cksum_case("121c_zero_seed0", g_buf, 0, 0x0000)); - /* seed=non-zero */ - ASSERT(run_cksum_case("121c_zero_seed1234", g_buf, 0, 0x1234)); - ASSERT(run_cksum_case("121c_zero_seedFFFF", g_buf, 0, 0xFFFF)); - PASS(); -} - -/* - * Single-byte buffers: verifies the per-byte carry-fold logic. - */ -TEST test_single_byte(void) -{ - /* 0x00: DX = seed + 0 */ - g_buf[0] = 0x00; - ASSERT(run_cksum_case("121c_1byte_00_seed0", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_1byte_00_seedFFFF", g_buf, 1, 0xFFFF)); - - /* 0x01 */ - g_buf[0] = 0x01; - ASSERT(run_cksum_case("121c_1byte_01_seed0", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_1byte_01_seedFFFE", g_buf, 1, 0xFFFE)); - - /* 0xFF: adding 0xFF to 0xFF00 causes carry */ - g_buf[0] = 0xFF; - ASSERT(run_cksum_case("121c_1byte_FF_seed0", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_1byte_FF_seedFF00", g_buf, 1, 0xFF00)); - ASSERT(run_cksum_case("121c_1byte_FF_seedFFFF", g_buf, 1, 0xFFFF)); - - /* 0x80 */ - g_buf[0] = 0x80; - ASSERT(run_cksum_case("121c_1byte_80_seed0", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_1byte_80_seedFF80", g_buf, 1, 0xFF80)); - - PASS(); -} - -/* - * All-zero buffer: checksum must equal seed (adding zeros changes nothing). - */ -TEST test_all_zeros(void) -{ - memset(g_buf, 0x00, MAX_BUF); - - ASSERT(run_cksum_case("121c_zeros_1", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_zeros_2", g_buf, 2, 0x0000)); - ASSERT(run_cksum_case("121c_zeros_16", g_buf, 16, 0x0000)); - ASSERT(run_cksum_case("121c_zeros_256", g_buf, 256, 0x0000)); - ASSERT(run_cksum_case("121c_zeros_512", g_buf, 512, 0x0000)); - /* Non-zero seed with all-zero data: result must equal seed */ - ASSERT(run_cksum_case("121c_zeros_16_seed1234", g_buf, 16, 0x1234)); - ASSERT(run_cksum_case("121c_zeros_256_seedABCD", g_buf, 256, 0xABCD)); - PASS(); -} - -/* - * All-0xFF buffer: every byte addition causes a carry. - * Verifies the carry-fold path is exercised on every iteration. - */ -TEST test_all_ff(void) -{ - memset(g_buf, 0xFF, MAX_BUF); - - ASSERT(run_cksum_case("121c_ff_1", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_ff_2", g_buf, 2, 0x0000)); - ASSERT(run_cksum_case("121c_ff_3", g_buf, 3, 0x0000)); - ASSERT(run_cksum_case("121c_ff_4", g_buf, 4, 0x0000)); - ASSERT(run_cksum_case("121c_ff_16", g_buf, 16, 0x0000)); - ASSERT(run_cksum_case("121c_ff_255", g_buf, 255, 0x0000)); - ASSERT(run_cksum_case("121c_ff_256", g_buf, 256, 0x0000)); - ASSERT(run_cksum_case("121c_ff_512", g_buf, 512, 0x0000)); - /* With non-zero seed */ - ASSERT(run_cksum_case("121c_ff_16_seed1234", g_buf, 16, 0x1234)); - PASS(); -} - -/* - * Incrementing pattern 0x00..0xFF (repeating): known-value test. - */ -TEST test_incrementing(void) -{ - unsigned short i; - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (unsigned char)(i & 0xFF); - - ASSERT(run_cksum_case("121c_incr_1", g_buf, 1, 0x0000)); - ASSERT(run_cksum_case("121c_incr_2", g_buf, 2, 0x0000)); - ASSERT(run_cksum_case("121c_incr_4", g_buf, 4, 0x0000)); - ASSERT(run_cksum_case("121c_incr_16", g_buf, 16, 0x0000)); - ASSERT(run_cksum_case("121c_incr_64", g_buf, 64, 0x0000)); - ASSERT(run_cksum_case("121c_incr_128", g_buf, 128, 0x0000)); - ASSERT(run_cksum_case("121c_incr_256", g_buf, 256, 0x0000)); - ASSERT(run_cksum_case("121c_incr_512", g_buf, 512, 0x0000)); - /* With non-zero seed */ - ASSERT(run_cksum_case("121c_incr_256_seedABCD", g_buf, 256, 0xABCD)); - PASS(); -} - -/* - * Alternating 0x55/0xAA pattern. - */ -TEST test_alternating(void) -{ - unsigned short i; - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (i & 1) ? 0xAA : 0x55; - - ASSERT(run_cksum_case("121c_alt_2", g_buf, 2, 0x0000)); - ASSERT(run_cksum_case("121c_alt_4", g_buf, 4, 0x0000)); - ASSERT(run_cksum_case("121c_alt_16", g_buf, 16, 0x0000)); - ASSERT(run_cksum_case("121c_alt_256", g_buf, 256, 0x0000)); - ASSERT(run_cksum_case("121c_alt_512", g_buf, 512, 0x0000)); - PASS(); -} - -/* - * Seed wrap-around: seeds that cause the initial DX to be near 0xFFFF, - * so the very first byte addition triggers a carry. - */ -TEST test_seed_wraparound(void) -{ - g_buf[0] = 0x01; - g_buf[1] = 0x02; - g_buf[2] = 0xFF; - g_buf[3] = 0x00; - - /* seed=0xFFFF, byte=0x01 -> DX=0x0000 + carry -> DX=0x0001 */ - ASSERT(run_cksum_case("121c_wrap_FFFF_01", g_buf, 1, 0xFFFF)); - /* seed=0xFFFE, byte=0x02 -> DX=0x0000 + carry -> DX=0x0001 */ - ASSERT(run_cksum_case("121c_wrap_FFFE_02", g_buf+1, 1, 0xFFFE)); - /* seed=0xFF00, byte=0xFF -> DX=0xFEFF + carry? no; 0xFF00+0xFF=0xFFFF no carry */ - ASSERT(run_cksum_case("121c_wrap_FF00_FF", g_buf+2, 1, 0xFF00)); - /* seed=0xFFFF, byte=0xFF -> DX=0xFFFE + carry -> DX=0xFFFF */ - ASSERT(run_cksum_case("121c_wrap_FFFF_FF", g_buf+2, 1, 0xFFFF)); - /* Multi-byte with wrapping seed */ - ASSERT(run_cksum_case("121c_wrap_multi", g_buf, 4, 0xFF00)); - PASS(); -} - -/* - * Boundary lengths: one below and one above each power-of-two. - */ -TEST test_boundary_lengths(void) -{ - unsigned short i; - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (unsigned char)(i * 3 + 7); /* pseudo-random pattern */ - - ASSERT(run_cksum_case("121c_bnd_3", g_buf, 3, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_7", g_buf, 7, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_8", g_buf, 8, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_9", g_buf, 9, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_15", g_buf, 15, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_17", g_buf, 17, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_31", g_buf, 31, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_33", g_buf, 33, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_63", g_buf, 63, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_65", g_buf, 65, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_127", g_buf, 127, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_129", g_buf, 129, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_255", g_buf, 255, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_257", g_buf, 257, 0x0000)); - ASSERT(run_cksum_case("121c_bnd_511", g_buf, 511, 0x0000)); - PASS(); -} - -/* - * Alignment: buffer starting at various byte offsets within g_buf. - * Catches any word-alignment assumptions in the DOS kernel. - */ -TEST test_alignment(void) -{ - unsigned short i, off; - char name[TC_NAME_MAX]; - - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (unsigned char)(i + 0x41); - - for (off = 0; off <= 7; off++) { - sprintf(name, "121c_align_off%u", off); - ASSERT(run_cksum_case(name, g_buf + off, 16, 0x0000)); - } - - PASS(); -} - -/* ---- */ -/* Suite */ -/* ---- */ - -SUITE(suite) -{ - RUN_TEST(test_zero_length); - RUN_TEST(test_single_byte); - RUN_TEST(test_all_zeros); - RUN_TEST(test_all_ff); - RUN_TEST(test_incrementing); - RUN_TEST(test_alternating); - RUN_TEST(test_seed_wraparound); - RUN_TEST(test_boundary_lengths); - RUN_TEST(test_alignment); -} diff --git a/tests/int2f-12/t121d.c b/tests/int2f-12/t121d.c deleted file mode 100644 index e607e095..00000000 --- a/tests/int2f-12/t121d.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * t121d.c -- INT 2Fh / AX=121Dh SUM MEMORY BLOCK (8-bit truncated) - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f121d.html): - * AX = 121Dh - * DS:SI -> start of buffer - * CX = byte count (0 = no bytes processed) - * Return: AL = 8-bit truncated running sum (carry discarded each step) - * SI = original SI + CX (advanced past the buffer) - * CX = 0 - * All other registers (AH, BX, DX, DI, DS, ES, FLAGS) are don't-cares. - * - * Algorithm (8-bit truncated sum): - * AL = 0 - * For each byte B at DS:SI: - * AL = (AL + B) & 0xFF (8-bit addition, carry discarded) - * SI++; CX-- - * Repeat until CX == 0. - * - * This differs from AX=121Ch which uses a 16-bit carry-folded (ones-complement) - * accumulation. 121Dh has no seed register; the accumulator always starts at 0. - * - * Care registers: - * AL -- 8-bit sum result (CARE_AL) - * SI -- advanced by CX (CARE_SI) - * CX -- must be 0 (CARE_CX) - * All other output registers are don't-cares. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 121d.ref, verbose stdout - * default / test TEST: read 121d.ref, run all cases, write 121d.tst - * - * Build: - * wcl -zq -q -ms -i=.. t121d.c ..\testlib.c - * - * Usage: - * T121D ref (reference mode, writes 121d.ref) - * T121D test (test mode, reads 121d.ref, writes 121d.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "121d"; - -/* ---- - * We care about AL (8-bit sum), SI (advanced pointer), and CX (must be 0). - * All other output registers are don't-cares. - * ---- */ -#define CARE_121D (CARE_AL | CARE_SI | CARE_CX) - -/* ---- - * Maximum buffer size for tests. - * ---- */ -#define MAX_BUF 512 -#define BUF_SIZE (MAX_BUF + 2) /* +2: sentinel bytes */ - -/* Static buffer -- avoids stack overflow in small model */ -static unsigned char g_buf[BUF_SIZE]; - -/* ---- - * Helper: set up a PROBE for AX=121Dh. - * DS:SI -> buf (start of data) - * CX = count - * (no seed register -- accumulator always starts at 0 inside DOS) - * ---- */ -static void setup_121d(PROBE *p, - const unsigned char *buf, - unsigned short count) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x121D; - p->before.ds = FP_SEG(buf); - p->before.si = FP_OFF(buf); - p->before.cx = count; - /* buffer tracking: record the input bytes for verbose log only */ - p->buffer = (unsigned char far *)buf; - p->bufsize = (count < 32) ? count : 32; -} - -/* ---- - * Core helper: run one sum test case. - * ---- */ -static int run_sum_case(const char *name, - const unsigned char *buf, - unsigned short count) -{ - PROBE p; - - setup_121d(&p, buf, count); - - if (g_ref_mode) { - printf("INPUT: count=%u buf[0..%u]:", - count, (count < 8 ? count : 8) - 1); - { - unsigned short i; - unsigned short show = (count < 8) ? count : 8; - for (i = 0; i < show; i++) - printf(" %02X", buf[i]); - if (count > 8) printf(" ..."); - } - printf("\n"); - } - - return run_case(name, &p, CARE_121D, NULL); -} - -/* ---- */ -/* Test suites */ -/* ---- */ - -/* - * Zero-length buffer: CX=0 on entry. - * AL must be 0 (no bytes processed), SI unchanged, CX=0. - */ -TEST test_zero_length(void) -{ - ASSERT(run_sum_case("121d_zero", g_buf, 0)); - PASS(); -} - -/* - * Single-byte buffers: verifies the per-byte truncation. - */ -TEST test_single_byte(void) -{ - /* 0x00: AL = 0 */ - g_buf[0] = 0x00; - ASSERT(run_sum_case("121d_1byte_00", g_buf, 1)); - - /* 0x01: AL = 1 */ - g_buf[0] = 0x01; - ASSERT(run_sum_case("121d_1byte_01", g_buf, 1)); - - /* 0x7F: AL = 0x7F */ - g_buf[0] = 0x7F; - ASSERT(run_sum_case("121d_1byte_7F", g_buf, 1)); - - /* 0x80: AL = 0x80 */ - g_buf[0] = 0x80; - ASSERT(run_sum_case("121d_1byte_80", g_buf, 1)); - - /* 0xFF: AL = 0xFF */ - g_buf[0] = 0xFF; - ASSERT(run_sum_case("121d_1byte_FF", g_buf, 1)); - - PASS(); -} - -/* - * Two-byte buffers: verifies carry is discarded (8-bit truncation). - * 0xFF + 0x01 = 0x100 -> AL = 0x00 (carry discarded). - * 0xFF + 0x02 = 0x101 -> AL = 0x01. - */ -TEST test_two_byte_overflow(void) -{ - /* 0xFF + 0x01 -> 0x00 (overflow, carry discarded) */ - g_buf[0] = 0xFF; g_buf[1] = 0x01; - ASSERT(run_sum_case("121d_2byte_FF_01", g_buf, 2)); - - /* 0xFF + 0x02 -> 0x01 */ - g_buf[0] = 0xFF; g_buf[1] = 0x02; - ASSERT(run_sum_case("121d_2byte_FF_02", g_buf, 2)); - - /* 0xFF + 0xFF -> 0xFE (0x1FE & 0xFF) */ - g_buf[0] = 0xFF; g_buf[1] = 0xFF; - ASSERT(run_sum_case("121d_2byte_FF_FF", g_buf, 2)); - - /* 0x80 + 0x80 -> 0x00 */ - g_buf[0] = 0x80; g_buf[1] = 0x80; - ASSERT(run_sum_case("121d_2byte_80_80", g_buf, 2)); - - /* 0x00 + 0x00 -> 0x00 */ - g_buf[0] = 0x00; g_buf[1] = 0x00; - ASSERT(run_sum_case("121d_2byte_00_00", g_buf, 2)); - - PASS(); -} - -/* - * All-zero buffer: sum must be 0 for any length. - */ -TEST test_all_zeros(void) -{ - memset(g_buf, 0x00, MAX_BUF); - - ASSERT(run_sum_case("121d_zeros_1", g_buf, 1)); - ASSERT(run_sum_case("121d_zeros_2", g_buf, 2)); - ASSERT(run_sum_case("121d_zeros_16", g_buf, 16)); - ASSERT(run_sum_case("121d_zeros_256", g_buf, 256)); - ASSERT(run_sum_case("121d_zeros_512", g_buf, 512)); - PASS(); -} - -/* - * All-0xFF buffer: every byte addition overflows. - * For N bytes of 0xFF: AL = (N * 0xFF) & 0xFF = (0xFF * N) mod 256. - * N=1: 0xFF; N=2: 0xFE; N=256: 0x00; N=257: 0xFF; etc. - */ -TEST test_all_ff(void) -{ - memset(g_buf, 0xFF, MAX_BUF); - - ASSERT(run_sum_case("121d_ff_1", g_buf, 1)); - ASSERT(run_sum_case("121d_ff_2", g_buf, 2)); - ASSERT(run_sum_case("121d_ff_3", g_buf, 3)); - ASSERT(run_sum_case("121d_ff_4", g_buf, 4)); - ASSERT(run_sum_case("121d_ff_16", g_buf, 16)); - ASSERT(run_sum_case("121d_ff_255", g_buf, 255)); - ASSERT(run_sum_case("121d_ff_256", g_buf, 256)); - ASSERT(run_sum_case("121d_ff_257", g_buf, 257)); - ASSERT(run_sum_case("121d_ff_512", g_buf, 512)); - PASS(); -} - -/* - * Incrementing pattern 0x00..0xFF (repeating). - * Sum of 0..255 = 0x7F80; truncated to 8 bits = 0x80. - * Sum of 0..255 twice = 0xFF00; truncated = 0x00. - */ -TEST test_incrementing(void) -{ - unsigned short i; - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (unsigned char)(i & 0xFF); - - ASSERT(run_sum_case("121d_incr_1", g_buf, 1)); - ASSERT(run_sum_case("121d_incr_2", g_buf, 2)); - ASSERT(run_sum_case("121d_incr_4", g_buf, 4)); - ASSERT(run_sum_case("121d_incr_16", g_buf, 16)); - ASSERT(run_sum_case("121d_incr_64", g_buf, 64)); - ASSERT(run_sum_case("121d_incr_128", g_buf, 128)); - ASSERT(run_sum_case("121d_incr_256", g_buf, 256)); - ASSERT(run_sum_case("121d_incr_512", g_buf, 512)); - PASS(); -} - -/* - * Alternating 0x55/0xAA pattern. - * Pair sum: 0x55 + 0xAA = 0xFF. - * 2 bytes: 0xFF; 4 bytes: 0xFE; 256 bytes: 0x80 (128 * 0xFF mod 256). - */ -TEST test_alternating(void) -{ - unsigned short i; - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (i & 1) ? 0xAA : 0x55; - - ASSERT(run_sum_case("121d_alt_1", g_buf, 1)); - ASSERT(run_sum_case("121d_alt_2", g_buf, 2)); - ASSERT(run_sum_case("121d_alt_4", g_buf, 4)); - ASSERT(run_sum_case("121d_alt_16", g_buf, 16)); - ASSERT(run_sum_case("121d_alt_256", g_buf, 256)); - ASSERT(run_sum_case("121d_alt_512", g_buf, 512)); - PASS(); -} - -/* - * Boundary lengths: one below and one above each power-of-two. - */ -TEST test_boundary_lengths(void) -{ - unsigned short i; - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (unsigned char)(i * 3 + 7); /* pseudo-random pattern */ - - ASSERT(run_sum_case("121d_bnd_3", g_buf, 3)); - ASSERT(run_sum_case("121d_bnd_7", g_buf, 7)); - ASSERT(run_sum_case("121d_bnd_8", g_buf, 8)); - ASSERT(run_sum_case("121d_bnd_9", g_buf, 9)); - ASSERT(run_sum_case("121d_bnd_15", g_buf, 15)); - ASSERT(run_sum_case("121d_bnd_17", g_buf, 17)); - ASSERT(run_sum_case("121d_bnd_31", g_buf, 31)); - ASSERT(run_sum_case("121d_bnd_33", g_buf, 33)); - ASSERT(run_sum_case("121d_bnd_63", g_buf, 63)); - ASSERT(run_sum_case("121d_bnd_65", g_buf, 65)); - ASSERT(run_sum_case("121d_bnd_127", g_buf, 127)); - ASSERT(run_sum_case("121d_bnd_129", g_buf, 129)); - ASSERT(run_sum_case("121d_bnd_255", g_buf, 255)); - ASSERT(run_sum_case("121d_bnd_257", g_buf, 257)); - ASSERT(run_sum_case("121d_bnd_511", g_buf, 511)); - PASS(); -} - -/* - * Alignment: buffer starting at various byte offsets within g_buf. - * Catches any word-alignment assumptions in the DOS kernel. - */ -TEST test_alignment(void) -{ - unsigned short i, off; - char name[TC_NAME_MAX]; - - for (i = 0; i < MAX_BUF; i++) - g_buf[i] = (unsigned char)(i + 0x41); - - for (off = 0; off <= 7; off++) { - sprintf(name, "121d_align_off%u", off); - ASSERT(run_sum_case(name, g_buf + off, 16)); - } - - PASS(); -} - -/* - * Difference from 121Ch: confirm 121Dh does NOT carry-fold. - * 0xFF + 0x01 = 0x100 -> 121Dh gives AL=0x00 (carry discarded). - * (121Ch would give DX=0x0001 because it folds the carry back in.) - * We record whatever DOS returns; the .ref file captures the truth. - */ -TEST test_no_carry_fold(void) -{ - /* Three bytes that would produce different results with carry-fold */ - g_buf[0] = 0xFF; - g_buf[1] = 0x01; - g_buf[2] = 0x00; - ASSERT(run_sum_case("121d_nocarry_FF_01_00", g_buf, 3)); - - g_buf[0] = 0xFF; - g_buf[1] = 0xFF; - g_buf[2] = 0x02; - ASSERT(run_sum_case("121d_nocarry_FF_FF_02", g_buf, 3)); - - /* 256 bytes of 0x01: 8-bit sum = 0x00 (256 mod 256); carry-fold would give 0x01 */ - memset(g_buf, 0x01, 256); - ASSERT(run_sum_case("121d_nocarry_256x01", g_buf, 256)); - - PASS(); -} - -/* ---- */ -/* Suite */ -/* ---- */ - -SUITE(suite) -{ - RUN_TEST(test_zero_length); - RUN_TEST(test_single_byte); - RUN_TEST(test_two_byte_overflow); - RUN_TEST(test_all_zeros); - RUN_TEST(test_all_ff); - RUN_TEST(test_incrementing); - RUN_TEST(test_alternating); - RUN_TEST(test_boundary_lengths); - RUN_TEST(test_alignment); - RUN_TEST(test_no_carry_fold); -} diff --git a/tests/int2f-12/t121f.c b/tests/int2f-12/t121f.c deleted file mode 100644 index b4f24e50..00000000 --- a/tests/int2f-12/t121f.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * t121f.c -- INT 2Fh / AX=121Fh BUILD TEMPORARY CDS FOR DRIVE LETTER - * - * FreeDOS inthndlr.c case 0x1f: - * Input: callerARG1 low byte = drive letter ASCII ('A'..'Z' or 'a'..'z') - * pushed on the stack by the caller (p->value). - * Output: On success: - * ES:DI -> TempCDS (DOS-internal global, address varies per run) - * CX = sizeof(TempCDS) (== sizeof(struct cds)) - * CF = 0 - * On failure (invalid letter, drive out of range): - * CF = 1 - * - * TempCDS is filled as follows: - * cdsCurrentPath[0] = drive letter (as supplied, not uppercased) - * cdsCurrentPath[1] = ':' - * cdsCurrentPath[2] = '\' - * cdsCurrentPath[3] = NUL - * cdsBackslashOffset = 2 - * If the real CDS for the drive has cdsFlags != 0 (drive active): - * cdsDpb = real CDS cdsDpb - * cdsFlags = CDSPHYSDRV (0x0040) - * Else (inactive drive): - * cdsDpb = NULL (0000:0000) - * cdsFlags = 0 - * cdsStrtClst = 0xFFFF - * cdsParam = 0xFFFF - * cdsUserData = 0xFFFF - * - * Care masks: - * Success path: CARE_FLAGS | CARE_BUF - * - CX may equal sizeof(struct cds), MSDOS leaves unchanged - * - CF must be clear. - * - The CDS content at ES:DI must match the reference byte-for-byte. - * - ES and DI are NOT in the care mask: TempCDS lives in DOS DGROUP - * whose address varies between DOS versions and builds. - * Failure path: CARE_FLAGS only (CF must be set). - * - * Buffer handling: - * ES:DI is only known after the INT 2Fh call returns. A post-probe - * hook (hook_121f) is passed to run_case() as the fn argument. The - * hook runs after probe_int2f() but before any ref/tst work: - * - If CF=0: sets p->buffer = MK_FP(p->after.es, p->after.di) - * and p->bufsize = p->after.cx. - * - If CF=1: leaves p->buffer=NULL / p->bufsize=0 (no buffer to compare). - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 121f.ref, verbose stdout - * default / test TEST: read 121f.ref, run all cases, write 121f.tst - * - * Build: - * wcl -zq -q -mt -i=.. -DUSEDOSSTACK t121f.c ..\testlib.c - * - * Usage: - * T121F ref (reference mode, writes 121f.ref) - * T121F test (test mode, reads 121f.ref, writes 121f.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "121f"; - -/* ---- - * Care masks - * ---- */ - -/* Success: FLAGS (CF=0), and the CDS buffer content. */ -#define CARE_121F_OK (CARE_FLAGS | CARE_BUF) - -/* Failure: only CF=1 matters; no buffer. */ -#define CARE_121F_FAIL (CARE_FLAGS) - -/* ---- - * Post-probe hook - * - * Called by run_case() after probe_int2f() fills p->after, but before - * any .ref writing or comparison. - * - * Returns 0 always (never signals hook-level failure). - * ---- */ - -static int hook_121f(const char *name, PROBE *p, unsigned short care) -{ - (void)name; - (void)care; - - if (p->after.flags & FLAG_CF) { - /* Failure path: no buffer */ - p->buffer = NULL; - p->bufsize = 0; - } else { - /* Success path: ES:DI -> TempCDS */ - p->buffer = (unsigned char far *)MK_FP(p->after.es, p->after.di); - p->bufsize = 58; /* sizeof(CDS) */ - } - - return 0; -} - -/* ---- - * Helper: set up a PROBE for AX=121Fh. - * drive_letter: ASCII drive letter ('A'..'Z' or 'a'..'z', or invalid). - * Passed via p->value (pushed on stack as callerARG1). - * ---- */ -static void setup_121f(PROBE *p, unsigned char drive_letter) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x121F; - p->value = (unsigned short)drive_letter; - /* buffer and bufsize are set by hook_121f after the call */ -} - -/* ---- - * Core helper: run one test case. - * label -- unique suffix (prefixed with "121f_") - * drive_letter -- ASCII drive letter to pass as callerARG1 - * care -- CARE_121F_OK or CARE_121F_FAIL - * ---- */ -static int run_121f_case(const char *label, - unsigned char drive_letter, - unsigned short care) -{ - PROBE p; - char name[TC_NAME_MAX]; - - setup_121f(&p, drive_letter); - sprintf(name, "121f_%s", label); - - if (g_ref_mode) - printf("INPUT: drive_letter=0x%02X ('%c')\n", - (unsigned)drive_letter, - (drive_letter >= 0x20 && drive_letter < 0x7F) - ? (char)drive_letter : '?'); - - return run_case(name, &p, care, hook_121f); -} - -/* ---- - * Test suites - * ---- */ - -/* - * All 26 uppercase drive letters A..Z. - * Each must succeed (CF=0), return CX=sizeof(cds), and produce a CDS - * whose cdsCurrentPath starts with the supplied uppercase letter. - */ -TEST test_valid_uppercase(void) -{ - char label[32]; - int i; - - printf("test_valid_uppercase\n"); - for (i = 0; i < 26; i++) { - unsigned char letter = (unsigned char)('A' + i); - sprintf(label, "upper_%c", 'A' + i); - ASSERT(run_121f_case(label, letter, CARE_121F_OK)); - } - PASS(); -} - -/* - * All 26 lowercase drive letters a..z. - * The kernel stores the letter as-is (no uppercasing), so cdsCurrentPath[0] - * will be the lowercase letter. The reference captures this exactly. - */ -TEST test_valid_lowercase(void) -{ - char label[32]; - int i; - - for (i = 0; i < 26; i++) { - unsigned char letter = (unsigned char)('a' + i); - sprintf(label, "lower_%c", 'a' + i); - ASSERT(run_121f_case(label, letter, CARE_121F_OK)); - } - PASS(); -} - -/* - * Characters immediately outside the valid letter ranges must fail (CF=1). - * '@' (0x40) is just below 'A' (0x41) - * '[' (0x5B) is just above 'Z' (0x5A) - * '`' (0x60) is just below 'a' (0x61) - * '{' (0x7B) is just above 'z' (0x7A) - */ -TEST test_boundary_invalid(void) -{ - ASSERT(run_121f_case("below_A", '@', CARE_121F_FAIL)); - ASSERT(run_121f_case("above_Z", '[', CARE_121F_FAIL)); - ASSERT(run_121f_case("below_a", '`', CARE_121F_FAIL)); - ASSERT(run_121f_case("above_z", '{', CARE_121F_FAIL)); - PASS(); -} - -/* - * Digits, punctuation, control characters, and high bytes -- all invalid. - */ -TEST test_invalid_chars(void) -{ - /* Digits */ - ASSERT(run_121f_case("digit_0", '0', CARE_121F_FAIL)); - ASSERT(run_121f_case("digit_9", '9', CARE_121F_FAIL)); - - /* Punctuation */ - ASSERT(run_121f_case("bang", '!', CARE_121F_FAIL)); - ASSERT(run_121f_case("colon", ':', CARE_121F_FAIL)); - ASSERT(run_121f_case("space", ' ', CARE_121F_FAIL)); - - /* Control characters */ - ASSERT(run_121f_case("nul", 0x00, CARE_121F_FAIL)); - ASSERT(run_121f_case("ctrl_01", 0x01, CARE_121F_FAIL)); - ASSERT(run_121f_case("ctrl_1f", 0x1F, CARE_121F_FAIL)); - - /* High bytes */ - ASSERT(run_121f_case("high_80", 0x80, CARE_121F_FAIL)); - ASSERT(run_121f_case("high_ff", 0xFF, CARE_121F_FAIL)); - - PASS(); -} - -/* - * CDS path prefix check. - * For a successful call the first four bytes of cdsCurrentPath must be - * ":\". The reference captures the full CDS so this is - * implicitly verified, but we call out A, C, a, c explicitly for clarity. - */ -TEST test_cds_path_prefix(void) -{ - ASSERT(run_121f_case("path_A", 'A', CARE_121F_OK)); - ASSERT(run_121f_case("path_C", 'C', CARE_121F_OK)); - ASSERT(run_121f_case("path_a", 'a', CARE_121F_OK)); - ASSERT(run_121f_case("path_c", 'c', CARE_121F_OK)); - PASS(); -} - -/* - * CX consistency check. - * CX must equal sizeof(struct cds) on every call. We verify three - * different drives so we can confirm the value is constant, not - * drive-dependent. - */ -TEST test_cx_equals_cds_size(void) -{ - ASSERT(run_121f_case("cx_A", 'A', CARE_121F_OK)); - ASSERT(run_121f_case("cx_B", 'B', CARE_121F_OK)); - ASSERT(run_121f_case("cx_Z", 'Z', CARE_121F_OK)); - PASS(); -} - -/* - * Repeated call for the same drive must produce identical CDS content. - * TempCDS is a single global; two consecutive calls for C: must agree. - */ -TEST test_repeated_call(void) -{ - ASSERT(run_121f_case("repeat_C_1", 'C', CARE_121F_OK)); - ASSERT(run_121f_case("repeat_C_2", 'C', CARE_121F_OK)); - PASS(); -} - -/* - * Uppercase and lowercase of the same drive letter produce the same CDS - * content except for cdsCurrentPath[0] (the letter itself). - * The reference captures both; the comparison is byte-for-byte so any - * difference beyond the first byte will be caught. - */ -TEST test_uppercase_lowercase_same_drive(void) -{ - ASSERT(run_121f_case("case_A_upper", 'A', CARE_121F_OK)); - ASSERT(run_121f_case("case_A_lower", 'a', CARE_121F_OK)); - ASSERT(run_121f_case("case_C_upper", 'C', CARE_121F_OK)); - ASSERT(run_121f_case("case_C_lower", 'c', CARE_121F_OK)); - PASS(); -} - -/* - * Inactive drives (Y: and Z: are unlikely to be active on a test machine). - * The kernel must still succeed (CF=0) and return a CDS with cdsDpb=NULL - * and cdsFlags=0. The reference captures whatever the DOS actually returns. - */ -TEST test_inactive_drives(void) -{ - ASSERT(run_121f_case("inactive_Y", 'Y', CARE_121F_OK)); - ASSERT(run_121f_case("inactive_Z", 'Z', CARE_121F_OK)); - PASS(); -} - -/* - * CF pre-set: confirm the kernel clears CF on success even when the - * caller enters with CF=1. - */ -TEST test_cf_clear_on_success(void) -{ - PROBE p; - - setup_121f(&p, 'C'); - p.before.flags = FLAG_CF; /* pre-set carry */ - - if (g_ref_mode) - printf("INPUT: drive='C' with CF pre-set\n"); - - ASSERT(run_case("121f_cf_presset_C", &p, CARE_121F_OK, hook_121f)); - PASS(); -} - -/* - * CF pre-clear: confirm the kernel sets CF on failure even when the - * caller enters with CF=0. - */ -TEST test_cf_set_on_failure(void) -{ - PROBE p; - - setup_121f(&p, '!'); - p.before.flags = 0; /* pre-clear carry */ - - if (g_ref_mode) - printf("INPUT: drive='!' (invalid) with CF pre-cleared\n"); - - ASSERT(run_case("121f_cf_preclear_bang", &p, CARE_121F_FAIL, hook_121f)); - PASS(); -} - -/* ---- - * Suite - * ---- */ - -SUITE(suite) -{ - printf("SUITE!\n"); - fflush(NULL); - RUN_TEST(test_valid_uppercase); - RUN_TEST(test_valid_lowercase); - RUN_TEST(test_boundary_invalid); - RUN_TEST(test_invalid_chars); - RUN_TEST(test_cds_path_prefix); - RUN_TEST(test_cx_equals_cds_size); - RUN_TEST(test_repeated_call); - RUN_TEST(test_uppercase_lowercase_same_drive); - RUN_TEST(test_inactive_drives); - RUN_TEST(test_cf_clear_on_success); - RUN_TEST(test_cf_set_on_failure); -} diff --git a/tests/int2f-12/t1225.c b/tests/int2f-12/t1225.c deleted file mode 100644 index b268c1ff..00000000 --- a/tests/int2f-12/t1225.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * t1225.c -- INT 2Fh / AX=1225h GET LENGTH OF ASCIZ STRING - * - * RBIL (https://fd.lod.bz/rbil/interrup/dos_kernel/2f1225.html): - * AX = 1225h - * DS:SI -> ASCIZ string - * Return: CX = length of string (not counting NUL terminator) - * - * All other registers (AX, BX, DX, DI, DS, ES, FLAGS) are don't-cares - * for pass/fail purposes; they are recorded in the .ref file but marked - * "????" so they do not affect test results on other DOS versions. - * - * Two modes (see testlib.h): - * ref REFERENCE: run all cases, write 1225.ref, verbose stdout - * default / test TEST: read 1225.ref, run all cases, write 1225.tst - * - * Build: - * wcl -zq -q -ms -i=.. t1225.c ..\testlib.c - * - * Usage: - * T1225 ref (reference mode, writes 1225.ref) - * T1225 test (test mode, reads 1225.ref, writes 1225.tst) - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include - -const char *g_tbasename = "1225"; - -/* ---- - * We only care about CX on return (the string length). - * All other output registers are don't-cares. - * ---- */ -#define CARE_1225 (CARE_CX) - -/* ---- - * Maximum string length we will test. - * DOS path buffers are 260 bytes; we go a bit beyond to probe limits. - * 513 bytes = 512-char string + NUL. - * ---- */ -#define MAX_STR_LEN 512 -#define BUF_SIZE (MAX_STR_LEN + 1) - -/* Static buffer -- avoids stack overflow in small model */ -static char g_strbuf[BUF_SIZE]; - -/* ---- - * Helper: set up a PROBE for AX=1225h with DS:SI -> string s - * ---- */ -static void setup_1225(PROBE *p, unsigned char far *s, unsigned short dumplen) -{ - memset(p, 0, sizeof(*p)); - p->before.ax = 0x1225; - p->before.ds = FP_SEG(s); - p->before.si = FP_OFF(s); - /* All other input regs zero -- they are not used by this subfunction */ - p->buffer = s; - p->bufsize = dumplen; -} - -/* ---- - * Helper: run one length-based test case - * ---- */ -static int run_len_case(unsigned short len) -{ - PROBE p; - char name[TC_NAME_MAX]; - - build_test_string(g_strbuf, len); - /* Dump at most 32 bytes of the string for the verbose log */ - setup_1225(&p, g_strbuf, (unsigned short)(_fstrlen(g_strbuf) < 32 ? _fstrlen(g_strbuf) + 1 : 32)); - - sprintf(name, "1225_len_%u", (unsigned)len); - - /* In verbose/reference mode, print the input string length */ - if (g_ref_mode) { - printf("INPUT: len=%u str=\"", (unsigned)len); - if (len <= 32) - printf("%s", g_strbuf); - else - printf("%.32s...", g_strbuf); - printf("\"\n"); - } - - return run_case(name, &p, CARE_1225, NULL); -} - -/* ---- - * Helper: run one literal string test case - * ---- */ -static int run_lit_case(const char *label, const char *lit) -{ - PROBE p; - char name[TC_NAME_MAX]; - - /* Copy literal into g_strbuf so it is in a known near buffer */ - strncpy(g_strbuf, lit, BUF_SIZE - 1); - g_strbuf[BUF_SIZE - 1] = '\0'; - - setup_1225(&p, g_strbuf, (unsigned short)(_fstrlen(g_strbuf) < 32 ? _fstrlen(g_strbuf) + 1 : 32)); - - sprintf(name, "1225_%s", label); - - if (g_ref_mode) { - printf("INPUT: literal=\"%s\"\n", g_strbuf); - } - - return run_case(name, &p, CARE_1225, NULL); -} - -/* ---- - * Test suites - * ---- */ - -/* - * Required lengths from the spec: - * 0, 1, 2, 3, 64, 128, 256, 260, 512 - */ -TEST test_required_lengths(void) -{ - ASSERT(run_len_case(0)); - ASSERT(run_len_case(1)); - ASSERT(run_len_case(2)); - ASSERT(run_len_case(3)); - ASSERT(run_len_case(64)); - ASSERT(run_len_case(128)); - ASSERT(run_len_case(256)); - ASSERT(run_len_case(260)); - ASSERT(run_len_case(512)); - PASS(); -} - -/* - * Boundary lengths: one below and one above each power-of-two and - * DOS-significant boundary. - */ -TEST test_boundary_lengths(void) -{ - ASSERT(run_len_case(4)); /* just above 3 */ - ASSERT(run_len_case(7)); /* 8 - 1 */ - ASSERT(run_len_case(8)); - ASSERT(run_len_case(9)); /* 8 + 1 */ - ASSERT(run_len_case(63)); /* 64 - 1 */ - ASSERT(run_len_case(65)); /* 64 + 1 */ - ASSERT(run_len_case(127)); /* 128 - 1 */ - ASSERT(run_len_case(129)); /* 128 + 1 */ - ASSERT(run_len_case(255)); /* 256 - 1 */ - ASSERT(run_len_case(257)); /* 256 + 1 */ - ASSERT(run_len_case(259)); /* MAX_PATH - 1 */ - ASSERT(run_len_case(261)); /* MAX_PATH + 1 */ - ASSERT(run_len_case(511)); /* 512 - 1 */ - PASS(); -} - -/* - * Literal corner-case strings that exercise specific DOS path semantics. - */ -TEST test_literal_cases(void) -{ - /* Empty string: length must be 0 */ - ASSERT(run_lit_case("empty", "")); - - /* Single characters */ - ASSERT(run_lit_case("dot", ".")); - ASSERT(run_lit_case("dotdot", "..")); - ASSERT(run_lit_case("backslash", "\\")); - ASSERT(run_lit_case("fwdslash", "/")); - ASSERT(run_lit_case("colon", ":")); - ASSERT(run_lit_case("space", " ")); - ASSERT(run_lit_case("nul_like_ctrl", "\x01")); /* non-NUL ctrl char */ - - /* Drive-letter forms */ - ASSERT(run_lit_case("drive_only", "C:")); - ASSERT(run_lit_case("drive_root", "C:\\")); - ASSERT(run_lit_case("drive_rel", "C:FOO")); - - /* Path forms */ - ASSERT(run_lit_case("root_only", "\\")); - ASSERT(run_lit_case("trailing_bslash", "ABC\\")); - ASSERT(run_lit_case("mixed_slashes", "A/B\\C/D")); - ASSERT(run_lit_case("deep_path", "A\\B\\C\\D\\E\\F\\G")); - ASSERT(run_lit_case("spaces_inside", "A B C D")); - ASSERT(run_lit_case("three_spaces", " ")); - - /* Wildcard characters (not path separators, but common in DOS) */ - ASSERT(run_lit_case("wildcard_star", "*.*")); - ASSERT(run_lit_case("wildcard_q", "?.?")); - - /* 8.3 filename */ - ASSERT(run_lit_case("filename_83", "FILENAME.EXT")); - - /* All printable ASCII (length 94) */ - ASSERT(run_lit_case("printable_ascii", - " !\"#$%&'()*+,-./0123456789:;<=>?@" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" - "abcdefghijklmnopqrstuvwxyz{|}~")); - - /* High-byte characters (DOS codepage chars, not NUL) */ - ASSERT(run_lit_case("high_byte_80", "\x80")); - ASSERT(run_lit_case("high_byte_fe", "\xFE")); - ASSERT(run_lit_case("high_byte_ff", "\xFF")); - - PASS(); -} - -/* - * Alignment corner cases: string starting at various offsets within - * g_strbuf to catch any word-alignment assumptions in the DOS kernel. - */ -TEST test_alignment_cases(void) -{ - PROBE p; - char name[TC_NAME_MAX]; - unsigned int offset; - - /* Test offsets 0..7 with a 16-char string */ - for (offset = 0; offset <= 7; offset++) { - char far *s; - - build_test_string(g_strbuf, 16); - s = (char far *)(g_strbuf + offset); - - setup_1225(&p, s, 17); - - sprintf(name, "1225_align_off%u", offset); - - if (g_ref_mode) - printf("INPUT: offset=%u str=\"%.16s\"\n", offset, s); - - ASSERT(run_case(name, &p, CARE_1225, NULL)); - } - - PASS(); -} - -/* - * Repeated-NUL / embedded-NUL: the function should stop at the FIRST NUL. - * We manually construct strings with a NUL in the middle. - * Expected CX = position of first NUL. - */ -TEST test_embedded_nul(void) -{ - PROBE p; - - /* "ABC\0DEF" -- length should be 3, not 7 */ - memcpy(g_strbuf, "ABC\x00" "DEF", 8); - - setup_1225(&p, g_strbuf, 8); - - if (g_ref_mode) - printf("INPUT: \"ABCDEF\" (embedded NUL at offset 3)\n"); - - ASSERT(run_case("1225_embedded_nul", &p, CARE_1225, NULL)); - - PASS(); -} - -/* ---- - * Suite - * ---- */ - -SUITE(suite) -{ - RUN_TEST(test_required_lengths); - RUN_TEST(test_boundary_lengths); - RUN_TEST(test_literal_cases); - RUN_TEST(test_alignment_cases); - RUN_TEST(test_embedded_nul); -} diff --git a/tests/opendev/DIREXIST/EMPTYDIR.txt b/tests/opendev/DIREXIST/EMPTYDIR.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/opendev/build.bat b/tests/opendev/build.bat deleted file mode 100644 index bd86e92d..00000000 --- a/tests/opendev/build.bat +++ /dev/null @@ -1,3 +0,0 @@ -@ECHO OFF -:: use -ms for exe, -mt for com -wcl -e3-we-wx-zq-os-s-zp1-ms-bt=DOS opendev.c diff --git a/tests/opendev/opendev.c b/tests/opendev/opendev.c deleted file mode 100644 index f8a4ebc6..00000000 --- a/tests/opendev/opendev.c +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include - -#define MAX_PATH 256 - -#define OPEN_HANDLE 0x3d -#define CLOSE_HANDLE 0x3e - -#define FAILURE 0 -#define SUCCESS (!FAILURE) - - -/* opens device, - prepends device name with specified drive letter, - returns handle to open device or -1 on error - */ -int open_dev(const char drive_letter, const char *device_name) -{ - union REGS regs; - struct SREGS sregs; - char buffer[MAX_PATH]; - - sprintf(buffer, "%c:%s", drive_letter, device_name); - - printf("Opening %s\n", buffer); - - regs.h.ah = OPEN_HANDLE; - regs.h.al = 0; - regs.x.dx = FP_OFF((void far *)buffer); - sregs.ds = FP_SEG((void far *)buffer); - intdosx(®s, ®s, &sregs); - if (regs.x.cflag) - return -1; - return regs.x.ax; -} - -/* close device using file descriptor returned from open_dev - */ -void close_dev(int fd) -{ - union REGS regs; - - regs.h.ah = CLOSE_HANDLE; - regs.x.bx = fd; - intdos(®s, ®s); -} - -int test_device(const char drive_letter, const char *device_name, int should_fail) -{ - int fd; - fd = open_dev(drive_letter, device_name); - if (fd != -1) - close_dev(fd); - - if ( ((fd == -1) && should_fail) || ((fd != -1) && !should_fail) ) - { - printf("SUCCESS - "); - if (should_fail) - printf("open failed\n"); - else - printf("open succeeded\n"); - return SUCCESS; - } - else - { - printf("FAILURE - "); - if (should_fail) - printf("open succeeded\n"); - else - printf("open failed\n"); - return FAILURE; - } -} - -int do_tests_on(const char *device_name) -{ - int status = SUCCESS; - char buffer[MAX_PATH]; - const char current_drive = (char)('A'+_getdrive()-1); - - sprintf(buffer, "%s", device_name); - if (!test_device('@', buffer,0)) status = FAILURE; /* special, should succeed */ - if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid directory, should succeed */ - - /* DIREXIST should exist in the current directory */ - sprintf(buffer, "DIREXIST\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid directory, should succeed */ - - sprintf(buffer, "BAD_PATH\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - if (!test_device(current_drive, buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - - /* assumes DEV directory does not exist in current directory */ - sprintf(buffer, "DEV\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - if (!test_device(current_drive, buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - - sprintf(buffer, "\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - if (!test_device(current_drive, buffer,0)) status = FAILURE; /* valid directory, should succeed */ - - sprintf(buffer, "\\BAD_PATH\\%s", device_name); - if (!test_device('@', buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - if (!test_device(current_drive, buffer,1)) status = FAILURE; /* directory does not exist, should fail */ - - sprintf(buffer, "\\DEV\\%s", device_name); - if (!test_device('@', buffer,0)) status = FAILURE; /* special, should succeed */ - if (!test_device(current_drive, buffer,0)) status = FAILURE; /* special, should succeed */ - - return status; -} - -int test_CON() -{ - return do_tests_on("CON"); -} - -int test_NUL() -{ - return do_tests_on("NUL"); -} - -int test_COM() -{ - return do_tests_on("COM1"); -} - -int main(int argc, char *argv[]) -{ - int error_code = 0; - if (!test_CON()) error_code |= 0x01; - if (!test_NUL()) error_code |= 0x02; - if (!test_COM()) error_code |= 0x04; - - return error_code; -} diff --git a/tests/testlib.c b/tests/testlib.c deleted file mode 100644 index 9fb5b39a..00000000 --- a/tests/testlib.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - * testlib.c -- shared test infrastructure implementation - * - * See testlib.h for full documentation. - * Build: wcl -zq -q -ms -c testlib.c - */ - -#include "../greatest.h" -#include "../testlib.h" - -#include -#include -#include -#include - -/* ----------------------------------------------------------------------- - * Globals - * --------------------------------------------------------------------- */ - -int g_ref_mode = 0; -FILE *g_ref_fp = NULL; -FILE *g_tst_fp = NULL; -TC_LIST g_tclist; /* zero-initialised by testlib_init */ - -/* ----------------------------------------------------------------------- - * TC_RECORD lifecycle - * --------------------------------------------------------------------- */ - -TC_RECORD *tc_create(const char *name) -{ - TC_RECORD *rec; - char *nm; - size_t nlen; - - rec = (TC_RECORD *)malloc(sizeof(TC_RECORD)); - if (!rec) return NULL; - memset(rec, 0, sizeof(TC_RECORD)); - - nlen = strlen(name) + 1; - nm = (char *)malloc(nlen); - if (!nm) { free(rec); return NULL; } - memcpy(nm, name, nlen); - - rec->name = nm; - rec->expected.ax = REF_DONTCARE; - rec->expected.bx = REF_DONTCARE; - rec->expected.cx = REF_DONTCARE; - rec->expected.dx = REF_DONTCARE; - rec->expected.si = REF_DONTCARE; - rec->expected.di = REF_DONTCARE; - rec->expected.ds = REF_DONTCARE; - rec->expected.es = REF_DONTCARE; - rec->expected.flags = REF_DONTCARE; - rec->care_mask = CARE_NONE; - rec->out_buf = NULL; - rec->out_len = 0; - rec->next = NULL; - return rec; -} - -void tc_set_buf(TC_RECORD *rec, - const unsigned char *ptr, - unsigned short len) -{ - if (rec->out_buf) { - free(rec->out_buf); - rec->out_buf = NULL; - rec->out_len = 0; - } - if (!ptr || len == 0) return; - - rec->out_buf = (unsigned char *)malloc(len); - if (!rec->out_buf) return; - memcpy(rec->out_buf, ptr, len); - rec->out_len = len; -} - -void tc_add(TC_LIST *list, TC_RECORD *rec) -{ - rec->next = NULL; - if (!list->root) { - list->root = rec; - list->tail = rec; - } else { - list->tail->next = rec; - list->tail = rec; - } - list->count++; -} - -TC_RECORD *tc_find(TC_LIST *list, const char *name) -{ - TC_RECORD *cur = list->root; - while (cur) { - if (strcmp(cur->name, name) == 0) return cur; - cur = cur->next; - } - return NULL; -} - -void tc_free(TC_RECORD *rec) -{ - if (!rec) return; - if (rec->name) free(rec->name); - if (rec->out_buf) free(rec->out_buf); - free(rec); -} - -void tc_free_all(TC_LIST *list) -{ - TC_RECORD *cur = list->root; - while (cur) { - TC_RECORD *nxt = cur->next; - tc_free(cur); - cur = nxt; - } - list->root = NULL; - list->tail = NULL; - list->count = 0; -} - -/* ----------------------------------------------------------------------- - * testlib_init / testlib_finish - * --------------------------------------------------------------------- */ - -int testlib_init(int argc, char **argv) -{ - char fname[20]; - int i; - - memset(&g_tclist, 0, sizeof(g_tclist)); - g_ref_mode = 0; /* default: test mode */ - - for (i = 1; i < argc; i++) { - if (argv[i][0] == 'r' || argv[i][0] == 'R') { /* ref */ - g_ref_mode = 1; - } - } - - if (g_ref_mode) { - sprintf(fname, "%s.ref", g_tbasename); - g_ref_fp = fopen(fname, "w"); - if (!g_ref_fp) { - fprintf(stderr, "testlib: cannot open %s for writing\n", fname); - return -1; - } - fprintf(g_ref_fp, - "# INT 2F/AH=12h subfunction %s reference file\n", g_tbasename); - fprintf(g_ref_fp, - "# Register line: NAME AX BX CX DX SI DI DS ES FLAGS\n"); - fprintf(g_ref_fp, - "# Each field: 4-digit hex, or ???? (don't-care)\n"); - fprintf(g_ref_fp, - "# Byte-level: ??HH = care low byte only; HH?? = care high byte only\n"); - fprintf(g_ref_fp, - "# Buffer line: B NAME COUNT HH HH ...\n"); - fprintf(g_ref_fp, "#\n"); - printf("=== INT 2F/12h test %s [REFERENCE MODE] ===\n\n", g_tbasename); - } else { - sprintf(fname, "%s.ref", g_tbasename); - if (ref_load(fname, &g_tclist) < 0) { - fprintf(stderr, "testlib: cannot load %s\n", fname); - return -1; - } - sprintf(fname, "%s.tst", g_tbasename); - g_tst_fp = fopen(fname, "w"); - if (!g_tst_fp) { - fprintf(stderr, "testlib: cannot open %s for writing\n", fname); - return -1; - } - fprintf(g_tst_fp, - "# INT 2F/AH=12h subfunction %s test results\n", g_tbasename); - fprintf(g_tst_fp, - "# Format: PASS/FAIL NAME [FIELD EXP GOT]\n"); - fprintf(g_tst_fp, "#\n"); - printf("=== INT 2F/12h test %s [TEST MODE] ===\n\n", g_tbasename); - } - - return 0; -} - -void testlib_finish(void) -{ - if (g_ref_fp) { fflush(g_ref_fp); fclose(g_ref_fp); g_ref_fp = NULL; } - if (g_tst_fp) { fflush(g_tst_fp); fclose(g_tst_fp); g_tst_fp = NULL; } - tc_free_all(&g_tclist); -} - -/* ----------------------------------------------------------------------- - * probe_int2f - * --------------------------------------------------------------------- */ - -void probe_int2f(PROBE far *p) -{ - unsigned short ax_in = p->before.ax; - unsigned short bx_in = p->before.bx; - unsigned short cx_in = p->before.cx; - unsigned short dx_in = p->before.dx; - unsigned short si_in = p->before.si; - unsigned short di_in = p->before.di; - unsigned short ds_in = p->before.ds; - unsigned short es_in = p->before.es; - unsigned short value_in = p->value; - - unsigned short ax_out, bx_out, cx_out, dx_out; - unsigned short si_out, di_out, ds_out, es_out, flags_out; - - unsigned short dos_ds = get_dos_data_segment(); - unsigned short my_sp, my_new_sp; - - if (!ds_in) { - ds_in = dos_ds; - p->before.ds = ds_in; - } - - _asm { - - /* Save harness segments (push DS then ES) */ - push ds - push es - - /* save our SP */ - mov my_sp, sp - } - printf("Probing: SP=%04X\n", my_sp); - _asm { - - /* Load input registers */ - mov bx, bx_in - mov cx, cx_in - mov dx, dx_in - mov si, si_in - mov di, di_in - - /* Load DS and ES */ - mov ax, es_in - mov es, ax - mov ax, ds_in - mov ds, ax - -#if USEDOSSTACK /* assumes tiny mode so CS=DS=SS */ - cli - /* update to DOS stack */ - mov ax, cs:dos_ds - mov ss, ax - mov sp, 0x580 /* roughly top of stack */ - /* now SS=DS=dos segment, SP = safe spot in DOS kernel */ - sti - - /* Push optional stack word (parameter for INT2F) */ - push cs:value_in - - /* Load AX */ - mov ax, cs:ax_in -#else - /* Push optional stack word (parameter for INT2F) */ - push ss:value_in - - /* Load AX */ - mov ax, ss:ax_in -#endif - - /* invoke DOS interrupt */ - int 0x2F - - /* restore stack and program segments but with - care to avoid overwriting results */ -#if USEDOSSTACK /* assumes tiny mode so CS=DS=SS */ - pushf - pop cs:flags_out - - mov cs:ax_out, ax /* save current AX so can use it */ - mov ax, cs /* !!! only true in tiny model */ - cli - mov ss, ax /* we don't care about DOS stack */ - mov sp, ss:my_sp - sti - - /* value_in was on temp stack, so nothing to pop off */ -#else - pushf - pop ss:flags_out - - mov ss:ax_out, ax - - /* Discard the parameter we pushed */ - add sp, 2 ; removes value_in (pop ??) -#endif - - mov ss:my_new_sp, sp - - /* capture outputs */ - - mov ss:bx_out, bx - mov ss:cx_out, cx - mov ss:dx_out, dx - mov ss:si_out, si - mov ss:di_out, di - mov ss:ds_out, ds - mov ss:es_out, es - - /* Restore harness segments in reverse order */ - pop es - pop ds - } - - p->after.ax = ax_out; - p->after.bx = bx_out; - p->after.cx = cx_out; - p->after.dx = dx_out; - p->after.si = si_out; - p->after.di = di_out; - p->after.ds = ds_out; - p->after.es = es_out; - p->after.flags = flags_out; - - if (my_new_sp != my_sp) printf("STACK CORRUPT!\n"); - else printf("STACK OK\n"); -} - -/* ----------------------------------------------------------------------- - * Verbose stdout output helpers - * --------------------------------------------------------------------- */ - -void print_section(const char *label) -{ - printf("--- %s ---\n", label); -} - -void print_call(unsigned short ax, unsigned short value, const char *name) -{ - printf("CALL AX=%04X [%04X=%d='%c'] (%s)\n", ax, value, value, value&0xFF, name); -} - -static void print_one_reg(const char *rname, - unsigned short before, - unsigned short after) -{ - if (before != after) - printf(" %-5s %04X -> %04X *CHANGED*\n", rname, before, after); - else - printf(" %-5s %04X\n", rname, after); -} - -void print_regs(const REGS16 far *b, const REGS16 far *a) -{ - printf("REGS:\n"); - print_one_reg("AX", b->ax, a->ax); - print_one_reg("BX", b->bx, a->bx); - print_one_reg("CX", b->cx, a->cx); - print_one_reg("DX", b->dx, a->dx); - print_one_reg("SI", b->si, a->si); - print_one_reg("DI", b->di, a->di); - print_one_reg("DS", b->ds, a->ds); - print_one_reg("ES", b->es, a->es); -} - -static void print_one_flag(const char *fname, - unsigned short mask, - unsigned short before, - unsigned short after) -{ - int bv = (before & mask) ? 1 : 0; - int av = (after & mask) ? 1 : 0; - if (bv != av) - printf(" %-4s %d -> %d *CHANGED*\n", fname, bv, av); - else - printf(" %-4s %d\n", fname, av); -} - -void print_flags(unsigned short before, unsigned short after) -{ - printf("FLAGS:\n"); - print_one_flag("CF", FLAG_CF, before, after); - print_one_flag("PF", FLAG_PF, before, after); - print_one_flag("AF", FLAG_AF, before, after); - print_one_flag("ZF", FLAG_ZF, before, after); - print_one_flag("SF", FLAG_SF, before, after); - print_one_flag("OF", FLAG_OF, before, after); -} - -void print_mem_dump(unsigned char far *ptr, unsigned short len, signed short max_dump_len) -{ - unsigned short i; - - if (!ptr || !len) { - printf("MEM: (none)\n"); - return; - } - printf("MEM: %04X:%04X len=%u\n", - FP_SEG(ptr), FP_OFF(ptr), len); - - /* don't print out more than buffer size, up to max requested, - where a negative value indicates print whole buffer */ - if (max_dump_len < len && max_dump_len >= 0) len = max_dump_len; - for (i = 0; i < len; i++) { - if (i && (i % 16) == 0) printf("\n"); - if ((i % 16) == 0) printf(" %04X: ", i); - printf("%02X ", ptr[i]); - } - printf("\n"); -} - -void print_end(void) -{ - printf("END\n\n"); -} - -void print_probe_verbose(const PROBE *p, const char *name, signed short max_dump_len) -{ - print_call(p->before.ax, p->value, name); - print_regs(&p->before, &p->after); - print_flags(p->before.flags, p->after.flags); - print_mem_dump(p->buffer, p->bufsize, max_dump_len); - print_end(); -} - -/* ----------------------------------------------------------------------- - * .ref file I/O - * --------------------------------------------------------------------- */ - -/* - * Write one 4-character register field to fp. - * If the full-word care bit is set: write 4 hex digits. - * If only the low-byte care bit is set: write "??HH". - * If only the high-byte care bit is set: write "HH??". - * If neither: write "????". - */ -static void write_reg_field(FILE *fp, - unsigned short val, - unsigned short care_hi_lo_mask) -{ - /* printf("val is %04X, mask is %04X\n", val, care_hi_lo_mask); */ - - if (care_hi_lo_mask & 0x02) - fprintf(fp, "%02X", (val >> 8) & 0xFF); - else - fprintf(fp, "??"); - if (care_hi_lo_mask & 0x01) - fprintf(fp, "%02X", val & 0xFF); - else - fprintf(fp, "??"); -} - -void ref_write(const char *name, - const REGS16 far *after, - unsigned short care_mask) -{ - if (!g_ref_fp) return; - - fprintf(g_ref_fp, "%s ", name); - - write_reg_field(g_ref_fp, after->ax, care_mask & CARE_AX); - fputc(' ', g_ref_fp); - write_reg_field(g_ref_fp, after->bx, (care_mask & CARE_BX)>>2); - fputc(' ', g_ref_fp); - write_reg_field(g_ref_fp, after->cx, (care_mask & CARE_CX)>>4); - fputc(' ', g_ref_fp); - write_reg_field(g_ref_fp, after->dx, (care_mask & CARE_DX)>>6); - fputc(' ', g_ref_fp); - - /* SI, DI, DS, ES: full word or don't-care only */ - if (care_mask & CARE_SI) fprintf(g_ref_fp, "%04X", after->si); - else fprintf(g_ref_fp, "????"); - fputc(' ', g_ref_fp); - - if (care_mask & CARE_DI) fprintf(g_ref_fp, "%04X", after->di); - else fprintf(g_ref_fp, "????"); - fputc(' ', g_ref_fp); - - if (care_mask & CARE_DS) fprintf(g_ref_fp, "%04X", after->ds); - else fprintf(g_ref_fp, "????"); - fputc(' ', g_ref_fp); - - if (care_mask & CARE_ES) fprintf(g_ref_fp, "%04X", after->es); - else fprintf(g_ref_fp, "????"); - fputc(' ', g_ref_fp); - - if (care_mask & CARE_FLAGS) fprintf(g_ref_fp, "%04X", after->flags); - else fprintf(g_ref_fp, "????"); - - fputc('\n', g_ref_fp); -} - -void ref_write_buf(const char *name, - const unsigned char far *ptr, - unsigned short len) -{ - unsigned short i; - if (!g_ref_fp) return; - fprintf(g_ref_fp, "B %s %u", name, (unsigned)len); - for (i = 0; i < len; i++) - fprintf(g_ref_fp, " %02X", ptr[i]); - fputc('\n', g_ref_fp); -} - -/* - * Parse a single register field from a .ref line. - * Handles "????", "HHHH", "??HH" (lo only), "HH??" (hi only). - * Returns pointer past the field (always consumes exactly 4 chars + leading ws). - * *out : parsed value; 0 if lo-only (high byte unknown), val<<8 if hi-only. - * REF_DONTCARE if "????". - * *care_mask is 1 for low byte OR'd 2 for high byte a number (not ?) - */ -static const char *parse_reg_field(const char *p, - unsigned short *out, - unsigned short *care_mask) -{ - unsigned char hi_val = (REF_DONTCARE>>8)&0xFFU, lo_val = REF_DONTCARE&0xFFU; - int hi_ok, lo_ok; - - *care_mask = 0; - *out = REF_DONTCARE; - - while (*p == ' ' || *p == '\t') p++; - - /* High byte: chars 0-1 */ - hi_ok = (isxdigit((unsigned char)p[0]) && isxdigit((unsigned char)p[1])); - if (hi_ok) { - char tmp[3]; - tmp[0]=p[0]; tmp[1]=p[1]; tmp[2]='\0'; - hi_val = (unsigned char)strtoul(tmp, NULL, 16); - *care_mask |= 0x02; - } - - /* Low byte: chars 2-3 */ - lo_ok = (isxdigit((unsigned char)p[2]) && isxdigit((unsigned char)p[3])); - if (lo_ok) { - char tmp[3]; - tmp[0]=p[2]; tmp[1]=p[3]; tmp[2]='\0'; - lo_val = (unsigned char)strtoul(tmp, NULL, 16); - *care_mask |= 0x01; - } - - *out = ((unsigned short)hi_val << 8) | lo_val; - - return p + 4; -} - -int ref_load(const char *filename, TC_LIST *list) -{ - FILE *fp; - char *line; - int count = 0; - TC_RECORD *last = NULL; /* most recently added register record */ - - line = (char *)malloc(REF_LINE_MAX); - if (!line) return -1; - - fp = fopen(filename, "r"); - if (!fp) { free(line); return -1; } - - while (fgets(line, REF_LINE_MAX, fp)) { - const char *p = line; - TC_RECORD *rec; - unsigned short vals[9]; /* parsed register values */ - unsigned short mask; - unsigned short care = CARE_NONE; - int i; - char name_buf[128]; - - /* Skip leading whitespace */ - while (*p == ' ' || *p == '\t') p++; - /* Skip comments and blank lines */ - if (*p == '#' || *p == '\n' || *p == '\r' || *p == '\0') continue; - - /* ---- Buffer line: "B NAME COUNT HH HH ..." ---- */ - if (p[0] == 'B' && (p[1] == ' ' || p[1] == '\t')) { - unsigned short bcount; - unsigned char *bbuf; - - p += 2; - while (*p == ' ' || *p == '\t') p++; - - /* Read name */ - i = 0; - while (*p && *p != ' ' && *p != '\t' && i < (int)sizeof(name_buf)-1) - name_buf[i++] = *p++; - name_buf[i] = '\0'; - - /* Read count */ - while (*p == ' ' || *p == '\t') p++; - bcount = (unsigned short)strtoul(p, (char **)&p, 10); - - if (bcount == 0 || !last) continue; - - bbuf = (unsigned char *)malloc(bcount); - if (!bbuf) continue; - - for (i = 0; i < (int)bcount; i++) { - while (*p == ' ' || *p == '\t') p++; - bbuf[i] = (unsigned char)strtoul(p, (char **)&p, 16); - } - - tc_set_buf(last, bbuf, bcount); - free(bbuf); - continue; - } - - /* ---- Register line: NAME AX BX CX DX SI DI DS ES FLAGS ---- */ - i = 0; - while (*p && *p != ' ' && *p != '\t' && i < (int)sizeof(name_buf)-1) - name_buf[i++] = *p++; - name_buf[i] = '\0'; - - /* Parse AX/BX/CX/DX with byte-level awareness */ - for (i = 0; i < 4; i++) { - p = parse_reg_field(p, &vals[i], &mask); - care |= (mask << (i*2)); /* AX-DX 2bits each for AL/AH-DL/DH */ - } - - /* Parse SI/DI/DS/ES/FLAGS -- full word or don't-care only */ - for (i = 4; i < 9; i++) { - p = parse_reg_field(p, &vals[i], &mask); - care |= (mask << (8+i-4)); /* remaining registers 1 bit each in 2nd byte */ - } - - rec = tc_create(name_buf); - if (!rec) continue; - - rec->expected.ax = vals[0]; - rec->expected.bx = vals[1]; - rec->expected.cx = vals[2]; - rec->expected.dx = vals[3]; - rec->expected.si = vals[4]; - rec->expected.di = vals[5]; - rec->expected.ds = vals[6]; - rec->expected.es = vals[7]; - rec->expected.flags = vals[8]; - - rec->care_mask = care; - - tc_add(list, rec); - last = rec; - count++; - } - - fclose(fp); - free(line); - return count; -} - -/* ----------------------------------------------------------------------- - * Test mode comparison - * --------------------------------------------------------------------- */ - -/* - * Emit one mismatch line to stdout and g_tst_fp. - */ -static void tst_mismatch(const char *rname, const char *suffix, - unsigned short exp, unsigned short got, - int byte_wide, int *failed) -{ - if (byte_wide) { - printf(" MISMATCH %s%s exp=%02X got=%02X\n", - rname, suffix, exp & 0xFF, got & 0xFF); - if (g_tst_fp) - fprintf(g_tst_fp, " MISMATCH %s%s exp=%02X got=%02X\n", - rname, suffix, exp & 0xFF, got & 0xFF); - } else { - printf(" MISMATCH %s exp=%04X got=%04X\n", rname, exp, got); - if (g_tst_fp) - fprintf(g_tst_fp, " MISMATCH %s exp=%04X got=%04X\n", - rname, exp, got); - } - *failed = 1; -} - -/* - * Compare one AX/BX/CX/DX register using its two byte-level care bits. - * hi_bit / lo_bit: the CARE_xH / CARE_xL constants for this register. - * exp / got: full 16-bit values (even if only one byte is compared). - */ -static void tst_field_byte(const char *rname, - unsigned short exp, - unsigned short got, - unsigned short care_mask, - unsigned short hi_bit, - unsigned short lo_bit, - int *failed) -{ - int has_hi = (care_mask & hi_bit); - int has_lo = (care_mask & lo_bit); - - /* - printf("TESTING BYTE for (%s) - expected:%04X, got:%04X, care_mask:%04X, hi_bit:%04X, lo_bit:%04X, AH:%04X, AL:%04X\n", - rname, exp, got, care_mask, hi_bit, lo_bit, (hi_bit & CARE_AH), (lo_bit & CARE_AL)); - */ - - if (!has_hi && !has_lo) return; /* register not in care set */ - - if (has_hi && has_lo) { - /* Full word */ - if (exp != got) - tst_mismatch(rname, "", exp, got, 0, failed); - } else if (has_hi) { - /* High byte only */ - if (((exp >> 8) & 0xFF) != ((got >> 8) & 0xFF)) - tst_mismatch(rname, "(H)", exp >> 8, got >> 8, 1, failed); - } else { - /* Low byte only */ - if ((exp & 0xFF) != (got & 0xFF)) - tst_mismatch(rname, "(L)", exp, got, 1, failed); - } -} - -/* Full-word field: SI/DI/DS/ES/FLAGS */ -static void tst_field_full(const char *rname, - unsigned short exp, - unsigned short got, - unsigned short care_mask, - unsigned short full_bit, - int *failed) -{ - if (!(care_mask & full_bit)) return; - if (exp == REF_DONTCARE) return; - if (exp != got) - tst_mismatch(rname, "", exp, got, 0, failed); -} - -int tst_compare(const char *name, - const REGS16 far *after, - const TC_RECORD *rec) -{ - int failed = 0; - unsigned short cm; - - if (!rec) { - printf(" NO_REF %s\n", name); - if (g_tst_fp) fprintf(g_tst_fp, "NO_REF %s\n", name); - return 0; - } - - cm = rec->care_mask; - - tst_field_byte("AX", rec->expected.ax, after->ax, cm, CARE_AH, CARE_AL, &failed); - tst_field_byte("BX", rec->expected.bx, after->bx, cm, CARE_BH, CARE_BL, &failed); - tst_field_byte("CX", rec->expected.cx, after->cx, cm, CARE_CH, CARE_CL, &failed); - tst_field_byte("DX", rec->expected.dx, after->dx, cm, CARE_DH, CARE_DL, &failed); - - tst_field_full("SI", rec->expected.si, after->si, cm, CARE_SI, &failed); - tst_field_full("DI", rec->expected.di, after->di, cm, CARE_DI, &failed); - tst_field_full("DS", rec->expected.ds, after->ds, cm, CARE_DS, &failed); - tst_field_full("ES", rec->expected.es, after->es, cm, CARE_ES, &failed); - tst_field_full("FLAGS", rec->expected.flags, after->flags, cm, CARE_FLAGS, &failed); - - if (!failed) { - printf("PASS %s\n", name); - if (g_tst_fp) fprintf(g_tst_fp, "PASS %s\n", name); - return 1; - } else { - printf("FAIL %s\n", name); - if (g_tst_fp) fprintf(g_tst_fp, "FAIL %s\n", name); - return 0; - } -} - -int tst_compare_buf(const char *name, - const unsigned char far *ptr, - unsigned short len, - const TC_RECORD *rec) -{ - unsigned short i, mismatches, cmp_len; - int failed = 0; - int got_empty = (!ptr || len == 0); - int ref_empty = (!rec || !rec->out_buf || rec->out_len == 0); - - /* Both sides empty -> pass silently (no buffer involvement) */ - if (got_empty && ref_empty) return 1; - - if (!rec) { - printf(" NO_REF_BUF %s\n", name); - if (g_tst_fp) fprintf(g_tst_fp, "NO_REF_BUF %s\n", name); - return 0; - } - - if (got_empty && !ref_empty) { - printf(" FAIL_BUF %s got=empty exp=%u bytes\n", name, rec->out_len); - if (g_tst_fp) - fprintf(g_tst_fp, "FAIL_BUF %s got=empty exp=%u bytes\n", - name, rec->out_len); - return 0; - } - if (!got_empty && ref_empty) { - printf(" FAIL_BUF %s got=%u bytes exp=empty\n", name, len); - if (g_tst_fp) - fprintf(g_tst_fp, "FAIL_BUF %s got=%u bytes exp=empty\n", - name, len); - return 0; - } - - /* Length mismatch (continue to report byte mismatches too) */ - if (len != rec->out_len) { - printf(" FAIL_BUF %s len: exp=%u got=%u\n", - name, rec->out_len, len); - if (g_tst_fp) - fprintf(g_tst_fp, "FAIL_BUF %s len: exp=%u got=%u\n", - name, rec->out_len, len); - failed = 1; - } - - cmp_len = (len < rec->out_len) ? len : rec->out_len; - mismatches = 0; - for (i = 0; i < cmp_len && mismatches < 8; i++) { - if (ptr[i] != rec->out_buf[i]) { - printf(" FAIL_BUF %s [%u] exp=%02X got=%02X\n", - name, i, rec->out_buf[i], ptr[i]); - if (g_tst_fp) - fprintf(g_tst_fp, "FAIL_BUF %s [%u] exp=%02X got=%02X\n", - name, i, rec->out_buf[i], ptr[i]); - failed = 1; - mismatches++; - } - } - - if (!failed) { - printf("PASS_BUF %s\n", name); - if (g_tst_fp) fprintf(g_tst_fp, "PASS_BUF %s\n", name); - return 1; - } - printf("FAIL_BUF %s\n", name); - if (g_tst_fp) fprintf(g_tst_fp, "FAIL_BUF %s\n", name); - return 0; -} - -/* ----------------------------------------------------------------------- - * All-in-one per-case runner - * --------------------------------------------------------------------- */ - -int run_case(const char *name, PROBE *p, unsigned short care_mask, fn_run_hook *fn) -{ - int reg_ok, buf_ok; - - probe_int2f(p); - - if (fn != NULL) { - if (fn(name, p, care_mask)) - return 0; - } - /* printf("buffer:%04X:%04X == %04X:%04X\n", FP_SEG(p->buffer), FP_OFF(p->buffer), p->after.es, p->after.di); */ - - if (g_ref_mode) { - print_probe_verbose(p, name, -1); - ref_write(name, &p->after, care_mask); - if (p->buffer && p->bufsize > 0) - ref_write_buf(name, p->buffer, p->bufsize); - return 1; - } else { - TC_RECORD *rec = tc_find(&g_tclist, name); - reg_ok = tst_compare(name, &p->after, rec); - buf_ok = tst_compare_buf(name, p->buffer, p->bufsize, rec); - return reg_ok && buf_ok; - } -} - -/* ----------------------------------------------------------------------- - * Utilities - * --------------------------------------------------------------------- */ - -void build_test_string(char far *buf, unsigned short len) -{ - static const char pat[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"; - unsigned short pat_len = (unsigned short)(sizeof(pat) - 1); - unsigned short i; - for (i = 0; i < len; i++) - buf[i] = pat[i % pat_len]; - buf[len] = '\0'; -} - -unsigned short get_dos_data_segment(void) -{ - unsigned short dos_ds; - _asm { - push ds - mov ax, 1203h - int 2Fh - mov ax, ds - mov dos_ds, ax - pop ds - } - return dos_ds; -} - - -#ifndef NO_MAIN -/* ------------------------------------------------------------------ */ -/* main */ -/* ------------------------------------------------------------------ */ - -GREATEST_MAIN_DEFS(); - -void suite(void); /* SUITE(suite) required in test */ - -int main(int argc, char **argv) -{ - int rc; - - rc = testlib_init(argc, argv); - if (rc < 0) return EXIT_FAILURE; - - GREATEST_MAIN_BEGIN(); - RUN_SUITE(suite); - - testlib_finish(); - - GREATEST_MAIN_END(); /* returns EXIT_SUCCESS if all tests pass */ -} -#endif diff --git a/tests/testlib.h b/tests/testlib.h deleted file mode 100644 index 829cd4db..00000000 --- a/tests/testlib.h +++ /dev/null @@ -1,433 +0,0 @@ -/* - * testlib.h -- shared test infrastructure - * - * Layout: - * tests/ - * greatest.h - * testlib.h <- this file - * testlib.c - * int2f-12/ - * t12xx.c <- each subfunction test, includes "../testlib.h" - * - * Build with Open Watcom 16-bit (wcl -zq -q -ms ...) - * Targets real-mode DOS (small model). - * - * Two runtime modes, selected by argv[1]: - * r / R REFERENCE mode: run tests, write NNN.ref, print verbose - * (none / anything) TEST mode: read NNN.ref, run tests, write NNN.tst - * - * .ref file format - * ---------------- - * Lines beginning with '#' are comments. Blank lines are ignored. - * - * Register line: - * NAME AX BX CX DX SI DI DS ES FLAGS - * Each field is a 4-digit hex value or "????" (don't-care). - * For AX/BX/CX/DX the high byte may be "??" and low byte a 2-digit hex - * value (or vice-versa) to express byte-level care: - * e.g. "??1A" means care only about AL=0x1A, ignore AH. - * "1A??" means care only about AH=0x1A, ignore AL. - * - * Buffer line (optional, immediately follows its register line): - * B NAME COUNT HH HH ... - * COUNT is a decimal byte count (may be 0). - * HH are COUNT space-separated 2-digit hex bytes. - * The empty string "" is represented as: B name 1 00 - * - */ - -#ifndef TESTLIB_H -#define TESTLIB_H - -#include -#include -#include -#include - -/* ----------------------------------------------------------------------- - * Version - * --------------------------------------------------------------------- */ - -#define TESTLIB_VERSION "2.0" - -/* ----------------------------------------------------------------------- - * Sentinel: "don't care" value in a .ref field - * --------------------------------------------------------------------- */ - -#define REF_DONTCARE 0xFEADU - -/* Maximum line length when reading .ref files (long buffer hex lines) */ -#define REF_LINE_MAX 1024 - -/* Maximum name length of a test case, must be less than REF_LINE_MAX */ -#define TC_NAME_MAX 128 - -/* ----------------------------------------------------------------------- - * Register snapshot - * --------------------------------------------------------------------- */ - -typedef struct { - unsigned short ax; - unsigned short bx; - unsigned short cx; - unsigned short dx; - unsigned short si; - unsigned short di; - unsigned short ds; - unsigned short es; - unsigned short flags; -} REGS16; - -/* ----------------------------------------------------------------------- - * PROBE -- per-call descriptor - * - * Caller fills ax_in, before.*, and optionally buffer/bufsize before - * calling probe_int2f(). probe_int2f() fills after.*. - * - * buffer / bufsize - * Optional I/O buffer (far pointer as may be DOS owned != our DS) - * testlib does NOT free or own this memory. - * In run_case(), when CARE_BUF is set in care_mask, the contents of - * buffer[0..bufsize-1] after the call are recorded to / compared - * against the TC_RECORD's out_buf. - * Set buffer=NULL and bufsize=0 if no buffer tracking is needed. - * - * Optionally may hex dump contents in reference mode only. - * - * value - * Optional word pushed on the stack immediately before INT 2Fh. - * Set to 0 if unused (it is always pushed; 0 is harmless for callers - * that ignore the stack word). - * --------------------------------------------------------------------- */ - -typedef struct { - /* AX --> (AH=12h, AL=subfunction) */ - REGS16 before; /* register state to load before INT 2Fh */ - REGS16 after; /* register state captured after INT 2Fh */ - unsigned char far *buffer; /* I/O buffer, or NULL, hex dumped */ - /* far as may be DOS provided ptr */ - unsigned short bufsize; /* valid bytes in buffer (0 if none) */ - unsigned short value; /* word pushed before INT 2Fh */ -} PROBE; - -/* ----------------------------------------------------------------------- - * care_mask bit positions - * - * Bits 0-8: which full registers to compare. - * Bits 9-16: byte-level overrides for AX/BX/CX/DX. - * CARE_xH -- compare only the high byte of register x (ignore low byte) - * CARE_xL -- compare only the low byte of register x (ignore high byte) - * If both CARE_xH and CARE_xL are set (or CARE_x is set), full word compared. - * CARE_x alone (without CARE_xH/CARE_xL) also means full word compared. - * - * Bit 17: CARE_BUF -- compare probe->buffer[0..bufsize-1] against stored ref. - * --------------------------------------------------------------------- */ - -/* Byte-level care for AX */ -#define CARE_AL 0x0001U -#define CARE_AH 0x0002U -/* Byte-level care for BX */ -#define CARE_BL 0x0004U -#define CARE_BH 0x0008U -/* Byte-level care for CX */ -#define CARE_CL 0x0010U -#define CARE_CH 0x0020U -/* Byte-level care for DX */ -#define CARE_DL 0x0040U -#define CARE_DH 0x0080U - -#define CARE_AX (CARE_AH | CARE_AL) -#define CARE_BX (CARE_BH | CARE_BL) -#define CARE_CX (CARE_CH | CARE_CL) -#define CARE_DX (CARE_DH | CARE_DL) -#define CARE_SI 0x0100U -#define CARE_DI 0x0200U -#define CARE_DS 0x0400U -#define CARE_ES 0x0800U -#define CARE_FLAGS 0x1000U -#define CARE_BUF 0x2000U - -#define CARE_NONE 0x0000U - -/* ----------------------------------------------------------------------- - * TC_RECORD -- one test case, heap-allocated, singly-linked list node - * - * All pointer fields are heap-allocated and owned by this record. - * tc_free() releases them all. - * --------------------------------------------------------------------- */ - -typedef struct TC_RECORD { - char *name; /* heap: strlen(name)+1 bytes */ - - /* Expected register values after the call. */ - REGS16 expected; - - /* Which registers to compare (CARE_xx bitmask, including byte bits). */ - unsigned short care_mask; - - /* Captured output buffer (heap: out_len bytes, or NULL if none). */ - unsigned char *out_buf; - unsigned short out_len; - - /* Linked list */ - struct TC_RECORD *next; -} TC_RECORD; - -/* ----------------------------------------------------------------------- - * TC_LIST -- linked list root/tail/count - * --------------------------------------------------------------------- */ - -typedef struct { - TC_RECORD *root; /* first record; NULL if empty */ - TC_RECORD *tail; /* last record; NULL if empty */ - int count; /* total records in chain */ -} TC_LIST; - -/* ----------------------------------------------------------------------- - * Flag bit positions (8086 FLAGS register) - * --------------------------------------------------------------------- */ - -#define FLAG_CF 0x0001U -#define FLAG_PF 0x0004U -#define FLAG_AF 0x0010U -#define FLAG_ZF 0x0040U -#define FLAG_SF 0x0080U -#define FLAG_TF 0x0100U -#define FLAG_IF 0x0200U -#define FLAG_DF 0x0400U -#define FLAG_OF 0x0800U - -/* ---- - * fn_run_hook -- post-probe, pre-comparison callback for run_case() - * - * Called by run_case() after probe_int2f() has filled p->after, but - * before any .ref writing or comparison is performed. The hook may - * inspect p->after and update any PROBE fields -- such as - * p->buffer and p->bufsize -- to reflect data that is only known after - * the INT 2Fh call returns (e.g. a pointer returned in ES:DI). - * - * Return value: - * 0 -- continue normally (proceed to ref_write / tst_compare). - * !0 -- abort this case; run_case() returns 0 (failure) immediately - * without writing to .ref or comparing. The hook should print - * a diagnostic before returning non-zero. - * - * Pass NULL as the fn argument to run_case() when no hook is needed; - * ---- */ - -typedef int (fn_run_hook)(const char *name, PROBE *p, unsigned short care); - -/* ----------------------------------------------------------------------- - * Globals (defined in testlib.c) - * --------------------------------------------------------------------- */ - -extern const char *g_tbasename; /* declared by test e.g. "1204" */ -extern int g_ref_mode; /* 1 = reference mode, 0 = test mode */ -extern FILE *g_ref_fp; /* .ref file (write in ref mode) */ -extern FILE *g_tst_fp; /* .tst file (write in test mode) */ -extern TC_LIST g_tclist; /* the global linked list of test records */ - -/* ----------------------------------------------------------------------- - * TC_RECORD lifecycle - * --------------------------------------------------------------------- */ - -/* - * tc_create(name) - * Allocate and zero-initialise a new TC_RECORD. - * Heap-allocates a copy of name. - * All expected fields initialised to REF_DONTCARE. - * out_buf = NULL, out_len = 0, next = NULL. - * Returns NULL on allocation failure. - */ -TC_RECORD *tc_create(const char *name); - -/* - * tc_set_buf(rec, ptr, len) - * Replace rec->out_buf with a heap copy of ptr[0..len-1]. - * Frees any previous out_buf. - * len=0 or ptr=NULL clears the buffer (sets out_buf=NULL, out_len=0). - */ -void tc_set_buf(TC_RECORD *rec, - const unsigned char *ptr, - unsigned short len); - -/* - * tc_add(list, rec) - * Append rec to the tail of list. rec->next must be NULL. - */ -void tc_add(TC_LIST *list, TC_RECORD *rec); - -/* - * tc_find(list, name) - * Linear search by name. Returns first match or NULL. - */ -TC_RECORD *tc_find(TC_LIST *list, const char *name); - -/* - * tc_free(rec) - * Free a single TC_RECORD and all its owned heap memory. - * Does NOT unlink from any list; caller must do that first. - */ -void tc_free(TC_RECORD *rec); - -/* - * tc_free_all(list) - * Free every record in the list and reset list to empty. - */ -void tc_free_all(TC_LIST *list); - -/* ----------------------------------------------------------------------- - * Initialisation / teardown - * --------------------------------------------------------------------- */ - -/* - * testlib_init(basename, argc, argv) - * Initialises globals, opens files, loads .ref in test mode. - * basename: e.g. "1211" -> "1211.ref" / "1211.tst" now global g_tbasename declared in test - * argv[1] == "r" or "R" -> reference mode; otherwise test mode. - * Returns 0 on success, -1 on error. - */ -int testlib_init(int argc, char **argv); - -/* - * testlib_finish() - * Flushes/closes output files and frees all TC_RECORD heap memory. - */ -void testlib_finish(void); - -/* ----------------------------------------------------------------------- - * Core INT 2Fh probe - * --------------------------------------------------------------------- */ - -/* - * probe_int2f(p) - * Issues INT 2Fh with registers from p->before (assumes AX indicates function). - * If p->before.ds == 0, substitutes the DOS data segment automatically - * and updates p->before.ds so the caller can see what was used. - * Captures all output registers and FLAGS into p->after. - * p->value is pushed on the stack immediately before INT 2Fh. - */ -void probe_int2f(PROBE far *p); - -/* ----------------------------------------------------------------------- - * .ref file I/O - * --------------------------------------------------------------------- */ - -/* - * ref_write(name, after, care_mask) - * Write one register line to g_ref_fp. - * Fields not in care_mask are written as "????". - * For AX/BX/CX/DX, byte-level care bits cause "??HH" or "HH??" output. - */ -void ref_write(const char *name, - const REGS16 far *after, - unsigned short care_mask); - -/* - * ref_write_buf(name, ptr, len) - * Write a "B NAME COUNT HH HH ..." line to g_ref_fp. - * len=0 writes "B NAME 0" with no hex bytes. - */ -void ref_write_buf(const char *name, - const unsigned char far *ptr, - unsigned short len); - -/* - * ref_load(filename, list) - * Parse a .ref file and populate list with TC_RECORDs. - * Register lines create new records; "B" lines attach buffers to the - * most-recently created record. - * Returns number of register records loaded, or -1 on file-open error. - */ -int ref_load(const char *filename, TC_LIST *list); - -/* ----------------------------------------------------------------------- - * Test mode comparison - * --------------------------------------------------------------------- */ - -/* - * tst_compare(name, after, rec) - * Compare after against rec->exp_* fields honoring rec->care_mask. - * Prints PASS/FAIL to stdout and g_tst_fp. - * Returns 1 if passed, 0 if failed or rec==NULL. - */ -int tst_compare(const char *name, - const REGS16 far *after, - const TC_RECORD *rec); - -/* - * tst_compare_buf(name, ptr, len, rec) - * Compare ptr[0..len-1] against rec->out_buf[0..rec->out_len-1]. - * Both NULL/0 -> PASS (neither side recorded a buffer). - * One side NULL/0 and the other not -> FAIL. - * Prints PASS_BUF/FAIL_BUF to stdout and g_tst_fp. - * Returns 1 if passed, 0 if failed. - */ -int tst_compare_buf(const char *name, - const unsigned char far *ptr, - unsigned short len, - const TC_RECORD *rec); - -/* ----------------------------------------------------------------------- - * All-in-one per-case runner - * --------------------------------------------------------------------- */ - -/* - * run_case(name, p, care_mask, fn) - * 1. Calls probe_int2f(p) to issue INT 2Fh and capture p->after. - * 2. If fn != NULL, calls fn(name, p, care_mask). - * - fn may update p->buffer / p->bufsize (or any other PROBE field) - * using information from p->after (e.g. ES:DI returned by DOS). - * - If fn returns non-zero the case is treated as failed and - * run_case() returns 0 immediately without writing to .ref or - * comparing against .ref. - * 3. Reference mode: print verbose output, write register line to .ref, - * and (if p->buffer != NULL && p->bufsize > 0) write buffer line. - * 4. Test mode: compare registers and (if CARE_BUF set) buffer against - * the loaded TC_RECORD for name. - * - * Pass fn=NULL when no post-probe hook is needed. - * - * Returns 1 if passed (or reference mode with no hook failure), 0 if failed. - */ -int run_case(const char *name, - PROBE *p, - unsigned short care_mask, - fn_run_hook *fn); - -/* ----------------------------------------------------------------------- - * Verbose stdout output helpers (used in reference mode) - * --------------------------------------------------------------------- */ - -void print_section(const char *label); -void print_call(unsigned short ax, unsigned short value, const char *name); -void print_regs(const REGS16 far *before, const REGS16 far *after); -void print_flags(unsigned short before, unsigned short after); -void print_mem_dump(unsigned char far *ptr, unsigned short len, signed short max_dump_len); -void print_end(void); -void print_probe_verbose(const PROBE *p, const char *name, signed short max_dump_len); - -/* ----------------------------------------------------------------------- - * Utilities - * --------------------------------------------------------------------- */ - -/* - * build_test_string(buf, len) - * Fill buf[0..len-1] with a repeating printable pattern; NUL-terminate. - * buf must be at least len+1 bytes. - */ -void build_test_string(char far *buf, unsigned short len); - -/* - * get_dos_data_segment() - * Return the DOS internal data segment via INT 2F/AX=1203h. - */ -unsigned short get_dos_data_segment(void); - -/* - * get_dos_stack_offset(void) - * Return a likely offset within DOS data segment for use as valid stack pointer. - */ -unsigned short get_dos_stack_offset(void); - -#endif /* TESTLIB_H */ diff --git a/utils/echoto.bat b/utils/echoto.bat old mode 100644 new mode 100755 index 958895fc..f3fe60db --- a/utils/echoto.bat +++ b/utils/echoto.bat @@ -1,6 +1 @@ -@echo off -if "%2%3%4%5%6%7%8%9" == "" goto nothing -echo %2 %3 %4 %5 %6 %7 %8 %9 >>%1 -shift -if not "%9" == "" echo echoto.bat arguments overflow -:nothing +@echo %2 %3 %4 %5 %6 %7 %8 %9>>%1 \ No newline at end of file diff --git a/utils/exeflat.c b/utils/exeflat.c index d0f3804f..c60a4da2 100644 --- a/utils/exeflat.c +++ b/utils/exeflat.c @@ -36,11 +36,11 @@ large portions copied from task.c /* history - 10/??/01 - Bart Oldeman - primary release + 10/??/01 - Bart Oldeman + primary release - 11/28/01 - tom ehlert - added -UPX option to make the kernel compressable with UPX + 11/28/01 - tom ehlert + added -UPX option to make the kernel compressable with UPX */ @@ -48,16 +48,11 @@ large portions copied from task.c #include "exe.h" #include #include -#include #include #define BUFSIZE 32768u -#define KERNEL_CONFIG_LENGTH (32 - 2 - 4) - /* 32 entrypoint structure, - 2 entrypoint short jump, - 4 near jump / ss:sp storage */ -unsigned char kernel_config[KERNEL_CONFIG_LENGTH]; +#define KERNEL_START 0x10 /* the kernel code really starts here at 60:10 */ typedef struct { UWORD off, seg; @@ -81,19 +76,16 @@ static int compReloc(const void *p1, const void *p2) static void usage(void) { printf("usage: exeflat (src.exe) (dest.sys) (relocation-factor)\n"); - printf(" -S10 - Silent relocate segment 10 (down list)\n"); - printf(" -E(path/to/upxentry.bin) - Omit to force DOS/SYS compression\n"); - printf(" -D(path/to/upxdevic.bin) - Omit to force DOS/EXE compression\n"); - printf(" -U (command) (parameters) - Specify to use UPX compression\n"); - printf(" @(indirect file) - Specify to use indirect file\n"); - printf(" indirect file format, each line contains single argument\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 use_upx, UWORD stubexesize, UWORD stubdevsize, - UWORD entryparagraphs, exe_header *header) +static exe_header header; + +int exeflat(int UPX, const char *srcfile, const char *dstfile, + const char *start, short *silentSegments, short silentcount) { int i, j; size_t bufsize; @@ -102,44 +94,46 @@ static int exeflat(const char *srcfile, const char *dstfile, ULONG size, to_xfer; UBYTE **buffers; UBYTE **curbuf; - UWORD curbufoffset; FILE *src, *dest; short silentdone = 0; - int compress_sys_file = 0; - UWORD stubsize = 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) + if (fread(&header, sizeof(header), 1, src) != 1) { printf("Error reading header from %s\n", srcfile); fclose(src); exit(1); } - if (header->exSignature != MAGIC) + if (header.exSignature != MAGIC) { printf("Source file %s is not a valid .EXE\n", srcfile); fclose(src); exit(1); } + if ((dest = fopen(dstfile, "wb+")) == NULL) + { + printf("Destination file %s could not be created\n", dstfile); + exit(1); + } start_seg = (UWORD)strtol(start, NULL, 0); - start_seg += entryparagraphs; - if (header->exExtraBytes == 0) - header->exExtraBytes = 0x200; - printf("header len = %lu = 0x%lx\n", header->exHeaderSize * 16UL, - header->exHeaderSize * 16UL); + 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; + ((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%x\n", header->exRelocTable, - header->exRelocTable); + 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); + fseek(src, header.exHeaderSize * 16UL, SEEK_SET); buffers = malloc((size_t)((size + BUFSIZE - 1) / BUFSIZE) * sizeof(char *)); if (buffers == NULL) { @@ -160,29 +154,29 @@ static int exeflat(const char *srcfile, const char *dstfile, } if (fread(*curbuf, sizeof(char), bufsize, src) != bufsize) { - printf("Source file read error %ld %d\n", to_xfer, (int)bufsize); + printf("Source file read error %ld %d\n", to_xfer, bufsize); exit(1); } } - if (header->exRelocTable && header->exRelocItems) + if (header.exRelocTable && header.exRelocItems) { - fseek(src, header->exRelocTable, SEEK_SET); - reloc = malloc(header->exRelocItems * sizeof(farptr)); + 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) + 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++) + 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)]; @@ -206,494 +200,232 @@ static int exeflat(const char *srcfile, const char *dstfile, *spot1 = segment >> 8; } - printf("\nProcessed %d relocations, %d not shown\n", - header->exRelocItems, silentdone); - - if (use_upx) - { - struct x { - char y[(KERNEL_CONFIG_LENGTH + 2) <= BUFSIZE ? 1 : -1]; - }; - memcpy(kernel_config, &buffers[0][2], KERNEL_CONFIG_LENGTH); - } - - 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. - Actually, UPX 3.96 appears to accept DOS/SYS files up to 65426 bytes. - To avoid problems we use a slightly lower limit. */ - if (use_upx) { - if (stubdevsize && stubexesize) - compress_sys_file = (size - stubdevsize) <= /* 65426 */ 65400; - /* would need to subtract 0x10 for the device header here - but then add in the same, because we skip 0x10 bytes - of the source file but fill the same length with the - doctored device header. so (size - stubdevsize) gives - the exact result that we want to compare against. */ - else if (stubexesize) - compress_sys_file = 0; - else if (stubdevsize) - compress_sys_file = 1; - else { - printf("Error: Entry file must be specified\n"); - exit(1); - } - printf("Compressing kernel - %s format\n", (compress_sys_file)?"sys":"exe"); - if (!compress_sys_file) { - ULONG realsize; + compress_sys_file = size < 0x10000L; + if (UPX && !compress_sys_file) { /* write header without relocations to file */ - exe_header nheader = *header; + exe_header nheader = header; nheader.exRelocItems = 0; nheader.exHeaderSize = 2; - stubsize = stubexesize; - realsize = size + 32 - stubsize; - nheader.exPages = (UWORD)(realsize >> 9); - nheader.exExtraBytes = (UWORD)realsize & 511; + size += 32; + nheader.exPages = (UWORD)(size >> 9); + nheader.exExtraBytes = (UWORD)size & 511; if (nheader.exExtraBytes) nheader.exPages++; - nheader.exInitCS = - (stubsize >> 4); - nheader.exInitIP = stubsize; if (fwrite(&nheader, sizeof(nheader), 1, dest) != 1) { printf("Destination file write error\n"); exit(1); } fseek(dest, 32UL, SEEK_SET); - if (stubsize < 0xC0) { - UWORD branchlength = 0xC0 - stubsize; - if ((branchlength - 2) < 0x80) { - buffers[0][stubsize] = 0xEB; /* short jump */ - buffers[0][stubsize + 1] = branchlength - 2; - } else { - branchlength -= 3; - buffers[0][stubsize] = 0xE9; /* near jump */ - buffers[0][stubsize + 1] = branchlength & 0xFF; - buffers[0][stubsize + 2] = (branchlength >> 8) & 0xFF; - } - } - } else { - /* create device header. it goes before the image. after - decompression its strategy is entered from the UPX - depacker. it consists of 5 words and a far jump: - next device offset, next device segment, attributes, - the fourth word is the offset of strategy entry, - the fifth word would be offset of interrupt entry - (not used by UPX apparently but better to give it). */ - UBYTE deviceheader[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - UWORD segment = start_seg; - UWORD offset = 0xC0; - stubsize = stubdevsize + 0x10; /* 0x10 for deviceheader */ - /* strategy will jump to us, interrupt never called */ - deviceheader[6] = 10; - deviceheader[7] = 0; /* needed: strategy entry */ - deviceheader[8] = 10; - deviceheader[9] = 0; /* interrupt entry */ - deviceheader[10] = 0xEA; /* jump far immediate */ - deviceheader[11] = offset & 0xFF; - deviceheader[12] = (offset >> 8) & 0xFF; - deviceheader[13] = segment & 0xFF; - deviceheader[14] = (segment >> 8) & 0xFF; - if (fwrite(deviceheader, 1, sizeof deviceheader, dest) - != sizeof deviceheader) { - printf("Destination file write error\n"); - exit(1); - } - } } /* write dest file from memory chunks */ + bufsize = BUFSIZE; + for (to_xfer = size, curbuf = buffers; to_xfer > 0; + to_xfer -= bufsize, curbuf++) { - struct x { - char y[0xC0 < BUFSIZE ? 1 : -1]; - /* insure the stub fits into the first chunk buffer. - needed for the branch patch above, and to - skip the source data corresponding to the - stub in the first iteration of the loop below. */ - }; - } - /* stubsize = 0 if not UPX */ - curbufoffset = stubsize; - bufsize = BUFSIZE - stubsize; - to_xfer = size - stubsize; - for (curbuf = buffers; to_xfer > 0; - to_xfer -= bufsize, curbuf++, curbufoffset = 0, bufsize = BUFSIZE) - { - if (to_xfer < bufsize) + if (to_xfer < BUFSIZE) bufsize = (size_t)to_xfer; - if (fwrite(&(*curbuf)[curbufoffset], sizeof(char), bufsize, dest) != bufsize) + 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); + printf("\nProcessed %d relocations, %d not shown\n", + header.exRelocItems, silentdone); return compress_sys_file; } -static void write_header(FILE *dest, unsigned char * code, UWORD stubsize, - const char *start, int compress_sys_file, exe_header *header) +static void write_header(FILE *dest, size_t size) { - UWORD stackpointerpatch, stacksegmentpatch, psppatch, csippatch, patchvalue; - UWORD end; - UWORD start_seg = (UWORD)strtol(start, NULL, 0); - - stackpointerpatch = code[0x100] + code[0x100 + 1] * 256U; - stacksegmentpatch = code[0x102] + code[0x102 + 1] * 256U; - psppatch = code[0x104] + code[0x104 + 1] * 256U; - csippatch = code[0x106] + code[0x106 + 1] * 256U; - end = code[0x108] + code[0x108 + 1] * 256U; - if (csippatch > (end - 4) || csippatch < 32 - || end > 0xC0 || end < 32) { - printf("Invalid entry file patch offsets\n"); - exit(1); - } - if (compress_sys_file) { - if (stackpointerpatch != 0 - || stacksegmentpatch != 0 - || psppatch != 0 - || end > (0xC0 - 0x10) || end < 32) { - printf("Invalid entry file patch offsets\n"); - exit(1); - } - } else { - if (stackpointerpatch > (end - 2) || stackpointerpatch < 32 - || stacksegmentpatch > (end - 2) || stacksegmentpatch < 32 - || psppatch > (end - 2) || psppatch < 32) { - printf("Invalid entry file patch offsets\n"); - exit(1); - } - } - - if (!compress_sys_file) { - patchvalue = code[stackpointerpatch] + code[stackpointerpatch + 1] * 256U; - patchvalue += header->exInitSP; - code[stackpointerpatch] = patchvalue & 0xFF; - code[stackpointerpatch + 1] = (patchvalue >> 8) & 0xFF; - patchvalue = code[stacksegmentpatch] + code[stacksegmentpatch + 1] * 256U; - patchvalue += header->exInitSS + start_seg + (stubsize >> 4); - code[stacksegmentpatch] = patchvalue & 0xFF; - code[stacksegmentpatch + 1] = (patchvalue >> 8) & 0xFF; - patchvalue = code[psppatch] + code[psppatch + 1] * 256U; - patchvalue += start_seg + (stubsize >> 4); - code[psppatch] = patchvalue & 0xFF; - code[psppatch + 1] = (patchvalue >> 8) & 0xFF; - } - /* ip and cs entered into header for DOS/SYS format*/ - patchvalue = header->exInitIP; - code[csippatch] = patchvalue & 0xFF; - code[csippatch + 1] = (patchvalue >> 8) & 0xFF; - patchvalue = header->exInitCS + start_seg + (stubsize >> 4); - code[csippatch + 2] = patchvalue & 0xFF; - code[csippatch + 3] = (patchvalue >> 8) & 0xFF; - - if (0 == memcmp(kernel_config, "CONFIG", 6)) { - unsigned long length = kernel_config[6] + kernel_config[7] * 256UL + 8; - if (length <= KERNEL_CONFIG_LENGTH) { - memcpy(&code[2], kernel_config, (size_t)length); - printf("Copied %lu bytes of kernel config block to header\n", length); - } else { - printf("Error: Found %lu bytes of kernel config block, too long!\n", length); - } - } else { - printf("Error: Found no kernel config block!\n"); - } + /* 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); - if (fwrite(code, 1, stubsize, dest) != stubsize) { - printf("Error writing header code to output file\n"); - exit(1); - } -} - -int my_isspace( int c ) -{ - switch( c ) { - case ' ': - case '\n': - case '\r': - case '\f': - case '\t': - case '\v': - return( 1 ); - default: - return( 0 ); - } + /* this assumes <= 0xfe00 code in kernel */ + *(short *)&JumpBehindCode[0x1e] += size; + /* the UPX created-header is 32 bytes long */ + fwrite(JumpBehindCode, 1, 0x20, dest); } -/* read command line argument from open FILE referenced by fp */ -char *getarg( FILE *fp ) +static void write_trailer(FILE *dest, size_t size, int compress_sys_file) { - static char buff[256]; - char *str; - size_t len; - - /* loop reading through file until end or new line or max characters */ - while( (str = fgets( buff, sizeof(buff) - 1, fp )) != NULL ) { - buff[sizeof(buff) - 1] = '\0'; /* ensure buffer is terminated */ - len = strlen(buff); - /* strip whitespace from end of string, i.e. "blah " --> "blah" */ - while( len > 0 ) { - len--; - if( my_isspace( buff[len] ) ) { - buff[len] = '\0'; - continue; - } - len++; - break; - } - /* skip past whitespace at beginning of string */ - /* str initially points to start of buff */ - while( len > 0 ) { - /* stop when str points to end of string or 1st non-space character */ - if( !my_isspace(*str) ) { - break; - } - str++; - len--; - } - /* if we got a blank line (*str=='\0') then keep looping, otherwise return what found */ - if( *str != '\0' ) { - break; - } - } - return( str ); + /* 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; + fwrite(trailer, 1, sizeof(trailer), dest); + fclose(dest); } int main(int argc, char **argv) { short silentSegments[20], silentcount = 0; - static exe_header header; /* must be initialized to zero */ - int use_upx = 0; - char *upx_cmd; - int i; - size_t len; int compress_sys_file; - char *buffer, *tmpexe, *cmdbuf, *entryexefilename = "", *entrydevfilename = ""; - FILE *dest, *source; - size_t size; - static unsigned char execode[256 + 10 + 1]; - static unsigned char devcode[256 + 10 + 1]; - FILE * entryf = NULL; - UWORD end; - UWORD stubexesize = 0, stubdevsize = 0; - FILE *indir = NULL; - - /* if no arguments provided, show usage and exit */ + char *upx, *tmpexe, *buffer; + char cmdbuf[128]; + int i; + FILE *dest; + long size; + + /* if no arguments provided, show usage and exit */ if (argc < 4) usage(); - upx_cmd = malloc(1); - *upx_cmd = '\0'; - i = 4; /* do optional argument processing here */ - while ( i < argc || indir != NULL ) + for (i = 4; i < argc; i++) { - char *argptr = NULL; - - if( indir != NULL ) { - argptr = getarg( indir ); - if(argptr == NULL) { - fclose( indir ); - indir = NULL; - continue; - } - } - if( argptr == NULL ) { - argptr = argv[i++]; - } - if( use_upx ) { - len = strlen( upx_cmd ); - if( len > 0 ) len++; - upx_cmd = realloc( upx_cmd, len + strlen( argptr ) + 1 ); - if( len > 0 ) upx_cmd[len - 1] = ' '; - strcpy( upx_cmd + len, argptr ); - } else { - switch (*(unsigned char *)argptr++) - { - case '@': - indir = fopen( argptr, "r" ); - if( indir == NULL ) { - printf("can't open indirect file '%s'\n", argptr); - exit(1); - } - break; - case '-': - case '/': - switch (toupper(*(unsigned char *)argptr++)) - { - case 'U': - use_upx = 1; - break; - case 'E': - entryexefilename = malloc(strlen(argptr) + 1); - strcpy(entryexefilename, argptr); - break; - case 'D': - entrydevfilename = malloc(strlen(argptr) + 1); - strcpy(entrydevfilename, argptr); - break; - case 'S': - if (silentcount >= LENGTH(silentSegments)) - { - printf("can't handle more then %d silent's\n", - (int)LENGTH(silentSegments)); - exit(1); - } - silentSegments[silentcount++] = (short)strtol(argptr, NULL, 0); - break; - default: - usage(); - } - break; - default: - usage(); - } - } - } + char *argptr = argv[i]; + + if (argptr[0] != '-' && argptr[0] != '/') + usage(); + + argptr++; - if (use_upx) { - if (*entryexefilename) { - entryf = fopen(entryexefilename, "rb"); - if (!entryf) { - printf("Cannot open entry file\n"); - exit(1); - } - if (fread(execode, 1, 256 + 10 + 1, entryf) != 256 + 10) { - printf("Invalid entry file length\n"); - exit(1); - } - end = execode[0x108] + execode[0x108 + 1] * 256U; - if (end > 0xC0 || end < 32) { - printf("Invalid entry file patch offsets\n"); - exit(1); - } - stubexesize = (end + 15U) & ~15U; - fclose(entryf); - entryf = NULL; - } - if (*entrydevfilename) { - entryf = fopen(entrydevfilename, "rb"); - if (!entryf) { - printf("Cannot open entry file\n"); - exit(1); - } - if (fread(devcode, 1, 256 + 10 + 1, entryf) != 256 + 10) { - printf("Invalid entry file length\n"); - exit(1); - } - end = devcode[0x108] + devcode[0x108 + 1] * 256U; - if (end > (0xC0 - 0x10) || end < 32) { /* 0x10 for device header */ - printf("Invalid entry file patch offsets\n"); - exit(1); - } - stubdevsize = (end + 15U) & ~15U; - fclose(entryf); - entryf = NULL; + switch (toupper(argptr[0])) + { + 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, - use_upx, stubexesize, stubdevsize, 0, &header); - if (use_upx) - { - /* move kernel.sys tmp.exe */ - if (!compress_sys_file) - { - tmpexe = "tmp.exe"; - } else { - tmpexe = "tmp.sys"; - } - if (rename(argv[2], tmpexe)) - { - printf("Can not rename %s to %s\n", argv[2], tmpexe); - exit(1); - } - - len = strlen(upx_cmd); - cmdbuf = malloc(len + 1 + strlen(tmpexe) + 1); - strcpy(cmdbuf, upx_cmd); - cmdbuf[len] = ' '; - /* if tmpexe is tmpfile set above no quotes needed, if user needs quotes should add on cmd line */ - strcpy(cmdbuf + len + 1, tmpexe); - printf("%s\n", cmdbuf); - fflush(stdout); - 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, "tmp.bin", argv[3], - silentSegments, silentcount, - FALSE, stubexesize, 0, stubexesize >> 4, &header); - } else { - UBYTE deviceheader[16]; - FILE * devfile = fopen("tmp.sys", "rb"); - if (!devfile) { - printf("Source file %s could not be opened\n", "tmp.sys"); - exit(1); - } - if (fread(deviceheader, 1, sizeof deviceheader, devfile) - != sizeof deviceheader) { - printf("Source file %s could not be read\n", "tmp.sys"); - exit(1); - } - fclose(devfile); - header.exInitIP = deviceheader[6] + deviceheader[7] * 256U; - header.exInitCS = 0; - rename("tmp.sys", "tmp.bin"); - } + upx = getenv("XUPX"); + compress_sys_file = exeflat((int)upx, argv[1], argv[2], argv[3], + silentSegments, silentcount); + if (upx == NULL) + exit(0); - /* tmp.bin now contains the final flattened file: just - the UPX entry header needs to be added. */ - /* the compressed file may exceed 64 KiB for DOS/EXE format. */ + /* move kernel.sys tmp$$$$$.exe */ + tmpexe = argv[2]; + if (!compress_sys_file) + { + tmpexe = "tmp$$$$$.exe"; + rename(argv[2], tmpexe); + } - if ((dest = fopen(argv[2], "wb")) == NULL) - { - printf("Destination file %s could not be opened\n", argv[2]); - exit(1); - } - if ((source = fopen("tmp.bin", "rb")) == NULL) - { - printf("Source file %s could not be opened\n", "tmp.bin"); - exit(1); - } +#if !defined(__TURBOC__) + /* upx kernel.exe -o kernel.sys */ + _snprintf(cmdbuf, sizeof cmdbuf, "%s %s", upx, tmpexe); +#else + /* oh well, let's hope for no buffer overflow...*/ + sprintf(cmdbuf, "%s %s", upx, tmpexe); +#endif - buffer = malloc(32 * 1024); - if (!buffer) - { - printf("Memory allocation failure\n"); - exit(1); - } + if (system(cmdbuf)) + { + printf("Problems executing %s\n", cmdbuf); + remove(tmpexe); + exit(1); + } - write_header(dest, - compress_sys_file ? devcode : execode, - compress_sys_file ? stubdevsize : stubexesize, - argv[3], compress_sys_file, &header); + if (!compress_sys_file) + { + size = exeflat(FALSE, tmpexe, argv[2], argv[3], + silentSegments, silentcount); + remove(tmpexe); + } + /* argv[2] does now contain 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); + } - do { - size = fread(buffer, 1, 32 * 1024, source); - if (fwrite(buffer, 1, size, dest) != size) { - printf("Write failure\n"); - exit(1); - } - } while (size); + buffer = malloc(0xfe01); - fclose(source); - remove("tmp.bin"); - remove(tmpexe); + 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); return 0; } diff --git a/utils/makefile b/utils/makefile index ffd2fed9..f29c6aa1 100644 --- a/utils/makefile +++ b/utils/makefile @@ -1,25 +1,20 @@ !include "../mkfiles/generic.mak" -CFLAGS = -I..$(DIRSEP)hdr +DEPENDS=$(DEPENDS) *.cfg +CFLAGSC=$(CFLAGSC) -DEXEFLAT -production: patchobj.com exeflat.exe upxentry.bin upxdevic.bin +######################################################################## -patchobj.com: patchobj.c - $(CLT) $(CFLAGS) patchobj.c +all: patchobj.com exeflat.exe -upxentry.bin: upxentry.asm - $(NASM) -f bin upxentry.asm -o upxentry.bin +patchobj.com: patchobj.c $(DEPENDS) -upxdevic.bin: upxdevic.asm - $(NASM) -f bin upxdevic.asm -o upxdevic.bin +exeflat.exe: exeflat.c ../hdr/exe.h $(DEPENDS) -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 upxentry.bin upxdevic.bin + -$(RM) *.bak *.cod *.crf *.err *.las *.lst *.map *.obj *.xrf +clobber: clean + -$(RM) patchobj.com exeflat.exe status.me diff --git a/utils/patchobj.c b/utils/patchobj.c index 87080897..72d9870b 100644 --- a/utils/patchobj.c +++ b/utils/patchobj.c @@ -13,7 +13,7 @@ *****************************************************************************/ #include -#if defined(__GNUC__) || defined(__WATCOMC__) +#ifdef __GNUC__ #include #else #include diff --git a/utils/proto.bat b/utils/proto.bat index b57c2080..472b76f1 100644 --- a/utils/proto.bat +++ b/utils/proto.bat @@ -1 +1,2 @@ for %%f in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do mkptypes %%f >>proto.h + diff --git a/utils/rmfiles.bat b/utils/rmfiles.bat index a4a052e9..e2423fdc 100644 --- a/utils/rmfiles.bat +++ b/utils/rmfiles.bat @@ -7,4 +7,3 @@ shift goto loop_commandline :done_with_commandline - diff --git a/utils/turboc.cfg b/utils/turboc.cfg new file mode 100644 index 00000000..84faa4cc --- /dev/null +++ b/utils/turboc.cfg @@ -0,0 +1,7 @@ +-d +-f- +-k- +-O -Z +-v- +-w -g1 +-I..\hdr diff --git a/utils/upxdevic.asm b/utils/upxdevic.asm deleted file mode 100644 index 4a6acd6e..00000000 --- a/utils/upxdevic.asm +++ /dev/null @@ -1,45 +0,0 @@ - -%if 0 - -UPX preparation stub for DOS/SYS format compressed FreeDOS kernel - Public Domain by C. Masloch, 2022 - -%endif - - cpu 8086 - org 0 - -bootloadunit: ; (byte of short jump re-used) -start: - jmp strict short entry - times (32 - 4) - ($ - $$) db 0 - ; area for CONFIG block - -bootloadstack: ; (dword re-used for original ss:sp) -entry: - ; common setup (copied from kernel.asm) - push cs - pop ds - xor di, di - mov byte [di + bootloadunit - $$], bl - push bp - mov word [di + bootloadstack - $$], sp - mov word [di + bootloadstack + 2 - $$], ss - - ; the UPX DOS/SYS depacker does not need a certain ss:sp - ; however it appears to need cs == ds - - mov ds, word [di + patchcsip + 2 - $$] - jmp 0:0 -patchcsip: equ $ - 4 -end: - - times 0C0h - ($ - $$) nop -entry_common: - - times 100h - ($ - $$) db 0 - dw 0 - dw 0 - dw 0 - dw patchcsip - dw end diff --git a/utils/upxentry.asm b/utils/upxentry.asm deleted file mode 100644 index f5693687..00000000 --- a/utils/upxentry.asm +++ /dev/null @@ -1,55 +0,0 @@ - -%if 0 - -UPX preparation stub for DOS/EXE format compressed FreeDOS kernel - Public Domain by C. Masloch, 2022 - -%endif - - cpu 8086 - org 0 - -bootloadunit: ; (byte of short jump re-used) -start: - jmp strict short entry - times (32 - 4) - ($ - $$) db 0 - ; area for CONFIG block - -bootloadstack: ; (dword re-used for original ss:sp) -entry: - ; common setup (copied from kernel.asm) - push cs - pop ds - xor di, di - mov byte [di + bootloadunit - $$], bl - push bp - mov word [di + bootloadstack - $$], sp - mov word [di + bootloadstack + 2 - $$], ss - - ; the UPX DOS/EXE depacker needs a certain ss:sp - cli - mov ax, 0 -patchstacksegment: equ $ - 2 - mov ss, ax - mov sp, 0 -patchstackpointer: equ $ - 2 - sti - - mov ax, -10h -patchpspsegment: equ $ - 2 - mov ds, ax - mov es, ax - - jmp 0:0 -patchcsip: equ $ - 4 -end: - - times 0C0h - ($ - $$) nop -entry_common: - - times 100h - ($ - $$) db 0 - dw patchstackpointer - dw patchstacksegment - dw patchpspsegment - dw patchcsip - dw end diff --git a/utils/wlinker.bat b/utils/wlinker.bat old mode 100644 new mode 100755 index 9d25845e..7c7ede27 --- a/utils/wlinker.bat +++ b/utils/wlinker.bat @@ -1,4 +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 +%BINPATH%\ms2wlink %1 %2 %3 %4 %5 %6 %7 %8 %9 ,,,, >kernel.lnk +echo op map,statics,verbose,eliminate,vfremoval>>kernel.lnk +%BINPATH%\wlink @kernel.lnk