/* This file is part of the program psim. Copyright (C) 1997,2008, Joel Sherrill 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 . */ #ifndef _HW_SHM_C_ #define _HW_SHM_C_ #include "device_table.h" #ifdef HAVE_STRING_H #include #else #ifdef HAVE_STRINGS_H #include #endif #endif #include #include /* 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 =
(required) Determine where the memory lives in the parents address space. The SHM area is assumed to be of the same length. key = (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); const device_unit *d; 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 ; iphysical_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*/ { hw_shm_device *shm = (hw_shm_device*)device_data(me); 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_ */