diskimage.cc Source File

Back to the index.

diskimage.cc
Go to the documentation of this file.
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  */
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  if (do_fsync)
378  fsync(fileno(d->overlays[overlay_nr].f_bitmap));
379 }
380 
381 
382 /* Helper function. */
383 static int overlay_has_block(struct diskimage *d, int overlay_nr, off_t ofs)
384 {
385  off_t bit_nr = ofs / OVERLAY_BLOCK_SIZE;
386  off_t bitmap_file_offset = bit_nr / 8;
387  int res;
388  unsigned char data;
389 
390  res = my_fseek(d->overlays[overlay_nr].f_bitmap,
391  bitmap_file_offset, SEEK_SET);
392  if (res != 0)
393  return 0;
394 
395  /* The seek succeeded, now read the bit: */
396  res = fread(&data, 1, 1, d->overlays[overlay_nr].f_bitmap);
397  if (res != 1)
398  return 0;
399 
400  if (data & (1 << (bit_nr & 7)))
401  return 1;
402 
403  return 0;
404 }
405 
406 
407 /*
408  * fwrite_helper():
409  *
410  * Internal helper function. Writes to a disk image file, or if the
411  * disk image has overlays, to the last overlay.
412  */
413 static size_t fwrite_helper(off_t offset, unsigned char *buf,
414  size_t len, struct diskimage *d)
415 {
416  off_t curofs;
417 
418  /* Fast return-path for the case when no overlays are used: */
419  if (d->nr_of_overlays == 0) {
420  int res = my_fseek(d->f, offset, SEEK_SET);
421  if (res != 0) {
422  fatal("[ diskimage__internal_access(): fseek() failed"
423  " on disk id %i \n", d->id);
424  return 0;
425  }
426 
427  size_t written = fwrite(buf, 1, len, d->f);
428 
429  if (do_fsync)
430  fsync(fileno(d->f));
431 
432  return written;
433  }
434 
435  if ((len & (OVERLAY_BLOCK_SIZE-1)) != 0) {
436  fatal("TODO: overlay access (write), len not multiple of "
437  "overlay block size. not yet implemented.\n");
438  fatal("len = %lli\n", (long long) len);
439  abort();
440  }
441  if ((offset & (OVERLAY_BLOCK_SIZE-1)) != 0) {
442  fatal("TODO: unaligned overlay access\n");
443  fatal("offset = %lli\n", (long long) offset);
444  abort();
445  }
446 
447  /* Split the write into OVERLAY_BLOCK_SIZE writes: */
448  for (curofs = offset; curofs < (off_t) (offset+len);
449  curofs += OVERLAY_BLOCK_SIZE) {
450  /* Always write to the last overlay: */
451  int overlay_nr = d->nr_of_overlays-1;
452  off_t lenwritten;
453  int res = my_fseek(d->overlays[overlay_nr].f_data,
454  curofs, SEEK_SET);
455  if (res != 0) {
456  fatal("[ diskimage__internal_access(): fseek()"
457  " failed on disk id %i \n", d->id);
458  return 0;
459  }
460 
461  lenwritten = fwrite(buf, 1, OVERLAY_BLOCK_SIZE,
462  d->overlays[overlay_nr].f_data);
463  buf += OVERLAY_BLOCK_SIZE;
464 
465  if (do_fsync)
466  fsync(fileno(d->overlays[overlay_nr].f_data));
467 
468  /* Mark this block in the last overlay as in use: */
469  overlay_set_block_in_use(d, overlay_nr, curofs);
470  }
471 
472  return len;
473 }
474 
475 
476 /*
477  * fread_helper():
478  *
479  * Internal helper function. Reads from a disk image file, or if the
480  * disk image has overlays, from the last overlay that has the specific
481  * data (or the disk image file itself).
482  */
483 static size_t fread_helper(off_t offset, unsigned char *buf,
484  size_t len, struct diskimage *d)
485 {
486  off_t curofs;
487  size_t totallenread = 0;
488 
489  /* Fast return-path for the case when no overlays are used: */
490  if (d->nr_of_overlays == 0) {
491  int res = my_fseek(d->f, offset, SEEK_SET);
492  if (res != 0) {
493  fatal("[ diskimage__internal_access(): fseek() failed"
494  " on disk id %i \n", d->id);
495  return 0;
496  }
497 
498  return fread(buf, 1, len, d->f);
499  }
500 
501  /* Split the read into OVERLAY_BLOCK_SIZE reads: */
502  for (curofs=offset; len != 0;
503  curofs = (curofs | (OVERLAY_BLOCK_SIZE-1)) + 1) {
504  /* Find the overlay, if any, that has this block: */
505  off_t lenread, lentoread;
506  int overlay_nr;
507  for (overlay_nr = d->nr_of_overlays-1;
508  overlay_nr >= 0; overlay_nr --) {
509  if (overlay_has_block(d, overlay_nr, curofs))
510  break;
511  }
512 
513  lentoread = len > OVERLAY_BLOCK_SIZE? OVERLAY_BLOCK_SIZE : len;
514 
515  if (overlay_nr >= 0) {
516  /* Read from overlay: */
517  int res = my_fseek(d->overlays[overlay_nr].f_data,
518  curofs, SEEK_SET);
519  if (res != 0) {
520  fatal("[ diskimage__internal_access(): fseek()"
521  " failed on disk id %i \n", d->id);
522  return 0;
523  }
524  lenread = fread(buf, 1, lentoread,
525  d->overlays[overlay_nr].f_data);
526  } else {
527  /* Read from the base disk image: */
528  int res = my_fseek(d->f, curofs, SEEK_SET);
529  if (res != 0) {
530  fatal("[ diskimage__internal_access(): fseek()"
531  " failed on disk id %i \n", d->id);
532  return 0;
533  }
534  lenread = fread(buf, 1, lentoread, d->f);
535  }
536 
537  if (lenread != lentoread) {
538  fatal("[ INCOMPLETE READ from disk id %i, offset"
539  " %lli ]\n", d->id, (long long)curofs);
540  }
541 
542  len -= lentoread;
543  totallenread += lenread;
544  buf += OVERLAY_BLOCK_SIZE;
545  }
546 
547  return totallenread;
548 }
549 
550 
551 /*
552  * diskimage__internal_access():
553  *
554  * Read from or write to a struct diskimage.
555  *
556  * Returns 1 if the access completed successfully, 0 otherwise.
557  */
558 int diskimage__internal_access(struct diskimage *d, int writeflag,
559  off_t offset, unsigned char *buf, size_t len)
560 {
561  ssize_t lendone;
562 
563  if (buf == NULL) {
564  fprintf(stderr, "diskimage__internal_access(): buf = NULL\n");
565  exit(1);
566  }
567  if (len == 0)
568  return 1;
569  if (d->f == NULL)
570  return 0;
571 
572  if (writeflag) {
573  if (!d->writable)
574  return 0;
575 
576  lendone = fwrite_helper(offset, buf, len, d);
577  } else {
578  /*
579  * Special case for CD-ROMs. Actually, this is not needed
580  * for .iso images, only for physical CDROMS on some OSes,
581  * such as FreeBSD.
582  */
583  if (d->is_a_cdrom)
584  lendone = diskimage_access__cdrom(d, offset, buf, len);
585  else
586  lendone = fread_helper(offset, buf, len, d);
587 
588  if (lendone >= 0 && lendone < (ssize_t)len)
589  memset(buf + lendone, 0, len - lendone);
590  }
591 
592  /*
593  * Incomplete data transfer?
594  *
595  * If we could not read anything at all, then return failure.
596  * If we could read a partial block, then return success (with
597  * the resulting buffer zero-filled at the end).
598  */
599  if (lendone <= 0) {
600  fatal("[ diskimage__internal_access(): disk_id %i, offset %lli"
601  ", transfer not completed. len=%i, len_done=%i ]\n",
602  d->id, (long long)offset, (int)len, (int)lendone);
603  return 0;
604  }
605 
606  return 1;
607 }
608 
609 
610 /*
611  * diskimage_access():
612  *
613  * Read from or write to a disk image on a machine.
614  *
615  * Returns 1 if the access completed successfully, 0 otherwise.
616  */
617 int diskimage_access(struct machine *machine, int id, int type, int writeflag,
618  off_t offset, unsigned char *buf, size_t len)
619 {
620  struct diskimage *d = machine->first_diskimage;
621 
622  while (d != NULL) {
623  if (d->type == type && d->id == id)
624  break;
625  d = d->next;
626  }
627 
628  if (d == NULL) {
629  fatal("[ diskimage_access(): ERROR: trying to access a "
630  "non-existant %s disk image (id %i)\n",
631  diskimage_types[type], id);
632  return 0;
633  }
634 
635  offset -= d->override_base_offset;
636  if (offset < 0 && offset + d->override_base_offset >= 0) {
637  debug("[ reading before start of disk image ]\n");
638  /* Returning zeros. */
639  memset(buf, 0, len);
640  return 1;
641  }
642 
643  return diskimage__internal_access(d, writeflag, offset, buf, len);
644 }
645 
646 
647 /*
648  * diskimage_add():
649  *
650  * Add a disk image. fname is the filename of the disk image.
651  * The filename may be prefixed with one or more modifiers, followed
652  * by a colon.
653  *
654  * b specifies that this is a bootable device
655  * c CD-ROM (instead of a normal DISK)
656  * d DISK (this is the default)
657  * f FLOPPY (instead of SCSI)
658  * gH;S; set geometry (H=heads, S=sectors per track, cylinders are
659  * automatically calculated). (This is ignored for floppies.)
660  * i IDE (instead of SCSI)
661  * oOFS; set base offset in bytes, when booting from an ISO9660 fs
662  * r read-only (don't allow changes to the file)
663  * s SCSI (this is the default)
664  * t tape
665  * V add an overlay to a disk image
666  * 0-7 force a specific SCSI ID number
667  *
668  * machine is assumed to be non-NULL.
669  * Returns an integer >= 0 identifying the disk image.
670  */
671 int diskimage_add(struct machine *machine, char *fname)
672 {
673  struct diskimage *d, *d2;
674  int id = 0, override_heads=0, override_spt=0;
675  int64_t bytespercyl, override_base_offset=0;
676  char *cp;
677  int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0;
678  int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id=-1;
679  int prefix_o=0, prefix_V=0;
680 
681  if (fname == NULL) {
682  fprintf(stderr, "diskimage_add(): NULL ptr\n");
683  return 0;
684  }
685 
686  /* Get prefix from fname: */
687  cp = strchr(fname, ':');
688  if (cp != NULL) {
689  while (fname <= cp) {
690  char c = *fname++;
691  switch (c) {
692  case '0':
693  case '1':
694  case '2':
695  case '3':
696  case '4':
697  case '5':
698  case '6':
699  case '7':
700  prefix_id = c - '0';
701  break;
702  case 'b':
703  prefix_b = 1;
704  break;
705  case 'c':
706  prefix_c = 1;
707  break;
708  case 'd':
709  prefix_d = 1;
710  break;
711  case 'f':
712  prefix_f = 1;
713  break;
714  case 'g':
715  prefix_g = 1;
716  override_heads = atoi(fname);
717  while (*fname != '\0' && *fname != ';')
718  fname ++;
719  if (*fname == ';')
720  fname ++;
721  override_spt = atoi(fname);
722  while (*fname != '\0' && *fname != ';' &&
723  *fname != ':')
724  fname ++;
725  if (*fname == ';')
726  fname ++;
727  if (override_heads < 1 ||
728  override_spt < 1) {
729  fatal("Bad geometry: heads=%i "
730  "spt=%i\n", override_heads,
731  override_spt);
732  exit(1);
733  }
734  break;
735  case 'i':
736  prefix_i = 1;
737  break;
738  case 'o':
739  prefix_o = 1;
740  override_base_offset = atoi(fname);
741  while (*fname != '\0' && *fname != ':'
742  && *fname != ';')
743  fname ++;
744  if (*fname == ':' || *fname == ';')
745  fname ++;
746  if (override_base_offset < 0) {
747  fatal("Bad base offset: %" PRIi64
748  "\n", override_base_offset);
749  exit(1);
750  }
751  break;
752  case 'r':
753  prefix_r = 1;
754  break;
755  case 's':
756  prefix_s = 1;
757  break;
758  case 't':
759  prefix_t = 1;
760  break;
761  case 'V':
762  prefix_V = 1;
763  break;
764  case ':':
765  break;
766  default:
767  fprintf(stderr, "diskimage_add(): invalid "
768  "prefix char '%c'\n", c);
769  exit(1);
770  }
771  }
772  }
773 
774  /* Allocate a new diskimage struct: */
775  CHECK_ALLOCATION(d = (struct diskimage *) malloc(sizeof(struct diskimage)));
776  memset(d, 0, sizeof(struct diskimage));
777 
778  /* Default to IDE disks... */
779  d->type = DISKIMAGE_IDE;
780 
781  /* ... but some machines use SCSI by default: */
786  d->type = DISKIMAGE_SCSI;
787 
788  if (prefix_i + prefix_f + prefix_s > 1) {
789  fprintf(stderr, "Invalid disk image prefix(es). You can"
790  "only use one of i, f, and s\nfor each disk image.\n");
791  exit(1);
792  }
793 
794  if (prefix_i)
795  d->type = DISKIMAGE_IDE;
796  if (prefix_f)
797  d->type = DISKIMAGE_FLOPPY;
798  if (prefix_s)
799  d->type = DISKIMAGE_SCSI;
800 
801  /* Special case: Add an overlay for an already added disk image: */
802  if (prefix_V) {
803  struct diskimage *dx = machine->first_diskimage;
804 
805  if (prefix_id < 0) {
806  fprintf(stderr, "The 'V' disk image prefix requires"
807  " a disk ID to also be supplied.\n");
808  exit(1);
809  }
810 
811  while (dx != NULL) {
812  if (d->type == dx->type && prefix_id == dx->id)
813  break;
814  dx = dx->next;
815  }
816 
817  if (dx == NULL) {
818  fprintf(stderr, "Bad ID supplied for overlay?\n");
819  exit(1);
820  }
821 
823 
824  /* Free the preliminary d struct: */
825  free(d);
826 
827  /* Don't add any disk image. This is an overlay! */
828  return -1;
829  }
830 
831  /* Add the new disk image in the disk image chain: */
832  d2 = machine->first_diskimage;
833  if (d2 == NULL) {
835  } else {
836  while (d2->next != NULL)
837  d2 = d2->next;
838  d2->next = d;
839  }
840 
841  if (prefix_o)
843 
844  CHECK_ALLOCATION(d->fname = strdup(fname));
845 
846  d->logical_block_size = 512;
847 
848  /*
849  * Is this a tape, CD-ROM or a normal disk?
850  *
851  * An intelligent guess, if no prefixes are used, would be that
852  * filenames ending with .iso or .cdr are CD-ROM images.
853  */
854  if (prefix_t) {
855  d->is_a_tape = 1;
856  } else {
857  if (prefix_c ||
858  ((strlen(d->fname) > 4 &&
859  (strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 ||
860  strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0))
861  && !prefix_d)
862  ) {
863  d->is_a_cdrom = 1;
864 
865  /*
866  * This is tricky. Should I use 512 or 2048 here?
867  * NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes
868  * per sector, but NetBSD 2.0_BETA suddenly ignores
869  * this value and uses 2048 instead.
870  *
871  * OpenBSD/arc doesn't like 2048, it requires 512
872  * to work correctly.
873  *
874  * TODO
875  */
876 
877 #if 0
879  d->logical_block_size = 512;
880  else
881  d->logical_block_size = 2048;
882 #endif
883  d->logical_block_size = 512;
884  }
885  }
886 
888 
889  if ((d->total_size == 720*1024 || d->total_size == 1474560
890  || d->total_size == 2949120 || d->total_size == 1228800)
891  && !prefix_i && !prefix_s)
892  d->type = DISKIMAGE_FLOPPY;
893 
894  switch (d->type) {
895  case DISKIMAGE_FLOPPY:
896  if (d->total_size < 737280) {
897  fatal("\nTODO: small (non-80-cylinder) floppies?\n\n");
898  exit(1);
899  }
900  d->cylinders = 80;
901  d->heads = 2;
902  d->sectors_per_track = d->total_size / (d->cylinders *
903  d->heads * 512);
904  break;
905  default:/* Non-floppies: */
906  d->heads = 16;
907  d->sectors_per_track = 63;
908  if (prefix_g) {
909  d->chs_override = 1;
910  d->heads = override_heads;
911  d->sectors_per_track = override_spt;
912  }
913  bytespercyl = d->heads * d->sectors_per_track * 512;
914  d->cylinders = d->total_size / bytespercyl;
915  if (d->cylinders * bytespercyl < d->total_size)
916  d->cylinders ++;
917  }
918 
919  d->rpms = 3600;
920 
921  if (prefix_b)
922  d->is_boot_device = 1;
923 
924  d->writable = access(fname, W_OK) == 0? 1 : 0;
925 
926  if (d->is_a_cdrom || prefix_r) {
927  d->writable = 0;
928  } else {
929  if (!d->writable) {
930  debug("NOTE: '%s' is read-only in the host file system, but 'r:' was not used.\n\n", d->fname);
931  }
932  }
933 
934  d->f = fopen(fname, d->writable? "r+" : "r");
935  if (d->f == NULL) {
936  char *errmsg = (char *) malloc(200 + strlen(fname));
937  snprintf(errmsg, 200+strlen(fname),
938  "could not fopen %s for reading%s", fname,
939  d->writable? " and writing" : "");
940  perror(errmsg);
941  exit(1);
942  }
943 
944  /* Calculate which ID to use: */
945  if (prefix_id == -1) {
946  int free = 0, collision = 1;
947 
948  while (collision) {
949  collision = 0;
950  d2 = machine->first_diskimage;
951  while (d2 != NULL) {
952  /* (don't compare against ourselves :) */
953  if (d2 == d) {
954  d2 = d2->next;
955  continue;
956  }
957  if (d2->id == free && d2->type == d->type) {
958  collision = 1;
959  break;
960  }
961  d2 = d2->next;
962  }
963  if (!collision)
964  id = free;
965  else
966  free ++;
967  }
968  } else {
969  id = prefix_id;
970  d2 = machine->first_diskimage;
971  while (d2 != NULL) {
972  /* (don't compare against ourselves :) */
973  if (d2 == d) {
974  d2 = d2->next;
975  continue;
976  }
977  if (d2->id == id && d2->type == d->type) {
978  fprintf(stderr, "disk image id %i "
979  "already in use\n", id);
980  exit(1);
981  }
982  d2 = d2->next;
983  }
984  }
985 
986  d->id = id;
987 
988  return id;
989 }
990 
991 
992 /*
993  * diskimage_bootdev():
994  *
995  * Returns the disk id of the device which we're booting from. If typep is
996  * non-NULL, the type is returned as well.
997  *
998  * If no disk was used as boot device, then -1 is returned. (In practice,
999  * this is used to fake network (tftp) boot.)
1000  */
1001 int diskimage_bootdev(struct machine *machine, int *typep)
1002 {
1003  struct diskimage *d;
1004 
1005  d = machine->first_diskimage;
1006  while (d != NULL) {
1007  if (d->is_boot_device) {
1008  if (typep != NULL)
1009  *typep = d->type;
1010  return d->id;
1011  }
1012  d = d->next;
1013  }
1014 
1015  d = machine->first_diskimage;
1016  if (d != NULL) {
1017  if (typep != NULL)
1018  *typep = d->type;
1019  return d->id;
1020  }
1021 
1022  return -1;
1023 }
1024 
1025 
1026 /*
1027  * diskimage_getname():
1028  *
1029  * Returns 1 if a valid disk image name was returned, 0 otherwise.
1030  */
1031 int diskimage_getname(struct machine *machine, int id, int type,
1032  char *buf, size_t bufsize)
1033 {
1034  struct diskimage *d = machine->first_diskimage;
1035 
1036  if (buf == NULL)
1037  return 0;
1038 
1039  while (d != NULL) {
1040  if (d->type == type && d->id == id) {
1041  char *p = strrchr(d->fname, '/');
1042  if (p == NULL)
1043  p = d->fname;
1044  else
1045  p ++;
1046  snprintf(buf, bufsize, "%s", p);
1047  return 1;
1048  }
1049  d = d->next;
1050  }
1051  return 0;
1052 }
1053 
1054 
1055 /*
1056  * diskimage_is_a_cdrom():
1057  *
1058  * Returns 1 if a disk image is a CDROM, 0 otherwise.
1059  */
1060 int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
1061 {
1062  struct diskimage *d = machine->first_diskimage;
1063 
1064  while (d != NULL) {
1065  if (d->type == type && d->id == id)
1066  return d->is_a_cdrom;
1067  d = d->next;
1068  }
1069  return 0;
1070 }
1071 
1072 
1073 /*
1074  * diskimage_is_a_tape():
1075  *
1076  * Returns 1 if a disk image is a tape, 0 otherwise.
1077  *
1078  * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation
1079  * boot strings.)
1080  */
1081 int diskimage_is_a_tape(struct machine *machine, int id, int type)
1082 {
1083  struct diskimage *d = machine->first_diskimage;
1084 
1085  while (d != NULL) {
1086  if (d->type == type && d->id == id)
1087  return d->is_a_tape;
1088  d = d->next;
1089  }
1090  return 0;
1091 }
1092 
1093 
1094 /*
1095  * diskimage_dump_info():
1096  *
1097  * Debug dump of all diskimages that are loaded for a specific machine.
1098  */
1100 {
1101  int i, iadd = DEBUG_INDENTATION;
1102  struct diskimage *d = machine->first_diskimage;
1103 
1104  while (d != NULL) {
1105  debug("diskimage: %s\n", d->fname);
1106  debug_indentation(iadd);
1107 
1108  switch (d->type) {
1109  case DISKIMAGE_SCSI:
1110  debug("SCSI");
1111  break;
1112  case DISKIMAGE_IDE:
1113  debug("IDE");
1114  break;
1115  case DISKIMAGE_FLOPPY:
1116  debug("FLOPPY");
1117  break;
1118  default:
1119  debug("UNKNOWN type %i", d->type);
1120  }
1121 
1122  debug(" %s", d->is_a_tape? "TAPE" :
1123  (d->is_a_cdrom? "CD-ROM" : "DISK"));
1124  debug(" id %i, ", d->id);
1125  debug("%s, ", d->writable? "read/write" : "read-only");
1126 
1127  if (d->type == DISKIMAGE_FLOPPY)
1128  debug("%lli KB", (long long) (d->total_size / 1024));
1129  else
1130  debug("%lli MB", (long long) (d->total_size / 1048576));
1131 
1132  if (d->type == DISKIMAGE_FLOPPY || d->chs_override)
1133  debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads,
1134  d->sectors_per_track);
1135  else
1136  debug(" (%lli sectors)", (long long)
1137  (d->total_size / 512));
1138 
1139  if (d->is_boot_device)
1140  debug(" (BOOT)");
1141  debug("\n");
1142 
1143  for (i=0; i<d->nr_of_overlays; i++) {
1144  debug("overlay %i: %s\n",
1145  i, d->overlays[i].overlay_basename);
1146  }
1147 
1148  debug_indentation(-iadd);
1149 
1150  d = d->next;
1151  }
1152 }
1153 
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:257
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:1001
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:558
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:617
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:1060
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:1081
strlen
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2686
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
do_fsync
bool do_fsync
Definition: diskimage.cc:47
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:671
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
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:1031
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:1099
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 Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18