Home | History | Annotate | Line # | Download | only in ppc
hw_shm.c revision 1.2
      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 typedef struct _hw_shm_device {
     81   unsigned_word physical_address;
     82   char *shm_address;
     83   unsigned sizeof_memory;
     84   key_t key;
     85   int id;
     86 } hw_shm_device;
     87 
     88 static void
     89 hw_shm_init_data(device *me)
     90 {
     91   hw_shm_device *shm = (hw_shm_device*)device_data(me);
     92   reg_property_spec reg;
     93   int i;
     94 
     95   /* Obtain the Key Value */
     96   if (device_find_property(me, "key") == NULL)
     97     error("shm_init_data() required key property is missing\n");
     98 
     99   shm->key = (key_t) device_find_integer_property(me, "key");
    100   DTRACE(shm, ("shm key (0x%08jx)\n", (intmax_t)shm->key) );
    101 
    102   /* Figure out where this memory is in address space and how long it is */
    103   if ( !device_find_reg_array_property(me, "reg", 0, &reg) )
    104     error("hw_shm_init_data() no address registered\n");
    105 
    106   /* Determine the address and length being as paranoid as possible */
    107   shm->physical_address = 0xffffffff;
    108   shm->sizeof_memory = 0xffffffff;
    109 
    110   for ( i=0 ; i<reg.address.nr_cells; i++ ) {
    111     if (reg.address.cells[0] == 0 && reg.size.cells[0] == 0)
    112       continue;
    113 
    114     if ( shm->physical_address != 0xffffffff )
    115       device_error(me, "Only single celled address ranges supported\n");
    116 
    117     shm->physical_address = reg.address.cells[i];
    118     DTRACE(shm, ("shm physical_address=0x%x\n", shm->physical_address));
    119 
    120     shm->sizeof_memory = reg.size.cells[i];
    121     DTRACE(shm, ("shm length=0x%x\n", shm->sizeof_memory));
    122   }
    123 
    124   if ( shm->physical_address == 0xffffffff )
    125     device_error(me, "Address not specified\n" );
    126 
    127   if ( shm->sizeof_memory == 0xffffffff )
    128     device_error(me, "Length not specified\n" );
    129 
    130   /* Now actually attach to or create the shared memory area */
    131   shm->id = shmget(shm->key, shm->sizeof_memory, IPC_CREAT | 0660);
    132   if (shm->id == -1)
    133     error("hw_shm_init_data() shmget failed\n");
    134 
    135   shm->shm_address = shmat(shm->id, (char *)0, SHM_RND);
    136   if (shm->shm_address == (void *)-1)
    137     error("hw_shm_init_data() shmat failed\n");
    138 }
    139 
    140 static void
    141 hw_shm_attach_address_callback(device *me,
    142 				attach_type attach,
    143 				int space,
    144 				unsigned_word addr,
    145 				unsigned nr_bytes,
    146 				access_type access,
    147 				device *client) /*callback/default*/
    148 {
    149   if (space != 0)
    150     error("shm_attach_address_callback() invalid address space\n");
    151 
    152   if (nr_bytes == 0)
    153     error("shm_attach_address_callback() invalid size\n");
    154 }
    155 
    156 
    157 static unsigned
    158 hw_shm_io_read_buffer(device *me,
    159 			 void *dest,
    160 			 int space,
    161 			 unsigned_word addr,
    162 			 unsigned nr_bytes,
    163 			 cpu *processor,
    164 			 unsigned_word cia)
    165 {
    166   hw_shm_device *shm = (hw_shm_device*)device_data(me);
    167 
    168   /* do we need to worry about out of range addresses? */
    169 
    170   DTRACE(shm, ("read %p %x %x %x\n", \
    171      shm->shm_address, shm->physical_address, addr, nr_bytes) );
    172 
    173   memcpy(dest, &shm->shm_address[addr - shm->physical_address], nr_bytes);
    174   return nr_bytes;
    175 }
    176 
    177 
    178 static unsigned
    179 hw_shm_io_write_buffer(device *me,
    180 			  const void *source,
    181 			  int space,
    182 			  unsigned_word addr,
    183 			  unsigned nr_bytes,
    184 			  cpu *processor,
    185 			  unsigned_word cia)
    186 {
    187   hw_shm_device *shm = (hw_shm_device*)device_data(me);
    188 
    189   /* do we need to worry about out of range addresses? */
    190 
    191   DTRACE(shm, ("write %p %x %x %x\n", \
    192      shm->shm_address, shm->physical_address, addr, nr_bytes) );
    193 
    194   memcpy(&shm->shm_address[addr - shm->physical_address], source, nr_bytes);
    195   return nr_bytes;
    196 }
    197 
    198 static device_callbacks const hw_shm_callbacks = {
    199   { generic_device_init_address, hw_shm_init_data },
    200   { hw_shm_attach_address_callback, }, /* address */
    201   { hw_shm_io_read_buffer,
    202     hw_shm_io_write_buffer }, /* IO */
    203   { NULL, }, /* DMA */
    204   { NULL, }, /* interrupt */
    205   { NULL, }, /* unit */
    206   NULL,
    207 };
    208 
    209 static void *
    210 hw_shm_create(const char *name,
    211 		 const device_unit *unit_address,
    212 		 const char *args)
    213 {
    214   hw_shm_device *shm = ZALLOC(hw_shm_device);
    215   return shm;
    216 }
    217 
    218 
    219 
    220 const device_descriptor hw_shm_device_descriptor[] = {
    221   { "shm", hw_shm_create, &hw_shm_callbacks },
    222   { NULL },
    223 };
    224 
    225 #endif /* _HW_SHM_C_ */
    226