From 2fe1437bd35016309e9ac4cfe57fb3daca3ba0a0 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 31 May 2010 17:21:47 +0200 Subject: make glue code of networking more independant. This change is required for block device drivers. When block device drivers are linked to the glue code, the linker should be able to perform garbage collection and exclude the code of networking from the driver programs. --- libmachdev/machdev.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 libmachdev/machdev.h (limited to 'libmachdev/machdev.h') diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h new file mode 100644 index 00000000..27c488a5 --- /dev/null +++ b/libmachdev/machdev.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2010 Free Software Foundation, Inc. + Written by Zheng Da. + + This file is part of the GNU Hurd. + + The GNU Hurd 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 2, or (at your option) + any later version. + + The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This file declares interfaces used by driver programs. */ + +#ifndef __MACHDEV_H__ +#define __MACHDEV_H__ + +void ds_server(void); +void mach_device_init(void); +void register_net(void); +void trivfs_server(void); +int trivfs_init(void); + +#endif -- cgit v1.2.3 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. --- libdde_linux26/lib/src/Makefile | 3 +- libdde_linux26/lib/src/arch/l4/mach_glue.c | 87 ---------- libdde_linux26/lib/src/mach_glue/block.c | 77 +++++++++ libdde_linux26/lib/src/mach_glue/net.c | 87 ++++++++++ libmachdev/Makefile | 2 +- libmachdev/block.c | 250 +++++++++++++++++++++++++++++ libmachdev/mach_glue.h | 30 ++++ libmachdev/machdev.h | 1 + libmachdev/net.c | 19 +-- windhoek/Makefile | 4 +- windhoek/main.c | 1 + 11 files changed, 453 insertions(+), 108 deletions(-) delete mode 100644 libdde_linux26/lib/src/arch/l4/mach_glue.c create mode 100644 libdde_linux26/lib/src/mach_glue/block.c create mode 100644 libdde_linux26/lib/src/mach_glue/net.c create mode 100644 libmachdev/block.c create mode 100644 libmachdev/mach_glue.h (limited to 'libmachdev/machdev.h') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 3743f91b..947f11b9 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -150,7 +150,7 @@ SRC_C_libdde_linux26.o.a += \ ################################################################## SRC_C_libdde_linux26_net.a += \ arch/l4/net.c \ - arch/l4/mach_glue.c \ + mach_glue/net.c \ drivers/net/mii.c \ net/core/dev.c \ net/core/dev_mcast.c \ @@ -180,6 +180,7 @@ SRC_C_libdde_linux26_sound.a += \ # SRC_C_libdde_linux26_block.a += \ arch/l4/inodes.c \ + mach_glue/block.c \ block/blk-barrier.c \ block/blk-core.c \ block/blk-exec.c \ diff --git a/libdde_linux26/lib/src/arch/l4/mach_glue.c b/libdde_linux26/lib/src/arch/l4/mach_glue.c deleted file mode 100644 index 48373a90..00000000 --- a/libdde_linux26/lib/src/arch/l4/mach_glue.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include - -/* List of sk_buffs waiting to be freed. */ -static struct sk_buff_head skb_done_list; - -struct net_device *search_netdev (char *name) -{ - struct net_device *dev; - struct net_device *found = NULL; - struct net *net; - - printk("search device %s\n", name); - read_lock(&dev_base_lock); - for_each_net(net) { - for_each_netdev(net, dev) { - printk("there is device %s, base addr: %x\n", - dev->name, dev->base_addr); - if (!strcmp (name, dev->name)) - { - found = dev; - goto end; - } - } - } -end: - read_unlock(&dev_base_lock); - return found; -} - -int linux_pkg_xmit (char *pkg_data, int len, void *del_data, - int (*del_func) (struct sk_buff *, void *), - struct net_device *dev) -{ - struct sk_buff *skb; - - if (len == 0 || len > dev->mtu + dev->hard_header_len) - return EINVAL; - - /* Allocate a sk_buff. */ - skb = dev_alloc_skb (len); - if (!skb) - return ENOMEM; - - skb->del_data = del_data; - skb->pre_del_func = del_func; - - /* Copy user data. This is only required if it spans multiple pages. */ - skb->len = len; - skb->tail = skb->data + len; - - memcpy (skb->data, pkg_data, len); - - skb->dev = dev; - - return dev_queue_xmit(skb); -} - -char *netdev_addr(struct net_device *dev) -{ - return dev->dev_addr; -} - -int netdev_flags(struct net_device *dev) -{ - return dev->flags; -} - -void *skb_reply(struct sk_buff *skb) -{ - return skb->del_data; -} - -void skb_done_head_init() -{ - skb_queue_head_init (&skb_done_list); -} - -struct sk_buff *skb_done_dequeue() -{ - return skb_dequeue (&skb_done_list); -} - -void skb_done_queue(struct sk_buff *skb) -{ - skb_queue_tail (&skb_done_list, skb); -} diff --git a/libdde_linux26/lib/src/mach_glue/block.c b/libdde_linux26/lib/src/mach_glue/block.c new file mode 100644 index 00000000..7eac7e46 --- /dev/null +++ b/libdde_linux26/lib/src/mach_glue/block.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +struct gendisk *find_disk_by_name (char *); +void dde_page_cache_add (struct page *); + +struct block_device *open_block_dev (char *name, int part, fmode_t mode) +{ + struct gendisk *disk = find_disk_by_name (name); + dev_t devid = MKDEV (disk->major, disk->first_minor + part); + return open_by_devnum (devid, 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 err = 0; + struct bio *bio; + struct page *page; + int i; + + void end_bio (struct bio *bio, int err) + { + write_done (err); + } + + assert (count <= PAGE_SIZE); + bio = bio_alloc (GFP_NOIO, 1); + if (bio == NULL) + { + err = ENOMEM; + goto out; + } + + page = kmalloc (sizeof (*page), GFP_KERNEL); + if (page == NULL) + { + err = ENOMEM; + goto out; + } + + bio->bi_sector = sectornr; + bio->bi_bdev = dev; + page->virtual = data; + dde_page_cache_add (page); + bio->bi_io_vec[0].bv_page = page; + bio->bi_io_vec[0].bv_len = count; + bio->bi_io_vec[0].bv_offset = (int) data & ~PAGE_MASK; + + bio->bi_vcnt = 1; + bio->bi_idx = 0; + bio->bi_size = count; + + bio->bi_end_io = end_bio; + bio->bi_private = NULL; + bio_get (bio); + submit_bio (WRITE, bio); + if (bio_flagged (bio, BIO_EOPNOTSUPP)) + { + err = -EOPNOTSUPP; + goto out; + } + bio_put (bio); +out: + if (err) + { + if (bio) + bio_put (bio); + kfree (page); + } + return err; +} diff --git a/libdde_linux26/lib/src/mach_glue/net.c b/libdde_linux26/lib/src/mach_glue/net.c new file mode 100644 index 00000000..48373a90 --- /dev/null +++ b/libdde_linux26/lib/src/mach_glue/net.c @@ -0,0 +1,87 @@ +#include +#include + +/* List of sk_buffs waiting to be freed. */ +static struct sk_buff_head skb_done_list; + +struct net_device *search_netdev (char *name) +{ + struct net_device *dev; + struct net_device *found = NULL; + struct net *net; + + printk("search device %s\n", name); + read_lock(&dev_base_lock); + for_each_net(net) { + for_each_netdev(net, dev) { + printk("there is device %s, base addr: %x\n", + dev->name, dev->base_addr); + if (!strcmp (name, dev->name)) + { + found = dev; + goto end; + } + } + } +end: + read_unlock(&dev_base_lock); + return found; +} + +int linux_pkg_xmit (char *pkg_data, int len, void *del_data, + int (*del_func) (struct sk_buff *, void *), + struct net_device *dev) +{ + struct sk_buff *skb; + + if (len == 0 || len > dev->mtu + dev->hard_header_len) + return EINVAL; + + /* Allocate a sk_buff. */ + skb = dev_alloc_skb (len); + if (!skb) + return ENOMEM; + + skb->del_data = del_data; + skb->pre_del_func = del_func; + + /* Copy user data. This is only required if it spans multiple pages. */ + skb->len = len; + skb->tail = skb->data + len; + + memcpy (skb->data, pkg_data, len); + + skb->dev = dev; + + return dev_queue_xmit(skb); +} + +char *netdev_addr(struct net_device *dev) +{ + return dev->dev_addr; +} + +int netdev_flags(struct net_device *dev) +{ + return dev->flags; +} + +void *skb_reply(struct sk_buff *skb) +{ + return skb->del_data; +} + +void skb_done_head_init() +{ + skb_queue_head_init (&skb_done_list); +} + +struct sk_buff *skb_done_dequeue() +{ + return skb_dequeue (&skb_done_list); +} + +void skb_done_queue(struct sk_buff *skb) +{ + skb_queue_tail (&skb_done_list, skb); +} diff --git a/libmachdev/Makefile b/libmachdev/Makefile index 2bd294ad..7475d041 100644 --- a/libmachdev/Makefile +++ b/libmachdev/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libmachdev SRCS = deviceUser.c machUser.c net.c ds_routines.c queue.c trivfs_server.c \ - device_replyUser.c deviceServer.c notifyServer.c misc.c + device_replyUser.c deviceServer.c notifyServer.c misc.c block.c LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \ util.h queue.h io_req.h if_ether.h machdev.h linux-errno.h \ errno-base.h diff --git a/libmachdev/block.c b/libmachdev/block.c new file mode 100644 index 00000000..54048fde --- /dev/null +++ b/libmachdev/block.c @@ -0,0 +1,250 @@ +/* + * Linux block driver support. + * + * Copyright (C) 1996 The University of Utah and the Computer Systems + * Laboratory at the University of Utah (CSL) + * + * 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 2, 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, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Shantanu Goel, University of Utah CSL + */ + +#include +#include +#include + +#include "mach_U.h" + +#include +#include + +#define MACH_INCLUDE + +#include + +#include "vm_param.h" +#include "device_reply_U.h" +#include "dev_hdr.h" +#include "util.h" +#include "mach_glue.h" + +/* One of these is associated with each open instance of a device. */ +struct block_data +{ + struct port_info port; /* device port */ + struct emul_device device; /* generic device structure */ + dev_mode_t mode; + struct block_device *dev; +}; + +/* Return a send right associated with network device ND. */ +static mach_port_t +dev_to_port (void *nd) +{ + return (nd + ? ports_get_send_right (nd) + : MACH_PORT_NULL); +} + +extern struct device_emulation_ops linux_block_emulation_ops; + +#define DISK_NAME_LEN 32 + +/* Parse the device NAME. + Set *SLICE to be the DOS partition and + *PART the BSD/Mach partition, if any. */ +static char * +translate_name (char *name, int *slice, int *part) +{ + char *p, *q, *end; + char *ret; + int disk_num; + + /* Parse name into name, unit, DOS partition (slice) and partition. */ + for (*slice = 0, *part = -1, p = name; isalpha (*p); p++) + ; + if (p == name || ! isdigit (*p)) + return NULL; + end = p; + disk_num = strtol (p, &p, 0); + if (disk_num < 0 || disk_num > 26) + return NULL; +// do +// p++; +// while (isdigit (*p)); + if (*p) + { + q = p; + if (*q == 's' && isdigit (*(q + 1))) + { + q++; + do + *slice = *slice * 10 + *q++ - '0'; + while (isdigit (*q)); + if (! *q) + goto find_major; + } + if (! isalpha (*q) || *(q + 1)) + return NULL; + *part = *q - 'a'; + } + +find_major: + ret = malloc (DISK_NAME_LEN); + sprintf (ret, "hd%c", 'a' + disk_num); + return ret; +} + +static io_return_t +device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + dev_mode_t mode, char *name, device_t *devp) +{ + io_return_t err = D_SUCCESS; + struct block_data *bd = NULL; + int slice, part; + char *dev_name = NULL; + + dev_name = translate_name (name, &slice, &part); + + // TODO when the port isn't used by clients, it should be destroyed. + err = create_device_port (sizeof (*bd), &bd); + if (err) + { + ddekit_printf ("after create_device_port: cannot create a port\n"); + goto out; + } + bd->dev = open_block_dev (dev_name, slice, mode); + if (bd->dev < 0) + { + ddekit_printf ("open_block_dev fails with %d\n", bd->dev); + err = linux_to_mach_error (err); + goto out; + } + bd->device.emul_data = bd; + bd->device.emul_ops = &linux_block_emulation_ops; + bd->mode = mode; + +out: + free (dev_name); + if (err) + { + if (bd) + { + ports_destroy_right (bd); + bd = NULL; + } + } + else + *devp = ports_get_right (bd); + return err; +} + +static io_return_t +device_write (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, io_buf_ptr_t data, unsigned int count, + int *bytes_written) +{ + struct block_data *bd = d; + /* the number of pages that contain DATA. */ + int npages = (((int) data + count) - ((int) data & ~PAGE_MASK) + + PAGE_MASK) / PAGE_SIZE; + io_return_t err = D_SUCCESS; + int i; + int writes = 0; + + void write_done (int err) + { + int len = err ? 0 : count; + writes--; + if (writes == 0) + { + err = linux_to_mach_error (err); + ds_device_write_reply (reply_port, reply_port_type, err, len); + } + } + + /* the data is at the beginning of a page. */ + if ((int) data & ~PAGE_MASK) + return D_INVALID_OPERATION; + + if ((bd->mode & D_WRITE) == 0) + return D_INVALID_OPERATION; + + for (i = 0; i < npages; i++) + { + int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? + PAGE_SIZE - ((int) data &~PAGE_MASK) : count; + + err = block_dev_write (bd->dev, bn, data, count, write_done); + if (err) + break; + bn += count >> 9; + data += size; + count -= size; + writes++; + } + if (writes) + return MIG_NO_REPLY; + return linux_to_mach_error (err); +} + +static io_return_t +device_read (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, int count, io_buf_ptr_t *data, + unsigned *bytes_read) +{ + struct block_data *bd = d; + + if ((bd->mode & D_READ) == 0) + return D_INVALID_OPERATION; + *bytes_read = 0; + return D_SUCCESS; +} + +static io_return_t +device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t *count) +{ + struct block_data *bd = (struct block_data *) d; + return D_SUCCESS; +} + +struct device_emulation_ops linux_block_emulation_ops = +{ + NULL, + NULL, + dev_to_port, + device_open, + NULL, + device_write, + NULL, + device_read, + NULL, + NULL, + device_get_status, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +void register_block() +{ + extern void reg_dev_emul (struct device_emulation_ops *ops); + reg_dev_emul (&linux_block_emulation_ops); +} 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 diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h index 27c488a5..cfa4b2d4 100644 --- a/libmachdev/machdev.h +++ b/libmachdev/machdev.h @@ -26,6 +26,7 @@ void ds_server(void); void mach_device_init(void); void register_net(void); +void register_block(void); void trivfs_server(void); int trivfs_init(void); diff --git a/libmachdev/net.c b/libmachdev/net.c index b21d6333..8c435b4b 100644 --- a/libmachdev/net.c +++ b/libmachdev/net.c @@ -74,6 +74,7 @@ #include "dev_hdr.h" #include "if_ether.h" #include "util.h" +#include "mach_glue.h" #define ether_header ethhdr @@ -99,22 +100,6 @@ struct skb_reply int pkglen; }; -struct sk_buff; -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(); - static struct net_data *nd_head; /* Forward declarations. */ @@ -337,7 +322,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, if_init_queues (ifp); #endif - if (err = dev_open(dev) < 0) + if ((err = dev_open(dev)) < 0) { fprintf (stderr, "after dev_open: cannot open the device\n"); err = linux_to_mach_error (err); diff --git a/windhoek/Makefile b/windhoek/Makefile index 6f355bb9..803e8dba 100644 --- a/windhoek/Makefile +++ b/windhoek/Makefile @@ -27,8 +27,8 @@ SRC_C += $(IDEFILES) \ $(CDROMFILES) \ $(PARTITIONFILES) -LIBS += --whole-archive -ldde_linux26_block --no-whole-archive \ - -ldde_linux26.o -lddekit ../libmachdev/libmachdev.a \ +LIBS += --whole-archive --no-whole-archive ../libmachdev/libmachdev.a \ + -ldde_linux26_block -ldde_linux26.o -lddekit \ -lfshelp -ltrivfs -lpciaccess -lthreads -lshouldbeinlibc \ -lports -lhurd-slab diff --git a/windhoek/main.c b/windhoek/main.c index 6c3cdb89..c4e88666 100644 --- a/windhoek/main.c +++ b/windhoek/main.c @@ -66,6 +66,7 @@ int main(int argc, const char **argv) printk("| ready to rumble.... |\n"); printk("+----------------------------------------+\n"); + register_block (); mach_device_init(); trivfs_init(); -- cgit v1.2.3