Home | History | Annotate | Line # | Download | only in ppc
hw_shm.c revision 1.3
      1 /*  This file is part of the program psim.
      2 
      3     Copyright (C) 1997,2008, Joel Sherrill <joel (at) OARcorp.com>
      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_SHM_C_
     22 #define _HW_SHM_C_
     23 
     24 #include "device_table.h"
     25 
     26 #include <string.h>
     27 #include <sys/ipc.h>
     28 #include <sys/shm.h>
     29 
     30 
     31 /* DEVICE
     32 
     33 
     34    shm - map unix shared memory into psim address space
     35 
     36 
     37    DESCRIPTION
     38 
     39 
     40    This device implements an area of memory which is mapped into UNIX
     41    shared memory.
     42 
     43 
     44    PROPERTIES
     45 
     46 
     47    reg = <address> <size> (required)
     48 
     49    Determine where the memory lives in the parents address space.
     50    The SHM area is assumed to be of the same length.
     51 
     52    key = <integer> (required)
     53 
     54    This is the key of the unix shared memory area.
     55 
     56    EXAMPLES
     57 
     58 
     59    Enable tracing of the shm:
     60 
     61    |  bash$ psim -t shm-device \
     62 
     63 
     64    Configure a 512 kilobytes of UNIX shared memory with the key 0x12345678
     65    mapped into psim address space at 0x0c000000.
     66 
     67    |  -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \
     68    |  -o '/shm@0x0c000000/key 0x12345678' \
     69 
     70    sim/ppc/run -o '/#address-cells 1' \
     71          -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \
     72          -o '/shm@0x0c000000/key 0x12345678' ../psim-hello/hello
     73 
     74    BUGS
     75 
     76    None known.
     77 
     78    */
     79 
     80 #ifdef HAVE_SYSV_SHM
     81 
     82 typedef struct _hw_shm_device {
     83   unsigned_word physical_address;
     84   char *shm_address;
     85   unsigned sizeof_memory;
     86   key_t key;
     87   int id;
     88 } hw_shm_device;
     89 
     90 static void
     91 hw_shm_init_data(device *me)
     92 {
     93   hw_shm_device *shm = (hw_shm_device*)device_data(me);
     94   reg_property_spec reg;
     95   int i;
     96 
     97   /* Obtain the Key Value */
     98   if (device_find_property(me, "key") == NULL)
     99     error("shm_init_data() required key property is missing\n");
    100 
    101   shm->key = (key_t) device_find_integer_property(me, "key");
    102   DTRACE(shm, ("shm key (0x%08jx)\n", (intmax_t)shm->key) );
    103 
    104   /* Figure out where this memory is in address space and how long it is */
    105   if ( !device_find_reg_array_property(me, "reg", 0, &reg) )
    106     error("hw_shm_init_data() no address registered\n");
    107 
    108   /* Determine the address and length being as paranoid as possible */
    109   shm->physical_address = 0xffffffff;
    110   shm->sizeof_memory = 0xffffffff;
    111 
    112   for ( i=0 ; i<reg.address.nr_cells; i++ ) {
    113     if (reg.address.cells[0] == 0 && reg.size.cells[0] == 0)
    114       continue;
    115 
    116     if ( shm->physical_address != 0xffffffff )
    117       device_error(me, "Only single celled address ranges supported\n");
    118 
    119     shm->physical_address = reg.address.cells[i];
    120     DTRACE(shm, ("shm physical_address=0x%x\n", shm->physical_address));
    121 
    122     shm->sizeof_memory = reg.size.cells[i];
    123     DTRACE(shm, ("shm length=0x%x\n", shm->sizeof_memory));
    124   }
    125 
    126   if ( shm->physical_address == 0xffffffff )
    127     device_error(me, "Address not specified\n" );
    128 
    129   if ( shm->sizeof_memory == 0xffffffff )
    130     device_error(me, "Length not specified\n" );
    131 
    132   /* Now actually attach to or create the shared memory area */
    133   shm->id = shmget(shm->key, shm->sizeof_memory, IPC_CREAT | 0660);
    134   if (shm->id == -1)
    135     error("hw_shm_init_data() shmget failed\n");
    136 
    137   shm->shm_address = shmat(shm->id, (char *)0, SHM_RND);
    138   if (shm->shm_address == (void *)-1)
    139     error("hw_shm_init_data() shmat failed\n");
    140 }
    141 
    142 static void
    143 hw_shm_attach_address_callback(device *me,
    144 				attach_type attach,
    145 				int space,
    146 				unsigned_word addr,
    147 				unsigned nr_bytes,
    148 				access_type access,
    149 				device *client) /*callback/default*/
    150 {
    151   if (space != 0)
    152     error("shm_attach_address_callback() invalid address space\n");
    153 
    154   if (nr_bytes == 0)
    155     error("shm_attach_address_callback() invalid size\n");
    156 }
    157 
    158 
    159 static unsigned
    160 hw_shm_io_read_buffer(device *me,
    161 			 void *dest,
    162 			 int space,
    163 			 unsigned_word addr,
    164 			 unsigned nr_bytes,
    165 			 cpu *processor,
    166 			 unsigned_word cia)
    167 {
    168   hw_shm_device *shm = (hw_shm_device*)device_data(me);
    169 
    170   /* do we need to worry about out of range addresses? */
    171 
    172   DTRACE(shm, ("read %p %x %x %x\n", \
    173      shm->shm_address, shm->physical_address, addr, nr_bytes) );
    174 
    175   memcpy(dest, &shm->shm_address[addr - shm->physical_address], nr_bytes);
    176   return nr_bytes;
    177 }
    178 
    179 
    180 static unsigned
    181 hw_shm_io_write_buffer(device *me,
    182 			  const void *source,
    183 			  int space,
    184 			  unsigned_word addr,
    185 			  unsigned nr_bytes,
    186 			  cpu *processor,
    187 			  unsigned_word cia)
    188 {
    189   hw_shm_device *shm = (hw_shm_device*)device_data(me);
    190 
    191   /* do we need to worry about out of range addresses? */
    192 
    193   DTRACE(shm, ("write %p %x %x %x\n", \
    194      shm->shm_address, shm->physical_address, addr, nr_bytes) );
    195 
    196   memcpy(&shm->shm_address[addr - shm->physical_address], source, nr_bytes);
    197   return nr_bytes;
    198 }
    199 
    200 static device_callbacks const hw_shm_callbacks = {
    201   { generic_device_init_address, hw_shm_init_data },
    202   { hw_shm_attach_address_callback, }, /* address */
    203   { hw_shm_io_read_buffer,
    204     hw_shm_io_write_buffer }, /* IO */
    205   { NULL, }, /* DMA */
    206   { NULL, }, /* interrupt */
    207   { NULL, }, /* unit */
    208   NULL,
    209 };
    210 
    211 static void *
    212 hw_shm_create(const char *name,
    213 		 const device_unit *unit_address,
    214 		 const char *args)
    215 {
    216   hw_shm_device *shm = ZALLOC(hw_shm_device);
    217   return shm;
    218 }
    219 
    220 
    221 
    222 const device_descriptor hw_shm_device_descriptor[] = {
    223   { "shm", hw_shm_create, &hw_shm_callbacks },
    224   { NULL },
    225 };
    226 
    227 #else
    228 
    229 const device_descriptor hw_shm_device_descriptor[] = {
    230   { NULL },
    231 };
    232 
    233 #endif /* HAVE_SYSV_SHM */
    234 
    235 #endif /* _HW_SHM_C_ */
    236