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