* Re: Allocating mock memory resources
2017-04-16 6:31 Allocating mock memory resources Pavel Roskin
@ 2017-04-21 19:02 ` Pavel Roskin
0 siblings, 0 replies; 2+ messages in thread
From: Pavel Roskin @ 2017-04-21 19:02 UTC (permalink / raw)
To: linux-mm
Hello
On Sat, Apr 15, 2017 at 11:31 PM, Pavel Roskin <plroskin@gmail.com> wrote:
> I'm working on a device driver for hardware that is being developed.
> I'm coding against the specification and hoping for the best. It would
> be very handy to have a mock implementation of the hardware so I could
> test the driver against it. In the end, it would be an integration
> test for the driver, which could be useful even after the hardware
> arrives. For example, I could emulate hardware failures and see how
> the driver reacts. Moreover, a driver test framework would be useful
> for others.
>
> One issue I'm facing is creating resources for the device. Luckily,
> the driver only needs memory resources. It should be simple to
> allocate such resources in system RAM, but I could not find a good way
> to do it. Either the resource allocation fails, or the kernel panics
> right away, or it panics when I run "cat /proc/iomem"
In case anybody cares, here's my working solution.
The RAM resource is needed because request_region() cannot traverse
busy RAM region, but request_resource() doesn't check if any resources
are busy. I don't like iterating over resources in a driver, but I
don't know a better approach. I assume that all system RAM resources
are direct children of iomem_resource.
SetPageReserved() is needed to allow ioremap() on the region (by the
way, CamelCase in the kernel code looks so weird).
I'm surprised there is no universal phys_to_page() macro, so I'm using
virtual addresses to iterate over pages.
The only limitation on the driver under test is that it should not be
using request_region() on iomem_resource, as the RAM resource is busy
and cannot be traversed.
static struct resource *fff_get_ram_resource(struct resource *res)
{
resource_size_t start = res->start;
resource_size_t end = res->end;
struct resource *p;
for (p = iomem_resource.child; p && p->start <= end; p = p->sibling) {
if (p->end >= start)
return p;
}
return NULL;
}
static int __init fff_emu_alloc_resources(void)
{
struct page *pg;
char *pg_base, *p;
struct resource *ram_res;
int ret;
pg = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(EMU_MEM_SIZE));
if (!pg) {
pr_err("Cannot allocate memory for emulator resource\n");
return -ENOMEM;
}
pg_base = page_to_virt(pg);
emu_mem.start = page_to_phys(pg);
emu_mem.end = emu_mem.start + EMU_MEM_SIZE - 1;
ram_res = fff_get_ram_resource(&emu_mem);
if (!ram_res) {
pr_err("no RAM resource found for %pR\n", &emu_mem);
ret = -ENXIO;
goto out_mem;
}
ret = request_resource(ram_res, &emu_mem);
if (ret) {
pr_err("request_resource failed on %pR under %pR: error %d\n",
&emu_mem, ram_res, ret);
goto out_mem;
}
for (p = pg_base; p < pg_base + EMU_MEM_SIZE; p += PAGE_SIZE)
SetPageReserved(virt_to_page(p));
return 0;
out_mem:
free_pages((unsigned long)pg_base, get_order(EMU_MEM_SIZE));
return ret;
}
static void fff_emu_free_resources(void)
{
char *pg_base, *p;
pg_base = __va(emu_mem.start);
release_resource(&emu_mem);
for (p = pg_base; p < pg_base + EMU_MEM_SIZE; p += PAGE_SIZE)
ClearPageReserved(virt_to_page(p));
free_pages((unsigned long)pg_base, get_order(EMU_MEM_SIZE));
}
--
Regards,
Pavel Roskin
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 2+ messages in thread