/[gxemul]/trunk/src/disk/diskimage.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/disk/diskimage.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 38 - (show annotations)
Mon Oct 8 16:21:53 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 26903 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1515 2007/04/14 05:39:46 debug Exp $
20070324	Adding a "--debug" option to the configure script, to disable
		optimizations in unstable development builds.
		Moving out SCSI-specific stuff from diskimage.c into a new
		diskimage_scsicmd.c.
		Applying Hĺvard Eidnes' patch for SCSICDROM_READ_DISKINFO and
		SCSICDROM_READ_TRACKINFO. (Not really tested yet.)
		Implementing disk image "overlays" (to allow simple roll-back
		to previous disk state). Adding a 'V' disk flag for this, and
		updating the man page and misc.html.
20070325	Stability fix to cpu_dyntrans.c, when multiple physical pages
		share the same initial table entry. (The ppp == NULL check
		should be physpage_ofs == 0.) Bug found by analysing GXemul
		against a version patched for Godson.
		Fixing a second occurance of the same problem (also in
		cpu_dyntrans.c).
		Fixing a MAJOR physical page leak in cpu_dyntrans.c; pages
		weren't _added_ to the set of translated pages, they _replaced_
		all previous pages. It's amazing that this bug has been able
		to live for this long. (Triggered when emulating >128MB RAM.)
20070326	Removing the GDB debugging stub support; it was too hackish
		and ugly.
20070328	Moving around some native code generation skeleton code.
20070329	The -lm check in the configure script now also checks for sin()
		in addition to sqrt(). (Thanks to Nigel Horne for noticing that
		sqrt was not enough on Fedora Core 6.) (Not verified yet.)
20070330	Fixing an indexing bug in dev_sh4.c, found by using gcc version
		4.3.0 20070323.
20070331	Some more experimentation with native code generation.
20070404	Attempting to fix some more SH4 SCIF interrupt bugs; rewriting
		the SH interrupt assertion/deassertion code somewhat.
20070410	Splitting src/file.c into separate files in src/file/.
		Cleanup: Removing the dummy TS7200, Walnut, PB1000, and
		Meshcube emulation modes, and dev_epcom and dev_au1x00.
		Removing the experimental CHIP8/RCA180x code; it wasn't really
		working much lately, anyway. It was fun while it lasted.
		Also removing the experimental Transputer CPU support.
20070412	Moving the section about how the dynamic translation system
		works from intro.html to a separate translation.html file.
		Minor SH fixes; attempting to get OpenBSD/landisk to run
		without randomly bugging out, but no success yet.
20070413	SH SCI (serial bit interface) should now work together with a
		(new) RS5C313 clock device (for Landisk emulation).
20070414	Moving Redhat/MIPS down from supported to experimental, in
		guestoses.html.
		Preparing for a new release; doing some regression testing etc.

==============  RELEASE 0.4.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26