| /* This file is part of the program psim. |
| |
| Copyright (C) 1997,2008, Joel Sherrill <joel@OARcorp.com> |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, see <http://www.gnu.org/licenses/>. |
| |
| */ |
| |
| |
| #ifndef _HW_SHM_C_ |
| #define _HW_SHM_C_ |
| |
| #include "device_table.h" |
| |
| #include <string.h> |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| |
| |
| /* DEVICE |
| |
| |
| shm - map unix shared memory into psim address space |
| |
| |
| DESCRIPTION |
| |
| |
| This device implements an area of memory which is mapped into UNIX |
| shared memory. |
| |
| |
| PROPERTIES |
| |
| |
| reg = <address> <size> (required) |
| |
| Determine where the memory lives in the parents address space. |
| The SHM area is assumed to be of the same length. |
| |
| key = <integer> (required) |
| |
| This is the key of the unix shared memory area. |
| |
| EXAMPLES |
| |
| |
| Enable tracing of the shm: |
| |
| | bash$ psim -t shm-device \ |
| |
| |
| Configure a 512 kilobytes of UNIX shared memory with the key 0x12345678 |
| mapped into psim address space at 0x0c000000. |
| |
| | -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \ |
| | -o '/shm@0x0c000000/key 0x12345678' \ |
| |
| sim/ppc/run -o '/#address-cells 1' \ |
| -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \ |
| -o '/shm@0x0c000000/key 0x12345678' ../psim-hello/hello |
| |
| BUGS |
| |
| None known. |
| |
| */ |
| |
| typedef struct _hw_shm_device { |
| unsigned_word physical_address; |
| char *shm_address; |
| unsigned sizeof_memory; |
| key_t key; |
| int id; |
| } hw_shm_device; |
| |
| static void |
| hw_shm_init_data(device *me) |
| { |
| hw_shm_device *shm = (hw_shm_device*)device_data(me); |
| reg_property_spec reg; |
| int i; |
| |
| /* Obtain the Key Value */ |
| if (device_find_property(me, "key") == NULL) |
| error("shm_init_data() required key property is missing\n"); |
| |
| shm->key = (key_t) device_find_integer_property(me, "key"); |
| DTRACE(shm, ("shm key (0x%08x)\n", shm->key) ); |
| |
| /* Figure out where this memory is in address space and how long it is */ |
| if ( !device_find_reg_array_property(me, "reg", 0, ®) ) |
| error("hw_shm_init_data() no address registered\n"); |
| |
| /* Determine the address and length being as paranoid as possible */ |
| shm->physical_address = 0xffffffff; |
| shm->sizeof_memory = 0xffffffff; |
| |
| for ( i=0 ; i<reg.address.nr_cells; i++ ) { |
| if (reg.address.cells[0] == 0 && reg.size.cells[0] == 0) |
| continue; |
| |
| if ( shm->physical_address != 0xffffffff ) |
| device_error(me, "Only single celled address ranges supported\n"); |
| |
| shm->physical_address = reg.address.cells[i]; |
| DTRACE(shm, ("shm physical_address=0x%x\n", shm->physical_address)); |
| |
| shm->sizeof_memory = reg.size.cells[i]; |
| DTRACE(shm, ("shm length=0x%x\n", shm->sizeof_memory)); |
| } |
| |
| if ( shm->physical_address == 0xffffffff ) |
| device_error(me, "Address not specified\n" ); |
| |
| if ( shm->sizeof_memory == 0xffffffff ) |
| device_error(me, "Length not specified\n" ); |
| |
| /* Now actually attach to or create the shared memory area */ |
| shm->id = shmget(shm->key, shm->sizeof_memory, IPC_CREAT | 0660); |
| if (shm->id == -1) |
| error("hw_shm_init_data() shmget failed\n"); |
| |
| shm->shm_address = shmat(shm->id, (char *)0, SHM_RND); |
| if (shm->shm_address == (void *)-1) |
| error("hw_shm_init_data() shmat failed\n"); |
| } |
| |
| static void |
| hw_shm_attach_address_callback(device *me, |
| attach_type attach, |
| int space, |
| unsigned_word addr, |
| unsigned nr_bytes, |
| access_type access, |
| device *client) /*callback/default*/ |
| { |
| if (space != 0) |
| error("shm_attach_address_callback() invalid address space\n"); |
| |
| if (nr_bytes == 0) |
| error("shm_attach_address_callback() invalid size\n"); |
| } |
| |
| |
| static unsigned |
| hw_shm_io_read_buffer(device *me, |
| void *dest, |
| int space, |
| unsigned_word addr, |
| unsigned nr_bytes, |
| cpu *processor, |
| unsigned_word cia) |
| { |
| hw_shm_device *shm = (hw_shm_device*)device_data(me); |
| |
| /* do we need to worry about out of range addresses? */ |
| |
| DTRACE(shm, ("read %p %x %x %x\n", \ |
| shm->shm_address, shm->physical_address, addr, nr_bytes) ); |
| |
| memcpy(dest, &shm->shm_address[addr - shm->physical_address], nr_bytes); |
| return nr_bytes; |
| } |
| |
| |
| static unsigned |
| hw_shm_io_write_buffer(device *me, |
| const void *source, |
| int space, |
| unsigned_word addr, |
| unsigned nr_bytes, |
| cpu *processor, |
| unsigned_word cia) |
| { |
| hw_shm_device *shm = (hw_shm_device*)device_data(me); |
| |
| /* do we need to worry about out of range addresses? */ |
| |
| DTRACE(shm, ("write %p %x %x %x\n", \ |
| shm->shm_address, shm->physical_address, addr, nr_bytes) ); |
| |
| memcpy(&shm->shm_address[addr - shm->physical_address], source, nr_bytes); |
| return nr_bytes; |
| } |
| |
| static device_callbacks const hw_shm_callbacks = { |
| { generic_device_init_address, hw_shm_init_data }, |
| { hw_shm_attach_address_callback, }, /* address */ |
| { hw_shm_io_read_buffer, |
| hw_shm_io_write_buffer }, /* IO */ |
| { NULL, }, /* DMA */ |
| { NULL, }, /* interrupt */ |
| { NULL, }, /* unit */ |
| NULL, |
| }; |
| |
| static void * |
| hw_shm_create(const char *name, |
| const device_unit *unit_address, |
| const char *args) |
| { |
| hw_shm_device *shm = ZALLOC(hw_shm_device); |
| return shm; |
| } |
| |
| |
| |
| const device_descriptor hw_shm_device_descriptor[] = { |
| { "shm", hw_shm_create, &hw_shm_callbacks }, |
| { NULL }, |
| }; |
| |
| #endif /* _HW_SHM_C_ */ |