diff --git a/plat/msdos386/boot.s b/plat/msdos386/boot.s
index 9e940c253..f3a4035e9 100644
--- a/plat/msdos386/boot.s
+++ b/plat/msdos386/boot.s
@@ -91,7 +91,7 @@ begtext:
     ! Copy the whole thing into 32-bit memory.
 
     mov ecx, 0x100/4
-    mov edi, _psp
+    mov edi, .psp
     cld
 1:
     eseg lods
@@ -101,7 +101,7 @@ begtext:
 
     ! Find the environment.
 
-    mov es, (_psp + 0x002C)     ! converted to pmode segment
+    mov es, (.psp + 0x002C)     ! converted to pmode segment
     
     ! Count the size of the environment variable block.
 
@@ -155,7 +155,7 @@ empty_environment:
     push 3              ! MS-DOS version
     push ecx            ! env. string data
     push edx            ! count of env. vars.
-    push _psp+0x80      ! raw command line
+    push .psp+0x80      ! raw command line
     call __sys_initmain
     add esp, 5*4
 
@@ -225,7 +225,7 @@ no_room_msg: .ascii 'No room$'
 .comm _errno, 4
 
 .comm .doshandle, 2
-.comm _psp, 256
+.comm .psp, 256
 
 .sect .bss
     .space 32*1024
diff --git a/plat/msdos386/build-pkg.lua b/plat/msdos386/build-pkg.lua
index 4b92b5619..8b3195afb 100644
--- a/plat/msdos386/build-pkg.lua
+++ b/plat/msdos386/build-pkg.lua
@@ -9,6 +9,7 @@ ackfile {
 ackfile {
 	name = "stub",
 	srcs = { "./stub.s" },
+	deps = { "plat/msdos386/libsys+headers" },
 	vars = { plat = "msdos386" }
 }
 
diff --git a/plat/msdos386/libsys/_hol0.s b/plat/msdos386/libsys/_hol0.s
index f01566fe8..ad666d56f 100644
--- a/plat/msdos386/libsys/_hol0.s
+++ b/plat/msdos386/libsys/_hol0.s
@@ -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
 
diff --git a/plat/msdos386/libsys/brk.s b/plat/msdos386/libsys/brk.s
index 3032bc929..ed2dcc6a1 100644
--- a/plat/msdos386/libsys/brk.s
+++ b/plat/msdos386/libsys/brk.s
@@ -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:
diff --git a/plat/msdos386/libsys/build.lua b/plat/msdos386/libsys/build.lua
index 71ac521b8..e972365e6 100644
--- a/plat/msdos386/libsys/build.lua
+++ b/plat/msdos386/libsys/build.lua
@@ -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"
+	}
 }
-
diff --git a/plat/msdos386/libsys/close.s b/plat/msdos386/libsys/close.s
index 412307b62..936509894 100644
--- a/plat/msdos386/libsys/close.s
+++ b/plat/msdos386/libsys/close.s
@@ -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.
 
diff --git a/plat/msdos386/libsys/errno.s b/plat/msdos386/libsys/errno.s
index 9858d2640..4126b8349 100644
--- a/plat/msdos386/libsys/errno.s
+++ b/plat/msdos386/libsys/errno.s
@@ -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
 
diff --git a/plat/msdos386/libsys/getpid.s b/plat/msdos386/libsys/getpid.s
index fd8706379..077674c50 100644
--- a/plat/msdos386/libsys/getpid.s
+++ b/plat/msdos386/libsys/getpid.s
@@ -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
diff --git a/plat/msdos386/libsys/isatty.s b/plat/msdos386/libsys/isatty.s
index 794274bfa..e4d02617a 100644
--- a/plat/msdos386/libsys/isatty.s
+++ b/plat/msdos386/libsys/isatty.s
@@ -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.
 
diff --git a/plat/msdos386/libsys/libsysasm.h b/plat/msdos386/libsys/libsysasm.h
new file mode 100644
index 000000000..3c758f099
--- /dev/null
+++ b/plat/msdos386/libsys/libsysasm.h
@@ -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
diff --git a/plat/msdos386/libsys/rename.s b/plat/msdos386/libsys/rename.s
index cfde5305e..ab181d0c7 100644
--- a/plat/msdos386/libsys/rename.s
+++ b/plat/msdos386/libsys/rename.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_cpyin.s b/plat/msdos386/libsys/sys_cpyin.s
new file mode 100644
index 000000000..873c75536
--- /dev/null
+++ b/plat/msdos386/libsys/sys_cpyin.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_cpyout.s b/plat/msdos386/libsys/sys_cpyout.s
new file mode 100644
index 000000000..b905904a3
--- /dev/null
+++ b/plat/msdos386/libsys/sys_cpyout.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_dpmidos.s b/plat/msdos386/libsys/sys_dpmidos.s
new file mode 100644
index 000000000..4900b1980
--- /dev/null
+++ b/plat/msdos386/libsys/sys_dpmidos.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_exists.s b/plat/msdos386/libsys/sys_exists.s
index 8dc1dc18c..77bec119d 100644
--- a/plat/msdos386/libsys/sys_exists.s
+++ b/plat/msdos386/libsys/sys_exists.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_getdate.s b/plat/msdos386/libsys/sys_getdate.s
index 981253b93..d220dd418 100644
--- a/plat/msdos386/libsys/sys_getdate.s
+++ b/plat/msdos386/libsys/sys_getdate.s
@@ -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.
 
diff --git a/plat/msdos386/libsys/sys_gettime.s b/plat/msdos386/libsys/sys_gettime.s
index 1d43d5f46..ce1614c5a 100644
--- a/plat/msdos386/libsys/sys_gettime.s
+++ b/plat/msdos386/libsys/sys_gettime.s
@@ -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.
 
diff --git a/plat/msdos386/libsys/sys_isopen.s b/plat/msdos386/libsys/sys_isopen.s
index 5f990f1c1..f0493587f 100644
--- a/plat/msdos386/libsys/sys_isopen.s
+++ b/plat/msdos386/libsys/sys_isopen.s
@@ -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.
diff --git a/plat/msdos386/libsys/sys_isreadyr.s b/plat/msdos386/libsys/sys_isreadyr.s
index 9a646adc8..8beda6366 100644
--- a/plat/msdos386/libsys/sys_isreadyr.s
+++ b/plat/msdos386/libsys/sys_isreadyr.s
@@ -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.
diff --git a/plat/msdos386/libsys/sys_rawcreat.s b/plat/msdos386/libsys/sys_rawcreat.s
index ce48d9d7c..f2db1b35c 100644
--- a/plat/msdos386/libsys/sys_rawcreat.s
+++ b/plat/msdos386/libsys/sys_rawcreat.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_rawlseek.s b/plat/msdos386/libsys/sys_rawlseek.s
index 8ff4bc1db..71e17de3d 100644
--- a/plat/msdos386/libsys/sys_rawlseek.s
+++ b/plat/msdos386/libsys/sys_rawlseek.s
@@ -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.
 
diff --git a/plat/msdos386/libsys/sys_rawopen.s b/plat/msdos386/libsys/sys_rawopen.s
index 3c8f2bf17..e8130d25b 100644
--- a/plat/msdos386/libsys/sys_rawopen.s
+++ b/plat/msdos386/libsys/sys_rawopen.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_rawread.s b/plat/msdos386/libsys/sys_rawread.s
index ef71bf915..0c17307ff 100644
--- a/plat/msdos386/libsys/sys_rawread.s
+++ b/plat/msdos386/libsys/sys_rawread.s
@@ -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
-
diff --git a/plat/msdos386/libsys/sys_rawwrite.s b/plat/msdos386/libsys/sys_rawwrite.s
index 56976b53b..28219f14c 100644
--- a/plat/msdos386/libsys/sys_rawwrite.s
+++ b/plat/msdos386/libsys/sys_rawwrite.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_scpyout.s b/plat/msdos386/libsys/sys_scpyout.s
new file mode 100644
index 000000000..9491e3c20
--- /dev/null
+++ b/plat/msdos386/libsys/sys_scpyout.s
@@ -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
diff --git a/plat/msdos386/libsys/sys_xret.s b/plat/msdos386/libsys/sys_xret.s
index e9b9017c9..3b376051d 100644
--- a/plat/msdos386/libsys/sys_xret.s
+++ b/plat/msdos386/libsys/sys_xret.s
@@ -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
diff --git a/plat/msdos386/libsys/unlink.s b/plat/msdos386/libsys/unlink.s
index d2289e3c4..0695f511d 100644
--- a/plat/msdos386/libsys/unlink.s
+++ b/plat/msdos386/libsys/unlink.s
@@ -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
diff --git a/plat/msdos386/stub.s b/plat/msdos386/stub.s
index 184c14a89..2e31daa02 100644
--- a/plat/msdos386/stub.s
+++ b/plat/msdos386/stub.s
@@ -3,14 +3,8 @@
 ! $State$
 ! $Revision$
 
-! Declare segments (the order is important).
+#include "libsysasm.h"
 
-.sect .text
-.sect .rom
-.sect .data
-.sect .bss
-
-.sect .text
 .use16
 exe_header:
     .data2 0x5a4d               ! magic number
@@ -319,12 +313,12 @@ int21:
     o32 or ebx, 0x210000
     ! Simulate interrupt in the high half of ebx.
 interrupt:
-    mov (dpmi_eax), ax
-    mov (dpmi_ebx), bx
-    mov (dpmi_ecx), cx
-    mov (dpmi_edx), dx
-    mov (dpmi_esi), si
-    mov (dpmi_edi), di
+    o32 mov (dpmi_eax), eax
+    o32 mov (dpmi_ebx), ebx
+    o32 mov (dpmi_ecx), ecx
+    o32 mov (dpmi_edx), edx
+    o32 mov (dpmi_esi), esi
+    o32 mov (dpmi_edi), edi
     pushf
     pop (dpmi_flags)
     mov ax, (rseg)
@@ -340,12 +334,12 @@ interrupt:
     xor cx, cx
     int 0x31                    ! simulate DOS interrupt
     pop es
-    o32 movzx eax, (dpmi_eax)
-    o32 movzx ebx, (dpmi_ebx)
-    o32 movzx ecx, (dpmi_ecx)
-    o32 movzx edx, (dpmi_edx)
-    o32 movzx esi, (dpmi_esi)
-    o32 movzx edi, (dpmi_edi)
+    o32 mov eax, (dpmi_eax)
+    o32 mov ebx, (dpmi_ebx)
+    o32 mov ecx, (dpmi_ecx)
+    o32 mov edx, (dpmi_edx)
+    o32 mov esi, (dpmi_esi)
+    o32 mov edi, (dpmi_edi)
     push (dpmi_flags)
     popf
     ret
@@ -410,7 +404,6 @@ stack:
     .space 512
 dosstack:
 
-TRANSFER_BUFFER_SIZE = 32*1024
 transfer_buffer:
     .space TRANSFER_BUFFER_SIZE