/[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 40 - (hide annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 7 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 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 40 * $Id: diskimage.c,v 1.6 2007/04/28 09:19:52 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 dpavlin 40 for (curofs = offset; curofs < (off_t) (offset+len);
423     curofs += OVERLAY_BLOCK_SIZE) {
424 dpavlin 38 /* 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 dpavlin 36 }
434    
435 dpavlin 38 lenwritten = fwrite(buf, 1, OVERLAY_BLOCK_SIZE,
436     d->overlays[overlay_nr].f_data);
437     buf += OVERLAY_BLOCK_SIZE;
438 dpavlin 36
439 dpavlin 38 /* Mark this block in the last overlay as in use: */
440     overlay_set_block_in_use(d, overlay_nr, curofs);
441     }
442 dpavlin 36
443 dpavlin 38 return len;
444     }
445 dpavlin 36
446    
447 dpavlin 38 /*
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 dpavlin 36
460 dpavlin 38 /* 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 dpavlin 36 }
468    
469 dpavlin 38 return fread(buf, 1, len, d->f);
470     }
471 dpavlin 36
472 dpavlin 38 /* 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 dpavlin 36 }
483    
484 dpavlin 38 lentoread = len > OVERLAY_BLOCK_SIZE? OVERLAY_BLOCK_SIZE : len;
485 dpavlin 36
486 dpavlin 38 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 dpavlin 36 }
495 dpavlin 38 lenread = fread(buf, 1, lentoread,
496     d->overlays[overlay_nr].f_data);
497 dpavlin 36 } else {
498 dpavlin 38 /* 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 dpavlin 36 }
505 dpavlin 38 lenread = fread(buf, 1, lentoread, d->f);
506 dpavlin 36 }
507    
508 dpavlin 38 if (lenread != lentoread) {
509     fatal("[ INCOMPLETE READ from disk id %i, offset"
510     " %lli ]\n", d->id, (long long)curofs);
511 dpavlin 36 }
512    
513 dpavlin 38 len -= lentoread;
514     totallenread += lenread;
515     buf += OVERLAY_BLOCK_SIZE;
516     }
517 dpavlin 36
518 dpavlin 38 return totallenread;
519     }
520 dpavlin 36
521    
522 dpavlin 38 /*
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 dpavlin 36
534 dpavlin 38 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 dpavlin 36
543 dpavlin 38 if (writeflag) {
544     if (!d->writable)
545     return 0;
546 dpavlin 36
547 dpavlin 38 lendone = fwrite_helper(offset, buf, len, d);
548     } else {
549 dpavlin 36 /*
550 dpavlin 38 * 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 dpavlin 36 */
554 dpavlin 38 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 dpavlin 36
559 dpavlin 38 if (lendone < (ssize_t)len)
560     memset(buf + lendone, 0, len - lendone);
561     }
562 dpavlin 36
563 dpavlin 38 /* 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 dpavlin 36 }
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 dpavlin 38 * V add an overlay to a disk image
636 dpavlin 36 * 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 dpavlin 38 int prefix_o=0, prefix_V=0;
650 dpavlin 36
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 dpavlin 38 case 'V':
732     prefix_V = 1;
733     break;
734 dpavlin 36 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 dpavlin 38 /* 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 dpavlin 36 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 dpavlin 38 int i, iadd = DEBUG_INDENTATION;
1069 dpavlin 36 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 dpavlin 38 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 dpavlin 36 debug_indentation(-iadd);
1116    
1117     d = d->next;
1118     }
1119     }
1120    

  ViewVC Help
Powered by ViewVC 1.1.26