From 21bf6f025d94c2987dfe30a0b327b6dfab7a8bff Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 4 Jun 2010 16:51:24 +0200 Subject: support block devices in the DDE library. --- libmachdev/mach_glue.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 libmachdev/mach_glue.h (limited to 'libmachdev/mach_glue.h') diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h new file mode 100644 index 00000000..6d0870ed --- /dev/null +++ b/libmachdev/mach_glue.h @@ -0,0 +1,30 @@ +#ifndef __MACH_GLUE_H__ +#define __MACH_GLUE_H__ + +/* network */ +#include + +struct sk_buff; +struct net_device; +void skb_done_queue(struct sk_buff *skb); +struct sk_buff *skb_done_dequeue(); +void *skb_reply(struct sk_buff *skb); +int netdev_flags(struct net_device *dev); +char *netdev_addr(struct net_device *dev); +int dev_change_flags (struct net_device *dev, short flags); +int linux_pkg_xmit (char *pkg_data, int len, void *del_data, + int (*del_func) (struct sk_buff *, void *), + struct net_device *dev); +struct net_device *search_netdev (char *name); +void kfree_skb (struct sk_buff *skb); +int dev_open(struct net_device *dev); +void *l4dde26_register_rx_callback(void *cb); +void skb_done_head_init(); + +/* block device */ +struct block_device; +struct block_device *open_block_dev (char *name, int part, dev_mode_t mode); +int block_dev_write (struct block_device *dev, int sectornr, + char *data, int count, void (*write_done) (int err)); + +#endif -- cgit v1.2.3 From 5a9d844a537293b0398f22003cd31bb61864f746 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 1 Aug 2010 15:57:31 +0200 Subject: Use BPF to filter the packets to be delivered. --- libdde_linux26/lib/src/mach_glue/net.c | 25 +++++ libmachdev/Makefile | 2 +- libmachdev/if_hdr.h | 165 +++++++++++++++++++++++++++++++++ libmachdev/mach_glue.h | 7 ++ libmachdev/net.c | 118 +++++++++++++---------- 5 files changed, 265 insertions(+), 52 deletions(-) create mode 100644 libmachdev/if_hdr.h (limited to 'libmachdev/mach_glue.h') diff --git a/libdde_linux26/lib/src/mach_glue/net.c b/libdde_linux26/lib/src/mach_glue/net.c index 48373a90..3ab9e44f 100644 --- a/libdde_linux26/lib/src/mach_glue/net.c +++ b/libdde_linux26/lib/src/mach_glue/net.c @@ -66,6 +66,31 @@ int netdev_flags(struct net_device *dev) return dev->flags; } +char *netdev_name (struct net_device *dev) +{ + return dev->name; +} + +unsigned int netdev_mtu (struct net_device *dev) +{ + return dev->mtu; +} + +unsigned short netdev_header_len (struct net_device *dev) +{ + return dev->hard_header_len; +} + +unsigned short netdev_type (struct net_device *dev) +{ + return dev->type; +} + +unsigned char netdev_addr_len (struct net_device *dev) +{ + return dev->addr_len; +} + void *skb_reply(struct sk_buff *skb) { return skb->del_data; diff --git a/libmachdev/Makefile b/libmachdev/Makefile index 22909949..224dfddb 100644 --- a/libmachdev/Makefile +++ b/libmachdev/Makefile @@ -30,7 +30,7 @@ OBJS = $(SRCS:.c=.o) $(MIGSTUBS) include ../Makeconf -CFLAGS += -I$(top_srcdir)/libddekit/include +CFLAGS += -I$(top_srcdir)/libddekit/include -I$(top_srcdir)/libbpf ourdevice.defs: device.defs $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out[ ]*device[ ]*:[ ]*device_t/s/device_t/mach_port_send_t/' > $@ diff --git a/libmachdev/if_hdr.h b/libmachdev/if_hdr.h new file mode 100644 index 00000000..74d0fa8a --- /dev/null +++ b/libmachdev/if_hdr.h @@ -0,0 +1,165 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Taken from (bsd)net/if.h. Modified for MACH kernel. + */ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. The name of the Laboratory may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if.h 7.3 (Berkeley) 6/27/88 + */ + +#ifndef _IF_HDR_ +#define _IF_HDR_ + +#include +#include +#include + +#if 0 +/* + * Queue for network output and filter input. + */ +struct ifqueue { + queue_head_t ifq_head; /* queue of io_req_t */ + int ifq_len; /* length of queue */ + int ifq_maxlen; /* maximum length of queue */ + int ifq_drops; /* number of packets dropped + because queue full */ + decl_simple_lock_data(, + ifq_lock) /* lock for queue and counters */ +}; +#endif + +/* + * Header for network interface drivers. + */ +struct ifnet { + short if_unit; /* unit number */ + short if_flags; /* up/down, broadcast, etc. */ + short if_timer; /* time until if_watchdog called */ + short if_mtu; /* maximum transmission unit */ + short if_header_size; /* length of header */ + short if_header_format; /* format of hardware header */ + short if_address_size; /* length of hardware address */ + short if_alloc_size; /* size of read buffer to allocate */ + char *if_address; /* pointer to hardware address */ +// struct ifqueue if_snd; /* output queue */ + if_filter_list_t port_list; + struct mutex if_rcv_port_list_lock;/* lock for input filter list */ + struct mutex if_snd_port_list_lock;/* lock for output filter list */ +/* statistics */ + int if_ipackets; /* packets received */ + int if_ierrors; /* input errors */ + int if_opackets; /* packets sent */ + int if_oerrors; /* output errors */ + int if_collisions; /* collisions on csma interfaces */ + int if_rcvdrops; /* packets received but dropped */ +}; + +#define IFF_UP 0x0001 /* interface is up */ +#define IFF_BROADCAST 0x0002 /* interface can broadcast */ +#define IFF_DEBUG 0x0004 /* turn on debugging */ +#define IFF_LOOPBACK 0x0008 /* is a loopback net */ +#define IFF_POINTOPOINT 0x0010 /* point-to-point link */ +#define IFF_RUNNING 0x0040 /* resources allocated */ +#define IFF_NOARP 0x0080 /* no address resolution protocol */ +#define IFF_PROMISC 0x0100 /* receive all packets */ +#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */ +#define IFF_BRIDGE 0x0100 /* support token ring routing field */ +#define IFF_SNAP 0x0200 /* support extended sap header */ + +/* internal flags only: */ +#define IFF_CANTCHANGE (IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING) + +/* + * Output queues (ifp->if_snd) + * have queues of messages stored on ifqueue structures. Entries + * are added to and deleted from these structures by these macros, which + * should be called with ipl raised to splimp(). + * XXX locking XXX + */ + +#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen) +#define IF_DROP(ifq) ((ifq)->ifq_drops++) +#define IF_ENQUEUE(ifq, ior) { \ + simple_lock(&(ifq)->ifq_lock); \ + enqueue_tail(&(ifq)->ifq_head, (queue_entry_t)ior); \ + (ifq)->ifq_len++; \ + simple_unlock(&(ifq)->ifq_lock); \ +} +#define IF_PREPEND(ifq, ior) { \ + simple_lock(&(ifq)->ifq_lock); \ + enqueue_head(&(ifq)->ifq_head, (queue_entry_t)ior); \ + (ifq)->ifq_len++; \ + simple_unlock(&(ifq)->ifq_lock); \ +} + +#define IF_DEQUEUE(ifq, ior) { \ + simple_lock(&(ifq)->ifq_lock); \ + if (((ior) = (io_req_t)dequeue_head(&(ifq)->ifq_head)) != 0) \ + (ifq)->ifq_len--; \ + simple_unlock(&(ifq)->ifq_lock); \ +} + +#define IFQ_MAXLEN 50 + +#define IFQ_INIT(ifq) { \ + queue_init(&(ifq)->ifq_head); \ + simple_lock_init(&(ifq)->ifq_lock); \ + (ifq)->ifq_len = 0; \ + (ifq)->ifq_maxlen = IFQ_MAXLEN; \ + (ifq)->ifq_drops = 0; \ +} + +#define IFNET_SLOWHZ 1 /* granularity is 1 second */ + +#endif /* _IF_HDR_ */ diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h index 6d0870ed..d1bd1fc7 100644 --- a/libmachdev/mach_glue.h +++ b/libmachdev/mach_glue.h @@ -9,8 +9,15 @@ struct net_device; void skb_done_queue(struct sk_buff *skb); struct sk_buff *skb_done_dequeue(); void *skb_reply(struct sk_buff *skb); + int netdev_flags(struct net_device *dev); char *netdev_addr(struct net_device *dev); +char *netdev_name (struct net_device *dev); +unsigned int netdev_mtu (struct net_device *dev); +unsigned short netdev_header_len (struct net_device *dev); +unsigned short netdev_type (struct net_device *dev); +unsigned char netdev_addr_len (struct net_device *dev); + int dev_change_flags (struct net_device *dev, short flags); int linux_pkg_xmit (char *pkg_data, int len, void *del_data, int (*del_func) (struct sk_buff *, void *), diff --git a/libmachdev/net.c b/libmachdev/net.c index b9d76731..88b1d6c8 100644 --- a/libmachdev/net.c +++ b/libmachdev/net.c @@ -61,6 +61,7 @@ #include #include #include +#include #include "mach_U.h" @@ -75,6 +76,7 @@ #include "if_ether.h" #include "util.h" #include "mach_glue.h" +#include "if_hdr.h" #define ether_header ethhdr @@ -86,9 +88,8 @@ extern struct port_class *dev_class; struct net_data { struct port_info port; /* device port */ -// struct ifnet ifnet; /* Mach ifnet structure (needed for filters) */ struct emul_device device; /* generic device structure */ - mach_port_t delivery_port; + struct ifnet ifnet; /* Mach ifnet structure (needed for filters) */ struct net_device *dev; /* Linux network device structure */ struct net_data *next; }; @@ -174,10 +175,12 @@ pre_kfree_skb (struct sk_buff *skb, void *data) * Deliver the message to all right pfinet servers that * connects to the virtual network interface. */ -static int -deliver_msg(mach_port_t dest, struct net_rcv_msg *msg) +int +deliver_msg(struct net_rcv_msg *msg, if_filter_list_t *ifp) { mach_msg_return_t err; + queue_head_t *if_port_list; + net_rcv_port_t infp, nextfp; msg->msg_hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0); /* remember message sizes must be rounded up */ @@ -185,19 +188,42 @@ deliver_msg(mach_port_t dest, struct net_rcv_msg *msg) msg->msg_hdr.msgh_kind = MACH_MSGH_KIND_NORMAL; msg->msg_hdr.msgh_id = NET_RCV_MSG_ID; - msg->msg_hdr.msgh_remote_port = dest; - err = mach_msg ((mach_msg_header_t *)msg, - MACH_SEND_MSG|MACH_SEND_TIMEOUT, - msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL, - 0, MACH_PORT_NULL); - if (err != MACH_MSG_SUCCESS) + if_port_list = &ifp->if_rcv_port_list; + FILTER_ITERATE (if_port_list, infp, nextfp, &infp->input) { - mach_port_deallocate(mach_task_self (), - ((mach_msg_header_t *)msg)->msgh_remote_port); - return err; + mach_port_t dest; + net_hash_entry_t entp, *hash_headp; + int ret_count; + + entp = (net_hash_entry_t) 0; + ret_count = bpf_do_filter (infp, + msg->packet + sizeof (struct packet_header), + msg->net_rcv_msg_packet_count, msg->header, + sizeof (struct ethhdr), &hash_headp, &entp); + if (entp == (net_hash_entry_t) 0) + dest = infp->rcv_port; + else + dest = entp->rcv_port; + + if (ret_count) + { + msg->msg_hdr.msgh_remote_port = dest; + err = mach_msg ((mach_msg_header_t *)msg, + MACH_SEND_MSG|MACH_SEND_TIMEOUT, + msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL, + 0, MACH_PORT_NULL); + if (err != MACH_MSG_SUCCESS) + { + mach_port_deallocate(mach_task_self (), + ((mach_msg_header_t *)msg)->msgh_remote_port); + error (0, err, "mach_msg"); + return -1; + } + } } + FILTER_ITERATE_END - return MACH_MSG_SUCCESS; + return 0; } /* Accept packet SKB received on an interface. */ @@ -241,7 +267,7 @@ netif_rx_handle (char *data, int len, struct net_device *dev) net_msg->header_type = header_type; net_msg->packet_type = packet_type; net_msg->net_rcv_msg_packet_count = ph->length; - deliver_msg (nd->delivery_port, net_msg); + deliver_msg (net_msg, &nd->ifnet.port_list); free (net_msg); } @@ -256,20 +282,18 @@ dev_to_port (void *nd) : MACH_PORT_NULL); } -#if 0 /* * Initialize send and receive queues on an interface. */ void if_init_queues(ifp) register struct ifnet *ifp; { - IFQ_INIT(&ifp->if_snd); - queue_init(&ifp->if_rcv_port_list); - queue_init(&ifp->if_snd_port_list); - simple_lock_init(&ifp->if_rcv_port_list_lock); - simple_lock_init(&ifp->if_snd_port_list_lock); +// IFQ_INIT(&ifp->if_snd); + queue_init(&ifp->port_list.if_rcv_port_list); + queue_init(&ifp->port_list.if_snd_port_list); + mutex_init(&ifp->if_rcv_port_list_lock); + mutex_init(&ifp->if_snd_port_list_lock); } -#endif static io_return_t device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, @@ -279,7 +303,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, io_return_t err = D_SUCCESS; struct net_device *dev; struct net_data *nd; -// struct ifnet *ifp; + struct ifnet *ifp; /* Search for the device. */ dev = search_netdev (name); @@ -293,6 +317,8 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, nd = search_nd (dev); if (!nd) { + char *name; + err = create_device_port (sizeof (*nd), &nd); if (err) { @@ -305,23 +331,17 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, nd->device.emul_ops = &linux_net_emulation_ops; nd->next = nd_head; nd_head = nd; -#if 0 - ipc_kobject_set (nd->port, (ipc_kobject_t) & nd->device, IKOT_DEVICE); - notify = ipc_port_make_sonce (nd->port); - ip_lock (nd->port); - ipc_port_nsrequest (nd->port, 1, notify, ¬ify); - assert (notify == IP_NULL); ifp = &nd->ifnet; - ifp->if_unit = dev->name[strlen (dev->name) - 1] - '0'; + name = netdev_name (dev); + ifp->if_unit = name[strlen (name) - 1] - '0'; ifp->if_flags = IFF_UP | IFF_RUNNING; - ifp->if_mtu = dev->mtu; - ifp->if_header_size = dev->hard_header_len; - ifp->if_header_format = dev->type; - ifp->if_address_size = dev->addr_len; - ifp->if_address = dev->dev_addr; + ifp->if_mtu = netdev_mtu (dev); + ifp->if_header_size = netdev_header_len (dev); + ifp->if_header_format = netdev_type (dev); + ifp->if_address_size = netdev_addr_len (dev); + ifp->if_address = netdev_addr (dev); if_init_queues (ifp); -#endif if ((err = dev_open(dev)) < 0) { @@ -425,8 +445,8 @@ device_write (void *d, mach_port_t reply_port, * Other network operations */ static io_return_t -net_getstat(dev, flavor, status, count) - struct net_device *dev; +net_getstat(ifp, flavor, status, count) + struct ifnet *ifp; dev_flavor_t flavor; dev_status_t status; /* pointer to OUT array */ natural_t *count; /* OUT */ @@ -440,12 +460,12 @@ net_getstat(dev, flavor, status, count) if (*count < NET_STATUS_COUNT) return (D_INVALID_OPERATION); - ns->min_packet_size = 60; - ns->max_packet_size = ETH_HLEN + ETHERMTU; - ns->header_format = HDR_ETHERNET; - ns->header_size = ETH_HLEN; - ns->address_size = ETH_ALEN; - ns->flags = 0; + ns->min_packet_size = ifp->if_header_size; + ns->max_packet_size = ifp->if_header_size + ifp->if_mtu; + ns->header_format = ifp->if_header_format; + ns->header_size = ifp->if_header_size; + ns->address_size = ifp->if_address_size; + ns->flags = ifp->if_flags; ns->mapped_size = 0; *count = NET_STATUS_COUNT; @@ -469,7 +489,7 @@ net_getstat(dev, flavor, status, count) return (D_INVALID_OPERATION); } - memcpy(status, netdev_addr(dev), addr_byte_count); + memcpy(status, ifp->if_address, addr_byte_count); if (addr_byte_count < addr_int_count * sizeof(int)) memset((char *)status + addr_byte_count, 0, (addr_int_count * sizeof(int) @@ -556,7 +576,7 @@ device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, #endif { /* common get_status request */ - return net_getstat (net->dev, flavor, status, count); + return net_getstat (&net->ifnet, flavor, status, count); } } @@ -618,12 +638,8 @@ static io_return_t device_set_filter (void *d, mach_port_t port, int priority, filter_t * filter, unsigned filter_count) { - ((struct net_data *) d)->delivery_port = port; - return 0; -#if 0 - return net_set_filter (&((struct net_data *) d)->ifnet, + return net_set_filter (&((struct net_data *) d)->ifnet.port_list, port, priority, filter, filter_count); -#endif } /* Do any initialization required for network devices. */ -- cgit v1.2.3 From 38b75c82d5555d1c2248fc98fb47d6fa2265059b Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 8 Aug 2010 07:17:50 +0200 Subject: Make the thread of DS server known to Linux. --- libmachdev/ds_routines.c | 7 +++++++ libmachdev/mach_glue.h | 4 ++++ 2 files changed, 11 insertions(+) (limited to 'libmachdev/mach_glue.h') diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c index 93ac7ecc..d31e3a9b 100644 --- a/libmachdev/ds_routines.c +++ b/libmachdev/ds_routines.c @@ -61,12 +61,15 @@ #include #include +#include + #include "vm_param.h" #include "device_reply_U.h" #include "io_req.h" #include "dev_hdr.h" #include "util.h" #include "queue.h" +#include "mach_glue.h" static struct port_bucket *port_bucket; static struct port_class *dev_class; @@ -466,6 +469,10 @@ void reg_dev_emul (struct device_emulation_ops *ops) void ds_server() { + /* This thread calls Linux functions, + * so I need to make it known to the Linux environment. */ + l4dde26_process_from_ddekit (ddekit_thread_myself ()); + /* Launch. */ do { diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h index d1bd1fc7..770ea51b 100644 --- a/libmachdev/mach_glue.h +++ b/libmachdev/mach_glue.h @@ -4,6 +4,8 @@ /* network */ #include +#include + struct sk_buff; struct net_device; void skb_done_queue(struct sk_buff *skb); @@ -34,4 +36,6 @@ struct block_device *open_block_dev (char *name, int part, dev_mode_t mode); int block_dev_write (struct block_device *dev, int sectornr, char *data, int count, void (*write_done) (int err)); +int l4dde26_process_from_ddekit(ddekit_thread_t *t); + #endif -- cgit v1.2.3 From 793af51f505adfa1ea138dc76be731faab58b1a6 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 8 Aug 2010 08:10:25 +0200 Subject: implement device_read for block devices. --- libdde_linux26/lib/src/mach_glue/block.c | 6 ++-- libmachdev/block.c | 55 ++++++++++++++++++++++++++++++-- libmachdev/mach_glue.h | 4 +-- 3 files changed, 57 insertions(+), 8 deletions(-) (limited to 'libmachdev/mach_glue.h') diff --git a/libdde_linux26/lib/src/mach_glue/block.c b/libdde_linux26/lib/src/mach_glue/block.c index a856cc9b..ea44d87f 100644 --- a/libdde_linux26/lib/src/mach_glue/block.c +++ b/libdde_linux26/lib/src/mach_glue/block.c @@ -20,8 +20,8 @@ struct block_device *open_block_dev (char *name, int part, fmode_t mode) /* write a piece of data to a block device. * DATA must be in one page. * SECTORNR: the writing location in sectors. */ -int block_dev_write (struct block_device *dev, int sectornr, - char *data, int count, void (*write_done (int err))) +int block_dev_rw (struct block_device *dev, int sectornr, + char *data, int count, int rw, void (*write_done (int err))) { int err = 0; struct bio *bio; @@ -63,7 +63,7 @@ int block_dev_write (struct block_device *dev, int sectornr, bio->bi_end_io = end_bio; bio->bi_private = NULL; bio_get (bio); - submit_bio (WRITE, bio); + submit_bio (rw, bio); if (bio_flagged (bio, BIO_EOPNOTSUPP)) { err = -EOPNOTSUPP; diff --git a/libmachdev/block.c b/libmachdev/block.c index 48fe6cd6..2a4b9ae2 100644 --- a/libmachdev/block.c +++ b/libmachdev/block.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "mach_U.h" @@ -40,6 +41,11 @@ #include "util.h" #include "mach_glue.h" +/* for submit_bio(). But it might not be very proper to keep + * my own definitions of these macros. */ +#define READ 0 +#define WRITE 1 + /* One of these is associated with each open instance of a device. */ struct block_data { @@ -180,6 +186,7 @@ device_write (void *d, mach_port_t reply_port, void write_done (int err) { int len = err ? 0 : count; + // TODO maybe I should send the reply as long as there is an error. writes--; if (writes == 0) { @@ -200,7 +207,7 @@ device_write (void *d, mach_port_t reply_port, int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? count : PAGE_SIZE - ((int) data &~PAGE_MASK); - err = block_dev_write (bd->dev, bn, data, size, write_done); + err = block_dev_rw (bd->dev, bn, data, size, WRITE, write_done); if (err) break; bn += size >> 9; @@ -220,11 +227,53 @@ device_read (void *d, mach_port_t reply_port, unsigned *bytes_read) { struct block_data *bd = d; + io_return_t err = D_SUCCESS; + int i; + int reads = 0; + char *buf; + int npages = (count + PAGE_SIZE - 1) / PAGE_SIZE; + + void read_done (int err) + { + int len = err ? 0 : count; + reads--; + if (reads == 0) + { + err = linux_to_mach_error (err); + ds_device_read_reply (reply_port, reply_port_type, err, buf, len); + } + } if ((bd->mode & D_READ) == 0) return D_INVALID_OPERATION; - *bytes_read = 0; - return D_SUCCESS; + + if (count == 0) + return 0; + + *data = 0; + buf = mmap (NULL, npages * PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (buf == MAP_FAILED) + return errno; + + ddekit_printf ("read %d pages.\n", npages); + for (i = 0; i < npages; i++) + { + int size = count > PAGE_SIZE ? PAGE_SIZE : count; + ddekit_printf ("read %d bytes starting from %d\n", size, bn); + + err = block_dev_rw (bd->dev, bn, buf + i * PAGE_SIZE, + size, READ, read_done); + if (err) + break; + bn += size >> 9; + count -= size; + reads++; + } + // TODO when should I deallocate the buffer? + if (reads) + return MIG_NO_REPLY; + return linux_to_mach_error (err); } static io_return_t diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h index 770ea51b..7b122583 100644 --- a/libmachdev/mach_glue.h +++ b/libmachdev/mach_glue.h @@ -33,8 +33,8 @@ void skb_done_head_init(); /* block device */ struct block_device; struct block_device *open_block_dev (char *name, int part, dev_mode_t mode); -int block_dev_write (struct block_device *dev, int sectornr, - char *data, int count, void (*write_done) (int err)); +int block_dev_rw (struct block_device *dev, int sectornr, + char *data, int count, int rw, void (*write_done) (int err)); int l4dde26_process_from_ddekit(ddekit_thread_t *t); -- cgit v1.2.3