diff --git a/repos/dde_linux/src/include/lx_emul/atomic.h b/repos/dde_linux/src/include/lx_emul/atomic.h index 9dd3181c36..4efa12bef1 100644 --- a/repos/dde_linux/src/include/lx_emul/atomic.h +++ b/repos/dde_linux/src/include/lx_emul/atomic.h @@ -42,8 +42,8 @@ #define ATOMIC_INIT(i) { (i) } -typedef struct atomic { long counter; } atomic_t; -typedef atomic_t atomic_long_t; +typedef struct atomic { int counter; } atomic_t; +typedef struct { long counter; } atomic_long_t; static inline int atomic_read(const atomic_t *p) { return p->counter; } static inline void atomic_set(atomic_t *p, int i) { p->counter = i; } @@ -60,10 +60,10 @@ static inline int atomic_inc_return(atomic_t *p) { return atomic_add_return(1 static inline int atomic_dec_and_test(atomic_t *p) { return atomic_sub_and_test(1, p); } static inline int atomic_inc_not_zero(atomic_t *p) { return p->counter ? atomic_inc_return(p) : 0; } -static inline void atomic_long_inc(atomic_long_t *p) { atomic_add(1, p); } -static inline void atomic_long_sub(int i, atomic_long_t *p) { atomic_sub(i, p); } -static inline long atomic_long_add_return(long i, atomic_long_t *p) { return atomic_add_return(i, p); } -static inline long atomic_long_read(atomic_long_t *p) { return atomic_read(p); } +static inline void atomic_long_inc(atomic_long_t *p) { p->counter += 1; } +static inline void atomic_long_sub(long i, atomic_long_t *p) { p->counter -= i; } +static inline long atomic_long_add_return(long i, atomic_long_t *p) { p->counter += i; return p->counter; } +static inline long atomic_long_read(atomic_long_t *p) { return p->counter; } static inline int atomic_cmpxchg(atomic_t *v, int old, int n) { @@ -101,6 +101,16 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) return ret != u; } +static inline int atomic_dec_if_positive(atomic_t *v) +{ + int c = atomic_read(v); + + if (c >= 0) + atomic_dec(v); + + return c - 1; +} + #define smp_mb__before_atomic_dec() diff --git a/repos/dde_linux/src/include/lx_emul/bitops.h b/repos/dde_linux/src/include/lx_emul/bitops.h index 10bddd3ccf..436b65948f 100644 --- a/repos/dde_linux/src/include/lx_emul/bitops.h +++ b/repos/dde_linux/src/include/lx_emul/bitops.h @@ -30,6 +30,7 @@ #define BIT(nr) (1UL << (nr)) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define BIT_ULL(nr) (1ULL << (nr)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) @@ -85,6 +86,11 @@ static inline unsigned long __ffs64(u64 word) (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) +#define for_each_clear_bit(bit, addr, size) \ + for ((bit) = find_first_zero_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) + static inline int get_bitmask_order(unsigned int count) { return __builtin_clz(count) ^ 0x1f; } @@ -109,3 +115,7 @@ static inline __u16 ror16(__u16 word, unsigned int shift) return (word >> shift) | (word << (16 - shift)); } +#define BITS_PER_LONG_LONG (sizeof(long long) * 8) +#define GENMASK_ULL(h, l) \ + (((~0ULL) - (1ULL << (l)) + 1) & \ + (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) diff --git a/repos/dde_linux/src/include/lx_emul/bug.h b/repos/dde_linux/src/include/lx_emul/bug.h index 5f3ee0efb1..bd43d8e65c 100644 --- a/repos/dde_linux/src/include/lx_emul/bug.h +++ b/repos/dde_linux/src/include/lx_emul/bug.h @@ -39,8 +39,14 @@ #define BUG_ON(condition) do { if (condition) BUG(); } while(0) +#define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e)))) +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); })) + #define BUILD_BUG_ON_MSG(cond,msg) ({ \ extern int __attribute__((error(msg))) build_bug(); \ if (cond) { build_bug(); } }) #define BUILD_BUG() BUILD_BUG_ON_MSG(1,"BUILD_BUG failed") + +#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ + BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0)) diff --git a/repos/dde_linux/src/include/lx_emul/compiler.h b/repos/dde_linux/src/include/lx_emul/compiler.h index 0352172b97..a4d67a69be 100644 --- a/repos/dde_linux/src/include/lx_emul/compiler.h +++ b/repos/dde_linux/src/include/lx_emul/compiler.h @@ -60,10 +60,15 @@ #define WRITE_ONCE(x, val) \ ({ \ barrier(); \ - __builtin_memcpy((void *)&(x), (const void *)&(val), sizeof(x)); \ + union { typeof(x) v; char c[1]; } u = \ + { .v = (typeof(x)) (val) }; \ + __builtin_memcpy((void *)&(x), (const void *)u.c, sizeof(x)); \ barrier(); \ }) +/* XXX alpha, powerpc, blackfin needs proper implementation */ +#define smp_read_barrier_depends() do { } while (0) +#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0) /************************** ** linux/compiler-gcc.h ** @@ -73,5 +78,9 @@ #define __packed __attribute__((packed)) #endif +#define __aligned(x) __attribute__((aligned(x))) + #define uninitialized_var(x) x = x +#define unreachable() \ + do { __builtin_unreachable(); } while (0) diff --git a/repos/dde_linux/src/include/lx_emul/completion.h b/repos/dde_linux/src/include/lx_emul/completion.h index 55b78dcec4..5a7ec826a4 100644 --- a/repos/dde_linux/src/include/lx_emul/completion.h +++ b/repos/dde_linux/src/include/lx_emul/completion.h @@ -21,7 +21,9 @@ struct completion; void complete(struct completion *); +void complete_all(struct completion *); void init_completion(struct completion *c); +bool try_wait_for_completion(struct completion *); void wait_for_completion(struct completion *c); unsigned long wait_for_completion_timeout(struct completion *c, diff --git a/repos/dde_linux/src/include/lx_emul/errno.h b/repos/dde_linux/src/include/lx_emul/errno.h index e0d0a5d24b..20edae857e 100644 --- a/repos/dde_linux/src/include/lx_emul/errno.h +++ b/repos/dde_linux/src/include/lx_emul/errno.h @@ -35,6 +35,8 @@ enum { EIO = 5, ENXIO = 6, E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, EDEADLK = 11, ENOMEM = 12, EACCES = 13, @@ -103,6 +105,8 @@ enum { EPROBE_DEFER = 210, EL3RST = 211, + ENOKEY = 212, + ECHRNG = 213, MAX_ERRNO = 4095, }; @@ -112,10 +116,10 @@ enum { ** linux/err.h ** *****************/ -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) +#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)(0UL-MAX_ERRNO)) static inline bool IS_ERR(void const *ptr) { - return (unsigned long)(ptr) > (unsigned long)(-1000); } + return (unsigned long)(ptr) >= (unsigned long)(0UL-MAX_ERRNO); } static inline void * ERR_PTR(long error) { return (void *) error; } diff --git a/repos/dde_linux/src/include/lx_emul/gfp.h b/repos/dde_linux/src/include/lx_emul/gfp.h index 159dfd89c8..a96a6ca88a 100644 --- a/repos/dde_linux/src/include/lx_emul/gfp.h +++ b/repos/dde_linux/src/include/lx_emul/gfp.h @@ -24,13 +24,12 @@ enum { __GFP_HIGHMEM = 0x00000002u, __GFP_DMA32 = 0x00000004u, __GFP_MOVABLE = 0x00000008u, - __GFP_WAIT = 0x00000010u, + __GFP_RECLAIMABLE = 0x00000010u, __GFP_HIGH = 0x00000020u, __GFP_IO = 0x00000040u, __GFP_FS = 0x00000080u, - __GFP_COLD = 0x00000100u, __GFP_NOWARN = 0x00000200u, - __GFP_REPEAT = 0x00000400u, + __GFP_RETRY_MAYFAIL = 0x00000400u, __GFP_NOFAIL = 0x00000800u, __GFP_NORETRY = 0x00001000u, __GFP_MEMALLOC = 0x00002000u, @@ -39,24 +38,24 @@ enum { __GFP_NOMEMALLOC = 0x00010000u, __GFP_HARDWALL = 0x00020000u, __GFP_THISNODE = 0x00040000u, - __GFP_RECLAIMABLE = 0x00080000u, - __GFP_KMEMCG = 0x00100000u, - __GFP_NOTRACK = 0x00200000u, - __GFP_NO_KSWAPD = 0x00400000u, - __GFP_OTHER_NODE = 0x00800000u, - __GFP_WRITE = 0x01000000u, - __GFP_DIRECT_RECLAIM = 0x400000u, - __GFP_KSWAPD_RECLAIM = 0x2000000u, + __GFP_ATOMIC = 0x00080000u, + __GFP_ACCOUNT = 0x00100000u, + __GFP_DIRECT_RECLAIM = 0x00200000u, + __GFP_WRITE = 0x00800000u, + __GFP_KSWAPD_RECLAIM = 0x01000000u, - GFP_LX_DMA = 0x80000000u, - __GFP_RECLAIM = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM, + GFP_LX_DMA = 0x80000000u, + __GFP_RECLAIM = __GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM, - GFP_ATOMIC = __GFP_HIGH, + GFP_ATOMIC = (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM), GFP_DMA = __GFP_DMA, GFP_DMA32 = __GFP_DMA32, - GFP_KERNEL = __GFP_WAIT | __GFP_IO | __GFP_FS, + GFP_KERNEL = __GFP_RECLAIM | __GFP_IO | __GFP_FS, +/* GFP_TEMPORARY = __GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_RECLAIMABLE, - GFP_USER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL, - GFP_HIGHUSER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | - __GFP_HIGHMEM, +*/ + GFP_USER = __GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL, + GFP_HIGHUSER = GFP_USER | __GFP_HIGHMEM, }; + +#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) diff --git a/repos/dde_linux/src/include/lx_emul/impl/completion.h b/repos/dde_linux/src/include/lx_emul/impl/completion.h index 21b045305d..97f19d9ee7 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/completion.h +++ b/repos/dde_linux/src/include/lx_emul/impl/completion.h @@ -24,13 +24,14 @@ void init_waitqueue_head(wait_queue_head_t *wq) wq->list = new (&Lx_kit::env().heap()) Wait_list; } - -void remove_wait_queue(wait_queue_head_t *wq, wait_queue_t *wait) +void add_wait_queue(wait_queue_head_t *q, wait_queue_entry_t *wait) { - Wait_list *list = static_cast(wq->list); - if (!list) { return; } + printk("%s called\n", __func__); +} - destroy(&Lx_kit::env().heap(), list); +void remove_wait_queue(wait_queue_head_t *wq, wait_queue_entry_t *wait) +{ + printk("%s called\n", __func__); } @@ -87,12 +88,32 @@ void init_completion(struct completion *work) void complete(struct completion *work) { - work->done = 1; + if (work->done != UINT_MAX) + work->done++; Lx::Task *task = static_cast(work->task); if (task) { task->unblock(); } } +void complete_all(struct completion *work) +{ + work->done = UINT_MAX; + + Lx::Task *task = static_cast(work->task); + if (task) { task->unblock(); } +} + +bool try_wait_for_completion(struct completion *work) +{ + int ret = 1; + + if (!work->done) + ret = 0; + else if (work->done != UINT_MAX) + work->done--; + + return ret; +} unsigned long wait_for_completion_timeout(struct completion *work, unsigned long timeout) diff --git a/repos/dde_linux/src/include/lx_emul/impl/delay.h b/repos/dde_linux/src/include/lx_emul/impl/delay.h index 83228ace6a..b9ddbbc459 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/delay.h +++ b/repos/dde_linux/src/include/lx_emul/impl/delay.h @@ -34,7 +34,11 @@ static inline void __delay_timer(unsigned long usecs) _delay_timer->usleep(usecs); } -void udelay(unsigned long usecs) { __delay_timer(usecs); } +void udelay(unsigned long usecs) +{ + __delay_timer(usecs); + Lx::timer_update_jiffies(); +} void msleep(unsigned int msecs) diff --git a/repos/dde_linux/src/include/lx_emul/impl/gfp.h b/repos/dde_linux/src/include/lx_emul/impl/gfp.h index d4bb2a86a5..6597faf289 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/gfp.h +++ b/repos/dde_linux/src/include/lx_emul/impl/gfp.h @@ -18,13 +18,18 @@ #include -struct page *alloc_pages(gfp_t gfp_mask, unsigned int order) +struct page *alloc_pages(gfp_t const gfp_mask, unsigned int order) { + using Genode::Cache_attribute; + struct page *page = (struct page *)kzalloc(sizeof(struct page), 0); size_t size = PAGE_SIZE << order; - Genode::Ram_dataspace_capability ds_cap = Lx::backend_alloc(size, Genode::UNCACHED); + gfp_t const dma_mask = (GFP_DMA | GFP_LX_DMA | GFP_DMA32); + Cache_attribute const cached = (gfp_mask & dma_mask) ? Genode::UNCACHED + : Genode::CACHED; + Genode::Ram_dataspace_capability ds_cap = Lx::backend_alloc(size, cached); page->addr = Lx_kit::env().rm().attach(ds_cap); page->paddr = Genode::Dataspace_client(ds_cap).phys_addr(); @@ -57,3 +62,9 @@ void get_page(struct page *page) { atomic_inc(&page->_count); } + + +void put_page(struct page *page) +{ + TRACE; +} diff --git a/repos/dde_linux/src/include/lx_emul/impl/mutex.h b/repos/dde_linux/src/include/lx_emul/impl/mutex.h index 35030e8746..745dce2885 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/mutex.h +++ b/repos/dde_linux/src/include/lx_emul/impl/mutex.h @@ -34,7 +34,7 @@ void mutex_destroy(struct mutex *m) Lx::Task::List *waiters = static_cast(m->waiters); /* FIXME potentially blocked tasks are not unblocked */ - if (waiters->first()) { + if (waiters && waiters->first()) { Genode::error(__func__, "destroying non-empty waiters list"); } diff --git a/repos/dde_linux/src/include/lx_emul/impl/sched.h b/repos/dde_linux/src/include/lx_emul/impl/sched.h index 923e7f6de5..5ec8afaf09 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/sched.h +++ b/repos/dde_linux/src/include/lx_emul/impl/sched.h @@ -1,6 +1,7 @@ /* * \brief Implementation of linux/sched.h * \author Norman Feske + * \author Stefan Kalkowski * \date 2015-09-09 */ @@ -14,26 +15,33 @@ /* Linux kit includes */ #include +struct process_timer { + struct timer_list timer; + Lx::Task &task; -static void unblock_task(unsigned long task) + process_timer(Lx::Task &task) : task(task) {} +}; + + +static void process_timeout(struct timer_list *list) { - Lx::Task *t = (Lx::Task *)task; - - t->unblock(); + struct process_timer *timeout = from_timer(timeout, list, timer); + timeout->task.unblock(); } signed long schedule_timeout(signed long timeout) { - struct timer_list timer; + Lx::Task & cur_task = *Lx::scheduler().current(); + struct process_timer timer { cur_task }; + timer_setup(&timer.timer, process_timeout, 0); unsigned long expire = timeout + jiffies; - setup_timer(&timer, unblock_task, (unsigned long)Lx::scheduler().current()); - mod_timer(&timer, expire); + mod_timer(&timer.timer, expire); - Lx::scheduler().current()->block_and_schedule(); + cur_task.block_and_schedule(); - del_timer(&timer); + del_timer(&timer.timer); timeout = (expire - jiffies); diff --git a/repos/dde_linux/src/include/lx_emul/impl/slab.h b/repos/dde_linux/src/include/lx_emul/impl/slab.h index 9e38dde2fa..abf0699879 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/slab.h +++ b/repos/dde_linux/src/include/lx_emul/impl/slab.h @@ -46,6 +46,12 @@ void *kzalloc(size_t size, gfp_t flags) } +void *kvzalloc(size_t size, gfp_t flags) +{ + return kmalloc(size, flags | __GFP_ZERO); +} + + void *kzalloc_node(size_t size, gfp_t flags, int node) { return kzalloc(size, 0); @@ -171,6 +177,17 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align } +struct kmem_cache *kmem_cache_create_usercopy(const char *name, size_t size, + size_t align, slab_flags_t flags, + size_t useroffset, size_t usersize, + void (*ctor)(void *)) +{ + /* XXX copied from above */ + enum { SLAB_LX_DMA = 0x80000000ul, }; + return new (Lx::Malloc::mem()) kmem_cache(size, flags & SLAB_LX_DMA, ctor); +} + + void kmem_cache_destroy(struct kmem_cache *cache) { destroy(Lx::Malloc::mem(), cache); diff --git a/repos/dde_linux/src/include/lx_emul/impl/timer.h b/repos/dde_linux/src/include/lx_emul/impl/timer.h index 09f4ef8d3e..c3dce2fd35 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/timer.h +++ b/repos/dde_linux/src/include/lx_emul/impl/timer.h @@ -15,9 +15,6 @@ #include -void init_timer(struct timer_list *timer) { } - - int mod_timer(struct timer_list *timer, unsigned long expires) { if (!Lx::timer().find(timer)) @@ -27,12 +24,12 @@ int mod_timer(struct timer_list *timer, unsigned long expires) } -void setup_timer(struct timer_list *timer,void (*function)(unsigned long), - unsigned long data) +void timer_setup(struct timer_list *timer, + void (*function)(struct timer_list *), + unsigned int flags) { timer->function = function; - timer->data = data; - init_timer(timer); + timer->flags = flags; } @@ -59,7 +56,7 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, enum hrtimer_mode m int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_ns, const enum hrtimer_mode mode) { - unsigned long expires = tim.tv64 / (NSEC_PER_MSEC * HZ); + unsigned long expires = tim / (NSEC_PER_MSEC * HZ); /* * Prevent truncation through rounding the values by adding 1 jiffy @@ -74,6 +71,12 @@ int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, } +bool hrtimer_active(const struct hrtimer *timer) +{ + return Lx::timer().find(timer); +} + + int hrtimer_cancel(struct hrtimer *timer) { int rv = Lx::timer().del(timer); diff --git a/repos/dde_linux/src/include/lx_emul/impl/wait.h b/repos/dde_linux/src/include/lx_emul/impl/wait.h index e99bde6da1..15bbbe0171 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/wait.h +++ b/repos/dde_linux/src/include/lx_emul/impl/wait.h @@ -15,7 +15,7 @@ #include -void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *w, int state) +void prepare_to_wait(wait_queue_head_t *q, wait_queue_entry_t *w, int state) { if (!q) { return; } @@ -26,13 +26,13 @@ void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *w, int state) } -void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *w, int state) +void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_entry_t *w, int state) { prepare_to_wait(q, w, state); } -void finish_wait(wait_queue_head_t *q, wait_queue_t *w) +void finish_wait(wait_queue_head_t *q, wait_queue_entry_t *w) { if (!q) { return; } diff --git a/repos/dde_linux/src/include/lx_emul/impl/work.h b/repos/dde_linux/src/include/lx_emul/impl/work.h index 717bfbfc38..e03d4fbef8 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/work.h +++ b/repos/dde_linux/src/include/lx_emul/impl/work.h @@ -27,6 +27,13 @@ bool queue_work(struct workqueue_struct *wq, struct work_struct *work) { work->wq = wq; + /* a invalid func pointer will lead to pagefault with ip=0 sp=0 */ + if (!work || !work->func) { + Genode::error("invalid work, called from ", + __builtin_return_address(0)); + return false; + } + /* check for separate work queue task */ if (wq && wq->task) { Lx::Work *lx_work = (Lx::Work *)wq->task; @@ -41,20 +48,10 @@ bool queue_work(struct workqueue_struct *wq, struct work_struct *work) } -static void _schedule_delayed_work(unsigned long w) +void delayed_work_timer_fn(struct timer_list *t) { - delayed_work *work = (delayed_work *)w; - workqueue_struct *wq = work->wq; - - /* check for separate work queue task */ - if (wq && wq->task) { - Lx::Work *lx_work = (Lx::Work *)wq->task; - lx_work->schedule_delayed(work, 0); - lx_work->unblock(); - } else { - Lx::Work::work_queue().schedule_delayed(work, 0); - Lx::Work::work_queue().unblock(); - } + struct delayed_work *dwork = from_timer(dwork, t, timer); + queue_work(dwork->wq, &dwork->work); } @@ -65,10 +62,10 @@ bool queue_delayed_work(struct workqueue_struct *wq, /* treat delayed work without delay like any other work */ if (delay == 0) { - _schedule_delayed_work((unsigned long)dwork); + delayed_work_timer_fn(&dwork->timer); } else { - setup_timer(&dwork->timer, _schedule_delayed_work, (unsigned long)dwork); - mod_timer(&dwork->timer, delay); + timer_setup(&dwork->timer, delayed_work_timer_fn, 0); + mod_timer(&dwork->timer, jiffies + delay); } return true; } @@ -82,7 +79,13 @@ int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) bool cancel_work_sync(struct work_struct *work) { - return Lx::Work::work_queue().cancel_work(work, true); + /* check for separate work queue task */ + if (work->wq && work->wq->task) { + Lx::Work *lx_work = (Lx::Work *)work->wq->task; + + return lx_work->cancel_work(work, true); + } + return false; } @@ -101,12 +104,8 @@ bool cancel_delayed_work_sync(struct delayed_work *dwork) bool pending = cancel_delayed_work(dwork); if (pending) { - Genode::warning("WARN: delayed_work ", dwork, " is executed directly in " - "current '", Lx::scheduler().current()->name(), "' routine"); - dwork->work.func(&dwork->work); } return pending; } - diff --git a/repos/dde_linux/src/include/lx_emul/ioport.h b/repos/dde_linux/src/include/lx_emul/ioport.h index 698ffe90fc..c86fcf2c81 100644 --- a/repos/dde_linux/src/include/lx_emul/ioport.h +++ b/repos/dde_linux/src/include/lx_emul/ioport.h @@ -22,6 +22,9 @@ #define IORESOURCE_IO 0x00000100 #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_UNSET 0x20000000 + +#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ struct resource { @@ -31,6 +34,20 @@ struct resource unsigned long flags; }; +/* helpers to define resources */ +#define DEFINE_RES_NAMED(_start, _size, _name, _flags) \ +{ \ + .start = (_start), \ + .end = (_start) + (_size) - 1, \ + .name = (_name), \ + .flags = (_flags), \ +} + +#define DEFINE_RES_MEM_NAMED(_start, _size, _name) \ + DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM) +#define DEFINE_RES_MEM(_start, _size) \ + DEFINE_RES_MEM_NAMED((_start), (_size), NULL) + struct device; struct resource *request_region(resource_size_t start, resource_size_t n, @@ -44,4 +61,22 @@ struct resource * devm_request_mem_region(struct device *dev, resource_size_t st void release_region(resource_size_t start, resource_size_t n); void release_mem_region(resource_size_t start, resource_size_t n); -resource_size_t resource_size(const struct resource *res); +static inline resource_size_t resource_size(const struct resource *res) +{ + return res->end - res->start + 1; +} + +static inline unsigned long resource_type(const struct resource *res) +{ + return res->flags & IORESOURCE_TYPE_BITS; +} + +/* True iff r1 completely contains r2 */ +static inline bool resource_contains(struct resource *r1, struct resource *r2) +{ + if (resource_type(r1) != resource_type(r2)) + return false; + if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET) + return false; + return r1->start <= r2->start && r1->end >= r2->end; +} diff --git a/repos/dde_linux/src/include/lx_emul/kernel.h b/repos/dde_linux/src/include/lx_emul/kernel.h index 288199f991..cabae4b4f0 100644 --- a/repos/dde_linux/src/include/lx_emul/kernel.h +++ b/repos/dde_linux/src/include/lx_emul/kernel.h @@ -19,9 +19,13 @@ ** linux/kconfig.h ** *********************/ -#define IS_ENABLED(x) x -#define IS_BUILTIN(x) x - +#define __ARG_PLACEHOLDER_1 0, +#define __take_second_arg(__ignored, val, ...) val +#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) +#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) +#define __is_defined(x) ___is_defined(x) +#define IS_BUILTIN(option) __is_defined(option) +#define IS_ENABLED(option) IS_BUILTIN(option) /******************** ** linux/kernel.h ** @@ -185,3 +189,4 @@ void might_sleep(); #define swap(a, b) \ do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) +#define max3(x, y, z) max((typeof(x))max(x, y), z) diff --git a/repos/dde_linux/src/include/lx_emul/list.h b/repos/dde_linux/src/include/lx_emul/list.h index 749f6d551b..3dec9af38c 100644 --- a/repos/dde_linux/src/include/lx_emul/list.h +++ b/repos/dde_linux/src/include/lx_emul/list.h @@ -31,10 +31,11 @@ #define LIST_POISON1 nullptr #define LIST_POISON2 nullptr #else -#define LIST_POISON1 ((void *)0x00100100) -#define LIST_POISON2 ((void *)0x00200200) +#define LIST_POISON1 ((void *)0x00000100) +#define LIST_POISON2 ((void *)0x00000200) #endif /* __cplusplus */ +#define POISON_INUSE 0x5a /****************** ** linux/list.h ** diff --git a/repos/dde_linux/src/include/lx_emul/module.h b/repos/dde_linux/src/include/lx_emul/module.h index f464a6a57e..90490b2b06 100644 --- a/repos/dde_linux/src/include/lx_emul/module.h +++ b/repos/dde_linux/src/include/lx_emul/module.h @@ -50,7 +50,7 @@ struct module; -#define module_init(fn) void module_##fn(void) { fn(); } +#define module_init(fn) int module_##fn(void) { return fn(); } #define module_exit(fn) void module_exit_##fn(void) { fn(); } void module_put_and_exit(int); diff --git a/repos/dde_linux/src/include/lx_emul/pm.h b/repos/dde_linux/src/include/lx_emul/pm.h index cb2c169d89..82f5396d55 100644 --- a/repos/dde_linux/src/include/lx_emul/pm.h +++ b/repos/dde_linux/src/include/lx_emul/pm.h @@ -26,7 +26,9 @@ typedef struct pm_message { int event; } pm_message_t; struct dev_pm_info { pm_message_t power_state; - bool is_prepared; + bool is_prepared:1; + bool is_suspended:1; + atomic_t usage_count; }; struct dev_pm_ops { diff --git a/repos/dde_linux/src/include/lx_emul/semaphore.h b/repos/dde_linux/src/include/lx_emul/semaphore.h index c72a63497b..21dc4c54db 100644 --- a/repos/dde_linux/src/include/lx_emul/semaphore.h +++ b/repos/dde_linux/src/include/lx_emul/semaphore.h @@ -30,5 +30,6 @@ void down_read(struct rw_semaphore *sem); void up_read(struct rw_semaphore *sem); void down_write(struct rw_semaphore *sem); void up_write(struct rw_semaphore *sem); +int down_write_killable(struct rw_semaphore *); #define __RWSEM_INITIALIZER(name) { 0 } diff --git a/repos/dde_linux/src/include/lx_emul/spinlock.h b/repos/dde_linux/src/include/lx_emul/spinlock.h index 9ad6af58d0..64b058a702 100644 --- a/repos/dde_linux/src/include/lx_emul/spinlock.h +++ b/repos/dde_linux/src/include/lx_emul/spinlock.h @@ -20,10 +20,12 @@ **********************/ typedef struct spinlock { unsigned unused; } spinlock_t; +typedef struct raw_spinlock { unsigned dummy; } raw_spinlock_t; #define DEFINE_SPINLOCK(name) spinlock_t name void spin_lock(spinlock_t *lock); void spin_lock_nested(spinlock_t *lock, int subclass); +void spin_lock_irqsave_nested(spinlock_t *lock, unsigned flags, int subclass); void spin_unlock(spinlock_t *lock); void spin_lock_init(spinlock_t *lock); void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); @@ -36,6 +38,8 @@ void spin_lock_bh(spinlock_t *lock); void spin_unlock_bh(spinlock_t *lock); int spin_trylock(spinlock_t *lock); +void raw_spin_lock_init(raw_spinlock_t *); +#define __RAW_SPIN_LOCK_UNLOCKED(raw_spinlock_t) {0} /**************************** ** linux/spinlock_types.h ** diff --git a/repos/dde_linux/src/include/lx_emul/time.h b/repos/dde_linux/src/include/lx_emul/time.h index 083ec492ae..93351a48e8 100644 --- a/repos/dde_linux/src/include/lx_emul/time.h +++ b/repos/dde_linux/src/include/lx_emul/time.h @@ -50,9 +50,21 @@ enum { ** linux/ktime.h ** *******************/ -union ktime { s64 tv64; }; +typedef s64 ktime_t; -typedef union ktime ktime_t; +static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2) +{ + if (cmp1 < cmp2) + return -1; + if (cmp1 > cmp2) + return 1; + return 0; +} + +static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2) +{ + return ktime_compare(cmp1, cmp2) < 0; +} ktime_t ktime_add_ns(const ktime_t kt, u64 nsec); @@ -61,29 +73,35 @@ static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec) return ktime_add_ns(kt, usec * 1000); } +static inline ktime_t ktime_add_ms(const ktime_t kt, const u64 msec) +{ + return ktime_add_ns(kt, msec * NSEC_PER_MSEC); +} + static inline ktime_t ktime_get(void) { - return (ktime_t){ .tv64 = (s64)jiffies * HZ * NSEC_PER_MSEC /* ns */ }; + return (ktime_t){ (s64)jiffies * HZ * NSEC_PER_MSEC /* ns */ }; } static inline ktime_t ktime_set(const long sec, const unsigned long nsec) { - return (ktime_t){ .tv64 = (s64)sec * NSEC_PER_SEC + (s64)nsec /* ns */ }; + return (ktime_t){ (s64)sec * NSEC_PER_SEC + (s64)nsec /* ns */ }; } static inline ktime_t ktime_add(const ktime_t a, const ktime_t b) { - return (ktime_t){ .tv64 = a.tv64 + b.tv64 /* ns */ }; + return (ktime_t){ a + b /* ns */ }; } +s64 ktime_ms_delta(const ktime_t, const ktime_t); s64 ktime_us_delta(const ktime_t later, const ktime_t earlier); static inline struct timeval ktime_to_timeval(const ktime_t kt) { struct timeval tv; - tv.tv_sec = kt.tv64 / NSEC_PER_SEC; - tv.tv_usec = (kt.tv64 - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC; + tv.tv_sec = kt / NSEC_PER_SEC; + tv.tv_usec = (kt - (tv.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC; return tv; } @@ -91,3 +109,4 @@ ktime_t ktime_get_real(void); ktime_t ktime_sub(const ktime_t, const ktime_t); ktime_t ktime_get_monotonic_offset(void); +ktime_t ktime_get_boottime(void); diff --git a/repos/dde_linux/src/include/lx_emul/timer.h b/repos/dde_linux/src/include/lx_emul/timer.h index acc6be57dc..207072db46 100644 --- a/repos/dde_linux/src/include/lx_emul/timer.h +++ b/repos/dde_linux/src/include/lx_emul/timer.h @@ -3,6 +3,7 @@ * \author Norman Feske * \author Sebastian Sumpf * \author Josef Soentgen + * \author Stefan Kalkowski * \date 2014-08-21 * * Based on the prototypes found in the Linux kernel's 'include/'. @@ -24,38 +25,40 @@ extern struct tvec_base boot_tvec_bases; /* needed by 'dwc_common_linux.c' */ struct timer_list { - void (*function)(unsigned long); - unsigned long data; - void *timer; unsigned long expires; - struct tvec_base *base; /* needed by 'dwc_common_linux.c' */ + void (*function)(struct timer_list*); + unsigned int flags; + + unsigned long data; /* keep for compat with 4.4.3 drivers */ }; -void init_timer(struct timer_list *); -void init_timer_deferrable(struct timer_list *); -int mod_timer(struct timer_list *timer, unsigned long expires); -int del_timer(struct timer_list * timer); -void setup_timer(struct timer_list *timer, void (*function)(unsigned long), - unsigned long data); - -int timer_pending(const struct timer_list * timer); +int mod_timer(struct timer_list *timer, unsigned long expires); +int del_timer(struct timer_list * timer); +void timer_setup(struct timer_list *timer, + void (*callback)(struct timer_list *), unsigned int flags); +int timer_pending(const struct timer_list * timer); unsigned long round_jiffies(unsigned long j); unsigned long round_jiffies_relative(unsigned long j); unsigned long round_jiffies_up(unsigned long j); - -void set_timer_slack(struct timer_list *time, int slack_hz); -static inline void add_timer(struct timer_list *timer) { mod_timer(timer, timer->expires); } - -static inline -int del_timer_sync(struct timer_list * timer) { return del_timer(timer); } +static inline void add_timer(struct timer_list *timer) { + mod_timer(timer, timer->expires); } +static inline int del_timer_sync(struct timer_list * timer) { + return del_timer(timer); } /********************* ** linux/hrtimer.h ** *********************/ -enum hrtimer_mode { HRTIMER_MODE_ABS = 0 }; -enum hrtimer_restart { HRTIMER_NORESTART = 0 }; +enum hrtimer_mode { + HRTIMER_MODE_ABS = 0, + HRTIMER_MODE_REL = 0x1, + HRTIMER_MODE_REL_PINNED = 0x03, +}; +enum hrtimer_restart { + HRTIMER_NORESTART, + HRTIMER_RESTART, +}; struct hrtimer { @@ -64,8 +67,9 @@ struct hrtimer void *timer; }; -int hrtimer_start_range_ns(struct hrtimer *, ktime_t, - unsigned long, const enum hrtimer_mode); +int hrtimer_start_range_ns(struct hrtimer *, ktime_t, + unsigned long, const enum hrtimer_mode); void hrtimer_init(struct hrtimer *, clockid_t, enum hrtimer_mode); -int hrtimer_cancel(struct hrtimer *); +int hrtimer_cancel(struct hrtimer *); +bool hrtimer_active(const struct hrtimer *); diff --git a/repos/dde_linux/src/include/lx_emul/types.h b/repos/dde_linux/src/include/lx_emul/types.h index 0d10af05cb..97667a548c 100644 --- a/repos/dde_linux/src/include/lx_emul/types.h +++ b/repos/dde_linux/src/include/lx_emul/types.h @@ -106,3 +106,5 @@ typedef u16 wchar_t; * XXX 'mode_t' is 'unsigned int' on x86_64 */ typedef unsigned short mode_t; + +typedef unsigned slab_flags_t; diff --git a/repos/dde_linux/src/include/lx_emul/work.h b/repos/dde_linux/src/include/lx_emul/work.h index ac409cb6c0..eb2b3b63ba 100644 --- a/repos/dde_linux/src/include/lx_emul/work.h +++ b/repos/dde_linux/src/include/lx_emul/work.h @@ -20,8 +20,10 @@ ***********************/ enum { - WQ_MEM_RECLAIM, - WQ_CPU_INTENSIVE, + WQ_FREEZABLE = 1 << 2, + WQ_MEM_RECLAIM = 1 << 3, + WQ_HIGHPRI = 1 << 4, + WQ_CPU_INTENSIVE = 1 << 5, }; struct work_struct; @@ -45,13 +47,14 @@ struct delayed_work { bool cancel_work_sync(struct work_struct *work); bool cancel_delayed_work_sync(struct delayed_work *work); bool cancel_delayed_work(struct delayed_work *dwork); -int schedule_delayed_work(struct delayed_work *work, unsigned long delay); -int schedule_work(struct work_struct *work); +int schedule_delayed_work(struct delayed_work *work, unsigned long delay); +int schedule_work(struct work_struct *work); void flush_scheduled_work(void); bool flush_work(struct work_struct *work); bool flush_work_sync(struct work_struct *work); +void delayed_work_timer_fn(struct timer_list *t); #define PREPARE_WORK(_work, _func) \ do { (_work)->func = (_func); } while (0) @@ -71,7 +74,7 @@ bool flush_work_sync(struct work_struct *work); #define INIT_DELAYED_WORK(_work, _func) \ do { \ INIT_WORK(&(_work)->work, (_func)); \ - init_timer(&(_work)->timer); \ + timer_setup(&(_work)->timer, delayed_work_timer_fn, 0); \ } while (0) @@ -87,6 +90,8 @@ void flush_workqueue(struct workqueue_struct *wq); bool queue_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long); bool flush_delayed_work(struct delayed_work *dwork); bool queue_work(struct workqueue_struct *wq, struct work_struct *work); +struct work_struct *current_work(void); +void drain_workqueue(struct workqueue_struct *); #define DECLARE_DELAYED_WORK(n, f) \ struct delayed_work n = { .work = { .func = f }, .timer = { .function = 0 } } @@ -100,6 +105,8 @@ static inline struct delayed_work *to_delayed_work(struct work_struct *work) } extern struct workqueue_struct *system_wq; +extern struct workqueue_struct *system_unbound_wq; +extern struct workqueue_struct *system_long_wq; enum { WORK_STRUCT_STATIC = 0, @@ -138,28 +145,31 @@ enum { ** linux/wait.h ** ******************/ -typedef struct wait_queue wait_queue_t; -typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key); +typedef struct wait_queue_entry wait_queue_entry_t; +typedef int (*wait_queue_func_t)(wait_queue_entry_t *, unsigned, int, void *); typedef struct wait_queue_head { void *list; } wait_queue_head_t; -struct wait_queue -{ - wait_queue_func_t func; - void *private; +struct wait_queue_entry { + unsigned int flags; + void *private; + wait_queue_func_t func; + struct list_head entry; }; +void init_wait_entry(struct wait_queue_entry *, int); + #define DEFINE_WAIT(name) \ - wait_queue_t name; + wait_queue_entry_t name; #define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 } #define DECLARE_WAITQUEUE(name, tsk) \ - wait_queue_t name + wait_queue_entry_t name #define DECLARE_WAIT_QUEUE_HEAD(name) \ wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) #define DEFINE_WAIT_FUNC(name, function) \ - wait_queue_t name + wait_queue_entry_t name /* simplified signature */ void __wake_up(wait_queue_head_t *q, bool all); @@ -176,14 +186,14 @@ int waitqueue_active(wait_queue_head_t *); void wake_up_interruptible_sync_poll(wait_queue_head_t *, int); void wake_up_interruptible_poll(wait_queue_head_t *, int); -void prepare_to_wait(wait_queue_head_t *, wait_queue_t *, int); -void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_t *, int); -void finish_wait(wait_queue_head_t *, wait_queue_t *); +void prepare_to_wait(wait_queue_head_t *, wait_queue_entry_t *, int); +void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_entry_t *, int); +void finish_wait(wait_queue_head_t *, wait_queue_entry_t *); -int autoremove_wake_function(wait_queue_t *, unsigned, int, void *); -void add_wait_queue(wait_queue_head_t *, wait_queue_t *); -void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_t *); -void remove_wait_queue(wait_queue_head_t *, wait_queue_t *); +int autoremove_wake_function(wait_queue_entry_t *, unsigned, int, void *); +void add_wait_queue(wait_queue_head_t *, wait_queue_entry_t *); +void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_entry_t *); +void remove_wait_queue(wait_queue_head_t *, wait_queue_entry_t *); /* our wait event implementation - it's okay as value */ void ___wait_event(wait_queue_head_t*); diff --git a/repos/dde_linux/src/include/lx_kit/addr_to_page_mapping.h b/repos/dde_linux/src/include/lx_kit/addr_to_page_mapping.h index d52ac47092..bae6133b47 100644 --- a/repos/dde_linux/src/include/lx_kit/addr_to_page_mapping.h +++ b/repos/dde_linux/src/include/lx_kit/addr_to_page_mapping.h @@ -76,6 +76,8 @@ class Lx::Addr_to_page_mapping : public Lx_kit::List::Elem return 0; } + + static struct page* find_page_by_paddr(unsigned long paddr); }; diff --git a/repos/dde_linux/src/include/lx_kit/internal/io_port.h b/repos/dde_linux/src/include/lx_kit/internal/io_port.h index 6abb968395..e9cb766f3c 100644 --- a/repos/dde_linux/src/include/lx_kit/internal/io_port.h +++ b/repos/dde_linux/src/include/lx_kit/internal/io_port.h @@ -59,6 +59,8 @@ class Lx::Io_port case 1: _port->outb(port, val); break; case 2: _port->outw(port, val); break; case 4: _port->outl(port, val); break; + default: + return false; } return true; @@ -74,6 +76,8 @@ class Lx::Io_port case 1: *val = _port->inb(port); break; case 2: *val = _port->inw(port); break; case 4: *val = _port->inl(port); break; + default: + return false; } return true; diff --git a/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h b/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h index 74796155d9..9699cee43d 100644 --- a/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h +++ b/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h @@ -35,12 +35,14 @@ namespace Lx { /** * Return singleton 'Platform::Connection' * - * Implementation must be privided by the driver. + * Implementation must be provided by the driver. */ Platform::Connection *pci(); template - static inline void for_each_pci_device(FUNC const &func); + static inline void for_each_pci_device(FUNC const &func, + unsigned const device_class = 0, + unsigned const class_mask = 0); } @@ -220,7 +222,8 @@ class Lx::Pci_dev : public pci_dev, public Lx_kit::List::Element * released at the platform driver. */ template -void Lx::for_each_pci_device(FUNC const &func) +void Lx::for_each_pci_device(FUNC const &func, unsigned const device_class, + unsigned const class_mask) { /* * Obtain first device, the operation may exceed the session quota. @@ -228,7 +231,7 @@ void Lx::for_each_pci_device(FUNC const &func) */ Platform::Device_capability cap = Lx::pci()->with_upgrade([&] () { - return Lx::pci()->first_device(); }); + return Lx::pci()->first_device(device_class, class_mask); }); /* * Iterate over the devices of the platform session. @@ -247,7 +250,7 @@ void Lx::for_each_pci_device(FUNC const &func) */ Platform::Device_capability next_cap = Lx::pci()->with_upgrade([&] () { - return pci()->next_device(cap); }); + return pci()->next_device(cap, device_class, class_mask); }); Lx::pci()->release_device(cap); cap = next_cap; diff --git a/repos/dde_linux/src/include/lx_kit/pci_dev_registry.h b/repos/dde_linux/src/include/lx_kit/pci_dev_registry.h index 79442dc048..7cee6f736c 100644 --- a/repos/dde_linux/src/include/lx_kit/pci_dev_registry.h +++ b/repos/dde_linux/src/include/lx_kit/pci_dev_registry.h @@ -17,6 +17,7 @@ /* Linux emulation environment includes */ #include #include +#include namespace Lx { @@ -27,7 +28,7 @@ namespace Lx { * * Implementation must be provided by the driver. */ - Pci_dev_registry *pci_dev_registry(); + Pci_dev_registry *pci_dev_registry(Genode::Env *env = nullptr); } @@ -35,15 +36,23 @@ class Lx::Pci_dev_registry { private: - Lx_kit::List _devs; + Lx_kit::List _devs; + Genode::Env &_env; public: + Pci_dev_registry(Genode::Env &env) : _env(env) { } + void insert(Pci_dev *pci_dev) { _devs.insert(pci_dev); } + void remove(Pci_dev *pci_dev) + { + _devs.remove(pci_dev); + } + Pci_dev* first() { return _devs.first(); } Genode::Io_mem_dataspace_capability io_mem(Genode::addr_t phys, @@ -89,17 +98,50 @@ class Lx::Pci_dev_registry return value; } + try { + Genode::Io_port_connection iox(_env, port, sizeof(T)); + switch (sizeof(T)) { + case 1: + return iox.inb(port); + case 2: + return iox.inw(port); + case 4: + return iox.inl(port); + } + } catch (...) { + Genode::error("unknown exception io_read"); + } + Genode::warning("I/O port(", port, ") read failed"); - return (T)~0; + + return (T)~0U; } template void io_write(unsigned port, T value) { /* try I/O access on all PCI devices, return on first success */ - for (Pci_dev *d = _devs.first(); d; d = d->next()) + for (Pci_dev *d = _devs.first(); d; d = d->next()) { if (d->io_port().out(port, value)) return; + } + + try { + Genode::Io_port_connection iox(_env, port, sizeof(T)); + switch (sizeof(T)) { + case 1: + iox.outb(port, value); + return; + case 2: + iox.outw(port, value); + return; + case 4: + iox.outl(port, value); + return; + } + } catch (...) { + Genode::error("unknown exception io_write"); + } Genode::warning("I/O port(", port, ") write failed"); } diff --git a/repos/dde_linux/src/include/lx_kit/work.h b/repos/dde_linux/src/include/lx_kit/work.h index f4c694320b..953747b01a 100644 --- a/repos/dde_linux/src/include/lx_kit/work.h +++ b/repos/dde_linux/src/include/lx_kit/work.h @@ -19,6 +19,7 @@ namespace Lx { class Work; + class Task; } @@ -34,16 +35,23 @@ class Lx::Work */ virtual void unblock() = 0; + /** + * Execute all queued work items + * + * The calling task is woken up afterwards. + */ + virtual void flush(Task &) = 0; + + /** + * Wakeup calling task after work item was executed + */ + virtual void wakeup_for(void const * const, Task &) = 0; + /** * Schedule work */ virtual void schedule(struct ::work_struct *) = 0; - /** - * Schedule delayed work - */ - virtual void schedule_delayed(struct ::delayed_work *, unsigned long delay) = 0; - /** * Schedule delayed work */ @@ -53,6 +61,11 @@ class Lx::Work * Cancel work item */ virtual bool cancel_work(struct ::work_struct *, bool sync = false) = 0; + + /** + * Check if work is currently queued + */ + virtual bool work_queued(void const * const) = 0; /** * Return task name diff --git a/repos/dde_linux/src/lx_kit/pci.cc b/repos/dde_linux/src/lx_kit/pci.cc index dab6cf3b2c..072165e601 100644 --- a/repos/dde_linux/src/lx_kit/pci.cc +++ b/repos/dde_linux/src/lx_kit/pci.cc @@ -90,6 +90,8 @@ void Lx::pci_init(Genode::Env &env, Genode::Ram_session &ram, _global_pci.construct(env); _global_ram = &ram; _global_md_alloc = &md_alloc; + + Lx::pci_dev_registry(&env); } @@ -99,9 +101,9 @@ Platform::Connection *Lx::pci() } -Lx::Pci_dev_registry *Lx::pci_dev_registry() +Lx::Pci_dev_registry *Lx::pci_dev_registry(Genode::Env *env) { - static Lx::Pci_dev_registry _pci_dev_registry; + static Lx::Pci_dev_registry _pci_dev_registry(*env); return &_pci_dev_registry; } diff --git a/repos/dde_linux/src/lx_kit/printf.cc b/repos/dde_linux/src/lx_kit/printf.cc index 264e32fc95..9d7cd224c2 100644 --- a/repos/dde_linux/src/lx_kit/printf.cc +++ b/repos/dde_linux/src/lx_kit/printf.cc @@ -76,7 +76,7 @@ class Lx::Format_command if (!format[++consumed]) return; /* check for %$x syntax */ - prefix = (format[consumed] == '#'); + prefix = (format[consumed] == '#') || (format[consumed] == '.'); if (prefix && !format[++consumed]) return; /* heading zero indicates zero-padding */ diff --git a/repos/dde_linux/src/lx_kit/timer.cc b/repos/dde_linux/src/lx_kit/timer.cc index 503fb54971..a27e92b807 100644 --- a/repos/dde_linux/src/lx_kit/timer.cc +++ b/repos/dde_linux/src/lx_kit/timer.cc @@ -61,7 +61,7 @@ class Lx_kit::Timer : public Lx::Timer { timer_list *t = static_cast(timer); if (t->function) - t->function(t->data); + t->function(t); } break; diff --git a/repos/dde_linux/src/lx_kit/work.cc b/repos/dde_linux/src/lx_kit/work.cc index 26a39c3362..68867bf253 100644 --- a/repos/dde_linux/src/lx_kit/work.cc +++ b/repos/dde_linux/src/lx_kit/work.cc @@ -36,6 +36,8 @@ class Lx_kit::Work : public Lx::Work */ struct Context : public Lx_kit::List::Element { + Lx::Task *waiting_task { nullptr }; + void *work; enum Type { NORMAL, DELAYED, TASKLET } type; @@ -86,6 +88,9 @@ class Lx_kit::Work : public Lx::Work public: + Lx::Task *_waiting_task = nullptr; + + Work(Genode::Allocator &alloc, char const *name = "work_queue") : _task(Work::run_work, reinterpret_cast(this), name, Lx::Task::PRIORITY_2, Lx::scheduler()), @@ -99,6 +104,12 @@ class Lx_kit::Work : public Lx::Work while (Context *c = _list.first()) { _list.remove(c); c->exec(); + + if (c->waiting_task) { + c->waiting_task->unblock(); + c->waiting_task = nullptr; + } + destroy(&_work_alloc, c); } } @@ -108,6 +119,12 @@ class Lx_kit::Work : public Lx::Work Work *work_queue = reinterpret_cast(wq); while (1) { work_queue->exec(); + + if (work_queue->_waiting_task) { + work_queue->_waiting_task->unblock(); + work_queue->_waiting_task = nullptr; + } + Lx::scheduler().current()->block_and_schedule(); } } @@ -116,15 +133,41 @@ class Lx_kit::Work : public Lx::Work ** Lx::Work interface ** ************************/ - void unblock() { _task.unblock(); } + void unblock() + { + _task.unblock(); + } + + void flush(Lx::Task &task) + { + _task.unblock(); + + _waiting_task = &task; + } + + void wakeup_for(void const * const work, Lx::Task &task) + { + Context *ctx = nullptr; + + for (Context *c = _list.first(); c; c = c->next()) { + if (c->work == work) { + ctx = c; + break; + } + } + + if (!ctx) { + Genode::error("BUG: no work queued for wakeup_for call"); + Genode::sleep_forever(); + } + + ctx->waiting_task = &task; + _task.unblock(); + } void schedule(struct work_struct *work) { _schedule(work); } - void schedule_delayed(struct delayed_work *work, - unsigned long /*delay*/) { - _schedule(work); } - void schedule_tasklet(struct tasklet_struct *tasklet) { _schedule(tasklet); } @@ -144,6 +187,17 @@ class Lx_kit::Work : public Lx::Work return false; } + bool work_queued(void const * const work) + { + for (Context *c = _list.first(); c; c = c->next()) { + if (c->work == work) { + return true; + } + } + + return false; + } + char const *task_name() override { return _task.name(); } };