/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 38 - (hide annotations)
Mon Oct 8 16:21:53 2007 UTC (16 years, 7 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 dpavlin 36 /*
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 dpavlin 38 * $Id: diskimage.c,v 1.5 2007/03/26 03:01:09 debug Exp $
29 dpavlin 36 *
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 dpavlin 38 * diskimage_exist():
104 dpavlin 36 *
105 dpavlin 38 * Returns 1 if the specified disk id (for a specific type) exists, 0
106     * otherwise.
107 dpavlin 36 */
108 dpavlin 38 int diskimage_exist(struct machine *machine, int id, int type)
109 dpavlin 36 {
110 dpavlin 38 struct diskimage *d = machine->first_diskimage;
111 dpavlin 36
112 dpavlin 38 while (d != NULL) {
113     if (d->type == type && d->id == id)
114     return 1;
115     d = d->next;
116 dpavlin 36 }
117 dpavlin 38 return 0;
118 dpavlin 36 }
119    
120    
121     /*
122 dpavlin 38 * diskimage_add_overlay():
123 dpavlin 36 *
124 dpavlin 38 * Opens an overlay data file and its corresponding bitmap file, and adds
125     * the overlay to a disk image.
126 dpavlin 36 */
127 dpavlin 38 void diskimage_add_overlay(struct diskimage *d, char *overlay_basename)
128 dpavlin 36 {
129 dpavlin 38 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 dpavlin 36 exit(1);
136     }
137 dpavlin 38 snprintf(bitmap_name, bitmap_name_len, "%s.map", overlay_basename);
138 dpavlin 36
139 dpavlin 38 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 dpavlin 36
146 dpavlin 38 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 dpavlin 36 }
152    
153 dpavlin 38 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 dpavlin 36 exit(1);
159     }
160    
161 dpavlin 38 d->overlays[d->nr_of_overlays - 1] = overlay;
162 dpavlin 36
163 dpavlin 38 free(bitmap_name);
164 dpavlin 36 }
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 dpavlin 38 void diskimage_recalc_size(struct diskimage *d)
174 dpavlin 36 {
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 dpavlin 38 /* Helper function. */
320     static void overlay_set_block_in_use(struct diskimage *d,
321     int overlay_nr, off_t ofs)
322 dpavlin 36 {
323 dpavlin 38 off_t bit_nr = ofs / OVERLAY_BLOCK_SIZE;
324     off_t bitmap_file_offset = bit_nr / 8;
325 dpavlin 36 int res;
326 dpavlin 38 unsigned char data;
327 dpavlin 36
328 dpavlin 38 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 dpavlin 36 exit(1);
335     }
336    
337 dpavlin 38 /* 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 dpavlin 36
342 dpavlin 38 data |= (1 << (bit_nr & 7));
343 dpavlin 36
344 dpavlin 38 /* 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 dpavlin 36 }
353 dpavlin 38 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 dpavlin 36 }
358     }
359    
360    
361 dpavlin 38 /* Helper function. */
362     static int overlay_has_block(struct diskimage *d, int overlay_nr, off_t ofs)
363 dpavlin 36 {
364 dpavlin 38 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 dpavlin 36
369 dpavlin 38 res = my_fseek(d->overlays[overlay_nr].f_bitmap,
370     bitmap_file_offset, SEEK_SET);
371     if (res != 0)
372 dpavlin 36 return 0;
373    
374 dpavlin 38 /* The seek succeeded, now read the bit: */
375     res = fread(&data, 1, 1, d->overlays[overlay_nr].f_bitmap);
376     if (res != 1)
377 dpavlin 36 return 0;
378    
379 dpavlin 38 if (data & (1 << (bit_nr & 7)))
380     return 1;
381 dpavlin 36
382 dpavlin 38 return 0;
383     }
384 dpavlin 36
385    
386 dpavlin 38 /*
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 dpavlin 36 {
395 dpavlin 38 off_t curofs;
396 dpavlin 36
397 dpavlin 38 /* 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 dpavlin 36 }
405    
406 dpavlin 38 return fwrite(buf, 1, len, d->f);
407     }
408 dpavlin 36
409 dpavlin 38 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 dpavlin 36
421 dpavlin 38 /* 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 dpavlin 36 }
433    
434 dpavlin 38 lenwritten = fwrite(buf, 1, OVERLAY_BLOCK_SIZE,
435     d->overlays[overlay_nr].f_data);
436     buf += OVERLAY_BLOCK_SIZE;
437 dpavlin 36
438 dpavlin 38 /* Mark this block in the last overlay as in use: */
439     overlay_set_block_in_use(d, overlay_nr, curofs);
440     }
441 dpavlin 36
442 dpavlin 38 return len;
443     }
444 dpavlin 36
445    
446 dpavlin 38 /*
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 dpavlin 36
459 dpavlin 38 /* 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 dpavlin 36 }
467    
468 dpavlin 38 return fread(buf, 1, len, d->f);
469     }
470 dpavlin 36
471 dpavlin 38 /* 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 dpavlin 36 }
482    
483 dpavlin 38 lentoread = len > OVERLAY_BLOCK_SIZE? OVERLAY_BLOCK_SIZE : len;
484 dpavlin 36
485 dpavlin 38 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 dpavlin 36 }
494 dpavlin 38 lenread = fread(buf, 1, lentoread,
495     d->overlays[overlay_nr].f_data);
496 dpavlin 36 } else {
497 dpavlin 38 /* 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 dpavlin 36 }
504 dpavlin 38 lenread = fread(buf, 1, lentoread, d->f);
505 dpavlin 36 }
506    
507 dpavlin 38 if (lenread != lentoread) {
508     fatal("[ INCOMPLETE READ from disk id %i, offset"
509     " %lli ]\n", d->id, (long long)curofs);
510 dpavlin 36 }
511    
512 dpavlin 38 len -= lentoread;
513     totallenread += lenread;
514     buf += OVERLAY_BLOCK_SIZE;
515     }
516 dpavlin 36
517 dpavlin 38 return totallenread;
518     }
519 dpavlin 36
520    
521 dpavlin 38 /*
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 dpavlin 36
533 dpavlin 38 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 dpavlin 36
542 dpavlin 38 if (writeflag) {
543     if (!d->writable)
544     return 0;
545 dpavlin 36
546 dpavlin 38 lendone = fwrite_helper(offset, buf, len, d);
547     } else {
548 dpavlin 36 /*
549 dpavlin 38 * 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 dpavlin 36 */
553 dpavlin 38 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 dpavlin 36
558 dpavlin 38 if (lendone < (ssize_t)len)
559     memset(buf + lendone, 0, len - lendone);
560     }
561 dpavlin 36
562 dpavlin 38 /* 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 dpavlin 36 }
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 dpavlin 38 * V add an overlay to a disk image
635 dpavlin 36 * 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 dpavlin 38 int prefix_o=0, prefix_V=0;
649 dpavlin 36
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 dpavlin 38 case 'V':
731     prefix_V = 1;
732     break;
733 dpavlin 36 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 dpavlin 38 /* 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 dpavlin 36 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 dpavlin 38 int i, iadd = DEBUG_INDENTATION;
1068 dpavlin 36 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 dpavlin 38 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 dpavlin 36 debug_indentation(-iadd);
1115    
1116     d = d->next;
1117     }
1118     }
1119    

  ViewVC Help
Powered by ViewVC 1.1.26