/[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 40 - (show annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 26925 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1539 2007/05/01 04:03:51 debug Exp $
20070415	Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes
		the clock run at correct speed.)
		FINALLY found and fixed the bug which caused OpenBSD/landisk
		to randomly bug out: an &-sign was missing in the special case
		handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction.
		Adding similar special case handling for 'LDC.L @Rm+,SR'
		(calling sh_update_sr() instead of just loading).
		Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL'
		SuperH instructions.
		The 'LDC Rm,SR' instruction now immediately breaks out of the
		dyntrans loop if an interrupt is to be triggered.
20070416	In memory_rw.c, if mapping a page as writable, make sure to
		invalidate code translations even if the data access was a
		read.
		Minor SuperH updates.
20070418	Removing the dummy M68K emulation mode.
		Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn,
		and sts_pr_rn instruction handlers into mov_rm_rn).
20070419	Beginning to add a skeleton for an M88K mode: Adding a hack to
		allow OpenBSD/m88k a.out binaries to be loaded, and disassembly
		of a few simple 88K instructions.
		Commenting out the 'LDC Rm,SR' fix from a few days ago, because
		it made Linux/dreamcast bug out.
		Adding a hack to dev_sh4.c (an extra translation cache
		invalidation), which allows OpenBSD/landisk to boot ok after
		an install. Upgrading the Landisk machine mode to stable,
		updating documentation, etc.
20070420	Experimenting with adding a PCI controller (pcic) to dev_sh4.
		Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c).
		Implementing the first M88K instructions (br, or[.u] imm), and
		adding disassembly of some more instructions.
20070421	Continuing a little on dev_rtl8139c.
20070422	Implementing the 9346 EEPROM "read" command for dev_rtl8139c.
		Finally found and fixed an old bug in the log n symbol search
		(it sometimes missed symbols). Debug trace (-i, -t etc) should
		now show more symbols. :-)
20070423	Continuing a little on M88K disassembly.
20070428	Fixing a memset arg order bug in src/net/net.c (thanks to
		Nigel Horne for noticing the bug).
		Applying parts of a patch from Carl van Schaik to clear out
		bottom bits of MIPS addresses more correctly, when using large
		page sizes, and doing some other minor cleanup/refactoring.
		Fixing a couple of warnings given by gcc with the -W option (a
		few more warnings than just plain -Wall).
		Reducing SuperH dyntrans physical address space from 64-bit to
		32-bit (since SH5/SH64 isn't imlemented yet anyway).
		Adding address-to-symbol annotation to a few more instructions
		in the SuperH instruction trace output.
		Beginning regression testing for the next release.
		Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2,
		because OpenBSD/landisk may otherwise hang randomly.
20070429	The ugly hack/workaround to get OpenBSD/landisk booting without
		crashing does NOT work anymore (with the April 21 snapshot
		of OpenBSD/landisk). Strangely enough, removing the hack
		completely causes OpenBSD/landisk to work (!).
		More regression testing (re-testing everything SuperH-related,
		and some other things).
		Cobalt interrupts were actually broken; fixing by commenting
		out the DEC21143s in the Cobalt machine.
20070430	More regression testing.
20070501	Updating the OpenBSD/landisk install instructions to use
		4.1 instead of the current snapshot.
		GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround;
		reintroducing it again. (The 4.1 kernel is actually from
		2007-03-11.)
		Simplifying the NetBSD/evbarm install instructions a bit.
		More regression testing.

==============  RELEASE 0.4.5.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26