Implement virtual memory for ARM manager
Instead of allocating memory for address range mappings (ARM) and handling all reads and writes to said memory, the new ARM manager calls a function for each received request with the data, transaction code, and allocation information. The ARM tag manager now must handle validation of memory accesses and retreive/write the data. This allows implementations to use network resources or generated data as memory. The ARM manager no longer automatically sends response packets. It is the responsibility of the user to send response packets using raw1394_send_rw_response(). The interface is not implemented for raw1394 and will probably never be implemented for raw1394. It is for firewire-cdev (modern Linux) only.
This commit is contained in:
parent
410e6dca92
commit
48b2af0507
|
@ -229,7 +229,7 @@ int raw1394_loop_iterate(raw1394handle_t handle)
|
|||
}
|
||||
|
||||
int raw1394_arm_register(raw1394handle_t handle, nodeaddr_t start,
|
||||
size_t length, byte_t *initial_value,
|
||||
size_t length,
|
||||
octlet_t arm_tag, arm_options_t access_rights,
|
||||
arm_options_t notification_options,
|
||||
arm_options_t client_transactions)
|
||||
|
@ -239,12 +239,13 @@ int raw1394_arm_register(raw1394handle_t handle, nodeaddr_t start,
|
|||
return -1;
|
||||
}
|
||||
if (handle->is_fw)
|
||||
return fw_arm_register(handle->mode.fw, start, length, initial_value,
|
||||
return fw_arm_register(handle->mode.fw, start, length,
|
||||
arm_tag, access_rights, notification_options, client_transactions);
|
||||
else
|
||||
return ieee1394_arm_register(handle->mode.ieee1394, start, length,
|
||||
initial_value, arm_tag, access_rights, notification_options,
|
||||
client_transactions);
|
||||
else {
|
||||
/* FIXME: implement for raw1394 */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start)
|
||||
|
@ -259,30 +260,21 @@ int raw1394_arm_unregister(raw1394handle_t handle, nodeaddr_t start)
|
|||
return ieee1394_arm_unregister(handle->mode.ieee1394, start);
|
||||
}
|
||||
|
||||
int raw1394_arm_set_buf (raw1394handle_t handle, nodeaddr_t start,
|
||||
size_t length, void *buf)
|
||||
int
|
||||
raw1394_send_rw_response(raw1394handle_t handle, int tcode, void *data, size_t len,
|
||||
unsigned kernel_handle)
|
||||
{
|
||||
if (!handle) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (handle->is_fw)
|
||||
return fw_arm_set_buf(handle->mode.fw, start, length, buf);
|
||||
else
|
||||
return ieee1394_arm_set_buf(handle->mode.ieee1394, start, length, buf);
|
||||
}
|
||||
|
||||
int raw1394_arm_get_buf (raw1394handle_t handle, nodeaddr_t start,
|
||||
size_t length, void *buf)
|
||||
{
|
||||
if (!handle) {
|
||||
errno = EINVAL;
|
||||
return fw_send_rw_response(handle->mode.fw, tcode, data, len, kernel_handle);
|
||||
else {
|
||||
/* FIXME: implement for raw1394 */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
if (handle->is_fw)
|
||||
return fw_arm_get_buf(handle->mode.fw, start, length, buf);
|
||||
else
|
||||
return ieee1394_arm_get_buf(handle->mode.ieee1394, start, length, buf);
|
||||
}
|
||||
|
||||
int raw1394_echo_request(raw1394handle_t handle, quadlet_t data)
|
||||
|
|
|
@ -65,12 +65,15 @@ int ieee1394_loop_iterate(struct raw1394_handle *handle)
|
|||
break;
|
||||
|
||||
case RAW1394_REQ_ARM:
|
||||
/* FIXME: implement new ARM for raw1394 */
|
||||
#if 0
|
||||
if (ihandle->arm_tag_handler) {
|
||||
retval = ihandle->arm_tag_handler(handle, req.tag,
|
||||
(req.misc & (0xFF)),
|
||||
((req.misc >> 16) & (0xFFFF)),
|
||||
int2ptr(req.recvb));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case RAW1394_REQ_ECHO:
|
||||
|
|
215
src/fw.c
215
src/fw.c
|
@ -31,6 +31,13 @@
|
|||
*/
|
||||
#define IMPLEMENTED_CDEV_ABI_VERSION 4
|
||||
|
||||
struct address_closure {
|
||||
int (*callback)(raw1394handle_t handle, struct address_closure *ac,
|
||||
int tcode, unsigned long long offset,
|
||||
int source_node_id, int card, unsigned kernel_handle,
|
||||
size_t length, void *data);
|
||||
};
|
||||
|
||||
int
|
||||
fw_errcode_to_errno(raw1394_errcode_t errcode)
|
||||
{
|
||||
|
@ -92,18 +99,25 @@ default_tag_handler(raw1394handle_t handle,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* do nothing */
|
||||
static int
|
||||
default_arm_tag_handler(raw1394handle_t handle, unsigned long arm_tag,
|
||||
byte_t type, unsigned int length, void *data)
|
||||
default_arm_tag_handler(
|
||||
raw1394handle_t handle, raw1394_arm_allocation_t *arm,
|
||||
int tcode, unsigned long long offset, int source_node_id,
|
||||
int card, unsigned kernel_handle, size_t length, void *data
|
||||
)
|
||||
{
|
||||
struct raw1394_arm_reqhandle *rh;
|
||||
(void)handle;
|
||||
(void)arm;
|
||||
(void)tcode;
|
||||
(void)offset;
|
||||
(void)source_node_id;
|
||||
(void)card;
|
||||
(void)kernel_handle;
|
||||
(void)length;
|
||||
(void)data;
|
||||
|
||||
if (arm_tag == 0)
|
||||
return -1;
|
||||
|
||||
rh = (struct raw1394_arm_reqhandle *) arm_tag;
|
||||
|
||||
return rh->arm_callback(handle, data, length, rh->pcontext, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -214,13 +228,6 @@ handle_lost_device(fw_handle_t handle, int i)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct address_closure {
|
||||
int (*callback)(raw1394handle_t handle, struct address_closure *ac,
|
||||
int tcode, unsigned long long offset,
|
||||
int source_node_id, int card, unsigned kernel_handle,
|
||||
size_t length, void *data);
|
||||
};
|
||||
|
||||
static int
|
||||
handle_fcp_request(raw1394handle_t handle, struct address_closure *ac,
|
||||
int tcode, unsigned long long offset, int source_node_id,
|
||||
|
@ -310,9 +317,9 @@ handle_device_event(raw1394handle_t handle,
|
|||
|
||||
return fwhandle->tag_handler(handle, tag, errcode);
|
||||
|
||||
case FW_CDEV_EVENT_REQUEST:
|
||||
ac = u64_to_ptr(u->request.closure);
|
||||
return ac->callback(handle, ac, u->request.tcode,
|
||||
case FW_CDEV_EVENT_REQUEST: {
|
||||
raw1394_arm_allocation_t *al = u64_to_ptr(u->response.closure);
|
||||
return fwhandle->arm_tag_handler(handle, al, u->request.tcode,
|
||||
u->request.offset,
|
||||
/* wild guess, but can't do better */
|
||||
fwhandle->devices[i].node_id,
|
||||
|
@ -320,15 +327,15 @@ handle_device_event(raw1394handle_t handle,
|
|||
u->request.handle,
|
||||
u->request.length, u->request.data);
|
||||
|
||||
case FW_CDEV_EVENT_REQUEST2:
|
||||
ac = u64_to_ptr(u->request.closure);
|
||||
return ac->callback(handle, ac, u->request2.tcode,
|
||||
} case FW_CDEV_EVENT_REQUEST2: {
|
||||
raw1394_arm_allocation_t *al = u64_to_ptr(u->response.closure);
|
||||
return fwhandle->arm_tag_handler(handle, al, u->request2.tcode,
|
||||
u->request2.offset,
|
||||
u->request2.source_node_id,
|
||||
u->request2.card,
|
||||
u->request2.handle,
|
||||
u->request2.length, u->request2.data);
|
||||
|
||||
}
|
||||
case FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED:
|
||||
case FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED:
|
||||
memcpy(u64_to_ptr(u->iso_resource.closure), u,
|
||||
|
@ -769,40 +776,26 @@ struct request_response_block {
|
|||
};
|
||||
|
||||
struct allocation {
|
||||
struct address_closure closure; /* must be first member */
|
||||
raw1394_arm_allocation_t info;
|
||||
struct allocation *next;
|
||||
__u32 handle;
|
||||
byte_t *buffer;
|
||||
octlet_t tag;
|
||||
arm_options_t access_rights;
|
||||
arm_options_t notification_options;
|
||||
arm_options_t client_transactions;
|
||||
nodeaddr_t offset;
|
||||
size_t length;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
static int
|
||||
handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
||||
int tcode, unsigned long long offset, int source_node_id,
|
||||
int card, unsigned kernel_handle, size_t length, void *data)
|
||||
int
|
||||
fw_send_rw_response(fw_handle_t fwhandle, int tcode, void *data, size_t len,
|
||||
unsigned kernel_handle)
|
||||
{
|
||||
fw_handle_t fwhandle = handle->mode.fw;
|
||||
struct allocation *allocation = (struct allocation *) ac;
|
||||
struct request_response_block *rrb;
|
||||
struct fw_cdev_send_response response;
|
||||
arm_options_t type;
|
||||
size_t in_length;
|
||||
int pos, retval;
|
||||
|
||||
pos = offset - allocation->offset;
|
||||
if (data == NULL)
|
||||
len = 0;
|
||||
|
||||
response.handle = kernel_handle;
|
||||
|
||||
response.data = ptr_to_u64(data);
|
||||
response.length = len;
|
||||
switch (tcode) {
|
||||
case TCODE_WRITE_QUADLET_REQUEST:
|
||||
case TCODE_WRITE_BLOCK_REQUEST:
|
||||
type = RAW1394_ARM_WRITE;
|
||||
in_length = length;
|
||||
response.rcode = RCODE_COMPLETE;
|
||||
response.length = 0;
|
||||
response.data = 0;
|
||||
|
@ -810,11 +803,7 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
|
||||
case TCODE_READ_QUADLET_REQUEST:
|
||||
case TCODE_READ_BLOCK_REQUEST:
|
||||
type = RAW1394_ARM_READ;
|
||||
in_length = 0;
|
||||
response.rcode = RCODE_COMPLETE;
|
||||
response.length = length;
|
||||
response.data = ptr_to_u64(allocation->data + pos);
|
||||
break;
|
||||
|
||||
case TCODE_LOCK_REQUEST:
|
||||
|
@ -829,84 +818,18 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
case TCODE_LOCK_BOUNDED_ADD:
|
||||
case TCODE_LOCK_WRAP_ADD:
|
||||
case TCODE_LOCK_VENDOR_DEPENDENT:
|
||||
type = RAW1394_ARM_LOCK;
|
||||
in_length = length;
|
||||
response.length = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
in_length = 0;
|
||||
type = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(allocation->access_rights & type)) {
|
||||
response.rcode = RCODE_TYPE_ERROR;
|
||||
response.length = 0;
|
||||
response.data = 0;
|
||||
if (ioctl(fwhandle->ioctl_fd,
|
||||
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
|
||||
if (ioctl(fwhandle->ioctl_fd, FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
|
||||
return -1;
|
||||
} else if (!(allocation->client_transactions & type)) {
|
||||
if (type == RAW1394_ARM_WRITE)
|
||||
memcpy(allocation->data + pos, data, length);
|
||||
else if (type == RAW1394_ARM_LOCK)
|
||||
/* FIXME: do lock ops here */;
|
||||
|
||||
if (ioctl(fwhandle->ioctl_fd,
|
||||
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* libraw1394 clients do not expect requests from nodes on
|
||||
* a card other than the one set by raw1394_set_port().
|
||||
*/
|
||||
if (card != fwhandle->card)
|
||||
return 0;
|
||||
|
||||
if (!(allocation->notification_options & type))
|
||||
return 0;
|
||||
|
||||
rrb = malloc(sizeof *rrb + in_length + response.length);
|
||||
if (rrb == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rrb->request_response.request = &rrb->request;
|
||||
rrb->request_response.response = &rrb->response;
|
||||
|
||||
rrb->request.destination_nodeid = fwhandle->reset.local_node_id;
|
||||
rrb->request.source_nodeid = source_node_id;
|
||||
rrb->request.destination_offset = offset;
|
||||
rrb->request.tlabel = 0;
|
||||
if (tcode < 0x10) {
|
||||
rrb->request.tcode = tcode;
|
||||
rrb->request.extended_transaction_code = 0;
|
||||
} else {
|
||||
rrb->request.tcode = TCODE_LOCK_REQUEST;
|
||||
rrb->request.extended_transaction_code = tcode - 0x10;
|
||||
}
|
||||
rrb->request.generation = fwhandle->reset.generation;
|
||||
rrb->request.buffer_length = in_length;
|
||||
rrb->request.buffer = rrb->data;
|
||||
memcpy(rrb->request.buffer, data, in_length);
|
||||
|
||||
rrb->response.response_code = response.rcode;
|
||||
rrb->response.buffer_length = response.length;
|
||||
rrb->response.buffer = rrb->data + in_length;
|
||||
memcpy(rrb->response.buffer, allocation->data + pos, response.length);
|
||||
|
||||
retval = fwhandle->arm_tag_handler(handle, allocation->tag, type,
|
||||
length, &rrb->request_response);
|
||||
free(rrb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
fw_arm_register(fw_handle_t handle, nodeaddr_t start,
|
||||
size_t length, byte_t *initial_value,
|
||||
size_t length,
|
||||
octlet_t arm_tag, arm_options_t access_rights,
|
||||
arm_options_t notification_options,
|
||||
arm_options_t client_transactions)
|
||||
|
@ -915,26 +838,22 @@ fw_arm_register(fw_handle_t handle, nodeaddr_t start,
|
|||
struct allocation *allocation;
|
||||
int retval;
|
||||
|
||||
allocation = malloc(sizeof *allocation + length);
|
||||
allocation = malloc(sizeof *allocation);
|
||||
if (allocation == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
allocation->closure.callback = handle_arm_request;
|
||||
allocation->buffer = initial_value;
|
||||
allocation->tag = arm_tag;
|
||||
allocation->access_rights = access_rights;
|
||||
allocation->notification_options = notification_options;
|
||||
allocation->client_transactions = client_transactions;
|
||||
allocation->offset = start;
|
||||
allocation->length = length;
|
||||
if (initial_value != NULL)
|
||||
memcpy(allocation->data, initial_value, length);
|
||||
allocation->info.tag = arm_tag;
|
||||
allocation->info.access_rights = access_rights;
|
||||
allocation->info.notification_options = notification_options;
|
||||
allocation->info.client_transactions = client_transactions;
|
||||
allocation->info.offset = start;
|
||||
allocation->info.length = length;
|
||||
|
||||
request.offset = start;
|
||||
request.length = length;
|
||||
request.closure = ptr_to_u64(&allocation->closure);
|
||||
request.closure = ptr_to_u64(allocation);
|
||||
request.region_end = start + length;
|
||||
|
||||
retval = ioctl(handle->ioctl_fd, FW_CDEV_IOC_ALLOCATE, &request);
|
||||
|
@ -957,7 +876,7 @@ lookup_allocation(fw_handle_t handle, nodeaddr_t start, int delete)
|
|||
|
||||
prev = &handle->allocations;
|
||||
for (a = handle->allocations; a != NULL; a = a->next) {
|
||||
if (a->offset <= start && start < a->offset + a->length)
|
||||
if (a->info.offset <= start && start < a->info.offset + a->info.length)
|
||||
break;
|
||||
prev = &a->next;
|
||||
}
|
||||
|
@ -986,40 +905,6 @@ fw_arm_unregister(fw_handle_t handle, nodeaddr_t start)
|
|||
return ioctl(handle->ioctl_fd, FW_CDEV_IOC_DEALLOCATE, &request);
|
||||
}
|
||||
|
||||
int
|
||||
fw_arm_set_buf(fw_handle_t handle, nodeaddr_t start,
|
||||
size_t length, void *buf)
|
||||
{
|
||||
struct allocation *allocation;
|
||||
|
||||
allocation = lookup_allocation(handle, start, 0);
|
||||
if (allocation == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(allocation->data + allocation->offset - start, buf, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fw_arm_get_buf(fw_handle_t handle, nodeaddr_t start,
|
||||
size_t length, void *buf)
|
||||
{
|
||||
struct allocation *allocation;
|
||||
|
||||
allocation = lookup_allocation(handle, start, 0);
|
||||
if (allocation == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf, allocation->data + allocation->offset - start, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fw_echo_request(fw_handle_t handle, quadlet_t data)
|
||||
{
|
||||
|
|
8
src/fw.h
8
src/fw.h
|
@ -150,16 +150,14 @@ int fw_get_port_info(fw_handle_t handle, struct raw1394_portinfo *pinf,
|
|||
int maxports);
|
||||
int fw_set_port(fw_handle_t handle, int port);
|
||||
int fw_reset_bus_new(fw_handle_t handle, int type);
|
||||
int fw_send_rw_response(fw_handle_t handle, int tcode, void *data, size_t len,
|
||||
unsigned kernel_handle);
|
||||
int fw_arm_register(fw_handle_t handle, nodeaddr_t start,
|
||||
size_t length, byte_t *initial_value,
|
||||
size_t length,
|
||||
octlet_t arm_tag, arm_options_t access_rights,
|
||||
arm_options_t notification_options,
|
||||
arm_options_t client_transactions);
|
||||
int fw_arm_unregister(fw_handle_t handle, nodeaddr_t start);
|
||||
int fw_arm_set_buf(fw_handle_t handle, nodeaddr_t start,
|
||||
size_t length, void *buf);
|
||||
int fw_arm_get_buf(fw_handle_t handle, nodeaddr_t start,
|
||||
size_t length, void *buf);
|
||||
int fw_echo_request(fw_handle_t handle, quadlet_t data);
|
||||
int fw_wake_up(fw_handle_t handle);
|
||||
int fw_start_read(fw_handle_t handle, nodeid_t node, nodeaddr_t addr,
|
||||
|
|
|
@ -705,9 +705,20 @@ typedef int (*tag_handler_t)(raw1394handle_t, unsigned long tag,
|
|||
tag_handler_t raw1394_set_tag_handler(raw1394handle_t handle,
|
||||
tag_handler_t new_h);
|
||||
|
||||
typedef int (*arm_tag_handler_t)(raw1394handle_t handle, unsigned long arm_tag,
|
||||
byte_t request_type,
|
||||
unsigned int requested_length, void *data);
|
||||
typedef struct raw1394_arm_allocation_t {
|
||||
octlet_t tag;
|
||||
arm_options_t access_rights;
|
||||
arm_options_t notification_options;
|
||||
arm_options_t client_transactions;
|
||||
nodeaddr_t offset;
|
||||
size_t length;
|
||||
} raw1394_arm_allocation_t;
|
||||
|
||||
typedef int (*arm_tag_handler_t)(
|
||||
raw1394handle_t handle, raw1394_arm_allocation_t *arm,
|
||||
int tcode, unsigned long long offset, int source_node_id,
|
||||
int card, unsigned kernel_handle, size_t length, void *data
|
||||
);
|
||||
|
||||
/**
|
||||
* raw1394_set_arm_tag_handler - set the async request handler
|
||||
|
@ -718,11 +729,40 @@ typedef int (*arm_tag_handler_t)(raw1394handle_t handle, unsigned long arm_tag,
|
|||
* arrived. The default action is to call the arm_callback in the
|
||||
* raw1394_arm_reqhandle pointed to by arm_tag.
|
||||
*
|
||||
* The program will not send requests for you. The kernel_handle and tcode must be
|
||||
* passed to send_rw_response() along with the data to be sent.
|
||||
*
|
||||
* The handler must handle the reads and writes. It must also arrange to call
|
||||
* send_rw_response(). It should be safe to call send_rw_response() from inside
|
||||
* the loop.
|
||||
*
|
||||
* Returns: old handler or NULL on failure (sets errno)
|
||||
**/
|
||||
arm_tag_handler_t raw1394_set_arm_tag_handler(raw1394handle_t handle,
|
||||
arm_tag_handler_t new_h);
|
||||
|
||||
/**
|
||||
* raw1394_send_rw_response - send response to ARM
|
||||
* @handle: libraw1394 handle
|
||||
* @tcode: tcode from ARM tag handler
|
||||
* @data: data to send
|
||||
* @len: length of data
|
||||
* @kernel_handle: handle from ARM tag handler
|
||||
*
|
||||
* Send a response to a request packet. The packet may contain data if the
|
||||
* request was a read request.
|
||||
*
|
||||
* The request can also be an error request if the tcode is changed to
|
||||
* an error code.
|
||||
*
|
||||
* If no data should be send, set data = NULL.
|
||||
*
|
||||
* Returns: 0 on success or -1 on failure.
|
||||
*/
|
||||
int
|
||||
raw1394_send_rw_response(raw1394handle_t handle, int tcode, void *data,
|
||||
size_t len, unsigned kernel_handle);
|
||||
|
||||
typedef int (*fcp_handler_t)(raw1394handle_t, nodeid_t nodeid, int response,
|
||||
size_t length, unsigned char *data);
|
||||
|
||||
|
@ -779,8 +819,6 @@ struct raw1394_arm_reqhandle {
|
|||
* @handle: libraw1394 handle
|
||||
* @start: identifies address range
|
||||
* @length: identifies address range
|
||||
* @initial_value: pointer to buffer containing (if necessary) initial value
|
||||
* NULL means undefined
|
||||
* @arm_tag: identifier for arm_tag_handler
|
||||
* (usually pointer to raw1394_arm_reqhandle)
|
||||
* @access_rights: access-rights for registered address range handled
|
||||
|
@ -803,7 +841,7 @@ struct raw1394_arm_reqhandle {
|
|||
* Returns: 0 on success or -1 on failure (sets errno)
|
||||
**/
|
||||
int raw1394_arm_register(raw1394handle_t handle, nodeaddr_t start,
|
||||
size_t length, byte_t *initial_value,
|
||||
size_t length,
|
||||
octlet_t arm_tag, arm_options_t access_rights,
|
||||
arm_options_t notification_options,
|
||||
arm_options_t client_transactions);
|
||||
|
|
Reference in New Issue