diskimage.cc Source File

Back to the index.

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

Generated on Tue Mar 24 2020 14:04:48 for GXemul by doxygen 1.8.17