From a3cfa2ac9b7f24ad37ff085743566f12ce95ff71 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 21 Nov 2009 23:45:58 +0200 Subject: [PATCH] Added a device attribute to capabilities - In progress Followed the kernel physical memory reservation convention with devices. Devices that are possessable by userspace are created as boot-time capabilities and placed under the kernel resources devmem_free capability list. Any userspace container that is defined with the possession of the device would delete the device capability making it unavailable to further requests. --- include/l4/generic/cap-types.h | 2 + include/l4/generic/capability.h | 7 +- include/l4/generic/container.h | 1 + src/generic/resource.c | 136 +++++++++++++++++--------------- src/platform/pb926/platform.c | 99 +++++++++++++++++++++-- 5 files changed, 173 insertions(+), 72 deletions(-) diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index 5fb02dc..c28fceb 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -40,6 +40,8 @@ {(c)->type &= ~CAP_RTYPE_MASK; \ (c)->type |= CAP_RTYPE_MASK & rtype;} +#define cap_devmem(c) (c)->uattr + /* * User-defined device-types * (Kept in the user field) diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index f17f543..172f912 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -71,8 +71,11 @@ struct capability { unsigned long end; /* Resource end value */ unsigned long size; /* Resource size */ - /* Used amount on resource _or_ user-defined attributes */ - unsigned long user; + /* Use count of resource */ + unsigned long used; + + /* User-defined attributes on capability (like devtypes) */ + unsigned int uattr; }; struct cap_list { diff --git a/include/l4/generic/container.h b/include/l4/generic/container.h index 02b3edb..09c59ad 100644 --- a/include/l4/generic/container.h +++ b/include/l4/generic/container.h @@ -60,6 +60,7 @@ struct cap_info { unsigned long start; unsigned long end; unsigned long size; + unsigned int uattr; /* User-level attributes (like device types) */ }; diff --git a/src/generic/resource.c b/src/generic/resource.c index 35e7bed..5ef70aa 100644 --- a/src/generic/resource.c +++ b/src/generic/resource.c @@ -267,18 +267,24 @@ int memcap_unmap(struct cap_list *used_list, const unsigned long unmap_end) { struct capability *cap, *n; - int err; + int ret; /* * If a used list was supplied, check that the * range does not intersect with the used list. * This is an optional sanity check. */ - if (used_list) - list_foreach_removable_struct(cap, n, &used_list->caps, list) + if (used_list) { + list_foreach_removable_struct(cap, n, + &used_list->caps, + list) { if (set_intersection(unmap_start, unmap_end, - cap->start, cap->end)) - return -EPERM; + cap->start, cap->end)) { + ret = -EPERM; + goto out_err; + } + } + } list_foreach_removable_struct(cap, n, &cap_list->caps, list) { /* Check for intersection */ @@ -287,12 +293,59 @@ int memcap_unmap(struct cap_list *used_list, if ((err = memcap_unmap_range(cap, cap_list, unmap_start, unmap_end))) { - return err; + goto out_err; } return 0; } } - return -EEXIST; + ret = -EEXIST; + +out_err: + if (ret == -ENOMEM) + printk("%s: FATAL: Insufficient boot memory " + "to split capability\n", __KERNELNAME__); + else if (ret == -EPERM) + printk("%s: FATAL: %s memory capability range " + "overlaps with an already used range. " + "start=0x%lx, end=0x%lx\n", __KERNELNAME__, + cap_type(cap) == CAP_TYPE_MAP_VIRTMEM ? + "Virtual" : "Physical", + __pfn_to_addr(cap->start), + __pfn_to_addr(cap->end)); + else if (ret == -EEXIST) + printk("%s: FATAL: %s memory capability range " + "does not match with any available free range. " + "start=0x%lx, end=0x%lx\n", __KERNELNAME__, + cap_type(cap) == CAP_TYPE_MAP_VIRTMEM ? + "Virtual" : "Physical", + __pfn_to_addr(cap->start), + __pfn_to_addr(cap->end)); + BUG(); +} + +/* + * Finds a device memory capability and deletes it from + * the available device capabilities list + */ +int memcap_request_device(struct cap_list *cap_list, + struct cap_info *devcap) +{ + list_foreach_removable_struct(cap, n, &cap_list->caps, list) { + if (cap->start == devcap->start && + cap->end == devcap->end && + cap->uattr == devcap->uattr) { + /* Unlink only. This is boot memory */ + list_remove(&cap); + return 0; + } + } + printk("%s: FATAL: Device memory requested " + "does not match any available device " + "capabilities start=0x%lx, end=0x%lx " + "uattr=0x%lx\n", __KERNELNAME__, + __pfn_to_addr(devcap->start), + __pfn_to_addr(devcap->end), devcap->uattr); + BUG(); } /* @@ -417,6 +470,8 @@ void init_kernel_resources(struct kernel_resources *kres) memcap_unmap(0, &kres->physmem_free, kernel_area->start, kernel_area->end); + /* Set up platform-specific device capabilities */ + platform_setup_device_caps(kres); /* TODO: * Add all virtual memory areas used by the kernel @@ -746,7 +801,6 @@ void init_resource_allocators(struct boot_resources *bootres, kres->pmd_cache = init_resource_cache(bootres->npmds, PMD_SIZE, kres, 1); - } /* @@ -785,61 +839,19 @@ int process_cap_info(struct cap_info *cap, break; } - switch (cap_type(cap)) { - case CAP_TYPE_MAP_VIRTMEM: - if ((ret = memcap_unmap(&kres->virtmem_used, &kres->virtmem_free, - cap->start, cap->end))) { - if (ret == -ENOMEM) - printk("%s: FATAL: Insufficient boot memory " - "to split capability\n", - __KERNELNAME__); - if (ret == -EPERM) - printk("%s: FATAL: Virtual memory capability range " - "overlaps with an already used range. " - "start=0x%lx, end=0x%lx\n", - __KERNELNAME__, - __pfn_to_addr(cap->start), - __pfn_to_addr(cap->end)); - if (ret == -EEXIST) - printk("%s: FATAL: Virtual memory capability range " - "does not match with any available free range. " - "start=0x%lx, end=0x%lx\n", - __KERNELNAME__, - __pfn_to_addr(cap->start), - __pfn_to_addr(cap->end)); - - BUG(); - } - break; - - case CAP_TYPE_MAP_PHYSMEM: - if ((ret = memcap_unmap(&kres->physmem_used, &kres->physmem_free, - cap->start, cap->end))) { - if (ret == -ENOMEM) - printk("%s: FATAL: Insufficient boot memory " - "to split capability\n", - __KERNELNAME__); - if (ret == -EPERM) - printk("%s: FATAL: Physical memory capability range " - "overlaps with an already used range. " - "start=0x%lx, end=0x%lx\n", - __KERNELNAME__, - __pfn_to_addr(cap->start), - __pfn_to_addr(cap->end)); - if (ret == -EEXIST) - printk("%s: FATAL: Physical memory capability range " - "does not match with any available free range. " - "start=0x%lx, end=0x%lx\n", - __KERNELNAME__, - __pfn_to_addr(cap->start), - __pfn_to_addr(cap->end)); - - BUG(); - } - - break; - + if (cap_type(cap) == CAP_TYPE_MAP_VIRTMEM) { + memcap_unmap(&kres->virtmem_used, + &kres->virtmem_free, + cap->start, cap->end) + } else if (cap_type(cap) == CAP_TYPE_MAP_PHYSMEM) { + if (!cap_devmem(cap)) + memcap_unmap(&kres->physmem_used, + &kres->physmem_free, + cap->start, cap->end) + else /* Delete device from free list */ + memcap_request_device(&kres->devmem_free, cap); } + return ret; } diff --git a/src/platform/pb926/platform.c b/src/platform/pb926/platform.c index 15ef6a2..9741b0b 100644 --- a/src/platform/pb926/platform.c +++ b/src/platform/pb926/platform.c @@ -3,7 +3,8 @@ * * Copyright (C) 2007 Bahadir Balban */ - +#include +#include #include #include #include @@ -19,11 +20,92 @@ #include INC_PLAT(irq.h) #include INC_ARCH(asm.h) +/* + * The devices that are used by the kernel are mapped + * independent of these capabilities, but these provide a + * concise description of what is used by the kernel. + */ +int platform_setup_device_caps(struct kernel_resources *kres) +{ + struct capability *uart[4], *timer[2], *irqctrl[2], *sysctrl; + +#if 0 + /* Setup kernel capability for uart0 as used */ + uart[0] = alloc_bootmem(sizeof(*uart[0]), 0); + uart[0]->start = __pfn(PB926_UART0_BASE); + uart[0]->end = uart[0]->start + 1; + uart[0]->uattr = CAP_DEVTYPE_UART; + link_init(&uart[0]->list); + cap_list_insert(uart[0], &kres->devmem_used); + + /* Setup timer0 capability as used */ + timer[0] = alloc_bootmem(sizeof(*timer[0]), 0); + timer[0]->start = __pfn(PB926_TIMER01_BASE); + timer[0]->end = timer[0]->start + 1; + timer[0]->uattr = CAP_DEVTYPE_TIMER; + link_init(&timer[0]->list); + cap_list_insert(timer[0], &kres->devmem_used); + + /* Setup irq controller 0 and 1 as used */ + irqctrl[0] = alloc_bootmem(sizeof(*irqctrl[0]), 0); + irqctrl[0]->start = __pfn(PB926_VIC_BASE); + irqctrl[0]->end = irqctrl[0]->start + 1; + irqctrl[0]->uattr = CAP_DEVTYPE_IRQCTRL; + link_init(&irqctrl[0]->list); + cap_list_insert(irqctrl[0], &kres->devmem_used); + + irqctrl[1] = alloc_bootmem(sizeof(*irqctrl[1]), 0); + irqctrl[1]->start = __pfn(PB926_SIC_BASE); + irqctrl[1]->end = irqctrl[1]->start + 1; + irqctrl[1]->uattr = CAP_DEVTYPE_IRQCTRL; + link_init(&irqctrl[1]->list); + cap_list_insert(irqctrl[1], &kres->devmem_used); + + /* Set up system controller as used */ + sysctrl = alloc_bootmem(sizeof(*sysctrl), 0); + sysctrl->start = __pfn(PB926_SYSCTRL_BASE); + sysctrl->end = sysctrl->start + 1; + sysctrl->uattr = CAP_DEVTYPE_SYSCTRL; + link_init(&sysctrl->list); + cap_list_insert(sysctrl, &kres->devmem_used); +#endif + + /* Setup capabilities for other uarts as free */ + uart[1] = alloc_bootmem(sizeof(*uart[i]), 0); + uart[1]->start = __pfn(PB926_UART1_BASE); + uart[1]->end = uart[1]->start + 1; + uart[1]->uattr = CAP_DEVTYPE_UART; + link_init(&uart[1]->list); + cap_list_insert(uart[1], &kres->devmem_free); + + uart[2] = alloc_bootmem(sizeof(*uart[2]), 0); + uart[2]->start = __pfn(PB926_UART2_BASE); + uart[2]->end = uart[2]->start + 1; + uart[2]->uattr = CAP_DEVTYPE_UART; + link_init(&uart[2]->list); + cap_list_insert(uart[2], &kres->devmem_free); + + uart[3] = alloc_bootmem(sizeof(*uart[3]), 0); + uart[3]->start = __pfn(PB926_UART3_BASE); + uart[3]->end = uart[3]->start + 1; + uart[3]->uattr = CAP_DEVTYPE_UART; + link_init(&uart[3]->list); + cap_list_insert(uart[3], &kres->devmem_free); + + /* Setup timer1 capability as free */ + timer[1] = alloc_bootmem(sizeof(*timer[1]), 0); + timer[1]->start = __pfn(PB926_TIMER12_BASE); + timer[1]->end = timer[1]->start + 1; + timer[1]->uattr = CAP_DEVTYPE_TIMER; + link_init(&timer[1]->list); + cap_list_insert(timer[1], &kres->devmem_free); +} + /* We will use UART0 for kernel as well as user tasks, so map it to kernel and user space */ void init_platform_console(void) { add_boot_mapping(PB926_UART0_BASE, PLATFORM_CONSOLE0_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + MAP_IO_DEFAULT_FLAGS); /* * Map same UART IO area to userspace so that primitive uart-based @@ -31,7 +113,7 @@ void init_platform_console(void) * removed in the future, when file-based io is implemented. */ add_boot_mapping(PB926_UART0_BASE, USERSPACE_UART_BASE, PAGE_SIZE, - MAP_USR_IO_FLAGS); + MAP_USR_IO_FLAGS); uart_init(); } @@ -44,19 +126,20 @@ void init_platform_console(void) void init_platform_timer(void) { add_boot_mapping(PB926_TIMER01_BASE, PLATFORM_TIMER0_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + MAP_IO_DEFAULT_FLAGS); + + add_boot_mapping(PB926_SYSCTRL_BASE, PB926_SYSCTRL_VBASE, PAGE_SIZE, + MAP_IO_DEFAULT_FLAGS); - add_boot_mapping(PB926_SYSCTRL_BASE, PB926_SYSCTRL_VBASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); timer_init(); } void init_platform_irq_controller() { add_boot_mapping(PB926_VIC_BASE, PLATFORM_IRQCTRL_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + MAP_IO_DEFAULT_FLAGS); add_boot_mapping(PB926_SIC_BASE, PLATFORM_SIRQCTRL_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + MAP_IO_DEFAULT_FLAGS); irq_controllers_init(); }