Mercurial > archived > louis > epitech > mq > rathaxes
view rathaxes_add_lkm_ethernet_sample.patch @ 38:f43900ad7e66
Fold All The Patches on the LKM Sample
author | Louis Opter <louis@lse.epitech.net> |
---|---|
date | Sun, 08 Jan 2012 01:51:34 +0100 |
parents | rathaxes_add_a_linux_lkm.patch@44a25ffd5c8c |
children | d761c8c625d3 |
line wrap: on
line source
# HG changeset patch # Parent b995d8934956b83383c144303178f3eb383d0acf rathaxes: add the PCI/Ethernet part of a Linux Intel e1000 network card driver diff --git a/rathaxes/samples/CMakeLists.txt b/rathaxes/samples/CMakeLists.txt --- a/rathaxes/samples/CMakeLists.txt +++ b/rathaxes/samples/CMakeLists.txt @@ -1,2 +1,3 @@ ADD_SUBDIRECTORY(helloworld) +ADD_SUBDIRECTORY(lkm) ADD_SUBDIRECTORY(syntax) diff --git a/rathaxes/samples/lkm/CMakeLists.txt b/rathaxes/samples/lkm/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/CMakeLists.txt @@ -0,0 +1,7 @@ +ADD_RATHAXES_SOURCES(lkm lkm.rtx + RTI log.rti lkm.rti pci.rti socket.rti ethernet.rti e1000.rti + BLT log.blt lkm.blt pci.blt socket.blt ethernet.blt e1000.blt) + +# We can't name lkm since it's already used as the target name to generate the +# source (with ADD_RATHAXES_SOURCES). +ADD_RATHAXES_LKM(lkm_hello lkm) diff --git a/rathaxes/samples/lkm/e1000.blt b/rathaxes/samples/lkm/e1000.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/e1000.blt @@ -0,0 +1,80 @@ +with e1000, Ethernet, Socket, PCI, LKM, Log +{ + template type e1000::Context() + { + chunk LKM::includes() + { + /* + * Force the generation of the structure in the "headers" part, we + * have to do this since we do not use the structure in this blt + * (we hacked a bit and used it in ethernet.blt directly). + */ + typedef int ${e1000::Context}; /* CNorm __std__ workaround */ + ${e1000::Context} force_declaration_in_includes; + } + + chunk ::decl() + { + struct rtx_e1000_ctx + { + int bars; + unsigned char /* __iomem */ *ioaddr; + }; + } + + map + { + } + } + + template sequence e1000::create_device() + { + chunk Ethernet::create_device() + { + rtx_ether_ctx->hw_ctx.bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_enable_device_mem(pdev)) + { + ${Log::info("e1000::create: pci_enable_device_mem failed")}; + } + + if (pci_request_selected_regions(pdev, rtx_ether_ctx->hw_ctx.bars, ${config.name})) + { + ${Log::info("e1000::create: pci_request_selected_regions failed")}; + } + + if (${config.set_master}) + { + pci_set_master(pdev); + } + + /* 0 here is for BAR_0: */ + rtx_ether_ctx->hw_ctx.ioaddr = pci_ioremap_bar(pdev, 0); + if (!rtx_ether_ctx->hw_ctx.ioaddr) + { + ${Log::info("e1000::create: pci_ioremap_bar failed")}; + } + } + + chunk ::CALL + { + } + } + + template sequence e1000::destroy_device() + { + chunk Ethernet::destroy_device + { + /* + * Here, we should have some checks to avoid to free resources that + * haven't been allocated. (e.g: in case of previous errors). + */ + struct rtx_ethernet_dev* rtx_ether_ctx = netdev_priv(net_dev); + iounmap(rtx_ether_ctx->hw_ctx.ioaddr); + pci_release_selected_regions(pdev, rtx_ether_ctx->hw_ctx.bars); + } + + chunk ::CALL + { + } + } +} diff --git a/rathaxes/samples/lkm/e1000.rti b/rathaxes/samples/lkm/e1000.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/e1000.rti @@ -0,0 +1,24 @@ +interface e1000 : Socket, Ethernet, PCI, LKM +{ + provided type e1000::Context; + + /* + * This sequence should receive an argument like Ethernet::Device, but it is + * unclear about how this argument should be bound to a variable/argument in + * the instrumented C code. + * + * Here again, we rely on the fact that *we* wrote the parent context and + * named the C variables we need/use with the same name everywhere. + */ + provided sequence e1000::create_device() + { + provided chunk Ethernet::create_device; + provided chunk ::CALL; + } + + provided sequence e1000::destroy_device() + { + provided chunk Ethernet::destroy_device; + provided chunk ::CALL; + } +} diff --git a/rathaxes/samples/lkm/ethernet.blt b/rathaxes/samples/lkm/ethernet.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/ethernet.blt @@ -0,0 +1,207 @@ +with Ethernet, PCI, LKM, Log +{ + template type Ethernet::Device() + { + chunk LKM::includes() + { + #include <linux/netdevice.h> + #include <linux/etherdevice.h> + } + + chunk ::decl() + { + struct rtx_ethernet_dev + { + /* + * I think it's useless to use the ${PCI::Device} "abstraction" + * here, since we are already in a Linux specific context here. + */ + struct pci_dev *pci_dev; + struct net_device *net_dev; + + /* while waiting on issue #8 */ + struct rtx_e1000_ctx hw_ctx; + }; + } + + chunk ::init(net_dev) + { + ${self} = ${net_dev}; + } + + map + { + } + } + + template sequence Ethernet::open(Ethernet::Device dev) + { + chunk LKM::prototypes() + { + static int rtx_ethernet_open(struct net_device *); + } + + chunk LKM::code() + { + static int rtx_ethernet_open(struct net_device *dev) + { + ${pointcut ::IMPLEMENTATION}; + + return 0; + } + } + } + + template sequence Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) + { + chunk LKM::prototypes() + { + static int rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev); + } + + chunk LKM::code() + { + static int rtx_ethernet_xmit(struct sk_buff* skb, struct net_device *dev) + { + ${pointcut ::IMPLEMENTATION}; + + return 0; + } + } + } + + template sequence Ethernet::close(Ethernet::Device dev) + { + chunk LKM::prototypes() + { + static int rtx_ethernet_close(struct net_device *); + } + + chunk LKM::code() + { + static int rtx_ethernet_close(struct net_device *dev) + { + ${pointcut ::IMPLEMENTATION}; + + return 0; + } + } + } + + template sequence Ethernet::interrupt_handler(Ethernet::Device dev) + { + /* + * We can't use the irqreturn_t type here because CNornm doesn't know + * it. + */ + chunk LKM::prototypes() + { + static enum irqreturn rtx_ethernet_interrupt_handler(int, void *); + } + + chunk LKM::code() + { + static enum irqreturn rtx_ethernet_interrupt_handler(int irq, void *dev_id) + { + ${pointcut ::IMPLEMENTATION}; + + return IRQ_NONE; + } + } + } + + template sequence Ethernet::init(PCI::Device pdev) + { + chunk LKM::data() + { + static const struct net_device_ops rtx_ether_ops = + { + .ndo_open = rtx_ethernet_open, + .ndo_stop = rtx_ethernet_close, + .ndo_start_xmit = rtx_ethernet_xmit, + }; + } + + chunk PCI::pci_probe_hook() + { + /* + * This typedef is needed to workaround a bug in CNorm __std__ + * dialect. + */ + typedef int ${Ethernet::Device}; + ${Ethernet::Device} *rtx_ether_ctx; + struct net_device *net_dev; + int error; + + error = 0; + net_dev = alloc_etherdev(sizeof(*rtx_ether_ctx)); + if (net_dev == 0) + { + ${Log::info("Cannot allocate memory")}; + /* + * Again, the error should be "raised" in the parent context. + * + * Here we know that we should return ENOMEM because *we* wrote + * the parent context. + */ + return -ENOMEM; + } + strlcpy(net_dev->name, ${config.ifname}, sizeof(net_dev->name)); + net_dev->irq = pdev->irq; + // Maybe we should try ${rtx_ether_ctx.init()} here: + rtx_ether_ctx = netdev_priv(net_dev); + //rtx_ether_ctx->pci_dev = ${pdev}; + rtx_ether_ctx->pci_dev = pdev; // In the meantime do it directly + rtx_ether_ctx->net_dev = net_dev; + + /* + * The substitution of ${pdev} fails here. I also tried to add a + * "substitute method" to the PCI::Device that was just doing + * "${self}" but it didn't work either (it was subsituted by a + * placeholder, e.g: _1). + * + * That's why we cheated a bit and named all the arguments pdev. + */ + //SET_NETDEV_DEV(net_dev, &${pdev}->dev); + SET_NETDEV_DEV(net_dev, &pdev->dev); + net_dev->netdev_ops = &rtx_ether_ops; + if ((error = register_netdev(net_dev))) + { + ${Log::info("Cannot register the driver")}; + return error; + } + + /* same problem as above with ${pdev} */ + //pci_set_drvdata(${pdev}, net_dev); + pci_set_drvdata(pdev, net_dev); + + ${pointcut Ethernet::create_device}; + } + + chunk ::CALL + { + } + } + + template sequence Ethernet::exit(PCI::Device pdev) + { + chunk PCI::pci_remove_hook() + { + struct net_device *net_dev = pci_get_drvdata(pdev); + + ${pointcut Ethernet::destroy_device}; + + unregister_netdev(net_dev); + /* + * If we had some cleanup todo with struct rtx_ether_ctx we would + * do a netdev_priv(net_dev) here and do it. + */ + free_netdev(net_dev); + } + + chunk ::CALL + { + } + } +} + diff --git a/rathaxes/samples/lkm/ethernet.rti b/rathaxes/samples/lkm/ethernet.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/ethernet.rti @@ -0,0 +1,47 @@ +interface Ethernet : Socket, PCI, LKM +{ + provided type Ethernet::Device; + + required variable ::string Ethernet::ifname; + + required sequence Ethernet::open(Ethernet::Device) + { + provided chunk LKM::prototypes; + provided chunk LKM::code; + } + + required sequence Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) + { + provided chunk LKM::prototypes; + provided chunk LKM::code; + } + + required sequence Ethernet::close(Ethernet::Device) + { + provided chunk LKM::prototypes; + provided chunk LKM::code; + } + + required sequence Ethernet::interrupt_handler(Ethernet::Device) + { + provided chunk LKM::prototypes; + provided chunk LKM::code; + } + + provided sequence Ethernet::init(PCI::Device) + { + provided chunk LKM::data; + provided chunk PCI::pci_probe_hook; + provided chunk ::CALL; + + provided pointcut Ethernet::create_device; + } + + provided sequence Ethernet::exit(PCI::Device) + { + provided chunk ::CALL; + provided chunk PCI::pci_remove_hook; + + provided pointcut Ethernet::destroy_device; + } +} diff --git a/rathaxes/samples/lkm/lkm.blt b/rathaxes/samples/lkm/lkm.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/lkm.blt @@ -0,0 +1,55 @@ +with LKM +{ + /* Skel of the generated C file: */ + ${pointcut LKM::includes}; + ${pointcut LKM::prototypes}; + ${pointcut LKM::data}; + ${pointcut LKM::code}; + + template sequence LKM::init() + { + chunk LKM::includes() + { + #include <linux/module.h> + #include <linux/kernel.h> + } + + chunk LKM::data() + { + MODULE_DESCRIPTION(${config.description}); + MODULE_AUTHOR(${config.author}); + MODULE_LICENSE(${config.license}); + } + + chunk LKM::code() + { + /* + * Rathaxes doesn't yet support arbitrary "decorators" like __init + * or __exit. + */ + static int __attribute__((__section__(".init.text"))) rtx_module_init(void) + { + ${pointcut ::IMPLEMENTATION}; + ${pointcut LKM::init_bus_hook}; + + return 0; + } + + module_init(rtx_module_init); + } + } + + template sequence LKM::exit() + { + chunk LKM::code() + { + static void __attribute__((__section__(".exit.text"))) rtx_module_exit(void) + { + ${pointcut ::IMPLEMENTATION}; + ${pointcut LKM::deinit_bus_hook}; + } + + module_exit(rtx_module_exit); + } + } +} diff --git a/rathaxes/samples/lkm/lkm.rti b/rathaxes/samples/lkm/lkm.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/lkm.rti @@ -0,0 +1,25 @@ +interface LKM +{ + provided pointcut LKM::includes; + /* maybe it should be possible to use chunk ::decl in sequence templates? */ + provided pointcut LKM::prototypes; + provided pointcut LKM::data; + provided pointcut LKM::code; + + required variable ::string LKM::author; + required variable ::string LKM::description; + required variable ::string LKM::license; + + required sequence LKM::init() + { + provided chunk LKM::includes; + provided chunk LKM::code; + provided pointcut LKM::init_bus_hook; + } + + required sequence LKM::exit() + { + provided chunk LKM::code; + provided pointcut LKM::deinit_bus_hook; + } +} diff --git a/rathaxes/samples/lkm/lkm.rtx b/rathaxes/samples/lkm/lkm.rtx new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/lkm.rtx @@ -0,0 +1,46 @@ +device LKM use LKM, PCI, Ethernet, Log +{ + Ethernet::open(Ethernet::Device dev) + { + Log::info("Open the device"); + } + + Ethernet::close(Ethernet::Device dev) + { + Log::info("Close the device"); + } + + Ethernet::interrupt_handler(Ethernet::Device dev) + { + Log::info("Got an interruption"); + } + + Ethernet::send(Ethernet::Device dev, Socket::SKBuff skb) + { + Log::info("We have one packet to transmit!"); + } + + LKM::init() + { + Log::info("Hello this is LKM"); + } + + LKM::exit() + { + Log::info("Good bye this was LKM"); + } +} + +configuration +{ + LKM::name = "hello"; + LKM::author = "Rathaxes"; + LKM::description = "Hello World Loadable Kernel Module (LKM)"; + LKM::license = "GPL"; + + PCI::vendor_id = 0x8086; + PCI::product_id = 0x100f; + PCI::set_master = true; + + Ethernet::ifname = "rtx%d"; +} diff --git a/rathaxes/samples/lkm/log.blt b/rathaxes/samples/lkm/log.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/log.blt @@ -0,0 +1,10 @@ +with Log +{ + template sequence Log::info(::string msg) + { + chunk ::CALL + { + pr_info("%s\n", ${msg}); + } + } +} diff --git a/rathaxes/samples/lkm/log.rti b/rathaxes/samples/lkm/log.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/log.rti @@ -0,0 +1,7 @@ +interface Log +{ + provided sequence Log::info(::string) + { + provided chunk ::CALL; + } +} diff --git a/rathaxes/samples/lkm/pci.blt b/rathaxes/samples/lkm/pci.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/pci.blt @@ -0,0 +1,143 @@ +with PCI, LKM, Log +{ + template type PCI::Device() + { + chunk LKM::includes() + { + #include <linux/pci.h> + } + + chunk ::decl() + { + struct pci_dev; + } + + chunk ::init(pci_dev) + { + ${self} = ${pci_dev}; + } + + map + { + } + } + + template sequence PCI::probe(PCI::Device pdev) + { + chunk LKM::prototypes() + { + static int /* __devinit */ rtx_pci_probe(struct pci_dev *, + const struct pci_device_id *); + } + + chunk LKM::code() + { + static int /* __devinit */ rtx_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *pdev_id) + { + int err; + + err = pci_enable_device(pdev); + if (err < 0) + goto fail; + + ${pointcut PCI::pci_probe_hook}; + + return 0; + + fail: + return err; + } + } + + chunk ::CALL + { + } + } + + template sequence PCI::remove(PCI::Device pdev) + { + chunk LKM::prototypes() + { + static void rtx_pci_remove(struct pci_dev *); + } + + chunk LKM::code() + { + static void rtx_pci_remove(struct pci_dev *pdev) + { + ${pointcut PCI::pci_remove_hook}; + + pci_disable_device(pdev); + } + } + + chunk ::CALL() + { + } + } + + template sequence PCI::register() + { + chunk LKM::data() + { + /* + * CNorm doesn't seem to like "dynamic" arrays (i.e: you always + * have to specify the exact size). + */ + static struct pci_device_id rtx_pci_device_table[2] = { + { ${config.vendor_id}, ${config.product_id}, PCI_ANY_ID, PCI_ANY_ID }, + { 0, } + }; + + static struct pci_driver rtx_pci_driver = { + .name = ${config.name}, + .id_table = rtx_pci_device_table, + .probe = rtx_pci_probe, + .remove = rtx_pci_remove + }; + } + + chunk LKM::init_bus_hook() + { + int error; + if ((error = pci_register_driver(&rtx_pci_driver))) + { + ${Log::info("Cannot register pci driver")}; + /* + * So we catched the error but how do we return it to the + * parent context? + * + * Here we know that we can just return error, but that's just + * a coincidence (and, in this case, *we* wrote the parent + * context). + */ + return error; + } + } + + chunk ::CALL() + { + /* + * The implementation of ::CALL is empty. This template sequence is + * actually not provided nor required. + * + * This sequence is just "intermediate" code that will just inject + * itself in the hook LKM::init_bus_hook for which this sequence + * has a chunk (see above chunk). + */ + } + } + + template sequence PCI::unregister() + { + chunk LKM::deinit_bus_hook() + { + pci_unregister_driver(&rtx_pci_driver); + } + + chunk ::CALL + { + } + } +} diff --git a/rathaxes/samples/lkm/pci.rti b/rathaxes/samples/lkm/pci.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/pci.rti @@ -0,0 +1,36 @@ +interface PCI : LKM +{ + provided type PCI::Device; + + required variable ::number PCI::vendor_id; + required variable ::number PCI::product_id; + + provided sequence PCI::register() + { + provided chunk ::CALL; + provided chunk LKM::data; + provided chunk LKM::init_bus_hook; + } + + provided sequence PCI::unregister() + { + provided chunk ::CALL; + provided chunk LKM::deinit_bus_hook; + } + + provided sequence PCI::probe(PCI::Device) + { + provided chunk LKM::prototypes; + provided chunk LKM::code; + + provided pointcut PCI::pci_probe_hook; + } + + provided sequence PCI::remove(PCI::Device) + { + provided chunk LKM::prototypes; + provided chunk LKM::code; + + provided pointcut PCI::pci_remove_hook; + } +} diff --git a/rathaxes/samples/lkm/socket.blt b/rathaxes/samples/lkm/socket.blt new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/socket.blt @@ -0,0 +1,27 @@ +with Socket, LKM +{ + template type Socket::SKBuff() + { + chunk LKM::includes() + { + #include <linux/skbuff.h> + } + + chunk ::decl() + { + struct sk_buff; + } + + chunk ::init() + { + } + + map + { + // some work may have to be done here in order + // to access to some field of the sk_buff. + // We should determine if all the sk_buff managment + // can be abstracted from the user. + } + } +} diff --git a/rathaxes/samples/lkm/socket.rti b/rathaxes/samples/lkm/socket.rti new file mode 100644 --- /dev/null +++ b/rathaxes/samples/lkm/socket.rti @@ -0,0 +1,4 @@ +interface Socket : LKM +{ + provided type Socket::SKBuff; +}