plat/msdos386: refactor, firm up, and optimize

- refactor code for transfer buffer reads/writes, real mode
   int 0x21 calls, and assembler segment declarations
 - define transfer buffer size in one place
 - beef up error checking for transfer buffer operations
   (prevent buffer overflows)
 - also optimize such operations to transfer dword by dword
   where feasible
This commit is contained in:
tkchia 2022-08-26 17:20:56 +00:00
parent 8891fae303
commit cba54b205b
26 changed files with 292 additions and 326 deletions

View file

@ -9,6 +9,7 @@ ackfile {
ackfile {
name = "stub",
srcs = { "./stub.s" },
deps = { "plat/msdos386/libsys+headers" },
vars = { plat = "msdos386" }
}

View file

@ -3,12 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
#include "libsysasm.h"
.sect .bss

View file

@ -1,11 +1,9 @@
! Declare segments (the order is important).
#
! $Source$
! $State$
! $Revision$
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
.define _brk
_brk:

View file

@ -1,6 +1,13 @@
bundle {
name = "headers",
srcs = {
"./libsysasm.h"
}
}
acklibrary {
name = "lib",
srcs = {
name = "lib",
srcs = {
"./_hol0.s",
"./brk.s",
"./close.s",
@ -9,6 +16,9 @@ acklibrary {
"./isatty.s",
"./rename.s",
"./sbrk.c",
"./sys_cpyin.s",
"./sys_cpyout.s",
"./sys_dpmidos.s",
"./sys_exists.s",
"./sys_getdate.s",
"./sys_gettime.s",
@ -19,17 +29,16 @@ acklibrary {
"./sys_rawopen.s",
"./sys_rawread.s",
"./sys_rawwrite.s",
"./sys_scpyout.s",
"./sys_xret.s",
"./unlink.s",
"plat/msdos/libsys+srcs",
},
deps = {
"lang/cem/libcc.ansi/headers+headers",
"plat/msdos386/include+headers",
"plat/msdos/libsys+headers",
},
vars = {
plat = "msdos386"
}
deps = {
"plat/msdos/libsys+headers",
"+headers"
},
vars = {
plat = "msdos386"
}
}

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Close a file.

View file

@ -3,12 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
#include "libsysasm.h"
#define D(e) .define e; e

View file

@ -15,14 +15,7 @@
! the new terms are clearly indicated on the first page of each file where
! they apply.
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Get the current process identifier. For MS-DOS, use the Program Segment
! Prefix (PSP) segment as the PID, unless the system supports an actual

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Say whether a given file descriptor number refers to a terminal.

View file

@ -0,0 +1,24 @@
/*
* © 2013 David Given
* © 2022 TK Chia
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef LIBSYSASM_H
#define LIBSYSASM_H
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Size of transfer buffer, for 32-bit DPMI mode.
TRANSFER_BUFFER_SIZE = 32 * 1024
#endif

View file

@ -3,54 +3,40 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Rename a file.
.define _rename
_rename:
mov ebx, esp
push esi
push edi
! Source filename.
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
! Destination filename.
mov eax, edi
mov esi, 8(ebx)
1:
lodsb
stosb
testb al, al
jnz 1b
mov eax, 4+8(esp)
#define DEST_NAME_OFFSET (TRANSFER_BUFFER_SIZE / 2)
mov edx, DEST_NAME_OFFSET
mov ecx, edx
call .sys_sncpyout
jc 9f
xchg edi, eax
! Source filename.
mov eax, 4+4(esp)
xor edx, edx
call .sys_sncpyout
jc 9f
xchg edx, eax
! Make the DOS call.
o16 mov dx, (transfer_buffer_ptr)
o16 mov di, ax
movb ah, 0x56
mov ebx, 0x210000
callf (interrupt_ptr)
call .sys_dpmidos
pop edi
pop esi
push ss
pop es
jmp .sys_zret
9:
pop edi
jmp .sys_toolongret

View file

@ -0,0 +1,32 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_cpyin: copy ecx bytes from the transfer buffer to es:eax (= ds:eax).
! Preserve all registers, except the flags.
.extern .sys_cpyin
.sys_cpyin:
push eax
push ecx
push esi
push edi
movzx esi, (transfer_buffer_ptr)
xchg edi, eax
mov ds, (pmode_ds)
mov eax, ecx
shr ecx, 2
rep movs
andb al, 3
movb cl, al
rep movsb
mov eax, ss
mov ds, eax
pop edi
pop esi
pop ecx
pop eax
ret

View file

@ -0,0 +1,34 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_cpyout: copy ecx bytes starting from ds:eax to the transfer
! buffer. Return eax := offset of transfer buffer in the real mode data
! segment. Preserve all other registers, except the flags.
.extern .sys_cpyout
.sys_cpyout:
push ecx
push edx
push esi
push edi
xchg esi, eax
movzx edi, (transfer_buffer_ptr)
mov eax, edi
mov es, (pmode_ds)
mov edx, ecx
shr ecx, 2
rep movs
movb cl, dl
andb cl, 3
rep movsb
mov ecx, ss
mov es, ecx
pop edi
pop esi
pop edx
pop ecx
ret

View file

@ -0,0 +1,16 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_dpmidos: simulate a call to real-mode int 0x21 with the current
! 16-bit register values.
.extern .sys_dpmidos
.sys_dpmidos:
movzx ebx, bx
or ebx, 0x210000
callf (interrupt_ptr)
ret

View file

@ -3,35 +3,19 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Say whether a file exists with the given name.
.define __sys_exists
__sys_exists:
push esi
mov esi, 4+4(esp)
movzx edi, (transfer_buffer_ptr)
mov edx, edi
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
mov eax, 4(esp)
call .sys_scpyout
jc 9f
xchg edx, eax
mov eax, 0x4300
mov ebx, 0x210000
callf (interrupt_ptr)
push ss
pop es
call .sys_dpmidos
9:
sbb eax, eax
inc eax
ret

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Get the current system date from MS-DOS.

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Get the current system time from MS-DOS.

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Say whether a given file descriptor number refers to a valid open file
! descriptor.

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Say whether a file descriptor is ready for input, i.e. reading from the
! fd will immediately return something.

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Create or truncate a file.
@ -18,30 +11,18 @@
__sys_rawcreat:
! Copy filename to transfer buffer.
mov ebx, esp
push esi
push edi
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
mov eax, 4(esp)
call .sys_scpyout
jc 9f
! Make the DOS call.
xchg edx, eax
movb ah, 0x3c
movzx edx, (transfer_buffer_ptr)
movb al, 8(ebx)
mov ebx, 0x210000
callf (interrupt_ptr)
movb al, 8(esp)
call .sys_dpmidos
pop edi
pop esi
push ss
pop es
jmp .sys_axret
9:
jmp .sys_toolongret

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Move the current file position for a file descriptor.

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Open an existing file.
@ -18,30 +11,14 @@
__sys_rawopen:
! Copy filename to transfer buffer.
mov ebx, esp
push esi
push edi
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
mov eax, 4(esp)
call .sys_scpyout
! Make the DOS call.
xchg edx, eax
movb ah, 0x3d
o16 mov dx, (transfer_buffer_ptr)
movb al, 8(ebx)
mov ebx, 0x210000
callf (interrupt_ptr)
movb al, 8(esp)
call .sys_dpmidos
pop edi
pop esi
push ss
pop es
jmp .sys_axret

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Read bytes from a file descriptor. These routines do not do any
! translation between CRLF and LF line endings.
@ -20,15 +13,12 @@
.define __sys_rawread
__sys_rawread:
enter 0, 0
push esi
push edi
file_handle = 2*4
write_buffer = 3*4
amount_to_read = 4*4
file_handle = 1*4
write_buffer = 2*4
amount_to_read = 3*4
mov eax, amount_to_read(ebp)
mov ecx, 32*1024
mov eax, amount_to_read(esp)
mov ecx, TRANSFER_BUFFER_SIZE
cmp eax, ecx
jge 2f
mov ecx, eax
@ -38,41 +28,23 @@ amount_to_read = 4*4
movb ah, 0x3f
o16 mov dx, (transfer_buffer_ptr)
movzx esi, dx
mov ebx, 0x210000
o16 mov bx, file_handle(ebp)
callf (interrupt_ptr)
jnc success
o16 mov bx, file_handle(esp)
call .sys_dpmidos
jc 3f
! Copy eax bytes out of the transfer buffer.
movzx ecx, ax
mov eax, write_buffer(esp)
call .sys_cpyin
xchg eax, ecx
ret
3:
! Process errors.
push eax
call __sys_seterrno
pop ecx
jmp exit
success:
! Copy eax bytes out of the transfer buffer.
movzx eax, ax
mov ecx, eax
jcxz exit
push eax
mov edi, write_buffer(ebp)
mov es, (pmode_ds)
cld
1:
eseg lodsb
movb (edi), al
inc edi
loop 1b
pop eax
exit:
pop edi
pop esi
push ss
pop es
leave
ret

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Write bytes to/to a file descriptor. These routines do not do any
! translation between CRLF and LF line endings.
@ -20,15 +13,12 @@
.define __sys_rawwrite
__sys_rawwrite:
enter 0, 0
push esi
push edi
file_handle = 2*4
read_buffer = 3*4
amount_to_write = 4*4
file_handle = 1*4
read_buffer = 2*4
amount_to_write = 3*4
mov eax, amount_to_write(ebp)
mov ecx, 32*1024 ! size of transfer buffer
mov eax, amount_to_write(esp)
mov ecx, TRANSFER_BUFFER_SIZE
cmp eax, ecx
jge 2f
mov ecx, eax
@ -36,32 +26,22 @@ amount_to_write = 4*4
! Copy ecx bytes into the transfer buffer.
push ecx
mov esi, read_buffer(ebp)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
rep movsb
pop ecx
mov eax, read_buffer(esp)
call .sys_cpyout
! Write from the transfer buffer to DOS.
xchg edx, eax
movb ah, 0x40
o16 mov dx, (transfer_buffer_ptr)
mov ebx, 0x210000
o16 mov bx, file_handle(ebp)
callf (interrupt_ptr)
o16 mov bx, file_handle(esp)
call .sys_dpmidos
movzx eax, ax
jnc exit
push eax
call __sys_seterrno
pop ecx
exit:
pop edi
pop esi
push ss
pop es
leave
ret
! vim: sw=4 ts=4 et

View file

@ -0,0 +1,58 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_scpyout: copy the ASCIIZ string starting from ds:eax to the
! transfer buffer. The resulting ASCIIZ string, including the final null,
! should fit into the entire transfer buffer. Return eax := offset of
! transfer buffer in real mode data segment. Return CF = 1 if and only if
! the ASCIIZ string is too long to fit. Preserve all other registers,
! except the flags.
!
! .sys_sncpyout: copy the ASCIIZ string starting from ds:eax to offset
! edx into the transfer buffer. The resulting ASCIIZ string should occupy
! at most ecx bytes, including the final null. Return eax : offset of
! string in real mode data segment. Return CF = 1 if and only if the ASCIIZ
! string is too long to fit. Preserve all other registers, except the
! flags.
.extern .sys_scpyout
.extern .sys_sncpyout
.sys_scpyout:
push ecx
push edx
mov ecx, TRANSFER_BUFFER_SIZE
xor edx, edx
jmp .cont
.sys_sncpyout:
push ecx
push edx
.cont:
push esi
push edi
mov esi, eax
movzx edi, (transfer_buffer_ptr)
add edi, edx
mov edx, edi
mov es, (pmode_ds)
jcxz .error
.loop:
lodsb
stosb
testb al, al
loopnz .loop
jz .ok
.error:
stc
.ok:
xchg edx, eax
mov edx, ss
mov es, edx
pop edi
pop esi
pop edx
pop ecx
ret

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! .sys_zret: if the carry flag is set, then set `errno' from the DOS error
! code in ax, and return an int -1. If the carry flag is clear, just
@ -18,14 +11,18 @@
!
! .sys_axret: if the carry flag is set, then set `errno' from the DOS error
! code in ax, and return a shortword -1. If the carry flag is clear, just
! return ax as a return value.
! return eax := ax as a return value.
!
! .sys_dxaxret: same as .sys_axret, but return -1 or eax := dx:ax as a
! return value.
!
! .sys_toolongret: a file name is too long: set `errno' to E2BIG, and return
! -1.
.extern .sys_zret
.extern .sys_axret
.extern .sys_dxaxret
.extern .sys_toolongret
.sys_zret:
jc error
xor eax, eax
@ -34,6 +31,7 @@ no_error:
.sys_axret:
jc error
movzx eax, ax
ret
.sys_dxaxret:
@ -43,6 +41,11 @@ no_error:
mov eax, edx
ret
.sys_toolongret:
mov (_errno), 7 ! E2BIG
or eax, -1
ret
error:
movzx eax, ax
push eax

View file

@ -3,14 +3,7 @@
! $State$
! $Revision$
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#include "libsysasm.h"
! Remove a file.
@ -18,29 +11,13 @@
_unlink:
! Copy filename to transfer buffer.
mov ebx, esp
push esi
push edi
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
mov eax, 4(esp)
call .sys_scpyout
! Make the DOS call.
mov dx, (transfer_buffer_ptr)
xchg edx, eax
movb ah, 0x41
or ebx, 0x210000
callf (interrupt_ptr)
call .sys_dpmidos
pop edi
pop esi
push ss
pop es
jmp .sys_zret