fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
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}