diff --git a/plat/msdos386/boot.s b/plat/msdos386/boot.s index 81ab6a7ea..858785558 100644 --- a/plat/msdos386/boot.s +++ b/plat/msdos386/boot.s @@ -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 diff --git a/plat/msdos386/descr b/plat/msdos386/descr index a18c266e2..718424e21 100644 --- a/plat/msdos386/descr +++ b/plat/msdos386/descr @@ -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 diff --git a/plat/msdos386/stub.s b/plat/msdos386/stub.s index 8422bcbf5..863d5d8f7 100644 --- a/plat/msdos386/stub.s +++ b/plat/msdos386/stub.s @@ -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: