Remove path name from test case
[binutils-gdb.git] / sim / ppc / hw_disk.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4
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.
9
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.
14
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/>.
17
18 */
19
20
21 #ifndef _HW_DISK_C_
22 #define _HW_DISK_C_
23
24 #include "device_table.h"
25
26 #include "pk.h"
27
28 #include <stdio.h>
29 #include <unistd.h>
30
31 #ifndef SEEK_SET
32 #define SEEK_SET 0
33 #endif
34
35 /* DEVICE
36
37
38 cdrom - read-only removable mass storage device
39
40 disk - mass storage device
41
42 floppy - removable mass storage device
43
44
45 DESCRIPTION
46
47
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.
52
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.
58
59 The above mass storage devices provide two interfaces - a logical
60 and a physical.
61
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.
65
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.
72
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.
77
78 | (gdb) sim
79
80
81 PROPERTIES
82
83
84 file = <file-name> (required)
85
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.
91
92
93 block-size = <nr-bytes> (optional)
94
95 The value is returned by the block-size method. The default value
96 is 512 bytes.
97
98
99 max-transfer = <nr-bytes> (optional)
100
101 The value is returned by the max-transfer method. The default value
102 is 512 bytes.
103
104
105 #blocks = <nr-blocks> (optional)
106
107 The value is returned by the #blocks method. If no value is
108 present then -1 is returned.
109
110
111 read-only = <anything> (optional)
112
113 If this property is present, the disk file image is always opened
114 read-only.
115
116 EXAMPLES
117
118
119 Enable tracing
120
121 | $ psim -t 'disk-device' \
122
123
124 Add a CDROM and disk to an IDE bus. Specify the host operating
125 system's cd drive as the CD-ROM image.
126
127 | -o '/pci/ide/disk@0/file "disk-image' \
128 | -o '/pci/ide/cdrom@1/file "/dev/cd0a' \
129
130
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
133 47.
134
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);
140
141
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.
145
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));
151
152
153 BUGS
154
155
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.
159
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.
163
164 The disk does not know its size. Hence it relies on the failure of
165 fread(), fwrite() and fseek() calls to detect errors.
166
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.
170
171 The method #blocks should `stat' the disk to determine the number
172 of blocks if there is no #blocks property.
173
174 It would appear that OpenFirmware does not define a client call for
175 changing (ejecting) the media of a device.
176
177 */
178
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;
187
188 typedef struct _hw_disk_instance {
189 unsigned_word pos;
190 hw_disk_device *disk;
191 } hw_disk_instance;
192
193
194 static void
195 open_disk_image(device *me,
196 hw_disk_device *disk,
197 const char *name)
198 {
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);
208 }
209
210 DTRACE(disk, ("image %s (%s)\n",
211 disk->name,
212 (disk->read_only ? "read-only" : "read-write")));
213 }
214
215 static void
216 hw_disk_init_address(device *me)
217 {
218 hw_disk_device *disk = device_data(me);
219 unsigned_word address;
220 int space;
221 const char *name;
222
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);
230
231 /* Tell the world we are a disk. */
232 device_add_string_property(me, "device_type", "block");
233
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");
240
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);
246
247 /* now open it */
248 open_disk_image(me, disk, name);
249 }
250
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)
257 {
258 switch (request) {
259 case device_ioctl_change_media:
260 {
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;
265 }
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");
271 }
272 open_disk_image(me, disk, name);
273 }
274 break;
275 default:
276 device_error(me, "insupported ioctl request");
277 break;
278 }
279 return 0;
280 }
281
282
283
284
285
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)
294 {
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;
310 }
311
312
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)
321 {
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;
339 }
340
341
342 /* instances of the hw_disk device */
343
344 static void
345 hw_disk_instance_delete(device_instance *instance)
346 {
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);
351 }
352
353 static int
354 hw_disk_instance_read(device_instance *instance,
355 void *buf,
356 unsigned_word len)
357 {
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;
370 }
371
372 static int
373 hw_disk_instance_write(device_instance *instance,
374 const void *buf,
375 unsigned_word len)
376 {
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;
391 }
392
393 static int
394 hw_disk_instance_seek(device_instance *instance,
395 unsigned_word pos_hi,
396 unsigned_word pos_lo)
397 {
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;
407 }
408
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*/])
415 {
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;
421 }
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;
433 }
434 }
435
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*/])
442 {
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;
448 }
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;
460 }
461 }
462
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*/])
469 {
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;
475 }
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;
487 }
488 }
489
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, },
495 };
496
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,
503 };
504
505 static device_instance *
506 hw_disk_create_instance(device *me,
507 const char *path,
508 const char *args)
509 {
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);
523 }
524
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,
535 };
536
537
538 static void *
539 hw_disk_create(const char *name,
540 const device_unit *unit_address,
541 const char *args)
542 {
543 /* create the descriptor */
544 hw_disk_device *hw_disk = ZALLOC(hw_disk_device);
545 return hw_disk;
546 }
547
548
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 },
554 };
555
556 #endif /* _HW_DISK_C_ */