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 .sect .text
#define STACK_BUFFER 128 /* number of bytes to leave for stack */ #define STACK_BUFFER 128 /* number of bytes to leave for stack */
! g 18b to break at the retf before coming here
begtext: begtext:
mov eax, 0x4c00 ! On entry, the stub has cs and ds pointing at the 32-bit
int 0x21 ! segment, but ss is still pointing at the 16-bit segment.
! Make sure we are running under MS-DOS 2 or above.
! !
! While at it, also remember the actual DOS version, so that we know ! si:di memory handle of linear block
! whether DOS gives us the program's name in the environment ! ax: pmode code segment of stub
! segment. (DOS 3+ does; DOS 2.x does not.) ! dx: pointer to realloc routine
movb ah, 0x30 ! fs: data segment (just a clone of the code segment)
int 0x21
cbw
cmpb al, 2
xchg bp, ax
jnc ok_sys
mov dx, bad_sys_msg ! Resize the segment to include the BSS.
dos_msg:
ret
ok_sys: o16 cseg mov (realloc_ptr+4), ax
! Resize the program's memory control block (MCB) to cover only the cseg mov (realloc_ptr+0), edx
! program's near code and data space. Use the starting sp value as mov eax, endbss
! a guide to how much memory we can grab. Abort on any failure. cseg callf (realloc_ptr)
!
! 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
! Clear BSS. ! Clear BSS.
mov di, begbss
mov cx, endbss+1 mov edi, begbss
sub cx, di mov ecx, endbss+1
shr cx, 1 sub ecx, edi
xor ax, ax shr ecx, 1
xor eax, eax
cld cld
rep stosw 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 ! Get the size of the environment variables plus (if present) the
! program name. Also count the number of environment variables. ! program name. Also count the number of environment variables.
xor di, di xor di, di
@ -130,7 +146,7 @@ copy_env:
no_room: no_room:
mov dx, no_room_msg mov dx, no_room_msg
call dos_msg !call dos_msg
movb al, -1 movb al, -1
jmp al_exit jmp al_exit
@ -147,6 +163,11 @@ al_exit:
movb ah, 0x4c movb ah, 0x4c
int 0x21 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 ! Define symbols at the beginning of our various segments, so that we can find
! them. (Except .text, which has already been done.) ! them. (Except .text, which has already been done.)
@ -168,5 +189,12 @@ no_room_msg: .ascii 'No room$'
.comm .ignmask, 4 .comm .ignmask, 4
.comm _errno, 4 .comm _errno, 4
.comm .doshandle, 2
.comm .psp, 4
.sect .bss
.space 512
.stack:
! vim: ts=4 sw=4 et ft=asm ! vim: ts=4 sw=4 et ft=asm

View file

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

View file

@ -51,6 +51,7 @@ exe_start:
xor di, di xor di, di
xorb al, al xorb al, al
mov cx, 0xffff mov cx, 0xffff
cld
1: 1:
repne scasb ! find end of next string repne scasb ! find end of next string
eseg cmpb (di), 0 eseg cmpb (di), 0
@ -90,8 +91,8 @@ exe_start:
xor cx, cx ! high offset xor cx, cx ! high offset
xor dx, dx ! low offset xor dx, dx ! low offset
int 0x21 ! lseek int 0x21 ! lseek
mov (textlen+0), ax mov (pmemlen+0), ax
mov (textlen+2), dx mov (pmemlen+2), dx
! Initialise DPMI. ! Initialise DPMI.
@ -115,7 +116,7 @@ exe_start:
callf (pmode_switch) callf (pmode_switch)
jc bad_dpmi jc bad_dpmi
! We're now in protected mode. (0xa9) ! We're now in protected mode. (ae)
mov (psegcs), cs mov (psegcs), cs
mov (psegds), ds mov (psegds), ds
@ -127,14 +128,15 @@ exe_start:
int 0x31 ! allocate LDT int 0x31 ! allocate LDT
jc bad_dpmi jc bad_dpmi
mov es, ax mov es, ax
mov (psegcs32), ax
mov cx, (textlen+0) mov cx, (pmemlen+0)
mov bx, (textlen+2) mov bx, (pmemlen+2)
mov ax, 0x0501 mov ax, 0x0501
int 0x31 ! allocate linear address int 0x31 ! allocate linear address
jc bad_dpmi jc bad_dpmi
mov (pmemhandle+0), si mov (pmemhandle+0), di
mov (pmemhandle+2), di mov (pmemhandle+2), si
mov dx, cx mov dx, cx
mov cx, bx mov cx, bx
@ -144,8 +146,8 @@ exe_start:
jc bad_dpmi jc bad_dpmi
mov bx, es mov bx, es
mov dx, (textlen+0) mov dx, (pmemlen+0)
mov cx, (textlen+2) mov cx, (pmemlen+2)
mov ax, 0x0008 mov ax, 0x0008
int 0x31 ! set segment limit int 0x31 ! set segment limit
@ -157,7 +159,23 @@ exe_start:
mov ax, 0x0009 mov ax, 0x0009
int 0x31 ! set descriptor access rights 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 bx, (fh)
mov ax, 0x4200 mov ax, 0x4200
@ -179,6 +197,7 @@ exe_start:
o32 movzx ecx, ax ! number of bytes read o32 movzx ecx, ax ! number of bytes read
o32 mov esi, transfer_buffer o32 mov esi, transfer_buffer
cld
o32 rep movsb o32 rep movsb
jmp 1b jmp 1b
2: 2:
@ -191,12 +210,75 @@ exe_start:
! Jump to the new segment and enter 32-bit mode! ! Jump to the new segment and enter 32-bit mode!
o32 mov eax, (pmemhandle) mov ax, (psegcs)
o32 movzx ebx, (rseg) mov bx, (psegds)
mov cx, (rseg)
o32 mov edx, realloc
push es
pop ds
push es push es
push 0 push 0
retf 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: bad_dpmi:
mov si, bad_dpmi_msg mov si, bad_dpmi_msg
jmp exit_with_error jmp exit_with_error
@ -250,8 +332,6 @@ int21:
mov bx, (dpmi_ebx) mov bx, (dpmi_ebx)
mov cx, (dpmi_ecx) mov cx, (dpmi_ecx)
mov dx, (dpmi_edx) mov dx, (dpmi_edx)
push (dpmi_flags)
popf
ret ret
bad_dpmi_msg: bad_dpmi_msg:
@ -260,7 +340,7 @@ no_file_msg:
.asciz "Couldn't open .exe" .asciz "Couldn't open .exe"
no_dpmi_msg: no_dpmi_msg:
.asciz "No DPMI host installed" .asciz "No DPMI host installed"
.align 2 .align 4
text_top: text_top:
exe_text_pages = [text_top - exe_header + 511] / 512 exe_text_pages = [text_top - exe_header + 511] / 512
@ -294,9 +374,12 @@ rseg: .space 2 ! real mode
pspseg: .space 2 ! real mode pspseg: .space 2 ! real mode
psegcs: .space 2 ! protected mode 16-bit code segment psegcs: .space 2 ! protected mode 16-bit code segment
psegds: .space 2 ! protected mode 16-bit data 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 pmemhandle: .space 4 ! protected mode linear memory handle
pmemlen: .space 4 ! protected mode linear memory length
fh: .space 2 fh: .space 2
textlen: .space 4
.space 128 .space 128
stack: stack: