/* * \brief Linux emulation code * \author Josef Soentgen * \date 2014-03-07 */ /* * Copyright (C) 2014-2017 Genode Labs GmbH * * This file is distributed under the terms of the GNU General Public License * version 2. */ /* Genode includes */ #include #include #include #include #include #include #include #include #include #include #include #include /* local includes */ #include #include #include #include #include typedef ::size_t size_t; typedef Genode::addr_t addr_t; /******************** ** linux/string.h ** ********************/ size_t strlen(const char *s) { return Genode::strlen(s); } int strcmp(const char* s1, const char *s2) { return Genode::strcmp(s1, s2); } int strncmp(const char *s1, const char *s2, size_t len) { return Genode::strcmp(s1, s2, len); } char *strchr(const char *p, int ch) { char c; c = ch; for (;; ++p) { if (*p == c) return ((char *)p); if (*p == '\0') break; } return 0; } void *memchr(const void *s, int c, size_t n) { const unsigned char *p = (unsigned char *)s; while (n-- != 0) { if ((unsigned char)c == *p++) { return (void *)(p - 1); } } return NULL; } char *strnchr(const char *p, size_t count, int ch) { char c; c = ch; for (; count; ++p, count--) { if (*p == c) return ((char *)p); if (*p == '\0') break; } return 0; } char *strcpy(char *dst, const char *src) { char *p = dst; while ((*dst = *src)) { ++src; ++dst; } return p; } size_t strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); if (size) { size_t len = (ret >= size) ? size - 1 : ret; Genode::memcpy(dest, src, len); dest[len] = '\0'; } return ret; } int sprintf(char *str, const char *format, ...) { enum { BUFFER_LEN = 128 }; va_list list; va_start(list, format); Genode::String_console sc(str, BUFFER_LEN); sc.vprintf(format, list); va_end(list); return sc.len(); } int snprintf(char *str, size_t size, const char *format, ...) { va_list list; va_start(list, format); Genode::String_console sc(str, size); sc.vprintf(format, list); va_end(list); return sc.len(); } int vsnprintf(char *str, size_t size, const char *format, va_list args) { Genode::String_console sc(str, size); sc.vprintf(format, args); return sc.len(); } int scnprintf(char *buf, size_t size, const char *fmt, ...) { va_list args; va_start(args, fmt); Genode::String_console sc(buf, size); sc.vprintf(fmt, args); va_end(args); return sc.len(); } size_t strnlen(const char *s, size_t maxlen) { size_t c; for (c = 0; c 0) { if (iov->iov_len) { size_t copy_len = (size_t)len < iov->iov_len ? len : iov->iov_len; Genode::memcpy(kdata, iov->iov_base, copy_len); len -= copy_len; kdata += copy_len; iov->iov_base = (unsigned char *)iov->iov_base + copy_len; iov->iov_len -= copy_len; } iov++; } return 0; } int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) { while (len > 0) { if (iov->iov_len) { size_t copy_len = (size_t)len < iov->iov_len ? len : iov->iov_len; Genode::memcpy(iov->iov_base, kdata, copy_len); len -= copy_len; kdata += copy_len; iov->iov_base = (unsigned char *)iov->iov_base + copy_len; iov->iov_len -= copy_len; } iov++; } return 0; } size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) { if (bytes > i->count) bytes = i->count; if (bytes == 0) return 0; char *kdata = reinterpret_cast(addr); struct iovec const *iov = i->iov; size_t len = bytes; while (len > 0) { if (iov->iov_len) { size_t copy_len = (size_t)len < iov->iov_len ? len : iov->iov_len; Genode::memcpy(kdata, iov->iov_base, copy_len); len -= copy_len; kdata += copy_len; } iov++; } return bytes; } bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) { if (bytes > i->count) return false; if (bytes == 0) return true; size_t const copied = copy_from_iter(addr, bytes, i); if (copied != bytes) { Genode::error(__func__, ":", __LINE__, " could not copy all bytes"); return false; } return true; } size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i) { if (bytes > i->count) bytes = i->count; if (bytes == 0) return 0; char *kdata = reinterpret_cast(addr); struct iovec const *iov = i->iov; size_t len = bytes; while (len > 0) { if (iov->iov_len) { size_t copy_len = (size_t)len < iov->iov_len ? len : iov->iov_len; Genode::memcpy(iov->iov_base, kdata, copy_len); len -= copy_len; kdata += copy_len; } iov++; } return bytes; } size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i) { return copy_to_iter(reinterpret_cast(page->addr) + offset, bytes, i); } size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i) { return copy_from_iter(reinterpret_cast(page->addr) + offset, bytes, i); } /******************** ** linux/socket.h ** ********************/ extern "C" int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, int offset, int len) { while (offset >= (int)iov->iov_len) { offset -= iov->iov_len; iov++; } while (len > 0) { u8 *base = ((u8*) iov->iov_base) + offset; size_t copy_len = len < (int)iov->iov_len - offset ? len : iov->iov_len - offset; offset = 0; Genode::memcpy(kdata, base, copy_len); len -= copy_len; kdata += copy_len; iov++; } return 0; } /********************** ** Memory allocation * **********************/ #include void *kvmalloc(size_t size, gfp_t flags) { return kmalloc(size, flags); } void *kmalloc_array(size_t n, size_t size, gfp_t flags) { if (size != 0 && n > SIZE_MAX / size) return NULL; return kmalloc(n * size, flags); } void kvfree(const void *p) { kfree(p); } void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) { return kzalloc(size, gfp | GFP_LX_DMA); } /********************* ** linux/vmalloc.h ** *********************/ void *vmalloc(unsigned long size) { size_t real_size = size + sizeof(size_t); size_t *addr; if (!Lx_kit::env().heap().alloc(real_size, (void**)&addr)) { return nullptr; } *addr = real_size; return addr + 1; } void *vzalloc(unsigned long size) { void *addr = vmalloc(size); if (addr) memset(addr, 0, size); return addr; } void vfree(const void *addr) { if (!addr) return; size_t size = *(((size_t *)addr) - 1); Lx_kit::env().heap().free(const_cast(addr), size); } /******************** ** linux/string.h ** ********************/ int memcmp(const void *p0, const void *p1, size_t size) { return Genode::memcmp(p0, p1, size); } /******************** ** linux/device.h ** ********************/ /** * Simple driver management class */ class Driver : public Genode::List::Element { private: struct device_driver *_drv; /* Linux driver */ public: Driver(struct device_driver *drv) : _drv(drv) { list()->insert(this); } /** * List of all currently registered drivers */ static Genode::List *list() { static Genode::List _list; return &_list; } /** * Match device and drivers */ bool match(struct device *dev) { /* * Don't try if buses don't match, since drivers often use 'container_of' * which might cast the device to non-matching type */ if (_drv->bus != dev->bus) return false; bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true; return ret; } /** * Probe device with driver */ int probe(struct device *dev) { dev->driver = _drv; if (dev->bus->probe) { return dev->bus->probe(dev); } else if (_drv->probe) { return _drv->probe(dev); } return 0; } }; int driver_register(struct device_driver *drv) { new (&Lx_kit::env().heap()) Driver(drv); return 0; } int device_add(struct device *dev) { if (dev->driver) return 0; /* foreach driver match and probe device */ for (Driver *driver = Driver::list()->first(); driver; driver = driver->next()) if (driver->match(dev)) { int ret = driver->probe(dev); if (!ret) return 0; } return 0; } int device_register(struct device *dev) { //XXX: initialize DMA pools (see device_initialize) return device_add(dev); } void *dev_get_drvdata(const struct device *dev) { return dev->driver_data; } int dev_set_drvdata(struct device *dev, void *data) { dev->driver_data = data; return 0; } const char *dev_name(const struct device *dev) { return dev->name; } int dev_set_name(struct device *dev, const char *fmt, ...) { enum { MAX_DEV_LEN = 64 }; /* XXX needs to be freed */ char *name = (char*)kmalloc(MAX_DEV_LEN, 0); if (!name) return 1; va_list list; va_start(list, fmt); Genode::String_console sc(name, MAX_DEV_LEN); sc.vprintf(fmt, list); va_end(list); dev->name = name; return 0; } /******************** ** linux/kernel.h ** ********************/ int strict_strtoul(const char *s, unsigned int base, unsigned long *res) { unsigned long r = -EINVAL; Genode::ascii_to_unsigned(s, r, base); *res = r; return r; } /******************* ** linux/delay.h ** *******************/ #include void usleep_range(unsigned long min, unsigned long max) { udelay(min); } /******************* ** linux/timer.h ** *******************/ static unsigned long round_jiffies(unsigned long j, bool force_up) { unsigned remainder = j % HZ; /* * from timer.c * * If the target jiffie is just after a whole second (which can happen * due to delays of the timer irq, long irq off times etc etc) then * we should round down to the whole second, not up. Use 1/4th second * as cutoff for this rounding as an extreme upper bound for this. * But never round down if @force_up is set. */ /* per default round down */ j = j - remainder; /* round up if remainder more than 1/4 second (or if we're forced to) */ if (remainder >= HZ/4 || force_up) j += HZ; return j; } unsigned long round_jiffies(unsigned long j) { return round_jiffies(j, false); } unsigned long round_jiffies_up(unsigned long j) { return round_jiffies(j, true); } unsigned long round_jiffies_relative(unsigned long j) { return round_jiffies(j + jiffies, false) - jiffies; } /******************* ** linux/ktime.h ** *******************/ ktime_t ktime_get_real(void) { return (ktime_t) (s64)(jiffies * (1000 / HZ) * NSEC_PER_MSEC); } ktime_t ktime_sub(ktime_t const lhs, ktime_t const rhs) { return lhs - rhs; } struct timespec ktime_to_timespec(ktime_t const nsec) { struct timespec ts; if (!nsec) { return (struct timespec) {0, 0}; } /* XXX check nsec < NSEC_PER_SEC */ ts.tv_sec = nsec / NSEC_PER_SEC; ts.tv_nsec = (nsec % NSEC_PER_SEC) * (1000*1000); return ts; } bool ktime_to_timespec_cond(ktime_t const kt, struct timespec *ts) { if (kt) { *ts = ktime_to_timespec(kt); return true; } return false; } struct timeval ns_to_timeval(ktime_t const nsec) { struct timespec ts = ktime_to_timespec(nsec); struct timeval tv; tv.tv_sec = ts.tv_sec; tv.tv_usec = ts.tv_nsec / 1000; return tv; } /************************* ** linux/timekeeping.h ** *************************/ time64_t ktime_get_seconds(void) { return jiffies_to_msecs(jiffies) / 1000; } /*********************** ** linux/workqueue.h ** ***********************/ struct workqueue_struct *create_singlethread_workqueue(char const *) { workqueue_struct *wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0); return wq; } struct workqueue_struct *alloc_ordered_workqueue(char const *name , unsigned int flags, ...) { return create_singlethread_workqueue(name); } struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...) { return create_singlethread_workqueue(nullptr); } /************************* ** linux/dma-mapping.h ** *************************/ /* use a smaller limit then possible to cover potential overhead */ enum { DMA_LARGE_ALLOC_SIZE = 60u << 10, }; void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { bool const large_alloc = size >= DMA_LARGE_ALLOC_SIZE; dma_addr_t dma_addr = 0; void *addr = large_alloc ? Lx::Malloc::dma().alloc_large(size) : Lx::Malloc::dma().alloc(size, 12, &dma_addr); if (addr) { *dma_handle = large_alloc ? Lx::Malloc::dma().phys_addr(addr) : dma_addr; } return addr; } void *dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { void *addr = dma_alloc_coherent(dev, size, dma_handle, flag); if (addr) Genode::memset(addr, 0, size); return addr; } void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) { if (size >= DMA_LARGE_ALLOC_SIZE) { Lx::Malloc::dma().free_large(vaddr); return; } if (Lx::Malloc::dma().inside((Genode::addr_t)vaddr)) { Lx::Malloc::dma().free(vaddr); } else { Genode::error("vaddr: ", vaddr, " is not DMA memory"); } } dma_addr_t dma_map_page(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction direction) { if (!Lx::Malloc::dma().inside((Genode::addr_t)page->addr)) { Genode::error(__func__, ": virtual address ", (void*)page->addr, " not an DMA address"); } dma_addr_t dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(page->addr); if (dma_addr == ~0UL) { Genode::error(__func__, ": virtual address ", (void*)page->addr, " not registered for DMA"); } return dma_addr; } dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction direction) { dma_addr_t dma_addr = (dma_addr_t) Lx::Malloc::dma().phys_addr(cpu_addr); if (dma_addr == ~0UL) { Genode::error(__func__, ": virtual address ", cpu_addr, " not registered for DMA ", __builtin_return_address(0)); BUG(); } return dma_addr; } int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return (dma_addr == ~0UL) ? 1 : 0; } /******************** ** linux/dcache.h ** ********************/ unsigned int full_name_hash(const unsigned char *name, unsigned int len) { unsigned hash = 0, i; for (i = 0; i < len; i++) hash += name[i]; return hash; } /****************** ** linux/hash.h ** ******************/ u32 hash_32(u32 val, unsigned int bits) { enum { GOLDEN_RATIO_PRIME_32 = 0x9e370001UL }; u32 hash = val * GOLDEN_RATIO_PRIME_32; hash = hash >> (32 - bits); return hash; } /***************** ** linux/gfp.h ** *****************/ class Addr_to_page_mapping : public Genode::List::Element { private: unsigned long _addr { 0 }; struct page *_page { 0 }; static Genode::List *_list() { static Genode::List _l; return &_l; } public: Addr_to_page_mapping(unsigned long addr, struct page *page) : _addr(addr), _page(page) { } static void insert(struct page *page) { Addr_to_page_mapping *m = (Addr_to_page_mapping*) Lx::Malloc::mem().alloc(sizeof (Addr_to_page_mapping)); m->_addr = (unsigned long)page->addr; m->_page = page; _list()->insert(m); } static void remove(struct page *page) { Addr_to_page_mapping *mp = 0; for (Addr_to_page_mapping *m = _list()->first(); m; m = m->next()) if (m->_page == page) mp = m; if (mp) { _list()->remove(mp); Lx::Malloc::mem().free(mp); } } static struct page* find_page(unsigned long addr) { for (Addr_to_page_mapping *m = _list()->first(); m; m = m->next()) if (m->_addr == addr) return m->_page; return 0; } }; unsigned long get_zeroed_page(gfp_t gfp_mask) { struct page *p = alloc_pages(gfp_mask, 0); if (!p) return 0UL; Genode::memset(p->addr, 0, PAGE_SIZE); return (unsigned long)p->addr; } struct page *alloc_pages(gfp_t gfp_mask, unsigned int order) { struct page *page = (struct page *)kzalloc(sizeof(struct page), 0); size_t size = PAGE_SIZE << order; page->addr = Lx::Malloc::dma().alloc(size, 12); if (!page->addr) { Genode::error("alloc_pages: ", size, " failed"); kfree(page); return 0; } Addr_to_page_mapping::insert(page); atomic_set(&page->_count, 1); return page; } void *__alloc_page_frag(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask) { struct page *page = alloc_pages(gfp_mask, fragsz / PAGE_SIZE); if (!page) return nullptr; return page->addr; } void *page_frag_alloc(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask) { return __alloc_page_frag(nc, fragsz, gfp_mask); } void page_frag_free(void *addr) { __free_page_frag(addr); } void __free_page_frag(void *addr) { struct page *page = virt_to_head_page(addr); __free_pages(page, 0xdeadbeef); } void __free_pages(struct page *page, unsigned int order) { if (!atomic_dec_and_test(&page->_count)) /* reference counter did not drop to zero - do not free yet */ return; Addr_to_page_mapping::remove(page); Lx::Malloc::dma().free(page->addr); kfree(page); } void free_pages(unsigned long page, unsigned int order) { struct page *p = Addr_to_page_mapping::find_page(page); __free_pages(p, order); } /**************** ** linux/mm.h ** ****************/ struct page *virt_to_head_page(const void *addr) { struct page *page = Addr_to_page_mapping::find_page((unsigned long)addr); if (!page) { /** * Linux uses alloc_pages() to allocate memory but passes addr + offset * to the caller (e.g. __netdev_alloc_frag()). Therefore, we also try to * find the aligned addr in our page mapping list. */ unsigned long aligned_addr = (unsigned long)addr & ~0xfff; page = Addr_to_page_mapping::find_page(aligned_addr); if (!page) { Genode::error("BUG: addr: ", addr, " and aligned addr: ", (void*)aligned_addr, " have no page mapping, "); Genode::sleep_forever(); } } return page; } void get_page(struct page *page) { atomic_inc(&page->_count); } void put_page(struct page *page) { if (!page) { Genode::warning(__func__, ": page is zero"); return; } if (!atomic_dec_and_test(&page->_count)) return; Lx::Malloc::dma().free(page->addr); kfree(page); } /******************************* ** asm-generic/bitops/find.h ** *******************************/ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { unsigned long i = offset / BITS_PER_LONG; offset -= (i * BITS_PER_LONG); for (; offset < size; offset++) if (addr[i] & (1UL << offset)) return offset; return size; } unsigned long find_next_zero_bit(unsigned long const *addr, unsigned long size, unsigned long offset) { unsigned long i, j; for (i = offset; i < (size / BITS_PER_LONG); i++) if (addr[i] != ~0UL) break; if (i == size) return size; for (j = 0; j < BITS_PER_LONG; j++) if ((~addr[i]) & (1UL << j)) break; return (i * BITS_PER_LONG) + j; } /********************** ** linux/notifier.h ** **********************/ int raw_notifier_chain_register(struct raw_notifier_head *nh, struct notifier_block *n) { struct notifier_block *nl = nh->head; struct notifier_block *pr = 0; while (nl) { if (n->priority > nl->priority) break; pr = nl; nl = nl->next; } n->next = nl; if (pr) pr->next = n; else nh->head = n; return 0; } int raw_notifier_call_chain(struct raw_notifier_head *nh, unsigned long val, void *v) { int ret = NOTIFY_DONE; struct notifier_block *nb = nh->head; while (nb) { ret = nb->notifier_call(nb, val, v); if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) break; nb = nb->next; } return ret; } /******************** ** linux/percpu.h ** ********************/ void *__alloc_percpu(size_t size, size_t align) { return kmalloc(size, 0); } /********************** ** net/ns/generic.h ** **********************/ void *net_generic(const struct net *net, unsigned int id) { if (id >= MAX_NET_GENERIC_PTR) { Genode::error(__func__, ":", " id ", id, " invalid"); return NULL; } struct net_generic *ng = net->gen; void *ptr = ng->ptr[id]; if (!ptr) { Genode::error(__func__, ":", " cannot get ptr"); BUG(); } return ptr; } /******************************* ** net/core/net/namespace.h ** *******************************/ int register_pernet_subsys(struct pernet_operations *ops) { if (!init_net.gen) { init_net.gen = (struct net_generic*)kzalloc( offsetof(struct net_generic, ptr[MAX_NET_GENERIC_PTR]), 0); if (!init_net.gen) { Genode::error("could not allocate net_generic memory"); return -1; } } if (ops->id && ops->size) { /* XXX AFAICS there is only netlink_tap_net_ops that requires it */ unsigned int id = *ops->id; if (id >= MAX_NET_GENERIC_PTR) { Genode::error(__func__, ":", " id ", id, " invalid"); return -1; } void *data = kzalloc(ops->size, 0); init_net.gen->ptr[id] = data; } if (ops->init) ops->init(&init_net); return 0; } int register_pernet_device(struct pernet_operations *ops) { return register_pernet_subsys(ops); } /************************** ** core/net_namespace.c ** **************************/ DEFINE_MUTEX(net_mutex); /******************* ** kernel/kmod.c ** *******************/ extern "C" void module_iwl_init(void); extern "C" void module_iwl_mvm_init(void); int __request_module(bool wait, char const *format, ...) { va_list list; char buf[128]; va_start(list, format); Genode::String_console sc(buf, sizeof(buf)); sc.vprintf(format, list); va_end(list); return 0; } /* XXX request_module() should not hardcode module names */ int request_module(char const* format, ...) { va_list list; char buf[128]; va_start(list, format); Genode::String_console sc(buf, sizeof(buf)); sc.vprintf(format, list); va_end(list); if (Genode::strcmp(buf, "iwldvm", 6) == 0) { module_iwl_init(); return 0; } else if (Genode::strcmp(buf, "iwlmvm", 6) == 0) { module_iwl_mvm_init(); return 0; } else if (Genode::strcmp(buf, "ccm(aes)", 7) == 0) { return 0; } else if (Genode::strcmp(buf, "cryptomgr", 9) == 0) { return 0; } return -1; } /**************************** ** kernel/locking/mutex.c ** ****************************/ #include /****************** ** linux/poll.h ** ******************/ bool poll_does_not_wait(const poll_table *p) { return p == nullptr; } /********************* ** linux/kthread.h ** *********************/ void *kthread_run(int (*threadfn)(void *), void *data, char const *name) { threadfn(data); return (void*)42; } /***************** ** linux/pci.h ** *****************/ #include void *pci_get_drvdata(struct pci_dev *pdev) { return dev_get_drvdata(&pdev->dev); } void pci_set_drvdata(struct pci_dev *pdev, void *data) { dev_set_drvdata(&pdev->dev, data); } static struct pcim_iomap_devres { void *table[6]; } _devres_table; int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask, const char *name) { /* XXX iwlwifi just want to map the first BAR */ void *addr = pci_ioremap_bar(pdev, 0); if (!addr) { return -1; } printk("%s:%d from: %p addr: %p\n", __func__, __LINE__, __builtin_return_address(0), addr); _devres_table.table[0] = addr; return 0; } void * const *pcim_iomap_table(struct pci_dev *pdev) { return _devres_table.table; } /*********************** ** linux/interrupt.h ** ***********************/ #include int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) { Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev); return 0; } int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long flags, const char *name, void *dev) { Lx::Pci_dev *pci_dev = Lx::pci_dev_registry()->first(); Lx::Irq::irq().request_irq(pci_dev->client(), handler, dev, thread_fn); return 0; } void pci_dev_put(struct pci_dev *pci_dev) { Genode::destroy(Lx_kit::env().heap(), pci_dev); } /*********************** ** linux/workquque.h ** ***********************/ /* Linux emul includes */ #include bool mod_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay) { queue_delayed_work(wq, dwork, delay); return true; } /*********************** ** linux/interrupt.h ** ***********************/ void tasklet_init(struct tasklet_struct *t, void (*f)(unsigned long), unsigned long d) { t->func = f; t->data = d; } void tasklet_schedule(struct tasklet_struct *tasklet) { Lx::Work::work_queue().schedule_tasklet(tasklet); } void tasklet_hi_schedule(struct tasklet_struct *tasklet) { tasklet_schedule(tasklet); } /************************ ** linux/completion.h ** ************************/ #include long __wait_completion(struct completion *work, unsigned long timeout) { return timeout ? 1 : 0; } int wait_for_completion_killable(struct completion *work) { __wait_completion(work, 0); return 0; } long wait_for_completion_killable_timeout(struct completion *work, unsigned long timeout) { __wait_completion(work, 0); return 1; } /****************** ** linux/wait.h ** ******************/ #include /******************* ** linux/timer.h ** *******************/ #include void init_timer_deferrable(struct timer_list *timer) { /* XXX */ } signed long schedule_timeout_uninterruptible(signed long timeout) { return 0; } int wake_up_process(struct task_struct *tsk) { return 0; } /******************* ** linux/sched.h ** *******************/ #include /***************** ** linux/idr.h ** *****************/ struct Idr { enum { INVALID_ENTRY = ~0ul, }; enum { MAX_ENTRIES = 1024, }; Genode::Bit_array _barray { }; addr_t _ptr[MAX_ENTRIES] { }; void *_idp { nullptr }; bool _check(addr_t index) { return index < MAX_ENTRIES ? true : false; } Idr(struct idr *idp) : _idp(idp) { } virtual ~Idr() { } bool handles(void *ptr) { return _idp == ptr; } bool set_id(addr_t index, void *ptr) { if (_barray.get(index, 1)) { return false; } _barray.set(index, 1); _ptr[index] = ptr; return true; } addr_t alloc(addr_t start, void *ptr) { addr_t index = INVALID_ENTRY; for (addr_t i = start; i < MAX_ENTRIES; i++) { if (_barray.get(i, 1)) { continue; } index = i; break; } if (index == INVALID_ENTRY) { return INVALID_ENTRY; } _barray.set(index, 1); _ptr[index] = ptr; return index; } void clear(addr_t index) { if (!_check(index)) { return; } _barray.clear(index, 1); _ptr[index] = 0; } addr_t next(addr_t index) { for (addr_t i = index; i < MAX_ENTRIES; i++) { if (_barray.get(i, 1)) { return i; } } return INVALID_ENTRY; } void *get_ptr(addr_t index) { if (!_check(index)) { return NULL; } return (void*)_ptr[index]; } }; static Genode::Registry> _idr_registry; static Idr &idp_to_idr(struct idr *idp) { Idr *idr = nullptr; auto lookup = [&](Idr &i) { if (i.handles(idp)) { idr = &i; } }; _idr_registry.for_each(lookup); if (!idr) { Genode::Registered *i = new (&Lx_kit::env().heap()) Genode::Registered(_idr_registry, idp); idr = &*i; } return *idr; } int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask) { Idr &idr = idp_to_idr(idp); if ((end - start) > 1) { addr_t const id = idr.alloc(start, ptr); return id != Idr::INVALID_ENTRY ? id : -1; } else { if (idr.set_id(start, ptr)) { return start; } } return -1; } void *idr_find(struct idr *idp, int id) { Idr &idr = idp_to_idr(idp); return idr.get_ptr(id); } void *idr_get_next(struct idr *idp, int *nextid) { Idr &idr = idp_to_idr(idp); addr_t i = idr.next(*nextid); if (i == Idr::INVALID_ENTRY) { return NULL; } *nextid = i; return idr.get_ptr(i); } /**************************** ** asm-generic/getorder.h ** ****************************/ int get_order(unsigned long size) { if (size < PAGE_SIZE) { return 0; } return Genode::log2(size) - PAGE_SHIFT; }