1 |
dpavlin |
36 |
/* |
2 |
|
|
* Copyright (C) 2003-2007 Anders Gavare. All rights reserved. |
3 |
|
|
* |
4 |
|
|
* Redistribution and use in source and binary forms, with or without |
5 |
|
|
* modification, are permitted provided that the following conditions are met: |
6 |
|
|
* |
7 |
|
|
* 1. Redistributions of source code must retain the above copyright |
8 |
|
|
* notice, this list of conditions and the following disclaimer. |
9 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
|
|
* notice, this list of conditions and the following disclaimer in the |
11 |
|
|
* documentation and/or other materials provided with the distribution. |
12 |
|
|
* 3. The name of the author may not be used to endorse or promote products |
13 |
|
|
* derived from this software without specific prior written permission. |
14 |
|
|
* |
15 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
|
|
* SUCH DAMAGE. |
26 |
|
|
* |
27 |
|
|
* |
28 |
dpavlin |
40 |
* $Id: diskimage.c,v 1.6 2007/04/28 09:19:52 debug Exp $ |
29 |
dpavlin |
36 |
* |
30 |
|
|
* Disk image support. |
31 |
|
|
* |
32 |
|
|
* TODO: diskimage_remove()? This would be useful for floppies in PC-style |
33 |
|
|
* machines, where disks may need to be swapped during boot etc. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
#include <stdio.h> |
37 |
|
|
#include <stdlib.h> |
38 |
|
|
#include <string.h> |
39 |
|
|
#include <unistd.h> |
40 |
|
|
#include <sys/types.h> |
41 |
|
|
#include <sys/stat.h> |
42 |
|
|
|
43 |
|
|
#include "cpu.h" |
44 |
|
|
#include "diskimage.h" |
45 |
|
|
#include "machine.h" |
46 |
|
|
#include "misc.h" |
47 |
|
|
|
48 |
|
|
|
49 |
|
|
/* #define debug fatal */ |
50 |
|
|
|
51 |
|
|
extern int single_step; |
52 |
|
|
|
53 |
|
|
static char *diskimage_types[] = DISKIMAGE_TYPES; |
54 |
|
|
|
55 |
|
|
|
56 |
|
|
/**************************************************************************/ |
57 |
|
|
|
58 |
|
|
/* |
59 |
|
|
* my_fseek(): |
60 |
|
|
* |
61 |
|
|
* A helper function, like fseek() but takes off_t. If the system has |
62 |
|
|
* fseeko, then that is used. Otherwise I try to fake off_t offsets here. |
63 |
|
|
* |
64 |
|
|
* The correct position is reached by seeking 2 billion bytes at a time |
65 |
|
|
* (or less). Note: This method is only used for SEEK_SET, for SEEK_CUR |
66 |
|
|
* and SEEK_END, normal fseek() is used! |
67 |
|
|
* |
68 |
|
|
* TODO: It seemed to work on Linux/i386, but not on Solaris/sparc (?). |
69 |
|
|
* Anyway, most modern systems have fseeko(), so it shouldn't be a problem. |
70 |
|
|
*/ |
71 |
|
|
static int my_fseek(FILE *f, off_t offset, int whence) |
72 |
|
|
{ |
73 |
|
|
#ifdef HACK_FSEEKO |
74 |
|
|
if (whence == SEEK_SET) { |
75 |
|
|
int res = 0; |
76 |
|
|
off_t curoff = 0; |
77 |
|
|
off_t cur_step; |
78 |
|
|
|
79 |
|
|
fseek(f, 0, SEEK_SET); |
80 |
|
|
while (curoff < offset) { |
81 |
|
|
/* How far to seek? */ |
82 |
|
|
cur_step = offset - curoff; |
83 |
|
|
if (cur_step > 2000000000) |
84 |
|
|
cur_step = 2000000000; |
85 |
|
|
res = fseek(f, cur_step, SEEK_CUR); |
86 |
|
|
if (res) |
87 |
|
|
return res; |
88 |
|
|
curoff += cur_step; |
89 |
|
|
} |
90 |
|
|
return 0; |
91 |
|
|
} else |
92 |
|
|
return fseek(f, offset, whence); |
93 |
|
|
#else |
94 |
|
|
return fseeko(f, offset, whence); |
95 |
|
|
#endif |
96 |
|
|
} |
97 |
|
|
|
98 |
|
|
|
99 |
|
|
/**************************************************************************/ |
100 |
|
|
|
101 |
|
|
|
102 |
|
|
/* |
103 |
dpavlin |
38 |
* diskimage_exist(): |
104 |
dpavlin |
36 |
* |
105 |
dpavlin |
38 |
* Returns 1 if the specified disk id (for a specific type) exists, 0 |
106 |
|
|
* otherwise. |
107 |
dpavlin |
36 |
*/ |
108 |
dpavlin |
38 |
int diskimage_exist(struct machine *machine, int id, int type) |
109 |
dpavlin |
36 |
{ |
110 |
dpavlin |
38 |
struct diskimage *d = machine->first_diskimage; |
111 |
dpavlin |
36 |
|
112 |
dpavlin |
38 |
while (d != NULL) { |
113 |
|
|
if (d->type == type && d->id == id) |
114 |
|
|
return 1; |
115 |
|
|
d = d->next; |
116 |
dpavlin |
36 |
} |
117 |
dpavlin |
38 |
return 0; |
118 |
dpavlin |
36 |
} |
119 |
|
|
|
120 |
|
|
|
121 |
|
|
/* |
122 |
dpavlin |
38 |
* diskimage_add_overlay(): |
123 |
dpavlin |
36 |
* |
124 |
dpavlin |
38 |
* Opens an overlay data file and its corresponding bitmap file, and adds |
125 |
|
|
* the overlay to a disk image. |
126 |
dpavlin |
36 |
*/ |
127 |
dpavlin |
38 |
void diskimage_add_overlay(struct diskimage *d, char *overlay_basename) |
128 |
dpavlin |
36 |
{ |
129 |
dpavlin |
38 |
struct diskimage_overlay overlay; |
130 |
|
|
size_t bitmap_name_len = strlen(overlay_basename) + 20; |
131 |
|
|
char *bitmap_name = malloc(bitmap_name_len); |
132 |
|
|
|
133 |
|
|
if (bitmap_name == NULL) { |
134 |
|
|
fprintf(stderr, "out of memory\n"); |
135 |
dpavlin |
36 |
exit(1); |
136 |
|
|
} |
137 |
dpavlin |
38 |
snprintf(bitmap_name, bitmap_name_len, "%s.map", overlay_basename); |
138 |
dpavlin |
36 |
|
139 |
dpavlin |
38 |
overlay.overlay_basename = strdup(overlay_basename); |
140 |
|
|
overlay.f_data = fopen(overlay_basename, d->writable? "r+" : "r"); |
141 |
|
|
if (overlay.f_data == NULL) { |
142 |
|
|
perror(overlay_basename); |
143 |
|
|
exit(1); |
144 |
|
|
} |
145 |
dpavlin |
36 |
|
146 |
dpavlin |
38 |
overlay.f_bitmap = fopen(bitmap_name, d->writable? "r+" : "r"); |
147 |
|
|
if (overlay.f_bitmap == NULL) { |
148 |
|
|
perror(bitmap_name); |
149 |
|
|
fprintf(stderr, "Please create the map file first.\n"); |
150 |
|
|
exit(1); |
151 |
dpavlin |
36 |
} |
152 |
|
|
|
153 |
dpavlin |
38 |
d->nr_of_overlays ++; |
154 |
|
|
d->overlays = realloc(d->overlays, sizeof(struct diskimage_overlay) |
155 |
|
|
* d->nr_of_overlays); |
156 |
|
|
if (d->overlays == NULL) { |
157 |
|
|
fprintf(stderr, "out of memory\n"); |
158 |
dpavlin |
36 |
exit(1); |
159 |
|
|
} |
160 |
|
|
|
161 |
dpavlin |
38 |
d->overlays[d->nr_of_overlays - 1] = overlay; |
162 |
dpavlin |
36 |
|
163 |
dpavlin |
38 |
free(bitmap_name); |
164 |
dpavlin |
36 |
} |
165 |
|
|
|
166 |
|
|
|
167 |
|
|
/* |
168 |
|
|
* diskimage_recalc_size(): |
169 |
|
|
* |
170 |
|
|
* Recalculate a disk's size by stat()-ing it. |
171 |
|
|
* d is assumed to be non-NULL. |
172 |
|
|
*/ |
173 |
dpavlin |
38 |
void diskimage_recalc_size(struct diskimage *d) |
174 |
dpavlin |
36 |
{ |
175 |
|
|
struct stat st; |
176 |
|
|
int res; |
177 |
|
|
off_t size = 0; |
178 |
|
|
|
179 |
|
|
res = stat(d->fname, &st); |
180 |
|
|
if (res) { |
181 |
|
|
fprintf(stderr, "[ diskimage_recalc_size(): could not stat " |
182 |
|
|
"'%s' ]\n", d->fname); |
183 |
|
|
return; |
184 |
|
|
} |
185 |
|
|
|
186 |
|
|
size = st.st_size; |
187 |
|
|
|
188 |
|
|
/* |
189 |
|
|
* TODO: CD-ROM devices, such as /dev/cd0c, how can one |
190 |
|
|
* check how much data is on that cd-rom without reading it? |
191 |
|
|
* For now, assume some large number, hopefully it will be |
192 |
|
|
* enough to hold any cd-rom image. |
193 |
|
|
*/ |
194 |
|
|
if (d->is_a_cdrom && size == 0) |
195 |
|
|
size = 762048000; |
196 |
|
|
|
197 |
|
|
d->total_size = size; |
198 |
|
|
d->ncyls = d->total_size / 1048576; |
199 |
|
|
|
200 |
|
|
/* TODO: There is a mismatch between d->ncyls and d->cylinders, |
201 |
|
|
SCSI-based stuff usually doesn't care. TODO: Fix this. */ |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
|
205 |
|
|
/* |
206 |
|
|
* diskimage_getsize(): |
207 |
|
|
* |
208 |
|
|
* Returns -1 if the specified disk id/type does not exists, otherwise |
209 |
|
|
* the size of the disk image is returned. |
210 |
|
|
*/ |
211 |
|
|
int64_t diskimage_getsize(struct machine *machine, int id, int type) |
212 |
|
|
{ |
213 |
|
|
struct diskimage *d = machine->first_diskimage; |
214 |
|
|
|
215 |
|
|
while (d != NULL) { |
216 |
|
|
if (d->type == type && d->id == id) |
217 |
|
|
return d->total_size; |
218 |
|
|
d = d->next; |
219 |
|
|
} |
220 |
|
|
return -1; |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
|
224 |
|
|
/* |
225 |
|
|
* diskimage_get_baseoffset(): |
226 |
|
|
* |
227 |
|
|
* Returns -1 if the specified disk id/type does not exists, otherwise |
228 |
|
|
* the base offset of the disk image is returned. |
229 |
|
|
*/ |
230 |
|
|
int64_t diskimage_get_baseoffset(struct machine *machine, int id, int type) |
231 |
|
|
{ |
232 |
|
|
struct diskimage *d = machine->first_diskimage; |
233 |
|
|
|
234 |
|
|
while (d != NULL) { |
235 |
|
|
if (d->type == type && d->id == id) |
236 |
|
|
return d->override_base_offset; |
237 |
|
|
d = d->next; |
238 |
|
|
} |
239 |
|
|
return -1; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
|
243 |
|
|
/* |
244 |
|
|
* diskimage_getchs(): |
245 |
|
|
* |
246 |
|
|
* Returns the current CHS values of a disk image. |
247 |
|
|
*/ |
248 |
|
|
void diskimage_getchs(struct machine *machine, int id, int type, |
249 |
|
|
int *c, int *h, int *s) |
250 |
|
|
{ |
251 |
|
|
struct diskimage *d = machine->first_diskimage; |
252 |
|
|
|
253 |
|
|
while (d != NULL) { |
254 |
|
|
if (d->type == type && d->id == id) { |
255 |
|
|
*c = d->cylinders; |
256 |
|
|
*h = d->heads; |
257 |
|
|
*s = d->sectors_per_track; |
258 |
|
|
return; |
259 |
|
|
} |
260 |
|
|
d = d->next; |
261 |
|
|
} |
262 |
|
|
fatal("diskimage_getchs(): disk id %i (type %i) not found?\n", |
263 |
|
|
id, diskimage_types[type]); |
264 |
|
|
exit(1); |
265 |
|
|
} |
266 |
|
|
|
267 |
|
|
|
268 |
|
|
/* |
269 |
|
|
* diskimage_access__cdrom(): |
270 |
|
|
* |
271 |
|
|
* This is a special-case function, called from diskimage__internal_access(). |
272 |
|
|
* On my FreeBSD 4.9 system, the cdrom device /dev/cd0c seems to not be able |
273 |
|
|
* to handle something like "fseek(512); fread(512);" but it handles |
274 |
|
|
* "fseek(2048); fread(512);" just fine. So, if diskimage__internal_access() |
275 |
|
|
* fails in reading a block of data, this function is called as an attempt to |
276 |
|
|
* align reads at 2048-byte sectors instead. |
277 |
|
|
* |
278 |
|
|
* (Ugly hack. TODO: how to solve this cleanly?) |
279 |
|
|
* |
280 |
|
|
* NOTE: Returns the number of bytes read, 0 if nothing was successfully |
281 |
|
|
* read. (These are not the same as diskimage_access()). |
282 |
|
|
*/ |
283 |
|
|
#define CDROM_SECTOR_SIZE 2048 |
284 |
|
|
static size_t diskimage_access__cdrom(struct diskimage *d, off_t offset, |
285 |
|
|
unsigned char *buf, size_t len) |
286 |
|
|
{ |
287 |
|
|
off_t aligned_offset; |
288 |
|
|
size_t bytes_read, total_copied = 0; |
289 |
|
|
unsigned char cdrom_buf[CDROM_SECTOR_SIZE]; |
290 |
|
|
off_t buf_ofs, i = 0; |
291 |
|
|
|
292 |
|
|
/* printf("diskimage_access__cdrom(): offset=0x%llx size=%lli\n", |
293 |
|
|
(long long)offset, (long long)len); */ |
294 |
|
|
|
295 |
|
|
aligned_offset = (offset / CDROM_SECTOR_SIZE) * CDROM_SECTOR_SIZE; |
296 |
|
|
my_fseek(d->f, aligned_offset, SEEK_SET); |
297 |
|
|
|
298 |
|
|
while (len != 0) { |
299 |
|
|
bytes_read = fread(cdrom_buf, 1, CDROM_SECTOR_SIZE, d->f); |
300 |
|
|
if (bytes_read != CDROM_SECTOR_SIZE) |
301 |
|
|
return 0; |
302 |
|
|
|
303 |
|
|
/* Copy (part of) cdrom_buf into buf: */ |
304 |
|
|
buf_ofs = offset - aligned_offset; |
305 |
|
|
while (buf_ofs < CDROM_SECTOR_SIZE && len != 0) { |
306 |
|
|
buf[i ++] = cdrom_buf[buf_ofs ++]; |
307 |
|
|
total_copied ++; |
308 |
|
|
len --; |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
aligned_offset += CDROM_SECTOR_SIZE; |
312 |
|
|
offset = aligned_offset; |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
return total_copied; |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
|
319 |
dpavlin |
38 |
/* Helper function. */ |
320 |
|
|
static void overlay_set_block_in_use(struct diskimage *d, |
321 |
|
|
int overlay_nr, off_t ofs) |
322 |
dpavlin |
36 |
{ |
323 |
dpavlin |
38 |
off_t bit_nr = ofs / OVERLAY_BLOCK_SIZE; |
324 |
|
|
off_t bitmap_file_offset = bit_nr / 8; |
325 |
dpavlin |
36 |
int res; |
326 |
dpavlin |
38 |
unsigned char data; |
327 |
dpavlin |
36 |
|
328 |
dpavlin |
38 |
res = my_fseek(d->overlays[overlay_nr].f_bitmap, |
329 |
|
|
bitmap_file_offset, SEEK_SET); |
330 |
|
|
if (res) { |
331 |
|
|
perror("my_fseek"); |
332 |
|
|
fprintf(stderr, "Could not seek in bitmap file?" |
333 |
|
|
" offset = %lli, read\n", (long long)bitmap_file_offset); |
334 |
dpavlin |
36 |
exit(1); |
335 |
|
|
} |
336 |
|
|
|
337 |
dpavlin |
38 |
/* Read the original bitmap data, and OR in the new bit: */ |
338 |
|
|
res = fread(&data, 1, 1, d->overlays[overlay_nr].f_bitmap); |
339 |
|
|
if (res != 1) |
340 |
|
|
data = 0x00; |
341 |
dpavlin |
36 |
|
342 |
dpavlin |
38 |
data |= (1 << (bit_nr & 7)); |
343 |
dpavlin |
36 |
|
344 |
dpavlin |
38 |
/* Write it back: */ |
345 |
|
|
res = my_fseek(d->overlays[overlay_nr].f_bitmap, |
346 |
|
|
bitmap_file_offset, SEEK_SET); |
347 |
|
|
if (res) { |
348 |
|
|
perror("my_fseek"); |
349 |
|
|
fprintf(stderr, "Could not seek in bitmap file?" |
350 |
|
|
" offset = %lli, write\n", (long long)bitmap_file_offset); |
351 |
|
|
exit(1); |
352 |
dpavlin |
36 |
} |
353 |
dpavlin |
38 |
res = fwrite(&data, 1, 1, d->overlays[overlay_nr].f_bitmap); |
354 |
|
|
if (res != 1) { |
355 |
|
|
fprintf(stderr, "Could not write to bitmap file. Aborting.\n"); |
356 |
|
|
exit(1); |
357 |
dpavlin |
36 |
} |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
|
361 |
dpavlin |
38 |
/* Helper function. */ |
362 |
|
|
static int overlay_has_block(struct diskimage *d, int overlay_nr, off_t ofs) |
363 |
dpavlin |
36 |
{ |
364 |
dpavlin |
38 |
off_t bit_nr = ofs / OVERLAY_BLOCK_SIZE; |
365 |
|
|
off_t bitmap_file_offset = bit_nr / 8; |
366 |
|
|
int res; |
367 |
|
|
unsigned char data; |
368 |
dpavlin |
36 |
|
369 |
dpavlin |
38 |
res = my_fseek(d->overlays[overlay_nr].f_bitmap, |
370 |
|
|
bitmap_file_offset, SEEK_SET); |
371 |
|
|
if (res != 0) |
372 |
dpavlin |
36 |
return 0; |
373 |
|
|
|
374 |
dpavlin |
38 |
/* The seek succeeded, now read the bit: */ |
375 |
|
|
res = fread(&data, 1, 1, d->overlays[overlay_nr].f_bitmap); |
376 |
|
|
if (res != 1) |
377 |
dpavlin |
36 |
return 0; |
378 |
|
|
|
379 |
dpavlin |
38 |
if (data & (1 << (bit_nr & 7))) |
380 |
|
|
return 1; |
381 |
dpavlin |
36 |
|
382 |
dpavlin |
38 |
return 0; |
383 |
|
|
} |
384 |
dpavlin |
36 |
|
385 |
|
|
|
386 |
dpavlin |
38 |
/* |
387 |
|
|
* fwrite_helper(): |
388 |
|
|
* |
389 |
|
|
* Internal helper function. Writes to a disk image file, or if the |
390 |
|
|
* disk image has overlays, to the last overlay. |
391 |
|
|
*/ |
392 |
|
|
static size_t fwrite_helper(off_t offset, unsigned char *buf, |
393 |
|
|
size_t len, struct diskimage *d) |
394 |
dpavlin |
36 |
{ |
395 |
dpavlin |
38 |
off_t curofs; |
396 |
dpavlin |
36 |
|
397 |
dpavlin |
38 |
/* Fast return-path for the case when no overlays are used: */ |
398 |
|
|
if (d->nr_of_overlays == 0) { |
399 |
|
|
int res = my_fseek(d->f, offset, SEEK_SET); |
400 |
|
|
if (res != 0) { |
401 |
|
|
fatal("[ diskimage__internal_access(): fseek() failed" |
402 |
|
|
" on disk id %i \n", d->id); |
403 |
|
|
return 0; |
404 |
dpavlin |
36 |
} |
405 |
|
|
|
406 |
dpavlin |
38 |
return fwrite(buf, 1, len, d->f); |
407 |
|
|
} |
408 |
dpavlin |
36 |
|
409 |
dpavlin |
38 |
if ((len & (OVERLAY_BLOCK_SIZE-1)) != 0) { |
410 |
|
|
fatal("TODO: overlay access (write), len not multiple of " |
411 |
|
|
"overlay block size. not yet implemented.\n"); |
412 |
|
|
fatal("len = %lli\n", (long long) len); |
413 |
|
|
abort(); |
414 |
|
|
} |
415 |
|
|
if ((offset & (OVERLAY_BLOCK_SIZE-1)) != 0) { |
416 |
|
|
fatal("TODO: unaligned overlay access\n"); |
417 |
|
|
fatal("offset = %lli\n", (long long) offset); |
418 |
|
|
abort(); |
419 |
|
|
} |
420 |
dpavlin |
36 |
|
421 |
dpavlin |
38 |
/* Split the write into OVERLAY_BLOCK_SIZE writes: */ |
422 |
dpavlin |
40 |
for (curofs = offset; curofs < (off_t) (offset+len); |
423 |
|
|
curofs += OVERLAY_BLOCK_SIZE) { |
424 |
dpavlin |
38 |
/* Always write to the last overlay: */ |
425 |
|
|
int overlay_nr = d->nr_of_overlays-1; |
426 |
|
|
off_t lenwritten; |
427 |
|
|
int res = my_fseek(d->overlays[overlay_nr].f_data, |
428 |
|
|
curofs, SEEK_SET); |
429 |
|
|
if (res != 0) { |
430 |
|
|
fatal("[ diskimage__internal_access(): fseek()" |
431 |
|
|
" failed on disk id %i \n", d->id); |
432 |
|
|
return 0; |
433 |
dpavlin |
36 |
} |
434 |
|
|
|
435 |
dpavlin |
38 |
lenwritten = fwrite(buf, 1, OVERLAY_BLOCK_SIZE, |
436 |
|
|
d->overlays[overlay_nr].f_data); |
437 |
|
|
buf += OVERLAY_BLOCK_SIZE; |
438 |
dpavlin |
36 |
|
439 |
dpavlin |
38 |
/* Mark this block in the last overlay as in use: */ |
440 |
|
|
overlay_set_block_in_use(d, overlay_nr, curofs); |
441 |
|
|
} |
442 |
dpavlin |
36 |
|
443 |
dpavlin |
38 |
return len; |
444 |
|
|
} |
445 |
dpavlin |
36 |
|
446 |
|
|
|
447 |
dpavlin |
38 |
/* |
448 |
|
|
* fread_helper(): |
449 |
|
|
* |
450 |
|
|
* Internal helper function. Reads from a disk image file, or if the |
451 |
|
|
* disk image has overlays, from the last overlay that has the specific |
452 |
|
|
* data (or the disk image file itself). |
453 |
|
|
*/ |
454 |
|
|
static size_t fread_helper(off_t offset, unsigned char *buf, |
455 |
|
|
size_t len, struct diskimage *d) |
456 |
|
|
{ |
457 |
|
|
off_t curofs; |
458 |
|
|
size_t totallenread = 0; |
459 |
dpavlin |
36 |
|
460 |
dpavlin |
38 |
/* Fast return-path for the case when no overlays are used: */ |
461 |
|
|
if (d->nr_of_overlays == 0) { |
462 |
|
|
int res = my_fseek(d->f, offset, SEEK_SET); |
463 |
|
|
if (res != 0) { |
464 |
|
|
fatal("[ diskimage__internal_access(): fseek() failed" |
465 |
|
|
" on disk id %i \n", d->id); |
466 |
|
|
return 0; |
467 |
dpavlin |
36 |
} |
468 |
|
|
|
469 |
dpavlin |
38 |
return fread(buf, 1, len, d->f); |
470 |
|
|
} |
471 |
dpavlin |
36 |
|
472 |
dpavlin |
38 |
/* Split the read into OVERLAY_BLOCK_SIZE reads: */ |
473 |
|
|
for (curofs=offset; len != 0; |
474 |
|
|
curofs = (curofs | (OVERLAY_BLOCK_SIZE-1)) + 1) { |
475 |
|
|
/* Find the overlay, if any, that has this block: */ |
476 |
|
|
off_t lenread, lentoread; |
477 |
|
|
int overlay_nr; |
478 |
|
|
for (overlay_nr = d->nr_of_overlays-1; |
479 |
|
|
overlay_nr >= 0; overlay_nr --) { |
480 |
|
|
if (overlay_has_block(d, overlay_nr, curofs)) |
481 |
|
|
break; |
482 |
dpavlin |
36 |
} |
483 |
|
|
|
484 |
dpavlin |
38 |
lentoread = len > OVERLAY_BLOCK_SIZE? OVERLAY_BLOCK_SIZE : len; |
485 |
dpavlin |
36 |
|
486 |
dpavlin |
38 |
if (overlay_nr >= 0) { |
487 |
|
|
/* Read from overlay: */ |
488 |
|
|
int res = my_fseek(d->overlays[overlay_nr].f_data, |
489 |
|
|
curofs, SEEK_SET); |
490 |
|
|
if (res != 0) { |
491 |
|
|
fatal("[ diskimage__internal_access(): fseek()" |
492 |
|
|
" failed on disk id %i \n", d->id); |
493 |
|
|
return 0; |
494 |
dpavlin |
36 |
} |
495 |
dpavlin |
38 |
lenread = fread(buf, 1, lentoread, |
496 |
|
|
d->overlays[overlay_nr].f_data); |
497 |
dpavlin |
36 |
} else { |
498 |
dpavlin |
38 |
/* Read from the base disk image: */ |
499 |
|
|
int res = my_fseek(d->f, curofs, SEEK_SET); |
500 |
|
|
if (res != 0) { |
501 |
|
|
fatal("[ diskimage__internal_access(): fseek()" |
502 |
|
|
" failed on disk id %i \n", d->id); |
503 |
|
|
return 0; |
504 |
dpavlin |
36 |
} |
505 |
dpavlin |
38 |
lenread = fread(buf, 1, lentoread, d->f); |
506 |
dpavlin |
36 |
} |
507 |
|
|
|
508 |
dpavlin |
38 |
if (lenread != lentoread) { |
509 |
|
|
fatal("[ INCOMPLETE READ from disk id %i, offset" |
510 |
|
|
" %lli ]\n", d->id, (long long)curofs); |
511 |
dpavlin |
36 |
} |
512 |
|
|
|
513 |
dpavlin |
38 |
len -= lentoread; |
514 |
|
|
totallenread += lenread; |
515 |
|
|
buf += OVERLAY_BLOCK_SIZE; |
516 |
|
|
} |
517 |
dpavlin |
36 |
|
518 |
dpavlin |
38 |
return totallenread; |
519 |
|
|
} |
520 |
dpavlin |
36 |
|
521 |
|
|
|
522 |
dpavlin |
38 |
/* |
523 |
|
|
* diskimage__internal_access(): |
524 |
|
|
* |
525 |
|
|
* Read from or write to a struct diskimage. |
526 |
|
|
* |
527 |
|
|
* Returns 1 if the access completed successfully, 0 otherwise. |
528 |
|
|
*/ |
529 |
|
|
int diskimage__internal_access(struct diskimage *d, int writeflag, |
530 |
|
|
off_t offset, unsigned char *buf, size_t len) |
531 |
|
|
{ |
532 |
|
|
ssize_t lendone; |
533 |
dpavlin |
36 |
|
534 |
dpavlin |
38 |
if (buf == NULL) { |
535 |
|
|
fprintf(stderr, "diskimage__internal_access(): buf = NULL\n"); |
536 |
|
|
exit(1); |
537 |
|
|
} |
538 |
|
|
if (len == 0) |
539 |
|
|
return 1; |
540 |
|
|
if (d->f == NULL) |
541 |
|
|
return 0; |
542 |
dpavlin |
36 |
|
543 |
dpavlin |
38 |
if (writeflag) { |
544 |
|
|
if (!d->writable) |
545 |
|
|
return 0; |
546 |
dpavlin |
36 |
|
547 |
dpavlin |
38 |
lendone = fwrite_helper(offset, buf, len, d); |
548 |
|
|
} else { |
549 |
dpavlin |
36 |
/* |
550 |
dpavlin |
38 |
* Special case for CD-ROMs. Actually, this is not needed |
551 |
|
|
* for .iso images, only for physical CDROMS on some OSes, |
552 |
|
|
* such as FreeBSD. |
553 |
dpavlin |
36 |
*/ |
554 |
dpavlin |
38 |
if (d->is_a_cdrom) |
555 |
|
|
lendone = diskimage_access__cdrom(d, offset, buf, len); |
556 |
|
|
else |
557 |
|
|
lendone = fread_helper(offset, buf, len, d); |
558 |
dpavlin |
36 |
|
559 |
dpavlin |
38 |
if (lendone < (ssize_t)len) |
560 |
|
|
memset(buf + lendone, 0, len - lendone); |
561 |
|
|
} |
562 |
dpavlin |
36 |
|
563 |
dpavlin |
38 |
/* Incomplete data transfer? Then return failure: */ |
564 |
|
|
if (lendone != (ssize_t)len) { |
565 |
|
|
#ifdef UNSTABLE_DEVEL |
566 |
|
|
fatal |
567 |
|
|
#else |
568 |
|
|
debug |
569 |
|
|
#endif |
570 |
|
|
("[ diskimage__internal_access(): disk_id %i, offset %lli" |
571 |
|
|
", transfer not completed. len=%i, len_done=%i ]\n", |
572 |
|
|
d->id, (long long)offset, (int)len, (int)lendone); |
573 |
|
|
return 0; |
574 |
dpavlin |
36 |
} |
575 |
|
|
|
576 |
|
|
return 1; |
577 |
|
|
} |
578 |
|
|
|
579 |
|
|
|
580 |
|
|
/* |
581 |
|
|
* diskimage_access(): |
582 |
|
|
* |
583 |
|
|
* Read from or write to a disk image on a machine. |
584 |
|
|
* |
585 |
|
|
* Returns 1 if the access completed successfully, 0 otherwise. |
586 |
|
|
*/ |
587 |
|
|
int diskimage_access(struct machine *machine, int id, int type, int writeflag, |
588 |
|
|
off_t offset, unsigned char *buf, size_t len) |
589 |
|
|
{ |
590 |
|
|
struct diskimage *d = machine->first_diskimage; |
591 |
|
|
|
592 |
|
|
while (d != NULL) { |
593 |
|
|
if (d->type == type && d->id == id) |
594 |
|
|
break; |
595 |
|
|
d = d->next; |
596 |
|
|
} |
597 |
|
|
|
598 |
|
|
if (d == NULL) { |
599 |
|
|
fatal("[ diskimage_access(): ERROR: trying to access a " |
600 |
|
|
"non-existant %s disk image (id %i)\n", |
601 |
|
|
diskimage_types[type], id); |
602 |
|
|
return 0; |
603 |
|
|
} |
604 |
|
|
|
605 |
|
|
offset -= d->override_base_offset; |
606 |
|
|
if (offset < 0 && offset + d->override_base_offset >= 0) { |
607 |
|
|
debug("[ reading before start of disk image ]\n"); |
608 |
|
|
/* Returning zeros. */ |
609 |
|
|
memset(buf, 0, len); |
610 |
|
|
return 1; |
611 |
|
|
} |
612 |
|
|
|
613 |
|
|
return diskimage__internal_access(d, writeflag, offset, buf, len); |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
|
617 |
|
|
/* |
618 |
|
|
* diskimage_add(): |
619 |
|
|
* |
620 |
|
|
* Add a disk image. fname is the filename of the disk image. |
621 |
|
|
* The filename may be prefixed with one or more modifiers, followed |
622 |
|
|
* by a colon. |
623 |
|
|
* |
624 |
|
|
* b specifies that this is a bootable device |
625 |
|
|
* c CD-ROM (instead of a normal DISK) |
626 |
|
|
* d DISK (this is the default) |
627 |
|
|
* f FLOPPY (instead of SCSI) |
628 |
|
|
* gH;S; set geometry (H=heads, S=sectors per track, cylinders are |
629 |
|
|
* automatically calculated). (This is ignored for floppies.) |
630 |
|
|
* i IDE (instead of SCSI) |
631 |
|
|
* oOFS; set base offset in bytes, when booting from an ISO9660 fs |
632 |
|
|
* r read-only (don't allow changes to the file) |
633 |
|
|
* s SCSI (this is the default) |
634 |
|
|
* t tape |
635 |
dpavlin |
38 |
* V add an overlay to a disk image |
636 |
dpavlin |
36 |
* 0-7 force a specific SCSI ID number |
637 |
|
|
* |
638 |
|
|
* machine is assumed to be non-NULL. |
639 |
|
|
* Returns an integer >= 0 identifying the disk image. |
640 |
|
|
*/ |
641 |
|
|
int diskimage_add(struct machine *machine, char *fname) |
642 |
|
|
{ |
643 |
|
|
struct diskimage *d, *d2; |
644 |
|
|
int id = 0, override_heads=0, override_spt=0; |
645 |
|
|
int64_t bytespercyl, override_base_offset=0; |
646 |
|
|
char *cp; |
647 |
|
|
int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0; |
648 |
|
|
int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id=-1; |
649 |
dpavlin |
38 |
int prefix_o=0, prefix_V=0; |
650 |
dpavlin |
36 |
|
651 |
|
|
if (fname == NULL) { |
652 |
|
|
fprintf(stderr, "diskimage_add(): NULL ptr\n"); |
653 |
|
|
return 0; |
654 |
|
|
} |
655 |
|
|
|
656 |
|
|
/* Get prefix from fname: */ |
657 |
|
|
cp = strchr(fname, ':'); |
658 |
|
|
if (cp != NULL) { |
659 |
|
|
while (fname <= cp) { |
660 |
|
|
char c = *fname++; |
661 |
|
|
switch (c) { |
662 |
|
|
case '0': |
663 |
|
|
case '1': |
664 |
|
|
case '2': |
665 |
|
|
case '3': |
666 |
|
|
case '4': |
667 |
|
|
case '5': |
668 |
|
|
case '6': |
669 |
|
|
case '7': |
670 |
|
|
prefix_id = c - '0'; |
671 |
|
|
break; |
672 |
|
|
case 'b': |
673 |
|
|
prefix_b = 1; |
674 |
|
|
break; |
675 |
|
|
case 'c': |
676 |
|
|
prefix_c = 1; |
677 |
|
|
break; |
678 |
|
|
case 'd': |
679 |
|
|
prefix_d = 1; |
680 |
|
|
break; |
681 |
|
|
case 'f': |
682 |
|
|
prefix_f = 1; |
683 |
|
|
break; |
684 |
|
|
case 'g': |
685 |
|
|
prefix_g = 1; |
686 |
|
|
override_heads = atoi(fname); |
687 |
|
|
while (*fname != '\0' && *fname != ';') |
688 |
|
|
fname ++; |
689 |
|
|
if (*fname == ';') |
690 |
|
|
fname ++; |
691 |
|
|
override_spt = atoi(fname); |
692 |
|
|
while (*fname != '\0' && *fname != ';' && |
693 |
|
|
*fname != ':') |
694 |
|
|
fname ++; |
695 |
|
|
if (*fname == ';') |
696 |
|
|
fname ++; |
697 |
|
|
if (override_heads < 1 || |
698 |
|
|
override_spt < 1) { |
699 |
|
|
fatal("Bad geometry: heads=%i " |
700 |
|
|
"spt=%i\n", override_heads, |
701 |
|
|
override_spt); |
702 |
|
|
exit(1); |
703 |
|
|
} |
704 |
|
|
break; |
705 |
|
|
case 'i': |
706 |
|
|
prefix_i = 1; |
707 |
|
|
break; |
708 |
|
|
case 'o': |
709 |
|
|
prefix_o = 1; |
710 |
|
|
override_base_offset = atoi(fname); |
711 |
|
|
while (*fname != '\0' && *fname != ':' |
712 |
|
|
&& *fname != ';') |
713 |
|
|
fname ++; |
714 |
|
|
if (*fname == ':' || *fname == ';') |
715 |
|
|
fname ++; |
716 |
|
|
if (override_base_offset < 0) { |
717 |
|
|
fatal("Bad base offset: %"PRIi64 |
718 |
|
|
"\n", override_base_offset); |
719 |
|
|
exit(1); |
720 |
|
|
} |
721 |
|
|
break; |
722 |
|
|
case 'r': |
723 |
|
|
prefix_r = 1; |
724 |
|
|
break; |
725 |
|
|
case 's': |
726 |
|
|
prefix_s = 1; |
727 |
|
|
break; |
728 |
|
|
case 't': |
729 |
|
|
prefix_t = 1; |
730 |
|
|
break; |
731 |
dpavlin |
38 |
case 'V': |
732 |
|
|
prefix_V = 1; |
733 |
|
|
break; |
734 |
dpavlin |
36 |
case ':': |
735 |
|
|
break; |
736 |
|
|
default: |
737 |
|
|
fprintf(stderr, "diskimage_add(): invalid " |
738 |
|
|
"prefix char '%c'\n", c); |
739 |
|
|
exit(1); |
740 |
|
|
} |
741 |
|
|
} |
742 |
|
|
} |
743 |
|
|
|
744 |
|
|
/* Allocate a new diskimage struct: */ |
745 |
|
|
d = malloc(sizeof(struct diskimage)); |
746 |
|
|
if (d == NULL) { |
747 |
|
|
fprintf(stderr, "out of memory in diskimage_add()\n"); |
748 |
|
|
exit(1); |
749 |
|
|
} |
750 |
|
|
memset(d, 0, sizeof(struct diskimage)); |
751 |
|
|
|
752 |
|
|
/* Default to IDE disks... */ |
753 |
|
|
d->type = DISKIMAGE_IDE; |
754 |
|
|
|
755 |
|
|
/* ... but some machines use SCSI by default: */ |
756 |
|
|
if (machine->machine_type == MACHINE_PMAX || |
757 |
|
|
machine->machine_type == MACHINE_ARC) |
758 |
|
|
d->type = DISKIMAGE_SCSI; |
759 |
|
|
|
760 |
|
|
if (prefix_i + prefix_f + prefix_s > 1) { |
761 |
|
|
fprintf(stderr, "Invalid disk image prefix(es). You can" |
762 |
|
|
"only use one of i, f, and s\nfor each disk image.\n"); |
763 |
|
|
exit(1); |
764 |
|
|
} |
765 |
|
|
|
766 |
|
|
if (prefix_i) |
767 |
|
|
d->type = DISKIMAGE_IDE; |
768 |
|
|
if (prefix_f) |
769 |
|
|
d->type = DISKIMAGE_FLOPPY; |
770 |
|
|
if (prefix_s) |
771 |
|
|
d->type = DISKIMAGE_SCSI; |
772 |
|
|
|
773 |
dpavlin |
38 |
/* Special case: Add an overlay for an already added disk image: */ |
774 |
|
|
if (prefix_V) { |
775 |
|
|
struct diskimage *dx = machine->first_diskimage; |
776 |
|
|
|
777 |
|
|
if (prefix_id < 0) { |
778 |
|
|
fprintf(stderr, "The 'V' disk image prefix requires" |
779 |
|
|
" a disk ID to also be supplied.\n"); |
780 |
|
|
exit(1); |
781 |
|
|
} |
782 |
|
|
|
783 |
|
|
while (dx != NULL) { |
784 |
|
|
if (d->type == dx->type && prefix_id == dx->id) |
785 |
|
|
break; |
786 |
|
|
dx = dx->next; |
787 |
|
|
} |
788 |
|
|
|
789 |
|
|
if (dx == NULL) { |
790 |
|
|
fprintf(stderr, "Bad ID supplied for overlay?\n"); |
791 |
|
|
exit(1); |
792 |
|
|
} |
793 |
|
|
|
794 |
|
|
diskimage_add_overlay(dx, fname); |
795 |
|
|
|
796 |
|
|
/* Free the preliminary d struct: */ |
797 |
|
|
free(d); |
798 |
|
|
|
799 |
|
|
/* Don't add any disk image. This is an overlay! */ |
800 |
|
|
return -1; |
801 |
|
|
} |
802 |
|
|
|
803 |
|
|
/* Add the new disk image in the disk image chain: */ |
804 |
|
|
d2 = machine->first_diskimage; |
805 |
|
|
if (d2 == NULL) { |
806 |
|
|
machine->first_diskimage = d; |
807 |
|
|
} else { |
808 |
|
|
while (d2->next != NULL) |
809 |
|
|
d2 = d2->next; |
810 |
|
|
d2->next = d; |
811 |
|
|
} |
812 |
|
|
|
813 |
dpavlin |
36 |
if (prefix_o) |
814 |
|
|
d->override_base_offset = override_base_offset; |
815 |
|
|
|
816 |
|
|
d->fname = strdup(fname); |
817 |
|
|
if (d->fname == NULL) { |
818 |
|
|
fprintf(stderr, "out of memory\n"); |
819 |
|
|
exit(1); |
820 |
|
|
} |
821 |
|
|
|
822 |
|
|
d->logical_block_size = 512; |
823 |
|
|
|
824 |
|
|
/* |
825 |
|
|
* Is this a tape, CD-ROM or a normal disk? |
826 |
|
|
* |
827 |
|
|
* An intelligent guess, if no prefixes are used, would be that |
828 |
|
|
* filenames ending with .iso or .cdr are CD-ROM images. |
829 |
|
|
*/ |
830 |
|
|
if (prefix_t) { |
831 |
|
|
d->is_a_tape = 1; |
832 |
|
|
} else { |
833 |
|
|
if (prefix_c || |
834 |
|
|
((strlen(d->fname) > 4 && |
835 |
|
|
(strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 || |
836 |
|
|
strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0)) |
837 |
|
|
&& !prefix_d) |
838 |
|
|
) { |
839 |
|
|
d->is_a_cdrom = 1; |
840 |
|
|
|
841 |
|
|
/* |
842 |
|
|
* This is tricky. Should I use 512 or 2048 here? |
843 |
|
|
* NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes |
844 |
|
|
* per sector, but NetBSD 2.0_BETA suddenly ignores |
845 |
|
|
* this value and uses 2048 instead. |
846 |
|
|
* |
847 |
|
|
* OpenBSD/arc doesn't like 2048, it requires 512 |
848 |
|
|
* to work correctly. |
849 |
|
|
* |
850 |
|
|
* TODO |
851 |
|
|
*/ |
852 |
|
|
|
853 |
|
|
#if 0 |
854 |
|
|
if (machine->machine_type == MACHINE_PMAX) |
855 |
|
|
d->logical_block_size = 512; |
856 |
|
|
else |
857 |
|
|
d->logical_block_size = 2048; |
858 |
|
|
#endif |
859 |
|
|
d->logical_block_size = 512; |
860 |
|
|
} |
861 |
|
|
} |
862 |
|
|
|
863 |
|
|
diskimage_recalc_size(d); |
864 |
|
|
|
865 |
|
|
if ((d->total_size == 720*1024 || d->total_size == 1474560 |
866 |
|
|
|| d->total_size == 2949120 || d->total_size == 1228800) |
867 |
|
|
&& !prefix_i && !prefix_s) |
868 |
|
|
d->type = DISKIMAGE_FLOPPY; |
869 |
|
|
|
870 |
|
|
switch (d->type) { |
871 |
|
|
case DISKIMAGE_FLOPPY: |
872 |
|
|
if (d->total_size < 737280) { |
873 |
|
|
fatal("\nTODO: small (non-80-cylinder) floppies?\n\n"); |
874 |
|
|
exit(1); |
875 |
|
|
} |
876 |
|
|
d->cylinders = 80; |
877 |
|
|
d->heads = 2; |
878 |
|
|
d->sectors_per_track = d->total_size / (d->cylinders * |
879 |
|
|
d->heads * 512); |
880 |
|
|
break; |
881 |
|
|
default:/* Non-floppies: */ |
882 |
|
|
d->heads = 16; |
883 |
|
|
d->sectors_per_track = 63; |
884 |
|
|
if (prefix_g) { |
885 |
|
|
d->chs_override = 1; |
886 |
|
|
d->heads = override_heads; |
887 |
|
|
d->sectors_per_track = override_spt; |
888 |
|
|
} |
889 |
|
|
bytespercyl = d->heads * d->sectors_per_track * 512; |
890 |
|
|
d->cylinders = d->total_size / bytespercyl; |
891 |
|
|
if (d->cylinders * bytespercyl < d->total_size) |
892 |
|
|
d->cylinders ++; |
893 |
|
|
} |
894 |
|
|
|
895 |
|
|
d->rpms = 3600; |
896 |
|
|
|
897 |
|
|
if (prefix_b) |
898 |
|
|
d->is_boot_device = 1; |
899 |
|
|
|
900 |
|
|
d->writable = access(fname, W_OK) == 0? 1 : 0; |
901 |
|
|
|
902 |
|
|
if (d->is_a_cdrom || prefix_r) |
903 |
|
|
d->writable = 0; |
904 |
|
|
|
905 |
|
|
d->f = fopen(fname, d->writable? "r+" : "r"); |
906 |
|
|
if (d->f == NULL) { |
907 |
|
|
perror(fname); |
908 |
|
|
exit(1); |
909 |
|
|
} |
910 |
|
|
|
911 |
|
|
/* Calculate which ID to use: */ |
912 |
|
|
if (prefix_id == -1) { |
913 |
|
|
int free = 0, collision = 1; |
914 |
|
|
|
915 |
|
|
while (collision) { |
916 |
|
|
collision = 0; |
917 |
|
|
d2 = machine->first_diskimage; |
918 |
|
|
while (d2 != NULL) { |
919 |
|
|
/* (don't compare against ourselves :) */ |
920 |
|
|
if (d2 == d) { |
921 |
|
|
d2 = d2->next; |
922 |
|
|
continue; |
923 |
|
|
} |
924 |
|
|
if (d2->id == free && d2->type == d->type) { |
925 |
|
|
collision = 1; |
926 |
|
|
break; |
927 |
|
|
} |
928 |
|
|
d2 = d2->next; |
929 |
|
|
} |
930 |
|
|
if (!collision) |
931 |
|
|
id = free; |
932 |
|
|
else |
933 |
|
|
free ++; |
934 |
|
|
} |
935 |
|
|
} else { |
936 |
|
|
id = prefix_id; |
937 |
|
|
d2 = machine->first_diskimage; |
938 |
|
|
while (d2 != NULL) { |
939 |
|
|
/* (don't compare against ourselves :) */ |
940 |
|
|
if (d2 == d) { |
941 |
|
|
d2 = d2->next; |
942 |
|
|
continue; |
943 |
|
|
} |
944 |
|
|
if (d2->id == id && d2->type == d->type) { |
945 |
|
|
fprintf(stderr, "disk image id %i " |
946 |
|
|
"already in use\n", id); |
947 |
|
|
exit(1); |
948 |
|
|
} |
949 |
|
|
d2 = d2->next; |
950 |
|
|
} |
951 |
|
|
} |
952 |
|
|
|
953 |
|
|
d->id = id; |
954 |
|
|
|
955 |
|
|
return id; |
956 |
|
|
} |
957 |
|
|
|
958 |
|
|
|
959 |
|
|
/* |
960 |
|
|
* diskimage_bootdev(): |
961 |
|
|
* |
962 |
|
|
* Returns the disk id of the device which we're booting from. If typep is |
963 |
|
|
* non-NULL, the type is returned as well. |
964 |
|
|
* |
965 |
|
|
* If no disk was used as boot device, then -1 is returned. (In practice, |
966 |
|
|
* this is used to fake network (tftp) boot.) |
967 |
|
|
*/ |
968 |
|
|
int diskimage_bootdev(struct machine *machine, int *typep) |
969 |
|
|
{ |
970 |
|
|
struct diskimage *d; |
971 |
|
|
|
972 |
|
|
d = machine->first_diskimage; |
973 |
|
|
while (d != NULL) { |
974 |
|
|
if (d->is_boot_device) { |
975 |
|
|
if (typep != NULL) |
976 |
|
|
*typep = d->type; |
977 |
|
|
return d->id; |
978 |
|
|
} |
979 |
|
|
d = d->next; |
980 |
|
|
} |
981 |
|
|
|
982 |
|
|
d = machine->first_diskimage; |
983 |
|
|
if (d != NULL) { |
984 |
|
|
if (typep != NULL) |
985 |
|
|
*typep = d->type; |
986 |
|
|
return d->id; |
987 |
|
|
} |
988 |
|
|
|
989 |
|
|
return -1; |
990 |
|
|
} |
991 |
|
|
|
992 |
|
|
|
993 |
|
|
/* |
994 |
|
|
* diskimage_getname(): |
995 |
|
|
* |
996 |
|
|
* Returns 1 if a valid disk image name was returned, 0 otherwise. |
997 |
|
|
*/ |
998 |
|
|
int diskimage_getname(struct machine *machine, int id, int type, |
999 |
|
|
char *buf, size_t bufsize) |
1000 |
|
|
{ |
1001 |
|
|
struct diskimage *d = machine->first_diskimage; |
1002 |
|
|
|
1003 |
|
|
if (buf == NULL) |
1004 |
|
|
return 0; |
1005 |
|
|
|
1006 |
|
|
while (d != NULL) { |
1007 |
|
|
if (d->type == type && d->id == id) { |
1008 |
|
|
char *p = strrchr(d->fname, '/'); |
1009 |
|
|
if (p == NULL) |
1010 |
|
|
p = d->fname; |
1011 |
|
|
else |
1012 |
|
|
p ++; |
1013 |
|
|
snprintf(buf, bufsize, "%s", p); |
1014 |
|
|
return 1; |
1015 |
|
|
} |
1016 |
|
|
d = d->next; |
1017 |
|
|
} |
1018 |
|
|
return 0; |
1019 |
|
|
} |
1020 |
|
|
|
1021 |
|
|
|
1022 |
|
|
/* |
1023 |
|
|
* diskimage_is_a_cdrom(): |
1024 |
|
|
* |
1025 |
|
|
* Returns 1 if a disk image is a CDROM, 0 otherwise. |
1026 |
|
|
*/ |
1027 |
|
|
int diskimage_is_a_cdrom(struct machine *machine, int id, int type) |
1028 |
|
|
{ |
1029 |
|
|
struct diskimage *d = machine->first_diskimage; |
1030 |
|
|
|
1031 |
|
|
while (d != NULL) { |
1032 |
|
|
if (d->type == type && d->id == id) |
1033 |
|
|
return d->is_a_cdrom; |
1034 |
|
|
d = d->next; |
1035 |
|
|
} |
1036 |
|
|
return 0; |
1037 |
|
|
} |
1038 |
|
|
|
1039 |
|
|
|
1040 |
|
|
/* |
1041 |
|
|
* diskimage_is_a_tape(): |
1042 |
|
|
* |
1043 |
|
|
* Returns 1 if a disk image is a tape, 0 otherwise. |
1044 |
|
|
* |
1045 |
|
|
* (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation |
1046 |
|
|
* boot strings.) |
1047 |
|
|
*/ |
1048 |
|
|
int diskimage_is_a_tape(struct machine *machine, int id, int type) |
1049 |
|
|
{ |
1050 |
|
|
struct diskimage *d = machine->first_diskimage; |
1051 |
|
|
|
1052 |
|
|
while (d != NULL) { |
1053 |
|
|
if (d->type == type && d->id == id) |
1054 |
|
|
return d->is_a_tape; |
1055 |
|
|
d = d->next; |
1056 |
|
|
} |
1057 |
|
|
return 0; |
1058 |
|
|
} |
1059 |
|
|
|
1060 |
|
|
|
1061 |
|
|
/* |
1062 |
|
|
* diskimage_dump_info(): |
1063 |
|
|
* |
1064 |
|
|
* Debug dump of all diskimages that are loaded for a specific machine. |
1065 |
|
|
*/ |
1066 |
|
|
void diskimage_dump_info(struct machine *machine) |
1067 |
|
|
{ |
1068 |
dpavlin |
38 |
int i, iadd = DEBUG_INDENTATION; |
1069 |
dpavlin |
36 |
struct diskimage *d = machine->first_diskimage; |
1070 |
|
|
|
1071 |
|
|
while (d != NULL) { |
1072 |
|
|
debug("diskimage: %s\n", d->fname); |
1073 |
|
|
debug_indentation(iadd); |
1074 |
|
|
|
1075 |
|
|
switch (d->type) { |
1076 |
|
|
case DISKIMAGE_SCSI: |
1077 |
|
|
debug("SCSI"); |
1078 |
|
|
break; |
1079 |
|
|
case DISKIMAGE_IDE: |
1080 |
|
|
debug("IDE"); |
1081 |
|
|
break; |
1082 |
|
|
case DISKIMAGE_FLOPPY: |
1083 |
|
|
debug("FLOPPY"); |
1084 |
|
|
break; |
1085 |
|
|
default: |
1086 |
|
|
debug("UNKNOWN type %i", d->type); |
1087 |
|
|
} |
1088 |
|
|
|
1089 |
|
|
debug(" %s", d->is_a_tape? "TAPE" : |
1090 |
|
|
(d->is_a_cdrom? "CD-ROM" : "DISK")); |
1091 |
|
|
debug(" id %i, ", d->id); |
1092 |
|
|
debug("%s, ", d->writable? "read/write" : "read-only"); |
1093 |
|
|
|
1094 |
|
|
if (d->type == DISKIMAGE_FLOPPY) |
1095 |
|
|
debug("%lli KB", (long long) (d->total_size / 1024)); |
1096 |
|
|
else |
1097 |
|
|
debug("%lli MB", (long long) (d->total_size / 1048576)); |
1098 |
|
|
|
1099 |
|
|
if (d->type == DISKIMAGE_FLOPPY || d->chs_override) |
1100 |
|
|
debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads, |
1101 |
|
|
d->sectors_per_track); |
1102 |
|
|
else |
1103 |
|
|
debug(" (%lli sectors)", (long long) |
1104 |
|
|
(d->total_size / 512)); |
1105 |
|
|
|
1106 |
|
|
if (d->is_boot_device) |
1107 |
|
|
debug(" (BOOT)"); |
1108 |
|
|
debug("\n"); |
1109 |
|
|
|
1110 |
dpavlin |
38 |
for (i=0; i<d->nr_of_overlays; i++) { |
1111 |
|
|
debug("overlay %i: %s\n", |
1112 |
|
|
i, d->overlays[i].overlay_basename); |
1113 |
|
|
} |
1114 |
|
|
|
1115 |
dpavlin |
36 |
debug_indentation(-iadd); |
1116 |
|
|
|
1117 |
|
|
d = d->next; |
1118 |
|
|
} |
1119 |
|
|
} |
1120 |
|
|
|