We can now load and run 32-bit protected-mode executables. We have not,

however, set up the data segment.
This commit is contained in:
David Given 2022-08-09 23:49:18 +02:00
parent b48b5b13ce
commit d464606dd6
6 changed files with 60 additions and 145 deletions

View file

@ -11,144 +11,12 @@
.sect .bss .sect .bss
.sect .text .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 */ #define STACK_BUFFER 128 /* number of bytes to leave for stack */
begtext: begtext:
mov eax, 0x4c00
int 0x21
! Make sure we are running under MS-DOS 2 or above. ! Make sure we are running under MS-DOS 2 or above.
! !
! While at it, also remember the actual DOS version, so that we know ! While at it, also remember the actual DOS version, so that we know

View file

@ -6,6 +6,32 @@ ackfile {
vars = { plat = "msdos386" } 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 { build_plat_libs {
name = "libs", name = "libs",
arch = "i386", arch = "i386",
@ -19,6 +45,7 @@ installable {
"+libs", "+libs",
"./include+pkg", "./include+pkg",
["$(PLATIND)/msdos386/boot.o"] = "+boot", ["$(PLATIND)/msdos386/boot.o"] = "+boot",
["$(PLATIND)/msdos386/stub.exe"] = "+stub_exe",
["$(PLATIND)/msdos386/libsys.a"] = "./libsys+lib", ["$(PLATIND)/msdos386/libsys.a"] = "./libsys+lib",
} }
} }

View file

@ -72,6 +72,6 @@ name cv
from .out from .out
to .exe to .exe
program {EM}/bin/aslod program {EM}/bin/aslod
args < > args -p {PLATFORMDIR}/stub.exe < >
outfile msdos386.exe outfile msdos386.exe
end end

View file

@ -162,7 +162,7 @@ exe_start:
mov bx, (fh) mov bx, (fh)
mov ax, 0x4200 mov ax, 0x4200
xor cx, cx ! high offset xor cx, cx ! high offset
xor dx, dx ! low offset mov dx, text_top ! low offset
int 0x21 ! lseek int 0x21 ! lseek
o32 xor edi, edi ! destination 32-bit register o32 xor edi, edi ! destination 32-bit register
@ -194,7 +194,7 @@ exe_start:
o32 mov eax, (pmemhandle) o32 mov eax, (pmemhandle)
o32 movzx ebx, (rseg) o32 movzx ebx, (rseg)
push es push es
push text_top push 0
retf retf
bad_dpmi: bad_dpmi:
@ -225,12 +225,6 @@ exit_with_error:
mov ax, 0x4cff mov ax, 0x4cff
int 0x21 ! terminate with error code al int 0x21 ! terminate with error code al
pmode:
.use32
mov ax, 0x4c00
int 0x21
.use16
! Simulate DOS interrupt. ! Simulate DOS interrupt.
int21: int21:
mov (dpmi_eax), ax mov (dpmi_eax), ax
@ -266,6 +260,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
text_top: text_top:
exe_text_pages = [text_top - exe_header + 511] / 512 exe_text_pages = [text_top - exe_header + 511] / 512

View file

@ -3,7 +3,7 @@
aslod \- ACK simple loader aslod \- ACK simple loader
.SH SYNOPSIS .SH SYNOPSIS
.B aslod .B aslod
[\-h] [\-v] inputfile outputfile [\-h] [\-v] [\-p prefixfile] inputfile outputfile
.SH DESCRIPTION .SH DESCRIPTION
.I aslod .I aslod
converts an absolute ack.out file into a simple binary memory dump. 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 fixed address. aslod will dump the segments, in order, such
that the first byte of TEXT is at offset 0 in the file that the first byte of TEXT is at offset 0 in the file
(regardless of where it is in memory). (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" .SH "SEE ALSO"
ack.out(5) ack.out(5)

View file

@ -37,6 +37,7 @@ struct outsect outsect[S_MAX];
char* stringarea; char* stringarea;
char* outputfile = NULL; /* Name of output file, or NULL */ 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] */ char* program; /* Name of current program: argv[0] */
FILE* input; /* Input stream */ 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 */ /* Macros from modules/src/object/obj.h */
#define Xchar(ch) ((ch) & 0377) #define Xchar(ch) ((ch) & 0377)
@ -204,6 +218,12 @@ int main(int argc, char* argv[])
verbose = true; verbose = true;
break; break;
case 'p':
argv++;
argc--;
prefixfile = argv[1];
break;
default: default:
syntaxerror: syntaxerror:
fatal("syntax error --- try -h for help"); fatal("syntax error --- try -h for help");
@ -288,6 +308,8 @@ int main(int argc, char* argv[])
/* And go! */ /* And go! */
if (prefixfile)
emitprefixfile();
emits(&outsect[TEXT], &outsect[ROM]); emits(&outsect[TEXT], &outsect[ROM]);
emits(&outsect[ROM], &outsect[DATA]); emits(&outsect[ROM], &outsect[DATA]);
emits(&outsect[DATA], NULL); emits(&outsect[DATA], NULL);