From a10a77a0a02a3fc167fa86d0555883ec0d086d18 Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Tue, 24 Nov 2009 23:00:42 +0530 Subject: [PATCH] Added UART service as baremetal4 container --- config/cml/container_ruleset.template | 2 + conts/baremetal/baremetal4/SConstruct | 66 ++++ conts/baremetal/baremetal4/container.c | 21 ++ .../baremetal/baremetal4/include/capability.h | 12 + .../baremetal/baremetal4/include/container.h | 13 + conts/baremetal/baremetal4/include/linker.h | 7 + conts/baremetal/baremetal4/main.c | 349 ++++++++++++++++++ conts/baremetal/baremetal4/src/test.c | 0 scripts/baremetal/files/linker.lds.in | 1 + 9 files changed, 471 insertions(+) create mode 100644 conts/baremetal/baremetal4/SConstruct create mode 100644 conts/baremetal/baremetal4/container.c create mode 100644 conts/baremetal/baremetal4/include/capability.h create mode 100644 conts/baremetal/baremetal4/include/container.h create mode 100644 conts/baremetal/baremetal4/include/linker.h create mode 100644 conts/baremetal/baremetal4/main.c create mode 100644 conts/baremetal/baremetal4/src/test.c diff --git a/config/cml/container_ruleset.template b/config/cml/container_ruleset.template index 5bb7216..4ab0db3 100644 --- a/config/cml/container_ruleset.template +++ b/config/cml/container_ruleset.template @@ -157,12 +157,14 @@ CONT%(cn)d_BAREMETAL_PROJ0 'Empty Project' CONT%(cn)d_BAREMETAL_PROJ1 'Hello World' CONT%(cn)d_BAREMETAL_PROJ2 'Thread Library Demo' CONT%(cn)d_BAREMETAL_PROJ3 'Test Project' +CONT%(cn)d_BAREMETAL_PROJ4 'UART Service' choices cont%(cn)d_baremetal_params CONT%(cn)d_BAREMETAL_PROJ0 CONT%(cn)d_BAREMETAL_PROJ1 CONT%(cn)d_BAREMETAL_PROJ2 CONT%(cn)d_BAREMETAL_PROJ3 + CONT%(cn)d_BAREMETAL_PROJ4 default CONT%(cn)d_BAREMETAL_PROJ0 menu cont%(cn)d_default_pager_params diff --git a/conts/baremetal/baremetal4/SConstruct b/conts/baremetal/baremetal4/SConstruct new file mode 100644 index 0000000..1b32b63 --- /dev/null +++ b/conts/baremetal/baremetal4/SConstruct @@ -0,0 +1,66 @@ +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- Virtualization microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd +# +import os, shelve, sys +from os.path import * + +PROJRELROOT = '../..' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from config.configuration import * + +config = configuration_retrieve() +platform = config.platform +arch = config.arch +gcc_cpu_flag = config.gcc_cpu_flag + +LIBL4_RELDIR = 'conts/libl4' +KERNEL_INCLUDE = join(PROJROOT, 'include') +LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) +LIBL4_INCLUDE = join(LIBL4_DIR, 'include') +LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR) + +# Locally important paths are here +LIBC_RELDIR = 'conts/libc' +LIBC_DIR = join(PROJROOT, LIBC_RELDIR) +LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR) +LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ + join(LIBC_DIR, 'include/arch' + '/' + arch)] + +LIBDEV_RELDIR = 'conts/libdev' +LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR) +LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace') +LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')] +LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper() + +# FIXME: Add these to autogenerated SConstruct !!! +LIBMEM_RELDIR = 'conts/libmem' +LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) +LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR) +LIBMEM_INCLUDE = LIBMEM_DIR + +env = Environment(CC = config.user_toolchain + 'gcc', + # We don't use -nostdinc because sometimes we need standard headers, + # such as stdarg.h e.g. for variable args, as in printk(). + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \ + '-Werror', ('-mcpu=' + gcc_cpu_flag), LIBDEV_CCFLAGS], + LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"], + ASFLAGS = ['-D__ASSEMBLY__'], \ + PROGSUFFIX = '.elf', # The suffix to use for final executable\ + ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\ + LIBS = ['gcc', 'libl4', 'libmalloc', 'c-userspace', 'libdev-userspace', 'gcc', 'c-userspace'], # libgcc.a - This is required for division routines. + CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBDEV_INCLUDE, LIBC_INCLUDE, LIBMEM_INCLUDE], + LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH, LIBMEM_LIBPATH], + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') + +src = Glob('*.[cS]') +src += Glob('src/*.[cS]') + +objs = env.Object(src) +prog = env.Program('main.elf', objs) +Depends(prog, 'include/linker.lds') diff --git a/conts/baremetal/baremetal4/container.c b/conts/baremetal/baremetal4/container.c new file mode 100644 index 0000000..f570c3d --- /dev/null +++ b/conts/baremetal/baremetal4/container.c @@ -0,0 +1,21 @@ +/* + * Container entry point for pager + * + * Copyright (C) 2007-2009 B Labs Ltd. + */ + +#include +#include + + +extern void main(void); + +void __container_init(void) +{ + /* Generic L4 initialisation */ + __l4_init(); + + /* Entry to main */ + main(); +} + diff --git a/conts/baremetal/baremetal4/include/capability.h b/conts/baremetal/baremetal4/include/capability.h new file mode 100644 index 0000000..5cfce89 --- /dev/null +++ b/conts/baremetal/baremetal4/include/capability.h @@ -0,0 +1,12 @@ +#ifndef __UART_SERVICE_CAPABILITY_H__ +#define __UART_SERVICE_CAPABILITY_H__ + +#include +#include +#include + +void cap_print(struct capability *cap); +void cap_list_print(struct cap_list *cap_list); +int cap_read_all(); + +#endif /* header */ diff --git a/conts/baremetal/baremetal4/include/container.h b/conts/baremetal/baremetal4/include/container.h new file mode 100644 index 0000000..e6eece5 --- /dev/null +++ b/conts/baremetal/baremetal4/include/container.h @@ -0,0 +1,13 @@ +/* + * Autogenerated definitions for this container. + */ +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + + +#define __CONTAINER_NAME__ "uart_service" +#define __CONTAINER_ID__ 0 +#define __CONTAINER__ "cont0" + + +#endif /* __CONTAINER_H__ */ diff --git a/conts/baremetal/baremetal4/include/linker.h b/conts/baremetal/baremetal4/include/linker.h new file mode 100644 index 0000000..e39da2f --- /dev/null +++ b/conts/baremetal/baremetal4/include/linker.h @@ -0,0 +1,7 @@ +#ifndef __LINKER_H__ +#define __LINKER_H__ + +extern char vma_start[]; +extern char __end[]; + +#endif /* __LINKER_H__ */ diff --git a/conts/baremetal/baremetal4/main.c b/conts/baremetal/baremetal4/main.c new file mode 100644 index 0000000..859d930 --- /dev/null +++ b/conts/baremetal/baremetal4/main.c @@ -0,0 +1,349 @@ +/* + * UART service for userspace + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include /* FIXME: Its best if this is */ +#include + +#define UARTS_TOTAL 3 + +static struct capability caparray[32]; +static int total_caps = 0; + +struct capability uart_cap[UARTS_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(); + } + + cap_array_print(&caparray); + + return 0; +} + +/* + * Scans for up to UARTS_TOTAL uart devices in capabilities. + */ +int uart_probe_devices(void) +{ + int uarts = 0; + + /* Scan for uart devices */ + for (int i = 0; i < total_caps; i++) { + /* Match device type */ + if (cap_devtype(&caparray[i]) == CAP_DEVTYPE_UART) { + /* Copy to correct device index */ + memcpy(&uart_cap[cap_devnum(&caparray[i]) - 1], + &caparray[i], sizeof(uart_cap[0])); + uarts++; + } + } + + if (uarts != UARTS_TOTAL) { + printf("%s: Error, not all uarts could be found. " + "uarts=%d\n", __CONTAINER_NAME__, uarts); + BUG(); + } + return 0; +} + +static struct pl011_uart uart[UARTS_TOTAL]; + +int uart_setup_devices(void) +{ + BUG(); /* Make sure to have set the device capability size as well */ + + for (int i = 0; i < UARTS_TOTAL; i++) { + /* Map uart to a virtual address region */ + if (IS_ERR(uart[i].base = + l4_map((void *)__pfn_to_addr(uart_cap[i].start), + l4_new_virtual(uart_cap[i].size), + uart_cap[i].size, + MAP_USR_IO_FLAGS, self_tid()))) { + printf("%s: FATAL: Failed to map UART device " + "%d to a virtual address\n", + __CONTAINER_NAME__, + cap_devnum(&uart_cap[i])); + BUG(); + } + + /* Initialize uart */ + pl011_initialise(&uart[i]); + } +} + +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 uarts? + */ + if (__pfn(page_align_up(__end)) + + UARTS_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, + (unsigned long)__end, + __pfn_to_addr(caparray[i].end), + UARTS_TOTAL); + return; + } else + goto out_err; + } + } + +out_err: + printf("%s: FATAL: No virtual memory " + "region available to map " + "devices.\n", __CONTAINER_NAME__); + BUG(); +} + +void uart_generic_tx(char c, int devno) +{ + +} + +char uart_generic_rx(int devno) +{ + return 0; +} + + +void handle_requests(void) +{ + l4id_t senderid; + u32 tag; + int ret; + + 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(); + + /* + * TODO: + * + * Maybe add tags here that handle requests for sharing + * of the requested uart 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 + */ + switch (tag) { + case L4_IPC_TAG_UART_SENDCHAR: + uart_generic_tx(0, 0); /*FIXME: Fill in */ + break; + case L4_IPC_TAG_UART_RECVCHAR: + uart_generic_rx(0); /* FIXME: Fill in */ + 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); + } + + /* Reply */ + if ((ret = l4_ipc_return(ret)) < 0) { + printf("%s: IPC return error: %d.\n", __FUNCTION__, ret); + BUG(); + } +} + +/* + * 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 uart devices in capabilities */ + uart_probe_devices(); + + /* Initialize virtual address pool for uarts */ + init_vaddr_pool(); + + /* Map and initialize uart devices */ + uart_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 uart requests */ + while (1) + handle_requests(); +} + diff --git a/conts/baremetal/baremetal4/src/test.c b/conts/baremetal/baremetal4/src/test.c new file mode 100644 index 0000000..e69de29 diff --git a/scripts/baremetal/files/linker.lds.in b/scripts/baremetal/files/linker.lds.in index d9740ab..ce91000 100644 --- a/scripts/baremetal/files/linker.lds.in +++ b/scripts/baremetal/files/linker.lds.in @@ -26,4 +26,5 @@ SECTIONS . = ALIGN(8); __stack = .; } + __end = .; }