OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [sim/] [ppc/] [hw_disk.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*  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_ */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.