Made realloc work; the 32-bit process can now be resized to include bss and

stack.
This commit is contained in:
David Given 2022-08-10 16:14:12 +02:00
parent 967b46e98e
commit 1764c6baa2
3 changed files with 172 additions and 59 deletions

View file

@ -13,57 +13,73 @@
.sect .text
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
! g 18b to break at the retf before coming here
begtext:
mov eax, 0x4c00
int 0x21
! Make sure we are running under MS-DOS 2 or above.
! On entry, the stub has cs and ds pointing at the 32-bit
! segment, but ss is still pointing at the 16-bit segment.
!
! While at it, also remember the actual DOS version, so that we know
! whether DOS gives us the program's name in the environment
! segment. (DOS 3+ does; DOS 2.x does not.)
movb ah, 0x30
int 0x21
cbw
cmpb al, 2
xchg bp, ax
jnc ok_sys
! si:di memory handle of linear block
! ax: pmode code segment of stub
! dx: pointer to realloc routine
! fs: data segment (just a clone of the code segment)
mov dx, bad_sys_msg
dos_msg:
ret
! Resize the segment to include the BSS.
ok_sys:
! Resize the program's memory control block (MCB) to cover only the
! program's near code and data space. Use the starting sp value as
! a guide to how much memory we can grab. Abort on any failure.
!
! As a side effect, this also frees up any memory allocated to our
! program beyond 64 KiB. (The freed memory can possibly be used by
! e.g. child processes, in the future.)
!
! Also check that we have some space between the BSS end and the
! starting sp.
cmp sp, endbss+STACK_BUFFER
jb no_room
movb ah, 0x4a
mov bx, sp
movb cl, 4
shr bx, cl
inc bx
int 0x21
jc no_room
o16 cseg mov (realloc_ptr+4), ax
cseg mov (realloc_ptr+0), edx
mov eax, endbss
cseg callf (realloc_ptr)
! Clear BSS.
mov di, begbss
mov cx, endbss+1
sub cx, di
shr cx, 1
xor ax, ax
mov edi, begbss
mov ecx, endbss+1
sub ecx, edi
shr ecx, 1
xor eax, eax
cld
rep stosw
! It's now safe to switch stacks.
cli
mov eax, ds
mov ss, eax
mov sp, .stack
sti
! Create a handle for low 1MB access.
o16 mov ax, 0x0000
o16 mov cx, 1
int 0x31 ! allocate LDT
mov es, ax
o16 mov bx, ax
o16 mov (.doshandle), bx
xor ecx, ecx
xor edx, edx
o16 mov ax, 0x0007
int 0x31 ! set base address to 0
o16 mov cx, 0x0010
o16 mov ax, 0x0008
int 0x31 ! set limit to 1MB
mov cx, ds
and cx, 3
shl cx, 5
or cx, 0xc093 ! 32-bit, big, data, r/w, expand-up
mov ax, 0x0009
int 0x31 ! set descriptor access rights
! Locate the PSP.
movb ah, 0x62
int 0x21
movzx ebx, bx
shl ebx, 4 ! convert to linear address
mov (.psp), ebx
! Get the size of the environment variables plus (if present) the
! program name. Also count the number of environment variables.
xor di, di
@ -130,7 +146,7 @@ copy_env:
no_room:
mov dx, no_room_msg
call dos_msg
!call dos_msg
movb al, -1
jmp al_exit
@ -147,6 +163,11 @@ al_exit:
movb ah, 0x4c
int 0x21
! This must be in the code segment due to bootstrap issues.
realloc_ptr:
.data2 0
.data4 0
! Define symbols at the beginning of our various segments, so that we can find
! them. (Except .text, which has already been done.)
@ -168,5 +189,12 @@ no_room_msg: .ascii 'No room$'
.comm .ignmask, 4
.comm _errno, 4
.comm .doshandle, 2
.comm .psp, 4
.sect .bss
.space 512
.stack:
! vim: ts=4 sw=4 et ft=asm

View file

@ -39,6 +39,7 @@ name as
program {EM}/lib/ack/{PLATFORM}/as
args - -o > <
prep cond
end
name led
from .o.a
@ -66,6 +67,7 @@ name led
{PLATFORMDIR}/libc.a \
{PLATFORMDIR}/libem.a \
{PLATFORMDIR}/libend.a)
linker
end
name cv

View file

@ -51,6 +51,7 @@ exe_start:
xor di, di
xorb al, al
mov cx, 0xffff
cld
1:
repne scasb ! find end of next string
eseg cmpb (di), 0
@ -90,8 +91,8 @@ exe_start:
xor cx, cx ! high offset
xor dx, dx ! low offset
int 0x21 ! lseek
mov (textlen+0), ax
mov (textlen+2), dx
mov (pmemlen+0), ax
mov (pmemlen+2), dx
! Initialise DPMI.
@ -115,7 +116,7 @@ exe_start:
callf (pmode_switch)
jc bad_dpmi
! We're now in protected mode. (0xa9)
! We're now in protected mode. (ae)
mov (psegcs), cs
mov (psegds), ds
@ -127,14 +128,15 @@ exe_start:
int 0x31 ! allocate LDT
jc bad_dpmi
mov es, ax
mov (psegcs32), ax
mov cx, (textlen+0)
mov bx, (textlen+2)
mov cx, (pmemlen+0)
mov bx, (pmemlen+2)
mov ax, 0x0501
int 0x31 ! allocate linear address
jc bad_dpmi
mov (pmemhandle+0), si
mov (pmemhandle+2), di
mov (pmemhandle+0), di
mov (pmemhandle+2), si
mov dx, cx
mov cx, bx
@ -144,8 +146,8 @@ exe_start:
jc bad_dpmi
mov bx, es
mov dx, (textlen+0)
mov cx, (textlen+2)
mov dx, (pmemlen+0)
mov cx, (pmemlen+2)
mov ax, 0x0008
int 0x31 ! set segment limit
@ -157,7 +159,23 @@ exe_start:
mov ax, 0x0009
int 0x31 ! set descriptor access rights
! Load the program. (0xff)
! Allocate the data segment (as a simple clone of the code segment). (10e)
mov ax, 0x000a
mov bx, es
int 0x31
mov fs, ax
mov (psegds32), ax
mov cx, ax
and cx, 3
shl cx, 5
or cx, 0xc093 ! 32-bit, big, data, r/w, expand-up
mov bx, fs
mov ax, 0x0009
int 0x31 ! set descriptor access rights
! Load the program.
mov bx, (fh)
mov ax, 0x4200
@ -179,6 +197,7 @@ exe_start:
o32 movzx ecx, ax ! number of bytes read
o32 mov esi, transfer_buffer
cld
o32 rep movsb
jmp 1b
2:
@ -191,12 +210,75 @@ exe_start:
! Jump to the new segment and enter 32-bit mode!
o32 mov eax, (pmemhandle)
o32 movzx ebx, (rseg)
mov ax, (psegcs)
mov bx, (psegds)
mov cx, (rseg)
o32 mov edx, realloc
push es
pop ds
push es
push 0
retf
! ALL CODE ABOVE THIS POINT DISCARDED ON ENTRY TO 32-BIT CODE
! (it's reused as the 16-bit stack)
stack16:
! Helper routine which reallocates the linear block that the 32-bit code
! is running from. This can't happen from inside the 32-bit code itself
! because it might move.
!
! On entry, ds and ss are ignored. On exit, ds is set to the 32-bit segment.
! eax: new block size
realloc:
cseg mov ds, (psegds)
cli ! atomically switch stacks
o32 mov (dpmi_ebp), esp ! yes, saving esp into the ebp field
mov (dpmi_ss), ss
mov ss, (psegds)
mov sp, stack16
sti
pusha
o32 add eax, 1024*1024 - 1
o32 and eax, ~[1024*1024 - 1]
o32 mov (pmemlen), eax
mov cx, (pmemlen+0)
mov bx, (pmemlen+2)
mov di, (pmemhandle+0)
mov si, (pmemhandle+2)
mov ax, 0x0503
int 0x31 ! resize memory block
jc bad_dpmi
mov (pmemhandle+0), di
mov (pmemhandle+2), si
mov (pmemaddr+0), cx
mov (pmemaddr+2), bx
mov bx, (psegds32)
mov dx, (pmemlen+0)
mov cx, (pmemlen+2)
mov ax, 0x0008
int 0x31 ! set ds segment limit
jc bad_dpmi
mov dx, (pmemaddr+0)
mov cx, (pmemaddr+2)
mov ax, 0x0007
int 0x31 ! set ds linear address
jc bad_dpmi
mov bx, (psegcs32)
int 0x31 ! set cs linear address
jc bad_dpmi
popa
cli ! atomically switch stacks back
mov ss, (dpmi_ss)
o32 mov esp, (dpmi_ebp)
mov ds, (psegds32)
sti
o32 retf
bad_dpmi:
mov si, bad_dpmi_msg
jmp exit_with_error
@ -250,8 +332,6 @@ int21:
mov bx, (dpmi_ebx)
mov cx, (dpmi_ecx)
mov dx, (dpmi_edx)
push (dpmi_flags)
popf
ret
bad_dpmi_msg:
@ -260,7 +340,7 @@ no_file_msg:
.asciz "Couldn't open .exe"
no_dpmi_msg:
.asciz "No DPMI host installed"
.align 2
.align 4
text_top:
exe_text_pages = [text_top - exe_header + 511] / 512
@ -294,9 +374,12 @@ rseg: .space 2 ! real mode
pspseg: .space 2 ! real mode
psegcs: .space 2 ! protected mode 16-bit code segment
psegds: .space 2 ! protected mode 16-bit data segment
psegcs32: .space 2 ! protected mode 32-bit code segment
psegds32: .space 2 ! protected mode 32-bit data segment
pmemaddr: .space 4 ! protected mode linear memory address
pmemhandle: .space 4 ! protected mode linear memory handle
pmemlen: .space 4 ! protected mode linear memory length
fh: .space 2
textlen: .space 4
.space 128
stack: