diff --git a/README b/README index 07903da95..5a305d6ab 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ =================================== © 1987-2005 Vrije Universiteit, Amsterdam - 2022-06-18 + 2022-08-19 INTRODUCTION @@ -38,6 +38,7 @@ cpm produces i80 CP/M .COM files rpi produces Raspberry Pi GPU binaries pdpv7 produces PDP/11 V7 Unix binaries msdos86 produces i86 MS-DOS .COM files +msdos386 produces i386 MS-DOS 32-bit DPMI .EXE files diff --git a/build.lua b/build.lua index 319571d8a..b0c2beebd 100644 --- a/build.lua +++ b/build.lua @@ -12,6 +12,7 @@ vars.plats = { "linuxppc", "linuxmips", "msdos86", + "msdos386", "osx386", "osxppc", "pc86", diff --git a/mach/i386/as/mach3.c b/mach/i386/as/mach3.c index 37f03566b..d5156ae0c 100644 --- a/mach/i386/as/mach3.c +++ b/mach/i386/as/mach3.c @@ -184,10 +184,13 @@ {0, NOOP_1, 0155, "ins"}, {0, NOOP_1, 0252, "stosb"}, {0, NOOP_1, 0253, "stos"}, +{0, NOOP_1, 0253, "stosw"}, {0, NOOP_1, 0254, "lodsb"}, {0, NOOP_1, 0255, "lods"}, +{0, NOOP_1, 0255, "lodsw"}, {0, NOOP_1, 0256, "scasb"}, {0, NOOP_1, 0257, "scas"}, +{0, NOOP_1, 0257, "scasw"}, {0, NOOP_1, 0311, "leave"}, {0, NOOP_1, 0316, "into"}, {0, NOOP_1, 0317, "iret"}, diff --git a/mach/i386/as/mach5.c b/mach/i386/as/mach5.c index 4c07402fb..8815828ec 100644 --- a/mach/i386/as/mach5.c +++ b/mach/i386/as/mach5.c @@ -10,8 +10,8 @@ void ea_1_16(int param) { - reg_1 &= 0377; - if ((reg_1 & 070) || (param & ~070)) { + reg_1 &= 0377; + if (param & ~070) { serror("bad operand"); } emit1(reg_1 | param); @@ -39,542 +39,545 @@ void ea_1_16(int param) } void ea_1(int param) { - if (! address_long) { - ea_1_16(param); - return; - } - if (is_expr(reg_1)) { - serror("bad operand"); - return; - } - if (is_reg(reg_1)) { - emit1(0300 | param | (reg_1&07)); - return; - } - if (rm_1 == 04) { - /* sib field use here */ - emit1(mod_1 << 6 | param | 04); - emit1(sib_1 | reg_1); - } - else emit1(mod_1<<6 | param | (reg_1&07)); - if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) { - /* ??? should this be protected by a call to "small" ??? */ + if (! address_long) { + ea_1_16(param); + return; + } + if (is_expr(reg_1)) { + serror("bad operand"); + return; + } + if (is_reg(reg_1)) { + emit1(0300 | param | (reg_1&07)); + return; + } + if (rm_1 == 04) { + /* sib field use here */ + emit1(mod_1 << 6 | param | 04); + emit1(sib_1 | reg_1); + } + else emit1(mod_1<<6 | param | (reg_1&07)); + if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) { + /* ??? should this be protected by a call to "small" ??? */ #ifdef RELOCATION - RELOMOVE(relonami, rel_1); - newrelo(exp_1.typ, RELO4); + RELOMOVE(relonami, rel_1); + newrelo(exp_1.typ, RELO4); #endif - emit4((long)(exp_1.val)); - } - else if (mod_1 == 1) { - emit1((int)(exp_1.val)); - } + emit4((long)(exp_1.val)); + } + else if (mod_1 == 1) { + emit1((int)(exp_1.val)); + } } void ea_2(int param) { - op_1 = op_2; - RELOMOVE(rel_1, rel_2); - ea_1(param); + op_1 = op_2; + RELOMOVE(rel_1, rel_2); + ea_1(param); } int checkscale(valu_t val) { - int v = val; + int v = val; - if (! address_long) { - serror("scaling not allowed in 16-bit mode"); - return 0; - } - if (v != val) v = 0; - switch(v) { - case 1: - return 0; - case 2: - return 1 << 6; - case 4: - return 2 << 6; - case 8: - return 3 << 6; - default: - serror("bad scale"); - return 0; - } - /*NOTREACHED*/ + if (! address_long) { + serror("scaling not allowed in 16-bit mode"); + return 0; + } + if (v != val) v = 0; + switch(v) { + case 1: + return 0; + case 2: + return 1 << 6; + case 4: + return 2 << 6; + case 8: + return 3 << 6; + default: + serror("bad scale"); + return 0; + } + /*NOTREACHED*/ } void reverse(void) { - struct operand op; + struct operand op; #ifdef RELOCATION - int r = rel_1; + int r = rel_1; - rel_1 = rel_2; rel_2 = r; + rel_1 = rel_2; rel_2 = r; #endif - op = op_1; op_1 = op_2; op_2 = op; + op = op_1; op_1 = op_2; op_2 = op; } void badsyntax(void) { - serror("bad operands"); + serror("bad operands"); } void regsize(int sz) { - register int bit; + register int bit; - bit = (sz&1) ? 0 : IS_R8; - if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) || - (is_reg(reg_2) && (reg_2 & IS_R8) != bit)) - serror("register error"); - if (! address_long) { - reg_1 &= ~010; - reg_2 &= ~010; - } + bit = (sz&1) ? 0 : IS_R8; + if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) || + (is_reg(reg_2) && (reg_2 & IS_R8) != bit)) + serror("register error"); + if (! address_long) { + reg_1 &= ~010; + reg_2 &= ~010; + } } void indexed(void) { - if (address_long) { - mod_2 = 0; - if (sib_2 == -1) - serror("register error"); - if (rm_2 == 0 && reg_2 == 4) { - /* base register sp, no index register; use - indexed mode without index register - */ - rm_2 = 04; - sib_2 = 044; - } - if (reg_2 == 015) { - reg_2 = 05; - return; - } - if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) { - if (small(exp_2.val == 0 && reg_2 != 5, 1)) { - } - else mod_2 = 01; - } - else if (small(0, 1)) { - } - else mod_2 = 02; - } - else { - if (reg_2 & ~7) - serror("register error"); - if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) { - if (small(exp_2.val == 0 && reg_2 != 6, 1)) { - } - else reg_2 |= 0100; - } - else if (small(0, 1)) { - } - else reg_2 |= 0200; - } + if (address_long) { + mod_2 = 0; + if (sib_2 == -1) + serror("register error"); + if (rm_2 == 0 && reg_2 == 4) { + /* base register sp, no index register; use + indexed mode without index register + */ + rm_2 = 04; + sib_2 = 044; + } + if (reg_2 == 015) { + reg_2 = 05; + return; + } + if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) { + if (small(exp_2.val == 0 && reg_2 != 5, 1)) { + } + else mod_2 = 01; + } + else if (small(0, 1)) { + } + else mod_2 = 02; + } + else { + if (reg_2 & ~7) + serror("register error"); + if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) { + if (small(exp_2.val == 0 && reg_2 != 6, 1)) { + } + else reg_2 |= 0100; + } + else if (small(0, 1)) { + } + else reg_2 |= 0200; + } } void ebranch(register int opc,expr_t exp) { - /* Conditional branching; Full displacements are available - on the 80386, so the welknown trick with the reverse branch - over a jump is not needed here. - The only complication here is with the address size, which - can be set with a prefix. In this case, the user gets what - he asked for. - */ - register int sm; - register long dist; - int saving = address_long ? 4 : 2; + /* Conditional branching; Full displacements are available + on the 80386, so the welknown trick with the reverse branch + over a jump is not needed here. + The only complication here is with the address size, which + can be set with a prefix. In this case, the user gets what + he asked for. + */ + register int sm; + register long dist; + int saving = address_long ? 4 : 2; - if (opc == 0353) saving--; - dist = exp.val - (DOTVAL + 2); - if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT)) - dist -= DOTGAIN; - sm = dist > 0 ? fitb(dist-saving) : fitb(dist); - if ((exp.typ & ~S_DOT) != DOTTYP) - sm = 0; - if ((sm = small(sm,saving)) == 0) { - if (opc == 0353) { - emit1(0xe9); - } - else { - emit1(0xF); - emit1(opc | 0x80); - } - dist -= saving; - exp.val = dist; - adsize_exp(exp, RELPC); - } - else { - if (opc == 0353) { - emit1(opc); - } - else { - emit1(opc | 0x70); - } - emit1((int)dist); - } + if (opc == 0353) saving--; + dist = exp.val - (DOTVAL + 2); + if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT)) + dist -= DOTGAIN; + sm = dist > 0 ? fitb(dist-saving) : fitb(dist); + if ((exp.typ & ~S_DOT) != DOTTYP) + sm = 0; + if ((sm = small(sm,saving)) == 0) { + if (opc == 0353) { + emit1(0xe9); + } + else { + emit1(0xF); + emit1(opc | 0x80); + } + dist -= saving; + exp.val = dist; + adsize_exp(exp, RELPC); + } + else { + if (opc == 0353) { + emit1(opc); + } + else { + emit1(opc | 0x70); + } + emit1((int)dist); + } } void branch(register int opc,expr_t exp) { - /* LOOP, JCXZ, etc. branch instructions. - Here, the offset just must fit in a byte. - */ - register long dist; + /* LOOP, JCXZ, etc. branch instructions. + Here, the offset just must fit in a byte. + */ + register long dist; - dist = exp.val - (DOTVAL + 2); - if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT)) - dist -= DOTGAIN; - fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist)); - emit1(opc); - emit1((int)dist); + dist = exp.val - (DOTVAL + 2); + if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT)) + dist -= DOTGAIN; + fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist)); + emit1(opc); + emit1((int)dist); } void pushop(register int opc) { - regsize(1); - if (is_segreg(reg_1)) { - /* segment register */ - if ((reg_1 & 07) <= 3) - emit1(6 | opc | (reg_1&7)<<3); - else { - emit1(0xF); - emit1(0200 | opc | ((reg_1&7)<<3)); - } - } else if (is_reg(reg_1)) { - /* normal register */ - emit1(0120 | opc<<3 | (reg_1&7)); - } else if (opc == 0) { - if (is_expr(reg_1)) { - if (small(exp_1.typ == S_ABS && fitb(exp_1.val), - operand_long ? 3 : 1)) { - emit1(0152); - emit1((int)(exp_1.val)); - } - else { - emit1(0150); - RELOMOVE(relonami, rel_1); - opsize_exp(exp_1, 1); - } - } - else { - emit1(0377); ea_1(6<<3); - } - } else { - emit1(0217); ea_1(0<<3); - } + regsize(1); + if (is_segreg(reg_1)) { + /* segment register */ + if ((reg_1 & 07) <= 3) + emit1(6 | opc | (reg_1&7)<<3); + else { + emit1(0xF); + emit1(0200 | opc | ((reg_1&7)<<3)); + } + } else if (is_reg(reg_1)) { + /* normal register */ + emit1(0120 | opc<<3 | (reg_1&7)); + } else if (opc == 0) { + if (is_expr(reg_1)) { + if (small(exp_1.typ == S_ABS && fitb(exp_1.val), + operand_long ? 3 : 1)) { + emit1(0152); + emit1((int)(exp_1.val)); + } + else { + emit1(0150); + RELOMOVE(relonami, rel_1); + opsize_exp(exp_1, 1); + } + } + else { + emit1(0377); ea_1(6<<3); + } + } else { + emit1(0217); ea_1(0<<3); + } } void opsize_exp(expr_t exp, int nobyte) { - if (! nobyte) { + if (! nobyte) { #ifdef RELOCATION - newrelo(exp.typ, RELO1); + newrelo(exp.typ, RELO1); #endif - emit1((int)(exp.val)); - } - else if (operand_long) { + emit1((int)(exp.val)); + } + else if (operand_long) { #ifdef RELOCATION - newrelo(exp.typ, RELO4); + newrelo(exp.typ, RELO4); #endif - emit4((long)(exp.val)); - } - else { + emit4((long)(exp.val)); + } + else { #ifdef RELOCATION - newrelo(exp.typ, RELO2); + newrelo(exp.typ, RELO2); #endif - emit2((int)(exp.val)); - } + emit2((int)(exp.val)); + } } void adsize_exp(expr_t exp, int relpc) { - if (address_long) { + if (address_long) { #ifdef RELOCATION - newrelo(exp.typ, RELO4 | relpc); + newrelo(exp.typ, RELO4 | relpc); #endif - emit4((long)(exp.val)); - } - else { + emit4((long)(exp.val)); + } + else { #ifdef RELOCATION - newrelo(exp.typ, RELO2 | relpc); + newrelo(exp.typ, RELO2 | relpc); #endif - emit2((int)(exp.val)); - } + emit2((int)(exp.val)); + } } void addop(register int opc) { - regsize(opc); - if (is_reg(reg_2)) { - /* Add register to register or memory */ - emit1(opc); ea_1((reg_2&7)<<3); - } else if (is_acc(reg_1) && is_expr(reg_2)) { - /* Add immediate to accumulator */ - emit1(opc | 4); - RELOMOVE(relonami, rel_2); - opsize_exp(exp_2, (opc&1)); - } else if (is_expr(reg_2)) { - /* Add immediate to register or memory */ - if ((opc&1) == 0) { - emit1(0200); - } else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val), - operand_long ? 3 : 1)) { - emit1(0201); - } else { - emit1(0203); opc &= ~1; - } - ea_1(opc & 070); - RELOMOVE(relonami, rel_2); - opsize_exp(exp_2, (opc&1)); - } else if (is_reg(reg_1)) { - /* Add register or memory to register */ - emit1(opc | 2); - ea_2((reg_1&7)<<3); - } else - badsyntax(); + regsize(opc); + if (is_reg(reg_2)) { + /* Add register to register or memory */ + emit1(opc); ea_1((reg_2&7)<<3); + } else if (is_acc(reg_1) && is_expr(reg_2)) { + /* Add immediate to accumulator */ + emit1(opc | 4); + RELOMOVE(relonami, rel_2); + opsize_exp(exp_2, (opc&1)); + } else if (is_expr(reg_2)) { + /* Add immediate to register or memory */ + if ((opc&1) == 0) { + emit1(0200); + } else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val), + operand_long ? 3 : 1)) { + emit1(0201); + } else { + emit1(0203); opc &= ~1; + } + ea_1(opc & 070); + RELOMOVE(relonami, rel_2); + opsize_exp(exp_2, (opc&1)); + } else if (is_reg(reg_1)) { + /* Add register or memory to register */ + emit1(opc | 2); + ea_2((reg_1&7)<<3); + } else + badsyntax(); } void rolop(register int opc) { - register int oreg; + register int oreg; - oreg = reg_2; - reg_2 = reg_1; - regsize(opc); - if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) { - /* cl register */ - emit1(0322 | (opc&1)); ea_1(opc&070); - } else if (is_expr(oreg)) { - if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) { - /* shift by 1 */ - emit1(0320 | (opc&1)); ea_1(opc&070); - } else { - /* shift by byte count */ - emit1(0300 | (opc & 1)); - ea_1(opc & 070); + oreg = reg_2; + reg_2 = reg_1; + regsize(opc); + if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) { + /* cl register */ + emit1(0322 | (opc&1)); ea_1(opc&070); + } else if (is_expr(oreg)) { + if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) { + /* shift by 1 */ + emit1(0320 | (opc&1)); ea_1(opc&070); + } else { + /* shift by byte count */ + emit1(0300 | (opc & 1)); + ea_1(opc & 070); #ifdef RELOCATION - RELOMOVE(relonami, rel_2); - newrelo(exp_2.typ, RELO1); + RELOMOVE(relonami, rel_2); + newrelo(exp_2.typ, RELO1); #endif - emit1((int)(exp_2.val)); - } - } - else - badsyntax(); + emit1((int)(exp_2.val)); + } + } + else + badsyntax(); } void incop(register int opc) { - regsize(opc); - if ((opc&1) && is_reg(reg_1)) { - /* word register */ - emit1(0100 | (opc&010) | (reg_1&7)); - } else { - emit1(0376 | (opc&1)); - ea_1(opc & 010); - } + regsize(opc); + if ((opc&1) && is_reg(reg_1)) { + /* word register */ + emit1(0100 | (opc&010) | (reg_1&7)); + } else { + emit1(0376 | (opc&1)); + ea_1(opc & 010); + } } void callop(register int opc) { - regsize(1); - if (is_expr(reg_1)) { - if (opc == (040+(0351<<8))) { - RELOMOVE(relonami, rel_1); - ebranch(0353,exp_1); - } else { - exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0)); - emit1(opc>>8); - RELOMOVE(relonami, rel_1); - adsize_exp(exp_1, RELPC); - } - } else { - emit1(0377); ea_1(opc&070); - } + regsize(1); + if (is_expr(reg_1)) { + if (opc == (040+(0351<<8))) { + RELOMOVE(relonami, rel_1); + ebranch(0353,exp_1); + } else { + exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0)); + emit1(opc>>8); + RELOMOVE(relonami, rel_1); + adsize_exp(exp_1, RELPC); + } + } else { + emit1(0377); ea_1(opc&070); + } } void xchg(register int opc) { - regsize(opc); - if (! is_reg(reg_1) || is_acc(reg_2)) { - reverse(); - } - if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) { - emit1(0220 | (reg_2&7)); - } else if (is_reg(reg_1)) { - emit1(0206 | opc); ea_2((reg_1&7)<<3); - } else - badsyntax(); + regsize(opc); + if (! is_reg(reg_1) || is_acc(reg_2)) { + reverse(); + } + if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) { + emit1(0220 | (reg_2&7)); + } else if (is_reg(reg_1)) { + emit1(0206 | opc); ea_2((reg_1&7)<<3); + } else + badsyntax(); } void test(register int opc) { - regsize(opc); - if (is_reg(reg_2) || is_expr(reg_1)) - reverse(); - if (is_expr(reg_2)) { - if (is_acc(reg_1)) { - emit1(0250 | opc); - RELOMOVE(relonami, rel_2); - opsize_exp(exp_2, (opc&1)); - } - else { - emit1(0366 | opc); - ea_1(0<<3); - RELOMOVE(relonami, rel_2); - opsize_exp(exp_2, (opc&1)); - } - } else if (is_reg(reg_1)) { - emit1(0204 | opc); ea_2((reg_1&7)<<3); - } else - badsyntax(); + regsize(opc); + if (is_reg(reg_2) || is_expr(reg_1)) + reverse(); + if (is_expr(reg_2)) { + if (is_acc(reg_1)) { + emit1(0250 | opc); + RELOMOVE(relonami, rel_2); + opsize_exp(exp_2, (opc&1)); + } + else { + emit1(0366 | opc); + ea_1(0<<3); + RELOMOVE(relonami, rel_2); + opsize_exp(exp_2, (opc&1)); + } + } else if (is_reg(reg_1)) { + emit1(0204 | opc); ea_2((reg_1&7)<<3); + } else + badsyntax(); } void mov(register int opc) { - regsize(opc); - if (is_segreg(reg_1)) { - /* to segment register */ - emit1(0216); ea_2((reg_1&07)<<3); - } else if (is_segreg(reg_2)) { - /* from segment register */ - emit1(0214); ea_1((reg_2&07)<<3); - } else if (is_expr(reg_2)) { - /* from immediate */ - if (is_reg(reg_1)) { - /* to register */ - emit1(0260 | opc<<3 | (reg_1&7)); - } else { - /* to memory */ - emit1(0306 | opc); ea_1(0<<3); - } - RELOMOVE(relonami, rel_2); - opsize_exp(exp_2, (opc&1)); - } else if (rm_1 == 05 && is_acc(reg_2)) { - /* from accumulator to memory (displacement) */ - emit1(0242 | opc); - RELOMOVE(relonami, rel_1); - adsize_exp(exp_1, 0); - } else if (rm_2 == 05 && is_acc(reg_1)) { - /* from memory (displacement) to accumulator */ - emit1(0240 | opc); - RELOMOVE(relonami, rel_2); - adsize_exp(exp_2, 0); - } else if (is_reg(reg_2)) { - /* from register to memory or register */ - emit1(0210 | opc); ea_1((reg_2&07)<<3); - } else if (is_reg(reg_1)) { - /* from memory or register to register */ - emit1(0212 | opc); ea_2((reg_1&07)<<3); - } else - badsyntax(); + regsize(opc); + if (is_segreg(reg_1)) { + /* to segment register */ + emit1(0216); ea_2((reg_1&07)<<3); + } else if (is_segreg(reg_2)) { + /* from segment register */ + emit1(0214); ea_1((reg_2&07)<<3); + } else if (is_expr(reg_2)) { + /* from immediate */ + if (is_reg(reg_1)) { + /* to register */ + emit1(0260 | opc<<3 | (reg_1&7)); + } else { + /* to memory */ + emit1(0306 | opc); ea_1(0<<3); + } + RELOMOVE(relonami, rel_2); + opsize_exp(exp_2, (opc&1)); + } else if (rm_1 == 05 && is_acc(reg_2)) { + /* from accumulator to memory (displacement) */ + emit1(0242 | opc); + RELOMOVE(relonami, rel_1); + adsize_exp(exp_1, 0); + } else if (rm_2 == 05 && is_acc(reg_1)) { + /* from memory (displacement) to accumulator */ + emit1(0240 | opc); + RELOMOVE(relonami, rel_2); + adsize_exp(exp_2, 0); + } else if (is_reg(reg_2)) { + /* from register to memory or register */ + emit1(0210 | opc); ea_1((reg_2&07)<<3); + } else if (is_reg(reg_1)) { + /* from memory or register to register */ + emit1(0212 | opc); ea_2((reg_1&07)<<3); + } else + badsyntax(); } void extshft(int opc, int reg) { - int oreg2 = reg_2; + int oreg2 = reg_2; - reg_2 = reg_1; - regsize(1); + reg_2 = reg_1; + regsize(1); - emit1(0xF); - if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) { - /* cl register */ - emit1(opc|1); - ea_1(reg << 3); - } - else if (is_expr(oreg2)) { - emit1(opc); - ea_1(reg << 3); + emit1(0xF); + if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) { + /* cl register */ + emit1(opc|1); + ea_1(reg << 3); + } + else if (is_expr(oreg2)) { + emit1(opc); + ea_1(reg << 3); #ifdef RELOCATION - RELOMOVE(relonami, rel_2); - newrelo(exp_2.typ, RELO1); + RELOMOVE(relonami, rel_2); + newrelo(exp_2.typ, RELO1); #endif - emit1((int)(exp_2.val)); - } - else badsyntax(); + emit1((int)(exp_2.val)); + } + else badsyntax(); } void bittestop(int opc) { - regsize(1); - emit1(0xF); - if (is_expr(reg_2)) { - emit1(0272); - ea_1(opc << 3); + regsize(1); + emit1(0xF); + if (is_expr(reg_2)) { + emit1(0272); + ea_1(opc << 3); #ifdef RELOCATION - RELOMOVE(relonami, rel_2); - newrelo(exp_2.typ, RELO1); + RELOMOVE(relonami, rel_2); + newrelo(exp_2.typ, RELO1); #endif - emit1((int)(exp_2.val)); - } - else if (is_reg(reg_2)) { - emit1(0203 | (opc<<3)); - ea_1((reg_2&7)<<3); - } - else badsyntax(); + emit1((int)(exp_2.val)); + } + else if (is_reg(reg_2)) { + emit1(0203 | (opc<<3)); + ea_1((reg_2&7)<<3); + } + else badsyntax(); } void imul(int reg) { - /* This instruction is more elaborate on the 80386. Its most - general form is: - imul reg, reg_or_mem, immediate. - This is the form processed here. - */ - regsize(1); - if (is_expr(reg_1)) { - /* To also handle - imul reg, immediate, reg_or_mem - */ - reverse(); - } - if (is_expr(reg_2)) { - /* The immediate form; two cases: */ - if (small(exp_2.typ == S_ABS && fitb(exp_2.val), - operand_long ? 3 : 1)) { - /* case 1: 1 byte encoding of immediate */ - emit1(0153); - ea_1((reg & 07) << 3); - emit1((int)(exp_2.val)); - } - else { - /* case 2: WORD or DWORD encoding of immediate */ - emit1(0151); - ea_1((reg & 07) << 3); - RELOMOVE(relonami, rel_2); - opsize_exp(exp_2, 1); - } - } - else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) { - /* the "reg" field and the "reg_or_mem" field are the same, - and the 3rd operand is not an immediate ... - */ - if (reg == 0) { - /* how lucky we are, the target is the ax register */ - /* However, we cannot make an optimization for f.i. - imul eax, blablabla - because the latter does not affect edx, whereas - imul blablabla - does! Therefore, "reg" is or-ed with 0x10 in the - former case, so that the test above fails. - */ - emit1(0367); - ea_2(050); - } - else { - /* another register ... */ - emit1(0xF); - emit1(0257); - ea_2((reg & 07) << 3); - } - } - else badsyntax(); + /* This instruction is more elaborate on the 80386. Its most + general form is: + imul reg, reg_or_mem, immediate. + This is the form processed here. + */ + regsize(1); + if (is_expr(reg_1)) { + /* To also handle + imul reg, immediate, reg_or_mem + */ + reverse(); + } + if (is_expr(reg_2)) { + /* The immediate form; two cases: */ + if (small(exp_2.typ == S_ABS && fitb(exp_2.val), + operand_long ? 3 : 1)) { + /* case 1: 1 byte encoding of immediate */ + emit1(0153); + ea_1((reg & 07) << 3); + emit1((int)(exp_2.val)); + } + else { + /* case 2: WORD or DWORD encoding of immediate */ + emit1(0151); + ea_1((reg & 07) << 3); + RELOMOVE(relonami, rel_2); + opsize_exp(exp_2, 1); + } + } + else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) { + /* the "reg" field and the "reg_or_mem" field are the same, + and the 3rd operand is not an immediate ... + */ + if (reg == 0) { + /* how lucky we are, the target is the ax register */ + /* However, we cannot make an optimization for f.i. + imul eax, blablabla + because the latter does not affect edx, whereas + imul blablabla + does! Therefore, "reg" is or-ed with 0x10 in the + former case, so that the test above fails. + */ + emit1(0367); + ea_2(050); + } + else { + /* another register ... */ + emit1(0xF); + emit1(0257); + ea_2((reg & 07) << 3); + } + } + else badsyntax(); } + +// vim: ts=8 sw=8 et + diff --git a/mach/proto/as/comm7.c b/mach/proto/as/comm7.c index 9b93139d4..06e11042b 100644 --- a/mach/proto/as/comm7.c +++ b/mach/proto/as/comm7.c @@ -86,6 +86,9 @@ char* remember(char* s) int combine(int typ1, int typ2, int op) { + typ1 &= ~S_VAR; + typ2 &= ~S_VAR; + switch (op) { case '+': diff --git a/plat/msdos/include/ack/plat.h b/plat/msdos/include/ack/plat.h new file mode 100644 index 000000000..4343f1cf8 --- /dev/null +++ b/plat/msdos/include/ack/plat.h @@ -0,0 +1,11 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#ifndef _ACK_PLAT_H +#define _ACK_PLAT_H + +#define ACKCONF_WANT_O_TEXT_O_BINARY 1 + +#endif diff --git a/plat/msdos/include/build.lua b/plat/msdos/include/build.lua new file mode 100644 index 000000000..6ae480041 --- /dev/null +++ b/plat/msdos/include/build.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "./"..h + packagemap["$(PLATIND)/msdos86/include/"..h] = "./"..h +end + +addheader("ack/plat.h") +addheader("sys/types.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} + + diff --git a/plat/msdos/include/sys/types.h b/plat/msdos/include/sys/types.h new file mode 100644 index 000000000..005f48eb0 --- /dev/null +++ b/plat/msdos/include/sys/types.h @@ -0,0 +1,9 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +typedef long pid_t; +typedef int mode_t; +typedef long time_t; +typedef long suseconds_t; + +#endif diff --git a/plat/msdos/libsys/build.lua b/plat/msdos/libsys/build.lua new file mode 100644 index 000000000..d808fe894 --- /dev/null +++ b/plat/msdos/libsys/build.lua @@ -0,0 +1,28 @@ +bundle { + name = "srcs", + srcs = { + "./creat.c", + "./gettimeofday.c", + "./kill.c", + "./lseek.c", + "./open.c", + "./read.c", + "./setmode.c", + "./signal.c", + "./sys_fdmodes.c", + "./sys_getmode.c", + "./sys_initmain.c", + "./sys_iseof.c", + "./sys_seteof.c", + "./sys_seterrno.c", + "./sys_setmode.c", + "./write.c", + } +} + +bundle { + name = "headers", + srcs = { + "./libsys.h" + } +} diff --git a/plat/msdos86/libsys/creat.c b/plat/msdos/libsys/creat.c similarity index 100% rename from plat/msdos86/libsys/creat.c rename to plat/msdos/libsys/creat.c diff --git a/plat/msdos86/libsys/gettimeofday.c b/plat/msdos/libsys/gettimeofday.c similarity index 100% rename from plat/msdos86/libsys/gettimeofday.c rename to plat/msdos/libsys/gettimeofday.c diff --git a/plat/msdos86/libsys/kill.c b/plat/msdos/libsys/kill.c similarity index 100% rename from plat/msdos86/libsys/kill.c rename to plat/msdos/libsys/kill.c diff --git a/plat/msdos86/libsys/libsys.h b/plat/msdos/libsys/libsys.h similarity index 100% rename from plat/msdos86/libsys/libsys.h rename to plat/msdos/libsys/libsys.h diff --git a/plat/msdos86/libsys/lseek.c b/plat/msdos/libsys/lseek.c similarity index 100% rename from plat/msdos86/libsys/lseek.c rename to plat/msdos/libsys/lseek.c diff --git a/plat/msdos86/libsys/open.c b/plat/msdos/libsys/open.c similarity index 100% rename from plat/msdos86/libsys/open.c rename to plat/msdos/libsys/open.c diff --git a/plat/msdos86/libsys/read.c b/plat/msdos/libsys/read.c similarity index 71% rename from plat/msdos86/libsys/read.c rename to plat/msdos/libsys/read.c index 5075958bd..bed9fcd14 100644 --- a/plat/msdos86/libsys/read.c +++ b/plat/msdos/libsys/read.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -16,9 +17,7 @@ ssize_t read(int fd, void* buffer, size_t count) ssize_t r, tot; size_t left; int eof = 0; - - if (!count || _sys_getmode(fd) == O_BINARY) - return _sys_rawread(fd, buffer, count); + bool text = _sys_getmode(fd) == O_TEXT; if (_sys_iseof(fd)) return 0; @@ -47,33 +46,36 @@ ssize_t read(int fd, void* buffer, size_t count) if (r <= 0) return tot ? tot : r; - q = memchr(p, 0x1a, (size_t)r); - if (q) + if (text) { - _sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR); - r = q - p; - eof = 1; - _sys_seteof(fd, 1); - } - - q = memchr(p, '\r', (size_t)r); - if (!q) - return tot + r; - - tot += q - p; - left = r - (q + 1 - p); - p = q; - ++q; - - while (left) - { - char c = *q++; - if (c != '\r') + q = memchr(p, 0x1a, (size_t)r); + if (q) { - *p++ = c; - ++tot; + _sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR); + r = q - p; + eof = 1; + _sys_seteof(fd, 1); + } + + q = memchr(p, '\r', (size_t)r); + if (!q) + return tot + r; + + tot += q - p; + left = r - (q + 1 - p); + p = q; + ++q; + + while (left) + { + char c = *q++; + if (c != '\r') + { + *p++ = c; + ++tot; + } + --left; } - --left; } } while (tot < count && !eof && _sys_isreadyr(fd)); diff --git a/plat/msdos86/libsys/setmode.c b/plat/msdos/libsys/setmode.c similarity index 100% rename from plat/msdos86/libsys/setmode.c rename to plat/msdos/libsys/setmode.c diff --git a/plat/msdos86/libsys/signal.c b/plat/msdos/libsys/signal.c similarity index 100% rename from plat/msdos86/libsys/signal.c rename to plat/msdos/libsys/signal.c diff --git a/plat/msdos86/libsys/sys_fdmodes.c b/plat/msdos/libsys/sys_fdmodes.c similarity index 100% rename from plat/msdos86/libsys/sys_fdmodes.c rename to plat/msdos/libsys/sys_fdmodes.c diff --git a/plat/msdos86/libsys/sys_getmode.c b/plat/msdos/libsys/sys_getmode.c similarity index 100% rename from plat/msdos86/libsys/sys_getmode.c rename to plat/msdos/libsys/sys_getmode.c diff --git a/plat/msdos86/libsys/sys_initmain.c b/plat/msdos/libsys/sys_initmain.c similarity index 100% rename from plat/msdos86/libsys/sys_initmain.c rename to plat/msdos/libsys/sys_initmain.c diff --git a/plat/msdos86/libsys/sys_iseof.c b/plat/msdos/libsys/sys_iseof.c similarity index 100% rename from plat/msdos86/libsys/sys_iseof.c rename to plat/msdos/libsys/sys_iseof.c diff --git a/plat/msdos86/libsys/sys_seteof.c b/plat/msdos/libsys/sys_seteof.c similarity index 100% rename from plat/msdos86/libsys/sys_seteof.c rename to plat/msdos/libsys/sys_seteof.c diff --git a/plat/msdos86/libsys/sys_seterrno.c b/plat/msdos/libsys/sys_seterrno.c similarity index 100% rename from plat/msdos86/libsys/sys_seterrno.c rename to plat/msdos/libsys/sys_seterrno.c diff --git a/plat/msdos86/libsys/sys_setmode.c b/plat/msdos/libsys/sys_setmode.c similarity index 100% rename from plat/msdos86/libsys/sys_setmode.c rename to plat/msdos/libsys/sys_setmode.c diff --git a/plat/msdos/libsys/write.c b/plat/msdos/libsys/write.c new file mode 100644 index 000000000..cfc764246 --- /dev/null +++ b/plat/msdos/libsys/write.c @@ -0,0 +1,74 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include +#include "libsys.h" + +ssize_t write(int fd, void* buffer, size_t count) +{ + static const char crlf[2] = "\r\n"; + int i; + char *p, *q; + size_t left, n; + ssize_t r, tot; + + if (!count) + return 0; + + p = buffer; + left = count; + tot = 0; + + if (_sys_getmode(fd) == O_BINARY) + { + while (left) + { + r = _sys_rawwrite(fd, p, left); + if (r <= 0) + return tot ? tot : r; + tot += r; + p += r; + left -= r; + } + } + else + { + /* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */ + while (left) + { + q = memchr(p, '\n', left); + if (!q) + return _sys_rawwrite(fd, p, left); + + n = q - p; + if (n) + { + r = _sys_rawwrite(fd, p, n); + if (r <= 0) + return tot ? tot : r; + tot += r; + p += r; + left -= r; + if (r != n) + break; + } + + r = _sys_rawwrite(fd, crlf, sizeof crlf); + if (r != 2) + { + if (r > 0) + r = 0; + return tot ? tot : r; + } + ++tot; + ++p; + --left; + } + } + return tot; +} diff --git a/plat/msdos386/README b/plat/msdos386/README new file mode 100644 index 000000000..0a52528a6 --- /dev/null +++ b/plat/msdos386/README @@ -0,0 +1,24 @@ +The msdos386 platform +===================== + +msdos386 is an i386-based BSP that produces DPMI DOS executables. It should +have the same functionality as msdos86 (as the libc is all the same code), but +has been much less well tested. + +The code runs in flat 32-bit mode, so normal 32-bit pointers work with no +worries about segmentation. It requires a DPMI host to run; it was tested with +CWSDPMI. It will _not_ automatically load the host --- you need to manually +install the DPMI hsot first. + +IEEE floating point is available, but requires an FPU. + + +Example command line +==================== + +ack -mmsdos386 -O -o msdos386.exe examples/paranoia.c + + +David Given +dg@cowlark.com + diff --git a/plat/msdos386/boot.s b/plat/msdos386/boot.s new file mode 100644 index 000000000..6e1b02add --- /dev/null +++ b/plat/msdos386/boot.s @@ -0,0 +1,236 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text +#define STACK_BUFFER 128 /* number of bytes to leave for stack */ + +! g 18b to break at the retf before coming here +begtext: + ! On entry, the stub has cs and ds pointing at the 32-bit + ! segment, but ss is still pointing at the 16-bit segment. + ! + ! ax: pmode code segment of stub + ! bx: pmode data segment of stub + ! cx: rmode segment of stub + ! dx: pointer to realloc routine (in stub)e + ! si: pointer to interrupt routine (in stub) + ! di: pointer to transfer buffer (in stub) + + ! Resize the segment to include the BSS. + + o16 cseg mov (realloc_ptr+4), ax + cseg mov (realloc_ptr+0), edx + cseg o16 mov (pmode_cs), ax + cseg o16 mov (pmode_ds), bx + cseg o16 mov (rmode), cx + cseg o16 mov (interrupt_ptr+4), ax + cseg mov (interrupt_ptr+0), esi + cseg o16 mov (transfer_buffer_ptr), di + + mov eax, __end + cseg callf (realloc_ptr) + + ! Clear BSS. + + 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 + mov es, 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 esi, bx + shl esi, 4 ! convert to linear address + + ! Copy the whole thing into 32-bit memory. + + mov ecx, 0x100/4 + mov edi, _psp + cld +1: + eseg lods + mov (edi), eax + add edi, 4 + loop 1b + + ! Find the environment. + + mov es, (_psp + 0x002C) ! converted to pmode segment + + ! Count the size of the environment variable block. + + xorb al, al ! byte to test for + xor edi, edi + xor edx, edx + cld + mov ecx, -1 + scasb + jz 2f ! empty environment +1: + repnz scasb + inc edx + scasb + jnz 1b +2: + add edi, 2 ! skip the mysterious word + repnz scasb ! program name + + ! Copy the whole environment block onto the stack. + + mov esi, edi + add esi, 3 + and esi, ~3 ! round up + jz empty_environment + mov ecx, esi + shr ecx, 2 ! number of dwords + std + sub esi, 4 +1: + eseg lods + push eax + loop 1b +empty_environment: + mov ecx, esp ! environment data + + ! Reset DF and es properly. + + cld + push ss + pop es + + ! Reserve space for argc and the argv and envp pointers on the + ! stack. These will be passed to __m_a_i_n later. + + sub esp, 3*4 + mov eax, esp + + ! Build up argc, argv[], and envp[]. + push eax ! output buffer for argc, argv, envp + push 3 ! MS-DOS version + push ecx ! env. string data + push edx ! count of env. vars. + push _psp+0x80 ! raw command line + call __sys_initmain + add esp, 5*4 + + ! Bail out if something went wrong. + test eax, eax + jnz no_room + + ! argc, argv, and envp are now at the stack top. Now go. + call __m_a_i_n + add sp, 3*4 + push ax + call _exit + +no_room: + mov dx, no_room_msg + !call dos_msg + movb al, -1 + jmp al_exit + + ! Exit. +.define __exit +.extern __exit +.define EXIT +.extern EXIT +__exit: +EXIT: + pop bx + pop ax +al_exit: + movb ah, 0x4c + int 0x21 + + ! These must be in the code segment due to bootstrap issues. +realloc_ptr: .space 6 ! far +interrupt_ptr: .space 6 ! far +transfer_buffer_ptr: .space 2 ! near +rmode: .space 2 +pmode_cs: .space 2 +pmode_ds: .space 2 + +.define realloc_ptr +.define interrupt_ptr +.define rmode +.define pmode_cs +.define pmode_ds +.define transfer_buffer_ptr + +! Define symbols at the beginning of our various segments, so that we can find +! them. (Except .text, which has already been done.) + +.define begtext, begdata, begbss +.sect .data; begdata: +.sect .rom; begrom: +.sect .bss; begbss: + +.sect .rom + +! Some text messages. +bad_sys_msg: .ascii 'Bad DOS$' +no_room_msg: .ascii 'No room$' + +! Some magic data. All EM systems need these. + +.define .trppc, .ignmask, _errno +.comm .trppc, 4 +.comm .ignmask, 4 +.comm _errno, 4 + +.comm .doshandle, 2 +.comm _psp, 256 + +.sect .bss + .space 32*1024 +.stack: + +! vim: ts=4 sw=4 et ft=asm + diff --git a/plat/msdos386/build-pkg.lua b/plat/msdos386/build-pkg.lua new file mode 100644 index 000000000..4b92b5619 --- /dev/null +++ b/plat/msdos386/build-pkg.lua @@ -0,0 +1,52 @@ +include("plat/build.lua") + +ackfile { + name = "boot", + srcs = { "./boot.s" }, + 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", + plat = "msdos386", +} + +installable { + name = "pkg", + map = { + "+tools", + "+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/build-tools.lua b/plat/msdos386/build-tools.lua new file mode 100644 index 000000000..d28aee904 --- /dev/null +++ b/plat/msdos386/build-tools.lua @@ -0,0 +1,21 @@ +include("plat/build.lua") + +build_as { + name = "as", + arch = "i386", +} + +build_ncg { + name = "ncg", + arch = "i386", +} + +return installable { + name = "tools", + map = { + ["$(PLATDEP)/msdos386/as"] = "+as", + ["$(PLATDEP)/msdos386/ncg"] = "+ncg", + ["$(PLATIND)/descr/msdos386"] = "./descr", + "util/opt+pkg", + } +} diff --git a/plat/msdos386/descr b/plat/msdos386/descr new file mode 100644 index 000000000..b6683871b --- /dev/null +++ b/plat/msdos386/descr @@ -0,0 +1,77 @@ +var w=4 +var wa=2 +var p=4 +var pa=2 +var s=2 +var sa=2 +var l=4 +var la=2 +var f=4 +var fa=2 +var d=8 +var da=2 +var x=8 +var xa=2 +var ARCH=i386 +var PLATFORM=msdos386 +var PLATFORMDIR={EM}/share/ack/{PLATFORM} +var CPP_F=-D__MSDOS__ -D__DOS__ -D_DOS +var ALIGN=-a0:2 -a1:2 -a2:2 -a3:2 +var MACHOPT_F=-m8 +var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr + +# Override the setting in fe so that files compiled for this platform can see +# the platform-specific headers. + +var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi + +name be + from .m.g + to .s + program {EM}/lib/ack/{PLATFORM}/ncg + args < + stdout + need .e +end +name as + from .s.so + to .o + program {EM}/lib/ack/{PLATFORM}/as + args - -o > < + prep cond +end +name led + from .o.a + to .out + program {EM}/lib/ack/em_led + mapflag -l* LNAME={PLATFORMDIR}/lib* + mapflag -fp FLOATS={EM}/{ILIB}fp + args {ALIGN} \ + ({RTS}:.b=-u _i_main) \ + (.e:{HEAD}={PLATFORMDIR}/boot.o) \ + ({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.c={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.mod={PLATFORMDIR}/modula2.o) \ + ({RTS}:.p={PLATFORMDIR}/pascal.o) \ + -o > < \ + (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \ + (.b:{TAIL}={PLATFORMDIR}/libb.a) \ + (.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \ + {FLOATS?} \ + (.e:{TAIL}={PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libsys.a \ + {PLATFORMDIR}/libc.a \ + {PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libend.a) + linker +end +name cv + from .out + to .exe + program {EM}/bin/aslod + args -p {PLATFORMDIR}/stub.exe < > + outfile msdos386.exe +end diff --git a/plat/msdos386/include/ack/plat.h b/plat/msdos386/include/ack/plat.h new file mode 100644 index 000000000..c0d1b9fff --- /dev/null +++ b/plat/msdos386/include/ack/plat.h @@ -0,0 +1,6 @@ +#ifndef _ACK_PLAT_H +#define _ACK_PLAT_H + +#define ACKCONF_WANT_O_TEXT_O_BINARY 1 + +#endif diff --git a/plat/msdos386/include/build.lua b/plat/msdos386/include/build.lua new file mode 100644 index 000000000..693abd0c1 --- /dev/null +++ b/plat/msdos386/include/build.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "./"..h + packagemap["$(PLATIND)/msdos386/include/"..h] = "./"..h +end + +addheader("ack/plat.h") +addheader("sys/types.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} + + diff --git a/plat/msdos386/include/sys/types.h b/plat/msdos386/include/sys/types.h new file mode 100644 index 000000000..005f48eb0 --- /dev/null +++ b/plat/msdos386/include/sys/types.h @@ -0,0 +1,9 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +typedef long pid_t; +typedef int mode_t; +typedef long time_t; +typedef long suseconds_t; + +#endif diff --git a/plat/msdos386/libsys/_hol0.s b/plat/msdos386/libsys/_hol0.s new file mode 100644 index 000000000..f01566fe8 --- /dev/null +++ b/plat/msdos386/libsys/_hol0.s @@ -0,0 +1,19 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .bss + +! This data block is used to store information about the current line number +! and file. + +.define hol0 +.comm hol0, 8 diff --git a/plat/msdos386/libsys/brk.s b/plat/msdos386/libsys/brk.s new file mode 100644 index 000000000..3032bc929 --- /dev/null +++ b/plat/msdos386/libsys/brk.s @@ -0,0 +1,18 @@ +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +.define _brk +_brk: + mov ebx, esp + mov eax, 1*4(ebx) + callf (realloc_ptr) + xor eax, eax + ret + + diff --git a/plat/msdos386/libsys/build.lua b/plat/msdos386/libsys/build.lua new file mode 100644 index 000000000..71ac521b8 --- /dev/null +++ b/plat/msdos386/libsys/build.lua @@ -0,0 +1,35 @@ +acklibrary { + name = "lib", + srcs = { + "./_hol0.s", + "./brk.s", + "./close.s", + "./errno.s", + "./getpid.s", + "./isatty.s", + "./rename.s", + "./sbrk.c", + "./sys_exists.s", + "./sys_getdate.s", + "./sys_gettime.s", + "./sys_isopen.s", + "./sys_isreadyr.s", + "./sys_rawcreat.s", + "./sys_rawlseek.s", + "./sys_rawopen.s", + "./sys_rawread.s", + "./sys_rawwrite.s", + "./sys_xret.s", + "./unlink.s", + "plat/msdos/libsys+srcs", + }, + deps = { + "lang/cem/libcc.ansi/headers+headers", + "plat/msdos386/include+headers", + "plat/msdos/libsys+headers", + }, + vars = { + plat = "msdos386" + } +} + diff --git a/plat/msdos386/libsys/close.s b/plat/msdos386/libsys/close.s new file mode 100644 index 000000000..412307b62 --- /dev/null +++ b/plat/msdos386/libsys/close.s @@ -0,0 +1,23 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Close a file. + +.define _close +_close: + mov ebx, esp + mov ebx, 1*4(esp) + movb ah, 0x3E + int 0x21 + jmp .sys_zret diff --git a/plat/msdos386/libsys/errno.s b/plat/msdos386/libsys/errno.s new file mode 100644 index 000000000..9858d2640 --- /dev/null +++ b/plat/msdos386/libsys/errno.s @@ -0,0 +1,28 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +#define D(e) .define e; e + +.sect .data + +! Define various ACK error numbers. Note that these are *not* ANSI C +! errnos, and are used for different purposes. + +D(ERANGE) = 1 +D(ESET) = 2 +D(EIDIVZ) = 6 +D(EHEAP) = 17 +D(EILLINS) = 18 +D(EODDZ) = 19 +D(ECASE) = 20 +D(EBADMON) = 25 + diff --git a/plat/msdos386/libsys/getpid.s b/plat/msdos386/libsys/getpid.s new file mode 100644 index 000000000..d2a250491 --- /dev/null +++ b/plat/msdos386/libsys/getpid.s @@ -0,0 +1,45 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Copyright (c) 2021--2022 TK Chia +! +! The authors hereby grant permission to use, copy, modify, distribute, +! and license this software and its documentation for any purpose, provided +! that existing copyright notices are retained in all copies and that this +! notice is included verbatim in any distributions. No written agreement, +! license, or royalty fee is required for any of the authorized uses. +! Modifications to this software may be copyrighted by their authors +! and need not follow the licensing terms described here, provided that +! the new terms are clearly indicated on the first page of each file where +! they apply. + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Get the current process identifier. For MS-DOS, use the Program Segment +! Prefix (PSP) segment as the PID, unless the system supports an actual +! `getpid' syscall, e.g. European MS-DOS 4.0. +! +! (Note that pid_t is a 32-bit type. This is to allow for PSP segments and +! MS-DOS PIDs above 0x7FFF.) + +.define _getpid +_getpid: + movb ah, 0x87 + stc + int 0x21 + jnc .eur_dos + movb ah, 0x51 + int 0x21 + xchg ebx, eax +.eur_dos: + xor edx, edx + ret diff --git a/plat/msdos386/libsys/isatty.s b/plat/msdos386/libsys/isatty.s new file mode 100644 index 000000000..794274bfa --- /dev/null +++ b/plat/msdos386/libsys/isatty.s @@ -0,0 +1,37 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Say whether a given file descriptor number refers to a terminal. + +.define _isatty +_isatty: + mov ebx, esp + mov ebx, 4(ebx) + o16 mov ax, 0x4400 + int 0x21 + jc error + testb dl, dl + jz not_tty + mov eax, 1 + ret +not_tty: + mov (_errno), 25 ! ENOTTY +not_tty_2: + xor eax, eax + ret +error: + push eax + call __sys_seterrno + pop ecx + jmp not_tty_2 diff --git a/plat/msdos386/libsys/rename.s b/plat/msdos386/libsys/rename.s new file mode 100644 index 000000000..4b43a0d48 --- /dev/null +++ b/plat/msdos386/libsys/rename.s @@ -0,0 +1,54 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Rename a file. + +.define _rename +_rename: + mov ebx, esp + push esi + push edi + + ! Source filename. + + mov esi, 4(ebx) + movzx edi, (transfer_buffer_ptr) + mov es, (pmode_ds) + cld +1: + lodsb + stosb + testb al, al + jnz 1b + + ! Destination filename. + + mov eax, edi + mov esi, 8(ebx) +1: + lodsb + stosb + testb al, al + jnz 1b + + ! Make the DOS call. + + o16 mov dx, (transfer_buffer_ptr) + o16 mov di, ax + movb ah, 0x56 + or ebx, 0x210000 + callf (interrupt_ptr) + pop edi + pop esi + jmp .sys_zret diff --git a/plat/msdos386/libsys/sbrk.c b/plat/msdos386/libsys/sbrk.c new file mode 100644 index 000000000..2dbd610f3 --- /dev/null +++ b/plat/msdos386/libsys/sbrk.c @@ -0,0 +1,40 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +extern char _end[1]; +static char* current = _end; + +void* sbrk(int increment) +{ + char* old; + char* new; + + if (increment == 0) + return current; + + old = current; + + new = old + increment; + + if ((increment > 0) && (new <= old)) + goto out_of_memory; + else if ((increment < 0) && (new >= old)) + goto out_of_memory; + + if (brk(new) < 0) + goto out_of_memory; + + current = new; + return old; + +out_of_memory: + errno = ENOMEM; + return OUT_OF_MEMORY; +} diff --git a/plat/msdos386/libsys/sys_exists.s b/plat/msdos386/libsys/sys_exists.s new file mode 100644 index 000000000..f57d28b3e --- /dev/null +++ b/plat/msdos386/libsys/sys_exists.s @@ -0,0 +1,25 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Say whether a file exists with the given name. + +.define __sys_exists +__sys_exists: + mov ebx, esp + mov edx, 4(ebx) + mov eax, 0x4300 + int 0x21 + sbb eax, eax + inc eax + ret diff --git a/plat/msdos386/libsys/sys_getdate.s b/plat/msdos386/libsys/sys_getdate.s new file mode 100644 index 000000000..981253b93 --- /dev/null +++ b/plat/msdos386/libsys/sys_getdate.s @@ -0,0 +1,25 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Get the current system date from MS-DOS. + +.define __sys_getdate +__sys_getdate: + movb ah, 0x2a + int 0x21 + mov ebx, esp + mov ebx, 4(ebx) + o16 mov 0(ebx), dx + o16 mov 2(ebx), cx + ret diff --git a/plat/msdos386/libsys/sys_gettime.s b/plat/msdos386/libsys/sys_gettime.s new file mode 100644 index 000000000..733ad58ac --- /dev/null +++ b/plat/msdos386/libsys/sys_gettime.s @@ -0,0 +1,26 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Get the current system time from MS-DOS. + +.define __sys_gettime +__sys_gettime: + int 3 + movb ah, 0x2c + int 0x21 + mov ebx, esp + mov ebx, 4(ebx) + o16 mov 0(ebx), cx + o16 mov 2(ebx), dx + ret diff --git a/plat/msdos386/libsys/sys_isopen.s b/plat/msdos386/libsys/sys_isopen.s new file mode 100644 index 000000000..5a5fed07c --- /dev/null +++ b/plat/msdos386/libsys/sys_isopen.s @@ -0,0 +1,26 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Say whether a given file descriptor number refers to a valid open file +! descriptor. + +.define __sys_isopen +__sys_isopen: + mov ebx, esp + mov ebx, 4(bx) + mov eax, 0x4400 + int 0x21 + sbb eax, eax + inc eax + ret diff --git a/plat/msdos386/libsys/sys_isreadyr.s b/plat/msdos386/libsys/sys_isreadyr.s new file mode 100644 index 000000000..9a646adc8 --- /dev/null +++ b/plat/msdos386/libsys/sys_isreadyr.s @@ -0,0 +1,29 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Say whether a file descriptor is ready for input, i.e. reading from the +! fd will immediately return something. + +.define __sys_isreadyr +__sys_isreadyr: + mov ebx, esp + mov eax, 0x4406 + mov ebx, 4(ebx) + int 0x21 + jnc ok + movb al, 0 +ok: + o16 cbw + cwde + ret diff --git a/plat/msdos386/libsys/sys_rawcreat.s b/plat/msdos386/libsys/sys_rawcreat.s new file mode 100644 index 000000000..b15df3f4f --- /dev/null +++ b/plat/msdos386/libsys/sys_rawcreat.s @@ -0,0 +1,45 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Create or truncate a file. + +.define __sys_rawcreat +__sys_rawcreat: + ! Copy filename to transfer buffer. + + mov ebx, esp + push esi + push edi + mov esi, 4(ebx) + movzx edi, (transfer_buffer_ptr) + mov es, (pmode_ds) + cld +1: + lodsb + stosb + testb al, al + jnz 1b + + ! Make the DOS call. + + movb ah, 0x3c + movzx edx, (transfer_buffer_ptr) + movb al, 8(ebx) + or ebx, 0x210000 + callf (interrupt_ptr) + + pop edi + pop esi + jmp .sys_axret + diff --git a/plat/msdos386/libsys/sys_rawlseek.s b/plat/msdos386/libsys/sys_rawlseek.s new file mode 100644 index 000000000..c38a1e0b1 --- /dev/null +++ b/plat/msdos386/libsys/sys_rawlseek.s @@ -0,0 +1,26 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Move the current file position for a file descriptor. + +.define __sys_rawlseek +__sys_rawlseek: + movb ah, 0x42 + mov ebx, esp + mov edx, 8(bx) + mov ecx, 12(bx) + movb al, 16(bx) + mov ebx, 4(bx) + int 0x21 + jmp .sys_dxaxret diff --git a/plat/msdos386/libsys/sys_rawopen.s b/plat/msdos386/libsys/sys_rawopen.s new file mode 100644 index 000000000..bb4ff5acb --- /dev/null +++ b/plat/msdos386/libsys/sys_rawopen.s @@ -0,0 +1,45 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Open an existing file. + +.define __sys_rawopen +__sys_rawopen: + ! Copy filename to transfer buffer. + + mov ebx, esp + push esi + push edi + + mov esi, 4(ebx) + movzx edi, (transfer_buffer_ptr) + mov es, (pmode_ds) + cld +1: + lodsb + stosb + testb al, al + jnz 1b + + ! Make the DOS call. + + movb ah, 0x3d + o16 mov dx, (transfer_buffer_ptr) + movb al, 8(ebx) + or ebx, 0x210000 + callf (interrupt_ptr) + + pop edi + pop esi + jmp .sys_axret diff --git a/plat/msdos386/libsys/sys_rawread.s b/plat/msdos386/libsys/sys_rawread.s new file mode 100644 index 000000000..f5b0c1a35 --- /dev/null +++ b/plat/msdos386/libsys/sys_rawread.s @@ -0,0 +1,74 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Read bytes from a file descriptor. These routines do not do any +! translation between CRLF and LF line endings. +! +! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate +! (or extend) the file to the current file position. + +.define __sys_rawread +__sys_rawread: + enter 0, 0 + push esi + push edi +file_handle = 2*4 +write_buffer = 3*4 +amount_to_read = 4*4 + + mov eax, amount_to_read(ebp) + mov ecx, 32*1024 + cmp eax, ecx + jge 2f + mov ecx, eax +2: + + ! Read from DOS into the transfer buffer. + + movb ah, 0x3f + o16 mov dx, (transfer_buffer_ptr) + o16 mov bx, file_handle(ebp) + or ebx, 0x210000 + callf (interrupt_ptr) + jnc success + + ! Process errors. + + push eax + call __sys_seterrno + pop ecx + jmp exit +success: + + ! Copy eax bytes out of the transfer buffer. + + push eax + mov ecx, eax + movzx esi, (transfer_buffer_ptr) + mov edi, write_buffer(ebp) + mov es, (pmode_ds) + cld +1: + eseg lodsb + movb (edi), al + inc edi + loop 1b + pop eax + +exit: + pop edi + pop esi + leave + ret + diff --git a/plat/msdos386/libsys/sys_rawwrite.s b/plat/msdos386/libsys/sys_rawwrite.s new file mode 100644 index 000000000..3ac3a7e16 --- /dev/null +++ b/plat/msdos386/libsys/sys_rawwrite.s @@ -0,0 +1,66 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Write bytes to/to a file descriptor. These routines do not do any +! translation between CRLF and LF line endings. +! +! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate +! (or extend) the file to the current file position. + +.define __sys_rawwrite +__sys_rawwrite: + enter 0, 0 + push esi + push edi +file_handle = 2*4 +read_buffer = 3*4 +amount_to_write = 4*4 + + mov eax, amount_to_write(ebp) + mov ecx, 32*1024 ! size of transfer buffer + cmp eax, ecx + jge 2f + mov ecx, eax +2: + + ! Copy ecx bytes into the transfer buffer. + + push ecx + mov esi, read_buffer(ebp) + movzx edi, (transfer_buffer_ptr) + mov es, (pmode_ds) + cld + rep movsb + pop ecx + + ! Write from the transfer buffer to DOS. + + movb ah, 0x40 + o16 mov dx, (transfer_buffer_ptr) + o16 mov bx, file_handle(ebp) + or ebx, 0x210000 + callf (interrupt_ptr) + jnc exit + + push eax + call __sys_seterrno + pop ecx +exit: + pop edi + pop esi + leave + ret + +! vim: sw=4 ts=4 et + diff --git a/plat/msdos386/libsys/sys_xret.s b/plat/msdos386/libsys/sys_xret.s new file mode 100644 index 000000000..20c2b454b --- /dev/null +++ b/plat/msdos386/libsys/sys_xret.s @@ -0,0 +1,50 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! .sys_zret: if the carry flag is set, then set `errno' from the DOS error +! code in ax, and return an int -1. If the carry flag is clear, just +! return an int zero. +! +! .sys_axret: if the carry flag is set, then set `errno' from the DOS error +! code in ax, and return a shortword -1. If the carry flag is clear, just +! return ax as a return value. +! +! .sys_dxaxret: same as .sys_axret, but return -1 or dx:ax as a return value. + +.extern .sys_zret +.extern .sys_axret +.extern .sys_dxaxret +.sys_zret: + jc error + xor eax, eax +no_error: + ret + +.sys_axret: + jc error + ret + +.sys_dxaxret: + jc error + shl edx, 16 + o16 mov dx, ax + mov eax, edx + ret + +error: + movzx eax, ax + push eax + call __sys_seterrno + pop ecx + ret diff --git a/plat/msdos386/libsys/unlink.s b/plat/msdos386/libsys/unlink.s new file mode 100644 index 000000000..7d023ad48 --- /dev/null +++ b/plat/msdos386/libsys/unlink.s @@ -0,0 +1,44 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Remove a file. + +.define _unlink +_unlink: + ! Copy filename to transfer buffer. + + mov ebx, esp + push esi + push edi + + mov esi, 4(ebx) + movzx edi, (transfer_buffer_ptr) + mov es, (pmode_ds) + cld +1: + lodsb + stosb + testb al, al + jnz 1b + + ! Make the DOS call. + + movzx edi, (transfer_buffer_ptr) + movb ah, 0x41 + or ebx, 0x210000 + callf (interrupt_ptr) + + pop edi + pop esi + jmp .sys_zret diff --git a/plat/msdos386/stub.s b/plat/msdos386/stub.s new file mode 100644 index 000000000..219d66470 --- /dev/null +++ b/plat/msdos386/stub.s @@ -0,0 +1,410 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text +.use16 +exe_header: + .data2 0x5a4d ! magic number + .data2 exe_last_page ! number of bytes in last loadable page + .data2 exe_text_pages ! 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 exe_ram_paras ! maximum RAM siz, in 16-byte paragraphs + .data2 0 ! initial SS, relative to program + .data2 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 + +exe_start: + ! On entry, DS=ES=PSP. Make DS=CS, so we're running in tiny mode. + + push cs + pop ds + mov (rseg), ds + mov (pspseg), es + + ! Ensure that at least two handles are available by blindly closing some. + + mov bx, 19 ! close handle + movb ah, 0x3e + int 0x21 + mov bx, 18 ! close handle + movb ah, 0x3e + int 0x21 + + ! Scan the environment to find the program name. + + eseg mov es, (0x2c) ! environment pointer segment from PSP + xor di, di + xorb al, al + mov cx, 0xffff + cld +1: + repne scasb ! find end of next string + eseg cmpb (di), 0 + jnz 1b +2: + add di, 3 + mov si, di + repne scasb + + ! es:si now points at the program name, and es:di at one past the end. + + mov cx, di + sub cx, si + sub sp, cx ! allocate space on stack + mov di, sp ! es:si source, ds:di dest +1: + eseg movb al, (si) + inc si + movb (di), al + inc di + cmpb al, 0 + jnz 1b + + ! Open the file. (0x5f) + + mov dx, sp + mov ax, 0x3d00 + int 0x21 + jc no_file + mov (fh), ax + add sp, cx ! don't need filename any more + + ! Get the file length (== text len). + + mov bx, ax + mov ax, 0x4202 + xor cx, cx ! high offset + xor dx, dx ! low offset + int 0x21 ! lseek + mov (pmemlen+0), ax + mov (pmemlen+2), dx + + ! Initialise DPMI. + + mov ax, 0x1687 + int 0x2f + or ax, ax + jnz no_dpmi + mov (pmode_switch+0), di ! write back PMODE switch routine + mov (pmode_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 (pmode_switch) + jc bad_dpmi + + ! We're now in protected mode. + + mov (psegcs), cs + mov (psegds), ds + + ! Allocate space for the code segment. + + mov ax, 0x0000 + mov cx, 1 + int 0x31 ! allocate LDT + jc bad_dpmi + mov es, ax + mov (psegcs32), ax + + mov cx, (pmemlen+0) + mov bx, (pmemlen+2) + mov ax, 0x0501 + int 0x31 ! allocate linear address + jc bad_dpmi + mov (pmemhandle+0), di + mov (pmemhandle+2), si + + mov dx, cx + mov cx, bx + mov bx, es + mov ax, 0x0007 + int 0x31 ! set segment base address + jc bad_dpmi + + mov bx, es + mov dx, (pmemlen+0) + mov cx, (pmemlen+2) + mov ax, 0x0008 + int 0x31 ! set segment limit + + mov cx, cs + and cx, 3 + shl cx, 5 + or cx, 0xc09b ! 32-bit, big, code, non-conforming, readable + mov bx, es + mov ax, 0x0009 + int 0x31 ! set descriptor access rights + + ! 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 + xor cx, cx ! high offset + mov dx, text_top ! low offset + int 0x21 ! lseek + + o32 xor edi, edi ! destination 32-bit register +1: + movb ah, 0x3f + mov bx, (fh) + mov cx, TRANSFER_BUFFER_SIZE + mov dx, transfer_buffer + o32 push edi + call int21 ! read up to 32kB into transfer buffer + o32 pop edi + cmp ax, 0 + je 2f + + o32 movzx ecx, ax ! number of bytes read + o32 mov esi, transfer_buffer + cld + o32 rep movsb + jmp 1b +2: + + ! Close the file. + + movb ah, 0x3e + mov bx, (fh) + int 0x21 ! close + + ! Jump to the new segment and enter 32-bit mode! + + o32 movzx eax, (psegcs) + o32 movzx ebx, (psegds) + o32 movzx ecx, (rseg) + o32 mov edx, realloc + o32 mov esi, interruptf + o32 mov edi, transfer_buffer + push es + pop ds + push es + push 0 + retf ! 19b + + ! 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, dosstack + 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 + o32 mov eax, (pmemlen) + 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 + +no_file: + mov si, no_file_msg + jmp exit_with_error + +no_dpmi: + mov si, no_dpmi_msg + ! fall through + +! Displays the message in si and exits. +! This uses a loop because from protected mode any interrupt which +! takes a pointer parameter requires special treatment. +exit_with_error: + movb dl, (si) + cmpb dl, 0 + je 1f + inc si + + movb ah, 2 + int 0x21 ! print character + jmp exit_with_error +1: + mov ax, 0x4cff + int 0x21 ! terminate with error code al + + ! Simulate DOS interrupt. +int21: + o32 or ebx, 0x210000 + ! Simulate interrupt in the high half of ebx. +interrupt: + mov (dpmi_eax), ax + mov (dpmi_ebx), bx + mov (dpmi_ecx), cx + mov (dpmi_edx), dx + mov (dpmi_esi), si + mov (dpmi_edi), di + mov ax, (rseg) + mov (dpmi_ds), ax + mov (dpmi_ss), ax + push es + mov (dpmi_sp), dosstack ! auto stack is too small + push ds + pop es + o32 mov edi, dpmi_edi + mov ax, 0x300 + o32 shr ebx, 16 + int 0x31 ! simulate DOS interrupt + pop es + o32 movzx eax, (dpmi_eax) + o32 movzx ebx, (dpmi_ebx) + o32 movzx ecx, (dpmi_ecx) + o32 movzx edx, (dpmi_edx) + o32 movzx esi, (dpmi_esi) + o32 movzx edi, (dpmi_edi) + push (dpmi_flags) + popf + ret + +! Far call wrapper around interrupt. +interruptf: + push ds + cseg mov ds, (psegds) + call interrupt + pop ds + o32 retf + +bad_dpmi_msg: + .asciz "DPMI error during setup" +no_file_msg: + .asciz "Couldn't open .exe" +no_dpmi_msg: + .asciz "No DPMI host installed" +.align 4 +text_top: + +exe_text_pages = [text_top - exe_header + 511] / 512 +exe_last_page = [text_top - exe_header] % 512 + +.sect .rom + +.sect .bss +bss_start: + +dpmi_edi: .space 4 +dpmi_esi: .space 4 +dpmi_ebp: .space 4 + .space 4 ! reserved +dpmi_ebx: .space 4 +dpmi_edx: .space 4 +dpmi_ecx: .space 4 +dpmi_eax: .space 4 +dpmi_flags: .space 2 +dpmi_es: .space 2 +dpmi_ds: .space 2 +dpmi_fs: .space 2 +dpmi_gs: .space 2 +dpmi_ip: .space 2 +dpmi_cs: .space 2 +dpmi_sp: .space 2 +dpmi_ss: .space 2 + +pmode_switch: .space 4 +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 + + .space 512 +stack: + .space 512 +dosstack: + +TRANSFER_BUFFER_SIZE = 32*1024 +transfer_buffer: + .space TRANSFER_BUFFER_SIZE + +bss_top: +exe_ram_paras = [bss_top - bss_start + 15] / 16 + +! vim: ts=4 sw=4 et ft=asm + diff --git a/plat/msdos86/descr b/plat/msdos86/descr index 333bb671b..2ef1724ee 100644 --- a/plat/msdos86/descr +++ b/plat/msdos86/descr @@ -84,5 +84,5 @@ name cv mapflag -i LOD=amzlod program {EM}/bin/{LOD} args < > - outfile msdos86.exe + outfile msdos86.com end diff --git a/plat/msdos86/libsys/build.lua b/plat/msdos86/libsys/build.lua index e39d90837..96988002d 100644 --- a/plat/msdos86/libsys/build.lua +++ b/plat/msdos86/libsys/build.lua @@ -3,42 +3,28 @@ acklibrary { srcs = { "./brk.c", "./close.s", - "./creat.c", "./errno.s", "./getpid.s", - "./gettimeofday.c", "./_hol0.s", "./isatty.s", - "./kill.c", - "./lseek.c", - "./open.c", - "./read.c", "./rename.s", - "./setmode.c", - "./signal.c", "./sys_exists.s", - "./sys_fdmodes.c", "./sys_getdate.s", - "./sys_getmode.c", "./sys_gettime.s", - "./sys_initmain.c", - "./sys_iseof.c", "./sys_isopen.s", "./sys_isreadyr.s", "./sys_rawcreat.s", "./sys_rawlseek.s", "./sys_rawopen.s", "./sys_rawrw.s", - "./sys_seteof.c", - "./sys_seterrno.c", - "./sys_setmode.c", "./sys_xret.s", "./unlink.s", - "./write.c", + "plat/msdos/libsys+srcs", }, deps = { "lang/cem/libcc.ansi/headers+headers", "plat/msdos86/include+headers", + "plat/msdos/libsys+headers", }, vars = { plat = "msdos86" diff --git a/plat/msdos86/libsys/write.c b/plat/msdos86/libsys/write.c deleted file mode 100644 index fc744b256..000000000 --- a/plat/msdos86/libsys/write.c +++ /dev/null @@ -1,61 +0,0 @@ -/* $Source$ - * $State$ - * $Revision$ - */ - -#include -#include -#include -#include -#include "libsys.h" - -ssize_t write(int fd, void* buffer, size_t count) -{ - static const char crlf[2] = "\r\n"; - int i; - char *p, *q; - size_t left, n; - ssize_t r, tot; - - if (!count) - return 0; - - if (_sys_getmode(fd) == O_BINARY) - return _sys_rawwrite(fd, buffer, count); - - /* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */ - p = buffer; - left = count; - tot = 0; - while (left) - { - q = memchr(p, '\n', left); - if (!q) - return _sys_rawwrite(fd, p, left); - - n = q - p; - if (n) - { - r = _sys_rawwrite(fd, p, n); - if (r <= 0) - return tot ? tot : r; - tot += r; - p += r; - left -= r; - if (r != n) - break; - } - - r = _sys_rawwrite(fd, crlf, sizeof crlf); - if (r != 2) - { - if (r > 0) - r = 0; - return tot ? tot : r; - } - ++tot; - ++p; - --left; - } - return tot; -} 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);