usb_hid: use heap instead of dma/mem allocator

The usb_hid driver does not need to distinguish between
normal memory and DMA capable memory, since all requests are routed via the
USB raw session to the usb host driver. The default Malloc implementation
implements this distinction, however exposes restrictions on the size of
allocations. As seen now by several USB HID devices, the size of device
driver allocations depend on read out hardware features and can be
larger than we support with our specialized default Malloc implementation.

Since we don't need this functionality, switching to an well
tested allocator (Heap) which can cope with varying sizes of allocation,
we can mitigate the size restriction.

Fixes #3953
This commit is contained in:
Alexander Boettcher 2020-11-20 11:19:35 +01:00 committed by Norman Feske
parent 2c639169fd
commit b097e598f1
3 changed files with 71 additions and 13 deletions

View File

@ -13,7 +13,6 @@
#include <lx_emul/impl/kernel.h>
#include <lx_emul/impl/delay.h>
#include <lx_emul/impl/slab.h>
#include <lx_emul/impl/work.h>
#include <lx_emul/impl/spinlock.h>
#include <lx_emul/impl/mutex.h>
@ -139,7 +138,13 @@ int mutex_lock_interruptible(struct mutex *m)
int driver_register(struct device_driver *drv)
{
if (drv) new (Lx::Malloc::mem()) Lx_driver(*drv);
if (!drv)
return 1;
Lx_driver * driver = (Lx_driver *)kzalloc(sizeof(Lx_driver), GFP_KERNEL);
Genode::construct_at<Lx_driver>(driver, *drv);
return 0;
}
@ -249,20 +254,14 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type,
void *vzalloc(unsigned long size)
{
size_t *addr;
try { addr = (size_t *)Lx::Malloc::mem().alloc_large(size); }
catch (...) { return 0; }
memset(addr, 0, size);
return addr;
return kzalloc(size, 0);
}
void vfree(void *addr)
{
if (!addr) return;
Lx::Malloc::mem().free_large(addr);
kfree(addr);
}
@ -551,3 +550,64 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
return 0;
}
static Genode::Allocator &heap()
{
static Genode::Heap heap(Lx_kit::env().env().ram(), Lx_kit::env().env().rm());
return heap;
}
extern "C"
void *kmalloc(size_t size, gfp_t flags)
{
try {
void * const addr = heap().alloc(size);
if (!addr)
return 0;
if ((Genode::addr_t)addr & 0x3)
Genode::error("unaligned kmalloc ", (Genode::addr_t)addr);
if (flags & __GFP_ZERO)
memset(addr, 0, size);
return addr;
} catch (...) {
return NULL;
}
}
extern "C"
void kfree(const void *p)
{
if (!p) return;
heap().free((void *)p, 0);
}
extern "C"
void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
extern "C"
void *kcalloc(size_t n, size_t size, gfp_t flags)
{
if (size != 0 && n > (~0UL / size))
return 0;
return kzalloc(n * size, flags);
}
extern "C"
void *kmemdup(const void *src, size_t size, gfp_t flags)
{
void *addr = kmalloc(size, flags);
if (addr)
memcpy(addr, src, size);
return addr;
}

View File

@ -14,7 +14,6 @@
#include <base/component.h>
#include <lx_kit/env.h>
#include <lx_kit/malloc.h>
#include <lx_kit/scheduler.h>
#include <lx_kit/timer.h>
@ -287,7 +286,6 @@ Driver::Driver(Genode::Env &env) : env(env)
LX_MUTEX_INIT(wacom_udev_list_lock);
Lx::scheduler(&env);
Lx::malloc_init(env, heap);
Lx::timer(&env, &ep, &heap, &jiffies);
main_task.construct(env.ep(), main_task_entry, reinterpret_cast<void*>(this),

View File

@ -1,7 +1,7 @@
TARGET := usb_hid_drv
SRC_C := dummies.c
SRC_CC := main.cc lx_emul.cc evdev.cc
SRC_CC += printf.cc timer.cc scheduler.cc malloc.cc env.cc work.cc
SRC_CC += printf.cc timer.cc scheduler.cc env.cc work.cc
LIBS := base usb_hid_include lx_kit_setjmp