Fix whitespace snafu in tc-riscv.c
[binutils-gdb.git] / sim / ppc / hw_disk.c
blob54a11f62827380a0b4ca524ec89dc903de035a0a
1 /* This file is part of the program psim.
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #ifndef _HW_DISK_C_
22 #define _HW_DISK_C_
24 #include "device_table.h"
26 #include "pk.h"
28 #include <stdio.h>
29 #include <unistd.h>
31 #ifndef SEEK_SET
32 #define SEEK_SET 0
33 #endif
35 /* DEVICE
38 cdrom - read-only removable mass storage device
40 disk - mass storage device
42 floppy - removable mass storage device
45 DESCRIPTION
48 Mass storage devices such as a hard-disk or cdrom-drive are not
49 normally directly connected to the processor. Instead, these
50 devices are attached to a logical bus, such as SCSI or IDE, and
51 then a controller of that bus is made accessible to the processor.
53 Reflecting this, within a device tree, mass storage devices such as
54 a <<cdrom>>, <<disk>> or <<floppy>> are created as children of of a
55 logical bus controller node (such as a SCSI or IDE interface).
56 That controller, in turn, would be made the child of a physical bus
57 node that is directly accessible to the processor.
59 The above mass storage devices provide two interfaces - a logical
60 and a physical.
62 At the physical level the <<device_io_...>> functions can be used
63 perform reads and writes of the raw media. The address being
64 interpreted as an offset from the start of the disk.
66 At the logical level, it is possible to create an instance of the
67 disk that provides access to any of the physical media, a disk
68 partition, or even a file within a partition. The <<disk-label>>
69 package, which implements this functionality, is described
70 elsewhere. Both the Open Firmware and Moto BUG rom emulations
71 support this interface.
73 Block devices such as the <<floppy>> and <<cdrom>> have removable
74 media. At the programmer level, the media can be changed using the
75 <<change_media>> ioctl. From within GDB, a <<change-media>>
76 operation can be initated by using the command.
78 | (gdb) sim
81 PROPERTIES
84 file = <file-name> (required)
86 The name of the file that contains an image of the disk. For
87 <<disk>> and <<floppy>> devices, the image will be opened for both
88 reading and writing. Multiple image files may be specified, the
89 second and later files being opened when <<change-media>> (with a
90 NULL file name) being specified.
93 block-size = <nr-bytes> (optional)
95 The value is returned by the block-size method. The default value
96 is 512 bytes.
99 max-transfer = <nr-bytes> (optional)
101 The value is returned by the max-transfer method. The default value
102 is 512 bytes.
105 #blocks = <nr-blocks> (optional)
107 The value is returned by the #blocks method. If no value is
108 present then -1 is returned.
111 read-only = <anything> (optional)
113 If this property is present, the disk file image is always opened
114 read-only.
116 EXAMPLES
119 Enable tracing
121 | $ psim -t 'disk-device' \
124 Add a CDROM and disk to an IDE bus. Specify the host operating
125 system's cd drive as the CD-ROM image.
127 | -o '/pci/ide/disk@0/file "disk-image' \
128 | -o '/pci/ide/cdrom@1/file "/dev/cd0a' \
131 As part of the code implementing a logical bus device (for instance
132 the IDE controller), locate the CDROM device and then read block
135 | device *cdrom = device_tree_find_device(me, "cdrom");
136 | char block[512];
137 | device_io_read_buffer(cdrom, buf, 0,
138 0, 47 * sizeof(block), // space, address
139 sizeof(block), NULL, 0);
142 Use the device instance interface to read block 47 of the file
143 called <<netbsd.elf>> on the disks default partition. Similar code
144 would be used in an operating systems pre-boot loader.
146 | device_instance *netbsd =
147 | device_create_instance(root, "/pci/ide/disk:,\netbsd.elf");
148 | char block[512];
149 | device_instance_seek(netbsd, 0, 47 * sizeof(block));
150 | device_instance_read(netbsd, block, sizeof(block));
153 BUGS
156 The block device specification includes mechanisms for determining
157 the physical device characteristics - such as the disks size.
158 Currently this mechanism is not implemented.
160 The functionality of this device (in particular the device instance
161 interface) depends on the implementation of <<disk-label>> package.
162 That package may not be fully implemented.
164 The disk does not know its size. Hence it relies on the failure of
165 fread(), fwrite() and fseek() calls to detect errors.
167 The disk size is limited by the addressable range covered by
168 unsigned_word (addr). An extension would be to instead use the
169 concatenated value space:addr.
171 The method #blocks should `stat' the disk to determine the number
172 of blocks if there is no #blocks property.
174 It would appear that OpenFirmware does not define a client call for
175 changing (ejecting) the media of a device.
179 typedef struct _hw_disk_device {
180 int name_index;
181 int nr_names;
182 char *name;
183 int read_only;
184 /* unsigned_word size; */
185 FILE *image;
186 } hw_disk_device;
188 typedef struct _hw_disk_instance {
189 unsigned_word pos;
190 hw_disk_device *disk;
191 } hw_disk_instance;
194 static void
195 open_disk_image(device *me,
196 hw_disk_device *disk,
197 const char *name)
199 if (disk->image != NULL)
200 fclose(disk->image);
201 if (disk->name != NULL)
202 free(disk->name);
203 disk->name = strdup(name);
204 disk->image = fopen(disk->name, disk->read_only ? "r" : "r+");
205 if (disk->image == NULL) {
206 perror(device_name(me));
207 device_error(me, "open %s failed\n", disk->name);
210 DTRACE(disk, ("image %s (%s)\n",
211 disk->name,
212 (disk->read_only ? "read-only" : "read-write")));
215 static void
216 hw_disk_init_address(device *me)
218 hw_disk_device *disk = device_data(me);
219 unsigned_word address;
220 int space;
221 const char *name;
223 /* attach to the parent. Since the bus is logical, attach using just
224 the unit-address (size must be zero) */
225 device_address_to_attach_address(device_parent(me), device_unit_address(me),
226 &space, &address, me);
227 device_attach_address(device_parent(me), attach_callback,
228 space, address, 0/*size*/, access_read_write_exec,
229 me);
231 /* Tell the world we are a disk. */
232 device_add_string_property(me, "device_type", "block");
234 /* get the name of the file specifying the disk image */
235 disk->name_index = 0;
236 disk->nr_names = device_find_string_array_property(me, "file",
237 disk->name_index, &name);
238 if (!disk->nr_names)
239 device_error(me, "invalid file property");
241 /* is it a RO device? */
242 disk->read_only =
243 (strcmp(device_name(me), "disk") != 0
244 && strcmp(device_name(me), "floppy") != 0
245 && device_find_property(me, "read-only") == NULL);
247 /* now open it */
248 open_disk_image(me, disk, name);
251 static int
252 hw_disk_ioctl(device *me,
253 cpu *processor,
254 unsigned_word cia,
255 device_ioctl_request request,
256 va_list ap)
258 switch (request) {
259 case device_ioctl_change_media:
261 hw_disk_device *disk = device_data(me);
262 const char *name = va_arg(ap, const char *);
263 if (name != NULL) {
264 disk->name_index = -1;
266 else {
267 disk->name_index = (disk->name_index + 1) % disk->nr_names;
268 if (!device_find_string_array_property(me, "file",
269 disk->name_index, &name))
270 device_error(me, "invalid file property");
272 open_disk_image(me, disk, name);
274 break;
275 default:
276 device_error(me, "insupported ioctl request");
277 break;
279 return 0;
286 static unsigned
287 hw_disk_io_read_buffer(device *me,
288 void *dest,
289 int space,
290 unsigned_word addr,
291 unsigned nr_bytes,
292 cpu *processor,
293 unsigned_word cia)
295 hw_disk_device *disk = device_data(me);
296 unsigned nr_bytes_read;
297 if (space != 0)
298 device_error(me, "read - extended disk addressing unimplemented");
299 if (nr_bytes == 0)
300 nr_bytes_read = 0;
301 else if (fseek(disk->image, addr, SEEK_SET) < 0)
302 nr_bytes_read = 0;
303 else if (fread(dest, nr_bytes, 1, disk->image) != 1)
304 nr_bytes_read = 0;
305 else
306 nr_bytes_read = nr_bytes;
307 DTRACE(disk, ("io-read - address 0x%lx, nr-bytes-read %d, requested %d\n",
308 (unsigned long) addr, (int)nr_bytes_read, (int)nr_bytes));
309 return nr_bytes_read;
313 static unsigned
314 hw_disk_io_write_buffer(device *me,
315 const void *source,
316 int space,
317 unsigned_word addr,
318 unsigned nr_bytes,
319 cpu *processor,
320 unsigned_word cia)
322 hw_disk_device *disk = device_data(me);
323 unsigned nr_bytes_written;
324 if (space != 0)
325 device_error(me, "write - extended disk addressing unimplemented");
326 if (disk->read_only)
327 nr_bytes_written = 0;
328 else if (nr_bytes == 0)
329 nr_bytes_written = 0;
330 else if (fseek(disk->image, addr, SEEK_SET) < 0)
331 nr_bytes_written = 0;
332 else if (fwrite(source, nr_bytes, 1, disk->image) != 1)
333 nr_bytes_written = 0;
334 else
335 nr_bytes_written = nr_bytes;
336 DTRACE(disk, ("io-write - address 0x%lx, nr-bytes-written %d, requested %d\n",
337 (unsigned long) addr, (int)nr_bytes_written, (int)nr_bytes));
338 return nr_bytes_written;
342 /* instances of the hw_disk device */
344 static void
345 hw_disk_instance_delete(device_instance *instance)
347 hw_disk_instance *data = device_instance_data(instance);
348 DITRACE(disk, ("delete - instance=%ld\n",
349 (unsigned long)device_instance_to_external(instance)));
350 free(data);
353 static int
354 hw_disk_instance_read(device_instance *instance,
355 void *buf,
356 unsigned_word len)
358 hw_disk_instance *data = device_instance_data(instance);
359 DITRACE(disk, ("read - instance=%ld len=%ld\n",
360 (unsigned long)device_instance_to_external(instance),
361 (long)len));
362 if ((data->pos + len) < data->pos)
363 return -1; /* overflow */
364 if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
365 return -1;
366 if (fread(buf, len, 1, data->disk->image) != 1)
367 return -1;
368 data->pos = ftell(data->disk->image);
369 return len;
372 static int
373 hw_disk_instance_write(device_instance *instance,
374 const void *buf,
375 unsigned_word len)
377 hw_disk_instance *data = device_instance_data(instance);
378 DITRACE(disk, ("write - instance=%ld len=%ld\n",
379 (unsigned long)device_instance_to_external(instance),
380 (long)len));
381 if ((data->pos + len) < data->pos)
382 return -1; /* overflow */
383 if (data->disk->read_only)
384 return -1;
385 if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
386 return -1;
387 if (fwrite(buf, len, 1, data->disk->image) != 1)
388 return -1;
389 data->pos = ftell(data->disk->image);
390 return len;
393 static int
394 hw_disk_instance_seek(device_instance *instance,
395 unsigned_word pos_hi,
396 unsigned_word pos_lo)
398 hw_disk_instance *data = device_instance_data(instance);
399 if (pos_hi != 0)
400 device_error(device_instance_device(instance),
401 "seek - extended addressing unimplemented");
402 DITRACE(disk, ("seek - instance=%ld pos_hi=%ld pos_lo=%ld\n",
403 (unsigned long)device_instance_to_external(instance),
404 (long)pos_hi, (long)pos_lo));
405 data->pos = pos_lo;
406 return 0;
409 static int
410 hw_disk_max_transfer(device_instance *instance,
411 int n_stack_args,
412 uint32_t stack_args[/*n_stack_args*/],
413 int n_stack_returns,
414 uint32_t stack_returns[/*n_stack_returns*/])
416 device *me = device_instance_device(instance);
417 if ((n_stack_args != 0)
418 || (n_stack_returns != 1)) {
419 device_error(me, "Incorrect number of arguments for max-transfer method\n");
420 return -1;
422 else {
423 unsigned_cell max_transfer;
424 if (device_find_property(me, "max-transfer"))
425 max_transfer = device_find_integer_property(me, "max-transfer");
426 else
427 max_transfer = 512;
428 DITRACE(disk, ("max-transfer - instance=%ld max-transfer=%ld\n",
429 (unsigned long)device_instance_to_external(instance),
430 (long int)max_transfer));
431 stack_returns[0] = max_transfer;
432 return 0;
436 static int
437 hw_disk_block_size(device_instance *instance,
438 int n_stack_args,
439 uint32_t stack_args[/*n_stack_args*/],
440 int n_stack_returns,
441 uint32_t stack_returns[/*n_stack_returns*/])
443 device *me = device_instance_device(instance);
444 if ((n_stack_args != 0)
445 || (n_stack_returns != 1)) {
446 device_error(me, "Incorrect number of arguments for block-size method\n");
447 return -1;
449 else {
450 unsigned_cell block_size;
451 if (device_find_property(me, "block-size"))
452 block_size = device_find_integer_property(me, "block-size");
453 else
454 block_size = 512;
455 DITRACE(disk, ("block-size - instance=%ld block-size=%ld\n",
456 (unsigned long)device_instance_to_external(instance),
457 (long int)block_size));
458 stack_returns[0] = block_size;
459 return 0;
463 static int
464 hw_disk_nr_blocks(device_instance *instance,
465 int n_stack_args,
466 uint32_t stack_args[/*n_stack_args*/],
467 int n_stack_returns,
468 uint32_t stack_returns[/*n_stack_returns*/])
470 device *me = device_instance_device(instance);
471 if ((n_stack_args != 0)
472 || (n_stack_returns != 1)) {
473 device_error(me, "Incorrect number of arguments for block-size method\n");
474 return -1;
476 else {
477 unsigned_word nr_blocks;
478 if (device_find_property(me, "#blocks"))
479 nr_blocks = device_find_integer_property(me, "#blocks");
480 else
481 nr_blocks = -1;
482 DITRACE(disk, ("#blocks - instance=%ld #blocks=%ld\n",
483 (unsigned long)device_instance_to_external(instance),
484 (long int)nr_blocks));
485 stack_returns[0] = nr_blocks;
486 return 0;
490 static device_instance_methods hw_disk_instance_methods[] = {
491 { "max-transfer", hw_disk_max_transfer },
492 { "block-size", hw_disk_block_size },
493 { "#blocks", hw_disk_nr_blocks },
494 { NULL, },
497 static const device_instance_callbacks hw_disk_instance_callbacks = {
498 hw_disk_instance_delete,
499 hw_disk_instance_read,
500 hw_disk_instance_write,
501 hw_disk_instance_seek,
502 hw_disk_instance_methods,
505 static device_instance *
506 hw_disk_create_instance(device *me,
507 const char *path,
508 const char *args)
510 device_instance *instance;
511 hw_disk_device *disk = device_data(me);
512 hw_disk_instance *data = ZALLOC(hw_disk_instance);
513 data->disk = disk;
514 data->pos = 0;
515 instance = device_create_instance_from(me, NULL,
516 data,
517 path, args,
518 &hw_disk_instance_callbacks);
519 DITRACE(disk, ("create - path=%s(%s) instance=%ld\n",
520 path, args,
521 (unsigned long)device_instance_to_external(instance)));
522 return pk_disklabel_create_instance(instance, args);
525 static device_callbacks const hw_disk_callbacks = {
526 { hw_disk_init_address, NULL },
527 { NULL, }, /* address */
528 { hw_disk_io_read_buffer,
529 hw_disk_io_write_buffer, },
530 { NULL, }, /* DMA */
531 { NULL, }, /* interrupt */
532 { NULL, }, /* unit */
533 hw_disk_create_instance,
534 hw_disk_ioctl,
538 static void *
539 hw_disk_create(const char *name,
540 const device_unit *unit_address,
541 const char *args)
543 /* create the descriptor */
544 hw_disk_device *hw_disk = ZALLOC(hw_disk_device);
545 return hw_disk;
549 const device_descriptor hw_disk_device_descriptor[] = {
550 { "disk", hw_disk_create, &hw_disk_callbacks },
551 { "cdrom", hw_disk_create, &hw_disk_callbacks },
552 { "floppy", hw_disk_create, &hw_disk_callbacks },
553 { NULL },
556 #endif /* _HW_DISK_C_ */