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