fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 247 lines 5.6 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/arch/dos/exec.c * 7 * Created: 2012-12-31 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2012-2015 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include "main.h" 24#include "dos.h" 25#include "dosmem.h" 26#include "exec.h" 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31 32 33static 34unsigned short get_uint16_le (const void *buf, unsigned addr) 35{ 36 const unsigned char *tmp = (const unsigned char *) buf + addr; 37 unsigned short ret; 38 39 ret = tmp[1]; 40 ret = (ret << 8) | tmp[0]; 41 42 return (ret); 43} 44 45static 46int sim_reloc_exe (dos_t *sim, FILE *fp, unsigned base, unsigned para, unsigned relofs, unsigned relcnt) 47{ 48 unsigned i; 49 unsigned short rseg, rofs, val; 50 unsigned char buf[4]; 51 52 if (fseek (fp, relofs, SEEK_SET)) { 53 return (1); 54 } 55 56 for (i = 0; i < relcnt; i++) { 57 if (fread (buf, 4, 1, fp) != 1) { 58 return (1); 59 } 60 61 rofs = ((unsigned) buf[1] << 8) | buf[0]; 62 rseg = ((unsigned) buf[3] << 8) | buf[2]; 63 64 val = sim_get_uint16 (sim, base + rseg, rofs); 65 val += base; 66 sim_set_uint16 (sim, base + rseg, rofs, val); 67 } 68 69 return (0); 70} 71 72static 73int sim_exec_exe (dos_t *sim, FILE *fp) 74{ 75 unsigned short para; 76 unsigned short size1, size2; 77 unsigned long size; 78 unsigned long imgsize, imgbase; 79 unsigned short relocofs, reloccnt; 80 unsigned short memmin, memmax; 81 unsigned long para_min, para_max; 82 unsigned short hsize; 83 unsigned short cs, ip, ss, sp; 84 unsigned char hdr[32]; 85 86 if (fread (hdr, 1, 32, fp) != 32) { 87 return (1); 88 } 89 90 if ((hdr[0] != 'M') || (hdr[1] != 'Z')) { 91 return (1); 92 } 93 94 size2 = get_uint16_le (hdr, 0x02); 95 size1 = get_uint16_le (hdr, 0x04); 96 reloccnt = get_uint16_le (hdr, 0x06); 97 hsize = get_uint16_le (hdr, 0x08); 98 memmin = get_uint16_le (hdr, 0x0a); 99 memmax = get_uint16_le (hdr, 0x0c); 100 ss = get_uint16_le (hdr, 0x0e); 101 sp = get_uint16_le (hdr, 0x10); 102 ip = get_uint16_le (hdr, 0x14); 103 cs = get_uint16_le (hdr, 0x16); 104 relocofs = get_uint16_le (hdr, 0x18); 105 106 size = 512UL * size1 - ((512 - size2) & 511); 107 para = (size + 15) >> 4; 108 imgbase = 16UL * hsize; 109 imgsize = size - imgbase; 110 111 para_min = para + 16UL + memmin; 112 para_max = para + 16UL + memmax; 113 114 if (para_min > 0xffff) { 115 para_min = 0xffff; 116 } 117 118 if (para_max > 0xffff) { 119 para_max = 0xffff; 120 } 121 122 sim->psp = sim_mem_alloc (sim, para_min, para_max); 123 124 if (sim->psp == 0) { 125 return (1); 126 } 127 128 if (fseek (fp, imgbase, SEEK_SET)) { 129 return (1); 130 } 131 132 if (fread (sim->mem + 16UL * sim->psp + 256, 1, imgsize, fp) != imgsize) { 133 return (1); 134 } 135 136 if (reloccnt > 0) { 137 if (sim_reloc_exe (sim, fp, sim->psp + 16, para, relocofs, reloccnt)) { 138 return (1); 139 } 140 } 141 142 cs += sim->psp + 16; 143 ss += sim->psp + 16; 144 145 e86_set_cs (&sim->cpu, cs); 146 e86_set_ip (&sim->cpu, ip); 147 e86_set_ss (&sim->cpu, ss); 148 e86_set_sp (&sim->cpu, sp); 149 150 e86_set_ds (&sim->cpu, sim->psp); 151 e86_set_es (&sim->cpu, sim->psp); 152 153 return (0); 154} 155 156static 157int sim_exec_com (dos_t *sim, FILE *fp) 158{ 159 unsigned long size; 160 unsigned short sp; 161 162 if (fseek (fp, 0, SEEK_END)) { 163 return (1); 164 } 165 166 size = ftell (fp); 167 168 rewind (fp); 169 170 if (size > (65536 - 512)) { 171 return (1); 172 } 173 174 sim->psp = sim_mem_alloc (sim, (size + 512 + 15) / 16, 0xffff); 175 176 if (sim->psp == 0) { 177 return (1); 178 } 179 180 if (fread (sim->mem + 16UL * sim->psp + 256, 1, size, fp) != size) { 181 return (1); 182 } 183 184 sp = sim_mem_get_size (sim, sim->psp); 185 sp = (sp < 0x1000) ? (sp << 4) : 0; 186 sp = (sp - 2) & 0xffff; 187 sim_set_uint16 (sim, sim->psp, sp, 0); 188 189 e86_set_cs (&sim->cpu, sim->psp); 190 e86_set_ip (&sim->cpu, 0x0100); 191 e86_set_ss (&sim->cpu, sim->psp); 192 e86_set_sp (&sim->cpu, sp); 193 194 e86_set_ds (&sim->cpu, sim->psp); 195 e86_set_es (&sim->cpu, sim->psp); 196 197 return (0); 198} 199 200int sim_exec (dos_t *sim, const char *name) 201{ 202 int r; 203 unsigned magic; 204 FILE *fp; 205 unsigned char buf[16]; 206 207 if ((fp = fopen (name, "rb")) == NULL) { 208 return (1); 209 } 210 211 if (fread (buf, 1, 16, fp) != 16) { 212 fclose (fp); 213 return (1); 214 } 215 216 rewind (fp); 217 218 e86_set_ax (&sim->cpu, 0); 219 e86_set_bx (&sim->cpu, 0); 220 e86_set_cx (&sim->cpu, 0); 221 e86_set_dx (&sim->cpu, 0); 222 e86_set_si (&sim->cpu, 0); 223 e86_set_di (&sim->cpu, 0); 224 e86_set_bp (&sim->cpu, 0); 225 226 magic = get_uint16_le (buf, 0); 227 228 if ((magic == 0x5a4d) || (magic == 0x4d5a)) { 229 r = sim_exec_exe (sim, fp); 230 } 231 else { 232 r = sim_exec_com (sim, fp); 233 } 234 235 fclose (fp); 236 237 if (r) { 238 return (1); 239 } 240 241 sim_init_psp (sim); 242 243 sim->dta[0] = 0x0080; 244 sim->dta[1] = sim->psp; 245 246 return (0); 247}