]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/hw_disk.c
Initial creation of sourceware repository
[thirdparty/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 2 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, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22 #ifndef _HW_DISK_C_
23 #define _HW_DISK_C_
24
25 #include "device_table.h"
26
27 #include "pk.h"
28
29 #include <stdio.h>
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #ifndef SEEK_SET
36 #define SEEK_SET 0
37 #endif
38
39 /* DEVICE
40
41
42 cdrom - read-only removable mass storage device
43
44 disk - mass storage device
45
46 floppy - removable mass storage device
47
48
49 DESCRIPTION
50
51
52 Mass storage devices such as a hard-disk or cdrom-drive are not
53 normally directly connected to the processor. Instead, these
54 devices are attached to a logical bus, such as SCSI or IDE, and
55 then a controller of that bus is made accessible to the processor.
56
57 Reflecting this, within a device tree, mass storage devices such as
58 a <<cdrom>>, <<disk>> or <<floppy>> are created as children of of a
59 logical bus controller node (such as a SCSI or IDE interface).
60 That controller, in turn, would be made the child of a physical bus
61 node that is directly accessible to the processor.
62
63 The above mass storage devices provide two interfaces - a logical
64 and a physical.
65
66 At the physical level the <<device_io_...>> functions can be used
67 perform reads and writes of the raw media. The address being
68 interpreted as an offset from the start of the disk.
69
70 At the logical level, it is possible to create an instance of the
71 disk that provides access to any of the physical media, a disk
72 partition, or even a file within a partition. The <<disk-label>>
73 package, which implements this functionality, is described
74 elsewhere. Both the Open Firmware and Moto BUG rom emulations
75 support this interface.
76
77 Block devices such as the <<floppy>> and <<cdrom>> have removable
78 media. At the programmer level, the media can be changed using the
79 <<change_media>> ioctl. From within GDB, a <<change-media>>
80 operation can be initated by using the command.
81
82 | (gdb) sim
83
84
85 PROPERTIES
86
87
88 file = <file-name> (required)
89
90 The name of the file that contains an image of the disk. For
91 <<disk>> and <<floppy>> devices, the image will be opened for both
92 reading and writing. Multiple image files may be specified, the
93 second and later files being opened when <<change-media>> (with a
94 NULL file name) being specified.
95
96
97 block-size = <nr-bytes> (optional)
98
99 The value is returned by the block-size method. The default value
100 is 512 bytes.
101
102
103 max-transfer = <nr-bytes> (optional)
104
105 The value is returned by the max-transfer method. The default value
106 is 512 bytes.
107
108
109 #blocks = <nr-blocks> (optional)
110
111 The value is returned by the #blocks method. If no value is
112 present then -1 is returned.
113
114
115 read-only = <anything> (optional)
116
117 If this property is present, the disk file image is always opened
118 read-only.
119
120 EXAMPLES
121
122
123 Enable tracing
124
125 | $ psim -t 'disk-device' \
126
127
128 Add a CDROM and disk to an IDE bus. Specify the host operating
129 system's cd drive as the CD-ROM image.
130
131 | -o '/pci/ide/disk@0/file "disk-image' \
132 | -o '/pci/ide/cdrom@1/file "/dev/cd0a' \
133
134
135 As part of the code implementing a logical bus device (for instance
136 the IDE controller), locate the CDROM device and then read block
137 47.
138
139 | device *cdrom = device_tree_find_device(me, "cdrom");
140 | char block[512];
141 | device_io_read_buffer(cdrom, buf, 0,
142 0, 47 * sizeof(block), // space, address
143 sizeof(block), NULL, 0);
144
145
146 Use the device instance interface to read block 47 of the file
147 called <<netbsd.elf>> on the disks default partition. Similar code
148 would be used in an operating systems pre-boot loader.
149
150 | device_instance *netbsd =
151 | device_create_instance(root, "/pci/ide/disk:,\netbsd.elf");
152 | char block[512];
153 | device_instance_seek(netbsd, 0, 47 * sizeof(block));
154 | device_instance_read(netbsd, block, sizeof(block));
155
156
157 BUGS
158
159
160 The block device specification includes mechanisms for determining
161 the physical device characteristics - such as the disks size.
162 Currently this mechanism is not implemented.
163
164 The functionality of this device (in particular the device instance
165 interface) depends on the implementation of <<disk-label>> package.
166 That package may not be fully implemented.
167
168 The disk does not know its size. Hence it relies on the failure of
169 fread(), fwrite() and fseek() calls to detect errors.
170
171 The disk size is limited by the addressable range covered by
172 unsigned_word (addr). An extension would be to instead use the
173 concatenated value space:addr.
174
175 The method #blocks should `stat' the disk to determine the number
176 of blocks if there is no #blocks property.
177
178 It would appear that OpenFirmware does not define a client call for
179 changing (ejecting) the media of a device.
180
181 */
182
183 typedef struct _hw_disk_device {
184 int name_index;
185 int nr_names;
186 char *name;
187 int read_only;
188 /* unsigned_word size; */
189 FILE *image;
190 } hw_disk_device;
191
192 typedef struct _hw_disk_instance {
193 unsigned_word pos;
194 hw_disk_device *disk;
195 } hw_disk_instance;
196
197
198 static void
199 open_disk_image(device *me,
200 hw_disk_device *disk,
201 const char *name)
202 {
203 if (disk->image != NULL)
204 fclose(disk->image);
205 if (disk->name != NULL)
206 zfree(disk->name);
207 disk->name = strdup(name);
208 disk->image = fopen(disk->name, disk->read_only ? "r" : "r+");
209 if (disk->image == NULL) {
210 perror(device_name(me));
211 device_error(me, "open %s failed\n", disk->name);
212 }
213
214 DTRACE(disk, ("image %s (%s)\n",
215 disk->name,
216 (disk->read_only ? "read-only" : "read-write")));
217 }
218
219 static void
220 hw_disk_init_address(device *me)
221 {
222 hw_disk_device *disk = device_data(me);
223 unsigned_word address;
224 int space;
225 const char *name;
226
227 /* attach to the parent. Since the bus is logical, attach using just
228 the unit-address (size must be zero) */
229 device_address_to_attach_address(device_parent(me), device_unit_address(me),
230 &space, &address, me);
231 device_attach_address(device_parent(me), attach_callback,
232 space, address, 0/*size*/, access_read_write_exec,
233 me);
234
235 /* get the name of the file specifying the disk image */
236 disk->name_index = 0;
237 disk->nr_names = device_find_string_array_property(me, "file",
238 disk->name_index, &name);
239 if (!disk->nr_names)
240 device_error(me, "invalid file property");
241
242 /* is it a RO device? */
243 disk->read_only =
244 (strcmp(device_name(me), "disk") != 0
245 && strcmp(device_name(me), "floppy") != 0
246 && device_find_property(me, "read-only") == NULL);
247
248 /* now open it */
249 open_disk_image(me, disk, name);
250 }
251
252 static int
253 hw_disk_ioctl(device *me,
254 cpu *processor,
255 unsigned_word cia,
256 device_ioctl_request request,
257 va_list ap)
258 {
259 switch (request) {
260 case device_ioctl_change_media:
261 {
262 hw_disk_device *disk = device_data(me);
263 const char *name = va_arg(ap, const char *);
264 if (name != NULL) {
265 disk->name_index = -1;
266 }
267 else {
268 disk->name_index = (disk->name_index + 1) % disk->nr_names;
269 if (!device_find_string_array_property(me, "file",
270 disk->name_index, &name))
271 device_error(me, "invalid file property");
272 }
273 open_disk_image(me, disk, name);
274 }
275 break;
276 default:
277 device_error(me, "insupported ioctl request");
278 break;
279 }
280 return 0;
281 }
282
283
284
285
286
287 static unsigned
288 hw_disk_io_read_buffer(device *me,
289 void *dest,
290 int space,
291 unsigned_word addr,
292 unsigned nr_bytes,
293 cpu *processor,
294 unsigned_word cia)
295 {
296 hw_disk_device *disk = device_data(me);
297 unsigned nr_bytes_read;
298 if (space != 0)
299 device_error(me, "read - extended disk addressing unimplemented");
300 if (nr_bytes == 0)
301 nr_bytes_read = 0;
302 else if (fseek(disk->image, addr, SEEK_SET) < 0)
303 nr_bytes_read = 0;
304 else if (fread(dest, nr_bytes, 1, disk->image) != 1)
305 nr_bytes_read = 0;
306 else
307 nr_bytes_read = nr_bytes;
308 DTRACE(disk, ("io-read - address 0x%lx, nr-bytes-read %d, requested %d\n",
309 (unsigned long) addr, (int)nr_bytes_read, (int)nr_bytes));
310 return nr_bytes_read;
311 }
312
313
314 static unsigned
315 hw_disk_io_write_buffer(device *me,
316 const void *source,
317 int space,
318 unsigned_word addr,
319 unsigned nr_bytes,
320 cpu *processor,
321 unsigned_word cia)
322 {
323 hw_disk_device *disk = device_data(me);
324 unsigned nr_bytes_written;
325 if (space != 0)
326 device_error(me, "write - extended disk addressing unimplemented");
327 if (disk->read_only)
328 nr_bytes_written = 0;
329 else if (nr_bytes == 0)
330 nr_bytes_written = 0;
331 else if (fseek(disk->image, addr, SEEK_SET) < 0)
332 nr_bytes_written = 0;
333 else if (fwrite(source, nr_bytes, 1, disk->image) != 1)
334 nr_bytes_written = 0;
335 else
336 nr_bytes_written = nr_bytes;
337 DTRACE(disk, ("io-write - address 0x%lx, nr-bytes-written %d, requested %d\n",
338 (unsigned long) addr, (int)nr_bytes_written, (int)nr_bytes));
339 return nr_bytes_written;
340 }
341
342
343 /* instances of the hw_disk device */
344
345 static void
346 hw_disk_instance_delete(device_instance *instance)
347 {
348 hw_disk_instance *data = device_instance_data(instance);
349 DITRACE(disk, ("delete - instance=%ld\n",
350 (unsigned long)device_instance_to_external(instance)));
351 zfree(data);
352 }
353
354 static int
355 hw_disk_instance_read(device_instance *instance,
356 void *buf,
357 unsigned_word len)
358 {
359 hw_disk_instance *data = device_instance_data(instance);
360 DITRACE(disk, ("read - instance=%ld len=%ld\n",
361 (unsigned long)device_instance_to_external(instance),
362 (long)len));
363 if ((data->pos + len) < data->pos)
364 return -1; /* overflow */
365 if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
366 return -1;
367 if (fread(buf, len, 1, data->disk->image) != 1)
368 return -1;
369 data->pos = ftell(data->disk->image);
370 return len;
371 }
372
373 static int
374 hw_disk_instance_write(device_instance *instance,
375 const void *buf,
376 unsigned_word len)
377 {
378 hw_disk_instance *data = device_instance_data(instance);
379 DITRACE(disk, ("write - instance=%ld len=%ld\n",
380 (unsigned long)device_instance_to_external(instance),
381 (long)len));
382 if ((data->pos + len) < data->pos)
383 return -1; /* overflow */
384 if (data->disk->read_only)
385 return -1;
386 if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
387 return -1;
388 if (fwrite(buf, len, 1, data->disk->image) != 1)
389 return -1;
390 data->pos = ftell(data->disk->image);
391 return len;
392 }
393
394 static int
395 hw_disk_instance_seek(device_instance *instance,
396 unsigned_word pos_hi,
397 unsigned_word pos_lo)
398 {
399 hw_disk_instance *data = device_instance_data(instance);
400 if (pos_hi != 0)
401 device_error(device_instance_device(instance),
402 "seek - extended addressing unimplemented");
403 DITRACE(disk, ("seek - instance=%ld pos_hi=%ld pos_lo=%ld\n",
404 (unsigned long)device_instance_to_external(instance),
405 (long)pos_hi, (long)pos_lo));
406 data->pos = pos_lo;
407 return 0;
408 }
409
410 static int
411 hw_disk_max_transfer(device_instance *instance,
412 int n_stack_args,
413 unsigned32 stack_args[/*n_stack_args*/],
414 int n_stack_returns,
415 unsigned32 stack_returns[/*n_stack_returns*/])
416 {
417 device *me = device_instance_device(instance);
418 if ((n_stack_args != 0)
419 || (n_stack_returns != 1)) {
420 device_error(me, "Incorrect number of arguments for max-transfer method\n");
421 return -1;
422 }
423 else {
424 unsigned_cell max_transfer;
425 if (device_find_property(me, "max-transfer"))
426 max_transfer = device_find_integer_property(me, "max-transfer");
427 else
428 max_transfer = 512;
429 DITRACE(disk, ("max-transfer - instance=%ld max-transfer=%ld\n",
430 (unsigned long)device_instance_to_external(instance),
431 (long int)max_transfer));
432 stack_returns[0] = max_transfer;
433 return 0;
434 }
435 }
436
437 static int
438 hw_disk_block_size(device_instance *instance,
439 int n_stack_args,
440 unsigned32 stack_args[/*n_stack_args*/],
441 int n_stack_returns,
442 unsigned32 stack_returns[/*n_stack_returns*/])
443 {
444 device *me = device_instance_device(instance);
445 if ((n_stack_args != 0)
446 || (n_stack_returns != 1)) {
447 device_error(me, "Incorrect number of arguments for block-size method\n");
448 return -1;
449 }
450 else {
451 unsigned_cell block_size;
452 if (device_find_property(me, "block-size"))
453 block_size = device_find_integer_property(me, "block-size");
454 else
455 block_size = 512;
456 DITRACE(disk, ("block-size - instance=%ld block-size=%ld\n",
457 (unsigned long)device_instance_to_external(instance),
458 (long int)block_size));
459 stack_returns[0] = block_size;
460 return 0;
461 }
462 }
463
464 static int
465 hw_disk_nr_blocks(device_instance *instance,
466 int n_stack_args,
467 unsigned32 stack_args[/*n_stack_args*/],
468 int n_stack_returns,
469 unsigned32 stack_returns[/*n_stack_returns*/])
470 {
471 device *me = device_instance_device(instance);
472 if ((n_stack_args != 0)
473 || (n_stack_returns != 1)) {
474 device_error(me, "Incorrect number of arguments for block-size method\n");
475 return -1;
476 }
477 else {
478 unsigned_word nr_blocks;
479 if (device_find_property(me, "#blocks"))
480 nr_blocks = device_find_integer_property(me, "#blocks");
481 else
482 nr_blocks = -1;
483 DITRACE(disk, ("#blocks - instance=%ld #blocks=%ld\n",
484 (unsigned long)device_instance_to_external(instance),
485 (long int)nr_blocks));
486 stack_returns[0] = nr_blocks;
487 return 0;
488 }
489 }
490
491 static device_instance_methods hw_disk_instance_methods[] = {
492 { "max-transfer", hw_disk_max_transfer },
493 { "block-size", hw_disk_block_size },
494 { "#blocks", hw_disk_nr_blocks },
495 { NULL, },
496 };
497
498 static const device_instance_callbacks hw_disk_instance_callbacks = {
499 hw_disk_instance_delete,
500 hw_disk_instance_read,
501 hw_disk_instance_write,
502 hw_disk_instance_seek,
503 hw_disk_instance_methods,
504 };
505
506 static device_instance *
507 hw_disk_create_instance(device *me,
508 const char *path,
509 const char *args)
510 {
511 device_instance *instance;
512 hw_disk_device *disk = device_data(me);
513 hw_disk_instance *data = ZALLOC(hw_disk_instance);
514 data->disk = disk;
515 data->pos = 0;
516 instance = device_create_instance_from(me, NULL,
517 data,
518 path, args,
519 &hw_disk_instance_callbacks);
520 DITRACE(disk, ("create - path=%s(%s) instance=%ld\n",
521 path, args,
522 (unsigned long)device_instance_to_external(instance)));
523 return pk_disklabel_create_instance(instance, args);
524 }
525
526 static device_callbacks const hw_disk_callbacks = {
527 { hw_disk_init_address, NULL },
528 { NULL, }, /* address */
529 { hw_disk_io_read_buffer,
530 hw_disk_io_write_buffer, },
531 { NULL, }, /* DMA */
532 { NULL, }, /* interrupt */
533 { NULL, }, /* unit */
534 hw_disk_create_instance,
535 hw_disk_ioctl,
536 };
537
538
539 static void *
540 hw_disk_create(const char *name,
541 const device_unit *unit_address,
542 const char *args)
543 {
544 /* create the descriptor */
545 hw_disk_device *hw_disk = ZALLOC(hw_disk_device);
546 return hw_disk;
547 }
548
549
550 const device_descriptor hw_disk_device_descriptor[] = {
551 { "disk", hw_disk_create, &hw_disk_callbacks },
552 { "cdrom", hw_disk_create, &hw_disk_callbacks },
553 { "floppy", hw_disk_create, &hw_disk_callbacks },
554 { NULL },
555 };
556
557 #endif /* _HW_DISK_C_ */