From d464606dd645a6d0ae904c499132ccccd0ab783f Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 9 Aug 2022 23:49:18 +0200 Subject: [PATCH] We can now load and run 32-bit protected-mode executables. We have not, however, set up the data segment. --- plat/msdos386/boot.s | 138 +----------------------------------- plat/msdos386/build-pkg.lua | 27 +++++++ plat/msdos386/descr | 2 +- plat/msdos386/stub.s | 11 +-- util/amisc/aslod.1 | 5 +- util/amisc/aslod.c | 22 ++++++ 6 files changed, 60 insertions(+), 145 deletions(-) diff --git a/plat/msdos386/boot.s b/plat/msdos386/boot.s index 4c6d060cf..81ab6a7ea 100644 --- a/plat/msdos386/boot.s +++ b/plat/msdos386/boot.s @@ -11,144 +11,12 @@ .sect .bss .sect .text -.use16 -exe_header: - .data2 0x5a4d ! magic number - .data2 0 ! number of bytes in last loadable page - .data2 exe_text_paras ! size of .exe, in pages - .data2 0 ! number of relocation entries - .data2 0 ! start of loadable area, in 16-byte paragraphs - .data2 exe_ram_paras ! required RAM size, in 16-byte paragraphs - .data2 0 ! maximum RAM siz, in 16-byte paragraphse - .data2 0 ! initial SS, relative to program - .data2 exe_stack ! initial SP - .data2 0 ! checksum (ignored) - .data2 exe_start ! initial IP - .data2 0 ! initial CS, relative to program - .data2 0 ! offset of relocation table - .data2 0 ! overlay number - -dpmi_edi = 0x00 -dpmi_esi = 0x04 -dpmi_ebp = 0x08 -dpmi_ebx = 0x10 -dpmi_edx = 0x14 -dpmi_ecx = 0x18 -dpmi_eax = 0x1c -dpmi_flags = 0x20 -dpmi_es = 0x22 -dpmi_ds = 0x24 -dpmi_fs = 0x26 -dpmi_gs = 0x28 -dpmi_ip = 0x2a -dpmi_cs = 0x2c -dpmi_sp = 0x2e -dpmi_ss = 0x30 - -dpmi_rs = 0x32 ! WORD: real segment -dpmi_psp = 0x34 ! WORD: PSP segment -dpmi_switch = 0x38 ! DWORD: far pointer of pmode switch routine - - .seek 0x3c -exe_start: - ! On entry, DS=ES=PSP. Make DS=CS, so we're running in tiny mode. - - push cs - pop ds - mov (dpmi_rs), ds - mov (dpmi_psp), es - - ! Initialise DPMI. - - mov ax, 0x1687 - int 0x2f - or ax, ax - jnz no_dpmi - mov (dpmi_switch+0), di ! write back PMODE switch routine - mov (dpmi_switch+2), es - or si, si ! do we need a DPMI private area? - jz 1f - - mov bx, si - movb ah, 0x48 - int 0x21 ! allocate memory from DOS - mov es, ax ! data area segment -> es -1: - ! Switch to protected mode. - - mov ax, 1 ! 32-bit app - callf (dpmi_switch) - jnc pmode ! Success! - - ! Could not switch to protected mode. - - mov dx, no_pmode_msg - jmp exit_with_error - -no_dpmi: - mov dx, no_dpmi_msg - ! fall through - -! Displays the message in dx and exits. -exit_with_error: - movb ah, 9 - int 0x21 ! print $-terminated string - mov ax, 0x4cff - int 0x21 ! terminate with error code al - -pmode: - ! We're now in protected mode! Switch our code segment to 32-bit mode. - - mov cx, cs - lar cx, cx - movb cl, ch - movb ch, 0xc0 - mov bx, cs - mov ax, 0x0009 - int 0x31 ! Make selector 32 bit - - .use32 - o16 mov (dpmi_edx), go_msg - o16 mov ax, (dpmi_rs) - o16 mov (dpmi_ds), ax - movb (dpmi_eax+1), 9 - call int21 - o16 mov ax, 0x4c00 - int 0x21 - - ! Simulate DOS interrupt bx. -int21: - o16 mov bx, 0x21 -callint: - o16 xor ax, ax - o16 mov (dpmi_ss), ax ! zero stack: DPMI host allocates one. - o16 mov (dpmi_sp), ax - push ds - pop es - mov di, ax - o16 mov ax, 0x300 - int 0x31 ! simulate DOS interrupt - push cs - pop ds - ret - -go_msg: - .ascii "Go!$" -no_pmode_msg: - .ascii "Couldn't switch to protected mode$" -no_dpmi_msg: - .ascii "No DPMI$" - -exe_top: - -exe_stack = exe_top + 512 -exe_text_paras = [exe_top - exe_header + 511] / 512 -exe_ram_paras = [exe_stack - exe_top + 15] / 16 - - #define STACK_BUFFER 128 /* number of bytes to leave for stack */ begtext: + mov eax, 0x4c00 + int 0x21 + ! Make sure we are running under MS-DOS 2 or above. ! ! While at it, also remember the actual DOS version, so that we know diff --git a/plat/msdos386/build-pkg.lua b/plat/msdos386/build-pkg.lua index 98cce47cc..4b92b5619 100644 --- a/plat/msdos386/build-pkg.lua +++ b/plat/msdos386/build-pkg.lua @@ -6,6 +6,32 @@ ackfile { vars = { plat = "msdos386" } } +ackfile { + name = "stub", + srcs = { "./stub.s" }, + vars = { plat = "msdos386" } +} + +normalrule { + name = "stub_aout", + ins = { + "util/led+led", + "+stub" + }, + outleaves = { "stub.aout" }, + commands = { "%{ins[1]} %{ins[2]} -o %{outs[1]}" } +} + +normalrule { + name = "stub_exe", + ins = { + "util/amisc+aslod", + "+stub_aout" + }, + outleaves = { "stub.exe" }, + commands = { "%{ins[1]} %{ins[2]} %{outs[1]}" } +} + build_plat_libs { name = "libs", arch = "i386", @@ -19,6 +45,7 @@ installable { "+libs", "./include+pkg", ["$(PLATIND)/msdos386/boot.o"] = "+boot", + ["$(PLATIND)/msdos386/stub.exe"] = "+stub_exe", ["$(PLATIND)/msdos386/libsys.a"] = "./libsys+lib", } } diff --git a/plat/msdos386/descr b/plat/msdos386/descr index f6559471e..a18c266e2 100644 --- a/plat/msdos386/descr +++ b/plat/msdos386/descr @@ -72,6 +72,6 @@ name cv from .out to .exe program {EM}/bin/aslod - args < > + args -p {PLATFORMDIR}/stub.exe < > outfile msdos386.exe end diff --git a/plat/msdos386/stub.s b/plat/msdos386/stub.s index 7eb3b2ddc..8422bcbf5 100644 --- a/plat/msdos386/stub.s +++ b/plat/msdos386/stub.s @@ -162,7 +162,7 @@ exe_start: mov bx, (fh) mov ax, 0x4200 xor cx, cx ! high offset - xor dx, dx ! low offset + mov dx, text_top ! low offset int 0x21 ! lseek o32 xor edi, edi ! destination 32-bit register @@ -194,7 +194,7 @@ exe_start: o32 mov eax, (pmemhandle) o32 movzx ebx, (rseg) push es - push text_top + push 0 retf bad_dpmi: @@ -225,12 +225,6 @@ exit_with_error: mov ax, 0x4cff int 0x21 ! terminate with error code al -pmode: - .use32 - mov ax, 0x4c00 - int 0x21 - .use16 - ! Simulate DOS interrupt. int21: mov (dpmi_eax), ax @@ -266,6 +260,7 @@ no_file_msg: .asciz "Couldn't open .exe" no_dpmi_msg: .asciz "No DPMI host installed" +.align 2 text_top: exe_text_pages = [text_top - exe_header + 511] / 512 diff --git a/util/amisc/aslod.1 b/util/amisc/aslod.1 index 5a1f857a0..a9f15ef3a 100644 --- a/util/amisc/aslod.1 +++ b/util/amisc/aslod.1 @@ -3,7 +3,7 @@ aslod \- ACK simple loader .SH SYNOPSIS .B aslod -[\-h] [\-v] inputfile outputfile +[\-h] [\-v] [\-p prefixfile] inputfile outputfile .SH DESCRIPTION .I aslod converts an absolute ack.out file into a simple binary memory dump. @@ -16,5 +16,8 @@ The file must have all references resolved and be linked to a fixed address. aslod will dump the segments, in order, such that the first byte of TEXT is at offset 0 in the file (regardless of where it is in memory). +.PP +If a prefix file is specified, this is prepended to the output before writing. +No changes to the output itself are made. .SH "SEE ALSO" ack.out(5) diff --git a/util/amisc/aslod.c b/util/amisc/aslod.c index 850c805f1..d5c3bee53 100644 --- a/util/amisc/aslod.c +++ b/util/amisc/aslod.c @@ -37,6 +37,7 @@ struct outsect outsect[S_MAX]; char* stringarea; char* outputfile = NULL; /* Name of output file, or NULL */ +char* prefixfile = NULL; /* Name of prefix file, or NULL */ char* program; /* Name of current program: argv[0] */ FILE* input; /* Input stream */ @@ -136,6 +137,19 @@ void emits(struct outsect* section, struct outsect* nextsect) } } +void emitprefixfile(void) +{ + FILE* fp = fopen(prefixfile, "rb"); + + while (!feof(fp)) + { + char buffer[BUFSIZ]; + size_t blocksize = fread(buffer, 1, BUFSIZ, fp); + writef(buffer, 1, blocksize); + } + + fclose(fp); +} /* Macros from modules/src/object/obj.h */ #define Xchar(ch) ((ch) & 0377) @@ -204,6 +218,12 @@ int main(int argc, char* argv[]) verbose = true; break; + case 'p': + argv++; + argc--; + prefixfile = argv[1]; + break; + default: syntaxerror: fatal("syntax error --- try -h for help"); @@ -288,6 +308,8 @@ int main(int argc, char* argv[]) /* And go! */ + if (prefixfile) + emitprefixfile(); emits(&outsect[TEXT], &outsect[ROM]); emits(&outsect[ROM], &outsect[DATA]); emits(&outsect[DATA], NULL);