diff --git a/conts/baremetal/baremetal5/main.c b/conts/baremetal/baremetal5/main.c index e4ebacf..023e732 100644 --- a/conts/baremetal/baremetal5/main.c +++ b/conts/baremetal/baremetal5/main.c @@ -1,105 +1,357 @@ /* - * Main function for this container + * Timer service for userspace */ #include #include -#include +#include +#include #include #include -#include "sp804_timer.h" -/* - * Address where we want to map timer - * Be sure that we using a valid address, depending upon - * how we make use of this driver. - */ -#define TIMER_VIRT_BASE 0x91000000 +#include +#include +#include +#include "sp804_timer.h" +#include + /* Frequency of timer in MHz */ #define TIMER_FREQUENCY 1 -#define __TASKNAME__ "Driver Mapper" +#define TIMERS_TOTAL 3 -void handle_request(void) +static struct capability caparray[32]; +static int total_caps = 0; + +struct capability timer_cap[TIMERS_TOTAL]; + +void cap_print(struct capability *cap) +{ + printf("Capability id:\t\t\t%d\n", cap->capid); + printf("Capability resource id:\t\t%d\n", cap->resid); + printf("Capability owner id:\t\t%d\n",cap->owner); + + switch (cap_type(cap)) { + case CAP_TYPE_TCTRL: + printf("Capability type:\t\t%s\n", "Thread Control"); + break; + case CAP_TYPE_EXREGS: + printf("Capability type:\t\t%s\n", "Exchange Registers"); + break; + case CAP_TYPE_MAP_PHYSMEM: + printf("Capability type:\t\t%s\n", "Map/Physmem"); + break; + case CAP_TYPE_MAP_VIRTMEM: + printf("Capability type:\t\t%s\n", "Map/Virtmem"); + break; + case CAP_TYPE_IPC: + printf("Capability type:\t\t%s\n", "Ipc"); + break; + case CAP_TYPE_UMUTEX: + printf("Capability type:\t\t%s\n", "Mutex"); + break; + case CAP_TYPE_QUANTITY: + printf("Capability type:\t\t%s\n", "Quantitative"); + break; + default: + printf("Capability type:\t\t%s\n", "Unknown"); + break; + } + + switch (cap_rtype(cap)) { + case CAP_RTYPE_THREAD: + printf("Capability resource type:\t%s\n", "Thread"); + break; + case CAP_RTYPE_SPACE: + printf("Capability resource type:\t%s\n", "Space"); + break; + case CAP_RTYPE_CONTAINER: + printf("Capability resource type:\t%s\n", "Container"); + break; + case CAP_RTYPE_THREADPOOL: + printf("Capability resource type:\t%s\n", "Thread Pool"); + break; + case CAP_RTYPE_SPACEPOOL: + printf("Capability resource type:\t%s\n", "Space Pool"); + break; + case CAP_RTYPE_MUTEXPOOL: + printf("Capability resource type:\t%s\n", "Mutex Pool"); + break; + case CAP_RTYPE_MAPPOOL: + printf("Capability resource type:\t%s\n", "Map Pool (PMDS)"); + break; + case CAP_RTYPE_CPUPOOL: + printf("Capability resource type:\t%s\n", "Cpu Pool"); + break; + case CAP_RTYPE_CAPPOOL: + printf("Capability resource type:\t%s\n", "Capability Pool"); + break; + default: + printf("Capability resource type:\t%s\n", "Unknown"); + break; + } + printf("\n"); +} + +void cap_array_print() +{ + printf("Capabilities\n" + "~~~~~~~~~~~~\n"); + + for (int i = 0; i < total_caps; i++) + cap_print(&caparray[i]); + + printf("\n"); +} + +int cap_read_all() +{ + int ncaps; + int err; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, 0, 0, &ncaps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + BUG(); + } + total_caps = ncaps; + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, 0, 0, caparray)) < 0) { + printf("l4_capability_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ_CAPS request.\n"); + BUG(); + } +#if 0 + cap_array_print(&caparray); +#endif + return 0; +} + +/* + * Scans for up to TIMERS_TOTAL timer devices in capabilities. + */ +int timer_probe_devices(void) +{ + int timers = 0; + + /* Scan for timer devices */ + for (int i = 0; i < total_caps; i++) { + /* Match device type */ + if (cap_devtype(&caparray[i]) == CAP_DEVTYPE_TIMER) { + /* Copy to correct device index */ + memcpy(&timer_cap[cap_devnum(&caparray[i]) - 1], + &caparray[i], sizeof(timer_cap[0])); + timers++; + } + } + + if (timers != TIMERS_TOTAL) { + printf("%s: Error, not all timers could be found. " + "timers=%d\n", __CONTAINER_NAME__, timers); + return -ENODEV; + } + return 0; +} + +static struct sp804_timer timer[TIMERS_TOTAL]; + +int timer_setup_devices(void) +{ + for (int i = 0; i < TIMERS_TOTAL; i++) { + /* Get one page from address pool */ + timer[i].base = (unsigned long)l4_new_virtual(1); + printf("timer base %x phy %lx\n", timer[i].base, timer_cap[i].start); + + /* Map timers to a virtual address region */ + if (IS_ERR(l4_map((void *)__pfn_to_addr(timer_cap[i].start), + (void *)timer[i].base, timer_cap[i].size, MAP_USR_IO_FLAGS, + self_tid()))) { + printf("%s: FATAL: Failed to map TIMER device " + "%d to a virtual address\n", + __CONTAINER_NAME__, + cap_devnum(&timer_cap[i])); + BUG(); + } + + /* Initialise timer */ + sp804_init(timer[i].base, SP804_TIMER_RUNMODE_FREERUN, \ + SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \ + SP804_TIMER_IRQDISABLE); + + /* Enable Timer */ + sp804_enable(timer[i].base, 1); + } + return 0; +} + +static struct address_pool device_vaddr_pool; + +/* + * Initialize a virtual address pool + * for mapping physical devices. + */ +void init_vaddr_pool(void) +{ + for (int i = 0; i < total_caps; i++) { + /* Find the virtual memory region for this process */ + if (cap_type(&caparray[i]) == CAP_TYPE_MAP_VIRTMEM && + __pfn_to_addr(caparray[i].start) == + (unsigned long)vma_start) { + + /* + * Do we have any unused virtual space + * where we run, and do we have enough + * pages of it to map all timers? + */ + if (__pfn(page_align_up(__end)) + + TIMERS_TOTAL <= caparray[i].end) { + /* + * Yes. We initialize the device + * virtual memory pool here. + * + * We may allocate virtual memory + * addresses from this pool. + */ + address_pool_init(&device_vaddr_pool, page_align_up(__end), + __pfn_to_addr(caparray[i].end), TIMERS_TOTAL); + return; + } else + goto out_err; + } + } + +out_err: + printf("%s: FATAL: No virtual memory " + "region available to map " + "devices.\n", __CONTAINER_NAME__); + BUG(); +} + +void *l4_new_virtual(int npages) +{ + + return address_new(&device_vaddr_pool, npages, PAGE_SIZE); +} + +int timer_gettime(int devno) +{ + return sp804_read_value(timer[devno].base); +} + +void handle_requests(void) { -# if 0 - /* Generic ipc data */ - u32 mr[MR_UNUSED_TOTAL]; l4id_t senderid; u32 tag; int ret; - if ((ret = l4_receive(L4_ANYTHREAD)) < 0) { - printf("%s: %s: IPC Error: %d. Quitting...\n", __TASKNAME__, - __FUNCTION__, ret); - BUG(); - } - - /* Syslib conventional ipc data which uses first few mrs. */ - tag = l4_get_tag(); - senderid = l4_get_sender(); - - - if (!(sender = find_task(senderid))) { - l4_ipc_return(-ESRCH); - return; - } - - - /* Read mrs not used by syslib */ - for (int i = 0; i < MR_UNUSED_TOTAL; i++) - mr[i] = read_mr(MR_UNUSED_START + i); - - switch(tag) { - case L4_IPC_TAG_GET_TIME: - ret = sp804_read_value(TIMER_VIRT_BASE); - break; - } - - /* Reply */ - if ((ret = l4_ipc_return(ret)) < 0) { - printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret); - BUG(); - } -#endif -} - -int main(void) -{ - int ret = 0; - unsigned value = 0; + printf("%s: Initiating ipc.\n", __CONTAINER__); + if ((ret = l4_receive(L4_ANYTHREAD)) < 0) { + printf("%s: %s: IPC Error: %d. Quitting...\n", __CONTAINER__, + __FUNCTION__, ret); + BUG(); + } + /* Syslib conventional ipc data which uses first few mrs. */ + tag = l4_get_tag(); + senderid = l4_get_sender(); + /* - * Map Timer 2 to Ram allocated to us - * FIXME: do we need to set the frequency for sp810? + * TODO: + * + * Maybe add tags here that handle requests for sharing + * of the requested timer device with the client? + * + * In order to be able to do that, we should have a + * shareable/grantable capability to the device. Also + * the request should (currently) come from a task + * inside the current container */ - ret = l4_map((void *)TIMER2_PHYS_BASE, (void *)TIMER_VIRT_BASE, 1, \ - MAP_USR_IO_FLAGS, self_tid()); - if (ret) { - printf("Failed to map the requested device\n"); - return ret; + switch (tag) { + case L4_IPC_TAG_TIMER_GETTIME: + timer_gettime(1); + break; + + default: + printf("%s: Error received ipc from 0x%x residing " + "in container %x with an unrecognized tag: " + "0x%x\n", __CONTAINER__, senderid, + __cid(senderid), tag); } - /* Initialise timer */ - sp804_init(TIMER_VIRT_BASE, SP804_TIMER_RUNMODE_FREERUN, \ - SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \ - SP804_TIMER_IRQDISABLE); - - sp804_enable(TIMER_VIRT_BASE, 1); - -#if 1 - /* Read Timer value */ - while(1) { - value = sp804_read_value(TIMER_VIRT_BASE); - printf("Read timer with value = %x\n", value); + /* Reply */ + if ((ret = l4_ipc_return(ret)) < 0) { + printf("%s: IPC return error: %d.\n", __FUNCTION__, ret); + BUG(); } -#else - printf("Driver Mapper: Waiting for ipc\n"); - while (1) { - handle_request(); - } -#endif - - return ret; } +/* + * UTCB-size aligned utcb. + * + * BIG WARNING NOTE: This declaration is legal if we are + * running in a disjoint virtual address space, where the + * utcb declaration lies in a unique virtual address in + * the system. + */ +#define DECLARE_UTCB(name) \ + struct utcb name ALIGN(sizeof(struct utcb)) + +DECLARE_UTCB(utcb); + +/* Set up own utcb for ipc */ +int l4_utcb_setup(void *utcb_address) +{ + struct task_ids ids; + struct exregs_data exregs; + int err; + + l4_getid(&ids); + + /* Clear utcb */ + memset(utcb_address, 0, sizeof(struct utcb)); + + /* Setup exregs for utcb request */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_utcb(&exregs, (unsigned long)utcb_address); + + if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) + return err; + + return 0; +} + +void main(void) +{ + int err; + + /* Read all capabilities */ + cap_read_all(); + + /* Scan for timer devices in capabilities */ + timer_probe_devices(); + + /* Initialize virtual address pool for timers */ + init_vaddr_pool(); + + /* Map and initialize timer devices */ + timer_setup_devices(); + + /* Setup own utcb */ + if ((err = l4_utcb_setup(&utcb)) < 0) { + printf("FATAL: Could not set up own utcb. " + "err=%d\n", err); + BUG(); + } + + /* Listen for timer requests */ + while (1) + handle_requests(); +} + + diff --git a/conts/libdev/SConscript b/conts/libdev/SConscript index 2ff6bb3..96e5a46 100644 --- a/conts/libdev/SConscript +++ b/conts/libdev/SConscript @@ -21,12 +21,16 @@ variant = type # Path for uart files LIBDEV_UART_PATH = join(PROJROOT, 'conts/libdev/uart') +# Path for timer files +LIBDEV_TIEMR_PATH = join(PROJROOT, 'conts/libdev/timer/sp804') + e = env.Clone() -e.Append(CPPPATH = [LIBDEV_UART_PATH + '/include'], +e.Append(CPPPATH = [LIBDEV_UART_PATH + '/include', LIBDEV_TIEMR_PATH + '/include'], CCFLAGS = ['-nostdinc', '-DVARIANT_' + variant.upper(), '-DPLATFORM_' + platform.upper()]) -source = Glob('uart/src' + '/*.c') +source = Glob('uart/src' + '/*.c') + \ + Glob('timer/sp804/src' + '/*.c') objects = e.StaticObject(source) library = e.StaticLibrary('libdev-' + variant, objects) diff --git a/conts/libdev/timer/sp804/include/sp804_timer.h b/conts/libdev/timer/sp804/include/sp804_timer.h index 70a5b1a..445074b 100644 --- a/conts/libdev/timer/sp804/include/sp804_timer.h +++ b/conts/libdev/timer/sp804/include/sp804_timer.h @@ -56,6 +56,10 @@ #define SP804_TIMERMIS 0x14 #define SP804_TIMERBGLOAD 0x18 +struct sp804_timer { + unsigned int base; +}; + void sp804_init(unsigned int timer_base, int runmode, int wrapmode, \ int width, int irq_enable); void sp804_irq_handler(unsigned int timer_base); diff --git a/conts/libl4/include/l4lib/ipcdefs.h b/conts/libl4/include/l4lib/ipcdefs.h index 6a9be08..bd94f72 100644 --- a/conts/libl4/include/l4lib/ipcdefs.h +++ b/conts/libl4/include/l4lib/ipcdefs.h @@ -72,4 +72,8 @@ extern l4id_t pagerid; #define L4_IPC_TAG_UART_SENDBUF 53 /* Buffered send */ #define L4_IPC_TAG_UART_RECVBUF 54 /* Buffered recv */ +/* For ipc to timer service (TODO: Shared mapping buffers???) */ +#define L4_IPC_TAG_TIMER_GETTIME 55 + + #endif /* __IPCDEFS_H__ */ diff --git a/include/l4/platform/pb926/platform.h b/include/l4/platform/pb926/platform.h index 9cf2ed1..a6db8ee 100644 --- a/include/l4/platform/pb926/platform.h +++ b/include/l4/platform/pb926/platform.h @@ -18,6 +18,8 @@ /* SP804 timer has TIMER1 at TIMER0 + 0x20 address */ #define PLATFORM_TIMER0_BASE PB926_TIMER01_VBASE +#define PLATFORM_TIMER_REL_OFFSET 0x20 + #define PLATFORM_SP810_BASE PB926_SYSCTRL_VBASE #define PLATFORM_IRQCTRL_BASE PB926_VIC_VBASE #define PLATFORM_SIRQCTRL_BASE PB926_SIC_VBASE diff --git a/src/platform/pb926/platform.c b/src/platform/pb926/platform.c index 48e69dc..d6422d6 100644 --- a/src/platform/pb926/platform.c +++ b/src/platform/pb926/platform.c @@ -26,7 +26,7 @@ */ int platform_setup_device_caps(struct kernel_resources *kres) { - struct capability *uart[4], *timer[2]; + struct capability *uart[4], *timer[4]; /* Setup capabilities for userspace uarts and timers */ uart[1] = alloc_bootmem(sizeof(*uart[1]), 0); @@ -58,7 +58,8 @@ int platform_setup_device_caps(struct kernel_resources *kres) /* Setup timer1 capability as free */ timer[1] = alloc_bootmem(sizeof(*timer[1]), 0); - timer[1]->start = __pfn(PB926_TIMER23_BASE); + timer[1]->start = + __pfn(PB926_TIMER01_BASE + PLATFORM_TIMER_REL_OFFSET); timer[1]->end = timer[1]->start + 1; timer[1]->size = timer[1]->end - timer[1]->start; cap_set_devtype(timer[1], CAP_DEVTYPE_TIMER); @@ -66,6 +67,27 @@ int platform_setup_device_caps(struct kernel_resources *kres) link_init(&timer[1]->list); cap_list_insert(timer[1], &kres->devmem_free); + /* Setup timer2 capability as free */ + timer[2] = alloc_bootmem(sizeof(*timer[2]), 0); + timer[2]->start = __pfn(PB926_TIMER23_BASE); + timer[2]->end = timer[2]->start + 1; + timer[2]->size = timer[2]->end - timer[2]->start; + cap_set_devtype(timer[2], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[2], 2); + link_init(&timer[2]->list); + cap_list_insert(timer[2], &kres->devmem_free); + + /* Setup timer3 capability as free */ + timer[3] = alloc_bootmem(sizeof(*timer[3]), 0); + timer[3]->start = + __pfn(PB926_TIMER23_BASE + PLATFORM_TIMER_REL_OFFSET); + timer[3]->end = timer[3]->start + 1; + timer[3]->size = timer[3]->end - timer[3]->start; + cap_set_devtype(timer[3], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[3], 3); + link_init(&timer[3]->list); + cap_list_insert(timer[3], &kres->devmem_free); + return 0; }