diskimage.cc Source File

Back to the index.

diskimage.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2011 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 
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  */
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: */
770  if (machine->machine_type == MACHINE_PMAX ||
771  machine->machine_type == MACHINE_ARC ||
772  machine->machine_type == MACHINE_MVME88K)
773  d->type = DISKIMAGE_SCSI;
774 
775  if (prefix_i + prefix_f + prefix_s > 1) {
776  fprintf(stderr, "Invalid disk image prefix(es). You can"
777  "only use one of i, f, and s\nfor each disk image.\n");
778  exit(1);
779  }
780 
781  if (prefix_i)
782  d->type = DISKIMAGE_IDE;
783  if (prefix_f)
784  d->type = DISKIMAGE_FLOPPY;
785  if (prefix_s)
786  d->type = DISKIMAGE_SCSI;
787 
788  /* Special case: Add an overlay for an already added disk image: */
789  if (prefix_V) {
790  struct diskimage *dx = machine->first_diskimage;
791 
792  if (prefix_id < 0) {
793  fprintf(stderr, "The 'V' disk image prefix requires"
794  " a disk ID to also be supplied.\n");
795  exit(1);
796  }
797 
798  while (dx != NULL) {
799  if (d->type == dx->type && prefix_id == dx->id)
800  break;
801  dx = dx->next;
802  }
803 
804  if (dx == NULL) {
805  fprintf(stderr, "Bad ID supplied for overlay?\n");
806  exit(1);
807  }
808 
809  diskimage_add_overlay(dx, fname);
810 
811  /* Free the preliminary d struct: */
812  free(d);
813 
814  /* Don't add any disk image. This is an overlay! */
815  return -1;
816  }
817 
818  /* Add the new disk image in the disk image chain: */
819  d2 = machine->first_diskimage;
820  if (d2 == NULL) {
821  machine->first_diskimage = d;
822  } else {
823  while (d2->next != NULL)
824  d2 = d2->next;
825  d2->next = d;
826  }
827 
828  if (prefix_o)
830 
831  CHECK_ALLOCATION(d->fname = strdup(fname));
832 
833  d->logical_block_size = 512;
834 
835  /*
836  * Is this a tape, CD-ROM or a normal disk?
837  *
838  * An intelligent guess, if no prefixes are used, would be that
839  * filenames ending with .iso or .cdr are CD-ROM images.
840  */
841  if (prefix_t) {
842  d->is_a_tape = 1;
843  } else {
844  if (prefix_c ||
845  ((strlen(d->fname) > 4 &&
846  (strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 ||
847  strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0))
848  && !prefix_d)
849  ) {
850  d->is_a_cdrom = 1;
851 
852  /*
853  * This is tricky. Should I use 512 or 2048 here?
854  * NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes
855  * per sector, but NetBSD 2.0_BETA suddenly ignores
856  * this value and uses 2048 instead.
857  *
858  * OpenBSD/arc doesn't like 2048, it requires 512
859  * to work correctly.
860  *
861  * TODO
862  */
863 
864 #if 0
865  if (machine->machine_type == MACHINE_PMAX)
866  d->logical_block_size = 512;
867  else
868  d->logical_block_size = 2048;
869 #endif
870  d->logical_block_size = 512;
871  }
872  }
873 
875 
876  if ((d->total_size == 720*1024 || d->total_size == 1474560
877  || d->total_size == 2949120 || d->total_size == 1228800)
878  && !prefix_i && !prefix_s)
879  d->type = DISKIMAGE_FLOPPY;
880 
881  switch (d->type) {
882  case DISKIMAGE_FLOPPY:
883  if (d->total_size < 737280) {
884  fatal("\nTODO: small (non-80-cylinder) floppies?\n\n");
885  exit(1);
886  }
887  d->cylinders = 80;
888  d->heads = 2;
889  d->sectors_per_track = d->total_size / (d->cylinders *
890  d->heads * 512);
891  break;
892  default:/* Non-floppies: */
893  d->heads = 16;
894  d->sectors_per_track = 63;
895  if (prefix_g) {
896  d->chs_override = 1;
897  d->heads = override_heads;
898  d->sectors_per_track = override_spt;
899  }
900  bytespercyl = d->heads * d->sectors_per_track * 512;
901  d->cylinders = d->total_size / bytespercyl;
902  if (d->cylinders * bytespercyl < d->total_size)
903  d->cylinders ++;
904  }
905 
906  d->rpms = 3600;
907 
908  if (prefix_b)
909  d->is_boot_device = 1;
910 
911  d->writable = access(fname, W_OK) == 0? 1 : 0;
912 
913  if (d->is_a_cdrom || prefix_r)
914  d->writable = 0;
915 
916  d->f = fopen(fname, d->writable? "r+" : "r");
917  if (d->f == NULL) {
918  char *errmsg = (char *) malloc(200 + strlen(fname));
919  snprintf(errmsg, 200+strlen(fname),
920  "could not fopen %s for reading%s", fname,
921  d->writable? " and writing" : "");
922  perror(errmsg);
923  exit(1);
924  }
925 
926  /* Calculate which ID to use: */
927  if (prefix_id == -1) {
928  int free = 0, collision = 1;
929 
930  while (collision) {
931  collision = 0;
932  d2 = machine->first_diskimage;
933  while (d2 != NULL) {
934  /* (don't compare against ourselves :) */
935  if (d2 == d) {
936  d2 = d2->next;
937  continue;
938  }
939  if (d2->id == free && d2->type == d->type) {
940  collision = 1;
941  break;
942  }
943  d2 = d2->next;
944  }
945  if (!collision)
946  id = free;
947  else
948  free ++;
949  }
950  } else {
951  id = prefix_id;
952  d2 = machine->first_diskimage;
953  while (d2 != NULL) {
954  /* (don't compare against ourselves :) */
955  if (d2 == d) {
956  d2 = d2->next;
957  continue;
958  }
959  if (d2->id == id && d2->type == d->type) {
960  fprintf(stderr, "disk image id %i "
961  "already in use\n", id);
962  exit(1);
963  }
964  d2 = d2->next;
965  }
966  }
967 
968  d->id = id;
969 
970  return id;
971 }
972 
973 
974 /*
975  * diskimage_bootdev():
976  *
977  * Returns the disk id of the device which we're booting from. If typep is
978  * non-NULL, the type is returned as well.
979  *
980  * If no disk was used as boot device, then -1 is returned. (In practice,
981  * this is used to fake network (tftp) boot.)
982  */
983 int diskimage_bootdev(struct machine *machine, int *typep)
984 {
985  struct diskimage *d;
986 
987  d = machine->first_diskimage;
988  while (d != NULL) {
989  if (d->is_boot_device) {
990  if (typep != NULL)
991  *typep = d->type;
992  return d->id;
993  }
994  d = d->next;
995  }
996 
997  d = machine->first_diskimage;
998  if (d != NULL) {
999  if (typep != NULL)
1000  *typep = d->type;
1001  return d->id;
1002  }
1003 
1004  return -1;
1005 }
1006 
1007 
1008 /*
1009  * diskimage_getname():
1010  *
1011  * Returns 1 if a valid disk image name was returned, 0 otherwise.
1012  */
1013 int diskimage_getname(struct machine *machine, int id, int type,
1014  char *buf, size_t bufsize)
1015 {
1016  struct diskimage *d = machine->first_diskimage;
1017 
1018  if (buf == NULL)
1019  return 0;
1020 
1021  while (d != NULL) {
1022  if (d->type == type && d->id == id) {
1023  char *p = strrchr(d->fname, '/');
1024  if (p == NULL)
1025  p = d->fname;
1026  else
1027  p ++;
1028  snprintf(buf, bufsize, "%s", p);
1029  return 1;
1030  }
1031  d = d->next;
1032  }
1033  return 0;
1034 }
1035 
1036 
1037 /*
1038  * diskimage_is_a_cdrom():
1039  *
1040  * Returns 1 if a disk image is a CDROM, 0 otherwise.
1041  */
1042 int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
1043 {
1044  struct diskimage *d = machine->first_diskimage;
1045 
1046  while (d != NULL) {
1047  if (d->type == type && d->id == id)
1048  return d->is_a_cdrom;
1049  d = d->next;
1050  }
1051  return 0;
1052 }
1053 
1054 
1055 /*
1056  * diskimage_is_a_tape():
1057  *
1058  * Returns 1 if a disk image is a tape, 0 otherwise.
1059  *
1060  * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation
1061  * boot strings.)
1062  */
1063 int diskimage_is_a_tape(struct machine *machine, int id, int type)
1064 {
1065  struct diskimage *d = machine->first_diskimage;
1066 
1067  while (d != NULL) {
1068  if (d->type == type && d->id == id)
1069  return d->is_a_tape;
1070  d = d->next;
1071  }
1072  return 0;
1073 }
1074 
1075 
1076 /*
1077  * diskimage_dump_info():
1078  *
1079  * Debug dump of all diskimages that are loaded for a specific machine.
1080  */
1082 {
1083  int i, iadd = DEBUG_INDENTATION;
1084  struct diskimage *d = machine->first_diskimage;
1085 
1086  while (d != NULL) {
1087  debug("diskimage: %s\n", d->fname);
1088  debug_indentation(iadd);
1089 
1090  switch (d->type) {
1091  case DISKIMAGE_SCSI:
1092  debug("SCSI");
1093  break;
1094  case DISKIMAGE_IDE:
1095  debug("IDE");
1096  break;
1097  case DISKIMAGE_FLOPPY:
1098  debug("FLOPPY");
1099  break;
1100  default:
1101  debug("UNKNOWN type %i", d->type);
1102  }
1103 
1104  debug(" %s", d->is_a_tape? "TAPE" :
1105  (d->is_a_cdrom? "CD-ROM" : "DISK"));
1106  debug(" id %i, ", d->id);
1107  debug("%s, ", d->writable? "read/write" : "read-only");
1108 
1109  if (d->type == DISKIMAGE_FLOPPY)
1110  debug("%lli KB", (long long) (d->total_size / 1024));
1111  else
1112  debug("%lli MB", (long long) (d->total_size / 1048576));
1113 
1114  if (d->type == DISKIMAGE_FLOPPY || d->chs_override)
1115  debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads,
1116  d->sectors_per_track);
1117  else
1118  debug(" (%lli sectors)", (long long)
1119  (d->total_size / 512));
1120 
1121  if (d->is_boot_device)
1122  debug(" (BOOT)");
1123  debug("\n");
1124 
1125  for (i=0; i<d->nr_of_overlays; i++) {
1126  debug("overlay %i: %s\n",
1127  i, d->overlays[i].overlay_basename);
1128  }
1129 
1130  debug_indentation(-iadd);
1131 
1132  d = d->next;
1133  }
1134 }
1135 
void fatal(const char *fmt,...)
Definition: main.cc:152
int is_a_cdrom
Definition: diskimage.h:79
#define DEBUG_INDENTATION
Definition: misc.h:212
int diskimage_getname(struct machine *machine, int id, int type, char *buf, size_t bufsize)
Definition: diskimage.cc:1013
int diskimage_exist(struct machine *machine, int id, int type)
Definition: diskimage.cc:106
int rpms
Definition: diskimage.h:87
int machine_type
Definition: machine.h:111
#define DISKIMAGE_SCSI
Definition: diskimage.h:40
#define CDROM_SECTOR_SIZE
Definition: diskimage.cc:301
void f(int s, int func, int only_name)
int logical_block_size
Definition: diskimage.h:76
#define MACHINE_PMAX
Definition: machine.h:213
void diskimage_set_baseoffset(struct machine *machine, int id, int type, int64_t offset)
Definition: diskimage.cc:242
char * overlay_basename
Definition: diskimage.h:51
int is_a_tape
Definition: diskimage.h:82
int chs_override
Definition: diskimage.h:69
int heads
Definition: diskimage.h:71
#define MACHINE_ARC
Definition: machine.h:218
#define DISKIMAGE_FLOPPY
Definition: diskimage.h:42
int id
Definition: diskimage.h:59
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
struct diskimage * first_diskimage
Definition: machine.h:142
int64_t override_base_offset
Definition: diskimage.h:75
int diskimage_bootdev(struct machine *machine, int *typep)
Definition: diskimage.cc:983
#define DISKIMAGE_IDE
Definition: diskimage.h:41
int writable
Definition: diskimage.h:78
struct diskimage * next
Definition: diskimage.h:57
u_short data
Definition: siireg.h:79
int nr_of_overlays
Definition: diskimage.h:66
int diskimage__internal_access(struct diskimage *d, int writeflag, off_t offset, unsigned char *buf, size_t len)
Definition: diskimage.cc:547
void diskimage_dump_info(struct machine *machine)
Definition: diskimage.cc:1081
off_t total_size
Definition: diskimage.h:74
int64_t diskimage_getsize(struct machine *machine, int id, int type)
Definition: diskimage.cc:203
FILE * f
Definition: diskimage.h:63
int single_step
Definition: debugger.cc:68
int type
Definition: diskimage.h:58
int64_t diskimage_get_baseoffset(struct machine *machine, int id, int type)
Definition: diskimage.cc:222
#define debug
Definition: dev_adb.cc:57
void diskimage_getchs(struct machine *machine, int id, int type, int *c, int *h, int *s)
Definition: diskimage.cc:266
void diskimage_recalc_size(struct diskimage *d)
Definition: diskimage.cc:165
int cylinders
Definition: diskimage.h:70
#define OVERLAY_BLOCK_SIZE
Definition: diskimage.h:48
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
int diskimage_is_a_cdrom(struct machine *machine, int id, int type)
Definition: diskimage.cc:1042
struct diskimage_overlay * overlays
Definition: diskimage.h:67
void debug_indentation(int diff)
Definition: main.cc:120
#define DISKIMAGE_TYPES
Definition: diskimage.h:44
#define MACHINE_MVME88K
Definition: machine.h:258
int diskimage_is_a_tape(struct machine *machine, int id, int type)
Definition: diskimage.cc:1063
void diskimage_add_overlay(struct diskimage *d, char *overlay_basename)
Definition: diskimage.cc:125
int diskimage_add(struct machine *machine, char *fname)
Definition: diskimage.cc:659
char * fname
Definition: diskimage.h:62
u_short id
Definition: siireg.h:71
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
int is_boot_device
Definition: diskimage.h:80
int sectors_per_track
Definition: diskimage.h:72
int ncyls
Definition: diskimage.h:88

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13