diff --git a/SConstruct b/SConstruct index 8a021b3..e401731 100644 --- a/SConstruct +++ b/SConstruct @@ -13,33 +13,100 @@ config = configuration_retrieve() arch = config.arch subarch = config.subarch platform = config.platform -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag all_syms = config.all +builddir='build/codezero/' -env = Environment(CC = config.kernel_toolchain + 'gcc', +# Generate kernel linker script at runtime using template file. +def generate_kernel_linker_script(target, source, env): + linker_in = source[0] + linker_out = target[0] + + cmd = config.toolchain + "cpp -D__CPP__ " + \ + "-I%s -imacros l4/macros.h -imacros %s -imacros %s -C -P %s -o %s" % \ + ('include', 'l4/platform/'+ platform + '/offsets.h', \ + 'l4/glue/' + arch + '/memlayout.h', linker_in, linker_out) + os.system(cmd) + +create_kernel_linker = Command(join(builddir, 'include/l4/arch/arm/linker.lds'), \ + join(PROJROOT, 'include/l4/arch/arm/linker.lds.in'), \ + generate_kernel_linker_script) + +''' +# Generate linker file with physical addresses, +# to be used for debug purpose only +def generate_kernel_phys_linker_script(target, source, env): + phys_linker_in = source[0] + phys_linker_out = target[0] + + cmd = config.toolchain + "cpp -D__CPP__ " + \ + "-I%s -imacros l4/macros.h -imacros %s -imacros %s -C -P %s -o %s" % \ + ('include', 'l4/platform/'+ platform + '/offsets.h', \ + 'l4/glue/' + arch + '/memlayout.h', phys_linker_in, phys_linker_out) + print cmd + os.system(cmd) + +create_kernel_phys_linker = Command(join(builddir, 'include/physlink.lds'), \ + join(PROJROOT, 'include/physlink.lds.in'), \ + generate_kernel_phys_linker_script) +''' +env = Environment(CC = config.toolchain + 'gcc', + AR = config.toolchain + 'ar', + RANLIB = config.toolchain + 'ranlib', # 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)], - LINKFLAGS = ['-nostdlib', '-T' + "include/l4/arch/arm/linker.lds"], + '-Werror', '-march=' + gcc_arch_flag], + LINKFLAGS = ['-nostdlib', '-T' + join(builddir, 'include/l4/arch/arm/linker.lds')], ASFLAGS = ['-D__ASSEMBLY__'], PROGSUFFIX = '.elf', # The suffix to use for final executable ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path LIBS = 'gcc', # libgcc.a - This is required for division routines. - CPPPATH = "#include", + CPPPATH = ["#include"], CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -D__KERNEL__') objects = [] -objects += SConscript('src/drivers/SConscript', exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/generic/SConscript',exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/arch/' + arch + '/SConscript', exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/platform/' + platform + '/SConscript', exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/arch/' + arch + '/' + subarch + '/SConscript', exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/glue/' + arch + '/SConscript', exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/lib/SConscript', exports = {'symbols' : all_syms, 'env' : env}) -objects += SConscript('src/api/SConscript', exports = {'symbols' : all_syms, 'env' : env}) + +objects += SConscript('src/generic/SConscript', + exports = {'symbols' : all_syms, 'env' : env}, + duplicate=0, build_dir=builddir + 'generic') + +objects += SConscript('src/glue/' + arch + '/SConscript', + exports = {'symbols' : all_syms, 'env' : env}, + duplicate=0, build_dir=builddir + 'glue' + '/' + arch) + +objects += SConscript('src/arch/' + arch + '/SConscript', + exports = {'symbols' : all_syms, 'env' : env}, + duplicate=0, build_dir=builddir + 'arch/' + arch) + +objects += SConscript('src/arch/' + arch + '/' + subarch + '/SConscript', + exports = {'symbols' : all_syms, 'env' : env}, + duplicate=0, build_dir=builddir + 'arch/' + arch + '/' + subarch) + +objects += SConscript('src/lib/SConscript', + exports = {'symbols' : all_syms, 'env' : env}, + duplicate=0, build_dir=builddir + 'lib') + +objects += SConscript('src/api/SConscript', + exports = {'symbols' : all_syms, 'env' : env}, + duplicate=0, build_dir=builddir + 'api') + +objects += SConscript('src/drivers/SConscript', + exports = {'symbols' : all_syms, 'env' : env, 'platform' : platform,'bdir' : 'driver/'}, + duplicate=0, build_dir=builddir) + +objects += SConscript('src/platform/' + platform + '/SConscript', + exports = {'symbols' : all_syms, 'env' : env,'platform' : platform}, duplicate=0, + build_dir=builddir + 'platform' + '/' +platform) kernel_elf = env.Program(BUILDDIR + '/kernel.elf', objects) +#env_phys = env.Clone() +#env_phys.Replace(LINKFLAGS = ['-nostdlib', '-T' + join(builddir, 'include/physlink.lds')]) +#env_phys.Program(BUILDDIR + '/kernel_phys.elf', objects) + Alias('kernel', kernel_elf) +Depends(kernel_elf, objects) +Depends(objects, create_kernel_linker) +#Depends(objects, create_kernel_phys_linker) Depends(objects, 'include/l4/config.h') diff --git a/SConstruct.loader b/SConstruct.loader index 4182b01..15fcf47 100644 --- a/SConstruct.loader +++ b/SConstruct.loader @@ -13,7 +13,7 @@ from config.projpaths import * config = configuration_retrieve() arch = config.arch platform = config.platform -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag variant = 'baremetal' @@ -24,18 +24,19 @@ LIBC_INCPATH = ['#' + join(LIBC_PATH, 'include'), \ '#' + join(LIBC_PATH, 'include/arch/' + arch)] LIBDEV_PATH = 'conts/libdev' -LIBDEV_LIBPATH = join(LIBDEV_PATH, 'uart') -LIBDEV_INCPATH = ['#' + join(LIBDEV_PATH, 'uart/include'),] +LIBDEV_INCPATH = ['#' + join(LIBDEV_PATH, 'include'),] LIBELF_PATH = 'loader/libs/elf' LIBELF_LIBPATH = LIBELF_PATH LIBELF_INCPATH = '#' + join(LIBELF_PATH, 'include') -env = Environment(CC = config.kernel_toolchain + 'gcc', +env = Environment(CC = config.toolchain + 'gcc', + AR = config.toolchain + 'ar', + RANLIB = config.toolchain + 'ranlib', # 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)], + '-Werror', '-march=' + gcc_arch_flag], LINKFLAGS = ['-nostdlib', '-T' + join(BUILDDIR, 'loader/linker.lds'), "-u_start"], ASFLAGS = ['-D__ASSEMBLY__'], PROGSUFFIX = '.elf', @@ -43,7 +44,8 @@ env = Environment(CC = config.kernel_toolchain + 'gcc', LIBS = ['gcc', 'elf', 'libdev-baremetal', 'c-baremetal', 'gcc'], LIBPATH = [join(join('build', LIBDEV_PATH), 'sys-' + variant), \ join('build', LIBELF_PATH), join('build', LIBC_PATH)], - CPPPATH = ['#include', LIBDEV_INCPATH, LIBC_INCPATH, LIBELF_INCPATH]) + CPPPATH = ['#include', LIBDEV_INCPATH, LIBC_INCPATH, LIBELF_INCPATH], + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -D__KERNEL__') libdev = SConscript('conts/libdev/SConscript', \ exports = { 'env' : env, 'arch' : arch, 'platform' : platform, 'type' : variant}, \ diff --git a/SConstruct.userlibs b/SConstruct.userlibs index 310a2d2..762ad15 100644 --- a/SConstruct.userlibs +++ b/SConstruct.userlibs @@ -11,16 +11,18 @@ from os.path import * config = configuration_retrieve() arch = config.arch -subarcn = config.subarch +subarch = config.subarch platform = config.platform -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag all_syms = config.all -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.toolchain + 'gcc', + AR = config.toolchain + 'ar', + RANLIB = config.toolchain + 'ranlib', # 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)], + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', + '-Werror', '-march=' + gcc_arch_flag], LINKFLAGS = ['-nostdlib'], ASFLAGS = ['-D__ASSEMBLY__'], ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path @@ -29,7 +31,7 @@ env = Environment(CC = config.user_toolchain + 'gcc', CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') libl4 = SConscript('conts/libl4/SConscript', \ - exports = { 'arch' : arch }, duplicate = 0, \ + exports = { 'env' : env, 'arch' : arch, 'subarch' : subarch }, duplicate = 0, \ variant_dir = join(BUILDDIR, os.path.relpath('conts/libl4', PROJROOT))) e = env.Clone() @@ -41,13 +43,12 @@ libdev = SConscript('conts/libdev/SConscript', \ join(join(BUILDDIR, os.path.relpath('conts/libdev', PROJROOT)), 'sys-' + type)) libc = SConscript('conts/libc/SConscript', \ - exports = { 'env' : env, 'arch' : arch, 'platform' : platform, 'type' : 'userspace' }, \ + exports = { 'env' : env, 'arch' : arch, 'type' : 'userspace' }, \ duplicate = 0, variant_dir = \ join(BUILDDIR, os.path.relpath('conts/libc', PROJROOT))) libmm, libmc, libmalloc = SConscript('conts/libmem/SConscript', \ - exports = { 'env' : env, 'arch' : arch, 'platform' : platform }, \ - duplicate = 0, variant_dir = \ + exports = { 'env' : env, }, duplicate = 0, variant_dir = \ join(BUILDDIR, os.path.relpath('conts/libmem', PROJROOT))) Alias('libl4', libl4) diff --git a/build.py b/build.py index 83f854b..54c3b3a 100755 --- a/build.py +++ b/build.py @@ -12,6 +12,7 @@ from os.path import join from config.projpaths import * from config.configuration import * from config.config_check import * +from scripts.qemu import qemu_cmdline from scripts.conts import containers from configure import * @@ -31,7 +32,10 @@ def main(): # Build userspace libraries # print "\nBuilding userspace libraries..." - os.system('scons -f SConstruct.userlibs') + ret = os.system('scons -f SConstruct.userlibs') + if(ret): + print "Build failed \n" + sys.exit(1) # # Build containers @@ -49,17 +53,31 @@ def main(): # print "\nBuilding the kernel..." os.chdir(PROJROOT) - os.system("scons") + ret = os.system("scons") + if(ret): + print "Build failed \n" + sys.exit(1) # # Build libs and loader # os.chdir(PROJROOT) print "\nBuilding the loader and packing..." - os.system("scons -f SConstruct.loader") + ret = os.system("scons -f SConstruct.loader") + if(ret): + print "Build failed \n" + sys.exit(1) + + # + # Build qemu-insight-script + # + print "\nBuilding qemu-insight-script.." + qemu_cmdline.build_qemu_cmdline_script() + #build_qemu_cmdline_script() print "\nBuild complete." + print "\nRun qemu with following command: ./tools/run-qemu-insight\n" if __name__ == "__main__": main() diff --git a/config/caps.py b/config/caps.py index 25a0a1e..d54532f 100644 --- a/config/caps.py +++ b/config/caps.py @@ -36,7 +36,7 @@ cap_strings = { 'ipc' : \ \t\t\t[${idx}] = { \t\t\t\t.target = ${cid}, \t\t\t\t.type = CAP_TYPE_IRQCTRL | ${target_rtype}, -\t\t\t\t.access = CAP_IRQCTRL_REGISTER +\t\t\t\t.access = CAP_IRQCTRL_REGISTER | CAP_IRQCTRL_WAIT \t\t\t\t | CAP_CHANGEABLE | CAP_REPLICABLE \t\t\t\t | CAP_TRANSFERABLE, \t\t\t\t.start = 0, .end = 0, .size = 0, @@ -146,10 +146,11 @@ cap_strings = { 'ipc' : \ \t\t\t\t.target = ${cid}, \t\t\t\t.type = CAP_TYPE_MAP_PHYSMEM | CAP_RTYPE_CONTAINER, \t\t\t\t.access = CAP_MAP_READ | CAP_MAP_WRITE | CAP_MAP_EXEC | -\t\t\t\t\tCAP_MAP_CACHED | CAP_MAP_UNCACHED | CAP_MAP_UNMAP, +\t\t\t\t\tCAP_MAP_CACHED | CAP_MAP_UNCACHED | CAP_MAP_UNMAP | +\t\t\t\t\tCAP_IRQCTRL_REGISTER, \t\t\t\t.start = __pfn(PLATFORM_${devname}_BASE), \t\t\t\t.end = __pfn(PLATFORM_${devname}_BASE + PLATFORM_${devname}_SIZE), -\t\t\t\t.size = 1, +\t\t\t\t.size = PLATFORM_${devname}_SIZE >> 12, \t\t\t\t.attr = (CAP_DEVTYPE_${devtype} & CAP_DEVTYPE_MASK) \t\t\t\t\t| ((${devnum} << CAP_DEVNUM_SHIFT) & CAP_DEVNUM_MASK), \t\t\t\t.irq = IRQ_${devname}, diff --git a/config/cml/arm.ruleset b/config/cml/arm.ruleset index cc8dfe0..c98b3e0 100644 --- a/config/cml/arm.ruleset +++ b/config/cml/arm.ruleset @@ -8,33 +8,42 @@ symbols ARCH_ARM 'ARM' arm_cpu_type 'ARM Processor Type' -CPU_ARM1136 'ARM1136 - To be added' -CPU_ARM11MPCORE 'ARM11 MPCore - To be added' +CPU_ARM1136 'ARM1136 - Experimental' +CPU_ARM11MPCORE 'ARM11 MPCore - Experimental' CPU_ARM926 'ARM926EJ-S' -CPU_CORTEXA8 'ARM Cortex-A8 - Not supported' - -arm_subarch_type 'ARM Architecture Family' -SUBARCH_V5 'ARM v5 Architecture' -SUBARCH_V6 'ARM v6 Architecture, To be added' -SUBARCH_V7 'ARM v7 Architecture, To be added' +CPU_CORTEXA8 'ARM Cortex-A8' +CPU_CORTEXA9 'ARM Cortex-A9' arm_platform_type 'ARM Platform Type' -PLATFORM_EB 'Realview EB Platform, Unsupported yet' +PLATFORM_EB 'Realview EB Platform' +PLATFORM_PBA8 'Realview PB-A8 Platform, To be added' PLATFORM_PB926 'Versatile PB926 Platform' PLATFORM_PB11MPCORE 'Realview PB11MPCore Platform' +PLATFORM_BEAGLE 'OMAP3530/Cortex-A8 Beagle Board' +PLATFORM_PBA9 'Realview Express Cortex-A9' main_menu 'Codezero Microkernel Configurator' arm_menu 'ARM Architecture Configuration' arm_cpu_menu 'ARM CPU type' arm_platform_menu 'ARM Platform Type' +processor_properties 'Generic Processor Properties' +kernel_generic_options 'Generic Kernel Properties' toolchain_menu 'Toolchain Prefix' containers_menu 'Container Setup' arch_type 'Main architecture' -TOOLCHAIN_KERNEL 'Toolchain prefix for kernel' -TOOLCHAIN_USER 'Toolchain prefix for userspace' +SMP 'Enable SMP Support' +NCPU 'Number of SMP CPUs' +DEBUG_ACCOUNTING 'Enable system operations accounting' +DEBUG_PERFMON 'Enable performance monitoring' +DEBUG_PERFMON_USER 'Userspace access to perfmon registers (in-kernel measurements disabled)' +DEBUG_SPINLOCKS 'Debug spinlocks, e.g. detect recursive locks, double unlocks' +SCHED_TICKS 'Scheduler ticks per second' +ICACHE_DISABLE 'Disable the L1 instruction cache' +DCACHE_DISABLE 'Disable the L1 data cache' +PREEMPT_DISABLE 'Disable Kernel Preemption' +TOOLCHAIN 'Toolchain prefix for kernel' -CONTAINERS 'Number of containers' CAPABILITIES 'Enable capability checking' ############# @@ -45,17 +54,13 @@ choices arch_type ARCH_ARM default ARCH_ARM -choices arm_subarch_type - SUBARCH_V5 - SUBARCH_V6 - SUBARCH_V7 - default SUBARCH_V5 - - choices arm_platform_type PLATFORM_EB + PLATFORM_PBA8 PLATFORM_PB926 PLATFORM_PB11MPCORE + PLATFORM_BEAGLE + PLATFORM_PBA9 default PLATFORM_PB926 choices arm_cpu_type @@ -63,6 +68,7 @@ choices arm_cpu_type CPU_ARM1136 CPU_ARM11MPCORE CPU_CORTEXA8 + CPU_CORTEXA9 default CPU_ARM926 ############# @@ -76,55 +82,119 @@ menu arm_platform_menu arm_platform_type menu arm_menu - arm_subarch_type - arm_cpu_menu arm_platform_menu + arm_cpu_menu + +menu processor_properties + SMP + NCPU% + ICACHE_DISABLE + DCACHE_DISABLE + +menu kernel_generic_options + PREEMPT_DISABLE + DEBUG_ACCOUNTING + DEBUG_PERFMON + DEBUG_PERFMON_USER + DEBUG_SPINLOCKS + SCHED_TICKS% menu toolchain_menu - TOOLCHAIN_KERNEL$ - TOOLCHAIN_USER$ + TOOLCHAIN$ menu main_menu arch_type arm_menu + processor_properties + kernel_generic_options toolchain_menu - CONTAINERS% containers_menu -#############` +############# # RULES # ############# #Capability/Container rules: default CAPABILITIES from y -default CONTAINERS from 1 +default DEBUG_ACCOUNTING from n +default DEBUG_PERFMON from n +default DEBUG_PERFMON_USER from n +default DEBUG_SPINLOCKS from n +default SCHED_TICKS from 1000 +derive DEBUG_PERFMON_KERNEL from DEBUG_PERFMON == y and DEBUG_PERFMON_USER != y -#Platform rules: -unless SUBARCH_V5 suppress PLATFORM_PB926 -unless SUBARCH_V6 suppress PLATFORM_PB11MPCORE +#Subarch Derivation Rules +derive SUBARCH_V5 from CPU_ARM926 + +derive SUBARCH_V6 from CPU_ARM1136 or + CPU_ARM11MPCORE + +derive SUBARCH_V7 from CPU_CORTEXA8 or + CPU_CORTEXA9 #CPU rules: -unless SUBARCH_V5 suppress CPU_ARM926 -unless SUBARCH_V6 suppress CPU_ARM1136 -unless SUBARCH_V6 suppress CPU_ARM11MPCORE -unless SUBARCH_V7 suppress CPU_CORTEXA8 +unless PLATFORM_PB926 suppress CPU_ARM926 +unless PLATFORM_PB11MPCORE or PLATFORM_EB suppress CPU_ARM11MPCORE +unless PLATFORM_EB suppress CPU_ARM1136 +unless PLATFORM_PBA9 or PLATFORM_EB suppress CPU_CORTEXA9 + +unless PLATFORM_BEAGLE or + PLATFORM_PBA8 or + PLATFORM_EB suppress CPU_CORTEXA8 + +#SMP support rules +unless CPU_CORTEXA9 or CPU_ARM11MPCORE suppress SMP +unless CPU_CORTEXA9 or CPU_ARM11MPCORE suppress NCPU +unless SMP suppress NCPU +unless DEBUG_ACCOUNTING suppress DEBUG_PERFMON + DEBUG_PERFMON_USER +unless DEBUG_PERFMON suppress DEBUG_PERFMON_USER # NOTE: Unlike menus, choices dont take { sym } model of visibility # dependencies. Instead, a choice symbol is declared in a menu, and # suppress statement is used to make sym visible, instead of a # { sym } model under the choices. (See manual for { sym } usage). -unless SUBARCH_V5 suppress PLATFORM_PB926 unless ARCH_ARM suppress arm_menu -unless PLATFORM_EB suppress CPU_ARM1136 -derive DRIVER_UART_PL011 from SUBARCH_V5 or SUBARCH_V6 or SUBARCH_V7 -derive DRIVER_TIMER_SP804 from SUBARCH_V5 or SUBARCH_V6 or SUBARCH_V7 -derive DRIVER_IRQ_PL190 from PLATFORM_PB926 -derive DRIVER_IRQ_GIC from PLATFORM_PB11MPCORE or PLATFORM_EB +derive DRIVER_UART_PL011 from PLATFORM_PB926 or + PLATFORM_PB11MPCORE or + PLATFORM_PBA9 or + PLATFORM_EB or + PLATFORM_PBA8 +derive DRIVER_TIMER_SP804 from PLATFORM_PB926 or + PLATFORM_PB11MPCORE or + PLATFORM_PBA9 or + PLATFORM_EB or + PLATFORM_PBA8 + +derive DRIVER_IRQ_PL190 from PLATFORM_PB926 + +derive DRIVER_IRQ_GIC from PLATFORM_PB11MPCORE or + PLATFORM_PBA9 or + PLATFORM_EB or + PLATFORM_PBA8 + +derive DRIVER_UART_OMAP from PLATFORM_BEAGLE +derive DRIVER_TIMER_OMAP from PLATFORM_BEAGLE +derive DRIVER_INTC_OMAP from PLATFORM_BEAGLE + +#SMP default value +default SMP from y +default NCPU from 4 +default ICACHE_DISABLE from n +default DCACHE_DISABLE from n +default PREEMPT_DISABLE from n + +require NCPU <= 4 + +# Derive Ram base address depending on platform selected +# we use this in setting containers physical regions +# default values +# FIXME: Find a better solution +derive RAM_BASE_PLAT from PLATFORM_BEAGLE ? 0x80000000 : 0x00000000 # Toolchains: -default TOOLCHAIN_KERNEL from 'arm-none-eabi-' -default TOOLCHAIN_USER from 'arm-none-linux-gnueabi-' +default TOOLCHAIN from 'arm-none-eabi-' prefix CONFIG_ diff --git a/config/cml/container_ruleset.template b/config/cml/container_ruleset.template index 5d47c15..974ce2a 100644 --- a/config/cml/container_ruleset.template +++ b/config/cml/container_ruleset.template @@ -4,6 +4,8 @@ CONT%(cn)d_TYPE_BAREMETAL 'Baremetal Container' CONT%(cn)d_TYPE_POSIX 'POSIX Container' CONT%(cn)d_OPT_NAME 'Container Name' +CONTAINERS 'Number of containers' + CONT%(cn)d_PHYSMEM_REGIONS 'Container %(cn)d Number of Physical Regions' CONT%(cn)d_PHYS0_START 'Container %(cn)d Physical Region 0 Start Address' CONT%(cn)d_PHYS0_END 'Container %(cn)d Physical Region 0 End Address' @@ -58,7 +60,7 @@ default CONT%(cn)d_LINUX_PAGE_OFFSET from CONT%(cn)d_VIRT0_START default CONT%(cn)d_LINUX_PHYS_OFFSET from CONT%(cn)d_PHYS0_START default CONT%(cn)d_LINUX_ROOTFS_ADDRESS from (CONT%(cn)d_LINUX_PHYS_OFFSET + 0x500000) -default CONT%(cn)d_VIRTMEM_REGIONS from 1 +default CONT%(cn)d_VIRTMEM_REGIONS from (CONT%(cn)d_TYPE_POSIX==y ? 4 : 1) default CONT%(cn)d_PHYSMEM_REGIONS from 1 # Define limits on virtual and physical memory regions of a _single_ container 0. Too much code! @@ -106,7 +108,7 @@ require CONT%(cn)d_PHYS3_START >= 0x40000 require CONT%(cn)d_LINUX_ZRELADDR > CONT%(cn)d_LINUX_PHYS_OFFSET + 0x8000 # TODO: Do we want to check if PAGER_LMA/VMA lies in allocated memory regions -default CONT%(cn)d_PHYS0_START from (%(cn)d == 0 ? 0x100000 : (0x100000 + %(cn)d * 0x1000000)) +default CONT%(cn)d_PHYS0_START from ((%(cn)d == 0 ? 0x100000 : (0x100000 + %(cn)d * 0x1000000)) + RAM_BASE_PLAT) default CONT%(cn)d_PHYS0_END from (CONT%(cn)d_PHYS0_START + 0xD00000) default CONT%(cn)d_PHYS1_START from CONT%(cn)d_PHYS0_END default CONT%(cn)d_PHYS1_END from (CONT%(cn)d_PHYS1_START + 0x100000) @@ -128,16 +130,14 @@ default CONT%(cn)d_VIRT4_END from (CONT%(cn)d_VIRT4_START + 0x10000000) default CONT%(cn)d_VIRT5_START from 0xe0000000 default CONT%(cn)d_VIRT5_END from 0xf0000000 -derive baremetal%(cn)d from -(CONT%(cn)d_BAREMETAL_PROJ_EMPTY==y) ? "empty%(cn)d" : +default CONT%(cn)d_OPT_NAME from +(CONT%(cn)d_TYPE_LINUX==y) ? "linux%(cn)d" : +((CONT%(cn)d_TYPE_POSIX==y) ? "posix%(cn)d" : ((CONT%(cn)d_BAREMETAL_PROJ_HELLO_WORLD==y) ? "hello_world%(cn)d" : ((CONT%(cn)d_BAREMETAL_PROJ_THREADS_DEMO==y) ? "thread_demo%(cn)d" : -((CONT%(cn)d_BAREMETAL_PROJ_TEST==y) ? "test%(cn)d" : +((CONT%(cn)d_BAREMETAL_PROJ_TEST_SUITE==y) ? "test_suite%(cn)d" : ((CONT%(cn)d_BAREMETAL_PROJ_UART_SERVICE==y) ? "uart_service%(cn)d" : -((CONT%(cn)d_BAREMETAL_PROJ_CLCD_SERVICE==y) ? "clcd_service%(cn)d" : -((CONT%(cn)d_BAREMETAL_PROJ_TIMER_SERVICE==y) ? "timer_service%(cn)d" : "baremetal_noname%(cn)d" )))))) - -default CONT%(cn)d_OPT_NAME from (CONT%(cn)d_TYPE_LINUX==y) ? "linux%(cn)d" : ((CONT%(cn)d_TYPE_BAREMETAL==y) ? baremetal%(cn)d : "posix%(cn)d") +((CONT%(cn)d_BAREMETAL_PROJ_TIMER_SERVICE==y) ? "timer_service%(cn)d" : "empty%(cn)d")))))) when CONT%(cn)d_TYPE_LINUX==y suppress cont%(cn)d_default_pager_params unless CONT%(cn)d_TYPE_POSIX==y suppress cont%(cn)d_posix_pager_params @@ -165,19 +165,17 @@ cont%(cn)d_baremetal_params 'Baremetal Project' CONT%(cn)d_BAREMETAL_PROJ_EMPTY 'Empty Project' CONT%(cn)d_BAREMETAL_PROJ_HELLO_WORLD 'Hello World' CONT%(cn)d_BAREMETAL_PROJ_THREADS_DEMO 'Thread Library Demo' -CONT%(cn)d_BAREMETAL_PROJ_TEST 'Test Project' +CONT%(cn)d_BAREMETAL_PROJ_TEST_SUITE 'Microkernel Tests' CONT%(cn)d_BAREMETAL_PROJ_UART_SERVICE 'UART Service' CONT%(cn)d_BAREMETAL_PROJ_TIMER_SERVICE 'Timer Service' -CONT%(cn)d_BAREMETAL_PROJ_CLCD_SERVICE 'CLCD Service' choices cont%(cn)d_baremetal_params CONT%(cn)d_BAREMETAL_PROJ_EMPTY CONT%(cn)d_BAREMETAL_PROJ_HELLO_WORLD CONT%(cn)d_BAREMETAL_PROJ_THREADS_DEMO - CONT%(cn)d_BAREMETAL_PROJ_TEST + CONT%(cn)d_BAREMETAL_PROJ_TEST_SUITE CONT%(cn)d_BAREMETAL_PROJ_UART_SERVICE CONT%(cn)d_BAREMETAL_PROJ_TIMER_SERVICE - CONT%(cn)d_BAREMETAL_PROJ_CLCD_SERVICE default CONT%(cn)d_BAREMETAL_PROJ_EMPTY menu cont%(cn)d_default_pager_params @@ -234,19 +232,16 @@ cont%(cn)d_cap_device_uart1 'Container %(cn)d UART1 Menu' cont%(cn)d_cap_device_uart2 'Container %(cn)d UART2 Menu' cont%(cn)d_cap_device_uart3 'Container %(cn)d UART3 Menu' cont%(cn)d_cap_device_timer1 'Container %(cn)d TIMER23 Menu' -cont%(cn)d_cap_device_clcd 'Container %(cn)d CLCD Menu' CONT%(cn)d_CAP_DEVICE_UART1_USE 'Container %(cn)d UART1 Enable' CONT%(cn)d_CAP_DEVICE_UART2_USE 'Container %(cn)d UART2 Enable' CONT%(cn)d_CAP_DEVICE_UART3_USE 'Container %(cn)d UART3 Enable' CONT%(cn)d_CAP_DEVICE_TIMER1_USE 'Container %(cn)d TIMER23 Enable' -CONT%(cn)d_CAP_DEVICE_CLCD0_USE 'Container %(cn)d CLCD Enable' default CONT%(cn)d_CAP_DEVICE_UART1_USE from n default CONT%(cn)d_CAP_DEVICE_UART2_USE from n default CONT%(cn)d_CAP_DEVICE_UART3_USE from n default CONT%(cn)d_CAP_DEVICE_TIMER1_USE from n -default CONT%(cn)d_CAP_DEVICE_CLCD0_USE from n menu cont%(cn)d_cap_device_uart1 CONT%(cn)d_CAP_DEVICE_UART1_USE @@ -260,15 +255,11 @@ menu cont%(cn)d_cap_device_uart3 menu cont%(cn)d_cap_device_timer1 CONT%(cn)d_CAP_DEVICE_TIMER1_USE -menu cont%(cn)d_cap_device_clcd - CONT%(cn)d_CAP_DEVICE_CLCD0_USE - menu cont%(cn)d_device_list cont%(cn)d_cap_device_uart1 cont%(cn)d_cap_device_uart2 cont%(cn)d_cap_device_uart3 cont%(cn)d_cap_device_timer1 - cont%(cn)d_cap_device_clcd # # Settings for Custom Capabilities @@ -512,6 +503,10 @@ CONT%(cn)d_CAP_CAPCTRL_USE 'Enable this Capability' CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER 'Capability Targets Current Container' CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE 'Capability Targets Current Pager`s Space' +CONT%(cn)d_CAP_IRQCTRL_USE 'Enable this Capability' +CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER 'Capability Targets Current Container' +CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE 'Capability Targets Current Pager`s Space' + CONT%(cn)d_CAP_UMUTEX_USE 'Enable this Capability' CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_CONTAINER 'Capability Targets Current Container' CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE 'Capability Targets Current Pager`s Space' @@ -539,6 +534,7 @@ cont%(cn)d_cap_tctrl 'Container %(cn)d Thread Control Capability' cont%(cn)d_cap_exregs 'Container %(cn)d Exchange Registers Capability' cont%(cn)d_cap_ipc 'Container %(cn)d IPC Capability' cont%(cn)d_cap_capctrl 'Container %(cn)d Capability Control Capability' +cont%(cn)d_cap_irqctrl 'Container %(cn)d IRQ Control Capability' cont%(cn)d_cap_umutex 'Container %(cn)d Userspace Mutex Control Capability' cont%(cn)d_cap_custom0 'Container %(cn)d Custom Capability 0 Parameters' cont%(cn)d_cap_custom1 'Container %(cn)d Custom Capability 1 Parameters' @@ -589,6 +585,10 @@ when CONT%(cn)d_CAP_CAPCTRL_USE == n suppress CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE +when CONT%(cn)d_CAP_IRQCTRL_USE == n + suppress CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER + CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE + when CONT%(cn)d_CAP_UMUTEX_USE == n suppress CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_CONTAINER CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE @@ -615,6 +615,10 @@ choicegroup CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE default CONT%(cn)d_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER from y +choicegroup CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER + CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE + default CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER from y + choicegroup CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_CONTAINER CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE default CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_CONTAINER from y @@ -623,6 +627,7 @@ default CONT%(cn)d_CAP_TCTRL_USE from y default CONT%(cn)d_CAP_EXREGS_USE from y default CONT%(cn)d_CAP_IPC_USE from y default CONT%(cn)d_CAP_CAPCTRL_USE from y +default CONT%(cn)d_CAP_IRQCTRL_USE from y default CONT%(cn)d_CAP_UMUTEX_USE from y default CONT%(cn)d_CAP_IPC_TARGET from 0 @@ -648,6 +653,11 @@ menu cont%(cn)d_cap_umutex CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_CONTAINER CONT%(cn)d_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE +menu cont%(cn)d_cap_irqctrl + CONT%(cn)d_CAP_IRQCTRL_USE + CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER + CONT%(cn)d_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE + menu cont%(cn)d_cap_ipc CONT%(cn)d_CAP_IPC_USE CONT%(cn)d_CAP_IPC_TARGET_CURRENT_CONTAINER @@ -687,6 +697,7 @@ menu cont%(cn)d_capability_list cont%(cn)d_cap_ipc cont%(cn)d_cap_capctrl cont%(cn)d_cap_umutex + cont%(cn)d_cap_irqctrl cont%(cn)d_cap_custom0 cont%(cn)d_cap_custom1 cont%(cn)d_cap_custom2 diff --git a/config/cml/examples/beagle/hello-world.cml b/config/cml/examples/beagle/hello-world.cml new file mode 100644 index 0000000..562ac8b --- /dev/null +++ b/config/cml/examples/beagle/hello-world.cml @@ -0,0 +1,302 @@ +# +# Automatically generated, don't edit +# +# Generated on: amit-laptop +# At: Tue, 23 Feb 2010 17:03:17 +0000 +# Linux version 2.6.28-11-generic (buildd@palmer) (gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) ) #42-Ubuntu SMP Fri Apr 17 01:57:59 UTC 2009 + +# +# Codezero Microkernel Configurator +# + +# +# Main architecture +# +CONFIG_ARCH_ARM=y + + +# +# ARM Architecture Configuration +# + +# +# ARM Platform Type +# + +# +# ARM Platform Type +# +CONFIG_PLATFORM_EB=n +CONFIG_PLATFORM_PBA8=n +CONFIG_PLATFORM_PB926=n +CONFIG_PLATFORM_PB11MPCORE=n +CONFIG_PLATFORM_BEAGLE=y +CONFIG_PLATFORM_PBA9=n + + + +# +# ARM CPU type +# + +# +# ARM Processor Type +# +CONFIG_CPU_CORTEXA8=y + + + + +# +# Generic Processor Properties +# +CONFIG_ICACHE_DISABLE=n +CONFIG_DCACHE_DISABLE=n + + +# +# Generic Kernel Properties +# +CONFIG_PREEMPT_DISABLE=n +CONFIG_DEBUG_ACCOUNTING=y +CONFIG_DEBUG_PERFMON=n + + +# +# Toolchain Prefix +# +CONFIG_TOOLCHAIN="arm-none-eabi-" + + +# +# Container Setup +# +CONFIG_CAPABILITIES=y +CONFIG_CONTAINERS=1 + +# +# Container 0 Parameters +# + +# +# Container 0 Type +# +CONFIG_CONT0_TYPE_BAREMETAL=y +CONFIG_CONT0_TYPE_POSIX=n +CONFIG_CONT0_TYPE_LINUX=n + + +# +# Container 0 Options +# +CONFIG_CONT0_OPT_NAME="hello_world0" + +# +# Baremetal Project +# +CONFIG_CONT0_BAREMETAL_PROJ_EMPTY=n +CONFIG_CONT0_BAREMETAL_PROJ_HELLO_WORLD=y +CONFIG_CONT0_BAREMETAL_PROJ_THREADS_DEMO=n +CONFIG_CONT0_BAREMETAL_PROJ_TEST_SUITE=n +CONFIG_CONT0_BAREMETAL_PROJ_UART_SERVICE=n +CONFIG_CONT0_BAREMETAL_PROJ_TIMER_SERVICE=n + + +# +# Container 0 Default Pager Parameters +# +CONFIG_CONT0_PAGER_LMA=0x80100000 +CONFIG_CONT0_PAGER_VMA=0xa0000000 + + +# +# Container 0 Physical Memory Regions (Capabilities) +# +CONFIG_CONT0_PHYSMEM_REGIONS=1 +CONFIG_CONT0_PHYS0_START=0x80100000 +CONFIG_CONT0_PHYS0_END=0x80e00000 + + +# +# Container 0 Virtual Memory Regions (Capabilities) +# +CONFIG_CONT0_VIRTMEM_REGIONS=1 +CONFIG_CONT0_VIRT0_START=0xa0000000 +CONFIG_CONT0_VIRT0_END=0xb0000000 + + +# +# Container 0 Capability List +# + +# +# Container 0 Thread Pool Capability +# +CONFIG_CONT0_CAP_THREADPOOL_USE=y +CONFIG_CONT0_CAP_THREADPOOL_SIZE=64 + + +# +# Container 0 Space Pool Capability +# +CONFIG_CONT0_CAP_SPACEPOOL_USE=y +CONFIG_CONT0_CAP_SPACEPOOL_SIZE=64 + + +# +# Container 0 Mutex Pool Capability +# +CONFIG_CONT0_CAP_MUTEXPOOL_USE=y +CONFIG_CONT0_CAP_MUTEXPOOL_SIZE=100 + + +# +# Container 0 Map Pool Capability +# +CONFIG_CONT0_CAP_MAPPOOL_USE=y +CONFIG_CONT0_CAP_MAPPOOL_SIZE=800 + + +# +# Container 0 Capability Pool Capability +# +CONFIG_CONT0_CAP_CAPPOOL_USE=y +CONFIG_CONT0_CAP_CAPPOOL_SIZE=32 + + +# +# Container 0 Thread Control Capability +# +CONFIG_CONT0_CAP_TCTRL_USE=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Exchange Registers Capability +# +CONFIG_CONT0_CAP_EXREGS_USE=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IPC Capability +# +CONFIG_CONT0_CAP_IPC_USE=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_PAGER_SPACE=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_CONTAINER=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_PAGER=n + + +# +# Container 0 Capability Control Capability +# +CONFIG_CONT0_CAP_CAPCTRL_USE=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Userspace Mutex Control Capability +# +CONFIG_CONT0_CAP_UMUTEX_USE=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IRQ Control Capability +# +CONFIG_CONT0_CAP_IRQCTRL_USE=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Custom Capability 0 Parameters +# +CONFIG_CONT0_CAP_CUSTOM0_USE=n + + +# +# Container 0 Custom Capability 1 Parameters +# +CONFIG_CONT0_CAP_CUSTOM1_USE=n + + +# +# Container 0 Custom Capability 2 Parameters +# +CONFIG_CONT0_CAP_CUSTOM2_USE=n + + +# +# Container 0 Custom Capability 3 Parameters +# +CONFIG_CONT0_CAP_CUSTOM3_USE=n + + + +# +# Container 0 Devices (Capabilities) +# + +# +# Container 0 UART1 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART1_USE=n + + +# +# Container 0 UART2 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART2_USE=n + + +# +# Container 0 UART3 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART3_USE=n + + +# +# Container 0 TIMER23 Menu +# +CONFIG_CONT0_CAP_DEVICE_TIMER1_USE=n + + + + + + +# +# Derived symbols +# +CONFIG_DEBUG_PERFMON_KERNEL=n +CONFIG_CONT1_PAGER_LOAD_ADDR=0x81100000 +CONFIG_DRIVER_IRQ_PL190=n +CONFIG_DRIVER_TIMER_SP804=n +CONFIG_CONT2_START_PC_ADDR=0xc0000000 +CONFIG_CONT3_START_PC_ADDR=0xd0000000 +CONFIG_DRIVER_IRQ_GIC=n +CONFIG_CONT2_PAGER_VIRT_ADDR=0xc0000000 +CONFIG_RAM_BASE_PLAT=2147483648 +CONFIG_DRIVER_INTC_OMAP=y +CONFIG_CONT2_PAGER_LOAD_ADDR=0x82100000 +CONFIG_CONT1_PAGER_VIRT_ADDR=0xb0000000 +CONFIG_CONT3_PAGER_LOAD_ADDR=0x83100000 +CONFIG_SUBARCH_V5=n +CONFIG_SUBARCH_V7=y +CONFIG_SUBARCH_V6=n +CONFIG_DRIVER_TIMER_OMAP=y +CONFIG_CONT0_PAGER_LOAD_ADDR=0x80100000 +CONFIG_CONT0_PAGER_VIRT_ADDR=0xa0000000 +CONFIG_DRIVER_UART_OMAP=y +CONFIG_DRIVER_UART_PL011=n +CONFIG_CONT3_PAGER_VIRT_ADDR=0xd0000000 +CONFIG_CONT0_START_PC_ADDR=0xa0000000 +CONFIG_CONT1_START_PC_ADDR=0xb0000000 +# +# That's all, folks! diff --git a/config/cml/examples/helloworld/config.cml b/config/cml/examples/helloworld/config.cml index af77149..aaba30b 100644 --- a/config/cml/examples/helloworld/config.cml +++ b/config/cml/examples/helloworld/config.cml @@ -54,8 +54,7 @@ CONFIG_PLATFORM_PB926=y # # Toolchain Prefix # -CONFIG_TOOLCHAIN_KERNEL="arm-none-eabi-" -CONFIG_TOOLCHAIN_USER="arm-none-linux-gnueabi-" +CONFIG_TOOLCHAIN="arm-none-eabi-" CONFIG_CONTAINERS=1 diff --git a/config/cml/examples/linux/beagle/config.cml b/config/cml/examples/linux/beagle/config.cml new file mode 100644 index 0000000..1210071 --- /dev/null +++ b/config/cml/examples/linux/beagle/config.cml @@ -0,0 +1,292 @@ +# +# Automatically generated, don't edit +# +# Generated on: amit-laptop +# At: Wed, 03 Mar 2010 21:07:44 +0000 +# Linux version 2.6.28-11-generic (buildd@palmer) (gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) ) #42-Ubuntu SMP Fri Apr 17 01:57:59 UTC 2009 + +# +# Codezero Microkernel Configurator +# + +# +# Main architecture +# +CONFIG_ARCH_ARM=y + + +# +# ARM Architecture Configuration +# + +# +# ARM Platform Type +# + +# +# ARM Platform Type +# +CONFIG_PLATFORM_EB=n +CONFIG_PLATFORM_PBA8=n +CONFIG_PLATFORM_PB926=n +CONFIG_PLATFORM_PB11MPCORE=n +CONFIG_PLATFORM_BEAGLE=y +CONFIG_PLATFORM_PBA9=n + + + +# +# ARM CPU type +# + +# +# ARM Processor Type +# +CONFIG_CPU_CORTEXA8=y + + + + +# +# Generic Processor Properties +# +CONFIG_ICACHE_DISABLE=n +CONFIG_DCACHE_DISABLE=n + + +# +# Generic Kernel Properties +# +CONFIG_PREEMPT_DISABLE=n +CONFIG_DEBUG_ACCOUNTING=n + + +# +# Toolchain Prefix +# +CONFIG_TOOLCHAIN="arm-none-eabi-" + + +# +# Container Setup +# +CONFIG_CAPABILITIES=y +CONFIG_CONTAINERS=1 + +# +# Container 0 Parameters +# + +# +# Container 0 Type +# +CONFIG_CONT0_TYPE_BAREMETAL=n +CONFIG_CONT0_TYPE_POSIX=n +CONFIG_CONT0_TYPE_LINUX=y + + +# +# Container 0 Options +# +CONFIG_CONT0_OPT_NAME="linux0" + +# +# Container 0 Linux Pager Parameters +# +CONFIG_CONT0_LINUX_PHYS_OFFSET=0x80200000 +CONFIG_CONT0_LINUX_ZRELADDR=0x80208000 +CONFIG_CONT0_LINUX_ROOTFS_ADDRESS=0x80700000 +CONFIG_CONT0_LINUX_PAGE_OFFSET=0xa0000000 + + +# +# Container 0 Physical Memory Regions (Capabilities) +# +CONFIG_CONT0_PHYSMEM_REGIONS=1 +CONFIG_CONT0_PHYS0_START=0x80200000 +CONFIG_CONT0_PHYS0_END=0x80f00000 + + +# +# Container 0 Virtual Memory Regions (Capabilities) +# +CONFIG_CONT0_VIRTMEM_REGIONS=1 +CONFIG_CONT0_VIRT0_START=0xa0000000 +CONFIG_CONT0_VIRT0_END=0xb0000000 + + +# +# Container 0 Capability List +# + +# +# Container 0 Thread Pool Capability +# +CONFIG_CONT0_CAP_THREADPOOL_USE=y +CONFIG_CONT0_CAP_THREADPOOL_SIZE=64 + + +# +# Container 0 Space Pool Capability +# +CONFIG_CONT0_CAP_SPACEPOOL_USE=y +CONFIG_CONT0_CAP_SPACEPOOL_SIZE=64 + + +# +# Container 0 Mutex Pool Capability +# +CONFIG_CONT0_CAP_MUTEXPOOL_USE=y +CONFIG_CONT0_CAP_MUTEXPOOL_SIZE=100 + + +# +# Container 0 Map Pool Capability +# +CONFIG_CONT0_CAP_MAPPOOL_USE=y +CONFIG_CONT0_CAP_MAPPOOL_SIZE=800 + + +# +# Container 0 Capability Pool Capability +# +CONFIG_CONT0_CAP_CAPPOOL_USE=y +CONFIG_CONT0_CAP_CAPPOOL_SIZE=32 + + +# +# Container 0 Thread Control Capability +# +CONFIG_CONT0_CAP_TCTRL_USE=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Exchange Registers Capability +# +CONFIG_CONT0_CAP_EXREGS_USE=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IPC Capability +# +CONFIG_CONT0_CAP_IPC_USE=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_PAGER_SPACE=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_CONTAINER=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_PAGER=n + + +# +# Container 0 Capability Control Capability +# +CONFIG_CONT0_CAP_CAPCTRL_USE=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Userspace Mutex Control Capability +# +CONFIG_CONT0_CAP_UMUTEX_USE=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IRQ Control Capability +# +CONFIG_CONT0_CAP_IRQCTRL_USE=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Custom Capability 0 Parameters +# +CONFIG_CONT0_CAP_CUSTOM0_USE=n + + +# +# Container 0 Custom Capability 1 Parameters +# +CONFIG_CONT0_CAP_CUSTOM1_USE=n + + +# +# Container 0 Custom Capability 2 Parameters +# +CONFIG_CONT0_CAP_CUSTOM2_USE=n + + +# +# Container 0 Custom Capability 3 Parameters +# +CONFIG_CONT0_CAP_CUSTOM3_USE=n + + + +# +# Container 0 Devices (Capabilities) +# + +# +# Container 0 UART1 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART1_USE=n + + +# +# Container 0 UART2 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART2_USE=n + + +# +# Container 0 UART3 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART3_USE=n + + +# +# Container 0 TIMER23 Menu +# +CONFIG_CONT0_CAP_DEVICE_TIMER1_USE=n + + + + + + +# +# Derived symbols +# +CONFIG_DEBUG_PERFMON_KERNEL=n +CONFIG_CONT1_PAGER_LOAD_ADDR=0x81100000 +CONFIG_DRIVER_IRQ_PL190=n +CONFIG_DRIVER_TIMER_SP804=n +CONFIG_CONT2_START_PC_ADDR=0xc0000000 +CONFIG_CONT3_START_PC_ADDR=0xd0000000 +CONFIG_DRIVER_IRQ_GIC=n +CONFIG_CONT2_PAGER_VIRT_ADDR=0xc0000000 +CONFIG_RAM_BASE_PLAT=2147483648 +CONFIG_DRIVER_INTC_OMAP=y +CONFIG_CONT2_PAGER_LOAD_ADDR=0x82100000 +CONFIG_CONT1_PAGER_VIRT_ADDR=0xb0000000 +CONFIG_CONT3_PAGER_LOAD_ADDR=0x83100000 +CONFIG_SUBARCH_V5=n +CONFIG_SUBARCH_V7=y +CONFIG_SUBARCH_V6=n +CONFIG_DRIVER_TIMER_OMAP=y +CONFIG_CONT0_PAGER_LOAD_ADDR=0x80200000 +CONFIG_CONT0_PAGER_VIRT_ADDR=0xa0000000 +CONFIG_DRIVER_UART_OMAP=y +CONFIG_DRIVER_UART_PL011=n +CONFIG_CONT3_PAGER_VIRT_ADDR=0xd0000000 +CONFIG_CONT0_START_PC_ADDR=0xa0008000 +CONFIG_CONT1_START_PC_ADDR=0xb0000000 +# +# That's all, folks! diff --git a/config/cml/examples/linux/pb926/config.cml b/config/cml/examples/linux/pb926/config.cml new file mode 100644 index 0000000..ddaa94c --- /dev/null +++ b/config/cml/examples/linux/pb926/config.cml @@ -0,0 +1,292 @@ +# +# Automatically generated, don't edit +# +# Generated on: amit-laptop +# At: Wed, 03 Mar 2010 08:42:40 +0000 +# Linux version 2.6.28-11-generic (buildd@palmer) (gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) ) #42-Ubuntu SMP Fri Apr 17 01:57:59 UTC 2009 + +# +# Codezero Microkernel Configurator +# + +# +# Main architecture +# +CONFIG_ARCH_ARM=y + + +# +# ARM Architecture Configuration +# + +# +# ARM Platform Type +# + +# +# ARM Platform Type +# +CONFIG_PLATFORM_EB=n +CONFIG_PLATFORM_PBA8=n +CONFIG_PLATFORM_PB926=y +CONFIG_PLATFORM_PB11MPCORE=n +CONFIG_PLATFORM_BEAGLE=n +CONFIG_PLATFORM_PBA9=n + + + +# +# ARM CPU type +# + +# +# ARM Processor Type +# +CONFIG_CPU_ARM926=y + + + + +# +# Generic Processor Properties +# +CONFIG_ICACHE_DISABLE=n +CONFIG_DCACHE_DISABLE=n + + +# +# Generic Kernel Properties +# +CONFIG_PREEMPT_DISABLE=n +CONFIG_DEBUG_ACCOUNTING=n + + +# +# Toolchain Prefix +# +CONFIG_TOOLCHAIN="arm-none-eabi-" + + +# +# Container Setup +# +CONFIG_CAPABILITIES=y +CONFIG_CONTAINERS=1 + +# +# Container 0 Parameters +# + +# +# Container 0 Type +# +CONFIG_CONT0_TYPE_BAREMETAL=n +CONFIG_CONT0_TYPE_POSIX=n +CONFIG_CONT0_TYPE_LINUX=y + + +# +# Container 0 Options +# +CONFIG_CONT0_OPT_NAME="linux0" + +# +# Container 0 Linux Pager Parameters +# +CONFIG_CONT0_LINUX_PHYS_OFFSET=0x200000 +CONFIG_CONT0_LINUX_ZRELADDR=0x208000 +CONFIG_CONT0_LINUX_ROOTFS_ADDRESS=0x700000 +CONFIG_CONT0_LINUX_PAGE_OFFSET=0xa0000000 + + +# +# Container 0 Physical Memory Regions (Capabilities) +# +CONFIG_CONT0_PHYSMEM_REGIONS=1 +CONFIG_CONT0_PHYS0_START=0x200000 +CONFIG_CONT0_PHYS0_END=0xf00000 + + +# +# Container 0 Virtual Memory Regions (Capabilities) +# +CONFIG_CONT0_VIRTMEM_REGIONS=1 +CONFIG_CONT0_VIRT0_START=0xa0000000 +CONFIG_CONT0_VIRT0_END=0xb0000000 + + +# +# Container 0 Capability List +# + +# +# Container 0 Thread Pool Capability +# +CONFIG_CONT0_CAP_THREADPOOL_USE=y +CONFIG_CONT0_CAP_THREADPOOL_SIZE=64 + + +# +# Container 0 Space Pool Capability +# +CONFIG_CONT0_CAP_SPACEPOOL_USE=y +CONFIG_CONT0_CAP_SPACEPOOL_SIZE=64 + + +# +# Container 0 Mutex Pool Capability +# +CONFIG_CONT0_CAP_MUTEXPOOL_USE=y +CONFIG_CONT0_CAP_MUTEXPOOL_SIZE=100 + + +# +# Container 0 Map Pool Capability +# +CONFIG_CONT0_CAP_MAPPOOL_USE=y +CONFIG_CONT0_CAP_MAPPOOL_SIZE=800 + + +# +# Container 0 Capability Pool Capability +# +CONFIG_CONT0_CAP_CAPPOOL_USE=y +CONFIG_CONT0_CAP_CAPPOOL_SIZE=32 + + +# +# Container 0 Thread Control Capability +# +CONFIG_CONT0_CAP_TCTRL_USE=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Exchange Registers Capability +# +CONFIG_CONT0_CAP_EXREGS_USE=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IPC Capability +# +CONFIG_CONT0_CAP_IPC_USE=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_PAGER_SPACE=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_CONTAINER=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_PAGER=n + + +# +# Container 0 Capability Control Capability +# +CONFIG_CONT0_CAP_CAPCTRL_USE=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Userspace Mutex Control Capability +# +CONFIG_CONT0_CAP_UMUTEX_USE=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IRQ Control Capability +# +CONFIG_CONT0_CAP_IRQCTRL_USE=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Custom Capability 0 Parameters +# +CONFIG_CONT0_CAP_CUSTOM0_USE=n + + +# +# Container 0 Custom Capability 1 Parameters +# +CONFIG_CONT0_CAP_CUSTOM1_USE=n + + +# +# Container 0 Custom Capability 2 Parameters +# +CONFIG_CONT0_CAP_CUSTOM2_USE=n + + +# +# Container 0 Custom Capability 3 Parameters +# +CONFIG_CONT0_CAP_CUSTOM3_USE=n + + + +# +# Container 0 Devices (Capabilities) +# + +# +# Container 0 UART1 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART1_USE=n + + +# +# Container 0 UART2 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART2_USE=n + + +# +# Container 0 UART3 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART3_USE=n + + +# +# Container 0 TIMER23 Menu +# +CONFIG_CONT0_CAP_DEVICE_TIMER1_USE=n + + + + + + +# +# Derived symbols +# +CONFIG_DEBUG_PERFMON_KERNEL=n +CONFIG_CONT1_PAGER_LOAD_ADDR=0x1100000 +CONFIG_DRIVER_IRQ_PL190=y +CONFIG_DRIVER_TIMER_SP804=y +CONFIG_CONT2_START_PC_ADDR=0xc0000000 +CONFIG_CONT3_START_PC_ADDR=0xd0000000 +CONFIG_DRIVER_IRQ_GIC=n +CONFIG_CONT2_PAGER_VIRT_ADDR=0xc0000000 +CONFIG_RAM_BASE_PLAT=0 +CONFIG_DRIVER_INTC_OMAP=n +CONFIG_CONT2_PAGER_LOAD_ADDR=0x2100000 +CONFIG_CONT1_PAGER_VIRT_ADDR=0xb0000000 +CONFIG_CONT3_PAGER_LOAD_ADDR=0x3100000 +CONFIG_SUBARCH_V5=y +CONFIG_SUBARCH_V7=n +CONFIG_SUBARCH_V6=n +CONFIG_DRIVER_TIMER_OMAP=n +CONFIG_CONT0_PAGER_LOAD_ADDR=0x200000 +CONFIG_CONT0_PAGER_VIRT_ADDR=0xa0000000 +CONFIG_DRIVER_UART_OMAP=n +CONFIG_DRIVER_UART_PL011=y +CONFIG_CONT3_PAGER_VIRT_ADDR=0xd0000000 +CONFIG_CONT0_START_PC_ADDR=0xa0008000 +CONFIG_CONT1_START_PC_ADDR=0xb0000000 +# +# That's all, folks! diff --git a/config/cml/examples/posix/single_posix.cml b/config/cml/examples/posix/single_posix.cml index 26a2f17..5e1e4fd 100644 --- a/config/cml/examples/posix/single_posix.cml +++ b/config/cml/examples/posix/single_posix.cml @@ -54,8 +54,7 @@ CONFIG_PLATFORM_PB926=y # # Toolchain Prefix # -CONFIG_TOOLCHAIN_KERNEL="arm-none-eabi-" -CONFIG_TOOLCHAIN_USER="arm-none-linux-gnueabi-" +CONFIG_TOOLCHAIN="arm-none-eabi-" CONFIG_CONTAINERS=1 diff --git a/config/cml/examples/posix/two_posix.cml b/config/cml/examples/posix/two_posix.cml index 8ecfbc7..a6c5bf4 100644 --- a/config/cml/examples/posix/two_posix.cml +++ b/config/cml/examples/posix/two_posix.cml @@ -54,8 +54,7 @@ CONFIG_PLATFORM_PB926=y # # Toolchain Prefix # -CONFIG_TOOLCHAIN_KERNEL="arm-none-eabi-" -CONFIG_TOOLCHAIN_USER="arm-none-linux-gnueabi-" +CONFIG_TOOLCHAIN="arm-none-eabi-" CONFIG_CONTAINERS=2 diff --git a/config/cml/examples/vxa9/config.cml b/config/cml/examples/vxa9/config.cml new file mode 100644 index 0000000..41ef798 --- /dev/null +++ b/config/cml/examples/vxa9/config.cml @@ -0,0 +1,302 @@ +# +# Automatically generated, don't edit +# +# Generated on: bahadir-laptop +# At: Thu, 25 Feb 2010 16:06:59 +0000 +# Linux version 2.6.31-19-generic (buildd@palmer) (gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu8) ) #56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010 + +# +# Codezero Microkernel Configurator +# + +# +# Main architecture +# +CONFIG_ARCH_ARM=y + + +# +# ARM Architecture Configuration +# + +# +# ARM Platform Type +# + +# +# ARM Platform Type +# +CONFIG_PLATFORM_EB=n +CONFIG_PLATFORM_PBA8=n +CONFIG_PLATFORM_PB926=n +CONFIG_PLATFORM_PB11MPCORE=n +CONFIG_PLATFORM_BEAGLE=n +CONFIG_PLATFORM_PBA9=y + + + +# +# ARM CPU type +# + +# +# ARM Processor Type +# +CONFIG_CPU_CORTEXA9=y + + + + +# +# Generic Processor Properties +# +CONFIG_SMP=n +CONFIG_ICACHE_DISABLE=n +CONFIG_DCACHE_DISABLE=n + + +# +# Generic Kernel Properties +# +CONFIG_PREEMPT_DISABLE=n +CONFIG_DEBUG_ACCOUNTING=y +CONFIG_DEBUG_PERFMON=y +CONFIG_DEBUG_PERFMON_USER=y + + +# +# Toolchain Prefix +# +CONFIG_TOOLCHAIN="arm-none-eabi-" + +CONFIG_CONTAINERS=1 + +# +# Container Setup +# +CONFIG_CAPABILITIES=y + +# +# Container 0 Parameters +# + +# +# Container 0 Type +# +CONFIG_CONT0_TYPE_BAREMETAL=y +CONFIG_CONT0_TYPE_POSIX=n +CONFIG_CONT0_TYPE_LINUX=n + + +# +# Container 0 Options +# +CONFIG_CONT0_OPT_NAME="test_suite0" + +# +# Baremetal Project +# +CONFIG_CONT0_BAREMETAL_PROJ_EMPTY=y +CONFIG_CONT0_BAREMETAL_PROJ_HELLO_WORLD=n +CONFIG_CONT0_BAREMETAL_PROJ_THREADS_DEMO=n +CONFIG_CONT0_BAREMETAL_PROJ_TEST_SUITE=n +CONFIG_CONT0_BAREMETAL_PROJ_UART_SERVICE=n +CONFIG_CONT0_BAREMETAL_PROJ_TIMER_SERVICE=n + + +# +# Container 0 Default Pager Parameters +# +CONFIG_CONT0_PAGER_LMA=0x100000 +CONFIG_CONT0_PAGER_VMA=0xa0000000 + + +# +# Container 0 Physical Memory Regions (Capabilities) +# +CONFIG_CONT0_PHYSMEM_REGIONS=1 +CONFIG_CONT0_PHYS0_START=0x100000 +CONFIG_CONT0_PHYS0_END=0xe00000 + + +# +# Container 0 Virtual Memory Regions (Capabilities) +# +CONFIG_CONT0_VIRTMEM_REGIONS=1 +CONFIG_CONT0_VIRT0_START=0xa0000000 +CONFIG_CONT0_VIRT0_END=0xb0000000 + + +# +# Container 0 Capability List +# + +# +# Container 0 Thread Pool Capability +# +CONFIG_CONT0_CAP_THREADPOOL_USE=y +CONFIG_CONT0_CAP_THREADPOOL_SIZE=64 + + +# +# Container 0 Space Pool Capability +# +CONFIG_CONT0_CAP_SPACEPOOL_USE=y +CONFIG_CONT0_CAP_SPACEPOOL_SIZE=64 + + +# +# Container 0 Mutex Pool Capability +# +CONFIG_CONT0_CAP_MUTEXPOOL_USE=y +CONFIG_CONT0_CAP_MUTEXPOOL_SIZE=100 + + +# +# Container 0 Map Pool Capability +# +CONFIG_CONT0_CAP_MAPPOOL_USE=y +CONFIG_CONT0_CAP_MAPPOOL_SIZE=800 + + +# +# Container 0 Capability Pool Capability +# +CONFIG_CONT0_CAP_CAPPOOL_USE=y +CONFIG_CONT0_CAP_CAPPOOL_SIZE=32 + + +# +# Container 0 Thread Control Capability +# +CONFIG_CONT0_CAP_TCTRL_USE=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_TCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Exchange Registers Capability +# +CONFIG_CONT0_CAP_EXREGS_USE=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_EXREGS_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IPC Capability +# +CONFIG_CONT0_CAP_IPC_USE=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IPC_TARGET_CURRENT_PAGER_SPACE=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_CONTAINER=n +CONFIG_CONT0_CAP_IPC_TARGET_ANOTHER_PAGER=n + + +# +# Container 0 Capability Control Capability +# +CONFIG_CONT0_CAP_CAPCTRL_USE=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_CAPCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Userspace Mutex Control Capability +# +CONFIG_CONT0_CAP_UMUTEX_USE=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_UMUTEX_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 IRQ Control Capability +# +CONFIG_CONT0_CAP_IRQCTRL_USE=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_CONTAINER=y +CONFIG_CONT0_CAP_IRQCTRL_TARGET_CURRENT_PAGER_SPACE=n + + +# +# Container 0 Custom Capability 0 Parameters +# +CONFIG_CONT0_CAP_CUSTOM0_USE=n + + +# +# Container 0 Custom Capability 1 Parameters +# +CONFIG_CONT0_CAP_CUSTOM1_USE=n + + +# +# Container 0 Custom Capability 2 Parameters +# +CONFIG_CONT0_CAP_CUSTOM2_USE=n + + +# +# Container 0 Custom Capability 3 Parameters +# +CONFIG_CONT0_CAP_CUSTOM3_USE=n + + + +# +# Container 0 Devices (Capabilities) +# + +# +# Container 0 UART1 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART1_USE=n + + +# +# Container 0 UART2 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART2_USE=n + + +# +# Container 0 UART3 Menu +# +CONFIG_CONT0_CAP_DEVICE_UART3_USE=n + + +# +# Container 0 TIMER23 Menu +# +CONFIG_CONT0_CAP_DEVICE_TIMER1_USE=y + + + + + + +# +# Derived symbols +# +CONFIG_DEBUG_PERFMON_KERNEL=n +CONFIG_CONT1_PAGER_LOAD_ADDR=0x1100000 +CONFIG_DRIVER_IRQ_PL190=n +CONFIG_DRIVER_TIMER_SP804=y +CONFIG_CONT2_START_PC_ADDR=0xc0000000 +CONFIG_CONT3_START_PC_ADDR=0xd0000000 +CONFIG_DRIVER_IRQ_GIC=y +CONFIG_CONT2_PAGER_VIRT_ADDR=0xc0000000 +CONFIG_CONT2_PAGER_LOAD_ADDR=0x2100000 +CONFIG_CONT1_PAGER_VIRT_ADDR=0xb0000000 +CONFIG_CONT3_PAGER_LOAD_ADDR=0x3100000 +CONFIG_SUBARCH_V5=n +CONFIG_SUBARCH_V7=y +CONFIG_SUBARCH_V6=n +CONFIG_DRIVER_TIMER_OMAP=n +CONFIG_CONT0_PAGER_LOAD_ADDR=0x100000 +CONFIG_CONT0_PAGER_VIRT_ADDR=0xa0000000 +CONFIG_DRIVER_UART_OMAP=n +CONFIG_DRIVER_UART_PL011=y +CONFIG_CONT3_PAGER_VIRT_ADDR=0xd0000000 +CONFIG_CONT0_START_PC_ADDR=0xa0000000 +CONFIG_CONT1_START_PC_ADDR=0xb0000000 +# +# That's all, folks! diff --git a/config/configuration.py b/config/configuration.py index c749e5b..b6dda1b 100644 --- a/config/configuration.py +++ b/config/configuration.py @@ -55,19 +55,21 @@ class Container: class configuration: def __init__(self): - # Mapping between platform selected and gcc flags for it - self.cpu_to_gcc_flag = (['ARM926', 'arm926ej-s'], - ['CORTEXA8', 'cortex-a8'], - ['ARM11MPCORE', 'mpcore'], - ['ARM1136', 'arm1136jf-s'], - ['ARM1176', 'arm1176jz-s'],) + # Mapping between cpu and gcc flags for it. + # Optimized solution to derive gcc arch flag from cpu + # gcc flag here is "-march" + # cpu -march flag + self.arch_to_gcc_flag = (['ARM926', 'armv5'], + ['ARM1136', 'armv6'], + ['ARM11MPCORE', 'armv6k'], + ['CORTEXA8', 'armv7-a'], + ['CORTEXA9', 'armv7-a']) self.arch = None self.subarch = None self.platform = None self.cpu = None - self.gcc_cpu_flag = None - self.user_toolchain = None - self.kernel_toolchain = None + self.gcc_arch_flag = None + self.toolchain = None self.all = [] self.containers = [] self.ncontainers = 0 @@ -102,26 +104,22 @@ class configuration: parts = name.split("_", 3) self.platform = parts[2].lower() - # Extract cpu and its gcc flag from a name value pair + # Extract cpu from a name value pair def get_cpu(self, name, val): if name[:len("CONFIG_CPU_")] == "CONFIG_CPU_": parts = name.split("_", 3) self.cpu = parts[2].lower() - for cputype, cpuflag in self.cpu_to_gcc_flag: - if parts[2] == cputype: - self.gcc_cpu_flag = cpuflag + + # derive gcc "-march" flag + for cputype, archflag in self.arch_to_gcc_flag: + if cputype == parts[2]: + self.gcc_arch_flag = archflag # Extract kernel space toolchain from a name value pair - def get_toolchain_kernel(self, name, val): - if name[:len("CONFIG_TOOLCHAIN_KERNEL")] == "CONFIG_TOOLCHAIN_KERNEL": - parts = val.split("\"", 3) - self.kernel_toolchain = parts[1] - - # Extract user space toolchain from a name value pair - def get_toolchain_user(self, name, val): - if name[:len("CONFIG_TOOLCHAIN_USER")] == "CONFIG_TOOLCHAIN_USER": - parts = val.split("\"", 3) - self.user_toolchain = parts[1] + def get_toolchain(self, name, val): + if name[:len("CONFIG_TOOLCHAIN")] == "CONFIG_TOOLCHAIN": + parts = val.split("\"", 2) + self.toolchain = parts[1] # Extract number of containers def get_ncontainers(self, name, val): diff --git a/config/projpaths.py b/config/projpaths.py index 60cdd49..dee7596 100644 --- a/config/projpaths.py +++ b/config/projpaths.py @@ -23,7 +23,7 @@ CONFIG_SHELVE_FILENAME = "configuration" CONFIG_SHELVE = join(CONFIG_SHELVE_DIR, CONFIG_SHELVE_FILENAME) KERNEL_CINFO_PATH = join(PROJROOT, "src/generic/cinfo.c") LINUXDIR = join(PROJROOT, 'conts/linux') -LINUX_KERNELDIR = join(LINUXDIR, 'linux-2.6.28.10') +LINUX_KERNELDIR = join(LINUXDIR, 'linux-2.6.33') LINUX_ROOTFSDIR = join(LINUXDIR, 'rootfs') LINUX_ATAGSDIR = join(LINUXDIR, 'atags') diff --git a/configure.py b/configure.py index b7a3f2e..c90d03e 100755 --- a/configure.py +++ b/configure.py @@ -36,21 +36,20 @@ def cml2_header_to_symbols(cml2_header, config): if pair is not None: name, value = pair config.get_all(name, value) + config.get_cpu(name, value) config.get_arch(name, value) config.get_subarch(name, value) config.get_platform(name, value) - config.get_cpu(name, value) config.get_ncontainers(name, value) config.get_container_parameters(name, value) - config.get_toolchain_kernel(name, value) - config.get_toolchain_user(name, value) + config.get_toolchain(name, value) def cml2_update_config_h(config_h_path, config): with open(config_h_path, "a") as config_h: config_h.write("#define __ARCH__ " + config.arch + '\n') config_h.write("#define __PLATFORM__ " + config.platform + '\n') config_h.write("#define __SUBARCH__ " + config.subarch + '\n') - + config_h.write("#define __CPU__ " + config.cpu + '\n') def configure_kernel(cml_file): config = configuration() @@ -91,6 +90,10 @@ def build_parse_options(): default = False, dest = "print_config", help = "Prints out configuration settings" "(Symbol values and container parameters are printed)") + parser.add_option("-q", "--quite", action="store_true", dest="quite", default = False, + help = "Enable quite mode" + "(will not be presented with a configuration screen)") + (options, args) = parser.parse_args() @@ -148,10 +151,17 @@ def configure_system(options, args): if os.path.exists(CML2_CONFIG_FILE) and options.backup_config: shutil.copy(CML2_CONFIG_FILE, CML2_CONFIG_FILE_SAVED) - # Create configuration from existing file - os.system(CML2TOOLSDIR + '/cmlconfigure.py -c -o ' + \ - CML2_CONFIG_FILE + ' -i ' + cml2_config_file + \ - ' ' + CML2_COMPILED_RULES) + if options.quite: + # Create configuration from existing file + os.system(CML2TOOLSDIR + '/cmlconfigure.py -b -o ' + \ + CML2_CONFIG_FILE + ' -i ' + cml2_config_file + \ + ' ' + CML2_COMPILED_RULES) + else: + # Create configuration from existing file + os.system(CML2TOOLSDIR + '/cmlconfigure.py -c -o ' + \ + CML2_CONFIG_FILE + ' -i ' + cml2_config_file + \ + ' ' + CML2_COMPILED_RULES) + else: rules_file = autogen_rules_file(options, args) diff --git a/conts/baremetal/baremetal0/include/capability.h b/conts/baremetal/baremetal0/include/capability.h deleted file mode 100644 index 5cfce89..0000000 --- a/conts/baremetal/baremetal0/include/capability.h +++ /dev/null @@ -1,12 +0,0 @@ -#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/baremetal1/include/capability.h b/conts/baremetal/baremetal1/include/capability.h deleted file mode 100644 index 5cfce89..0000000 --- a/conts/baremetal/baremetal1/include/capability.h +++ /dev/null @@ -1,12 +0,0 @@ -#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/baremetal2/include/capability.h b/conts/baremetal/baremetal2/include/capability.h deleted file mode 100644 index 5cfce89..0000000 --- a/conts/baremetal/baremetal2/include/capability.h +++ /dev/null @@ -1,12 +0,0 @@ -#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/clcd_service/include/capability.h b/conts/baremetal/clcd_service/include/capability.h deleted file mode 100644 index 5cfce89..0000000 --- a/conts/baremetal/clcd_service/include/capability.h +++ /dev/null @@ -1,12 +0,0 @@ -#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/clcd_service/main.c b/conts/baremetal/clcd_service/main.c index 72a8f85..df85e26 100644 --- a/conts/baremetal/clcd_service/main.c +++ b/conts/baremetal/clcd_service/main.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include /* FIXME: Its best if this is */ #include @@ -28,7 +28,7 @@ int cap_read_all() /* Read number of capabilities */ if ((err = l4_capability_control(CAP_CONTROL_NCAPS, - 0, 0, 0, &ncaps)) < 0) { + 0, &ncaps)) < 0) { printf("l4_capability_control() reading # of" " capabilities failed.\n Could not " "complete CAP_CONTROL_NCAPS request.\n"); @@ -38,7 +38,7 @@ int cap_read_all() /* Read all capabilities */ if ((err = l4_capability_control(CAP_CONTROL_READ, - 0, 0, 0, caparray)) < 0) { + 0, caparray)) < 0) { printf("l4_capability_control() reading of " "capabilities failed.\n Could not " "complete CAP_CONTROL_READ_CAPS request.\n"); diff --git a/conts/baremetal/empty/SConstruct b/conts/baremetal/empty/SConstruct index e775824..3a65e11 100644 --- a/conts/baremetal/empty/SConstruct +++ b/conts/baremetal/empty/SConstruct @@ -17,7 +17,7 @@ from config.configuration import * config = configuration_retrieve() platform = config.platform arch = config.arch -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag LIBL4_RELDIR = 'conts/libl4' KERNEL_INCLUDE = join(PROJROOT, 'include') @@ -36,18 +36,17 @@ 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() 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', +env = Environment(CC = config.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], + '-Werror', '-march=' + gcc_arch_flag], LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"], ASFLAGS = ['-D__ASSEMBLY__'], \ PROGSUFFIX = '.elf', # The suffix to use for final executable\ diff --git a/conts/baremetal/empty/main.c b/conts/baremetal/empty/main.c index 8397a52..fb2becf 100644 --- a/conts/baremetal/empty/main.c +++ b/conts/baremetal/empty/main.c @@ -1,8 +1,10 @@ /* * Main function for this container */ -#include -#include + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) #include int main(void) diff --git a/conts/baremetal/hello_world/SConstruct b/conts/baremetal/hello_world/SConstruct index cd4af65..5d0435a 100644 --- a/conts/baremetal/hello_world/SConstruct +++ b/conts/baremetal/hello_world/SConstruct @@ -17,7 +17,7 @@ from config.configuration import * config = configuration_retrieve() platform = config.platform arch = config.arch -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag LIBL4_RELDIR = 'conts/libl4' KERNEL_INCLUDE = join(PROJROOT, 'include') @@ -36,18 +36,17 @@ 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() 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', +env = Environment(CC = config.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], + '-Werror', '-march=' + gcc_arch_flag], LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\ ASFLAGS = ['-D__ASSEMBLY__'], \ PROGSUFFIX = '.elf', # The suffix to use for final executable @@ -58,7 +57,7 @@ env = Environment(CC = config.user_toolchain + 'gcc', 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') + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -include l4lib/macros.h') src = Glob('*.[cS]') src += Glob('src/*.[cS]') diff --git a/conts/baremetal/hello_world/main.c b/conts/baremetal/hello_world/main.c index d2d8ed6..b1096e5 100644 --- a/conts/baremetal/hello_world/main.c +++ b/conts/baremetal/hello_world/main.c @@ -1,8 +1,10 @@ /* * Main function for this container */ -#include -#include + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) #include extern int print_hello_world(void); diff --git a/conts/baremetal/hello_world/src/test.c b/conts/baremetal/hello_world/src/test.c index e69de29..139597f 100644 --- a/conts/baremetal/hello_world/src/test.c +++ b/conts/baremetal/hello_world/src/test.c @@ -0,0 +1,2 @@ + + diff --git a/conts/baremetal/test/SConstruct b/conts/baremetal/test/SConstruct index 3d615b2..f2d8f75 100644 --- a/conts/baremetal/test/SConstruct +++ b/conts/baremetal/test/SConstruct @@ -39,6 +39,11 @@ LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace') LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')] LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper() +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(). @@ -48,13 +53,15 @@ env = Environment(CC = config.user_toolchain + 'gcc', ASFLAGS = ['-D__ASSEMBLY__'], \ PROGSUFFIX = '.elf', # The suffix to use for final executable\ ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\ - LIBS = ['gcc', 'libl4', '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], - LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH], + LIBS = ['gcc', 'libl4', 'c-userspace', 'libdev-userspace', 'gcc', 'libmalloc', + '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]') +src += Glob('src/arch/*.[cS]') objs = env.Object(src) prog = env.Program('main.elf', objs) diff --git a/conts/baremetal/test/include/capability.h b/conts/baremetal/test/include/capability.h index 4beadac..f30cb58 100644 --- a/conts/baremetal/test/include/capability.h +++ b/conts/baremetal/test/include/capability.h @@ -1,12 +1,6 @@ #ifndef __CAPABILITY_H__ #define __CAPABILITY_H__ -#include -#include -#include - -void capability_print(struct capability *cap); - int caps_read_all(); #endif /* __CAPABILITY_H__ */ diff --git a/conts/baremetal/test/main.c b/conts/baremetal/test/main.c index aaa03ed..6b550bf 100644 --- a/conts/baremetal/test/main.c +++ b/conts/baremetal/test/main.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/conts/baremetal/test/src/arch-arm/new_thread.S b/conts/baremetal/test/src/arch-arm/new_thread.S index 2dbaaf2..88dcfc7 100644 --- a/conts/baremetal/test/src/arch-arm/new_thread.S +++ b/conts/baremetal/test/src/arch-arm/new_thread.S @@ -1,11 +1,11 @@ #include -BEGIN_PROC(setup_new_thread) +BEGIN_PROC(local_setup_new_thread) ldr r0, [sp, #-4]! @ Load first argument. mov lr, pc @ Save return address ldr pc, [sp, #-4]! @ Load function pointer from stack new_thread_exit: b new_thread_exit @ We infinitely loop for now. -END_PROC(setup_new_thread) +END_PROC(local_setup_new_thread) diff --git a/conts/baremetal/test/src/capability.c b/conts/baremetal/test/src/capability.c index 44e1550..ee2b826 100644 --- a/conts/baremetal/test/src/capability.c +++ b/conts/baremetal/test/src/capability.c @@ -4,7 +4,7 @@ * Copyright (C) 2009 B Labs Ltd. */ #include -#include +#include #include static struct capability cap_array[30]; @@ -76,78 +76,6 @@ void cap_grant_single(struct capability *orig, struct capability *share, l4id_t #endif -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_TGROUP: - printf("Capability resource type:\t%s\n", "Thread Group"); - 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"); -} - int caps_read_all(void) { int ncaps; @@ -170,9 +98,7 @@ int caps_read_all(void) "complete CAP_CONTROL_READ_CAPS request.\n"); BUG(); } - - for (int i = 0; i < ncaps; i++) - cap_print(&cap_array[i]); + //cap_array_print(ncaps, caparray); return 0; } diff --git a/conts/baremetal/test/src/captest.c b/conts/baremetal/test/src/captest.c index b7bd7c9..da70565 100644 --- a/conts/baremetal/test/src/captest.c +++ b/conts/baremetal/test/src/captest.c @@ -1,9 +1,10 @@ #include -#include #include +#include #include #include #include +#include int simple_pager_thread(void *arg) { @@ -14,8 +15,8 @@ int simple_pager_thread(void *arg) l4_getid(&ids); - //printf("Thread spawned from pager, " - // "trying to create new thread.\n"); + printf("Thread spawned from pager, \ + trying to create new thread.\n"); err = l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE | TC_AS_PAGER, &ids); @@ -23,8 +24,8 @@ int simple_pager_thread(void *arg) if (res == 0) if (err == -ENOCAP || err == -ENOMEM) { - //printf("Creation failed with %d " - // "as expected.\n", err); + printf("Creation failed with %d " + "as expected.\n", err); testres = 0; } else { printf("Creation was supposed to fail " @@ -58,7 +59,7 @@ int wait_check_test(struct task_ids *ids) int result; /* Wait for thread to finish */ - //result = l4_thread_control(THREAD_WAIT, ids); + result = l4_thread_control(THREAD_WAIT, ids); if (result < 0) { printf("Waiting on (%d)'s exit failed.\n", ids->tid); return -1; @@ -66,6 +67,7 @@ int wait_check_test(struct task_ids *ids) printf("Top-level test has failed\n"); } /* Else it is a success */ + return 0; } @@ -74,7 +76,7 @@ int capability_test(void) int err; struct task_ids ids; int TEST_MUST_FAIL = 0; - int TEST_MUST_SUCCEED = 1; + //int TEST_MUST_SUCCEED = 1; /* Read pager capabilities */ caps_read_all(); @@ -90,17 +92,17 @@ int capability_test(void) goto out_err; } + printf("waititng for result\n"); /* Wait for test to finish and check result */ if (wait_check_test(&ids) < 0) goto out_err; - #if 0 + /* Destroy test thread */ if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { printf("Destruction of top-level simple_pager failed.\n"); BUG(); } -#endif /* * Share operations with the same thread @@ -129,7 +131,6 @@ int capability_test(void) if (wait_check_test(&ids) < 0) goto out_err; -#if 0 /* Destroy test thread */ if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { printf("Destruction of top-level simple_pager failed.\n"); diff --git a/conts/baremetal/test/src/thread.c b/conts/baremetal/test/src/thread.c index 6235dfb..3936d43 100644 --- a/conts/baremetal/test/src/thread.c +++ b/conts/baremetal/test/src/thread.c @@ -12,7 +12,7 @@ char *__stack_ptr = &stack[1][0]; char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8); char *__utcb_ptr = &utcb[1][0]; -extern void setup_new_thread(void); +extern void local_setup_new_thread(void); int thread_create(int (*func)(void *), void *args, unsigned int flags, struct task_ids *new_ids) @@ -44,16 +44,16 @@ int thread_create(int (*func)(void *), void *args, unsigned int flags, return -ENOMEM; /* First word of new stack is arg */ - ((unsigned long *)__stack_ptr)[-1] = (unsigned long)args; + *(((unsigned int *)__stack_ptr) -1) = (unsigned int)args; /* Second word of new stack is function address */ - ((unsigned long *)__stack_ptr)[-2] = (unsigned long)func; + *(((unsigned int *)__stack_ptr) -2) = (unsigned int)func; /* Setup new thread pc, sp, utcb */ memset(&exregs, 0, sizeof(exregs)); exregs_set_stack(&exregs, (unsigned long)__stack_ptr); exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr); - exregs_set_pc(&exregs, (unsigned long)setup_new_thread); + exregs_set_pc(&exregs, (unsigned long)local_setup_new_thread); if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) return err; diff --git a/conts/baremetal/test_suite/SConstruct b/conts/baremetal/test_suite/SConstruct new file mode 100644 index 0000000..b4e2216 --- /dev/null +++ b/conts/baremetal/test_suite/SConstruct @@ -0,0 +1,67 @@ +# -*- 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 * +from config.lib import * + +config = configuration_retrieve() +arch = config.arch +platform = config.platform +gcc_arch_flag = config.gcc_arch_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')] + +LIBMEM_RELDIR = 'conts/libmem' +LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) +LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR) +LIBMEM_INCLUDE = LIBMEM_DIR + +env = Environment(CC = config.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', '-march=' + gcc_arch_flag], + 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', 'c-userspace', 'libdev-userspace', 'gcc', 'libmalloc', + '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]') +src += Glob('src/arch/*.[cS]') + +objs = env.Object(src) +prog = env.Program('main.elf', objs) +Depends(prog, 'include/linker.lds') diff --git a/conts/baremetal/test_suite/container.c b/conts/baremetal/test_suite/container.c new file mode 100644 index 0000000..f570c3d --- /dev/null +++ b/conts/baremetal/test_suite/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/test_suite/include/capability.h b/conts/baremetal/test_suite/include/capability.h new file mode 100644 index 0000000..f30cb58 --- /dev/null +++ b/conts/baremetal/test_suite/include/capability.h @@ -0,0 +1,6 @@ +#ifndef __CAPABILITY_H__ +#define __CAPABILITY_H__ + +int caps_read_all(); + +#endif /* __CAPABILITY_H__ */ diff --git a/conts/baremetal/test_suite/include/tests.h b/conts/baremetal/test_suite/include/tests.h new file mode 100644 index 0000000..43283a1 --- /dev/null +++ b/conts/baremetal/test_suite/include/tests.h @@ -0,0 +1,7 @@ +#ifndef __TESTS_H__ +#define __TESTS_H__ + + +int capability_test(void); + +#endif /* __TESTS_H__ */ diff --git a/conts/baremetal/test_suite/include/thread.h b/conts/baremetal/test_suite/include/thread.h new file mode 100644 index 0000000..1805d27 --- /dev/null +++ b/conts/baremetal/test_suite/include/thread.h @@ -0,0 +1,19 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include + + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids); + +/* For same space */ +#define STACK_SIZE 0x1000 + +#define THREADS_TOTAL 10 + +#endif /* __THREAD_H__ */ diff --git a/conts/baremetal/test_suite/main.c b/conts/baremetal/test_suite/main.c new file mode 100644 index 0000000..d2ea465 --- /dev/null +++ b/conts/baremetal/test_suite/main.c @@ -0,0 +1,81 @@ +/* + * Main function for all tests + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include +#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include + + +int exit_test_thread(void *arg) +{ + while (1) + ; + //l4_thread_switch(0); + //l4_exit(5); + return 0; +} + +int exit_test(void) +{ + int ret; + struct task_ids ids; + + /* Create and run a new thread */ + if ((ret = thread_create(exit_test_thread, 0, + TC_SHARE_SPACE | TC_AS_PAGER, + &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } else + printf("Thread (%d) created successfully.\n", ids.tid); + + // l4_thread_switch(0); + + /* Kill it */ + printf("Killing Thread (%d).\n", ids.tid); + if ((ret = l4_thread_control(THREAD_DESTROY, &ids)) < 0) + printf("Error: Killing Thread (%d), err = %d\n", ids.tid, ret); + else + printf("Success: Killed Thread (%d)\n", ids.tid); + + +#if 0 + /* Wait on it */ + printf("Waiting on Thread (%d) to exit.\n", ids.tid); + if ((ret = l4_thread_control(THREAD_WAIT, &ids)) >= 0) + printf("Success. Paged child returned %d\n", ret); + else + printf("Error. Wait on (%d) failed. err = %d\n", + ids.tid, ret); + +#endif + return 0; +out_err: + BUG(); +} + +int main(void) +{ + printf("%s: Container %s started\n", + __CONTAINER__, __CONTAINER_NAME__); + + capability_test(); + + //exit_test(); + + /* Now quit to demo self-paging quit */ + //l4_exit(0); + + /* Now quit by null pointer */ + // *((int *)0) = 5; + + return 0; +} + diff --git a/conts/libl4/include/l4lib/arch b/conts/baremetal/test_suite/src/arch similarity index 100% rename from conts/libl4/include/l4lib/arch rename to conts/baremetal/test_suite/src/arch diff --git a/conts/baremetal/test_suite/src/arch-arm/new_thread.S b/conts/baremetal/test_suite/src/arch-arm/new_thread.S new file mode 100644 index 0000000..68c5ea5 --- /dev/null +++ b/conts/baremetal/test_suite/src/arch-arm/new_thread.S @@ -0,0 +1,11 @@ +#include +#include L4LIB_INC_ARCH(asm.h) + +BEGIN_PROC(local_setup_new_thread) + ldr r0, [sp, #-4]! @ Load first argument. + mov lr, pc @ Save return address + ldr pc, [sp, #-4]! @ Load function pointer from stack +new_thread_exit: + b new_thread_exit @ We infinitely loop for now. +END_PROC(local_setup_new_thread) + diff --git a/conts/baremetal/test_suite/src/capability.c b/conts/baremetal/test_suite/src/capability.c new file mode 100644 index 0000000..970e26a --- /dev/null +++ b/conts/baremetal/test_suite/src/capability.c @@ -0,0 +1,106 @@ +/* + * Capability-related userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include +#include L4LIB_INC_ARCH(syscalls.h) + +static struct capability cap_array[30]; + +#if 0 +struct cap_group { + struct cap_list virtmem; + struct cap_list physmem; + struct cap_list threadpool; + struct cap_list tctrl; + struct cap_list exregs; + struct cap_list ipc; + struct cap_list mutex; + struct cap_list sched; + struct cap_list mutexpool; + struct cap_list spacepool; + struct cap_list cappool; +}; + +static inline struct capability *cap_get_thread() +{ + +} + +static inline struct capability *cap_get_space() +{ + +} + +static inline struct capability *cap_get_ipc() +{ + +} + +static inline struct capability *cap_get_virtmem() +{ + +} + +static inline struct capability *cap_get_physmem() +{ + +} + +static inline struct capability *cap_get_physmem(unsigned long phys) +{ + +} + +static inline struct capability *cap_get_virtmem(unsigned long virt) +{ + +} + +static inline struct capability *cap_get_byid(l4id_t id) +{ + +} + + +void cap_share_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags) +{ + +} + +void cap_grant_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags) +{ +} + +#endif + +int caps_read_all(void) +{ + int ncaps; + int err; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, &ncaps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + BUG(); + } + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, cap_array)) < 0) { + printf("l4_capability resource_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ_CAPS request.\n"); + BUG(); + } + //cap_array_print(ncaps, caparray); + + return 0; +} + diff --git a/conts/baremetal/test_suite/src/captest.c b/conts/baremetal/test_suite/src/captest.c new file mode 100644 index 0000000..27c50e0 --- /dev/null +++ b/conts/baremetal/test_suite/src/captest.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include + +int simple_pager_thread(void *arg) +{ + int err; + int res = *(int *)arg; + struct task_ids ids; + int testres = 0; + + l4_getid(&ids); + + printf("Thread spawned from pager, \ + trying to create new thread.\n"); + err = l4_thread_control(THREAD_CREATE | + TC_SHARE_SPACE | + TC_AS_PAGER, &ids); + + if (res == 0) + if (err == -ENOCAP || + err == -ENOMEM) { + printf("Creation failed with %d " + "as expected.\n", err); + testres = 0; + } else { + printf("Creation was supposed to fail " + "with %d or %d, but err = %d\n", + -ENOMEM, -ENOCAP, err); + testres = 1; + } + else + if (err == 0) { + // printf("Creation succeeded as expected.\n"); + testres = 0; + } else { + printf("Creation was supposed to succeed, " + "but err = %d\n", err); + testres = 1; + } + + /* Destroy thread we created */ + if (err == 0 && + res == 0) + l4_thread_control(THREAD_DESTROY, &ids); + + /* Destroy self */ + l4_exit(testres); + + return 0; +} + +int wait_check_test(struct task_ids *ids) +{ + int result; + + /* Wait for thread to finish */ + result = l4_thread_control(THREAD_WAIT, ids); + if (result < 0) { + printf("Waiting on (%d)'s exit failed.\n", ids->tid); + return -1; + } else if (result > 0) { + printf("Top-level test has failed\n"); + } + /* Else it is a success */ + + return 0; +} + +int capability_test(void) +{ + int err; + struct task_ids ids; + int TEST_MUST_FAIL = 0; + //int TEST_MUST_SUCCEED = 1; + + /* Read pager capabilities */ + caps_read_all(); + + /* + * Create new thread that will attempt + * a pager privileged operation + */ + if ((err = thread_create(simple_pager_thread, + &TEST_MUST_FAIL, + TC_SHARE_SPACE, &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } + + printf("waititng for result\n"); + /* Wait for test to finish and check result */ + if (wait_check_test(&ids) < 0) + goto out_err; +#if 0 + + /* Destroy test thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + printf("Destruction of top-level simple_pager failed.\n"); + BUG(); + } + + /* + * Share operations with the same thread + * group + */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE, + CAP_SHARE_CONTAINER, 0)) < 0) { + printf("Sharing capability with thread group failed.\n"); + goto out_err; + } + + /* + * Create new thread that will attempt a pager privileged + * operation. This should succeed as we shared caps with + * the thread group. + */ + if ((err = thread_create(simple_pager_thread, + &TEST_MUST_SUCCEED, + TC_SHARE_SPACE | + TC_SHARE_GROUP, &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } + + /* Wait for test to finish and check result */ + if (wait_check_test(&ids) < 0) + goto out_err; + + /* Destroy test thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + printf("Destruction of top-level simple_pager failed.\n"); + BUG(); + } +#endif + + printf("Capability Sharing Test -- PASSED --\n"); + + return 0; + +out_err: + printf("Capability Sharing Test -- FAILED --\n"); + return 0; +} diff --git a/conts/baremetal/test_suite/src/example.c b/conts/baremetal/test_suite/src/example.c new file mode 100644 index 0000000..6321f2d --- /dev/null +++ b/conts/baremetal/test_suite/src/example.c @@ -0,0 +1,220 @@ + +#if 0 + +int mutex_user_thread(void *arg) +{ + /* TODO: Create and access a mutex */ +} + +int independent_thread(void *arg) +{ + /* TODO: Do whatever syscall available */ +} + + +/* + * This example demonstrates how the capability-based + * security model can be bypassed and taken out of the + * way for the sake of implementing an application that + * doesn't worry too much about security. + * + * The benefit is that the user does neither worry about + * capabilities nor using its api to design correctly + * secure systems. The downside is that the system is + * less security-enforced, i.e. all parties must be + * trusted. + */ +int multi_threaded_nocaps_example(void) +{ + /* + * We are the first pager with capabilities to + * create new tasks, spaces, in its own container. + */ + pager_read_caps(); + + /* + * We have all our capabilities private to us. + * + * If we create a new task, it won't be able to + * any kernel operations that we can do, because + * we hold our capabilities privately. + * + * In order to settle all capability access issues + * once and for all threads we will create and manage, + * we share our capabilities with the most global + * collection possible. + */ + + /* + * Share all of our capabilities with all threads + * in the same container. + * + * From this point onwards, any thread we create and + * manage (i.e. whose container id is equal to our + * container id) will have the ability to leverage + * all of our capabilities as defined for us at + * configuration time. + */ + l4_cap_share(0, CAP_SHARE_CONTAINER | CAP_SHARE_ALL, self_tid()); + + + /* + * Lets try it. + * + * Create new thread that we don't have any hieararchical + * relationship, i.e. one that is a pager of itself, one + * that runs in a new address space, and in a new thread + * group. All we share is the container. + */ + if ((err = thread_create(independent_thread, 0, + TC_NO_SHARING, &ids)) < 0) { + printf("mutex_user_thread creation failed.\n"); + goto out_err; + } + + /* + * We can inspect the new thread by doing an ipc to it. + * NOTE: + * + * We are able to send to this thread from the start, + * as we had a container-wide ipc capability defined at + * config-time. + * + * But we would not be able to receive from it, if we + * did not share this capability with the container. It + * would have no rights to do a send to us. But because + * we're in the same container, and we shared our + * capability, it now can. + */ + if ((err = l4_recv(ids->tid, ids->tid, 0)) < 0) { + print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd); + goto out_err; + } + + /* + * From this point onwards we can create more threads + * without worrying about whether they have the caps + * to do certain ops, and the caps api. because we shared + * them all at the beginning. + */ + +out_err: + BUG(); +} + +/* + * This example demonstrates how a pager would + * share part of its capabilities on the system + * with its children. + * + * The example includes sharing of a mutex + * capability with a paged-child. + */ +int multi_threaded_capability_sharing_example(void) +{ + struct capability *mutex_cap; + int thread_retval; + + /* + * We are the first pager with capabilities to + * create new tasks, spaces, in its own container. + */ + pager_read_caps(); + + /* + * We have all our capabilities private to us. + * + * If we create a new task, it won't be able to + * create and use userspace mutexes, because we + * hold mutex capabilities privately. + * + * Lets try it. + */ + + /* + * Create new thread that will attempt + * a mutex operation, and die on us with a + * negative return code if it fails. + */ + if ((err = thread_create(mutex_user_thread, 0, + TC_SHARE_SPACE | + TC_AS_PAGER, &ids)) < 0) { + printf("mutex_user_thread creation failed.\n"); + goto out_err; + } + + /* Check on how the thread has done */ + if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) { + print("Waiting on thread %d failed. err = %d\n", + ids->tid, err); + goto out_err; + } + + if (thread_retval == 0) { + printf("Thread %d returned with success, where " + "we expected failure.\n", ids->tid); + goto out_err; + } + + /* + * Therefore, we share our capabilities with a + * collection so that our capabilities may be also + * used by them. + */ + + /* Get our private mutex cap */ + mutex_cap = cap_get(CAP_TYPE_MUTEX); + + /* We have ability to create and use this many mutexes */ + printf("%s: We have ability to create/use %d mutexes\n", + self_tid(), mutex_cap->size); + + /* Split it */ + cap_new = cap_split(mutex_cap, 10, CAP_SPLIT_SIZE); + + /* + * Share the split part with paged-children. + * + * From this point onwards, any thread we create and + * manage (i.e. whose pagerid == self_tid()) will have + * the ability to use mutexes, as defined by cap_new + * we created. + */ + l4_cap_share(cap_new, CAP_SHARE_PGGROUP, self_tid()); + + /* + * Create new thread that will attempt + * a mutex operation, and die on us with a + * negative return code if it fails. + */ + if ((err = thread_create(mutex_user_thread, 0, + TC_SHARE_SPACE | + TC_AS_PAGER, &ids)) < 0) { + printf("mutex_user_thread creation failed.\n"); + goto out_err; + } + + /* Check on how the thread has done */ + if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) { + printf("Waiting on thread %d failed. err = %d\n", + ids->tid, err); + goto out_err; + } + + if (thread_retval < 0) { + printf("Thread %d returned with failure, where " + "we expected success.\n", ids->tid); + goto out_err; + } + +out_err: + BUG(); +} + + + + + + +#endif + diff --git a/conts/baremetal/test_suite/src/thread.c b/conts/baremetal/test_suite/src/thread.c new file mode 100644 index 0000000..3936d43 --- /dev/null +++ b/conts/baremetal/test_suite/src/thread.c @@ -0,0 +1,73 @@ +/* + * Thread creation userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include + +char stack[THREADS_TOTAL][STACK_SIZE] ALIGN(8); +char *__stack_ptr = &stack[1][0]; + +char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8); +char *__utcb_ptr = &utcb[1][0]; + +extern void local_setup_new_thread(void); + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids) +{ + struct task_ids ids; + struct exregs_data exregs; + int err; + + l4_getid(&ids); + + /* Shared space only */ + if (!(TC_SHARE_SPACE & flags)) { + printf("%s: This function allows only " + "shared space thread creation.\n", + __FUNCTION__); + return -EINVAL; + } + + /* Create thread */ + if ((err = l4_thread_control(THREAD_CREATE | flags, &ids)) < 0) + return err; + + /* Check if more stack/utcb available */ + if ((unsigned long)__utcb_ptr == + (unsigned long)&utcb[THREADS_TOTAL][0]) + return -ENOMEM; + if ((unsigned long)__stack_ptr == + (unsigned long)&stack[THREADS_TOTAL][0]) + return -ENOMEM; + + /* First word of new stack is arg */ + *(((unsigned int *)__stack_ptr) -1) = (unsigned int)args; + + /* Second word of new stack is function address */ + *(((unsigned int *)__stack_ptr) -2) = (unsigned int)func; + + /* Setup new thread pc, sp, utcb */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_stack(&exregs, (unsigned long)__stack_ptr); + exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr); + exregs_set_pc(&exregs, (unsigned long)local_setup_new_thread); + + if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) + return err; + + /* Update utcb, stack pointers */ + __stack_ptr += STACK_SIZE; + __utcb_ptr += UTCB_SIZE; + + /* Start the new thread */ + if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0) + return err; + + memcpy(new_ids, &ids, sizeof(ids)); + + return 0; +} + diff --git a/conts/baremetal/threads_demo/SConstruct b/conts/baremetal/threads_demo/SConstruct index b497069..923a918 100644 --- a/conts/baremetal/threads_demo/SConstruct +++ b/conts/baremetal/threads_demo/SConstruct @@ -17,7 +17,7 @@ from config.configuration import * config = configuration_retrieve() platform = config.platform arch = config.arch -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag LIBL4_RELDIR = 'conts/libl4' KERNEL_INCLUDE = join(PROJROOT, 'include') @@ -36,33 +36,25 @@ 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() - -LIBL4THREAD_RELDIR = 'conts/libl4thread' -LIBL4THREAD_DIR = join(PROJROOT, LIBL4THREAD_RELDIR) -LIBL4THREAD_LIBPATH = join(BUILDDIR, LIBL4THREAD_RELDIR) -LIBL4THREAD_INCLUDE = join(LIBL4THREAD_DIR, 'include') 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', +env = Environment(CC = config.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], + '-Werror', '-march=' + gcc_arch_flag], 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 = ['libl4thread', '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, LIBL4THREAD_INCLUDE], - LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH, LIBL4THREAD_LIBPATH, \ - LIBMEM_LIBPATH], + LIBS = ['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], + 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]') diff --git a/conts/baremetal/threads_demo/main.c b/conts/baremetal/threads_demo/main.c index 272021e..f2ad27b 100644 --- a/conts/baremetal/threads_demo/main.c +++ b/conts/baremetal/threads_demo/main.c @@ -1,10 +1,11 @@ /* * Main function for this container */ -#include -#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) #include -#include +#include /* Symbolic constants */ #define STACK_SIZE 0x1000 diff --git a/conts/baremetal/timer_service/SConstruct b/conts/baremetal/timer_service/SConstruct index cc082da..707fb8a 100644 --- a/conts/baremetal/timer_service/SConstruct +++ b/conts/baremetal/timer_service/SConstruct @@ -18,7 +18,7 @@ from configure import * config = configuration_retrieve() arch = config.arch platform = config.platform -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag # Wrapper library for system calls LIBL4_RELDIR = 'conts/libl4' @@ -37,20 +37,18 @@ LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ 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'), - join(LIBDEV_DIR, 'timer/sp804/include')] -LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper() +LIBDEV_INCLUDE = join(LIBDEV_DIR, 'include') 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', +env = Environment(CC = config.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], \ + '-Werror', '-march=' + gcc_arch_flag], \ LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\ ASFLAGS = ['-D__ASSEMBLY__'], \ PROGSUFFIX = '.elf', # The suffix to use for final executable @@ -65,6 +63,7 @@ env = Environment(CC = config.user_toolchain + 'gcc', src = Glob('*.[cS]') src += Glob('src/*.[cS]') +src += Glob('src/arch/*.[cS]') objs = env.Object(src) prog = env.Program('main.elf', objs) diff --git a/conts/baremetal/timer_service/include/capability.h b/conts/baremetal/timer_service/include/capability.h deleted file mode 100644 index 5cfce89..0000000 --- a/conts/baremetal/timer_service/include/capability.h +++ /dev/null @@ -1,12 +0,0 @@ -#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/timer_service/include/thread.h b/conts/baremetal/timer_service/include/thread.h new file mode 100644 index 0000000..1805d27 --- /dev/null +++ b/conts/baremetal/timer_service/include/thread.h @@ -0,0 +1,19 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include + + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids); + +/* For same space */ +#define STACK_SIZE 0x1000 + +#define THREADS_TOTAL 10 + +#endif /* __THREAD_H__ */ diff --git a/conts/baremetal/timer_service/include/timer.h b/conts/baremetal/timer_service/include/timer.h index 260b57b..a78052b 100644 --- a/conts/baremetal/timer_service/include/timer.h +++ b/conts/baremetal/timer_service/include/timer.h @@ -1,36 +1,84 @@ +/* + * Timer details. + */ #ifndef __TIMER_H__ #define __TIMER_H__ -/* - * Timer specific things are here - */ #include #include +#include -/* - * Structure representing the sleeping tasks, - * tgid: tgid of sleeping task - * wait_count: time left, in microseconds, after which task - * will be signalled to get out of sleep - */ -struct timer_task { +/* Structure representing the sleeping tasks */ +struct sleeper_task { struct link list; - l4id_t tgid; - unsigned int wait_count; + l4id_t tid; /* tid of sleeping task */ + int retval; /* return value on wakeup */ }; +/* list of tasks to be woken up */ +struct wake_task_list { + struct link head; + struct link *end; /* optimization */ + struct l4_mutex lock; /* lock for sanity of head */ +}; + +#define BUCKET_BASE_LEVEL_BITS 8 +#define BUCKET_HIGHER_LEVEL_BITS 6 + +#define BUCKET_BASE_LEVEL_SIZE (1 << BUCKET_BASE_LEVEL_BITS) +#define BUCKET_HIGHER_LEVEL_SIZE (1 << BUCKET_HIGHER_LEVEL_BITS) + +#define BUCKET_BASE_LEVEL_MASK 0xFF +#define BUCKET_HIGHER_LEVEL_MASK 0x3F + /* - * Timer structure, - * base: base address of sp804 timer encapsulated - * count: Count in microseconds from the start of this timer - * tasklist: list of tasks sleeping for some value of count - * lock: lock protecting the corruption of tasklist - */ -struct sp804_timer { - unsigned int base; - unsigned int count; - struct link tasklist; - struct l4_mutex lock; + * Web of sleeping tasks + * based on timer wheel base algorithm + */ +struct sleeper_task_bucket { + struct link bucket_level0[BUCKET_BASE_LEVEL_SIZE]; + struct link bucket_level1[BUCKET_HIGHER_LEVEL_SIZE]; + struct link bucket_level2[BUCKET_HIGHER_LEVEL_SIZE]; + struct link bucket_level3[BUCKET_HIGHER_LEVEL_SIZE]; + struct link bucket_level4[BUCKET_HIGHER_LEVEL_SIZE]; +}; + +/* Macros to extract bucket levels */ +#define GET_BUCKET_LEVEL4(x) \ + ((x >> (BUCKET_BASE_LEVEL_BITS + (3 * BUCKET_HIGHER_LEVEL_BITS))) & \ + BUCKET_HIGHER_LEVEL_MASK) +#define GET_BUCKET_LEVEL3(x) \ + ((x >> (BUCKET_BASE_LEVEL_BITS + (2 * BUCKET_HIGHER_LEVEL_BITS))) & \ + BUCKET_HIGHER_LEVEL_MASK) +#define GET_BUCKET_LEVEL2(x) \ + ((x >> (BUCKET_BASE_LEVEL_BITS + (1 * BUCKET_HIGHER_LEVEL_BITS))) & \ + BUCKET_HIGHER_LEVEL_MASK) +#define GET_BUCKET_LEVEL1(x) \ + ((x >> BUCKET_BASE_LEVEL_BITS) & BUCKET_HIGHER_LEVEL_MASK) +#define GET_BUCKET_LEVEL0(x) (x & BUCKET_BASE_LEVEL_MASK) + +/* Macros to find bucket level */ +#define IS_IN_LEVEL0_BUCKET(x) \ + (x < (1 << BUCKET_BASE_LEVEL_BITS)) +#define IS_IN_LEVEL1_BUCKET(x) \ + (x < (1 << (BUCKET_BASE_LEVEL_BITS + BUCKET_HIGHER_LEVEL_BITS))) +#define IS_IN_LEVEL2_BUCKET(x) \ + (x < (1 << (BUCKET_BASE_LEVEL_BITS + (2 * BUCKET_HIGHER_LEVEL_BITS)))) +#define IS_IN_LEVEL3_BUCKET(x) \ + (x < (1 << (BUCKET_BASE_LEVEL_BITS + (3 * BUCKET_HIGHER_LEVEL_BITS)))) + +/* + * Timer structure + * TODO: Keep timer 32 bit for time being, + * we will make it 64 in future + */ +struct timer { + int slot; /* Notify slot on utcb */ + unsigned long base; /* Virtual base address */ + unsigned int count; /* Counter/jiffies */ + struct sleeper_task_bucket task_list; /* List of sleeping tasks */ + struct l4_mutex lock; /* Lock for sleeper_task_bucket */ + struct capability cap; /* Capability describing timer */ }; #endif /* __TIMER_H__ */ diff --git a/conts/baremetal/timer_service/main.c b/conts/baremetal/timer_service/main.c index b7d94c1..d3754ba 100644 --- a/conts/baremetal/timer_service/main.c +++ b/conts/baremetal/timer_service/main.c @@ -1,136 +1,37 @@ /* * Timer service for userspace */ -#include -#include -#include -#include +#include +#include #include #include - +#include +#include +#include #include #include -#include #include -#include "sp804_timer.h" #include #include +#include +#include -/* Frequency of timer in MHz */ -#define TIMER_FREQUENCY 1 - -#define TIMERS_TOTAL 1 - +/* Capabilities of this service */ static struct capability caparray[32]; static int total_caps = 0; -struct capability timer_cap[TIMERS_TOTAL]; +/* Total number of timer chips being handled by us */ +#define TIMERS_TOTAL 1 +static struct timer timer[TIMERS_TOTAL]; +/* Deafult timer to be used for sleep/wake etc purposes */ +#define SLEEP_WAKE_TIMER 0 -void cap_dev_print(struct capability *cap) -{ - switch (cap_devtype(cap)) { - case CAP_DEVTYPE_UART: - printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap)); - break; - case CAP_DEVTYPE_TIMER: - printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap)); - break; - case CAP_DEVTYPE_CLCD: - printf("Device type:\t\t\t%s%d\n", "CLCD", cap_devnum(cap)); - break; - default: - return; - } - printf("Device Irq:\t\t%d\n", cap->irq); -} +/* tasks whose sleep time has finished */ +struct wake_task_list wake_tasks; -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: - if (!cap_is_devmem(cap)) { - printf("Capability type:\t\t%s\n", "Map/Physmem"); - } else { - printf("Capability type:\t\t%s\n", "Map/Physmem/Device"); - cap_dev_print(cap); - } - 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_IRQCTRL: - printf("Capability type:\t\t%s\n", "IRQ Control"); - 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"); -} +/* tid of handle_request thread */ +l4id_t tid_ipc_handler; int cap_read_all() { @@ -139,7 +40,7 @@ int cap_read_all() /* Read number of capabilities */ if ((err = l4_capability_control(CAP_CONTROL_NCAPS, - 0, 0, 0, &ncaps)) < 0) { + 0, &ncaps)) < 0) { printf("l4_capability_control() reading # of" " capabilities failed.\n Could not " "complete CAP_CONTROL_NCAPS request.\n"); @@ -149,18 +50,116 @@ int cap_read_all() /* Read all capabilities */ if ((err = l4_capability_control(CAP_CONTROL_READ, - 0, 0, 0, caparray)) < 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; } +int cap_share_all_with_space() +{ + int err; + + /* Share all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE, + CAP_SHARE_ALL_SPACE, 0)) < 0) { + printf("l4_capability_control() sharing of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_SHARE request. err=%d\n", + err); + BUG(); + } + + return 0; +} + +/* + * Initialize timer devices + */ +void timer_struct_init(struct timer* timer, unsigned long base) +{ + timer->base = base; + timer->count = 0; + timer->slot = 0; + l4_mutex_init(&timer->lock); + + for (int i = 0; i < BUCKET_BASE_LEVEL_SIZE ; ++i) { + link_init(&timer->task_list.bucket_level0[i]); + } + + for (int i = 0; i < BUCKET_HIGHER_LEVEL_SIZE ; ++i) { + link_init(&timer->task_list.bucket_level1[i]); + link_init(&timer->task_list.bucket_level2[i]); + link_init(&timer->task_list.bucket_level3[i]); + link_init(&timer->task_list.bucket_level4[i]); + } +} + +/* + * Initialize wake list head structure + */ +void wake_task_list_init(void) +{ + link_init(&wake_tasks.head); + wake_tasks.end = &wake_tasks.head; + l4_mutex_init(&wake_tasks.lock); +} + +/* + * Allocate new sleeper task struct + */ +struct sleeper_task *new_sleeper_task(l4id_t tid, int ret) +{ + struct sleeper_task *task; + + /* May be we can prepare a cache for timer_task structs */ + task = (struct sleeper_task *)kzalloc(sizeof(struct sleeper_task)); + + link_init(&task->list); + task->tid = tid; + task->retval = ret; + + return task; +} + +void free_sleeper_task(struct sleeper_task *task) +{ + kfree(task); + task = NULL; +} + +/* + * Find the bucket list correspongding to seconds value + */ +struct link* find_bucket_list(unsigned long seconds) +{ + struct link *vector; + struct sleeper_task_bucket *bucket; + + bucket = &timer[SLEEP_WAKE_TIMER].task_list; + + /* + * TODO: Check if we have already surpassed seconds + */ + if (IS_IN_LEVEL0_BUCKET(seconds)) { + vector = &bucket->bucket_level0[GET_BUCKET_LEVEL0(seconds)]; + } else if (IS_IN_LEVEL1_BUCKET(seconds)) { + vector = &bucket->bucket_level1[GET_BUCKET_LEVEL1(seconds)]; + } else if (IS_IN_LEVEL2_BUCKET(seconds)) { + vector = &bucket->bucket_level2[GET_BUCKET_LEVEL2(seconds)]; + } else if (IS_IN_LEVEL3_BUCKET(seconds)) { + vector = &bucket->bucket_level3[GET_BUCKET_LEVEL3(seconds)]; + } else { + vector = &bucket->bucket_level4[GET_BUCKET_LEVEL4(seconds)]; + } + + return vector; +} + /* * Scans for up to TIMERS_TOTAL timer devices in capabilities. */ @@ -173,8 +172,8 @@ int timer_probe_devices(void) /* 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])); + memcpy(&timer[cap_devnum(&caparray[i]) - 1].cap, + &caparray[i], sizeof(timer[0].cap)); timers++; } } @@ -187,57 +186,164 @@ int timer_probe_devices(void) return 0; } -static struct sp804_timer timer[TIMERS_TOTAL]; - -struct timer_task *get_timer_task(l4id_t tgid) +/* + * Irq handler for timer interrupts + */ +int timer_irq_handler(void *arg) { - /* May be we can prepare a cache for timer_task structs */ - struct timer_task *task = (struct timer_task *)kzalloc(sizeof(struct timer_task)); + int err; + struct timer *timer = (struct timer *)arg; + struct link *vector; + const int slot = 0; - link_init(&task->list); - task->tgid = tgid; - task->wait_count = timer[0].count; + /* Initialise timer */ + timer_init(timer->base); - return task; + /* Register self for timer irq, using notify slot 0 */ + if ((err = l4_irq_control(IRQ_CONTROL_REGISTER, slot, + timer->cap.irq)) < 0) { + printf("%s: FATAL: Timer irq could not be registered. " + "err=%d\n", __FUNCTION__, err); + BUG(); + } + + /* Enable Timer */ + timer_start(timer->base); + + /* Handle irqs forever */ + while (1) { + int count; + struct link *task_list; + + /* Block on irq */ + if((count = l4_irq_wait(slot, timer->cap.irq)) < 0) { + printf("l4_irq_wait() returned with negative value\n"); + BUG(); + } + + //printf("Got irq(count 0x%x)\n", timer->count); + /* + * Update timer count + * TODO: Overflow check, we have 1 interrupt/sec from timer + * with 32bit count it will take 9years to overflow + */ + timer->count += count; + + /* find bucket list of taks to be woken for current count */ + vector = find_bucket_list(timer->count); + + if (!list_empty(vector)) { + /* Removing tasks from sleeper list */ + l4_mutex_lock(&timer[SLEEP_WAKE_TIMER].lock); + task_list = list_detach(vector); + l4_mutex_unlock(&timer[SLEEP_WAKE_TIMER].lock); + + /* Add tasks to wake_task_list */ + l4_mutex_lock(&wake_tasks.lock); + list_attach(task_list, + &wake_tasks.head, wake_tasks.end); + l4_mutex_unlock(&wake_tasks.lock); + + /* + * Send ipc to handle_request + * thread to send wake signals + */ + printf("sending ipc %d to thread %d\n", L4_IPC_TAG_TIMER_WAKE_THREADS, tid_ipc_handler); + l4_send(tid_ipc_handler,L4_IPC_TAG_TIMER_WAKE_THREADS); + } + } } -void free_timer_task(struct timer_task *task) +/* + * Helper routine to wake tasks from wake list + */ +void task_wake(void) { - kfree(task); + struct sleeper_task *struct_ptr, *temp_ptr; + int ret; + + if (!list_empty(&wake_tasks.head)) { + list_foreach_removable_struct(struct_ptr, temp_ptr, + &wake_tasks.head, list) { + /* Remove task from wake list */ + l4_mutex_lock(&wake_tasks.lock); + list_remove(&struct_ptr->list); + l4_mutex_unlock(&wake_tasks.lock); + + /* Set sender correctly */ + l4_set_sender(struct_ptr->tid); + +#if 0 + printf("waking thread at time %x\n", + (unsigned int)timer[SLEEP_WAKE_TIMER].count); +#endif + /* send wake ipc */ + if ((ret = l4_ipc_return(struct_ptr->retval)) < 0) { + printf("%s: IPC return error: %d.\n", + __FUNCTION__, ret); + BUG(); + } + + /* free allocated sleeper task struct */ + free_sleeper_task(struct_ptr); + } + } + /* If wake list is empty set end = start */ + if (list_empty(&wake_tasks.head)) + wake_tasks.end = &wake_tasks.head; + } 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); - timer[i].count = 0; - link_init(&timer[i].tasklist); - l4_mutex_init(&timer[i].lock); + struct task_ids irq_tids; + int err; - /* 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, + for (int i = 0; i < TIMERS_TOTAL; i++) { + /* initialize timer */ + timer_struct_init(&timer[i],(unsigned long)l4_new_virtual(1) ); + + /* Map timer to a virtual address region */ + if (IS_ERR(l4_map((void *)__pfn_to_addr(timer[i].cap.start), + (void *)timer[i].base, timer[i].cap.size, + MAP_USR_IO, self_tid()))) { printf("%s: FATAL: Failed to map TIMER device " "%d to a virtual address\n", __CONTAINER_NAME__, - cap_devnum(&timer_cap[i])); + cap_devnum(&timer[i].cap)); BUG(); } - /* Initialise timer */ - sp804_init(timer[i].base, SP804_TIMER_RUNMODE_PERIODIC, \ - SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \ - SP804_TIMER_IRQDISABLE); - - /* Enable Timer */ - sp804_enable(timer[i].base, 1); + /* + * Create new timer irq handler thread. + * + * This will initialize its timer argument, register + * itself as its irq handler, initiate the timer and + * wait on irqs. + */ + if ((err = thread_create(timer_irq_handler, &timer[i], + TC_SHARE_SPACE, + &irq_tids)) < 0) { + printf("FATAL: Creation of irq handler " + "thread failed.\n"); + BUG(); + } } + return 0; } +/* + * Declare a statically allocated char buffer + * with enough bitmap size to cover given size + */ +#define DECLARE_IDPOOL(name, size) \ + char name[(sizeof(struct id_pool) + ((size >> 12) >> 3))] + +#define PAGE_POOL_SIZE SZ_1MB static struct address_pool device_vaddr_pool; +DECLARE_IDPOOL(device_id_pool, PAGE_POOL_SIZE); /* * Initialize a virtual address pool @@ -247,8 +353,8 @@ 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) == + if (cap_type(&caparray[i]) == CAP_TYPE_MAP_VIRTMEM + && __pfn_to_addr(caparray[i].start) == (unsigned long)vma_start) { /* @@ -265,8 +371,10 @@ void init_vaddr_pool(void) * 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); + address_pool_init(&device_vaddr_pool, + (struct id_pool *)&device_id_pool, + page_align_up(__end), + __pfn_to_addr(caparray[i].end)); return; } else goto out_err; @@ -285,46 +393,23 @@ void *l4_new_virtual(int npages) return address_new(&device_vaddr_pool, npages, PAGE_SIZE); } -void timer_irq_handler(void) +/* + * Got request for sleep for seconds, + * right now max sleep allowed is 2^32 sec + */ +void task_sleep(l4id_t tid, unsigned long seconds, int ret) { - struct timer_task *struct_ptr, *temp_ptr; + struct sleeper_task *task = new_sleeper_task(tid, ret); + struct link *vector; - timer[0].count += 1; + /* can overflow happen here?, timer is in 32bit mode */ + seconds += timer[SLEEP_WAKE_TIMER].count; - /* - * FIXME: - * Traverse through the sleeping process list and - * wake any process if required, we need to put this part in bottom half - */ - list_foreach_removable_struct(struct_ptr, temp_ptr, &timer[0].tasklist, list) - if (struct_ptr->wait_count == timer[0].count) { + vector = find_bucket_list(seconds); - /* Remove task from list */ - l4_mutex_lock(&timer[0].lock); - list_remove(&struct_ptr->list); - l4_mutex_unlock(&timer[0].lock); - - /* wake the sleeping process, send wake ipc */ - - free_timer_task(struct_ptr); - } -} - -int timer_gettime(void) -{ - return timer[0].count; -} - -void timer_sleep(l4id_t tgid, int sec) -{ - struct timer_task *task = get_timer_task(tgid); - - /* Check for overflow */ - task->wait_count += (sec * 1000000); - - l4_mutex_lock(&timer[0].lock); - list_insert_tail(&task->list, &timer[0].tasklist); - l4_mutex_unlock(&timer[0].lock); + l4_mutex_lock(&timer[SLEEP_WAKE_TIMER].lock); + list_insert(&task->list, vector); + l4_mutex_unlock(&timer[SLEEP_WAKE_TIMER].lock); } void handle_requests(void) @@ -334,10 +419,9 @@ void handle_requests(void) 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); + printf("%s: %s: IPC Error: %d. Quitting...\n", + __CONTAINER__, __FUNCTION__, ret); BUG(); } @@ -361,13 +445,35 @@ void handle_requests(void) * inside the current container */ switch (tag) { + /* Return time in seconds, since the timer was started */ case L4_IPC_TAG_TIMER_GETTIME: - mr[0] = timer_gettime(); + mr[0] = timer[SLEEP_WAKE_TIMER].count; + + /* Reply */ + if ((ret = l4_ipc_return(ret)) < 0) { + printf("%s: IPC return error: %d.\n", __FUNCTION__, ret); + BUG(); + } break; case L4_IPC_TAG_TIMER_SLEEP: - timer_sleep(senderid, mr[0]); - /* TODO: Halt the caller for mr[0] seconds */ + printf("%s: Got sleep request from thread 0x%x, duration %d\n", __CONTAINER_NAME__, + senderid, mr[0]); + if (mr[0] > 0) { + task_sleep(senderid, mr[0], ret); + } + else { + if ((ret = l4_ipc_return(ret)) < 0) { + printf("%s: IPC return error: %d.\n", + __FUNCTION__, ret); + BUG(); + } + } + break; + + /* Intra container ipc by irq_thread */ + case L4_IPC_TAG_TIMER_WAKE_THREADS: + task_wake(); break; default: @@ -376,12 +482,6 @@ void handle_requests(void) "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(); - } } /* @@ -426,25 +526,33 @@ void main(void) /* Read all capabilities */ cap_read_all(); + /* Share all with space */ + cap_share_all_with_space(); + /* 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 */ + /* Setup own static utcb */ if ((err = l4_utcb_setup(&utcb)) < 0) { printf("FATAL: Could not set up own utcb. " "err=%d\n", err); BUG(); } + /* initialise timed_out_task list */ + wake_task_list_init(); + + /* Map and initialize timer devices */ + timer_setup_devices(); + + /* Set the tid of ipc handler */ + tid_ipc_handler = self_tid(); + /* Listen for timer requests */ while (1) handle_requests(); } - diff --git a/conts/baremetal/timer_service/src/new_thread.S b/conts/baremetal/timer_service/src/new_thread.S new file mode 100644 index 0000000..68c5ea5 --- /dev/null +++ b/conts/baremetal/timer_service/src/new_thread.S @@ -0,0 +1,11 @@ +#include +#include L4LIB_INC_ARCH(asm.h) + +BEGIN_PROC(local_setup_new_thread) + ldr r0, [sp, #-4]! @ Load first argument. + mov lr, pc @ Save return address + ldr pc, [sp, #-4]! @ Load function pointer from stack +new_thread_exit: + b new_thread_exit @ We infinitely loop for now. +END_PROC(local_setup_new_thread) + diff --git a/conts/baremetal/timer_service/src/thread.c b/conts/baremetal/timer_service/src/thread.c new file mode 100644 index 0000000..79a0453 --- /dev/null +++ b/conts/baremetal/timer_service/src/thread.c @@ -0,0 +1,75 @@ +/* + * Thread creation userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include + +char stack[THREADS_TOTAL][STACK_SIZE] ALIGN(8); +char *__stack_ptr = &stack[1][0]; + +char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8); +//char utcb[THREADS_TOTAL][0x1000] ALIGN(0x1000); +char *__utcb_ptr = &utcb[1][0]; + +extern void local_setup_new_thread(void); + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids) +{ + struct task_ids ids; + struct exregs_data exregs; + int err; + + l4_getid(&ids); + + /* Shared space only */ + if (!(TC_SHARE_SPACE & flags)) { + printf("%s: Warning - This function allows only " + "shared space thread creation.\n", + __FUNCTION__); + return -EINVAL; + } + + /* Create thread */ + if ((err = l4_thread_control(THREAD_CREATE | flags, &ids)) < 0) + return err; + + /* Check if more stack/utcb available */ + if ((unsigned long)__utcb_ptr == + (unsigned long)&utcb[THREADS_TOTAL][0]) + return -ENOMEM; + if ((unsigned long)__stack_ptr == + (unsigned long)&stack[THREADS_TOTAL][0]) + return -ENOMEM; + + /* First word of new stack is arg */ + ((unsigned long *)__stack_ptr)[-1] = (unsigned long)args; + + /* Second word of new stack is function address */ + ((unsigned long *)__stack_ptr)[-2] = (unsigned long)func; + + /* Setup new thread pc, sp, utcb */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_stack(&exregs, (unsigned long)__stack_ptr); + exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr); + exregs_set_pc(&exregs, (unsigned long)local_setup_new_thread); + + if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) + return err; + + /* Update utcb, stack pointers */ + __stack_ptr += STACK_SIZE; + __utcb_ptr += UTCB_SIZE; + //__utcb_ptr += 0x1000; + + /* Start the new thread */ + if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0) + return err; + + memcpy(new_ids, &ids, sizeof(ids)); + + return 0; +} + diff --git a/conts/baremetal/uart_service/SConstruct b/conts/baremetal/uart_service/SConstruct index 1b32b63..19e4a56 100644 --- a/conts/baremetal/uart_service/SConstruct +++ b/conts/baremetal/uart_service/SConstruct @@ -17,7 +17,7 @@ from config.configuration import * config = configuration_retrieve() platform = config.platform arch = config.arch -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag LIBL4_RELDIR = 'conts/libl4' KERNEL_INCLUDE = join(PROJROOT, 'include') @@ -35,8 +35,7 @@ LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ 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() +LIBDEV_INCLUDE = join(LIBDEV_DIR, 'include') # FIXME: Add these to autogenerated SConstruct !!! LIBMEM_RELDIR = 'conts/libmem' @@ -44,16 +43,17 @@ LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR) LIBMEM_INCLUDE = LIBMEM_DIR -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.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], + '-Werror', '-march=' + gcc_arch_flag], 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. + 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') diff --git a/conts/baremetal/uart_service/include/capability.h b/conts/baremetal/uart_service/include/capability.h deleted file mode 100644 index 5cfce89..0000000 --- a/conts/baremetal/uart_service/include/capability.h +++ /dev/null @@ -1,12 +0,0 @@ -#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/uart_service/main.c b/conts/baremetal/uart_service/main.c index 6152910..4bed218 100644 --- a/conts/baremetal/uart_service/main.c +++ b/conts/baremetal/uart_service/main.c @@ -1,130 +1,28 @@ /* * UART service for userspace */ -#include -#include -#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) #include +#include #include #include - +#include +#include #include -#include #include -#include /* FIXME: Its best if this is */ #include +#include +#include -#define UARTS_TOTAL 3 - +/* Capabilities of this service */ static struct capability caparray[32]; static int total_caps = 0; -struct capability uart_cap[UARTS_TOTAL]; - -void cap_dev_print(struct capability *cap) -{ - switch (cap_devtype(cap)) { - case CAP_DEVTYPE_UART: - printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap)); - break; - case CAP_DEVTYPE_TIMER: - printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap)); - break; - case CAP_DEVTYPE_CLCD: - printf("Device type:\t\t\t%s%d\n", "CLCD", cap_devnum(cap)); - break; - default: - return; - } - printf("Device Irq:\t\t%d\n", cap->irq); -} - -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: - if (!cap_is_devmem(cap)) { - printf("Capability type:\t\t%s\n", "Map/Physmem"); - } else { - printf("Capability type:\t\t%s\n", "Map/Physmem/Device"); - cap_dev_print(cap); - } - 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_IRQCTRL: - printf("Capability type:\t\t%s\n", "IRQ Control"); - 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"); -} +/* Number of UARTS to be managed by this service */ +#define UARTS_TOTAL 1 +static struct uart uart[UARTS_TOTAL]; int cap_read_all() { @@ -133,7 +31,7 @@ int cap_read_all() /* Read number of capabilities */ if ((err = l4_capability_control(CAP_CONTROL_NCAPS, - 0, 0, 0, &ncaps)) < 0) { + 0, &ncaps)) < 0) { printf("l4_capability_control() reading # of" " capabilities failed.\n Could not " "complete CAP_CONTROL_NCAPS request.\n"); @@ -143,15 +41,27 @@ int cap_read_all() /* Read all capabilities */ if ((err = l4_capability_control(CAP_CONTROL_READ, - 0, 0, 0, caparray)) < 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; +} + +int cap_share_all_with_space() +{ + int err; + /* Share all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE, + CAP_SHARE_ALL_SPACE, 0)) < 0) { + printf("l4_capability_control() sharing of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_SHARE request. err=%d\n", err); + BUG(); + } return 0; } @@ -168,8 +78,8 @@ int uart_probe_devices(void) /* 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])); + memcpy(&uart[cap_devnum(&caparray[i]) - 1].cap, + &caparray[i], sizeof(uart[0].cap)); uarts++; } } @@ -182,7 +92,7 @@ int uart_probe_devices(void) return 0; } -static struct pl011_uart uart[UARTS_TOTAL]; +static struct uart uart[UARTS_TOTAL]; int uart_setup_devices(void) { @@ -191,24 +101,32 @@ int uart_setup_devices(void) uart[i].base = (unsigned long)l4_new_virtual(1); /* Map uart to a virtual address region */ - if (IS_ERR(l4_map((void *)__pfn_to_addr(uart_cap[i].start), - (void *)uart[i].base, uart_cap[i].size, - MAP_USR_IO_FLAGS, - self_tid()))) { + if (IS_ERR(l4_map((void *)__pfn_to_addr(uart[i].cap.start), + (void *)uart[i].base, uart[i].cap.size, + MAP_USR_IO, self_tid()))) { printf("%s: FATAL: Failed to map UART device " "%d to a virtual address\n", __CONTAINER_NAME__, - cap_devnum(&uart_cap[i])); + cap_devnum(&uart[i].cap)); BUG(); } /* Initialize uart */ - pl011_initialise(&uart[i]); + uart_init(uart[i].base); } return 0; } +/* + * Declare a statically allocated char buffer + * with enough bitmap size to cover given size + */ +#define DECLARE_IDPOOL(name, size) \ + char name[(sizeof(struct id_pool) + ((size >> 12) >> 3))] + +#define PAGE_POOL_SIZE SZ_1MB static struct address_pool device_vaddr_pool; +DECLARE_IDPOOL(device_id_pool, PAGE_POOL_SIZE); /* * Initialize a virtual address pool @@ -237,9 +155,9 @@ void init_vaddr_pool(void) * addresses from this pool. */ address_pool_init(&device_vaddr_pool, + (struct id_pool *)&device_id_pool, page_align_up(__end), - __pfn_to_addr(caparray[i].end), - UARTS_TOTAL); + __pfn_to_addr(caparray[i].end)); return; } else goto out_err; @@ -260,16 +178,12 @@ void *l4_new_virtual(int npages) void uart_generic_tx(char c, int devno) { - pl011_tx_char(uart[devno].base, c); + uart_tx_char(uart[devno].base, c); } char uart_generic_rx(int devno) { - char c; - - pl011_rx_char(uart[devno].base, &c); - - return c; + return uart_rx_char(uart[devno].base); } void handle_requests(void) @@ -375,6 +289,9 @@ void main(void) /* Read all capabilities */ cap_read_all(); + /* Share all with space */ + cap_share_all_with_space(); + /* Scan for uart devices in capabilities */ uart_probe_devices(); diff --git a/conts/libc/SConscript b/conts/libc/SConscript index be39cd2..a200276 100644 --- a/conts/libc/SConscript +++ b/conts/libc/SConscript @@ -18,17 +18,18 @@ from config.projpaths import * Import('env', 'arch', 'type') variant = type -# Needed by fputc(), for declaration of pl011_uart_tx() -LIBDEV_PATH = join(PROJROOT, 'conts/libdev') -LIBDEV_INCPATH = [LIBDEV_PATH + '/uart/include'] +# Needed by fputc(), for declaration of uart_tx() +LIBDEV_RELDIR = 'conts/libdev' +LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR) +LIBDEV_INC = join(LIBDEV_DIR, 'include') e = env.Clone() -e.Append(CPPPATH = ['include', 'include/sys-' + variant + '/arch-' + arch, - LIBDEV_INCPATH], - CCFLAGS = '-nostdinc') +e.Append(CPPPATH = ['include', 'include/sys-' + variant + \ + '/arch-' + arch, LIBDEV_INC], + CCFLAGS = ['-nostdinc']) source = \ - Glob('src/*.c') + \ + Glob('src/*.[cS]') + \ Glob('src/sys-' + variant + '/*.c') + \ Glob('src/sys-' + variant + '/arch-' + arch + '/*.c') + \ Glob('src/arch-' + arch + '/*.c') + \ diff --git a/conts/libc/SConstruct b/conts/libc/SConstruct new file mode 100644 index 0000000..ac379f2 --- /dev/null +++ b/conts/libc/SConstruct @@ -0,0 +1,50 @@ +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- a microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd +# +import os, sys + +PROJRELROOT = '../..' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from config.configuration import * + +config = configuration_retrieve() +gcc_arch_flag = config.gcc_arch_flag +arch = config.arch + +# We assume we are compiling for userspace. +# variant can be specified from cmdline using +# scons variant=xxx +variant = ARGUMENTS.get('variant', 'userspace') +print '\nCompiling for variant: ' + variant + '\n' + +# Needed by fputc(), for declaration of uart_tx() +LIBDEV_RELDIR = 'conts/libdev' +LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR) +LIBDEV_INC = join(LIBDEV_DIR, 'include') + +env = Environment(CC = config.toolchain + 'gcc', + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \ + '-nostdinc', '-Wall', '-Werror', '-march=' + gcc_arch_flag], + LINKFLAGS = ['-nostdlib'], + ASFLAGS = ['-D__ASSEMBLY__'], + ENV = {'PATH' : os.environ['PATH']}, + CPPPATH = ['include', LIBDEV_INC, join(PROJROOT,'include'), \ + 'include/sys-' + variant + '/arch-' + arch]) + +source = \ + Glob('src/*.[cS]') + \ + Glob('src/sys-' + variant + '/*.c') + \ + Glob('src/sys-' + variant + '/arch-' + arch + '/*.c') + \ + Glob('src/arch-' + arch + '/*.c') + \ + Glob('src/arch-' + arch + '/*.S') + \ + Glob('crt/sys-' + variant + '/arch-' + arch + '/*.[cS]') + +objects = env.StaticObject(source) +library = env.StaticLibrary('c-' + variant, objects) + diff --git a/conts/libc/include/stdio.h b/conts/libc/include/stdio.h index a3c544f..24b9c1b 100644 --- a/conts/libc/include/stdio.h +++ b/conts/libc/include/stdio.h @@ -181,7 +181,8 @@ int vsprintf(char *, const char *format, va_list arg); int vsscanf(const char *s, const char *format, va_list arg); /* 7.19.7 Character i/o functions */ -int fgetc(FILE *); +char fgetc(FILE *); +char *fgetline(FILE *); char *fgets(char *, int, FILE *); int fputc(int, FILE *); int fputs(const char *, FILE *); diff --git a/conts/libc/src/memcpy.c b/conts/libc/include/sys-baremetal/arch-arm/arch/stdint.h similarity index 73% rename from conts/libc/src/memcpy.c rename to conts/libc/include/sys-baremetal/arch-arm/arch/stdint.h index b9c7075..6078b0a 100644 --- a/conts/libc/src/memcpy.c +++ b/conts/libc/include/sys-baremetal/arch-arm/arch/stdint.h @@ -3,15 +3,15 @@ * * Version 1-0 * - * Copyright (c) 2004 University of New South Wales + * Copyright (c) 2004 National ICT Australia * * All rights reserved. * - * Developed by: Operating Systems and Distributed Systems Group (DiSy) - * University of New South Wales - * http://www.disy.cse.unsw.edu.au + * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS) + * National ICT Australia + * http://www.ertos.nicta.com.au * - * Permission is granted by University of New South Wales, free of charge, to + * Permission is granted by National ICT Australia, free of charge, to * any person obtaining a copy of this software and any associated * documentation files (the "Software") to deal with the Software without * restriction, including (without limitation) the rights to use, copy, @@ -28,7 +28,7 @@ * disclaimers in the documentation and/or other materials provided * with the distribution. * - * * Neither the name of University of New South Wales, nor the names of its + * * Neither the name of National ICT Australia, nor the names of its * contributors, may be used to endorse or promote products derived * from this Software without specific prior written permission. * @@ -57,10 +57,10 @@ * DAMAGES OR OTHER LIABILITY. * * If applicable legislation implies representations, warranties, or - * conditions, or imposes obligations or liability on University of New South - * Wales or one of its contributors in respect of the Software that + * conditions, or imposes obligations or liability on National ICT + * Australia or one of its contributors in respect of the Software that * cannot be wholly or partly excluded, restricted or modified, the - * liability of University of New South Wales or the contributor is limited, to + * liability of National ICT Australia or the contributor is limited, to * the full extent permitted by the applicable legislation, at its * option, to: * a. in the case of goods, any one or more of the following: @@ -77,39 +77,16 @@ * by the laws in force in New South Wales, Australia. */ /* - Author: Carl van Schaik + Author: Ben Leslie */ -#include -#include +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; -/* - * copy n bytes from s to d; the regions must not overlap - */ -/* THREAD SAFE */ -void * -memcpy(void *d, const void *s, size_t n) -{ - size_t i; - uintptr_t align = sizeof(uintptr_t)-1; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; - if (((uintptr_t)d & align) || ((uintptr_t)s & align) || (n & align)) - { - char *bs = (char *)s; - char *bd = (char *)d; - - /* XXX - optimize this */ - for (i = 0; i < n; i++) - *bd++ = *bs++; - } - else - { /* memcpy - word aligned */ - uintptr_t *ws = (uintptr_t*)s; - uintptr_t *wd = (uintptr_t*)d; - - n /= sizeof(uintptr_t); - - for (i = 0; i < n; i++) - *wd++ = *ws++; - } - return d; -} +#define __PTR_SIZE 32 diff --git a/conts/libc/src/memcpy.S b/conts/libc/src/memcpy.S new file mode 100644 index 0000000..383f5d2 --- /dev/null +++ b/conts/libc/src/memcpy.S @@ -0,0 +1,60 @@ +/* + * Copyright 2010 B Labs.Ltd. + * + * Author: Prem Mallappa + * + * Description: Optimized memcpy for ARM + * + */ + +#include INC_ARCH(asm.h) +/* +void* +memcpy(void *dst, const void *src, register uint len) +*/ +BEGIN_PROC(memcpy) + push {r0, r4-r11, lr} + loop32: + cmp r2, #32 + blt loop16 + ldmia r1!, {r4 - r11} + stmia r0!, {r4 - r11} + sub r2, r2, #32 + b loop32 + + loop16: + cmp r2, #16 + blt loop8 + ldmia r1!, {r4 - r7} + stmia r0!, {r4 - r7} + sub r2, r2, #16 + b loop16 + + loop8: + cmp r2, #8 + blt loop4 + ldmia r1!, {r4, r5} + stmia r0!, {r4, r5} + sub r2, r2, #8 + b loop8 + + loop4: + cmp r2, #4 + blt end + ldmia r1!, {r4} + stmia r0!, {r4} + sub r2, r2, #4 + b loop4 + end: + last: + teq r2, #0 + ldrgtb r4, [r1] + strneb r4, [r0] // V7 supports strneb , [, +/-] !, with write back + lsrne r4, r4, #8 + subne r2, r2, #1 // Can be reduced to 1 LDR, but has a catch if it is end of memory + addne r0, r0, #1 // we dont want to fetch 1 byte extra to end up in abort + addne r1, r1, #1 // so, playing safe, worst case 3 LDRs + bne last + 1: + pop {r0, r4 - r11, pc} +END_PROC(_memcpy) diff --git a/conts/libc/src/memset.S b/conts/libc/src/memset.S new file mode 100644 index 0000000..ce9b06c --- /dev/null +++ b/conts/libc/src/memset.S @@ -0,0 +1,68 @@ +/* + * Copyright 2010 (C) B Labs. + * Author: Prem Mallappa + * Description: Optimized memset for ARM + */ + +#include INC_ARCH(asm.h) + +/* +void * +memset(void *dst, int c, int len) +*/ +BEGIN_PROC(memset) + stmfd sp!, {r4 - r11, lr} + + and r1, r1, #255 /* c &= 0xff */ + orr r1, r1, lsl #8 /* c |= c<<8 */ + orr r1, r1, lsl #16 /* c |= c<<16 */ + mov r4, r1 + cmp r2, #8 + blt 4f + movge r5, r4 + cmpge r2, #16 + blt 8f + movge r6, r4 + movge r7, r4 + cmpge r2, #32 + blt 16f + movge r8, r4 + movge r9, r4 + movge r10, r4 + movge r11, r4 + 32: + cmp r2, #32 + blt 16f + stmia r0!, {r4 - r11} + sub r2, r2, #32 + b 32b + + 16: + cmp r2, #16 + blt 8f + stmia r0!, {r4 - r7} + sub r2, r2, #16 + b 16b + + 8: + cmp r2, #8 + blt 4f + stmia r0!, {r4, r5} + sub r2, r2, #8 + b 8b + + 4: + cmp r2, #4 + blt end + stmia r0!, {r4} + sub r2, r2, #4 + b 4b + end: + teq r2, #0 + strneb r4, [r0, #0] + subne r2, r2, #1 + addne r0, r0, #1 + bne end + + ldmfd sp!, {r4 - r11, pc} +END_PROC(_memset) diff --git a/conts/libc/src/sys-userspace/arch-arm/sys_fputc.c b/conts/libc/src/sys-userspace/arch-arm/sys_fputc.c index 01580de..4ced173 100644 --- a/conts/libc/src/sys-userspace/arch-arm/sys_fputc.c +++ b/conts/libc/src/sys-userspace/arch-arm/sys_fputc.c @@ -2,19 +2,12 @@ * Ties up platform's uart driver functions with printf * * Copyright (C) 2009 B Labs Ltd. - * */ #include -#include - -extern struct pl011_uart uart; +#include int __fputc(int c, FILE *stream) { - int res; - do { - res = pl011_tx_char(uart.base, c); - } while( res < 0); - - return(0); + uart_tx_char(uart_print_base, c); + return 0; } diff --git a/conts/libc/src/sys-userspace/arch-arm/sys_getc.c b/conts/libc/src/sys-userspace/arch-arm/sys_getc.c new file mode 100644 index 0000000..2428f2f --- /dev/null +++ b/conts/libc/src/sys-userspace/arch-arm/sys_getc.c @@ -0,0 +1,31 @@ +/* + * Library calls for uart rx. + * + * Copyright (C) 2009 B Labs Ltd. + * + */ +#include +#include + +char fgetc(FILE * file) +{ + return uart_rx_char(uart_print_base); +} + +#define MAX_LINE_LEN 256 +char data[MAX_LINE_LEN]; + +char *fgetline(FILE * file) +{ + int index = 0; + + /* + * Line will end if, + * 1. We have recieved 256 chars or + * 2. we recieved EOL: '\n' followed by '\r' + */ + while((data[index] != '\n' && ((data[index++] = fgetc(file)) != '\r')) || + index != MAX_LINE_LEN); + + return data; +} diff --git a/conts/libdev/SConscript b/conts/libdev/SConscript index 1432a6f..13f18d9 100644 --- a/conts/libdev/SConscript +++ b/conts/libdev/SConscript @@ -15,29 +15,32 @@ sys.path.append(PROJRELROOT) from config.configuration import * from config.projpaths import * -Import('env', 'arch', 'platform', 'type') +Import('env', 'platform', 'type') variant = type -# Path for uart files -LIBDEV_UART_PATH = join(PROJROOT, 'conts/libdev/uart') +# To include setbit/clrbit functions +LIBL4_RELDIR = 'conts/libl4' +LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) +LIBL4_INC = join(LIBL4_DIR, 'include') -# Path for timer files -LIBDEV_TIEMR_PATH = join(PROJROOT, 'conts/libdev/timer/sp804') - -# Path for clcd files -LIBDEV_CLCD_PATH = join(PROJROOT, 'conts/libdev/clcd/pl110') +LIBC_RELDIR = 'conts/libc' +LIBC_DIR = join(PROJROOT, LIBC_RELDIR) +LIBC_INC = join(LIBC_DIR, 'include') e = env.Clone() -e.Append(CPPPATH = [LIBDEV_UART_PATH + '/include', LIBDEV_TIEMR_PATH + '/include', - LIBDEV_CLCD_PATH + '/include',], - CCFLAGS = ['-nostdinc', '-DVARIANT_' + variant.upper(), - '-DPLATFORM_' + platform.upper()]) +e.Append(CPPPATH = ['#conts/libdev/include', LIBC_INC, LIBL4_INC], + CCFLAGS = ['-DVARIANT_' + variant.upper()]) -source = Glob('uart/src' + '/*.c') + \ - Glob('timer/sp804/src' + '/*.c') + \ - Glob('clcd/pl110/src' + '/*.c') +objects = [] +objects += SConscript('uart/pl011/SConscript', duplicate=0, \ + exports = {'platform' : platform, 'env' : e}) +objects += SConscript('timer/sp804/SConscript', duplicate=0, \ + exports = {'platform' : platform, 'env' : e}) + +objects += SConscript('uart/omap/SConscript', duplicate=0, \ + exports = {'platform' : platform, 'env' : e}) +objects += SConscript('timer/omap/SConscript', duplicate=0, \ + exports = {'platform' : platform, 'env' : e}) -objects = e.StaticObject(source) library = e.StaticLibrary('libdev-' + variant, objects) - Return('library') diff --git a/conts/libdev/SConstruct b/conts/libdev/SConstruct new file mode 100644 index 0000000..84e2935 --- /dev/null +++ b/conts/libdev/SConstruct @@ -0,0 +1,51 @@ +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- a microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd +# +import os, sys + +PROJRELROOT = '../..' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from config.configuration import * + +config = configuration_retrieve() +gcc_arch_flag = config.gcc_arch_flag +platform = config.platform + +# We assume we are compiling for userspace. +# variant can be specified from cmdline using +# scons variant=xxx +variant = ARGUMENTS.get('variant', 'userspace') +print '\nCompiling for variant: ' + variant + '\n' + +# To include setbit/clrbit functions +LIBL4_RELDIR = 'conts/libl4' +LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) +LIBL4_INC = join(LIBL4_DIR, 'include') + +LIBC_RELDIR = 'conts/libc' +LIBC_DIR = join(PROJROOT, LIBC_RELDIR) +LIBC_INC = join(LIBC_DIR, 'include') + +env = Environment(CC = config.toolchain + 'gcc', + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \ + '-nostdinc', '-Wall', '-DVARIANT_' + variant.upper(), \ + '-march=' + gcc_arch_flag, '-Werror'], + LINKFLAGS = ['-nostdlib'], + ASFLAGS = ['-D__ASSEMBLY__'], + ENV = {'PATH' : os.environ['PATH']}, + CPPPATH = ['#include', LIBC_INC, LIBL4_INC, join(PROJROOT,'include')]) + +objects = [] +objects += SConscript('uart/pl011/SConscript', duplicate=0, \ + exports = {'platform' : platform, 'env' : env}) +objects += SConscript('timer/sp804/SConscript', duplicate=0, \ + exports = {'platform' : platform, 'env' : env}) + +library = env.StaticLibrary('libdev-' + variant, objects) + diff --git a/conts/libdev/include/libdev/io.h b/conts/libdev/include/libdev/io.h new file mode 100644 index 0000000..18427dc --- /dev/null +++ b/conts/libdev/include/libdev/io.h @@ -0,0 +1,12 @@ +/* + * IO functions/macros. + * + * Copyright (C) 2007 Bahadir Balban + */ +#ifndef __LIBDEV_IO_H__ +#define __LIBDEV_IO_H__ + +#define read(address) *((volatile unsigned int *)(address)) +#define write(val, address) *((volatile unsigned int *)(address)) = val + +#endif /* __LIBDEV_IO_H__ */ diff --git a/conts/libdev/include/libdev/timer.h b/conts/libdev/include/libdev/timer.h new file mode 100644 index 0000000..61a4f86 --- /dev/null +++ b/conts/libdev/include/libdev/timer.h @@ -0,0 +1,23 @@ +/* + * Generic timer library API + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#ifndef __LIBDEV_TIMER_H__ +#define __LIBDEV_TIMER_H__ + +/* + * Simple API for the primary timer + * for userspace + */ +void timer_start(unsigned long timer_base); +void timer_load(u32 val, unsigned long timer_base); +u32 timer_read(unsigned long timer_base); +void timer_stop(unsigned long timer_base); +void timer_init_oneshot(unsigned long timer_base); +void timer_init_periodic(unsigned long timer_base); +void timer_init(unsigned long timer_base); + +#endif /* __LIBDEV_TIMER_H__ */ diff --git a/conts/libdev/include/libdev/uart.h b/conts/libdev/include/libdev/uart.h new file mode 100644 index 0000000..5f7db44 --- /dev/null +++ b/conts/libdev/include/libdev/uart.h @@ -0,0 +1,21 @@ +/* + * Generic uart API + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#ifndef __LIBDEV_UART_H__ +#define __LIBDEV_UART_H__ + +void uart_tx_char(unsigned long uart_base, char c); +char uart_rx_char(unsigned long uart_base); +void uart_set_baudrate(unsigned long uart_base, unsigned int val); +void uart_init(unsigned long base); + +/* + * Base of primary uart used for printf + */ +extern unsigned long uart_print_base; + +#endif /* __LIBDEV_UART_H__ */ diff --git a/conts/libdev/timer/omap/SConscript b/conts/libdev/timer/omap/SConscript new file mode 100644 index 0000000..3c107f9 --- /dev/null +++ b/conts/libdev/timer/omap/SConscript @@ -0,0 +1,15 @@ +Import('env', 'platform') + +#Platforms using omap_uart +plat_list = 'beagle' + +# The set of source files associated with this SConscript file. +src_local = [] + +#for plat_supported in plat_list: +#if plat_supported == platform: +if plat_list == platform: + src_local += ['timer.c'] + +obj = env.StaticObject(src_local) +Return('obj') diff --git a/conts/libdev/timer/omap/timer.c b/conts/libdev/timer/omap/timer.c new file mode 100644 index 0000000..c051090 --- /dev/null +++ b/conts/libdev/timer/omap/timer.c @@ -0,0 +1,97 @@ +/* + * omap GP timer driver honoring generic + * timer library API + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ + +#include +#include +#include "timer.h" + +#define OMAP_TIMER_MAT_IT_FLAG (1 << 0) +#define OMAP_TIMER_OVR_IT_FLAG (1 << 1) +#define OMAP_TIMER_TCAR_IT_FLAG (1 << 2) +u32 timer_periodic_intr_status(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TISR); + return (reg & OMAP_TIMER_OVR_IT_FLAG); +} + +#define OMAP_TIMER_SOFT_RESET (1 << 1) +void timer_reset(unsigned long timer_base) +{ + /* Reset Timer */ + write(OMAP_TIMER_SOFT_RESET, timer_base + OMAP_TIMER_TIOCP); + + /* Wait for reset completion */ + while (!read(timer_base + OMAP_TIMER_TSTAT)); +} + +void timer_load(unsigned long timer_base, u32 value) +{ + write(value, timer_base + OMAP_TIMER_TLDR); + write(value, timer_base + OMAP_TIMER_TCRR); +} + +u32 timer_read(unsigned long timer_base) +{ + return read(timer_base + OMAP_TIMER_TCRR); +} + +#define OMAP_TIMER_START (1 << 0) +void timer_start(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TCLR); + reg |= OMAP_TIMER_START; + write(reg, timer_base + OMAP_TIMER_TCLR); +} + +void timer_stop(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TCLR); + reg &= (~OMAP_TIMER_START); + write(reg, timer_base + OMAP_TIMER_TCLR); +} + +void timer_init_periodic(unsigned long timer_base) +{ + volatile u32 reg; + + /* Reset the timer */ + timer_reset(timer_base); + + /* Set timer to autoreload mode */ + reg = read(timer_base + OMAP_TIMER_TCLR); + reg |= (1 << OMAP_TIMER_MODE_AUTORELAOD); + write(reg, timer_base + OMAP_TIMER_TCLR); + + /* + * Beagle Board RevC manual: + * overflow period = (0xffffffff - TLDR + 1)*PS*(1/TIMER_FCLK) + * where, + * PS: Prescaler divisor (we are not using this) + * + * Beagle board manual says, 26MHz oscillator present on board. + * U-Boot divides the sys_clock by 2 if sys_clk is >19MHz, + * so,we have sys_clk frequency = 13MHz + * + * TIMER_FCLK = 13MHz + * So, for 1ms period, TLDR = 0xffffcd38 + * + */ + timer_load(timer_base, 0xffffcd38); + + /* Clear pending Interrupts, if any */ + write(7, timer_base + OMAP_TIMER_TISR); + + /* Enable inteerupts */ + write((1 << OMAP_TIMER_INTR_OVERFLOW), timer_base + OMAP_TIMER_TIER); +} + +void timer_init(unsigned long timer_base) +{ + timer_init_periodic(timer_base); +} diff --git a/conts/libdev/timer/omap/timer.h b/conts/libdev/timer/omap/timer.h new file mode 100644 index 0000000..64fb587 --- /dev/null +++ b/conts/libdev/timer/omap/timer.h @@ -0,0 +1,51 @@ +/* + * OMAP GP Timer offsets + * + * Copyright (C) 2007 Bahadir Balban + * + */ +#ifndef __OMAP_GPTIMER_H__ +#define __OMAP_GPTIMER_H__ + +/* Register offsets */ +#define OMAP_TIMER_TIOCP 0x10 +#define OMAP_TIMER_TSTAT 0x14 +#define OMAP_TIMER_TISR 0x18 +#define OMAP_TIMER_TIER 0x1C +#define OMAP_TIMER_TCLR 0x24 +#define OMAP_TIMER_TCRR 0x28 +#define OMAP_TIMER_TLDR 0x2C +#define OMAP_TIMER_TPIR 0x48 +#define OMAP_TIMER_TNIR 0x4C +#define OMAP_TIMER_TCVR 0x50 + +/* Enable/Disable IRQ */ +#define OMAP_TIMER_IRQENABLE 1 +#define OMAP_TIMER_IRQDISABLE 0 + +/* Timer modes supported */ +#define OMAP_TIMER_MODE_AUTORELAOD 1 +#define OMAP_TIMER_MODE_COMPARE 6 +#define OMAP_TIMER_MODE_CAPTURE 13 + +/* Interrupt types */ +#define OMAP_TIMER_INTR_MATCH 0x0 +#define OMAP_TIMER_INTR_OVERFLOW 0x1 +#define OMAP_TIMER_INTR_CAPTURE 0x2 + +/* Clock source for timer */ +#define OMAP_TIMER_CLKSRC_SYS_CLK 0x1 +#define OMAP_TIMER_CLKSRC_32KHZ_CLK 0x0 + +u32 timer_periodic_intr_status(unsigned long timer_base); +void timer_start(unsigned long base); +void timer_set_mode(unsigned long base, int mode); +void timer_reset(unsigned long timer_base); +void timer_load(unsigned long timer_base, u32 value); +u32 timer_read(unsigned long timer_base); +void timer_start(unsigned long timer_base); +void timer_stop(unsigned long timer_base); +void timer_init_periodic(unsigned long timer_base); +void timer_init(unsigned long timer_base); + +#endif /* __OMAP_GPTIMER_H__*/ diff --git a/conts/libdev/timer/sp804/SConscript b/conts/libdev/timer/sp804/SConscript new file mode 100644 index 0000000..38f5ee9 --- /dev/null +++ b/conts/libdev/timer/sp804/SConscript @@ -0,0 +1,14 @@ +Import('env', 'platform') + +#Platforms using sp804 +plat_list = ('eb', 'pba8', 'pba9', 'pb11mpcore', 'pb926') + +# The set of source files associated with this SConscript file. +src_local = [] + +for plat_supported in plat_list: + if plat_supported == platform: + src_local += Glob('*.c') + +obj = env.StaticObject(src_local) +Return('obj') diff --git a/conts/libdev/timer/sp804/timer.c b/conts/libdev/timer/sp804/timer.c new file mode 100644 index 0000000..9236c65 --- /dev/null +++ b/conts/libdev/timer/sp804/timer.c @@ -0,0 +1,65 @@ +/* + * SP804 primecell driver honoring generic + * timer library API + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include "timer.h" + +/* Enable timer with its current configuration */ +void timer_start(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + SP804_CTRL); + + reg |= SP804_ENABLE; + + write(reg, timer_base + SP804_CTRL); + +} + +/* Load the timer with ticks value */ +void timer_load(u32 loadval, unsigned long timer_base) +{ + write(loadval, timer_base + SP804_LOAD); +} + +u32 timer_read(unsigned long timer_base) +{ + return read(timer_base + SP804_VALUE); +} + +void timer_stop(unsigned long timer_base) +{ + write(0, timer_base + SP804_CTRL); +} + +void timer_init_periodic(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + SP804_CTRL); + + reg |= SP804_PERIODIC | SP804_32BIT | SP804_IRQEN; + + write(reg, timer_base + SP804_CTRL); + + /* 1 tick per usec, 1 irq per msec */ + timer_load(1000, timer_base); +} + +void timer_init_oneshot(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + SP804_CTRL); + + /* One shot, 32 bits, no irqs */ + reg |= SP804_32BIT | SP804_ONESHOT; + + write(reg, timer_base + SP804_CTRL); +} + +void timer_init(unsigned long timer_base) +{ + timer_stop(timer_base); + timer_init_periodic(timer_base); +} diff --git a/conts/libdev/timer/sp804/timer.h b/conts/libdev/timer/sp804/timer.h new file mode 100644 index 0000000..e8c21c0 --- /dev/null +++ b/conts/libdev/timer/sp804/timer.h @@ -0,0 +1,63 @@ +/* + * SP804 Primecell Timer offsets + * + * Copyright (C) 2007 Bahadir Balban + * + */ +#ifndef __SP804_TIMER_H__ +#define __SP804_TIMER_H__ + +#include + +/* Register offsets */ +#define SP804_LOAD 0x0 +#define SP804_VALUE 0x4 +#define SP804_CTRL 0x8 +#define SP804_INTCLR 0xC +#define SP804_RIS 0x10 +#define SP804_MIS 0x14 +#define SP804_BGLOAD 0x18 + +#define SP804_ENABLE (1 << 7) +#define SP804_PERIODIC (1 << 6) +#define SP804_IRQEN (1 << 5) +#define SP804_32BIT (1 << 1) +#define SP804_ONESHOT (1 << 0) + +/* Timer prescaling */ +#define SP804_SCALE_SHIFT 2 +#define SP804_SCALE_DIV16 1 +#define SP804_SCALE_DIV256 2 + +/* Wrapping = 0, Oneshot = 1 */ +#define SP804_ONESHOT (1 << 0) + +static inline __attribute__ ((always_inline)) +void sp804_load(unsigned long timer_base, u32 val) +{ + write(val, timer_base + SP804_LOAD); +} + +static inline __attribute__ ((always_inline)) +void sp804_irq_clear(unsigned long timer_base) +{ + write(1, timer_base + SP804_INTCLR); +} + +static inline __attribute__ ((always_inline)) +void sp804_enable(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + SP804_CTRL); + + write(reg | SP804_ENABLE, timer_base + SP804_CTRL); +} + +void timer_start(unsigned long timer_base); +void timer_load(u32 loadval, unsigned long timer_base); +u32 timer_read(unsigned long timer_base); +void timer_stop(unsigned long timer_base); +void timer_init_periodic(unsigned long timer_base); +void timer_init_oneshot(unsigned long timer_base); +void timer_init(unsigned long timer_base); + +#endif /* __SP804_TIMER_H__ */ diff --git a/conts/libdev/uart/omap/SConscript b/conts/libdev/uart/omap/SConscript new file mode 100644 index 0000000..479c63e --- /dev/null +++ b/conts/libdev/uart/omap/SConscript @@ -0,0 +1,15 @@ +Import('env', 'platform') + +#Platforms using omap_uart +plat_list = 'beagle' + +# The set of source files associated with this SConscript file. +src_local = [] + +#for plat_supported in plat_list: +#if plat_supported == platform: +if plat_list == platform: + src_local += ['uart.c'] + +obj = env.StaticObject(src_local) +Return('obj') diff --git a/conts/libdev/uart/omap/uart.c b/conts/libdev/uart/omap/uart.c new file mode 100644 index 0000000..b8d86fe --- /dev/null +++ b/conts/libdev/uart/omap/uart.c @@ -0,0 +1,115 @@ +/* + * UART driver used by OMAP devices + * + * Copyright (C) 2007 Bahadir Balban + */ + +#include +#include +#include "uart.h" + +#define OMAP_UART_TXFE 0x20 +void uart_tx_char(unsigned long uart_base, char c) +{ + volatile u32 reg; + + /* Check if there is space for tx */ + do { + reg = read(uart_base + OMAP_UART_LSR); + } while(!(reg & OMAP_UART_TXFE)); + + write(c, uart_base + OMAP_UART_THR); +} + +#define OMAP_UART_RXFNE 0x1 +#define OMAP_UART_RX_FIFO_STATUS 0x8 +char uart_rx_char(unsigned long uart_base) +{ + volatile u32 reg; + + /* Check if pending data is there */ + do { + reg = read(uart_base + OMAP_UART_LSR); + } while(!(reg & OMAP_UART_RXFNE)); + +#if 0 + /* Check if there is some error in recieve */ + if(reg & OMAP_UART_RX_FIFO_STATUS) + return -1; +#endif + return (char)read(uart_base + OMAP_UART_RHR); + +} + +void uart_set_baudrate(unsigned long uart_base, u32 baudrate) +{ + u32 clk_div; + + /* 48Mhz clock fixed on beagleboard */ + const u32 clkrate = 48000000; + + /* If baud out of range, set default rate */ + if(baudrate > 3686400 || baudrate < 300) + baudrate = 115200; + + clk_div = clkrate/(16 * baudrate); + + /* Set clockrate in DLH and DLL */ + write((clk_div & 0xff), uart_base + OMAP_UART_DLL); + write(((clk_div >> 8) & 0xff ), uart_base + OMAP_UART_DLH); +} + +void uart_init(unsigned long uart_base) +{ + /* Disable UART */ + uart_select_mode(uart_base, OMAP_UART_MODE_DEFAULT); + + /* Disable interrupts */ + uart_disable_interrupt(uart_base); + + /* Change to config mode, to set baud divisor */ + uart_set_link_control(uart_base, OMAP_UART_BANKED_MODE_CONFIG_A); + + /* Set the baud rate */ + uart_set_baudrate(uart_base, 115200); + + /* Switch to operational mode */ + uart_set_link_control(uart_base, OMAP_UART_BANKED_MODE_OPERATIONAL); + + /* Set up the link- parity, data bits stop bits to 8N1 */ + uart_disable_parity(uart_base); + uart_set_data_bits(uart_base, OMAP_UART_DATA_BITS_8); + uart_set_stop_bits(uart_base, OMAP_UART_STOP_BITS_1); + + /* Disable Fifos */ + uart_disable_fifo(uart_base); + + /* Enable modem Rx/Tx */ + uart_enable_tx(uart_base); + uart_enable_rx(uart_base); + + /* Enable UART in 16x mode */ + uart_select_mode(uart_base, OMAP_UART_MODE_UART16X); +} + +unsigned long uart_print_base; + +void platform_init(void) +{ + uart_print_base = OMAP_UART_BASE; + + /* + * We dont need to initialize uart here for variant-userspace, + * as this is the same uart as used by kernel and hence + * already initialized, we just need + * a uart struct instance with proper base address. + * + * But in case of baremetal like loader, no one has done + * initialization, so we need to do it. + */ +#if defined(VARIANT_BAREMETAL) + uart_init(uart_print_base); +#endif +} + + diff --git a/conts/libdev/uart/omap/uart.h b/conts/libdev/uart/omap/uart.h new file mode 100644 index 0000000..19a5081 --- /dev/null +++ b/conts/libdev/uart/omap/uart.h @@ -0,0 +1,195 @@ +/* + * OMAP UART Generic driver implementation. + * + * Copyright (C) 2007 Bahadir Balban + * + * The particular intention of this code is that it has been carefully written + * as decoupled from os-specific code and in a verbose way such that it clearly + * demonstrates how the device operates, reducing the amount of time to be spent + * for understanding the operational model and implementing a driver from + * scratch. This is the very first to be such a driver so far, hopefully it will + * turn out to be useful. + */ + +#ifndef __OMAP_UART_H__ +#define __OMAP_UART_H__ + +#include /* To get PLATFORM */ +#include + +#if defined(VARIANT_USERSPACE) +/* FIXME: Take this value in agreement from kernel, or from kernel only */ +#include +#include INC_ARCH(io.h) +#define OMAP_UART_BASE USERSPACE_CONSOLE_VBASE +#endif + +#if defined(VARIANT_BAREMETAL) +#if defined(CONFIG_PLATFORM_BEAGLE) +#define OMAP_UART_BASE 0x49020000 +#endif +#endif + +/* Register offsets */ +#define OMAP_UART_DLL 0x00 +#define OMAP_UART_THR 0x00 +#define OMAP_UART_RHR 0x00 +#define OMAP_UART_DLH 0x04 +#define OMAP_UART_IER 0x04 +#define OMAP_UART_FCR 0x08 +#define OMAP_UART_MCR 0x10 +#define OMAP_UART_LSR 0x14 +#define OMAP_UART_MDR1 0x20 +#define OMAP_UART_LCR 0x0C + +/* Modes supported by OMAP UART/IRDA/CIR IP */ +#define OMAP_UART_MODE_UART16X 0x0 +#define OMAP_UART_MODE_SIR 0x1 +#define OMAP_UART_MODE_UART16X_AUTO_BAUD 0x2 +#define OMAP_UART_MODE_UART13X 0x3 +#define OMAP_UART_MODE_MIR 0x4 +#define OMAP_UART_MODE_FIR 0x5 +#define OMAP_UART_MODE_CIR 0x6 +#define OMAP_UART_MODE_DEFAULT 0x7 /* Disable */ + +/* Number of data bits for UART */ +#define OMAP_UART_DATA_BITS_5 0x0 +#define OMAP_UART_DATA_BITS_6 0x1 +#define OMAP_UART_DATA_BITS_7 0x2 +#define OMAP_UART_DATA_BITS_8 0x3 + +/* Stop bits to be used for UART data */ +#define OMAP_UART_STOP_BITS_1 0x0 +#define OMAP_UART_STOP_BITS_1_5 0x1 + +/* Banked Register modes- ConfigA, ConfigB, Operational */ +#define OMAP_UART_BANKED_MODE_OPERATIONAL 0x00 +#define OMAP_UART_BANKED_MODE_CONFIG_A 0x80 +#define OMAP_UART_BANKED_MODE_CONFIG_B 0xBF + +void uart_tx_char(unsigned long uart_base, char c); +char uart_rx_char(unsigned long uart_base); +void uart_set_baudrate(unsigned long uart_base, u32 baudrate); +void uart_init(unsigned long uart_base); + + +#define OMAP_UART_FIFO_ENABLE (1 << 0) +#define OMAP_UART_RX_FIFO_CLR (1 << 1) +#define OMAP_UART_TX_FIFO_CLR (1 << 2) +static inline void uart_enable_fifo(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_FCR); + reg |= (OMAP_UART_FIFO_ENABLE | OMAP_UART_RX_FIFO_CLR | + OMAP_UART_TX_FIFO_CLR); + write(reg, uart_base + OMAP_UART_FCR); +} + +static inline void uart_disable_fifo(unsigned long uart_base) +{ + volatile u32 reg= read(uart_base + OMAP_UART_FCR); + reg &= (~OMAP_UART_FIFO_ENABLE | OMAP_UART_RX_FIFO_CLR | + OMAP_UART_TX_FIFO_CLR); + write(reg, uart_base + OMAP_UART_FCR); +} + +#define OMAP_UART_TX_ENABLE (1 << 0) +static inline void uart_enable_tx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg |= OMAP_UART_TX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); +} + +static inline void uart_disable_tx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg &= ~OMAP_UART_TX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); + +} + +#define OMAP_UART_RX_ENABLE (1 << 1) +static inline void uart_enable_rx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg |= OMAP_UART_RX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); +} + +static inline void uart_disable_rx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg &= ~OMAP_UART_RX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); +} + +#define OMAP_UART_STOP_BITS_MASK (1 << 2) +static inline void uart_set_stop_bits(unsigned long uart_base, int bits) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_STOP_BITS_MASK; + reg |= (bits << 2); + write(reg, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_DATA_BITS_MASK (0x3) +static inline void uart_set_data_bits(unsigned long uart_base, int bits) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_DATA_BITS_MASK; + reg |= bits; + write(reg, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_PARITY_ENABLE (1 << 3) +static inline void uart_enable_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg |= OMAP_UART_PARITY_ENABLE; + write(reg, uart_base + OMAP_UART_LCR); +} + +static inline void uart_disable_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_PARITY_ENABLE; + write(reg, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_PARITY_EVEN (1 << 4) +static inline void uart_set_even_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg |= OMAP_UART_PARITY_EVEN; + write(reg, uart_base + OMAP_UART_LCR); +} + +static inline void uart_set_odd_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_PARITY_EVEN; + write(reg, uart_base + OMAP_UART_LCR); +} + +static inline void uart_select_mode(unsigned long uart_base, int mode) +{ + write(mode, uart_base + OMAP_UART_MDR1); +} + +#define OMAP_UART_INTR_EN 1 +static inline void uart_enable_interrupt(unsigned long uart_base) +{ + write(OMAP_UART_INTR_EN, uart_base + OMAP_UART_IER); +} + +static inline void uart_disable_interrupt(unsigned long uart_base) +{ + write((~OMAP_UART_INTR_EN), uart_base + OMAP_UART_IER); +} + +static inline void uart_set_link_control(unsigned long uart_base, int mode) +{ + write(mode, uart_base + OMAP_UART_LCR); +} + +#endif /* __OMAP_UART_H__ */ diff --git a/conts/libdev/uart/pl011/SConscript b/conts/libdev/uart/pl011/SConscript new file mode 100644 index 0000000..ad9de61 --- /dev/null +++ b/conts/libdev/uart/pl011/SConscript @@ -0,0 +1,14 @@ +Import('env', 'platform') + +#Platforms using pl011 +plat_list = ('eb', 'pba8', 'pba9', 'pb11mpcore', 'pb926') + +# The set of source files associated with this SConscript file. +src_local = [] + +for plat_supported in plat_list: + if plat_supported == platform: + src_local += Glob('*.c') + +obj = env.StaticObject(src_local) +Return('obj') diff --git a/conts/libdev/uart/pl011/uart.c b/conts/libdev/uart/pl011/uart.c new file mode 100644 index 0000000..01f6ac9 --- /dev/null +++ b/conts/libdev/uart/pl011/uart.c @@ -0,0 +1,127 @@ +/* + * PL011 UART driver + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include "uart.h" + +/* Error status bits in receive status register */ +#define PL011_FE (1 << 0) +#define PL011_PE (1 << 1) +#define PL011_BE (1 << 2) +#define PL011_OE (1 << 3) + +/* Status bits in flag register */ +#define PL011_TXFE (1 << 7) +#define PL011_RXFF (1 << 6) +#define PL011_TXFF (1 << 5) +#define PL011_RXFE (1 << 4) +#define PL011_BUSY (1 << 3) +#define PL011_DCD (1 << 2) +#define PL011_DSR (1 << 1) +#define PL011_CTS (1 << 0) + +void uart_tx_char(unsigned long base, char c) +{ + unsigned int val = 0; + + do { + val = read((base + PL011_UARTFR)); + } while (val & PL011_TXFF); /* TX FIFO FULL */ + + write(c, (base + PL011_UARTDR)); +} + +char uart_rx_char(unsigned long base) +{ + unsigned int val = 0; + + do { + val = read(base + PL011_UARTFR); + } while (val & PL011_RXFE); /* RX FIFO Empty */ + + return (char)read((base + PL011_UARTDR)); +} + +/* + * Sets the baud rate in kbps. It is recommended to use + * standard rates such as: 1200, 2400, 3600, 4800, 7200, + * 9600, 14400, 19200, 28800, 38400, 57600 76800, 115200. + */ +void pl011_set_baudrate(unsigned long base, unsigned int baud, + unsigned int clkrate) +{ + const unsigned int uartclk = 24000000; /* 24Mhz clock fixed on pb926 */ + unsigned int val = 0, ipart = 0, fpart = 0; + + /* Use default pb926 rate if no rate is supplied */ + if (clkrate == 0) + clkrate = uartclk; + if (baud > 115200 || baud < 1200) + baud = 38400; /* Default rate. */ + + /* 24000000 / (38400 * 16) */ + ipart = 39; + + write(ipart, base + PL011_UARTIBRD); + write(fpart, base + PL011_UARTFBRD); + + /* + * For the IBAUD and FBAUD to update, we need to + * write to UARTLCR_H because the 3 registers are + * actually part of a single register in hardware + * which only updates by a write to UARTLCR_H + */ + val = read(base + PL011_UARTLCR_H); + write(val, base + PL011_UARTLCR_H); + +} + +void uart_init(unsigned long uart_base) +{ + /* Initialise data register for 8 bit data read/writes */ + pl011_set_word_width(uart_base, 8); + + /* + * Fifos are disabled because by default it is assumed the port + * will be used as a user terminal, and in that case the typed + * characters will only show up when fifos are flushed, rather than + * when each character is typed. We avoid this by not using fifos. + */ + pl011_disable_fifos(uart_base); + + /* Set default baud rate of 38400 */ + pl011_set_baudrate(uart_base, 38400, 24000000); + + /* Set default settings of 1 stop bit, no parity, no hw flow ctrl */ + pl011_set_stopbits(uart_base, 1); + pl011_parity_disable(uart_base); + + /* Enable rx, tx, and uart chip */ + pl011_tx_enable(uart_base); + pl011_rx_enable(uart_base); + pl011_uart_enable(uart_base); +} + +unsigned long uart_print_base; + +void platform_init(void) +{ + uart_print_base = PL011_BASE; + + /* + * We dont need to initialize uart here for variant-userspace, + * as this is the same uart as used by kernel and hence + * already initialized, we just need + * a uart struct instance with proper base address. + * + * But in case of baremetal like loader, no one has done + * initialization, so we need to do it. + */ +#if defined(VARIANT_BAREMETAL) + uart_init(uart_print_base); +#endif +} + diff --git a/conts/libdev/uart/pl011/uart.h b/conts/libdev/uart/pl011/uart.h new file mode 100644 index 0000000..077be0d --- /dev/null +++ b/conts/libdev/uart/pl011/uart.h @@ -0,0 +1,252 @@ +/* + * PL011 UART Generic driver implementation. + * Copyright Bahadir Balban (C) 2009 + */ +#ifndef __PL011_H__ +#define __PL011_H__ + +#include /* To get PLATFORM */ +#include + +#if defined(VARIANT_USERSPACE) +/* FIXME: Take this value in agreement from kernel, or from kernel only */ +#include +#include INC_ARCH(io.h) +#define PL011_BASE USERSPACE_CONSOLE_VBASE +#endif + +#if defined(VARIANT_BAREMETAL) +#if defined(CONFIG_PLATFORM_PB926) +#define PL011_BASE 0x101F1000 +#elif defined(CONFIG_PLATFORM_EB) || defined(CONFIG_PLATFORM_PB11MPCORE) +#define PL011_BASE 0x10009000 +#elif defined(CONFIG_PLATFORM_PBA9) || defined(CONFIG_PLATFORM_PBA8) +#define PL011_BASE 0x10009000 +#endif +#endif + +/* Register offsets */ +#define PL011_UARTDR 0x00 +#define PL011_UARTRSR 0x04 +#define PL011_UARTECR 0x04 +#define PL011_UARTFR 0x18 +#define PL011_UARTILPR 0x20 +#define PL011_UARTIBRD 0x24 +#define PL011_UARTFBRD 0x28 +#define PL011_UARTLCR_H 0x2C +#define PL011_UARTCR 0x30 +#define PL011_UARTIFLS 0x34 +#define PL011_UARTIMSC 0x38 +#define PL011_UARTRIS 0x3C +#define PL011_UARTMIS 0x40 +#define PL011_UARTICR 0x44 +#define PL011_UARTDMACR 0x48 + +/* IRQ bits for each uart irq event */ +#define PL011_RXIRQ (1 << 4) +#define PL011_TXIRQ (1 << 5) +#define PL011_RXTIMEOUTIRQ (1 << 6) +#define PL011_FEIRQ (1 << 7) +#define PL011_PEIRQ (1 << 8) +#define PL011_BEIRQ (1 << 9) +#define PL011_OEIRQ (1 << 10) + + +void pl011_set_baudrate(unsigned long base, unsigned int baud, + unsigned int clkrate); + +#define PL011_UARTEN (1 << 0) +static inline void pl011_uart_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val |= PL011_UARTEN; + write(val, (base + PL011_UARTCR)); + + return; +} + +static inline void pl011_uart_disable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val &= ~PL011_UARTEN; + write(val, (base + PL011_UARTCR)); + + return; +} + +#define PL011_TXE (1 << 8) +static inline void pl011_tx_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val |= PL011_TXE; + write(val, (base + PL011_UARTCR)); + return; +} + +static inline void pl011_tx_disable(unsigned long base) +{ + unsigned int val = 0; + + val =read((base + PL011_UARTCR)); + val &= ~PL011_TXE; + write(val, (base + PL011_UARTCR)); + return; +} + +#define PL011_RXE (1 << 9) +static inline void pl011_rx_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val |= PL011_RXE; + write(val, (base + PL011_UARTCR)); + return; +} + +static inline void pl011_rx_disable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val &= ~PL011_RXE; + write(val, (base + PL011_UARTCR)); + return; +} + +#define PL011_TWO_STOPBITS_SELECT (1 << 3) +static inline void pl011_set_stopbits(unsigned long base, int stopbits) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + + if(stopbits == 2) { /* Set to two bits */ + val |= PL011_TWO_STOPBITS_SELECT; + } else { /* Default is 1 */ + val &= ~PL011_TWO_STOPBITS_SELECT; + } + write(val, (base + PL011_UARTLCR_H)); + return; +} + +#define PL011_PARITY_ENABLE (1 << 1) +static inline void pl011_parity_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base +PL011_UARTLCR_H)); + val |= PL011_PARITY_ENABLE; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +static inline void pl011_parity_disable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val &= ~PL011_PARITY_ENABLE; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +#define PL011_PARITY_EVEN (1 << 2) +static inline void pl011_set_parity_even(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val |= PL011_PARITY_EVEN; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +static inline void pl011_set_parity_odd(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val &= ~PL011_PARITY_EVEN; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +#define PL011_ENABLE_FIFOS (1 << 4) +static inline void pl011_enable_fifos(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val |= PL011_ENABLE_FIFOS; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +static inline void pl011_disable_fifos(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val &= ~PL011_ENABLE_FIFOS; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +/* Sets the transfer word width for the data register. */ +static inline void pl011_set_word_width(unsigned long base, int size) +{ + unsigned int val = 0; + if(size < 5 || size > 8) /* Default is 8 */ + size = 8; + + /* Clear size field */ + val = read((base + PL011_UARTLCR_H)); + val &= ~(0x3 << 5); + write(val, (base + PL011_UARTLCR_H)); + + /* + * The formula is to write 5 less of size given: + * 11 = 8 bits + * 10 = 7 bits + * 01 = 6 bits + * 00 = 5 bits + */ + val = read((base + PL011_UARTLCR_H)); + val |= (size - 5) << 5; + write(val, (base + PL011_UARTLCR_H)); + + return; +} + +/* + * Defines at which level of fifo fullness an irq will be generated. + * @xfer: tx fifo = 0, rx fifo = 1 + * @level: Generate irq if: + * 0 rxfifo >= 1/8 full txfifo <= 1/8 full + * 1 rxfifo >= 1/4 full txfifo <= 1/4 full + * 2 rxfifo >= 1/2 full txfifo <= 1/2 full + * 3 rxfifo >= 3/4 full txfifo <= 3/4 full + * 4 rxfifo >= 7/8 full txfifo <= 7/8 full + * 5-7 reserved reserved + */ +static inline void pl011_set_irq_fifolevel(unsigned long base, \ + unsigned int xfer, unsigned int level) +{ + if(xfer != 1 && xfer != 0) /* Invalid fifo */ + return; + if(level > 4) /* Invalid level */ + return; + + write(level << (xfer * 3), (base + PL011_UARTIFLS)); + return; +} + +#endif /* __PL011__UART__ */ + diff --git a/conts/libl4/SConscript b/conts/libl4/SConscript index 162b657..0adfb6b 100644 --- a/conts/libl4/SConscript +++ b/conts/libl4/SConscript @@ -26,36 +26,36 @@ sys.path.append(PROJRELROOT) from config.projpaths import * from configure import * -Import('arch') +Import('env', 'arch', 'subarch') config = configuration_retrieve() LIBMEM_RELDIR = 'conts/libmem' LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) -env = Environment(CC = config.user_toolchain + 'gcc', - CCFLAGS = ['-g', '-std=gnu99', '-nostdlib', '-ffreestanding'], - LINKFLAGS = ['-nostdlib'], - ASFLAGS = ['-D__ASSEMBLY__'], - ENV = {'PATH' : os.environ['PATH']}, - LIBS = 'gcc', - CPPPATH = ['include', 'include/l4lib/arch', join(PROJROOT, 'include') ]) +e = env.Clone() +e.Append(CPPPATH = ['include', 'include/l4lib/arch', + LIBMEM_DIR], + CPPFLAGS = ' -include l4lib/macros.h ') -env.Append(CPPPATH = [LIBMEM_DIR]) +#Do we need to remove CPPFLAGS coming from top level env? -def create_symlinks(arch): - print os.getcwd() - prefix = 'conts/libl4/include/l4lib' - symlink = join(prefix, 'arch') - reallink = join(prefix, 'arch-' + arch) +# Use os.path.walk(dirname, glob_by_walk, ['*.[cS]', filelist]) +# To collect all files in the tree. - if not os.path.exists(symlink): - cmd = "ln -s %s %s" % (reallink, symlink) - print cmd - os.system(cmd) +def glob_by_walk(arg, dirname, names): + ext, imglist = arg + files = glob.glob(join(dirname, ext)) + imglist.extend(files) -#create_symlinks(arch) -objects = env.StaticObject(Glob('src/*.c') + Glob('src/thread/*.c') + Glob('src/' + arch + '/*.[cS]')) -library = env.StaticLibrary('l4', objects) +objects = e.StaticObject(Glob('src/*.c') + \ + Glob('src/lib/*.c') + \ + Glob('src/lib/cap/*.c')) + \ + Glob('src/lib/thread/*.c') + \ + Glob('src/arch/' + arch + '/exregs.c') + \ + Glob('src/arch/' + arch + '/*.S') + \ + Glob('src/arch/' + arch + '/' + subarch + '/*.[cS]') + +library = e.StaticLibrary('l4', objects) Return('library') diff --git a/conts/libl4/SConstruct b/conts/libl4/SConstruct index 63f360f..191b007 100644 --- a/conts/libl4/SConstruct +++ b/conts/libl4/SConstruct @@ -14,23 +14,35 @@ from config.projpaths import * from config.configuration import * config = configuration_retrieve() +gcc_arch_flag = config.gcc_arch_flag arch = config.arch +subarch = config.subarch LIBMEM_RELDIR = 'conts/libmem' LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) -env = Environment(CC = config.user_toolchain + 'gcc', - CCFLAGS = ['-std=gnu99', '-g', '-nostdlib', '-ffreestanding', '-Werror'], +LIBC_RELDIR = 'conts/libc' +LIBC_DIR = join(PROJROOT, LIBC_RELDIR) +LIBC_INC = join(LIBC_DIR, 'include') + +env = Environment(CC = config.toolchain + 'gcc', + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \ + '-nostdinc', '-Wall', '-Werror', '-march=' + gcc_arch_flag], LINKFLAGS = ['-nostdlib'], ASFLAGS = ['-D__ASSEMBLY__'], ENV = {'PATH' : os.environ['PATH']}, - LIBS = 'gcc', - CPPPATH = ['#include', '#include/l4lib/arch', join(PROJROOT,'include'), \ - LIBMEM_DIR]) + CPPPATH = ['include', 'include/l4lib/arch', LIBC_INC, \ + join(PROJROOT,'include'), LIBMEM_DIR], + CPPFLAGS = ' -include l4lib/macros.h ') + +objects = env.StaticObject(Glob('src/*.c') + \ + Glob('src/lib/*.c') + \ + Glob('src/arch/' + arch + '/exregs.c') + \ + Glob('src/arch/' + arch + '/*.[cS]') + \ + Glob('src/arch/' + arch + '/' + subarch + '/*.[cS]') + \ + Glob('src/lib/cap/*.c')) + \ + Glob('src/lib/thread/*.c') -# TODO: There are errors in this code that -Werror gives problems with. -objects = env.StaticObject(Glob('src/*.c') + Glob('src/thread/*.c') + Glob('src/' + arch + '/*.[cS]')) library = env.StaticLibrary('l4', objects) -#Return('library') diff --git a/conts/libl4/include/l4lib/arch-arm/irq.h b/conts/libl4/include/l4lib/arch-arm/irq.h new file mode 100644 index 0000000..d0de913 --- /dev/null +++ b/conts/libl4/include/l4lib/arch-arm/irq.h @@ -0,0 +1,11 @@ +#ifndef __L4LIB_ARCH_IRQ_H__ +#define __L4LIB_ARCH_IRQ_H__ + +/* + * Destructive atomic-read. + * + * Write 0 to byte at @location as its contents are read back. + */ +char l4_atomic_dest_readb(void *location); + +#endif diff --git a/conts/libl4/include/l4lib/arch/arm/asm.h b/conts/libl4/include/l4lib/arch/arm/asm.h new file mode 100644 index 0000000..430b9ed --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/asm.h @@ -0,0 +1,15 @@ +#ifndef __ARM_ASM_H__ +#define __ARM_ASM_H__ + +#define BEGIN_PROC(name) \ + .global name; \ + .type name,function; \ + .align; \ +name: + +#define END_PROC(name) \ +.fend_##name: \ + .size name,.fend_##name - name; + +#endif /* __ARM_ASM_H__ */ + diff --git a/conts/libl4/include/l4lib/arch/arm/irq.h b/conts/libl4/include/l4lib/arch/arm/irq.h new file mode 100644 index 0000000..d0de913 --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/irq.h @@ -0,0 +1,11 @@ +#ifndef __L4LIB_ARCH_IRQ_H__ +#define __L4LIB_ARCH_IRQ_H__ + +/* + * Destructive atomic-read. + * + * Write 0 to byte at @location as its contents are read back. + */ +char l4_atomic_dest_readb(void *location); + +#endif diff --git a/conts/libl4/include/l4lib/arch/arm/syscalls.h b/conts/libl4/include/l4lib/arch/arm/syscalls.h new file mode 100644 index 0000000..be1e4a8 --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/syscalls.h @@ -0,0 +1,95 @@ +/* + * System call prototypes. + * + * Copyright (C) 2007 Bahadir Balban + */ +#ifndef __ARM_SYSCALLS_H__ +#define __ARM_SYSCALLS_H__ + + +#include L4LIB_INC_ARCH(types.h) +#include L4LIB_INC_ARCH(utcb.h) +#include +#include +#include +#include +#include + +struct task_ids { + l4id_t tid; + l4id_t spid; + l4id_t tgid; +}; + +static inline void * +l4_kernel_interface(unsigned int *api_version, unsigned int *api_flags, + unsigned int *kernel_id) +{ + return (void *)L4_KIP_ADDRESS; +} + +typedef unsigned int (*__l4_thread_switch_t)(u32); +extern __l4_thread_switch_t __l4_thread_switch; +unsigned int l4_thread_switch (u32 dest); + +typedef int (*__l4_getid_t)(struct task_ids *ids); +extern __l4_getid_t __l4_getid; +int l4_getid(struct task_ids *ids); + +typedef int (*__l4_ipc_t)(l4id_t to, l4id_t from, u32 flags); +extern __l4_ipc_t __l4_ipc; +int l4_ipc(l4id_t to, l4id_t from, u32 flags); + +typedef int (*__l4_capability_control_t)(unsigned int req, unsigned int flags, void *buf); +extern __l4_capability_control_t __l4_capability_control; +int l4_capability_control(unsigned int req, unsigned int flags, void *buf); + +typedef int (*__l4_map_t)(void *phys, void *virt, + u32 npages, u32 flags, l4id_t tid); +extern __l4_map_t __l4_map; +int l4_map(void *p, void *v, u32 npages, u32 flags, l4id_t tid); + +typedef int (*__l4_unmap_t)(void *virt, unsigned long npages, l4id_t tid); +extern __l4_unmap_t __l4_unmap; +int l4_unmap(void *virtual, unsigned long numpages, l4id_t tid); + +typedef int (*__l4_thread_control_t)(unsigned int action, struct task_ids *ids); +extern __l4_thread_control_t __l4_thread_control; +int l4_thread_control(unsigned int action, struct task_ids *ids); + +typedef int (*__l4_irq_control_t)(unsigned int req, unsigned int flags, l4id_t id); +extern __l4_irq_control_t __l4_irq_control; +int l4_irq_control(unsigned int req, unsigned int flags, l4id_t id); + +typedef int (*__l4_ipc_control_t)(unsigned int action, l4id_t blocked_sender, + u32 blocked_tag); +extern __l4_ipc_control_t __l4_ipc_control; +int l4_ipc_control(unsigned int, l4id_t blocked_sender, u32 blocked_tag); + +typedef int (*__l4_exchange_registers_t)(void *exregs_struct, l4id_t tid); +extern __l4_exchange_registers_t __l4_exchange_registers; +int l4_exchange_registers(void *exregs_struct, l4id_t tid); + +typedef int (*__l4_container_control_t)(unsigned int req, unsigned int flags, void *buf); +extern __l4_container_control_t __l4_container_control; +int l4_container_control(unsigned int req, unsigned int flags, void *buf); + +typedef int (*__l4_time_t)(void *timeval, int set); +extern __l4_time_t __l4_time; +int l4_time(void *timeval, int set); + +typedef int (*__l4_mutex_control_t)(void *mutex_word, int op); +extern __l4_mutex_control_t __l4_mutex_control; +int l4_mutex_control(void *mutex_word, int op); + +typedef int (*__l4_cache_control_t)(void *start, void *end, unsigned int flags); +extern __l4_cache_control_t __l4_cache_control; +int l4_cache_control(void *start, void *end, unsigned int flags); + +/* To be supplied by server tasks. */ +void *virt_to_phys(void *); +void *phys_to_virt(void *); + + +#endif /* __ARM_SYSCALLS_H__ */ + diff --git a/conts/libl4/include/l4lib/arch/arm/syslib.h b/conts/libl4/include/l4lib/arch/arm/syslib.h new file mode 100644 index 0000000..fbd82a1 --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/syslib.h @@ -0,0 +1,366 @@ +/* + * Helper functions that wrap raw l4 syscalls. + * + * Copyright (C) 2007-2009 Bahadir Bilgehan Balban + */ + +#ifndef __L4LIB_SYSLIB_H__ +#define __L4LIB_SYSLIB_H__ + +#include +#include +#include L4LIB_INC_ARCH(syscalls.h) + +/* + * NOTE: + * Its best to use these wrappers because they generalise the way + * common ipc data like sender id, error, ipc tag are passed + * between ipc parties. + * + * The arguments to l4_ipc() are used by the microkernel to initiate + * the ipc. Any data passed in message registers may or may not be + * a duplicate of this data, but the distinction is that anything + * that is passed via the mrs are meant to be used by the other party + * participating in the ipc. + */ + +/* For system call arguments */ +#define L4SYS_ARG0 (MR_UNUSED_START) +#define L4SYS_ARG1 (MR_UNUSED_START + 1) +#define L4SYS_ARG2 (MR_UNUSED_START + 2) +#define L4SYS_ARG3 (MR_UNUSED_START + 3) + + +#define L4_IPC_TAG_MASK 0x00000FFF + + +/* + * Servers get sender. + */ +static inline l4id_t l4_get_sender(void) +{ + return (l4id_t)read_mr(MR_SENDER); +} + +/* + * When doing an ipc the sender never has to be explicitly set in + * the utcb via this function since this information is found out + * by the microkernel by checking the system caller's id. This is + * only used for restoring the sender on the utcb in order to + * complete an earlier ipc. + */ +static inline void l4_set_sender(l4id_t sender) +{ + write_mr(MR_SENDER, sender); +} + +static inline unsigned int l4_set_ipc_size(unsigned int word, unsigned int size) +{ + word &= ~L4_IPC_FLAGS_SIZE_MASK; + word |= ((size << L4_IPC_FLAGS_SIZE_SHIFT) & L4_IPC_FLAGS_SIZE_MASK); + return word; +} + +static inline unsigned int l4_get_ipc_size(unsigned int word) +{ + return (word & L4_IPC_FLAGS_SIZE_MASK) >> L4_IPC_FLAGS_SIZE_SHIFT; +} + +static inline unsigned int l4_set_ipc_msg_index(unsigned int word, unsigned int index) +{ + /* FIXME: Define MR_PRIMARY_TOTAL, MR_TOTAL etc. and use MR_TOTAL HERE! */ + BUG_ON(index > UTCB_SIZE); + + word &= ~L4_IPC_FLAGS_MSG_INDEX_MASK; + word |= (index << L4_IPC_FLAGS_MSG_INDEX_SHIFT) & + L4_IPC_FLAGS_MSG_INDEX_MASK; + return word; +} + +static inline unsigned int l4_get_ipc_msg_index(unsigned int word) +{ + return (word & L4_IPC_FLAGS_MSG_INDEX_MASK) + >> L4_IPC_FLAGS_MSG_INDEX_SHIFT; +} + +static inline unsigned int l4_set_ipc_flags(unsigned int word, unsigned int flags) +{ + word &= ~L4_IPC_FLAGS_TYPE_MASK; + word |= flags & L4_IPC_FLAGS_TYPE_MASK; + return word; +} + +static inline unsigned int l4_get_ipc_flags(unsigned int word) +{ + return word & L4_IPC_FLAGS_TYPE_MASK; +} + +static inline unsigned int l4_get_tag(void) +{ + return read_mr(MR_TAG) & L4_IPC_TAG_MASK; +} + +static inline void l4_set_tag(unsigned int tag) +{ + unsigned int tag_flags = read_mr(MR_TAG); + + tag_flags &= ~L4_IPC_TAG_MASK; + tag_flags |= tag & L4_IPC_TAG_MASK; + + write_mr(MR_TAG, tag_flags); +} + +/* Servers: + * Sets the message register for returning errors back to client task. + * These are usually posix error codes. + */ +static inline void l4_set_retval(int retval) +{ + write_mr(MR_RETURN, retval); +} + +/* Clients: + * Learn result of request. + */ +static inline int l4_get_retval(void) +{ + return read_mr(MR_RETURN); +} + +/* + * This is useful for stacked IPC. A stacked IPC happens + * when a new IPC is initiated before concluding the current + * one. + * + * This saves the last ipc's parameters such as the sender + * and tag information. Any previously saved data in save + * slots are destroyed. This is fine as IPC stacking is only + * useful if done once. + */ +static inline void l4_save_ipcregs(void) +{ + l4_get_utcb()->saved_sender = l4_get_sender(); + l4_get_utcb()->saved_tag = l4_get_tag(); +} + +static inline void l4_restore_ipcregs(void) +{ + l4_set_tag(l4_get_utcb()->saved_tag); + l4_set_sender(l4_get_utcb()->saved_sender); +} + +#define TASK_CID_MASK 0xFF000000 +#define TASK_ID_MASK 0x00FFFFFF +#define TASK_CID_SHIFT 24 + +static inline l4id_t __raw_tid(l4id_t tid) +{ + return tid & TASK_ID_MASK; +} + +static inline l4id_t __cid(l4id_t tid) +{ + return (tid & TASK_CID_MASK) >> TASK_CID_SHIFT; +} + +static inline l4id_t self_tid(void) +{ + struct task_ids ids; + + l4_getid(&ids); + return ids.tid; +} + +static inline l4id_t __raw_self_tid(void) +{ + return __raw_tid(self_tid()); +} + +static inline int l4_send_full(l4id_t to, unsigned int tag) +{ + l4_set_tag(tag); + return l4_ipc(to, L4_NILTHREAD, L4_IPC_FLAGS_FULL); +} + +static inline int l4_receive_full(l4id_t from) +{ + return l4_ipc(L4_NILTHREAD, from, L4_IPC_FLAGS_FULL); +} + +static inline int l4_sendrecv_full(l4id_t to, l4id_t from, unsigned int tag) +{ + int err; + + BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD); + l4_set_tag(tag); + + err = l4_ipc(to, from, L4_IPC_FLAGS_FULL); + + return err; +} + +static inline int l4_send_extended(l4id_t to, unsigned int tag, + unsigned int size, void *buf) +{ + unsigned int flags = 0; + + l4_set_tag(tag); + + /* Set up flags word for extended ipc */ + flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED); + flags = l4_set_ipc_size(flags, size); + flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0); + + /* Write buffer pointer to MR index that we specified */ + write_mr(L4SYS_ARG0, (unsigned long)buf); + + return l4_ipc(to, L4_NILTHREAD, flags); +} + +static inline int l4_receive_extended(l4id_t from, unsigned int size, void *buf) +{ + unsigned int flags = 0; + + /* Indicate extended receive */ + flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED); + + /* How much data is accepted */ + flags = l4_set_ipc_size(flags, size); + + /* Indicate which MR index buffer pointer is stored */ + flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0); + + /* Set MR with buffer to receive data */ + write_mr(L4SYS_ARG0, (unsigned long)buf); + + return l4_ipc(L4_NILTHREAD, from, flags); +} + +/* + * Return result value as extended IPC. + * + * Extended IPC copies up to 2KB user address space buffers. + * Along with such an ipc, a return value is sent using a primary + * mr that is used as the return register. + * + * It may not be desirable to return a payload on certain conditions, + * (such as an error return value) So a nopayload field is provided. + */ +static inline int l4_return_extended(int retval, unsigned int size, + void *buf, int nopayload) +{ + unsigned int flags = 0; + l4id_t sender = l4_get_sender(); + + l4_set_retval(retval); + + /* Set up flags word for extended ipc */ + flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED); + flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0); + + /* Write buffer pointer to MR index that we specified */ + write_mr(L4SYS_ARG0, (unsigned long)buf); + + if (nopayload) + flags = l4_set_ipc_size(flags, 0); + else + flags = l4_set_ipc_size(flags, size); + + return l4_ipc(sender, L4_NILTHREAD, flags); +} + +static inline int l4_sendrecv_extended(l4id_t to, l4id_t from, + unsigned int tag, void *buf) +{ + /* Need to imitate sendrecv but with extended send/recv flags */ + return 0; +} + +static inline int l4_send(l4id_t to, unsigned int tag) +{ + l4_set_tag(tag); + + return l4_ipc(to, L4_NILTHREAD, 0); +} + +static inline int l4_sendrecv(l4id_t to, l4id_t from, unsigned int tag) +{ + int err; + + BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD); + l4_set_tag(tag); + + err = l4_ipc(to, from, 0); + + return err; +} + +static inline int l4_receive(l4id_t from) +{ + return l4_ipc(L4_NILTHREAD, from, 0); +} + +static inline void l4_print_mrs() +{ + printf("Message registers: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + read_mr(0), read_mr(1), read_mr(2), read_mr(3), + read_mr(4), read_mr(5)); +} + +/* Servers: + * Return the ipc result back to requesting task. + */ +static inline int l4_ipc_return(int retval) +{ + l4id_t sender = l4_get_sender(); + + l4_set_retval(retval); + + /* Setting the tag would overwrite retval so we l4_send without tagging */ + return l4_ipc(sender, L4_NILTHREAD, 0); +} + +void *l4_new_virtual(int npages); +void *l4_del_virtual(void *virt, int npages); + +/* A helper that translates and maps a physical address to virtual */ +static inline void *l4_map_helper(void *phys, int npages) +{ + struct task_ids ids; + int err; + + void *virt = l4_new_virtual(npages); + + l4_getid(&ids); + + if ((err = l4_map(phys, virt, npages, + MAP_USR_DEFAULT, ids.tid)) < 0) + return PTR_ERR(err); + + return virt; +} + + +/* A helper that translates and maps a physical address to virtual */ +static inline void *l4_unmap_helper(void *virt, int npages) +{ + struct task_ids ids; + + l4_getid(&ids); + l4_unmap(virt, npages, ids.tid); + l4_del_virtual(virt, npages); + return 0; +} + +#define L4_EXIT_MASK 0xFFFF + +static inline void l4_exit(unsigned int exit_code) +{ + struct task_ids ids; + l4_getid(&ids); + l4_thread_control(THREAD_DESTROY | + (exit_code & L4_EXIT_MASK), + &ids); +} + +#endif /* __L4LIB_SYSLIB_H__ */ diff --git a/conts/libl4/include/l4lib/arch/arm/types.h b/conts/libl4/include/l4lib/arch/arm/types.h new file mode 100644 index 0000000..76dc5ba --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/types.h @@ -0,0 +1,8 @@ +#ifndef __L4LIB_ARM_TYPES_H___ +#define __L4LIB_ARM_TYPES_H__ + +#define TASK_ID_INVALID 0xFFFFFFFF + +#include + +#endif /* __L4LIB_ARM_TYPES_H__ */ diff --git a/conts/libl4/include/l4lib/arch/arm/utcb.h b/conts/libl4/include/l4lib/arch/arm/utcb.h new file mode 100644 index 0000000..fccd729 --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/utcb.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009 Bahadir Bilgehan Balban + */ +#ifndef __ARM_UTCB_H__ +#define __ARM_UTCB_H__ + +#define USER_UTCB_REF 0xFF000050 +#define L4_KIP_ADDRESS 0xFF000000 +#define UTCB_KIP_OFFSET 0x50 + +#ifndef __ASSEMBLY__ +#include +#include +#include +#include INC_GLUE(message.h) +#include INC_GLUE(memory.h) +#include +#include +#include L4LIB_INC_SUBARCH(utcb.h) + +/* + * See kernel glue/arch/message.h for utcb details + */ +extern struct kip *kip; + + + + +/* Functions to read/write utcb registers */ +static inline unsigned int read_mr(int offset) +{ + if (offset < MR_TOTAL) + return l4_get_utcb()->mr[offset]; + else + return l4_get_utcb()->mr_rest[offset - MR_TOTAL]; +} + +static inline void write_mr(unsigned int offset, unsigned int val) +{ + if (offset < MR_TOTAL) + l4_get_utcb()->mr[offset] = val; + else + l4_get_utcb()->mr_rest[offset - MR_TOTAL] = val; +} + + +static inline void *utcb_full_buffer() +{ + return &l4_get_utcb()->mr_rest[0]; +} + +static inline char *utcb_full_strcpy_from(const char *src) +{ + return strncpy((char *)&l4_get_utcb()->mr_rest[0], src, + L4_UTCB_FULL_BUFFER_SIZE); +} + +static inline void *utcb_full_memcpy_from(const char *src, int size) +{ + return memcpy(&l4_get_utcb()->mr_rest[0], src, + min(size, L4_UTCB_FULL_BUFFER_SIZE)); +} + +static inline char *utcb_full_strcpy_to(char *dst) +{ + return strncpy(dst, (char *)&l4_get_utcb()->mr_rest[0], + L4_UTCB_FULL_BUFFER_SIZE); +} + +static inline void *utcb_full_memcpy_to(char *dst, int size) +{ + return memcpy(dst, &l4_get_utcb()->mr_rest[0], + min(size, L4_UTCB_FULL_BUFFER_SIZE)); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ARM_UTCB_H__ */ diff --git a/conts/libl4/include/l4lib/arch/arm/v5/perfmon.h b/conts/libl4/include/l4lib/arch/arm/v5/perfmon.h new file mode 100644 index 0000000..ce58df8 --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/v5/perfmon.h @@ -0,0 +1,3 @@ +#ifndef __PERFMON_H__ + +#endif diff --git a/conts/libl4/include/l4lib/arch/arm/v5/utcb.h b/conts/libl4/include/l4lib/arch/arm/v5/utcb.h new file mode 100644 index 0000000..9cab31d --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/v5/utcb.h @@ -0,0 +1,21 @@ +#ifndef __ARM_V5_UTCB_H__ +#define __ARM_V5_UTCB_H__ + +/* + * Pointer to Kernel Interface Page's UTCB pointer offset. + */ +extern struct utcb **kip_utcb_ref; + +static inline struct utcb *l4_get_utcb() +{ + /* + * By double dereferencing, we get the private TLS + * (aka UTCB). First reference is to the KIP's utcb + * offset, second is to the utcb itself, to which + * the KIP's utcb reference had been updated during + * context switch. + */ + return *kip_utcb_ref; +} + +#endif /* __ARM_V5_UTCB_H__ */ diff --git a/conts/libl4/include/l4lib/arch/arm/v7/perfmon.h b/conts/libl4/include/l4lib/arch/arm/v7/perfmon.h new file mode 100644 index 0000000..f47e5fb --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/v7/perfmon.h @@ -0,0 +1,405 @@ +/* + * ARMv7 Performance Monitor operations + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#ifndef __PERFMON_H__ +#define __PERFMON_H__ + +#include + +/* Perfmon control register */ +#define PMCR_DP_BIT 5 /* Disable prohibited */ +#define PMCR_X_BIT 4 /* Export event enable */ +#define PMCR_D_BIT 3 /* 64-cycle granularity */ +#define PMCR_C_BIT 2 /* PMCCNTR reset */ +#define PMCR_P_BIT 1 /* Events all reset */ +#define PMCR_E_BIT 0 /* Enable all */ + +/* Obtain number of event counters */ +#define PMCR_N_SHIFT 11 +#define PMCR_N_MASK 0x1F + +/* Special bit for cycle counter */ +#define PMCCNTR_BIT 31 + + +/* + * Performance Events + */ + +/* Generic v7 events */ +#define PERFMON_EVENT_SOFTINC 0 +#define PERFMON_EVENT_IFETCH_L1CREFILL 1 +#define PERFMON_EVENT_IFETCH_TLBREFILL 2 +#define PERFMON_EVENT_DFETCH_L1CREFILL 3 +#define PERFMON_EVENT_DFETCH_L1CACCESS 4 +#define PERFMON_EVENT_DFETCH_TLBREFILL 5 +#define PERFMON_EVENT_MEMREAD_INSTR 6 +#define PERFMON_EVENT_MEMWRITE_INSTR 7 +#define PERFMON_EVENT_ALL_INSTR 8 +#define PERFMON_EVENT_EXCEPTION 9 +#define PERFMON_EVENT_EXCEPTION_RETURN 10 +#define PERFMON_EVENT_CONTEXTIDR_CHANGE 11 +#define PERFMON_EVENT_PC_CHANGE 12 +#define PERFMON_EVENT_IMM_BRANCH 13 +#define PERFMON_EVENT_FUNCTION_RETURN 14 +#define PERFMON_EVENT_UNALIGNED_ACCESS 15 +#define PERFMON_EVENT_BRANCH_MISS 16 +#define PERFMON_EVENT_RAW_CYCLE_COUNT 17 +#define PERFMON_EVENT_BRANCH_MAYBEHIT 18 + +/* + * Cortex-A9 events (only relevant ones) + * 0x40-2, 0x6E, 0x70, 0x71-4, 0x80-0x81, 0x8A-8B + * 0xA0-5 omitted + */ + +/* + * Linefill not satisfied from other cpu caches but + * has to go to external memory + */ +#define PERFMON_EVENT_SMP_LINEFILL_MISS 0x50 + +/* Linefill satisfied from other cpu caches */ +#define PERFMON_EVENT_SMP_LINEFILL_HIT 0x51 + +/* Icache refill stall cycles on cpu pipeline */ +#define PERFMON_EVENT_ICACHE_CPU_STALL 0x60 + +/* Dcache refill stall cycles on cpu pipeline */ +#define PERFMON_EVENT_DCACHE_CPU_STALL 0x61 + +/* TLB miss stall cycles on cpu pipeline */ +#define PERFMON_EVENT_TLBMISS_CPU_STALL 0x62 + +#define PERFMON_EVENT_STREX_SUCCESS 0x63 +#define PERFMON_EVENT_STREX_FAIL 0x64 +#define PERFMON_EVENT_DCACHE_EVICTION 0x65 + +/* Issue stage can't proceed to dispatch any instruction */ +#define PERFMON_EVENT_PIPELINE_CANT_ISSUE 0x66 + +/* Issue stage empty */ +#define PERFMON_EVENT_PIPELINE_ISSUE_EMPTY 0x67 + +/* Register renamed instructions */ +#define PERFMON_EVENT_REGRENAMED_INSTR 0x68 + +#define PERFMON_EVENT_CPUSTALL_ITLB_MISS 0x82 +#define PERFMON_EVENT_CPUSTALL_DTLB_MISS 0x83 +#define PERFMON_EVENT_CPUSTALL_IUTLB_MISS 0x84 +#define PERFMON_EVENT_CPUSTALL_DUTLB_MISS 0x85 +#define PERFMON_EVENT_CPUSTALL_DMB 0x86 +#define PERFMON_EVENT_ISB_COUNT 0x90 +#define PERFMON_EVENT_DSB_COUNT 0x91 +#define PERFMON_EVENT_DMB_COUNT 0x92 +#define PERFMON_EVENT_EXTIRQ_COUNT 0x93 + + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_ctrl(void) +{ + volatile u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c12, 0\n" + "isb\n" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_ctrl(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c12, 0" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_cntenset(void) +{ + volatile u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c12, 1\n" + "isb\n" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_cntenset(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c12, 1" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_cntenclr(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c12, 2" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_cntenclr(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c12, 2" + : + : "r" (word) + ); +} + + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_overflow(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c12, 3" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_overflow(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c12, 3" + : + : "r" (word) + ); +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_softinc(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c12, 4" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_evcntsel(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c12, 5" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_evcntsel(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c12, 5" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_cyccnt(void) +{ + volatile u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c13, 0\n" + "isb\n" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_cyccnt(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c13, 0" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_evtypesel(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c13, 1" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_evtypesel(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c13, 1" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_evcnt(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c13, 2" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_evcnt(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c13, 2" + : + : "r" (word) + ); +} + + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_useren(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c14, 0" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_useren(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c14, 0" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_intenset(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c14, 1" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_intenset(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c14, 1" + : + : "r" (word) + ); +} + +static inline u32 __attribute__((always_inline)) +cp15_read_perfmon_intenclr(void) +{ + u32 val = 0; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c9, c14, 2" + : "=r" (val) + : + ); + + return val; +} + +static inline void __attribute__((always_inline)) +cp15_write_perfmon_intenclr(volatile u32 word) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c9, c14, 2" + : + : "r" (word) + ); +} + +#include + +#if defined (CONFIG_DEBUG_PERFMON_USER) +static inline +u32 perfmon_read_cyccnt() +{ + u32 cnt = cp15_read_perfmon_cyccnt(); + u32 ovfl = cp15_read_perfmon_overflow(); + + /* Detect overflow and signal something was wrong */ + if (ovfl & (1 << PMCCNTR_BIT)) + printf("%s: Overflow.\n", __FUNCTION__); + return cnt; +} + +void perfmon_reset_start_cyccnt(); +u32 perfmon_read_reset_start_cyccnt(); + +#endif + + +void perfmon_init(); + +#endif /* __PERFMON_H__ */ + diff --git a/conts/libl4/include/l4lib/arch/arm/v7/utcb.h b/conts/libl4/include/l4lib/arch/arm/v7/utcb.h new file mode 100644 index 0000000..b42b059 --- /dev/null +++ b/conts/libl4/include/l4lib/arch/arm/v7/utcb.h @@ -0,0 +1,59 @@ +#ifndef __ARM_V5_UTCB_H__ +#define __ARM_V5_UTCB_H__ + +/* + * NOTE: Any changes you make here, you *MUST* change + * utcb_address() macro in syscall.S assembler. + */ + +/* Read Thread ID User RW register */ +static inline u32 l4_cp15_read_tid_usr_rw(void) +{ + volatile u32 val; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c13, c0, 2" + : "=r" (val) + : + ); + + return val; +} + +/* Write Thread ID User RW register */ +static inline void l4_cp15_write_tid_usr_rw(volatile u32 val) +{ + __asm__ __volatile__ ( + "mcr p15, 0, %0, c13, c0, 2" + : + : "r" (val) + ); +} + +/* Read Thread ID User RO register */ +static inline u32 l4_cp15_read_tid_usr_ro(void) +{ + volatile u32 val; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c13, c0, 3" + : "=r" (val) + : + ); + + return val; +} + +/* + * In ARMv7, utcb resides in the userspace read-only + * thread register. This adds the benefit of avoiding + * dirtying the cache and extra management for smp since + * it is per-cpu. + */ +static inline struct utcb *l4_get_utcb() +{ +// printf("%s: UTCB Adddress: 0x%x\n", __FUNCTION__, l4_cp15_read_tid_usr_ro()); + return (struct utcb *)l4_cp15_read_tid_usr_ro(); +} + +#endif /* __ARM_V5_UTCB_H__ */ diff --git a/conts/libl4/include/l4lib/cache.h b/conts/libl4/include/l4lib/cache.h new file mode 100644 index 0000000..0ec418c --- /dev/null +++ b/conts/libl4/include/l4lib/cache.h @@ -0,0 +1,13 @@ + +/* + * Cache control operations + * + * Copyright (C) 2009 Bora Sahin + */ + +#ifndef __L4_CACHE_CONTROL__ +#define __L4_CACHE_CONTROL__ + +#include + +#endif /* __L4_CACHE_CONTROL__ */ diff --git a/conts/libl4/include/l4lib/capability/cap_print.h b/conts/libl4/include/l4lib/capability/cap_print.h new file mode 100644 index 0000000..6668d53 --- /dev/null +++ b/conts/libl4/include/l4lib/capability/cap_print.h @@ -0,0 +1,12 @@ + +#ifndef __CAP_PRINT_H__ +#define __CAP_PRINT_H__ + +#include +#include + +void cap_dev_print(struct capability *cap); +void cap_print(struct capability *cap); +void cap_array_print(int total_caps, struct capability *caparray); + +#endif /* __CAP_PRINT_H__*/ diff --git a/conts/libl4/include/l4lib/exregs.h b/conts/libl4/include/l4lib/exregs.h index 196a5fd..be7289e 100644 --- a/conts/libl4/include/l4lib/exregs.h +++ b/conts/libl4/include/l4lib/exregs.h @@ -8,7 +8,10 @@ void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val); void exregs_set_pc(struct exregs_data *s, unsigned long pc); void exregs_set_pager(struct exregs_data *s, l4id_t pagerid); void exregs_set_utcb(struct exregs_data *s, unsigned long virt); +void exregs_set_read(struct exregs_data *exregs); +unsigned long exregs_get_utcb(struct exregs_data *s); +unsigned long exregs_get_stack(struct exregs_data *s); /* exregs_set_stack(unsigned long sp) exregs_set_pc(unsigned long pc) diff --git a/conts/libl4/include/l4lib/ipcdefs.h b/conts/libl4/include/l4lib/ipcdefs.h index 3d9a907..2cffbe3 100644 --- a/conts/libl4/include/l4lib/ipcdefs.h +++ b/conts/libl4/include/l4lib/ipcdefs.h @@ -10,6 +10,7 @@ #define __IPCDEFS_H__ #include +#include /*** IPC Tags used between server tasks ***/ @@ -69,7 +70,8 @@ extern l4id_t pagerid; #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 -#define L4_IPC_TAG_TIMER_SLEEP 56 +#define L4_IPC_TAG_TIMER_GETTIME 55 +#define L4_IPC_TAG_TIMER_SLEEP 56 +#define L4_IPC_TAG_TIMER_WAKE_THREADS 57 #endif /* __IPCDEFS_H__ */ diff --git a/conts/libl4/include/l4lib/irq.h b/conts/libl4/include/l4lib/irq.h new file mode 100644 index 0000000..3876f2e --- /dev/null +++ b/conts/libl4/include/l4lib/irq.h @@ -0,0 +1,7 @@ +#ifndef __L4LIB_IRQ_H__ +#define __L4LIB_IRQ_H__ + + +int l4_irq_wait(int slot, int irqnum); + +#endif /* __L4LIB_IRQ_H__ */ diff --git a/conts/libl4/include/l4lib/kip.h b/conts/libl4/include/l4lib/kip.h index 35b57ff..8d524f8 100644 --- a/conts/libl4/include/l4lib/kip.h +++ b/conts/libl4/include/l4lib/kip.h @@ -9,7 +9,7 @@ /* Use the kernel header */ #include -#include #include +#include L4LIB_INC_ARCH(syscalls.h) #endif /* __KIP_H__ */ diff --git a/conts/libl4/include/l4lib/lib/addr.h b/conts/libl4/include/l4lib/lib/addr.h new file mode 100644 index 0000000..4ff6c26 --- /dev/null +++ b/conts/libl4/include/l4lib/lib/addr.h @@ -0,0 +1,27 @@ +/* + * Address allocation pool. + * + * Copyright (C) 2007 Bahadir Balban + */ +#ifndef __ADDR_H__ +#define __ADDR_H__ + +#include + +/* Address pool to allocate from a range of addresses */ +struct address_pool { + struct id_pool *idpool; + unsigned long start; + unsigned long end; +}; + +int address_pool_init(struct address_pool *pool, + struct id_pool *idpool, + unsigned long start, unsigned long end); +int address_pool_alloc_init(struct address_pool *pool, + unsigned long start, unsigned long end, + unsigned int size); +void *address_new(struct address_pool *pool, int nitems, int size); +int address_del(struct address_pool *, void *addr, int nitems, int size); + +#endif /* __ADDR_H__ */ diff --git a/conts/libl4/include/l4lib/lib/bit.h b/conts/libl4/include/l4lib/lib/bit.h new file mode 100644 index 0000000..775fca4 --- /dev/null +++ b/conts/libl4/include/l4lib/lib/bit.h @@ -0,0 +1,44 @@ +#ifndef __BIT_H__ +#define __BIT_H__ + +#include + +unsigned int __clz(unsigned int bitvector); +int find_and_set_first_free_bit(u32 *word, unsigned int lastbit); +int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, + int nbits); +int check_and_clear_bit(u32 *word, int bit); +int check_and_clear_contig_bits(u32 *word, int first, int nbits); + +int check_and_set_bit(u32 *word, int bit); + +/* Set */ +static inline void setbit(unsigned int *w, unsigned int flags) +{ + *w |= flags; +} + + +/* Clear */ +static inline void clrbit(unsigned int *w, unsigned int flags) +{ + *w &= ~flags; +} + +/* Test */ +static inline int tstbit(unsigned int *w, unsigned int flags) +{ + return *w & flags; +} + +/* Test and clear */ +static inline int tstclr(unsigned int *w, unsigned int flags) +{ + int res = tstbit(w, flags); + + clrbit(w, flags); + + return res; +} + +#endif /* __BIT_H__ */ diff --git a/conts/libl4/include/l4lib/lib/cap.h b/conts/libl4/include/l4lib/lib/cap.h new file mode 100644 index 0000000..d343a0b --- /dev/null +++ b/conts/libl4/include/l4lib/lib/cap.h @@ -0,0 +1,75 @@ +/* + * Capability-related management. + * + * Copyright (C) 2009 Bahadir Balban + */ +#ifndef __LIBL4_CAPABILITY_H__ +#define __LIBL4_CAPABILITY_H__ + +#include +#include +#include +#include + +void cap_dev_print(struct capability *cap); +void cap_print(struct capability *cap); +void cap_array_print(int total_caps, struct capability *caparray); + +/* + * Definitions for lists of capabilities + */ +struct cap_list { + int ncaps; + struct link caps; +}; + +static inline void cap_list_init(struct cap_list *clist) +{ + clist->ncaps = 0; + link_init(&clist->caps); +} + +static inline void cap_list_insert(struct capability *cap, + struct cap_list *clist) +{ + list_insert(&cap->list, &clist->caps); + clist->ncaps++; +} + +/* Detach a whole list of capabilities from list head */ +static inline struct capability * +cap_list_detach(struct cap_list *clist) +{ + struct link *list = list_detach(&clist->caps); + clist->ncaps = 0; + return link_to_struct(list, struct capability, list); +} + +/* Attach a whole list of capabilities to list head */ +static inline void cap_list_attach(struct capability *cap, + struct cap_list *clist) +{ + /* Attach as if cap is the list and clist is the element */ + list_insert(&clist->caps, &cap->list); + + /* Count the number of caps attached */ + list_foreach_struct(cap, &clist->caps, list) + clist->ncaps++; +} + +static inline void cap_list_move(struct cap_list *to, + struct cap_list *from) +{ + struct capability *cap_head = cap_list_detach(from); + cap_list_attach(cap_head, to); +} + +/* + * Definitions for reading from the library capability array + */ +void __l4_capability_init(void); +struct capability *cap_get_by_type(unsigned int cap_type); +struct capability *cap_get_physmem(unsigned int cap_type); + + +#endif /* __LIBL4_CAPABILITY_H__ */ diff --git a/conts/libl4/include/l4lib/lib/idpool.h b/conts/libl4/include/l4lib/lib/idpool.h new file mode 100644 index 0000000..2cb1734 --- /dev/null +++ b/conts/libl4/include/l4lib/lib/idpool.h @@ -0,0 +1,32 @@ +#ifndef __IDPOOL_H__ +#define __IDPOOL_H__ + +#include +#include +#include +#include INC_GLUE(memory.h) + +struct id_pool { + int nwords; + int bitlimit; + u32 bitmap[]; +}; + +/* Copy one id pool to another by calculating its size */ +static inline void id_pool_copy(struct id_pool *to, struct id_pool *from, int totalbits) +{ + int nwords = BITWISE_GETWORD(totalbits); + + memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool)); +} + +void id_pool_init(struct id_pool *idpool, int bits); +struct id_pool *id_pool_new_init(int mapsize); +int id_new(struct id_pool *pool); +int id_del(struct id_pool *pool, int id); +int id_get(struct id_pool *pool, int id); +int id_is_empty(struct id_pool *pool); +int ids_new_contiguous(struct id_pool *pool, int numids); +int ids_del_contiguous(struct id_pool *pool, int first, int numids); + +#endif /* __IDPOOL_H__ */ diff --git a/conts/libl4/include/l4lib/lib/thread.h b/conts/libl4/include/l4lib/lib/thread.h new file mode 100644 index 0000000..5a5a3f7 --- /dev/null +++ b/conts/libl4/include/l4lib/lib/thread.h @@ -0,0 +1,65 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include + +/* + * Library specific-flags for thread creation + */ +#define TC_USER_FLAGS_MASK 0x000F0000 +#define TC_NOSTART 0x00010000 + +/* For same space */ +#define STACK_SIZE PAGE_SIZE + +/* Total threads the library supports */ +#define THREADS_TOTAL 10 + +/* + * Keeps track of threads in the system + * created by the pager + */ +struct l4_thread_list { + int total; /* Total number of threads */ + struct l4_mutex lock; /* Threads list lock */ + struct link thread_list; /* Threads list */ + struct mem_cache *thread_cache; /* Cache for thread structures */ +}; + +struct l4_thread { + struct task_ids ids; /* Thread ids */ + struct l4_mutex lock; /* Lock for thread struct */ + struct link list; /* Link to list of threads */ + unsigned long *stack; /* Stack (grows downwards) */ + struct utcb *utcb; /* UTCB address */ +}; + +/* + * These are thread calls that are meant to be + * called by library users + */ +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct l4_thread **tptr); +int thread_wait(struct l4_thread *t); +void thread_exit(int exitcode); + +/* + * This is to be called only if to-be-destroyed thread is in + * sane condition for destruction + */ +int thread_destroy(struct l4_thread *thread); + +/* Library init function called by __container_init */ +void __l4_threadlib_init(void); +void l4_parent_thread_init(void); +extern struct mem_cache *utcb_cache, *stack_cache; +extern struct l4_thread_list l4_thread_list; +extern void setup_new_thread(void); + +#endif /* __THREAD_H__ */ diff --git a/conts/libl4/include/l4lib/macros.h b/conts/libl4/include/l4lib/macros.h new file mode 100644 index 0000000..7a20d28 --- /dev/null +++ b/conts/libl4/include/l4lib/macros.h @@ -0,0 +1,25 @@ +/* + * Userspace-specific macros. + * + * Copyright (C) 2010 B Labs Ltd. + */ +#ifndef __LIBL4_MACROS_H__ +#define __LIBL4_MACROS_H__ + +#include + +/* + * These are for the userspace code to include + * different directories based on configuration + * values for platform, architecture and so on. + * + * This file is meant to be included from all + * userspace projects by default. + */ + +#define L4LIB_INC_ARCH(x) +#define L4LIB_INC_SUBARCH(x) +#define L4LIB_INC_PLAT(x) +#define L4LIB_INC_GLUE(x) + +#endif /* __LIBL4_MACROS_H__ */ diff --git a/conts/libl4/include/l4lib/perfmon.h b/conts/libl4/include/l4lib/perfmon.h new file mode 100644 index 0000000..9d99e2e --- /dev/null +++ b/conts/libl4/include/l4lib/perfmon.h @@ -0,0 +1,13 @@ + +#include +#include L4LIB_INC_SUBARCH(perfmon.h) + +#if !defined (CONFIG_DEBUG_PERFMON_USER) + +/* Common empty definitions for all arches */ +static inline u32 perfmon_read_cyccnt() { return 0; } + +static inline void perfmon_reset_start_cyccnt() { } +static inline u32 perfmon_read_reset_start_cyccnt() { return 0; } + +#endif diff --git a/conts/libl4/include/l4lib/thread/thread.h b/conts/libl4/include/l4lib/thread/thread.h index 408e612..eb5b2ec 100644 --- a/conts/libl4/include/l4lib/thread/thread.h +++ b/conts/libl4/include/l4lib/thread/thread.h @@ -1,8 +1,8 @@ #ifndef __L4_THREAD_H__ #define __L4_THREAD_H__ -#include -#include +#include +#include struct l4_thread_struct { l4id_t tlid; /* Thread local id */ @@ -14,9 +14,13 @@ struct l4_thread_struct { /* -- Bora start -- */ -/* A helper macro easing utcb space creation. */ +/* + * A helper macro easing utcb space creation, + * FIXME: We need to fix address allocation path, so as to use + * actual size of units instead of page size + */ #define DECLARE_UTCB_SPACE(name, entries) \ - char name[(entries + PAGE_SIZE / UTCB_SIZE) * UTCB_SIZE] ALIGN(PAGE_SIZE); + char name[entries * PAGE_SIZE] ALIGN(PAGE_SIZE); int l4_set_stack_params(unsigned long stack_top, unsigned long stack_bottom, diff --git a/conts/libl4/include/l4lib/types.h b/conts/libl4/include/l4lib/types.h index 85ae442..58ffe31 100644 --- a/conts/libl4/include/l4lib/types.h +++ b/conts/libl4/include/l4lib/types.h @@ -1,6 +1,7 @@ #ifndef __TYPES_H__ #define __TYPES_H__ -#include +#include +#include L4LIB_INC_ARCH(types.h) #endif /* __TYPES_H__ */ diff --git a/conts/libl4/include/l4lib/utcb.h b/conts/libl4/include/l4lib/utcb.h index ece82ab..bd31b7c 100644 --- a/conts/libl4/include/l4lib/utcb.h +++ b/conts/libl4/include/l4lib/utcb.h @@ -5,7 +5,8 @@ #define __UTCB_H__ #include -#include +#include +#include L4LIB_INC_ARCH(utcb.h) int utcb_init(void); diff --git a/conts/libl4/src/addr.c b/conts/libl4/src/addr.c index 1b1d047..4151922 100644 --- a/conts/libl4/src/addr.c +++ b/conts/libl4/src/addr.c @@ -26,7 +26,7 @@ int address_pool_init(struct address_pool *pool, unsigned long start, unsigned long end, unsigned int size) { - if ((pool->idpool = id_pool_new_init(__pfn(end - start) / size)) < 0) + if ((pool->idpool = id_pool_new_init(__pfn(end - start) )) < 0) return (int)pool->idpool; pool->start = start; pool->end = end; diff --git a/conts/libl4/src/arch/arm/exregs.c b/conts/libl4/src/arch/arm/exregs.c new file mode 100644 index 0000000..207f6be --- /dev/null +++ b/conts/libl4/src/arch/arm/exregs.c @@ -0,0 +1,99 @@ +/* + * Generic to arch-specific interface for + * exchange_registers() + * + * Copyright (C) 2008 Bahadir Balban + */ +#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include INC_GLUE(message.h) + +void exregs_set_read(struct exregs_data *exregs) +{ + exregs->flags |= EXREGS_READ; +} + +void exregs_print_registers(void) +{ + struct exregs_data exregs; + + /* Read registers */ + memset(&exregs, 0, sizeof(exregs)); + exregs.valid_vect = ~0; /* Set all flags */ + exregs.flags |= EXREGS_READ; + exregs.flags |= EXREGS_SET_UTCB; + exregs.flags |= EXREGS_SET_PAGER; + BUG_ON(l4_exchange_registers(&exregs, self_tid()) < 0); + + /* Print out registers */ + printf("Task (%x) register state upon fault:\n", self_tid()); + printf("R0: 0x%x\n", exregs.context.r0); + printf("R1: 0x%x\n", exregs.context.r1); + printf("R2: 0x%x\n", exregs.context.r2); + printf("R3: 0x%x\n", exregs.context.r3); + printf("R4: 0x%x\n", exregs.context.r4); + printf("R5: 0x%x\n", exregs.context.r5); + printf("R6: 0x%x\n", exregs.context.r6); + printf("R7: 0x%x\n", exregs.context.r7); + printf("R8: 0x%x\n", exregs.context.r8); + printf("R9: 0x%x\n", exregs.context.r9); + printf("R10: 0x%x\n", exregs.context.r10); + printf("R11: 0x%x\n", exregs.context.r11); + printf("R12: 0x%x\n", exregs.context.r12); + printf("R13: 0x%x\n", exregs.context.sp); + printf("R14: 0x%x\n", exregs.context.lr); + printf("R15: 0x%x\n", exregs.context.pc); + printf("Pager: 0x%x\n", exregs.pagerid); + printf("Utcb @ 0x%lx\n", exregs.utcb_address); +} + +void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val) +{ + /* Get MR0 */ + u32 *mr = &s->context.MR0_REGISTER; + + /* Sanity check */ + BUG_ON(offset > MR_TOTAL || offset < 0); + + /* Set MR */ + mr[offset] = val; + + /* Set valid bit for mr register */ + s->valid_vect |= FIELD_TO_BIT(exregs_context_t, MR0_REGISTER) << offset; +} + +void exregs_set_pager(struct exregs_data *s, l4id_t pagerid) +{ + s->pagerid = pagerid; + s->flags |= EXREGS_SET_PAGER; +} + +unsigned long exregs_get_utcb(struct exregs_data *s) +{ + return s->utcb_address; +} + +unsigned long exregs_get_stack(struct exregs_data *s) +{ + return s->context.sp; +} + +void exregs_set_utcb(struct exregs_data *s, unsigned long virt) +{ + s->utcb_address = virt; + s->flags |= EXREGS_SET_UTCB; +} + +void exregs_set_stack(struct exregs_data *s, unsigned long sp) +{ + s->context.sp = sp; + s->valid_vect |= FIELD_TO_BIT(exregs_context_t, sp); +} + +void exregs_set_pc(struct exregs_data *s, unsigned long pc) +{ + s->context.pc = pc; + s->valid_vect |= FIELD_TO_BIT(exregs_context_t, pc); +} + diff --git a/conts/libl4/src/arch/arm/new_thread.S b/conts/libl4/src/arch/arm/new_thread.S new file mode 100644 index 0000000..8840e65 --- /dev/null +++ b/conts/libl4/src/arch/arm/new_thread.S @@ -0,0 +1,21 @@ +/* + * Set up new thread's argument and call its function. + * Return would be made to thread_exit with the return code. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(asm.h) + + +BEGIN_PROC(setup_new_thread) + ldr r0, [sp, #-4]! @ Load first argument + mov lr, pc @ Save return address + ldr pc, [sp, #-4]! @ Load function pointer from stack + b thread_exit @ Call l4_thread_exit for cleanup +1: + b 1b @ Never reaches here +END_PROC(setup_new_thread) + diff --git a/conts/libl4/src/arch/arm/syscalls.S b/conts/libl4/src/arch/arm/syscalls.S new file mode 100644 index 0000000..f6a912a --- /dev/null +++ b/conts/libl4/src/arch/arm/syscalls.S @@ -0,0 +1,235 @@ +/* + * Userspace system call interface. + * + * Copyright (C) 2007 - 2009 Bahadir Balban + */ +#include L4LIB_INC_ARCH(asm.h) +#include L4LIB_INC_ARCH(utcb.h) +#include +#include +#include INC_GLUE(message.h) + + +#if defined (CONFIG_ARCH_ARM) && defined (CONFIG_SUBARCH_V7) + /* ARMv7 uses a special per-cpu register to keep thread-local utcb pointer */ + .macro utcb_address rx + mrc p15, 0, \rx, c13, c0, 3 @ Read user-RO thread register TPIDRURO + .endm +#else /* End of ARMv7 */ + /* Get it from KIP page by double dereference */ + .macro utcb_address rx + ldr \rx, =kip_utcb_ref @ First get pointer to utcb pointer in KIP + ldr \rx, [\rx] @ Get pointer to UTCB address from UTCB pointer in KIP + ldr \rx, [\rx] @ Get the utcb address + .endm +#endif + +BEGIN_PROC(l4_thread_switch) + ldr r12, =__l4_thread_switch + ldr pc, [r12] @ Jump into the SWI. Kernel returns to LR_USR, which is the caller. +END_PROC(l4_thread_switch) + +/* + * The syscall returns process ids. This function saves the returned values in the + * arguments passed by reference. @r0 = struct task_ids * + */ +BEGIN_PROC(l4_getid) + ldr r12, =__l4_getid @ See l4_kdata_read for why its so simple. + ldr pc, [r12] @ Return. +END_PROC(l4_getid) + +/* + * For clone() we need special assembler handling + * Same signature as ipc(): @r0 = to, @r1 = from @r2 = flags + * + * NOTE: Note that this breaks l4 system call interface, + * this should be moved elsewhere and modified using existing l4 mechanisms. + */ +BEGIN_PROC(arch_clone) + stmfd sp!, {r4-r8,lr} @ Save context. + utcb_address r12 @ Get utcb address. + ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5 + + ldr r12, =__l4_ipc + mov lr, pc + ldr pc, [r12] @ Perform the ipc() + + /* + * At this moment: + * - MR_RETURN tells us whether we are parent or child (or have failed). + * - Child has new SP set, with |func_ptr|arg1|{End of stack}SP<-| on stack. + * - Child needs exit logic when its function is finished. + */ + cmp r0, #0 @ Check ipc success + blt ipc_failed + cmp MR_RETURN_REGISTER, #0 @ Check ipc return register MR_RETURN. + blt clone_failed @ Ipc was ok but clone() failed. + bgt parent_return @ It has child pid, goto parent return. +child: + ldr r0, [sp, #-4]! @ Load child's first argument. + mov lr, pc @ Save return address + ldr pc, [sp, #-4]! @ Load function pointer from stack +child_exit: + b child_exit @ We infinitely loop for now. + + @ Return with normal ipc return sequence +parent_return: +clone_failed: +ipc_failed: + utcb_address r12 @ Get utcb + stmia r12, {r3-r8} @ Store mrs. + ldmfd sp!, {r4-r8,pc} @ Return restoring pc and context. +END_PROC(arch_clone) + +/* + * Inter-process communication. Loads message registers as arguments before the call, + * and stores them as results after the call. @r0 = to, @r1 = from. + */ +BEGIN_PROC(l4_ipc) + stmfd sp!, {r4-r8,lr} @ Save context. + utcb_address r12 @ Get utcb address. + ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5 + ldr r12, =__l4_ipc + mov lr, pc + ldr pc, [r12] + utcb_address r12 @ Get utcb address. + stmia r12, {r3-r8} @ Store 6 Message registers to utcb. MR0-MR5 + ldmfd sp!, {r4-r8,pc} @ Return restoring pc, and context. +END_PROC(l4_ipc) + +/* + * System call that maps an area of memory into the given address space. + * @r0 = physical address, @r1 = virtual address, @r2 = map size in pages, + * @r3 = map flags, @r4 = The tgid of the address space to map. + */ +BEGIN_PROC(l4_map) + stmfd sp!, {r4, lr} + ldr r4, [sp, #8] @ FIXME: Is this right? + ldr r12, =__l4_map + mov lr, pc @ We must return here to restore r4. + ldr pc, [r12] + ldmfd sp!, {r4, pc} +END_PROC(l4_map) + +/* + * Reads/manipulates capabilities of a thread, particularly a pager. + * @r0 = request type, @r1 = request flags, @r2 = Capability buffer pointer + */ +BEGIN_PROC(l4_capability_control) + stmfd sp!, {lr} + ldr r12, =__l4_capability_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_capability_control) + +/* + * System call that unmaps an area of memory into the given address space. + * @r0 = virtual, @r1 = pages, @r2 = tid of address space to unmap + */ +BEGIN_PROC(l4_unmap) + stmfd sp!, {lr} + ldr r12, =__l4_unmap + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_unmap) + +/* + * System call that controls containers and their parameters. + * @r0 = request type, @r1 = request flags, @r2 = io buffer ptr + */ +BEGIN_PROC(l4_container_control) + stmfd sp!, {lr} + ldr r12, =__l4_container_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_container_control) + +/* + * System call that gets or sets the time info structure. + * @r0 = ptr to time structure @r1 = set or get. set = 1, get = 0. + */ +BEGIN_PROC(l4_time) + stmfd sp!, {lr} + ldr r12, =__l4_time + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_time) + +/* + * System call that controls thread creation, destruction and modification. + * @r0 = thread action, @r1 = &ids, @r2 = utcb address + */ +BEGIN_PROC(l4_thread_control) + stmfd sp!, {lr} + ldr r12, =__l4_thread_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_thread_control) + +/* + * System call that modifies ipc blocked sender lists of receivers. + * @r0 = Action (e.g. block/unblock), @r1 = sender id, @r2 = sender tag + */ +BEGIN_PROC(l4_ipc_control) + stmfd sp!, {lr} + ldr r12, =__l4_ipc_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_ipc_control) + +/* + * Manipulates address spaces, e.g. sets up shared memory areas between threads + * @r0 = operation code, @r1 = operation flags, @r2 = An id (irqnum, or capid) + */ +BEGIN_PROC(l4_irq_control) + stmfd sp!, {lr} + ldr r12, =__l4_irq_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_irq_control) + +/* + * Locks/unlocks a userspace mutex. + * @r0 = mutex virtual address, @r1 = mutex operation code + */ +BEGIN_PROC(l4_mutex_control) + stmfd sp!, {lr} + ldr r12, =__l4_mutex_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_mutex_control) + +/* + * Sets registers of a thread and its pager. + * @r0 = ptr to exregs_data structure, @r1 = tid of thread. + */ +BEGIN_PROC(l4_exchange_registers) + stmfd sp!, {lr} + ldr r12, =__l4_exchange_registers + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_exchange_registers) + +/* + * System call that manipulates caches and tlbs. + * + * @r0 = starting virtual address (inclusive), + * @r1 = ending virtual address (exclusive), + * @r3 = cache operation + */ +BEGIN_PROC(l4_cache_control) + stmfd sp!, {lr} + ldr r12, =__l4_cache_control + mov lr, pc + ldr pc, [r12] + ldmfd sp!, {pc} @ Restore original lr and return. +END_PROC(l4_cache_control) diff --git a/conts/libl4/src/arch/arm/v5/mutex.c b/conts/libl4/src/arch/arm/v5/mutex.c new file mode 100644 index 0000000..fb8c648 --- /dev/null +++ b/conts/libl4/src/arch/arm/v5/mutex.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009-2010 B Labs Ltd. + * Author: Bahadir Balban + */ + +#include L4LIB_INC_ARCH(asm.h) +#include +#include +#include INC_SUBARCH(irq.h) +#include L4LIB_INC_ARCH(syslib.h) /* for BUG/BUG_ON, */ + +/* + * NOTES: + * + * Recap on swp: + * + * swp rx, ry, [rz] + * + * In one instruction: + * + * 1) Stores the value in ry into location pointed by rz. + * 2) Loads the value in the location of rz into rx. + * By doing so, in one instruction one can attempt to lock + * a word, and discover whether it was already locked. + * + * Why use tid of thread to lock mutex instead of + * a single lock value? + * + * Because in one atomic instruction, not only the locking attempt + * should be able to indicate whether it is locked, but also + * the contentions. A unified lock value would not be sufficient. + * The only way to indicate a contended lock is to store the + * unique TID of the locker. + */ + +/* + * Any non-negative value that is a potential TID + * (including 0) means mutex is locked. + */ + + +int __l4_mutex_lock(void *m, l4id_t tid) +{ + unsigned int tmp; + + __asm__ __volatile__( + "swp %0, %1, [%2]" + : "=r" (tmp) + : "r"(tid), "r" (m) + : "memory" + ); + + if (tmp == L4_MUTEX_UNLOCKED) + return L4_MUTEX_SUCCESS; + + return L4_MUTEX_CONTENDED; +} + + +int __l4_mutex_unlock(void *m, l4id_t tid) +{ + unsigned int tmp, tmp2 = L4_MUTEX_UNLOCKED; + + __asm__ __volatile__( + "swp %0, %1, [%2]" + : "=r" (tmp) + : "r" (tmp2), "r"(m) + : "memory" + ); + + BUG_ON(tmp == L4_MUTEX_UNLOCKED); + + if (tmp == tid) + return L4_MUTEX_SUCCESS; + + return L4_MUTEX_CONTENDED; +} + +u8 l4_atomic_dest_readb(unsigned long *location) +{ +#if 0 + unsigned int tmp; + __asm__ __volatile__ ( + "swpb r0, r2, [r1] \n" + : "=r"(tmp) + : "r"(location), "r"(0) + : "memory" + ); + return (u8)tmp; +#endif + + unsigned int tmp; + // unsigned long state; + // irq_local_disable_save(&state); + + tmp = *location; + *location = 0; + + //irq_local_restore(state); + + return (u8)tmp; + +} diff --git a/conts/libl4/src/arch/arm/v6/mutex.c b/conts/libl4/src/arch/arm/v6/mutex.c new file mode 100644 index 0000000..8f1076f --- /dev/null +++ b/conts/libl4/src/arch/arm/v6/mutex.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * Author: Prem Mallappa + */ + +#include +#include +#include L4LIB_INC_ARCH(syslib.h) /* for BUG/BUG_ON, */ +#include L4LIB_INC_ARCH(asm.h) +#include INC_SUBARCH(mmu_ops.h) + +int __l4_mutex_lock(void *m, l4id_t tid) +{ + int tmp, ret; + loop: + __asm__ __volatile__( + "ldrex %0, [%1]\n" + : "=r"(tmp) + : "r"(m) + ); + + if(tmp != L4_MUTEX_UNLOCKED) + ret = L4_MUTEX_CONTENDED; + else + ret = L4_MUTEX_SUCCESS; + + /* Store our 'tid' */ + __asm__ __volatile__( + "strex %0, %1, [%2]\n" + :"=&r"(tmp) + :"r"(tid), "r"(m) + ); + if (tmp != 0) { + /* We couldn't succeed the store, we retry */ +#ifdef CONFIG_SMP + /* don't hog the CPU, sleep till an event */ + __asm__ __volatile__("wfe\n"); +#endif + goto loop; + } + + dsb(); + + return ret; +} + +int __l4_mutex_unlock(void *m, l4id_t tid) +{ + int tmp, ret; + loop: + /* Load and see if the lock had our tid */ + __asm__ __volatile__( + "ldrex %0, [%1]\n" + : "=r"(tmp) + : "r"(m) + ); + + if(tmp != tid) + ret = L4_MUTEX_CONTENDED; + else + ret = L4_MUTEX_SUCCESS; + + /* We store unlock value '0' */ + __asm__ __volatile__( + "strex %0, %1, [%2]\n" + :"=&r"(tmp) + :"rI"(L4_MUTEX_UNLOCKED), "r"(m) + ); + if(tmp != 0) { + /* The store wasn't successfull, retry */ + goto loop; + } + + dsb(); + +#ifdef CONFIG_SMP + __asm__ __volatile__("sev\n"); +#endif + return ret; +} + +u8 l4_atomic_dest_readb(u8 *location) +{ + unsigned int tmp, res; + __asm__ __volatile__ ( + "1: \n" + "ldrex %0, [%2] \n" + "strex %1, %3, [%2] \n" + "teq %1, #0 \n" + "bne 1b \n" + : "=&r"(tmp), "=&r"(res) + : "r"(location), "r"(0) + : "cc", "memory" + ); + + return (u8)tmp; +} diff --git a/conts/libl4/src/arch/arm/v7/mutex.S b/conts/libl4/src/arch/arm/v7/mutex.S new file mode 100644 index 0000000..155e581 --- /dev/null +++ b/conts/libl4/src/arch/arm/v7/mutex.S @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Bahadir Balban + */ + +#include +#include + +/* + * @r0 = address of mutex word + * @r1 = unique tid of current thread + */ +BEGIN_PROC(__l4_mutex_lock) +1: + ldrex r2, [r0] @ Load value + cmp r2, #L4_MUTEX_UNLOCKED @ Decide what state lock will be if we succeed in a store + movne r2, #L4_MUTEX_CONTENDED + moveq r2, #L4_MUTEX_SUCCESS + strex r3, r1, [r0] @ Store prospective lock state + cmp r3, #0 @ If not successful + @ No WFE. Whatif this were between 2 threads running on the same cpu + bne 1b @ Retry and decide again on the prospective lock state. + dsb + mov r0, r2 + mov pc, lr +END_PROC(__l4_mutex_lock) + +/* + * @r0 = address of mutex word + * @r1 = unique tid of current thread + */ +BEGIN_PROC(__l4_mutex_unlock) + dsb + push {r4} + mov r4, #L4_MUTEX_UNLOCKED +1: + ldrex r2, [r0] + cmp r2, r1 + moveq r3, #L4_MUTEX_SUCCESS + movne r3, #L4_MUTEX_CONTENDED + strex r2, r4, [r0] + cmp r2, #0 + bne 1b + mov r0, r3 + pop {r4} + mov pc, lr +END_PROC(__l4_mutex_unlock) + + diff --git a/conts/libl4/src/arch/arm/v7/perfmon.c b/conts/libl4/src/arch/arm/v7/perfmon.c new file mode 100644 index 0000000..28a8a65 --- /dev/null +++ b/conts/libl4/src/arch/arm/v7/perfmon.c @@ -0,0 +1,45 @@ +/* + * Performance monitoring + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include + +#if defined (CONFIG_DEBUG_PERFMON_USER) +/* + * Resets/restarts cycle counter + */ +void perfmon_reset_start_cyccnt() +{ + volatile u32 pmcctrl; + + /* Disable the cycle counter register */ + cp15_write_perfmon_cntenclr(1 << PMCCNTR_BIT); + + /* Clear the cycle counter on ctrl register */ + pmcctrl = cp15_read_perfmon_ctrl(); + pmcctrl |= (1 << PMCR_C_BIT); + cp15_write_perfmon_ctrl(pmcctrl); + + /* Clear overflow register */ + cp15_write_perfmon_overflow(1 << PMCCNTR_BIT); + + /* Enable the cycle count */ + cp15_write_perfmon_cntenset(1 << PMCCNTR_BIT); +} + +/* + * Reads current counter, clears and restarts it + */ +u32 perfmon_read_reset_start_cyccnt() +{ + volatile u32 cyccnt = cp15_read_perfmon_cyccnt(); + + perfmon_reset_start_cyccnt(); + + return cyccnt; +} + +#endif /* End of !CONFIG_DEBUG_PERFMON_USER */ diff --git a/conts/libl4/src/arm/mutex.S b/conts/libl4/src/arm/mutex.S index 375c176..144f312 100644 --- a/conts/libl4/src/arm/mutex.S +++ b/conts/libl4/src/arm/mutex.S @@ -63,4 +63,13 @@ BEGIN_PROC(__l4_mutex_unlock) mov pc, lr END_PROC(__l4_mutex_unlock) +/* + * r0 = byte address to read from. + */ +BEGIN_PROC(l4_atomic_dest_readb) + mov r1, r0 @ Move byte address to r1 + mov r2, #0 @ Move 0 to r2 + swpb r0, r2, [r1] @ Write 0 to byte location, while reading its value to r0 + mov pc, lr @ Return byte location value +END_PROC(l4_atomic_dest_readb) diff --git a/conts/libl4/src/capability/cap_print.c b/conts/libl4/src/capability/cap_print.c new file mode 100644 index 0000000..001ef1b --- /dev/null +++ b/conts/libl4/src/capability/cap_print.c @@ -0,0 +1,117 @@ + + +/* Capability printing generic routines */ + +#include +#include + +void cap_dev_print(struct capability *cap) +{ + switch (cap_devtype(cap)) { + case CAP_DEVTYPE_UART: + printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap)); + break; + case CAP_DEVTYPE_TIMER: + printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap)); + break; + case CAP_DEVTYPE_CLCD: + printf("Device type:\t\t\t%s%d\n", "CLCD", cap_devnum(cap)); + break; + default: + return; + } + printf("Device Irq:\t\t%d\n", cap->irq); +} + +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: + if (!cap_is_devmem(cap)) { + printf("Capability type:\t\t%s\n", "Map/Physmem"); + } else { + printf("Capability type:\t\t%s\n", "Map/Physmem/Device"); + cap_dev_print(cap); + } + 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_IRQCTRL: + printf("Capability type:\t\t%s\n", "IRQ Control"); + break; + case CAP_TYPE_QUANTITY: + printf("Capability type:\t\t%s\n", "Quantitative"); + break; + case CAP_TYPE_CAP: + printf("Capability type:\t\t%s\n", "Capability Control"); + break; + default: + printf("Capability type:\t\t%s, cap_type=0x%x\n", + "Unknown", cap_type(cap)); + 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, id=0x%x\n", "Unknown", + cap_rtype(cap)); + break; + } + printf("\n"); +} + +void cap_array_print(int total_caps, struct capability *caparray) +{ + printf("Capabilities\n" + "~~~~~~~~~~~~\n"); + + for (int i = 0; i < total_caps; i++) + cap_print(&caparray[i]); + + printf("\n"); +} + diff --git a/conts/libl4/src/init.c b/conts/libl4/src/init.c index 0959696..605c7f2 100644 --- a/conts/libl4/src/init.c +++ b/conts/libl4/src/init.c @@ -4,8 +4,8 @@ * Copyright (C) 2007-2009 Bahadir Bilgehan Balban */ #include -#include -#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(utcb.h) #include #include #include INC_GLUE(memlayout.h) @@ -24,6 +24,7 @@ __l4_container_control_t __l4_container_control = 0; __l4_capability_control_t __l4_capability_control = 0; __l4_time_t __l4_time = 0; __l4_mutex_control_t __l4_mutex_control = 0; +__l4_cache_control_t __l4_cache_control = 0; struct kip *kip; @@ -60,5 +61,6 @@ void __l4_init(void) (__l4_container_control_t)kip->container_control; __l4_time = (__l4_time_t)kip->time; __l4_mutex_control = (__l4_mutex_control_t)kip->mutex_control; + __l4_cache_control = (__l4_cache_control_t)kip->cache_control; } diff --git a/conts/libl4/src/irq.c b/conts/libl4/src/irq.c new file mode 100644 index 0000000..7c7cd8d --- /dev/null +++ b/conts/libl4/src/irq.c @@ -0,0 +1,23 @@ +/* + * Functions for userspace irq handling. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include L4LIB_INC_ARCH(irq.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include + +/* + * Reads the irq notification slot. Destructive atomic read ensures that + * an irq may write to the slot in sync. + */ +int l4_irq_wait(int slot, int irqnum) +{ + int irqval = l4_atomic_dest_readb(&(l4_get_utcb()->notify[slot])); + + if (!irqval) + return l4_irq_control(IRQ_CONTROL_WAIT, 0, irqnum); + else + return irqval; +} + diff --git a/conts/libl4/src/lib/addr.c b/conts/libl4/src/lib/addr.c new file mode 100644 index 0000000..1ea8ba9 --- /dev/null +++ b/conts/libl4/src/lib/addr.c @@ -0,0 +1,62 @@ +/* + * This module allocates an unused address range from + * a given memory region defined as the pool range. + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include + +/* + * Initializes an address pool, but uses an already + * allocated id pool for it. + */ +int address_pool_init(struct address_pool *pool, + struct id_pool *idpool, + unsigned long start, unsigned long end) +{ + pool->idpool = idpool; + pool->start = start; + pool->end = end; + + id_pool_init(idpool, __pfn(end - start)); + + return 0; +} + +/* + * Allocates an id pool and initializes it + */ +int address_pool_alloc_init(struct address_pool *pool, + unsigned long start, unsigned long end, + unsigned int size) +{ + if ((pool->idpool = id_pool_new_init(__pfn(end - start) )) < 0) + return (int)pool->idpool; + pool->start = start; + pool->end = end; + return 0; +} + +void *address_new(struct address_pool *pool, int nitems, int size) +{ + unsigned int idx; + + if ((int)(idx = ids_new_contiguous(pool->idpool, nitems)) < 0) + return 0; + + return (void *)(idx * size) + pool->start; +} + +int address_del(struct address_pool *pool, void *addr, int nitems, int size) +{ + unsigned long idx = (addr - (void *)pool->start) / size; + + if (ids_del_contiguous(pool->idpool, idx, nitems) < 0) { + printf("%s: Invalid address range returned to " + "virtual address pool.\n", __FUNCTION__); + return -1; + } + return 0; +} + diff --git a/conts/libl4/src/lib/bit.c b/conts/libl4/src/lib/bit.c new file mode 100644 index 0000000..711c7b4 --- /dev/null +++ b/conts/libl4/src/lib/bit.c @@ -0,0 +1,109 @@ +/* + * Bit manipulation functions. + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include INC_GLUE(memory.h) + +/* Emulation of ARM's CLZ (count leading zeroes) instruction */ +unsigned int __clz(unsigned int bitvector) +{ + unsigned int x = 0; + while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) { + bitvector <<= 1; + x++; + } + return x; +} + +int find_and_set_first_free_bit(u32 *word, unsigned int limit) +{ + int success = 0; + int i; + + for(i = 0; i < limit; i++) { + /* Find first unset bit */ + if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) { + /* Set it */ + word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i); + success = 1; + break; + } + } + /* Return bit just set */ + if (success) + return i; + else + return -1; +} + +int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, + int nbits) +{ + int i = 0, first = 0, last = 0, found = 0; + + /* Can't allocate more than the limit */ + if (nbits > limit) + return -1; + + /* This is a state machine that checks n contiguous free bits. */ + while (i + nbits <= limit) { + first = i; + last = i; + while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) { + last++; + i++; + if (last == first + nbits) { + found = 1; + break; + } + } + if (found) + break; + i++; + } + + /* If found, set the bits */ + if (found) { + for (int x = first; x < first + nbits; x++) + word[BITWISE_GETWORD(x)] |= BITWISE_GETBIT(x); + return first; + } else + return -1; +} + +int check_and_clear_bit(u32 *word, int bit) +{ + /* Check that bit was set */ + if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) { + word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit); + return 0; + } else { + printf("Trying to clear already clear bit\n"); + return -1; + } +} + +int check_and_set_bit(u32 *word, int bit) +{ + /* Check that bit was clear */ + if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) { + word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit); + return 0; + } else { + //printf("Trying to set already set bit\n"); + return -1; + } +} + +int check_and_clear_contig_bits(u32 *word, int first, int nbits) +{ + for (int i = first; i < first + nbits; i++) + if (check_and_clear_bit(word, i) < 0) + return -1; + return 0; +} + diff --git a/conts/libl4/src/lib/cap/cap.c b/conts/libl4/src/lib/cap/cap.c new file mode 100644 index 0000000..00269c7 --- /dev/null +++ b/conts/libl4/src/lib/cap/cap.c @@ -0,0 +1,179 @@ +/* + * Capability-related userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include + +/* A static limit to total capabilities held by the library */ +#define CAPS_TOTAL 64 + +static struct capability cap_array[CAPS_TOTAL]; + +static int total_caps = 0; + +struct capability *cap_get_by_type(unsigned int cap_type) +{ + for (int i = 0; i < total_caps; i++) + if (cap_type(&cap_array[i]) == cap_type) + return &cap_array[i]; + return 0; +} + +struct capability *cap_get_physmem(unsigned int cap_type) +{ + for (int i = 0; i < total_caps; i++) + if ((cap_type(&cap_array[i]) == CAP_TYPE_MAP_PHYSMEM) && + !cap_is_devmem(&cap_array[i])) { + return &cap_array[i]; + } + return 0; +} + +/* + * Read all capabilities + */ +int caps_read_all(void) +{ + int err; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, &total_caps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + return err; + } + + if (total_caps > CAPS_TOTAL) { + printf("FATAL: More capabilities defined for the " + "container than the libl4 static limit. libl4 " + "limit=%d, actual = %d\n", CAPS_TOTAL, total_caps); + BUG(); + } + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, cap_array)) < 0) { + printf("l4_capability resource_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ request.\n"); + return err; + } + //cap_array_print(ncaps, caparray); + + return 0; +} + +void __l4_capability_init(void) +{ + caps_read_all(); +} + +void cap_dev_print(struct capability *cap) +{ + switch (cap_devtype(cap)) { + case CAP_DEVTYPE_UART: + printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap)); + break; + case CAP_DEVTYPE_TIMER: + printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap)); + break; + default: + return; + } + printf("Device Irq:\t\t%d\n", cap->irq); +} + +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: + if (!cap_is_devmem(cap)) { + printf("Capability type:\t\t%s\n", "Map/Physmem"); + } else { + printf("Capability type:\t\t%s\n", "Map/Physmem/Device"); + cap_dev_print(cap); + } + 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_IRQCTRL: + printf("Capability type:\t\t%s\n", "IRQ Control"); + 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(int total_caps, struct capability *caparray) +{ + printf("Capabilities\n" + "~~~~~~~~~~~~\n"); + + for (int i = 0; i < total_caps; i++) + cap_print(&caparray[i]); + + printf("\n"); +} + + diff --git a/conts/libl4/src/lib/cap/read.c b/conts/libl4/src/lib/cap/read.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/conts/libl4/src/lib/cap/read.c @@ -0,0 +1 @@ + diff --git a/conts/libl4/src/lib/idpool.c b/conts/libl4/src/lib/idpool.c new file mode 100644 index 0000000..71ca9b6 --- /dev/null +++ b/conts/libl4/src/lib/idpool.c @@ -0,0 +1,93 @@ +/* + * Used for thread and space ids, and also for + * utcb tracking in page-sized-chunks. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include +#include + +void id_pool_init(struct id_pool *pool, int totalbits) +{ + pool->nwords = BITWISE_GETWORD(totalbits) + 1; + pool->bitlimit = totalbits; +} + +struct id_pool *id_pool_new_init(int totalbits) +{ + int nwords = BITWISE_GETWORD(totalbits) + 1; + struct id_pool *new = kzalloc((nwords * SZ_WORD) + + sizeof(struct id_pool)); + if (!new) + return PTR_ERR(-ENOMEM); + + new->nwords = nwords; + new->bitlimit = totalbits; + + return new; +} + +/* Search for a free slot up to the limit given */ +int id_new(struct id_pool *pool) +{ + return find_and_set_first_free_bit(pool->bitmap, pool->bitlimit); +} + +/* This finds n contiguous free ids, allocates and returns the first one */ +int ids_new_contiguous(struct id_pool *pool, int numids) +{ + int id = find_and_set_first_free_contig_bits(pool->bitmap, + pool->bitlimit, + numids); + if (id < 0) + printf("%s: Warning! New id alloc failed\n", __FUNCTION__); + return id; +} + +/* This deletes a list of contiguous ids given the first one and number of ids */ +int ids_del_contiguous(struct id_pool *pool, int first, int numids) +{ + int ret; + + if (pool->nwords * WORD_BITS < first + numids) + return -1; + if ((ret = check_and_clear_contig_bits(pool->bitmap, first, numids))) + printf("%s: Error: Invalid argument range.\n", __FUNCTION__); + return ret; +} + +int id_del(struct id_pool *pool, int id) +{ + int ret; + + if (pool->nwords * WORD_BITS < id) + return -1; + + if ((ret = check_and_clear_bit(pool->bitmap, id) < 0)) + printf("%s: Error: Could not delete id.\n", __FUNCTION__); + return ret; +} + +/* Return a specific id, if available */ +int id_get(struct id_pool *pool, int id) +{ + int ret; + + ret = check_and_set_bit(pool->bitmap, id); + + if (ret < 0) + return ret; + else + return id; +} + +int id_is_empty(struct id_pool *pool) +{ + for (int i = 0; i < pool->nwords; i++) + if (pool->bitmap[i]) + return 0; + return 1; +} + diff --git a/conts/libl4/src/lib/thread/init.c b/conts/libl4/src/lib/thread/init.c new file mode 100644 index 0000000..77ea75d --- /dev/null +++ b/conts/libl4/src/lib/thread/init.c @@ -0,0 +1,71 @@ + +#include +#include +#include + +/* + * Static stack and utcb for same-space threads. + * +1 is a good approximation for allocating for bitmap + * structures in the memcache. + */ +static char stack[THREADS_TOTAL * (STACK_SIZE + 1)] ALIGN(STACK_SIZE); +static char utcb[THREADS_TOTAL * (UTCB_SIZE + 1)] ALIGN(UTCB_SIZE); + +struct mem_cache *utcb_cache; +struct mem_cache *stack_cache; + +struct l4_thread_list l4_thread_list; + +/* Number of thread structs + allowance for memcache internal data */ +#define L4_THREAD_LIST_BUFFER_SIZE (THREADS_TOTAL * \ + (sizeof(struct l4_thread_list)) + 256) + +static char l4_thread_list_buf[L4_THREAD_LIST_BUFFER_SIZE]; + +void l4_thread_list_init(void) +{ + struct l4_thread_list *tlist = &l4_thread_list; + + /* Initialize the head struct */ + memset(tlist, 0, sizeof (*tlist)); + link_init(&tlist->thread_list); + l4_mutex_init(&tlist->lock); + + /* Initialize a cache of l4_thread_list structs */ + if (!(tlist->thread_cache = + mem_cache_init(&l4_thread_list_buf, + L4_THREAD_LIST_BUFFER_SIZE, + sizeof(struct l4_thread), 0))) { + printf("FATAL: Could not initialize internal " + "thread struct cache.\n"); + BUG(); + } +} + +void l4_stack_alloc_init(void) +{ + BUG_ON(!(stack_cache = + mem_cache_init((void *)stack, STACK_SIZE * + (THREADS_TOTAL + 1), + STACK_SIZE, STACK_SIZE))); +} + +/* + * Initialize a memcache that is aligned to utcb size + */ +void l4_utcb_alloc_init(void) +{ + BUG_ON(!(utcb_cache = + mem_cache_init((void *)utcb, UTCB_SIZE * + (THREADS_TOTAL + 1), + UTCB_SIZE, UTCB_SIZE))); +} + +void __l4_threadlib_init(void) +{ + l4_utcb_alloc_init(); + l4_stack_alloc_init(); + l4_thread_list_init(); + l4_parent_thread_init(); +} + diff --git a/conts/libl4/src/lib/thread/thread.c b/conts/libl4/src/lib/thread/thread.c new file mode 100644 index 0000000..7de4391 --- /dev/null +++ b/conts/libl4/src/lib/thread/thread.c @@ -0,0 +1,286 @@ +/* + * Thread creation userspace helpers + * + * Copyright (C) 2009 - 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include +#include +#include +#include +#include + +void *l4_utcb_alloc(void) +{ + return mem_cache_alloc(utcb_cache); +} + +void l4_utcb_free(void *utcb) +{ + BUG_ON(mem_cache_free(utcb_cache, utcb) < 0); +} + +void *l4_stack_alloc(void) +{ + void *stack = mem_cache_alloc(stack_cache); + + /* Since it will grow downwards */ + stack += (unsigned long)STACK_SIZE; + + return stack; +} + +/* + * NOTE: may be unaligned + */ +void l4_stack_free(void *stack) +{ + /* Allocation pointer was from beginning of stack */ + stack -= (unsigned long)STACK_SIZE; + BUG_ON(mem_cache_free(stack_cache, stack) < 0); +} + +/* + * Allocate and init a thread struct for same space + */ +struct l4_thread *l4_thread_init(struct l4_thread *thread) +{ + /* + * Allocate stack and utcb + */ + if (!(thread->utcb = l4_utcb_alloc())) + return PTR_ERR(-ENOMEM); + if (!(thread->stack = l4_stack_alloc())) { + l4_utcb_free(thread->utcb); + return PTR_ERR(-ENOMEM); + } + return thread; +} + +void l4_thread_free(struct l4_thread *thread) +{ + struct l4_thread_list *tlist = &l4_thread_list; + + /* Lock the list */ + l4_mutex_lock(&tlist->lock); + + /* Lock the thread */ + l4_mutex_lock(&thread->lock); + + /* Remove the thread from its list */ + list_remove(&thread->list); + tlist->total--; + + /* Unlock list */ + l4_mutex_unlock(&tlist->lock); + + /* Free thread's stack and utcb if they exist */ + if (thread->stack) + l4_stack_free(thread->stack); + if (thread->utcb) + l4_utcb_free(thread->utcb); + + /* Free the thread itself */ + BUG_ON(mem_cache_free(tlist->thread_cache, thread) < 0); +} + +/* + * No locking version + */ +void l4_thread_free_nolock(struct l4_thread *thread) +{ + struct l4_thread_list *tlist = &l4_thread_list; + + /* Free thread's stack and utcb if they exist */ + if (thread->stack) + l4_stack_free(thread->stack); + if (thread->utcb) + l4_utcb_free(thread->utcb); + + /* Free the thread itself */ + BUG_ON(mem_cache_free(tlist->thread_cache, thread) < 0); +} + +/* + * Destroys a child thread and reclaims its + * stack and utcb. + * + * NOTE: This function is to be called with caution: + * The destroyed child must be in a state that will + * not compromise the system integrity, i.e. not holding + * any locks, not in the middle of an operation. + * + * We usually don't know whether a synchronous destruction + * would cause the thread to leave structures prematurely + * (e.g. need to figure out a way of knowing if the thread + * is holding any locks, busy, has children ...) + */ +int thread_destroy(struct l4_thread *thread) +{ + struct l4_thread_list *tlist = &l4_thread_list; + int err; + + /* Lock the list */ + l4_mutex_lock(&tlist->lock); + + /* Lock the thread */ + l4_mutex_lock(&thread->lock); + + /* Remove the thread from its list */ + list_remove(&thread->list); + tlist->total--; + + /* Unlock list */ + l4_mutex_unlock(&tlist->lock); + + /* Destroy the thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &thread->ids)) < 0) + return err; + + /* Reclaim l4_thread structure */ + l4_thread_free_nolock(thread); + + return 0; +} + +struct l4_thread *l4_thread_alloc_init(void) +{ + struct l4_thread_list *tlist = &l4_thread_list; + struct l4_thread *thread; + + if (!(thread = mem_cache_zalloc(tlist->thread_cache))) + return PTR_ERR(-ENOMEM); + + link_init(&thread->list); + l4_mutex_init(&thread->lock); + + if (IS_ERR(thread = l4_thread_init(thread))) { + mem_cache_free(tlist->thread_cache, thread); + return PTR_ERR(thread); + } + + list_insert(&tlist->thread_list, &thread->list); + tlist->total++; + + return thread; +} + +/* + * Called during initialization for setting up the + * existing runnable thread + */ +void l4_parent_thread_init(void) +{ + struct l4_thread *thread; + struct exregs_data exregs; + int err; + + /* Allocate structures for the first thread */ + thread = l4_thread_alloc_init(); + + /* Free the allocated stack since its unnecessary */ + l4_stack_free(thread->stack); + + /* Read thread ids */ + l4_getid(&thread->ids); + + /* Set up utcb via exregs */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_utcb(&exregs, (unsigned long)thread->utcb); + if ((err = l4_exchange_registers(&exregs, + thread->ids.tid)) < 0) { + printf("FATAL: Initialization of structures for " + "currently runnable thread has failed.\n" + "exregs err=%d\n", err); + l4_thread_free(thread); + } +} + +/* For threads to exit on their own without any library maintenance */ +void thread_exit(int exit_code) +{ + struct task_ids ids; + + /* FIXME: Find this from utcb */ + l4_getid(&ids); + l4_thread_control(THREAD_DESTROY | exit_code, &ids); +} + +int thread_wait(struct l4_thread *thread) +{ + int ret; + + /* Wait for the thread to exit */ + if ((ret = l4_thread_control(THREAD_WAIT, &thread->ids)) < 0) + return ret; + + /* Claim its library structures */ + l4_thread_free(thread); + + /* Return zero or positive thread exit code */ + return ret; +} + +/* + * Create a new thread in the same address space as caller + */ +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct l4_thread **tptr) +{ + struct exregs_data exregs; + struct l4_thread *thread; + int err; + + /* Shared space only */ + if (!(TC_SHARE_SPACE & flags)) { + printf("%s: Warning - This function allows only " + "shared space thread creation.\n", + __FUNCTION__); + return -EINVAL; + } + + /* Allocate a thread struct */ + if (IS_ERR(thread = l4_thread_alloc_init())) + return (int)thread; + + /* Assign own space id since TC_SHARE_SPACE requires it */ + l4_getid(&thread->ids); + + /* Create thread in kernel */ + if ((err = l4_thread_control(THREAD_CREATE | + flags, &thread->ids)) < 0) + goto out_err; + + /* First word of new stack is arg */ + thread->stack[-1] = (unsigned long)args; + + /* Second word of new stack is function address */ + thread->stack[-2] = (unsigned long)func; + + /* Setup new thread pc, sp, utcb */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_stack(&exregs, (unsigned long)thread->stack); + exregs_set_utcb(&exregs, (unsigned long)thread->utcb); + exregs_set_pc(&exregs, (unsigned long)setup_new_thread); + + if ((err = l4_exchange_registers(&exregs, thread->ids.tid)) < 0) + goto out_err; + + /* Start the new thread, unless specified otherwise */ + if (!(flags & TC_NOSTART)) + if ((err = l4_thread_control(THREAD_RUN, + &thread->ids)) < 0) + goto out_err; + + /* Set pointer to thread structure */ + *tptr = thread; + + return 0; + +out_err: + l4_thread_free(thread); + return err; +} + diff --git a/conts/libl4/src/mutex.c b/conts/libl4/src/mutex.c index 0d7dab0..8fc0bcb 100644 --- a/conts/libl4/src/mutex.c +++ b/conts/libl4/src/mutex.c @@ -5,8 +5,8 @@ */ #include #include -#include -#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) /* * NOTES: diff --git a/conts/libl4/src/thread/tcb.c b/conts/libl4/src/thread/tcb.c index 9cc822b..2804195 100644 --- a/conts/libl4/src/thread/tcb.c +++ b/conts/libl4/src/thread/tcb.c @@ -17,7 +17,7 @@ struct l4lib_global_list global_tasks = { }; /* Function definitions */ -void global_add_task(struct l4lib_tcb *task) +void l4lib_global_add_task(struct l4lib_tcb *task) { BUG_ON(!list_empty(&task->list)); list_insert_tail(&task->list, &global_tasks.list); diff --git a/conts/libl4/src/thread/thread.c b/conts/libl4/src/thread/thread.c index 5578936..7b5fb46 100644 --- a/conts/libl4/src/thread/thread.c +++ b/conts/libl4/src/thread/thread.c @@ -22,8 +22,6 @@ extern unsigned long lib_utcb_range_size; /* Static variable definitions */ struct l4_mutex lib_mutex; -extern void global_add_task(struct l4lib_tcb *task); - /* Function definitions */ int l4_thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg) diff --git a/conts/libl4/src/thread/utcb-common.c b/conts/libl4/src/thread/utcb-common.c index 8991b91..053896a 100644 --- a/conts/libl4/src/thread/utcb-common.c +++ b/conts/libl4/src/thread/utcb-common.c @@ -7,6 +7,7 @@ #include #include #include +#include INC_GLUE(message.h) /* Globally disjoint utcb virtual region pool */ static struct address_pool utcb_region_pool; diff --git a/conts/libl4/src/thread/utcb.c b/conts/libl4/src/thread/utcb.c index 2d21141..eeaab39 100644 --- a/conts/libl4/src/thread/utcb.c +++ b/conts/libl4/src/thread/utcb.c @@ -130,6 +130,7 @@ int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) "than utcb start address.\n"); return -EINVAL; } +#if 0 /* * This check guarantees two things: * 1. The range must be multiple of UTCB_SIZE, at least one item. @@ -140,6 +141,7 @@ int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) "of the utcb size(%d).\n", UTCB_SIZE); return -EINVAL; } +#endif /* Arguments passed the validity tests. */ /* Init utcb virtual address pool. */ diff --git a/conts/libmem/SConscript b/conts/libmem/SConscript index de74643..d109462 100644 --- a/conts/libmem/SConscript +++ b/conts/libmem/SConscript @@ -12,28 +12,20 @@ sys.path.append(PROJRELROOT) from config.projpaths import * from configure import * -config = configuration_retrieve() +Import('env') -KERNEL_INCLUDE = join(PROJROOT, 'include') LIBL4_RELDIR = 'conts/libl4' LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) LIBL4_INCLUDE = join(LIBL4_DIR, 'include') -LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR) -env = Environment(CC = config.user_toolchain + 'gcc', - CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'], - LINKFLAGS = ['-nostdlib'], - ASFLAGS = ['-D__ASSEMBLY__'], - ENV = {'PATH' : os.environ['PATH']}, - LIBS = 'gcc', - CPPPATH = ['.', KERNEL_INCLUDE, LIBL4_INCLUDE], - CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') +e = env.Clone() +e.Append(CPPPATH = ['include', '.', LIBL4_INCLUDE]) -objmm = env.StaticObject(Glob('mm/*.c')) -objmc = env.StaticObject(Glob('memcache/*.[cS]')) -objmalloc = env.StaticObject(Glob('malloc/*.[cS]')) -libmm = env.StaticLibrary('mm', objmm) -libmc = env.StaticLibrary('mc', objmc) -libmalloc = env.StaticLibrary('malloc', objmalloc) +objmm = e.StaticObject(Glob('mm/*.c')) +objmc = e.StaticObject(Glob('memcache/*.[cS]')) +objmalloc = e.StaticObject(Glob('malloc/*.[cS]')) +libmm = e.StaticLibrary('mm', objmm) +libmc = e.StaticLibrary('mc', objmc) +libmalloc = e.StaticLibrary('malloc', objmalloc) Return('libmm', 'libmc', 'libmalloc') diff --git a/conts/libmem/SConstruct b/conts/libmem/SConstruct index 7636a63..a579c79 100644 --- a/conts/libmem/SConstruct +++ b/conts/libmem/SConstruct @@ -10,7 +10,9 @@ PROJRELROOT = '../..' sys.path.append(PROJRELROOT) from configure import * +from config.projpaths import * config = configuration_retrieve() +gcc_arch_flag = config.gcc_arch_flag headers_root = join(PROJRELROOT, "include/l4") config_h = join(headers_root, "config.h") @@ -28,21 +30,24 @@ tests_dir = tests LIBL4_RELDIR = 'conts/libl4' LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) LIBL4_INCLUDE = join(LIBL4_DIR, 'include') -LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR) -test_env = Environment(CC = 'gcc -m32', - CCFLAGS = ['-g', '-std=gnu99', '-Wall', '-Werror'], +# This does not work, need to check +test_env = Environment(CC = config.toolchain + 'gcc', + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \ + '-nostdinc', '-Werror', '-march=' + gcc_arch_flag], ENV = {'PATH' : os.environ['PATH']}, - LIBS = ['gcc', 'mm', 'km', 'mc'], + LIBS = ['mm', 'km', 'mc'], LIBPATH = ['#'], CPPPATH = ['#include', join(PROJRELROOT, "include"), "#", LIBL4_INCLUDE]) -env = Environment(CC = config.user_toolchain + 'gcc', - CCFLAGS = ['-g', '-nostdlib', '-Wall', '-Werror', '-ffreestanding', '-std=gnu99'], - LINKFLAGS = ['-nostdlib'], - ENV = {'PATH' : os.environ['PATH']}, - LIBS = 'gcc', - CPPPATH = [join(PROJRELROOT, "include"), "#", LIBL4_INCLUDE]) +env = Environment(CC = config.toolchain + 'gcc', + CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \ + '-Wall', '-Werror', '-march=' + gcc_arch_flag], + LINKFLAGS = ['-nostdlib'], + ASFLAGS = ['-D__ASSEMBLY__'], + ENV = {'PATH' : os.environ['PATH']}, + LIBS = 'gcc', + CPPPATH = ['.', join(PROJROOT, 'include'), LIBL4_INCLUDE]) if os.path.exists(config_h) is False: print "\nThis build requires a valid kernel configuration header." diff --git a/conts/libmem/memcache/memcache.c b/conts/libmem/memcache/memcache.c index 7bd1d17..0ce8104 100644 --- a/conts/libmem/memcache/memcache.c +++ b/conts/libmem/memcache/memcache.c @@ -179,12 +179,13 @@ struct mem_cache *mem_cache_init(void *start, unsigned int diff = addr_aligned - addr; BUG_ON(diff >= struct_size); - if (diff) - total--; cache_size -= diff; area_start = addr_aligned; } + /* Now recalculate total over cache bytes left */ + total = cache_size / struct_size; + link_init(&cache->list); cache->start = area_start; cache->end = area_start + cache_size; diff --git a/conts/libmem/mm/alloc_page.c b/conts/libmem/mm/alloc_page.c index ae46cf6..730213c 100644 --- a/conts/libmem/mm/alloc_page.c +++ b/conts/libmem/mm/alloc_page.c @@ -9,12 +9,13 @@ #include #include #include -#include -#include #include "alloc_page.h" #include INC_GLUE(memory.h) #include INC_SUBARCH(mm.h) #include INC_GLUE(memlayout.h) +#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) struct page_allocator allocator; @@ -95,7 +96,7 @@ void init_page_allocator(unsigned long start, unsigned long end) link_init(&allocator.pga_cache_list); /* Initialise the first page area cache */ - cache = mem_cache_init(l4_map_helper((void *)start, 1), PAGE_SIZE, + cache = mem_cache_init(phys_to_virt((void *)start), PAGE_SIZE, sizeof(struct page_area), 0); list_insert(&cache->list, &allocator.pga_cache_list); @@ -134,7 +135,6 @@ int check_page_areas(struct page_allocator *p) { struct page_area *new; struct mem_cache *newcache; - void *newpage; /* If only one free area left */ if (p->pga_free == 1) { @@ -146,12 +146,9 @@ int check_page_areas(struct page_allocator *p) /* Free page areas must now be reduced to 0 */ BUG_ON(p->pga_free != 0); - /* Map the new page into virtual memory */ - newpage = l4_map_helper((void *)__pfn_to_addr(new->pfn), 1); - /* Initialise it as a new source of page area structures */ - newcache = mem_cache_init(newpage, PAGE_SIZE, - sizeof(struct page_area), 0); + newcache = mem_cache_init(phys_to_virt((void *)__pfn_to_addr(new->pfn)), + PAGE_SIZE, sizeof(struct page_area), 0); /* * Update the free page area counter @@ -209,7 +206,12 @@ struct page_area *merge_free_areas(struct page_area *before, /* Recursively free the cache page */ if (mem_cache_is_empty(c)) { list_remove(&c->list); - BUG_ON(free_page(l4_unmap_helper(c, 1)) < 0) + if (free_page(virt_to_phys(c)) < 0) { + printf("Page ptr: 0x%lx, virt_to_phys = 0x%lx\n" + "Page not found in cache.\n", + (unsigned long)c, (unsigned long)virt_to_phys(c)); + BUG(); + } } return before; } diff --git a/conts/libmem/tests/debug.h b/conts/libmem/tests/debug.h index 9110321..3a9cda3 100644 --- a/conts/libmem/tests/debug.h +++ b/conts/libmem/tests/debug.h @@ -1,7 +1,7 @@ #ifndef __DEBUG_H__ #define __DEBUG_H__ -#include +//#include #include #include diff --git a/conts/libmem/tests/main.c b/conts/libmem/tests/main.c index 4a6a4c8..0f3cecd 100644 --- a/conts/libmem/tests/main.c +++ b/conts/libmem/tests/main.c @@ -10,7 +10,7 @@ #include INC_SUBARCH(mm.h) #include INC_ARCH(linker.h) -#include INC_PLAT(printascii.h) +#include INC_PLAT(print-early.h) #include INC_PLAT(offsets.h) #include INC_GLUE(memlayout.h) diff --git a/conts/posix/SConstruct b/conts/posix/SConstruct index 675f95e..90cc306 100644 --- a/conts/posix/SConstruct +++ b/conts/posix/SConstruct @@ -18,6 +18,7 @@ from config.lib import * config = configuration_retrieve() arch = config.arch +gcc_arch_flag = config.gcc_arch_flag LIBL4_RELDIR = 'conts/libl4' KERNEL_INCLUDE = join(PROJROOT, 'include') @@ -48,25 +49,27 @@ LIBPOSIX_INCLUDE_SERVER = join(LIBPOSIX_DIR, 'include') LIBPOSIX_INCLUDE_USERSPACE = join(LIBPOSIX_DIR, 'include/posix') LIBPOSIX_LIBPATH = join(BUILDDIR, LIBPOSIX_RELDIR) -env = Environment(CC = config.user_toolchain + 'gcc', - CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', \ - '-std=gnu99', '-Wall', '-Werror'], - LINKFLAGS = ['-nostdlib'], - ASFLAGS = ['-D__ASSEMBLY__'], - PROGSUFFIX = '.elf', - ENV = {'PATH' : os.environ['PATH']}, - LIBS = ['gcc', 'libl4', 'c-userspace','libdev-userspace', \ - 'libmm', 'libmc', 'libmalloc', 'gcc'], - CPPPATH = ['include', LIBDEV_INCLUDE, LIBC_INCLUDE, KERNEL_INCLUDE, - LIBL4_INCLUDE, LIBMEM_INCLUDE], - LIBPATH = [LIBDEV_LIBPATH, LIBC_LIBPATH, LIBL4_LIBPATH, - LIBMEM_LIBPATH, LIBPOSIX_LIBPATH], - CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') +env = Environment(CC = config.toolchain + 'gcc', + AR = config.toolchain + 'ar', + RANLIB = config.toolchain + 'ranlib', + CCFLAGS = ['-g','-nostdinc', '-nostdlib', '-ffreestanding', + '-march=' + gcc_arch_flag, '-std=gnu99', '-Wall', '-Werror'], + LINKFLAGS = ['-nostdlib'], + ASFLAGS = ['-D__ASSEMBLY__'], + PROGSUFFIX = '.elf', + ENV = {'PATH' : os.environ['PATH']}, + LIBS = ['libl4', 'libdev-userspace', 'gcc', 'c-userspace', \ + 'gcc', 'libmm', 'libmc', 'libmalloc'], + CPPPATH = ['include', LIBDEV_INCLUDE, LIBC_INCLUDE, KERNEL_INCLUDE, + LIBL4_INCLUDE, LIBMEM_INCLUDE, LIBPOSIX_INCLUDE_USERSPACE], + LIBPATH = [LIBDEV_LIBPATH, LIBC_LIBPATH, LIBL4_LIBPATH, + LIBMEM_LIBPATH, LIBPOSIX_LIBPATH], + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') contid = ARGUMENTS.get('cont', '0') libposix_env = env.Clone() -libposix_env.Replace(CPPPATH = [LIBPOSIX_INCLUDE_USERSPACE, 'include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE]) +libposix_env.Replace(CPPPATH = [LIBPOSIX_INCLUDE_USERSPACE, 'include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE, LIBC_INCLUDE]) libposix = SConscript('libposix/SConscript', \ exports = { 'config' : config, 'env' : libposix_env, 'contid' : contid}, duplicate = 0, \ variant_dir = join(BUILDDIR, 'conts' + '/posix' + '/libposix')) @@ -83,7 +86,7 @@ rootfs = SConscript('rootfs/SConscript', \ # No libposix reference because it conflicts with the compiler C library + the cluncky libc we have. test0_env = env.Clone() -test0_env.Replace(CPPPATH = ['include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE]) +test0_env.Replace(CPPPATH = ['include', KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE, LIBC_INCLUDE, LIBPOSIX_INCLUDE_USERSPACE]) test0 = SConscript('test0/SConscript', \ exports = { 'config' : config, 'environment' : test0_env, 'contid' : contid, 'previmage' : rootfs }, duplicate = 0, \ variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/test0')) diff --git a/conts/posix/bootdesc/SConscript b/conts/posix/bootdesc/SConscript index 77875af..5e4eed9 100644 --- a/conts/posix/bootdesc/SConscript +++ b/conts/posix/bootdesc/SConscript @@ -97,8 +97,8 @@ def relocate_bootdesc(target, source, env): images = source[1:] mm0 = images[0] start, end = image_lma_start_end(mm0.path) - print config.user_toolchain + "objcopy --adjust-section-vma .data=" + conv_hex(end) + " " + bootdesc_raw.path - os.system(config.user_toolchain + "objcopy --adjust-section-vma .data=" + conv_hex(end) + " " + bootdesc_raw.path) + print config.toolchain + "objcopy --adjust-section-vma .data=" + conv_hex(end) + " " + bootdesc_raw.path + os.system(config.toolchain + "objcopy --adjust-section-vma .data=" + conv_hex(end) + " " + bootdesc_raw.path) shutil.copyfile(bootdesc_raw.path, target[0].path) bootdesc_c = e.Command('bootdesc.c', images, generate_bootdesc) diff --git a/conts/posix/bootdesc/SConstruct b/conts/posix/bootdesc/SConstruct index 641b15f..8fbecac 100644 --- a/conts/posix/bootdesc/SConstruct +++ b/conts/posix/bootdesc/SConstruct @@ -12,7 +12,7 @@ from configure import * config = configuration_retrieve() builddir = ARGUMENTS.get('builddir', 'build/conts/posix') -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.toolchain + 'gcc', CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'], LINKFLAGS = ['-nostdlib','-Tlinker.lds'], ASFLAGS = ['-D__ASSEMBLY__'], diff --git a/conts/posix/libposix/SConscript b/conts/posix/libposix/SConscript index cda7781..f9c8557 100644 --- a/conts/posix/libposix/SConscript +++ b/conts/posix/libposix/SConscript @@ -8,7 +8,8 @@ Import('env') e = env.Clone() e.Append(CPPPATH = ['include', 'include/posix']) -e.Replace(CCFLAGS = ['-g', '-nostdlib', '-Wall', '-Werror', '-ffreestanding', '-std=gnu99']) +e.Replace(CCFLAGS = ['-g','-nostdinc', '-nostdlib', '-Wall', '-Werror', '-ffreestanding', '-std=gnu99'], + CPPFLAGS = ' -include l4lib/macros.h ') objects = e.StaticObject(Glob('*.c')) libposix = e.StaticLibrary('posix', objects) diff --git a/conts/posix/libposix/SConstruct b/conts/posix/libposix/SConstruct index 1423aca..8e11147 100644 --- a/conts/posix/libposix/SConstruct +++ b/conts/posix/libposix/SConstruct @@ -16,7 +16,7 @@ kernel_headers = join(project_root, "include") l4lib_headers = join(project_root, "tasks/libl4/include") config_h = join(project_root, "include/l4/config.h") -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.toolchain + 'gcc', CCFLAGS = ['-g', '-std=gnu99', '-nostdlib', '-ffreestanding'], LINKFLAGS = ['-nostdlib'], CPPPATH = ['#include'], diff --git a/conts/posix/libposix/chdir.c b/conts/posix/libposix/chdir.c index ce48e39..9426653 100644 --- a/conts/posix/libposix/chdir.c +++ b/conts/posix/libposix/chdir.c @@ -11,8 +11,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/conts/posix/libposix/close.c b/conts/posix/libposix/close.c index d45e63d..257d657 100644 --- a/conts/posix/libposix/close.c +++ b/conts/posix/libposix/close.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/execve.c b/conts/posix/libposix/execve.c index fc01fd1..27e8e3f 100644 --- a/conts/posix/libposix/execve.c +++ b/conts/posix/libposix/execve.c @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/exit.c b/conts/posix/libposix/exit.c index b396eba..d703296 100644 --- a/conts/posix/libposix/exit.c +++ b/conts/posix/libposix/exit.c @@ -1,6 +1,6 @@ -#include -#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) #include #include #include diff --git a/conts/posix/libposix/fork.c b/conts/posix/libposix/fork.c index f679b43..306e6ec 100644 --- a/conts/posix/libposix/fork.c +++ b/conts/posix/libposix/fork.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/getpid.c b/conts/posix/libposix/getpid.c index d4f9287..cc523aa 100644 --- a/conts/posix/libposix/getpid.c +++ b/conts/posix/libposix/getpid.c @@ -1,6 +1,4 @@ -#include -#include #include #include #include diff --git a/conts/posix/libposix/include/libposix.h b/conts/posix/libposix/include/libposix.h index d0f05db..c7c4682 100644 --- a/conts/posix/libposix/include/libposix.h +++ b/conts/posix/libposix/include/libposix.h @@ -1,6 +1,12 @@ #ifndef __LIBPOSIX_H__ #define __LIBPOSIX_H__ +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) + +#include +#include + /* Abort debugging conditions */ // #define LIBPOSIX_ERROR_MESSAGES #if defined (LIBPOSIX_ERROR_MESSAGES) diff --git a/conts/posix/libposix/include/posix/bits/local_lim.h b/conts/posix/libposix/include/posix/bits/local_lim.h index 023ebf3..c64b495 100644 --- a/conts/posix/libposix/include/posix/bits/local_lim.h +++ b/conts/posix/libposix/include/posix/bits/local_lim.h @@ -33,7 +33,7 @@ #endif /* The kernel sources contain a file with all the needed information. */ -#include +//#include /* Have to remove NR_OPEN? */ #ifdef __undef_NR_OPEN diff --git a/conts/posix/libposix/include/posix/bits/uClibc_pthread.h b/conts/posix/libposix/include/posix/bits/uClibc_pthread.h index 1d6209f..9e1016c 100644 --- a/conts/posix/libposix/include/posix/bits/uClibc_pthread.h +++ b/conts/posix/libposix/include/posix/bits/uClibc_pthread.h @@ -23,9 +23,9 @@ #ifndef _UCLIBC_PTHREAD_H #define _UCLIBC_PTHREAD_H -#ifndef _PTHREAD_H -# error "Always include rather than " -#endif +//#ifndef _PTHREAD_H +//# error "Always include rather than " +//#endif #if defined _LIBC && (defined IS_IN_libc || defined NOT_IN_libc) /* Threading functions internal to uClibc. Make these thread functions diff --git a/include/l4/arch/arm/v7/mutex.h b/conts/posix/libposix/include/posix/pthread.h similarity index 100% rename from include/l4/arch/arm/v7/mutex.h rename to conts/posix/libposix/include/posix/pthread.h diff --git a/conts/posix/libposix/include/posix/shpage.h b/conts/posix/libposix/include/posix/shpage.h index 1d12790..77fab8c 100644 --- a/conts/posix/libposix/include/posix/shpage.h +++ b/conts/posix/libposix/include/posix/shpage.h @@ -8,11 +8,11 @@ #define __LIBPOSIX_SHPAGE_H__ #include -#include -#include #include #include #include INC_GLUE(memory.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) extern void *shared_page; diff --git a/conts/posix/libposix/include/posix/stdio.h b/conts/posix/libposix/include/posix/stdio.h index fd2a738..445200d 100644 --- a/conts/posix/libposix/include/posix/stdio.h +++ b/conts/posix/libposix/include/posix/stdio.h @@ -328,16 +328,16 @@ extern int sprintf (char *__restrict __s, This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format, - __gnuc_va_list __arg); +//extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format, +// __gnuc_va_list __arg); /* Write formatted output to stdout from argument list ARG. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg); +//extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg); /* Write formatted output to S from argument list ARG. */ -extern int vsprintf (char *__restrict __s, __const char *__restrict __format, - __gnuc_va_list __arg) __THROW; +//extern int vsprintf (char *__restrict __s, __const char *__restrict __format, +// __gnuc_va_list __arg) __THROW; __END_NAMESPACE_STD #if defined __USE_BSD || defined __USE_ISOC99 || defined __USE_UNIX98 @@ -347,18 +347,18 @@ extern int snprintf (char *__restrict __s, size_t __maxlen, __const char *__restrict __format, ...) __THROW __attribute__ ((__format__ (__printf__, 3, 4))); -extern int vsnprintf (char *__restrict __s, size_t __maxlen, - __const char *__restrict __format, __gnuc_va_list __arg) - __THROW __attribute__ ((__format__ (__printf__, 3, 0))); +//extern int vsnprintf (char *__restrict __s, size_t __maxlen, +// __const char *__restrict __format, __gnuc_va_list __arg) +// __THROW __attribute__ ((__format__ (__printf__, 3, 0))); __END_NAMESPACE_C99 #endif #ifdef __USE_GNU /* Write formatted output to a string dynamically allocated with `malloc'. Store the address of the string in *PTR. */ -extern int vasprintf (char **__restrict __ptr, __const char *__restrict __f, - __gnuc_va_list __arg) - __THROW __attribute__ ((__format__ (__printf__, 2, 0))); +//extern int vasprintf (char **__restrict __ptr, __const char *__restrict __f, +// __gnuc_va_list __arg) +// __THROW __attribute__ ((__format__ (__printf__, 2, 0))); #if 0 /* uClibc: disabled */ extern int __asprintf (char **__restrict __ptr, __const char *__restrict __fmt, ...) @@ -374,8 +374,8 @@ extern int asprintf (char **__restrict __ptr, cancellation point. But due to similarity with an POSIX interface or due to the implementation they are cancellation points and therefore not marked with __THROW. */ -extern int vdprintf (int __fd, __const char *__restrict __fmt, - __gnuc_va_list __arg) +//extern int vdprintf (int __fd, __const char *__restrict __fmt, +// __gnuc_va_list __arg) __attribute__ ((__format__ (__printf__, 2, 0))); extern int dprintf (int __fd, __const char *__restrict __fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); @@ -405,21 +405,21 @@ __BEGIN_NAMESPACE_C99 This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int vfscanf (FILE *__restrict __s, __const char *__restrict __format, - __gnuc_va_list __arg) - __attribute__ ((__format__ (__scanf__, 2, 0))); +//extern int vfscanf (FILE *__restrict __s, __const char *__restrict __format, +// __gnuc_va_list __arg) +// __attribute__ ((__format__ (__scanf__, 2, 0))); /* Read formatted input from stdin into argument list ARG. This function is a possible cancellation point and therefore not marked with __THROW. */ -extern int vscanf (__const char *__restrict __format, __gnuc_va_list __arg) - __attribute__ ((__format__ (__scanf__, 1, 0))); +//extern int vscanf (__const char *__restrict __format, __gnuc_va_list __arg) +// __attribute__ ((__format__ (__scanf__, 1, 0))); /* Read formatted input from S into argument list ARG. */ -extern int vsscanf (__const char *__restrict __s, - __const char *__restrict __format, __gnuc_va_list __arg) - __THROW __attribute__ ((__format__ (__scanf__, 2, 0))); +//extern int vsscanf (__const char *__restrict __s, +// __const char *__restrict __format, __gnuc_va_list __arg) +// __THROW __attribute__ ((__format__ (__scanf__, 2, 0))); __END_NAMESPACE_C99 #endif /* Use ISO C9x. */ diff --git a/conts/posix/libposix/lseek.c b/conts/posix/libposix/lseek.c index 44fa8aa..92a7a83 100644 --- a/conts/posix/libposix/lseek.c +++ b/conts/posix/libposix/lseek.c @@ -7,8 +7,6 @@ #include #include #include -#include -#include #include #include diff --git a/conts/posix/libposix/mkdir.c b/conts/posix/libposix/mkdir.c index ffb4996..3c5a193 100644 --- a/conts/posix/libposix/mkdir.c +++ b/conts/posix/libposix/mkdir.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/mmap.c b/conts/posix/libposix/mmap.c index 7efefcc..ea29c1c 100644 --- a/conts/posix/libposix/mmap.c +++ b/conts/posix/libposix/mmap.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include diff --git a/conts/posix/libposix/open.c b/conts/posix/libposix/open.c index 2c1155a..ec4df71 100644 --- a/conts/posix/libposix/open.c +++ b/conts/posix/libposix/open.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/read.c b/conts/posix/libposix/read.c index c451f17..9bf0f1a 100644 --- a/conts/posix/libposix/read.c +++ b/conts/posix/libposix/read.c @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/shm.c b/conts/posix/libposix/shm.c index 65204a9..1874d6e 100644 --- a/conts/posix/libposix/shm.c +++ b/conts/posix/libposix/shm.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/shpage.c b/conts/posix/libposix/shpage.c index a556104..b1ae5de 100644 --- a/conts/posix/libposix/shpage.c +++ b/conts/posix/libposix/shpage.c @@ -4,17 +4,15 @@ * Copyright (C) 2007-2009 Bahadir Balban */ #include -#include -#include #include #include -#include INC_GLUE(memlayout.h) #include #include #include #include #include #include +#include INC_GLUE(memlayout.h) #if 0 diff --git a/conts/posix/libposix/stat.c b/conts/posix/libposix/stat.c index e87b869..ec9be7f 100644 --- a/conts/posix/libposix/stat.c +++ b/conts/posix/libposix/stat.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/conts/posix/libposix/time.c b/conts/posix/libposix/time.c index 0341bd7..013bb3d 100644 --- a/conts/posix/libposix/time.c +++ b/conts/posix/libposix/time.c @@ -1,5 +1,4 @@ -#include #include #include #include diff --git a/conts/posix/libposix/write.c b/conts/posix/libposix/write.c index c5cd32b..743f621 100644 --- a/conts/posix/libposix/write.c +++ b/conts/posix/libposix/write.c @@ -7,8 +7,6 @@ #include #include #include -#include -#include #include #include diff --git a/conts/posix/mm0/SConscript b/conts/posix/mm0/SConscript index d4bf57d..7c477c1 100644 --- a/conts/posix/mm0/SConscript +++ b/conts/posix/mm0/SConscript @@ -4,22 +4,13 @@ Import('config', 'env', 'contid') import os, sys arch = config.arch +subarch = config.subarch sys.path.append('../../../../') from config.lib import * container = next((c for c in config.containers if int(c.id) == int(contid)), None) -def create_symlinks(arch): - arch_path = "include/arch" - arch_path2 ="src/arch" - if os.path.exists(arch_path): - os.system("rm %s" % (arch_path)) - os.system("ln -s %s %s" % ("arch-" + arch, arch_path)) - if os.path.exists(arch_path2): - os.system("rm %s" % (arch_path2)) - os.system("ln -s %s %s" % ("arch-" + arch, arch_path2)) - def generate_container_h(target, source, env): base_value_dict = {} with open(source[0].path, 'r') as ch_in: @@ -52,13 +43,15 @@ def generate_vma_lma_lds(target, source, env): lma_lds = Command('include/linker.lds', 'include/linker.lds.in', generate_vma_lma_lds) container_h = Command('include/container.h', 'include/container.h.in', generate_container_h) -src = [Glob('*.c') + Glob('mm/*.c') + Glob('lib/*.c') + Glob('fs/*.c') + Glob('fs/memfs/*.c') + Glob('lib/elf/*.c') + Glob('mm/arch/*.[Sc]')] +src = [Glob('*.c') + Glob('mm/*.c') + Glob('lib/*.c') + Glob('fs/*.c') + \ + Glob('fs/memfs/*.c') + Glob('lib/elf/*.c') + Glob('mm/arch/' + arch + '/*.[Sc]') + + Glob('mm/arch/' + arch + '/' + subarch + '/*.[Sc]')] e = env.Clone() e.Append(LINKFLAGS = ['-T' + lma_lds[0].path, '-u_start']) e.Append(LIBS = 'posix') -e.Append(CPPFLAGS = ' -include ' + container_h[0].path) +e.Append(CPPFLAGS = ' -include ' + container_h[0].path + ' -include macros.h -include l4lib/macros.h ') objs = e.Object(src) mm0 = e.Program('mm0.elf', objs) Depends(objs, container_h) diff --git a/conts/posix/mm0/SConstruct b/conts/posix/mm0/SConstruct index b9579c8..fa724aa 100644 --- a/conts/posix/mm0/SConstruct +++ b/conts/posix/mm0/SConstruct @@ -30,7 +30,7 @@ LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR) LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ join(LIBC_DIR, 'include/arch' + '/' + arch)] -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.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', \ @@ -41,7 +41,7 @@ env = Environment(CC = config.user_toolchain + 'gcc', PROGSUFFIX = '.elf', # The suffix to use for final executable ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path LIBS = ['gcc', 'libl4', 'libc', 'libmm', 'libmc'], - CPPPATH = ["#include", LIBC_INCLUDE, KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE], + CPPPATH = ["#include", LIBC_INCLUDE, KERNEL_INCLUDE, LIBL4_INCLUDE], CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -D__KERNEL__') diff --git a/conts/posix/mm0/fs/bdev.c b/conts/posix/mm0/fs/bdev.c index 6a0e1c0..667e9dd 100644 --- a/conts/posix/mm0/fs/bdev.c +++ b/conts/posix/mm0/fs/bdev.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include L4LIB_INC_ARCH(syslib.h) void *vfs_rootdev_open(void) { diff --git a/conts/posix/mm0/include/arch b/conts/posix/mm0/include/arch deleted file mode 120000 index 85405c2..0000000 --- a/conts/posix/mm0/include/arch +++ /dev/null @@ -1 +0,0 @@ -arch-arm \ No newline at end of file diff --git a/conts/posix/mm0/include/arch/arm/debug.h b/conts/posix/mm0/include/arch/arm/debug.h new file mode 100644 index 0000000..5a703d8 --- /dev/null +++ b/conts/posix/mm0/include/arch/arm/debug.h @@ -0,0 +1,44 @@ +/* + * Debug/performance measurements for mm0 + * + * Copyright (C) 2010 B Labs Ltd. + */ +#ifndef __ARCH_DEBUG_H__ +#define __ARCH_DEBUG_H__ + +#if !defined(CONFIG_DEBUG_PERFMON_USER) + +#include + +/* Common empty definitions for all arches */ +static inline u32 perfmon_read_cyccnt() { return 0; } + +static inline void perfmon_reset_start_cyccnt() { } +static inline u32 perfmon_read_reset_start_cyccnt() { return 0; } + +#define debug_record_cycles(str) + +#else /* End of CONFIG_DEBUG_PERFMON_USER */ + +/* Architecture specific perfmon cycle counting */ +#include L4LIB_INC_SUBARCH(perfmon.h) + +extern u64 perfmon_total_cycles; +extern u64 current_cycles; + +/* + * This is for Cortex-A9 running at 400Mhz. 25 / 100000 is + * a rewriting of 2.5 nanosec / 1,000,000 + */ +#define debug_record_cycles(str) \ +{ \ + current_cycles = perfmon_read_cyccnt(); \ + perfmon_total_cycles += current_cycles; \ + printf("%s: took %llu milliseconds\n", str, \ + current_cycles * 64 * 25 / 100000); \ + perfmon_reset_start_cyccnt(); \ +} + +#endif /* End of !CONFIG_DEBUG_PERFMON_USER */ + +#endif /* __ARCH_DEBUG_H__ */ diff --git a/conts/posix/mm0/include/arch/arm/mm.h b/conts/posix/mm0/include/arch/arm/mm.h new file mode 100644 index 0000000..224143d --- /dev/null +++ b/conts/posix/mm0/include/arch/arm/mm.h @@ -0,0 +1,15 @@ +#ifndef __INITTASK_ARCH_MM_H__ +#define __INITTASK_ARCH_MM_H__ + +#include +#include +#include INC_GLUE(memory.h) +#include INC_ARCH(exception.h) +#include + +struct fault_data; +void set_generic_fault_params(struct fault_data *fault); +void arch_print_fault_params(struct fault_data *fault); +void fault_handle_error(struct fault_data *fault); + +#endif /* __INITTASK_ARCH_MM_H__ */ diff --git a/conts/posix/mm0/include/capability.h b/conts/posix/mm0/include/capability.h index d9db553..c1ab667 100644 --- a/conts/posix/mm0/include/capability.h +++ b/conts/posix/mm0/include/capability.h @@ -6,7 +6,7 @@ #ifndef __MM0_CAPABILITY_H__ #define __MM0_CAPABILITY_H__ -#include +#include #include extern struct cap_list capability_list; @@ -17,7 +17,6 @@ void copy_boot_capabilities(); int sys_request_cap(struct tcb *sender, struct capability *c); -void cap_print(struct capability *cap); void cap_list_print(struct cap_list *cap_list); void setup_caps(); #endif /* __MM0_CAPABILITY_H__ */ diff --git a/conts/posix/mm0/include/macros.h b/conts/posix/mm0/include/macros.h new file mode 100644 index 0000000..954d581 --- /dev/null +++ b/conts/posix/mm0/include/macros.h @@ -0,0 +1,9 @@ +#ifndef __MM0_MACROS_H__ +#define __MM0_MACROS_H__ + +#define __INC_ARCH(x) +#define __INC_SUBARCH(x) +#define __INC_PLAT(x) +#define __INC_GLUE(x) + +#endif /* __MM0_MACROS_H__ */ diff --git a/conts/posix/mm0/include/memory.h b/conts/posix/mm0/include/memory.h index 6db55ad..a4e87c9 100644 --- a/conts/posix/mm0/include/memory.h +++ b/conts/posix/mm0/include/memory.h @@ -21,15 +21,11 @@ struct container_memory_regions { }; extern struct container_memory_regions cont_mem_regions; -#define PAGER_MMAP_SEGMENT SZ_4MB -#define PAGER_MMAP_START (page_align_up(__stack)) -#define PAGER_MMAP_END (PAGER_MMAP_START + PAGER_MMAP_SEGMENT) - void init_mm_descriptors(struct page_bitmap *page_map, struct bootdesc *bootdesc, struct membank *membank); void init_physmem(void); -int pager_address_pool_init(void); +int pager_address_pool_init(); void *pager_new_address(int npages); int pager_delete_address(void *virt_addr, int npages); void *pager_map_pages(struct vm_file *f, unsigned long page_offset, unsigned long npages); @@ -38,6 +34,7 @@ void *pager_map_page(struct vm_file *f, unsigned long page_offset); void pager_unmap_page(void *addr); void *pager_map_file_range(struct vm_file *f, unsigned long byte_offset, unsigned long size); + void *pager_validate_map_user_range2(struct tcb *user, void *userptr, unsigned long size, unsigned int vm_flags); diff --git a/conts/posix/mm0/include/task.h b/conts/posix/mm0/include/task.h index c42fbb2..e5ece35 100644 --- a/conts/posix/mm0/include/task.h +++ b/conts/posix/mm0/include/task.h @@ -10,8 +10,8 @@ #include #include INC_GLUE(memlayout.h) #include -#include -#include +#include L4LIB_INC_ARCH(types.h) +#include L4LIB_INC_ARCH(syscalls.h) #include #include #include diff --git a/conts/posix/mm0/include/user.h b/conts/posix/mm0/include/user.h index e91e2e4..d3829dd 100644 --- a/conts/posix/mm0/include/user.h +++ b/conts/posix/mm0/include/user.h @@ -5,10 +5,8 @@ int pager_validate_user_range(struct tcb *user, void *userptr, unsigned long size, unsigned int vm_flags); -void *pager_validate_map_user_range(struct tcb *user, void *userptr, - unsigned long size, unsigned int vm_flags); -void pager_unmap_user_range(void *mapped_ptr, unsigned long size); - +void *pager_get_user_page(struct tcb *user, void *userptr, + unsigned long size, unsigned int vm_flags); int copy_user_args(struct tcb *task, struct args_struct *args, void *argv_user, int args_max); int copy_user_buf(struct tcb *task, void *buf, char *user, int maxlength, diff --git a/conts/posix/mm0/include/vm_area.h b/conts/posix/mm0/include/vm_area.h index f68f0a4..4984836 100644 --- a/conts/posix/mm0/include/vm_area.h +++ b/conts/posix/mm0/include/vm_area.h @@ -11,9 +11,10 @@ #include #include #include -#include #include #include +#include +#include __INC_ARCH(mm.h) // #define DEBUG_FAULT_HANDLING #ifdef DEBUG_FAULT_HANDLING @@ -22,6 +23,14 @@ #define dprintf(...) #endif +/* Some task segment marks for mm0 */ +#define PAGER_MMAP_SEGMENT SZ_1MB +#define PAGER_MMAP_START (page_align_up(__stack)) +#define PAGER_MMAP_END (PAGER_MMAP_START + PAGER_MMAP_SEGMENT) +#define PAGER_EXT_VIRTUAL_START PAGER_MMAP_END +#define PAGER_EXT_VIRTUAL_END (unsigned long)(PAGER_MMAP_END + SZ_2MB) +#define PAGER_VIRTUAL_START PAGER_EXT_VIRTUAL_END + /* Protection flags */ #define VM_NONE (1 << 0) #define VM_READ (1 << 1) @@ -75,6 +84,10 @@ extern struct page *page_array; sizeof(struct page)) + \ membank[0].start) +/* Multiple conversions together */ +#define virt_to_page(x) (phys_to_page(virt_to_phys(x))) +#define page_to_virt(x) (phys_to_virt((void *)page_to_phys(x))) + /* Fault data specific to this task + ptr to kernel's data */ struct fault_data { fault_kdata_t *kdata; /* Generic data forged by the kernel */ @@ -226,9 +239,12 @@ void vm_object_print(struct vm_object *vmo); void vm_print_objects(struct link *vmo_list); void vm_print_files(struct link *file_list); -/* Used for pre-faulting a page from mm0 */ +/* Buggy version. Used for pre-faulting a page from mm0 */ struct page *task_prefault_page(struct tcb *task, unsigned long address, unsigned int vmflags); +/* New version */ +struct page *task_prefault_smart(struct tcb *task, unsigned long address, + unsigned int vmflags); struct page *page_init(struct page *page); struct page *find_page(struct vm_object *vmo, unsigned long page_offset); void *pager_map_page(struct vm_file *f, unsigned long page_offset); diff --git a/conts/posix/mm0/main.c b/conts/posix/mm0/main.c index 412d8f5..b297503 100644 --- a/conts/posix/mm0/main.c +++ b/conts/posix/mm0/main.c @@ -5,9 +5,9 @@ */ #include #include -#include -#include -#include +#include L4LIB_INC_ARCH(utcb.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) #include #include #include diff --git a/conts/posix/mm0/mm/arch b/conts/posix/mm0/mm/arch deleted file mode 120000 index 85405c2..0000000 --- a/conts/posix/mm0/mm/arch +++ /dev/null @@ -1 +0,0 @@ -arch-arm \ No newline at end of file diff --git a/conts/libc/src/memset.c b/conts/posix/mm0/mm/arch/arm/crt0.S similarity index 67% rename from conts/libc/src/memset.c rename to conts/posix/mm0/mm/arch/arm/crt0.S index 66bb045..9bcb3a8 100644 --- a/conts/libc/src/memset.c +++ b/conts/posix/mm0/mm/arch/arm/crt0.S @@ -3,15 +3,15 @@ * * Version 1-0 * - * Copyright (c) 2004 University of New South Wales + * Copyright (c) 2004 National ICT Australia * * All rights reserved. * - * Developed by: Operating Systems and Distributed Systems Group (DiSy) - * University of New South Wales - * http://www.disy.cse.unsw.edu.au + * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS) + * National ICT Australia + * http://www.ertos.nicta.com.au * - * Permission is granted by University of New South Wales, free of charge, to + * Permission is granted by National ICT Australia, free of charge, to * any person obtaining a copy of this software and any associated * documentation files (the "Software") to deal with the Software without * restriction, including (without limitation) the rights to use, copy, @@ -28,7 +28,7 @@ * disclaimers in the documentation and/or other materials provided * with the distribution. * - * * Neither the name of University of New South Wales, nor the names of its + * * Neither the name of National ICT Australia, nor the names of its * contributors, may be used to endorse or promote products derived * from this Software without specific prior written permission. * @@ -57,10 +57,10 @@ * DAMAGES OR OTHER LIABILITY. * * If applicable legislation implies representations, warranties, or - * conditions, or imposes obligations or liability on University of New South - * Wales or one of its contributors in respect of the Software that + * conditions, or imposes obligations or liability on National ICT + * Australia or one of its contributors in respect of the Software that * cannot be wholly or partly excluded, restricted or modified, the - * liability of University of New South Wales or the contributor is limited, to + * liability of National ICT Australia or the contributor is limited, to * the full extent permitted by the applicable legislation, at its * option, to: * a. in the case of goods, any one or more of the following: @@ -76,63 +76,19 @@ * The construction, validity and performance of this licence is governed * by the laws in force in New South Wales, Australia. */ -/* - Author: Carl van Schaik -*/ -#include -#include -#include -/* - * Fill memory at s with (n) * byte value 'c' - */ -void * -memset(void *s, int c, size_t n) -{ - uintptr_t num, align, pattern, *p, x; - unsigned char *mem = s; - - x = (unsigned char)c; - align = sizeof(uintptr_t)-1; - - if ((uintptr_t)s & align) - { - num = n > align ? (sizeof(uintptr_t) - ((uintptr_t)s & align)) : n; - n -= num; - while (num--) - *mem++ = x; - } - - num = (uintptr_t)n / sizeof(uintptr_t); - - p = (uintptr_t*)mem; - -#if UINTPTR_MAX == UINT32_MAX - pattern = x | x << 8 | x << 16 | x << 24; -#elif UINTPTR_MAX == UINT64_MAX - pattern = x | x << 8 | x << 16 | x << 24 | - x << 32 | x << 40 | x << 48 | x << 56; -#else -#error UINTPTR_MAX not valid +#ifdef __thumb__ +#define bl blx #endif - while (num) { - /* simple hand unrolled loop */ - if ((num & 3)==0) { - num -= 4; - *p++ = pattern; - *p++ = pattern; - *p++ = pattern; - *p++ = pattern; - } else { - num--; - *p++ = pattern; - } - } - mem = (unsigned char*)p; - num = n & align; - while (num--) - *mem++ = x; + .section .text.head + .code 32 + .global _start; + .align; +_start: + ldr sp, =__stack + bl platform_init + bl __container_init +1: + b 1b - return s; -} diff --git a/conts/posix/mm0/mm/arch/arm/debug.c b/conts/posix/mm0/mm/arch/arm/debug.c new file mode 100644 index 0000000..e2ec7ac --- /dev/null +++ b/conts/posix/mm0/mm/arch/arm/debug.c @@ -0,0 +1,11 @@ +/* + * Perfmon globals + */ + + +#if defined(CONFIG_DEBUG_PERFMON_USER) + +u64 perfmon_total_cycles; +u64 current_cycles; + +#endif diff --git a/conts/posix/mm0/mm/arch/arm/mm.c b/conts/posix/mm0/mm/arch/arm/mm.c new file mode 100644 index 0000000..58d1905 --- /dev/null +++ b/conts/posix/mm0/mm/arch/arm/mm.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include __INC_ARCH(mm.h) + +#if defined(DEBUG_FAULT_HANDLING) +void arch_print_fault_params(struct fault_data *fault) +{ + printf("%s: Handling %s fault (%s abort) from %d. fault @ 0x%x, generic pte flags: 0x%x\n", + __TASKNAME__, (fault->reason & VM_READ) ? "read" : + (fault->reason & VM_WRITE) ? "write" : "exec", + is_prefetch_abort(fault->kdata->fsr) ? "prefetch" : "data", + fault->task->tid, fault->address, fault->pte_flags); +} +#else +void arch_print_fault_params(struct fault_data *fault) { } +#endif + + +void fault_handle_error(struct fault_data *fault) +{ + struct task_ids ids; + + /* Suspend the task */ + ids.tid = fault->task->tid; + BUG_ON(l4_thread_control(THREAD_SUSPEND, &ids) < 0); + + BUG(); +} + diff --git a/conts/posix/mm0/mm/arch/arm/v5/mm.c b/conts/posix/mm0/mm/arch/arm/v5/mm.c new file mode 100644 index 0000000..c246aa3 --- /dev/null +++ b/conts/posix/mm0/mm/arch/arm/v5/mm.c @@ -0,0 +1,65 @@ +/* + * ARMv5 specific functions + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + */ +#include +#include +#include +#include __INC_ARCH(mm.h) + +/* Extracts generic protection flags from architecture-specific pte */ +unsigned int vm_prot_flags(pte_t pte) +{ + unsigned int vm_prot_flags = 0; + unsigned int rw_flags = __MAP_USR_RW & PTE_PROT_MASK; + unsigned int ro_flags = __MAP_USR_RO & PTE_PROT_MASK; + + /* Clear non-protection flags */ + pte &= PTE_PROT_MASK; + + if (pte == ro_flags) + vm_prot_flags = VM_READ | VM_EXEC; + else if (pte == rw_flags) + vm_prot_flags = VM_READ | VM_WRITE | VM_EXEC; + else + vm_prot_flags = VM_NONE; + + return vm_prot_flags; +} + +/* + * PTE STATES: + * PTE type field: 00 (Translation fault) + * PTE type field correct, AP bits: None (Read or Write access fault) + * PTE type field correct, AP bits: RO (Write access fault) + */ + +/* + * Extracts arch-specific fault parameters + * and puts them into generic format + */ +void set_generic_fault_params(struct fault_data *fault) +{ + unsigned int prot_flags = vm_prot_flags(fault->kdata->pte); + + fault->reason = 0; + fault->pte_flags = prot_flags; + + if (is_prefetch_abort(fault->kdata->fsr)) { + fault->reason |= VM_READ; + fault->address = fault->kdata->faulty_pc; + } else { + fault->address = fault->kdata->far; + + /* Always assume read fault first */ + if (prot_flags & VM_NONE) + fault->reason |= VM_READ; + else if (prot_flags & VM_READ) + fault->reason |= VM_WRITE; + else + BUG(); + } + arch_print_fault_params(fault); +} + diff --git a/conts/posix/mm0/mm/arch/arm/v6/mm.c b/conts/posix/mm0/mm/arch/arm/v6/mm.c new file mode 100644 index 0000000..c246aa3 --- /dev/null +++ b/conts/posix/mm0/mm/arch/arm/v6/mm.c @@ -0,0 +1,65 @@ +/* + * ARMv5 specific functions + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + */ +#include +#include +#include +#include __INC_ARCH(mm.h) + +/* Extracts generic protection flags from architecture-specific pte */ +unsigned int vm_prot_flags(pte_t pte) +{ + unsigned int vm_prot_flags = 0; + unsigned int rw_flags = __MAP_USR_RW & PTE_PROT_MASK; + unsigned int ro_flags = __MAP_USR_RO & PTE_PROT_MASK; + + /* Clear non-protection flags */ + pte &= PTE_PROT_MASK; + + if (pte == ro_flags) + vm_prot_flags = VM_READ | VM_EXEC; + else if (pte == rw_flags) + vm_prot_flags = VM_READ | VM_WRITE | VM_EXEC; + else + vm_prot_flags = VM_NONE; + + return vm_prot_flags; +} + +/* + * PTE STATES: + * PTE type field: 00 (Translation fault) + * PTE type field correct, AP bits: None (Read or Write access fault) + * PTE type field correct, AP bits: RO (Write access fault) + */ + +/* + * Extracts arch-specific fault parameters + * and puts them into generic format + */ +void set_generic_fault_params(struct fault_data *fault) +{ + unsigned int prot_flags = vm_prot_flags(fault->kdata->pte); + + fault->reason = 0; + fault->pte_flags = prot_flags; + + if (is_prefetch_abort(fault->kdata->fsr)) { + fault->reason |= VM_READ; + fault->address = fault->kdata->faulty_pc; + } else { + fault->address = fault->kdata->far; + + /* Always assume read fault first */ + if (prot_flags & VM_NONE) + fault->reason |= VM_READ; + else if (prot_flags & VM_READ) + fault->reason |= VM_WRITE; + else + BUG(); + } + arch_print_fault_params(fault); +} + diff --git a/conts/posix/mm0/mm/arch/arm/v7/mm.c b/conts/posix/mm0/mm/arch/arm/v7/mm.c new file mode 100644 index 0000000..85a329c --- /dev/null +++ b/conts/posix/mm0/mm/arch/arm/v7/mm.c @@ -0,0 +1,77 @@ +/* + * ARMv7 specific functions + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + */ +#include +#include +#include +#include __INC_ARCH(mm.h) +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(exception.h) + +/* Get simplified access permissions */ +int pte_get_access_simple(pte_t pte) +{ + /* Place AP[2] and AP[1] in [1:0] positions and return */ + return (((pte >> PTE_AP2_BIT) & 1) << 1) + | ((pte >> PTE_AP1_BIT) & 1); +} + +int is_translation_fault(u32 fsr) +{ + return (fsr & FSR_FS_MASK) == ABORT_TRANSLATION_PAGE; +} + +unsigned int vm_prot_flags(pte_t pte, u32 fsr) +{ + unsigned int pte_prot_flags = 0; + + /* Translation fault means no permissions */ + if (is_translation_fault(fsr)) + return VM_NONE; + + /* Check simplified permission bits */ + switch (pte_get_access_simple(pte)) { + case AP_SIMPLE_USER_RW_KERN_RW: + pte_prot_flags |= VM_WRITE; + case AP_SIMPLE_USER_RO_KERN_RO: + pte_prot_flags |= VM_READ; + + /* Also, check exec never bit */ + if (!(pte & (1 << PTE_XN_BIT))) + pte_prot_flags |= VM_EXEC; + break; + case AP_SIMPLE_USER_NONE_KERN_RW: + case AP_SIMPLE_USER_NONE_KERN_RO: + default: + pte_prot_flags = VM_NONE; + break; + } + + return pte_prot_flags; +} + +void set_generic_fault_params(struct fault_data *fault) +{ + fault->pte_flags = vm_prot_flags(fault->kdata->pte, fault->kdata->fsr); + fault->reason = 0; + + /* + * Prefetch fault denotes exec fault. + */ + if (is_prefetch_abort(fault->kdata->fsr)) { + fault->reason |= VM_EXEC; + fault->address = fault->kdata->faulty_pc; + } else { + fault->address = fault->kdata->far; + + /* Write-not-read bit determines fault */ + if (fault->kdata->fsr & (1 << DFSR_WNR_BIT)) + fault->reason |= VM_WRITE; + else + fault->reason |= VM_READ; + } + arch_print_fault_params(fault); +} + diff --git a/conts/posix/mm0/mm/bootdesc.c b/conts/posix/mm0/mm/bootdesc.c index 472f3c9..c3dc655 100644 --- a/conts/posix/mm0/mm/bootdesc.c +++ b/conts/posix/mm0/mm/bootdesc.c @@ -8,8 +8,7 @@ #include #include #include - -#include +#include L4LIB_INC_ARCH(syslib.h) extern unsigned long pager_offset; diff --git a/conts/posix/mm0/mm/capability.c b/conts/posix/mm0/mm/capability.c index 83efe95..d0ee46b 100644 --- a/conts/posix/mm0/mm/capability.c +++ b/conts/posix/mm0/mm/capability.c @@ -7,12 +7,11 @@ #include #include #include -#include #include #include -#include +#include L4LIB_INC_ARCH(syscalls.h) #include /* TODO: Move this to API */ -#include +#include L4LIB_INC_ARCH(syslib.h) #include #include @@ -22,113 +21,6 @@ struct cap_list capability_list; __initdata static struct capability *caparray; __initdata static int total_caps = 0; - -void cap_dev_print(struct capability *cap) -{ - switch (cap_devtype(cap)) { - case CAP_DEVTYPE_UART: - printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap)); - break; - case CAP_DEVTYPE_TIMER: - printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap)); - break; - case CAP_DEVTYPE_CLCD: - printf("Device type:\t\t\t%s%d\n", "CLCD", cap_devnum(cap)); - break; - default: - return; - } - printf("Device Irq:\t\t%d\n", cap->irq); -} - -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: - if (!cap_is_devmem(cap)) { - printf("Capability type:\t\t%s\n", "Map/Physmem"); - } else { - printf("Capability type:\t\t%s\n", "Map/Physmem/Device"); - cap_dev_print(cap); - } - 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_IRQCTRL: - printf("Capability type:\t\t%s\n", "IRQ Control"); - 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"); -} - - void cap_list_print(struct cap_list *cap_list) { struct capability *cap; @@ -611,15 +503,14 @@ int sys_request_cap(struct tcb *task, struct capability *__cap_userptr) struct capability *cap; int ret; - if (!(cap = pager_validate_map_user_range(task, __cap_userptr, - sizeof(*__cap_userptr), - VM_READ | VM_WRITE))) + if (!(cap = pager_get_user_page(task, __cap_userptr, + sizeof(*__cap_userptr), + VM_READ | VM_WRITE))) return -EFAULT; /* Only support IPC requests for now */ if (cap_type(cap) != CAP_TYPE_IPC) { ret = -EPERM; - goto out; } /* Validate rest of the fields */ @@ -667,7 +558,6 @@ int sys_request_cap(struct tcb *task, struct capability *__cap_userptr) } out: - pager_unmap_user_range(cap, sizeof(*cap)); return ret; } diff --git a/conts/posix/mm0/mm/clone.c b/conts/posix/mm0/mm/clone.c index eec8453..469ae07 100644 --- a/conts/posix/mm0/mm/clone.c +++ b/conts/posix/mm0/mm/clone.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Bahadir Balban */ -#include +#include L4LIB_INC_ARCH(syslib.h) #include #include #include @@ -111,6 +111,7 @@ int sys_clone(struct tcb *parent, if (!child_stack) return -EINVAL; + BUG_ON((unsigned long)child_stack < 0x10000); if (clone_flags & CLONE_VM) { flags |= TCB_SHARED_VM; diff --git a/conts/posix/mm0/mm/execve.c b/conts/posix/mm0/mm/execve.c index 9eabc7c..656e1b7 100644 --- a/conts/posix/mm0/mm/execve.c +++ b/conts/posix/mm0/mm/execve.c @@ -3,8 +3,8 @@ * * Copyright (C) 2008 Bahadir Balban */ -#include -#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) #include #include #include diff --git a/conts/posix/mm0/mm/exit.c b/conts/posix/mm0/mm/exit.c index f37cbe9..43ffd30 100644 --- a/conts/posix/mm0/mm/exit.c +++ b/conts/posix/mm0/mm/exit.c @@ -11,12 +11,12 @@ #include #include #include -#include -#include #include #include #include #include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) /* Closes all file descriptors of a task */ diff --git a/conts/posix/mm0/mm/fault.c b/conts/posix/mm0/mm/fault.c index 28a6aff..f1300cf 100644 --- a/conts/posix/mm0/mm/fault.c +++ b/conts/posix/mm0/mm/fault.c @@ -1,17 +1,12 @@ /* * Page fault handling. * - * Copyright (C) 2007, 2008 Bahadir Balban + * Copyright (C) 2007, 2008-2010 Bahadir Bilgehan Balban */ #include #include #include #include -#include -#include -#include INC_GLUE(memory.h) -#include INC_SUBARCH(mm.h) -#include #include #include #include @@ -20,6 +15,12 @@ #include #include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) +#include INC_GLUE(memory.h) +#include INC_SUBARCH(mm.h) +#include __INC_ARCH(mm.h) +#include __INC_ARCH(debug.h) /* Given a page and the vma it is in, returns that page's virtual address */ unsigned long vma_page_to_virtual(struct vm_area *vma, struct page *page) @@ -245,28 +246,16 @@ struct vm_obj_link *vma_create_shadow(void) /* Allocates a new page, copies the original onto it and returns. */ struct page *copy_to_new_page(struct page *orig) { - void *new_vaddr, *vaddr, *paddr; - struct page *new; + void *paddr = alloc_page(1); - BUG_ON(!(paddr = alloc_page(1))); - - new = phys_to_page(paddr); - - /* Map the new and orig page to self */ - new_vaddr = l4_map_helper(paddr, 1); - vaddr = l4_map_helper((void *)page_to_phys(orig), 1); + BUG_ON(!paddr); /* Copy the page into new page */ - memcpy(new_vaddr, vaddr, PAGE_SIZE); + memcpy(phys_to_virt(paddr), page_to_virt(orig), PAGE_SIZE); - /* Unmap both pages from current task. */ - l4_unmap_helper(vaddr, 1); - l4_unmap_helper(new_vaddr, 1); - - return new; + return phys_to_page(paddr); } - /* Copy all mapped object link stack from vma to new vma */ int vma_copy_links(struct vm_area *new_vma, struct vm_area *vma) { @@ -649,96 +638,140 @@ struct page *copy_on_write(struct fault_data *fault) * FIXME: Add VM_DIRTY bit for every page that has write-faulted. */ -struct page *__do_page_fault(struct fault_data *fault) +/* Handle read faults */ +struct page *page_read_fault(struct fault_data *fault) { - unsigned int reason = fault->reason; - unsigned int vma_flags = fault->vma->flags; - unsigned int pte_flags = fault->pte_flags; struct vm_area *vma = fault->vma; struct vm_obj_link *vmo_link; unsigned long file_offset; - struct page *page; + struct page *page = 0; - /* Handle read */ - if ((reason & VM_READ) && (pte_flags & VM_NONE)) { - file_offset = fault_to_file_offset(fault); + file_offset = fault_to_file_offset(fault); - /* Get the first object, either original file or a shadow */ - if (!(vmo_link = vma_next_link(&vma->vm_obj_list, &vma->vm_obj_list))) { - printf("%s:%s: No vm object in vma!\n", - __TASKNAME__, __FUNCTION__); + /* Get the first object, either original file or a shadow */ + if (!(vmo_link = vma_next_link(&vma->vm_obj_list, &vma->vm_obj_list))) { + printf("%s:%s: No vm object in vma!\n", + __TASKNAME__, __FUNCTION__); + BUG(); + } + + /* Traverse the list of read-only vm objects and search for the page */ + while (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj, + file_offset))) { + if (!(vmo_link = vma_next_link(&vmo_link->list, + &vma->vm_obj_list))) { + printf("%s:%s: Traversed all shadows and the original " + "file's vm_object, but could not find the " + "faulty page in this vma.\n",__TASKNAME__, + __FUNCTION__); BUG(); } + } + BUG_ON(!page); - /* Traverse the list of read-only vm objects and search for the page */ - while (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj, - file_offset))) { - if (!(vmo_link = vma_next_link(&vmo_link->list, - &vma->vm_obj_list))) { - printf("%s:%s: Traversed all shadows and the original " - "file's vm_object, but could not find the " - "faulty page in this vma.\n",__TASKNAME__, - __FUNCTION__); + return page; +} + +struct page *page_write_fault(struct fault_data *fault) +{ + unsigned int vma_flags = fault->vma->flags; + struct vm_area *vma = fault->vma; + struct vm_obj_link *vmo_link; + unsigned long file_offset; + struct page *page = 0; + + /* Copy-on-write. All private vmas are always COW */ + if (vma_flags & VMA_PRIVATE) { + BUG_ON(IS_ERR(page = copy_on_write(fault))); + + /* + * This handles shared pages that are both anon and non-anon. + */ + } else if ((vma_flags & VMA_SHARED)) { + file_offset = fault_to_file_offset(fault); + + /* Don't traverse, just take the first object */ + BUG_ON(!(vmo_link = vma_next_link(&vma->vm_obj_list, + &vma->vm_obj_list))); + + /* Get the page from its pager */ + if (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj, + file_offset))) { + /* + * Writable page does not exist, + * if it is anonymous, it needs to be COW'ed, + * otherwise the file must have paged-in this + * page, so its a bug. + */ + if (vma_flags & VMA_ANONYMOUS) { + BUG_ON(IS_ERR(page = copy_on_write(fault))); + return page; + } else { + printf("%s: Could not obtain faulty " + "page from regular file.\n", + __TASKNAME__); BUG(); } } - BUG_ON(!page); - } - - /* Handle write */ - if ((reason & VM_WRITE) && (pte_flags & VM_READ)) { - /* Copy-on-write. All private vmas are always COW */ - if (vma_flags & VMA_PRIVATE) { - BUG_ON(IS_ERR(page = copy_on_write(fault))); /* - * This handles shared pages that are both anon and non-anon. + * Page and object are now dirty. Currently it's + * only relevant for file-backed shared objects. */ - } else if ((vma_flags & VMA_SHARED)) { - file_offset = fault_to_file_offset(fault); + page->flags |= VM_DIRTY; + page->owner->flags |= VM_DIRTY; + } else + BUG(); - /* Don't traverse, just take the first object */ - BUG_ON(!(vmo_link = vma_next_link(&vma->vm_obj_list, - &vma->vm_obj_list))); + return page; +} - /* Get the page from its pager */ - if (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj, - file_offset))) { - /* - * Writable page does not exist, - * if it is anonymous, it needs to be COW'ed, - * otherwise the file must have paged-in this - * page, so its a bug. - */ - if (vma_flags & VMA_ANONYMOUS) { - BUG_ON(IS_ERR(page = copy_on_write(fault))); - goto out_success; - } else { - printf("%s: Could not obtain faulty " - "page from regular file.\n", - __TASKNAME__); - BUG(); - } - } +struct page *__do_page_fault(struct fault_data *fault) +{ + unsigned int reason = fault->reason; + unsigned int pte_flags = fault->pte_flags; + unsigned int map_flags = 0; + struct page *page = 0; - /* - * Page and object are now dirty. Currently it's - * only relevant for file-backed shared objects. - */ - page->flags |= VM_DIRTY; - page->owner->flags |= VM_DIRTY; - } else - BUG(); + if ((reason & VM_READ) && (pte_flags & VM_NONE)) { + page = page_read_fault(fault); + map_flags = MAP_USR_RO; + + } else if ((reason & VM_WRITE) && (pte_flags & VM_NONE)) { + page = page_read_fault(fault); + page = page_write_fault(fault); + map_flags = MAP_USR_RW; + + } else if ((reason & VM_EXEC) && (pte_flags & VM_NONE)) { + page = page_read_fault(fault); + map_flags = MAP_USR_RX; + + } else if ((reason & VM_EXEC) && (pte_flags & VM_READ)) { + /* Retrieve already paged in file */ + page = page_read_fault(fault); + if (pte_flags & VM_WRITE) + map_flags = MAP_USR_RWX; + else + map_flags = MAP_USR_RX; + + } else if ((reason & VM_WRITE) && (pte_flags & VM_READ)) { + page = page_write_fault(fault); + if (pte_flags & VM_EXEC) + map_flags = MAP_USR_RWX; + else + map_flags = MAP_USR_RW; + + } else { + printf("mm0: Unhandled page fault.\n"); + BUG(); } -out_success: + BUG_ON(!page); + /* Map the new page to faulty task */ l4_map((void *)page_to_phys(page), (void *)page_align(fault->address), 1, - (reason & VM_READ) ? MAP_USR_RO_FLAGS : MAP_USR_RW_FLAGS, - fault->task->tid); - dprintf("%s: Mapped 0x%x as writable to tid %d.\n", __TASKNAME__, - page_align(fault->address), fault->task->tid); + map_flags, fault->task->tid); // vm_object_print(page->owner); return page; @@ -796,7 +829,7 @@ int vm_freeze_shadows(struct tcb *task) /* Map the page as read-only */ l4_map((void *)page_to_phys(p), (void *)virtual, 1, - MAP_USR_RO_FLAGS, task->tid); + MAP_USR_RO, task->tid); } } @@ -860,11 +893,6 @@ struct page *do_page_fault(struct fault_data *fault) fault_handle_error(fault); } - if ((reason & VM_EXEC) && (vma_flags & VM_EXEC)) { - printf("Exec faults unsupported yet.\n"); - fault_handle_error(fault); - } - /* Handle legitimate faults */ return __do_page_fault(fault); } @@ -890,20 +918,145 @@ struct page *page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata) return do_page_fault(&fault); } -int vm_compare_prot_flags(unsigned int current, unsigned int needed) +static inline unsigned int pte_to_map_flags(unsigned int pte_flags) { - current &= VM_PROT_MASK; - needed &= VM_PROT_MASK; + unsigned int map_flags; - if (needed & VM_READ) - if (current & (VM_READ | VM_WRITE)) - return 1; + switch(pte_flags) { + case VM_READ: + map_flags = MAP_USR_RO; + break; + case (VM_READ | VM_WRITE): + map_flags = MAP_USR_RW; + break; + case (VM_READ | VM_WRITE | VM_EXEC): + map_flags = MAP_USR_RWX; + break; + case (VM_READ | VM_EXEC): + map_flags = MAP_USR_RX; + break; + default: + BUG(); + } - if (needed & VM_WRITE && - (current & VM_WRITE)) - return 1; + return map_flags; +} - return 0; +/* + * Prefaults a page of a task. The catch is that the page may already + * have been faulted with even more progress than the desired + * flags would progress in the fault (e.g. read-faulting a + * copy-on-write'd page). + * + * This function detects whether progress is necessary or not by + * inspecting the vma's vm_object chain state. + * + * Generally both read-fault and write-fault paths are repeatable, in + * the sense that an already faulted page may be safely re-faulted again + * and again, be it a read-only or copy-on-write'd page. + * + * The retrieval of the same page in a repetitive fashion is safe, + * but while it also seems to appear safe, it is unnecessary to downgrade + * or change mapping permissions of a page. E.g. make a copy-on-write'd + * page read-only by doing a blind read-fault on it. + * + * Hence this function checks whether a fault is necessary and simply + * returns if it isn't. + * + * FIXME: Escalate any page fault errors like a civilized function! + */ +struct page *task_prefault_smart(struct tcb *task, unsigned long address, + unsigned int wanted_flags) +{ + struct vm_obj_link *vmo_link; + unsigned long file_offset; + unsigned int vma_flags, pte_flags; + struct vm_area *vma; + struct page *page; + int err; + + struct fault_data fault = { + .task = task, + .address = address, + }; + + /* Find the vma */ + if (!(fault.vma = find_vma(fault.address, + &fault.task->vm_area_head->list))) { + dprintf("%s: Invalid: No vma for given address. %d\n", + __FUNCTION__, -EINVAL); + return PTR_ERR(-EINVAL); + } + + /* Read fault, repetitive safe */ + if (wanted_flags & VM_READ) + if (IS_ERR(page = page_read_fault(&fault))) + return page; + + /* Write fault, repetitive safe */ + if (wanted_flags & VM_WRITE) + if (IS_ERR(page = page_write_fault(&fault))) + return page; + + /* + * If we came this far, it means we have more + * permissions than VM_NONE. + * + * Now we _must_ find out what those page + * protection flags were, and do this without + * needing to inspect any ptes. + * + * We don't want to downgrade a RW page to RO again. + */ + file_offset = fault_to_file_offset(&fault); + vma_flags = fault.vma->flags; + vma = fault.vma; + + /* Get the topmost vm_object */ + if (!(vmo_link = vma_next_link(&vma->vm_obj_list, + &vma->vm_obj_list))) { + printf("%s:%s: No vm object in vma!\n", + __TASKNAME__, __FUNCTION__); + BUG(); + } + + /* Traverse the list of vm objects and search for the page */ + while (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj, + file_offset))) { + if (!(vmo_link = vma_next_link(&vmo_link->list, + &vma->vm_obj_list))) { + printf("%s:%s: Traversed all shadows and the original " + "file's vm_object, but could not find the " + "faulty page in this vma.\n",__TASKNAME__, + __FUNCTION__); + BUG(); + } + } + + /* Use flags for the vm_object containing the page */ + if (vmo_link->obj->flags & VM_WRITE) + pte_flags = VM_WRITE | VM_READ; + else + pte_flags = VM_READ; + + /* + * Now check vma flags for adding the VM_EXEC + * The real pte may not have this flag yet, but + * it is allowed to have it and it doesn't harm. + */ + if (vma_flags & VM_EXEC) + pte_flags |= VM_EXEC; + + /* Map the page to task using these flags */ + if ((err = l4_map((void *)page_to_phys(page), + (void *)page_align(fault.address), 1, + pte_to_map_flags(pte_flags), + fault.task->tid)) < 0) { + printf("l4_map() failed. err=%d\n", err); + BUG(); + } + + return page; } /* @@ -914,6 +1067,16 @@ int vm_compare_prot_flags(unsigned int current, unsigned int needed) struct page *task_prefault_page(struct tcb *task, unsigned long address, unsigned int vmflags) { + struct page *ret; + + perfmon_reset_start_cyccnt(); + ret = task_prefault_smart(task, address, vmflags); + + debug_record_cycles("task_prefault_smart"); + + return ret; + +#if 0 struct page *p; struct fault_data fault = { .task = task, @@ -949,6 +1112,23 @@ struct page *task_prefault_page(struct tcb *task, unsigned long address, BUG_ON(vmflags & ~(VM_READ | VM_WRITE)); return p; +#endif } +int vm_compare_prot_flags(unsigned int current, unsigned int needed) +{ + current &= VM_PROT_MASK; + needed &= VM_PROT_MASK; + + if (needed & VM_READ) + if (current & (VM_READ | VM_WRITE)) + return 1; + + if (needed & VM_WRITE && + (current & VM_WRITE)) + return 1; + + return 0; +} + diff --git a/conts/posix/mm0/mm/file.c b/conts/posix/mm0/mm/file.c index 6d508a5..47f75bb 100644 --- a/conts/posix/mm0/mm/file.c +++ b/conts/posix/mm0/mm/file.c @@ -10,8 +10,8 @@ #include #include #include -#include -#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) #include #include #include @@ -43,8 +43,8 @@ int page_copy(struct page *dst, struct page *src, BUG_ON(dst_offset + size > PAGE_SIZE); BUG_ON(src_offset + size > PAGE_SIZE); - dstvaddr = l4_map_helper((void *)page_to_phys(dst), 1); - srcvaddr = l4_map_helper((void *)page_to_phys(src), 1); + dstvaddr = page_to_virt(dst); + srcvaddr = page_to_virt(src); /* printf("%s: Copying from page with offset %lx to page with offset %lx\n" "src copy offset: 0x%lx, dst copy offset: 0x%lx, copy size: %lx\n", @@ -56,9 +56,6 @@ int page_copy(struct page *dst, struct page *src, memcpy(dstvaddr + dst_offset, srcvaddr + src_offset, size); - l4_unmap_helper(dstvaddr, 1); - l4_unmap_helper(srcvaddr, 1); - return 0; } @@ -552,16 +549,16 @@ int copy_cache_pages(struct vm_file *vmfile, struct tcb *task, void *buf, copysize = min(copysize, PAGE_SIZE - page_offset(task_offset)); if (read) - page_copy(task_prefault_page(task, task_offset, - VM_READ | VM_WRITE), + page_copy(task_prefault_smart(task, task_offset, + VM_READ | VM_WRITE), file_page, page_offset(task_offset), page_offset(file_offset), copysize); else page_copy(file_page, - task_prefault_page(task, task_offset, - VM_READ), + task_prefault_smart(task, task_offset, + VM_READ), page_offset(file_offset), page_offset(task_offset), copysize); diff --git a/conts/posix/mm0/mm/init.c b/conts/posix/mm0/mm/init.c index d23044b..f0ace78 100644 --- a/conts/posix/mm0/mm/init.c +++ b/conts/posix/mm0/mm/init.c @@ -3,8 +3,9 @@ * * Copyright (C) 2007 - 2009 Bahadir Balban */ -#include -#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) +#include __INC_ARCH(debug.h) #include #include #include @@ -229,6 +230,8 @@ void init_physmem_secondary(struct membank *membank) { struct page_bitmap *pmap = initdata.page_map; int npages = pmap->pfn_end - pmap->pfn_start; + void *virtual_start; + int err; /* * Allocation marks for the struct @@ -253,17 +256,6 @@ void init_physmem_secondary(struct membank *membank) */ pg_npages = __pfn(page_align_up((sizeof(struct page) * npages))); - - /* These are relative pfn offsets - * to the start of the memory bank - * - * FIXME: - * 1.) These values were only right - * when membank started from pfn 0. - * - * 2.) Use set_page_map to set page map - * below instead of manually. - */ pg_spfn = __pfn(membank[0].free); pg_epfn = pg_spfn + pg_npages; @@ -311,7 +303,34 @@ void init_physmem_secondary(struct membank *membank) /* Test that page/phys macros work */ BUG_ON(phys_to_page(page_to_phys(&page_array[5])) - != &page_array[5]) + != &page_array[5]); + + /* Now map all physical pages to virtual correspondents */ + virtual_start = (void *)PAGER_VIRTUAL_START; + if ((err = l4_map((void *)membank[0].start, + virtual_start, + __pfn(membank[0].end - membank[0].start), + MAP_USR_RW, self_tid())) < 0) { + printk("FATAL: Could not map all physical pages to " + "virtual. err=%d\n", err); + BUG(); + } + +#if 0 + printf("Virtual offset: %p\n", virtual_start); + printf("Physical page offset: 0x%lx\n", membank[0].start); + printf("page address: 0x%lx\n", (unsigned long)&page_array[5]); + printf("page_to_virt: %p\n", page_to_virt(&page_array[5])); + printf("virt_to_phys, virtual_start: %p\n", virt_to_phys(virtual_start)); + printf("page_to_virt_to_phys: %p\n", virt_to_phys(page_to_virt(&page_array[5]))); + printf("page_to_phys: 0x%lx\n", page_to_phys(&page_array[5])); +#endif + + /* Now test that virt/phys macros work */ + BUG_ON(virt_to_phys(page_to_virt(&page_array[5])) + != (void *)page_to_phys(&page_array[5])); + BUG_ON(virt_to_page(page_to_virt(&page_array[5])) + != &page_array[5]); } @@ -354,6 +373,7 @@ void init_physmem_primary() physmem.numpages = physmem.end - physmem.start; } + void init_physmem(void) { init_physmem_primary(); @@ -377,6 +397,9 @@ void copy_init_process(void) void *mapped; int err; + /* Measure performance, if enabled */ + perfmon_reset_start_cyccnt(); + if ((fd = sys_open(self, "/test0", O_TRUNC | O_RDWR | O_CREAT, 0)) < 0) { printf("FATAL: Could not open file " @@ -384,6 +407,8 @@ void copy_init_process(void) BUG(); } + debug_record_cycles("sys_open"); + init_img = bootdesc_get_image_byname("test0"); img_size = page_align_up(init_img->phys_end) - page_align(init_img->phys_start); @@ -407,6 +432,8 @@ void copy_init_process(void) BUG(); } + debug_record_cycles("Until after do_mmap"); + /* Prefault it */ if ((err = task_prefault_range(self, (unsigned long)mapped, img_size, VM_READ | VM_WRITE)) @@ -415,26 +442,38 @@ void copy_init_process(void) BUG(); } + /* Copy the raw image to anon region */ memcpy(mapped, init_img_start, img_size); + + debug_record_cycles("memcpy image"); + + /* Write it to real file from anon region */ sys_write(find_task(self_tid()), fd, mapped, img_size); + debug_record_cycles("sys_write"); + /* Close file */ sys_close(find_task(self_tid()), fd); + + debug_record_cycles("sys_close"); + /* Unmap anon region */ do_munmap(self, (unsigned long)mapped, __pfn(img_size)); /* Unmap raw virtual range for image memory */ l4_unmap_helper(init_img_start,__pfn(img_size)); + debug_record_cycles("Final do_munmap/l4_unmap"); + } void start_init_process(void) { - /* Copy raw test0 elf image from memory to memfs first */ + copy_init_process(); init_execve("/test0"); diff --git a/conts/posix/mm0/mm/memory.c b/conts/posix/mm0/mm/memory.c index 789e9a9..fc620bb 100644 --- a/conts/posix/mm0/mm/memory.c +++ b/conts/posix/mm0/mm/memory.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include L4LIB_INC_ARCH(syslib.h) #include INC_GLUE(memory.h) #include INC_SUBARCH(mm.h) #include @@ -30,6 +30,8 @@ struct address_pool pager_vaddr_pool; /* Bitmap size to represent an address pool of 256 MB. */ #define ADDRESS_POOL_256MB 2048 +unsigned long free_virtual_address_start; + /* Same as a regular id pool except that its bitmap size is fixed */ static struct pager_virtual_address_id_pool { int nwords; @@ -60,8 +62,8 @@ int pager_address_pool_init(void) address_pool_init_with_idpool(&pager_vaddr_pool, (struct id_pool *) &pager_virtual_address_id_pool, - PAGER_MMAP_END, - __pfn_to_addr(cont_mem_regions.pager->end)); + PAGER_EXT_VIRTUAL_START, + PAGER_EXT_VIRTUAL_END); return 0; } @@ -126,7 +128,7 @@ void *pager_map_pages(struct vm_file *f, unsigned long page_offset, unsigned lon /* Map pages contiguously one by one */ for (unsigned long pfn = page_offset; pfn < page_offset + npages; pfn++) { BUG_ON(!(p = find_page(&f->vm_obj, pfn))) - l4_map((void *)page_to_phys(p), addr, 1, MAP_USR_RW_FLAGS, self_tid()); + l4_map((void *)page_to_phys(p), addr, 1, MAP_USR_RW, self_tid()); addr += PAGE_SIZE; } @@ -192,7 +194,7 @@ void *pager_validate_map_user_range2(struct tcb *user, void *userptr, } l4_map((void *)page_to_phys(p), - virt, 1, MAP_USR_RW_FLAGS, self_tid()); + virt, 1, MAP_USR_RW, self_tid()); virt += PAGE_SIZE; } @@ -207,3 +209,25 @@ void *pager_validate_map_user_range2(struct tcb *user, void *userptr, } +/* + * Find the page's offset from membank physical start, + * simply add the same offset to virtual start + */ +void *phys_to_virt(void *p) +{ + unsigned long paddr = (unsigned long)p; + + return (void *)(paddr - membank[0].start + PAGER_VIRTUAL_START); +} + +/* + * Find the page's offset from virtual start, add it to membank + * physical start offset + */ +void *virt_to_phys(void *v) +{ + unsigned long vaddr = (unsigned long)v; + + return (void *)(vaddr - PAGER_VIRTUAL_START + membank[0].start); +} + diff --git a/conts/posix/mm0/mm/mmap.c b/conts/posix/mm0/mm/mmap.c index 3fec710..b46e78f 100644 --- a/conts/posix/mm0/mm/mmap.c +++ b/conts/posix/mm0/mm/mmap.c @@ -8,8 +8,8 @@ #include #include INC_API(errno.h) #include -#include -#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) #include #include #include @@ -401,17 +401,15 @@ void *sys_mmap(struct tcb *task, struct sys_mmap_args *args) struct sys_mmap_args *mapped_args; void *ret; - if (!(mapped_args = pager_validate_map_user_range(task, args, - sizeof(*args), - VM_READ | VM_WRITE))) + if (!(mapped_args = pager_get_user_page(task, args, + sizeof(*args), + VM_READ | VM_WRITE))) return PTR_ERR(-EINVAL); ret = __sys_mmap(task, mapped_args->start, mapped_args->length, mapped_args->prot, mapped_args->flags, mapped_args->fd, mapped_args->offset); - pager_unmap_user_range(mapped_args, sizeof(*args)); - return ret; } diff --git a/conts/posix/mm0/mm/munmap.c b/conts/posix/mm0/mm/munmap.c index 5c6850c..434ef69 100644 --- a/conts/posix/mm0/mm/munmap.c +++ b/conts/posix/mm0/mm/munmap.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include L4LIB_INC_ARCH(syslib.h) #include #include diff --git a/conts/posix/mm0/mm/pagers.c b/conts/posix/mm0/mm/pagers.c index c962969..3990ff4 100644 --- a/conts/posix/mm0/mm/pagers.c +++ b/conts/posix/mm0/mm/pagers.c @@ -3,8 +3,8 @@ */ #include #include -#include -#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) #include #include #include @@ -66,7 +66,7 @@ int file_page_out(struct vm_object *vm_obj, unsigned long page_offset) { struct vm_file *f = vm_object_to_file(vm_obj); struct page *page; - void *vaddr, *paddr; + void *paddr; int err; /* Check first if the file has such a page at all */ @@ -86,46 +86,26 @@ int file_page_out(struct vm_object *vm_obj, unsigned long page_offset) return 0; paddr = (void *)page_to_phys(page); - vaddr = l4_new_virtual(1); - - /* FIXME: - * Are we sure that pages need - * to be mapped to self one-by-one? - * - * This needs fixing. - */ - - /* Map the page to self */ - l4_map(paddr, vaddr, 1, MAP_USR_RW_FLAGS, self_tid()); //printf("%s/%s: Writing to vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n", // __TASKNAME__, __FUNCTION__, f->vnode->vnum, page_offset, 1, vaddr); /* Syscall to vfs to write page back to file. */ - if ((err = vfs_write(f->vnode, page_offset, 1, vaddr)) < 0) - goto out_err; - - /* Unmap it from self */ - l4_unmap(vaddr, 1, self_tid()); - l4_del_virtual(vaddr, 1); + if ((err = vfs_write(f->vnode, page_offset, 1, + phys_to_virt(paddr))) < 0) + return err; /* Clear dirty flag */ page->flags &= ~VM_DIRTY; return 0; - -out_err: - l4_unmap(vaddr, 1, self_tid()); - l4_del_virtual(vaddr, 1); - - return err; } struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset) { struct vm_file *f = vm_object_to_file(vm_obj); struct page *page; - void *vaddr, *paddr; + void *paddr; int err; /* Check first if the file has such a page at all */ @@ -140,24 +120,19 @@ struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset) if (!(page = find_page(vm_obj, page_offset))) { /* Allocate a new page */ paddr = alloc_page(1); - vaddr = l4_new_virtual(1); page = phys_to_page(paddr); - /* Map the page to vfs task */ - l4_map(paddr, vaddr, 1, MAP_USR_RW_FLAGS, self_tid()); - - /* Syscall to vfs to read into the page. */ + /* Call to vfs to read into the page. */ if ((err = vfs_read(f->vnode, page_offset, - 1, vaddr)) < 0) - goto out_err; + 1, phys_to_virt(paddr))) < 0) { + + free_page(paddr); + return PTR_ERR(err); + } // printf("%s/%s: Reading into vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n", // __TASKNAME__, __FUNCTION__, f->vnode->vnum, page_offset, 1, vaddr); - /* Unmap it from vfs */ - l4_unmap(vaddr, 1, self_tid()); - l4_del_virtual(vaddr, 1); - /* Update vm object details */ vm_obj->npages++; @@ -174,12 +149,6 @@ struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset) } return page; - -out_err: - l4_unmap(vaddr, 1, self_tid()); - l4_del_virtual(vaddr, 1); - free_page(paddr); - return PTR_ERR(err); } /* @@ -392,9 +361,13 @@ int init_devzero(void) /* Allocate and initialise the zero page */ zphys = alloc_page(1); zpage = phys_to_page(zphys); - zvirt = l4_map_helper(zphys, 1); + zvirt = (void *)phys_to_virt(zphys); memset(zvirt, 0, PAGE_SIZE); - l4_unmap_helper(zvirt, 1); + + /* + * FIXME: + * Flush the dcache if virtual data cache + */ /* Allocate and initialise devzero file */ devzero = vm_file_create(); diff --git a/conts/posix/mm0/mm/physmem.c b/conts/posix/mm0/mm/physmem.c index 223bf22..0adc2c8 100644 --- a/conts/posix/mm0/mm/physmem.c +++ b/conts/posix/mm0/mm/physmem.c @@ -13,7 +13,7 @@ #include #include INC_GLUE(memory.h) -#include +#include L4LIB_INC_ARCH(syslib.h) #include #include #include diff --git a/conts/posix/mm0/mm/shm.c b/conts/posix/mm0/mm/shm.c index 9c701ed..cd3f778 100644 --- a/conts/posix/mm0/mm/shm.c +++ b/conts/posix/mm0/mm/shm.c @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) #include #include #include diff --git a/conts/posix/mm0/mm/task.c b/conts/posix/mm0/mm/task.c index 316cc3e..0bd1d89 100644 --- a/conts/posix/mm0/mm/task.c +++ b/conts/posix/mm0/mm/task.c @@ -12,10 +12,10 @@ #include #include #include INC_GLUE(memory.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(utcb.h) -#include -#include -#include #include #include @@ -358,9 +358,7 @@ struct tcb *task_create(struct tcb *parent, struct task_ids *ids, } /* Create the thread structures and address space as the pager */ - if ((err = l4_thread_control(THREAD_CREATE | - TC_AS_PAGER | - ctrl_flags, ids)) < 0) { + if ((err = l4_thread_control(THREAD_CREATE | ctrl_flags, ids)) < 0) { printf("l4_thread_control failed with %d.\n", err); return PTR_ERR(err); } @@ -464,6 +462,7 @@ int task_copy_args_to_user(char *user_stack, /* Set beginning of envp */ envp_start = (char **)user_stack; + /* Forward by number of envp ptrs */ user_stack += sizeof(int) * env->argc; @@ -509,6 +508,7 @@ int task_prefault_range(struct tcb *task, unsigned long start, { struct page *p; + for (unsigned long i = start; i < start + size; i += PAGE_SIZE) if (IS_ERR(p = task_prefault_page(task, i, vm_flags))) return (int)p; diff --git a/conts/posix/mm0/mm/test.c b/conts/posix/mm0/mm/test.c index e84e67b..dcbee52 100644 --- a/conts/posix/mm0/mm/test.c +++ b/conts/posix/mm0/mm/test.c @@ -53,6 +53,7 @@ int vm_object_test_shadow_count(struct vm_object *vmo) * Add checking that total open file descriptors are * equal to total opener count of all files */ +#if defined (DEBUG_FAULT_HANDLING) int mm0_test_global_vm_integrity(void) { struct tcb *task; @@ -123,6 +124,8 @@ int mm0_test_global_vm_integrity(void) } return 0; } +#else /* End of DEBUG_FAULT_HANDLING */ +int mm0_test_global_vm_integrity(void) { return 0; } - +#endif /* End of !DEBUG_FAULT_HANDLING */ diff --git a/conts/posix/mm0/mm/user.c b/conts/posix/mm0/mm/user.c index 30bc691..6898390 100644 --- a/conts/posix/mm0/mm/user.c +++ b/conts/posix/mm0/mm/user.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Bahadir Balban */ -#include +#include L4LIB_INC_ARCH(syslib.h) #include #include #include @@ -46,8 +46,8 @@ int pager_validate_user_range(struct tcb *user, void *userptr, unsigned long siz * FIXME: There's no logic here to make non-contiguous physical pages * to get mapped virtually contiguous. */ -void *pager_validate_map_user_range(struct tcb *user, void *userptr, - unsigned long size, unsigned int vm_flags) +void *pager_get_user_page(struct tcb *user, void *userptr, + unsigned long size, unsigned int vm_flags) { unsigned long start = page_align(userptr); unsigned long end = page_align_up(userptr + size); @@ -58,26 +58,17 @@ void *pager_validate_map_user_range(struct tcb *user, void *userptr, return 0; /* Map first page and calculate the mapped address of pointer */ - mapped = l4_map_helper((void *)page_to_phys(task_prefault_page(user, start, - vm_flags)), 1); + mapped = page_to_virt(task_prefault_page(user, start, vm_flags)); mapped = (void *)(((unsigned long)mapped) | ((unsigned long)(PAGE_MASK & (unsigned long)userptr))); /* Map the rest of the pages, if any */ for (unsigned long i = start + PAGE_SIZE; i < end; i += PAGE_SIZE) - l4_map_helper((void *) - page_to_phys(task_prefault_page(user, start + i, - vm_flags)), 1); + BUG(); return mapped; } -void pager_unmap_user_range(void *mapped_ptr, unsigned long size) -{ - l4_unmap_helper((void *)page_align(mapped_ptr), - __pfn(page_align_up(size))); -} - /* * Copy from one buffer to another. Stop if maxlength or * a page boundary is hit. @@ -164,28 +155,23 @@ int copy_from_user(struct tcb *task, void *buf, char *user, int size) int count = size; void *mapped = 0; - if (!(mapped = pager_validate_map_user_range(task, user, - TILL_PAGE_ENDS(user), - VM_READ))) + if (!(mapped = pager_get_user_page(task, user, TILL_PAGE_ENDS(user), + VM_READ))) return -EINVAL; while ((ret = memcpy_page(buf + copied, mapped, count, 0)) < 0) { - pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped)); copied += TILL_PAGE_ENDS(mapped); count -= TILL_PAGE_ENDS(mapped); if (!(mapped = - pager_validate_map_user_range(task, user + copied, - TILL_PAGE_ENDS(user + copied), - VM_READ))) + pager_get_user_page(task, user + copied, + TILL_PAGE_ENDS(user + copied), + VM_READ))) return -EINVAL; } /* Note copied is always in bytes */ total = copied + ret; - /* Unmap the final page */ - pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped)); - return total; } @@ -196,28 +182,23 @@ int copy_to_user(struct tcb *task, char *user, void *buf, int size) void *mapped = 0; /* Map the user page */ - if (!(mapped = pager_validate_map_user_range(task, user, - TILL_PAGE_ENDS(user), - VM_READ))) + if (!(mapped = pager_get_user_page(task, user, + TILL_PAGE_ENDS(user), + VM_READ | VM_WRITE))) return -EINVAL; while ((ret = memcpy_page(mapped, buf + copied, count, 1)) < 0) { - pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped)); copied += TILL_PAGE_ENDS(mapped); count -= TILL_PAGE_ENDS(mapped); - if (!(mapped = - pager_validate_map_user_range(task, user + copied, - TILL_PAGE_ENDS(user + copied), - VM_READ))) + if (!(mapped = pager_get_user_page(task, user + copied, + TILL_PAGE_ENDS(user + copied), + VM_READ | VM_WRITE))) return -EINVAL; } /* Note copied is always in bytes */ total = copied + ret; - /* Unmap the final page */ - pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped)); - return total; } @@ -243,9 +224,8 @@ int copy_user_buf(struct tcb *task, void *buf, char *user, int maxlength, return -EINVAL; /* Map the first page the user buffer is in */ - if (!(mapped = pager_validate_map_user_range(task, user, - TILL_PAGE_ENDS(user), - VM_READ))) + if (!(mapped = pager_get_user_page(task, user, TILL_PAGE_ENDS(user), + VM_READ))) return -EINVAL; while ((ret = copy_func(buf + copied, mapped, count)) < 0) { @@ -257,13 +237,12 @@ int copy_user_buf(struct tcb *task, void *buf, char *user, int maxlength, * because we know we hit a page boundary and we increase * by the page boundary bytes */ - pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped)); copied += TILL_PAGE_ENDS(mapped); count -= TILL_PAGE_ENDS(mapped); if (!(mapped = - pager_validate_map_user_range(task, user + copied, - TILL_PAGE_ENDS(user + copied), - VM_READ))) + pager_get_user_page(task, user + copied, + TILL_PAGE_ENDS(user + copied), + VM_READ))) return -EINVAL; } } @@ -271,9 +250,6 @@ int copy_user_buf(struct tcb *task, void *buf, char *user, int maxlength, /* Note copied is always in bytes */ total = (copied / elem_size) + ret; - /* Unmap the final page */ - pager_unmap_user_range(mapped, TILL_PAGE_ENDS(mapped)); - return total; } diff --git a/conts/posix/mm0/mm/utcb.c b/conts/posix/mm0/mm/utcb.c index 028d855..371a1f8 100644 --- a/conts/posix/mm0/mm/utcb.c +++ b/conts/posix/mm0/mm/utcb.c @@ -3,9 +3,10 @@ * * Copyright (C) 2007-2009 Bahadir Bilgehan Balban */ -#include + #include #include INC_GLUE(memlayout.h) +#include L4LIB_INC_ARCH(utcb.h) #include #include #include diff --git a/conts/posix/mm0/tools/generate_bootdesc.py b/conts/posix/mm0/tools/generate_bootdesc.py index 04b0d86..45f1b62 100755 --- a/conts/posix/mm0/tools/generate_bootdesc.py +++ b/conts/posix/mm0/tools/generate_bootdesc.py @@ -12,7 +12,7 @@ linkoutput_file_suffix = "-linkinfo.txt" linkoutput_file = image_name + linkoutput_file_suffix def generate_bootdesc(): - command = config.user_toolchain + objdump + " -t " + image_name + " > " + linkoutput_file + command = config.toolchain + objdump + " -t " + image_name + " > " + linkoutput_file print command os.system(command) f = open(linkoutput_file, "r") diff --git a/conts/posix/test0/SConscript b/conts/posix/test0/SConscript index 7f03636..34672e2 100644 --- a/conts/posix/test0/SConscript +++ b/conts/posix/test0/SConscript @@ -69,7 +69,7 @@ test_exec_env = environment.Clone() test_exec_env.Append(LIBS = ['posix', 'c-userspace']) test_exec_env.Append(LINKFLAGS = '-T' + test_exec_lds[0].path) -test_exec_env.Append(CPPFLAGS = ' -D__USERSPACE__') +test_exec_env.Append(CPPFLAGS = ' -D__USERSPACE__ -include l4lib/macros.h ') test_exec_env.Replace(PROGSUFFIX = '') test_exec_src = Glob('src/test_exec/*.[cS]') test_exec_objs = test_exec_env.Object(test_exec_src) @@ -81,7 +81,7 @@ AlwaysBuild(test_exec_lds) env.Append(LIBS = ['posix', 'c-userspace']) env.Append(LINKFLAGS = '-T' + lma_lds[0].path) -env.Append(CPPFLAGS = ' -D__USERSPACE__') +env.Append(CPPFLAGS = ' -D__USERSPACE__ -include l4lib/macros.h ') env.Replace(PROGSUFFIX = '') objs = env.Object(src + test_exec_asm) test0 = env.Program('test0', objs) diff --git a/conts/posix/test0/SConstruct b/conts/posix/test0/SConstruct index bc197e4..ea6a5ee 100644 --- a/conts/posix/test0/SConstruct +++ b/conts/posix/test0/SConstruct @@ -58,7 +58,7 @@ def get_physical_base(source, target, env): prev_image + " >> " + physical_base_ld_script)) # The kernel build environment -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.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'], @@ -74,7 +74,7 @@ env = Environment(CC = config.user_toolchain + 'gcc', test_exec_ld_script = "include/test_exec_linker.lds" # The kernel build environment: -test_exec_env = Environment(CC = config.user_toolchain + 'gcc', +test_exec_env = Environment(CC = config.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 = ['-O3', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'], diff --git a/conts/posix/test0/include/capability.h b/conts/posix/test0/include/capability.h index 63a819b..e4353a0 100644 --- a/conts/posix/test0/include/capability.h +++ b/conts/posix/test0/include/capability.h @@ -2,7 +2,7 @@ #define __TEST0_CAP_H__ -#include +#include #include #include diff --git a/conts/posix/test0/include/tests.h b/conts/posix/test0/include/tests.h index 7ecdac6..5d1d6e2 100644 --- a/conts/posix/test0/include/tests.h +++ b/conts/posix/test0/include/tests.h @@ -3,6 +3,8 @@ #define __TASKNAME__ "test0" +#include L4LIB_INC_ARCH(syslib.h) + // #define TEST_VERBOSE_PRINT #if defined (TEST_VERBOSE_PRINT) #define test_printf(...) printf(__VA_ARGS__) diff --git a/conts/posix/test0/main.c b/conts/posix/test0/main.c index fa9b625..669c0c3 100644 --- a/conts/posix/test0/main.c +++ b/conts/posix/test0/main.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -15,6 +14,7 @@ #include #include #include +#include L4LIB_INC_ARCH(syslib.h) void wait_pager(l4id_t partner) { @@ -50,10 +50,10 @@ int main(int argc, char *argv[]) shmtest(); - forktest(); - fileio(); + forktest(); + clonetest(); undeftest(); diff --git a/conts/posix/test0/src/capability.c b/conts/posix/test0/src/capability.c index 92d72aa..53825be 100644 --- a/conts/posix/test0/src/capability.c +++ b/conts/posix/test0/src/capability.c @@ -1,6 +1,6 @@ #include -#include #include +#include L4LIB_INC_ARCH(syslib.h) int cap_request_pager(struct capability *cap) { diff --git a/conts/posix/test0/src/clonetest.c b/conts/posix/test0/src/clonetest.c index a0f50d2..2b29205 100644 --- a/conts/posix/test0/src/clonetest.c +++ b/conts/posix/test0/src/clonetest.c @@ -26,14 +26,16 @@ int clonetest(void) void *child_stack; /* Parent loops and calls clone() to clone new threads. Children don't come back from the clone() call */ - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 20; i++) { if ((child_stack = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, 0, 0)) == MAP_FAILED) { test_printf("MMAP failed.\n"); goto out_err; } else { test_printf("Mapped area starting at %p\n", child_stack); } - ((int *)child_stack)[-1] = 5; /* Test mapped area */ + // printf("mmap returned child stack: %p\n", child_stack); + + // ((int *)child_stack)[-1] = 5; /* Test mapped area */ test_printf("Cloning...\n"); diff --git a/conts/posix/test0/src/exectest.c b/conts/posix/test0/src/exectest.c index 38ede37..8a95d6c 100644 --- a/conts/posix/test0/src/exectest.c +++ b/conts/posix/test0/src/exectest.c @@ -12,8 +12,6 @@ #include #include -#define PAGE_SIZE 0x1000 - extern char _start_test_exec[]; extern char _end_test_exec[]; diff --git a/conts/posix/test0/src/ipctest.c b/conts/posix/test0/src/ipctest.c index cdafda5..d0daa36 100644 --- a/conts/posix/test0/src/ipctest.c +++ b/conts/posix/test0/src/ipctest.c @@ -3,7 +3,6 @@ * * Copyright (C) 2007-2009 Bahadir Bilgehan Balban */ -#include #include #include #include diff --git a/conts/posix/test0/src/mmaptest.c b/conts/posix/test0/src/mmaptest.c index b6e82ec..7522fd7 100644 --- a/conts/posix/test0/src/mmaptest.c +++ b/conts/posix/test0/src/mmaptest.c @@ -15,8 +15,6 @@ #include #include -#define PAGE_SIZE 0x1000 - int mmaptest(void) { int fd; diff --git a/conts/posix/test0/src/mutextest.c b/conts/posix/test0/src/mutextest.c index d4f4574..3b39908 100644 --- a/conts/posix/test0/src/mutextest.c +++ b/conts/posix/test0/src/mutextest.c @@ -3,7 +3,6 @@ * * Copyright (C) 2007-2009 Bahadir Bilgehan Balban */ -#include #include #include #include diff --git a/conts/posix/test0/src/test_exec/test_exec.c b/conts/posix/test0/src/test_exec/test_exec.c index 3955b0e..61de5e7 100644 --- a/conts/posix/test0/src/test_exec/test_exec.c +++ b/conts/posix/test0/src/test_exec/test_exec.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/conts/test_suite0/SConstruct b/conts/test_suite0/SConstruct new file mode 100644 index 0000000..e48f2ae --- /dev/null +++ b/conts/test_suite0/SConstruct @@ -0,0 +1,71 @@ +# -*- 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 * +from config.lib import * + +config = configuration_retrieve() +arch = config.arch +subarch = config.subarch +platform = config.platform +gcc_arch_flag = config.gcc_arch_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'), join(LIBDEV_DIR, 'include')] + +LIBMEM_RELDIR = 'conts/libmem' +LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) +LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR) +LIBMEM_INCLUDE = LIBMEM_DIR + +env = Environment(CC = config.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', '-march=' + gcc_arch_flag], + LINKFLAGS = ['-nostdlib', '-T' + "include/project_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', 'libmc', 'c-userspace', 'libdev-userspace', 'gcc', 'libmalloc', + '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]') +src += Glob('src/arch/' + arch + '/*.[cS]') +src += Glob('src/api/*.c'); +src += Glob('src/perf/*.c'); +src += Glob('src/cli_serv/*.c'); +src += Glob('src/mthread/*.c'); +src += Glob('src/arch/' + arch + '/' + subarch + '/*.[cS]') +objs = env.Object(src) +prog = env.Program('main.elf', objs) +Depends(prog, 'include/linker.lds') diff --git a/conts/test_suite0/TODO b/conts/test_suite0/TODO new file mode 100644 index 0000000..80ada45 --- /dev/null +++ b/conts/test_suite0/TODO @@ -0,0 +1,34 @@ + +Missing tests: + +1) Library tests: +~~~~~~~~~~~~~~~~~ +- L4Lib Thread library needs to be tested + - Stack allocation + - UTCB allocation +- L4Lib Capability library needs to be tested + - Capability read, print, manipulation + +- Address allocation, id allocation functions need to be tested. + +- Page allocator needs to be tested. +- Memcache needs to be tested. +- All above libraries must be tested with many many different combinations. + + +2) API Tests: +~~~~~~~~~~~~~ +- Null pointer tests +- Extended IPC via page faulting. +- Mutex tests on different virtual but same physical page. +- Cache flushing tests +- Capability limit tests (e.g. pushing limits of given capabilities) +- Capability manipulation tests (manipulating existing capabilities) + +3) Performance Tests: +~~~~~~~~~~~~~~~~~~~~~ +Performance tests should fall back to using timer if perfmon does not exist. +Performance tests need to run on multiple architectures. +(e.g. beagleboard perfmon, timer ...) +- Map/unmap +- Ipc results are missing diff --git a/conts/test_suite0/build.readme b/conts/test_suite0/build.readme new file mode 100644 index 0000000..7f2ecf4 --- /dev/null +++ b/conts/test_suite0/build.readme @@ -0,0 +1,112 @@ + Codezero Buildsystem For This Container + + Autogenerated by the Build system + + +This is an autogenerated file that is meant to walk you through the build +process. It is meant to be the most simple to get on with, therefore if +you feel any complications, please reach us on our l4dev.org mailing list +on http://lists.l4dev.org/mailman/listinfo/codezero-devel + +You have created a new container called `test_suite0'. + +The parameters you have supplied are described in the ".container" file +placed at the top-level directory. Note, that this is only an informative +file for your reference, and it can be optionally removed. + + + 1. Directory Structure: + +1.1) Directory tree: +. +|-- SConstruct +|-- build.readme +|-- .container +|-- include +| `-- linker.lds.example +|-- main.c +`-- src + |-- test.c + +In the above directory tree: + +1.2) |-- SConstruct + +This is the top-level build file, that will build your project in its current +state. You may freely reorganize directories, but must reflect changes in this +file. For more, please see the SCons build tool at http://www.scons.org/ + +The build system will search for this file, and execute it by the: + +`scons' + +command at the root of the directory. You may issue the same command manually +for building and testing your build. If you choose to use another build tool +such as make, you may freely replace scons, and the build system will search +and call your custom build command. + +1.3) |--include + `--src + +These are the directories that include your header files and sources. You may +freely change and reorganize these, but make sure to have a valid build file +that reflects those changes at the top-level directory. + +1.4) |-- include + | `-- linker.lds.example + +This is an example linker script for your project. Using this as your default +linker script is often useful, since it has been autogenerated to contain all +the parameters you need for the memory regions of your application defined at +configuration time. You may freely replace it, but make sure to edit the +top-level build script accordingly. + + + 2. Build Process + +2.1) Build overview + +The complete Codezero system will be built from a top-level `build.py' script by +that resides in the top-level directory of Codezero sources. + +The Codezero system build script will build this container at a certain stage +during the build, by referring to build script file named such as `SConstruct' +or `Makefile' that resides in this container's top-level directory. + +Once the executables are built, it will search for all files with a .elf +extension in any of the subdirectories, and recognize those as loadable +executables. There may be more than one of these files present after the build. + +In the future this behaviour may change such that the loadable executable files +are also specified in the configuration. + +Finally, executables of all containers will be picked up and built into the +final.elf file, which is a self-loading elf executable. + + + 3. Reconfiguring this container + +If you want to reconfigure the container with new parameters, you may do so by +executing the `configure.py' script at the top-level Codezero directory by: + +'./configure.py' + +This will populate only brand new container directories with new files. It will +update it's existing internal configuration for existing containers (such as +container memory regions) but it won't touch any files that exist under an +already-defined container. + +If you want to start from scratch, specify a new directory name, if you want +to reconfigure existing container parameters, run this on an existing directory, +and it will only update its internal records for this container, but not touch +the directory. + + + 4. Example source files + +Example source files populated by the configuration contain valid examples +of how the generic libl4 userspace library can be used. Each test contains a +valid example from the available API, and may be modified, changed and removed +freely. + + diff --git a/conts/test_suite0/container.c b/conts/test_suite0/container.c new file mode 100644 index 0000000..4b97317 --- /dev/null +++ b/conts/test_suite0/container.c @@ -0,0 +1,28 @@ +/* + * Container entry point for pager + * + * Copyright (C) 2007-2009 B Labs Ltd. + */ + +#include +#include +#include +#include + +extern void main(void); + +void __container_init(void) +{ + /* Generic L4 initialisation */ + __l4_init(); + + /* Thread library initialisation */ + __l4_threadlib_init(); + + /* Capability library initialization */ + __l4_capability_init(); + + /* Entry to main */ + main(); +} + diff --git a/conts/test_suite0/exit.ct b/conts/test_suite0/exit.ct new file mode 100644 index 0000000..9d11b9c --- /dev/null +++ b/conts/test_suite0/exit.ct @@ -0,0 +1,83 @@ +/* + * Main function for all tests + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include +#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include + + +int exit_test_thread(void *arg) +{ + while (1) + ; + //l4_thread_switch(0); + //l4_exit(5); + return 0; +} + +int exit_test(void) +{ + int ret; + struct task_ids ids; + + /* Create and run a new thread */ + if ((ret = thread_create(exit_test_thread, 0, + TC_SHARE_SPACE | TC_AS_PAGER, + &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } else + printf("Thread (%d) created successfully.\n", ids.tid); + + // l4_thread_switch(0); + + /* Kill it */ + printf("Killing Thread (%d).\n", ids.tid); + if ((ret = l4_thread_control(THREAD_DESTROY, &ids)) < 0) + printf("Error: Killing Thread (%d), err = %d\n", ids.tid, ret); + else + printf("Success: Killed Thread (%d)\n", ids.tid); + + +#if 0 + /* Wait on it */ + printf("Waiting on Thread (%d) to exit.\n", ids.tid); + if ((ret = l4_thread_control(THREAD_WAIT, &ids)) >= 0) + printf("Success. Paged child returned %d\n", ret); + else + printf("Error. Wait on (%d) failed. err = %d\n", + ids.tid, ret); + +#endif + return 0; +out_err: + BUG(); +} + +int main(void) +{ + printf("%s: Container %s started\n", + __CONTAINER__, __CONTAINER_NAME__); + + /* Performance tests */ + /* API Tests */ + capability_test(); + + //exit_test(); + + /* Now quit to demo self-paging quit */ + //l4_exit(0); + + /* Now quit by null pointer */ + // *((int *)0) = 5; + + return 0; +} + diff --git a/conts/test_suite0/include/api/api.h b/conts/test_suite0/include/api/api.h new file mode 100644 index 0000000..b1e03bc --- /dev/null +++ b/conts/test_suite0/include/api/api.h @@ -0,0 +1,16 @@ +#ifndef __TEST_SUITE_API_H__ +#define __TEST_SUITE_API_H__ + + +int test_api_cctrl(void); +int test_api_tctrl(void); +int test_api_capctrl(void); +int test_api_getid(void); +int test_api_mutexctrl(void); +int test_api_tswitch(void); +int test_api_exregs(void); +int test_api_ipc(void); +int test_api_irqctrl(void); +int test_api_map_unmap(void); + +#endif /* __TEST_SUITE_API_H__ */ diff --git a/conts/test_suite0/include/capability.h b/conts/test_suite0/include/capability.h new file mode 100644 index 0000000..f30cb58 --- /dev/null +++ b/conts/test_suite0/include/capability.h @@ -0,0 +1,6 @@ +#ifndef __CAPABILITY_H__ +#define __CAPABILITY_H__ + +int caps_read_all(); + +#endif /* __CAPABILITY_H__ */ diff --git a/conts/test_suite0/include/container.h b/conts/test_suite0/include/container.h new file mode 100644 index 0000000..ef93768 --- /dev/null +++ b/conts/test_suite0/include/container.h @@ -0,0 +1,13 @@ +/* + * Autogenerated definitions for this container. + */ +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + + +#define __CONTAINER_NAME__ "test_suite0" +#define __CONTAINER_ID__ 0 +#define __CONTAINER__ "cont0" + + +#endif /* __CONTAINER_H__ */ diff --git a/conts/test_suite0/include/debug.h b/conts/test_suite0/include/debug.h new file mode 100644 index 0000000..5a703d8 --- /dev/null +++ b/conts/test_suite0/include/debug.h @@ -0,0 +1,44 @@ +/* + * Debug/performance measurements for mm0 + * + * Copyright (C) 2010 B Labs Ltd. + */ +#ifndef __ARCH_DEBUG_H__ +#define __ARCH_DEBUG_H__ + +#if !defined(CONFIG_DEBUG_PERFMON_USER) + +#include + +/* Common empty definitions for all arches */ +static inline u32 perfmon_read_cyccnt() { return 0; } + +static inline void perfmon_reset_start_cyccnt() { } +static inline u32 perfmon_read_reset_start_cyccnt() { return 0; } + +#define debug_record_cycles(str) + +#else /* End of CONFIG_DEBUG_PERFMON_USER */ + +/* Architecture specific perfmon cycle counting */ +#include L4LIB_INC_SUBARCH(perfmon.h) + +extern u64 perfmon_total_cycles; +extern u64 current_cycles; + +/* + * This is for Cortex-A9 running at 400Mhz. 25 / 100000 is + * a rewriting of 2.5 nanosec / 1,000,000 + */ +#define debug_record_cycles(str) \ +{ \ + current_cycles = perfmon_read_cyccnt(); \ + perfmon_total_cycles += current_cycles; \ + printf("%s: took %llu milliseconds\n", str, \ + current_cycles * 64 * 25 / 100000); \ + perfmon_reset_start_cyccnt(); \ +} + +#endif /* End of !CONFIG_DEBUG_PERFMON_USER */ + +#endif /* __ARCH_DEBUG_H__ */ diff --git a/conts/test_suite0/include/fault.h b/conts/test_suite0/include/fault.h new file mode 100644 index 0000000..5b92fe4 --- /dev/null +++ b/conts/test_suite0/include/fault.h @@ -0,0 +1,44 @@ +#ifndef __FAULT_H__ +#define __FAULT_H__ + +#include +#include +#include INC_GLUE(memory.h) +#include INC_ARCH(exception.h) + +/* Protection flags */ +#define VM_NONE (1 << 0) +#define VM_READ (1 << 1) +#define VM_EXEC (1 << 2) +#define VM_WRITE (1 << 3) +#define VM_PROT_MASK (VM_READ | VM_WRITE | VM_EXEC) + +/* Shared copy of a file */ +#define VMA_SHARED (1 << 4) +/* VMA that's not file-backed, always maps devzero as VMA_COW */ +#define VMA_ANONYMOUS (1 << 5) +/* Private copy of a file */ +#define VMA_PRIVATE (1 << 6) +/* For wired pages */ +#define VMA_FIXED (1 << 7) +/* For stack, where mmap returns end address */ +#define VMA_GROWSDOWN (1 << 8) + +/* Set when the page is dirty in cache but not written to disk */ +#define VM_DIRTY (1 << 9) + +/* Fault data specific to this task + ptr to kernel's data */ +struct fault_data { + fault_kdata_t *kdata; /* Generic data forged by the kernel */ + unsigned int reason; /* Generic fault reason flags */ + unsigned int address; /* Aborted address */ + unsigned int pte_flags; /* Generic protection flags on pte */ + l4id_t sender; /* Inittask-related fault data */ +}; + + +void set_generic_fault_params(struct fault_data *fault); +void arch_print_fault_params(struct fault_data *fault); +void fault_handle_error(struct fault_data *fault); + +#endif /* __FAULT_H__ */ diff --git a/conts/test_suite0/include/linker.h b/conts/test_suite0/include/linker.h new file mode 100644 index 0000000..099195f --- /dev/null +++ b/conts/test_suite0/include/linker.h @@ -0,0 +1,16 @@ +#ifndef __TEST_SUITE_LINKER_H__ +#define __TEST_SUITE_LINKER_H__ + +extern unsigned char __stack[]; +extern unsigned char __end[]; +extern unsigned char vma_start[]; +extern unsigned char lma_start[]; +extern unsigned char offset[]; +extern unsigned char __data_start[]; +extern unsigned char __data_end[]; +extern unsigned char __bss_start[]; +extern unsigned char __bss_end[]; +extern unsigned char __stack_start[]; +extern unsigned char __stack_end[]; + +#endif /* __LINKER_H__ */ diff --git a/conts/test_suite0/include/linker.lds b/conts/test_suite0/include/linker.lds new file mode 100644 index 0000000..45a75c3 --- /dev/null +++ b/conts/test_suite0/include/linker.lds @@ -0,0 +1,30 @@ +/* + * Example working linker script for this container. + * + * Copyright (C) 2009 B Labs Ltd. + */ + +vma_start = 0xa0000000; +lma_start = 0x100000; +offset = vma_start - lma_start; + +ENTRY(_start) + +SECTIONS +{ + . = vma_start; + .text : AT (ADDR(.text) - offset) { *(.text.head) *(.text) } + .rodata : AT (ADDR(.rodata) - offset) { *(.rodata) } + .rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) } + + . = ALIGN(4K); + .data : AT (ADDR(.data) - offset) { *(.data) } + .bss : AT (ADDR(.bss) - offset) + { + *(.bss) + . += 0x1000; + . = ALIGN(8); + __stack = .; + } + __end = .; +} diff --git a/conts/test_suite0/include/macros.h b/conts/test_suite0/include/macros.h new file mode 100644 index 0000000..0da543b --- /dev/null +++ b/conts/test_suite0/include/macros.h @@ -0,0 +1,9 @@ +#ifndef __TEST_MACROS_H__ +#define __TEST_MACROS_H__ + +#define __INC_ARCH(x) +#define __INC_SUBARCH(x) +#define __INC_PLAT(x) +#define __INC_GLUE(x) + +#endif /* __TEST_MACROS_H__ */ diff --git a/conts/test_suite0/include/memory.h b/conts/test_suite0/include/memory.h new file mode 100644 index 0000000..f126dea --- /dev/null +++ b/conts/test_suite0/include/memory.h @@ -0,0 +1,12 @@ +#ifndef __TESTSUITE_MEMORY_H__ +#define __TESTSUITE_MEMORY_H__ + + + +void *virtual_page_new(int npages); +void *physical_page_new(int npages); +void virtual_page_free(void *address, int npages); +void physical_page_free(void *address, int npages); + +void page_pool_init(void); +#endif /* __TESTSUITE_MEMORY_H__ */ diff --git a/conts/test_suite0/include/perf.h b/conts/test_suite0/include/perf.h new file mode 100644 index 0000000..20ee58a --- /dev/null +++ b/conts/test_suite0/include/perf.h @@ -0,0 +1,69 @@ +#ifndef __PERF_TESTS_H__ +#define __PERF_TESTS_H__ + +/* Architecture specific perfmon cycle counting */ +#include +#include +#include L4LIB_INC_SUBARCH(perfmon.h) + +struct perfmon_cycles { + u64 last; /* Last op cycles */ + u64 min; /* Minimum cycles */ + u64 max; /* Max cycles */ + u64 avg; /* Average cycles */ + u64 total; /* Total cycles */ + u64 ops; /* Total ops */ +}; + +/* + * This is for converting cycle count to timings on + * Cortex-A9 running at 400Mhz. 25 / 100000 is + * a rewriting of 2.5 nanosec / 1,000,000 in millisec + * + * 25 / 100 = 2.5nanosec * 10 / 1000 = microseconds + */ + +#define CORTEXA9_400MHZ_USEC 25 / 10000 +#define CORTEXA9_400MHZ_MSEC 25 / 10000000 +#define USEC_MULTIPLIER CORTEXA9_400MHZ_USEC +#define MSEC_MULTIPLIER CORTEXA9_400MHZ_MSEC + +#if !defined(CONFIG_DEBUG_PERFMON_USER) + + +#define perfmon_record_cycles(ptr, str) + +#else /* End of CONFIG_DEBUG_PERFMON_USER */ + +#define perfmon_record_cycles(pcyc, str) \ +{ \ + (pcyc)->ops++; \ + (pcyc)->last = perfmon_read_cyccnt() * 64; \ + (pcyc)->total += (pcyc)->last; \ + if ((pcyc)->min > (pcyc)->last) \ + (pcyc)->min = (pcyc)->last; \ + if ((pcyc)->max < (pcyc)->last) \ + (pcyc)->max = (pcyc)->last; \ +} + +/* Same as above but restarts counter */ +#define perfmon_checkpoint_cycles(pcyc, str) \ +{ \ + (pcyc)->last = perfmon_read_cyccnt(); \ + (pcyc)->total += pcyc->last; \ + perfmon_reset_start_cyccnt(); \ +} +#endif /* End of !CONFIG_DEBUG_PERFMON_USER */ + +void platform_measure_cpu_cycles(void); +void perf_measure_getid_ticks(void); +void perf_measure_cpu_cycles(void); +void perf_measure_getid(void); +void perf_measure_tctrl(void); +int perf_measure_exregs(void); +void perf_measure_ipc(void); +void perf_measure_map(void); +void perf_measure_unmap(void); +void perf_measure_mutex(void); + +#endif /* __PERF_TESTS_H__ */ diff --git a/conts/test_suite0/include/project_linker.lds b/conts/test_suite0/include/project_linker.lds new file mode 100644 index 0000000..d6e3a92 --- /dev/null +++ b/conts/test_suite0/include/project_linker.lds @@ -0,0 +1,38 @@ +/* + * Example working linker script for this container. + * + * Copyright (C) 2009 B Labs Ltd. + */ + +vma_start = 0xa0000000; +lma_start = 0x100000; +offset = vma_start - lma_start; + +ENTRY(_start) + +SECTIONS +{ + . = vma_start; + .text : AT (ADDR(.text) - offset) { *(.text.head) *(.text) } + .rodata : AT (ADDR(.rodata) - offset) { *(.rodata) } + .rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) } + + . = ALIGN(4K); + __data_start = .; + .data : AT (ADDR(.data) - offset) { *(.data) } + __data_end = .; + + __bss_start = .; + .bss : AT (ADDR(.bss) - offset) { *(.bss) } + __bss_end = .; + + __stack_start = .; + .stack : AT (ADDR(.stack) - offset) + { + . += 0x3000; + . = ALIGN(4K); + __stack = .; + } + __stack_end = .; + __end = .; +} diff --git a/conts/test_suite0/include/tests.h b/conts/test_suite0/include/tests.h new file mode 100644 index 0000000..e3e9b0d --- /dev/null +++ b/conts/test_suite0/include/tests.h @@ -0,0 +1,18 @@ +#ifndef __TESTS_H__ +#define __TESTS_H__ + +/* Abort debugging conditions */ +#define DEBUG_TESTS 0 +#if DEBUG_TESTS +#define dbg_printf(...) printf(__VA_ARGS__) +#else +#define dbg_printf(...) +#endif + +int test_smp(); +int test_performance(); +int test_api(); +int test_cli_serv(); +int test_mthread(); + +#endif /* __TESTS_H__ */ diff --git a/conts/test_suite0/include/thread.h b/conts/test_suite0/include/thread.h new file mode 100644 index 0000000..1805d27 --- /dev/null +++ b/conts/test_suite0/include/thread.h @@ -0,0 +1,19 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include + + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids); + +/* For same space */ +#define STACK_SIZE 0x1000 + +#define THREADS_TOTAL 10 + +#endif /* __THREAD_H__ */ diff --git a/conts/test_suite0/include/timer.h b/conts/test_suite0/include/timer.h new file mode 100644 index 0000000..06db1f6 --- /dev/null +++ b/conts/test_suite0/include/timer.h @@ -0,0 +1,9 @@ +#ifndef __PERF_TESTS_TIMER_H__ +#define __PERF_TESTS_TIMER_H__ + +#include + +extern unsigned long timer_base; +void perf_timer_init(void); + +#endif /* __PERF_TESTS_TIMER_H__ */ diff --git a/conts/test_suite0/main.c b/conts/test_suite0/main.c new file mode 100644 index 0000000..ad6537d --- /dev/null +++ b/conts/test_suite0/main.c @@ -0,0 +1,47 @@ +/* + * Main function for all tests + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include + + +void run_tests(void) +{ + /* Performance tests */ + //if (test_performance() < 0) + // printf("Performance tests failed.\n"); + + if (test_smp() < 0) + printf("SMP tests failed.\n"); + + /* API Tests */ + if (test_api() < 0) + printf("API tests failed.\n"); + + /* Container client/server setup test */ + if (test_cli_serv() < 0) + printf("Client/server tests failed.\n"); + + /* Container multithreaded/standalone setup test */ + if (test_mthread() < 0) + printf("Multi-threaded tests failed.\n"); +} + +int main(void) +{ + printf("%s: Container %s started\n", + __CONTAINER__, __CONTAINER_NAME__); + + run_tests(); + + return 0; +} + diff --git a/conts/test_suite0/src/api/api.c b/conts/test_suite0/src/api/api.c new file mode 100644 index 0000000..aa5090e --- /dev/null +++ b/conts/test_suite0/src/api/api.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * API tests + * + * Author: Bahadir Balban + */ +#include +#include +#include + +/* + * Tests all api functions by expected and unexpected input + */ +int test_api(void) +{ + int err; + + /* Initialize free pages */ + page_pool_init(); + + if ((err = test_api_tctrl()) < 0) + return err; + + if ((err = test_api_getid()) < 0) + return err; + + if ((err = test_api_exregs()) < 0) + return err; + + if ((err = test_api_map_unmap()) < 0) + return err; + + if ((err = test_api_ipc()) < 0) + return err; + + if ((err = test_api_mutexctrl()) < 0) + return err; + + if ((err = test_api_cctrl()) < 0) + return err; + + if ((err = test_api_capctrl()) < 0) + return err; + + if ((err = test_api_irqctrl()) < 0) + return err; + + return 0; +} + diff --git a/conts/test_suite0/src/api/cache.c b/conts/test_suite0/src/api/cache.c new file mode 100644 index 0000000..366b9f5 --- /dev/null +++ b/conts/test_suite0/src/api/cache.c @@ -0,0 +1,80 @@ +/* + * Test cache control system call + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include INC_GLUE(memory.h) +#include +#include +#include +#include + +#include +#include L4LIB_INC_ARCH(syscalls.h) + +/* This simply tests that all cache calls are working */ +int test_cctrl_basic(void) +{ + struct capability *virtcap = cap_get_by_type(CAP_TYPE_MAP_VIRTMEM); + void *start = (void *)__pfn_to_addr(virtcap->start); + void *end = (void *)__end; + int err; + + if ((err = l4_cache_control(start, end, L4_INVALIDATE_ICACHE)) < 0) + return err; + + if ((err = l4_cache_control(start, end, L4_INVALIDATE_DCACHE)) < 0) + return err; + + if ((err = l4_cache_control(start, end, L4_CLEAN_INVALIDATE_DCACHE)) < 0) + return err; + + if ((err = l4_cache_control(start, end, L4_CLEAN_DCACHE)) < 0) + return err; + + if ((err = l4_cache_control(start, end, L4_INVALIDATE_TLB)) < 0) + return err; + + return 0; +} + +int test_cctrl_sync_caches() +{ + /* + * Double-map a physical page and fill it with + * mov r0, r0, r0 * PAGE_SIZE - 1 + * b return_label + */ + + /* Flush the Dcache for that page */ + + /* Invalidate I cache for that page */ + + /* Execute the page */ + + /* + * Create a new address space and execute the page from + * that space + */ + return 0; +} + +int test_api_cctrl(void) +{ + int err; + + if ((err = test_cctrl_basic()) < 0) + goto out_err; + + + printf("CACHE CONTROL: -- PASSED --\n"); + return 0; + +out_err: + printf("CACHE CONTROL: -- FAILED --\n"); + return err; + +} + diff --git a/conts/test_suite0/src/api/cap.c b/conts/test_suite0/src/api/cap.c new file mode 100644 index 0000000..8c8aafa --- /dev/null +++ b/conts/test_suite0/src/api/cap.c @@ -0,0 +1,56 @@ +/* + * Test capability control system call + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include +#include L4LIB_INC_ARCH(syscalls.h) + +#define TOTAL_CAPS 32 + +struct capability cap_array[TOTAL_CAPS]; + +/* + * Read number of capabilities + */ +int test_cap_read(void) +{ + int ncaps; + int err; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, &ncaps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + return err; + } + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, cap_array)) < 0) { + printf("l4_capability resource_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ_CAPS request.\n"); + return err; + } + //cap_array_print(ncaps, caparray); + + return 0; +} + + +int test_api_capctrl(void) +{ + int err; + + if ((err = test_cap_read()) < 0) + return err; + + return 0; +} + diff --git a/conts/test_suite0/src/api/exregs.c b/conts/test_suite0/src/api/exregs.c new file mode 100644 index 0000000..d4478e0 --- /dev/null +++ b/conts/test_suite0/src/api/exregs.c @@ -0,0 +1,96 @@ +/* + * Test exchange registers system call. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ + +#include +#include +#include +#include +#include + +int test_exregs_read_write(void) +{ + struct task_ids ids; + struct exregs_data exregs[2]; + int err; + + /* Get own space id */ + l4_getid(&ids); + + /* + * Create a thread in the same space. + * Thread is not runnable. + */ + if ((err = l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE, + &ids)) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", ids.tid); + + /* + * Prepare a context part full of 0xFF + */ + memset(&exregs[0].context, 0xFF, sizeof(exregs[1].context)); + exregs[0].valid_vect = 0xFFFFFFFF; + + /* Write to context */ + if ((err = l4_exchange_registers(&exregs[0], ids.tid)) < 0) + goto out; + + /* Set the other as read-all */ + exregs_set_read(&exregs[1]); + exregs[1].valid_vect = 0xFFFFFFFF; + if ((err = l4_exchange_registers(&exregs[1], + ids.tid)) < 0) + goto out; + + /* + * Read back all context and compare results + */ + if (memcmp(&exregs[0].context, &exregs[1].context, + sizeof(exregs[0].context))) { + err = -1; + goto out; + } + +out: + /* + * Destroy the thread + */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + dbg_printf("Thread destroy failed. err=%d\n", + err); + } + return 0; +} + + +int test_api_exregs(void) +{ + int err; + + if ((err = test_exregs_read_write()) < 0) + goto out_err; + + /* + * TODO: Should add more tests here, e.g. setting + * values of a thread we're not a pager of. + */ + + printf("EXCHANGE REGISTERS: -- PASSED --\n"); + return 0; + +out_err: + printf("EXCHANGE REGISTERS: -- FAILED --\n"); + return err; + +} + diff --git a/conts/test_suite0/src/api/getid.c b/conts/test_suite0/src/api/getid.c new file mode 100644 index 0000000..82c70c9 --- /dev/null +++ b/conts/test_suite0/src/api/getid.c @@ -0,0 +1,123 @@ +/* + * Test l4_getid system call. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include + + +int thread_getid_nullptr(void *arg) +{ + return l4_getid(0); +} + +/* + * Pass nullptr to l4_getid syscall + * + * This exercise proves that the kernel does not crash + * and validly sends a page fault to offending thread's + * pager. + */ +int test_getid_nullptr(void) +{ + struct l4_thread *thread; + int err; + + /* + * Create a new thread who will attempt + * passing null ptr argument + */ + if ((err = thread_create(thread_getid_nullptr, + 0, TC_SHARE_SPACE, + &thread)) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", thread->ids.tid); + + /* + * Listen on thread for its page fault + * ipc. (Recap: Upon illegal access, the kernel sends + * a page fault ipc message to thread's pager) + */ + if ((err = l4_receive(thread->ids.tid)) < 0) { + dbg_printf("%s: listening on page fault for " + "nullptr thread failed. " + "err = %d\n", __FUNCTION__, err); + return err; + } + + /* + * Verify ipc was a page fault ipc + */ + if (l4_get_tag() != L4_IPC_TAG_PFAULT) { + dbg_printf("%s: Nullptr thread ipc does not " + "have expected page fault tag.\n" + "tag=%d, expected=%d\n", + __FUNCTION__, l4_get_tag(), + L4_IPC_TAG_PFAULT); + return -1; + } + + /* + * Destroy the thread. + */ + if ((err = thread_destroy(thread)) < 0) { + dbg_printf("%s: Failed destroying thread. " + "err= %d, tid = %d\n", + __FUNCTION__, err, + thread->ids.tid); + return err; + } + return 0; +} + +int test_api_getid(void) +{ + struct task_ids ids; + int err; + + /* + * Test valid getid request + */ + if ((err = l4_getid(&ids)) < 0) { + dbg_printf("Getid request failed. err=%d\n", err); + goto out_err; + } + + /* Check returned results */ + if (ids.tid != 1 || ids.spid != 1 || ids.tgid != 1) { + dbg_printf("Getid results not as expected. " + "tid=%d, spid=%d, tgid=%d\n", + ids.tid, ids.spid, ids.tgid); + err = -1; + goto out_err; + } + + /* + * Test null pointer argument + */ + if ((err = test_getid_nullptr()) < 0) { + dbg_printf("l4_getid() null pointer test failed." + " err=%d\n", err); + goto out_err; + } + + printf("GETID: -- PASSED --\n"); + return 0; + +out_err: + printf("GETID: -- FAILED --\n"); + return err; + +} + diff --git a/conts/test_suite0/src/api/ipc.c b/conts/test_suite0/src/api/ipc.c new file mode 100644 index 0000000..e78e7e6 --- /dev/null +++ b/conts/test_suite0/src/api/ipc.c @@ -0,0 +1,547 @@ +/* + * Test ipc system call. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include +#include + +struct ipc_ext_data { + void *virtual; /* Virtual address to start ipc from */ + l4id_t partner; /* Partner to do extended ipc */ +}; + +int ipc_extended_sender(void *arg) +{ + struct ipc_ext_data *data = arg; + int err; + + if ((err = l4_send_extended(data->partner, 0, + SZ_2K, data->virtual)) < 0) { + printf("%s: Extended send failed. err=%d\n", + __FUNCTION__, err); + } + return 0; +} + +int ipc_extended_receiver(void *arg) +{ + struct ipc_ext_data *data = arg; + int err; + + if ((err = l4_receive_extended(data->partner, SZ_2K, + data->virtual)) < 0) { + printf("%s: Extended receive failed. err=%d\n", + __FUNCTION__, err); + } + + /* + * Test the data received + */ + for (int i = 0; i < SZ_2K; i++) { + if (((char *)data->virtual)[i] != 'A' + i) + printf("%s: Extended receive buffer has unexpected " + "data: Start %p, Offset: %d, " + "Data=%d, expected=%d\n", __FUNCTION__, + data->virtual, i, ((char *)data->virtual)[i], + 'A' + i); + return err; + } + + return 0; +} + +int ipc_ext_handle_pfault(struct ipc_ext_data *ipc_data, + void **virt, void **phys) +{ + u32 mr[MR_UNUSED_TOTAL]; + struct fault_data fault; + int err; + + /* Read mrs not used by syslib */ + for (int i = 0; i < MR_UNUSED_TOTAL; i++) + mr[i] = read_mr(MR_UNUSED_START + i); + + fault.kdata = (fault_kdata_t *)&mr[0]; + fault.sender = l4_get_sender(); + + /* Convert from arch-specific to generic fault data */ + set_generic_fault_params(&fault); + + /* + * Handle the fault using a basic logic - if a virtual index + * is faulted, map the corresponding page at same physical index. + */ + if (page_align(fault.address) == (unsigned long)virt[0]) { + if ((err = l4_map(phys[0], virt[0], 1, + MAP_USR_RW, fault.sender)) < 0) { + printf("%s: Error: l4_map failed. " + "phys=%p, virt=%p\n", __FUNCTION__, + phys[0], virt[0]); + return err; + } + } else if (page_align(fault.address) == (unsigned long)virt[1]) { + if ((err = l4_map(phys[1], virt[1], 1, + MAP_USR_RW, fault.sender)) < 0) { + printf("%s: Error: l4_map failed. " + "phys=%p, virt=%p\n", __FUNCTION__, + phys[1], virt[1]); + return err; + } + } else if (page_align(fault.address) == (unsigned long)virt[2]) { + if ((err = l4_map(phys[2], virt[2], 1, + MAP_USR_RW, fault.sender)) < 0) { + printf("%s: Error: l4_map failed. " + "phys=%p, virt=%p\n", __FUNCTION__, + phys[2], virt[2]); + return err; + } + } else if (page_align(fault.address) == (unsigned long)virt[3]) { + if ((err = l4_map(phys[3], virt[3], 1, + MAP_USR_RW, fault.sender)) < 0) { + printf("%s: Error: l4_map failed. " + "phys=%p, virt=%p\n", __FUNCTION__, + phys[3], virt[3]); + return err; + } + } else { + printf("%s: Error, page fault occured on an unexpected " + "address. adress=0x%x\n", __FUNCTION__, + fault.address); + return -1; + } + + /* Reply back to fault thread and return */ + return l4_ipc_return(0); +} + +/* + * Create two threads who will do page-faulting ipc to each other. + * Their parent waits and handles the page faults. + * + * This test allocates 4 virtual page and 4 physical page addresses. + * It fills a total of 2KB of payload starting from the 3rd quarter + * of the first page and until the 2nd quarter of the 2nd page to + * be sent by the sender thread. + * + * The payload is copied and the pages deliberately unmapped so that + * the sender thread will page fault during the send operation. + * + * The receive pages are also set up same as above, so the receiving + * thread also faults during the receive. + * + * The main thread starts both ipc threads, and starts waiting on + * page faults. It handles the faults and the test succeeds if the + * data is transfered safely to receiving end, despite all faults. + */ +int test_ipc_extended(void) +{ + struct task_ids self_ids; + struct ipc_ext_data ipc_data[2]; + struct l4_thread *thread[2]; + void *virt[4], *phys[4]; + int err, tag; + + l4_getid(&self_ids); + + /* Get 4 physical pages */ + for (int i = 0; i < 4; i++) + phys[i] = physical_page_new(1); + + /* Get 2 pairs of virtual pages */ + virt[0] = virtual_page_new(2); + virt[1] = virt[0] + PAGE_SIZE; + virt[2] = virtual_page_new(2); + virt[3] = virt[2] + PAGE_SIZE; + + /* Map sender pages to self */ + if ((err = l4_map(phys[0], virt[0], 1, + MAP_USR_RW, self_ids.tid)) < 0) { + printf("Error: Mapping Sender pages failed. phys: 0x%p," + " virt: 0x%p, tid=%d, err=%d\n", phys[0], virt[0], + self_ids.tid, err); + return err; + } + if ((err = l4_map(phys[1], virt[1], 1, + MAP_USR_RW, self_ids.tid)) < 0) { + printf("Error: Mapping Sender pages failed. phys: 0x%p," + " virt: 0x%p, tid=%d, err=%d\n", phys[0], virt[0], + self_ids.tid, err); + return err; + } + + /* + * Fill them with values to be sent + * Filling in 3rd KB of first page to 2nd KB of second page + */ + for (int i = 0; i < SZ_2K; i++) + ((char *)virt[0] + SZ_1K * 3)[i] = 'A' + i; + + /* Unmap the pages */ + l4_unmap(virt[0], 2, self_ids.tid); + + /* Create ipc threads but don't start. */ + if ((err = thread_create(ipc_extended_sender, + &ipc_data[0], + TC_SHARE_SPACE | TC_NOSTART, + &thread[0])) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", thread[0]->ids.tid); + + if ((err = thread_create(ipc_extended_receiver, + &ipc_data[1], + TC_SHARE_SPACE | TC_NOSTART, + &thread[1])) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", thread[1]->ids.tid); + + /* + * Set up arguments to sender, + * Send offset at 3rd quarter of first page. + */ + ipc_data[0].virtual = virt[0] + SZ_1K * 3; + ipc_data[0].partner = thread[1]->ids.tid; + + /* + * Set up arguments to receiver + * Receive offset at 3rd quarter of first page. + */ + ipc_data[1].virtual = virt[1] + SZ_1K * 3; + ipc_data[1].partner = thread[0]->ids.tid; + + /* Start the threads */ + l4_thread_control(THREAD_RUN, &thread[0]->ids); + l4_thread_control(THREAD_RUN, &thread[1]->ids); + + /* Expecting 4 faults on 4 pages */ + for (int i = 0; i < 4; i++) { + /* Wait on page fault */ + if ((err = l4_receive(L4_ANYTHREAD)) < 0) { + printf("Error: l4_receive() for page" + " fault has failed. err=%d\n", + err); + } + if ((tag = l4_get_tag()) != L4_IPC_TAG_PFAULT) { + printf("Error: Parent thread received " + "non-page fault ipc tag. tag=%d\n", + tag); + return -1; + } + + /* Handle fault */ + if ((err = ipc_ext_handle_pfault(ipc_data, virt, phys)) < 0) { + printf("Error: An error occured during ipc " + "page fault handling. err=%d\n", err); + return err; + } + } + + /* Wait for the ipc threads */ + for (int i = 0; i < 2; i ++) + if ((err = thread_wait(thread[i])) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } + + /* Unmap and release pages */ + for (int i = 0; i < 4; i++) { + l4_unmap(virt[i], 1, self_ids.tid); + virtual_page_free(virt[i], 1); + physical_page_free(phys[i], 1); + } + + return 0; +} + +int ipc_full_thread(void *arg) +{ + l4id_t parent = *((l4id_t *)arg); + int err; + + /* Do two full send/receives */ + for (int i = 0; i < 2; i++) { + /* Full receive, return positive if error */ + if ((err = l4_receive_full(parent)) < 0) { + dbg_printf("Full receive failed on new " + "thread. err=%d", err); + return 1; + } + + /* Test full utcb received values */ + for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) { + if (read_mr(i) != i) { + dbg_printf("IPC full receive on new thread: " + "Unexpected message register " + "values. MR%d = %d, should be %d\n", + i, read_mr(i), i); + return 1; /* Exit positive without reply */ + } + } + + /* + * Reset all message registers + */ + for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) + write_mr(i, 0); + + /* Send full return reply */ + l4_send_full(parent, 0); + } + return 0; +} + +int ipc_short_thread(void *arg) +{ + l4id_t parent = *((l4id_t *)arg); + int err; + + /* Short receive, return positive if error */ + if ((err = l4_receive(parent)) < 0) { + dbg_printf("Short receive failed on new " + "thread. err=%d", err); + return 1; + } + + /* Test received registers */ + for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) { + if (read_mr(i) != i) { + dbg_printf("IPC Receive on new thread: " + "Unexpected message register " + "values.\n" + "read = %d, expected = %d\n", + read_mr(i), i); + l4_print_mrs(); + return 1; /* Exit positive without reply */ + } + } + + /* + * Reset all message registers + */ + for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) + write_mr(i, 0); + + /* + * Send return reply and exit + */ + return l4_send(parent, 0); +} + + +/* + * Create a thread and do a full ipc to it + */ +int test_ipc_full(void) +{ + struct task_ids self_ids; + struct l4_thread *thread; + int err; + + l4_getid(&self_ids); + + /* + * Create a thread in the same space + */ + if ((err = thread_create(ipc_full_thread, + &self_ids.tid, + TC_SHARE_SPACE, + &thread)) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", thread->ids.tid); + + /* + * Try one short and one full send/recv + * to test full send/recv occurs on both cases + */ + + /* + * Write data to full utcb registers + */ + for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) + write_mr(i, i); + + /* + * First, do a full ipc send/recv + */ + if ((err = l4_sendrecv_full(thread->ids.tid, + thread->ids.tid, + 0)) < 0) { + dbg_printf("Full IPC send/recv failed. " + "err=%d\n", err); + return err; + } + + /* + * Check that payload registers are modified to 0 + */ + dbg_printf("%s: After send/recv:\n", __FUNCTION__); + for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) { + if (read_mr(i) != 0) { + dbg_printf("Full IPC send/recv: " + "Received payload is not " + "as expected.\n " + "MR%d = %d, should be %d\n", + i, read_mr(i), 0); + return -1; + } + } + + /* + * Write data to full utcb registers + */ + for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) + write_mr(i, i); + + /* + * Try a short ipc send/recv. This should still result + * in full ipc since the other side is doing full send/recv. + */ + if ((err = l4_sendrecv(thread->ids.tid, + thread->ids.tid, + 0)) < 0) { + dbg_printf("Full IPC send/recv failed. " + "err=%d\n", err); + return err; + } + + /* + * Check that payload registers are modified to 0 + */ + // dbg_printf("%s: After send/recv:\n", __FUNCTION__); + for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) { + // dbg_printf("MR%d: %d\n", i, read_mr(i)); + if (read_mr(i) != 0) { + dbg_printf("Full IPC send/recv: " + "Received payload is not " + "as expected.\n " + "MR%d = %d, should be %d\n", + i, read_mr(i), 0); + return -1; + } + } + + /* Wait for the ipc thread to die */ + if ((err = thread_wait(thread)) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Full IPC send/recv successful.\n"); + return 0; +} + +/* + * Create a thread and do a short ipc to it + */ +int test_ipc_short(void) +{ + struct task_ids self_ids; + struct l4_thread *thread; + int err; + + l4_getid(&self_ids); + + /* + * Create a thread in the same space + */ + if ((err = thread_create(ipc_short_thread, + &self_ids.tid, + TC_SHARE_SPACE, + &thread)) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", thread->ids.tid); + + /* + * Write data to short ipc registers + */ + for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) + write_mr(i, i); + + /* + * Do short ipc send/recv and check data is reset + */ + if ((err = l4_sendrecv(thread->ids.tid, + thread->ids.tid, + 0)) < 0) { + dbg_printf("Short IPC send/recv failed. " + "err=%d\n", err); + return err; + } + + /* + * Check that payload registers are reset + */ + for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) { + if (read_mr(i) != 0) { + dbg_printf("Short IPC send/recv: " + "Received payload is incorrect." + "read = %d, expected=%d\n", + read_mr(i), 0); + return -1; + } + } + + /* Wait for the ipc thread */ + if ((err = thread_wait(thread)) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Short IPC send/recv successful.\n"); + return 0; +} + +int test_api_ipc(void) +{ + int err; + + if ((err = test_ipc_extended()) < 0) + goto out_err; + + if ((err = test_ipc_short()) < 0) + goto out_err; + + if ((err = test_ipc_full()) < 0) + goto out_err; + + printf("IPC: -- PASSED --\n"); + return 0; + +out_err: + printf("IPC: -- FAILED --\n"); + return err; + +} + diff --git a/conts/test_suite0/src/api/irq.c b/conts/test_suite0/src/api/irq.c new file mode 100644 index 0000000..867e083 --- /dev/null +++ b/conts/test_suite0/src/api/irq.c @@ -0,0 +1,12 @@ +/* + * Test irq control system call + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +int test_api_irqctrl(void) +{ + return 0; +} + diff --git a/conts/test_suite0/src/api/map.c b/conts/test_suite0/src/api/map.c new file mode 100644 index 0000000..d6f848e --- /dev/null +++ b/conts/test_suite0/src/api/map.c @@ -0,0 +1,366 @@ +/* + * Test l4_map/unmap system call. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syscalls.h) +#include L4LIB_INC_ARCH(syslib.h) +#include INC_GLUE(memory.h) +#include +#include + +#define KERNEL_PAGE 0xF0000000UL +#define KIP_PAGE 0xFF000000UL +#define SYSCALL_PAGE 0xFFFFF000UL +#define VECTOR_PAGE 0xFFFF0000UL + +int test_api_map(void) +{ + int err; + unsigned int flags; + l4id_t self = self_tid(); + + /* + * Make a valid mapping, a few pages below + * the end of physical and virtual marks + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + MAP_USR_RW, + self)) < 0) { + dbg_printf("sys_map failed on valid request. err=%d\n", + err); + return err; + } + + /* + * Redo the same mapping. This should be valid. + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + MAP_USR_RW, + self)) < 0) { + dbg_printf("sys_map failed on re-doing " + "valid request. err=%d\n", err); + return err; + } + + /* + * Try mapping outside the virtual range + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded on invalid " + "virtual range ret=%d\n", err); + return -1; + } + + /* + * Try mapping outside the physical range + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded on invalid " + "physical range ret=%d\n", err); + return -1; + } + + /* + * Try having them both out of range + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END, + (void *)CONFIG_CONT0_VIRT0_END, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "physical and virtual ranges " + "supplied ret=%d\n", err); + return -1; + } + + /* + * Try out of range by off-by-one page size excess + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 6, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "physical and virtual ranges using " + "off-by-one page size." + "ret=%d\n", err); + return -1; + } + + /* + * Try invalid page size + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 0xFFFFFFFF, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "page size supplied ret=%d\n", err); + return -1; + } + + /* + * Try invalid flags + */ + flags = 0; + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + flags, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "flags supplied flags=%u, ret=%d\n", flags, err); + return -1; + } + flags = MAP_KERN_RWX; + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + 0, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "flags supplied flags=%u, ret=%d\n", flags, err); + return -1; + } + flags = MAP_KERN_IO; + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + 0, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "flags supplied flags=%u, ret=%d\n", flags, err); + return -1; + } + + flags = MAP_KERN_RX; + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + 0, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "flags supplied flags=%u, ret=%d\n", flags, err); + return -1; + } + + flags = 0xF0F0F01; + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + 0, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "flags supplied flags=%u, ret=%d\n", flags, err); + return -1; + } + + /* + * Try passing wraparound values + */ + if ((err = l4_map((void *)0xFFFFFFFF, + (void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "wraparound ranges supplied ret=%d\n", err); + return -1; + } + + /* + * Try passing wraparound values + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)0xFFFFF000, + 2, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when invalid " + "wraparound ranges supplied ret=%d\n", err); + return -1; + } + + /* + * Try mapping onto kernel + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)0xF0000000, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when trying to " + "map onto the kernel ret=%d\n", err); + return -1; + } + + /* + * Try mapping to vector page + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)0xFFFF0000, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when trying to " + "map to the vectors page ret=%d\n", err); + return -1; + } + + /* + * Try mapping to kip + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)0xFF000000, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when trying to " + "map to the kip page ret=%d\n", err); + return -1; + } + + /* + * Try mapping to syscall page + */ + if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5, + (void *)0xFFFFF000, + 1, + MAP_USR_RW, + self)) == 0) { + dbg_printf("sys_map succeeded when trying to " + "map to the kip page ret=%d\n", err); + return -1; + } + + return 0; +} + + +int test_api_unmap(void) +{ + int err; + l4id_t self = self_tid(); + + /* + * Try a valid unmap + */ + if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + self)) < 0) { + dbg_printf("sys_unmap failed on valid request. err=%d\n", + err); + return err; + } + + /* + * Try the same unmap, should return ENOMAP + */ + if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, + self)) != -ENOMAP) { + dbg_printf("sys_unmap did not return ENOMAP " + "on second unmap of same region. err=%d\n", + err); + return -1; + } + + + /* + * Try unmapping privileged areas + */ + if ((err = l4_unmap((void *)KERNEL_PAGE, 1, self)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + + if ((err = l4_unmap((void *)VECTOR_PAGE, 1, self)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + + if ((err = l4_unmap((void *)SYSCALL_PAGE, 1, self)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + + /* + * Try unmapping with range rollover + */ + if ((err = l4_unmap((void *)KERNEL_PAGE, 0xFFFFFFFF, self)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 0xFFFFFFFF, self)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + + /* + * Try unmapping zero pages + */ + if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 0, self)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + + /* + * Try unmapping with invalid id + */ + if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5, + 1, 0xFFFFFFFF)) == 0) { + dbg_printf("sys_unmap succeeded on invalid " + "unmap region. err=%d\n", err); + return -1; + } + + return 0; +} + +int test_api_map_unmap(void) +{ + int err; + + if ((err = test_api_map()) < 0) + goto out_err; + + if ((err = test_api_unmap()) < 0) + goto out_err; + + + printf("MAP/UNMAP: -- PASSED --\n"); + return 0; + +out_err: + printf("MAP/UNMAP: -- FAILED --\n"); + return err; + +} + diff --git a/conts/test_suite0/src/api/memory.c b/conts/test_suite0/src/api/memory.c new file mode 100644 index 0000000..82797e5 --- /dev/null +++ b/conts/test_suite0/src/api/memory.c @@ -0,0 +1,198 @@ +/* + * Empty virtual and physical pages for + * creating test scenarios + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include INC_GLUE(memory.h) +#include +#include +#include +#include +#include +#include +#include + +/* + * Declare a statically allocated char buffer + * with enough bitmap size to cover given size + */ +#define DECLARE_IDPOOL(name, size) \ + char name[(sizeof(struct id_pool) + ((size >> 12) >> 3))] + +struct address_pool virtual_page_pool, physical_page_pool; + +#define PAGE_POOL_SIZE SZ_16MB + +DECLARE_IDPOOL(virtual_idpool, PAGE_POOL_SIZE); +DECLARE_IDPOOL(physical_idpool, PAGE_POOL_SIZE); + +#define virt_to_phys(virtual) ((unsigned long)(virtual) - (unsigned long)(offset)) +#define phys_to_virt(physical) ((unsigned long)(physical) + (unsigned long)(offset)) + + +#define TEST_POOL_TOTAL 5 +/* + * Test page pool + */ +void test_page_pool(void) +{ + void *p[TEST_POOL_TOTAL], *v[TEST_POOL_TOTAL]; + + /* Allocate test pages */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + v[i] = virtual_page_new(1); + p[i] = physical_page_new(1); + dbg_printf("Test allocated: Virtual%d: 0x%p, " + "Physical%d, 0x%p\n", + i, v[i], i, p[i]); + } + + /* Free test pages */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + virtual_page_free(v[i], 1); + physical_page_free(p[i], 1); + } + + /* Re-allocate test pages */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + v[i] = virtual_page_new(1); + p[i] = physical_page_new(1); + dbg_printf("Test allocated: Virtual%d: 0x%p, " + "Physical%d, 0x%p\n", + i, v[i], i, p[i]); + } + + /* Free test pages */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + virtual_page_free(v[i], 1); + physical_page_free(p[i], 1); + } + + /* Allocate in different lengths */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + v[i] = virtual_page_new(i); + p[i] = physical_page_new(i); + dbg_printf("Test allocated: Virtual%d: 0x%p, " + "Physical%d, 0x%p\n", + i, v[i], i, p[i]); + } + + /* Free test pages in different order */ + for (int i = TEST_POOL_TOTAL - 1; i >= 0; i--) { + virtual_page_free(v[i], 1); + physical_page_free(p[i], 1); + } + + /* Allocate in different lengths */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + v[i] = virtual_page_new(i); + p[i] = physical_page_new(i); + dbg_printf("Test allocated: Virtual%d: 0x%p, " + "Physical%d, 0x%p\n", + i, v[i], i, p[i]); + } + + /* Free test pages in normal order */ + for (int i = 0; i < TEST_POOL_TOTAL; i++) { + virtual_page_free(v[i], 1); + physical_page_free(p[i], 1); + } +} + +void page_pool_init(void) +{ + struct capability *physcap, *virtcap; + unsigned long phys_start, phys_end; + unsigned long virt_start, virt_end; + + /* + * Get physmem capability (Must be only one) + */ + if (!(physcap = cap_get_physmem(CAP_TYPE_MAP_PHYSMEM))) { + printf("FATAL: Could not find a physical memory" + "capability to use as a page pool.\n"); + BUG(); + } + + /* + * Get virtmem capability (Must be only one) + */ + if (!(virtcap = cap_get_by_type(CAP_TYPE_MAP_VIRTMEM))) { + printf("FATAL: Could not find a virtual memory" + "capability to use as a page pool.\n"); + BUG(); + } + + /* + * Now initialize physical and virtual page marks + * from unused pages. Linker script will help us + * on this. + */ + /* + printf("__data_start symbol: %lx\n", (unsigned long)__data_start); + printf("__data_end symbol: %lx\n", (unsigned long)__data_end); + printf("__bss_start symbol: %lx\n", (unsigned long)__bss_start); + printf("__bss_end symbol: %lx\n", (unsigned long)__bss_end); + printf("__stack_start symbol: %lx\n", (unsigned long)__stack_start); + printf("__stack_end symbol: %lx\n", (unsigned long)__stack_end); + printf("__end symbol: %lx\n", (unsigned long)__end); + */ + + phys_start = page_align_up(virt_to_phys(__end) + + (unsigned long)lma_start); + phys_end = __pfn_to_addr(physcap->end); + + dbg_printf("%s: Initializing physical range 0x%lx - 0x%lx\n", + __FUNCTION__, phys_start, phys_end); + + virt_start = page_align_up(__end) + (unsigned long)lma_start; + virt_end = __pfn_to_addr(virtcap->end); + + dbg_printf("%s: Initializing virtual range 0x%lx - 0x%lx\n", + __FUNCTION__, virt_start, virt_end); + + /* Initialize pools, maximum of PAGE_POOL_SIZE size */ + address_pool_init(&virtual_page_pool, + (struct id_pool *)&virtual_idpool, + virt_start, min(virt_end, + virt_start + PAGE_POOL_SIZE)); + address_pool_init(&physical_page_pool, + (struct id_pool *)&physical_idpool, + phys_start, min(phys_end, + phys_start + PAGE_POOL_SIZE)); + + // test_page_pool(); +} + +/* + * Some tests require page-faulting virtual addresses or + * differing virtual addresses that map onto the same + * physical page. These functions provide these pages. + */ + +void *virtual_page_new(int npages) +{ + return address_new(&virtual_page_pool, npages, PAGE_SIZE); +} + +void *physical_page_new(int npages) +{ + return address_new(&physical_page_pool, npages, PAGE_SIZE); +} + +void virtual_page_free(void *address, int npages) +{ + address_del(&virtual_page_pool, address, + npages, PAGE_SIZE); +} + +void physical_page_free(void *address, int npages) +{ + address_del(&physical_page_pool, address, + npages, PAGE_SIZE); +} + diff --git a/conts/test_suite0/src/api/mutex.c b/conts/test_suite0/src/api/mutex.c new file mode 100644 index 0000000..4d643cf --- /dev/null +++ b/conts/test_suite0/src/api/mutex.c @@ -0,0 +1,204 @@ +/* + * Test l4_mutex_control system call. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include + +#define MUTEX_NTHREADS 8 +#define MUTEX_INCREMENTS 200 +#define MUTEX_VALUE_TOTAL (MUTEX_NTHREADS * MUTEX_INCREMENTS) + +struct mutex_test_data { + struct l4_mutex lock; + int val; +}; + +static struct mutex_test_data tdata; + +static void init_test_data(struct mutex_test_data *tdata) +{ + l4_mutex_init(&tdata->lock); + tdata->val = 0; +} + + +int mutex_thread_non_contending(void *arg) +{ + struct mutex_test_data *data = + (struct mutex_test_data *)arg; + l4id_t tid = self_tid(); + int err = tid; + + for (int i = 0; i < MUTEX_INCREMENTS; i++) { + /* Lock the data structure */ + if ((err = l4_mutex_lock(&data->lock)) < 0) { + dbg_printf("Thread %d: Acquiring mutex failed. " + "err = %d\n", tid, err); + return -err; + } + + /* + * Increment and release lock + */ + data->val++; + + /* Unlock the data structure */ + if ((err = l4_mutex_unlock(&data->lock)) < 0) { + dbg_printf("Thread %d: Releasing the mutex failed. " + "err = %d\n", tid, err); + return -err; + } + } + + return 0; +} + + + +int mutex_thread_contending(void *arg) +{ + struct mutex_test_data *data = + (struct mutex_test_data *)arg; + l4id_t tid = self_tid(); + int err = tid; + + for (int i = 0; i < MUTEX_INCREMENTS; i++) { + /* Lock the data structure */ + if ((err = l4_mutex_lock(&data->lock)) < 0) { + dbg_printf("Thread %d: Acquiring mutex failed. " + "err = %d\n", tid, err); + return -err; + } + + /* + * Sleep some time to have some + * threads blocked on the mutex + */ + for (int j = 0; j < 3; j++) + l4_thread_switch(0); + + /* + * Increment and release lock + */ + data->val++; + + /* Unlock the data structure */ + if ((err = l4_mutex_unlock(&data->lock)) < 0) { + dbg_printf("Thread %d: Releasing the mutex failed. " + "err = %d\n", tid, err); + return -err; + } + } + + return 0; +} + + +int test_mutex(int (*mutex_thread)(void *)) +{ + struct l4_thread *thread[MUTEX_NTHREADS]; + int err; + + /* Init mutex data */ + init_test_data(&tdata); + + /* + * Lock the mutex so nobody starts working + */ + if ((err = l4_mutex_lock(&tdata.lock)) < 0) { + dbg_printf("Acquiring mutex failed. " + "err = %d\n", err); + return err; + } + + /* Create threads */ + for (int i = 0; i < MUTEX_NTHREADS; i++) { + if ((err = thread_create(mutex_thread, + &tdata, + TC_SHARE_SPACE, + &thread[i])) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + } + + /* Unlock the mutex and initiate all workers */ + if ((err = l4_mutex_unlock(&tdata.lock)) < 0) { + dbg_printf("Releasing the mutex failed. " + "err = %d\n", err); + return -err; + } + + /* + * Wait for all threads to exit successfully + */ + for (int i = 0; i < MUTEX_NTHREADS; i++) { + if ((err = thread_wait(thread[i])) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } + } + + /* + * Test that lock is in correct state + */ + if (tdata.lock.lock != L4_MUTEX_UNLOCKED) { + dbg_printf("MUTEX is not in unlocked condition " + "after tests. lockval = %d, expected = %d\n", + tdata.lock.lock, L4_MUTEX_UNLOCKED); + return -1; + } + + /* + * Test that increments have occured correctly + */ + if (tdata.val != MUTEX_VALUE_TOTAL) { + dbg_printf("Lock-protected value incremented incorrectly " + "after mutex worker threads.\n" + "val = %d, expected = %d\n", + tdata.val, + MUTEX_VALUE_TOTAL); + return -1; + } + if (tdata.val != MUTEX_VALUE_TOTAL) { + dbg_printf("Lock-protected value incremented incorrectly " + "after mutex worker threads.\n" + "val = %d, expected = %d\n", + tdata.val, + MUTEX_VALUE_TOTAL); + return -1; + } + + dbg_printf("Mutex test successful.\n"); + return 0; +} + +int test_api_mutexctrl(void) +{ + int err; + + if ((err = test_mutex(mutex_thread_contending)) < 0) + goto out_err; + + if ((err = test_mutex(mutex_thread_non_contending)) < 0) + goto out_err; + + printf("USERSPACE MUTEX: -- PASSED --\n"); + return 0; + +out_err: + printf("USERSPACE MUTEX: -- FAILED --\n"); + return err; +} + diff --git a/conts/test_suite0/src/api/smp.c b/conts/test_suite0/src/api/smp.c new file mode 100644 index 0000000..2908fdf --- /dev/null +++ b/conts/test_suite0/src/api/smp.c @@ -0,0 +1,146 @@ +/* + * Some minimal tests for SMP functionality + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include +#include +#include +#include + +static int new_thread_func(void *args) +{ + struct exregs_data exregs; + struct task_ids ids; + int err; + + l4_getid(&ids); + +#if 0 + memset(&exregs, 0, sizeof(exregs)); + exregs_set_read(&exregs); + if ((err = l4_exchange_registers(&exregs, + ids.tid)) < 0) { + printf("SMP test: Exregs call failed on %s\n", + __FUNCTION__); + } + + dbg_printf("New thread running successfully on cpu %d " + "tid=%d. Exiting...\n", self_tid(), + exregs.cpu_affinity); +#endif + + dbg_printf("SMP:New thread running successfully" + "tid=%d. Exiting...\n", self_tid()); + + return 0; +} + +/* + * Create 2 threads on different cpus and run them. + * + * Parent then destroys the child. Parent and child + * are on different cpus. + */ +int test_smp_two_threads(void) +{ + struct exregs_data exregs; + struct l4_thread *thread; + int err, err2; + + dbg_printf("%s: Creating a new thread\n", __FUNCTION__); + /* + * Create new thread but don't start it + */ + if ((err = thread_create(new_thread_func, 0, + TC_SHARE_SPACE | TC_NOSTART, + &thread)) < 0) { + dbg_printf("THREAD_CREATE failed. " + "err=%d\n", err); + return err; + } +#if 0 + dbg_printf("%s: Setting child affinity to %d\n", __FUNCTION__, 1); + /* + * Set its cpu affinity to cpu = 1 + */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_affinity(&exregs, 1); + + /* Write to affinity field */ + if ((err = l4_exchange_registers(&exregs, + thread->ids.tid)) < 0) { + printf("%s: Exregs on setting cpu affinity " + "failed on newly created thread. err=%d\n", + __FUNCTION__, err); + goto out_err; + } + + dbg_printf("%s: Running child on other cpu\n", __FUNCTION__); +#endif + /* Start the thread */ + l4_thread_control(THREAD_RUN, &thread->ids); + + dbg_printf("%s: Waiting on child\n", __FUNCTION__); + /* Wait on the thread */ + if ((err = thread_wait(thread)) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + goto out_err; + } else { + dbg_printf("Thread %d exited successfully. ret=%d\n", + thread->ids.tid, err); + } + + dbg_printf("%s: Child destroyed successfully\n", __FUNCTION__); + return 0; + +out_err: + /* + * Destroy the thread from parent + */ + if ((err2 = thread_destroy(thread)) < 0) { + dbg_printf("THREAD_DESTROY failed. " + "err=%d\n", err2); + return err2; + } + return err; +} + +int test_smp_two_spaces(void) +{ + return 0; +} + +int test_smp_ipc(void) +{ + return 0; +} + +#if defined (CONFIG_SMP) +int test_smp(void) +{ + int err; + + if ((err = test_smp_two_threads()) < 0) + return err; + + if ((err = test_smp_two_spaces()) < 0) + return err; + + if ((err = test_smp_ipc()) < 0) + return err; + + return 0; +} +#else /* Not CONFIG_SMP */ + +int test_smp(void) +{ + return 0; +} +#endif /* Endif */ + diff --git a/conts/test_suite0/src/api/thread.c b/conts/test_suite0/src/api/thread.c new file mode 100644 index 0000000..57d425c --- /dev/null +++ b/conts/test_suite0/src/api/thread.c @@ -0,0 +1,249 @@ +/* + * Test l4_thread_control system call. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ + +#include +#include +#include + +/* + * A secondary thread that tests + * various conditions by taking actions + * told by its parent. + */ +int new_thread_func(void *args) +{ + dbg_printf("New thread running successfully. " + "tid=%d\n", self_tid()); + + return 0; +} + +/* + * Thread that exits by doing some number of + * thread switches to ensure parent has a chance + * to wait on it or attempt to destroy it + * The purpose is to test parent-wait before self-destroy. + */ +int delayed_exit_func(void *args) +{ + int x = 5; + l4id_t parent = *((l4id_t *)args); + + dbg_printf("%s: thread running successfully. " + "tid=%d\n", __FUNCTION__, self_tid()); + + /* + * Switch to parent a few times to ensure it + * runs and begins to wait on us + */ + while (x--) + l4_thread_switch(parent); + + return 5; +} + +/* + * Thread that exits immediately + * Purpose is to test parent-wait after self-destroy. + */ +int imm_exit_func(void *args) +{ + return 5; +} + +/* + * We have 3 thread creation scenarios to test. + */ +struct l4_thread *test_thread_create() +{ + struct l4_thread *tptr; + int err; + + dbg_printf("%s: Creating thread", __FUNCTION__); + + /* + * Create a thread in the same space + */ + if ((err = thread_create(new_thread_func, 0, + TC_SHARE_SPACE, + &tptr)) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return PTR_ERR(err); + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", tptr->ids.tid); + + return tptr; +} + +/* + * Test thread run/resume, suspend + * + * We don't test recycle as that would delete the current + * address space + */ +int test_thread_actions(struct l4_thread *thread) +{ + int err; + + dbg_printf("Suspending thread " + "tid=%d\n", thread->ids.tid); + + /* + * Suspend/resume the thread + */ + if ((err = l4_thread_control(THREAD_SUSPEND, &thread->ids)) < 0) { + dbg_printf("THREAD_SUSPEND failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Suspend OK. Resuming thread " + "tid=%d\n", thread->ids.tid); + + if ((err = l4_thread_control(THREAD_RUN, &thread->ids)) < 0) { + dbg_printf("THREAD_RUN failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Resume OK." + "tid=%d\n", thread->ids.tid); + + return 0; +} + +/* + * Test thread destruction + */ +int test_thread_destroy(struct l4_thread *thread) +{ + int err; + l4id_t id_self = self_tid(); + + dbg_printf("Destroying thread." + "tid=%d\n", thread->ids.tid); + + /* + * Destroy the thread from parent + */ + if ((err = thread_destroy(thread)) < 0) { + dbg_printf("THREAD_DESTROY failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("%s: Destroy OK\n", __FUNCTION__); + + dbg_printf("%s: Creating new thread\n", __FUNCTION__); + + /* + * Create a new thread + * and tell it to destroy itself + * by adding a delay, then wait on it. + * + * Delay ensures we test the case that + * wait occurs before thread is destroyed. + */ + if ((err = thread_create(delayed_exit_func, &id_self, + TC_SHARE_SPACE, + &thread)) < 0) { + dbg_printf("THREAD_CREATE failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", thread->ids.tid); + + dbg_printf("Waiting on thread, " + "tid=%d\n", thread->ids.tid); + + /* Wait on the thread */ + if ((err = thread_wait(thread)) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } else { + dbg_printf("Thread %d exited successfully. ret=%d\n", + thread->ids.tid, err); + } + + /* + * Create a new thread + * and tell it to destroy itself + * immediately, add a delay and + * then wait on it. + * + * Delay ensures we test the case that + * wait occurs after thread is destroyed. + */ + if ((err = thread_create(imm_exit_func, 0, + TC_SHARE_SPACE, + &thread)) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } + + /* Wait on the thread */ + if ((err = thread_wait(thread)) < 0) { + dbg_printf("THREAD_WAIT failed. " + "err=%d\n", err); + return err; + } else { + dbg_printf("Thread %d exited successfully. ret=%d\n", + thread->ids.tid, err); + } + + return 0; +} + +/* + * TODO: In order to test null pointers a separate + * thread who is paged by the main one should attempt + * to pass a null ptr. + */ +int test_thread_invalid(struct l4_thread *thread) +{ + return 0; +} + +int test_api_tctrl(void) +{ + struct l4_thread *thread; + int err; + + /* Test thread create */ + if (IS_ERR(thread = test_thread_create())) { + err = (int)thread; + goto out_err; + } + + /* Test thread actions */ + if ((err = test_thread_actions(thread)) < 0) + goto out_err; + + /* Test thread destruction */ + if ((err = test_thread_destroy(thread)) < 0) + goto out_err; + + /* Test thread invalid input */ + if ((err = test_thread_invalid(thread)) < 0) + goto out_err; + + printf("THREAD CONTROL: -- PASSED --\n"); + return 0; + +out_err: + printf("THREAD CONTROL: -- FAILED --\n"); + return err; +} + diff --git a/conts/test_suite0/src/arch/arm/v5/mm.c b/conts/test_suite0/src/arch/arm/v5/mm.c new file mode 100644 index 0000000..c246aa3 --- /dev/null +++ b/conts/test_suite0/src/arch/arm/v5/mm.c @@ -0,0 +1,65 @@ +/* + * ARMv5 specific functions + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + */ +#include +#include +#include +#include __INC_ARCH(mm.h) + +/* Extracts generic protection flags from architecture-specific pte */ +unsigned int vm_prot_flags(pte_t pte) +{ + unsigned int vm_prot_flags = 0; + unsigned int rw_flags = __MAP_USR_RW & PTE_PROT_MASK; + unsigned int ro_flags = __MAP_USR_RO & PTE_PROT_MASK; + + /* Clear non-protection flags */ + pte &= PTE_PROT_MASK; + + if (pte == ro_flags) + vm_prot_flags = VM_READ | VM_EXEC; + else if (pte == rw_flags) + vm_prot_flags = VM_READ | VM_WRITE | VM_EXEC; + else + vm_prot_flags = VM_NONE; + + return vm_prot_flags; +} + +/* + * PTE STATES: + * PTE type field: 00 (Translation fault) + * PTE type field correct, AP bits: None (Read or Write access fault) + * PTE type field correct, AP bits: RO (Write access fault) + */ + +/* + * Extracts arch-specific fault parameters + * and puts them into generic format + */ +void set_generic_fault_params(struct fault_data *fault) +{ + unsigned int prot_flags = vm_prot_flags(fault->kdata->pte); + + fault->reason = 0; + fault->pte_flags = prot_flags; + + if (is_prefetch_abort(fault->kdata->fsr)) { + fault->reason |= VM_READ; + fault->address = fault->kdata->faulty_pc; + } else { + fault->address = fault->kdata->far; + + /* Always assume read fault first */ + if (prot_flags & VM_NONE) + fault->reason |= VM_READ; + else if (prot_flags & VM_READ) + fault->reason |= VM_WRITE; + else + BUG(); + } + arch_print_fault_params(fault); +} + diff --git a/conts/test_suite0/src/arch/arm/v7/mm.c b/conts/test_suite0/src/arch/arm/v7/mm.c new file mode 100644 index 0000000..c5bdf3e --- /dev/null +++ b/conts/test_suite0/src/arch/arm/v7/mm.c @@ -0,0 +1,75 @@ +/* + * ARMv7 specific functions + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + */ +#include +#include +#include +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(exception.h) + +/* Get simplified access permissions */ +int pte_get_access_simple(pte_t pte) +{ + /* Place AP[2] and AP[1] in [1:0] positions and return */ + return (((pte >> PTE_AP2_BIT) & 1) << 1) + | ((pte >> PTE_AP1_BIT) & 1); +} + +int is_translation_fault(u32 fsr) +{ + return (fsr & FSR_FS_MASK) == ABORT_TRANSLATION_PAGE; +} + +unsigned int vm_prot_flags(pte_t pte, u32 fsr) +{ + unsigned int pte_prot_flags = 0; + + /* Translation fault means no permissions */ + if (is_translation_fault(fsr)) + return VM_NONE; + + /* Check simplified permission bits */ + switch (pte_get_access_simple(pte)) { + case AP_SIMPLE_USER_RW_KERN_RW: + pte_prot_flags |= VM_WRITE; + case AP_SIMPLE_USER_RO_KERN_RO: + pte_prot_flags |= VM_READ; + + /* Also, check exec never bit */ + if (!(pte & (1 << PTE_XN_BIT))) + pte_prot_flags |= VM_EXEC; + break; + case AP_SIMPLE_USER_NONE_KERN_RW: + case AP_SIMPLE_USER_NONE_KERN_RO: + default: + pte_prot_flags = VM_NONE; + break; + } + + return pte_prot_flags; +} + +void set_generic_fault_params(struct fault_data *fault) +{ + fault->pte_flags = vm_prot_flags(fault->kdata->pte, fault->kdata->fsr); + fault->reason = 0; + + /* + * Prefetch fault denotes exec fault. + */ + if (is_prefetch_abort(fault->kdata->fsr)) { + fault->reason |= VM_EXEC; + fault->address = fault->kdata->faulty_pc; + } else { + fault->address = fault->kdata->far; + + /* Write-not-read bit determines fault */ + if (fault->kdata->fsr & (1 << DFSR_WNR_BIT)) + fault->reason |= VM_WRITE; + else + fault->reason |= VM_READ; + } +} + diff --git a/conts/test_suite0/src/capability.c b/conts/test_suite0/src/capability.c new file mode 100644 index 0000000..95b96ff --- /dev/null +++ b/conts/test_suite0/src/capability.c @@ -0,0 +1,106 @@ +/* + * Capability-related userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include +#include L4LIB_INC_ARCH(syscalls.h) + +#if 0 +static struct capability cap_array[30]; + +struct cap_group { + struct cap_list virtmem; + struct cap_list physmem; + struct cap_list threadpool; + struct cap_list tctrl; + struct cap_list exregs; + struct cap_list ipc; + struct cap_list mutex; + struct cap_list sched; + struct cap_list mutexpool; + struct cap_list spacepool; + struct cap_list cappool; +}; + +static inline struct capability *cap_get_thread() +{ + +} + +static inline struct capability *cap_get_space() +{ + +} + +static inline struct capability *cap_get_ipc() +{ + +} + +static inline struct capability *cap_get_virtmem() +{ + +} + +static inline struct capability *cap_get_physmem() +{ + +} + +static inline struct capability *cap_get_physmem(unsigned long phys) +{ + +} + +static inline struct capability *cap_get_virtmem(unsigned long virt) +{ + +} + +static inline struct capability *cap_get_byid(l4id_t id) +{ + +} + + +void cap_share_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags) +{ + +} + +void cap_grant_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags) +{ +} + + +int caps_read_all(void) +{ + int ncaps; + int err; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, &ncaps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + BUG(); + } + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, cap_array)) < 0) { + printf("l4_capability resource_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ_CAPS request.\n"); + BUG(); + } + //cap_array_print(ncaps, caparray); + + return 0; +} + +#endif diff --git a/conts/test_suite0/src/captest.c b/conts/test_suite0/src/captest.c new file mode 100644 index 0000000..94b9365 --- /dev/null +++ b/conts/test_suite0/src/captest.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include + +int simple_pager_thread(void *arg) +{ + int err; + int res = *(int *)arg; + struct task_ids ids; + int testres = 0; + + l4_getid(&ids); + + printf("Thread spawned from pager, \ + trying to create new thread.\n"); + err = l4_thread_control(THREAD_CREATE | + TC_SHARE_SPACE, &ids); + + if (res == 0) + if (err == -ENOCAP || + err == -ENOMEM) { + printf("Creation failed with %d " + "as expected.\n", err); + testres = 0; + } else { + printf("Creation was supposed to fail " + "with %d or %d, but err = %d\n", + -ENOMEM, -ENOCAP, err); + testres = 1; + } + else + if (err == 0) { + // printf("Creation succeeded as expected.\n"); + testres = 0; + } else { + printf("Creation was supposed to succeed, " + "but err = %d\n", err); + testres = 1; + } + + /* Destroy thread we created */ + if (err == 0 && + res == 0) + l4_thread_control(THREAD_DESTROY, &ids); + + /* Destroy self */ + l4_exit(testres); + + return 0; +} + +int wait_check_test(struct task_ids *ids) +{ + int result; + + /* Wait for thread to finish */ + result = l4_thread_control(THREAD_WAIT, ids); + if (result < 0) { + printf("Waiting on (%d)'s exit failed.\n", ids->tid); + return -1; + } else if (result > 0) { + printf("Top-level test has failed\n"); + } + /* Else it is a success */ + + return 0; +} + +int capability_test(void) +{ + int err; + struct task_ids ids; + int TEST_MUST_FAIL = 0; + //int TEST_MUST_SUCCEED = 1; + + /* Read pager capabilities */ + caps_read_all(); + + /* + * Create new thread that will attempt + * a pager privileged operation + */ + if ((err = thread_create(simple_pager_thread, + &TEST_MUST_FAIL, + TC_SHARE_SPACE, &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } + + printf("waititng for result\n"); + /* Wait for test to finish and check result */ + if (wait_check_test(&ids) < 0) + goto out_err; +#if 0 + + /* Destroy test thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + printf("Destruction of top-level simple_pager failed.\n"); + BUG(); + } + + /* + * Share operations with the same thread + * group + */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE, + CAP_SHARE_CONTAINER, 0)) < 0) { + printf("Sharing capability with thread group failed.\n"); + goto out_err; + } + + /* + * Create new thread that will attempt a pager privileged + * operation. This should succeed as we shared caps with + * the thread group. + */ + if ((err = thread_create(simple_pager_thread, + &TEST_MUST_SUCCEED, + TC_SHARE_SPACE | + TC_SHARE_GROUP, &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } + + /* Wait for test to finish and check result */ + if (wait_check_test(&ids) < 0) + goto out_err; + + /* Destroy test thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + printf("Destruction of top-level simple_pager failed.\n"); + BUG(); + } +#endif + + printf("Capability Sharing Test -- PASSED --\n"); + + return 0; + +out_err: + printf("Capability Sharing Test -- FAILED --\n"); + return 0; +} diff --git a/conts/test_suite0/src/cli_serv/cli_serv.c b/conts/test_suite0/src/cli_serv/cli_serv.c new file mode 100644 index 0000000..822fc76 --- /dev/null +++ b/conts/test_suite0/src/cli_serv/cli_serv.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * Tests client/server style container setup + * + * Author: Bahadir Balban + */ +#include + +/* + * A container can be set up in many different combinations + * of hierarchy where the hierarchical differences between + * the threads are determined by a finely grained capability + * configuration. + * + * However, this boils down to two main sets of hierarchical + * setup: client/server or multithreaded/standalone entities. + * + * This test tests the client/server style hierarchical set up. + */ +int test_cli_serv(void) +{ + /* + * Create a child thread in a new address space. + * copying current pager's page tables to child + */ + + /* Copy current pager's all sections to child pages */ + + /* + * Set up child's registers to execute the special + * child entry function + */ + + /* + * Start the child + */ + + /* + * Interact with the child: + * + * Handle short, full, extended ipc + * + * Handle page fault + */ + + /* + * Destroy child + */ + + return 0; +} + diff --git a/conts/test_suite0/src/example.c b/conts/test_suite0/src/example.c new file mode 100644 index 0000000..6321f2d --- /dev/null +++ b/conts/test_suite0/src/example.c @@ -0,0 +1,220 @@ + +#if 0 + +int mutex_user_thread(void *arg) +{ + /* TODO: Create and access a mutex */ +} + +int independent_thread(void *arg) +{ + /* TODO: Do whatever syscall available */ +} + + +/* + * This example demonstrates how the capability-based + * security model can be bypassed and taken out of the + * way for the sake of implementing an application that + * doesn't worry too much about security. + * + * The benefit is that the user does neither worry about + * capabilities nor using its api to design correctly + * secure systems. The downside is that the system is + * less security-enforced, i.e. all parties must be + * trusted. + */ +int multi_threaded_nocaps_example(void) +{ + /* + * We are the first pager with capabilities to + * create new tasks, spaces, in its own container. + */ + pager_read_caps(); + + /* + * We have all our capabilities private to us. + * + * If we create a new task, it won't be able to + * any kernel operations that we can do, because + * we hold our capabilities privately. + * + * In order to settle all capability access issues + * once and for all threads we will create and manage, + * we share our capabilities with the most global + * collection possible. + */ + + /* + * Share all of our capabilities with all threads + * in the same container. + * + * From this point onwards, any thread we create and + * manage (i.e. whose container id is equal to our + * container id) will have the ability to leverage + * all of our capabilities as defined for us at + * configuration time. + */ + l4_cap_share(0, CAP_SHARE_CONTAINER | CAP_SHARE_ALL, self_tid()); + + + /* + * Lets try it. + * + * Create new thread that we don't have any hieararchical + * relationship, i.e. one that is a pager of itself, one + * that runs in a new address space, and in a new thread + * group. All we share is the container. + */ + if ((err = thread_create(independent_thread, 0, + TC_NO_SHARING, &ids)) < 0) { + printf("mutex_user_thread creation failed.\n"); + goto out_err; + } + + /* + * We can inspect the new thread by doing an ipc to it. + * NOTE: + * + * We are able to send to this thread from the start, + * as we had a container-wide ipc capability defined at + * config-time. + * + * But we would not be able to receive from it, if we + * did not share this capability with the container. It + * would have no rights to do a send to us. But because + * we're in the same container, and we shared our + * capability, it now can. + */ + if ((err = l4_recv(ids->tid, ids->tid, 0)) < 0) { + print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd); + goto out_err; + } + + /* + * From this point onwards we can create more threads + * without worrying about whether they have the caps + * to do certain ops, and the caps api. because we shared + * them all at the beginning. + */ + +out_err: + BUG(); +} + +/* + * This example demonstrates how a pager would + * share part of its capabilities on the system + * with its children. + * + * The example includes sharing of a mutex + * capability with a paged-child. + */ +int multi_threaded_capability_sharing_example(void) +{ + struct capability *mutex_cap; + int thread_retval; + + /* + * We are the first pager with capabilities to + * create new tasks, spaces, in its own container. + */ + pager_read_caps(); + + /* + * We have all our capabilities private to us. + * + * If we create a new task, it won't be able to + * create and use userspace mutexes, because we + * hold mutex capabilities privately. + * + * Lets try it. + */ + + /* + * Create new thread that will attempt + * a mutex operation, and die on us with a + * negative return code if it fails. + */ + if ((err = thread_create(mutex_user_thread, 0, + TC_SHARE_SPACE | + TC_AS_PAGER, &ids)) < 0) { + printf("mutex_user_thread creation failed.\n"); + goto out_err; + } + + /* Check on how the thread has done */ + if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) { + print("Waiting on thread %d failed. err = %d\n", + ids->tid, err); + goto out_err; + } + + if (thread_retval == 0) { + printf("Thread %d returned with success, where " + "we expected failure.\n", ids->tid); + goto out_err; + } + + /* + * Therefore, we share our capabilities with a + * collection so that our capabilities may be also + * used by them. + */ + + /* Get our private mutex cap */ + mutex_cap = cap_get(CAP_TYPE_MUTEX); + + /* We have ability to create and use this many mutexes */ + printf("%s: We have ability to create/use %d mutexes\n", + self_tid(), mutex_cap->size); + + /* Split it */ + cap_new = cap_split(mutex_cap, 10, CAP_SPLIT_SIZE); + + /* + * Share the split part with paged-children. + * + * From this point onwards, any thread we create and + * manage (i.e. whose pagerid == self_tid()) will have + * the ability to use mutexes, as defined by cap_new + * we created. + */ + l4_cap_share(cap_new, CAP_SHARE_PGGROUP, self_tid()); + + /* + * Create new thread that will attempt + * a mutex operation, and die on us with a + * negative return code if it fails. + */ + if ((err = thread_create(mutex_user_thread, 0, + TC_SHARE_SPACE | + TC_AS_PAGER, &ids)) < 0) { + printf("mutex_user_thread creation failed.\n"); + goto out_err; + } + + /* Check on how the thread has done */ + if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) { + printf("Waiting on thread %d failed. err = %d\n", + ids->tid, err); + goto out_err; + } + + if (thread_retval < 0) { + printf("Thread %d returned with failure, where " + "we expected success.\n", ids->tid); + goto out_err; + } + +out_err: + BUG(); +} + + + + + + +#endif + diff --git a/conts/test_suite0/src/mthread/mthread.c b/conts/test_suite0/src/mthread/mthread.c new file mode 100644 index 0000000..6d6c601 --- /dev/null +++ b/conts/test_suite0/src/mthread/mthread.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * Tests client/server style container setup + * + * Author: Bahadir Balban + */ +#include + +/* + * A container can be set up in many different combinations + * of hierarchy where the hierarchical differences between + * the threads are determined by a finely grained capability + * configuration. + * + * However, this boils down to two main sets of hierarchical + * setup: client/server or multithreaded/standalone entities. + * + * This test tests the multithreaded/standalone style container + * set up. + */ +int test_mthread(void) +{ + /* Create multiple threads in same space */ + + /* + * Set up childs' registers to execute the special + * child entry function + */ + + /* + * Start the child + */ + + /* + * Run child threads and interact + * + * Handle short, full, extended ipc + */ + + /* + * Destroy child + */ + + return 0; +} + diff --git a/conts/test_suite0/src/perf/cycles.c b/conts/test_suite0/src/perf/cycles.c new file mode 100644 index 0000000..c189472 --- /dev/null +++ b/conts/test_suite0/src/perf/cycles.c @@ -0,0 +1,58 @@ +/* + * Test cpu cycles using platform timer + * ticks. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include +#include + + +void platform_measure_cpu_cycles() +{ + /* Initialize the timer */ + const int load_value = 1000; + int mhz_top, mhz_bot, temp; + int cyccnt; + + /* Make sure timer is disabled */ + timer_stop(timer_base); + + /* Load the timer with ticks value */ + timer_load(load_value, timer_base); + + /* One shot, 32 bits, no irqs */ + timer_init_oneshot(timer_base); + + /* Start the timer */ + timer_start(timer_base); + + /* Start counter */ + perfmon_reset_start_cyccnt(); + + /* Wait until 0 */ + while (timer_read(timer_base) != 0) + ; + + cyccnt = perfmon_read_cyccnt(); + + /* Fixed-point accuracy on bottom digit */ + temp = cyccnt * 64 * 10 / load_value; + mhz_top = temp / 10; + mhz_bot = temp - mhz_top * 10; + + //printk("Perfmon: %u cycles/%dMhz\n", + // cyccnt * 64, timer_load); + printk("%s: %d.%d MHz CPU speed measured by timer REFCLK at 1MHz\n", + __KERNELNAME__, mhz_top, mhz_bot); +} + diff --git a/conts/test_suite0/src/perf/exregs.c b/conts/test_suite0/src/perf/exregs.c new file mode 100644 index 0000000..3a7f981 --- /dev/null +++ b/conts/test_suite0/src/perf/exregs.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_exchange_registers performance tests + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include +#include +#include + +struct perfmon_cycles l4_exregs_cycles; + +#define PERFTEST_EXREGS_COUNT 100 + +int perf_measure_exregs(void) +{ + struct task_ids ids; + struct exregs_data exregs[2]; + int err; + + /* Get own space id */ + l4_getid(&ids); + + /* + * Initialize cycle structures + */ + memset(&l4_exregs_cycles, 0, sizeof (struct perfmon_cycles)); + l4_exregs_cycles.min = ~0; /* Init as maximum possible */ + + /* + * Create a thread in the same space. + * Thread is not runnable. + */ + if ((err = l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE, + &ids)) < 0) { + dbg_printf("Thread create failed. " + "err=%d\n", err); + return err; + } + + dbg_printf("Thread created successfully. " + "tid=%d\n", ids.tid); + + /* + * Prepare a context part full of 0xFF + */ + memset(&exregs[0].context, 0xFF, sizeof(exregs[1].context)); + exregs[0].valid_vect = 0xFFFFFFFF; + + dbg_printf("Starting l4_exregs write measurement\n"); + for (int i = 0; i < PERFTEST_EXREGS_COUNT; i++) { + perfmon_reset_start_cyccnt(); + /* Write to context */ + if ((err = l4_exchange_registers(&exregs[0], ids.tid)) < 0) + goto out; + perfmon_record_cycles(&l4_exregs_cycles, + "l4_exchange_registers"); + } + + /* Calculate average */ + l4_exregs_cycles.avg = l4_exregs_cycles.total / l4_exregs_cycles.ops; + + /* + * Print results + */ + printf("PERFMON: %s took %llu min, %llu max, %llu avg, " + "%llu total microseconds in %llu ops.\n", + "l4_exchange_registers()/WRITE", + l4_exregs_cycles.min * USEC_MULTIPLIER, + l4_exregs_cycles.max * USEC_MULTIPLIER, + l4_exregs_cycles.avg * USEC_MULTIPLIER, + l4_exregs_cycles.total * USEC_MULTIPLIER, + l4_exregs_cycles.ops); + + /* + * Prepare a context part full of 0xFF + */ + memset(&exregs[0].context, 0xFF, sizeof(exregs[1].context)); + exregs[0].valid_vect = 0xFFFFFFFF; + + dbg_printf("Starting l4_exregs read measurement\n"); + for (int i = 0; i < PERFTEST_EXREGS_COUNT; i++) { + /* Set the other as read-all */ + exregs_set_read(&exregs[1]); + exregs[1].valid_vect = 0xFFFFFFFF; + + if ((err = l4_exchange_registers(&exregs[1], + ids.tid)) < 0) + goto out; + } + + /* + * Read back all context and compare results + */ + if (memcmp(&exregs[0].context, &exregs[1].context, + sizeof(exregs[0].context))) { + err = -1; + goto out; + } + + /* Calculate average */ + l4_exregs_cycles.avg = l4_exregs_cycles.total / l4_exregs_cycles.ops; + + /* + * Print results + */ + printf("PERFMON: %s took %llu min, %llu max, %llu avg, " + "%llu total microseconds in %llu ops.\n", + "l4_exchange_registers()/READ", + l4_exregs_cycles.min * USEC_MULTIPLIER, + l4_exregs_cycles.max * USEC_MULTIPLIER, + l4_exregs_cycles.avg * USEC_MULTIPLIER, + l4_exregs_cycles.total * USEC_MULTIPLIER, + l4_exregs_cycles.ops); + +out: + /* + * Destroy the thread + */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + dbg_printf("Thread destroy failed. err=%d\n", + err); + } + return 0; + +} diff --git a/conts/test_suite0/src/perf/getid.c b/conts/test_suite0/src/perf/getid.c new file mode 100644 index 0000000..5aacd09 --- /dev/null +++ b/conts/test_suite0/src/perf/getid.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_getid performance tests + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include +#include + +struct perfmon_cycles l4_getid_cycles; + +#define PERFTEST_GETID_COUNT 100 + +/* + * Measure l4_getid by timer ticks + */ +void perf_measure_getid_ticks(void) +{ + const int timer_ldval = 0xFFFFFFFF; + unsigned int timer_val, timer_stamp = 0xFFFFFFFF; + unsigned int min = ~0, max = 0, last = 0, total = 0, ops = 0; + struct task_ids ids; + + /* Make sure timer is disabled */ + timer_stop(timer_base); + + /* Configure timer as one shot */ + timer_init_oneshot(timer_base); + + /* Load the timer with ticks value */ + timer_load(timer_ldval, timer_base); + + /* Start the timer */ + printf("Starting the l4_getid timer tick test.\n"); + timer_start(timer_base); + + /* Do the operation */ + for (int i = 0; i < PERFTEST_GETID_COUNT; i++) { + l4_getid(&ids); + timer_val = timer_read(timer_base); + last = timer_stamp - timer_val; + timer_stamp = timer_val; + if (min > last) + min = last; + if (max < last) + max = last; + ops++; + total += last; + } + + printf("TIMER: l4_getid took each %u min, %u max, %u avg,\n" + "%u total microseconds, and %u total ops\n", min, + max, total/ops, total, ops); +} + +/* + * Measure l4_getid by cpu cycles + */ +void perf_measure_getid(void) +{ + struct task_ids ids; + + /* + * Initialize structures + */ + memset(&l4_getid_cycles, 0, sizeof (l4_getid_cycles)); + l4_getid_cycles.min = ~0; /* Init as maximum possible */ + + /* + * Do the test + */ + printf("Starting the l4_getid cycle counter test.\n"); + for (int i = 0; i < PERFTEST_GETID_COUNT; i++) { + perfmon_reset_start_cyccnt(); + l4_getid(&ids); + perfmon_record_cycles(&l4_getid_cycles, + "l4_getid"); + } + + /* + * Calculate average + */ + l4_getid_cycles.avg = l4_getid_cycles.total / l4_getid_cycles.ops; + + /* + * Print results + */ + printf("PERFMON: %s took %llu min, %llu max, %llu avg, " + "%llu total microseconds in %llu ops.\n", + "l4_getid()", + l4_getid_cycles.min * USEC_MULTIPLIER, + l4_getid_cycles.max * USEC_MULTIPLIER, + l4_getid_cycles.avg * USEC_MULTIPLIER, + l4_getid_cycles.total * USEC_MULTIPLIER, + l4_getid_cycles.ops); +} diff --git a/conts/test_suite0/src/perf/ipc.c b/conts/test_suite0/src/perf/ipc.c new file mode 100644 index 0000000..b4b56b3 --- /dev/null +++ b/conts/test_suite0/src/perf/ipc.c @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_ipc performance tests + * + * Author: Bahadir Balban + */ + +void perf_measure_ipc(void) +{ + +} diff --git a/conts/test_suite0/src/perf/map.c b/conts/test_suite0/src/perf/map.c new file mode 100644 index 0000000..9cee3ee --- /dev/null +++ b/conts/test_suite0/src/perf/map.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_map/l4_unmap performance tests + * + * Author: Bahadir Balban + */ + +void perf_measure_map(void) +{ + +} + +void perf_measure_unmap(void) +{ + +} diff --git a/conts/test_suite0/src/perf/mutex.c b/conts/test_suite0/src/perf/mutex.c new file mode 100644 index 0000000..f7a8140 --- /dev/null +++ b/conts/test_suite0/src/perf/mutex.c @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_mutex performance tests + * + * Author: Bahadir Balban + */ + +void perf_measure_mutex(void) +{ +} diff --git a/conts/test_suite0/src/perf/perf.c b/conts/test_suite0/src/perf/perf.c new file mode 100644 index 0000000..aedd6c5 --- /dev/null +++ b/conts/test_suite0/src/perf/perf.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * API performance tests + * + * Author: Bahadir Balban + */ +#include +#include +#include + +/* + * Tests all api functions by performance + */ +int test_performance(void) +{ + perf_timer_init(); + + platform_measure_cpu_cycles(); + + perf_measure_getid_ticks(); + perf_measure_getid(); + perf_measure_tctrl(); + perf_measure_exregs(); + perf_measure_ipc(); + perf_measure_map(); + perf_measure_unmap(); + perf_measure_mutex(); + + return 0; +} + diff --git a/conts/test_suite0/src/perf/simple.c b/conts/test_suite0/src/perf/simple.c new file mode 100644 index 0000000..ecfef90 --- /dev/null +++ b/conts/test_suite0/src/perf/simple.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_getid performance tests + * + * Author: Bahadir Balban + */ +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include + +struct perfmon_cycles simple_cycles; + +#define PERFTEST_SIMPLE_LOOP 2000 + +void perf_test_simple(void) +{ + dbg_printf("%s: This will test the cycle count of basic loops.\n", + __FUNCTION__); + + /* + * Initialize structures + */ + memset(&simple_cycles, 0, sizeof(struct perfmon_cycles)); + simple_cycles.min = ~0; /* Init as maximum possible */ + + /* + * Do the test + */ + perfmon_reset_start_cyccnt(); + for (int i = 0; i < PERFTEST_SIMPLE_LOOP; i++) + ; + + perfmon_record_cycles(&simple_cycles,"empty_loop"); + + /* + * Calculate average + */ + simple_cycles.avg = simple_cycles.total / simple_cycles.ops; + + /* + * Print results + */ + printf("%s took %llu min, %llu max, %llu avg, in %llu ops.\n", + "simple loop", + simple_cycles.min * USEC_MULTIPLIER, + simple_cycles.max * USEC_MULTIPLIER, + simple_cycles.avg * USEC_MULTIPLIER, + simple_cycles.ops); +} + diff --git a/conts/test_suite0/src/perf/tctrl.c b/conts/test_suite0/src/perf/tctrl.c new file mode 100644 index 0000000..9ab1e31 --- /dev/null +++ b/conts/test_suite0/src/perf/tctrl.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * l4_thread_control performance tests + * + * Author: Bahadir Balban + */ + +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) +#include +#include +#include +#include +#include + +struct perfmon_cycles tctrl_cycles; + +#define PERFTEST_THREAD_CREATE 50 + +void perf_measure_tctrl(void) +{ + struct task_ids ids[PERFTEST_THREAD_CREATE]; + struct task_ids selfids; + l4_getid(&selfids); + + /* + * Initialize structures + */ + memset(&tctrl_cycles, 0, sizeof (struct perfmon_cycles)); + tctrl_cycles.min = ~0; /* Init as maximum possible */ + + /* + * Thread create test + */ + for (int i = 0; i < PERFTEST_THREAD_CREATE; i++) { + perfmon_reset_start_cyccnt(); + l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE, &selfids); + perfmon_record_cycles(&tctrl_cycles, "THREAD_CREATE"); + + /* Copy ids of created task */ + memcpy(&ids[i], &selfids, sizeof(struct task_ids)); + } + + /* + * Calculate average + */ + tctrl_cycles.avg = tctrl_cycles.total / tctrl_cycles.ops; + + /* + * Print results + */ + printf("%s took %llu min, %llu max, %llu avg, in %llu ops.\n", + "THREAD_CREATE", + tctrl_cycles.min * USEC_MULTIPLIER, + tctrl_cycles.max * USEC_MULTIPLIER, + tctrl_cycles.avg * USEC_MULTIPLIER, + tctrl_cycles.ops); + + /* + * Thread destroy test + */ + for (int i = 0; i < PERFTEST_THREAD_CREATE; i++) { + perfmon_reset_start_cyccnt(); + l4_thread_control(THREAD_DESTROY, &ids[i]); + perfmon_record_cycles(&tctrl_cycles,"THREAD_DESTROY"); + } + + /* + * Calculate average + */ + tctrl_cycles.avg = tctrl_cycles.total / tctrl_cycles.ops; + + /* + * Print results + */ + printf("%s took %llu min, %llu max, %llu avg, in %llu ops.\n", + "THREAD_DESTROY", + tctrl_cycles.min * USEC_MULTIPLIER, + tctrl_cycles.max * USEC_MULTIPLIER, + tctrl_cycles.avg * USEC_MULTIPLIER, + tctrl_cycles.ops); +} + diff --git a/conts/test_suite0/src/perf/timer.c b/conts/test_suite0/src/perf/timer.c new file mode 100644 index 0000000..1c6eb14 --- /dev/null +++ b/conts/test_suite0/src/perf/timer.c @@ -0,0 +1,40 @@ +/* + * Initialize platform timer virtual address + * + * Copyright (C) 2010 B Labs Ltd. + * + * Bahadir Balban + */ +#include +#include +#include +#include L4LIB_INC_ARCH(syslib.h) +#include L4LIB_INC_ARCH(syscalls.h) + +/* Note this must be obtained from the capability */ +#define TIMER_PHYSICAL_BASE 0x10012000 + +unsigned long timer_base; + +void perf_timer_init(void) +{ + int err; + struct task_ids ids; + + l4_getid(&ids); + + /* Initialize timer base */ + timer_base = page_align_up(__stack); + + /* Map timer base */ + if ((err = l4_map((void *)TIMER_PHYSICAL_BASE, + (void *)timer_base, + 1, MAP_USR_IO, ids.tid)) < 0) { + printf("FATAL: Performance tests: Could not map " + "timer.\ntimer must be selected as a " + "container capability. err=%d\n", + err); + BUG(); + } +} + diff --git a/conts/test_suite0/src/perf/tswitch.c b/conts/test_suite0/src/perf/tswitch.c new file mode 100644 index 0000000..e69de29 diff --git a/conts/test_suite0/tests_howto.txt b/conts/test_suite0/tests_howto.txt new file mode 100644 index 0000000..de75a4c --- /dev/null +++ b/conts/test_suite0/tests_howto.txt @@ -0,0 +1,114 @@ + + + TESTING HOWTO + + By Bahadir Balban + +HOW TO ADD TESTS + +Tests in this project are meant to test basic functionality of the microkernel +but cover test cases comprehensively. The special trait with these tests is +that each is meant to test only one aspect of the microkernel, rather than +trying to test multiple aspects at once. + +A benefit of having this approach is that when a test fails, it is easier to +spot the problem as opposed to a failure that is caused by a complex +interaction of multiple aspects of the microkernel. + +The software must be also tested for more complex interactions, but these +tests are not the place to create them. When a new test is added, it must cover +a valid test case but the test itself must be as shallow as possible. + + +EXAMPLE + +A thread creation test, while using other aspects of the microkernel such as +the l4_exchange_registers system call, should only test thread creation aspect +of the microkernel. A separate l4_exchange_registers test would need to be +created who then uses the thread creation aspect of the microkernel, but only +testing the parameters to l4_exchange_registers system call, covering it +exhaustively. In essence, each test must be shallow in itself, and have a single +focus. + + +Here's a step-by-step approach to testing: + +1.) Create one test that tests one thing well. + This is about the above paragraphs. Test one aspect, so we know that that + aspect is functional. When there are lots of changes to code and many + invariables, this will make sure that these tests are one solid invariable + in the equation. They should be as deterministic and simple as possible + so that other variants can be debugged using the tests as anchor points. + + Each test must be significantly simple. E.g. If I have 2 test cases that + require slightly differing input to a test function, I would not use a + loop of i = 0..2 where parameters change when i == 0 and i == 1. That + would be difficult to understand, and complicated. Instead, each of those + inputs should be 2 test cases. This way, I focus %100 on the debugged code, + I don't put a tiny fraction of my focus trying to understand the test. + +2.) Number (1) is unexpectedly hard to achieve. Especially a person who is + accustomed to design complex systems that work will have a hard time in + applying an approach that is completely the opposite. Make sure to stop + thinking smart and get used to thinking not moderately dumb but very dumb. + +3.) Make sure to escalate errors properly. + When porting to a new architecture or where there are lots of variables, + your tests will fail. It is an extra burden to find out how. Error + escalation provides a quick and easy means to provide error details. + +4.) Make sure to print only when necessary. + Tests should print out values only when a tested aspect goes wrong. + a) It should describe what the test was trying to do, i.e. describe what + was expected to happen. This way it is quicker to see expected results. + b) It should describe what has happend, contrary to expected. This should + tell what went wrong. + c) It should tell no more. Printout clutter is a huge negative factor in + making tests effective. + +4.) Complicating the tests: + It is often necessary that simple tests must be the building blocks for + more complicated tests so that complicated interactions in the system + can be tested. + + Complicating the test cases should be done with a systematic approach: + + a) Tests are like building blocks. Each test that tests one aspect of the + software should be designed as a rock solid way of testing that one + aspect. See (1) above for the first step. Design extremely simple tests. + + b) A design should be carefully made such that multiple aspects as + described in (a) provide a highly deterministic and reproducable + sequence of events when combined together. While this significantly + narrows down the tested domain of functionality, it equally much ensures + that the test case is covered in full control, thus should anything + go wrong and test fails, it is much easier to find out what went wrong. + + E.g. a test that randomly creates threads would be almost useless since + any failure of the test would be irreproducable and very hard to use + to recover any bug. + + c) Test cases should slowly and surely grow into a larger domain of + functionality by rigorously and systematically following steps (a) and + (b). If these steps are not rigorously followed, the tests would be + diluted in quality, and the testing structure would quickly become a + mess. + + Some examples: + ~~~~~~~~~~~~~~ + 1) Test 1: Extended ipc on already mapped pages. + 2) Test 2: Extended ipc on page faulting pages. + 3) Test 3: Extended ipc on page faulting pages, but non contiguous + physical pages. + 4) Test 4: Extended ipc on page faulting pages, but non contiguous + physical pages, and between threads in different address spaces. + 5) Test 5: Extended ipc on page faulting pages, but non contiguous + physical pages, and between threads in different address spaces, + but using the same virtual addresses on both threads. + + You see, a single ipc test is systematically growing into a more complex + test, but at each step, only one possibly variable aspect is added and + tested. The other test aspects have already been validated by earlier, + simpler combinations of test cases. + + diff --git a/docs/architecture.txt b/docs/architecture.txt new file mode 100644 index 0000000..50c4af3 --- /dev/null +++ b/docs/architecture.txt @@ -0,0 +1,14 @@ + ++-+ + + + + + + + + + + + + + + + + +|T| | | | | | | | | | | | | | | | | +|H| | | | | | | | | | | | | | | | | +|R| | | | | | | | | | | | | | | | | +|E| | | | | | | | | | | | | | | | | +|A| | | | | | | | | | | | | | | | | +|D| | | | | | | | | | | | | | | | | ++-------+-------+ +-------+-------+ +| Space | Space | | Space | Space | ++---------------+ +---------------+ +| Container | | Container | ++---------------+ +---------------+ + diff --git a/docs/man/man7/capability.7 b/docs/man/man7/capability.7 index 82e4510..023c928 100755 --- a/docs/man/man7/capability.7 +++ b/docs/man/man7/capability.7 @@ -15,29 +15,26 @@ Each thread, address space and container is associated with its own capability l The capability structure is defined as follows: .nf -.TP -.BI "struct" " capability " "{" -.in 16 -.BI "struct link " "list" ";" +.B struct capability { +.BI " struct link " "list" ";" .BI "" -/* Capability identifiers */ -.BI "l4id_t " "capid" "; /* Unique capability ID */" -.BI "l4id_t " "owner" "; /* Capability owner ID */" -.BI "l4id_t " "resid" "; /* Targeted resource ID */" -.BI "unsigned int " "type" "; /* Capability and target resource type */" + /* Capability identifiers */ +.BI " l4id_t " "capid" "; /* Unique capability ID */" +.BI " l4id_t " "owner" "; /* Capability owner ID */" +.BI " l4id_t " "resid" "; /* Targeted resource ID */" +.BI " unsigned int " "type" "; /* Capability and target resource type */" .BI "" -/* Capability permissions */ -.BI "u32 " "access" "; /* Permitted operations */" + /* Capability permissions */ +.BI " u32 " "access" "; /* Permitted operations */" .BI "" -/* Other Limits/Attributes of the resource */ -.BI "unsigned long " "start" "; /* Resource start value */" -.BI "unsigned long " "end" "; /* Resource end value */" -.BI "unsigned long " "size" "; /* Resource size */" + /* Other Limits/Attributes of the resource */ +.BI " unsigned long " "start" "; /* Resource start value */" +.BI " unsigned long " "end" "; /* Resource end value */" +.BI " unsigned long " "size" "; /* Resource size */" .BI "" -.BI "unsigned long " "used" "; /* Resource used size */" -.BI "unsigned int " "attr" "; /* User-defined attribute. (Device index and type on devices) */" -.BI "l4id_t " "irq" "; /* Device irq (Devices Only) */" -.in 6 +.BI " unsigned long " "used" "; /* Resource used size */" +.BI " unsigned int " "attr" "; /* User-defined attribute. (Device index and type on devices) */" +.BI " l4id_t " "irq" "; /* Device irq (Devices Only) */" .B }; .TP diff --git a/docs/man/man7/kip.7 b/docs/man/man7/kip.7 old mode 100644 new mode 100755 index 27eeee5..f4a9cb3 --- a/docs/man/man7/kip.7 +++ b/docs/man/man7/kip.7 @@ -13,41 +13,38 @@ The kernel interface page acts as a read-only identification structure for syste KIP also provides the address of the thread-local UTCB address, and the value of this field dynamically changes as each thread becomes runnable. The KIP structure is defined as follows: .nf -.TP -.BI "struct" " kip " "{" -.in 16 -/* System descriptions */ -.BI "u32 " "magic" ";" -.BI "u16 " "version_rsrv" ";" -.BI "u8 " "api_subversion" ";" -.BI "u8 " "api_version" ";" -.BI "u32 " "api_flags" ";" +.B struct kip { + /* System descriptions */ +.BI " u32 " "magic" ";" +.BI " u16 " "version_rsrv" ";" +.BI " u8 " "api_subversion" ";" +.BI " u8 " "api_version" ";" +.BI " u32 " "api_flags" ";" .BI "" -/* Addresses of various avaiable System calls */ -.BI "u32 " "container_control" ";" -.BI "u32 " "time" ";" -.BI "u32 " "irq_control" ";" -.BI "u32 " "thread_control" ";" -.BI "u32 " "ipc_control" ";" -.BI "u32 " "map" ";" -.BI "u32 " "ipc" ";" -.BI "u32 " "capability_control" ";" -.BI "u32 " "unmap" ";" -.BI "u32 " "exchange_registers" ";" -.BI "u32 " "thread_switch" ";" -.BI "u32 " "schedule" ";" -.BI "u32 " "getid" ";" -.BI "u32 " "mutex_control" ";" -.BI "u32 " "arch_syscall0" ";" -.BI "u32 " "arch_syscall1" ";" -.BI "u32 " "arch_syscall2" ";" + /* Addresses of various avaiable System calls */ +.BI " u32 " "container_control" ";" +.BI " u32 " "time" ";" +.BI " u32 " "irq_control" ";" +.BI " u32 " "thread_control" ";" +.BI " u32 " "ipc_control" ";" +.BI " u32 " "map" ";" +.BI " u32 " "ipc" ";" +.BI " u32 " "capability_control" ";" +.BI " u32 " "unmap" ";" +.BI " u32 " "exchange_registers" ";" +.BI " u32 " "thread_switch" ";" +.BI " u32 " "schedule" ";" +.BI " u32 " "getid" ";" +.BI " u32 " "mutex_control" ";" +.BI " u32 " "arch_syscall0" ";" +.BI " u32 " "arch_syscall1" ";" +.BI " u32 " "arch_syscall2" ";" .BI "" -/* UTCB address field */ -.BI "u32 " "utcb" ";" + /* UTCB address field */ +.BI " u32 " "utcb" ";" .BI "" -/* Brief Description of Kernel */ -.BI "struct " "kernel_descriptor kdesc" ";" -.in 6 + /* Brief Description of Kernel */ +.BI " struct " "kernel_descriptor kdesc" ";" .B }; .TP diff --git a/docs/man/man7/l4_cache_control.7 b/docs/man/man7/l4_cache_control.7 new file mode 100755 index 0000000..f666abc --- /dev/null +++ b/docs/man/man7/l4_cache_control.7 @@ -0,0 +1,80 @@ +.TH L4_CACHE_CONTROL 7 2009-11-07 "Codezero" "Codezero Programmer's Manual" +.SH NAME +.nf +.BR "l4_cache_control" " - Cache/TLB manipulation" + +.SH SYNOPSIS +.nf +.B #include +.B #include + +.BI "int l4_cache_control (unsigned int " "start" ", unsigned int " "end" ", unsigned int " "flags"); +.SH DESCRIPTION +.B l4_cache_control() +enables a thread to invalidate and clean the cache memory. +.TP +.fi +.I start +denotes the start address(virtual memory address) of memory region to be invalidated/cleaned. This is not used in case of armv5. + +.TP +.fi +.I end +denotes the end address(virtual memory address) of memory region to be invalidated/cleaned. This is not used in case of armv5. + +.TP +.fi +.I flags +denotes the operation to be performed. + +.TP +.BR L4_INVALIDATE_CACHE +Invalidate/flush both I and D caches. + +.TP +.BR L4_INVALIDATE_ICACHE +Invalidate/flush I cache. + +.TP +.BR L4_INVALIDATE_DCACHE +Invalidate/flush D cache. + +.TP +.BR L4_CLEAN_DCACHE +Clean D cache. + +.TP +.BR L4_CLEAN_INVALIDATE_DCACHE +Clean and Invalidate D cache. + +.TP +.BR L4_CLEAN_INVALIDATE_CACHE +Invalidate/flush both I and D cache and Clean D cache. + +.TP +.BR L4_DRAIN_WRITEBUFFER +Drain Write Buffer. + +.TP +.BR L4_INVALIDATE_TLB +Invalidate/flush TLB. + +.TP +.BR L4_INVALIDATE_ITLB +Invalidate/flush I TLB. + +.TP +.BR L4_INVALIDATE_DTLB +Invalidate/flush D TLB. + +.SH RETURN VALUE +.IR "l4_cache_control"() +Returns 0 on success, and negative value on failure. See below for error codes. + +.SH ERRORS +.TP +.B -EINVAL +when a +.IR "flag" +is passed with invalid fields. + diff --git a/docs/man/man7/l4_capability_control.7 b/docs/man/man7/l4_capability_control.7 index 1165af2..af2e5dd 100755 --- a/docs/man/man7/l4_capability_control.7 +++ b/docs/man/man7/l4_capability_control.7 @@ -16,20 +16,21 @@ enables a thread to read and manipulate the list of capabilities that it possess .fi .I req denotes the type of request. See below for a full list. + .TP .fi .I flags denotes additional flags for the given request. See below for a list of flags. + .TP .fi - .I buf almost always contains a capability structure that describes the request with regard to given .IR "req" and .IR "flags." -.TP +.TP .BR CAP_CONTROL_NCAPS Get capability count. This is the sum of thread-private capabilities, address space capabilities and container capabilities. .TP @@ -47,9 +48,9 @@ Shares a single capability or list of capabilities with a collection entity such .B CAP_SHARE_SINGLE is specified in .IR "flag", -a single capability is shared. Currently no method has been defined for sharing a larger entity than a single capability at a time, i.e. a list of capabilities. To achieve this, a -.B CAP_SHARE_ALL -flag is planned for a future release. +a single capability is shared. +.BR "CAP_SHARE_ALL_CONTAINER " "makes the caller thread share all of its thread-level and address space-level capability lists with its container. The caller must also be the owner of all of the capabilities, in case of the address space. +.BR "CAP_SHARE_ALL_SPACE " "makes the caller thread share all of its thread-level capabilities with its address space." The sharing must be made with a thread collection entity that contains the capability owner. For example, a capability possessed by a thread may be shared with the thread's address space, or the thread's container. However it is not possible to share a capability in one container with another container. See .B CAP_CONTROL_REPLICATE diff --git a/docs/man/man7/l4_exchange_registers.7 b/docs/man/man7/l4_exchange_registers.7 index a3e4dee..873cc9a 100755 --- a/docs/man/man7/l4_exchange_registers.7 +++ b/docs/man/man7/l4_exchange_registers.7 @@ -17,44 +17,37 @@ By this call, pagers can read and modify any register or other crucial informati is passed to the kernel for modifying the targeted thread's context. See below for a detailed description of this structure and the default context structure for the ARM architecture. .nf -.in 8 /* Exchange registers context structure for the ARM architecture */ .B typedef struct arm_exregs_context { -.in 16 -.BI "u32 " "r0" "; /* 0x4 */" -.BI "u32 " "r1" "; /* 0x8 */" -.BI "u32 " "r2" "; /* 0xC */" -.BI "u32 " "r3" "; /* 0x10 */" -.BI "u32 " "r4" "; /* 0x14 */" -.BI "u32 " "r5" "; /* 0x18 */" -.BI "u32 " "r6" "; /* 0x1C */" -.BI "u32 " "r7" "; /* 0x20 */" -.BI "u32 " "r8" "; /* 0x24 */" -.BI "u32 " "r9" "; /* 0x28 */" -.BI "u32 " "r10" "; /* 0x2C */" -.BI "u32 " "r11" "; /* 0x30 */" -.BI "u32 " "r12" "; /* 0x34 */" -.BI "u32 " "sp" "; /* 0x38 */" -.BI "u32 " "lr" "; /* 0x3C */" -.BI "u32 " "pc" "; /* 0x40 */" -.ti 8 +.BI " u32 " "r0" "; /* 0x4 */" +.BI " u32 " "r1" "; /* 0x8 */" +.BI " u32 " "r2" "; /* 0xC */" +.BI " u32 " "r3" "; /* 0x10 */" +.BI " u32 " "r4" "; /* 0x14 */" +.BI " u32 " "r5" "; /* 0x18 */" +.BI " u32 " "r6" "; /* 0x1C */" +.BI " u32 " "r7" "; /* 0x20 */" +.BI " u32 " "r8" "; /* 0x24 */" +.BI " u32 " "r9" "; /* 0x28 */" +.BI " u32 " "r10" "; /* 0x2C */" +.BI " u32 " "r11" "; /* 0x30 */" +.BI " u32 " "r12" "; /* 0x34 */" +.BI " u32 " "sp" "; /* 0x38 */" +.BI " u32 " "lr" "; /* 0x3C */" +.BI " u32 " "pc" "; /* 0x40 */" .B } __attribute__((__packed__)) exregs_context_t; .nf -.in 8 - /* * Generic structure passed by userspace pagers * for exchanging registers */ .B struct exregs_data { -.in 16 -.BI "exregs_context_t " "context" ";" -.BI "u32 " "valid_vect" ";" -.BI "u32 " "flags" ";" -.BI "l4id_t " "pagerid" ";" -.BI "unsigned long " "utcb_address" ";" -.ti 8 +.BI " exregs_context_t " "context" ";" +.BI " u32 " "valid_vect" ";" +.BI " u32 " "flags" ";" +.BI " l4id_t " "pagerid" ";" +.BI " unsigned long " "utcb_address" ";" .B }; .fi diff --git a/docs/man/man7/l4_getid.7 b/docs/man/man7/l4_getid.7 index 7ecfea1..93c2269 100755 --- a/docs/man/man7/l4_getid.7 +++ b/docs/man/man7/l4_getid.7 @@ -13,13 +13,10 @@ .BR "l4_getid() " "returns thread id, thread group id and space id of a thread in a " "struct task_ids " "structure, as shown below." .nf -.TP -.BI "struct" " task_ids { " -.in 15 -.BI "int " "tid" "; /* Fully qualified thread id */" -.BI "int " "spid" "; /* Address space id (local to container) */" -.BI "int " "tgid" "; /* Thread group id (local, defined by userspace protocol) */" -.ti 7 +.B struct task_ids { +.BI " int " "tid" "; /* Fully qualified thread id */" +.BI " int " "spid" "; /* Address space id (local to container) */" +.BI " int " "tgid" "; /* Thread group id (local, defined by userspace protocol) */" }; .fi @@ -27,7 +24,11 @@ .in 7 Every thread in the system has a thread id, space id and a thread group id associated with it. Each thread and space id is globally unique across the system. Thread group ids are available for grouping threads in arbitrary groups, via a user-defined protocol. A newly created thread may join an existing thread group or create a new group. This behaviour is defined by the thread's pager. Such a user-defined thread group allocation protocol may be useful for implementing groups of threads by higher level OS services. -Even though both thread and space ids are globally unique across the system, there is an addressability difference between them. Each thread id is a fully qualified id, carrying its container id information with it. Upon a system call that targets a thread id, the system allows addressing threads in other containers. In contrast, space ids are not fully qualified. They are local to a container, and any system call addressing a space id cannot target a space in another container. +Even though both thread and space ids are globally unique across the system, there is an addressability difference between them. Each thread id is a fully qualified id, carrying its container id information with it. Upon a system call that targets a thread id, the system allows addressing threads that reside in other containers. In contrast, space ids are not fully qualified. They are local to a container, and any system call addressing a space id cannot target a space in another container. For thread ids, +.BI "__cid("tid ")" +macro extracts the Container ID information from the fully qualified thread id, whereas the +.BI " __raw_tid("tid ")" +macro provides the raw Thread ID, which omits the container ID information from the thread id. Such a raw ID still uniquely identifies the thread across containers, i.e. there is one such raw id per thread across the system. .SH FUTURE .BR "l4_getid() " "call is currently not subject to capability checking, as every thread has a natural right to discover their ids. In the future, it is possible that this system call is used for naming discovery for other addressable entities. If such a role is given to this call, it may also become subject to capability checking, as access control would prove beneficial over naming discovery services." diff --git a/docs/man/man7/l4_irq_control.7 b/docs/man/man7/l4_irq_control.7 new file mode 100755 index 0000000..f7c19fb --- /dev/null +++ b/docs/man/man7/l4_irq_control.7 @@ -0,0 +1,67 @@ +.TH L4_IRQ_CONTROL 7 2009-11-07 "Codezero" "Codezero Programmer's Manual" +.SH NAME +.nf +.BR "l4_irq_control" " - Register/unregister device irqs. + +.SH SYNOPSIS +.nf +.B #include +.B #include + +.BI "int l4_irq_control (unsigned int " "req" ", unsigned int " "flags" ", l4id_t " "id"); +.SH DESCRIPTION +.B l4_irq_control() +enables a thread to register/unregister device irqs. Caller of this sytem call has an option to choose between synchronous or asynchronous irq handling. +.TP +.fi +.I req +denotes the type of operation to be performed. + +.TP +.BR IRQ_CONTROL_REGISTER +Register the caller thread as irq handler for the irq index +.BR "id". + +.TP +.BR IRQ_CONTROL_RELEASE +Unregister the caller thread, earlier registered as irq handler for the irq index +.BR "id". + +.TP +.BR IRQ_CONTROL_WAIT +Wait for irq to happen. This flag is used by the irq handler to block and wait for irq to happen. + +.TP +.fi +.I flags +denotes the slot number representing the irq handler, this is the identifier which distinguishes various handlers registered for the same device. + +.TP +.fi +.I id +denotes the platform specific irq index of the concerned device. + +.SH RETURN VALUE +.IR "l4_irq_control"() +Returns 0 on success, and negative value on failure. See below for error codes. + +.SH ERRORS +.TP +.B -EINVAL +when the +.IR "flags" +passed is not having valid information. + +.TP +.B -ENOUTCB +in case the thread making the system call does not have a valid utcb. + +.TP +.B -EFAULT +in case utcb of caller thread is not mapped. + +.TP +.B -ENOIRQ +in case the device represented by irq index +.BR "id" +is invalid or kernel does not allow user space tasks to avail this device. diff --git a/docs/man/man7/l4_mutex_control.7 b/docs/man/man7/l4_mutex_control.7 index e9adec8..e09dcc7 100755 --- a/docs/man/man7/l4_mutex_control.7 +++ b/docs/man/man7/l4_mutex_control.7 @@ -42,12 +42,8 @@ argument specifies the userspace virtual address for the lock. See below for a u .SH L4 USERSPACE LIBRARY .nf -.br -.in 7 .B struct l4_mutex { -.in 15 -.BI "unsigned int " "lock" ";" -.in 7 +.BI " unsigned int " "lock" ";" .B } __attribute__((aligned(sizeof(int)))); .BI "void l4_mutex_init(struct l4_mutex " "*m" ");" diff --git a/docs/man/man7/l4_thread_control.7 b/docs/man/man7/l4_thread_control.7 index ee3bb45..7d0b98c 100755 --- a/docs/man/man7/l4_thread_control.7 +++ b/docs/man/man7/l4_thread_control.7 @@ -18,26 +18,54 @@ system call manipulates threads in the system. Pagers may create, destroy, recyc subsection below for a detailed explanation of the matter. .fi +.IR "ids " "field specifies the thread, address space, and thread group ids of the targeted thread. Below is the declaration for this structure:" + +.nf +.TP +.BI "struct" " task_ids { " +.in 15 +.BI "int " "tid" "; /* Fully qualified thread id */" +.BI "int " "spid" "; /* Address space id (local to container) */" +.BI "int " "tgid" "; /* Thread group id (local, defined by userspace protocol) */" +.ti 7 +}; +.ti 7 +.TP +.fi +.I tid +argument may have different meanings for different thread control actions. For an existing thread, this argument specifies the thread on which the action is to be performed. On a thread creation request, this argument would specify the thread whose context is to be copied from for creating the new thread. See +.I actions +below for a more detailed explanation. + +.TP +.fi +.I spid +field has meaning only on a +.B THREAD_CREATE +request, in conjunction with one of +.B TC_SHARE_SPACE, +.B TC_NEW_SPACE +or +.B TC_COPY_SPACE +flags +.TP +.fi +.I tgid +field is provided as an extra id slot for the thread. The pager of the thread may designate a group of threads to be in the same thread group, defining the group by a userspace protocol. This field has no meaning from the kernel's perspective, and may be removed in future releases. + .I action field is the main action specifier where one of the following may be supplied as valid actions: .TP .TP .B THREAD_CREATE -Creates a new thread in a new or existing space depending on the spid argument. If spid argument denotes an existing space, new thread is added to that space. If spid argument has the value -.B THREAD_ID_INVALID -this is taken as a new address space creation request, and the new thread is placed into a newly allocated address space. +Creates a new thread in a new or existing space depending on the provided space flags. +.RI "A thread create request requires valid " "tid" " and " "spid" " fields in order to specify which thread context and address space to copy from or use." Following are the action flags that are associated with a .B THREAD_CREATE request: .in 14 -.B TC_AS_PAGER -Sets the creator of the thread as the pager of the new thread. - -.B TC_SHARE_PAGER -Sets the creator's pagerid as the pager of the new thread. - .B TC_SHARE_UTCB Sets the new thread's utcb as the creator's utcb. Threads may validly share UTCBs by making sure that they don't initiate IPC at the same time, or ensure synchronized access to UTCB fields. @@ -47,12 +75,14 @@ Sets the new thread's thread group id as the id specified by .B TC_SHARE_SPACE Places the new thread into the address space specified by -.I spid +.IR "spid" ", and copies the thread context from thread specified by " "tid" " field. The thread represented by the " "tid " "argument is said to represent a " +.BR "parent " " relationship to the newly created thread." .B TC_COPY_SPACE Copies all page tables of the address space specified by .I spid -to the new thread's newly created address space. This flag is particularly useful for implementing the +to the new thread's newly created address space. +.RI "Also copies the thread context from thread specified by the " "tid " "field, who is said to represent a " "parent" " relationship to the newly created thread. This flag is particularly useful for implementing the" .B POSIX fork() system call. @@ -77,41 +107,6 @@ Waits on a thread to exit, with exit status. On a system setup where a pager is responsible for creating threads in separate address spaces and communicating with them via IPC, the children may send an exit IPC message to their pager. This way, a pager may synchronously receive exit status of a child in the form of IPC, and take action to destroy it as part of handling the IPC. However, on systems where the application is a multi-threaded, single address space application, a thread wait call provides a simple synchronous channel for the parent to wait on its child's exit status, without requiring any extra set up for IPC handling. .ti 7 -.IR "ids " "field specifies the thread, address space, and thread group ids of the targeted thread. Below is the declaration for this structure:" - -.nf -.TP -.BI "struct" " task_ids { " -.in 15 -.BI "int " "tid" "; /* Fully qualified thread id */" -.BI "int " "spid" "; /* Address space id (local to container) */" -.BI "int " "tgid" "; /* Thread group id (local, defined by userspace protocol) */" -.ti 7 -}; -.ti 7 -.TP -.fi -.I tid -argument specifies the targeted thread id for the request. This is a fully qualified thread id that uniquely identifies the thread in the system. The benefit of a fully qualified id is that it may be used to address threads that exist in other containers in the system. -.BI "__cid("tid ")" -macro extracts the Container ID information from the fully qualified thread id, whereas the -.BI " __raw_tid("tid ")" -macro provides the raw Thread ID, which omits the container ID information from the thread id. Such a raw ID still uniquely identifies the thread across containers. -.TP -.fi -.I spid -field has meaning only on a -.B THREAD_CREATE -request, in conjunction with one of -.B TC_SHARE_SPACE, -.B TC_NEW_SPACE -or -.B TC_COPY_SPACE -flags -.TP -.fi -.I tgid -field is provided as an extra id slot for the thread. The pager of the thread may designate a group of threads to be in the same thread group, defining the group by a userspace protocol. This field has no meaning from the kernel's perspective, and may be removed in future releases. .in 7 .RB "See " "l4_getid" "(7) for more details on resource ids in Codezero." diff --git a/docs/man/man7/utcb.7 b/docs/man/man7/utcb.7 index 08fd96d..83bfc4f 100755 --- a/docs/man/man7/utcb.7 +++ b/docs/man/man7/utcb.7 @@ -22,18 +22,12 @@ system call reference page. .RI "UTCB may also be used for any thread-local information that is private to each thread in an address space. For example on stacked IPCs where a new IPC is initiated before the current IPC has been completed, " "saved_tag " "and " "saved_sender " "fields serve the purpose of saving the unfinished IPC information. For a full description of each field please refer to below. " .fi -.ti 8 -.BI "struct " "utcb " -{ -.ti 16 -.BI "u32 " "mr[MR_TOTAL]" "; /* MRs that are mapped to real registers */" -.ti 16 -.BI "u32 " "saved_tag" "; /* Saved tag field for stacked ipc */" -.ti 16 -.BI "u32 " "saved_sender" "; /* Saved sender field for stacked ipc */" -.ti 16 -.BI "u32 " "mr_rest[MR_REST]" "; /* Complete the utcb to 64 words */" -.ti 8 +.nf +.B struct utcb { +.BI " u32 " "mr[MR_TOTAL]" "; /* MRs that are mapped to real registers */" +.BI " u32 " "saved_tag" "; /* Saved tag field for stacked ipc */" +.BI " u32 " "saved_sender" "; /* Saved sender field for stacked ipc */" +.BI " u32 " "mr_rest[MR_REST]" "; /* Complete the utcb to 64 words */" }; .TP diff --git a/docs/tls.txt b/docs/tls.txt index 0faa216..fe29641 100644 --- a/docs/tls.txt +++ b/docs/tls.txt @@ -6,12 +6,12 @@ registers and write the IPC payload. This necessitates a convenient method of accessing the thread-specific utcb structure. Here are some of the possible methods of accessing a thread local storage in general: -1.) Keep a global pointer to it. The scheduler updates the pointer to TLS -upon every context switch. - -2.) Map the private physical TLS page to thread address space at same virtual +1.) Map the private physical TLS page to thread address space at same virtual offset, everytime there is a context switch. +2.) Keep a global pointer to it. The scheduler updates the pointer to TLS +upon every context switch. + 3.) Manage everything by the run-time library in the application. This includes the following: @@ -42,9 +42,9 @@ as new threads come to life, and map this when they run, without managing utcb table size. The downside is that a page is wasted per-thread. The solution Codezero uses includes a mixture of both (1) and (2). Upon a -context switch, a private page is allocated and mapped by the pager, but also +context switch, a page private to each context is mapped by the pager, but also the UTCB pointer is updated to point at an offset in this page. As an example, if a UTCB is sized 1/4th of a page, a single page is used by 4 UTCBs. This way, the pager needs to manage 4 entries per-private page, utcbs utilise page memory -fully, and there is no need for a fixed table of utcbs per address space. - +fully, and there is no need for a fixed table of utcbs per address space. Of +course, utcb pages are only shared by threads in the same address space. diff --git a/include/l4/api/cache.h b/include/l4/api/cache.h new file mode 100644 index 0000000..7ed40e8 --- /dev/null +++ b/include/l4/api/cache.h @@ -0,0 +1,17 @@ +/* + * Generic macros for cache operations + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __CACHE_CONTROL_H__ +#define __CACHE_CONTROL_H__ + +#include INC_GLUE(cache.h) + +#define L4_INVALIDATE_ICACHE ARCH_INVALIDATE_ICACHE +#define L4_INVALIDATE_DCACHE ARCH_INVALIDATE_DCACHE +#define L4_CLEAN_DCACHE ARCH_CLEAN_DCACHE +#define L4_CLEAN_INVALIDATE_DCACHE ARCH_CLEAN_INVALIDATE_DCACHE +#define L4_INVALIDATE_TLB ARCH_INVALIDATE_TLB + +#endif /* __CACHE_CONTROL_H__ */ diff --git a/include/l4/api/capability.h b/include/l4/api/capability.h index 771c411..96347a7 100644 --- a/include/l4/api/capability.h +++ b/include/l4/api/capability.h @@ -6,9 +6,8 @@ #ifndef __API_CAPABILITY_H__ #define __API_CAPABILITY_H__ -#if defined(__KERNEL__) #include -#endif +#include INC_ARCH(types.h) /* Capability syscall request types */ #define CAP_CONTROL_NCAPS 0x00000000 @@ -20,8 +19,10 @@ #define CAP_CONTROL_DEDUCE 0x00000006 #define CAP_CONTROL_DESTROY 0x00000007 -#define CAP_SHARE_MASK 0x00000003 +#define CAP_SHARE_MASK 0x0000000F #define CAP_SHARE_SINGLE 0x00000001 +#define CAP_SHARE_ALL_CONTAINER 0x00000002 +#define CAP_SHARE_ALL_SPACE 0x00000003 #define CAP_GRANT_MASK 0x0000000F #define CAP_GRANT_SINGLE 0x00000001 diff --git a/include/l4/api/errno.h b/include/l4/api/errno.h index 35301eb..ccc4712 100644 --- a/include/l4/api/errno.h +++ b/include/l4/api/errno.h @@ -141,5 +141,8 @@ #define ENOCAP 134 /* None or insufficient capability */ #define ENOUTCB 135 /* Task has no utcb set up */ #define ENOMAP 136 /* The memory area has unmapped regions */ +#define ENOIRQ 137 /* Irq cannot be registered */ +#define EABORT 138 /* Abort cannot be handled */ +#define ENOCHILD 139 /* Task is not paged by caller */ #endif /* __ERRNO_H__ */ diff --git a/include/l4/api/irq.h b/include/l4/api/irq.h index 9bfcfe2..f94a0ba 100644 --- a/include/l4/api/irq.h +++ b/include/l4/api/irq.h @@ -4,6 +4,7 @@ #define IRQ_CONTROL_REGISTER 0 #define IRQ_CONTROL_RELEASE 1 +#define IRQ_CONTROL_WAIT 2 #endif /* __API_IRQ_H__ */ diff --git a/include/l4/api/kip.h b/include/l4/api/kip.h index 9e0dd0a..536386e 100644 --- a/include/l4/api/kip.h +++ b/include/l4/api/kip.h @@ -61,7 +61,8 @@ struct kip { u32 schedule; u32 getid; u32 mutex_control; - + u32 cache_control; + u32 arch_syscall0; u32 arch_syscall1; u32 arch_syscall2; diff --git a/include/l4/api/syscall.h b/include/l4/api/syscall.h index 232b2d4..d8f5f4f 100644 --- a/include/l4/api/syscall.h +++ b/include/l4/api/syscall.h @@ -26,7 +26,8 @@ #define sys_container_control_offset 0x2C #define sys_time_offset 0x30 #define sys_mutex_control_offset 0x34 -#define syscalls_end_offset sys_mutex_control_offset +#define sys_cache_control_offset 0x38 +#define syscalls_end_offset sys_cache_control_offset #define SYSCALLS_TOTAL ((syscalls_end_offset >> 2) + 1) void print_syscall_context(struct ktcb *t); @@ -46,5 +47,7 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *addr); int sys_container_control(unsigned int req, unsigned int flags, void *addr); int sys_time(struct timeval *tv, int set); int sys_mutex_control(unsigned long mutex_address, int mutex_op); +int sys_cache_control(unsigned long start, unsigned long end, + unsigned int flags); #endif /* __SYSCALL_H__ */ diff --git a/include/l4/api/thread.h b/include/l4/api/thread.h index 1bc89a4..e800b2d 100644 --- a/include/l4/api/thread.h +++ b/include/l4/api/thread.h @@ -9,15 +9,17 @@ #define THREAD_RECYCLE 0x40000000 #define THREAD_WAIT 0x50000000 -#define THREAD_CREATE_MASK 0x0FF00000 +#define THREAD_SHARE_MASK 0x00F00000 +#define THREAD_SPACE_MASK 0x0F000000 +#define THREAD_CREATE_MASK (THREAD_SHARE_MASK | THREAD_SPACE_MASK) #define TC_SHARE_CAPS 0x00100000 /* Share all thread capabilities */ #define TC_SHARE_UTCB 0x00200000 /* Share utcb location (same space */ #define TC_SHARE_GROUP 0x00400000 /* Share thread group id */ -#define TC_SHARE_SPACE 0x00800000 /* New thread, use given space */ -#define TC_COPY_SPACE 0x01000000 /* New thread, copy given space */ -#define TC_NEW_SPACE 0x02000000 /* New thread, new space */ -#define TC_SHARE_PAGER 0x04000000 /* New thread, shared pager */ -#define TC_AS_PAGER 0x08000000 /* Set new thread as child */ +#define TC_SHARE_SPACE 0x01000000 /* New thread, use given space */ +#define TC_COPY_SPACE 0x02000000 /* New thread, copy given space */ +#define TC_NEW_SPACE 0x04000000 /* New thread, new space */ + +/* #define THREAD_USER_MASK 0x000F0000 Reserved for userspace */ #define THREAD_EXIT_MASK 0x0000FFFF /* Thread exit code */ #endif /* __API_THREAD_H__ */ diff --git a/include/l4/arch/arm/asm-macros.S b/include/l4/arch/arm/asm-macros.S new file mode 100644 index 0000000..19cdb89 --- /dev/null +++ b/include/l4/arch/arm/asm-macros.S @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * Common assembler macros + * + * Prem Mallappa, Bahadir Balban + */ +#ifndef __ASM_MACROS_S__ +#define __ASM_MACROS_S__ + + .macro get_cpuid cpuid + mrc p15, 0, \cpuid, c0, c0, 5 @ Read MPIDR + and \cpuid, \cpuid, #0xF @ Mask lower cpuid bits + .endm + +#endif /* __ASM_MACROS_S__ */ diff --git a/include/l4/arch/arm/asm.h b/include/l4/arch/arm/asm.h index ce3152c..9ee06d4 100644 --- a/include/l4/arch/arm/asm.h +++ b/include/l4/arch/arm/asm.h @@ -20,9 +20,11 @@ #define ARM_NOIRQ_FIQ 0xD1 #define ARM_NOIRQ_USR 0xD0 #define ARM_NOIRQ_SYS 0xDF + /* For enabling *clear* these bits */ -#define ARM_IRQ_BIT 0x80 -#define ARM_FIQ_BIT 0x40 +#define ARM_IRQ_BIT 0x080 +#define ARM_FIQ_BIT 0x040 +#define ARM_A_BIT 0x100 /* Asynchronous abort */ /* Notes about ARM instructions: * diff --git a/include/l4/arch/arm/exception.h b/include/l4/arch/arm/exception.h index 91b0a0d..ca189c2 100644 --- a/include/l4/arch/arm/exception.h +++ b/include/l4/arch/arm/exception.h @@ -1,89 +1,57 @@ /* - * Definitions for exception support on ARM + * Common definitions for exceptions + * across ARM sub-architectures. * - * Copyright (C) 2007 Bahadir Balban + * Copyright (C) 2010 B Labs Ltd. */ -#ifndef __ARCH_EXCEPTIONS_H__ -#define __ARCH_EXCEPTIONS_H__ +#ifndef __EXCEPTION_H__ +#define __EXCEPTION_H__ + +#include INC_SUBARCH(exception.h) #include INC_ARCH(asm.h) +/* Abort debugging conditions */ +//#define DEBUG_ABORTS +#if defined (DEBUG_ABORTS) +#define dbg_abort(...) printk(__VA_ARGS__) +#else +#define dbg_abort(...) +#endif -static inline void enable_irqs() -{ - __asm__ __volatile__( - "mrs r0, cpsr_fc\n" - "bic r0, r0, #0x80\n" /* ARM_IRQ_BIT */ - "msr cpsr_fc, r0\n" - ); -} +/* Codezero-specific abort type */ +#define ABORT_TYPE_PREFETCH 1 +#define ABORT_TYPE_DATA 0 -static inline int irqs_enabled() -{ - register unsigned int enabled asm("r1"); - __asm__ __volatile__( - "mrs r0, cpsr_fc\n" - "tst r0, #0x80\n" /* ARM_IRQ_BIT. See asm.h for TST inst. */ - "moveq r1, #1\n" - "movne r1, #0\n" - ); - return enabled; -} +/* If abort is handled and resolved in check_aborts */ +#define ABORT_HANDLED 1 -static inline void disable_irqs() -{ - __asm__ __volatile__( - "mrs r0, cpsr_fc\n" - "orr r0, r0, #0x80\n" /* ARM_IRQ_BIT */ - "msr cpsr_fc, r0\n" - ); -} +/* Codezero makes use of bit 8 (Always Zero) of FSR to define which type of abort */ +#define set_abort_type(fsr, x) { fsr &= ~(1 << 8); fsr |= ((x & 1) << 8); } +#define is_prefetch_abort(fsr) ((fsr >> 8) & 0x1) +#define is_data_abort(fsr) (!is_prefetch_abort(fsr)) -/* Disable the irqs unconditionally, but also keep the previous state such that - * if it was already disabled before the call, the restore call would retain - * this state. */ -static inline void irq_local_disable_save(unsigned long *state) -{ - unsigned long temp; - __asm__ __volatile__ ( - "mrs %0, cpsr_fc\n" - "orr %1, %0, #0x80\n" - "msr cpsr_fc, %1\n" - :: "r" (*state), "r" (temp) - ); -} -/* Simply change it back to original state supplied in @flags. This might enable - * or retain disabled state of the irqs for example. Useful for nested calls. */ -static inline void irq_local_restore(unsigned long state) -{ - __asm__ __volatile__ ( - "msr cpsr_fc, %0\n" - :: "r" (state) - ); -} +/* Kernel's data about the fault */ +typedef struct fault_kdata { + u32 faulty_pc; /* In DABT: Aborting PC, In PABT: Same as FAR */ + u32 fsr; /* In DABT: DFSR, In PABT: IFSR */ + u32 far; /* In DABT: DFAR, in PABT: IFAR */ + pte_t pte; /* Faulty page table entry */ +} __attribute__ ((__packed__)) fault_kdata_t; -static inline void irq_local_enable() -{ - enable_irqs(); -} - -static inline void irq_local_disable() -{ - disable_irqs(); -} /* This is filled on entry to irq handler, only if a process was interrupted.*/ extern unsigned int preempted_psr; -/* - * FIXME: TASK_IN_KERNEL works for non-current tasks, in_kernel() works for current task? - * in_kernel() is for irq, since normally in process context you know if you are in kernel or not :-) - */ - /* Implementing these as functions cause circular include dependency for tcb.h */ #define TASK_IN_KERNEL(tcb) (((tcb)->context.spsr & ARM_MODE_MASK) == ARM_MODE_SVC) #define TASK_IN_USER(tcb) (!TASK_IN_KERNEL(tcb)) +static inline int is_user_mode(u32 spsr) +{ + return ((spsr & ARM_MODE_MASK) == ARM_MODE_USR); +} + static inline int in_kernel() { return (((preempted_psr & ARM_MODE_MASK) == ARM_MODE_SVC)) ? 1 : 0; @@ -97,4 +65,9 @@ static inline int in_user() int pager_pagein_request(unsigned long vaddr, unsigned long size, unsigned int flags); -#endif +int fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far, u32 ipc_tag); + +int is_kernel_abort(u32 faulted_pc, u32 fsr, u32 far, u32 spsr); +int check_abort_type(u32 faulted_pc, u32 fsr, u32 far, u32 spsr); + +#endif /* __EXCEPTION_H__ */ diff --git a/include/l4/arch/arm/io.h b/include/l4/arch/arm/io.h index 89ae6a4..c33f548 100644 --- a/include/l4/arch/arm/io.h +++ b/include/l4/arch/arm/io.h @@ -6,7 +6,20 @@ * Copyright (C) 2007 Bahadir Balban */ -#define read(val, address) val = *((volatile unsigned int *) address) -#define write(val, address) *((volatile unsigned int *) address) = val +#if defined (__KERNEL__) + +#include INC_GLUE(memlayout.h) + +#define read(address) *((volatile unsigned int *) (address)) +#define write(val, address) *((volatile unsigned int *) (address)) = val + +#endif /* ends __KERNEL__ */ + +/* + * Generic uart virtual address until a file-based console access + * is available for userspace + */ +#define USERSPACE_CONSOLE_VBASE 0xF9800000 + #endif /* __ARM_IO_H__ */ diff --git a/include/l4/arch/arm/irq.h b/include/l4/arch/arm/irq.h new file mode 100644 index 0000000..db38692 --- /dev/null +++ b/include/l4/arch/arm/irq.h @@ -0,0 +1,29 @@ +#ifndef __ARM_IRQ_H__ +#define __ARM_IRQ_H__ + +#include INC_SUBARCH(irq.h) + +void irq_local_restore(unsigned long state); +void irq_local_disable_save(unsigned long *state); +int irqs_enabled(); + +static inline void irq_local_enable() +{ + enable_irqs(); +} + +static inline void irq_local_disable() +{ + disable_irqs(); +} + + +/* + * Destructive atomic-read. + * + * Write 0 to byte at @location as its contents are read back. + */ +char l4_atomic_dest_readb(void *location); + + +#endif /* __ARM_IRQ_H__ */ diff --git a/include/l4/arch/arm/linker.h b/include/l4/arch/arm/linker.h index 545817b..2edebc9 100644 --- a/include/l4/arch/arm/linker.h +++ b/include/l4/arch/arm/linker.h @@ -16,9 +16,15 @@ extern unsigned long arm_high_vector[]; extern unsigned long _end_vectors[]; extern unsigned long _start_kip[]; extern unsigned long _end_kip[]; +extern unsigned long _start_syscalls[]; +extern unsigned long _end_syscalls[]; extern unsigned long _start_init[]; extern unsigned long _end_init[]; -extern unsigned long _bootstack[]; +extern unsigned long _start_bootstack[]; +extern unsigned long _end_bootstack[]; +extern unsigned long _start_init_pgd[]; +extern unsigned long _end_init_pgd[]; + extern unsigned long _end_kernel[]; extern unsigned long _end[]; diff --git a/include/l4/arch/arm/linker.lds.in b/include/l4/arch/arm/linker.lds.in new file mode 100644 index 0000000..eadfeeb --- /dev/null +++ b/include/l4/arch/arm/linker.lds.in @@ -0,0 +1,89 @@ +/* + * Simple linker script + * + * Copyright (C) 2007 Bahadir Balban + */ +#if !defined (CONFIG_NCPU) +#define CONFIG_NCPU 1 +#endif + +phys_ram_start = PLATFORM_PHYS_MEM_START; +kernel_offset = KERNEL_AREA_START - phys_ram_start; +kernel_physical = 0x8000 + phys_ram_start; +kernel_virtual = kernel_physical + kernel_offset; + +/* A temporary boot stack is used before a proper kernel stack is set up */ +_bootstack_physical = _end_bootstack - kernel_offset; + +/* The symbols are linked at virtual addresses. So is _start. + * We must set the entry point to a physical address, so that + * when the image is loaded, it doesn't jump to a non existing + * virtual address. + */ +ENTRY(kernel_physical) + +SECTIONS +{ + . = kernel_virtual; + _start_kernel = .; + .text : AT (ADDR(.text) - kernel_offset) + { + _start_text = .; + /* Make sure head.S comes first */ + /* *head.o(.text) This only works when given its full path. Bad limitation. */ + *(.text.head) + *(.text) + _end_text = .; + } + . = ALIGN(4); + /* rodata is needed else your strings will link at physical! */ + .rodata : AT (ADDR(.rodata) - kernel_offset) { *(.rodata) } + .rodata1 : AT (ADDR(.rodata1) - kernel_offset) { *(.rodata1) } + .data : AT (ADDR(.data) - kernel_offset) + { + _start_data = .; + *(.data) + /* Best alignment because we need 4 x (4K) and 1 x 16K block */ + . = ALIGN(16K); + _start_vectors = .; + *(.data.vectors) + _end_vectors = .; + . = ALIGN(4K); + _start_kip = .; + *(.data.kip) + . = ALIGN(4K); + _end_kip = .; + _start_syscalls = .; + *(.data.syscalls) + . = ALIGN(4K); + _end_syscalls = .; + _start_init_pgd = .; + *(.data.pgd); + _end_init_pgd = .; + _start_bootstack = .; + . = ALIGN(4K); + . += PAGE_SIZE * CONFIG_NCPU; + _end_bootstack = .; + _end_data = .; + } + .bss : AT (ADDR(.bss) - kernel_offset) + { + *(.bss) + } + . = ALIGN(4K); + . += PAGE_SIZE * 2; /* This is required as the link counter does not seem + * to increment for the bss section + * TODO: Change this with PAGE_SIZE */ + + /* Below part is to be discarded after boot */ + _start_init = .; + .init : AT (ADDR(.init) - kernel_offset) + { + *(.init.task.pgd) /* Non-global task table on split tables, otherwise nil */ + *(.init.bootmem) + *(.init.data) + } + _end_init = .; + _end_kernel = .; + _end = .; +} diff --git a/include/l4/arch/arm/mutex.h b/include/l4/arch/arm/mutex.h index e8a12e0..37cdbe6 100644 --- a/include/l4/arch/arm/mutex.h +++ b/include/l4/arch/arm/mutex.h @@ -1,15 +1,16 @@ -#ifndef __ARCH_MUTEX_H__ -#define __ARCH_MUTEX_H__ /* * ARM specific low-level mutex interfaces * * Copyright (C) 2007 Bahadir Balban */ +#ifndef __ARCH_MUTEX_H__ +#define __ARCH_MUTEX_H__ + /* TODO: The return types could be improved for debug checking */ void __spin_lock(unsigned int *s); void __spin_unlock(unsigned int *s); unsigned int __mutex_lock(unsigned int *m); void __mutex_unlock(unsigned int *m); -#endif +#endif /* __ARCH_MUTEX_H__ */ diff --git a/include/l4/arch/arm/scu.h b/include/l4/arch/arm/scu.h new file mode 100644 index 0000000..12bf9f6 --- /dev/null +++ b/include/l4/arch/arm/scu.h @@ -0,0 +1,34 @@ +/* + * SCU registers + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Prem Mallappa + */ +#ifndef __SCU_H__ +#define __SCU_H__ + + +/* Following defines may well go into realview/scu.h */ +#define SCU_CTRL_REG 0x00 /* Control Register */ +#define SCU_CFG_REG 0x04 /* Configuration Register */ +#define SCU_CPU_PWR_REG 0x08 /* SCU CPU Power state register */ +#define SCU_INV_ALL_S 0x0C /* SCU Invalidate all Secure Registers */ +#define SCU_ACCESS_REG_S 0x50 /* SCU Access Control Secure */ +#define SCU_ACCESS_REG_NS 0x54 /* SCU Access Control Non-Secure */ + +/* The contents of CONTROL AND CONFIG are Implementation Defined. so they may go into platform specific scu.h */ +#define SCU_CTRL_EN (1 << 0) +#define SCU_CTRL_ADDR_FLTR_EN (1 << 1) +#define SCU_CTRL_PARITY_ON (1 << 2) +#define SCU_CTRL_STBY_EN (1 << 5) /* SCU StandBy Enable */ +#define SCU_CTRL_GIC_STBY_EN (1 << 6) /* GIC Standby enable */ + +/* Config register */ +#define SCU_CFG_SMP_MASK 0x000000f0 +#define SCU_CFG_TAG_RAM_MASK 0x0000ff00 +#define SCU_CFG_NCPU_MASK 0x7 +#define SCU_CFG_SMP_NCPU_SHIFT 4 + + +#endif /* __SCU_H__ */ diff --git a/include/l4/arch/arm/v5/cache.h b/include/l4/arch/arm/v5/cache.h new file mode 100644 index 0000000..e69de29 diff --git a/include/l4/arch/arm/v5/cpu.h b/include/l4/arch/arm/v5/cpu.h new file mode 100644 index 0000000..b326bff --- /dev/null +++ b/include/l4/arch/arm/v5/cpu.h @@ -0,0 +1,24 @@ +/* + * Cpu specific features + * defined upon the base architecture. + * + * Copyright (C) 2010 B Labs Ltd. + * Written by Bahadir Balban + */ + +#ifndef __V5_CPU_H__ +#define __V5_CPU_H__ + +#include INC_SUBARCH(mmu_ops.h) + +static inline void cpu_startup(void) +{ + +} + +static inline int smp_get_cpuid() +{ + return 0; +} + +#endif /* __V5_CPU_H__ */ diff --git a/include/l4/arch/arm/v5/debug.h b/include/l4/arch/arm/v5/debug.h new file mode 100644 index 0000000..e69de29 diff --git a/include/l4/arch/arm/v5/exception.h b/include/l4/arch/arm/v5/exception.h new file mode 100644 index 0000000..f88631e --- /dev/null +++ b/include/l4/arch/arm/v5/exception.h @@ -0,0 +1,33 @@ +/* + * Definitions for exception support on ARMv5 + * + * Copyright (C) 2007 Bahadir Balban + */ +#ifndef __ARCH_V5_EXCEPTION_H__ +#define __ARCH_V5_EXCEPTION_H__ + +#include INC_ARCH(asm.h) + +/* + * v5 Architecture-defined data abort values for FSR ordered + * in highest to lowest priority. + */ +#define DABT_TERMINAL 0x2 +#define DABT_VECTOR 0x0 /* Obsolete */ +#define DABT_ALIGN 0x1 +#define DABT_EXT_XLATE_LEVEL1 0xC +#define DABT_EXT_XLATE_LEVEL2 0xE +#define DABT_XLATE_SECT 0x5 +#define DABT_XLATE_PAGE 0x7 +#define DABT_DOMAIN_SECT 0x9 +#define DABT_DOMAIN_PAGE 0xB +#define DABT_PERM_SECT 0xD +#define DABT_PERM_PAGE 0xF +#define DABT_EXT_LFETCH_SECT 0x4 +#define DABT_EXT_LFETCH_PAGE 0x6 +#define DABT_EXT_NON_LFETCH_SECT 0x8 +#define DABT_EXT_NON_LFETCH_PAGE 0xA + +#define FSR_FS_MASK 0xF + +#endif /* __ARCH_V5_EXCEPTION_H__ */ diff --git a/include/l4/arch/arm/v5/irq.h b/include/l4/arch/arm/v5/irq.h new file mode 100644 index 0000000..8ec1559 --- /dev/null +++ b/include/l4/arch/arm/v5/irq.h @@ -0,0 +1,28 @@ +#ifndef __ARM_V5_IRQ_H__ +#define __ARM_V5_IRQ_H__ + +static inline void enable_irqs() +{ + __asm__ __volatile__( + "mrs r0, cpsr_fc\n" + "bic r0, r0, #0x80\n" /* ARM_IRQ_BIT */ + "msr cpsr_fc, r0\n" + ); +} + +static inline void disable_irqs() +{ + __asm__ __volatile__( + "mrs r0, cpsr_fc\n" + "orr r0, r0, #0x80\n" /* ARM_IRQ_BIT */ + "msr cpsr_fc, r0\n" + ); +} + +/* Disable the irqs unconditionally, but also keep the previous state such that + * if it was already disabled before the call, the restore call would retain + * this state. */ +void irq_local_disable_save(unsigned long *state); +void irq_local_restore(unsigned long state); + +#endif diff --git a/include/l4/arch/arm/v5/mm.h b/include/l4/arch/arm/v5/mm.h index d0ff6d2..77db85e 100644 --- a/include/l4/arch/arm/v5/mm.h +++ b/include/l4/arch/arm/v5/mm.h @@ -9,53 +9,65 @@ /* ARM specific definitions */ #define VIRT_MEM_START 0 #define VIRT_MEM_END 0xFFFFFFFF -#define ARM_SECTION_SIZE SZ_1MB -#define ARM_SECTION_MASK (ARM_SECTION_SIZE - 1) -#define ARM_SECTION_BITS 20 +#define SECTION_SIZE SZ_1MB +#define SECTION_MASK (SECTION_SIZE - 1) +#define SECTION_ALIGN_MASK (~SECTION_MASK) +#define SECTION_BITS 20 #define ARM_PAGE_SIZE SZ_4K #define ARM_PAGE_MASK 0xFFF #define ARM_PAGE_BITS 12 #define PGD_SIZE SZ_4K * 4 #define PGD_ENTRY_TOTAL SZ_4K -#define PGD_TYPE_MASK 0x3 -#define PGD_COARSE_ALIGN_MASK 0xFFFFFC00 -#define PGD_SECTION_ALIGN_MASK 0xFFF00000 -#define PGD_FINE_ALIGN_MASK 0xFFFFF000 -#define PGD_TYPE_FAULT 0 -#define PGD_TYPE_COARSE 1 -#define PGD_TYPE_SECTION 2 -#define PGD_TYPE_FINE 3 - -#define PMD_TYPE_MASK 0x3 -#define PMD_TYPE_FAULT 0 -#define PMD_TYPE_LARGE 1 -#define PMD_TYPE_SMALL 2 -#define PMD_TYPE_TINY 3 - -/* Permission field offsets */ -#define SECTION_AP0 10 #define PMD_SIZE SZ_1K #define PMD_ENTRY_TOTAL 256 #define PMD_MAP_SIZE SZ_1MB +#define PMD_ALIGN_MASK (~(PMD_SIZE - 1)) +#define PMD_TYPE_MASK 0x3 +#define PMD_TYPE_FAULT 0 +#define PMD_TYPE_PMD 1 +#define PMD_TYPE_SECTION 2 -/* We need this as printascii.S is including this file */ +#define PTE_TYPE_MASK 0x3 +#define PTE_TYPE_FAULT 0 +#define PTE_TYPE_LARGE 1 +#define PTE_TYPE_SMALL 2 +#define PTE_TYPE_TINY 3 + +/* Permission field offsets */ +#define SECTION_AP0 10 + +/* + * These are indices into arrays with pgd_t or pmd_t sized elements, + * therefore the index must be divided by appropriate element size + */ +#define PGD_INDEX(x) (((((unsigned long)(x)) >> 18) \ + & 0x3FFC) / sizeof(pmd_t)) + +/* + * Strip out the page offset in this + * megabyte from a total of 256 pages. + */ +#define PMD_INDEX(x) (((((unsigned long)(x)) >> 10) \ + & 0x3FC) / sizeof (pte_t)) + + +/* We need this as print-early.S is including this file */ #ifndef __ASSEMBLY__ /* Type-checkable page table elements */ -typedef u32 pgd_t; typedef u32 pmd_t; typedef u32 pte_t; /* Page global directory made up of pgd_t entries */ typedef struct pgd_table { - pgd_t entry[PGD_ENTRY_TOTAL]; + pmd_t entry[PGD_ENTRY_TOTAL]; } pgd_table_t; /* Page middle directory made up of pmd_t entries */ typedef struct pmd_table { - pmd_t entry[PMD_ENTRY_TOTAL]; + pte_t entry[PMD_ENTRY_TOTAL]; } pmd_table_t; /* Applies for both small and large pages */ @@ -79,86 +91,38 @@ typedef struct pmd_table { #define unbufferable 0 /* Helper macros for common cases */ -#define __MAP_USR_RW_FLAGS (cacheable | bufferable | (SVC_RW_USR_RW << PAGE_AP0) \ - | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ - | (SVC_RW_USR_RW << PAGE_AP3)) -#define __MAP_USR_RO_FLAGS (cacheable | bufferable | (SVC_RW_USR_RO << PAGE_AP0) \ - | (SVC_RW_USR_RO << PAGE_AP1) | (SVC_RW_USR_RO << PAGE_AP2) \ - | (SVC_RW_USR_RO << PAGE_AP3)) -#define __MAP_SVC_RW_FLAGS (cacheable | bufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ - | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ - | (SVC_RW_USR_NONE << PAGE_AP3)) -#define __MAP_SVC_IO_FLAGS (uncacheable | unbufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ - | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ - | (SVC_RW_USR_NONE << PAGE_AP3)) -#define __MAP_USR_IO_FLAGS (uncacheable | unbufferable | (SVC_RW_USR_RW << PAGE_AP0) \ - | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ - | (SVC_RW_USR_RW << PAGE_AP3)) +#define __MAP_USR_RW (cacheable | bufferable | (SVC_RW_USR_RW << PAGE_AP0) \ + | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ + | (SVC_RW_USR_RW << PAGE_AP3)) +#define __MAP_USR_RO (cacheable | bufferable | (SVC_RW_USR_RO << PAGE_AP0) \ + | (SVC_RW_USR_RO << PAGE_AP1) | (SVC_RW_USR_RO << PAGE_AP2) \ + | (SVC_RW_USR_RO << PAGE_AP3)) +#define __MAP_KERN_RW (cacheable | bufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ + | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ + | (SVC_RW_USR_NONE << PAGE_AP3)) +#define __MAP_KERN_IO (uncacheable | unbufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ + | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ + | (SVC_RW_USR_NONE << PAGE_AP3)) +#define __MAP_USR_IO (uncacheable | unbufferable | (SVC_RW_USR_RW << PAGE_AP0) \ + | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ + | (SVC_RW_USR_RW << PAGE_AP3)) -/* Abort information */ +/* There is no execute bit in ARMv5, so we ignore it */ +#define __MAP_USR_RWX __MAP_USR_RW +#define __MAP_USR_RX __MAP_USR_RO +#define __MAP_KERN_RWX __MAP_KERN_RW +#define __MAP_KERN_RX __MAP_KERN_RW /* We always have kernel RW */ +#define __MAP_FAULT 0 -/*FIXME: Carry all these definitions to an abort.h, Also carry all abort code to abort.c. Much neater!!! */ - -/* Abort type */ -#define ARM_PABT 1 -#define ARM_DABT 0 -/* The kernel makes use of bit 8 (Always Zero) of FSR to define which type of abort */ -#define set_abort_type(fsr, x) { fsr &= ~(1 << 8); fsr |= ((x & 1) << 8); } -#define ARM_FSR_MASK 0xF -#define is_prefetch_abort(fsr) ((fsr >> 8) & 0x1) -#define is_data_abort(fsr) (!is_prefetch_abort(fsr)) - -/* - * v5 Architecture-defined data abort values for FSR ordered - * in highest to lowest priority. - */ -#define DABT_TERMINAL 0x2 -#define DABT_VECTOR 0x0 /* Obsolete */ -#define DABT_ALIGN 0x1 -#define DABT_EXT_XLATE_LEVEL1 0xC -#define DABT_EXT_XLATE_LEVEL2 0xE -#define DABT_XLATE_SECT 0x5 -#define DABT_XLATE_PAGE 0x7 -#define DABT_DOMAIN_SECT 0x9 -#define DABT_DOMAIN_PAGE 0xB -#define DABT_PERM_SECT 0xD -#define DABT_PERM_PAGE 0xF -#define DABT_EXT_LFETCH_SECT 0x4 -#define DABT_EXT_LFETCH_PAGE 0x6 -#define DABT_EXT_NON_LFETCH_SECT 0x8 -#define DABT_EXT_NON_LFETCH_PAGE 0xA - -#define TASK_PGD(x) (x)->space->pgd - -#define STACK_ALIGNMENT 8 - -/* Kernel's data about the fault */ -typedef struct fault_kdata { - u32 faulty_pc; - u32 fsr; - u32 far; - pte_t pte; -} __attribute__ ((__packed__)) fault_kdata_t; - -void arch_hardware_flush(pgd_table_t *pgd); void add_section_mapping_init(unsigned int paddr, unsigned int vaddr, unsigned int size, unsigned int flags); -void add_boot_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags); - -struct address_space; -int delete_page_tables(struct address_space *space); -int copy_user_tables(struct address_space *new, struct address_space *orig); -pgd_table_t *copy_page_tables(pgd_table_t *from); -void remap_as_pages(void *vstart, void *vend); - -int pgd_count_pmds(pgd_table_t *pgd); -pgd_table_t *realloc_page_tables(void); void remove_section_mapping(unsigned long vaddr); -void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, - unsigned long start, unsigned long end); +extern pgd_table_t init_pgd; + +void arch_update_utcb(unsigned long utcb_address); +void system_identify(void); #endif /* __ASSEMBLY__ */ #endif /* __V5_MM_H__ */ diff --git a/include/l4/arch/arm/v5/mmu_ops.h b/include/l4/arch/arm/v5/mmu_ops.h index f7f0b88..b076c12 100644 --- a/include/l4/arch/arm/v5/mmu_ops.h +++ b/include/l4/arch/arm/v5/mmu_ops.h @@ -18,6 +18,7 @@ void arm_enable_high_vectors(void); void arm_invalidate_cache(void); void arm_invalidate_icache(void); void arm_invalidate_dcache(void); +void arm_clean_dcache(void); void arm_clean_invalidate_dcache(void); void arm_clean_invalidate_cache(void); void arm_drain_writebuffer(void); @@ -31,4 +32,22 @@ static inline void arm_enable_caches(void) arm_enable_dcache(); } + +static inline void dmb(void) +{ + /* This is the closest to its meaning */ + arm_drain_writebuffer(); +} + +static inline void dsb(void) +{ + /* No op */ +} + +static inline void isb(void) +{ + /* No op */ +} + + #endif /* __MMU__OPS__H__ */ diff --git a/include/l4/arch/arm/v5/perfmon.h b/include/l4/arch/arm/v5/perfmon.h new file mode 100644 index 0000000..72757e5 --- /dev/null +++ b/include/l4/arch/arm/v5/perfmon.h @@ -0,0 +1,6 @@ +#ifndef __PERFMON_H__ +#define __PERFMON_H__ + +static inline void perfmon_init(void) { } + +#endif diff --git a/include/l4/arch/arm/v6/abort.h b/include/l4/arch/arm/v6/abort.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include/l4/arch/arm/v6/abort.h @@ -0,0 +1 @@ + diff --git a/include/l4/arch/arm/v6/cpu.h b/include/l4/arch/arm/v6/cpu.h new file mode 100644 index 0000000..90bd1ac --- /dev/null +++ b/include/l4/arch/arm/v6/cpu.h @@ -0,0 +1,43 @@ +/* + * Cpu specific features + * defined upon the base architecture. + * + * Copyright (C) 2010 B Labs Ltd. + * Written by Bahadir Balban + */ + +#ifndef __V6_CPU_H__ +#define __V6_CPU_H__ + +#include INC_SUBARCH(mmu_ops.h) + +#define MPIDR_CPUID_MASK 0x7 + +/* Read multi-processor affinity register */ +static inline unsigned int __attribute__((always_inline)) +cp15_read_mpidr(void) +{ + unsigned int val; + + __asm__ __volatile__ ( + "mrc p15, 0, %0, c0, c0, 5\n" + : "=r" (val) + : + ); + + return val; +} + +static inline int smp_get_cpuid() +{ + volatile u32 mpidr = cp15_read_mpidr(); + + return mpidr & MPIDR_CPUID_MASK; +} + +static inline void cpu_startup(void) +{ + +} + +#endif /* __V6_CPU_H__ */ diff --git a/include/l4/arch/arm/v6/exception.h b/include/l4/arch/arm/v6/exception.h new file mode 100644 index 0000000..f88631e --- /dev/null +++ b/include/l4/arch/arm/v6/exception.h @@ -0,0 +1,33 @@ +/* + * Definitions for exception support on ARMv5 + * + * Copyright (C) 2007 Bahadir Balban + */ +#ifndef __ARCH_V5_EXCEPTION_H__ +#define __ARCH_V5_EXCEPTION_H__ + +#include INC_ARCH(asm.h) + +/* + * v5 Architecture-defined data abort values for FSR ordered + * in highest to lowest priority. + */ +#define DABT_TERMINAL 0x2 +#define DABT_VECTOR 0x0 /* Obsolete */ +#define DABT_ALIGN 0x1 +#define DABT_EXT_XLATE_LEVEL1 0xC +#define DABT_EXT_XLATE_LEVEL2 0xE +#define DABT_XLATE_SECT 0x5 +#define DABT_XLATE_PAGE 0x7 +#define DABT_DOMAIN_SECT 0x9 +#define DABT_DOMAIN_PAGE 0xB +#define DABT_PERM_SECT 0xD +#define DABT_PERM_PAGE 0xF +#define DABT_EXT_LFETCH_SECT 0x4 +#define DABT_EXT_LFETCH_PAGE 0x6 +#define DABT_EXT_NON_LFETCH_SECT 0x8 +#define DABT_EXT_NON_LFETCH_PAGE 0xA + +#define FSR_FS_MASK 0xF + +#endif /* __ARCH_V5_EXCEPTION_H__ */ diff --git a/include/l4/arch/arm/v6/irq.h b/include/l4/arch/arm/v6/irq.h new file mode 100644 index 0000000..7ac31f9 --- /dev/null +++ b/include/l4/arch/arm/v6/irq.h @@ -0,0 +1,26 @@ +#ifndef __ARM_V5_IRQ_H__ +#define __ARM_V5_IRQ_H__ + +static inline void enable_irqs() +{ + __asm__ __volatile__( + "mrs r0, cpsr_fc\n" + "bic r0, r0, #0x80\n" /* ARM_IRQ_BIT */ + "msr cpsr_fc, r0\n" + ); +} + +static inline void disable_irqs() +{ + __asm__ __volatile__( + "mrs r0, cpsr_fc\n" + "orr r0, r0, #0x80\n" /* ARM_IRQ_BIT */ + "msr cpsr_fc, r0\n" + ); +} + +/* Disable the irqs unconditionally, but also keep the previous state such that + * if it was already disabled before the call, the restore call would retain + * this state. */ +void irq_local_disable_save(unsigned long *state); +#endif diff --git a/include/l4/arch/arm/v6/mm.h b/include/l4/arch/arm/v6/mm.h index b03d55d..4df7653 100644 --- a/include/l4/arch/arm/v6/mm.h +++ b/include/l4/arch/arm/v6/mm.h @@ -9,53 +9,65 @@ /* ARM specific definitions */ #define VIRT_MEM_START 0 #define VIRT_MEM_END 0xFFFFFFFF -#define ARM_SECTION_SIZE SZ_1MB -#define ARM_SECTION_MASK (ARM_SECTION_SIZE - 1) -#define ARM_SECTION_BITS 20 +#define SECTION_SIZE SZ_1MB +#define SECTION_MASK (SECTION_SIZE - 1) +#define SECTION_ALIGN_MASK (~SECTION_MASK) +#define SECTION_BITS 20 #define ARM_PAGE_SIZE SZ_4K #define ARM_PAGE_MASK 0xFFF #define ARM_PAGE_BITS 12 #define PGD_SIZE SZ_4K * 4 #define PGD_ENTRY_TOTAL SZ_4K -#define PGD_TYPE_MASK 0x3 -#define PGD_COARSE_ALIGN_MASK 0xFFFFFC00 -#define PGD_SECTION_ALIGN_MASK 0xFFF00000 -#define PGD_FINE_ALIGN_MASK 0xFFFFF000 -#define PGD_TYPE_FAULT 0 -#define PGD_TYPE_COARSE 1 -#define PGD_TYPE_SECTION 2 -#define PGD_TYPE_FINE 3 - -#define PMD_TYPE_MASK 0x3 -#define PMD_TYPE_FAULT 0 -#define PMD_TYPE_LARGE 1 -#define PMD_TYPE_SMALL 2 -#define PMD_TYPE_TINY 3 - -/* Permission field offsets */ -#define SECTION_AP0 10 #define PMD_SIZE SZ_1K #define PMD_ENTRY_TOTAL 256 #define PMD_MAP_SIZE SZ_1MB +#define PMD_ALIGN_MASK (~(PMD_SIZE - 1)) +#define PMD_TYPE_MASK 0x3 +#define PMD_TYPE_FAULT 0 +#define PMD_TYPE_PMD 1 +#define PMD_TYPE_SECTION 2 -/* We need this as printascii.S is including this file */ +#define PTE_TYPE_MASK 0x3 +#define PTE_TYPE_FAULT 0 +#define PTE_TYPE_LARGE 1 +#define PTE_TYPE_SMALL 2 +#define PTE_TYPE_TINY 3 + +/* Permission field offsets */ +#define SECTION_AP0 10 + +/* + * These are indices into arrays with pgd_t or pmd_t sized elements, + * therefore the index must be divided by appropriate element size + */ +#define PGD_INDEX(x) (((((unsigned long)(x)) >> 18) \ + & 0x3FFC) / sizeof(pmd_t)) + +/* + * Strip out the page offset in this + * megabyte from a total of 256 pages. + */ +#define PMD_INDEX(x) (((((unsigned long)(x)) >> 10) \ + & 0x3FC) / sizeof (pte_t)) + + +/* We need this as print-early.S is including this file */ #ifndef __ASSEMBLY__ /* Type-checkable page table elements */ -typedef u32 pgd_t; typedef u32 pmd_t; typedef u32 pte_t; /* Page global directory made up of pgd_t entries */ typedef struct pgd_table { - pgd_t entry[PGD_ENTRY_TOTAL]; + pmd_t entry[PGD_ENTRY_TOTAL]; } pgd_table_t; /* Page middle directory made up of pmd_t entries */ typedef struct pmd_table { - pmd_t entry[PMD_ENTRY_TOTAL]; + pte_t entry[PMD_ENTRY_TOTAL]; } pmd_table_t; /* Applies for both small and large pages */ @@ -79,86 +91,35 @@ typedef struct pmd_table { #define unbufferable 0 /* Helper macros for common cases */ -#define __MAP_USR_RW_FLAGS (cacheable | bufferable | (SVC_RW_USR_RW << PAGE_AP0) \ - | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ - | (SVC_RW_USR_RW << PAGE_AP3)) -#define __MAP_USR_RO_FLAGS (cacheable | bufferable | (SVC_RW_USR_RO << PAGE_AP0) \ - | (SVC_RW_USR_RO << PAGE_AP1) | (SVC_RW_USR_RO << PAGE_AP2) \ - | (SVC_RW_USR_RO << PAGE_AP3)) -#define __MAP_SVC_RW_FLAGS (cacheable | bufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ - | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ - | (SVC_RW_USR_NONE << PAGE_AP3)) -#define __MAP_SVC_IO_FLAGS (uncacheable | unbufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ - | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ - | (SVC_RW_USR_NONE << PAGE_AP3)) -#define __MAP_USR_IO_FLAGS (uncacheable | unbufferable | (SVC_RW_USR_RW << PAGE_AP0) \ - | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ - | (SVC_RW_USR_RW << PAGE_AP3)) +#define __MAP_USR_RW (cacheable | bufferable | (SVC_RW_USR_RW << PAGE_AP0) \ + | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ + | (SVC_RW_USR_RW << PAGE_AP3)) +#define __MAP_USR_RO (cacheable | bufferable | (SVC_RW_USR_RO << PAGE_AP0) \ + | (SVC_RW_USR_RO << PAGE_AP1) | (SVC_RW_USR_RO << PAGE_AP2) \ + | (SVC_RW_USR_RO << PAGE_AP3)) +#define __MAP_KERN_RW (cacheable | bufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ + | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ + | (SVC_RW_USR_NONE << PAGE_AP3)) +#define __MAP_KERN_IO (uncacheable | unbufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ + | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ + | (SVC_RW_USR_NONE << PAGE_AP3)) +#define __MAP_USR_IO (uncacheable | unbufferable | (SVC_RW_USR_RW << PAGE_AP0) \ + | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ + | (SVC_RW_USR_RW << PAGE_AP3)) -/* Abort information */ +/* There is no execute bit in ARMv5, so we ignore it */ +#define __MAP_USR_RWX __MAP_USR_RW +#define __MAP_USR_RX __MAP_USR_RO +#define __MAP_KERN_RWX __MAP_KERN_RW +#define __MAP_KERN_RX __MAP_KERN_RW /* We always have kernel RW */ +#define __MAP_FAULT 0 -/*FIXME: Carry all these definitions to an abort.h, Also carry all abort code to abort.c. Much neater!!! */ - -/* Abort type */ -#define ARM_PABT 1 -#define ARM_DABT 0 -/* The kernel makes use of bit 8 (Always Zero) of FSR to define which type of abort */ -#define set_abort_type(fsr, x) { fsr &= ~(1 << 8); fsr |= ((x & 1) << 8); } -#define ARM_FSR_MASK 0xF -#define is_prefetch_abort(fsr) ((fsr >> 8) & 0x1) -#define is_data_abort(fsr) (!is_prefetch_abort(fsr)) - -/* - * v5 Architecture-defined data abort values for FSR ordered - * in highest to lowest priority. - */ -#define DABT_TERMINAL 0x2 -#define DABT_VECTOR 0x0 /* Obsolete */ -#define DABT_ALIGN 0x1 -#define DABT_EXT_XLATE_LEVEL1 0xC -#define DABT_EXT_XLATE_LEVEL2 0xE -#define DABT_XLATE_SECT 0x5 -#define DABT_XLATE_PAGE 0x7 -#define DABT_DOMAIN_SECT 0x9 -#define DABT_DOMAIN_PAGE 0xB -#define DABT_PERM_SECT 0xD -#define DABT_PERM_PAGE 0xF -#define DABT_EXT_LFETCH_SECT 0x4 -#define DABT_EXT_LFETCH_PAGE 0x6 -#define DABT_EXT_NON_LFETCH_SECT 0x8 -#define DABT_EXT_NON_LFETCH_PAGE 0xA - -#define TASK_PGD(x) (x)->space->pgd - -#define STACK_ALIGNMENT 8 - -/* Kernel's data about the fault */ -typedef struct fault_kdata { - u32 faulty_pc; - u32 fsr; - u32 far; - pte_t pte; -} __attribute__ ((__packed__)) fault_kdata_t; - -void arch_hardware_flush(pgd_table_t *pgd); void add_section_mapping_init(unsigned int paddr, unsigned int vaddr, unsigned int size, unsigned int flags); -void add_boot_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags); - -struct address_space; -int delete_page_tables(struct address_space *space); -int copy_user_tables(struct address_space *new, struct address_space *orig); -pgd_table_t *copy_page_tables(pgd_table_t *from); -void remap_as_pages(void *vstart, void *vend); - -int pgd_count_pmds(pgd_table_t *pgd); -pgd_table_t *realloc_page_tables(void); void remove_section_mapping(unsigned long vaddr); -void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, - unsigned long start, unsigned long end); +extern pgd_table_t init_pgd; -#endif /* __ASSEMBLY__*/ +#endif /* __ASSEMBLY__ */ #endif /* __V5_MM_H__ */ diff --git a/include/l4/arch/arm/v6/mmu_ops.h b/include/l4/arch/arm/v6/mmu_ops.h index f7f0b88..0472ff4 100644 --- a/include/l4/arch/arm/v6/mmu_ops.h +++ b/include/l4/arch/arm/v6/mmu_ops.h @@ -6,7 +6,6 @@ * Copyright (C) 2005 Bahadir Balban * */ - void arm_set_ttb(unsigned int); void arm_set_domain(unsigned int); unsigned int arm_get_domain(void); @@ -18,6 +17,7 @@ void arm_enable_high_vectors(void); void arm_invalidate_cache(void); void arm_invalidate_icache(void); void arm_invalidate_dcache(void); +void arm_clean_dcache(void); void arm_clean_invalidate_dcache(void); void arm_clean_invalidate_cache(void); void arm_drain_writebuffer(void); @@ -31,4 +31,22 @@ static inline void arm_enable_caches(void) arm_enable_dcache(); } + +static inline void dmb(void) +{ + /* This is the closest to its meaning */ + arm_drain_writebuffer(); +} + +static inline void dsb(void) +{ + /* No op */ +} + +static inline void isb(void) +{ + /* No op */ +} + + #endif /* __MMU__OPS__H__ */ diff --git a/include/l4/arch/arm/v7/cortexa8/cpu.h b/include/l4/arch/arm/v7/cortexa8/cpu.h deleted file mode 100644 index 2d11b60..0000000 --- a/include/l4/arch/arm/v7/cortexa8/cpu.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * - * Copyright (C) 2005 Bahadir Balban - * - */ -#ifndef __ARM926EJS__H__ -#define __ARM926EJS__H__ - - - - - -#endif /* __ARM926EJS__H__ */ diff --git a/include/l4/arch/arm/v7/mm.h b/include/l4/arch/arm/v7/mm.h deleted file mode 100644 index b03d55d..0000000 --- a/include/l4/arch/arm/v7/mm.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * ARM v5-specific virtual memory details - * - * Copyright (C) 2007 Bahadir Balban - */ -#ifndef __V5_MM_H__ -#define __V5_MM_H__ - -/* ARM specific definitions */ -#define VIRT_MEM_START 0 -#define VIRT_MEM_END 0xFFFFFFFF -#define ARM_SECTION_SIZE SZ_1MB -#define ARM_SECTION_MASK (ARM_SECTION_SIZE - 1) -#define ARM_SECTION_BITS 20 -#define ARM_PAGE_SIZE SZ_4K -#define ARM_PAGE_MASK 0xFFF -#define ARM_PAGE_BITS 12 - -#define PGD_SIZE SZ_4K * 4 -#define PGD_ENTRY_TOTAL SZ_4K -#define PGD_TYPE_MASK 0x3 -#define PGD_COARSE_ALIGN_MASK 0xFFFFFC00 -#define PGD_SECTION_ALIGN_MASK 0xFFF00000 -#define PGD_FINE_ALIGN_MASK 0xFFFFF000 -#define PGD_TYPE_FAULT 0 -#define PGD_TYPE_COARSE 1 -#define PGD_TYPE_SECTION 2 -#define PGD_TYPE_FINE 3 - -#define PMD_TYPE_MASK 0x3 -#define PMD_TYPE_FAULT 0 -#define PMD_TYPE_LARGE 1 -#define PMD_TYPE_SMALL 2 -#define PMD_TYPE_TINY 3 - -/* Permission field offsets */ -#define SECTION_AP0 10 - -#define PMD_SIZE SZ_1K -#define PMD_ENTRY_TOTAL 256 -#define PMD_MAP_SIZE SZ_1MB - -/* We need this as printascii.S is including this file */ -#ifndef __ASSEMBLY__ - -/* Type-checkable page table elements */ -typedef u32 pgd_t; -typedef u32 pmd_t; -typedef u32 pte_t; - -/* Page global directory made up of pgd_t entries */ -typedef struct pgd_table { - pgd_t entry[PGD_ENTRY_TOTAL]; -} pgd_table_t; - -/* Page middle directory made up of pmd_t entries */ -typedef struct pmd_table { - pmd_t entry[PMD_ENTRY_TOTAL]; -} pmd_table_t; - -/* Applies for both small and large pages */ -#define PAGE_AP0 4 -#define PAGE_AP1 6 -#define PAGE_AP2 8 -#define PAGE_AP3 10 - -/* Permission values with rom and sys bits ignored */ -#define SVC_RW_USR_NONE 1 -#define SVC_RW_USR_RO 2 -#define SVC_RW_USR_RW 3 - -#define PTE_PROT_MASK (0xFF << 4) - -#define CACHEABILITY 3 -#define BUFFERABILITY 2 -#define cacheable (1 << CACHEABILITY) -#define bufferable (1 << BUFFERABILITY) -#define uncacheable 0 -#define unbufferable 0 - -/* Helper macros for common cases */ -#define __MAP_USR_RW_FLAGS (cacheable | bufferable | (SVC_RW_USR_RW << PAGE_AP0) \ - | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ - | (SVC_RW_USR_RW << PAGE_AP3)) -#define __MAP_USR_RO_FLAGS (cacheable | bufferable | (SVC_RW_USR_RO << PAGE_AP0) \ - | (SVC_RW_USR_RO << PAGE_AP1) | (SVC_RW_USR_RO << PAGE_AP2) \ - | (SVC_RW_USR_RO << PAGE_AP3)) -#define __MAP_SVC_RW_FLAGS (cacheable | bufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ - | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ - | (SVC_RW_USR_NONE << PAGE_AP3)) -#define __MAP_SVC_IO_FLAGS (uncacheable | unbufferable | (SVC_RW_USR_NONE << PAGE_AP0) \ - | (SVC_RW_USR_NONE << PAGE_AP1) | (SVC_RW_USR_NONE << PAGE_AP2) \ - | (SVC_RW_USR_NONE << PAGE_AP3)) -#define __MAP_USR_IO_FLAGS (uncacheable | unbufferable | (SVC_RW_USR_RW << PAGE_AP0) \ - | (SVC_RW_USR_RW << PAGE_AP1) | (SVC_RW_USR_RW << PAGE_AP2) \ - | (SVC_RW_USR_RW << PAGE_AP3)) - -/* Abort information */ - -/*FIXME: Carry all these definitions to an abort.h, Also carry all abort code to abort.c. Much neater!!! */ - -/* Abort type */ -#define ARM_PABT 1 -#define ARM_DABT 0 -/* The kernel makes use of bit 8 (Always Zero) of FSR to define which type of abort */ -#define set_abort_type(fsr, x) { fsr &= ~(1 << 8); fsr |= ((x & 1) << 8); } -#define ARM_FSR_MASK 0xF -#define is_prefetch_abort(fsr) ((fsr >> 8) & 0x1) -#define is_data_abort(fsr) (!is_prefetch_abort(fsr)) - -/* - * v5 Architecture-defined data abort values for FSR ordered - * in highest to lowest priority. - */ -#define DABT_TERMINAL 0x2 -#define DABT_VECTOR 0x0 /* Obsolete */ -#define DABT_ALIGN 0x1 -#define DABT_EXT_XLATE_LEVEL1 0xC -#define DABT_EXT_XLATE_LEVEL2 0xE -#define DABT_XLATE_SECT 0x5 -#define DABT_XLATE_PAGE 0x7 -#define DABT_DOMAIN_SECT 0x9 -#define DABT_DOMAIN_PAGE 0xB -#define DABT_PERM_SECT 0xD -#define DABT_PERM_PAGE 0xF -#define DABT_EXT_LFETCH_SECT 0x4 -#define DABT_EXT_LFETCH_PAGE 0x6 -#define DABT_EXT_NON_LFETCH_SECT 0x8 -#define DABT_EXT_NON_LFETCH_PAGE 0xA - -#define TASK_PGD(x) (x)->space->pgd - -#define STACK_ALIGNMENT 8 - -/* Kernel's data about the fault */ -typedef struct fault_kdata { - u32 faulty_pc; - u32 fsr; - u32 far; - pte_t pte; -} __attribute__ ((__packed__)) fault_kdata_t; - -void arch_hardware_flush(pgd_table_t *pgd); -void add_section_mapping_init(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags); - -void add_boot_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags); - -struct address_space; -int delete_page_tables(struct address_space *space); -int copy_user_tables(struct address_space *new, struct address_space *orig); -pgd_table_t *copy_page_tables(pgd_table_t *from); -void remap_as_pages(void *vstart, void *vend); - -int pgd_count_pmds(pgd_table_t *pgd); -pgd_table_t *realloc_page_tables(void); -void remove_section_mapping(unsigned long vaddr); - -void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, - unsigned long start, unsigned long end); - -#endif /* __ASSEMBLY__*/ -#endif /* __V5_MM_H__ */ diff --git a/include/l4/arch/arm/v7/mmu_ops.h b/include/l4/arch/arm/v7/mmu_ops.h deleted file mode 100644 index f7f0b88..0000000 --- a/include/l4/arch/arm/v7/mmu_ops.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __MMU__OPS__H__ -#define __MMU__OPS__H__ -/* - * Prototypes for low level mmu operations - * - * Copyright (C) 2005 Bahadir Balban - * - */ - -void arm_set_ttb(unsigned int); -void arm_set_domain(unsigned int); -unsigned int arm_get_domain(void); -void arm_enable_mmu(void); -void arm_enable_icache(void); -void arm_enable_dcache(void); -void arm_enable_wbuffer(void); -void arm_enable_high_vectors(void); -void arm_invalidate_cache(void); -void arm_invalidate_icache(void); -void arm_invalidate_dcache(void); -void arm_clean_invalidate_dcache(void); -void arm_clean_invalidate_cache(void); -void arm_drain_writebuffer(void); -void arm_invalidate_tlb(void); -void arm_invalidate_itlb(void); -void arm_invalidate_dtlb(void); - -static inline void arm_enable_caches(void) -{ - arm_enable_icache(); - arm_enable_dcache(); -} - -#endif /* __MMU__OPS__H__ */ diff --git a/include/l4/drivers/irq/gic/gic.h b/include/l4/drivers/irq/gic/gic.h index 9ae7286..d51cb9f 100644 --- a/include/l4/drivers/irq/gic/gic.h +++ b/include/l4/drivers/irq/gic/gic.h @@ -1,35 +1,91 @@ /* * Generic Interrupt Controller offsets * - * Copyright (C) 2007 Bahadir Balban + * Copyright (C) 2009 B Labs Ltd. * */ #ifndef __ARM_GIC_H__ #define __ARM_GIC_H__ +#include #include INC_PLAT(platform.h) +#include INC_PLAT(offsets.h) -/* GIC CPU register offsets */ -#define ARM_GIC_CPU_IC 0x00 /* Interface Control */ -#define ARM_GIC_CPUPM 0x04 /* Interrupt Priority Mask */ -#define ARM_GIC_CPU_BP 0x08 /* Binary Point */ -#define ARM_GIC_CPU_IA 0x0c /* Interrupt Acknowledge */ -#define ARM_GIC_CPU_EOI 0x10 /* End of Interrupt */ -#define ARM_GIC_CPU_RPI 0x14 /* Running Priority */ -#define ARM_GIC_CPU_HPI 0x18 /* Highest Priority Interrupt*/ +/* CPU registers */ +struct gic_cpu +{ + u32 control; /* Control Register */ + u32 prio_mask; /* Priority Mask */ + u32 bin_point; /* Binary Point Register */ + u32 ack; /* Interrupt */ + u32 eoi; /* End of Interrupt */ + u32 running; /* Running Priority register */ + u32 high_pending; /* Highest Pending Register */ +}; -/* Distributor register map */ -#define ARM_GIC_DIST_CNTRL 0x000 /* Control Register */ -#define ARM_GIC_DIST_ICT 0x004 /* Interface Controller Type */ -#define ARM_GIC_DIST_ISE 0x100 /* Interrupt Set Enable */ -#define ARM_GIC_DIST_ICE 0x180 /* Interrupt Clear Enable */ -#define ARM_GIC_DIST_ISP 0x200 /* Interrupt Set Pending */ -#define ARM_GIC_DIST_ICP 0x280 /* Interrupt Clear Pending*/ -#define ARM_GIC_DIST_AB 0x300 /* Active Bit */ -#define ARM_GIC_DIST_IP 0x400 /* Interrupt Priority */ -#define ARM_GIC_DIST_IPT 0x800 /* Interrupt Processor Target */ -#define ARM_GIC_DIST_IC 0xc00 /* Interrupt Configuration */ -#define ARM_GIC_DIST_SGI 0xf00 /* Software Generated Interrupt */ +#define NIRQ 1024 +#define NREGS_1_BIT_PER_INT 32 /* when 1 bit per interrupt */ +#define NREGS_4_BIT_PER_INT 256 +#define NREGS_4_BIT_PER_INT 256 +#define NREGS_2_BIT_PER_INT 64 +#define NID 4 -#endif /* __ARM_GIC_H__ */ +/* Distributor registers */ +/* -r- -- reserved */ +struct gic_dist{ + u32 control; /* Control Register */ + u32 const type; /* Type Register */ + u32 dummy1[62]; /* -r- */ + u32 set_en[NREGS_1_BIT_PER_INT]; /* Enable Set */ + u32 clr_en[NREGS_1_BIT_PER_INT]; /* Enable Clear */ + u32 set_pending[NREGS_1_BIT_PER_INT]; /* Set Pending */ + u32 clr_pending[NREGS_1_BIT_PER_INT]; /* Clear Pending */ + u32 active[NREGS_1_BIT_PER_INT]; /* Active Bit registers */ + u32 dummy2[32]; /* -r- */ + u32 priority[NREGS_4_BIT_PER_INT]; /* Interrupt Priority */ + u32 target[NREGS_4_BIT_PER_INT]; /* CPU Target Registers */ + u32 config[NREGS_2_BIT_PER_INT]; /* Interrupt Config */ + u32 level[NREGS_2_BIT_PER_INT]; /* Interrupt Line Level */ + u32 dummy3[64]; /* -r- */ + u32 soft_int; /* Software Interrupts */ + u32 dummy4[55]; /* -r- */ + u32 id[NID]; /* Primecell ID registers */ +}; + + +struct gic_data { + struct gic_cpu *cpu; + struct gic_dist *dist; +}; + + +l4id_t gic_read_irq(void *data); + +void gic_mask_irq(l4id_t irq); + +void gic_unmask_irq(l4id_t irq); + +void gic_ack_irq(l4id_t irq); + +void gic_ack_and_mask(l4id_t irq); + +void gic_clear_pending(l4id_t irq); + +void gic_cpu_init(int idx, unsigned long base); + +void gic_dist_init(int idx, unsigned long base); + +void gic_send_ipi(int cpu, int ipi_cmd); + +void gic_set_target(u32 irq, u32 cpu); + +u32 gic_get_target(u32 irq); + +void gic_set_priority(u32 irq, u32 prio); + +u32 gic_get_priority(u32 irq); + +void gic_dummy_init(void); + +#endif /* __GIC_H__ */ diff --git a/include/l4/drivers/irq/omap3/omap3_intc.h b/include/l4/drivers/irq/omap3/omap3_intc.h new file mode 100644 index 0000000..c9930a8 --- /dev/null +++ b/include/l4/drivers/irq/omap3/omap3_intc.h @@ -0,0 +1,73 @@ +/* + * OMAP3XXX Interrupt Controller Defines + * + * Copyright 2010 B Labs Ltd. + */ +#ifndef __OMAP3_INTC_H__ +#define __OMAP3_INTC_H__ + +#include INC_ARCH(io.h) + +#define OMAP3_INTC_SYSCONFIG (0x00000010) /* RW */ +#define OMAP3_INTC_SYSSTATUS (0x00000014) /* RO */ + +#define OMAP3_INTC_SIR_IRQ (0x00000040) /* RO */ +#define OMAP3_INTC_SIR_FIQ (0x00000044) /* RO */ +#define OMAP3_INTC_CONTROL (0x00000048) /* RW */ +#define OMAP3_INTC_PROT (0x0000004C) /* RW - Protection */ +#define OMAP3_INTC_IDLE (0x00000050) /* RW */ + +#define OMAP3_INTC_IRQ_PRIO (0x00000060) /* RW - IRQ Priority */ +#define OMAP3_INTC_FIQ_PRIO (0x00000064) /* RW - FIQ Priority */ +#define OMAP3_INTC_THREASHOLD (0x00000068) /* RW */ + +#define OMAP3_INTC_ITR (0x00000080) /* RO - Raw Interrupt Status*/ +#define OMAP3_INTC_MIR (0x00000084) /* RW - Masked Int Status */ +#define OMAP3_INTC_MIR_CLR (0x00000088) /* WO - Clear Mask*/ +#define OMAP3_INTC_MIR_SET (0x0000008C) /* WO - Set Mask*/ +#define OMAP3_INTC_ISR_SET (0x00000090) /* RW - Software Int Set */ +#define OMAP3_INTC_ISR_CLR (0x00000094) /* WO */ +#define OMAP3_INTC_IRQ_PEND (0x00000098) /* RO */ +#define OMAP3_INTC_FIQ_PEND (0x0000009C) /* RO */ +#define OMAP3_INTC_ILR (0x00000100) /* RW */ + +/* Reset Bits */ +#define OMAP_INTC_SOFTRESET (1 << 1) + +static inline unsigned int omap3_intc_get_ilr(unsigned long base, + unsigned int irq) +{ + return read((base + OMAP3_INTC_ILR + (irq * 4))); +} + +static inline void omap3_intc_set_ilr(unsigned long base, unsigned int irq, + unsigned int val) +{ + write(val, (base + OMAP3_INTC_ILR + (irq * 4))); +} + +/* Set clear Interrupt masks */ +static inline +void omap3_intc_set_irq_status(unsigned long base, unsigned int reg, + unsigned int irq) +{ + unsigned int val = 0; + unsigned int offset = (irq >> 5); /* Same as dividing by 32 */ + + irq -= (offset * 32); + + val = read((base + reg + (0x20 * offset))); + val |= (1 << irq); + write(val, (base + reg + (0x20 * offset))); +} + +void omap3_intc_reset(unsigned long base); +void omap3_intc_init(void); +void omap3_intc_eoi_irq(l4id_t irq); +void omap3_intc_mask_irq(l4id_t irq); +void omap3_intc_unmask_irq(l4id_t irq); +void omap3_intc_ack_irq(l4id_t irq); +void omap3_intc_ack_and_mask(l4id_t irq); +l4id_t omap3_intc_read_irq(void *data); + +#endif /* !__OMAP3_INTC_H__ */ diff --git a/include/l4/drivers/irq/pl190/pl190_vic.h b/include/l4/drivers/irq/pl190/pl190_vic.h index 77c7f3b..b859b91 100644 --- a/include/l4/drivers/irq/pl190/pl190_vic.h +++ b/include/l4/drivers/irq/pl190/pl190_vic.h @@ -10,9 +10,10 @@ #include INC_PLAT(platform.h) #include INC_ARCH(types.h) +#include INC_ARCH(io.h) -#define PL190_BASE PLATFORM_IRQCTRL0_VIRTUAL -#define PL190_SIC_BASE PLATFORM_IRQCTRL1_VIRTUAL +#define PL190_BASE PLATFORM_IRQCTRL0_VBASE +#define PL190_SIC_BASE PLATFORM_IRQCTRL1_VBASE #define PL190_IRQS_MAX 32 @@ -49,9 +50,9 @@ void pl190_vic_init(void); void pl190_ack_irq(l4id_t irq); void pl190_mask_irq(l4id_t irq); void pl190_unmask_irq(l4id_t irq); -l4id_t pl190_read_irq(void); +l4id_t pl190_read_irq(void *irq_chip_data); -l4id_t pl190_sic_read_irq(void); +l4id_t pl190_sic_read_irq(void *irq_chip_data); void pl190_sic_mask_irq(l4id_t irq); void pl190_sic_mask_irq(l4id_t irq); void pl190_sic_ack_irq(l4id_t irq); diff --git a/include/l4/drivers/timer/omap/timer.h b/include/l4/drivers/timer/omap/timer.h new file mode 100644 index 0000000..b9ced10 --- /dev/null +++ b/include/l4/drivers/timer/omap/timer.h @@ -0,0 +1,52 @@ +/* + * OMAP GP Timer offsets + * + * Copyright (C) 2007 Bahadir Balban + * + */ +#ifndef __OMAP_GPTIMER_H__ +#define __OMAP_GPTIMER_H__ + +/* Register offsets */ +#define OMAP_TIMER_TIOCP 0x10 +#define OMAP_TIMER_TSTAT 0x14 +#define OMAP_TIMER_TISR 0x18 +#define OMAP_TIMER_TIER 0x1C +#define OMAP_TIMER_TCLR 0x24 +#define OMAP_TIMER_TCRR 0x28 +#define OMAP_TIMER_TLDR 0x2C +#define OMAP_TIMER_TMAR 0x38 +#define OMAP_TIMER_TPIR 0x48 +#define OMAP_TIMER_TNIR 0x4C +#define OMAP_TIMER_TCVR 0x50 + +/* Enable/Disable IRQ */ +#define OMAP_TIMER_IRQENABLE 1 +#define OMAP_TIMER_IRQDISABLE 0 + +/* Timer modes supported */ +#define OMAP_TIMER_MODE_AUTORELAOD 1 +#define OMAP_TIMER_MODE_COMPARE 6 +#define OMAP_TIMER_MODE_CAPTURE 13 + +/* Interrupt types */ +#define OMAP_TIMER_INTR_MATCH 0x0 +#define OMAP_TIMER_INTR_OVERFLOW 0x1 +#define OMAP_TIMER_INTR_CAPTURE 0x2 + +/* Clock source for timer */ +#define OMAP_TIMER_CLKSRC_SYS_CLK 0x1 +#define OMAP_TIMER_CLKSRC_32KHZ_CLK 0x0 + +void timer_init_oneshot(unsigned long timer_base); +u32 timer_periodic_intr_status(unsigned long timer_base); +void timer_reset(unsigned long timer_base); +void timer_load(unsigned long timer_base, u32 value); +u32 timer_read(unsigned long timer_base); +void timer_start(unsigned long timer_base); +void timer_stop(unsigned long timer_base); +void timer_init_periodic(unsigned long timer_base); +void timer_irq_clear(unsigned long timer_base); +void timer_init(unsigned long timer_base); + +#endif /* __OMAP_GPTIMER_H__*/ diff --git a/include/l4/drivers/timer/sp804/timer.h b/include/l4/drivers/timer/sp804/timer.h new file mode 100644 index 0000000..90edf27 --- /dev/null +++ b/include/l4/drivers/timer/sp804/timer.h @@ -0,0 +1,46 @@ +/* + * SP804 Primecell Timer offsets + * + * Copyright (C) 2007 Bahadir Balban + * + */ +#ifndef __SP804_TIMER_H__ +#define __SP804_TIMER_H__ + +#include INC_ARCH(io.h) + +/* Register offsets */ +#define SP804_LOAD 0x0 +#define SP804_VALUE 0x4 +#define SP804_CTRL 0x8 +#define SP804_INTCLR 0xC +#define SP804_RIS 0x10 +#define SP804_MIS 0x14 +#define SP804_BGLOAD 0x18 + +#define SP804_ENABLE (1 << 7) +#define SP804_PERIODIC (1 << 6) +#define SP804_IRQEN (1 << 5) +#define SP804_32BIT (1 << 1) +#define SP804_ONESHOT (1 << 0) + +#define SP804_SECONDARY_OFFSET 0x20 + +/* Timer prescaling */ +#define SP804_SCALE_SHIFT 2 +#define SP804_SCALE_DIV16 1 +#define SP804_SCALE_DIV256 2 + +/* Wrapping = 0, Oneshot = 1 */ +#define SP804_ONESHOT (1 << 0) + +unsigned long timer_secondary_base(unsigned long timer_base); +void timer_irq_clear(unsigned long timer_base); +void timer_start(unsigned long timer_base); +void timer_load(u32 loadval, unsigned long timer_base); +u32 timer_read(unsigned long timer_base); +void timer_stop(unsigned long timer_base); +void timer_init_periodic(unsigned long timer_base, unsigned int load_value); +void timer_init_oneshot(unsigned long timer_base); +void timer_init(unsigned long timer_base, unsigned int load_value); +#endif /* __SP804_TIMER_H__ */ diff --git a/include/l4/drivers/uart/omap/uart.h b/include/l4/drivers/uart/omap/uart.h new file mode 100644 index 0000000..ac87a04 --- /dev/null +++ b/include/l4/drivers/uart/omap/uart.h @@ -0,0 +1,62 @@ +/* + * OMAP UART Generic driver implementation. + * + * Copyright (C) 2007 Bahadir Balban + * + * The particular intention of this code is that it has been carefully written + * as decoupled from os-specific code and in a verbose way such that it clearly + * demonstrates how the device operates, reducing the amount of time to be spent + * for understanding the operational model and implementing a driver from + * scratch. This is the very first to be such a driver so far, hopefully it will + * turn out to be useful. + */ + +#ifndef __OMAP_UART_H__ +#define __OMAP_UART_H__ + +#include INC_PLAT(uart.h) +#include INC_ARCH(io.h) + +/* Register offsets */ +#define OMAP_UART_DLL 0x00 +#define OMAP_UART_THR 0x00 +#define OMAP_UART_RHR 0x00 +#define OMAP_UART_DLH 0x04 +#define OMAP_UART_IER 0x04 +#define OMAP_UART_FCR 0x08 +#define OMAP_UART_MCR 0x10 +#define OMAP_UART_LSR 0x14 +#define OMAP_UART_MDR1 0x20 +#define OMAP_UART_LCR 0x0C + +/* Modes supported by OMAP UART/IRDA/CIR IP */ +#define OMAP_UART_MODE_UART16X 0x0 +#define OMAP_UART_MODE_SIR 0x1 +#define OMAP_UART_MODE_UART16X_AUTO_BAUD 0x2 +#define OMAP_UART_MODE_UART13X 0x3 +#define OMAP_UART_MODE_MIR 0x4 +#define OMAP_UART_MODE_FIR 0x5 +#define OMAP_UART_MODE_CIR 0x6 +#define OMAP_UART_MODE_DEFAULT 0x7 /* Disable */ + +/* Number of data bits for UART */ +#define OMAP_UART_DATA_BITS_5 0x0 +#define OMAP_UART_DATA_BITS_6 0x1 +#define OMAP_UART_DATA_BITS_7 0x2 +#define OMAP_UART_DATA_BITS_8 0x3 + +/* Stop bits to be used for UART data */ +#define OMAP_UART_STOP_BITS_1 0x0 +#define OMAP_UART_STOP_BITS_1_5 0x1 + +/* Banked Register modes- ConfigA, ConfigB, Operational */ +#define OMAP_UART_BANKED_MODE_OPERATIONAL 0x00 +#define OMAP_UART_BANKED_MODE_CONFIG_A 0x80 +#define OMAP_UART_BANKED_MODE_CONFIG_B 0xBF + +void uart_tx_char(unsigned long base, char c); +char uart_rx_char(unsigned long uart_base); +void uart_set_baudrate(unsigned long uart_base, u32 baudrate, u32 clkrate); +void uart_init(unsigned long uart_base); + +#endif /* __OMAP_UART_H__ */ diff --git a/include/l4/drivers/uart/pl011/uart.h b/include/l4/drivers/uart/pl011/uart.h new file mode 100644 index 0000000..93cdedc --- /dev/null +++ b/include/l4/drivers/uart/pl011/uart.h @@ -0,0 +1,35 @@ +/* + * PL011 UART Generic driver implementation. + * Copyright Bahadir Balban (C) 2009 + */ +#ifndef __PL011_H__ +#define __PL011_H__ + +#include INC_ARCH(io.h) +#include INC_PLAT(offsets.h) + +/* Register offsets */ +#define PL011_UARTDR 0x00 +#define PL011_UARTRSR 0x04 +#define PL011_UARTECR 0x04 +#define PL011_UARTFR 0x18 +#define PL011_UARTILPR 0x20 +#define PL011_UARTIBRD 0x24 +#define PL011_UARTFBRD 0x28 +#define PL011_UARTLCR_H 0x2C +#define PL011_UARTCR 0x30 +#define PL011_UARTIFLS 0x34 +#define PL011_UARTIMSC 0x38 +#define PL011_UARTRIS 0x3C +#define PL011_UARTMIS 0x40 +#define PL011_UARTICR 0x44 +#define PL011_UARTDMACR 0x48 + + +void uart_tx_char(unsigned long uart_base, char c); +char uart_rx_char(unsigned long uart_base); +void uart_init(unsigned long base); + + +#endif /* __PL011__UART__ */ + diff --git a/include/l4/generic/bootmem.h b/include/l4/generic/bootmem.h index 0cb9413..d594fbb 100644 --- a/include/l4/generic/bootmem.h +++ b/include/l4/generic/bootmem.h @@ -9,6 +9,4 @@ unsigned long bootmem_free_pages(void); void *alloc_bootmem(int size, int alignment); pmd_table_t *alloc_boot_pmd(void); -extern pgd_table_t init_pgd; - #endif /* __BOOTMEM_H__ */ diff --git a/include/l4/generic/cap-types.h b/include/l4/generic/cap-types.h index e301450..fb50cf2 100644 --- a/include/l4/generic/cap-types.h +++ b/include/l4/generic/cap-types.h @@ -46,7 +46,6 @@ */ #define CAP_DEVTYPE_TIMER 1 #define CAP_DEVTYPE_UART 2 -#define CAP_DEVTYPE_CLCD 3 #define CAP_DEVTYPE_OTHER 0xF #define CAP_DEVTYPE_MASK 0xFFFF #define CAP_DEVNUM_MASK 0xFFFF0000 @@ -102,14 +101,23 @@ #define CAP_MAP_UNMAP (1 << 5) #define CAP_MAP_UTCB (1 << 6) +/* Cache operations, applicable to (virtual) memory regions */ +#define CAP_CACHE_INVALIDATE (1 << 7) +#define CAP_CACHE_CLEAN (1 << 8) + /* * IRQ Control capability - * + */ +#define CAP_IRQCTRL_WAIT (1 << 8) + +/* * This is a common one and it applies to both * CAP_TYPE_IRQCTRL and CAP_TYPE_MAP_PHYSMEM */ #define CAP_IRQCTRL_REGISTER (1 << 7) + + /* Ipc capability */ #define CAP_IPC_SEND (1 << 0) #define CAP_IPC_RECV (1 << 1) @@ -132,4 +140,6 @@ #define CAP_CAP_DESTROY (1 << 6) #define CAP_CAP_MODIFY (CAP_CAP_DEDUCE | CAP_CAP_SPLIT \ | CAP_CAP_DESTROY) + + #endif /* __CAP_TYPES_H__ */ diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index e11a0bc..9f9bc41 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -55,7 +55,12 @@ static inline void cap_list_remove(struct capability *cap, static inline struct capability * cap_list_detach(struct cap_list *clist) { - struct link *list = list_detach(&clist->caps); + struct link *list; + + if (!clist->ncaps) + return 0; + + list = list_detach(&clist->caps); clist->ncaps = 0; return link_to_struct(list, struct capability, list); } @@ -75,6 +80,9 @@ static inline void cap_list_attach(struct capability *cap, static inline void cap_list_move(struct cap_list *to, struct cap_list *from) { + if (!from->ncaps) + return; + struct capability *cap_head = cap_list_detach(from); cap_list_attach(cap_head, to); } @@ -96,6 +104,8 @@ struct capability *cap_find_by_capid(l4id_t capid, struct cap_list **clist); /* Capability checking on system calls */ int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt, unsigned long npages, unsigned int flags); +int cap_unmap_check(struct ktcb *task, unsigned long virt, + unsigned long npages); int cap_thread_check(struct ktcb *task, unsigned int flags, struct task_ids *ids); int cap_exregs_check(struct ktcb *task, struct exregs_data *exregs); @@ -106,5 +116,7 @@ int cap_mutex_check(unsigned long mutex_address, int mutex_op); int cap_irq_check(struct ktcb *registrant, unsigned int req, unsigned int flags, l4id_t irq); +int cap_cache_check(unsigned long start, unsigned long end, + unsigned int flags); #endif /* __GENERIC_CAPABILITY_H__ */ diff --git a/include/l4/generic/container.h b/include/l4/generic/container.h index e192acb..b28e99f 100644 --- a/include/l4/generic/container.h +++ b/include/l4/generic/container.h @@ -106,8 +106,7 @@ void kres_insert_container(struct container *c, struct container *container_create(void); -int container_init_pagers(struct kernel_resources *kres, - pgd_table_t *current_pgd); +int container_init_pagers(struct kernel_resources *kres); int init_containers(struct kernel_resources *kres); struct container *container_find(struct kernel_resources *kres, l4id_t cid); diff --git a/include/l4/generic/debug.h b/include/l4/generic/debug.h new file mode 100644 index 0000000..c581130 --- /dev/null +++ b/include/l4/generic/debug.h @@ -0,0 +1,162 @@ +/* + * Definitions for kernel entry accounting. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Written by Bahadir Balban + */ +#ifndef __GENERIC_DEBUG_H__ +#define __GENERIC_DEBUG_H__ + +#include INC_ARCH(types.h) +#include INC_SUBARCH(cache.h) +#include + +#if defined(CONFIG_DEBUG_ACCOUNTING) + +struct exception_count { + u64 syscall; + u64 data_abort; + u64 prefetch_abort; + u64 irq; + u64 undefined_abort; +}; + +/* + * Note these are packed to match systable offsets + * so that they're incremented with an auccess + */ +struct syscall_count { + u64 ipc; + u64 tswitch; + u64 tctrl; + u64 exregs; + u64 emtpy; + u64 unmap; + u64 irqctrl; + u64 empty1; + u64 map; + u64 getid; + u64 capctrl; + u64 empty2; + u64 time; + u64 mutexctrl; + u64 cachectrl; +} __attribute__ ((__packed__)); + +struct task_op_count { + u64 context_switch; + u64 space_switch; +}; + +struct cache_op_count { + u64 dcache_clean_mva; + u64 dcache_inval_mva; + u64 icache_clean_mva; + u64 icache_inval_mva; + u64 dcache_clean_setway; + u64 dcache_inval_setway; + u64 tlb_mva; +}; + +#if defined(CONFIG_DEBUG_PERFMON_KERNEL) + +/* Minimum, maximum and average timings for the call */ +struct syscall_timing { + u64 total; + u32 min; + u32 max; + u32 avg; +}; + +struct syscall_timings { + struct syscall_timing ipc; + struct syscall_timing tswitch; + struct syscall_timing tctrl; + struct syscall_timing exregs; + struct syscall_timing emtpy; + struct syscall_timing unmap; + struct syscall_timing irqctrl; + struct syscall_timing empty1; + struct syscall_timing map; + struct syscall_timing getid; + struct syscall_timing capctrl; + struct syscall_timing empty2; + struct syscall_timing time; + struct syscall_timing mutexctrl; + struct syscall_timing cachectrl; + u64 all_total; +} __attribute__ ((__packed__)); + +extern struct syscall_timings syscall_timings; + + +#endif /* End of CONFIG_DEBUG_PERFMON_KERNEL */ + +struct system_accounting { + struct syscall_count syscalls; + +#if defined(CONFIG_DEBUG_PERFMON_KERNEL) + struct syscall_timings syscall_timings; +#endif + + struct exception_count exceptions; + struct cache_op_count cache_ops; + struct task_op_count task_ops; +} __attribute__ ((__packed__)); + + +extern struct system_accounting system_accounting; + +static inline void system_account_dabort(void) +{ + system_accounting.exceptions.data_abort++; +} + +static inline void system_account_pabort(void) +{ + system_accounting.exceptions.prefetch_abort++; +} + +static inline void system_account_undef_abort(void) +{ + system_accounting.exceptions.undefined_abort++; +} + +static inline void system_account_irq(void) +{ + system_accounting.exceptions.irq++; +} + +static inline void system_account_syscall(void) +{ + system_accounting.exceptions.syscall++; +} + +static inline void system_account_context_switch(void) +{ + system_accounting.task_ops.context_switch++; +} + +static inline void system_account_space_switch(void) +{ + system_accounting.task_ops.space_switch++; +} + +#include INC_SUBARCH(debug.h) + +#else /* End of CONFIG_DEBUG_ACCOUNTING */ + +static inline void system_account_cache_op(int op) { } +static inline void system_account_irq(void) { } +static inline void system_account_syscall(void) { } +static inline void system_account_dabort(void) { } +static inline void system_account_pabort(void) { } +static inline void system_account_undef_abort(void) { } +static inline void system_account_space_switch(void) { } +static inline void system_account_context_switch(void) { } + +#endif /* End of !CONFIG_DEBUG_ACCOUNTING */ + + +#endif /* __GENERIC_DEBUG_H__ */ diff --git a/include/l4/generic/irq.h b/include/l4/generic/irq.h index e8a70d5..b6523ff 100644 --- a/include/l4/generic/irq.h +++ b/include/l4/generic/irq.h @@ -7,6 +7,7 @@ #define __GENERIC_IRQ_H__ #include +#include #include INC_PLAT(irq.h) #include INC_ARCH(types.h) @@ -18,8 +19,8 @@ typedef void (*irq_op_t)(l4id_t irq); struct irq_chip_ops { - void (*init)(void); - l4id_t (*read_irq)(void); + void (*init)(); + l4id_t (*read_irq)(void *data); irq_op_t ack_and_mask; irq_op_t unmask; }; @@ -30,6 +31,7 @@ struct irq_chip { int cascade; /* The irq that lower chip uses on this chip */ int start; /* The global irq offset for this chip */ int end; /* End of this chip's irqs */ + void *data; /* Anything that a of interest to a driver */ struct irq_chip_ops ops; }; @@ -40,11 +42,14 @@ struct irq_desc { struct irq_chip *chip; /* Thread registered for this irq */ - struct ktcb *irq_thread; + struct ktcb *task; /* Notification slot for this irq */ int task_notify_slot; + /* Waitqueue head for this irq */ + struct waitqueue_head wqh_irq; + /* NOTE: This could be a list for multiple handlers for shared irqs */ irq_handler_t handler; }; @@ -68,8 +73,8 @@ static inline void irq_disable(int irq_index) this_chip->ops.ack_and_mask(irq_index - this_chip->start); } -int irq_register(struct ktcb *task, int notify_slot, - l4id_t irq_index, irq_handler_t handler); +int irq_register(struct ktcb *task, int notify_slot, l4id_t irq_index); +int irq_thread_notify(struct irq_desc *desc); void do_irq(void); void irq_controllers_init(void); diff --git a/include/l4/generic/platform.h b/include/l4/generic/platform.h index 562eb3e..51b00c7 100644 --- a/include/l4/generic/platform.h +++ b/include/l4/generic/platform.h @@ -2,21 +2,32 @@ #define __PLATFORM_H__ /* * Generic functions to be provided by every platform. + * + * Include only those API's that are needed by sources + * outside the src/platform code. */ +#include + void platform_init(void); -/* Uart APIs */ -void uart_init(void); -void uart_putc(char c); - -/* Timer APIs */ -void timer_init(void); -void timer_start(void); - /* IRQ controller */ void irq_controller_init(void); void platform_irq_enable(int irq); void platform_irq_disable(int irq); +#define dprintk(str, val) \ +{ \ + print_early(str); \ + printhex8((val)); \ + print_early("\n"); \ +} + +void print_early(char *str); +void printhex8(unsigned int); + +int platform_setup_device_caps(struct kernel_resources *kres); + +void platform_test_cpucycles(void); + #endif /* __PLATFORM_H__ */ diff --git a/include/l4/generic/preempt.h b/include/l4/generic/preempt.h index 4322260..f71b6e3 100644 --- a/include/l4/generic/preempt.h +++ b/include/l4/generic/preempt.h @@ -12,4 +12,5 @@ int preempt_count(void); int in_nested_irq_context(void); int in_irq_context(void); int in_task_context(void); + #endif /* __PREEMPT_H__ */ diff --git a/include/l4/generic/resource.h b/include/l4/generic/resource.h index 6856dc3..ed23958 100644 --- a/include/l4/generic/resource.h +++ b/include/l4/generic/resource.h @@ -92,15 +92,20 @@ struct kernel_resources { struct mem_cache *cont_cache; /* Zombie thread list */ - struct ktcb_list zombie_list; + DECLARE_PERCPU(struct ktcb_list, zombie_list); + +#if defined(CONFIG_SUBARCH_V7) + /* Global page tables on split page tables */ + pgd_global_table_t *pgd_global; +#endif }; extern struct kernel_resources kernel_resources; void free_pgd(void *addr); void free_pmd(void *addr); -void free_space(void *addr); -void free_ktcb(void *addr); +void free_space(void *addr, struct ktcb *task); +void free_ktcb(void *addr, struct ktcb *task); void free_capability(void *addr); void free_container(void *addr); void free_user_mutex(void *addr); @@ -118,4 +123,6 @@ int free_boot_memory(struct kernel_resources *kres); int init_system_resources(struct kernel_resources *kres); +void setup_idle_caps(); /*TODO: Delete this when done with it */ + #endif /* __RESOURCES_H__ */ diff --git a/include/l4/generic/scheduler.h b/include/l4/generic/scheduler.h index 3f79237..844a3bb 100644 --- a/include/l4/generic/scheduler.h +++ b/include/l4/generic/scheduler.h @@ -7,8 +7,11 @@ #define __SCHEDULER_H__ #include +#include +#include INC_SUBARCH(cpu.h) #include INC_SUBARCH(mm.h) #include INC_GLUE(memory.h) +#include INC_GLUE(smp.h) /* Task priorities */ #define TASK_PRIO_MAX 10 @@ -19,14 +22,16 @@ #define TASK_PRIO_LOW 2 #define TASK_PRIO_TOTAL 30 -/* Ticks per second, try ticks = 1000 + timeslice = 1 for regressed preemption test. */ -#define SCHED_TICKS 100 +/* + * CONFIG_SCHED_TICKS gives ticks per second. + * try ticks = 1000, and timeslice = 1 for regressed preemption test. + */ /* * A task can run continuously at this granularity, * even if it has a greater total time slice. */ -#define SCHED_GRANULARITY SCHED_TICKS/50 +#define SCHED_GRANULARITY CONFIG_SCHED_TICKS/10 static inline struct ktcb *current_task(void) { @@ -37,13 +42,13 @@ static inline struct ktcb *current_task(void) #define current current_task() #define need_resched (current->ts_need_resched) -#define SCHED_RQ_TOTAL 2 - +#define SCHED_RQ_TOTAL 2 /* A basic runqueue */ struct runqueue { + struct scheduler *sched; struct spinlock lock; /* Lock */ - struct link task_list; /* List of tasks in rq */ + struct link task_list; /* List of tasks in rq */ unsigned int total; /* Total tasks */ }; @@ -52,22 +57,25 @@ struct scheduler { struct runqueue sched_rq[SCHED_RQ_TOTAL]; struct runqueue *rq_runnable; struct runqueue *rq_expired; + struct ktcb *idle_task; /* Total priority of all tasks in container */ int prio_total; }; -extern struct scheduler scheduler; -void sched_init_runqueue(struct runqueue *rq); +DECLARE_PERCPU(extern struct scheduler, scheduler); + +void sched_init_runqueue(struct scheduler *sched, struct runqueue *rq); void sched_init_task(struct ktcb *task, int priority); void sched_prepare_sleep(void); -void sched_exit_sync(void); void sched_suspend_sync(void); void sched_suspend_async(void); void sched_resume_sync(struct ktcb *task); void sched_resume_async(struct ktcb *task); +void sched_enqueue_task(struct ktcb *first_time_runner, int sync); void scheduler_start(void); void schedule(void); -void sched_init(struct scheduler *scheduler); +void sched_init(void); +void idle_task(void); #endif /* __SCHEDULER_H__ */ diff --git a/include/l4/generic/smp.h b/include/l4/generic/smp.h new file mode 100644 index 0000000..31de458 --- /dev/null +++ b/include/l4/generic/smp.h @@ -0,0 +1,23 @@ +/* + * Copyright 2010 B Labs Ltd. + * + * Author: Prem Mallappa + */ + +#ifndef __GENERIC_SMP_H__ +#define __GENERIC_SMP_H__ + +#include INC_SUBARCH(cpu.h) + +/* IPIs, we define more as we go */ +/* we have limited IPI's on ARM, exactly 15 */ +#define IPI_TLB_FLUSH 0x00000001 +#define IPI_SCHEDULE 0x00000002 +#define IPI_CACH_FLUSH 0x00000003 + +#if !defined (CONFIG_NCPU) +#define CONFIG_NCPU 1 +#define smp_get_cpuid() 0 +#endif + +#endif /* __GENERIC_SMP_H__ */ diff --git a/include/l4/generic/space.h b/include/l4/generic/space.h index 1c6adeb..1ef4281 100644 --- a/include/l4/generic/space.h +++ b/include/l4/generic/space.h @@ -1,22 +1,31 @@ /* * Generic address space related information. * - * Copyright (C) 2007 Bahadir Balban + * Copyright (C) 2007-2010 Bahadir Balban */ #ifndef __SPACE_H__ #define __SPACE_H__ -/* The flags not embedded in the name behave as expected. E.g USR_RW is also */ -#define MAP_USR_RW_FLAGS 0 /* CB as one would expect */ -#define MAP_USR_RO_FLAGS 1 /* CB as one would expect */ -#define MAP_SVC_RW_FLAGS 2 /* CB as one would expect */ -#define MAP_USR_IO_FLAGS 3 /* Non-CB, RW TODO: How about RO one? */ -#define MAP_SVC_IO_FLAGS 4 /* Non-CB, RW */ +/* + * Generic mapping flags. + */ +#define MAP_FAULT 0 +#define MAP_USR_RW 1 +#define MAP_USR_RO 2 +#define MAP_KERN_RW 3 +#define MAP_USR_IO 4 +#define MAP_KERN_IO 5 +#define MAP_USR_RWX 6 +#define MAP_KERN_RWX 7 +#define MAP_USR_RX 8 +#define MAP_KERN_RX 9 +#define MAP_UNMAP 10 /* For unmap syscall */ +#define MAP_INVALID_FLAGS (1 << 31) /* Some default aliases */ -#define MAP_USR_DEFAULT_FLAGS MAP_USR_RW_FLAGS -#define MAP_SVC_DEFAULT_FLAGS MAP_SVC_RW_FLAGS -#define MAP_IO_DEFAULT_FLAGS MAP_SVC_IO_FLAGS +#define MAP_USR_DEFAULT MAP_USR_RW +#define MAP_KERN_DEFAULT MAP_KERN_RW +#define MAP_IO_DEFAULT MAP_KERN_IO #if defined (__KERNEL__) @@ -46,11 +55,14 @@ struct address_space_list { }; struct address_space *address_space_create(struct address_space *orig); -void address_space_delete(struct address_space *space); +void address_space_delete(struct address_space *space, + struct ktcb *task_accounted); void address_space_attach(struct ktcb *tcb, struct address_space *space); struct address_space *address_space_find(l4id_t spid); void address_space_add(struct address_space *space); -void address_space_remove(struct address_space *space); + +struct container; +void address_space_remove(struct address_space *space, struct container *cont); void init_address_space_list(struct address_space_list *space_list); int check_access(unsigned long vaddr, unsigned long size, unsigned int flags, int page_in); diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index f65ebfd..8bf68f5 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -28,15 +28,20 @@ #define TASK_INTERRUPTED (1 << 0) #define TASK_SUSPENDING (1 << 1) #define TASK_RESUMING (1 << 2) -#define TASK_EXITING (1 << 3) -#define TASK_PENDING_SIGNAL (TASK_SUSPENDING | TASK_EXITING) +#define TASK_PENDING_SIGNAL (TASK_SUSPENDING) + +/* + * This is to indicate a task (either current or one of + * its children) exit has occured and cleanup needs to be + * called + */ +#define TASK_EXITED (1 << 3) /* Task states */ enum task_state { TASK_INACTIVE = 0, TASK_SLEEPING = 1, TASK_RUNNABLE = 2, - TASK_DEAD = 3, }; #define TASK_CID_MASK 0xFF000000 @@ -82,6 +87,9 @@ struct ktcb { l4id_t tid; /* Global thread id */ l4id_t tgid; /* Global thread group id */ + /* CPU affinity */ + int affinity; + /* Other related threads */ l4id_t pagerid; @@ -94,6 +102,9 @@ struct ktcb { /* Lock for blocking thread state modifications via a syscall */ struct mutex thread_control_lock; + /* To protect against thread deletion/modification */ + struct spinlock thread_lock; + u32 ts_need_resched; /* Scheduling flag */ enum task_state state; @@ -171,13 +182,14 @@ static inline void set_task_ids(struct ktcb *task, struct task_ids *ids) } struct ktcb *tcb_find(l4id_t tid); +struct ktcb *tcb_find_lock(l4id_t tid); void tcb_add(struct ktcb *tcb); void tcb_remove(struct ktcb *tcb); void tcb_init(struct ktcb *tcb); struct ktcb *tcb_alloc_init(l4id_t cid); void tcb_delete(struct ktcb *tcb); - +void tcb_delete_zombies(void); void ktcb_list_remove(struct ktcb *task, struct ktcb_list *ktcb_list); void ktcb_list_add(struct ktcb *new, struct ktcb_list *ktcb_list); diff --git a/include/l4/generic/thread.h b/include/l4/generic/thread.h index 7046993..ca5961a 100644 --- a/include/l4/generic/thread.h +++ b/include/l4/generic/thread.h @@ -11,6 +11,7 @@ void thread_id_pool_init(void); int thread_id_new(void); int thread_id_del(int tid); +void thread_setup_affinity(struct ktcb *task); void thread_destroy(struct ktcb *); #endif /* __GENERIC_THREAD_H__ */ diff --git a/include/l4/generic/time.h b/include/l4/generic/time.h index 62471c5..8bcc8f8 100644 --- a/include/l4/generic/time.h +++ b/include/l4/generic/time.h @@ -4,8 +4,8 @@ * Copyright (C) 2007 Bahadir Balban */ -#ifndef __GENERIC_TIMER_H__ -#define __GENERIC_TIMER_H__ +#ifndef __GENERIC_TIME_H__ +#define __GENERIC_TIME_H__ /* Used by posix systems */ struct timeval { @@ -17,4 +17,4 @@ extern volatile u32 jiffies; int do_timer_irq(void); -#endif /* __GENERIC_TIMER_H__ */ +#endif /* __GENERIC_TIME_H__ */ diff --git a/include/l4/glue/arm/cache.h b/include/l4/glue/arm/cache.h new file mode 100644 index 0000000..8b155ac --- /dev/null +++ b/include/l4/glue/arm/cache.h @@ -0,0 +1,26 @@ +/* + * Generic cache api calls + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#ifndef __GLUE_CACHE_H__ +#define __GLUE_CACHE_H__ + +#include INC_SUBARCH(mmu_ops.h) + +/* Lowest byte is reserved for and used by capability permissions */ +#define ARCH_INVALIDATE_ICACHE 0x10 +#define ARCH_INVALIDATE_DCACHE 0x20 +#define ARCH_CLEAN_DCACHE 0x30 +#define ARCH_CLEAN_INVALIDATE_DCACHE 0x40 +#define ARCH_INVALIDATE_TLB 0x50 + +void arch_invalidate_dcache(unsigned long start, unsigned long end); +void arch_clean_invalidate_dcache(unsigned long start, unsigned long end); +void arch_invalidate_icache(unsigned long start, unsigned long end); +void arch_invalidate_tlb(unsigned long start, unsigned long end); +void arch_clean_dcache(unsigned long start, unsigned long end); + +#endif /* __GLUE_CACHE_H__ */ diff --git a/include/l4/glue/arm/debug.h b/include/l4/glue/arm/debug.h new file mode 100644 index 0000000..dad9331 --- /dev/null +++ b/include/l4/glue/arm/debug.h @@ -0,0 +1,51 @@ +/* + * ARM-specific syscall type accounting. + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ + +#ifndef __ARM_DEBUG_H__ +#define __ARM_DEBUG_H__ + +#include INC_SUBARCH(perfmon.h) + +#if defined (CONFIG_DEBUG_ACCOUNTING) + +extern struct system_accounting system_accounting; + +static inline void +system_account_syscall_type(unsigned long swi_address) +{ + *(((u64 *)&system_accounting.syscalls) + + ((swi_address & 0xFF) >> 2)) += 1; +} + +#else /* End of CONFIG_DEBUG_ACCOUNTING */ + +static inline void system_account_syscall_type(unsigned long swi_address) { } + +#endif /* End of !CONFIG_DEBUG_ACCOUNTING */ + + +#if defined (CONFIG_DEBUG_PERFMON_KERNEL) + +static inline void +system_measure_syscall_start(void) +{ + /* To avoid non-voluntary rescheduling during call */ + perfmon_reset_start_cyccnt(); +} + +/* Defined in arm/glue/debug.c */ +void system_measure_syscall_end(unsigned long swi_address); + +#else /* End of CONFIG_DEBUG_PERFMON_KERNEL */ + +static inline void system_measure_syscall_start(void) { } +static inline void system_measure_syscall_end(unsigned long swi_address) { } + +#endif /* End of !CONFIG_DEBUG_PERFMON_KERNEL */ + +#endif /* __ARM_DEBUG_H__ */ diff --git a/include/l4/glue/arm/init.h b/include/l4/glue/arm/init.h index 485d8eb..1aa1a30 100644 --- a/include/l4/glue/arm/init.h +++ b/include/l4/glue/arm/init.h @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * Author: Prem Mallappa + */ + #ifndef __ARM_GLUE_INIT_H__ #define __ARM_GLUE_INIT_H__ @@ -8,5 +13,14 @@ void switch_to_user(struct ktcb *inittask); void timer_start(void); extern struct address_space init_space; +void init_kernel_mappings(void); +void start_virtual_memory(void); +void finalize_virtual_memory(void); +void init_finalize(void); +void remove_section_mapping(unsigned long vaddr); + +void vectors_init(void); +void setup_idle_caps(void); +void setup_idle_task(void); #endif /* __ARM_GLUE_INIT_H__ */ diff --git a/include/l4/glue/arm/ipi.h b/include/l4/glue/arm/ipi.h new file mode 100644 index 0000000..ca44626 --- /dev/null +++ b/include/l4/glue/arm/ipi.h @@ -0,0 +1,18 @@ +#ifndef __IPI_H__ +#define __IPI_H__ + +/* + * Copyright 2010 B Labs.Ltd. + * + * Author: Prem Mallappa + * + * Description: + */ + + +#include + +int ipi_handler(struct irq_desc *desc); + + +#endif /* __IPI_H__ */ diff --git a/include/l4/glue/arm/mapping.h b/include/l4/glue/arm/mapping.h new file mode 100644 index 0000000..1142406 --- /dev/null +++ b/include/l4/glue/arm/mapping.h @@ -0,0 +1,89 @@ +/* + * Generic mapping operations + * + * Operations on address space mappings that + * all subarchitectures support generically. + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + * Written by Bahadir Balban + */ + +#ifndef __ARM_GLUE_MAPPING_H__ +#define __ARM_GLUE_MAPPING_H__ + +#include INC_SUBARCH(mm.h) + +#define TASK_PGD(x) (x)->space->pgd + +unsigned int space_flags_to_ptflags(unsigned int flags); + +void add_mapping_pgd(unsigned long paddr, unsigned long vaddr, + unsigned int size, unsigned int flags, + pgd_table_t *pgd); + +void add_mapping(unsigned long paddr, unsigned long vaddr, + unsigned int size, unsigned int flags); + +void add_boot_mapping(unsigned long paddr, unsigned long vaddr, + unsigned int size, unsigned int flags); + +int remove_mapping(unsigned long vaddr); +int remove_mapping_pgd(pgd_table_t *pgd, unsigned long vaddr); +void remove_mapping_pgd_all_user(pgd_table_t *pgd); + +int check_mapping_pgd(unsigned long vaddr, unsigned long size, + unsigned int flags, pgd_table_t *pgd); + +int check_mapping(unsigned long vaddr, unsigned long size, + unsigned int flags); + +void copy_pgd_kern_all(pgd_table_t *); + +struct address_space; +int delete_page_tables(struct address_space *space); +int copy_user_tables(struct address_space *new, struct address_space *orig); +void remap_as_pages(void *vstart, void *vend); + +void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, + unsigned long start, unsigned long end); + +/* + * TODO: Some of these may be made inline by + * removing their signature from here completely + * and creating an arch-specific mapping.h which + * has inline definitions or just signatures. + */ + +pte_t virt_to_pte(unsigned long vaddr); +pte_t *virt_to_ptep(unsigned long vaddr); +pte_t virt_to_pte_from_pgd(pgd_table_t *pgd, unsigned long vaddr); +unsigned long virt_to_phys_by_pgd(pgd_table_t *pgd, unsigned long vaddr); + +void arch_prepare_pte(u32 paddr, u32 vaddr, unsigned int flags, + pte_t *ptep); + +void arch_write_pte(pte_t *ptep, pte_t pte, u32 vaddr); + +void arch_prepare_write_pte(u32 paddr, u32 vaddr, + unsigned int flags, pte_t *ptep); + +pmd_t *arch_pick_pmd(pgd_table_t *pgd, unsigned long vaddr); + +void arch_write_pmd(pmd_t *pmd_entry, u32 pmd_phys, u32 vaddr); + +int arch_check_pte_access_perms(pte_t pte, unsigned int flags); + +pgd_table_t *arch_realloc_page_tables(void); + +void arch_copy_pgd_kernel_entries(pgd_table_t *to); + +int is_global_pgdi(int i); + +struct ktcb; +void arch_space_switch(struct ktcb *task); + +int pgd_count_boot_pmds(); + +void idle_task(void); + +#endif /* __ARM_GLUE_MAPPING_H__ */ diff --git a/include/l4/glue/arm/memlayout.h b/include/l4/glue/arm/memlayout.h index b272fd2..f72700b 100644 --- a/include/l4/glue/arm/memlayout.h +++ b/include/l4/glue/arm/memlayout.h @@ -27,19 +27,24 @@ /* ARM-specific offset in KIP that tells the address of UTCB page */ #define UTCB_KIP_OFFSET 0x50 -#define IO_AREA0_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*0)) -#define IO_AREA1_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*1)) -#define IO_AREA2_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*2)) -#define IO_AREA3_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*3)) -#define IO_AREA4_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*4)) -#define IO_AREA5_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*5)) -#define IO_AREA6_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*6)) -#define IO_AREA7_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*7)) +#define IO_AREA0_VADDR IO_AREA_START +#define IO_AREA1_VADDR (IO_AREA_START + (SZ_1MB*1)) +#define IO_AREA2_VADDR (IO_AREA_START + (SZ_1MB*2)) +#define IO_AREA3_VADDR (IO_AREA_START + (SZ_1MB*3)) +#define IO_AREA4_VADDR (IO_AREA_START + (SZ_1MB*4)) +#define IO_AREA5_VADDR (IO_AREA_START + (SZ_1MB*5)) +#define IO_AREA6_VADDR (IO_AREA_START + (SZ_1MB*6)) +#define IO_AREA7_VADDR (IO_AREA_START + (SZ_1MB*7)) + +/* + * IO_AREA8_VADDR + * The beginning page in this slot is used for userspace uart mapping + */ #define ARM_HIGH_VECTOR 0xFFFF0000 #define ARM_SYSCALL_VECTOR 0xFFFFFF00 -#define KERNEL_OFFSET (KERNEL_AREA_START - PHYS_MEM_START) +#define KERNEL_OFFSET (KERNEL_AREA_START - PLATFORM_PHYS_MEM_START) /* User tasks define them differently */ #if defined (__KERNEL__) @@ -49,7 +54,7 @@ #define KERN_ADDR(x) ((x >= KERNEL_AREA_START) && (x < KERNEL_AREA_END)) #define UTCB_ADDR(x) ((x >= UTCB_AREA_START) && (x < UTCB_AREA_END)) -#define PRIVILEGED_ADDR(x) (KERN_ADDR(x) || (x >= ARM_HIGH_VECTOR) || \ +#define is_kernel_address(x) (KERN_ADDR(x) || (x >= ARM_HIGH_VECTOR) || \ (x >= IO_AREA_START && x < IO_AREA_END)) #endif /* __MEMLAYOUT_H__ */ diff --git a/include/l4/glue/arm/memory.h b/include/l4/glue/arm/memory.h index b50664f..988e83d 100644 --- a/include/l4/glue/arm/memory.h +++ b/include/l4/glue/arm/memory.h @@ -11,35 +11,32 @@ #include INC_SUBARCH(mm.h) /* Generic definitions */ -#define PAGE_SIZE ARM_PAGE_SIZE -#define PAGE_MASK ARM_PAGE_MASK -#define PAGE_BITS ARM_PAGE_BITS - -/* - * This defines the largest size defined by this architecture that is - * easily mappable. ARM supports 1MB mappings so it fits well. If it's - * unsupported by the arch then a reasonable size could be 1MB. - */ -#define SECTION_SIZE ARM_SECTION_SIZE -#define SECTION_MASK ARM_SECTION_MASK -#define SECTION_BITS ARM_SECTION_BITS +#define PFN_SHIFT 12 +#define PAGE_BITS PFN_SHIFT +#define PAGE_SIZE SZ_4K +#define PAGE_MASK (PAGE_SIZE - 1) /* Aligns to the upper page (ceiling) FIXME: Must add a wraparound checker. */ -#define page_align_up(addr) ((((unsigned int)(addr)) + \ - (PAGE_SIZE - 1)) & \ - (~PAGE_MASK)) -/* Aligns to the lower page (floor) */ -#define page_align(addr) (((unsigned int)(addr)) & \ +#define page_align_up(addr) ((((unsigned long)(addr)) + PAGE_MASK) & \ (~PAGE_MASK)) -#define is_aligned(val, size) (!(((unsigned long)(val)) & ((size) - 1))) +/* Aligns to the lower page (floor) */ +#define page_align(addr) (((unsigned long)(addr)) & \ + (~PAGE_MASK)) + +#define is_aligned(val, size) (!(((unsigned long)(val)) & (((unsigned long)size) - 1))) #define is_page_aligned(val) (!(((unsigned long)(val)) & PAGE_MASK)) #define page_boundary(x) is_page_aligned(x) -/* Align to given size */ -#define align(addr, size) (((unsigned int)(addr)) & (~(size-1))) +/* + * Align to given size. + * + * Note it must be an alignable size i.e. one that is a power of two. + * E.g. 0x1000 would work but 0x1010 would not. + */ +#define align(addr, size) (((unsigned int)(addr)) & (~((unsigned long)size-1))) #define align_up(addr, size) ((((unsigned long)(addr)) + \ - ((size) - 1)) & (~((size) - 1))) + ((size) - 1)) & (~(((unsigned long)size) - 1))) /* The bytes left until the end of the page that x is in */ #define TILL_PAGE_ENDS(x) (PAGE_SIZE - ((unsigned long)(x) & PAGE_MASK)) @@ -58,6 +55,8 @@ #define BITWISE_GETWORD(x) ((x) >> WORD_BITS_LOG2) /* Divide by 32 */ #define BITWISE_GETBIT(x) (1 << ((x) % WORD_BITS)) +/* Minimum stack alignment restriction across functions, exceptions */ +#define STACK_ALIGNMENT 8 /* Endianness conversion */ static inline void be32_to_cpu(unsigned int x) @@ -75,31 +74,6 @@ static inline void be32_to_cpu(unsigned int x) p[2] = tmp; } -void paging_init(void); - -unsigned int space_flags_to_ptflags(unsigned int flags); - -void add_mapping_pgd(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags, - pgd_table_t *pgd); -void add_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags); -int remove_mapping(unsigned long vaddr); -int remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd); -int remove_mapping_pgd_all_user(pgd_table_t *pgd); -void prealloc_phys_pagedesc(void); - -int check_mapping_pgd(unsigned long vaddr, unsigned long size, - unsigned int flags, pgd_table_t *pgd); - -int check_mapping(unsigned long vaddr, unsigned long size, - unsigned int flags); - -void copy_pgd_kern_all(pgd_table_t *); -pte_t virt_to_pte(unsigned long virtual); -pte_t virt_to_pte_from_pgd(unsigned long virtual, pgd_table_t *pgd); -unsigned long virt_to_phys_by_pgd(unsigned long vaddr, pgd_table_t *pgd); - struct ktcb; void task_init_registers(struct ktcb *task, unsigned long pc); diff --git a/include/l4/glue/arm/message.h b/include/l4/glue/arm/message.h index 62d35dd..e04af8d 100644 --- a/include/l4/glue/arm/message.h +++ b/include/l4/glue/arm/message.h @@ -58,7 +58,7 @@ * Complicated for you? Suggest a simpler design and it shall be implemented! */ -#define MR_REST ((UTCB_SIZE >> 2) - MR_TOTAL - 2) /* -2 is for fields on utcb */ +#define MR_REST ((UTCB_SIZE >> 2) - MR_TOTAL - 4) /* -4 is for fields on utcb */ #define MR_TOTAL 6 #define MR_TAG 0 /* Contains the purpose of message */ #define MR_SENDER 1 /* For anythread receivers to discover sender */ @@ -73,6 +73,9 @@ #define MR0_REGISTER r3 #define MR_RETURN_REGISTER r3 +#define TASK_NOTIFY_SLOTS 8 +#define TASK_NOTIFY_MAXVALUE 255 + /* Primaries aren't used for memcopy. Those ops use this as a parameter */ #define L4_UTCB_FULL_BUFFER_SIZE (MR_REST * sizeof(int)) @@ -83,6 +86,7 @@ struct utcb { u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */ u32 saved_tag; /* Saved tag field for stacked ipcs */ u32 saved_sender; /* Saved sender field for stacked ipcs */ + u8 notify[TASK_NOTIFY_SLOTS]; /* Irq notification slots */ u32 mr_rest[MR_REST]; /* Complete the utcb for up to 64 words */ }; #endif diff --git a/include/l4/glue/arm/smp.h b/include/l4/glue/arm/smp.h new file mode 100644 index 0000000..fa5933b --- /dev/null +++ b/include/l4/glue/arm/smp.h @@ -0,0 +1,46 @@ +/* + * Copyright 2010 B Labs Ltd. + * + * Authors: Prem Mallappa, Bahadir Balban + * + * SMP support + */ +#ifndef __GLUE_ARM_SMP_H__ +#define __GLUE_ARM_SMP_H__ + +#include INC_ARCH(scu.h) + +struct cpuinfo { + u32 ncpus; + u32 flags; + volatile u32 cpu_spinning; + void (*send_ipi)(int cpu, int ipi_cmd); + void (*smp_spin)(void); + void (*smp_finish)(void); + +} __attribute__ ((__packed__)); + +extern struct cpuinfo cpuinfo; + +#if defined(CONFIG_SMP) + +void smp_attach(void); +void smp_start_cores(void); + +#else +static inline void smp_attach(void) {} +static inline void smp_start_cores(void) {} +#endif + +void init_smp(void); +void arch_smp_spin(void); +void arch_send_ipi(u32 cpu, int ipi); +void platform_smp_init(int ncpus); +int platform_smp_start(int cpu, void (*start)(int)); +void secondary_init_platform(void); + +extern unsigned long secondary_run_signal; + +#define CPUID_TO_MASK(cpu) (1 << (cpu)) + +#endif diff --git a/include/l4/lib/list.h b/include/l4/lib/list.h index 9601e06..8c123b8 100644 --- a/include/l4/lib/list.h +++ b/include/l4/lib/list.h @@ -1,6 +1,8 @@ #ifndef __LIST_H__ #define __LIST_H__ +#include + #define L4_DEADWORD 0xDEADCCCC struct link { @@ -66,6 +68,7 @@ static inline void list_remove_init(struct link *link) struct link *prev = link->prev; struct link *next = link->next; + //BUG_ON(prev == NULL || next == NULL || link == NULL); prev->next = next; next->prev = prev; @@ -85,6 +88,26 @@ static inline struct link *list_detach(struct link *head) return next; } +/* append new_list to list given by head/end pair */ +static inline void list_attach(struct link *new_list, struct link *head, struct link *end) +{ + /* attach new list at the end of original list */ + end->next = new_list; + new_list->prev = end; + + /* go to the end of list to be attached */ + while (new_list->next != end->next) + new_list = new_list->next; + + /* set end nodes properly */ + new_list->next = head; + head->prev = new_list; + + /* set end to new end */ + end = new_list; +} + + static inline int list_empty(struct link *list) { return list->prev == list && list->next == list; diff --git a/include/l4/lib/math.h b/include/l4/lib/math.h index 320380e..8671e41 100644 --- a/include/l4/lib/math.h +++ b/include/l4/lib/math.h @@ -1,6 +1,16 @@ #ifndef __LIB_MATH_H__ #define __LIB_MATH_H__ +/* Take the power */ +static inline int pow(int val, int exp) +{ + int res = 1; + + for (int i = 0; i < exp; i++) + res *= val; + return res; +} + static inline int min(int x, int y) { return x < y ? x : y; diff --git a/include/l4/lib/printk.h b/include/l4/lib/printk.h index ab02f53..08e55e3 100644 --- a/include/l4/lib/printk.h +++ b/include/l4/lib/printk.h @@ -4,15 +4,12 @@ #include -#if defined(ARCH_TEST) -/* For host tests all printks mean printf using the host C library */ -#include -#define printk printf -#elif !defined(__KERNEL__) +#if !defined(__KERNEL__) #define printk printf #else int printk(char *format, ...) __attribute__((format (printf, 1, 2))); extern void putc(char c); +void init_printk_lock(void); #endif #endif /* __PRINTK_H__ */ diff --git a/include/l4/lib/spinlock.h b/include/l4/lib/spinlock.h index 3e27986..46b2df9 100644 --- a/include/l4/lib/spinlock.h +++ b/include/l4/lib/spinlock.h @@ -3,12 +3,21 @@ #include #include -#include INC_ARCH(exception.h) +#include INC_ARCH(irq.h) +#include INC_ARCH(mutex.h) struct spinlock { unsigned int lock; }; +#define DECLARE_SPINLOCK(lockname) \ + struct spinlock lockname = { \ + .lock = 0, \ + } + +void spin_lock_record_check(void *lock_addr); +void spin_unlock_delete_check(void *lock_addr); + static inline void spin_lock_init(struct spinlock *s) { memset(s, 0, sizeof(struct spinlock)); @@ -22,6 +31,10 @@ static inline void spin_lock(struct spinlock *s) { preempt_disable(); /* This must disable local preempt */ #if defined(CONFIG_SMP) + +#if defined (CONFIG_DEBUG_SPINLOCKS) + spin_lock_record_check(s); +#endif __spin_lock(&s->lock); #endif } @@ -29,6 +42,10 @@ static inline void spin_lock(struct spinlock *s) static inline void spin_unlock(struct spinlock *s) { #if defined(CONFIG_SMP) + +#if defined (CONFIG_DEBUG_SPINLOCKS) + spin_unlock_delete_check(s); +#endif __spin_unlock(&s->lock); #endif preempt_enable(); @@ -40,10 +57,14 @@ static inline void spin_unlock(struct spinlock *s) * on other cpus. */ static inline void spin_lock_irq(struct spinlock *s, - unsigned long state) + unsigned long *state) { - irq_local_disable_save(&state); + irq_local_disable_save(state); #if defined(CONFIG_SMP) +#if defined (CONFIG_DEBUG_SPINLOCKS) + spin_lock_record_check(s); +#endif + __spin_lock(&s->lock); #endif } @@ -52,6 +73,11 @@ static inline void spin_unlock_irq(struct spinlock *s, unsigned long state) { #if defined(CONFIG_SMP) + +#if defined (CONFIG_DEBUG_SPINLOCKS) + spin_unlock_delete_check(s); +#endif + __spin_unlock(&s->lock); #endif irq_local_restore(state); diff --git a/include/l4/lib/wait.h b/include/l4/lib/wait.h index 98453a8..ef81fe8 100644 --- a/include/l4/lib/wait.h +++ b/include/l4/lib/wait.h @@ -13,8 +13,8 @@ struct waitqueue { #define WAKEUP_ASYNC 0 enum wakeup_flags { - WAKEUP_INTERRUPT = (1 << 0), - WAKEUP_SYNC = (1 << 1) + WAKEUP_INTERRUPT = (1 << 0), /* Set interrupt flag for task */ + WAKEUP_SYNC = (1 << 1), /* Wake it up synchronously */ }; #define CREATE_WAITQUEUE_ON_STACK(wq, tsk) \ @@ -50,18 +50,20 @@ void task_unset_wqh(struct ktcb *task); do { \ ret = 0; \ for (;;) { \ - spin_lock(&(wqh)->slock); \ + unsigned long irqsave; \ + spin_lock_irq(&(wqh)->slock, &irqsave); \ if (condition) { \ - spin_unlock(&(wqh)->slock); \ + spin_unlock_irq(&(wqh)->slock, irqsave);\ break; \ } \ CREATE_WAITQUEUE_ON_STACK(wq, current); \ task_set_wqh(current, wqh, &wq); \ (wqh)->sleepers++; \ - list_insert_tail(&wq.task_list, &(wqh)->task_list);\ - /* printk("(%d) waiting...\n", current->tid); */ \ + list_insert_tail(&wq.task_list, \ + &(wqh)->task_list); \ + /* printk("(%d) waiting...\n", current->tid); */\ sched_prepare_sleep(); \ - spin_unlock(&(wqh)->slock); \ + spin_unlock_irq(&(wqh)->slock, irqsave); \ schedule(); \ /* Did we wake up normally or get interrupted */\ if (current->flags & TASK_INTERRUPTED) { \ @@ -72,6 +74,7 @@ do { \ } \ } while(0); + void wake_up(struct waitqueue_head *wqh, unsigned int flags); int wake_up_task(struct ktcb *task, unsigned int flags); void wake_up_all(struct waitqueue_head *wqh, unsigned int flags); diff --git a/include/l4/macros.h b/include/l4/macros.h index 3a45b83..7d908f3 100644 --- a/include/l4/macros.h +++ b/include/l4/macros.h @@ -9,7 +9,6 @@ * source file, using gcc's -imacro command line option. Only macro * definitions will be extracted. */ - #define INC_ARCH(x) #define INC_SUBARCH(x) #define INC_CPU(x) @@ -19,9 +18,16 @@ #define __initdata SECTION(".init.data") +/* + * FIXME: Remove __CPP__ + * This is defined in kernel linker.lds.in, + * find some better way. + */ +#if !defined(__CPP__) /* use this to place code/data in a certain section */ #define SECTION(x) __attribute__((section(x))) #define ALIGN(x) __attribute__((aligned (x))) +#endif /* Functions for critical path optimizations */ #if (__GNUC__ >= 3) @@ -40,11 +46,13 @@ #endif /* Convenience functions for memory sizes. */ #define SZ_1K 1024 +#define SZ_2K 2048 #define SZ_4K 0x1000 #define SZ_16K 0x4000 #define SZ_32K 0x8000 #define SZ_64K 0x10000 #define SZ_1MB 0x100000 +#define SZ_2MB 0x200000 #define SZ_4MB (4*SZ_1MB) #define SZ_8MB (8*SZ_1MB) #define SZ_16MB (16*SZ_1MB) @@ -53,6 +61,25 @@ #define SZ_16K_BITS 14 #define SZ_1MB_BITS 20 +/* Per-cpu variables */ + +#if defined CONFIG_SMP +#define DECLARE_PERCPU(type, name) \ +type name[CONFIG_NCPU] + +#define per_cpu(val) (val)[smp_get_cpuid()] +#define per_cpu_byid(val, cpu) (val)[(cpu)] + +#else /* Not CONFIG_SMP */ + +#define DECLARE_PERCPU(type, name) \ +type name + +#define per_cpu(val) (val) +#define per_cpu_byid(val, cpu) val + +#endif /* End of Not CONFIG_SMP */ + #ifndef __ASSEMBLY__ #include /* offsetof macro, defined in the `standard' way. */ #endif diff --git a/include/l4/platform/beagle/cm.h b/include/l4/platform/beagle/cm.h new file mode 100644 index 0000000..0541aae --- /dev/null +++ b/include/l4/platform/beagle/cm.h @@ -0,0 +1,25 @@ +/* + * Clock mangaer module of the beagleboard. + * + * Copyright (C) 2007 Bahadir Balban + * + */ + +#ifndef __PLATFORM_BEAGLE_CM_H__ +#define __PLATFORM_BEAGLE_CM_H__ + +/* + * Register offsets for Clock Manager(CM) + * PER_CM, WKUP_CM etc all have same offsets + * for registers + */ +#define CM_FCLKEN_OFFSET 0x00 +#define CM_ICLKEN_OFFSET 0x10 +#define CM_CLKSEL_OFFSET 0x40 + +void omap_cm_enable_iclk(unsigned long cm_base, int bit); +void omap_cm_enable_fclk(unsigned long cm_base, int bit); +void omap_cm_clk_select(unsigned long cm_base, int bit, int src); + +#endif /* __PLATFORM_BEAGLE_CM_H__ */ + diff --git a/include/l4/platform/beagle/irq.h b/include/l4/platform/beagle/irq.h new file mode 100644 index 0000000..4c5b51f --- /dev/null +++ b/include/l4/platform/beagle/irq.h @@ -0,0 +1,35 @@ + +#ifndef __PLATFORM_IRQ_H__ +#define __PLATFORM_IRQ_H__ + +/* + * Support for generic irq handling using platform irq controller (GIC) + * + * Copyright (C) 2007 Bahadir Balban + */ + +/* TODO: Not sure about this, need to check */ +#define IRQ_CHIPS_MAX 1 +#define IRQS_MAX 96 + +/* IRQ indices. */ +#define IRQ_UART0 72 +#define IRQ_UART1 73 +#define IRQ_UART2 74 + +/* General Purpose Timers */ +#define IRQ_TIMER0 37 +#define IRQ_TIMER1 38 +#define IRQ_TIMER2 39 +#define IRQ_TIMER3 40 +#define IRQ_TIMER4 41 +#define IRQ_TIMER5 42 +#define IRQ_TIMER6 43 +#define IRQ_TIMER7 44 +#define IRQ_TIMER8 45 +#define IRQ_TIMER9 46 +#define IRQ_TIMER10 47 +#define IRQ_TIMER11 95 + +#endif /* __PLATFORM_IRQ_H__ */ + diff --git a/include/l4/platform/beagle/offsets.h b/include/l4/platform/beagle/offsets.h new file mode 100644 index 0000000..9a4c8b8 --- /dev/null +++ b/include/l4/platform/beagle/offsets.h @@ -0,0 +1,66 @@ +/* + * + * Describes physical memory layout of Beagle Boards. + * We have rev3 boards. + * + * Copyright (C) 2007 Bahadir Balban + */ + +#ifndef __PLATFORM_BEAGLE_OFFSETS_H__ +#define __PLATFORM_BEAGLE_OFFSETS_H__ + +/* + * Physical memory base + * FIXME: Somewhere its written: Rev 1 and 2 + * of Beagleboard has 128MB SDRAM while Rev 3 has 256MB + * SDRAM which is detected automatically on intiliazation, + * we have Rev3 boards, so hardcoding this only. + */ +#define PLATFORM_PHYS_MEM_START 0x80000000 /* inclusive */ +#define PLATFORM_PHYS_MEM_END 0x90000000 /* 256MB, exclusive */ + +/* + * Device offsets in physical memory + * Naming of devices done starting with 0 subscript, + * as we use these names for device capability + */ +#define PLATFORM_WKUP_CM_BASE 0x48004C00 /* Wake up clock manager */ +#define PLATFORM_PERCM_BASE 0x48005000 /* Peripheral Clock Manager */ +#define PLATFORM_UART0_BASE 0x4806A000 /* UART 0 */ +#define PLATFORM_UART1_BASE 0x4806C000 /* UART 1 */ +#define PLATFORM_UART2_BASE 0x49020000 /* UART 2 */ +#define PLATFORM_TIMER0_BASE 0x48318000 /* GPTIMER1 */ +#define PLATFORM_TIMER1_BASE 0x49032000 /* GPTIMER2 */ +#define PLATFORM_TIMER2_BASE 0x49034000 /* GPTIMER3 */ +#define PLATFORM_TIMER3_BASE 0x49036000 /* GPTIMER4 */ +#define PLATFORM_TIMER4_BASE 0x49038000 /* GPTIMER5 */ +#define PLATFORM_TIMER5_BASE 0x4903A000 /* GPTIMER6 */ +#define PLATFORM_TIMER6_BASE 0x4903C000 /* GPTIMER7 */ +#define PLATFORM_TIMER7_BASE 0x4903E000 /* GPTIMER8 */ +#define PLATFORM_TIMER8_BASE 0x49040000 /* GPTIMER9 */ +#define PLATFORM_TIMER9_BASE 0x48086000 /* GPTIMER10 */ +#define PLATFORM_TIMER10_BASE 0x48088000 /* GPTIMER11 */ +#define PLATFORM_TIMER11_BASE 0x48304000 /* GPTIMER12 */ +#define PLATFORM_INTC_BASE 0x48200000 /* Interrupt controller */ + +/* + * Virtual Memory base address, where devices will be mapped. + * Each Device will take one page in virtual memory. + * Nice and smooth. + */ +#define DEVICE_PAGE 0x1000 + +#define PLATFORM_WKUP_CM_VBASE (IO_AREA0_VADDR + (0 * DEVICE_PAGE)) +#define PLATFORM_CONSOLE_VBASE (IO_AREA0_VADDR + (1 * DEVICE_PAGE)) +#define PLATFORM_TIMER0_VBASE (IO_AREA0_VADDR + (2 * DEVICE_PAGE)) +#define PLATFORM_INTC_VBASE (IO_AREA0_VADDR + (3 * DEVICE_PAGE)) +#define PLATFORM_PERCM_VBASE (IO_AREA0_VADDR + (4 * DEVICE_PAGE)) + +/* Add userspace devices here as they become necessary for irqs */ +#define PLATFORM_TIMER1_VBASE (IO_AREA0_VADDR + (5 * DEVICE_PAGE)) + +/* Add size of various user space devices, to be used in capability generation */ +#define PLATFORM_TIMER1_SIZE DEVICE_PAGE + +#endif /* __PLATFORM_BEAGLE_OFFSETS_H__ */ + diff --git a/include/l4/platform/beagle/platform.h b/include/l4/platform/beagle/platform.h new file mode 100644 index 0000000..b23174f --- /dev/null +++ b/include/l4/platform/beagle/platform.h @@ -0,0 +1,18 @@ +#ifndef __BEAGLE_PLATFORM_H__ +#define __BEAGLE_PLATFORM_H__ +/* + * Platform specific ties between drivers and generic APIs used by the kernel. + * E.g. system timer and console. + * + * Copyright (C) Bahadir Balban 2007 + */ + +#include INC_PLAT(offsets.h) +#include INC_GLUE(memlayout.h) +#include +#include + +void platform_timer_start(void); + +void platform_test_cpucycles(void); +#endif /* __BEAGLE_PLATFORM_H__ */ diff --git a/include/l4/platform/beagle/timer.h b/include/l4/platform/beagle/timer.h new file mode 100644 index 0000000..3f0ad95 --- /dev/null +++ b/include/l4/platform/beagle/timer.h @@ -0,0 +1,13 @@ +/* + * Platform encapsulation over timer driver. + * + * Copyright (C) 2007 Bahadir Balban + * + */ + +#ifndef __PLATFORM_BEAGLE_TIMER_H__ +#define __PLATFORM_BEAGLE_TIMER_H__ + +#include + +#endif /* __PLATFORM_BEAGLE_TIMER_H__ */ diff --git a/include/l4/platform/beagle/uart.h b/include/l4/platform/beagle/uart.h new file mode 100644 index 0000000..0478dda --- /dev/null +++ b/include/l4/platform/beagle/uart.h @@ -0,0 +1,13 @@ +/* + * Platform specific ties to generic uart functions that putc expects. + * + * Copyright (C) 2007 Bahadir Balban + * + */ + +#ifndef __PLATFORM_BEAGLE_UART_H__ +#define __PLATFORM_BEAGLE_UART_H__ + +#include + +#endif /* __PLATFORM_BEAGLE_UART_H__ */ diff --git a/include/l4/platform/eb/irq.h b/include/l4/platform/eb/irq.h index 3c17bee..4a3e3bd 100644 --- a/include/l4/platform/eb/irq.h +++ b/include/l4/platform/eb/irq.h @@ -1,26 +1,20 @@ +/* + * Copyright (C) 2009 B Labs Ltd. + */ + #ifndef __PLATFORM_IRQ_H__ #define __PLATFORM_IRQ_H__ -/* TODO: Not sure about this, need to check */ -#define IRQ_CHIPS_MAX 4 -#define IRQS_MAX 96 +/* Actually there are 4 GIC's on the EB, only 2 are used for tile site 1 */ +#define IRQ_CHIPS_MAX 2 + +#if defined(CONFIG_CPU_ARM11MPCORE) || defined (CONFIG_CPU_CORTEXA9) +#define IRQS_MAX 64 +#else +#define IRQS_MAX 96 +#endif /* - * IRQ indices, - * GIC 0 and 1 are for logic tile 1 - * GIC 2 and 3 are for logic tile 2 - */ -#define IRQ_TIMER01 4 -#define IRQ_TIMER23 5 -#define IRQ_RTC 10 -#define IRQ_UART0 12 -#define IRQ_UART1 13 -#define IRQ_UART2 14 -#define IRQ_UART3 15 - -/* - * TODO: Seems like GIC0 and GIC1 are cascaded for logic tile1 - * and GIC2 and GIC3 are cascaded for logic tile 2. * Interrupt Distribution: * 0-31: Used as SI provided by distributed interrupt controller * 32-63: Externel Peripheral Interrupts @@ -28,4 +22,57 @@ * 72-79: Interrupts from tile site 2 * 80-95: PCI and reserved Interrupts */ +#define EB_GIC_IRQ_OFFSET 32 +#define EB_IRQ_WATCHDOG (EB_GIC_IRQ_OFFSET + 0) +#define EB_IRQ_SOFTINT (EB_GIC_IRQ_OFFSET + 1) +#define EB_IRQ_COMRX (EB_GIC_IRQ_OFFSET + 2) +#define EB_IRQ_COMTX (EB_GIC_IRQ_OFFSET + 3) +#define EB_IRQ_TIMER01 (EB_GIC_IRQ_OFFSET + 4) +#define EB_IRQ_TIMER23 (EB_GIC_IRQ_OFFSET + 5) +#define EB_IRQ_GPIO0 (EB_GIC_IRQ_OFFSET + 6) +#define EB_IRQ_GPIO1 (EB_GIC_IRQ_OFFSET + 7) +#define EB_IRQ_GPIO2 (EB_GIC_IRQ_OFFSET + 8) + +#define EB_IRQ_RTC (EB_GIC_IRQ_OFFSET + 10) +#define EB_IRQ_UART0 (EB_GIC_IRQ_OFFSET + 12) +#define EB_IRQ_UART1 (EB_GIC_IRQ_OFFSET + 13) +#define EB_IRQ_UART2 (EB_GIC_IRQ_OFFSET + 14) +#define EB_IRQ_UART3 (EB_GIC_IRQ_OFFSET + 15) +#define EB_IRQ_SCI (EB_GIC_IRQ_OFFSET + 16) /* Smart Card Interface */ +#define EB_IRQ_MCI0 (EB_GIC_IRQ_OFFSET + 17) +#define EB_IRQ_MCI1 (EB_GIC_IRQ_OFFSET + 18) +#define EB_IRQ_AACI (EB_GIC_IRQ_OFFSET + 19) /* Advanced Audio codec */ +#define EB_IRQ_KMI0 (EB_GIC_IRQ_OFFSET + 20) /* Keyboard */ +#define EB_IRQ_KMI1 (EB_GIC_IRQ_OFFSET + 21) /* Mouse */ +#define EB_IRQ_LCD (EB_GIC_IRQ_OFFSET + 20) /* Character LCD */ +#define EB_IRQ_DMAC (EB_GIC_IRQ_OFFSET + 20) /* DMA Controller */ + + +/* Interrupt Sources to ARM 11 MPCore or EB+A9 MPCore GIC */ +#define MPCORE_GIC_IRQ_AACI (EB_GIC_IRQ_OFFSET + 0) +#define MPCORE_GIC_IRQ_TIMER01 (EB_GIC_IRQ_OFFSET + 1) +#define MPCORE_GIC_IRQ_TIMER23 (EB_GIC_IRQ_OFFSET + 2) +#define MPCORE_GIC_IRQ_USB (EB_GIC_IRQ_OFFSET + 3) +#define MPCORE_GIC_IRQ_UART0 (EB_GIC_IRQ_OFFSET + 4) +#define MPCORE_GIC_IRQ_UART1 (EB_GIC_IRQ_OFFSET + 5) +#define MPCORE_GIC_IRQ_RTC (EB_GIC_IRQ_OFFSET + 6) +#define MPCORE_GIC_IRQ_KMI0 (EB_GIC_IRQ_OFFSET + 7) +#define MPCORE_GIC_IRQ_KMI1 (EB_GIC_IRQ_OFFSET + 8) +#define MPCORE_GIC_IRQ_ETH (EB_GIC_IRQ_OFFSET + 9) + +/* Interrupt from GIC1 on Base board */ +#define MPCORE_GIC_IRQ_EB_GIC1 (EB_GIC_IRQ_OFFSET + 10) +#define MPCORE_GIC_IRQ_EB_GIC2 (EB_GIC_IRQ_OFFSET + 11) +#define MPCORE_GIC_IRQ_EB_GIC3 (EB_GIC_IRQ_OFFSET + 12) +#define MPCORE_GIC_IRQ_EB_GIC4 (EB_GIC_IRQ_OFFSET + 13) + +#if defined (CONFIG_CPU_ARM11MPCORE) || defined (CONFIG_CPU_CORTEXA9) +#define IRQ_TIMER0 MPCORE_GIC_IRQ_TIMER01 +#define IRQ_TIMER1 MPCORE_GIC_IRQ_TIMER23 +#else +#define IRQ_TIMER0 EB_IRQ_TIMER01 +#define IRQ_TIMER1 EB_IRQ_TIMER23 +#endif + + #endif /* __PLATFORM_IRQ_H__ */ diff --git a/include/l4/platform/eb/offsets.h b/include/l4/platform/eb/offsets.h index eb411ad..41451ef 100644 --- a/include/l4/platform/eb/offsets.h +++ b/include/l4/platform/eb/offsets.h @@ -1,71 +1,61 @@ /* * Describes physical memory layout of EB platform. * - * Copyright (C) 2007 Bahadir Balban + * This only include physical and memory offsets that + * are not included in realview/offsets.h + * + * Copyright (C) 2009 B Labs Ltd. + * Author: Prem Mallappa */ #ifndef __PLATFORM_EB_OFFSETS_H__ #define __PLATFORM_EB_OFFSETS_H__ -/* Physical memory base */ -#define PHYS_MEM_START 0x00000000 /* inclusive */ -#define PHYS_MEM_END 0x10000000 /* 256 MB, exclusive */ - -/* - * These bases taken from where kernel is `physically' linked at, - * also used to calculate virtual-to-physical translation offset. - * See the linker script for their sources. PHYS_ADDR_BASE can't - * use a linker variable because it's referred from assembler. - */ -#define PHYS_ADDR_BASE 0x100000 - -/* Device memory base */ -#define EB_DEV_PHYS 0x10000000 +#include /* Device offsets in physical memory */ -#define EB_SYSTEM_REGISTERS 0x10000000 /* System registers */ -#define EB_SYSCTRL_BASE 0x10001000 /* System controller */ -#define EB_UART0_BASE 0x10009000 /* UART 0 */ -#define EB_UART1_BASE 0x1000A000 /* UART 1 */ -#define EB_UART2_BASE 0x1000B000 /* UART 2 */ -#define EB_UART3_BASE 0x1000C000 /* UART 3 */ -#define EB_WATCHDOG0_BASE 0x10010000 /* WATCHDOG */ -#define EB_TIMER01_BASE 0x10011000 /* TIMER 0-1 */ -#define EB_TIMER23_BASE 0x10012000 /* TIMER 2-3 */ -#define EB_RTC_BASE 0x10017000 /* RTC interface */ -#define EB_GIC0_BASE 0x10040000 /* GIC 0 */ -#define EB_GIC1_BASE 0x10050000 /* GIC 1 */ -#define EB_GIC2_BASE 0x10060000 /* GIC 2 */ -#define EB_GIC3_BASE 0x10070000 /* GIC 3 */ +#define PLATFORM_GIC1_BASE 0x10040000 /* GIC 1 */ +#define PLATFORM_GIC2_BASE 0x10050000 /* GIC 2 */ +#define PLATFORM_GIC3_BASE 0x10060000 /* GIC 3 */ +#define PLATFORM_GIC4_BASE 0x10070000 /* GIC 4 */ -/* - * Uart virtual address until a file-based console access - * is available for userspace - */ -#define USERSPACE_UART_BASE 0x500000 +#define MPCORE_PRIVATE_VBASE (IO_AREA0_VADDR + (13 * DEVICE_PAGE)) -/* - * Device offsets in virtual memory. They offset to some virtual - * device base address. Each page on this virtual base is consecutively - * allocated to devices. Nice and smooth. - */ -#define EB_SYSREGS_VOFFSET 0x00000000 -#define EB_SYSCTRL_VOFFSET 0x00001000 -#define EB_UART0_VOFFSET 0x00002000 -#define EB_TIMER01_VOFFSET 0x00003000 -#define EB_GIC0_VOFFSET 0x00004000 -#define EB_GIC1_VOFFSET 0x00005000 -#define EB_GIC2_VOFFSET 0x00006000 -#define EB_GIC3_VOFFSET 0x00007000 +#if defined (CONFIG_CPU_CORTEXA9) +#define MPCORE_PRIVATE_BASE 0x1F000000 +#endif /* End CORTEXA9 */ -#define EB_SYSREGS_VBASE (IO_AREA0_VADDR + EB_SYSREGS_VOFFSET) -#define EB_SYSCTRL_VBASE (IO_AREA0_VADDR + EB_SYSCTRL_VOFFSET) -#define EB_UART0_VBASE (IO_AREA0_VADDR + EB_UART0_VOFFSET) -#define EB_TIMER01_VBASE (IO_AREA0_VADDR + EB_TIMER01_VOFFSET) -#define EB_GIC0_VBASE (IO_AREA0_VADDR + EB_GIC0_VOFFSET) -#define EB_GIC1_VBASE (IO_AREA0_VADDR + EB_GIC1_VOFFSET) -#define EB_GIC2_VBASE (IO_AREA0_VADDR + EB_GIC2_VOFFSET) -#define EB_GIC3_VBASE (IO_AREA0_VADDR + EB_GIC3_VOFFSET) +#if defined (CONFIG_CPU_ARM11MPCORE) +#if defined REV_C || defined REV_D +#define MPCORE_PRIVATE_BASE 0x1F000000 +#else /* REV_B and QEMU */ +#define MPCORE_PRIVATE_BASE 0x10100000 +#endif /* End REV_B and QEMU */ +#endif /* End ARM11MPCORE */ + +#if defined (CONFIG_CPU_CORTEXA9) || defined (CONFIG_CPU_ARM11MPCORE) +/* MPCore private memory region */ +#define SCU_BASE MPCORE_PRIVATE_BASE +#define SCU_VBASE MPCORE_PRIVATE_VBASE +#define GIC0_CPU_VBASE (MPCORE_PRIVATE_VBASE + 0x100) +#define GIC0_DIST_VBASE (MPCORE_PRIVATE_VBASE + 0x1000) +#endif /* End CORTEXA9 || ARM11MPCORE */ + +#define GIC1_CPU_VBASE (PLATFORM_GIC1_VBASE + 0x0) +#define GIC2_CPU_VBASE (PLATFORM_GIC2_VBASE + 0x0) +#define GIC3_CPU_VBASE (PLATFORM_GIC3_VBASE + 0x0) +#define GIC4_CPU_VBASE (PLATFORM_GIC4_VBASE + 0x0) + +#define GIC1_DIST_VBASE (PLATFORM_GIC1_VBASE + 0x1000) +#define GIC2_DIST_VBASE (PLATFORM_GIC2_VBASE + 0x1000) +#define GIC3_DIST_VBASE (PLATFORM_GIC3_VBASE + 0x1000) +#define GIC4_DIST_VBASE (PLATFORM_GIC4_VBASE + 0x1000) + +#if defined (CONFIG_CPU_ARM11MPCORE) || defined (CONFIG_CPU_CORTEXA9) +#define PLATFORM_IRQCTRL0_VIRTUAL EB_GIC0_VBASE +#endif + +#define PLATFORM_IRQCTRL1_VIRTUAL EB_GIC1_VBASE #endif /* __PLATFORM_EB_OFFSETS_H__ */ diff --git a/include/l4/platform/eb/platform.h b/include/l4/platform/eb/platform.h index cebed1a..5d38f35 100644 --- a/include/l4/platform/eb/platform.h +++ b/include/l4/platform/eb/platform.h @@ -1,28 +1,18 @@ -#ifndef __EB_PLATFORM_H__ -#define __EB_PLATFORM_H__ /* * Platform specific ties between drivers and generic APIs used by the kernel. * E.g. system timer and console. * - * Copyright (C) Bahadir Balban 2007 + * Copyright (C) 2009 B Labs Ltd. */ +#ifndef __EB_PLATFORM_H__ +#define __EB_PLATFORM_H__ -#include INC_PLAT(offsets.h) -#include INC_GLUE(memlayout.h) +#include INC_PLAT(sysctrl.h) +#include +#include -#define PLATFORM_CONSOLE0_BASE EB_UART0_VBASE -#define PLATFORM_TIMER0_BASE EB_TIMER01_VBASE -#define PLATFORM_SP810_BASE EB_SYSCTRL_VBASE +void cpu_extra_init(void); +void init_platform_irq_controller(); +void init_platform_devices(); -/* Total number of timers present in this platform */ -#define TOTAL_TIMERS 4 - -#define PLATFORM_TIMER0 0 -#define PLATFORM_TIMER1 1 -#define PLATFORM_TIMER2 2 -#define PLATFORM_TIMER3 3 - -void platform_irq_enable(int irq); -void platform_irq_disable(int irq); -void timer_start(void); #endif /* __EB_PLATFORM_H__ */ diff --git a/include/l4/platform/eb/sysctrl.h b/include/l4/platform/eb/sysctrl.h new file mode 100644 index 0000000..94fb459 --- /dev/null +++ b/include/l4/platform/eb/sysctrl.h @@ -0,0 +1,95 @@ +#ifndef __EB_SYSCTRL_H__ +#define __EB_SYSCTRL_H__ +/* TODO: Better to stick this file in a ARM specific folder as most realview boards + * tend to have this component + */ +#define SYS_ID 0x0000 +#define SYS_SW 0x0004 +#define SYS_LED 0x0008 + +#define SYS_OSC0 0x000C +#define SYS_OSC1 0x0010 +#define SYS_OSC2 0x0014 +#define SYS_OSC3 0x0018 +#define SYS_OSC4 0x001C + +#define SYS_LOCK 0x0020 +#define SYS_100HZ 0x0024 + +#define SYS_CFGDATA0 0x0028 +#define SYS_CFGDATA1 0x002C + +#define SYS_FLAGS 0x0030 +#define SYS_FLAGS_SET 0x0030 +#define SYS_FLAGS_CLR 0x0034 +#define SYS_NVFLAGS 0x0038 +#define SYS_NVFLAGS_SET 0x0038 +#define SYS_NVFLAGS_CLR 0x003C + +#define SYS_PCICTL 0x0044 +#define SYS_MCI 0x0048 +#define SYS_FLASH 0x004C +#define SYS_CLCD 0x0050 +#define SYS_CLCDSER 0x0054 +#define SYS_BOOTCS 0x0058 + +#define SYS_24MHZ 0x005C +#define SYS_MISC 0x0060 +#define SYS_DMAPSR0 0x0064 +#define SYS_DMAPSR1 0x0068 +#define SYS_DMAPSR2 0x006C +#define SYS_IOSEL 0x0070 +#define SYS_PLDCTL1 0x0074 +#define SYS_PLDCTL2 0x0078 + +#define SYS_BUSID 0x0080 +#define SYS_PROCID1 0x0084 +#define SYS_PROCID0 0x0088 + +#define SYS_OSCRESET0 0x008C +#define SYS_OSCRESET1 0x0090 +#define SYS_OSCRESET2 0x0094 +#define SYS_OSCRESET3 0x0098 +#define SYS_OSCRESET4 0x009C + + +/* System Controller Lock/Unlock */ +#define SYSCTRL_LOCK 0xFF +#define SYSCTRL_UNLOCK 0xA05F + + +#define ID_MASK_REV 0xF0000000 +#define ID_MASK_HBI 0x0FFF0000 +#define ID_MASK_BUILD 0x0000F000 +#define ID_MASK_ARCH 0x00000F00 +#define ID_MASK_FPGA 0x000000FF + + +#define SW_MASK_BOOTSEL 0x0000FF00 +#define SW_MASK_GP 0x000000FF + +#define LED_MASK_LED 0x000000FF + +#define FLASH_WRITE_EN 0x1 +#define FLASH_WRITE_DIS 0x0 + +#define CLCD_QVGA (0 << 8) /* 320x240 */ +#define CLDE_VGA (1 << 8) /* 640x480 */ +#define CLCD_SMALL (2 << 8) /* 220x176 */ +#define CLCD_SSP_CS (1 << 7) /* SSP Chip Select */ +#define CLCD_TS_EN (1 << 6) /* Touch Screen Enable */ +/* Different Voltages */ +#define CLCD_NEG_EN (1 << 5) +#define CLCD_3V5V_EN (1 << 4) +#define CLCD_POS_EN (1 << 3) +#define CLCD_IO_ON (1 << 2) + + +/* Normal without DCC, no FIQ, recommended for SMP */ +#define PLD_CTRL1_INTMOD_WITHOUT_DCC (1 << 22) +/* Not Recommended */ +#define PLD_CTRL1_INTMOD_WITH_DCC (2 << 22) +/* For single cpu such as 1136 */ +#define PLD_CTRL1_INTMOD_LEGACY (4 << 22) + +#endif /* __EB_SYSCTRL_H__ */ diff --git a/include/l4/platform/eb/uart.h b/include/l4/platform/eb/uart.h index 69bb0da..a192be6 100644 --- a/include/l4/platform/eb/uart.h +++ b/include/l4/platform/eb/uart.h @@ -1,20 +1,6 @@ -/* - * Platform specific ties to generic uart functions that putc expects. - * - * Copyright (C) 2007 Bahadir Balban - * - */ +#ifndef __EB_UART_H__ +#define __EB_UART_H__ -#ifndef __PLATFORM_EB_UART_H__ -#define __PLATFORM_EB_UART_H__ +#include -#include INC_PLAT(offsets.h) -#include INC_GLUE(memlayout.h) - -#define PLATFORM_CONSOLE_BASE EB_UART0_VBASE -#include - -void uart_init(void); -void uart_putc(char c); - -#endif /* __PLATFORM_EB_UART_H__ */ +#endif /* __EB_UART_H__ */ diff --git a/include/l4/platform/pb11mpcore/irq.h b/include/l4/platform/pb11mpcore/irq.h index 9773759..6ed2d3e 100644 --- a/include/l4/platform/pb11mpcore/irq.h +++ b/include/l4/platform/pb11mpcore/irq.h @@ -6,10 +6,10 @@ #define IRQS_MAX 96 /* IRQ indices. */ -#define IRQ_TIMER01 36 -#define IRQ_TIMER23 37 -#define IRQ_TIMER45 73 -#define IRQ_TIMER67 74 +#define IRQ_TIMER0 36 +#define IRQ_TIMER1 37 +#define IRQ_TIMER2 73 +#define IRQ_TIMER3 74 #define IRQ_RTC 42 #define IRQ_UART0 44 #define IRQ_UART1 45 diff --git a/include/l4/platform/pb11mpcore/offsets.h b/include/l4/platform/pb11mpcore/offsets.h index 61c23ae..4014acc 100644 --- a/include/l4/platform/pb11mpcore/offsets.h +++ b/include/l4/platform/pb11mpcore/offsets.h @@ -1,77 +1,35 @@ /* * Describes physical memory layout of PB11MPCORE platform. * + * This only include physical and memory offsets that + * are not included in realview/offsets.h + * * Copyright (C) 2007 Bahadir Balban */ #ifndef __PLATFORM_PB11MPCORE_OFFSETS_H__ #define __PLATFORM_PB11MPCORE_OFFSETS_H__ -/* Physical memory base */ -#define PHYS_MEM_START 0x00000000 /* inclusive */ -#define PHYS_MEM_END 0x10000000 /* 256 MB, exclusive */ - -/* - * These bases taken from where kernel is `physically' linked at, - * also used to calculate virtual-to-physical translation offset. - * See the linker script for their sources. PHYS_ADDR_BASE can't - * use a linker variable because it's referred from assembler. - */ -#define PHYS_ADDR_BASE 0x100000 - -/* Device memory base */ -#define PB11MPCORE_DEV_PHYS 0x10000000 +#include /* Device offsets in physical memory */ -#define PB11MPCORE_SYSTEM_REGISTERS 0x10000000 /* System registers */ -#define PB11MPCORE_SYSCTRL0_BASE 0x10001000 /* System controller 0 */ -#define PB11MPCORE_UART0_BASE 0x10009000 /* UART 0 */ -#define PB11MPCORE_UART1_BASE 0x1000A000 /* UART 1 */ -#define PB11MPCORE_UART2_BASE 0x1000B000 /* UART 2 */ -#define PB11MPCORE_UART3_BASE 0x1000C000 /* UART 3 */ -#define PB11MPCORE_WATCHDOG0_BASE 0x1000F000 /* WATCHDOG 0 */ -#define PB11MPCORE_WATCHDOG1_BASE 0x10010000 /* WATCHDOG 1 */ -#define PB11MPCORE_TIMER01_BASE 0x10011000 /* TIMER 0-1 */ -#define PB11MPCORE_TIMER23_BASE 0x10012000 /* TIMER 2-3 */ -#define PB11MPCORE_RTC_BASE 0x10017000 /* RTC interface */ -#define PB11MPCORE_TIMER45_BASE 0x10018000 /* TIMER 4-5 */ -#define PB11MPCORE_TIMER67_BASE 0x10019000 /* TIMER 6-7 */ -#define PB11MPCORE_SYSCTRL1_BASE 0x1001A000 /* System controller 1 */ -#define PB11MPCORE_GIC0_BASE 0x1E000000 /* GIC 0 */ -#define PB11MPCORE_GIC1_BASE 0x1E010000 /* GIC 1 */ -#define PB11MPCORE_GIC2_BASE 0x1E020000 /* GIC 2 */ -#define PB11MPCORE_GIC3_BASE 0x1E030000 /* GIC 3 */ - -/* - * Uart virtual address until a file-based console access - * is available for userspace - */ -#define USERSPACE_UART_BASE 0x500000 +#define PLATFORM_TIMER2_BASE 0x10018000 /* TIMER 4-5 */ +#define PLATFORM_TIMER3_BASE 0x10019000 /* TIMER 6-7 */ +#define PLATFORM_SYSCTRL1_BASE 0x1001A000 /* System controller 1 */ +#define PLATFORM_GIC0_BASE 0x1E000000 /* GIC 0 */ +#define PLATFORM_GIC1_BASE 0x1E010000 /* GIC 1 */ +#define PLATFORM_GIC2_BASE 0x1E020000 /* GIC 2 */ +#define PLATFORM_GIC3_BASE 0x1E030000 /* GIC 3 */ /* * Device offsets in virtual memory. They offset to some virtual * device base address. Each page on this virtual base is consecutively * allocated to devices. Nice and smooth. */ -#define PB11MPCORE_SYSREGS_VOFFSET 0x00000000 -#define PB11MPCORE_SYSCTRL0_VOFFSET 0x00001000 -#define PB11MPCORE_SYSCTRL1_VOFFSET 0x00002000 -#define PB11MPCORE_UART0_VOFFSET 0x00003000 -#define PB11MPCORE_TIMER01_VOFFSET 0x00004000 -#define PB11MPCORE_GIC0_VOFFSET 0x00005000 -#define PB11MPCORE_GIC1_VOFFSET 0x00006000 -#define PB11MPCORE_GIC2_VOFFSET 0x00007000 -#define PB11MPCORE_GIC3_VOFFSET 0x00008000 -#define PB11MPCORE_SYSREGS_VBASE (IO_AREA0_VADDR + PB11MPCORE_SYSREGS_VOFFSET) -#define PB11MPCORE_SYSCTRL0_VBASE (IO_AREA0_VADDR + PB11MPCORE_SYSCTRL0_VOFFSET) -#define PB11MPCORE_SYSCTRL1_VBASE (IO_AREA0_VADDR + PB11MPCORE_SYSCTRL1_VOFFSET) -#define PB11MPCORE_UART0_VBASE (IO_AREA0_VADDR + PB11MPCORE_UART0_VOFFSET) -#define PB11MPCORE_TIMER01_VBASE (IO_AREA0_VADDR + PB11MPCORE_TIMER01_VOFFSET) -#define PB11MPCORE_GIC0_VBASE (IO_AREA0_VADDR + PB11MPCORE_GIC0_VOFFSET) -#define PB11MPCORE_GIC1_VBASE (IO_AREA0_VADDR + PB11MPCORE_GIC1_VOFFSET) -#define PB11MPCORE_GIC2_VBASE (IO_AREA0_VADDR + PB11MPCORE_GIC2_VOFFSET) -#define PB11MPCORE_GIC3_VBASE (IO_AREA0_VADDR + PB11MPCORE_GIC3_VOFFSET) +/* Add userspace devices here as they become necessary for irqs */ + +/* Add size of various user space devices, to be used in capability generation */ #endif /* __PLATFORM_PB11MPCORE_OFFSETS_H__ */ diff --git a/include/l4/platform/pb11mpcore/platform.h b/include/l4/platform/pb11mpcore/platform.h index 1fb4153..3b027d4 100644 --- a/include/l4/platform/pb11mpcore/platform.h +++ b/include/l4/platform/pb11mpcore/platform.h @@ -1,5 +1,5 @@ -#ifndef __PB11MPCORE_PLATFORM_H__ -#define __PB11MPCORE_PLATFORM_H__ +#ifndef __PBA9_PLATFORM_H__ +#define __PBA9_PLATFORM_H__ /* * Platform specific ties between drivers and generic APIs used by the kernel. * E.g. system timer and console. @@ -7,28 +7,6 @@ * Copyright (C) Bahadir Balban 2007 */ -#include INC_PLAT(offsets.h) -#include INC_GLUE(memlayout.h) +#include -#define PLATFORM_CONSOLE0_BASE PB11MPCORE_UART0_VBASE -#define PLATFORM_TIMER0_BASE PB11MPCORE_TIMER01_VBASE -/* Need to add syscntrl1 here */ -#define PLATFORM_SP810_BASE PB11MPCORE_SYSCTRL0_VBASE - -/* Total number of timers present in this platform */ -#define TOTAL_TIMERS 8 - -#define PLATFORM_TIMER0 0 -#define PLATFORM_TIMER1 1 -#define PLATFORM_TIMER2 2 -#define PLATFORM_TIMER3 3 -#define PLATFORM_TIMER4 4 -#define PLATFORM_TIMER5 5 -#define PLATFORM_TIMER6 6 -#define PLATFORM_TIMER7 7 - -void platform_irq_enable(int irq); -void platform_irq_disable(int irq); -void timer_start(void); - -#endif /* __PB11MPCORE_PLATFORM_H__ */ +#endif /* __PBA9_PLATFORM_H__ */ diff --git a/include/l4/platform/pb11mpcore/uart.h b/include/l4/platform/pb11mpcore/uart.h index fb37ce9..6e6db45 100644 --- a/include/l4/platform/pb11mpcore/uart.h +++ b/include/l4/platform/pb11mpcore/uart.h @@ -1,20 +1,6 @@ -/* - * Platform specific ties to generic uart functions that putc expects. - * - * Copyright (C) 2007 Bahadir Balban - * - */ +#ifndef __PB11MPCORE_UART_H__ +#define __PB11MPCORE_UART_H__ -#ifndef __PLATFORM_PB11MPCORE_UART_H__ -#define __PLATFORM_PB11MPCORE_UART_H__ +#include -#include INC_PLAT(offsets.h) -#include INC_GLUE(memlayout.h) - -#define PLATFORM_CONSOLE_BASE PB11MPCORE_UART0_VBASE -#include - -void uart_init(void); -void uart_putc(char c); - -#endif /* __PLATFORM_PB11MPCORE_UART_H__ */ +#endif /* __PB11MPCORE_UART_H__ */ diff --git a/include/l4/platform/pb926/irq.h b/include/l4/platform/pb926/irq.h index b336fec..2ac4a01 100644 --- a/include/l4/platform/pb926/irq.h +++ b/include/l4/platform/pb926/irq.h @@ -16,18 +16,19 @@ #define SIC_CHIP_OFFSET 32 /* Maximum irqs on VIC and SIC */ -#define VIC_IRQS_MAX PL190_IRQS_MAX -#define SIC_IRQS_MAX PL190_SIC_IRQS_MAX +#define VIC_IRQS_MAX 32 +#define SIC_IRQS_MAX 32 #define IRQS_MAX VIC_IRQS_MAX + SIC_IRQS_MAX /* Vectored Interrupt Controller local IRQ numbers */ -#define VIC_IRQ_TIMER01 4 -#define VIC_IRQ_TIMER23 5 +#define VIC_IRQ_TIMER0 4 +#define VIC_IRQ_TIMER1 5 #define VIC_IRQ_RTC 10 #define VIC_IRQ_UART0 12 #define VIC_IRQ_UART1 13 #define VIC_IRQ_UART2 14 +#define VIC_IRQ_CLCD0 16 #define VIC_IRQ_SIC 31 /* Secondary Interrupt controller local IRQ numbers */ @@ -35,12 +36,13 @@ #define SIC_IRQ_UART3 6 /* Global irq numbers, note these should reflect global device names */ -#define IRQ_TIMER0 (VIC_IRQ_TIMER01 + VIC_CHIP_OFFSET) -#define IRQ_TIMER1 (VIC_IRQ_TIMER23 + VIC_CHIP_OFFSET) +#define IRQ_TIMER0 (VIC_IRQ_TIMER0 + VIC_CHIP_OFFSET) +#define IRQ_TIMER1 (VIC_IRQ_TIMER1 + VIC_CHIP_OFFSET) #define IRQ_RTC (VIC_IRQ_RTC + VIC_CHIP_OFFSET) #define IRQ_UART0 (VIC_IRQ_UART0 + VIC_CHIP_OFFSET) #define IRQ_UART1 (VIC_IRQ_UART1 + VIC_CHIP_OFFSET) #define IRQ_UART2 (VIC_IRQ_UART2 + VIC_CHIP_OFFSET) +#define IRQ_CLCD0 (VIC_IRQ_CLCD0 + VIC_CHIP_OFFSET) #define IRQ_SIC (VIC_IRQ_SIC + VIC_CHIP_OFFSET) #define IRQ_SICSWI (SIC_IRQ_SWI + SIC_CHIP_OFFSET) diff --git a/include/l4/platform/pb926/offsets.h b/include/l4/platform/pb926/offsets.h index 262ef51..393f131 100644 --- a/include/l4/platform/pb926/offsets.h +++ b/include/l4/platform/pb926/offsets.h @@ -8,48 +8,53 @@ #define __PLATFORM_PB926_OFFSETS_H__ /* Physical memory base */ -#define PHYS_MEM_START 0x00000000 /* inclusive */ -#define PHYS_MEM_END 0x08000000 /* 128 MB, exclusive */ - -/* Device offsets in physical memory */ -#define PB926_SYSTEM_REGISTERS 0x10000000 /* System registers */ -#define PB926_SYSCTRL_BASE 0x101E0000 /* System controller */ -#define PB926_WATCHDOG_BASE 0x101E1000 /* Watchdog */ -#define PB926_TIMER01_BASE 0x101E2000 /* Timers 0 and 1 */ -#define PB926_TIMER23_BASE 0x101E3000 /* Timers 2 and 3 */ -#define PB926_RTC_BASE 0x101E8000 /* Real Time Clock */ -#define PB926_VIC_BASE 0x10140000 /* Primary Vectored IC */ -#define PB926_SIC_BASE 0x10003000 /* Secondary IC */ -#define PB926_UART0_BASE 0x101F1000 /* Console port (UART0) */ -#define PB926_UART1_BASE 0x101F2000 /* Console port (UART1) */ -#define PB926_UART2_BASE 0x101F3000 /* Console port (UART2) */ -#define PB926_UART3_BASE 0x10009000 /* Console port (UART3) */ -#define PB926_CLCD_BASE 0x10120000 /* Color LCD */ +#define PLATFORM_PHYS_MEM_START 0x00000000 /* inclusive */ +#define PLATFORM_PHYS_MEM_END 0x08000000 /* 128 MB, exclusive */ /* - * Uart virtual address until a file-based console access - * is available for userspace + * Device offsets in physical memory + * Naming of devices done starting with 0 subscript, + * as we use these names for device capability */ -#define USERSPACE_CONSOLE_VIRTUAL 0x500000 +#define PLATFORM_SYSTEM_REGISTERS 0x10000000 /* System registers */ +#define PLATFORM_SYSCTRL_BASE 0x101E0000 /* System controller */ +#define PLATFORM_WATCHDOG_BASE 0x101E1000 /* Watchdog */ +#define PLATFORM_TIMER0_BASE 0x101E2000 /* Timers 0 and 1 */ +#define PLATFORM_TIMER1_BASE 0x101E3000 /* Timers 2 and 3 */ +#define PLATFORM_RTC_BASE 0x101E8000 /* Real Time Clock */ +#define PLATFORM_VIC_BASE 0x10140000 /* Primary Vectored IC */ +#define PLATFORM_SIC_BASE 0x10003000 /* Secondary IC */ +#define PLATFORM_UART0_BASE 0x101F1000 /* Console port (UART0) */ +#define PLATFORM_UART1_BASE 0x101F2000 /* Console port (UART1) */ +#define PLATFORM_UART2_BASE 0x101F3000 /* Console port (UART2) */ +#define PLATFORM_UART3_BASE 0x10009000 /* Console port (UART3) */ +#define PLATFORM_CLCD0_BASE 0x10120000 /* Color LCD */ /* * Device offsets in virtual memory. They offset to some virtual * device base address. Each page on this virtual base is consecutively * allocated to devices. Nice and smooth. */ -#define PB926_TIMER01_VOFFSET 0x00000000 -#define PB926_UART0_VOFFSET 0x00001000 -#define PB926_VIC_VOFFSET 0x00002000 -#define PB926_SIC_VOFFSET 0x00003000 -#define PB926_SYSREGS_VOFFSET 0x00005000 -#define PB926_SYSCTRL_VOFFSET 0x00006000 +#define DEVICE_PAGE 0x1000 -#define PLATFORM_CONSOLE_VIRTUAL (IO_AREA0_VADDR + PB926_UART0_VOFFSET) -#define PLATFORM_TIMER0_VIRTUAL (IO_AREA0_VADDR + PB926_TIMER01_VOFFSET) -#define PLATFORM_SYSCTRL_VIRTUAL (IO_AREA0_VADDR + PB926_SYSCTRL_VOFFSET) -#define PLATFORM_IRQCTRL0_VIRTUAL (IO_AREA0_VADDR + PB926_VIC_VOFFSET) -#define PLATFORM_IRQCTRL1_VIRTUAL (IO_AREA0_VADDR + PB926_SIC_VOFFSET) +#define PLATFORM_TIMER0_VBASE (IO_AREA0_VADDR + (0 * DEVICE_PAGE)) +#define PLATFORM_CONSOLE_VBASE (IO_AREA0_VADDR + (1 * DEVICE_PAGE)) +#define PLATFORM_IRQCTRL0_VBASE (IO_AREA0_VADDR + (2 * DEVICE_PAGE)) +#define PLATFORM_IRQCTRL1_VBASE (IO_AREA0_VADDR + (3 * DEVICE_PAGE)) +#define PLATFORM_SYSCTRL_VBASE (IO_AREA0_VADDR + (4 * DEVICE_PAGE)) +/* Add userspace devices here as they become necessary for irqs */ +#define PLATFORM_TIMER1_VBASE (IO_AREA0_VADDR + (6 * DEVICE_PAGE)) + +/* The SP810 system controller offsets */ +#define SP810_BASE PLATFORM_SYSCTRL_VBASE +#define SP810_SCCTRL (SP810_BASE + 0x0) + +/* Add size of various user space devices, to be used in capability generation */ +#define PLATFORM_UART1_SIZE 0x1000 +#define PLATFORM_UART2_SIZE 0x1000 +#define PLATFORM_UART3_SIZE 0x1000 +#define PLATFORM_TIMER1_SIZE 0x1000 #endif /* __PLATFORM_PB926_OFFSETS_H__ */ diff --git a/include/l4/platform/pb926/platform.h b/include/l4/platform/pb926/platform.h index 9cba6d4..97cb5a1 100644 --- a/include/l4/platform/pb926/platform.h +++ b/include/l4/platform/pb926/platform.h @@ -7,46 +7,6 @@ * Copyright (C) Bahadir Balban 2007 */ -#include INC_PLAT(offsets.h) -#include INC_GLUE(memlayout.h) -#include -#include -#include - -/* Default console used by kernel */ -#define PLATFORM_CONSOLE_BASE PB926_UART0_BASE - -/* SP804 timer has TIMER1 at TIMER0 + 0x20 address */ -#define PLATFORM_TIMER0_BASE PB926_TIMER01_BASE - -/* Total number of timers present in this platform */ -#define TOTAL_TIMERS 4 - -#define PLATFORM_TIMER0 0 -#define PLATFORM_TIMER1 1 -#define PLATFORM_TIMER2 2 -#define PLATFORM_TIMER3 3 - -#define PB926_UART_SIZE 0x1000 -#define PB926_TIMER_SIZE 0x1000 -#define PB926_CLCD_SIZE 0x1000 - -#define PLATFORM_UART1_BASE PB926_UART1_BASE -#define PLATFORM_UART2_BASE PB926_UART2_BASE -#define PLATFORM_UART3_BASE PB926_UART3_BASE -#define PLATFORM_UART1_SIZE PB926_UART_SIZE -#define PLATFORM_UART2_SIZE PB926_UART_SIZE -#define PLATFORM_UART3_SIZE PB926_UART_SIZE - -#define PLATFORM_TIMER1_BASE PB926_TIMER23_BASE -#define PLATFORM_TIMER1_SIZE PB926_TIMER_SIZE - -#define PLATFORM_CLCD0_BASE PB926_CLCD_BASE -#define PLATFORM_CLCD0_SIZE PB926_CLCD_SIZE - -int platform_setup_device_caps(struct kernel_resources *kres); -void platform_irq_enable(int irq); -void platform_irq_disable(int irq); -void timer_start(void); +void platform_timer_start(void); #endif /* __PB926_PLATFORM_H__ */ diff --git a/include/l4/platform/pb926/timer.h b/include/l4/platform/pb926/timer.h new file mode 100644 index 0000000..38ed604 --- /dev/null +++ b/include/l4/platform/pb926/timer.h @@ -0,0 +1,13 @@ +/* + * Platform encapsulation over timer driver. + * + * Copyright (C) 2007 Bahadir Balban + * + */ + +#ifndef __PLATFORM_PB926_TIMER_H__ +#define __PLATFORM_PB926_TIMER_H__ + +#include + +#endif /* __PLATFORM_PB926_TIMER_H__ */ diff --git a/include/l4/platform/pb926/uart.h b/include/l4/platform/pb926/uart.h index ad356a9..e2fa6e1 100644 --- a/include/l4/platform/pb926/uart.h +++ b/include/l4/platform/pb926/uart.h @@ -8,12 +8,6 @@ #ifndef __PLATFORM_PB926_UART_H__ #define __PLATFORM_PB926_UART_H__ -#include INC_PLAT(offsets.h) -#include INC_GLUE(memlayout.h) - -#include - -void uart_init(void); -void uart_putc(char c); +#include #endif /* __PLATFORM_PB926_UART_H__ */ diff --git a/include/l4/platform/pba8/irq.h b/include/l4/platform/pba8/irq.h new file mode 100644 index 0000000..17ab678 --- /dev/null +++ b/include/l4/platform/pba8/irq.h @@ -0,0 +1,28 @@ + +#ifndef __PLATFORM_IRQ_H__ +#define __PLATFORM_IRQ_H__ + +/* + * Support for generic irq handling using platform irq controller (GIC) + * + * Copyright (C) 2007 Bahadir Balban + */ + +/* TODO: Not sure about this, need to check */ +#define IRQ_CHIPS_MAX 4 +#define IRQS_MAX 96 + +/* IRQ indices. */ +#define IRQ_UART0 44 +#define IRQ_UART1 45 +#define IRQ_UART2 46 +#define IRQ_UART3 47 + +/* General Purpose Timers */ +#define IRQ_TIMER0 36 +#define IRQ_TIMER1 37 +#define IRQ_TIMER2 73 +#define IRQ_TIMER3 74 + +#endif /* __PLATFORM_IRQ_H__ */ + diff --git a/include/l4/platform/pba8/offsets.h b/include/l4/platform/pba8/offsets.h new file mode 100644 index 0000000..fd59006 --- /dev/null +++ b/include/l4/platform/pba8/offsets.h @@ -0,0 +1,41 @@ +/* + * Describes physical memory layout of EB platform. + * + * This only include physical and memory offsets that + * are not included in realview/offsets.h + * + * Copyright (C) 2009 B Labs Ltd. + */ + +#ifndef __PLATFORM_PBA8_OFFSETS_H__ +#define __PLATFORM_PBA8_OFFSETS_H__ + +#include + +/* + * These bases taken from where kernel is `physically' linked at, + * also used to calculate virtual-to-physical translation offset. + * See the linker script for their sources. PHYS_ADDR_BASE can't + * use a linker variable because it's referred from assembler. + */ +#define PHYS_ADDR_BASE 0x100000 + +/* Device offsets in physical memory */ +#define PLATFORM_TIMER2_BASE 0x10018000 /* Timers 4 and 5 */ +#define PLATFORM_TIMER3_BASE 0x10019000 /* Timers 6 and 7 */ +#define PLATFORM_SYSCTRL1_BASE 0x1001A000 /* System controller1 */ +#define PLATFORM_GIC1_BASE 0x1E000000 /* GIC 1 */ +#define PLATFORM_GIC2_BASE 0x1E010000 /* GIC 2 */ +#define PLATFORM_GIC3_BASE 0x1E020000 /* GIC 3 */ +#define PLATFORM_GIC4_BASE 0x1E030000 /* GIC 4 */ + +/* + * Device offsets in virtual memory. They offset to some virtual + * device base address. Each page on this virtual base is consecutively + * allocated to devices. Nice and smooth. + * Make sure the offsets used here are not conflicting with the ones + * present in + */ + +#endif /* __PLATFORM_PBA8_OFFSETS_H__ */ + diff --git a/include/l4/platform/pba8/platform.h b/include/l4/platform/pba8/platform.h new file mode 100644 index 0000000..d5ba28e --- /dev/null +++ b/include/l4/platform/pba8/platform.h @@ -0,0 +1,16 @@ +/* + * Platform specific ties between drivers and generic APIs used by the kernel. + * E.g. system timer and console. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __PBA8_PLATFORM_H__ +#define __PBA8_PLATFORM_H__ + +#include +#include + +void init_platform_irq_controller(); +void init_platform_devices(); + +#endif /* __PBA8_PLATFORM_H__ */ diff --git a/include/l4/platform/pba8/uart.h b/include/l4/platform/pba8/uart.h new file mode 100644 index 0000000..2f018b9 --- /dev/null +++ b/include/l4/platform/pba8/uart.h @@ -0,0 +1,6 @@ +#ifndef __PBA8_UART_H__ +#define __PBA8_UART_H__ + +#include + +#endif /* __PBA8_UART_H__ */ diff --git a/include/l4/platform/pba9/irq.h b/include/l4/platform/pba9/irq.h new file mode 100644 index 0000000..dc64be3 --- /dev/null +++ b/include/l4/platform/pba9/irq.h @@ -0,0 +1,34 @@ +/* + * Support for generic irq handling using platform irq controller (GIC) + * + * Copyright (C) 2007 B Labs Ltd. + */ +#ifndef __PLATFORM_IRQ_H__ +#define __PLATFORM_IRQ_H__ + + +/* TODO: Not sure about this, need to check */ +#define IRQ_CHIPS_MAX 1 +#define IRQS_MAX 96 +#define IRQ_OFFSET 0 + +/* IRQ indices. */ +#define IRQ_TIMER0 34 +#define IRQ_TIMER1 35 +#define IRQ_RTC 36 +#define IRQ_UART0 37 +#define IRQ_UART1 38 +#define IRQ_UART2 39 +#define IRQ_UART3 40 +#define IRQ_CLCD0 46 + +/* + * Interrupt Distribution: + * 0-31: SI, provided by distributed interrupt controller + * 32-63: Externel peripheral interrupts + * 64-71: Tile site interrupt + * 72-95: Externel peripheral interrupts + */ + +#endif /* __PLATFORM_IRQ_H__ */ + diff --git a/include/l4/platform/pba9/offsets.h b/include/l4/platform/pba9/offsets.h new file mode 100644 index 0000000..8685503 --- /dev/null +++ b/include/l4/platform/pba9/offsets.h @@ -0,0 +1,35 @@ +/* + * Describes physical memory layout of pb926 platform. + * + * This only include physical and memory offsets that + * are not included in realview/offsets.h + * + * Copyright (C) 2010 B Labs Ltd. + * Author: Bahadir Balban + */ + +#ifndef __PLATFORM_PBA9_OFFSETS_H__ +#define __PLATFORM_PBA9_OFFSETS_H__ + +#include + +/* + * Device offsets in physical memory + * Naming of devices done starting with 0 subscript, + * as we use these names for device capability + */ +#define PLATFORM_TIMER2_BASE 0x10018000 /* Timers 2 and 3 */ +#define PLATFORM_TIMER3_BASE 0x10019000 /* Timers 2 and 3 */ +#define PLATFORM_SYSCTRL1_BASE 0x1001A000 /* System controller1 */ + +#define PLATFORM_GIC0_BASE 0x1E000000 /* GIC 0 */ + +#define MPCORE_PRIVATE_BASE 0x1E000000 +#define MPCORE_PRIVATE_VBASE (IO_AREA0_VADDR + (13 * DEVICE_PAGE)) + +#define SCU_BASE MPCORE_PRIVATE_BASE +#define SCU_VBASE MPCORE_PRIVATE_VBASE +#define GIC0_CPU_VBASE (MPCORE_PRIVATE_VBASE + 0x100) +#define GIC0_DIST_VBASE (MPCORE_PRIVATE_VBASE + 0x1000) + +#endif /* __PLATFORM_PBA9_OFFSETS_H__ */ diff --git a/include/l4/platform/pba9/platform.h b/include/l4/platform/pba9/platform.h new file mode 100644 index 0000000..3b027d4 --- /dev/null +++ b/include/l4/platform/pba9/platform.h @@ -0,0 +1,12 @@ +#ifndef __PBA9_PLATFORM_H__ +#define __PBA9_PLATFORM_H__ +/* + * Platform specific ties between drivers and generic APIs used by the kernel. + * E.g. system timer and console. + * + * Copyright (C) Bahadir Balban 2007 + */ + +#include + +#endif /* __PBA9_PLATFORM_H__ */ diff --git a/include/l4/platform/pba9/platsmp.h b/include/l4/platform/pba9/platsmp.h new file mode 100644 index 0000000..752827a --- /dev/null +++ b/include/l4/platform/pba9/platsmp.h @@ -0,0 +1,21 @@ +/* + * Copyright 2010 B Labs Ltd. + * Author: Prem Mallappa + */ + +#ifndef __VXA9_PLATSMP_H__ +#define __VXA9_PLATSMP_H__ + +#include +#include +#include +#include +#include INC_GLUE(smp.h) +#include INC_PLAT(sysctrl.h) + +void boot_secondary(int); +void platform_smp_init(int ncpus); +int platform_smp_start(int cpu, void (*start)(int)); +void secondary_init_platform(void); + +#endif /* VXA9_PLATSMP_H */ diff --git a/include/l4/platform/pba9/sysctrl.h b/include/l4/platform/pba9/sysctrl.h new file mode 100644 index 0000000..94fb459 --- /dev/null +++ b/include/l4/platform/pba9/sysctrl.h @@ -0,0 +1,95 @@ +#ifndef __EB_SYSCTRL_H__ +#define __EB_SYSCTRL_H__ +/* TODO: Better to stick this file in a ARM specific folder as most realview boards + * tend to have this component + */ +#define SYS_ID 0x0000 +#define SYS_SW 0x0004 +#define SYS_LED 0x0008 + +#define SYS_OSC0 0x000C +#define SYS_OSC1 0x0010 +#define SYS_OSC2 0x0014 +#define SYS_OSC3 0x0018 +#define SYS_OSC4 0x001C + +#define SYS_LOCK 0x0020 +#define SYS_100HZ 0x0024 + +#define SYS_CFGDATA0 0x0028 +#define SYS_CFGDATA1 0x002C + +#define SYS_FLAGS 0x0030 +#define SYS_FLAGS_SET 0x0030 +#define SYS_FLAGS_CLR 0x0034 +#define SYS_NVFLAGS 0x0038 +#define SYS_NVFLAGS_SET 0x0038 +#define SYS_NVFLAGS_CLR 0x003C + +#define SYS_PCICTL 0x0044 +#define SYS_MCI 0x0048 +#define SYS_FLASH 0x004C +#define SYS_CLCD 0x0050 +#define SYS_CLCDSER 0x0054 +#define SYS_BOOTCS 0x0058 + +#define SYS_24MHZ 0x005C +#define SYS_MISC 0x0060 +#define SYS_DMAPSR0 0x0064 +#define SYS_DMAPSR1 0x0068 +#define SYS_DMAPSR2 0x006C +#define SYS_IOSEL 0x0070 +#define SYS_PLDCTL1 0x0074 +#define SYS_PLDCTL2 0x0078 + +#define SYS_BUSID 0x0080 +#define SYS_PROCID1 0x0084 +#define SYS_PROCID0 0x0088 + +#define SYS_OSCRESET0 0x008C +#define SYS_OSCRESET1 0x0090 +#define SYS_OSCRESET2 0x0094 +#define SYS_OSCRESET3 0x0098 +#define SYS_OSCRESET4 0x009C + + +/* System Controller Lock/Unlock */ +#define SYSCTRL_LOCK 0xFF +#define SYSCTRL_UNLOCK 0xA05F + + +#define ID_MASK_REV 0xF0000000 +#define ID_MASK_HBI 0x0FFF0000 +#define ID_MASK_BUILD 0x0000F000 +#define ID_MASK_ARCH 0x00000F00 +#define ID_MASK_FPGA 0x000000FF + + +#define SW_MASK_BOOTSEL 0x0000FF00 +#define SW_MASK_GP 0x000000FF + +#define LED_MASK_LED 0x000000FF + +#define FLASH_WRITE_EN 0x1 +#define FLASH_WRITE_DIS 0x0 + +#define CLCD_QVGA (0 << 8) /* 320x240 */ +#define CLDE_VGA (1 << 8) /* 640x480 */ +#define CLCD_SMALL (2 << 8) /* 220x176 */ +#define CLCD_SSP_CS (1 << 7) /* SSP Chip Select */ +#define CLCD_TS_EN (1 << 6) /* Touch Screen Enable */ +/* Different Voltages */ +#define CLCD_NEG_EN (1 << 5) +#define CLCD_3V5V_EN (1 << 4) +#define CLCD_POS_EN (1 << 3) +#define CLCD_IO_ON (1 << 2) + + +/* Normal without DCC, no FIQ, recommended for SMP */ +#define PLD_CTRL1_INTMOD_WITHOUT_DCC (1 << 22) +/* Not Recommended */ +#define PLD_CTRL1_INTMOD_WITH_DCC (2 << 22) +/* For single cpu such as 1136 */ +#define PLD_CTRL1_INTMOD_LEGACY (4 << 22) + +#endif /* __EB_SYSCTRL_H__ */ diff --git a/include/l4/platform/pba9/uart.h b/include/l4/platform/pba9/uart.h new file mode 100644 index 0000000..ae77c92 --- /dev/null +++ b/include/l4/platform/pba9/uart.h @@ -0,0 +1,6 @@ +#ifndef __PBA9_UART_H__ +#define __PBA9_UART_H__ + +#include + +#endif /* __PBA9_UART_H__ */ diff --git a/include/l4/platform/realview/offsets.h b/include/l4/platform/realview/offsets.h new file mode 100644 index 0000000..e03632c --- /dev/null +++ b/include/l4/platform/realview/offsets.h @@ -0,0 +1,64 @@ +/* + * Describes physical memory layout of realview platform. + * Right now this contains common offsets for + * pb11mpcore, pba9 and eb. + * + * This is internally included by respective platform's offsets.h + * + * Copyright (C) 2007 Bahadir Balban + */ + +#ifndef __PLATFORM_REALVIEW_OFFSETS_H__ +#define __PLATFORM_REALVIEW_OFFSETS_H__ + +/* Physical memory base */ +#define PLATFORM_PHYS_MEM_START 0x00000000 /* inclusive */ +#define PLATFORM_PHYS_MEM_END 0x10000000 /* 256 MB, exclusive */ + +/* + * Device offsets in physical memory + * Naming of devices done starting with 0 subscript, + * as we use these names for device capability + */ +#define PLATFORM_SYSTEM_REGISTERS 0x10000000 /* System registers */ +#define PLATFORM_SYSCTRL_BASE 0x10001000 /* System controller0 */ +#define PLATFORM_UART0_BASE 0x10009000 /* Console port (UART0) */ +#define PLATFORM_UART1_BASE 0x1000A000 /* Console port (UART1) */ +#define PLATFORM_UART2_BASE 0x1000B000 /* Console port (UART2) */ +#define PLATFORM_UART3_BASE 0x1000C000 /* Console port (UART3) */ +#define PLATFORM_TIMER0_BASE 0x10011000 /* Timers 0 and 1 */ +#define PLATFORM_TIMER1_BASE 0x10012000 /* Timers 2 and 3 */ + +/* + * Virtual Memory base address, where devices will be mapped. + * Each Device will take one page in virtual memory. + * Nice and smooth. + */ +#define DEVICE_PAGE 0x1000 + +#define PLATFORM_SYSREGS_VBASE (IO_AREA0_VADDR + (0 * DEVICE_PAGE)) +#define PLATFORM_SYSCTRL_VBASE (IO_AREA0_VADDR + (1 * DEVICE_PAGE)) +#define PLATFORM_SYSCTRL1_VBASE (IO_AREA0_VADDR + (2 * DEVICE_PAGE)) +#define PLATFORM_CONSOLE_VBASE (IO_AREA0_VADDR + (3 * DEVICE_PAGE)) +#define PLATFORM_TIMER0_VBASE (IO_AREA0_VADDR + (4 * DEVICE_PAGE)) +#define PLATFORM_GIC0_VBASE (IO_AREA0_VADDR + (5 * DEVICE_PAGE)) +#define PLATFORM_GIC1_VBASE (IO_AREA0_VADDR + (7 * DEVICE_PAGE)) +#define PLATFORM_GIC2_VBASE (IO_AREA0_VADDR + (9 * DEVICE_PAGE)) +#define PLATFORM_GIC3_VBASE (IO_AREA0_VADDR + (11 * DEVICE_PAGE)) + +/* Add userspace devices here as they become necessary for irqs */ + +/* Add size of various user space devices, to be used in capability generation */ + +/* The SP810 system controller offsets */ +#define SP810_BASE PLATFORM_SYSCTRL_VBASE +#define SP810_SCCTRL (SP810_BASE + 0x0) + +/* Add size of various user space devices, to be used in capability generation */ +#define PLATFORM_UART1_SIZE DEVICE_PAGE +#define PLATFORM_UART2_SIZE DEVICE_PAGE +#define PLATFORM_UART3_SIZE DEVICE_PAGE +#define PLATFORM_TIMER1_SIZE DEVICE_PAGE + +#endif /* __PLATFORM_REALVIEW_OFFSETS_H__ */ + diff --git a/include/l4/platform/realview/platform.h b/include/l4/platform/realview/platform.h new file mode 100644 index 0000000..cf99fd6 --- /dev/null +++ b/include/l4/platform/realview/platform.h @@ -0,0 +1,24 @@ +/* + * Platform specific ties between drivers and + * generic APIs used by the kernel. + * E.g. system timer and console. + * + * Copyright (C) Bahadir Balban 2007 + */ + +#ifndef __REALVIEW_PLATFORM_H__ +#define __REALVIEW_PLATFORM_H__ + +void init_platform_irq_controller(); +void init_platform_devices(); + +void platform_timer_start(void); +void platform_test_cpucycles(); + +void platform_timer_start(void); + +void scu_init(void); + +void scu_print_state(void); + +#endif /* __REALVIEW_PLATFORM_H__ */ diff --git a/include/l4/platform/realview/timer.h b/include/l4/platform/realview/timer.h new file mode 100644 index 0000000..70a0f5a --- /dev/null +++ b/include/l4/platform/realview/timer.h @@ -0,0 +1,13 @@ +/* + * Platform encapsulation over timer driver. + * + * Copyright (C) 2007 Bahadir Balban + * + */ + +#ifndef __PLATFORM_REALVIEW_TIMER_H__ +#define __PLATFORM_REALVIEW_TIMER_H__ + +#include + +#endif /* __PLATFORM_REALVIEW_TIMER_H__ */ diff --git a/include/l4/platform/realview/uart.h b/include/l4/platform/realview/uart.h new file mode 100644 index 0000000..9519b49 --- /dev/null +++ b/include/l4/platform/realview/uart.h @@ -0,0 +1,14 @@ +/* + * Ties generic uart call to platform specific + * uart driver implementation + * + * Copyright (C) 2007 Bahadir Balban + */ + +#ifndef __PLATFORM_REALVIEW_UART_H__ +#define __PLATFORM_REALVIEW_UART_H__ + +/* Platform specific implementations are defined here */ +#include + +#endif /* __PLATFORM_REALVIEW_UART_H__ */ diff --git a/include/physlink.lds.in b/include/physlink.lds.in new file mode 100644 index 0000000..76035ae --- /dev/null +++ b/include/physlink.lds.in @@ -0,0 +1,88 @@ +/* + * Simple linker script + * + * Copyright (C) 2007 Bahadir Balban + */ + +phys_ram_start = PLATFORM_PHYS_MEM_START; +kernel_offset = 0x00000000; +kernel_physical = 0x8000 + phys_ram_start; +kernel_virtual = kernel_physical + kernel_offset; + +/* A temporary boot stack is used before a proper kernel stack is set up */ +_bootstack_physical = _bootstack - kernel_offset; +_secondary_bootstack_physical = _secondary_bootstack - kernel_offset; + +/* The symbols are linked at virtual addresses. So is _start. + * We must set the entry point to a physical address, so that + * when the image is loaded, it doesn't jump to a non existing + * virtual address. + */ +ENTRY(kernel_physical) + +SECTIONS +{ + . = kernel_virtual; + _start_kernel = .; + .text : AT (ADDR(.text) - kernel_offset) + { + _start_text = .; + /* Make sure head.S comes first */ + /* *head.o(.text) This only works when given its full path. Bad limitation. */ + *(.text.head) + *(.text) + _end_text = .; + } + . = ALIGN(4); + /* rodata is needed else your strings will link at physical! */ + .rodata : AT (ADDR(.rodata) - kernel_offset) { *(.rodata) } + .rodata1 : AT (ADDR(.rodata1) - kernel_offset) { *(.rodata1) } + .data : AT (ADDR(.data) - kernel_offset) + { + _start_data = .; + *(.data) + _start_vectors = .; + *(.data.vectors) + . = ALIGN(4K); + _end_vectors = .; + *(.data.pgd) + _start_kip = .; + *(.data.kip) + . = ALIGN(4K); + _end_kip = .; + _start_syscalls = .; + *(.data.syscalls) + . = ALIGN(4K); + _end_syscalls = .; + *(.data.pgd); /* Global table on split tables, otherwise nil */ + _end_data = .; + } + .bss : AT (ADDR(.bss) - kernel_offset) + { + *(.bss) + } + . = ALIGN(4K); + . += 0x2000; /* This is required as the link counter does not seem + * to increment for the bss section + * TODO: Change this with PAGE_SIZE */ + + /* Below part is to be discarded after boot */ + _start_init = .; + .init : AT (ADDR(.init) - kernel_offset) + { + *(.init.pgd) /* Global table on _non_-split tables, otherwise nil */ + *(.init.task.pgd) /* Non-global task table on split tables, otherwise nil */ + *(.init.bootmem) + *(.init.data) + } + /* Space for boot stack */ + . += 0x1000; + . = ALIGN(4K); /* A page aligned stack of at least 4KB */ + _end_init = .; + _bootstack = .; + . += 0x1000; + . = ALIGN(4K); + _secondary_bootstack = .; + _end_kernel = .; + _end = .; +} diff --git a/loader/SConscript b/loader/SConscript index 16a5acc..38e0ae4 100644 --- a/loader/SConscript +++ b/loader/SConscript @@ -71,9 +71,9 @@ lma_lds = Command(join(BUILDDIR, 'loader/linker.lds'), \ src = Glob('*.[cS]') objs = env.Object(src) -Depends(src, lma_lds) -Depends(src, loader_ksyms) -Depends(src, loader_image_S) +Depends(objs, lma_lds) +Depends(objs, loader_ksyms) +Depends(objs, loader_image_S) Depends(objs, join(BUILDDIR, 'conts/containers.elf')) Depends(objs, join(BUILDDIR, 'kernel.elf')) Return('objs', 'loader_image_S') diff --git a/loader/libs/c/SConstruct b/loader/libs/c/SConstruct index 90fe40c..b671e99 100644 --- a/loader/libs/c/SConstruct +++ b/loader/libs/c/SConstruct @@ -11,19 +11,19 @@ variant = "baremetal" config = configuration_retrieve() arch = config.arch subarch = config.subarch -gcc_cpu_flag = config.gcc_cpu_flag +gcc_arch_flag = config.gcc_arch_flag -env = Environment(CC = config.kernel_toolchain + 'gcc', +env = Environment(CC = config.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)], + '-Werror', '-march=' + gcc_arch_flag], LINKFLAGS = ['-nostdlib', '-T' + "include/l4/arch/arm/linker.lds"], ASFLAGS = ['-D__ASSEMBLY__'], PROGSUFFIX = '.elf', # The suffix to use for final executable ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path LIBS = 'gcc', # libgcc.a - This is required for division routines. - CPPFLAGS = []) + CPPFLAGS = ['-include l4/config.h']) e = env.Clone() e.Append(CPPPATH = ['include/sys-' + variant + '/arch-' + arch]) diff --git a/loader/libs/c/crt/sys-baremetal/arch-arm/crt0.S b/loader/libs/c/crt/sys-baremetal/arch-arm/crt0.S index 6b3c859..8912f1f 100644 --- a/loader/libs/c/crt/sys-baremetal/arch-arm/crt0.S +++ b/loader/libs/c/crt/sys-baremetal/arch-arm/crt0.S @@ -76,12 +76,35 @@ * The construction, validity and performance of this licence is governed * by the laws in force in New South Wales, Australia. */ +#include INC_PLAT(offsets.h) +#include INC_ARCH(scu.h) +#include INC_ARCH(asm.h) +#include INC_ARCH(asm-macros.S) + + .section .text .code 32 .global _start; .align; _start: ldr sp, 1f + +#if defined(CONFIG_SMP) + /* In case all cores start executing at _start */ + get_cpuid r0 + teq r0, #0 + beq core0 +wfiloop: /* Secondary cores wait here */ + mov r0, #0x10000000 /* System Controller base */ + orr r0, r0, #0x30 + ldr r1, [r0] + teq r1, #0 + wfeeq + beq wfiloop + mov pc, r1 /* Jump to the address specified */ +#endif + +core0: bl platform_init bl main 1: .word _stack_top diff --git a/loader/libs/c/include/stddef.h b/loader/libs/c/include/stddef.h index 99a5f12..1eaa096 100644 --- a/loader/libs/c/include/stddef.h +++ b/loader/libs/c/include/stddef.h @@ -111,7 +111,9 @@ typedef __SIZE_TYPE__ size_t; things such as varargs and printf */ typedef __WCHAR_TYPE__ wchar_t; #endif +#ifndef NULL #define NULL ((void *)0) +#endif #define offsetof(type, member) ((size_t) &((type *)0)->member) #endif /* _STDDEF_H_ */ diff --git a/loader/libs/c/src/sys-baremetal/arch-arm/sys_fputc.c b/loader/libs/c/src/sys-baremetal/arch-arm/sys_fputc.c index 521ab61..04d3c9a 100644 --- a/loader/libs/c/src/sys-baremetal/arch-arm/sys_fputc.c +++ b/loader/libs/c/src/sys-baremetal/arch-arm/sys_fputc.c @@ -2,20 +2,15 @@ * Ties up platform's uart driver functions with printf * * Copyright (C) 2009 B Labs Ltd. - * */ #include -#include - -extern struct pl011_uart uart; +#include +#include int __fputc(int c, FILE *stream) { - int res; - do { - res = pl011_tx_char(uart.base, c); - } while( res < 0); + uart_tx_char(uart_print_base, c); - return(0); + return 0; } diff --git a/loader/libs/elf/SConstruct b/loader/libs/elf/SConstruct index 995c8ba..47fe2d2 100644 --- a/loader/libs/elf/SConstruct +++ b/loader/libs/elf/SConstruct @@ -21,7 +21,7 @@ LIBC_LIBPATH = LIBC_PATH LIBC_INCPATH = [join(LIBC_PATH, 'include'), \ join(LIBC_PATH, 'include/arch/' + arch)] -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = config.toolchain + 'gcc', CCFLAGS = ['-g', '-nostdinc', '-nostdlib', '-ffreestanding'], LINKFLAGS = ['-nostdlib'], ENV = {'PATH' : os.environ['PATH']}, diff --git a/scripts/cml/generate_container_cml.py b/scripts/cml/generate_container_cml.py index f19e313..075de18 100755 --- a/scripts/cml/generate_container_cml.py +++ b/scripts/cml/generate_container_cml.py @@ -21,6 +21,12 @@ containers_menu = \ ''' menu containers_menu CAPABILITIES + CONTAINERS% +''' + +default_number_of_containers = \ +''' +default CONTAINERS from 1 ''' containers_constraint = \ @@ -87,6 +93,8 @@ def generate_container_cml(arch, ncont): for cont in range(ncont): fbody += '\tcont%d_menu\n' % cont + fbody += default_number_of_containers + # Generate inter-container suppression rules for as many rules as containers fbody += generate_container_suppress_rules(ncont) diff --git a/scripts/conts/containers.py b/scripts/conts/containers.py index ae79ca0..43b1746 100755 --- a/scripts/conts/containers.py +++ b/scripts/conts/containers.py @@ -33,7 +33,7 @@ def build_linux_container(config, projpaths, container): # Calculate and store size of pager pager_binary = \ - "cont" + str(container.id) + "/linux/linux-2.6.28.10/linux.elf" + "cont" + str(container.id) + "/linux/linux-2.6.33/linux.elf" config.containers[container.id].pager_size = \ conv_hex(elf_binary_size(join(BUILDDIR, pager_binary))) diff --git a/scripts/conts/pack.py b/scripts/conts/pack.py index 78bf4a7..b2c8af9 100755 --- a/scripts/conts/pack.py +++ b/scripts/conts/pack.py @@ -96,7 +96,7 @@ class LinuxContainerPacker: self.atags_elf_in]) self.generate_container_assembler([self.kernel_image_in, self.rootfs_elf_in, \ self.atags_elf_in]) - os.system(config.user_toolchain + "gcc " + "-nostdlib -o %s -T%s %s" \ + os.system(config.toolchain + "gcc " + "-nostdlib -o %s -T%s %s" \ % (self.container_elf_out, self.container_lds_out, \ self.container_S_out)) # Final file is returned so that the final packer needn't @@ -155,7 +155,7 @@ class DefaultContainerPacker: def pack_container(self, config): self.generate_container_lds(self.images_in) self.generate_container_assembler(self.images_in) - os.system(config.user_toolchain + "gcc " + "-nostdlib -o %s -T%s %s" \ + os.system(config.toolchain + "gcc " + "-nostdlib -o %s -T%s %s" \ % (self.container_elf_out, self.container_lds_out, \ self.container_S_out)) # Final file is returned so that the final packer needn't diff --git a/scripts/conts/packall.py b/scripts/conts/packall.py index 85354f0..7a609c3 100755 --- a/scripts/conts/packall.py +++ b/scripts/conts/packall.py @@ -79,7 +79,7 @@ class AllContainerPacker: def pack_all(self, config): self.generate_container_lds(self.containers_lds_out) self.generate_container_S(self.containers_S_out) - os.system(config.user_toolchain + "gcc " + "-nostdlib -o %s -T%s %s" \ + os.system(config.toolchain + "gcc " + "-nostdlib -o %s -T%s %s" \ % (self.containers_elf_out, self.containers_lds_out, \ self.containers_S_out)) diff --git a/scripts/kernel/generate_kernel_cinfo.py b/scripts/kernel/generate_kernel_cinfo.py index 180b55b..7bed6f7 100755 --- a/scripts/kernel/generate_kernel_cinfo.py +++ b/scripts/kernel/generate_kernel_cinfo.py @@ -82,7 +82,8 @@ cap_virtmem = \ \t\t\t\t.target = %(cn)d, \t\t\t\t.type = CAP_TYPE_MAP_VIRTMEM | CAP_RTYPE_CONTAINER, \t\t\t\t.access = CAP_MAP_READ | CAP_MAP_WRITE | CAP_MAP_EXEC -\t\t\t\t\t| CAP_MAP_CACHED | CAP_MAP_UNCACHED | CAP_MAP_UNMAP | CAP_MAP_UTCB, +\t\t\t\t\t| CAP_MAP_CACHED | CAP_MAP_UNCACHED | CAP_MAP_UNMAP | CAP_MAP_UTCB | +\t\t\t\t\tCAP_CACHE_INVALIDATE | CAP_CACHE_CLEAN, \t\t\t\t.start = __pfn(CONFIG_CONT%(cn)d_VIRT%(vn)d_START), \t\t\t\t.end = __pfn(CONFIG_CONT%(cn)d_VIRT%(vn)d_END), \t\t\t\t.size = __pfn(CONFIG_CONT%(cn)d_VIRT%(vn)d_END - CONFIG_CONT%(cn)d_VIRT%(vn)d_START), diff --git a/scripts/linux/build_atags.py b/scripts/linux/build_atags.py index c0c82d9..f3c059a 100755 --- a/scripts/linux/build_atags.py +++ b/scripts/linux/build_atags.py @@ -64,7 +64,7 @@ class AtagsBuilder: with open(self.atags_h_in, 'r') as input: output.write(input.read() % {'cn' : self.cont_id}) - os.system(config.user_toolchain + "cpp -I%s -P %s > %s" % \ + os.system(config.toolchain + "cpp -I%s -P %s > %s" % \ (self.LINUX_ATAGS_BUILDDIR, self.atags_lds_in, \ self.atags_lds_out)) @@ -72,7 +72,7 @@ class AtagsBuilder: with open(self.atags_c_in, 'r') as input: output.write(input.read() % {'cn' : self.cont_id}) - os.system(config.user_toolchain + "gcc " + \ + os.system(config.toolchain + "gcc " + \ "-g -ffreestanding -std=gnu99 -Wall -Werror " + \ "-nostdlib -o %s -T%s %s" % \ (self.atags_elf_out, self.atags_lds_out, self.atags_c_out)) diff --git a/scripts/linux/build_linux.py b/scripts/linux/build_linux.py index dd13533..95cd1b3 100755 --- a/scripts/linux/build_linux.py +++ b/scripts/linux/build_linux.py @@ -40,12 +40,31 @@ class LinuxUpdateKernel: ['USB_SUPPORT', 'UNSET'],['SOUND', 'UNSET'],) # List of CPUIDs, to be used by linux based on codezero config - self.cpuid_list = (['ARM926', '0x41069265'],) + self.cpuid_list = (['ARM926', '0x41069265'], + ['CORTEXA8', '0x410fc080'], + ['ARM11MPCORE', '0x410fb022'], + ['CORTEXA9', '0x410fc090']) # List of ARCHIDs, to be used by linux based on codezero config self.archid_list = (['PB926', '0x183'], - ['PB1176', '0x5E0'], ['EB', '0x33B'], - ['PB11MPCORE', '0x3D4'],) + ['PB11MPCORE', '0x3D4'], + ['BEAGLE', '0x60A'], + ['PBA9', '0x76D'], + ['PBA8', '0x769']) + + # Path of system_macros header file + self.system_macros_h_out = \ + join(LINUX_KERNELDIR, + 'arch/codezero/include/virtualization/system_macros.h') + self.system_macros_h_in = \ + join(LINUX_KERNELDIR, + 'arch/codezero/include/virtualization/system_macros.h.in') + + #Path for kernel_param file + self.kernel_param_out = \ + join(LINUX_KERNELDIR, 'arch/codezero/include/virtualization/kernel_param') + self.kernel_param_in = \ + join(LINUX_KERNELDIR, 'arch/codezero/include/virtualization/kernel_param.in') # Replace line(having input_pattern) in filename with new_data def replace_line(self, filename, input_pattern, new_data, prev_line): @@ -81,41 +100,20 @@ class LinuxUpdateKernel: # Write back to file f.write(l.replace(line, new_data)) - def update_kernel_params(self, container): - # Update TEXT_START - file = join(LINUX_KERNELDIR, 'arch/arm/boot/compressed/Makefile') - param = str(conv_hex(container.linux_phys_offset)) - new_data = ('ZTEXTADDR' + '\t' + ':= ' + param + '\n') - data_to_replace = "(ZTEXTADDR)(\t)(:= 0)" - prev_line = '' - self.replace_line(file, data_to_replace, new_data, prev_line) - - # Update PHYS_OFFSET - file = join(LINUX_KERNELDIR, 'arch/arm/mach-versatile/include/mach/memory.h') - param = str(conv_hex(container.linux_phys_offset)) - new_data = ('#define PHYS_OFFSET UL(' + param + ')\n') - data_to_replace = "(#define PHYS_OFFSET)" - prev_line = '' - self.replace_line(file, data_to_replace, new_data, prev_line) - + # Update kernel parameters + def update_kernel_params(self, config, container): # Update PAGE_OFFSET - file = join(LINUX_KERNELDIR, 'arch/arm/Kconfig') + # FIXME: Find a way to add this in system_macros.h or kernel_param + # issue is we have to update this in KCONFIG file which cannot + # have dependency on other files. + file = join(LINUX_KERNELDIR, 'arch/codezero/Kconfig') param = str(conv_hex(container.linux_page_offset)) new_data = ('\t' + 'default ' + param + '\n') data_to_replace = "(\t)(default )" prev_line = ('\t'+'default 0x80000000 if VMSPLIT_2G' + '\n') self.replace_line(file, data_to_replace, new_data, prev_line) - # Update ZRELADDR - file = join(LINUX_KERNELDIR, 'arch/arm/mach-versatile/Makefile.boot') - param = str(conv_hex(container.linux_zreladdr)) - new_data = (' zreladdr-y' + '\t' + ':= ' + param + '\n') - data_to_replace = "(\s){3}(zreladdr-y)(\t)(:= )" - prev_line = '' - self.replace_line(file, data_to_replace, new_data, prev_line) - # Update ARCHID, CPUID and ATAGS ADDRESS - def modify_register_values(self, config, container): for cpu_type, cpu_id in self.cpuid_list: if cpu_type == config.cpu.upper(): cpuid = cpu_id @@ -125,23 +123,28 @@ class LinuxUpdateKernel: archid = arch_id break - file = join(LINUX_KERNELDIR, 'arch/arm/kernel/head.S') - prev_line = '' - new_data = ('cpuid: .word ' + cpuid + '\n') - data_to_replace = "(cpuid:)" - self.replace_line(file, data_to_replace, new_data, prev_line) + # Create system_macros header + with open(self.system_macros_h_out, 'w+') as output: + with open(self.system_macros_h_in, 'r') as input: + output.write(input.read() % \ + {'cpuid' : cpuid, \ + 'archid' : archid, \ + 'atags' : str(conv_hex(container.linux_page_offset + 0x100)), \ + 'ztextaddr' : str(conv_hex(container.linux_phys_offset)), \ + 'phys_offset' : str(conv_hex(container.linux_phys_offset)), \ + 'page_offset' : str(conv_hex(container.linux_page_offset)), \ + 'zreladdr' : str(conv_hex(container.linux_zreladdr))}) - new_data = ('archid: .word ' + archid + '\n') - data_to_replace = "(archid:)" - self.replace_line(file, data_to_replace, new_data, prev_line) - # Atags will be present at PHYS_OFFSET + 0x100(=256) - new_data = ('atags: .word ' + \ - str(conv_hex(container.linux_phys_offset + 0x100)) + '\n') - data_to_replace = "(atags:)" - self.replace_line(file, data_to_replace, new_data, prev_line) + with open(self.kernel_param_out, 'w+') as output: + with open(self.kernel_param_in, 'r') as input: + output.write(input.read() % \ + {'ztextaddr' : str(conv_hex(container.linux_phys_offset)), \ + 'phys_offset' : str(conv_hex(container.linux_phys_offset)), \ + 'page_offset' : str(conv_hex(container.linux_page_offset)), \ + 'zreladdr' : str(conv_hex(container.linux_zreladdr))}) - def modify_kernel_config(self): - file = join(LINUX_KERNELDIR, 'arch/arm/configs/versatile_defconfig') + def modify_kernel_config(self, linux_builddir): + file = join(linux_builddir, '.config') for param_name, param_value in self.config_param_list: param = 'CONFIG_' + param_name prev_line = '' @@ -152,7 +155,7 @@ class LinuxUpdateKernel: data_to_replace = param new_data = ('# ' + param + ' is not set' + '\n') - self.replace_line(file, data_to_replace, new_data, prev_line) + self.replace_line(file, data_to_replace, new_data, prev_line) class LinuxBuilder: @@ -170,23 +173,36 @@ class LinuxBuilder: self.kernel_image = join(self.LINUX_KERNEL_BUILDDIR, "linux.elf") self.kernel_updater = LinuxUpdateKernel(self.container) + # Default configuration file to use based on selected platform + self.platform_config_file = (['PB926', 'versatile_defconfig'], + ['BEAGLE', 'omap3_beagle_defconfig'], + ['PBA8', 'realview_defconfig'], + ['PBA9', 'realview-smp_defconfig'], + ['PB11MPCORE', 'realview-smp_defconfig'],) + def build_linux(self, config): print '\nBuilding the linux kernel...' os.chdir(self.LINUX_KERNELDIR) if not os.path.exists(self.LINUX_KERNEL_BUILDDIR): os.makedirs(self.LINUX_KERNEL_BUILDDIR) - self.kernel_updater.modify_kernel_config() - self.kernel_updater.update_kernel_params(self.container) - self.kernel_updater.modify_register_values(config, self.container) + for platform, config_file in self.platform_config_file: + if platform == config.platform.upper(): + configuration_file = config_file + os.system("make ARCH=codezero CROSS_COMPILE=" + config.toolchain + \ + " O=" + self.LINUX_KERNEL_BUILDDIR + " " + configuration_file) - os.system("make defconfig ARCH=arm O=" + self.LINUX_KERNEL_BUILDDIR) - os.system("make ARCH=arm " + \ - "CROSS_COMPILE=" + config.user_toolchain + " O=" + \ + self.kernel_updater.modify_kernel_config(self.LINUX_KERNEL_BUILDDIR) + self.kernel_updater.update_kernel_params(config, self.container) + + os.system("make ARCH=codezero CROSS_COMPILE=" + config.toolchain + \ + " O=" + self.LINUX_KERNEL_BUILDDIR + " menuconfig") + os.system("make ARCH=codezero " + \ + "CROSS_COMPILE=" + config.toolchain + " O=" + \ self.LINUX_KERNEL_BUILDDIR) # Generate kernel_image, elf to be used by codezero - linux_elf_gen_cmd = ("arm-none-linux-gnueabi-objcopy -R .note \ + linux_elf_gen_cmd = (config.toolchain + "objcopy -R .note \ -R .note.gnu.build-id -R .comment -S --change-addresses " + \ str(conv_hex(-self.container.linux_page_offset + self.container.linux_phys_offset)) + \ " " + self.kernel_binary_image + " " + self.kernel_image) diff --git a/scripts/linux/build_rootfs.py b/scripts/linux/build_rootfs.py index 35bd7c3..8c11b77 100755 --- a/scripts/linux/build_rootfs.py +++ b/scripts/linux/build_rootfs.py @@ -51,10 +51,10 @@ class RootfsBuilder: with open(self.rootfs_h_in, 'r') as input: output.write(input.read() % {'cn' : self.cont_id}) - os.system(config.user_toolchain + "cpp -I%s -P %s > %s" % \ + os.system(config.toolchain + "cpp -I%s -P %s > %s" % \ (self.LINUX_ROOTFS_BUILDDIR, self.rootfs_lds_in, \ self.rootfs_lds_out)) - os.system(config.user_toolchain + "gcc " + \ + os.system(config.toolchain + "gcc " + \ "-nostdlib -o %s -T%s rootfs.S" % (self.rootfs_elf_out, \ self.rootfs_lds_out)) print "Done..." diff --git a/scripts/loader/generate_loader_asm.py b/scripts/loader/generate_loader_asm.py index e30698f..796c6df 100755 --- a/scripts/loader/generate_loader_asm.py +++ b/scripts/loader/generate_loader_asm.py @@ -53,7 +53,7 @@ def generate_ksym_to_loader(target_path, source_path): asm_file.write(ksym_header % (target_path, source_path, sys.argv[0])) for symbol in symbols: process = \ - subprocess.Popen(config.kernel_toolchain + 'objdump -d ' + \ + subprocess.Popen(config.toolchain + 'objdump -d ' + \ source_path + ' | grep "<' + \ symbol + '>"', shell=True, \ stdout=subprocess.PIPE) diff --git a/scripts/qemu/__init__.py b/scripts/qemu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/qemu/qemu_cmdline.py b/scripts/qemu/qemu_cmdline.py new file mode 100644 index 0000000..e3f48e9 --- /dev/null +++ b/scripts/qemu/qemu_cmdline.py @@ -0,0 +1,67 @@ +#! /usr/bin/env python2.6 +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- Virtualization microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd +# +import os, sys +from os.path import join + +PROJRELROOT = "../.." +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), PROJRELROOT))) + +from config.projpaths import * +from config.configuration import * + +#config = configuration_retrieve() +#cpu = config.cpu +#platform = config.platform + +# Mapping between system configuration and qemu flags +# Platform CPU qemu "-M" flag qemu "-cpu" flag +map_list = (['EB', 'ARM1136', 'realview-eb', 'arm1136'], + ['EB', 'ARM11MPCORE', 'realview-eb-mpcore', 'arm11mpcore'], + ['EB', 'CORTEXA8', 'realview-eb', 'cortex-a8'], + ['PB926', 'ARM926', 'versatilepb', 'arm926'], + ['BEAGLE', 'CORTEXA8', 'beagle', 'cortex-a8'], + ['PBA9', 'CORTEXA9', 'realview-pbx-a9', 'cortex-a9'], + ['PBA8', 'CORTEXA8', 'realview-pb-a8', 'cortex-a8']) + +data = \ +''' +cd build +qemu-system-arm -s -S -kernel final.elf -nographic -M %s -cpu %s & +arm-none-insight ; pkill qemu-system-arm +cd .. +''' + +def build_qemu_cmdline_script(): + build_tools_folder = 'tools' + qemu_cmd_file = join(build_tools_folder, 'run-qemu-insight') + + # Get system selected platform and cpu + config = configuration_retrieve() + cpu = config.cpu.upper() + platform = config.platform.upper() + + # Find appropriate flags + for platform_type, cpu_type, mflag, cpuflag in map_list: + if platform_type == platform and cpu_type == cpu: + break + + if not mflag or not cpuflag: + print 'Qemu flags not found' + sys.exit(1) + + if os.path.exists(build_tools_folder) is False: + os.system("mkdir " + build_tools_folder) + + # Write run-qemu-insight file + with open(qemu_cmd_file, 'w+') as f: + f.write(data % (mflag, cpuflag)) + + os.system("chmod +x " + qemu_cmd_file) + +if __name__ == "__main__": + build_qemu_cmdline_script() diff --git a/src/api/SConscript b/src/api/SConscript index 51c0dd8..ae64648 100644 --- a/src/api/SConscript +++ b/src/api/SConscript @@ -3,7 +3,7 @@ Import('env') Import('symbols') # The set of source files associated with this SConscript file. -src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'map.c', 'mutex.c', 'cap.c', 'exregs.c', 'irq.c'] +src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'map.c', 'mutex.c', 'cap.c', 'exregs.c', 'irq.c', 'cache.c'] obj = env.Object(src_local) diff --git a/src/api/cache.c b/src/api/cache.c new file mode 100644 index 0000000..5586e5a --- /dev/null +++ b/src/api/cache.c @@ -0,0 +1,50 @@ +/* + * Low level cache control functions. + * + * Copyright (C) 2009 - 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include +#include +#include +#include +#include INC_GLUE(cache.h) + +int sys_cache_control(unsigned long start, unsigned long end, + unsigned int flags) +{ + int ret = 0; + + if ((ret = cap_cache_check(start, end, flags)) < 0) + return ret; + + switch (flags) { + case L4_INVALIDATE_ICACHE: + arch_invalidate_icache(start, end); + break; + + case L4_INVALIDATE_DCACHE: + arch_invalidate_dcache(start, end); + break; + + case L4_CLEAN_DCACHE: + arch_clean_dcache(start, end); + break; + + case L4_CLEAN_INVALIDATE_DCACHE: + arch_clean_invalidate_dcache(start, end); + break; + + case L4_INVALIDATE_TLB: + arch_invalidate_tlb(start, end); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + diff --git a/src/api/cap.c b/src/api/cap.c index b72a7b6..bea6ee9 100644 --- a/src/api/cap.c +++ b/src/api/cap.c @@ -69,24 +69,43 @@ int cap_share_single(struct capability *user) return 0; } -#if 0 -/* Shares the whole list */ -int cap_share_all(void) +/* + * Shares the whole capability list. + * + * FIXME: Make sure each and every capability has its + * share right set! + */ +int cap_share_all(unsigned int flags) { - cap_list_move(&curcont->cap_list, - ¤t->space->cap_list); + if (flags == CAP_SHARE_ALL_CONTAINER) { + + /* Move all private caps to container */ + cap_list_move(&curcont->cap_list, + ¤t->cap_list); + + /* + * Move all space caps to container, also. + * + * FIXME: Make sure all space capabilities + * are owned by the sharer!!! + */ + cap_list_move(&curcont->cap_list, + ¤t->space->cap_list); + } else if (flags == CAP_SHARE_ALL_SPACE) { + + /* Move all private caps to space */ + cap_list_move(¤t->space->cap_list, + ¤t->cap_list); + } return 0; } -#endif int cap_share(struct capability *cap, unsigned int flags) { - if (flags & CAP_SHARE_SINGLE) - cap_share_single(cap); + if (flags == CAP_SHARE_SINGLE) + return cap_share_single(cap); else - return -EINVAL; - - return 0; + return cap_share_all(flags); } #if 0 @@ -367,6 +386,16 @@ int cap_destroy(struct capability *cap) if (!(cap_generic_perms(orig) & CAP_CHANGEABLE)) return -ENOCAP; + /* + * Check that it is not a device. + * + * We don't allow devices for now. To do this + * correctly, we need to check if device irq + * is not currently registered. + */ + if (cap_is_devmem(orig)) + return -ENOCAP; + cap_list_remove(orig, clist); free_capability(orig); return 0; @@ -644,17 +673,20 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) case CAP_CONTROL_NCAPS: if ((err = check_access((unsigned long)userbuf, sizeof(int), - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; break; case CAP_CONTROL_READ: if ((err = check_access((unsigned long)userbuf, cap_count(current) * sizeof(struct capability), - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; break; case CAP_CONTROL_SHARE: + if (flags == CAP_SHARE_ALL_CONTAINER || + flags == CAP_SHARE_ALL_SPACE) + break; case CAP_CONTROL_GRANT: case CAP_CONTROL_SPLIT: case CAP_CONTROL_REPLICATE: @@ -662,7 +694,7 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) case CAP_CONTROL_DESTROY: if ((err = check_access((unsigned long)userbuf, sizeof(struct capability), - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; break; default: diff --git a/src/api/exregs.c b/src/api/exregs.c index 6471402..2d1dde0 100644 --- a/src/api/exregs.c +++ b/src/api/exregs.c @@ -71,7 +71,7 @@ flags: /* * If task is the one currently runnable, - * update kip utcb reference + * update utcb reference */ if (task == current) task_update_utcb(task); @@ -161,7 +161,7 @@ int sys_exchange_registers(struct exregs_data *exregs, l4id_t tid) if ((err = check_access((unsigned long)exregs, sizeof(*exregs), - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; /* Find tcb from its list */ diff --git a/src/api/ipc.c b/src/api/ipc.c index 4a32056..ee748fb 100644 --- a/src/api/ipc.c +++ b/src/api/ipc.c @@ -208,7 +208,7 @@ int ipc_send(l4id_t recv_tid, unsigned int flags) struct waitqueue_head *wqhs, *wqhr; int ret = 0; - if (!(receiver = tcb_find(recv_tid))) + if (!(receiver = tcb_find_lock(recv_tid))) return -ESRCH; wqhs = &receiver->wqh_send; @@ -240,8 +240,11 @@ int ipc_send(l4id_t recv_tid, unsigned int flags) // printk("%s: (%d) Waking up (%d)\n", __FUNCTION__, // current->tid, receiver->tid); - /* Wake it up, we can yield here. */ - sched_resume_sync(receiver); + /* Wake it up async */ + sched_resume_async(receiver); + + /* Release thread lock (protects for delete) */ + spin_unlock(&receiver->thread_lock); return ret; } @@ -253,6 +256,7 @@ int ipc_send(l4id_t recv_tid, unsigned int flags) sched_prepare_sleep(); spin_unlock(&wqhr->slock); spin_unlock(&wqhs->slock); + spin_unlock(&receiver->thread_lock); // printk("%s: (%d) waiting for (%d)\n", __FUNCTION__, // current->tid, recv_tid); schedule(); @@ -405,7 +409,7 @@ int ipc_recv_extended(l4id_t sendertid, unsigned int flags) /* Page fault user pages if needed */ if ((err = check_access(ipc_address, size, - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; /* @@ -455,7 +459,7 @@ int ipc_send_extended(l4id_t recv_tid, unsigned int flags) /* Page fault those pages on the current task if needed */ if ((err = check_access(ipc_address, size, - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; /* diff --git a/src/api/irq.c b/src/api/irq.c index f79588c..cfa1ab2 100644 --- a/src/api/irq.c +++ b/src/api/irq.c @@ -12,11 +12,11 @@ #include #include INC_GLUE(message.h) #include +#include INC_SUBARCH(irq.h) -#if 0 /* * Default function that handles userspace - * threaded irqs. Increases notification count and wakes + * threaded irqs. Increases irq count and wakes * up any waiters. * * The increment is a standard read/update/write, and @@ -36,37 +36,35 @@ * * FIXME: Instead of UTCB, do it by incrementing a semaphore. */ -int thread_notify_default(struct irq_desc *desc) +int irq_thread_notify(struct irq_desc *desc) { struct utcb *utcb; int err; /* Make sure irq thread's utcb is mapped */ - if ((err = tcb_check_and_lazy_map_utcb(desc->irq_thread, + if ((err = tcb_check_and_lazy_map_utcb(desc->task, 0)) < 0) { printk("%s: Irq occured but registered task's utcb " - "is inaccessible. task id=0x%x err=%d\n" + "is inaccessible without a page fault. " + "task id=0x%x err=%d\n" "Destroying task.", __FUNCTION__, - desc->irq_thread->tid, err); - thread_destroy(desc->irq_thread); + desc->task->tid, err); + /* FIXME: Racy for irqs. */ + thread_destroy(desc->task); /* FIXME: Deregister and disable irq as well */ } /* Get thread's utcb */ - utcb = (struct utcb *)desc->irq_thread->utcb_address; + utcb = (struct utcb *)desc->task->utcb_address; /* Atomic increment (See above comments) with no wraparound */ - if (utcb->notify[desc->task_notify_slot] != TASK_NOTIFY_MAX) + if (utcb->notify[desc->task_notify_slot] != TASK_NOTIFY_MAXVALUE) utcb->notify[desc->task_notify_slot]++; - /* - * Wake up any waiters - * - * NOTE: There's no contention on this queue, if there was, - * we would have to have spin_lock_irq()'s on the wakeup - */ - wake_up(&desc->irq_thread->wqh_notify, WAKEUP_ASYNC); + /* Async wake up any waiter irq threads */ + wake_up(&desc->wqh_irq, WAKEUP_ASYNC); + BUG_ON(!irqs_enabled()); return 0; } @@ -74,7 +72,7 @@ int thread_notify_default(struct irq_desc *desc) * Register the given globally unique irq number with the * current thread with given flags */ -int irq_control_register(struct ktcb *task, int notify_slot, l4id_t irqnum) +int irq_control_register(struct ktcb *task, int slot, l4id_t irqnum) { int err; @@ -89,43 +87,64 @@ int irq_control_register(struct ktcb *task, int notify_slot, l4id_t irqnum) if ((err = tcb_check_and_lazy_map_utcb(current, 1)) < 0) return err; - /* Register the irq and thread notification handler */ - if ((err = irq_register(current, notify_slot, irqnum, - thread_notify_default)) < 0) + /* Register the irq for thread notification */ + if ((err = irq_register(current, slot, irqnum)) < 0) return err; return 0; } +/* + * Makes current task wait on the given irq + */ +int irq_wait(l4id_t irq_index) +{ + struct irq_desc *desc = irq_desc_array + irq_index; + struct utcb *utcb = (struct utcb *)current->utcb_address; + int ret; + + /* Index must be valid */ + if (irq_index > IRQS_MAX || irq_index < 0) + return -EINVAL; + + /* UTCB must be mapped */ + if ((ret = tcb_check_and_lazy_map_utcb(current, 1)) < 0) + return ret; + + /* Wait until the irq changes slot value */ + WAIT_EVENT(&desc->wqh_irq, + utcb->notify[desc->task_notify_slot] != 0, + ret); + + if (ret < 0) + return ret; + else + return l4_atomic_dest_readb(&utcb->notify[desc->task_notify_slot]); +} + + /* * Register/deregister device irqs. Optional synchronous and * asynchronous irq handling. */ -int sys_irq_control(unsigned int req, int slot, unsigned int flags, l4id_t irqno) +int sys_irq_control(unsigned int req, unsigned int flags, l4id_t irqnum) { /* Currently a task is allowed to register only for itself */ struct ktcb *task = current; int err; - if ((err = cap_irq_check(task, req, flags, irqno)) < 0) + if ((err = cap_irq_check(task, req, flags, irqnum)) < 0) return err; switch (req) { case IRQ_CONTROL_REGISTER: - irq_control_register(task, flags, irqno); + return irq_control_register(task, flags, irqnum); + case IRQ_CONTROL_WAIT: + return irq_wait(irqnum); default: - return -EINVAL; + return -EINVAL; } - return 0; -} -#endif -/* - * Register/deregister device irqs. Optional synchronous and - * asynchronous irq handling. - */ -int sys_irq_control(unsigned int req, int slot, unsigned int flags, l4id_t irqno) -{ return 0; } diff --git a/src/api/kip.c b/src/api/kip.c index 2487795..28149ad 100644 --- a/src/api/kip.c +++ b/src/api/kip.c @@ -5,5 +5,5 @@ */ #include INC_API(kip.h) -SECTION(".data.kip") struct kip kip; +SECTION(".data.kip") ALIGN(SZ_4K) struct kip kip; diff --git a/src/api/map.c b/src/api/map.c index d1c6932..e9c04cd 100644 --- a/src/api/map.c +++ b/src/api/map.c @@ -8,9 +8,29 @@ #include INC_SUBARCH(mm.h) #include #include +#include INC_GLUE(mapping.h) -int sys_map(unsigned long phys, unsigned long virt, unsigned long npages, - unsigned int flags, l4id_t tid) +/* + * Userspace syscall requests can only map + * using read/write/exec userspace flags. + */ +int user_map_flags_validate(unsigned int flags) +{ + switch (flags) { + case MAP_USR_RO: + case MAP_USR_RW: + case MAP_USR_RWX: + case MAP_USR_RX: + case MAP_USR_IO: + return 1; + default: + return 0; + } + return 0; +} + +int sys_map(unsigned long phys, unsigned long virt, + unsigned long npages, unsigned int flags, l4id_t tid) { struct ktcb *target; int err; @@ -18,10 +38,18 @@ int sys_map(unsigned long phys, unsigned long virt, unsigned long npages, if (!(target = tcb_find(tid))) return -ESRCH; + /* Check flags validity */ + if (!user_map_flags_validate(flags)) + return -EINVAL; + + if (!npages || !phys || !virt) + return -EINVAL; + if ((err = cap_map_check(target, phys, virt, npages, flags)) < 0) return err; - add_mapping_pgd(phys, virt, npages << PAGE_BITS, flags, TASK_PGD(target)); + add_mapping_pgd(phys, virt, npages << PAGE_BITS, + flags, TASK_PGD(target)); return 0; } @@ -36,17 +64,22 @@ int sys_unmap(unsigned long virtual, unsigned long npages, unsigned int tid) struct ktcb *target; int ret = 0, retval = 0; - if (tid == current->tid) - target = current; - else if (!(target = tcb_find(tid))) + if (!(target = tcb_find(tid))) return -ESRCH; + if (!npages || !virtual) + return -EINVAL; + + if ((ret = cap_unmap_check(target, virtual, npages)) < 0) + return ret; + for (int i = 0; i < npages; i++) { - ret = remove_mapping_pgd(virtual + i * PAGE_SIZE, TASK_PGD(target)); + ret = remove_mapping_pgd(TASK_PGD(target), + virtual + i * PAGE_SIZE); if (ret) retval = ret; } - return retval; + return ret; } diff --git a/src/api/mutex.c b/src/api/mutex.c index 829d190..427a09f 100644 --- a/src/api/mutex.c +++ b/src/api/mutex.c @@ -15,6 +15,7 @@ #include INC_API(syscall.h) #include INC_ARCH(exception.h) #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) void init_mutex_queue_head(struct mutex_queue_head *mqhead) { @@ -205,6 +206,22 @@ int mutex_control_unlock(struct mutex_queue_head *mqhead, return wait_on_prepared_wait(); } + /* + * Note, the mutex in userspace was left free before the + * syscall was entered. + * + * It is possible that a thread has acquired it, another + * contended on it and the holder made it to the kernel + * quicker than us. We detect this situation here. + */ + if (mutex_queue->wqh_holders.sleepers) { + /* + * Let the first holder do all the waking up + */ + mutex_queue_head_unlock(mqhead); + return 0; + } + /* * Found it, if it exists, there are contenders, * now wake all of them up in FIFO order. @@ -226,6 +243,8 @@ int sys_mutex_control(unsigned long mutex_address, int mutex_op) unsigned long mutex_physical; int ret = 0; + // printk("%s: Thread %d enters.\n", __FUNCTION__, current->tid); + /* Check valid operation */ if (mutex_op != MUTEX_CONTROL_LOCK && mutex_op != MUTEX_CONTROL_UNLOCK) { @@ -249,8 +268,7 @@ int sys_mutex_control(unsigned long mutex_address, int mutex_op) * capabilities of current task. */ if (!(mutex_physical = - virt_to_phys_by_pgd(mutex_address, - TASK_PGD(current)))) + virt_to_phys_by_pgd(TASK_PGD(current), mutex_address))) return -EINVAL; switch (mutex_op) { diff --git a/src/api/syscall.c b/src/api/syscall.c index 4d5cb10..571da52 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -39,6 +39,12 @@ int sys_schedule(void) int sys_getid(struct task_ids *ids) { struct ktcb *this = current; + int err; + + if ((err = check_access((unsigned long)ids, + sizeof(struct task_ids), + MAP_USR_RW, 1)) < 0) + return err; ids->tid = this->tid; ids->spid = this->space->spid; diff --git a/src/api/thread.c b/src/api/thread.c index 1da38c3..4dbcd80 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -16,6 +16,7 @@ #include #include INC_ARCH(asm.h) #include INC_SUBARCH(mm.h) +#include INC_GLUE(mapping.h) int sys_thread_switch(void) { @@ -56,11 +57,10 @@ int thread_suspend(struct ktcb *task) int thread_exit(struct ktcb *task) { - - return thread_signal(task, TASK_EXITING, TASK_DEAD); + return thread_signal(task, TASK_SUSPENDING, TASK_INACTIVE); } -static inline int TASK_IS_CHILD(struct ktcb *task) +static inline int task_is_child(struct ktcb *task) { return (((task) != current) && ((task)->pagerid == current->tid)); @@ -68,18 +68,26 @@ static inline int TASK_IS_CHILD(struct ktcb *task) int thread_destroy_child(struct ktcb *task) { + /* Wait until thread exits */ thread_exit(task); + /* Hint scheduler that an exit occured */ + current->flags |= TASK_EXITED; + + /* Now remove it atomically */ tcb_remove(task); - /* Wake up waiters */ + /* Wake up waiters that arrived before removing */ wake_up_all(&task->wqh_send, WAKEUP_INTERRUPT); wake_up_all(&task->wqh_recv, WAKEUP_INTERRUPT); BUG_ON(task->wqh_pager.sleepers > 0); - BUG_ON(task->state != TASK_DEAD); + BUG_ON(task->state != TASK_INACTIVE); + + /* Place the task on the zombie queue for its cpu */ + ktcb_list_add(task, &per_cpu_byid(kernel_resources.zombie_list, + task->affinity)); - tcb_delete(task); return 0; } @@ -91,7 +99,7 @@ int thread_destroy_children(void) list_foreach_removable_struct(task, n, &curcont->ktcb_list.list, task_list) { - if (TASK_IS_CHILD(task)) { + if (task_is_child(task)) { spin_unlock(&curcont->ktcb_list.list_lock); thread_destroy_child(task); spin_lock(&curcont->ktcb_list.list_lock); @@ -104,14 +112,37 @@ int thread_destroy_children(void) void thread_destroy_self(unsigned int exit_code) { + /* Destroy all children first */ thread_destroy_children(); - /* Wake up waiters */ - wake_up_all(¤t->wqh_send, WAKEUP_INTERRUPT); - wake_up_all(¤t->wqh_recv, WAKEUP_INTERRUPT); + /* If self-paged, finish everything except deletion */ + if (current->tid == current->pagerid) { + /* Remove self safe against ipc */ + tcb_remove(current); + /* Wake up any waiters queued up before removal */ + wake_up_all(¤t->wqh_send, WAKEUP_INTERRUPT); + wake_up_all(¤t->wqh_recv, WAKEUP_INTERRUPT); + + /* Move capabilities to current cpu idle task */ + cap_list_move(&per_cpu(scheduler).idle_task->cap_list, + ¤t->cap_list); + + /* Place self on the per-cpu zombie queue */ + ktcb_list_add(current, &per_cpu(kernel_resources.zombie_list)); + } + + /* + * Both child and a self-paging would set exit + * code and quit the scheduler + */ current->exit_code = exit_code; - sched_exit_sync(); + + /* + * Hint scheduler that an exit has occured + */ + current->flags |= TASK_EXITED; + sched_suspend_sync(); } int thread_wait(struct ktcb *task) @@ -119,27 +150,50 @@ int thread_wait(struct ktcb *task) unsigned int exit_code; int ret; + // printk("%s: (%d) for (%d)\n", __FUNCTION__, current->tid, task->tid); + /* Wait until task switches to desired state */ WAIT_EVENT(&task->wqh_pager, - task->state == TASK_DEAD, ret); + task->state == TASK_INACTIVE, ret); + + /* Return if interrupted by async event */ if (ret < 0) return ret; - else { - exit_code = (int)task->exit_code; - tcb_remove(task); - tcb_delete(task); - return exit_code; - } + + /* Now remove it safe against ipc */ + tcb_remove(task); + + /* Wake up waiters that arrived before removing */ + wake_up_all(&task->wqh_send, WAKEUP_INTERRUPT); + wake_up_all(&task->wqh_recv, WAKEUP_INTERRUPT); + + BUG_ON(task->wqh_pager.sleepers > 0); + BUG_ON(task->state != TASK_INACTIVE); + + /* Obtain exit code */ + exit_code = (int)task->exit_code; + + /* Place it on the zombie queue */ + ktcb_list_add(task, + &per_cpu_byid(kernel_resources.zombie_list, + task->affinity)); + + return exit_code; } int thread_destroy(struct ktcb *task, unsigned int exit_code) { + // printk("%s: (%d) for (%d)\n", __FUNCTION__, current->tid, task->tid); + exit_code &= THREAD_EXIT_MASK; - if (TASK_IS_CHILD(task)) + if (task_is_child(task)) return thread_destroy_child(task); else if (task == current) thread_destroy_self(exit_code); + else + BUG(); + return 0; } @@ -208,13 +262,12 @@ int thread_start(struct ktcb *task) if (!mutex_trylock(&task->thread_control_lock)) return -EAGAIN; - /* FIXME: Refuse to run dead tasks */ - /* Notify scheduler of task resume */ sched_resume_async(task); /* Release lock and return */ mutex_unlock(&task->thread_control_lock); + return 0; } @@ -229,10 +282,15 @@ int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig, } BUG_ON(!orig); + + /* If original has no syscall context yet, don't copy */ + if (!orig->syscall_regs) + return 0; + /* * For duplicated threads pre-syscall context is saved on * the kernel stack. We copy this context of original - * into the duplicate thread's current context structure + * into the duplicate thread's current context structure, * * No locks needed as the thread is not known to the system yet. */ @@ -262,6 +320,24 @@ int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig, return 0; } +static DECLARE_SPINLOCK(task_select_affinity_lock); +static unsigned int cpu_rr_affinity; + +/* Select which cpu to place the new task in round-robin fashion */ +void thread_setup_affinity(struct ktcb *task) +{ + spin_lock(&task_select_affinity_lock); + task->affinity = cpu_rr_affinity; + + //printk("Set up thread %d affinity=%d\n", + // task->tid, task->affinity); + cpu_rr_affinity++; + if (cpu_rr_affinity >= CONFIG_NCPU) + cpu_rr_affinity = 0; + + spin_unlock(&task_select_affinity_lock); +} + static inline void thread_setup_new_ids(struct task_ids *ids, unsigned int flags, struct ktcb *new, struct ktcb *orig) @@ -344,8 +420,8 @@ int thread_create(struct task_ids *ids, unsigned int flags) & TC_COPY_SPACE & TC_NEW_SPACE) || !flags) return -EINVAL; - /* Can't have multiple pager specifiers */ - if (flags & TC_SHARE_PAGER & TC_AS_PAGER) + /* Must have one space flag */ + if ((flags & THREAD_SPACE_MASK) == 0) return -EINVAL; /* Can't request shared utcb or tgid without shared space */ @@ -371,29 +447,23 @@ int thread_create(struct task_ids *ids, unsigned int flags) } } - /* - * Note this is a kernel-level relationship - * between the creator and the new thread. - * - * Any higher layer may define parent/child - * relationships between orig and new separately. - */ - if (flags & TC_AS_PAGER) - new->pagerid = current->tid; - else if (flags & TC_SHARE_PAGER) - new->pagerid = current->pagerid; - else - new->pagerid = new->tid; + /* Set creator as pager */ + new->pagerid = current->tid; - //printk("Thread (%d) pager set as (%d)\n", new->tid, new->pagerid); - - /* - * Setup container-generic fields from current task - */ + /* Setup container-generic fields from current task */ new->container = current->container; + /* + * Set up cpu affinity. + * + * This is the default setting, it may be changed + * by a subsequent exchange_registers call + */ + thread_setup_affinity(new); + /* Set up new thread context by using parent ids and flags */ thread_setup_new_ids(ids, flags, new, orig); + arch_setup_new_thread(new, orig, flags); tcb_add(new); @@ -406,7 +476,7 @@ int thread_create(struct task_ids *ids, unsigned int flags) out_err: /* Pre-mature tcb needs freeing by free_ktcb */ - free_ktcb(new); + free_ktcb(new, current); return err; } @@ -421,13 +491,25 @@ int sys_thread_control(unsigned int flags, struct task_ids *ids) int err, ret = 0; if ((err = check_access((unsigned long)ids, sizeof(*ids), - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; - if ((flags & THREAD_ACTION_MASK) != THREAD_CREATE) + if ((flags & THREAD_ACTION_MASK) != THREAD_CREATE) { if (!(task = tcb_find(ids->tid))) return -ESRCH; + /* + * Tasks may only operate on their children. They may + * also destroy themselves or any children. + */ + if ((flags & THREAD_ACTION_MASK) == THREAD_DESTROY && + !task_is_child(task) && task != current) + return -EPERM; + if ((flags & THREAD_ACTION_MASK) != THREAD_DESTROY + && !task_is_child(task)) + return -EPERM; + } + if ((err = cap_thread_check(task, flags, ids)) < 0) return err; diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index 57bc74f..8b6fa21 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -1,10 +1,23 @@ - - # Inherit global environment -Import('env') +import os, sys, glob + +PROJRELROOT = '../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import('env', 'symbols') + # The set of source files associated with this SConscript file. -src_local = ['head.S', 'vectors.S', 'syscall.S', 'exception.c'] +src_local = ['head.S', 'vectors.S', 'syscall.S', 'exception-common.c', 'mapping-common.c', 'memset.S', 'memcpy.S'] + +for name, val in symbols: + if 'CONFIG_SMP' == name: + src_local += ['head-smp.S'] + obj = env.Object(src_local) Return('obj') diff --git a/src/arch/arm/exception-common.c b/src/arch/arm/exception-common.c new file mode 100644 index 0000000..ae910cf --- /dev/null +++ b/src/arch/arm/exception-common.c @@ -0,0 +1,334 @@ +/* + * Common exception handling code + * + * Copyright (C) 2008 - 2010 B Labs Ltd. + * Written by Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include INC_ARCH(exception.h) +#include INC_GLUE(memlayout.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(message.h) +#include INC_GLUE(ipc.h) +#include INC_SUBARCH(mm.h) + + +void abort_die(void) +{ + disable_irqs(); + print_early("Unhandled kernel abort.\n"); + print_early("Kernel panic.\n"); + print_early("Halting system...\n"); + while (1) + ; +} + +struct ipc_state { + u32 mr[MR_TOTAL]; + unsigned int flags; +}; + +void ipc_save_state(struct ipc_state *state) +{ + unsigned int *mr0_current = KTCB_REF_MR0(current); + + BUG_ON(!mr0_current); + + /* Save primary message registers */ + for (int i = 0; i < MR_TOTAL; i++) + state->mr[i] = mr0_current[i]; + + /* Save ipc flags */ + state->flags = tcb_get_ipc_flags(current); +} + +void ipc_restore_state(struct ipc_state *state) +{ + unsigned int *mr0_current = KTCB_REF_MR0(current); + + BUG_ON(!mr0_current); + + /* Restore primary message registers */ + for (int i = 0; i < MR_TOTAL; i++) + mr0_current[i] = state->mr[i]; + + /* Restore ipc flags */ + tcb_set_ipc_flags(current, state->flags); +} + +/* Send data fault ipc to the faulty task's pager */ +int __attribute__((optimize("O0"))) +fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far, u32 ipc_tag) +{ + int err; + + /* mr[0] has the fault tag. The rest is the fault structure */ + u32 mr[MR_TOTAL] = { + [MR_TAG] = ipc_tag, + [MR_SENDER] = current->tid + }; + + fault_kdata_t *fault = (fault_kdata_t *)&mr[MR_UNUSED_START]; + + /* Fill in fault information to pass over during ipc */ + fault->faulty_pc = faulty_pc; + fault->fsr = fsr; + fault->far = far; + + /* + * Write pte of the abort address, + * which is different on pabt/dabt + */ + if (is_prefetch_abort(fsr)) + fault->pte = virt_to_pte(faulty_pc); + else + fault->pte = virt_to_pte(far); + + /* + * System calls save arguments (and message registers) + * on the kernel stack. They are then referenced from + * the caller's ktcb. Here, we forge a fault structure + * as if an ipc syscall has occured. Then the reference + * to the fault structure is set in the ktcb such that + * it lies on the mr0 offset when referred as the syscall + * context. + */ + + /* + * Assign fault such that it overlaps + * as the MR0 reference in ktcb. + */ + current->syscall_regs = (syscall_context_t *) + ((unsigned long)&mr[0] - + offsetof(syscall_context_t, r3)); + + /* Set current flags to short ipc */ + tcb_set_ipc_flags(current, IPC_FLAGS_SHORT); + + /* Detect if a pager is self-faulting */ + if (current->tid == current->pagerid) { + printk("Pager (%d) faulted on itself. " + "FSR: 0x%x, FAR: 0x%x, PC: 0x%x pte: 0x%x CPU%d Exiting.\n", + current->tid, fault->fsr, fault->far, + fault->faulty_pc, fault->pte, smp_get_cpuid()); + thread_destroy(current); + } + + /* Send ipc to the task's pager */ + if ((err = ipc_sendrecv(current->pagerid, + current->pagerid, 0)) < 0) { + BUG_ON(current->nlocks); + + /* Return on interrupt */ + if (err == -EINTR) { + printk("Thread (%d) page-faulted " + "and got interrupted by its pager.\n", + current->tid); + return err; + } else { /* Suspend on any other error */ + printk("Thread (%d) faulted in kernel " + "and an error occured during " + "page-fault ipc. err=%d. " + "Suspending task.\n", + current->tid, err); + current->flags |= TASK_SUSPENDING; + sched_suspend_sync(); + } + } + return 0; +} + +/* + * When a task calls the kernel and the supplied user buffer is + * not mapped, the kernel generates a page fault to the task's + * pager so that the pager can make the decision on mapping the + * buffer. Remember that if a task maps its own user buffer to + * itself this way, the kernel can access it, since it shares + * that task's page table. + */ +int pager_pagein_request(unsigned long addr, unsigned long size, + unsigned int flags) +{ + int err; + u32 abort = 0; + unsigned long npages = __pfn(align_up(size, PAGE_SIZE)); + struct ipc_state ipc_state; + + set_abort_type(abort, ABORT_TYPE_DATA); + + /* Save current ipc state */ + ipc_save_state(&ipc_state); + + /* For every page to be used by the + * kernel send a page-in request */ + for (int i = 0; i < npages; i++) + if ((err = fault_ipc_to_pager(0, abort, + addr + (i * PAGE_SIZE), + L4_IPC_TAG_PFAULT)) < 0) + return err; + + /* Restore ipc state */ + ipc_restore_state(&ipc_state); + + return 0; +} + +/* + * @r0: The address where the program counter was during the fault. + * @r1: Contains the fault status register + * @r2: Contains the fault address register + */ +void data_abort_handler(u32 faulted_pc, u32 dfsr, u32 dfar, u32 spsr) +{ + int ret; + + system_account_dabort(); + + /* Indicate abort type on dfsr */ + set_abort_type(dfsr, ABORT_TYPE_DATA); + + dbg_abort("Data abort PC:0x%x, FAR: 0x%x, FSR: 0x%x, CPU%d\n", + faulted_pc, dfar, dfsr, smp_get_cpuid()); + + /* + * Check abort type and tell + * if it's an irrecoverable fault + */ + if ((ret = check_abort_type(faulted_pc, dfsr, dfar, spsr)) < 0) + goto die; /* Die if irrecoverable */ + else if (ret == ABORT_HANDLED) + return; + + /* Notify the pager */ + fault_ipc_to_pager(faulted_pc, dfsr, dfar, L4_IPC_TAG_PFAULT); + + /* + * FIXME: + * Check return value of pager, and also make a record of + * the fault that has occured. We ought to expect progress + * from the pager. If the same fault is occuring a number + * of times consecutively, we might want to kill the pager. + */ + + /* See if current task has various flags set by its pager */ + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } + + return; +die: + dprintk("FAR:", dfar); + dprintk("PC:", faulted_pc); + abort_die(); +} + +void prefetch_abort_handler(u32 faulted_pc, u32 ifsr, u32 ifar, u32 spsr) +{ + int ret; + + system_account_pabort(); + + /* Indicate abort type on dfsr */ + set_abort_type(ifsr, ABORT_TYPE_PREFETCH); + + dbg_abort("Prefetch abort PC:0x%x, FAR: 0x%x, FSR: 0x%x, CPU%d\n", + faulted_pc, ifar, ifsr, smp_get_cpuid()); + + /* + * Check abort type and tell + * if it's an irrecoverable fault + */ + + if ((ret = check_abort_type(0, ifsr, ifar, spsr)) < 0) + goto die; /* Die if irrecoverable */ + else if (ret == ABORT_HANDLED) + return; /* Return if handled internally */ + + /* Notify the pager */ + fault_ipc_to_pager(faulted_pc, ifsr, ifar, L4_IPC_TAG_PFAULT); + + /* + * FIXME: + * Check return value of pager, and also make a record of + * the fault that has occured. We ought to expect progress + * from the pager. If the same fault is occuring a number + * of times consecutively, we might want to kill the pager. + */ + + /* See if current task has various flags set by its pager */ + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } + + return; +die: + dprintk("FAR:", ifar); + abort_die(); + +} + +void undefined_instr_handler(u32 undefined_address, u32 spsr, u32 lr) +{ + dbg_abort("Undefined instruction. PC:0x%x", undefined_address); + + system_account_undef_abort(); + + fault_ipc_to_pager(undefined_address, 0, undefined_address, + L4_IPC_TAG_UNDEF_FAULT); + + if (!is_user_mode(spsr)) { + dprintk("Undefined instruction occured in " + "non-user mode. addr=", undefined_address); + goto die; + } + + /* See if current task has various flags set by its pager */ + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } + + return; + +die: + abort_die(); +} + +extern int current_irq_nest_count; + +/* + * This is called right where the nest count is increased + * in case the nesting is beyond the predefined max limit. + * It is another matter whether this limit is enough to + * guarantee the kernel stack is not overflown. + * + * FIXME: Take measures to recover. (E.g. disable irqs etc) + * + * Note that this is called in irq context, and it *also* + * thrashes the designated irq stack which is only 12 bytes. + * + * It really is assumed the system has come to a halt when + * this happens. + */ +void irq_overnest_error(void) +{ + dprintk("Irqs nested beyond limit. Current count: ", + current_irq_nest_count); + print_early("System halted...\n"); + while(1) + ; +} + diff --git a/src/arch/arm/head-smp.S b/src/arch/arm/head-smp.S new file mode 100644 index 0000000..0c2f7d9 --- /dev/null +++ b/src/arch/arm/head-smp.S @@ -0,0 +1,114 @@ +/* + * Kernel Entry point for secondary cpus + * + * Copyright (C) 2010 B Labs Ltd. + * Author: Prem Mallappa + */ + +#include INC_ARCH(asm.h) +#include INC_PLAT(offsets.h) +#include INC_ARCH(asm-macros.S) + +#define C15_C0_M 0x0001 /* MMU */ +#define C15_C0_A 0x0002 /* Alignment */ +#define C15_C0_C 0x0004 /* (D) Cache */ +#define C15_C0_W 0x0008 /* Write buffer */ +#define C15_C0_B 0x0080 /* Endianness */ +#define C15_C0_S 0x0100 /* System */ +#define C15_C0_R 0x0200 /* ROM */ +#define C15_C0_Z 0x0800 /* Branch Prediction */ +#define C15_C0_I 0x1000 /* I cache */ +#define C15_C0_V 0x2000 /* High vectors */ + + .section .text.head + +BEGIN_PROC(__smp_start) + msr cpsr_fxsc, #ARM_NOIRQ_SVC + + /* Disable mmu if it is enabled */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #C15_C0_M @ Disable MMU + bic r0, r0, #C15_C0_C @ Disable (D) Cache + bic r0, r0, #C15_C0_I @ Disable I cache + bic r0, r0, #C15_C0_W @ Disable Write buffer + mcr p15, 0, r0, c1, c0, 0 + + /* Setup boot stack (physical address) */ + + /* + * Each processor gets a unique 1024 byte stack. + * This stack is used until the first task becomes + * runnable, so there needs to be one for each core + * + * +----------+ + * |CPU3 Stack| + * +----------+ + * |CPU2 Stack| + * +----------+ + * |CPU1 Stack| + * +----------+ + * |CPU0 Stack| + * +----------+ _bootstack_physical + */ + get_cpuid r0 + mov r0, r0, lsl #12 /* 4 KB stack per-cpu */ + ldr sp, _secondary_cpu_stack + sub sp, sp, r0 + + /* + * Each processor will get its own irq/fiq/abt/und/svc stack + * of size 16 bytes per mode. Each mode would have 64 bytes + * of stack used in total for 4 cores. + * + * Note, unlike SVC mode all abort modes also include the + * stack for primary core, i.e CPU0. There's no separation + * of primary and secondary stack regions. + * + * +------------------+ __abt_stack_high + * | CPU0 ABT Stack | + * +------------------+ __abt_stack_high - 0x10 + * | CPU1 ABT Stack | + * +------------------+ __abt_stack_high - 0x20 + * | CPU2 ABT Stack | + * +------------------+ __abt_stack_high - 0x30 + * | CPU3 ABT Stack | + * +------------------+ __abt_stack_high - 0x40 + * + */ + get_cpuid r0 + mov r0, r0, lsl #4 /* 16 byte stack for each core */ + + /* Exception stacks are defined in vector page */ + msr cpsr_fcx, #ARM_NOIRQ_ABT + ldr sp, _sec_kern_abt_stack + sub sp, sp, r0 + msr cpsr_fcx, #ARM_NOIRQ_IRQ + ldr sp, _sec_kern_irq_stack + sub sp, sp, r0 + msr cpsr_fcx, #ARM_NOIRQ_FIQ + ldr sp, _sec_kern_fiq_stack + sub sp, sp, r0 + msr cpsr_fcx, #ARM_NOIRQ_UND + ldr sp, _sec_kern_und_stack + sub sp, sp, r0 + msr cpsr_fcx, #ARM_NOIRQ_SVC + + /* Jump to start_kernel */ + bl smp_secondary_init + + /* Never reached */ +1: + b 1b + +_secondary_cpu_stack: + .word _bootstack_physical + +/* Exception stacks are defined in vector page */ +_sec_kern_abt_stack: + .word __abt_stack_high +_sec_kern_irq_stack: + .word __irq_stack_high +_sec_kern_fiq_stack: + .word __fiq_stack_high +_sec_kern_und_stack: + .word __und_stack_high diff --git a/src/arch/arm/head.S b/src/arch/arm/head.S index 4cfbe0e..b08b079 100644 --- a/src/arch/arm/head.S +++ b/src/arch/arm/head.S @@ -26,7 +26,7 @@ .section .text.head BEGIN_PROC(_start) /* Setup status register for supervisor mode, interrupts disabled */ - msr cpsr_fc, #ARM_MODE_SVC + msr cpsr_fcxs, #ARM_MODE_SVC /* Disable mmu if it is enabled */ mrc p15, 0, r0, c1, c0, 0 @@ -34,6 +34,7 @@ BEGIN_PROC(_start) bic r0, r0, #C15_C0_C @ Disable (D) Cache bic r0, r0, #C15_C0_I @ Disable I cache bic r0, r0, #C15_C0_W @ Disable Write buffer + bic r0, r0, #C15_C0_Z @ Disable Branch prediction mcr p15, 0, r0, c1, c0, 0 /* Setup boot stack (physical address) */ diff --git a/src/arch/arm/mapping-common.c b/src/arch/arm/mapping-common.c new file mode 100644 index 0000000..9816ead --- /dev/null +++ b/src/arch/arm/mapping-common.c @@ -0,0 +1,418 @@ +/* + * Low-level page table functions that are common + * and abstracted between v5-v7 ARM architectures + * + * Copyright (C) 2007 - 2010 B Labs Ltd. + * Written by Bahadir Balban + */ + +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(memlayout.h) +#include INC_ARCH(linker.h) +#include INC_GLUE(mapping.h) +#include +#include +#include +#include +#include +#include + +/* Find out whether a pmd exists or not and return it */ +pmd_table_t *pmd_exists(pgd_table_t *task_pgd, unsigned long vaddr) +{ + pmd_t *pmd = arch_pick_pmd(task_pgd, vaddr); + + /* + * Check that it has a valid pmd + * (i.e. not a fault, not a section) + */ + if ((*pmd & PMD_TYPE_MASK) == PMD_TYPE_PMD) + return (pmd_table_t *) + phys_to_virt(*pmd & PMD_ALIGN_MASK); + else if ((*pmd & PMD_TYPE_MASK) == 0) + return 0; + else + BUG(); /* Anything that's not a pmd or fault is bug */ + return 0; +} + +/* + * Convert virtual address to a pte from a task-specific pgd + * FIXME: Remove this by using ptep version, leaving due to + * too many things to test right now. + */ +pte_t virt_to_pte_from_pgd(pgd_table_t *task_pgd, + unsigned long virtual) +{ + pmd_table_t *pmd = pmd_exists(task_pgd, virtual); + + if (pmd) + return (pte_t)pmd->entry[PMD_INDEX(virtual)]; + else + return (pte_t)0; +} + +/* Convert virtual address to a pte from a task-specific pgd */ +pte_t *virt_to_ptep_from_pgd(pgd_table_t *task_pgd, + unsigned long virtual) +{ + pmd_table_t *pmd = pmd_exists(task_pgd, virtual); + + if (pmd) + return (pte_t *)&pmd->entry[PMD_INDEX(virtual)]; + else + return (pte_t *)0; +} + +/* + * Convert a virtual address to a pte if it + * exists in the page tables. + */ +pte_t virt_to_pte(unsigned long virtual) +{ + return virt_to_pte_from_pgd(TASK_PGD(current), virtual); +} + +pte_t *virt_to_ptep(unsigned long virtual) +{ + return virt_to_ptep_from_pgd(TASK_PGD(current), virtual); +} + +unsigned long virt_to_phys_by_pgd(pgd_table_t *pgd, unsigned long vaddr) +{ + pte_t pte = virt_to_pte_from_pgd(pgd, vaddr); + return pte & ~PAGE_MASK; +} + +static inline unsigned long +virt_to_phys_by_task(struct ktcb *task, unsigned long vaddr) +{ + return virt_to_phys_by_pgd(TASK_PGD(task), vaddr); +} + +/* + * Attaches a pmd to either a task or the global pgd + * depending on the virtual address passed. + */ +void attach_pmd(pgd_table_t *task_pgd, pmd_table_t *pmd_table, + unsigned long vaddr) +{ + u32 pmd_phys = virt_to_phys(pmd_table); + pmd_t *pmd; + + BUG_ON(!is_aligned(pmd_phys, PMD_SIZE)); + + /* + * Pick the right pmd from the right pgd. + * It makes a difference if split tables are used. + */ + pmd = arch_pick_pmd(task_pgd, vaddr); + + /* Write the pmd into hardware pgd */ + arch_write_pmd(pmd, pmd_phys, vaddr); +} + +void add_mapping_pgd(unsigned long physical, unsigned long virtual, + unsigned int sz_bytes, unsigned int flags, + pgd_table_t *task_pgd) +{ + unsigned long npages = (sz_bytes >> PFN_SHIFT); + pmd_table_t *pmd_table; + + if (sz_bytes < PAGE_SIZE) { + print_early("Error: Mapping size less than PAGE_SIZE. " + "Mapping size is in bytes not pages.\n"); + BUG(); + } + + if (sz_bytes & PAGE_MASK) + npages++; + + /* Convert generic map flags to arch specific flags */ + BUG_ON(!(flags = space_flags_to_ptflags(flags))); + + /* Map all pages that cover given size */ + for (int i = 0; i < npages; i++) { + /* Check if a pmd was attached previously */ + if (!(pmd_table = pmd_exists(task_pgd, virtual))) { + + /* First mapping in pmd, allocate it */ + pmd_table = alloc_pmd(); + + /* Prepare the pte but don't sync */ + arch_prepare_pte(physical, virtual, flags, + &pmd_table->entry[PMD_INDEX(virtual)]); + + /* Attach pmd to its pgd and sync it */ + attach_pmd(task_pgd, pmd_table, virtual); + } else { + /* Prepare, write the pte and sync */ + arch_prepare_write_pte(physical, virtual, + flags, &pmd_table->entry[PMD_INDEX(virtual)]); + } + + /* Move on to the next page */ + physical += PAGE_SIZE; + virtual += PAGE_SIZE; + } +} + +void add_boot_mapping(unsigned long physical, unsigned long virtual, + unsigned int sz_bytes, unsigned int flags) +{ + unsigned long npages = (sz_bytes >> PFN_SHIFT); + pmd_table_t *pmd_table; + + if (sz_bytes < PAGE_SIZE) { + print_early("Error: Mapping size less than PAGE_SIZE. " + "Mapping size should be in _bytes_ " + "not pages.\n"); + BUG(); + } + + if (sz_bytes & PAGE_MASK) + npages++; + + /* Convert generic map flags to arch specific flags */ + BUG_ON(!(flags = space_flags_to_ptflags(flags))); + + /* Map all pages that cover given size */ + for (int i = 0; i < npages; i++) { + /* Check if a pmd was attached previously */ + if (!(pmd_table = pmd_exists(&init_pgd, virtual))) { + + /* First mapping in pmd, allocate it */ + pmd_table = alloc_boot_pmd(); + + /* Prepare the pte but don't sync */ + arch_prepare_pte(physical, virtual, flags, + &pmd_table->entry[PMD_INDEX(virtual)]); + + /* Attach pmd to its pgd and sync it */ + attach_pmd(&init_pgd, pmd_table, virtual); + } else { + /* Prepare, write the pte and sync */ + arch_prepare_write_pte(physical, virtual, + flags, &pmd_table->entry[PMD_INDEX(virtual)]); + } + + /* Move on to the next page */ + physical += PAGE_SIZE; + virtual += PAGE_SIZE; + } +} + +void add_mapping(unsigned long paddr, unsigned long vaddr, + unsigned int size, unsigned int flags) +{ + add_mapping_pgd(paddr, vaddr, size, flags, TASK_PGD(current)); +} + +/* + * Checks if a virtual address range has same or more permissive + * flags than the given ones, returns 0 if not, and 1 if OK. + */ +int check_mapping_pgd(unsigned long vaddr, unsigned long size, + unsigned int flags, pgd_table_t *pgd) +{ + unsigned int npages = __pfn(align_up(size, PAGE_SIZE)); + pte_t pte; + + /* Convert generic map flags to pagetable-specific */ + BUG_ON(!(flags = space_flags_to_ptflags(flags))); + + for (int i = 0; i < npages; i++) { + pte = virt_to_pte_from_pgd(pgd, vaddr + i * PAGE_SIZE); + + /* Check if pte perms are equal or gt given flags */ + if (arch_check_pte_access_perms(pte, flags)) + continue; + else + return 0; + } + + return 1; +} + +int check_mapping(unsigned long vaddr, unsigned long size, + unsigned int flags) +{ + return check_mapping_pgd(vaddr, size, flags, + TASK_PGD(current)); +} + +/* + * This can be made common for v5/v7, keeping split/page table + * and cache flush parts in arch-specific files. + */ +int remove_mapping_pgd(pgd_table_t *task_pgd, unsigned long vaddr) +{ + pmd_table_t *pmd_table; + int pgd_i, pmd_i; + pmd_t *pmd; + unsigned int pmd_type, pte_type; + + vaddr = page_align(vaddr); + pgd_i = PGD_INDEX(vaddr); + pmd_i = PMD_INDEX(vaddr); + + /* + * Get the right pgd's pmd according to whether + * the address is global or task-specific. + */ + pmd = arch_pick_pmd(task_pgd, vaddr); + + pmd_type = *pmd & PMD_TYPE_MASK; + + if (pmd_type == PMD_TYPE_FAULT) + return -ENOMAP; + + /* Anything else must be a proper pmd */ + BUG_ON(pmd_type != PMD_TYPE_PMD); + + /* Get the 2nd level pmd table */ + pmd_table = (pmd_table_t *) + phys_to_virt((unsigned long)*pmd + & PMD_ALIGN_MASK); + + /* Get the pte type already there */ + pte_type = pmd_table->entry[pmd_i] & PTE_TYPE_MASK; + + /* If it's a fault we're done */ + if (pte_type == PTE_TYPE_FAULT) + return -ENOMAP; + /* It must be a small pte if not fault */ + else if (pte_type != PTE_TYPE_SMALL) + BUG(); + + /* Write to pte, also syncing it as required by arch */ + arch_prepare_write_pte(0, vaddr, + space_flags_to_ptflags(MAP_FAULT), + (pte_t *)&pmd_table->entry[pmd_i]); + return 0; +} + +int remove_mapping(unsigned long vaddr) +{ + return remove_mapping_pgd(TASK_PGD(current), vaddr); +} + + +int delete_page_tables(struct address_space *space) +{ + remove_mapping_pgd_all_user(space->pgd); + free_pgd(space->pgd); + return 0; +} + +/* + * Copies userspace entries of one task to another. + * In order to do that, it allocates new pmds and + * copies the original values into new ones. + */ +int copy_user_tables(struct address_space *new, + struct address_space *orig_space) +{ + pgd_table_t *to = new->pgd, *from = orig_space->pgd; + pmd_table_t *pmd, *orig; + + /* Allocate and copy all pmds that will be exclusive to new task. */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + /* Detect a pmd entry that is not a global pmd? */ + if (!is_global_pgdi(i) && + ((from->entry[i] & PMD_TYPE_MASK) + == PMD_TYPE_PMD)) { + /* Allocate new pmd */ + if (!(pmd = alloc_pmd())) + goto out_error; + + /* Find original pmd */ + orig = (pmd_table_t *) + phys_to_virt((from->entry[i] & + PMD_ALIGN_MASK)); + + /* Copy original to new */ + memcpy(pmd, orig, sizeof(pmd_table_t)); + + /* Replace original pmd entry in pgd with new */ + to->entry[i] = (pmd_t)(virt_to_phys(pmd) + | PMD_TYPE_PMD); + } + } + + /* Just in case the new table is written to any ttbr + * after here, make sure all writes on it are complete. */ + dmb(); + + return 0; + +out_error: + /* Find all non-kernel pmds we have just allocated and free them */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + /* Non-kernel pmd that has just been allocated. */ + if (!is_global_pgdi(i) && + (to->entry[i] & PMD_TYPE_MASK) == PMD_TYPE_PMD) { + /* Obtain the pmd handle */ + pmd = (pmd_table_t *) + phys_to_virt((to->entry[i] & + PMD_ALIGN_MASK)); + /* Free pmd */ + free_pmd(pmd); + } + } + return -ENOMEM; +} + + + +/* + * Useful for upgrading to page-grained control + * over the kernel section mapping. + * + * Remaps a section mapping in pages. It allocates a pmd, + * fills in the page information, and replaces the direct + * section physical translation with the address of the + * pmd. Syncs the caches. + * + * NOTE: Assumes only a single pmd is enough. + */ +void remap_as_pages(void *vstart, void *vend) +{ + unsigned long pstart = virt_to_phys(vstart); + unsigned long pend = virt_to_phys(vend); + unsigned long paddr = pstart; + unsigned long vaddr = (unsigned long)vstart; + int pmd_i = PMD_INDEX(vstart); + pgd_table_t *pgd = &init_pgd; + pmd_table_t *pmd = alloc_boot_pmd(); + int npages = __pfn(pend - pstart); + int map_flags; + + /* Map the whole kernel into the pmd first */ + for (int n = 0; n < npages; n++) { + /* Map text pages as executable */ + if ((vaddr >= (unsigned long)_start_text && + vaddr < page_align_up(_end_text)) || + (vaddr >= (unsigned long)_start_vectors && + vaddr < page_align_up(_end_vectors))) + map_flags = MAP_KERN_RWX; + else + map_flags = MAP_KERN_RW; + + arch_prepare_pte(paddr, vaddr, + space_flags_to_ptflags(map_flags), + &pmd->entry[pmd_i + n]); + paddr += PAGE_SIZE; + vaddr += PAGE_SIZE; + } + + attach_pmd(pgd, pmd, (unsigned long)vstart); + + printk("%s: Kernel area 0x%lx - 0x%lx " + "remapped as %d pages\n", __KERNELNAME__, + (unsigned long)vstart, (unsigned long)vend, + npages); +} + diff --git a/src/arch/arm/memcpy.S b/src/arch/arm/memcpy.S new file mode 100644 index 0000000..bbf48b9 --- /dev/null +++ b/src/arch/arm/memcpy.S @@ -0,0 +1,60 @@ +/* + * Copyright 2010 B Labs.Ltd. + * + * Author: Prem Mallappa + * + * Description: Optimized memcpy for ARM + * + */ + +#include INC_ARCH(asm.h) +/* +void* +_memcpy(void *dst, const void *src, register uint len) +*/ +BEGIN_PROC(_memcpy) + push {r0, r4-r11, lr} + loop32: + cmp r2, #32 + blt loop16 + ldmia r1!, {r4 - r11} + stmia r0!, {r4 - r11} + sub r2, r2, #32 + b loop32 + + loop16: + cmp r2, #16 + blt loop8 + ldmia r1!, {r4 - r7} + stmia r0!, {r4 - r7} + sub r2, r2, #16 + b loop16 + + loop8: + cmp r2, #8 + blt loop4 + ldmia r1!, {r4, r5} + stmia r0!, {r4, r5} + sub r2, r2, #8 + b loop8 + + loop4: + cmp r2, #4 + blt end + ldmia r1!, {r4} + stmia r0!, {r4} + sub r2, r2, #4 + b loop4 + end: + last: + teq r2, #0 + ldrgtb r4, [r1] + strneb r4, [r0] // V7 supports strneb , [, +/-] !, with write back + lsrne r4, r4, #8 + subne r2, r2, #1 // Can be reduced to 1 LDR, but has a catch if it is end of memory + addne r0, r0, #1 // we dont want to fetch 1 byte extra to end up in abort + addne r1, r1, #1 // so, playing safe, worst case 3 LDRs + bne last + 1: + pop {r0, r4 - r11, pc} +END_PROC(_memcpy) diff --git a/src/arch/arm/memset.S b/src/arch/arm/memset.S new file mode 100644 index 0000000..3a203d8 --- /dev/null +++ b/src/arch/arm/memset.S @@ -0,0 +1,68 @@ +/* + * Copyright 2010 (C) B Labs. + * Author: Prem Mallappa + * Description: Optimized memset for ARM + */ + +#include INC_ARCH(asm.h) + +/* +void * +memset(void *dst, int c, int len) +*/ +BEGIN_PROC(_memset) + stmfd sp!, {r4 - r11, lr} + + and r1, r1, #255 /* c &= 0xff */ + orr r1, r1, lsl #8 /* c |= c<<8 */ + orr r1, r1, lsl #16 /* c |= c<<16 */ + mov r4, r1 + cmp r2, #8 + blt 4f + movge r5, r4 + cmpge r2, #16 + blt 8f + movge r6, r4 + movge r7, r4 + cmpge r2, #32 + blt 16f + movge r8, r4 + movge r9, r4 + movge r10, r4 + movge r11, r4 + 32: + cmp r2, #32 + blt 16f + stmia r0!, {r4 - r11} + sub r2, r2, #32 + b 32b + + 16: + cmp r2, #16 + blt 8f + stmia r0!, {r4 - r7} + sub r2, r2, #16 + b 16b + + 8: + cmp r2, #8 + blt 4f + stmia r0!, {r4, r5} + sub r2, r2, #8 + b 8b + + 4: + cmp r2, #4 + blt end + stmia r0!, {r4} + sub r2, r2, #4 + b 4b + end: + teq r2, #0 + strneb r4, [r0, #0] + subne r2, r2, #1 + addne r0, r0, #1 + bne end + + ldmfd sp!, {r4 - r11, pc} +END_PROC(_memset) diff --git a/src/arch/arm/syscall.S b/src/arch/arm/syscall.S index 9c8e6f9..c511645 100644 --- a/src/arch/arm/syscall.S +++ b/src/arch/arm/syscall.S @@ -31,5 +31,6 @@ BEGIN_PROC(arm_system_calls) swi 0x14 @ kmem_control /* 0x2C */ swi 0x14 @ time /* 0x30 */ swi 0x14 @ mutex_control /* 0x34 */ + swi 0x14 @ cache_control /* 0x38 */ END_PROC(arm_system_calls) diff --git a/src/arch/arm/v5/SConscript b/src/arch/arm/v5/SConscript index 4fd282a..71ff4c4 100644 --- a/src/arch/arm/v5/SConscript +++ b/src/arch/arm/v5/SConscript @@ -4,7 +4,7 @@ Import('env') # The set of source files associated with this SConscript file. -src_local = ['mm.c', 'mmu_ops.S', 'mutex.S'] +src_local = ['mapping.c', 'exception.c', 'mmu_ops.S', 'cache.c', 'mutex.c', 'irq.c', 'init.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/arch/arm/v5/cache.c b/src/arch/arm/v5/cache.c new file mode 100644 index 0000000..f2145e2 --- /dev/null +++ b/src/arch/arm/v5/cache.c @@ -0,0 +1,32 @@ +/* + * Generic layer over ARMv5 soecific cache calls + * + * Copyright B-Labs Ltd 2010. + */ + +#include INC_SUBARCH(mmu_ops.h) + +void arch_invalidate_dcache(unsigned long start, unsigned long end) +{ + arm_invalidate_dcache(); +} + +void arch_clean_invalidate_dcache(unsigned long start, unsigned long end) +{ + arm_clean_invalidate_dcache(); +} + +void arch_invalidate_icache(unsigned long start, unsigned long end) +{ + arm_invalidate_icache(); +} + +void arch_clean_dcache(unsigned long start, unsigned long end) +{ + arm_clean_dcache(); +} + +void arch_invalidate_tlb(unsigned long start, unsigned long end) +{ + arm_invalidate_tlb(); +} diff --git a/src/arch/arm/v5/exception.c b/src/arch/arm/v5/exception.c new file mode 100644 index 0000000..6fbf5d5 --- /dev/null +++ b/src/arch/arm/v5/exception.c @@ -0,0 +1,246 @@ +/* + * Memory exception handling in process context. + * + * Copyright (C) 2007, 2008 Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include INC_ARCH(exception.h) +#include INC_GLUE(memlayout.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(message.h) +#include INC_GLUE(ipc.h) +#include INC_SUBARCH(mm.h) + +int check_abort_type(u32 faulted_pc, u32 fsr, u32 far, u32 spsr) +{ + int ret = 0; + + /* + * On ARMv5, prefetch aborts dont have different + * status values. We validate them here and return. + */ + if (is_prefetch_abort(fsr)) { + dbg_abort("Prefetch abort: 0x%x\n", faulted_pc); + + /* Happened in any mode other than user */ + if (!is_user_mode(spsr)) { + dprintk("Unhandled kernel prefetch " + "abort at address ", far); + return -EABORT; + } + return 0; + } + + switch (fsr & FSR_FS_MASK) { + /* Aborts that are expected on page faults: */ + case DABT_PERM_PAGE: + dbg_abort("Page permission fault 0x%x\n", far); + ret = 0; + break; + case DABT_XLATE_PAGE: + dbg_abort("Page translation fault 0x%x\n", far); + ret = 0; + break; + case DABT_XLATE_SECT: + dbg_abort("Section translation fault 0x%x\n", far); + ret = 0; + break; + + /* Aborts that can't be handled by a pager yet: */ + case DABT_TERMINAL: + dprintk("Terminal fault dabt %x", far); + ret = -EABORT; + break; + case DABT_VECTOR: + dprintk("Vector abort (obsolete!) %x", far); + ret = -EABORT; + break; + case DABT_ALIGN: + dprintk("Alignment fault dabt %x", far); + ret = -EABORT; + break; + case DABT_EXT_XLATE_LEVEL1: + dprintk("External LVL1 translation fault %x", far); + ret = -EABORT; + break; + case DABT_EXT_XLATE_LEVEL2: + dprintk("External LVL2 translation fault %x", far); + ret = -EABORT; + break; + case DABT_DOMAIN_SECT: + dprintk("Section domain fault dabt %x", far); + ret = -EABORT; + break; + case DABT_DOMAIN_PAGE: + dprintk("Page domain fault dabt %x", far); + ret = -EABORT; + break; + case DABT_PERM_SECT: + dprintk("Section permission fault dabt %x", far); + ret = -EABORT; + break; + case DABT_EXT_LFETCH_SECT: + dprintk("External section linefetch " + "fault dabt %x", far); + ret = -EABORT; + break; + case DABT_EXT_LFETCH_PAGE: + dprintk("Page perm fault dabt %x", far); + ret = -EABORT; + break; + case DABT_EXT_NON_LFETCH_SECT: + dprintk("External section non-linefetch " + "fault dabt %x ", far); + ret = -EABORT; + break; + case DABT_EXT_NON_LFETCH_PAGE: + dprintk("External page non-linefetch " + "fault dabt %x ", far); + ret = -EABORT; + break; + default: + dprintk("FATAL: Unrecognised/Unknown " + "data abort %x ", far); + dprintk("FATAL: FSR code: ", fsr); + ret = -EABORT; + } + + /* + * Check validity of data abort's source. + * + * FIXME: Why not use spsr to do this? + */ + if (is_kernel_address(faulted_pc)) { + dprintk("Unhandled kernel data " + "abort at address %x", + faulted_pc); + ret = -EABORT; + } + + return ret; +} + +#if 0 +void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far) +{ + set_abort_type(fsr, ARM_DABT); + + dbg_abort("Data abort @ PC: ", faulted_pc); + + //printk("Data abort: %d, PC: 0x%x\n", + //current->tid, faulted_pc); + + /* Check for more details */ + if (check_aborts(faulted_pc, fsr, far) < 0) { + printascii("This abort can't be handled by " + "any pager.\n"); + goto error; + } + + /* This notifies the pager */ + fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } else if (current->flags & TASK_EXITING) { + BUG_ON(current->nlocks); + sched_exit_sync(); + } + + return; + +error: + disable_irqs(); + dprintk("Unhandled data abort @ PC address: ", faulted_pc); + dprintk("FAR:", far); + dprintk("FSR:", fsr); + printascii("Kernel panic.\n"); + printascii("Halting system...\n"); + while (1) + ; +} + +void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 spsr) +{ + set_abort_type(fsr, ARM_PABT); + + if (check_aborts(faulted_pc, fsr, far) < 0) { + printascii("This abort can't be handled by any pager.\n"); + goto error; + } + + /* Did the abort occur in kernel mode? */ + if ((spsr & ARM_MODE_MASK) == ARM_MODE_SVC) + goto error; + + fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } else if (current->flags & TASK_EXITING) { + BUG_ON(current->nlocks); + sched_exit_sync(); + } + + return; + +error: + disable_irqs(); + dprintk("Unhandled prefetch abort @ address: ", faulted_pc); + dprintk("FAR:", far); + dprintk("FSR:", fsr); + dprintk("Aborted PSR:", spsr); + printascii("Kernel panic.\n"); + printascii("Halting system...\n"); + while (1) + ; +} + +void undef_handler(u32 undef_addr, u32 spsr, u32 lr) +{ + dbg_abort("Undefined instruction @ PC: ", undef_addr); + + //printk("Undefined instruction: tid: %d, PC: 0x%x, Mode: %s\n", + // current->tid, undef_addr, + // (spsr & ARM_MODE_MASK) == ARM_MODE_SVC ? "SVC" : "User"); + + if ((spsr & ARM_MODE_MASK) == ARM_MODE_SVC) { + printk("Panic: Undef in Kernel\n"); + goto error; + } + + fault_ipc_to_pager(undef_addr, 0, undef_addr, L4_IPC_TAG_UNDEF_FAULT); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } else if (current->flags & TASK_EXITING) { + BUG_ON(current->nlocks); + sched_exit_sync(); + } + + return; + +error: + disable_irqs(); + dprintk("SPSR:", spsr); + dprintk("LR:", lr); + printascii("Kernel panic.\n"); + printascii("Halting system...\n"); + while(1) + ; +} +#endif + diff --git a/src/arch/arm/v5/init.c b/src/arch/arm/v5/init.c new file mode 100644 index 0000000..691d7ee --- /dev/null +++ b/src/arch/arm/v5/init.c @@ -0,0 +1,146 @@ +/* + * ARM v5 specific init routines + * + * Copyright (C) 2007 - 2010 B Labs Ltd. + */ + +#include +#include +#include +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_ARCH(linker.h) + +SECTION(".data.pgd") ALIGN(PGD_SIZE) pgd_table_t init_pgd; +struct address_space init_space; + +void system_identify(void) +{ + +} + + +void jump(struct ktcb *task) +{ + __asm__ __volatile__ ( + "mov lr, %0\n" /* Load pointer to context area */ + "ldr r0, [lr]\n" /* Load spsr value to r0 */ + "msr spsr, r0\n" /* Set SPSR as ARM_MODE_USR */ + "add sp, lr, %1\n" /* Reset SVC stack */ + "sub sp, sp, %2\n" /* Align to stack alignment */ + "ldmib lr, {r0-r14}^\n" /* Load all USR registers */ + + "nop \n" /* Spec says dont touch banked registers + * right after LDM {no-pc}^ for one instruction */ + "add lr, lr, #64\n" /* Manually move to PC location. */ + "ldr lr, [lr]\n" /* Load the PC_USR to LR */ + "movs pc, lr\n" /* Jump to userspace, also switching SPSR/CPSR */ + : + : "r" (task), "r" (PAGE_SIZE), "r" (STACK_ALIGNMENT) + ); +} + +void switch_to_user(struct ktcb *task) +{ + arm_clean_invalidate_cache(); + arm_invalidate_tlb(); + arm_set_ttb(virt_to_phys(TASK_PGD(task))); + arm_invalidate_tlb(); + jump(task); +} + +/* Maps the early memory regions needed to bootstrap the system */ +void init_kernel_mappings(void) +{ + //memset((void *)virt_to_phys(&init_pgd), 0, sizeof(pgd_table_t)); + + /* Map kernel area to its virtual region */ + add_section_mapping_init(align(virt_to_phys(_start_text), SZ_1MB), + align((unsigned int)_start_text, SZ_1MB), 1, + cacheable | bufferable); + + /* Map kernel one-to-one to its physical region */ + add_section_mapping_init(align(virt_to_phys(_start_text), SZ_1MB), + align(virt_to_phys(_start_text), SZ_1MB), + 1, 0); +} + +/* + * Enable virtual memory using kernel's pgd + * and continue execution on virtual addresses. + */ +void start_virtual_memory() +{ + /* + * TTB must be 16K aligned. This is because first level tables are + * sized 16K. + */ + if ((unsigned int)&init_pgd & 0x3FFF) + dprintk("kspace not properly aligned for ttb:", + (u32)&init_pgd); + // memset((void *)&kspace, 0, sizeof(pgd_table_t)); + arm_set_ttb(virt_to_phys(&init_pgd)); + + /* + * This sets all 16 domains to zero and domain 0 to 1. The outcome + * is that page table access permissions are in effect for domain 0. + * All other domains have no access whatsoever. + */ + arm_set_domain(1); + + /* Enable everything before mmu permissions are in place */ + arm_enable_caches(); + arm_enable_wbuffer(); + + arm_enable_high_vectors(); + + /* + * Leave the past behind. Tlbs are invalidated, write buffer is drained. + * The whole of I + D caches are invalidated unconditionally. This is + * important to ensure that the cache is free of previously loaded + * values. Otherwise unpredictable data aborts may occur at arbitrary + * times, each time a load/store operation hits one of the invalid + * entries and those entries are cleaned to main memory. + */ + arm_invalidate_cache(); + arm_drain_writebuffer(); + arm_invalidate_tlb(); + arm_enable_mmu(); + + /* Jump to virtual memory addresses */ + __asm__ __volatile__ ( + "add sp, sp, %0 \n" /* Update stack pointer */ + "add fp, fp, %0 \n" /* Update frame pointer */ + /* On the next instruction below, r0 gets + * current PC + KOFFSET + 2 instructions after itself. */ + "add r0, pc, %0 \n" + /* Special symbol that is extracted and included in the loader. + * Debuggers can break on it to load the virtual symbol table */ + ".global break_virtual;\n" + "break_virtual:\n" + "mov pc, r0 \n" /* (r0 has next instruction) */ + : + : "r" (KERNEL_OFFSET) + : "r0" + ); + + /* + * Restore link register (LR) for this function. + * + * NOTE: LR values are pushed onto the stack at each function call, + * which means the restored return values will be physical for all + * functions in the call stack except this function. So the caller + * of this function must never return but initiate scheduling etc. + */ + __asm__ __volatile__ ( + "add %0, %0, %1 \n" + "mov pc, %0 \n" + :: "r" (__builtin_return_address(0)), "r" (KERNEL_OFFSET) + ); + + /* should never come here */ + while(1); +} + diff --git a/src/arch/arm/v5/irq.S b/src/arch/arm/v5/irq.S new file mode 100644 index 0000000..480e80c --- /dev/null +++ b/src/arch/arm/v5/irq.S @@ -0,0 +1,43 @@ + + + +#include INC_ARCH(asm.h) + +/* + * r0 = unsigned long *state, stores current irq state. + */ +BEGIN_PROC(irq_local_disable_save) + mov r1, r0 @ Move address of state to r1 + mrs r2, cpsr_fc @ Read cpsr + orr r3, r2, #0x80 @ Disable irq bit in cpsr + msr cpsr_fc, r3 @ Write to cpsr + str r2, [r1] @ Store original cpsr in r2 to state + mov pc, lr +END_PROC(irq_local_disable_save) + +/* + * r0 = last cpsr state + */ +BEGIN_PROC(irq_local_restore) + msr cpsr_fc, r0 @ Write r0 to cpsr + mov pc, lr +END_PROC(irq_local_restore) + +/* + * r0 = byte address to read from. + */ +BEGIN_PROC(l4_atomic_dest_readb) + mov r1, r0 @ Move byte address to r1 + mov r2, #0 @ Move 0 to r2 + swpb r0, r2, [r1] @ Write 0 to byte location, while reading its value to r0 + mov pc, lr @ Return byte location value +END_PROC(l4_atomic_dest_readb) + +BEGIN_PROC(irqs_enabled) + mrs r1, cpsr_fc + tst r1, #0x80 + moveq r0, #1 + movne r0, #0 + mov pc, lr +END_PROC(irqs_enabled) + diff --git a/src/arch/arm/v5/irq.c b/src/arch/arm/v5/irq.c new file mode 100644 index 0000000..11a99ba --- /dev/null +++ b/src/arch/arm/v5/irq.c @@ -0,0 +1,72 @@ +/* + * Low-level irq routines. + * + * Copyright (C) 2010 B Labs Ltd. + * Written by Bahadir Balban + * Prem Mallappa + */ + +void irq_local_disable_save(unsigned long *state) +{ + unsigned int tmp, tmp2; + __asm__ __volatile__ ( + "mrs %0, cpsr_fc \n" + "orr %1, %0, #0x80 \n" + "msr cpsr_fc, %1 \n" + : "=&r"(tmp), "=r"(tmp2) + : + : "cc" + ); + *state = tmp; +} + +void irq_local_restore(unsigned long state) +{ + __asm__ __volatile__ ( + "msr cpsr_fc, %0\n" + : + : "r"(state) + : "cc" + ); +} + +u8 l4_atomic_dest_readb(unsigned long *location) +{ +#if 0 + unsigned int tmp; + __asm__ __volatile__ ( + "swpb r0, r2, [r1] \n" + : "=r"(tmp) + : "r"(location), "r"(0) + : "memory" + ); + + return (u8)tmp; +#endif + + unsigned int tmp; + unsigned long state; + irq_local_disable_save(&state); + + tmp = *location; + *location = 0; + + irq_local_restore(state); + + return (u8)tmp; + +} + +int irqs_enabled(void) +{ + int tmp; + __asm__ __volatile__ ( + "mrs %0, cpsr_fc\n" + : "=r"(tmp) + ); + + if (tmp & 0x80) + return 0; + + return 1; +} diff --git a/src/arch/arm/v5/mapping.c b/src/arch/arm/v5/mapping.c new file mode 100644 index 0000000..d3bfaa3 --- /dev/null +++ b/src/arch/arm/v5/mapping.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(memlayout.h) +#include INC_ARCH(linker.h) +#include INC_ARCH(asm.h) +#include INC_API(kip.h) +#include INC_ARCH(io.h) + +/* + * Removes initial mappings needed for transition to virtual memory. + * Used one-time only. + */ +void remove_section_mapping(unsigned long vaddr) +{ + pgd_table_t *pgd = &init_pgd; + pmd_t pgd_i = PGD_INDEX(vaddr); + if (!((pgd->entry[pgd_i] & PMD_TYPE_MASK) + & PMD_TYPE_SECTION)) + while(1); + pgd->entry[pgd_i] = 0; + pgd->entry[pgd_i] |= PMD_TYPE_FAULT; + arm_invalidate_tlb(); +} + +/* + * Maps given section-aligned @paddr to @vaddr using enough number + * of section-units to fulfill @size in sections. Note this overwrites + * a mapping if same virtual address was already mapped. + */ +void __add_section_mapping_init(unsigned int paddr, + unsigned int vaddr, + unsigned int size, + unsigned int flags) +{ + pte_t *ppte; + unsigned int l1_ptab; + unsigned int l1_offset; + + /* 1st level page table address */ + l1_ptab = virt_to_phys(&init_pgd); + + /* Get the section offset for this vaddr */ + l1_offset = (vaddr >> 18) & 0x3FFC; + + /* The beginning entry for mapping */ + ppte = (unsigned int *)(l1_ptab + l1_offset); + for(int i = 0; i < size; i++) { + *ppte = 0; /* Clear out old value */ + *ppte |= paddr; /* Assign physical address */ + *ppte |= PMD_TYPE_SECTION; /* Assign translation type */ + /* Domain is 0, therefore no writes. */ + /* Only kernel access allowed */ + *ppte |= (SVC_RW_USR_NONE << SECTION_AP0); + /* Cacheability/Bufferability flags */ + *ppte |= flags; + ppte++; /* Next section entry */ + paddr += SECTION_SIZE; /* Next physical section */ + } + return; +} + +void add_section_mapping_init(unsigned int paddr, unsigned int vaddr, + unsigned int size, unsigned int flags) +{ + unsigned int psection; + unsigned int vsection; + + /* Align each address to the pages they reside in */ + psection = paddr & ~SECTION_MASK; + vsection = vaddr & ~SECTION_MASK; + + if (size == 0) + return; + + __add_section_mapping_init(psection, vsection, size, flags); + + return; +} + +void arch_prepare_pte(u32 paddr, u32 vaddr, unsigned int flags, + pte_t *ptep) +{ + /* They must be aligned at this stage */ + if (!is_page_aligned(paddr) || !is_page_aligned(vaddr)) { + printk("address not aligned, phys address %x" + " virtual address %x\n", paddr, vaddr); + BUG(); + } + + /* + * NOTE: In v5, the flags converted from generic + * by space_flags_to_ptflags() can be directly + * written to the pte. No further conversion is needed. + * Therefore this function doesn't do much on flags. In + * contrast in ARMv7 the flags need an extra level of + * processing. + */ + if (flags == __MAP_FAULT) + *ptep = paddr | flags | PTE_TYPE_FAULT; + else + *ptep = paddr | flags | PTE_TYPE_SMALL; +} + +void arch_write_pte(pte_t *ptep, pte_t pte, u32 vaddr) +{ + /* FIXME: + * Clean the dcache and invalidate the icache + * for the old translation first? + * + * The dcache is virtual, therefore the data + * in those entries should be cleaned first, + * before the translation of that virtual + * address is changed to a new physical address. + * + * Check that the entry was not faulty first. + */ + arm_clean_invalidate_cache(); + + *ptep = pte; + + /* FIXME: Fix this! + * - Use vaddr to clean the dcache pte by MVA. + * - Use mapped area to invalidate the icache + * - Invalidate the tlb for mapped area + */ + arm_clean_invalidate_cache(); + arm_invalidate_tlb(); +} + + +void arch_prepare_write_pte(u32 paddr, u32 vaddr, + unsigned int flags, pte_t *ptep) +{ + pte_t pte = 0; + + /* They must be aligned at this stage */ + BUG_ON(!is_page_aligned(paddr)); + BUG_ON(!is_page_aligned(vaddr)); + + arch_prepare_pte(paddr, vaddr, flags, &pte); + + arch_write_pte(ptep, pte, vaddr); +} + +pmd_t * +arch_pick_pmd(pgd_table_t *pgd, unsigned long vaddr) +{ + return &pgd->entry[PGD_INDEX(vaddr)]; +} + +/* + * v5 pmd writes + */ +void arch_write_pmd(pmd_t *pmd_entry, u32 pmd_phys, u32 vaddr) +{ + /* FIXME: Clean the dcache if there was a valid entry */ + *pmd_entry = (pmd_t)(pmd_phys | PMD_TYPE_PMD); + arm_clean_invalidate_cache(); /*FIXME: Write these properly! */ + arm_invalidate_tlb(); +} + + +int arch_check_pte_access_perms(pte_t pte, unsigned int flags) +{ + if ((pte & PTE_PROT_MASK) >= (flags & PTE_PROT_MASK)) + return 1; + else + return 0; +} + +/* + * Tell if a pgd index is a common kernel index. + * This is used to distinguish common kernel entries + * in a pgd, when copying page tables. + */ +int is_global_pgdi(int i) +{ + if ((i >= PGD_INDEX(KERNEL_AREA_START) && + i < PGD_INDEX(KERNEL_AREA_END)) || + (i >= PGD_INDEX(IO_AREA_START) && + i < PGD_INDEX(IO_AREA_END)) || + (i == PGD_INDEX(USER_KIP_PAGE)) || + (i == PGD_INDEX(ARM_HIGH_VECTOR)) || + (i == PGD_INDEX(ARM_SYSCALL_VECTOR)) || + (i == PGD_INDEX(USERSPACE_CONSOLE_VBASE))) + return 1; + else + return 0; +} + +extern pmd_table_t *pmd_array; + +void remove_mapping_pgd_all_user(pgd_table_t *pgd) +{ + pmd_table_t *pmd; + + /* Traverse through all pgd entries. */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + if (!is_global_pgdi(i)) { + /* Detect a pmd entry */ + if (((pgd->entry[i] & PMD_TYPE_MASK) + == PMD_TYPE_PMD)) { + + /* Obtain the user pmd handle */ + pmd = (pmd_table_t *) + phys_to_virt((pgd->entry[i] & + PMD_ALIGN_MASK)); + /* Free it */ + free_pmd(pmd); + } + + /* Clear the pgd entry */ + pgd->entry[i] = PMD_TYPE_FAULT; + } + } +} + + +int pgd_count_boot_pmds() +{ + int npmd = 0; + pgd_table_t *pgd = &init_pgd; + + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) + if ((pgd->entry[i] & PMD_TYPE_MASK) == PMD_TYPE_PMD) + npmd++; + return npmd; +} + + +/* + * Jumps from boot pmd/pgd page tables to tables allocated from the cache. + */ +pgd_table_t *arch_realloc_page_tables(void) +{ + pgd_table_t *pgd_new = alloc_pgd(); + pgd_table_t *pgd_old = &init_pgd; + pmd_table_t *orig, *pmd; + + /* Copy whole pgd entries */ + memcpy(pgd_new, pgd_old, sizeof(pgd_table_t)); + + /* Allocate and copy all pmds */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + /* Detect a pmd entry */ + if ((pgd_old->entry[i] & PMD_TYPE_MASK) == PMD_TYPE_PMD) { + /* Allocate new pmd */ + if (!(pmd = alloc_pmd())) { + printk("FATAL: PMD allocation " + "failed during system initialization\n"); + BUG(); + } + + /* Find original pmd */ + orig = (pmd_table_t *) + phys_to_virt((pgd_old->entry[i] & + PMD_ALIGN_MASK)); + + /* Copy original to new */ + memcpy(pmd, orig, sizeof(pmd_table_t)); + + /* Replace original pmd entry in pgd with new */ + pgd_new->entry[i] = (pmd_t)virt_to_phys(pmd); + pgd_new->entry[i] |= PMD_TYPE_PMD; + } + } + + /* Switch the virtual memory system into new area */ + arm_clean_invalidate_cache(); + arm_drain_writebuffer(); + arm_invalidate_tlb(); + arm_set_ttb(virt_to_phys(pgd_new)); + arm_invalidate_tlb(); + + printk("%s: Initial page tables moved from 0x%x to 0x%x physical\n", + __KERNELNAME__, virt_to_phys(pgd_old), + virt_to_phys(pgd_new)); + + return pgd_new; +} + +/* + * Copies global kernel entries into another pgd. Even for + * sub-pmd ranges the associated pmd entries are copied, + * assuming any pmds copied are applicable to all tasks in + * the system. + */ +void copy_pgd_global_by_vrange(pgd_table_t *to, pgd_table_t *from, + unsigned long start, unsigned long end) +{ + /* Extend sub-pmd ranges to their respective pmd boundaries */ + start = align(start, PMD_MAP_SIZE); + + if (end < start) + end = 0; + + /* Aligning would overflow if mapping the last virtual pmd */ + if (end < align(~0, PMD_MAP_SIZE) || + start > end) /* end may have already overflown as input */ + end = align_up(end, PMD_MAP_SIZE); + else + end = 0; + + copy_pgds_by_vrange(to, from, start, end); +} + +void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, + unsigned long start, unsigned long end) +{ + unsigned long start_i = PGD_INDEX(start); + unsigned long end_i = PGD_INDEX(end); + unsigned long irange = (end_i != 0) ? (end_i - start_i) + : (PGD_ENTRY_TOTAL - start_i); + + memcpy(&to->entry[start_i], &from->entry[start_i], + irange * sizeof(pmd_t)); +} + +void arch_copy_pgd_kernel_entries(pgd_table_t *to) +{ + pgd_table_t *from = TASK_PGD(current); + + copy_pgd_global_by_vrange(to, from, KERNEL_AREA_START, + KERNEL_AREA_END); + copy_pgd_global_by_vrange(to, from, IO_AREA_START, IO_AREA_END); + copy_pgd_global_by_vrange(to, from, USER_KIP_PAGE, + USER_KIP_PAGE + PAGE_SIZE); + copy_pgd_global_by_vrange(to, from, ARM_HIGH_VECTOR, + ARM_HIGH_VECTOR + PAGE_SIZE); + copy_pgd_global_by_vrange(to, from, ARM_SYSCALL_VECTOR, + ARM_SYSCALL_VECTOR + PAGE_SIZE); + + /* We temporarily map uart registers to every process */ + copy_pgd_global_by_vrange(to, from, USERSPACE_CONSOLE_VBASE, + USERSPACE_CONSOLE_VBASE + PAGE_SIZE); +} + +void arch_update_utcb(unsigned long utcb_address) +{ + /* Update the KIP pointer */ + kip.utcb = utcb_address; +} + +/* Scheduler uses this to switch context */ +void arch_space_switch(struct ktcb *to) +{ + pgd_table_t *pgd = TASK_PGD(to); + + system_account_space_switch(); + + arm_clean_invalidate_cache(); + arm_invalidate_tlb(); + arm_set_ttb(virt_to_phys(pgd)); + arm_invalidate_tlb(); +} + +void idle_task(void) +{ + while(1) { + tcb_delete_zombies(); + + // printk("Idle task.\n"); + schedule(); + } +} + diff --git a/src/arch/arm/v5/mmu_ops.S b/src/arch/arm/v5/mmu_ops.S index ceda880..ec9cca5 100644 --- a/src/arch/arm/v5/mmu_ops.S +++ b/src/arch/arm/v5/mmu_ops.S @@ -88,7 +88,7 @@ END_PROC(arm_enable_high_vectors) BEGIN_PROC(arm_invalidate_cache) mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c7, c7 @ Flush I cache and D cache + mcr p15, 0, r0, c7, c7, 0 @ Flush I cache and D cache mov pc, lr END_PROC(arm_invalidate_cache) @@ -105,7 +105,7 @@ BEGIN_PROC(arm_invalidate_dcache) END_PROC(arm_invalidate_dcache) BEGIN_PROC(arm_clean_dcache) - mrc p15, 0 , pc, c7, c10, 3 @ Test/clean dcache line + mrc p15, 0 , r15, c7, c10, 3 @ Test/clean dcache line bne arm_clean_dcache mcr p15, 0, ip, c7, c10, 4 @ Drain WB mov pc, lr @@ -113,7 +113,7 @@ END_PROC(arm_clean_dcache) BEGIN_PROC(arm_clean_invalidate_dcache) 1: - mrc p15, 0, pc, c7, c14, 3 @ Test/clean/flush dcache line + mrc p15, 0, r15, c7, c14, 3 @ Test/clean/flush dcache line @ COMMENT: Why use PC? bne 1b mcr p15, 0, ip, c7, c10, 4 @ Drain WB diff --git a/src/arch/arm/v5/mutex.c b/src/arch/arm/v5/mutex.c new file mode 100644 index 0000000..989bde5 --- /dev/null +++ b/src/arch/arm/v5/mutex.c @@ -0,0 +1,75 @@ +/* + * ARM v5 Binary semaphore (mutex) implementation. + * + * Copyright (C) 2007-2010 B Labs Ltd. + * Author: Prem Mallappa + */ + +#include + +/* Recap on swp: + * swp rx, ry, [rz] + * In one instruction: + * 1) Stores the value in ry into location pointed by rz. + * 2) Loads the value in the location of rz into rx. + * By doing so, in one instruction one can attempt to lock + * a word, and discover whether it was already locked. + */ + +#define MUTEX_UNLOCKED 0 +#define MUTEX_LOCKED 1 + +void __spin_lock(unsigned long *s) +{ + int tmp = 0, tmp2; + __asm__ __volatile__( + "1: \n" + "swp %0, %1, [%2] \n" + "teq %0, %3 \n" + "bne 1b \n" + : "=&r" (tmp2) + : "r" (tmp), "r"(s), "r"(0) + : "cc", "memory" + ); +} + +void __spin_unlock(unsigned long *s) +{ + int tmp = 1, tmp2; + __asm__ __volatile__( + "1: \n" + "swp %0, %1, [%2] \n" + "teq %0, %3 \n" + "bne 1b \n" + : "=&r" (tmp2) + : "r" (tmp), "r"(s), "r"(0) + : "cc", "memory" + ); +} + +int __mutex_lock(unsigned long *s) +{ + int tmp = MUTEX_LOCKED, tmp2; + __asm__ __volatile__( + "swp %0, %1, [%2] \n" + : "=&r"(tmp2) + : "r"(tmp), "r"(s) + : "cc", "memory" + ); + if (tmp2 == MUTEX_UNLOCKED) + return 1; + + return 0; +} + +void __mutex_unlock(unsigned long *s) +{ + int tmp, tmp2=MUTEX_UNLOCKED; + __asm__ __volatile__( + "swp %0, %1, [%2] \n" + : "=&r"(tmp) + : "r"(tmp2), "r"(s) + : "cc", "memory" + ); + BUG_ON(tmp != MUTEX_LOCKED); +} diff --git a/src/arch/arm/v6/SConscript b/src/arch/arm/v6/SConscript index 4fd282a..ff681b2 100644 --- a/src/arch/arm/v6/SConscript +++ b/src/arch/arm/v6/SConscript @@ -4,7 +4,7 @@ Import('env') # The set of source files associated with this SConscript file. -src_local = ['mm.c', 'mmu_ops.S', 'mutex.S'] +src_local = ['mapping.c', 'exception.c', 'mmu_ops.S', 'mutex.c', 'irq.c', 'init.c', 'cpu_startup.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/arch/arm/v6/cpu_startup.c b/src/arch/arm/v6/cpu_startup.c new file mode 100644 index 0000000..3a4f980 --- /dev/null +++ b/src/arch/arm/v6/cpu_startup.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * Author: Prem Mallappa + */ + +#include INC_CPU(cpu.h) +//#include INC_SUBARCH(cpu.h) +//#include INC_ARCH(cpu.h) + + +/* This code is guaranteed to be executed before MMU is enabled */ + +void cpu_startup(void) +{ + /* For now this should have + * cache disabling + * branch prediction disabling + */ + + /* Here enable the common bits + * cache + * branch prediction + * write buffers + */ + + /* Enable V6 page tables */ + //unsigned int val = arm_get_cp15_cr() | 1<<23; + //arm_set_cp15_cr(val); + + +#if defined (CONFIG_SMP) + /* Enable SCU*/ + /* Enable SMP bit in CP15 */ +#endif + +} diff --git a/src/arch/arm/v6/exception.c b/src/arch/arm/v6/exception.c new file mode 100644 index 0000000..2f35158 --- /dev/null +++ b/src/arch/arm/v6/exception.c @@ -0,0 +1,246 @@ +/* + * Memory exception handling in process context. + * + * Copyright (C) 2007, 2008 Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include INC_ARCH(exception.h) +#include INC_GLUE(memlayout.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(message.h) +#include INC_GLUE(ipc.h) +#include INC_SUBARCH(mm.h) + +int check_abort_type(u32 faulted_pc, u32 fsr, u32 far, u32 spsr) +{ + int ret = 0; + + /* + * On ARMv5, prefetch aborts dont have different + * status values. We validate them here and return. + */ + if (is_prefetch_abort(fsr)) { + dbg_abort("Prefetch abort @ ", faulted_pc); + + /* Happened in any mode other than user */ + if (!is_user_mode(spsr)) { + dprintk("Unhandled kernel prefetch " + "abort at address ", far); + return -EABORT; + } + return 0; + } + + switch (fsr & FSR_FS_MASK) { + /* Aborts that are expected on page faults: */ + case DABT_PERM_PAGE: + dbg_abort("Page permission fault @ ", far); + ret = 0; + break; + case DABT_XLATE_PAGE: + dbg_abort("Page translation fault @ ", far); + ret = 0; + break; + case DABT_XLATE_SECT: + dbg_abort("Section translation fault @ ", far); + ret = 0; + break; + + /* Aborts that can't be handled by a pager yet: */ + case DABT_TERMINAL: + dprintk("Terminal fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_VECTOR: + dprintk("Vector abort (obsolete!) @ ", far); + ret = -EABORT; + break; + case DABT_ALIGN: + dprintk("Alignment fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_EXT_XLATE_LEVEL1: + dprintk("External LVL1 translation fault @ ", far); + ret = -EABORT; + break; + case DABT_EXT_XLATE_LEVEL2: + dprintk("External LVL2 translation fault @ ", far); + ret = -EABORT; + break; + case DABT_DOMAIN_SECT: + dprintk("Section domain fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_DOMAIN_PAGE: + dprintk("Page domain fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_PERM_SECT: + dprintk("Section permission fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_EXT_LFETCH_SECT: + dprintk("External section linefetch " + "fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_EXT_LFETCH_PAGE: + dprintk("Page perm fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_EXT_NON_LFETCH_SECT: + dprintk("External section non-linefetch " + "fault dabt @ ", far); + ret = -EABORT; + break; + case DABT_EXT_NON_LFETCH_PAGE: + dprintk("External page non-linefetch " + "fault dabt @ ", far); + ret = -EABORT; + break; + default: + dprintk("FATAL: Unrecognised/Unknown " + "data abort @ ", far); + dprintk("FATAL: FSR code: ", fsr); + ret = -EABORT; + } + + /* + * Check validity of data abort's source. + * + * FIXME: Why not use spsr to do this? + */ + if (is_kernel_address(faulted_pc)) { + dprintk("Unhandled kernel data " + "abort at address ", + faulted_pc); + ret = -EABORT; + } + + return ret; +} + +#if 0 +void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far) +{ + set_abort_type(fsr, ARM_DABT); + + dbg_abort("Data abort @ PC: ", faulted_pc); + + //printk("Data abort: %d, PC: 0x%x\n", + //current->tid, faulted_pc); + + /* Check for more details */ + if (check_aborts(faulted_pc, fsr, far) < 0) { + printascii("This abort can't be handled by " + "any pager.\n"); + goto error; + } + + /* This notifies the pager */ + fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } else if (current->flags & TASK_EXITING) { + BUG_ON(current->nlocks); + sched_exit_sync(); + } + + return; + +error: + disable_irqs(); + dprintk("Unhandled data abort @ PC address: ", faulted_pc); + dprintk("FAR:", far); + dprintk("FSR:", fsr); + printascii("Kernel panic.\n"); + printascii("Halting system...\n"); + while (1) + ; +} + +void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 spsr) +{ + set_abort_type(fsr, ARM_PABT); + + if (check_aborts(faulted_pc, fsr, far) < 0) { + printascii("This abort can't be handled by any pager.\n"); + goto error; + } + + /* Did the abort occur in kernel mode? */ + if ((spsr & ARM_MODE_MASK) == ARM_MODE_SVC) + goto error; + + fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } else if (current->flags & TASK_EXITING) { + BUG_ON(current->nlocks); + sched_exit_sync(); + } + + return; + +error: + disable_irqs(); + dprintk("Unhandled prefetch abort @ address: ", faulted_pc); + dprintk("FAR:", far); + dprintk("FSR:", fsr); + dprintk("Aborted PSR:", spsr); + printascii("Kernel panic.\n"); + printascii("Halting system...\n"); + while (1) + ; +} + +void undef_handler(u32 undef_addr, u32 spsr, u32 lr) +{ + dbg_abort("Undefined instruction @ PC: ", undef_addr); + + //printk("Undefined instruction: tid: %d, PC: 0x%x, Mode: %s\n", + // current->tid, undef_addr, + // (spsr & ARM_MODE_MASK) == ARM_MODE_SVC ? "SVC" : "User"); + + if ((spsr & ARM_MODE_MASK) == ARM_MODE_SVC) { + printk("Panic: Undef in Kernel\n"); + goto error; + } + + fault_ipc_to_pager(undef_addr, 0, undef_addr, L4_IPC_TAG_UNDEF_FAULT); + + if (current->flags & TASK_SUSPENDING) { + BUG_ON(current->nlocks); + sched_suspend_sync(); + } else if (current->flags & TASK_EXITING) { + BUG_ON(current->nlocks); + sched_exit_sync(); + } + + return; + +error: + disable_irqs(); + dprintk("SPSR:", spsr); + dprintk("LR:", lr); + printascii("Kernel panic.\n"); + printascii("Halting system...\n"); + while(1) + ; +} +#endif + diff --git a/src/arch/arm/v6/init.c b/src/arch/arm/v6/init.c new file mode 100644 index 0000000..82f232c --- /dev/null +++ b/src/arch/arm/v6/init.c @@ -0,0 +1,139 @@ +/* + * ARM v5 specific init routines + * + * Copyright (C) 2007 - 2010 B Labs Ltd. + */ + +#include +#include +#include +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_ARCH(linker.h) + +SECTION(".init.pgd") ALIGN(PGD_SIZE) pgd_table_t init_pgd; + + +void jump(struct ktcb *task) +{ + __asm__ __volatile__ ( + "mov lr, %0\n" /* Load pointer to context area */ + "ldr r0, [lr]\n" /* Load spsr value to r0 */ + "msr spsr, r0\n" /* Set SPSR as ARM_MODE_USR */ + "add sp, lr, %1\n" /* Reset SVC stack */ + "sub sp, sp, %2\n" /* Align to stack alignment */ + "ldmib lr, {r0-r14}^\n" /* Load all USR registers */ + + "nop \n" /* Spec says dont touch banked registers + * right after LDM {no-pc}^ for one instruction */ + "add lr, lr, #64\n" /* Manually move to PC location. */ + "ldr lr, [lr]\n" /* Load the PC_USR to LR */ + "movs pc, lr\n" /* Jump to userspace, also switching SPSR/CPSR */ + : + : "r" (task), "r" (PAGE_SIZE), "r" (STACK_ALIGNMENT) + ); +} + +void switch_to_user(struct ktcb *task) +{ + arm_clean_invalidate_cache(); + arm_invalidate_tlb(); + arm_set_ttb(virt_to_phys(TASK_PGD(task))); + arm_invalidate_tlb(); + jump(task); +} + +/* Maps the early memory regions needed to bootstrap the system */ +void init_kernel_mappings(void) +{ + memset((void *)virt_to_phys(&init_pgd), 0, sizeof(pgd_table_t)); + + /* Map kernel area to its virtual region */ + add_section_mapping_init(align(virt_to_phys(_start_text), SZ_1MB), + align((unsigned int)_start_text, SZ_1MB), 1, + cacheable | bufferable); + + /* Map kernel one-to-one to its physical region */ + add_section_mapping_init(align(virt_to_phys(_start_text), SZ_1MB), + align(virt_to_phys(_start_text), SZ_1MB), + 1, 0); +} + +/* + * Enable virtual memory using kernel's pgd + * and continue execution on virtual addresses. + */ +void start_virtual_memory() +{ + /* + * TTB must be 16K aligned. This is because first level tables are + * sized 16K. + */ + if ((unsigned int)&init_pgd & 0x3FFF) + dprintk("kspace not properly aligned for ttb:", + (u32)&init_pgd); + // memset((void *)&kspace, 0, sizeof(pgd_table_t)); + arm_set_ttb(virt_to_phys(&init_pgd)); + + /* + * This sets all 16 domains to zero and domain 0 to 1. The outcome + * is that page table access permissions are in effect for domain 0. + * All other domains have no access whatsoever. + */ + arm_set_domain(1); + + /* Enable everything before mmu permissions are in place */ + arm_enable_caches(); + arm_enable_wbuffer(); + + arm_enable_high_vectors(); + + /* + * Leave the past behind. Tlbs are invalidated, write buffer is drained. + * The whole of I + D caches are invalidated unconditionally. This is + * important to ensure that the cache is free of previously loaded + * values. Otherwise unpredictable data aborts may occur at arbitrary + * times, each time a load/store operation hits one of the invalid + * entries and those entries are cleaned to main memory. + */ + arm_invalidate_cache(); + arm_drain_writebuffer(); + arm_invalidate_tlb(); + arm_enable_mmu(); + + /* Jump to virtual memory addresses */ + __asm__ __volatile__ ( + "add sp, sp, %0 \n" /* Update stack pointer */ + "add fp, fp, %0 \n" /* Update frame pointer */ + /* On the next instruction below, r0 gets + * current PC + KOFFSET + 2 instructions after itself. */ + "add r0, pc, %0 \n" + /* Special symbol that is extracted and included in the loader. + * Debuggers can break on it to load the virtual symbol table */ + ".global break_virtual;\n" + "break_virtual:\n" + "mov pc, r0 \n" /* (r0 has next instruction) */ + : + : "r" (KERNEL_OFFSET) + : "r0" + ); + + /* + * Restore link register (LR) for this function. + * + * NOTE: LR values are pushed onto the stack at each function call, + * which means the restored return values will be physical for all + * functions in the call stack except this function. So the caller + * of this function must never return but initiate scheduling etc. + */ + __asm__ __volatile__ ( + "add %0, %0, %1 \n" + "mov pc, %0 \n" + :: "r" (__builtin_return_address(0)), "r" (KERNEL_OFFSET) + ); + + /* should never come here */ + while(1); +} diff --git a/src/arch/arm/v6/irq.c b/src/arch/arm/v6/irq.c new file mode 100644 index 0000000..dbbb82a --- /dev/null +++ b/src/arch/arm/v6/irq.c @@ -0,0 +1,60 @@ +/* + * Low-level irq routines. + * + * Copyright (C) 2010 B Labs Ltd. + * Written by Bahadir Balban + * Prem Mallappa + */ + +void irq_local_disable_save(unsigned long *state) +{ + unsigned int tmp; + __asm__ __volatile__ ( + "mrs %0, cpsr_fc \n" + "cpsid ia \n" + : "=r"(tmp) + : + : "cc" + ); + *state = tmp; +} + +void irq_local_restore(unsigned long state) +{ + __asm__ __volatile__ ( + "msr cpsr_fc, %0\n" + : + : "r"(state) + : "cc" + ); +} + +u8 l4_atomic_dest_readb(u8 *location) +{ + unsigned int tmp, res; + __asm__ __volatile__ ( + "1: \n" + "ldrex %0, [%2] \n" + "strex %1, %3, [%2] \n" + "teq %1, #0 \n" + "bne 1b \n" + : "=&r"(tmp), "=&r"(res) + : "r"(location), "r"(0) + : "cc", "memory" + ); + + return (u8)tmp; +} + +int irqs_enabled(void) +{ + int tmp; + __asm__ __volatile__ ( + "mrs %0, cpsr_fc\n" + : "=r"(tmp) + ); + if (tmp & 0x80) + return 0; + + return 1; +} diff --git a/src/arch/arm/v6/mapping.c b/src/arch/arm/v6/mapping.c new file mode 100644 index 0000000..16660c0 --- /dev/null +++ b/src/arch/arm/v6/mapping.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(memlayout.h) +#include INC_ARCH(linker.h) +#include INC_ARCH(asm.h) +#include INC_API(kip.h) +#include INC_ARCH(io.h) + +/* + * Removes initial mappings needed for transition to virtual memory. + * Used one-time only. + */ +void remove_section_mapping(unsigned long vaddr) +{ + pgd_table_t *pgd = &init_pgd; + pmd_t pgd_i = PGD_INDEX(vaddr); + if (!((pgd->entry[pgd_i] & PMD_TYPE_MASK) + & PMD_TYPE_SECTION)) + while(1); + pgd->entry[pgd_i] = 0; + pgd->entry[pgd_i] |= PMD_TYPE_FAULT; + arm_invalidate_tlb(); +} + +/* + * Maps given section-aligned @paddr to @vaddr using enough number + * of section-units to fulfill @size in sections. Note this overwrites + * a mapping if same virtual address was already mapped. + */ +void __add_section_mapping_init(unsigned int paddr, + unsigned int vaddr, + unsigned int size, + unsigned int flags) +{ + pte_t *ppte; + unsigned int l1_ptab; + unsigned int l1_offset; + + /* 1st level page table address */ + l1_ptab = virt_to_phys(&init_pgd); + + /* Get the section offset for this vaddr */ + l1_offset = (vaddr >> 18) & 0x3FFC; + + /* The beginning entry for mapping */ + ppte = (unsigned int *)(l1_ptab + l1_offset); + for(int i = 0; i < size; i++) { + *ppte = 0; /* Clear out old value */ + *ppte |= paddr; /* Assign physical address */ + *ppte |= PMD_TYPE_SECTION; /* Assign translation type */ + /* Domain is 0, therefore no writes. */ + /* Only kernel access allowed */ + *ppte |= (SVC_RW_USR_NONE << SECTION_AP0); + /* Cacheability/Bufferability flags */ + *ppte |= flags; + ppte++; /* Next section entry */ + paddr += SECTION_SIZE; /* Next physical section */ + } + return; +} + +void add_section_mapping_init(unsigned int paddr, unsigned int vaddr, + unsigned int size, unsigned int flags) +{ + unsigned int psection; + unsigned int vsection; + + /* Align each address to the pages they reside in */ + psection = paddr & ~SECTION_MASK; + vsection = vaddr & ~SECTION_MASK; + + if (size == 0) + return; + + __add_section_mapping_init(psection, vsection, size, flags); + + return; +} + +void arch_prepare_pte(u32 paddr, u32 vaddr, unsigned int flags, + pte_t *ptep) +{ + /* They must be aligned at this stage */ + BUG_ON(!is_page_aligned(paddr)); + BUG_ON(!is_page_aligned(vaddr)); + + /* + * NOTE: In v5, the flags converted from generic + * by space_flags_to_ptflags() can be directly + * written to the pte. No further conversion is needed. + * Therefore this function doesn't do much on flags. In + * contrast in ARMv7 the flags need an extra level of + * processing. + */ + if (flags == __MAP_FAULT) + *ptep = paddr | flags | PTE_TYPE_FAULT; + else + *ptep = paddr | flags | PTE_TYPE_SMALL; +} + +void arch_write_pte(pte_t *ptep, pte_t pte, u32 vaddr) +{ + /* FIXME: + * Clean the dcache and invalidate the icache + * for the old translation first? + * + * The dcache is virtual, therefore the data + * in those entries should be cleaned first, + * before the translation of that virtual + * address is changed to a new physical address. + * + * Check that the entry was not faulty first. + */ + arm_clean_invalidate_cache(); + + *ptep = pte; + + /* FIXME: Fix this! + * - Use vaddr to clean the dcache pte by MVA. + * - Use mapped area to invalidate the icache + * - Invalidate the tlb for mapped area + */ + arm_clean_invalidate_cache(); + arm_invalidate_tlb(); +} + + +void arch_prepare_write_pte(u32 paddr, u32 vaddr, + unsigned int flags, pte_t *ptep) +{ + pte_t pte = 0; + + /* They must be aligned at this stage */ + BUG_ON(!is_page_aligned(paddr)); + BUG_ON(!is_page_aligned(vaddr)); + + arch_prepare_pte(paddr, vaddr, flags, &pte); + + arch_write_pte(ptep, pte, vaddr); +} + +pmd_t * +arch_pick_pmd(pgd_table_t *pgd, unsigned long vaddr) +{ + return &pgd->entry[PGD_INDEX(vaddr)]; +} + +/* + * v5 pmd writes + */ +void arch_write_pmd(pmd_t *pmd_entry, u32 pmd_phys, u32 vaddr) +{ + /* FIXME: Clean the dcache if there was a valid entry */ + *pmd_entry = (pmd_t)(pmd_phys | PMD_TYPE_PMD); + arm_clean_invalidate_cache(); /*FIXME: Write these properly! */ + arm_invalidate_tlb(); +} + + +int arch_check_pte_access_perms(pte_t pte, unsigned int flags) +{ + if ((pte & PTE_PROT_MASK) >= (flags & PTE_PROT_MASK)) + return 1; + else + return 0; +} + +/* + * Tell if a pgd index is a common kernel index. + * This is used to distinguish common kernel entries + * in a pgd, when copying page tables. + */ +int is_global_pgdi(int i) +{ + if ((i >= PGD_INDEX(KERNEL_AREA_START) && + i < PGD_INDEX(KERNEL_AREA_END)) || + (i >= PGD_INDEX(IO_AREA_START) && + i < PGD_INDEX(IO_AREA_END)) || + (i == PGD_INDEX(USER_KIP_PAGE)) || + (i == PGD_INDEX(ARM_HIGH_VECTOR)) || + (i == PGD_INDEX(ARM_SYSCALL_VECTOR)) || + (i == PGD_INDEX(USERSPACE_CONSOLE_VBASE))) + return 1; + else + return 0; +} + +extern pmd_table_t *pmd_array; + +void remove_mapping_pgd_all_user(pgd_table_t *pgd) +{ + pmd_table_t *pmd; + + /* Traverse through all pgd entries. */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + if (!is_global_pgdi(i)) { + /* Detect a pmd entry */ + if (((pgd->entry[i] & PMD_TYPE_MASK) + == PMD_TYPE_PMD)) { + + /* Obtain the user pmd handle */ + pmd = (pmd_table_t *) + phys_to_virt((pgd->entry[i] & + PMD_ALIGN_MASK)); + /* Free it */ + free_pmd(pmd); + } + + /* Clear the pgd entry */ + pgd->entry[i] = PMD_TYPE_FAULT; + } + } +} + + +int pgd_count_boot_pmds() +{ + int npmd = 0; + pgd_table_t *pgd = &init_pgd; + + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) + if ((pgd->entry[i] & PMD_TYPE_MASK) == PMD_TYPE_PMD) + npmd++; + return npmd; +} + + +/* + * Jumps from boot pmd/pgd page tables to tables allocated from the cache. + */ +pgd_table_t *arch_realloc_page_tables(void) +{ + pgd_table_t *pgd_new = alloc_pgd(); + pgd_table_t *pgd_old = &init_pgd; + pmd_table_t *orig, *pmd; + + /* Copy whole pgd entries */ + memcpy(pgd_new, pgd_old, sizeof(pgd_table_t)); + + /* Allocate and copy all pmds */ + for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { + /* Detect a pmd entry */ + if ((pgd_old->entry[i] & PMD_TYPE_MASK) == PMD_TYPE_PMD) { + /* Allocate new pmd */ + if (!(pmd = alloc_pmd())) { + printk("FATAL: PMD allocation " + "failed during system initialization\n"); + BUG(); + } + + /* Find original pmd */ + orig = (pmd_table_t *) + phys_to_virt((pgd_old->entry[i] & + PMD_ALIGN_MASK)); + + /* Copy original to new */ + memcpy(pmd, orig, sizeof(pmd_table_t)); + + /* Replace original pmd entry in pgd with new */ + pgd_new->entry[i] = (pmd_t)virt_to_phys(pmd); + pgd_new->entry[i] |= PMD_TYPE_PMD; + } + } + + /* Switch the virtual memory system into new area */ + arm_clean_invalidate_cache(); + arm_drain_writebuffer(); + arm_invalidate_tlb(); + arm_set_ttb(virt_to_phys(pgd_new)); + arm_invalidate_tlb(); + + printk("%s: Initial page tables moved from 0x%x to 0x%x physical\n", + __KERNELNAME__, virt_to_phys(pgd_old), + virt_to_phys(pgd_new)); + + return pgd_new; +} + +/* + * Copies global kernel entries into another pgd. Even for + * sub-pmd ranges the associated pmd entries are copied, + * assuming any pmds copied are applicable to all tasks in + * the system. + */ +void copy_pgd_global_by_vrange(pgd_table_t *to, pgd_table_t *from, + unsigned long start, unsigned long end) +{ + /* Extend sub-pmd ranges to their respective pmd boundaries */ + start = align(start, PMD_MAP_SIZE); + + if (end < start) + end = 0; + + /* Aligning would overflow if mapping the last virtual pmd */ + if (end < align(~0, PMD_MAP_SIZE) || + start > end) /* end may have already overflown as input */ + end = align_up(end, PMD_MAP_SIZE); + else + end = 0; + + copy_pgds_by_vrange(to, from, start, end); +} + +void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, + unsigned long start, unsigned long end) +{ + unsigned long start_i = PGD_INDEX(start); + unsigned long end_i = PGD_INDEX(end); + unsigned long irange = (end_i != 0) ? (end_i - start_i) + : (PGD_ENTRY_TOTAL - start_i); + + memcpy(&to->entry[start_i], &from->entry[start_i], + irange * sizeof(pmd_t)); +} + +void arch_copy_pgd_kernel_entries(pgd_table_t *to) +{ + pgd_table_t *from = TASK_PGD(current); + + copy_pgd_global_by_vrange(to, from, KERNEL_AREA_START, + KERNEL_AREA_END); + copy_pgd_global_by_vrange(to, from, IO_AREA_START, IO_AREA_END); + copy_pgd_global_by_vrange(to, from, USER_KIP_PAGE, + USER_KIP_PAGE + PAGE_SIZE); + copy_pgd_global_by_vrange(to, from, ARM_HIGH_VECTOR, + ARM_HIGH_VECTOR + PAGE_SIZE); + copy_pgd_global_by_vrange(to, from, ARM_SYSCALL_VECTOR, + ARM_SYSCALL_VECTOR + PAGE_SIZE); + + /* We temporarily map uart registers to every process */ + copy_pgd_global_by_vrange(to, from, USERSPACE_CONSOLE_VBASE, + USERSPACE_CONSOLE_VBASE + PAGE_SIZE); +} + +/* Scheduler uses this to switch context */ +void arch_space_switch(struct ktcb *to) +{ + pgd_table_t *pgd = TASK_PGD(to); + + arm_clean_invalidate_cache(); + arm_invalidate_tlb(); + arm_set_ttb(virt_to_phys(pgd)); + arm_invalidate_tlb(); +} + +void idle_task(void) +{ + printk("Idle task.\n"); + + while(1); +} + diff --git a/src/arch/arm/v6/mmu_ops.S b/src/arch/arm/v6/mmu_ops.S index eb6d9da..ceda880 100644 --- a/src/arch/arm/v6/mmu_ops.S +++ b/src/arch/arm/v6/mmu_ops.S @@ -105,7 +105,7 @@ BEGIN_PROC(arm_invalidate_dcache) END_PROC(arm_invalidate_dcache) BEGIN_PROC(arm_clean_dcache) - mcr p15, 0 , pc, c7, c10, 3 @ Test/clean dcache line + mrc p15, 0 , pc, c7, c10, 3 @ Test/clean dcache line bne arm_clean_dcache mcr p15, 0, ip, c7, c10, 4 @ Drain WB mov pc, lr diff --git a/src/arch/arm/v6/mutex.c b/src/arch/arm/v6/mutex.c new file mode 100644 index 0000000..0a0b64f --- /dev/null +++ b/src/arch/arm/v6/mutex.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 B Labs Ltd. + */ + +#include +#include +#include +#include INC_SUBARCH(mmu_ops.h) + +#define MUTEX_UNLOCKED 0 +#define MUTEX_LOCKED 1 + + +/* Notes on ldrex/strex: + * ldrex rD, [rN, #imm] : loads rD with contents of at address (rN + imm) + * strex rD, rS, [rN, #imm]: pushes contents of rS to memory location (rN + imm) + * rD is 0 if operation is successful, 1 otherwise + */ + +void __spin_lock(unsigned int *s) +{ + unsigned int tmp; + __asm__ __volatile__ ( + "1:\n" + "ldrex %0, [%2]\n" + "teq %0, #0\n" + "strexeq %0, %1, [%2]\n" + "teq %0, #0\n" +#ifdef CONFIG_SMP + "wfene\n" +#endif + "bne 1b\n" + : "=&r" (tmp) + : "r"(1), "r"(s) + : "cc", "memory" + ); + + dsb(); +} + +void __spin_unlock(unsigned int *s) +{ + __asm__ __volatile__ ( + "str %0, [%1]\n" + : + : "r"(0), "r"(s) + : "memory" + ); + +#ifdef CONFIG_SMP + dsb(); + __asm__ __volatile__ ("sev\n"); +#endif +} + + +/* + * Current implementation uses __mutex_(un)lock within a protected + * spinlock, needs to be revisited in the future + */ +unsigned int __mutex_lock(unsigned int *m) +{ + unsigned int tmp, res; + __asm__ __volatile__ ( + "1:\n" + "ldrex %0, [%3]\n" + "tst %0, #0\n" + "strexeq %1, %2, [%3]\n" + "tsteq %1, #0\n" + "bne 1b\n" + : "=&r" (tmp), "=&r"(res) + : "r"(1), "r"(m) + : "cc", "memory" + ); + + if ((tmp | res) != 0) + return 0; + return 1; +} + +void __mutex_unlock(unsigned int *m) +{ + __asm__ __volatile__ ( + "str %0, [%1] \n" + : + : "r"(0), "r"(m) + : "memory" + ); + +} + diff --git a/src/arch/arm/v7/mm.c b/src/arch/arm/v7/mm.c deleted file mode 100644 index 1b7e339..0000000 --- a/src/arch/arm/v7/mm.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - * Copyright (C) 2007 Bahadir Balban - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include INC_SUBARCH(mm.h) -#include INC_SUBARCH(mmu_ops.h) -#include INC_GLUE(memory.h) -#include INC_PLAT(printascii.h) -#include INC_GLUE(memlayout.h) -#include INC_ARCH(linker.h) -#include INC_ARCH(asm.h) -#include INC_API(kip.h) - -/* - * These are indices into arrays with pgd_t or pmd_t sized elements, - * therefore the index must be divided by appropriate element size - */ -#define PGD_INDEX(x) (((((unsigned long)(x)) >> 18) & 0x3FFC) / sizeof(pgd_t)) -/* Strip out the page offset in this megabyte from a total of 256 pages. */ -#define PMD_INDEX(x) (((((unsigned long)(x)) >> 10) & 0x3FC) / sizeof (pmd_t)) - -/* - * Removes initial mappings needed for transition to virtual memory. - * Used one-time only. - */ -void remove_section_mapping(unsigned long vaddr) -{ - pgd_table_t *pgd = &init_pgd;; - pgd_t pgd_i = PGD_INDEX(vaddr); - if (!((pgd->entry[pgd_i] & PGD_TYPE_MASK) - & PGD_TYPE_SECTION)) - while(1); - pgd->entry[pgd_i] = 0; - pgd->entry[pgd_i] |= PGD_TYPE_FAULT; - arm_invalidate_tlb(); -} - -/* - * Maps given section-aligned @paddr to @vaddr using enough number - * of section-units to fulfill @size in sections. Note this overwrites - * a mapping if same virtual address was already mapped. - */ -void __add_section_mapping_init(unsigned int paddr, - unsigned int vaddr, - unsigned int size, - unsigned int flags) -{ - pte_t *ppte; - unsigned int l1_ptab; - unsigned int l1_offset; - - /* 1st level page table address */ - l1_ptab = virt_to_phys(&init_pgd); - - /* Get the section offset for this vaddr */ - l1_offset = (vaddr >> 18) & 0x3FFC; - - /* The beginning entry for mapping */ - ppte = (unsigned int *)(l1_ptab + l1_offset); - for(int i = 0; i < size; i++) { - *ppte = 0; /* Clear out old value */ - *ppte |= paddr; /* Assign physical address */ - *ppte |= PGD_TYPE_SECTION; /* Assign translation type */ - /* Domain is 0, therefore no writes. */ - /* Only kernel access allowed */ - *ppte |= (SVC_RW_USR_NONE << SECTION_AP0); - /* Cacheability/Bufferability flags */ - *ppte |= flags; - ppte++; /* Next section entry */ - paddr += ARM_SECTION_SIZE; /* Next physical section */ - } - return; -} - -void add_section_mapping_init(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags) -{ - unsigned int psection; - unsigned int vsection; - - /* Align each address to the pages they reside in */ - psection = paddr & ~ARM_SECTION_MASK; - vsection = vaddr & ~ARM_SECTION_MASK; - - if(size == 0) - return; - - __add_section_mapping_init(psection, vsection, size, flags); - - return; -} - -/* TODO: Make sure to flush tlb entry and caches */ -void __add_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int flags, pmd_table_t *pmd) -{ - unsigned int pmd_i = PMD_INDEX(vaddr); - pmd->entry[pmd_i] = paddr; - pmd->entry[pmd_i] |= PMD_TYPE_SMALL; /* Small page type */ - pmd->entry[pmd_i] |= flags; - - /* TODO: Is both required? Investigate */ - - /* TEST: - * I think cleaning or invalidating the cache is not required, - * because the entries in the cache aren't for the new mapping anyway. - * It's required if a mapping is removed, but not when newly added. - */ - arm_clean_invalidate_cache(); - - /* TEST: tlb must be flushed because a new mapping is present in page - * tables, and tlb is inconsistent with the page tables */ - arm_invalidate_tlb(); -} - -/* Return whether a pmd associated with @vaddr is mapped on a pgd or not. */ -pmd_table_t *pmd_exists(pgd_table_t *pgd, unsigned long vaddr) -{ - unsigned int pgd_i = PGD_INDEX(vaddr); - - /* Return true if non-zero pgd entry */ - switch (pgd->entry[pgd_i] & PGD_TYPE_MASK) { - case PGD_TYPE_COARSE: - return (pmd_table_t *) - phys_to_virt((pgd->entry[pgd_i] & - PGD_COARSE_ALIGN_MASK)); - break; - - case PGD_TYPE_FAULT: - return 0; - break; - - case PGD_TYPE_SECTION: - dprintk("Warning, a section is already mapped " - "where a coarse page mapping is attempted:", - (u32)(pgd->entry[pgd_i] - & PGD_SECTION_ALIGN_MASK)); - BUG(); - break; - - case PGD_TYPE_FINE: - dprintk("Warning, a fine page table is already mapped " - "where a coarse page mapping is attempted:", - (u32)(pgd->entry[pgd_i] - & PGD_FINE_ALIGN_MASK)); - printk("Fine tables are unsupported. "); - printk("What is this doing here?"); - BUG(); - break; - - default: - dprintk("Unrecognised pmd type @ pgd index:", pgd_i); - BUG(); - break; - } - return 0; -} - -/* Convert a virtual address to a pte if it exists in the page tables. */ -pte_t virt_to_pte_from_pgd(unsigned long virtual, pgd_table_t *pgd) -{ - pmd_table_t *pmd = pmd_exists(pgd, virtual); - - if (pmd) - return (pte_t)pmd->entry[PMD_INDEX(virtual)]; - else - return (pte_t)0; -} - -/* Convert a virtual address to a pte if it exists in the page tables. */ -pte_t virt_to_pte(unsigned long virtual) -{ - return virt_to_pte_from_pgd(virtual, TASK_PGD(current)); -} - -unsigned long virt_to_phys_by_pgd(unsigned long vaddr, pgd_table_t *pgd) -{ - pte_t pte = virt_to_pte_from_pgd(vaddr, pgd); - return pte & ~PAGE_MASK; -} - -unsigned long virt_to_phys_by_task(unsigned long vaddr, struct ktcb *task) -{ - return virt_to_phys_by_pgd(vaddr, TASK_PGD(task)); -} - -void attach_pmd(pgd_table_t *pgd, pmd_table_t *pmd, unsigned int vaddr) -{ - u32 pgd_i = PGD_INDEX(vaddr); - u32 pmd_phys = virt_to_phys(pmd); - - /* Domain is 0, therefore no writes. */ - pgd->entry[pgd_i] = (pgd_t)pmd_phys; - pgd->entry[pgd_i] |= PGD_TYPE_COARSE; -} - -/* - * Same as normal mapping but with some boot tweaks. - */ -void add_boot_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags) -{ - pmd_table_t *pmd; - pgd_table_t *pgd = &init_pgd; - unsigned int numpages = (size >> PAGE_BITS); - - if (size < PAGE_SIZE) { - printascii("Error: Mapping size must be in bytes not pages.\n"); - while(1); - } - if (size & PAGE_MASK) - numpages++; - - /* Convert generic map flags to pagetable-specific */ - BUG_ON(!(flags = space_flags_to_ptflags(flags))); - - /* Map all consecutive pages that cover given size */ - for (int i = 0; i < numpages; i++) { - /* Check if another mapping already has a pmd attached. */ - pmd = pmd_exists(pgd, vaddr); - if (!pmd) { - /* - * If this is the first vaddr in - * this pmd, allocate new pmd - */ - pmd = alloc_boot_pmd(); - - /* Attach pmd to its entry in pgd */ - attach_pmd(pgd, pmd, vaddr); - } - - /* Attach paddr to this pmd */ - __add_mapping(page_align(paddr), - page_align(vaddr), flags, pmd); - - /* Go to the next page to be mapped */ - paddr += PAGE_SIZE; - vaddr += PAGE_SIZE; - } -} - -/* - * Maps @paddr to @vaddr, covering @size bytes also allocates new pmd if - * necessary. This flavor explicitly supplies the pgd to modify. This is useful - * when modifying userspace of processes that are not currently running. (Only - * makes sense for userspace mappings since kernel mappings are common.) - */ -void add_mapping_pgd(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags, - pgd_table_t *pgd) -{ - pmd_table_t *pmd; - unsigned int numpages = (size >> PAGE_BITS); - - - if (size < PAGE_SIZE) { - printascii("Error: Mapping size must be in bytes not pages.\n"); - while(1); - } - if (size & PAGE_MASK) - numpages++; - - /* Convert generic map flags to pagetable-specific */ - BUG_ON(!(flags = space_flags_to_ptflags(flags))); - - /* Map all consecutive pages that cover given size */ - for (int i = 0; i < numpages; i++) { - /* Check if another mapping already has a pmd attached. */ - pmd = pmd_exists(pgd, vaddr); - if (!pmd) { - /* - * If this is the first vaddr in - * this pmd, allocate new pmd - */ - pmd = alloc_pmd(); - - /* Attach pmd to its entry in pgd */ - attach_pmd(pgd, pmd, vaddr); - } - - /* Attach paddr to this pmd */ - __add_mapping(page_align(paddr), - page_align(vaddr), flags, pmd); - - /* Go to the next page to be mapped */ - paddr += PAGE_SIZE; - vaddr += PAGE_SIZE; - } -} - -void add_mapping(unsigned int paddr, unsigned int vaddr, - unsigned int size, unsigned int flags) -{ - add_mapping_pgd(paddr, vaddr, size, flags, TASK_PGD(current)); -} - -/* - * Checks if a virtual address range has same or more permissive - * flags than the given ones, returns 0 if not, and 1 if OK. - */ -int check_mapping_pgd(unsigned long vaddr, unsigned long size, - unsigned int flags, pgd_table_t *pgd) -{ - unsigned int npages = __pfn(align_up(size, PAGE_SIZE)); - pte_t pte; - - /* Convert generic map flags to pagetable-specific */ - BUG_ON(!(flags = space_flags_to_ptflags(flags))); - - for (int i = 0; i < npages; i++) { - pte = virt_to_pte_from_pgd(vaddr + i * PAGE_SIZE, pgd); - - /* Check if pte perms are equal or gt given flags */ - if ((pte & PTE_PROT_MASK) >= (flags & PTE_PROT_MASK)) - continue; - else - return 0; - } - - return 1; -} - -int check_mapping(unsigned long vaddr, unsigned long size, - unsigned int flags) -{ - return check_mapping_pgd(vaddr, size, flags, TASK_PGD(current)); -} - -/* FIXME: Empty PMDs should be returned here !!! */ -int __remove_mapping(pmd_table_t *pmd, unsigned long vaddr) -{ - pmd_t pmd_i = PMD_INDEX(vaddr); - int ret; - - switch (pmd->entry[pmd_i] & PMD_TYPE_MASK) { - case PMD_TYPE_FAULT: - ret = -ENOENT; - break; - case PMD_TYPE_LARGE: - pmd->entry[pmd_i] = 0; - pmd->entry[pmd_i] |= PMD_TYPE_FAULT; - ret = 0; - break; - case PMD_TYPE_SMALL: - pmd->entry[pmd_i] = 0; - pmd->entry[pmd_i] |= PMD_TYPE_FAULT; - ret = 0; - break; - default: - printk("Unknown page mapping in pmd. Assuming bug.\n"); - BUG(); - } - return ret; -} - -/* - * Tell if a pgd index is a common kernel index. This is used to distinguish - * common kernel entries in a pgd, when copying page tables. - */ -int is_kern_pgdi(int i) -{ - if ((i >= PGD_INDEX(KERNEL_AREA_START) && i < PGD_INDEX(KERNEL_AREA_END)) || - (i >= PGD_INDEX(IO_AREA_START) && i < PGD_INDEX(IO_AREA_END)) || - (i == PGD_INDEX(USER_KIP_PAGE)) || - (i == PGD_INDEX(ARM_HIGH_VECTOR)) || - (i == PGD_INDEX(ARM_SYSCALL_VECTOR)) || - (i == PGD_INDEX(USERSPACE_UART_BASE))) - return 1; - else - return 0; -} - -/* - * Removes all userspace mappings from a pgd. Frees any pmds that it - * detects to be user pmds - */ -int remove_mapping_pgd_all_user(pgd_table_t *pgd) -{ - pmd_table_t *pmd; - - /* Traverse through all pgd entries */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { - - /* Detect a pgd entry that is not a kernel entry */ - if (!is_kern_pgdi(i)) { - - /* Detect a pmd entry */ - if (((pgd->entry[i] & PGD_TYPE_MASK) - == PGD_TYPE_COARSE)) { - - /* Obtain the user pmd handle */ - pmd = (pmd_table_t *) - phys_to_virt((pgd->entry[i] & - PGD_COARSE_ALIGN_MASK)); - /* Free it */ - free_pmd(pmd); - } - - /* Clear the pgd entry */ - pgd->entry[i] = PGD_TYPE_FAULT; - } - } - - return 0; -} - -int remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd) -{ - pgd_t pgd_i = PGD_INDEX(vaddr); - pmd_table_t *pmd; - pmd_t pmd_i; - int ret; - - /* - * Clean the cache to main memory before removing the mapping. Otherwise - * entries in the cache for this mapping will cause tranlation faults - * if they're cleaned to main memory after the mapping is removed. - */ - arm_clean_invalidate_cache(); - - /* TEST: - * Can't think of a valid reason to flush tlbs here, but keeping it just - * to be safe. REMOVE: Remove it if it's unnecessary. - */ - arm_invalidate_tlb(); - - /* Return true if non-zero pgd entry */ - switch (pgd->entry[pgd_i] & PGD_TYPE_MASK) { - case PGD_TYPE_COARSE: - // printk("Removing coarse mapping @ 0x%x\n", vaddr); - pmd = (pmd_table_t *) - phys_to_virt((pgd->entry[pgd_i] - & PGD_COARSE_ALIGN_MASK)); - pmd_i = PMD_INDEX(vaddr); - ret = __remove_mapping(pmd, vaddr); - break; - - case PGD_TYPE_FAULT: - ret = -1; - break; - - case PGD_TYPE_SECTION: - printk("Removing section mapping for 0x%lx", - vaddr); - pgd->entry[pgd_i] = 0; - pgd->entry[pgd_i] |= PGD_TYPE_FAULT; - ret = 0; - break; - - case PGD_TYPE_FINE: - printk("Table mapped is a fine page table.\n" - "Fine tables are unsupported. Assuming bug.\n"); - BUG(); - break; - - default: - dprintk("Unrecognised pmd type @ pgd index:", pgd_i); - printk("Assuming bug.\n"); - BUG(); - break; - } - /* The tlb must be invalidated here because it might have cached the - * old translation for this mapping. */ - arm_invalidate_tlb(); - - return ret; -} - -int remove_mapping(unsigned long vaddr) -{ - return remove_mapping_pgd(vaddr, TASK_PGD(current)); -} - -int delete_page_tables(struct address_space *space) -{ - remove_mapping_pgd_all_user(space->pgd); - free_pgd(space->pgd); - return 0; -} - -/* - * Copies userspace entries of one task to another. In order to do that, - * it allocates new pmds and copies the original values into new ones. - */ -int copy_user_tables(struct address_space *new, struct address_space *orig_space) -{ - pgd_table_t *to = new->pgd, *from = orig_space->pgd; - pmd_table_t *pmd, *orig; - - /* Allocate and copy all pmds that will be exclusive to new task. */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { - /* Detect a pmd entry that is not a kernel pmd? */ - if (!is_kern_pgdi(i) && - ((from->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE)) { - /* Allocate new pmd */ - if (!(pmd = alloc_pmd())) - goto out_error; - - /* Find original pmd */ - orig = (pmd_table_t *) - phys_to_virt((from->entry[i] & - PGD_COARSE_ALIGN_MASK)); - - /* Copy original to new */ - memcpy(pmd, orig, sizeof(pmd_table_t)); - - /* Replace original pmd entry in pgd with new */ - to->entry[i] = (pgd_t)virt_to_phys(pmd); - to->entry[i] |= PGD_TYPE_COARSE; - } - } - - return 0; - -out_error: - /* Find all non-kernel pmds we have just allocated and free them */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { - /* Non-kernel pmd that has just been allocated. */ - if (!is_kern_pgdi(i) && - (to->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) { - /* Obtain the pmd handle */ - pmd = (pmd_table_t *) - phys_to_virt((to->entry[i] & - PGD_COARSE_ALIGN_MASK)); - /* Free pmd */ - free_pmd(pmd); - } - } - return -ENOMEM; -} - -int pgd_count_pmds(pgd_table_t *pgd) -{ - int npmd = 0; - - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) - if ((pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) - npmd++; - return npmd; -} - -/* - * Allocates and copies all levels of page tables from one task to another. - * Useful when forking. - * - * The copied page tables end up having shared pmds for kernel entries - * and private copies of same pmds for user entries. - */ -pgd_table_t *copy_page_tables(pgd_table_t *from) -{ - pmd_table_t *pmd, *orig; - pgd_table_t *pgd; - - /* Allocate and copy pgd. This includes all kernel entries */ - if (!(pgd = alloc_pgd())) - return PTR_ERR(-ENOMEM); - - /* First copy whole pgd entries */ - memcpy(pgd, from, sizeof(pgd_table_t)); - - /* Allocate and copy all pmds that will be exclusive to new task. */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { - /* Detect a pmd entry that is not a kernel pmd? */ - if (!is_kern_pgdi(i) && - ((pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE)) { - /* Allocate new pmd */ - if (!(pmd = alloc_pmd())) - goto out_error; - - /* Find original pmd */ - orig = (pmd_table_t *) - phys_to_virt((pgd->entry[i] & - PGD_COARSE_ALIGN_MASK)); - - /* Copy original to new */ - memcpy(pmd, orig, sizeof(pmd_table_t)); - - /* Replace original pmd entry in pgd with new */ - pgd->entry[i] = (pgd_t)virt_to_phys(pmd); - pgd->entry[i] |= PGD_TYPE_COARSE; - } - } - - return pgd; - -out_error: - /* Find all allocated non-kernel pmds and free them */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { - /* Non-kernel pmd that has just been allocated. */ - if (!is_kern_pgdi(i) && - (pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) { - /* Obtain the pmd handle */ - pmd = (pmd_table_t *) - phys_to_virt((pgd->entry[i] & - PGD_COARSE_ALIGN_MASK)); - /* Free pmd */ - free_pmd(pmd); - } - } - /* Free the pgd */ - free_pgd(pgd); - return PTR_ERR(-ENOMEM); -} - -extern pmd_table_t *pmd_array; - -/* - * Jumps from boot pmd/pgd page tables to tables allocated from the cache. - */ -pgd_table_t *realloc_page_tables(void) -{ - pgd_table_t *pgd_new = alloc_pgd(); - pgd_table_t *pgd_old = &init_pgd; - pmd_table_t *orig, *pmd; - - /* Copy whole pgd entries */ - memcpy(pgd_new, pgd_old, sizeof(pgd_table_t)); - - /* Allocate and copy all pmds */ - for (int i = 0; i < PGD_ENTRY_TOTAL; i++) { - /* Detect a pmd entry */ - if ((pgd_old->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) { - /* Allocate new pmd */ - if (!(pmd = alloc_pmd())) { - printk("FATAL: PMD allocation " - "failed during system initialization\n"); - BUG(); - } - - /* Find original pmd */ - orig = (pmd_table_t *) - phys_to_virt((pgd_old->entry[i] & - PGD_COARSE_ALIGN_MASK)); - - /* Copy original to new */ - memcpy(pmd, orig, sizeof(pmd_table_t)); - - /* Replace original pmd entry in pgd with new */ - pgd_new->entry[i] = (pgd_t)virt_to_phys(pmd); - pgd_new->entry[i] |= PGD_TYPE_COARSE; - } - } - - /* Switch the virtual memory system into new area */ - arm_clean_invalidate_cache(); - arm_drain_writebuffer(); - arm_invalidate_tlb(); - arm_set_ttb(virt_to_phys(pgd_new)); - arm_invalidate_tlb(); - - printk("%s: Initial page tables moved from 0x%x to 0x%x physical\n", - __KERNELNAME__, virt_to_phys(pgd_old), - virt_to_phys(pgd_new)); - - return pgd_new; -} - -/* - * Useful for upgrading to page-grained control over a section mapping: - * Remaps a section mapping in pages. It allocates a pmd, (at all times because - * there can't really be an already existing pmd for a section mapping) fills - * in the page information, and origaces the direct section physical translation - * with the address of the pmd. Flushes the caches/tlbs. - */ -void remap_as_pages(void *vstart, void *vend) -{ - unsigned long pstart = virt_to_phys(vstart); - unsigned long pend = virt_to_phys(vend); - unsigned long paddr = pstart; - pgd_t pgd_i = PGD_INDEX(vstart); - pmd_t pmd_i = PMD_INDEX(vstart); - pgd_table_t *pgd = &init_pgd; - pmd_table_t *pmd = alloc_boot_pmd(); - u32 pmd_phys = virt_to_phys(pmd); - int numpages = __pfn(pend - pstart); - - /* Fill in the pmd first */ - for (int n = 0; n < numpages; n++) { - pmd->entry[pmd_i + n] = paddr; - pmd->entry[pmd_i + n] |= PMD_TYPE_SMALL; /* Small page type */ - pmd->entry[pmd_i + n] |= space_flags_to_ptflags(MAP_SVC_DEFAULT_FLAGS); - paddr += PAGE_SIZE; - } - - /* Fill in the type to produce a complete pmd translator information */ - pmd_phys |= PGD_TYPE_COARSE; - - /* Make sure memory is coherent first. */ - arm_clean_invalidate_cache(); - arm_invalidate_tlb(); - - /* Replace the direct section physical address with pmd's address */ - pgd->entry[pgd_i] = (pgd_t)pmd_phys; - printk("%s: Kernel area 0x%lx - 0x%lx remapped as %d pages\n", __KERNELNAME__, - (unsigned long)vstart, (unsigned long)vend, numpages); -} - -void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from, - unsigned long start, unsigned long end) -{ - unsigned long start_i = PGD_INDEX(start); - unsigned long end_i = PGD_INDEX(end); - unsigned long irange = (end_i != 0) ? (end_i - start_i) - : (PGD_ENTRY_TOTAL - start_i); - - memcpy(&to->entry[start_i], &from->entry[start_i], - irange * sizeof(pgd_t)); -} - - -/* Scheduler uses this to switch context */ -void arch_hardware_flush(pgd_table_t *pgd) -{ - arm_clean_invalidate_cache(); - arm_invalidate_tlb(); - arm_set_ttb(virt_to_phys(pgd)); - arm_invalidate_tlb(); -} - diff --git a/src/arch/arm/v7/mmu_ops.S b/src/arch/arm/v7/mmu_ops.S deleted file mode 100644 index eb6d9da..0000000 --- a/src/arch/arm/v7/mmu_ops.S +++ /dev/null @@ -1,155 +0,0 @@ -/* - * low-level mmu operations - * - * Copyright (C) 2007 Bahadir Balban - */ - -#include INC_ARCH(asm.h) - -#define C15_id c0 -#define C15_control c1 -#define C15_ttb c2 -#define C15_dom c3 -#define C15_fsr c5 -#define C15_far c6 -#define C15_tlb c8 - -#define C15_C0_M 0x0001 /* MMU */ -#define C15_C0_A 0x0002 /* Alignment */ -#define C15_C0_C 0x0004 /* (D) Cache */ -#define C15_C0_W 0x0008 /* Write buffer */ -#define C15_C0_B 0x0080 /* Endianness */ -#define C15_C0_S 0x0100 /* System */ -#define C15_C0_R 0x0200 /* ROM */ -#define C15_C0_Z 0x0800 /* Branch Prediction */ -#define C15_C0_I 0x1000 /* I cache */ -#define C15_C0_V 0x2000 /* High vectors */ - -/* FIXME: Make sure the ops that need r0 dont trash r0, or if they do, - * save it on stack before these operations. - */ - -/* - * In ARM terminology, flushing the cache means invalidating its contents. - * Cleaning the cache means, writing the contents of the cache back to - * main memory. In write-back caches the cache must be cleaned before - * flushing otherwise in-cache data is lost. - */ - -BEGIN_PROC(arm_set_ttb) - mcr p15, 0, r0, C15_ttb, c0, 0 - mov pc, lr -END_PROC(arm_set_ttb) - -BEGIN_PROC(arm_get_domain) - mrc p15, 0, r0, C15_dom, c0, 0 - mov pc, lr -END_PROC(arm_get_domain) - -BEGIN_PROC(arm_set_domain) - mcr p15, 0, r0, C15_dom, c0, 0 - mov pc, lr -END_PROC(arm_set_domain) - -BEGIN_PROC(arm_enable_mmu) - mrc p15, 0, r0, C15_control, c0, 0 - orr r0, r0, #C15_C0_M - mcr p15, 0, r0, C15_control, c0, 0 - mov pc, lr -END_PROC(arm_enable_mmu) - -BEGIN_PROC(arm_enable_icache) - mrc p15, 0, r0, C15_control, c0, 0 - orr r0, r0, #C15_C0_I - mcr p15, 0, r0, C15_control, c0, 0 - mov pc, lr -END_PROC(arm_enable_icache) - -BEGIN_PROC(arm_enable_dcache) - mrc p15, 0, r0, C15_control, c0, 0 - orr r0, r0, #C15_C0_C - mcr p15, 0, r0, C15_control, c0, 0 - mov pc, lr -END_PROC(arm_enable_dcache) - -BEGIN_PROC(arm_enable_wbuffer) - mrc p15, 0, r0, C15_control, c0, 0 - orr r0, r0, #C15_C0_W - mcr p15, 0, r0, C15_control, c0, 0 - mov pc, lr -END_PROC(arm_enable_wbuffer) - -BEGIN_PROC(arm_enable_high_vectors) - mrc p15, 0, r0, C15_control, c0, 0 - orr r0, r0, #C15_C0_V - mcr p15, 0, r0, C15_control, c0, 0 - mov pc, lr -END_PROC(arm_enable_high_vectors) - -BEGIN_PROC(arm_invalidate_cache) - mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c7, c7 @ Flush I cache and D cache - mov pc, lr -END_PROC(arm_invalidate_cache) - -BEGIN_PROC(arm_invalidate_icache) - mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c7, c5, 0 @ Flush I cache - mov pc, lr -END_PROC(arm_invalidate_icache) - -BEGIN_PROC(arm_invalidate_dcache) - mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c7, c6, 0 @ Flush D cache - mov pc, lr -END_PROC(arm_invalidate_dcache) - -BEGIN_PROC(arm_clean_dcache) - mcr p15, 0 , pc, c7, c10, 3 @ Test/clean dcache line - bne arm_clean_dcache - mcr p15, 0, ip, c7, c10, 4 @ Drain WB - mov pc, lr -END_PROC(arm_clean_dcache) - -BEGIN_PROC(arm_clean_invalidate_dcache) -1: - mrc p15, 0, pc, c7, c14, 3 @ Test/clean/flush dcache line - @ COMMENT: Why use PC? - bne 1b - mcr p15, 0, ip, c7, c10, 4 @ Drain WB - mov pc, lr -END_PROC(arm_clean_invalidate_dcache) - -BEGIN_PROC(arm_clean_invalidate_cache) -1: - mrc p15, 0, r15, c7, c14, 3 @ Test/clean/flush dcache line - @ COMMENT: Why use PC? - bne 1b - mcr p15, 0, ip, c7, c5, 0 @ Flush icache - mcr p15, 0, ip, c7, c10, 4 @ Drain WB - mov pc, lr -END_PROC(arm_clean_invalidate_cache) - -BEGIN_PROC(arm_drain_writebuffer) - mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c7, c10, 4 - mov pc, lr -END_PROC(arm_drain_writebuffer) - -BEGIN_PROC(arm_invalidate_tlb) - mcr p15, 0, ip, c8, c7 - mov pc, lr -END_PROC(arm_invalidate_tlb) - -BEGIN_PROC(arm_invalidate_itlb) - mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c8, c5, 0 - mov pc, lr -END_PROC(arm_invalidate_itlb) - -BEGIN_PROC(arm_invalidate_dtlb) - mov r0, #0 @ FIX THIS - mcr p15, 0, r0, c8, c6, 0 - mov pc, lr -END_PROC(arm_invalidate_dtlb) - diff --git a/src/arch/arm/v7/mutex.S b/src/arch/arm/v7/mutex.S deleted file mode 100644 index bc81708..0000000 --- a/src/arch/arm/v7/mutex.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ARM v5 Binary semaphore (mutex) implementation. - * - * Copyright (C) 2007 Bahadir Balban - * - */ - -#include INC_ARCH(asm.h) - -/* Recap on swp: - * swp rx, ry, [rz] - * In one instruction: - * 1) Stores the value in ry into location pointed by rz. - * 2) Loads the value in the location of rz into rx. - * By doing so, in one instruction one can attempt to lock - * a word, and discover whether it was already locked. - */ - -#define MUTEX_UNLOCKED 0 -#define MUTEX_LOCKED 1 - -BEGIN_PROC(__spin_lock) - mov r1, #1 -__spin: - swp r2, r1, [r0] - cmp r2, #0 - bne __spin - mov pc, lr -END_PROC(__spin_lock) - -BEGIN_PROC(__spin_unlock) - mov r1, #0 - swp r2, r1, [r0] - cmp r2, #1 @ Debug check. -1: - bne 1b - mov pc, lr -END_PROC(__spin_unlock) - - -/* - * @r0: Address of mutex location. - */ -BEGIN_PROC(__mutex_lock) - mov r1, #1 - swp r2, r1, [r0] - cmp r2, #0 - movne r0, #0 - moveq r0, #1 - mov pc, lr -END_PROC(__mutex_lock) - -/* - * @r0: Address of mutex location. - */ -BEGIN_PROC(__mutex_unlock) - mov r1, #0 - swp r2, r1, [r0] - cmp r2, #1 -1: @ Debug check. - bne 1b - mov pc, lr -END_PROC(__mutex_unlock) - -/* - * @r0: Address of mutex location. - */ -BEGIN_PROC(__mutex_inc) - swp r2, r1, [r0] - mov r1, #1 - swp r2, r1, [r0] - cmp r2, #0 - movne r0, #0 - moveq r0, #1 - mov pc, lr -END_PROC(__mutex_inc) - -/* - * @r0: Address of mutex location. - */ -BEGIN_PROC(__mutex_dec) - mov r1, #0 - swp r2, r1, [r0] - cmp r2, #1 -1: @ Debug check. - bne 1b - mov pc, lr -END_PROC(__mutex_dec) - - diff --git a/src/arch/arm/vectors.S b/src/arch/arm/vectors.S index b65d81c..7e3b7a4 100644 --- a/src/arch/arm/vectors.S +++ b/src/arch/arm/vectors.S @@ -5,6 +5,7 @@ */ #include INC_ARCH(asm.h) +#include INC_ARCH(asm-macros.S) .balign 4096 .section .data.vectors @@ -39,30 +40,8 @@ END_PROC(arm_high_vector) BEGIN_PROC(arm_reset_exception) END_PROC(arm_reset_exception) -/* - * vect_undef - * - * Upon Entry: - * - R14: Address of next instruction after undefined instruction - * - PC: 0x00000004 - * - IRQs are disabled (CPSR[7] = 1) - * - * - * PURPOSE: - * A co-processor instruction not supported by the core can be - * emulated here. Also unrecognised/invalid instructions are handled. - */ -BEGIN_PROC(arm_undef_exception) - sub lr, lr, #4 - mov r0, lr @ Get undefined abort address - mrs r1, spsr @ Get previous abort state - mov r5, lr @ Save it in r5 in case r0 is trashed - mov lr, pc @ Save return address - ldr pc, =undef_handler -1: - b 1b -END_PROC(arm_undef_exception) +#if defined(CONFIG_SUBARCH_V5) .macro disable_irqs rx mrs \rx, cpsr_fc orr \rx, #ARM_IRQ_BIT @@ -73,6 +52,26 @@ END_PROC(arm_undef_exception) bic \rx, #ARM_IRQ_BIT msr cpsr_fc, \rx .endm +#endif + +#if defined (CONFIG_SUBARCH_V7) || defined(CONFIG_SUBARCH_V6) + .macro disable_irqs rx + cpsid ia + .endm + .macro enable_irqs rx + cpsie ia + .endm +#endif + +#if defined (CONFIG_SUBARCH_V7) + .macro clear_exclusive + clrex + .endm +#else + .macro clear_exclusive + .endm +#endif + /* Only works in SVC MODE. Know what you are doing! */ .macro get_current rx bic \rx, sp, #0xFF0 @@ -114,14 +113,61 @@ END_PROC(arm_undef_exception) cmp \rx, #ARM_MODE_USR .endm +/* These really both read the same unified FSR and FAR registers */ +#if defined (CONFIG_SUBARCH_V5) + .macro cp15_read_ifsr rx + mrc p15, 0, \rx, c5, c0, 0 @ Read FSR (Tells why the fault occured) + + .endm + .macro cp15_read_ifar rx + mrc p15, 0, \rx, c6, c0, 0 @ Read FAR (Contains the faulted data address) + .endm + .macro cp15_read_dfsr rx + mrc p15, 0, \rx, c5, c0, 0 @ Read FSR (Tells why the fault occured) + + .endm + .macro cp15_read_dfar rx + mrc p15, 0, \rx, c6, c0, 0 @ Read FAR (Contains the faulted data address) + .endm +#endif + +/* These read the distinguished IFSR, IFAR, DFSR and DFAR registers */ +#if defined (CONFIG_SUBARCH_V6) || defined (CONFIG_SUBARCH_V7) + .macro cp15_read_ifsr rx + mrc p15, 0, \rx, c5, c0, 1 @ Read IFSR (Tells why the fault occured) + + .endm + .macro cp15_read_ifar rx + mrc p15, 0, \rx, c6, c0, 2 @ Read IFAR (Contains the faulted data address) + .endm + .macro cp15_read_dfsr rx + mrc p15, 0, \rx, c5, c0, 0 @ Read DFSR (Tells why the fault occured) + + .endm + .macro cp15_read_dfar rx + mrc p15, 0, \rx, c6, c0, 0 @ Read DFAR (Contains the faulted data address) + .endm +#endif #define UNDEF_R0 0 #define UNDEF_SPSR -4 #define UNDEF_R14 -8 +/* + * vect_undef + * + * Upon Entry: + * - R14: Address of next instruction after undefined instruction + * - PC: 0x00000004 + * - IRQs are disabled (CPSR[7] = 1) + * + * + * PURPOSE: + * A co-processor instruction not supported by the core can be + * emulated here. Also unrecognised/invalid instructions are handled. + */ BEGIN_PROC(arm_undef_exception_reentrant) - @ lr contains address of instruction following the one caused undef - @ sub lr, lr, #4 + clear_exclusive str lr, [sp, #UNDEF_R14] @ Store undef address mrs lr, spsr @ Get SPSR str lr, [sp, #UNDEF_SPSR] @ Store SPSR @@ -142,8 +188,9 @@ BEGIN_PROC(arm_undef_exception_reentrant) ldr r0, [r0, #UNDEF_R0] stmfd sp!, {r0-r3,r12,lr} @ Stack state: |R0<-|R1|R2|R3|R12|UNDEF_SPSR|LR_SVC|LR_DUNDEF|{original SP_SVC}| - push_user_sp_lr sp - + push_user_sp_lr sp @ NOTE: These must be pushed to avoid trashing them if preempted + @ Stack state: |SP_USR<-|LR_USR|R0<-|R1|R2|R3|R12|UNDEF_SPSR|LR_SVC|LR_DUNDEF|{original SP_SVC}| + @ All undef state saved. Can safely enable irqs here, if need be. ldr r3, [sp, #28] @ Load UNDEF_SPSR can_abort_enable_irqs r0, r3 @ Judge if irqs can be enabled depending on prev state. @@ -151,7 +198,7 @@ BEGIN_PROC(arm_undef_exception_reentrant) enable_irqs r3 1: /* Now check in what mode exception occured, and return that mode's LR in R4 - * Also poplulate r0,r1,r2 parameters for undef_handler + * Also poplulate r0,r1,r2 parameters for undefined_instr_handler */ ldr r1, [sp, #28] @ Load UNDEF_SPSR is_psr_usr r0 @ Test if UNDEF_SPSR was user mode. @@ -159,7 +206,7 @@ BEGIN_PROC(arm_undef_exception_reentrant) ldreq r2, [sp, #4] @ Abort occured in user, load LR_USR ldr r0, [sp, #36] @ Load LR_UNDEF saved previously. mov lr, pc - ldr pc, =undef_handler @ Jump to function outside this page. + ldr pc, =undefined_instr_handler @ Jump to function outside this page. disable_irqs r0 @ Disable irqs to avoid corrupting spsr. @ (i.e. an interrupt could overwrite spsr with current psr) ldmfd sp, {sp, lr}^ @ Restore user sp and lr which might have been corrupt on preemption @@ -173,7 +220,6 @@ BEGIN_PROC(arm_undef_exception_reentrant) @ down from where svc stack had left. END_PROC(arm_undef_exception_reentrant) - /* * vect_swi * @@ -210,6 +256,7 @@ END_PROC(arm_undef_exception_reentrant) * determine the correct system call, rather than [7:0] bits of the SWI. */ BEGIN_PROC(arm_swi_exception) + clear_exclusive sub lr, lr, #4 @ Get address of swi instruction user executed. stmfd sp, {r0-r12,sp,lr}^ @ Push arguments, LR_USR and SP_USR to stack. nop @@ -278,7 +325,7 @@ END_PROC(arm_swi_exception) * vect_pabt * * Upon Entry: - * - R14_svc: Address of next instruction after aborted instruction + * - R14_abt: Address of next instruction after aborted instruction * - R14_usr: Address of return instruction in last function call** * - PC: 0x0000000c * - IRQs are disabled (CPSR[7] = 1) @@ -300,6 +347,7 @@ END_PROC(arm_swi_exception) * where this call came from. */ BEGIN_PROC(arm_prefetch_abort_exception_reentrant) + clear_exclusive sub lr, lr, #4 @ lr-4 points at aborted instruction str lr, [r13, #ABT_R14] @ Store abort address. mrs lr, spsr @ Get SPSR @@ -320,23 +368,19 @@ transfer_pabt_state_to_svc: @ Move data saved on PABT stack to SVC stack. ldr r0, [r0, #ABT_R0] stmfd sp!, {r0-r3,r12,lr} @ Stack state: |R0<-|R1|R2|R3|R12|PABT_SPSR|LR_SVC|LR_PABT|{original SP_SVC}| - push_user_sp_lr sp + push_user_sp_lr sp @ NOTE: These must be pushed to avoid trashing if preempted @ Stack state: |SP_USR<-|LR_USR|R0|R1|R2|R3|R12|PABT_SPSR|LR_SVC|LR_PABT|{original SP_SVC}| read_pabt_state: - mrc p15, 0, r1, c5, c0, 0 @ Read FSR (Tells why the fault occured) FIXME: Do we need this in pabt? - mrc p15, 0, r2, c6, c0, 0 @ Read FAR (Contains the faulted data address) Do we need this in pabt? + cp15_read_ifsr r1 @ Reads FSR on ARMv5, IFSR on ARMv6-v7. Fault status information + cp15_read_ifar r2 @ Reads FAR on ARMv5, IFAR on ARMv6-v7. Fault address information @ All abort state and (FAR/FSR) saved. Can safely enable irqs here, if need be. ldr r3, [sp, #28] @ Load PABT_SPSR can_abort_enable_irqs r0, r3 @ Judge if irqs can be enabled depending on prev state. bne 1f @ Branch here based on previous irq judgement. enable_irqs r3 1: - /* Now check in what mode abort occured, and return that mode's LR in R4 */ - ldr r0, [sp, #28] @ Load PABT_SPSR - is_psr_usr r0 @ Test if PABT_SPSR was user mode. - ldrne r3, [sp, #32] @ Abort occured in kernel, load LR_SVC - ldreq r3, [sp, #4] @ Abort occured in user, load LR_USR - ldr r0, [sp, #36] @ Load LR_PABT saved previously. + ldr r3, [sp, #28] @ Load PABT_SPSR to r3, the spsr for the aborted mode + ldr r0, [sp, #36] @ Load LR_PABT - 4 saved previously. (Address that aborted) mov lr, pc ldr pc, =prefetch_abort_handler @ Jump to function outside this page. disable_irqs r0 @ Disable irqs to avoid corrupting spsr. @@ -381,12 +425,14 @@ BEGIN_PROC(arm_data_abort_exception) 1: b 1b END_PROC(arm_data_abort_exception) + /* * The method of saving abort state to svc stack is identical with that of * reentrant irq vector. Natural to this, Restoring of the previous state * is also identical. */ BEGIN_PROC(arm_data_abort_exception_reentrant) + clear_exclusive sub lr, lr, #8 @ Get abort address str lr, [r13, #ABT_R14] @ Store abort address mrs lr, spsr @ Get SPSR @@ -411,8 +457,8 @@ transfer_dabt_state_to_svc: push_user_sp_lr sp @ Stack state: |SP_USR<-|LR_USR|R0|R1|R2|R3|R12|DABT_SPSR|LR_SVC|LR_DABT|{original SP_SVC}| read_dabt_state: - mrc p15, 0, r1, c5, c0, 0 @ Read FSR (Tells why the fault occured) - mrc p15, 0, r2, c6, c0, 0 @ Read FAR (Contains the faulted data address) + cp15_read_dfsr r1 @ Read DFSR (Tells why the fault occured) + cp15_read_dfar r2 @ Read DFAR (Contains the faulted data address) @ All abort state and (FAR/FSR) saved. Can safely enable irqs here, if need be. ldr r3, [sp, #28] @ Load DABT_SPSR can_abort_enable_irqs r0, r3 @ Judge if irqs can be enabled depending on prev state. @@ -493,12 +539,6 @@ BEGIN_PROC(arm_irq_exception_reentrant) @ down from where svc stack had left. END_PROC(arm_irq_exception_reentrant) - .macro was_irq_mode rx - mrs rx, spsr_fc - and rx, rx, 0x1F - cmp rx, #ARM_MODE_IRQ - .endm - .macro need_resched rx, ry get_current \rx ldr \ry, =need_resched_offset @@ -514,20 +554,39 @@ END_PROC(arm_irq_exception_reentrant) .global preempted_psr; preempted_psr: .word 0 +.word 0 +.word 0 +.word 0 /* Keeps track of how many nests of irqs have happened. */ .global current_irq_nest_count; current_irq_nest_count: .word 0 +.word 0 +.word 0 +.word 0 + +#if defined (CONFIG_SMP) + @ Rx contains the address of per cpu variable + .macro per_cpu adr, temp, varname + get_cpuid \temp + ldr \adr, =\varname + add \adr, \adr, \temp, lsl #2 + .endm +#else + .macro per_cpu adr, temp, varname + ldr \adr, =\varname + .endm +#endif /* * FIXME: current_irq_nest_count also counts for any preempt_disable() calls. * However this nesting check assumes all nests come from real irqs. * We should make this check just the real ones. */ -#define IRQ_NESTING_MAX 15 +#define IRQ_NESTING_MAX 32 .macro inc_irq_cnt_with_overnest_check rx, ry - ldr \rx, =current_irq_nest_count @ Load the irq nest status word. + per_cpu \rx, \ry, current_irq_nest_count @ Get per-cpu address of variable ldr \ry, [\rx] add \ry, \ry, #1 @ No need for atomic inc since irqs are disabled. str \ry, [\rx] @@ -541,21 +600,37 @@ current_irq_nest_count: @ it back to the original value as it was when we read it, before it returns. So effectively @ anything that runs during the decrement does not affect the value of the count. .macro dec_irq_nest_cnt rx, ry - ldr \ry, =current_irq_nest_count + per_cpu \ry, \rx, current_irq_nest_count ldr \rx, [\ry] sub \rx, \rx, #1 str \rx, [\ry] .endm - .macro in_process_context rx - ldr \rx, =current_irq_nest_count + .macro in_process_context rx, ry + per_cpu \rx, \ry, current_irq_nest_count ldr \rx, [\rx] cmp \rx, #0 .endm /* If interrupted a process (as opposed to another irq), saves spsr value to preempted_psr */ - .macro cmp_and_save_process_psr rx, process_psr - in_process_context \rx @ If nest count is 0, a running process is preempted. - ldreq \rx, =preempted_psr - streq \process_psr, [\rx] + .macro cmp_and_save_process_psr rx, ry + in_process_context \rx, \ry @ If nest count is 0, a running process is preempted. + bne 9999f @ Branch ahead if not a process + per_cpu \rx, \ry, preempted_psr @ Get per-cpu preempted psr + mrs \ry, SPSR @ Re-read spsr since register was trashed + str \ry, [\rx] @ Store it in per-cpu preempted psr + 9999: + .endm + + /* + * Clear irq bits on register. + * + * If ARMv5, only I-bit is cleared, but if ARMv6-v7, + * A-bit is also cleared. + */ + .macro clr_irq_bits_on_reg rx + bic \rx, #ARM_IRQ_BIT +#if defined (CONFIG_SUBARCH_V6) || defined (CONFIG_SUBARCH_V7) + bic \rx, #ARM_A_BIT +#endif .endm #define CONTEXT_PSR 0 @@ -576,7 +651,14 @@ current_irq_nest_count: #define CONTEXT_R14 60 #define CONTEXT_PC 64 +/* + * TODO: Optimization: + * May use SRS/RFE on irq exception _only_. But not + * yet aware of its implications. Only irq handler can + * do it because RFE enables interrupts unconditionally. + */ BEGIN_PROC(arm_irq_exception_reentrant_with_schedule) + clear_exclusive sub lr, lr, #4 str lr, [r13, #IRQ_R14] @ Save lr_irq mrs r14, spsr @ Copy spsr @@ -600,12 +682,22 @@ BEGIN_PROC(arm_irq_exception_reentrant_with_schedule) mov lr, pc ldr pc, =do_irq @ Read irq number etc. Free to re-enable irqs here. @ stack state: (Low) r0|r1|r2|r3|r12|SPSR|LR_SVC|LR_IRQ| (High) - ldr r0, =current_irq_nest_count + +/* + * Decision point for taking the preemption path + */ +#if !defined(CONFIG_PREEMPT_DISABLE) + per_cpu r0, r1, current_irq_nest_count ldr r0, [r0] cmp r0, #1 @ Expect 1 as lowest since each irq increase preempt cnt by 1. bgt return_to_prev_context @ if (irq_nest > 1) return_to_prev_context(); need_resched r0, r1 @ if (irq_nest == 1 && need_resched) schedule(); beq preemption_path @ if (irq_nest == 1 && !need_resched) return_to_prev_context(); +#endif + +/* + * Return to previous context path + */ return_to_prev_context: dec_irq_nest_cnt r0, r1 disable_irqs r0 @ Disable irqs to avoid corrupting spsr. @@ -615,6 +707,11 @@ return_to_prev_context: ldmfd r13!, {r14, pc}^ @ Return, restoring cpsr. Note r14 gets r14_svc, @ and pc gets lr_irq. Saved at #4 and #8 offsets @ down from where svc stack had left. + +/* + * Preemption path + */ +#if !defined(CONFIG_PREEMPT_DISABLE) preemption_path: disable_irqs r0 @ Interrupts can corrupt stack state. get_current r0 @ Get the interrupted process @@ -661,6 +758,8 @@ prepare_schedule: ldr pc, =schedule 1: b 1b /* To catch if schedule returns in irq mode */ +#endif /* End of !CONFIG_PREEMPT_DISABLE */ + END_PROC(arm_irq_exception_reentrant_with_schedule) /* @@ -688,8 +787,9 @@ END_PROC(arm_irq_exception_reentrant_with_schedule) * Furthermore, irqs are also disabled shortly before calling switch_to() from both contexts. * This happens at points where stack state would be irrecoverable if an irq occured. */ -BEGIN_PROC(arch_switch) - in_process_context r2 @ Note this depends on preempt count being 0. +BEGIN_PROC(arch_context_switch) + clear_exclusive + in_process_context r2, r3 @ Note this depends on preempt count being 0. beq save_process_context @ Voluntary switch needs explicit saving of current state. dec_irq_nest_cnt r2, r3 @ Soon leaving irq context, so reduce preempt count here. b load_next_context @ Interrupted context already saved by irq handler. @@ -702,7 +802,7 @@ load_next_context: @ stack state: (Low) |..|..|..|..|..|..|..|..|..|->(Original)| (High) mov sp, r1 ldr r0, [sp, #CONTEXT_PSR] @ Load r0 with SPSR - bic r0, r0, #ARM_IRQ_BIT @ Enable irqs on will-be-restored context. + clr_irq_bits_on_reg r0 @ Enable irqs on will-be-restored context. msr spsr_fcxs, r0 @ Restore spsr from r0. is_psr_usr r0 bne load_next_context_svc @ Loading user context is different than svc. @@ -715,7 +815,7 @@ load_next_context_usr: load_next_context_svc: ldmib sp, {r0-r15}^ @ Switch to svc context and jump, loading R13 and R14 from stack. @ This is OK since the jump is to current context. -END_PROC(arch_switch) +END_PROC(arch_context_switch) /* @@ -788,11 +888,13 @@ END_PROC(arm_fiq_exception) * (use a macro, e.g. ____arm_asm_cache_aligned) */ .balign 4 -__stacks_end: .space 256 -__abt_stack: .space 256 -__irq_stack: .space 256 -__fiq_stack: .space 256 -__und_stack: .space 256 + +/* 16 bytes each per-cpu, up to 8 cpus */ +__stacks_end: .space 128 +__abt_stack: .space 128 +__irq_stack: .space 128 +__fiq_stack: .space 128 +__und_stack: .space 128 .balign 4096 diff --git a/src/drivers/SConscript b/src/drivers/SConscript index bfd799e..0ca81e6 100644 --- a/src/drivers/SConscript +++ b/src/drivers/SConscript @@ -1,19 +1,32 @@ -import glob +import os, sys, glob -Import("env", "symbols") +PROJRELROOT = '../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import("env", "symbols", "platform", "bdir") src_local = [] +objs = [] for name, val in symbols: if "CONFIG_DRIVER_UART_PL011" == name: - src_local.append(glob.glob("uart/pl011/*.c")) + objs += SConscript("uart/pl011/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + 'pl011') if "CONFIG_DRIVER_TIMER_SP804" == name: - src_local.append(glob.glob("timer/sp804/*.c")) + objs += SConscript("timer/sp804/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + 'timer') if "CONFIG_DRIVER_IRQ_PL190" == name: - src_local.append(glob.glob("irq/pl190/*.c")) + objs += SConscript("irq/pl190/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + 'vic') if "CONFIG_DRIVER_IRQ_GIC" == name: - src_local.append(glob.glob("irq/gic/*.c")) + objs += SConscript("irq/gic/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + 'gic') + if "CONFIG_DRIVER_INTC_OMAP" == name: + objs += SConscript("irq/omap3/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + '/omap/intc') + if "CONFIG_DRIVER_UART_OMAP" == name: + objs += SConscript("uart/omap/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + '/omap/uart') + if "CONFIG_DRIVER_TIMER_OMAP" == name: + objs += SConscript("timer/omap/SConscript", exports = {'env' : env}, duplicate=0, build_dir=bdir + '/omap/timer') -obj = env.Object(src_local) -Return('obj') +Return('objs') diff --git a/src/drivers/irq/gic/SConscript b/src/drivers/irq/gic/SConscript new file mode 100644 index 0000000..dac152b --- /dev/null +++ b/src/drivers/irq/gic/SConscript @@ -0,0 +1,17 @@ +# Inherit global environment + +#import os, sys + +#PROJRELROOT = '../../../' + +#sys.path.append(PROJRELROOT) + +#from config.projpaths import * +#from configure import * + +Import('env') +# The set of source files associated with this SConscript file. +src_local = ['gic.c'] +obj = env.Object(src_local) + +Return('obj') diff --git a/src/drivers/irq/gic/gic.c b/src/drivers/irq/gic/gic.c index 3d58a3b..93957c9 100644 --- a/src/drivers/irq/gic/gic.c +++ b/src/drivers/irq/gic/gic.c @@ -1,106 +1,222 @@ /* - * PL190 Vectored irq controller support. + * PLXXX Generic Interrupt Controller support. * - * This is more pb926 specific as it also touches the SIC, a partial irq - * controller.Normally, irq controller must be independent and singular. Later - * other generic code should make thlongwork in cascaded setup. - * - * Copyright (C) 2007 Bahadir Balban + * This is more ARM Realview EB/PB + * Copyright (C) 2009-2010 B Labs Ltd. + * Author: Prem Mallappa */ #include -#include +#include +#include +#include INC_PLAT(irq.h) +#include INC_SUBARCH(mmu_ops.h) /* for dmb/dsb() */ +#include -/* FIXME: Fix the stupid uart driver and change to single definition of this! */ -#if defined(read) -#undef read -#endif -#if defined(write) -#undef write -#endif +volatile struct gic_data gic_data[IRQ_CHIPS_MAX]; -#define read(a) *((volatile unsigned int *)(a)) -#define write(v, a) (*((volatile unsigned int *)(a)) = v) -#define setbit(bitvect, a) write(read(a) | (bitvect), a) -#define clrbit(bitvect, a) write(read(a) & ~(bitvect), a) -#define devio(base, reg, bitvect, setclr) \ - ((setclr) ? setbit(bitvect, (base + reg)) \ - : clrbit(bitvect, (base + reg))) +static inline struct gic_data *get_gic_data(l4id_t irq) +{ + struct irq_chip *chip = irq_desc_array[irq].chip; + if (chip) + return (struct gic_data *)irq_desc_array[irq].chip->data; + else + return 0; +} -#if 0 /* Returns the irq number on this chip converting the irq bitvector */ -int pl190_read_irq(void) +l4id_t gic_read_irq(void *data) { - /* This also correctly returns a negative value for a spurious irq. */ - return 31 - __clz(read(PL190_VIC_IRQSTATUS)); + int irq; + volatile struct gic_data *gic = (struct gic_data *)data; + irq = gic->cpu->ack & 0x1ff; + + if (irq == 1023) + return -1023; /* Spurious */ + + return irq; } -void pl190_mask_irq(int irq) +void gic_mask_irq(l4id_t irq) { - /* Reading WO registers blows QEMU/PB926. - * setbit((1 << irq), PL190_VIC_INTENCLEAR); */ - write(1 << irq, PL190_VIC_INTENCLEAR); + u32 offset = irq >> 5; /* offset = irq / 32, avoiding division */ + volatile struct gic_data *gic = get_gic_data(irq); + gic->dist->clr_en[offset] = 1 << (irq % 32); } -/* Ack is same as mask */ -void pl190_ack_irq(int irq) +void gic_unmask_irq(l4id_t irq) { - pl190_mask_irq(irq); + volatile struct gic_data *gic = get_gic_data(irq); + + u32 offset = irq >> 5 ; /* offset = irq / 32 */ + gic->dist->set_en[offset] = 1 << (irq % 32); } -void pl190_unmask_irq(int irq) +void gic_ack_irq(l4id_t irq) { - setbit(1 << irq, PL190_VIC_INTENABLE); + u32 offset = irq >> 5; /* offset = irq / 32, avoiding division */ + volatile struct gic_data *gic = get_gic_data(irq); + gic->dist->clr_en[offset] = 1 << (irq % 32); + gic->cpu->eoi = irq; } -int pl190_sic_read_irq(void) +void gic_ack_and_mask(l4id_t irq) { - return 32 - __clz(read(PL190_SIC_STATUS)); + gic_ack_irq(irq); + gic_mask_irq(irq); } -void pl190_sic_mask_irq(int irq) +void gic_set_pending(l4id_t irq) { - write(1 << irq, PL190_SIC_ENCLR); + u32 offset = irq >> 5; /* offset = irq / 32, avoiding division */ + volatile struct gic_data *gic = get_gic_data(irq); + gic->dist->set_pending[offset] = 1 << (irq % 32); } -void pl190_sic_ack_irq(int irq) +void gic_clear_pending(l4id_t irq) { - pl190_sic_mask_irq(irq); + u32 offset = irq >> 5; /* offset = irq / 32, avoiding division */ + volatile struct gic_data *gic = get_gic_data(irq); + gic->dist->clr_pending[offset] = 1 << (irq % 32); } -void pl190_sic_unmask_irq(int irq) + +void gic_cpu_init(int idx, unsigned long base) { - setbit(1 << irq, PL190_SIC_ENSET); + struct gic_cpu *cpu; + cpu = gic_data[idx].cpu = (struct gic_cpu *)base; + + /* Disable */ + cpu->control = 0; + + cpu->prio_mask = 0xf0; + cpu->bin_point = 3; + + cpu->control = 1; } -/* Initialises the primary and secondary interrupt controllers */ -void pl190_vic_init(void) +void gic_dist_init(int idx, unsigned long base) { + int i, irqs_per_word; /* Interrupts per word */ + struct gic_dist *dist; + dist = gic_data[idx].dist = (struct gic_dist *)(base); + + /* Surely disable GIC */ + dist->control = 0; + + /* 32*(N+1) interrupts supported */ + int nirqs = 32 * ((dist->type & 0x1f) + 1); + if (nirqs > IRQS_MAX) + nirqs = IRQS_MAX; + /* Clear all interrupts */ - write(0, PL190_VIC_INTENABLE); - write(0xFFFFFFFF, PL190_VIC_INTENCLEAR); + irqs_per_word = 32; + for(i = 0; i < nirqs ; i+=irqs_per_word) { + dist->clr_en[i/irqs_per_word] = 0xffffffff; + } - /* Set all irqs as normal IRQs (i.e. not FIQ) */ - write(0, PL190_VIC_INTSELECT); - /* TODO: Is there a SIC_IRQ_SELECT for irq/fiq ??? */ + /* Clear all pending interrupts */ + for(i = 0; i < nirqs ; i+=irqs_per_word) { + dist->clr_pending[i/irqs_per_word] = 0xffffffff; + } - /* Disable user-mode access to VIC registers */ - write(1, PL190_VIC_PROTECTION); + /* Set all irqs as normal priority, 8 bits per interrupt */ + irqs_per_word = 4; + for(i = 32; i < nirqs ; i+=irqs_per_word) { + dist->priority[i/irqs_per_word] = 0xa0a0a0a0; + } - /* Clear software interrupts */ - write(0xFFFFFFFF, PL190_VIC_SOFTINTCLEAR); + /* Set all target to cpu0, 8 bits per interrupt */ + for(i = 32; i < nirqs ; i+=irqs_per_word) { + dist->target[i/irqs_per_word] = 0x01010101; + } - /* At this point, all interrupts are cleared and disabled. - * the controllers are ready to receive interrupts, if enabled. */ - return; + /* Configure all to be level-sensitive, 2 bits per interrupt */ + irqs_per_word = 16; + for(i = 32; i < nirqs ; i+=irqs_per_word) { + dist->config[i/irqs_per_word] = 0x00000000; + } + + /* Enable GIC Distributor */ + dist->control = 1; } -void pl190_sic_init(void) + +/* Some functions, may be helpful */ +void gic_set_target(u32 irq, u32 cpu) { - write(0, PL190_SIC_ENABLE); - write(0xFFFFFFFF, PL190_SIC_ENCLR); - /* Disable SIC-to-PIC direct routing of individual irq lines on SIC */ - write(0xFFFFFFFF, PL190_SIC_PICENCLR); + /* cpu is a mask, not cpu number */ + cpu &= 0xF; + irq &= 0xFF; + volatile struct gic_data *gic = get_gic_data(irq); + u32 offset = irq >> 2; /* offset = irq / 4 */ + gic->dist->target[offset] |= (cpu << ((irq % 4) * 8)); } -#endif +u32 gic_get_target(u32 irq) +{ + /* cpu is a mask, not cpu number */ + unsigned int target; + irq &= 0xFF; + u32 offset = irq >> 2; /* offset = irq / 4 */ + volatile struct gic_data *gic = get_gic_data(irq); + target = gic->dist->target[offset]; + target >>= ((irq % 4) * 8); + + return target & 0xFF; +} + +void gic_set_priority(u32 irq, u32 prio) +{ + /* cpu is a mask, not cpu number */ + prio &= 0xF; + irq &= 0xFF; + u32 offset = irq >> 3; /* offset = irq / 8 */ + volatile struct gic_data *gic = get_gic_data(irq); + /* target = cpu << ((irq % 4) * 4) */ + gic->dist->target[offset] |= (prio << (irq & 0x1C)); +} + +u32 gic_get_priority(u32 irq) +{ + /* cpu is a mask, not cpu number */ + irq &= 0xFF; + u32 offset = irq >> 3; /* offset = irq / 8 */ + volatile struct gic_data *gic = get_gic_data(irq); + return gic->dist->target[offset] & (irq & 0xFC); +} + +#define TO_MANY 0 /* to all specified in a CPU mask */ +#define TO_OTHERS 1 /* all but me */ +#define TO_SELF 2 /* just to the requesting CPU */ + +#define CPU_MASK_BIT 16 +#define TYPE_MASK_BIT 24 + +void gic_send_ipi(int cpu, int ipi_cmd) +{ + /* if cpu is 0, then ipi is sent to self + * if cpu has exactly 1 bit set, the ipi to just that core + * if cpu has a mask, sent to all but current + */ + struct gic_dist *dist = gic_data[0].dist; + + ipi_cmd &= 0xf; + cpu &= 0xff; + + dsb(); + + if (cpu == 0) /* Self */ + dist->soft_int = (TO_SELF << 24) | ipi_cmd; + else if ((cpu & (cpu-1)) == 0) /* Exactly to one CPU */ + dist->soft_int = (TO_MANY << 24) | (cpu << 16) | ipi_cmd; + else /* All but me */ + dist->soft_int = (TO_OTHERS << 24) | (cpu << 16) | ipi_cmd; + +} + +/* Make the generic code happy :) */ +void gic_dummy_init() +{ + +} diff --git a/src/drivers/irq/omap3/SConscript b/src/drivers/irq/omap3/SConscript new file mode 100644 index 0000000..ede27df --- /dev/null +++ b/src/drivers/irq/omap3/SConscript @@ -0,0 +1,7 @@ +Import('env') + +# The set of source files associated with this SConscript file. +src_local = Glob('*.c') +obj = env.Object(src_local) + +Return('obj') diff --git a/src/drivers/irq/omap3/omap3_intc.c b/src/drivers/irq/omap3/omap3_intc.c new file mode 100644 index 0000000..54995ef --- /dev/null +++ b/src/drivers/irq/omap3/omap3_intc.c @@ -0,0 +1,70 @@ +/* + * Interrupt Controller - Beagleboard + * + * Copyright 2010 B Labs Ltd. + */ + +#include +#include INC_PLAT(offsets.h) +#include INC_PLAT(irq.h) + +void omap3_intc_ack_irq(l4id_t irq) +{ + write(0x1, PLATFORM_INTC_VBASE + OMAP3_INTC_CONTROL); +} + +void omap3_intc_mask_irq(l4id_t irq) +{ + omap3_intc_set_irq_status(PLATFORM_INTC_VBASE, OMAP3_INTC_MIR_SET, irq); +} + +void omap3_intc_unmask_irq(l4id_t irq) +{ + omap3_intc_set_irq_status(PLATFORM_INTC_VBASE, OMAP3_INTC_MIR_CLR, irq); +} + +/* End of Interrupt */ +void omap3_intc_ack_and_mask(l4id_t irq) +{ + omap3_intc_mask_irq(irq); + omap3_intc_ack_irq(irq); +} + +l4id_t omap3_intc_read_irq(void *data) +{ + unsigned int irq = 0; + + if ((irq = (read(PLATFORM_INTC_VBASE + OMAP3_INTC_SIR_IRQ) & 0x7F))) + return irq; + + return -1; +} + +void omap3_intc_reset(unsigned long base) +{ + /* Assert Reset */ + write(OMAP_INTC_SOFTRESET, (base + OMAP3_INTC_SYSCONFIG)); + + /* wait for completion */ + while (!(read((base + OMAP3_INTC_SYSSTATUS)) & 0x1)); +} + +void omap3_intc_init(void) +{ + int i; + + /* Do Soft-Reset */ + omap3_intc_reset(PLATFORM_INTC_VBASE); + + /* + * Set All IRQ to IRQ type and + * Priority as 0x0A- some random value + */ + for (i = 0; i < IRQS_MAX; i++) + omap3_intc_set_ilr(PLATFORM_INTC_VBASE, i, (0x0A << 2)); + + /* Mask(set mask) all interrupts */ + for (i = 0; i < IRQS_MAX; i++) + omap3_intc_set_irq_status(PLATFORM_INTC_VBASE, + OMAP3_INTC_MIR_SET, i); +} diff --git a/src/arch/arm/v7/SConscript b/src/drivers/irq/pl190/SConscript similarity index 76% rename from src/arch/arm/v7/SConscript rename to src/drivers/irq/pl190/SConscript index 4fd282a..a878bcc 100644 --- a/src/arch/arm/v7/SConscript +++ b/src/drivers/irq/pl190/SConscript @@ -1,10 +1,8 @@ - - # Inherit global environment + Import('env') - # The set of source files associated with this SConscript file. -src_local = ['mm.c', 'mmu_ops.S', 'mutex.S'] - +src_local = ['pl190_vic.c'] obj = env.Object(src_local) + Return('obj') diff --git a/src/drivers/irq/pl190/pl190_vic.c b/src/drivers/irq/pl190/pl190_vic.c index 9f65c02..5ee86ae 100644 --- a/src/drivers/irq/pl190/pl190_vic.c +++ b/src/drivers/irq/pl190/pl190_vic.c @@ -12,24 +12,8 @@ #include #include -/* FIXME: Fix the stupid uart driver and change to single definition of this! */ -#if defined(read) -#undef read -#endif -#if defined(write) -#undef write -#endif - -#define read(a) *((volatile unsigned int *)(a)) -#define write(v, a) (*((volatile unsigned int *)(a)) = v) -#define setbit(bitvect, a) write(read(a) | (bitvect), a) -#define clrbit(bitvect, a) write(read(a) & ~(bitvect), a) -#define devio(base, reg, bitvect, setclr) \ - ((setclr) ? setbit(bitvect, (base + reg)) \ - : clrbit(bitvect, (base + reg))) - /* Returns the irq number on this chip converting the irq bitvector */ -l4id_t pl190_read_irq(void) +l4id_t pl190_read_irq(void *nil) { l4id_t irq; @@ -54,10 +38,10 @@ void pl190_ack_irq(l4id_t irq) void pl190_unmask_irq(l4id_t irq) { - setbit(1 << irq, PL190_VIC_INTENABLE); + setbit((unsigned int *)PL190_VIC_INTENABLE, (1 << irq)); } -l4id_t pl190_sic_read_irq(void) +l4id_t pl190_sic_read_irq(void *nil) { l4id_t irq; @@ -79,7 +63,7 @@ void pl190_sic_ack_irq(l4id_t irq) void pl190_sic_unmask_irq(l4id_t irq) { - setbit(1 << irq, PL190_SIC_ENSET); + setbit((unsigned int *)PL190_SIC_ENSET, (1 << irq)); } /* Initialises the primary and secondary interrupt controllers */ diff --git a/src/drivers/timer/omap/SConscript b/src/drivers/timer/omap/SConscript new file mode 100644 index 0000000..c69a25c --- /dev/null +++ b/src/drivers/timer/omap/SConscript @@ -0,0 +1,7 @@ +Import('env') + +# The set of source files associated with this SConscript file. +src_local = ['timer.c'] +obj = env.Object(src_local) + +Return('obj') diff --git a/src/drivers/timer/omap/timer.c b/src/drivers/timer/omap/timer.c new file mode 100644 index 0000000..3b3a71d --- /dev/null +++ b/src/drivers/timer/omap/timer.c @@ -0,0 +1,133 @@ +/* + * omap GP timer driver honoring generic + * timer library API + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include INC_ARCH(io.h) + +#define OMAP_TIMER_MAT_IT_FLAG (1 << 0) +#define OMAP_TIMER_OVR_IT_FLAG (1 << 1) +#define OMAP_TIMER_TCAR_IT_FLAG (1 << 2) +void timer_irq_clear(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TISR); + reg |= OMAP_TIMER_OVR_IT_FLAG; + write(reg, timer_base + OMAP_TIMER_TISR); +} + +u32 timer_periodic_intr_status(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TISR); + return (reg & OMAP_TIMER_OVR_IT_FLAG); +} + +#define OMAP_TIMER_SOFT_RESET (1 << 1) +void timer_reset(unsigned long timer_base) +{ + /* Reset Timer */ + write(OMAP_TIMER_SOFT_RESET, timer_base + OMAP_TIMER_TIOCP); + + /* Wait for reset completion */ + while (!read(timer_base + OMAP_TIMER_TSTAT)); +} + +void timer_load(unsigned long timer_base, u32 value) +{ + write(value, timer_base + OMAP_TIMER_TLDR); + write(value, timer_base + OMAP_TIMER_TCRR); +} + +u32 timer_read(unsigned long timer_base) +{ + return read(timer_base + OMAP_TIMER_TCRR); +} + +#define OMAP_TIMER_START (1 << 0) +void timer_start(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TCLR); + reg |= OMAP_TIMER_START; + write(reg, timer_base + OMAP_TIMER_TCLR); +} + +void timer_stop(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + OMAP_TIMER_TCLR); + reg &= (~OMAP_TIMER_START); + write(reg, timer_base + OMAP_TIMER_TCLR); +} + +/* +* Beagle Board RevC manual: +* overflow period = (0xffffffff - TLDR + 1)*PS*(1/TIMER_FCLK) +* where, +* PS: Prescaler divisor (we are not using this) +* +* Beagle board manual says, 26MHz oscillator present on board. +* U-Boot divides the sys_clock by 2 if sys_clk is >19MHz, +* so,we have sys_clk frequency = 13MHz +* +* TIMER_FCLK = 13MHz +* +*/ +void timer_init_oneshot(unsigned long timer_base) +{ + volatile u32 reg; + + /* Reset the timer */ + timer_reset(timer_base); + + /* Set timer to compare mode */ + reg = read(timer_base + OMAP_TIMER_TCLR); + reg |= (1 << OMAP_TIMER_MODE_COMPARE); + write(reg, timer_base + OMAP_TIMER_TCLR); + + write(0xffffffff, timer_base + OMAP_TIMER_TMAR); + + /* Clear pending Interrupts, if any */ + write(7, timer_base + OMAP_TIMER_TISR); +} + +void timer_init_periodic(unsigned long timer_base) +{ + volatile u32 reg; + + /* Reset the timer */ + timer_reset(timer_base); + + /* Set timer to autoreload mode */ + reg = read(timer_base + OMAP_TIMER_TCLR); + reg |= (1 << OMAP_TIMER_MODE_AUTORELAOD); + write(reg, timer_base + OMAP_TIMER_TCLR); + + /* + * Beagle Board RevC manual: + * overflow period = (0xffffffff - TLDR + 1)*PS*(1/TIMER_FCLK) + * where, + * PS: Prescaler divisor (we are not using this) + * + * Beagle board manual says, 26MHz oscillator present on board. + * U-Boot divides the sys_clock by 2 if sys_clk is >19MHz, + * so,we have sys_clk frequency = 13MHz + * + * TIMER_FCLK = 13MHz + * So, for 1ms period, TLDR = 0xffffcd38 + * + */ + timer_load(timer_base, 0xffffcd38); + + /* Clear pending Interrupts, if any */ + write(7, timer_base + OMAP_TIMER_TISR); + + /* Enable inteerupts */ + write((1 << OMAP_TIMER_INTR_OVERFLOW), timer_base + OMAP_TIMER_TIER); +} + +void timer_init(unsigned long timer_base) +{ + timer_init_periodic(timer_base); +} diff --git a/src/drivers/timer/sp804/SConscript b/src/drivers/timer/sp804/SConscript new file mode 100644 index 0000000..c69a25c --- /dev/null +++ b/src/drivers/timer/sp804/SConscript @@ -0,0 +1,7 @@ +Import('env') + +# The set of source files associated with this SConscript file. +src_local = ['timer.c'] +obj = env.Object(src_local) + +Return('obj') diff --git a/src/drivers/timer/sp804/timer.c b/src/drivers/timer/sp804/timer.c new file mode 100644 index 0000000..ae549da --- /dev/null +++ b/src/drivers/timer/sp804/timer.c @@ -0,0 +1,78 @@ +/* + * SP804 primecell driver honoring generic + * timer library API + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include INC_ARCH(io.h) +#include + +unsigned long timer_secondary_base(unsigned long timer_base) +{ + return timer_base + SP804_SECONDARY_OFFSET; +} + +void timer_irq_clear(unsigned long timer_base) +{ + write(1, timer_base + SP804_INTCLR); +} + +/* Enable timer with its current configuration */ +void timer_start(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + SP804_CTRL); + + reg |= SP804_ENABLE; + + write(reg, timer_base + SP804_CTRL); + +} + +/* Load the timer with ticks value */ +void timer_load(u32 loadval, unsigned long timer_base) +{ + write(loadval, timer_base + SP804_LOAD); +} + +u32 timer_read(unsigned long timer_base) +{ + return read(timer_base + SP804_VALUE); +} + +void timer_stop(unsigned long timer_base) +{ + write(0, timer_base + SP804_CTRL); +} + +void timer_init_periodic(unsigned long timer_base, unsigned int load_value) +{ + volatile u32 reg; + + /* Periodic, wraparound, 32 bit, irq on wraparound */ + reg = SP804_PERIODIC | SP804_32BIT | SP804_IRQEN; + + write(reg, timer_base + SP804_CTRL); + + /* 1 tick per usec, 1 irq per msec */ + if (load_value) + timer_load(load_value, timer_base); + else + timer_load(1000, timer_base); +} + +void timer_init_oneshot(unsigned long timer_base) +{ + volatile u32 reg = read(timer_base + SP804_CTRL); + + /* One shot, 32 bits, no irqs */ + reg |= SP804_32BIT | SP804_ONESHOT; + + write(reg, timer_base + SP804_CTRL); +} + +void timer_init(unsigned long timer_base, unsigned int load_value) +{ + timer_init_periodic(timer_base, load_value); +} diff --git a/src/drivers/uart/omap/SConscript b/src/drivers/uart/omap/SConscript new file mode 100644 index 0000000..84c1a71 --- /dev/null +++ b/src/drivers/uart/omap/SConscript @@ -0,0 +1,7 @@ +Import('env') + +# The set of source files associated with this SConscript file. +src_local = ['uart.c'] +obj = env.Object(src_local) + +Return('obj') diff --git a/src/drivers/uart/omap/uart.c b/src/drivers/uart/omap/uart.c new file mode 100644 index 0000000..3d8346c --- /dev/null +++ b/src/drivers/uart/omap/uart.c @@ -0,0 +1,214 @@ +/* + * UART driver used by OMAP devices + * + * Copyright (C) 2007 Bahadir Balban + */ + +#include +#include INC_ARCH(io.h) + +#define OMAP_UART_FIFO_ENABLE (1 << 0) +#define OMAP_UART_RX_FIFO_CLR (1 << 1) +#define OMAP_UART_TX_FIFO_CLR (1 << 2) +static inline void uart_enable_fifo(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_FCR); + reg |= (OMAP_UART_FIFO_ENABLE | OMAP_UART_RX_FIFO_CLR | + OMAP_UART_TX_FIFO_CLR); + write(reg, uart_base + OMAP_UART_FCR); +} + +static inline void uart_disable_fifo(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_FCR); + reg &= (~OMAP_UART_FIFO_ENABLE | OMAP_UART_RX_FIFO_CLR | + OMAP_UART_TX_FIFO_CLR); + write(reg, uart_base + OMAP_UART_FCR); +} + +#define OMAP_UART_TX_ENABLE (1 << 0) +static inline void uart_enable_tx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg |= OMAP_UART_TX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); +} + +static inline void uart_disable_tx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg &= ~OMAP_UART_TX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); + +} + +#define OMAP_UART_RX_ENABLE (1 << 1) +static inline void uart_enable_rx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg |= OMAP_UART_RX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); +} + +static inline void uart_disable_rx(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_MCR); + reg &= ~OMAP_UART_RX_ENABLE; + write(reg, uart_base + OMAP_UART_MCR); +} + +#define OMAP_UART_STOP_BITS_MASK (1 << 2) +static inline void uart_set_stop_bits(unsigned long uart_base, int bits) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_STOP_BITS_MASK; + reg |= (bits << 2); + write(reg, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_DATA_BITS_MASK (0x3) +static inline void uart_set_data_bits(unsigned long uart_base, int bits) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_DATA_BITS_MASK; + reg |= bits; + write(reg, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_PARITY_ENABLE (1 << 3) +static inline void uart_enable_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg |= OMAP_UART_PARITY_ENABLE; + write(reg, uart_base + OMAP_UART_LCR); +} + +static inline void uart_disable_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_PARITY_ENABLE; + write(reg, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_PARITY_EVEN (1 << 4) +static inline void uart_set_even_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg |= OMAP_UART_PARITY_EVEN; + write(reg, uart_base + OMAP_UART_LCR); +} + +static inline void uart_set_odd_parity(unsigned long uart_base) +{ + volatile u32 reg = read(uart_base + OMAP_UART_LCR); + reg &= ~OMAP_UART_PARITY_EVEN; + write(reg, uart_base + OMAP_UART_LCR); +} + +static inline void uart_select_mode(unsigned long uart_base, int mode) +{ + write(mode, uart_base + OMAP_UART_MDR1); +} + +#define OMAP_UART_INTR_EN 1 +static inline void uart_enable_interrupt(unsigned long uart_base) +{ + write(OMAP_UART_INTR_EN, uart_base + OMAP_UART_IER); +} + +static inline void uart_disable_interrupt(unsigned long uart_base) +{ + write((~OMAP_UART_INTR_EN), uart_base + OMAP_UART_IER); +} + +static inline void uart_set_link_control(unsigned long uart_base, int mode) +{ + write(mode, uart_base + OMAP_UART_LCR); +} + +#define OMAP_UART_TXFE 0x20 +void uart_tx_char(unsigned long uart_base, char c) +{ + volatile u32 reg; + + /* Check if there is space for tx */ + do { + reg = read(uart_base + OMAP_UART_LSR); + } while(!(reg & OMAP_UART_TXFE)); + + write(c, uart_base + OMAP_UART_THR); +} + +#define OMAP_UART_RXFNE 0x1 +#define OMAP_UART_RX_FIFO_STATUS 0x8 +char uart_rx_char(unsigned long uart_base) +{ + volatile u32 reg; + + /* Check if pending data is there */ + do { + reg = read(uart_base + OMAP_UART_LSR); + } while(!(reg & OMAP_UART_RXFNE)); + +#if 0 + /* Check if there is some error in recieve */ + if(reg & OMAP_UART_RX_FIFO_STATUS) + return -1; +#endif + + return (char)read(uart_base + OMAP_UART_RHR); +} + +void uart_set_baudrate(unsigned long uart_base, u32 baudrate, u32 clkrate) +{ + u32 clk_div = 0; + + /* 48Mhz clock fixed on beagleboard */ + const u32 uartclk = 48000000; + + if(clkrate == 0) + clkrate = uartclk; + + /* If baud out of range, set default rate */ + if(baudrate > 3686400 || baudrate < 300) + baudrate = 115200; + + clk_div = clkrate/(16 * baudrate); + + /* Set clockrate in DLH and DLL */ + write((clk_div & 0xff), uart_base + OMAP_UART_DLL); + write(((clk_div >> 8) & 0xff ), uart_base + OMAP_UART_DLH); +} + +void uart_init(unsigned long uart_base) +{ + /* Disable UART */ + uart_select_mode(uart_base, OMAP_UART_MODE_DEFAULT); + + /* Disable interrupts */ + uart_disable_interrupt(uart_base); + + /* Change to config mode, to set baud divisor */ + uart_set_link_control(uart_base, OMAP_UART_BANKED_MODE_CONFIG_A); + + /* Set the baud rate */ + uart_set_baudrate(uart_base, 115200, 48000000); + + /* Switch to operational mode */ + uart_set_link_control(uart_base, OMAP_UART_BANKED_MODE_OPERATIONAL); + + /* Set up the link- parity, data bits stop bits to 8N1 */ + uart_disable_parity(uart_base); + uart_set_data_bits(uart_base, OMAP_UART_DATA_BITS_8); + uart_set_stop_bits(uart_base, OMAP_UART_STOP_BITS_1); + + /* Disable Fifos */ + uart_disable_fifo(uart_base); + + /* Enable modem Rx/Tx */ + uart_enable_tx(uart_base); + uart_enable_rx(uart_base); + + /* Enable UART in 16x mode */ + uart_select_mode(uart_base, OMAP_UART_MODE_UART16X); +} diff --git a/src/drivers/uart/pl011/SConscript b/src/drivers/uart/pl011/SConscript new file mode 100644 index 0000000..84c1a71 --- /dev/null +++ b/src/drivers/uart/pl011/SConscript @@ -0,0 +1,7 @@ +Import('env') + +# The set of source files associated with this SConscript file. +src_local = ['uart.c'] +obj = env.Object(src_local) + +Return('obj') diff --git a/src/drivers/uart/pl011/uart.c b/src/drivers/uart/pl011/uart.c new file mode 100644 index 0000000..307dadc --- /dev/null +++ b/src/drivers/uart/pl011/uart.c @@ -0,0 +1,298 @@ +/* + * PL011 UART driver + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include INC_ARCH(io.h) + +/* Error status bits in receive status register */ +#define PL011_FE (1 << 0) +#define PL011_PE (1 << 1) +#define PL011_BE (1 << 2) +#define PL011_OE (1 << 3) + +/* Status bits in flag register */ +#define PL011_TXFE (1 << 7) +#define PL011_RXFF (1 << 6) +#define PL011_TXFF (1 << 5) +#define PL011_RXFE (1 << 4) +#define PL011_BUSY (1 << 3) +#define PL011_DCD (1 << 2) +#define PL011_DSR (1 << 1) +#define PL011_CTS (1 << 0) + +#define PL011_UARTEN (1 << 0) +static inline void pl011_uart_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val |= PL011_UARTEN; + write(val, (base + PL011_UARTCR)); + + return; +} + +static inline void pl011_uart_disable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val &= ~PL011_UARTEN; + write(val, (base + PL011_UARTCR)); + + return; +} + +#define PL011_TXE (1 << 8) +static inline void pl011_tx_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val |= PL011_TXE; + write(val, (base + PL011_UARTCR)); + return; +} + +static inline void pl011_tx_disable(unsigned long base) +{ + unsigned int val = 0; + + val =read((base + PL011_UARTCR)); + val &= ~PL011_TXE; + write(val, (base + PL011_UARTCR)); + return; +} + +#define PL011_RXE (1 << 9) +static inline void pl011_rx_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val |= PL011_RXE; + write(val, (base + PL011_UARTCR)); + return; +} + +static inline void pl011_rx_disable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTCR)); + val &= ~PL011_RXE; + write(val, (base + PL011_UARTCR)); + return; +} + +#define PL011_TWO_STOPBITS_SELECT (1 << 3) +static inline void pl011_set_stopbits(unsigned long base, int stopbits) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + + if(stopbits == 2) { /* Set to two bits */ + val |= PL011_TWO_STOPBITS_SELECT; + } else { /* Default is 1 */ + val &= ~PL011_TWO_STOPBITS_SELECT; + } + write(val, (base + PL011_UARTLCR_H)); + return; +} + +#define PL011_PARITY_ENABLE (1 << 1) +static inline void pl011_parity_enable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base +PL011_UARTLCR_H)); + val |= PL011_PARITY_ENABLE; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +static inline void pl011_parity_disable(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val &= ~PL011_PARITY_ENABLE; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +#define PL011_PARITY_EVEN (1 << 2) +static inline void pl011_set_parity_even(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val |= PL011_PARITY_EVEN; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +static inline void pl011_set_parity_odd(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val &= ~PL011_PARITY_EVEN; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +#define PL011_ENABLE_FIFOS (1 << 4) +static inline void pl011_enable_fifos(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val |= PL011_ENABLE_FIFOS; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +static inline void pl011_disable_fifos(unsigned long base) +{ + unsigned int val = 0; + + val = read((base + PL011_UARTLCR_H)); + val &= ~PL011_ENABLE_FIFOS; + write(val, (base + PL011_UARTLCR_H)); + return; +} + +/* Sets the transfer word width for the data register. */ +static inline void pl011_set_word_width(unsigned long base, int size) +{ + unsigned int val = 0; + if(size < 5 || size > 8) /* Default is 8 */ + size = 8; + + /* Clear size field */ + val = read((base + PL011_UARTLCR_H)); + val &= ~(0x3 << 5); + write(val, (base + PL011_UARTLCR_H)); + + /* + * The formula is to write 5 less of size given: + * 11 = 8 bits + * 10 = 7 bits + * 01 = 6 bits + * 00 = 5 bits + */ + val = read((base + PL011_UARTLCR_H)); + val |= (size - 5) << 5; + write(val, (base + PL011_UARTLCR_H)); + + return; +} + +/* + * Defines at which level of fifo fullness an irq will be generated. + * @xfer: tx fifo = 0, rx fifo = 1 + * @level: Generate irq if: + * 0 rxfifo >= 1/8 full txfifo <= 1/8 full + * 1 rxfifo >= 1/4 full txfifo <= 1/4 full + * 2 rxfifo >= 1/2 full txfifo <= 1/2 full + * 3 rxfifo >= 3/4 full txfifo <= 3/4 full + * 4 rxfifo >= 7/8 full txfifo <= 7/8 full + * 5-7 reserved reserved + */ +static inline void pl011_set_irq_fifolevel(unsigned long base, \ + unsigned int xfer, unsigned int level) +{ + if(xfer != 1 && xfer != 0) /* Invalid fifo */ + return; + if(level > 4) /* Invalid level */ + return; + + write(level << (xfer * 3), (base + PL011_UARTIFLS)); + return; +} + +void uart_tx_char(unsigned long base, char c) +{ + unsigned int val = 0; + + do { + val = read((base + PL011_UARTFR)); + } while (val & PL011_TXFF); /* TX FIFO FULL */ + + write(c, (base + PL011_UARTDR)); +} + +char uart_rx_char(unsigned long base) +{ + unsigned int val = 0; + + do { + val = read(base + PL011_UARTFR); + } while (val & PL011_RXFE); /* RX FIFO Empty */ + + return (char)read((base + PL011_UARTDR)); +} + +/* + * Sets the baud rate in kbps. It is recommended to use + * standard rates such as: 1200, 2400, 3600, 4800, 7200, + * 9600, 14400, 19200, 28800, 38400, 57600 76800, 115200. + */ +void pl011_set_baudrate(unsigned long base, unsigned int baud, + unsigned int clkrate) +{ + const unsigned int uartclk = 24000000; /* 24Mhz clock fixed on pb926 */ + unsigned int val = 0, ipart = 0, fpart = 0; + + /* Use default pb926 rate if no rate is supplied */ + if (clkrate == 0) + clkrate = uartclk; + if (baud > 115200 || baud < 1200) + baud = 38400; /* Default rate. */ + + /* 24000000 / (38400 * 16) */ + ipart = 39; + + write(ipart, base + PL011_UARTIBRD); + write(fpart, base + PL011_UARTFBRD); + + /* + * For the IBAUD and FBAUD to update, we need to + * write to UARTLCR_H because the 3 registers are + * actually part of a single register in hardware + * which only updates by a write to UARTLCR_H + */ + val = read(base + PL011_UARTLCR_H); + write(val, base + PL011_UARTLCR_H); + +} + +void uart_init(unsigned long uart_base) +{ + /* Initialise data register for 8 bit data read/writes */ + pl011_set_word_width(uart_base, 8); + + /* + * Fifos are disabled because by default it is assumed the port + * will be used as a user terminal, and in that case the typed + * characters will only show up when fifos are flushed, rather than + * when each character is typed. We avoid this by not using fifos. + */ + pl011_disable_fifos(uart_base); + + /* Set default baud rate of 38400 */ + pl011_set_baudrate(uart_base, 38400, 24000000); + + /* Set default settings of 1 stop bit, no parity, no hw flow ctrl */ + pl011_set_stopbits(uart_base, 1); + pl011_parity_disable(uart_base); + + /* Enable rx, tx, and uart chip */ + pl011_tx_enable(uart_base); + pl011_rx_enable(uart_base); + pl011_uart_enable(uart_base); +} diff --git a/src/generic/SConscript b/src/generic/SConscript index 62cecca..3366d42 100644 --- a/src/generic/SConscript +++ b/src/generic/SConscript @@ -4,7 +4,7 @@ Import('env') # The set of source files associated with this SConscript file. -src_local = ['irq.c', 'scheduler.c', 'time.c', 'tcb.c', 'space.c', 'bootmem.c', 'resource.c', 'container.c', 'capability.c', 'cinfo.c'] +src_local = ['irq.c', 'scheduler.c', 'time.c', 'tcb.c', 'space.c', 'bootmem.c', 'resource.c', 'container.c', 'capability.c', 'cinfo.c', 'debug.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/generic/bootmem.c b/src/generic/bootmem.c index a3771ee..85462fd 100644 --- a/src/generic/bootmem.c +++ b/src/generic/bootmem.c @@ -15,10 +15,8 @@ * Increase this size if bootmem allocations fail. */ #define BOOTMEM_SIZE (SZ_4K * 4) - -SECTION(".init.pgd") pgd_table_t init_pgd; SECTION(".init.bootmem") char bootmem[BOOTMEM_SIZE]; -__initdata struct address_space init_space; +struct address_space init_space; static unsigned long cursor = (unsigned long)&bootmem; diff --git a/src/generic/capability.c b/src/generic/capability.c index 360131b..6044015 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -16,6 +16,7 @@ #include #include #include +#include #include INC_GLUE(message.h) #include INC_GLUE(ipc.h) @@ -584,6 +585,7 @@ struct capability *cap_match_mem(struct capability *cap, { struct sys_map_args *args = args_ptr; struct ktcb *target = args->task; + unsigned long long start, end, pfn_point; unsigned long pfn; unsigned int perms; @@ -593,27 +595,45 @@ struct capability *cap_match_mem(struct capability *cap, else pfn = __pfn(args->virt); - /* Check range */ - if (cap->start > pfn || cap->end < pfn + args->npages) + /* Long long range check to avoid overflow */ + start = cap->start; + end = cap->end; + pfn_point = pfn; + if (start > pfn_point || cap->end < pfn_point + args->npages) return 0; /* Check permissions */ switch (args->flags) { - case MAP_USR_RW_FLAGS: + case MAP_USR_RW: perms = CAP_MAP_READ | CAP_MAP_WRITE | CAP_MAP_CACHED; if ((cap->access & perms) != perms) return 0; break; - case MAP_USR_RO_FLAGS: + case MAP_USR_RWX: + perms = CAP_MAP_READ | CAP_MAP_WRITE | + CAP_MAP_EXEC | CAP_MAP_CACHED; + if ((cap->access & perms) != perms) + return 0; + break; + case MAP_USR_RO: perms = CAP_MAP_READ | CAP_MAP_CACHED; if ((cap->access & perms) != perms) return 0; break; - case MAP_USR_IO_FLAGS: + case MAP_USR_RX: + perms = CAP_MAP_READ | CAP_MAP_EXEC | CAP_MAP_CACHED; + if ((cap->access & perms) != perms) + return 0; + break; + case MAP_USR_IO: perms = CAP_MAP_READ | CAP_MAP_WRITE | CAP_MAP_UNCACHED; if ((cap->access & perms) != perms) return 0; break; + case MAP_UNMAP: /* Check for unmap syscall */ + if (!(cap->access & CAP_MAP_UNMAP)) + return 0; + break; default: /* Anything else is an invalid/unrecognised argument */ return 0; @@ -726,6 +746,10 @@ struct capability *cap_match_irqctrl(struct capability *cap, if (!(cap->access & CAP_IRQCTRL_REGISTER)) return 0; break; + case IRQ_CONTROL_WAIT: + if (!(cap->access & CAP_IRQCTRL_WAIT)) + return 0; + break; default: /* We refuse to accept anything else */ return 0; @@ -756,6 +780,53 @@ struct capability *cap_match_irqctrl(struct capability *cap, return cap; } + +struct sys_cache_args { + unsigned long start; + unsigned long npages; + unsigned int flags; +}; + +struct capability *cap_match_cache(struct capability *cap, void *args_ptr) +{ + struct sys_cache_args *args = args_ptr; + unsigned long pfn = __pfn(args->start); + unsigned long long start, end, pfn_point; + unsigned int perms; + + /* Long long range check to avoid overflow */ + start = cap->start; + end = cap->end; + pfn_point = pfn; + if (start > pfn_point || end < pfn_point + args->npages) + return 0; + + /* Check permissions */ + switch (args->flags) { + /* check for cache functionality flags */ + case L4_INVALIDATE_DCACHE: + case L4_INVALIDATE_ICACHE: + case L4_INVALIDATE_TLB: + perms = CAP_CACHE_INVALIDATE; + if ((cap->access & perms) != perms) + return 0; + break; + + case L4_CLEAN_DCACHE: + case L4_CLEAN_INVALIDATE_DCACHE: + perms = CAP_CACHE_CLEAN; + if ((cap->access & perms) != perms) + return 0; + break; + + default: + /* Anything else is an invalid/unrecognised argument */ + return 0; + } + + return cap; +} + #if defined(CONFIG_CAPABILITIES) int cap_mutex_check(unsigned long mutex_address, int mutex_op) { @@ -809,6 +880,26 @@ int cap_map_check(struct ktcb *target, unsigned long phys, unsigned long virt, return 0; } +int cap_unmap_check(struct ktcb *target, unsigned long virt, + unsigned long npages) +{ + struct capability *virtmem; + + /* Unmap check also uses identical struct as map check */ + struct sys_map_args args = { + .task = target, + .virt = virt, + .npages = npages, + .flags = MAP_UNMAP, + }; + + if (!(virtmem = cap_find(current, cap_match_mem, + &args, CAP_TYPE_MAP_VIRTMEM))) + return -ENOCAP; + + return 0; +} + /* * Limitation: We currently only check from sender's * perspective. This is because sender always targets a @@ -892,16 +983,40 @@ int cap_irq_check(struct ktcb *registrant, unsigned int req, return -ENOCAP; /* - * Find the device capability and - * check that it allows irq registration + * If it is an irq registration, find the device + * capability and check that it allows irq registration. */ - if (!(cap_find(current, cap_match_devmem, - &args, CAP_TYPE_MAP_PHYSMEM))) - return -ENOCAP; - + if (req == IRQ_CONTROL_REGISTER) + if (!cap_find(current, cap_match_devmem, + &args, CAP_TYPE_MAP_PHYSMEM)) + return -ENOCAP; return 0; } +/* + * This is just a wrapper call for l4_cache_control + * system call sanity check + */ +int cap_cache_check(unsigned long start, unsigned long end, unsigned int flags) +{ + struct capability *virtmem; + struct sys_cache_args args = { + .start = start, + .npages = __pfn(end) - __pfn(start), + .flags = flags, + }; + + /* + * We just want to check if the virtual memory region + * concerned here has + * appropriate permissions for cache calls + */ + if (!(virtmem = cap_find(current, cap_match_cache, + &args, CAP_TYPE_MAP_VIRTMEM))) + return -ENOCAP; + + return 0; +} #else /* Meaning !CONFIG_CAPABILITIES */ int cap_mutex_check(unsigned long mutex_address, int mutex_op) @@ -926,6 +1041,12 @@ int cap_map_check(struct ktcb *task, unsigned long phys, unsigned long virt, return 0; } +int cap_unmap_check(struct ktcb *target, unsigned long virt, + unsigned long npages) +{ + return 0; +} + int cap_exregs_check(struct ktcb *task, struct exregs_data *exregs) { return 0; @@ -944,4 +1065,9 @@ int cap_irq_check(struct ktcb *registrant, unsigned int req, return 0; } +int cap_cache_check(unsigned long start, unsigned long end, + unsigned int flags) +{ + return 0; +} #endif /* End of !CONFIG_CAPABILITIES */ diff --git a/src/generic/container.c b/src/generic/container.c index 33774c1..a4d39da 100644 --- a/src/generic/container.c +++ b/src/generic/container.c @@ -8,8 +8,10 @@ #include #include #include +#include #include #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) #include INC_SUBARCH(mm.h) #include INC_ARCH(linker.h) @@ -83,22 +85,16 @@ struct container *container_find(struct kernel_resources *kres, l4id_t cid) * This involves setting up pager's ktcb, space, utcb, * all ids, registers, and mapping its (perhaps) first * few pages in order to make it runnable. - * - * The first pager initialization is a special-case - * since it uses the current kernel pgd. */ -int init_pager(struct pager *pager, - struct container *cont, - pgd_table_t *current_pgd) +int init_pager(struct pager *pager, struct container *cont) { struct ktcb *task; struct address_space *space; - int first = !!current_pgd; /* * Set up dummy current cap_list so that cap accounting * can be done to this pager. Note, that we're still on - * bootstack. + * idle task stack. */ cap_list_move(¤t->cap_list, &pager->cap_list); @@ -108,25 +104,8 @@ int init_pager(struct pager *pager, /* New ktcb allocation is needed */ task = tcb_alloc_init(cont->cid); - /* If first, manually allocate/initalize space */ - if (first) { - if (!(space = alloc_space())) - return -ENOMEM; - - /* Set up space id */ - space->spid = id_new(&kernel_resources.space_ids); - - /* Initialize space structure */ - link_init(&space->list); - mutex_init(&space->lock); - cap_list_init(&space->cap_list); - space->pgd = current_pgd; - address_space_attach(task, space); - } else { - /* Otherwise allocate conventionally */ - space = address_space_create(0); - address_space_attach(task, space); - } + space = address_space_create(0); + address_space_attach(task, space); /* Initialize ktcb */ task_init_registers(task, pager->start_address); @@ -136,6 +115,9 @@ int init_pager(struct pager *pager, task->tgid = task->tid; task->container = cont; + /* Set cpu affinity */ + thread_setup_affinity(task); + /* Add the address space to container space list */ address_space_add(task->space); @@ -148,7 +130,7 @@ int init_pager(struct pager *pager, /* Map the task's space */ add_mapping_pgd(pager->start_lma, pager->start_vma, page_align_up(pager->memsize), - MAP_USR_DEFAULT_FLAGS, TASK_PGD(task)); + MAP_USR_RWX, TASK_PGD(task)); /* Move capability list from dummy to task's space cap list */ cap_list_move(&task->space->cap_list, ¤t->cap_list); @@ -162,6 +144,7 @@ int init_pager(struct pager *pager, /* Container list that keeps all tasks */ tcb_add(task); + return 0; } @@ -256,24 +239,15 @@ int update_dynamic_capids(struct kernel_resources *kres) * Initialize all containers with their initial set of tasks, * spaces, scheduler parameters such that they can be started. */ -int container_init_pagers(struct kernel_resources *kres, - pgd_table_t *current_pgd) +int container_init_pagers(struct kernel_resources *kres) { struct container *cont; struct pager *pager; - int first = 1; list_foreach_struct(cont, &kres->containers.list, list) { for (int i = 0; i < cont->npagers; i++) { pager = &cont->pager[i]; - - /* First pager initializes specially */ - if (first) { - init_pager(pager, cont, current_pgd); - first = 0; - } else { - init_pager(pager, cont, 0); - } + init_pager(pager, cont); } } diff --git a/src/generic/debug.c b/src/generic/debug.c new file mode 100644 index 0000000..21acbc8 --- /dev/null +++ b/src/generic/debug.c @@ -0,0 +1,126 @@ +/* + * Basic debug information about the kernel + * + * Copyright (C) 2010 B Labs Ltd. + * + * Written by Bahadir Balban + */ +#include +#include +#include INC_SUBARCH(cpu.h) +#include + +#if defined (CONFIG_DEBUG_ACCOUNTING) + +struct system_accounting system_accounting; + +void system_accounting_print(struct system_accounting *sys_acc) +{ + printk("System Operations Accounting:\n\n"); + + printk("System calls:\n"); + printk("=============\n"); + printk("IPC: %llu\n", sys_acc->syscalls.ipc); + printk("Thread Switch: %llu\n", sys_acc->syscalls.tswitch); + printk("Thread Control: %llu\n", sys_acc->syscalls.tctrl); + printk("Exchange Registers: %llu\n", sys_acc->syscalls.exregs); + printk("Unmap: %llu\n", sys_acc->syscalls.unmap); + printk("Irq Control: %llu\n", sys_acc->syscalls.irqctrl); + printk("Map: %llu\n", sys_acc->syscalls.map); + printk("Getid: %llu\n", sys_acc->syscalls.getid); + printk("Capability Control: %llu\n", sys_acc->syscalls.capctrl); + printk("Time: %llu\n", sys_acc->syscalls.time); + printk("Mutex Control: %llu\n", sys_acc->syscalls.mutexctrl); + printk("Cache Control: %llu\n", sys_acc->syscalls.cachectrl); + + printk("\nExceptions:\n"); + printk("===========\n"); + printk("System call: %llu\n", sys_acc->exceptions.syscall); + printk("Data Abort: %llu\n", sys_acc->exceptions.data_abort); + printk("Prefetch Abort: %llu\n", sys_acc->exceptions.prefetch_abort); + printk("Irq: %llu\n", sys_acc->exceptions.irq); + printk("Undef Abort: %llu\n", sys_acc->exceptions.undefined_abort); + printk("Context Switch: %llu\n", sys_acc->task_ops.context_switch); + printk("Space Switch: %llu\n", sys_acc->task_ops.space_switch); + + printk("\nCache operations:\n"); + +} +#endif + + +/* + * For spinlock debugging + */ +#if defined (CONFIG_DEBUG_SPINLOCKS) + +#include + +#define DEBUG_SPINLOCK_TOTAL 10 + +DECLARE_PERCPU(static unsigned long, held_lock_array[DEBUG_SPINLOCK_TOTAL]); +DECLARE_PERCPU(static u32, held_lock_bitmap); + +void spin_lock_record_check(void *lock_addr) +{ + int bit = 0; + + /* + * Check if we already hold this lock + */ + for (int i = 0; i < DEBUG_SPINLOCK_TOTAL; i++) { + if (per_cpu(held_lock_array[i]) == (unsigned long)lock_addr) { + print_early("Spinlock already held.\n"); + printk("lock_addr=%p\n", lock_addr); + BUG(); + } + } + + /* + * Add it as a new lock + */ + bit = find_and_set_first_free_bit(&per_cpu(held_lock_bitmap), + DEBUG_SPINLOCK_TOTAL); + per_cpu(held_lock_array[bit]) = (unsigned long)lock_addr; +} + +void spin_unlock_delete_check(void *lock_addr) +{ + /* + * Check if already unlocked + */ + if (*((unsigned int *)lock_addr) == 0) { + print_early("Spinlock already unlocked."); + BUG(); + } + + /* + * Search for the value + */ + for (int i = 0; i < DEBUG_SPINLOCK_TOTAL; i++) { + if (per_cpu(held_lock_array[i]) == (unsigned long)lock_addr) { + /* + * Delete its entry + */ + per_cpu(held_lock_array[i]) = 0; + BUG_ON(check_and_clear_bit(&per_cpu(held_lock_bitmap), + i) < 0); + return; + } + } + /* + * It must have been recorded + */ + BUG(); +} + +#endif + + + + + + + + + diff --git a/src/generic/irq.c b/src/generic/irq.c index 04dfaa2..4eac287 100644 --- a/src/generic/irq.c +++ b/src/generic/irq.c @@ -1,42 +1,54 @@ /* - * Kernel irq handling (core irqs like timer). - * Also thread-level irq handling. + * Generic kernel irq handling. * * Copyright (C) 2007 - 2009 Bahadir Balban */ #include #include #include +#include #include #include #include #include #include +#include #include INC_PLAT(irq.h) #include INC_ARCH(exception.h) /* * Registers a userspace thread as an irq handler. + * + * A userspace irq thread should have a low-level, device-specific + * irq handler as an in-kernel counterpart. This and its irq chip + * must have been set up at compile-time. These handlers should + * also know how to notify their userspace threads. + * + * If the irq does not have these set up, we cannot allow + * the irq registry. */ -int irq_register(struct ktcb *task, int notify_slot, - l4id_t irq_index, irq_handler_t handler) +int irq_register(struct ktcb *task, int notify_slot, l4id_t irq_index) { struct irq_desc *this_desc = irq_desc_array + irq_index; - struct irq_chip *current_chip = irq_chip_array; - for (int i = 0; i < IRQ_CHIPS_MAX; i++) { - if (irq_index >= current_chip->start && - irq_index < current_chip->end) { - this_desc->chip = current_chip; - break; - } - } - /* Setup the handler */ - this_desc->handler = handler; + /* Kernel counterpart not set up, don't allow */ + if (!this_desc->handler || !this_desc->chip) + return -ENOIRQ; - /* Setup the slot to notify the task */ + /* Index must be valid */ + if (irq_index > IRQS_MAX || irq_index < 0) + return -ENOIRQ; + + /* Setup the task and notify slot */ + this_desc->task = task; this_desc->task_notify_slot = notify_slot; + /* Setup irq desc waitqueue */ + waitqueue_head_init(&this_desc->wqh_irq); + + /* Enable the irq */ + irq_enable(irq_index); + return 0; } @@ -46,7 +58,8 @@ static inline void cascade_irq_chip(struct irq_chip *this_chip) { if (this_chip->cascade >= 0) { BUG_ON(IRQ_CHIPS_MAX == 1); - this_chip->ops.unmask(this_chip->cascade); + if(this_chip->ops.unmask) + this_chip->ops.unmask(this_chip->cascade); } } @@ -58,7 +71,8 @@ void irq_controllers_init(void) this_chip = irq_chip_array + i; /* Initialise the irq chip (e.g. reset all registers) */ - this_chip->ops.init(); + if (this_chip->ops.init) + this_chip->ops.init(); /* Enable cascaded irq on this chip if it exists */ cascade_irq_chip(this_chip); @@ -87,8 +101,10 @@ l4id_t global_irq_index(void) this_chip = irq_chip_array + i; /* Find local irq that is triggered on this chip */ - BUG_ON((irq_index = - this_chip->ops.read_irq()) == IRQ_NIL); + if (this_chip->ops.read_irq) { + irq_index = this_chip->ops.read_irq(this_chip->data); + BUG_ON(irq_index == IRQ_NIL); + } /* See if this irq is a cascaded irq */ if (irq_index == this_chip->cascade) @@ -116,6 +132,8 @@ void do_irq(void) l4id_t irq_index = global_irq_index(); struct irq_desc *this_irq = irq_desc_array + irq_index; + system_account_irq(); + /* * Note, this can be easily done a few instructions * quicker by some immediate read/disable/enable_all(). diff --git a/src/generic/resource.c b/src/generic/resource.c index 2060032..2de8dba 100644 --- a/src/generic/resource.c +++ b/src/generic/resource.c @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) #include INC_ARCH(linker.h) #include INC_PLAT(platform.h) #include @@ -132,22 +134,28 @@ void free_pmd(void *addr) BUG_ON(mem_cache_free(kernel_resources.pmd_cache, addr) < 0); } -void free_space(void *addr) +void free_space(void *addr, struct ktcb *task) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current, + BUG_ON(!(cap = capability_find_by_rtype(task, CAP_RTYPE_SPACEPOOL))); capability_free(cap, 1); BUG_ON(mem_cache_free(kernel_resources.space_cache, addr) < 0); } -void free_ktcb(void *addr) + +/* + * Account it to pager, but if it doesn't exist, + * to current idle task + */ +void free_ktcb(void *addr, struct ktcb *acc_task) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current, + /* Account it to task's pager if it exists */ + BUG_ON(!(cap = capability_find_by_rtype(acc_task, CAP_RTYPE_THREADPOOL))); capability_free(cap, 1); @@ -449,8 +457,8 @@ void init_kernel_resources(struct kernel_resources *kres) /* Set up total physical memory as single capability */ physmem = alloc_bootmem(sizeof(*physmem), 0); - physmem->start = __pfn(PHYS_MEM_START); - physmem->end = __pfn(PHYS_MEM_END); + physmem->start = __pfn(PLATFORM_PHYS_MEM_START); + physmem->end = __pfn(PLATFORM_PHYS_MEM_END); link_init(&physmem->list); cap_list_insert(physmem, &kres->physmem_free); @@ -599,14 +607,7 @@ void setup_kernel_resources(struct boot_resources *bootres, { struct capability *cap; struct container *container; - pgd_table_t *current_pgd; - - /* - * See how many containers we have. Assign next - * unused container id for kernel resources - */ - kres->cid = id_get(&kres->container_ids, bootres->nconts + 1); - // kres->cid = id_get(&kres->container_ids, 0); // Gets id 0 + //pgd_table_t *current_pgd; /* First initialize the list of non-memory capabilities */ cap = boot_capability_create(); @@ -646,11 +647,34 @@ void setup_kernel_resources(struct boot_resources *bootres, * since we want to avoid allocating an uncertain * amount of memory from the boot allocators. */ - current_pgd = realloc_page_tables(); + // current_pgd = arch_realloc_page_tables(); /* Move it back */ cap_list_move(&kres->non_memory_caps, ¤t->cap_list); + + /* + * Setting up ids used internally. + * + * See how many containers we have. Assign next + * unused container id for kernel resources + */ + kres->cid = id_get(&kres->container_ids, bootres->nconts + 1); + // kres->cid = id_get(&kres->container_ids, 0); // Gets id 0 + + /* + * Assign thread and space ids to current which will later + * become the idle task + */ + current->tid = id_new(&kres->ktcb_ids); + current->space->spid = id_new(&kres->space_ids); + + /* + * Init per-cpu zombie lists + */ + for (int i = 0; i < CONFIG_NCPU; i++) + init_ktcb_list(&per_cpu_byid(kres->zombie_list, i)); + /* * Create real containers from compile-time created * cinfo structures @@ -667,8 +691,7 @@ void setup_kernel_resources(struct boot_resources *bootres, } /* Initialize pagers */ - container_init_pagers(kres, current_pgd); - + container_init_pagers(kres); } /* @@ -703,11 +726,11 @@ struct mem_cache *init_resource_cache(int nstruct, int struct_size, add_boot_mapping(__pfn_to_addr(cap->start), virtual, page_align_up(bufsize), - MAP_SVC_RW_FLAGS); + MAP_KERN_RW); } else { add_mapping_pgd(__pfn_to_addr(cap->start), virtual, page_align_up(bufsize), - MAP_SVC_RW_FLAGS, &init_pgd); + MAP_KERN_RW, &init_pgd); } /* Unmap area from memcap */ memcap_unmap_range(cap, &kres->physmem_free, @@ -791,12 +814,11 @@ void init_resource_allocators(struct boot_resources *bootres, kres, 0); /* Count boot pmds used so far and add them */ - bootres->nkpmds += pgd_count_pmds(&init_pgd); + bootres->nkpmds += pgd_count_boot_pmds(); /* - * Calculate maximum possible pmds - * that may be used during this pmd - * cache init and add them. + * Calculate maximum possible pmds that may be used + * during this pmd cache initialization and add them. */ bootres->nkpmds += ((bootres->npmds * PMD_SIZE) / PMD_MAP_SIZE); if (!is_aligned(bootres->npmds * PMD_SIZE, diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index 4f88fd2..8a50e8b 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -15,60 +15,71 @@ #include #include #include +#include #include #include #include #include #include INC_SUBARCH(mm.h) -#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(mapping.h) #include INC_GLUE(init.h) #include INC_PLAT(platform.h) #include INC_ARCH(exception.h) +#include INC_SUBARCH(irq.h) -struct scheduler scheduler; +DECLARE_PERCPU(struct scheduler, scheduler); /* This is incremented on each irq or voluntarily by preempt_disable() */ -extern unsigned int current_irq_nest_count; +DECLARE_PERCPU(extern unsigned int, current_irq_nest_count); /* This ensures no scheduling occurs after voluntary preempt_disable() */ -static int voluntary_preempt = 0; +DECLARE_PERCPU(static int, voluntary_preempt); - -void sched_lock_runqueues(void) +void sched_lock_runqueues(struct scheduler *sched, unsigned long *irqflags) { - spin_lock(&scheduler.sched_rq[0].lock); - spin_lock(&scheduler.sched_rq[1].lock); + spin_lock_irq(&sched->sched_rq[0].lock, irqflags); + spin_lock(&sched->sched_rq[1].lock); + BUG_ON(irqs_enabled()); } -void sched_unlock_runqueues(void) +void sched_unlock_runqueues(struct scheduler *sched, unsigned long irqflags) { - spin_unlock(&scheduler.sched_rq[0].lock); - spin_unlock(&scheduler.sched_rq[1].lock); + spin_unlock(&sched->sched_rq[1].lock); + spin_unlock_irq(&sched->sched_rq[0].lock, irqflags); } int preemptive() { - return current_irq_nest_count == 0; + return per_cpu(current_irq_nest_count) == 0; } int preempt_count() { - return current_irq_nest_count; + return per_cpu(current_irq_nest_count); } +#if !defined(CONFIG_PREEMPT_DISABLE) + void preempt_enable(void) { - voluntary_preempt--; - current_irq_nest_count--; + per_cpu(voluntary_preempt)--; + per_cpu(current_irq_nest_count)--; } /* A positive irq nest count implies current context cannot be preempted. */ void preempt_disable(void) { - current_irq_nest_count++; - voluntary_preempt++; + per_cpu(current_irq_nest_count)++; + per_cpu(voluntary_preempt)++; } +#else /* End of !CONFIG_PREEMPT_DISABLE */ + +void preempt_enable(void) { } +void preempt_disable(void) { } + +#endif /* CONFIG_PREEMPT_DISABLE */ + int in_irq_context(void) { /* @@ -76,50 +87,40 @@ int in_irq_context(void) * one more than all preempt_disable()'s which are * counted by voluntary_preempt. */ - return (current_irq_nest_count == (voluntary_preempt + 1)); + return (per_cpu(current_irq_nest_count) == + (per_cpu(voluntary_preempt) + 1)); } int in_nested_irq_context(void) { /* Deducing voluntary preemptions we get real irq nesting */ - return (current_irq_nest_count - voluntary_preempt) > 1; + return (per_cpu(current_irq_nest_count) - + per_cpu(voluntary_preempt)) > 1; } -int in_task_context(void) +int in_process_context(void) { return !in_irq_context(); } -/* - * In current implementation, if all task are asleep it is considered - * a bug. We use idle_task() to investigate. - * - * In the future, it will be natural that all tasks may be asleep, - * so this will change to something such as a Wait-for-Interrupt - * routine. - */ -void idle_task(void) +void sched_init_runqueue(struct scheduler *sched, struct runqueue *rq) { - printk("Idle task.\n"); - - while(1); -} - -void sched_init_runqueue(struct runqueue *rq) -{ - memset(rq, 0, sizeof(struct runqueue)); link_init(&rq->task_list); spin_lock_init(&rq->lock); + rq->sched = sched; } -void sched_init(struct scheduler *scheduler) +void sched_init() { - for (int i = 0; i < SCHED_RQ_TOTAL; i++) - sched_init_runqueue(&scheduler->sched_rq[i]); + struct scheduler *sched = &per_cpu(scheduler); - scheduler->rq_runnable = &scheduler->sched_rq[0]; - scheduler->rq_expired = &scheduler->sched_rq[1]; - scheduler->prio_total = TASK_PRIO_TOTAL; + for (int i = 0; i < SCHED_RQ_TOTAL; i++) + sched_init_runqueue(sched, &sched->sched_rq[i]); + + sched->rq_runnable = &sched->sched_rq[0]; + sched->rq_expired = &sched->sched_rq[1]; + sched->prio_total = TASK_PRIO_TOTAL; + sched->idle_task = current; } /* Swap runnable and expired runqueues. */ @@ -127,12 +128,12 @@ static void sched_rq_swap_runqueues(void) { struct runqueue *temp; - BUG_ON(list_empty(&scheduler.rq_expired->task_list)); + BUG_ON(list_empty(&per_cpu(scheduler).rq_expired->task_list)); /* Queues are swapped and expired list becomes runnable */ - temp = scheduler.rq_runnable; - scheduler.rq_runnable = scheduler.rq_expired; - scheduler.rq_expired = temp; + temp = per_cpu(scheduler).rq_runnable; + per_cpu(scheduler).rq_runnable = per_cpu(scheduler).rq_expired; + per_cpu(scheduler).rq_expired = temp; } /* Set policy on where to add tasks in the runqueue */ @@ -142,37 +143,46 @@ static void sched_rq_swap_runqueues(void) /* Helper for adding a new task to a runqueue */ static void sched_rq_add_task(struct ktcb *task, struct runqueue *rq, int front) { + unsigned long irqflags; + struct scheduler *sched = + &per_cpu_byid(scheduler, task->affinity); + BUG_ON(!list_empty(&task->rq_list)); - sched_lock_runqueues(); + /* Lock that particular cpu's runqueue set */ + sched_lock_runqueues(sched, &irqflags); if (front) list_insert(&task->rq_list, &rq->task_list); else list_insert_tail(&task->rq_list, &rq->task_list); rq->total++; task->rq = rq; - sched_unlock_runqueues(); + + /* Unlock that particular cpu's runqueue set */ + sched_unlock_runqueues(sched, irqflags); } /* Helper for removing a task from its runqueue. */ static inline void sched_rq_remove_task(struct ktcb *task) { - struct runqueue *rq; + unsigned long irqflags; + struct scheduler *sched = + &per_cpu_byid(scheduler, task->affinity); - sched_lock_runqueues(); + sched_lock_runqueues(sched, &irqflags); /* * We must lock both, otherwise rqs may swap and * we may get the wrong rq. */ - rq = task->rq; BUG_ON(list_empty(&task->rq_list)); list_remove_init(&task->rq_list); - task->rq = 0; - rq->total--; - BUG_ON(rq->total < 0); - sched_unlock_runqueues(); + task->rq->total--; + BUG_ON(task->rq->total < 0); + task->rq = 0; + + sched_unlock_runqueues(sched, irqflags); } @@ -206,7 +216,8 @@ void sched_resume_sync(struct ktcb *task) BUG_ON(task == current); task->state = TASK_RUNNABLE; sched_rq_add_task(task, - scheduler.rq_runnable, + per_cpu_byid(scheduler, + task->affinity).rq_runnable, RQ_ADD_FRONT); schedule(); } @@ -221,38 +232,10 @@ void sched_resume_async(struct ktcb *task) { task->state = TASK_RUNNABLE; sched_rq_add_task(task, - scheduler.rq_runnable, + per_cpu_byid(scheduler, + task->affinity).rq_runnable, RQ_ADD_FRONT); -} - - -/* Same as suspend, task state and flags are different */ -void sched_exit_sync(void) -{ - preempt_disable(); - sched_rq_remove_task(current); - current->state = TASK_DEAD; - current->flags &= ~TASK_EXITING; - - if (current->pagerid != current->tid) - wake_up(¤t->wqh_pager, 0); - preempt_enable(); - - schedule(); -} - -void sched_exit_async(void) -{ - preempt_disable(); - sched_rq_remove_task(current); - current->state = TASK_DEAD; - current->flags &= ~TASK_EXITING; - - if (current->pagerid != current->tid) - wake_up(¤t->wqh_pager, 0); - preempt_enable(); - - need_resched = 1; +// printk("CPU%d: Resuming task %d with affinity %d\n", smp_get_cpuid(), task->tid, task->affinity); } /* @@ -288,23 +271,25 @@ void sched_suspend_async(void) } -extern void arch_switch(struct ktcb *cur, struct ktcb *next); +extern void arch_context_switch(struct ktcb *cur, struct ktcb *next); static inline void context_switch(struct ktcb *next) { struct ktcb *cur = current; - //printk("(%d) to (%d)\n", cur->tid, next->tid); +// printk("Core:%d (%d) to (%d)\n", smp_get_cpuid(), cur->tid, next->tid); + system_account_context_switch(); /* Flush caches and everything */ - arch_hardware_flush(TASK_PGD(next)); + if (current->space->spid != next->space->spid) + arch_space_switch(next); /* Update utcb region for next task */ task_update_utcb(next); /* Switch context */ - arch_switch(cur, next); + arch_context_switch(cur, next); // printk("Returning from yield. Tid: (%d)\n", cur->tid); } @@ -318,7 +303,7 @@ static inline int sched_recalc_ticks(struct ktcb *task, int prio_total) BUG_ON(prio_total < task->priority); BUG_ON(prio_total == 0); return task->ticks_assigned = - SCHED_TICKS * task->priority / prio_total; + CONFIG_SCHED_TICKS * task->priority / prio_total; } @@ -355,14 +340,16 @@ void schedule() { struct ktcb *next; - /* Should not schedule with preemption disabled or in nested irq */ - BUG_ON(voluntary_preempt); + /* Should not schedule with preemption + * disabled or in nested irq */ + BUG_ON(per_cpu(voluntary_preempt)); BUG_ON(in_nested_irq_context()); /* Should not have more ticks than SCHED_TICKS */ - BUG_ON(current->ticks_left > SCHED_TICKS); + BUG_ON(current->ticks_left > CONFIG_SCHED_TICKS); - /* Cannot have any irqs that schedule after this */ + /* If coming from process path, cannot have + * any irqs that schedule after this */ preempt_disable(); /* Reset schedule flag */ @@ -373,16 +360,17 @@ void schedule() sched_rq_remove_task(current); if (current->ticks_left) sched_rq_add_task(current, - scheduler.rq_runnable, + per_cpu(scheduler).rq_runnable, RQ_ADD_BEHIND); else sched_rq_add_task(current, - scheduler.rq_expired, + per_cpu(scheduler).rq_expired, RQ_ADD_BEHIND); } /* - * FIXME: Are these smp-safe? + * FIXME: Are these smp-safe? BB: On first glance they + * should be because runqueues are per-cpu right now. * * If task is about to sleep and * it has pending events, wake it up. @@ -401,22 +389,34 @@ void schedule() TASK_IN_USER(current)) { if (current->flags & TASK_SUSPENDING) sched_suspend_async(); - else if (current->flags & TASK_EXITING) - sched_exit_async(); } - /* Determine the next task to be run */ - if (scheduler.rq_runnable->total > 0) { - next = link_to_struct(scheduler.rq_runnable->task_list.next, - struct ktcb, rq_list); - } else { - if (scheduler.rq_expired->total > 0) { + /* Simpler task pick up loop. May put in sched_pick_next() */ + for (;;) { + struct scheduler *sched = &per_cpu(scheduler); + + /* If we or a child has just exited, run idle task once for clean up */ + if (current->flags & TASK_EXITED) { + current->flags &= ~TASK_EXITED; + next = sched->idle_task; + break; + } else if (sched->rq_runnable->total > 0) { + /* Get a runnable task, if available */ + next = link_to_struct(sched->rq_runnable->task_list.next, + struct ktcb, rq_list); + break; + } else if (sched->rq_expired->total > 0) { + /* Swap queues and retry if not */ sched_rq_swap_runqueues(); - next = link_to_struct( - scheduler.rq_runnable->task_list.next, - struct ktcb, rq_list); + continue; + } else if (in_process_context()) { + /* Do idle task if no runnable tasks and in process */ + next = sched->idle_task; + break; } else { - idle_task(); + /* Irq calls must return to interrupted current process */ + next = current; + break; } } @@ -431,7 +431,7 @@ void schedule() * becomes runnable rather than all at once. It is done * every runqueue swap */ - sched_recalc_ticks(next, scheduler.prio_total); + sched_recalc_ticks(next, per_cpu(scheduler).prio_total); next->ticks_left = next->ticks_assigned; } @@ -450,7 +450,7 @@ void schedule() */ void scheduler_start() { - timer_start(); + platform_timer_start(); switch_to_user(current); } diff --git a/src/generic/space.c b/src/generic/space.c index 200f89f..9174894 100644 --- a/src/generic/space.c +++ b/src/generic/space.c @@ -4,6 +4,7 @@ * Copyright (C) 2008 Bahadir Balban */ #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) #include INC_GLUE(memlayout.h) #include INC_ARCH(exception.h) #include INC_SUBARCH(mm.h) @@ -15,7 +16,6 @@ #include #include - void init_address_space_list(struct address_space_list *space_list) { memset(space_list, 0, sizeof(*space_list)); @@ -47,15 +47,16 @@ void address_space_add(struct address_space *space) BUG_ON(!++curcont->space_list.count); } -void address_space_remove(struct address_space *space) +void address_space_remove(struct address_space *space, struct container *cont) { BUG_ON(list_empty(&space->list)); - BUG_ON(--curcont->space_list.count < 0); + BUG_ON(--cont->space_list.count < 0); list_remove_init(&space->list); } /* Assumes address space reflock is already held */ -void address_space_delete(struct address_space *space) +void address_space_delete(struct address_space *space, + struct ktcb *task_accounted) { BUG_ON(space->ktcb_refs); @@ -66,7 +67,7 @@ void address_space_delete(struct address_space *space) id_del(&kernel_resources.space_ids, space->spid); /* Deallocate the space structure */ - free_space(space); + free_space(space, task_accounted); } struct address_space *address_space_create(struct address_space *orig) @@ -81,7 +82,7 @@ struct address_space *address_space_create(struct address_space *orig) /* Allocate pgd */ if (!(pgd = alloc_pgd())) { - free_space(space); + free_space(space, current); return PTR_ERR(-ENOMEM); } @@ -92,7 +93,7 @@ struct address_space *address_space_create(struct address_space *orig) space->pgd = pgd; /* Copy all kernel entries */ - copy_pgd_kern_all(pgd); + arch_copy_pgd_kernel_entries(pgd); /* * Set up space id: Always allocate a new one. Specifying a space id @@ -106,7 +107,7 @@ struct address_space *address_space_create(struct address_space *orig) /* Copy its user entries/tables */ if ((err = copy_user_tables(space, orig)) < 0) { free_pgd(pgd); - free_space(space); + free_space(space, current); return PTR_ERR(err); } } diff --git a/src/generic/tcb.c b/src/generic/tcb.c index 507bcea..932942a 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -16,6 +16,8 @@ #include INC_ARCH(exception.h) #include INC_SUBARCH(mm.h) #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) +#include INC_SUBARCH(mmu_ops.h) void init_ktcb_list(struct ktcb_list *ktcb_list) { @@ -30,6 +32,8 @@ void tcb_init(struct ktcb *new) link_init(&new->task_list); mutex_init(&new->thread_control_lock); + spin_lock_init(&new->thread_lock); + init_ktcb_list(&new->child_exit_list); cap_list_init(&new->cap_list); @@ -65,32 +69,52 @@ struct ktcb *tcb_alloc_init(l4id_t cid) void tcb_delete(struct ktcb *tcb) { + struct ktcb *pager, *acc_task; + /* Sanity checks first */ BUG_ON(!is_page_aligned(tcb)); BUG_ON(tcb->wqh_pager.sleepers > 0); BUG_ON(tcb->wqh_send.sleepers > 0); BUG_ON(tcb->wqh_recv.sleepers > 0); - BUG_ON(!list_empty(&tcb->task_list) && - !(tcb->flags & TASK_EXITING)); - BUG_ON(!list_empty(&tcb->rq_list) && tcb != current); - BUG_ON(tcb->rq && tcb != current); + BUG_ON(tcb->affinity != current->affinity); + BUG_ON(tcb->state != TASK_INACTIVE); + BUG_ON(!list_empty(&tcb->rq_list)); + BUG_ON(tcb->rq); + BUG_ON(tcb == current); BUG_ON(tcb->nlocks); BUG_ON(tcb->waiting_on); BUG_ON(tcb->wq); - mutex_lock(&curcont->space_list.lock); + /* Remove from zombie list */ + list_remove(&tcb->task_list); + + /* Determine task to account deletions */ + if (!(pager = tcb_find(tcb->pagerid))) + acc_task = current; + else + acc_task = pager; + + /* + * NOTE: This protects single threaded space + * deletion against space modification. + * + * If space deletion were multi-threaded, list + * traversal would be needed to ensure list is + * still there. + */ + mutex_lock(&tcb->container->space_list.lock); mutex_lock(&tcb->space->lock); BUG_ON(--tcb->space->ktcb_refs < 0); /* No refs left for the space, delete it */ if (tcb->space->ktcb_refs == 0) { - address_space_remove(tcb->space); + address_space_remove(tcb->space, tcb->container); mutex_unlock(&tcb->space->lock); - address_space_delete(tcb->space); - mutex_unlock(&curcont->space_list.lock); + address_space_delete(tcb->space, acc_task); + mutex_unlock(&tcb->container->space_list.lock); } else { mutex_unlock(&tcb->space->lock); - mutex_unlock(&curcont->space_list.lock); + mutex_unlock(&tcb->container->space_list.lock); } /* Clear container id part */ @@ -100,7 +124,7 @@ void tcb_delete(struct ktcb *tcb) id_del(&kernel_resources.ktcb_ids, tcb->tid); /* Free the tcb */ - free_ktcb(tcb); + free_ktcb(tcb, acc_task); } struct ktcb *tcb_find_by_space(l4id_t spid) @@ -133,6 +157,22 @@ struct ktcb *container_find_tcb(struct container *c, l4id_t tid) return 0; } +struct ktcb *container_find_lock_tcb(struct container *c, l4id_t tid) +{ + struct ktcb *task; + + spin_lock(&c->ktcb_list.list_lock); + list_foreach_struct(task, &c->ktcb_list.list, task_list) { + if (task->tid == tid) { + spin_lock(&task->thread_lock); + spin_unlock(&c->ktcb_list.list_lock); + return task; + } + } + spin_unlock(&c->ktcb_list.list_lock); + return 0; +} + /* * Threads are the only resource where inter-container searches are * allowed. This is because on other containers, only threads can be @@ -158,6 +198,26 @@ struct ktcb *tcb_find(l4id_t tid) } } +struct ktcb *tcb_find_lock(l4id_t tid) +{ + struct container *c; + + if (current->tid == tid) { + spin_lock(¤t->thread_lock); + return current; + } + + if (tid_to_cid(tid) == curcont->cid) { + return container_find_lock_tcb(curcont, tid); + } else { + if (!(c = container_find(&kernel_resources, + tid_to_cid(tid)))) + return 0; + else + return container_find_lock_tcb(c, tid); + } +} + void ktcb_list_add(struct ktcb *new, struct ktcb_list *ktcb_list) { spin_lock(&ktcb_list->list_lock); @@ -178,13 +238,45 @@ void tcb_add(struct ktcb *new) spin_unlock(&c->ktcb_list.list_lock); } -void tcb_remove(struct ktcb *new) +/* + * Its important that this is per-cpu. This is + * because it must be guaranteed that the task + * is not runnable. Idle task on that cpu guarantees it. + */ +void tcb_delete_zombies(void) { + struct ktcb *zombie, *n; + struct ktcb_list *ktcb_list = + &per_cpu(kernel_resources.zombie_list); + + /* Traverse the per-cpu zombie list */ + spin_lock(&ktcb_list->list_lock); + list_foreach_removable_struct(zombie, n, + &ktcb_list->list, + task_list) + /* Delete all zombies one by one */ + tcb_delete(zombie); + spin_unlock(&ktcb_list->list_lock); +} + + +/* + * It's enough to lock list and thread without + * traversing the list, because we're only + * protecting against thread modification. + * Deletion is a single-threaded operation + */ +void tcb_remove(struct ktcb *task) +{ + /* Lock list */ spin_lock(&curcont->ktcb_list.list_lock); - BUG_ON(list_empty(&new->task_list)); + BUG_ON(list_empty(&task->task_list)); BUG_ON(--curcont->ktcb_list.count < 0); - list_remove_init(&new->task_list); + spin_lock(&task->thread_lock); + + list_remove_init(&task->task_list); spin_unlock(&curcont->ktcb_list.list_lock); + spin_unlock(&task->thread_lock); } void ktcb_list_remove(struct ktcb *new, struct ktcb_list *ktcb_list) @@ -207,8 +299,7 @@ unsigned int syscall_regs_offset = offsetof(struct ktcb, syscall_regs); */ void task_update_utcb(struct ktcb *task) { - /* Update the KIP pointer */ - kip.utcb = task->utcb_address; + arch_update_utcb(task->utcb_address); } /* @@ -251,7 +342,7 @@ int tcb_check_and_lazy_map_utcb(struct ktcb *task, int page_in) if (current == task) { /* Check own utcb, if not there, page it in */ if ((ret = check_access(task->utcb_address, UTCB_SIZE, - MAP_SVC_RW_FLAGS, page_in)) < 0) + MAP_KERN_RW, page_in)) < 0) return -EFAULT; else return 0; @@ -259,7 +350,7 @@ int tcb_check_and_lazy_map_utcb(struct ktcb *task, int page_in) /* Check another's utcb, but don't try to map in */ if ((ret = check_access_task(task->utcb_address, UTCB_SIZE, - MAP_SVC_RW_FLAGS, 0, + MAP_KERN_RW, 0, task)) < 0) { return -EFAULT; } else { @@ -268,18 +359,18 @@ int tcb_check_and_lazy_map_utcb(struct ktcb *task, int page_in) * unless they're identical */ if ((phys = - virt_to_phys_by_pgd(task->utcb_address, - TASK_PGD(task))) != - virt_to_phys_by_pgd(task->utcb_address, - TASK_PGD(current))) { + virt_to_phys_by_pgd(TASK_PGD(task), + task->utcb_address)) != + virt_to_phys_by_pgd(TASK_PGD(current), + task->utcb_address)) { /* * We have none or an old reference. * Update it with privileged flags, * so that only kernel can access. */ - add_mapping_pgd(phys, task->utcb_address, + add_mapping_pgd(phys, page_align(task->utcb_address), page_align_up(UTCB_SIZE), - MAP_SVC_RW_FLAGS, + MAP_KERN_RW, TASK_PGD(current)); } BUG_ON(!phys); diff --git a/src/generic/time.c b/src/generic/time.c index cbce9ab..b192ff5 100644 --- a/src/generic/time.c +++ b/src/generic/time.c @@ -58,7 +58,7 @@ void update_system_time(void) * TODO: Investigate: how do we make sure timer_irq is * called SCHED_TICKS times per second? */ - if (systime.thz == SCHED_TICKS) { + if (systime.thz == CONFIG_SCHED_TICKS) { systime.thz = 0; systime.sec++; } @@ -71,7 +71,7 @@ int sys_time(struct timeval *tv, int set) int err; if ((err = check_access((unsigned long)tv, sizeof(*tv), - MAP_USR_RW_FLAGS, 1)) < 0) + MAP_USR_RW, 1)) < 0) return err; /* Get time */ @@ -79,7 +79,7 @@ int sys_time(struct timeval *tv, int set) while(retries > 0) { systime.reader = 1; tv->tv_sec = systime.sec; - tv->tv_usec = 1000000 * systime.thz / SCHED_TICKS; + tv->tv_usec = 1000000 * systime.thz / CONFIG_SCHED_TICKS; retries--; if (systime.reader) diff --git a/src/glue/arm/SConscript b/src/glue/arm/SConscript index 328e946..fb4231b 100644 --- a/src/glue/arm/SConscript +++ b/src/glue/arm/SConscript @@ -1,10 +1,22 @@ - # Inherit global environment -Import('env') +import os, sys, glob + +PROJRELROOT = '../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import('env', 'symbols') # The set of source files associated with this SConscript file. -src_local = ['init.c', 'memory.c', 'systable.c', 'irq.c'] +src_local = ['init.c', 'memory.c', 'systable.c', 'irq.c', 'cache.c', 'debug.c'] + +for name, val in symbols: + if 'CONFIG_SMP' == name: + src_local += ['smp.c', 'ipi.c', 'smp_test.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/glue/arm/cache.c b/src/glue/arm/cache.c new file mode 100644 index 0000000..9b50651 --- /dev/null +++ b/src/glue/arm/cache.c @@ -0,0 +1,49 @@ + +/* + * Wrapper for arm specific cache related functions + * + * Copyright (C) 2009 B Labs Ltd. + */ + +#include INC_GLUE(cache.h) + +void invalidate_cache(void) +{ +} + + +void invalidate_icache(void) +{ +} + +void invalidate_dcache(void) +{ +} + +void clean_dcache(void) +{ +} + +void clean_invalidate_dcache(void) +{ +} + +void clean_invalidate_cache(void) +{ +} + +void drain_writebuffer(void) +{ +} + +void invalidate_tlb(void) +{ +} + +void invalidate_itlb(void) +{ +} + +void invalidate_dtlb(void) +{ +} diff --git a/src/glue/arm/debug.c b/src/glue/arm/debug.c new file mode 100644 index 0000000..a1b4c83 --- /dev/null +++ b/src/glue/arm/debug.c @@ -0,0 +1,43 @@ + +#include +#include +#include INC_SUBARCH(perfmon.h) +#include INC_GLUE(debug.h) + +#if defined (CONFIG_DEBUG_PERFMON_KERNEL) + +#define CYCLES_PER_COUNTER_TICKS 64 +void system_measure_syscall_end(unsigned long swi_address) +{ + volatile u64 cnt = perfmon_read_cyccnt() * CYCLES_PER_COUNTER_TICKS; + unsigned int call_offset = (swi_address & 0xFF) >> 2; + + /* Number of syscalls */ + u64 call_count = + *(((u64 *)&system_accounting.syscalls) + call_offset); + + /* System call timing structure */ + struct syscall_timing *st = + (struct syscall_timing *) + &system_accounting.syscall_timings + call_offset; + + /* Set min */ + if (st->min == 0) + st->min = cnt; + else if (st->min > cnt) + st->min = cnt; + + /* Set max */ + if (st->max < cnt) + st->max = cnt; + + st->total += cnt; + + /* Average = total timings / total calls */ + st->avg = st->total / call_count; + + /* Update total */ + system_accounting.syscall_timings.all_total += cnt; +} + +#endif diff --git a/src/glue/arm/init.c b/src/glue/arm/init.c index 2964b26..db48ff4 100644 --- a/src/glue/arm/init.c +++ b/src/glue/arm/init.c @@ -1,7 +1,7 @@ /* * Main initialisation code for the ARM kernel * - * Copyright (C) 2007 Bahadir Balban + * Copyright (C) 2007 - 2010 B Labs Ltd. */ #include #include @@ -17,36 +17,23 @@ #include INC_ARCH(linker.h) #include INC_ARCH(asm.h) #include INC_SUBARCH(mm.h) +#include INC_SUBARCH(cpu.h) #include INC_SUBARCH(mmu_ops.h) +#include INC_SUBARCH(perfmon.h) #include INC_GLUE(memlayout.h) #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) #include INC_GLUE(message.h) #include INC_GLUE(syscall.h) #include INC_GLUE(init.h) +#include INC_GLUE(smp.h) #include INC_PLAT(platform.h) -#include INC_PLAT(printascii.h) #include INC_API(syscall.h) #include INC_API(kip.h) #include INC_API(mutex.h) unsigned int kernel_mapping_end; -/* Maps the early memory regions needed to bootstrap the system */ -void init_kernel_mappings(void) -{ - memset((void *)virt_to_phys(&init_pgd), 0, sizeof(pgd_table_t)); - - /* Map kernel area to its virtual region */ - add_section_mapping_init(align(virt_to_phys(_start_text),SZ_1MB), - align((unsigned int)_start_text, SZ_1MB), 1, - cacheable | bufferable); - - /* Map kernel one-to-one to its physical region */ - add_section_mapping_init(align(virt_to_phys(_start_text),SZ_1MB), - align(virt_to_phys(_start_text),SZ_1MB), - 1, 0); -} - void print_sections(void) { dprintk("_start_kernel: ",(unsigned int)_start_kernel); @@ -59,89 +46,20 @@ void print_sections(void) dprintk("_end_vectors: ",(unsigned int)_end_vectors); dprintk("_start_kip: ", (unsigned int) _start_kip); dprintk("_end_kip: ", (unsigned int) _end_kip); - dprintk("_bootstack: ", (unsigned int)_bootstack); + dprintk("_start_syscalls: ", (unsigned int) _start_syscalls); + dprintk("_end_syscalls: ", (unsigned int) _end_syscalls); + dprintk("_start_bootstack: ", (unsigned int)_start_bootstack); + dprintk("_end_bootstack: ", (unsigned int)_end_bootstack); + dprintk("_start_bootstack: ", (unsigned int)_start_bootstack); + dprintk("_end_bootstack: ", (unsigned int)_end_bootstack); + dprintk("_start_init_pgd: ", (unsigned int)_start_init_pgd); + dprintk("_end_init_pgd: ", (unsigned int)_end_init_pgd); dprintk("_end_kernel: ", (unsigned int)_end_kernel); dprintk("_start_init: ", (unsigned int)_start_init); dprintk("_end_init: ", (unsigned int)_end_init); dprintk("_end: ", (unsigned int)_end); } -/* - * Enable virtual memory using kernel's pgd - * and continue execution on virtual addresses. - */ -void start_vm() -{ - /* - * TTB must be 16K aligned. This is because first level tables are - * sized 16K. - */ - if ((unsigned int)&init_pgd & 0x3FFF) - dprintk("kspace not properly aligned for ttb:", - (u32)&init_pgd); - // memset((void *)&kspace, 0, sizeof(pgd_table_t)); - arm_set_ttb(virt_to_phys(&init_pgd)); - - /* - * This sets all 16 domains to zero and domain 0 to 1. The outcome - * is that page table access permissions are in effect for domain 0. - * All other domains have no access whatsoever. - */ - arm_set_domain(1); - - /* Enable everything before mmu permissions are in place */ - arm_enable_caches(); - arm_enable_wbuffer(); - - /* - * Leave the past behind. Tlbs are invalidated, write buffer is drained. - * The whole of I + D caches are invalidated unconditionally. This is - * important to ensure that the cache is free of previously loaded - * values. Otherwise unpredictable data aborts may occur at arbitrary - * times, each time a load/store operation hits one of the invalid - * entries and those entries are cleaned to main memory. - */ - arm_invalidate_cache(); - arm_drain_writebuffer(); - arm_invalidate_tlb(); - arm_enable_mmu(); - - /* Jump to virtual memory addresses */ - __asm__ __volatile__ ( - "add sp, sp, %0 \n" /* Update stack pointer */ - "add fp, fp, %0 \n" /* Update frame pointer */ - /* On the next instruction below, r0 gets - * current PC + KOFFSET + 2 instructions after itself. */ - "add r0, pc, %0 \n" - /* Special symbol that is extracted and included in the loader. - * Debuggers can break on it to load the virtual symbol table */ - ".global break_virtual;\n" - "break_virtual:\n" - "mov pc, r0 \n" /* (r0 has next instruction) */ - : - : "r" (KERNEL_OFFSET) - : "r0" - ); - - /* At this point, execution is on virtual addresses. */ - remove_section_mapping(virt_to_phys(_start_kernel)); - - /* - * Restore link register (LR) for this function. - * - * NOTE: LR values are pushed onto the stack at each function call, - * which means the restored return values will be physical for all - * functions in the call stack except this function. So the caller - * of this function must never return but initiate scheduling etc. - */ - __asm__ __volatile__ ( - "add %0, %0, %1 \n" - "mov pc, %0 \n" - :: "r" (__builtin_return_address(0)), "r" (KERNEL_OFFSET) - ); - while(1); -} - /* This calculates what address the kip field would have in userspace. */ #define KIP_USR_OFFSETOF(kip, field) ((void *)(((unsigned long)&kip.field - \ (unsigned long)&kip) + USER_KIP_PAGE)) @@ -171,128 +89,117 @@ void kip_init() utcb_ref = (struct utcb **)((unsigned long)&kip + UTCB_KIP_OFFSET); add_boot_mapping(virt_to_phys(&kip), USER_KIP_PAGE, PAGE_SIZE, - MAP_USR_RO_FLAGS); + MAP_USR_RO); printk("%s: Kernel built on %s, %s\n", __KERNELNAME__, kip.kdesc.date, kip.kdesc.time); } - void vectors_init() { unsigned int size = ((u32)_end_vectors - (u32)arm_high_vector); /* Map the vectors in high vector page */ add_boot_mapping(virt_to_phys(arm_high_vector), - ARM_HIGH_VECTOR, size, 0); - arm_enable_high_vectors(); + ARM_HIGH_VECTOR, size, MAP_KERN_RWX); /* Kernel memory trapping is enabled at this point. */ } -void abort() + +#include +#include +#include + +/* This is what an idle task needs */ +static DECLARE_PERCPU(struct capability, pmd_cap); + +/* + * FIXME: Add this when initializing kernel resources + * This is a hack. + */ +void setup_idle_caps() { - printk("Aborting on purpose to halt system.\n"); -#if 0 - /* Prefetch abort */ - __asm__ __volatile__ ( - "mov pc, #0x0\n" - :: - ); -#endif - /* Data abort */ - __asm__ __volatile__ ( - "mov r0, #0 \n" - "ldr r0, [r0] \n" - :: - ); + struct capability *cap = &per_cpu(pmd_cap); + + cap_list_init(¤t->cap_list); + cap->type = CAP_RTYPE_MAPPOOL | CAP_TYPE_QUANTITY; + cap->size = 50; + + link_init(&cap->list); + cap_list_insert(cap, ¤t->cap_list); } -void jump(struct ktcb *task) +/* + * Set up current stack's beginning, and initial page tables + * as a valid task environment for idle task for current cpu + */ +void setup_idle_task() { - __asm__ __volatile__ ( - "mov lr, %0\n" /* Load pointer to context area */ - "ldr r0, [lr]\n" /* Load spsr value to r0 */ - "msr spsr, r0\n" /* Set SPSR as ARM_MODE_USR */ - "add sp, lr, %1\n" /* Reset SVC stack */ - "sub sp, sp, %2\n" /* Align to stack alignment */ - "ldmib lr, {r0-r14}^\n" /* Load all USR registers */ - - "nop \n" /* Spec says dont touch banked registers - * right after LDM {no-pc}^ for one instruction */ - "add lr, lr, #64\n" /* Manually move to PC location. */ - "ldr lr, [lr]\n" /* Load the PC_USR to LR */ - "movs pc, lr\n" /* Jump to userspace, also switching SPSR/CPSR */ - : - : "r" (task), "r" (PAGE_SIZE), "r" (STACK_ALIGNMENT) - ); -} - -void switch_to_user(struct ktcb *task) -{ - arm_clean_invalidate_cache(); - arm_invalidate_tlb(); - arm_set_ttb(virt_to_phys(TASK_PGD(task))); - arm_invalidate_tlb(); - jump(task); -} - -void setup_dummy_current() -{ - /* - * Temporarily iInitialize the beginning of - * last page of stack as the current ktcb - */ memset(current, 0, sizeof(struct ktcb)); current->space = &init_space; TASK_PGD(current) = &init_pgd; + + /* Initialize space caps list */ + cap_list_init(¤t->space->cap_list); + +#if 0 + /* + * Unneeded stuff + */ + /* + * Set up idle context. + */ + current->context.spsr = ARM_MODE_SVC; + current->context.pc = (u32)idle_task; + current->context.sp = (u32)align((unsigned long)current + PAGE_SIZE, + STACK_ALIGNMENT); +#endif + + /* + * FIXME: This must go to kernel resources init. + */ + + /* + * If using split page tables, kernel + * resources must point at the global pgd + * TODO: We may need this for V6, in the future + */ +#if defined(CONFIG_SUBARCH_V7) + kernel_resources.pgd_global = &init_global_pgd; +#endif } -void init_finalize(struct kernel_resources *kres) +void remove_initial_mapping(void) { - volatile register unsigned int stack; - volatile register unsigned int newstack; - struct ktcb *first_task; - struct container *c; + /* At this point, execution is on virtual addresses. */ + remove_section_mapping(virt_to_phys(_start_kernel)); +} - /* Get the first container */ - c = link_to_struct(kres->containers.list.next, - struct container, list); +void init_finalize(void) +{ + /* Set up idle task capabilities */ + setup_idle_caps(); - /* Get the first pager in container */ - first_task = link_to_struct(c->ktcb_list.list.next, - struct ktcb, task_list); + platform_timer_start(); - /* Calculate first stack address */ - newstack = align((unsigned long)first_task + PAGE_SIZE - 1, - STACK_ALIGNMENT); +#if defined (CONFIG_SMP) + /* Tell other cores to continue */ + secondary_run_signal = 1; + dmb(); +#endif - /* Switch to new stack */ - stack = newstack; - asm("mov sp, %0\n\t"::"r"(stack)); - - /* -- Point of no stack unwinding -- */ - - /* - * Unmap boot memory, and add it as - * an unused kernel memcap - */ - free_boot_memory(&kernel_resources); - - /* - * Set up initial KIP UTCB ref - */ - kip.utcb = (u32)current->utcb_address; - - /* - * Start the scheduler, jumping to task - */ - scheduler_start(); + idle_task(); } void start_kernel(void) { - printascii("\n"__KERNELNAME__": start kernel...\n"); + print_early("\n"__KERNELNAME__": start kernel...\n"); + + // print_sections(); + + /* Early cpu initialization */ + cpu_startup(); /* * Initialise section mappings @@ -300,17 +207,19 @@ void start_kernel(void) */ init_kernel_mappings(); + print_early("\n"__KERNELNAME__": Init kernel mappings...\n"); + /* * Enable virtual memory * and jump to virtual addresses */ - start_vm(); + start_virtual_memory(); /* - * Set up a dummy current ktcb on - * boot stack with initial pgd + * Set up initial page tables and ktcb + * as a valid environment for idle task */ - setup_dummy_current(); + setup_idle_task(); /* * Initialise platform-specific @@ -322,6 +231,17 @@ void start_kernel(void) printk("%s: Virtual memory enabled.\n", __KERNELNAME__); + /* Identify CPUs and system */ + system_identify(); + + sched_init(); + + /* Try to initialize secondary cores if there are any */ + smp_start_cores(); + + /* Remove one-to-one kernel mapping */ + remove_initial_mapping(); + /* * Map and enable high vector page. * Faults can be handled after here. @@ -341,8 +261,8 @@ void start_kernel(void) /* Initialise system call page */ syscall_init(); - /* Init scheduler */ - sched_init(&scheduler); + /* Init performance monitor, if enabled */ + perfmon_init(); /* * Evaluate system resources @@ -354,7 +274,7 @@ void start_kernel(void) * Free boot memory, switch to first * task's stack and start scheduler */ - init_finalize(&kernel_resources); + init_finalize(); BUG(); } diff --git a/src/glue/arm/ipi.c b/src/glue/arm/ipi.c new file mode 100644 index 0000000..2e5eff5 --- /dev/null +++ b/src/glue/arm/ipi.c @@ -0,0 +1,18 @@ +/* + * Copyright 2010 B Labs.Ltd. + * + * Author: Prem Mallappa + * + * Description: IPI handler for all ARM SMP cores + */ + +#include INC_GLUE(ipi.h) +#include INC_GLUE(smp.h) +#include INC_SUBARCH(cpu.h) +#include + +/* This should be in a file something like exception.S */ +int ipi_handler(struct irq_desc *desc) +{ + return 0; +} diff --git a/src/glue/arm/memory.c b/src/glue/arm/memory.c index 40abd72..cc2428d 100644 --- a/src/glue/arm/memory.c +++ b/src/glue/arm/memory.c @@ -8,34 +8,51 @@ #include #include #include +#include #include INC_SUBARCH(mm.h) #include INC_GLUE(memlayout.h) #include INC_GLUE(memory.h) -#include INC_PLAT(printascii.h) +#include INC_GLUE(mapping.h) #include INC_PLAT(offsets.h) #include INC_ARCH(linker.h) +#include INC_ARCH(asm.h) /* - * Conversion from generic protection flags to arch-specific - * pte flags. + * Return arch-specific pte flags from generic space flags. */ unsigned int space_flags_to_ptflags(unsigned int flags) { switch (flags) { - case MAP_USR_RW_FLAGS: - return __MAP_USR_RW_FLAGS; - case MAP_USR_RO_FLAGS: - return __MAP_USR_RO_FLAGS; - case MAP_SVC_RW_FLAGS: - return __MAP_SVC_RW_FLAGS; - case MAP_USR_IO_FLAGS: - return __MAP_USR_IO_FLAGS; - case MAP_SVC_IO_FLAGS: - return __MAP_SVC_IO_FLAGS; + case MAP_FAULT: + return __MAP_FAULT; + case MAP_USR_RW: + return __MAP_USR_RW; + case MAP_USR_RO: + return __MAP_USR_RO; + case MAP_KERN_RW: + return __MAP_KERN_RW; + case MAP_USR_IO: + return __MAP_USR_IO; + case MAP_KERN_IO: + return __MAP_KERN_IO; + case MAP_USR_RWX: + return __MAP_USR_RWX; + case MAP_KERN_RWX: + return __MAP_KERN_RWX; + case MAP_USR_RX: + return __MAP_USR_RX; + case MAP_KERN_RX: + return __MAP_KERN_RX; + /* + * Don't remove this, if a flag with + * same value is introduced, compiler will warn us + */ + case MAP_INVALID_FLAGS: default: - BUG(); + return MAP_INVALID_FLAGS; } - BUG(); return 0; + + return 0; } void task_init_registers(struct ktcb *task, unsigned long pc) @@ -46,45 +63,12 @@ void task_init_registers(struct ktcb *task, unsigned long pc) /* - * Copies global kernel entries into another pgd. Even for sub-pmd ranges - * the associated pmd entries are copied, assuming any pmds copied are - * applicable to all tasks in the system. + * Copies all global kernel entries that a user process + * should have in its pgd. In split page table setups + * this is a noop. */ -void copy_pgd_kern_by_vrange(pgd_table_t *to, pgd_table_t *from, - unsigned long start, unsigned long end) +void copy_pgd_kernel_entries(pgd_table_t *to) { - /* Extend sub-pmd ranges to their respective pmd boundaries */ - start = align(start, PMD_MAP_SIZE); - - if (end < start) - end = 0; - - /* Aligning would overflow if mapping the last virtual pmd */ - if (end < align(~0, PMD_MAP_SIZE) || - start > end) /* end may have already overflown as input */ - end = align_up(end, PMD_MAP_SIZE); - else - end = 0; - - copy_pgds_by_vrange(to, from, start, end); -} - -/* Copies all standard bits that a user process should have in its pgd */ -void copy_pgd_kern_all(pgd_table_t *to) -{ - pgd_table_t *from = TASK_PGD(current); - - copy_pgd_kern_by_vrange(to, from, KERNEL_AREA_START, KERNEL_AREA_END); - copy_pgd_kern_by_vrange(to, from, IO_AREA_START, IO_AREA_END); - copy_pgd_kern_by_vrange(to, from, USER_KIP_PAGE, - USER_KIP_PAGE + PAGE_SIZE); - copy_pgd_kern_by_vrange(to, from, ARM_HIGH_VECTOR, - ARM_HIGH_VECTOR + PAGE_SIZE); - copy_pgd_kern_by_vrange(to, from, ARM_SYSCALL_VECTOR, - ARM_SYSCALL_VECTOR + PAGE_SIZE); - - /* We temporarily map uart registers to every process */ - copy_pgd_kern_by_vrange(to, from, USERSPACE_CONSOLE_VIRTUAL, - USERSPACE_CONSOLE_VIRTUAL + PAGE_SIZE); + arch_copy_pgd_kernel_entries(to); } diff --git a/src/glue/arm/smp.c b/src/glue/arm/smp.c new file mode 100644 index 0000000..7c8d2af --- /dev/null +++ b/src/glue/arm/smp.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 B Labs Ltd. + * + * Authors: Prem Mallappa, Bahadir Balban + * + * SMP Initialization of cores. + */ + +#include +#include INC_GLUE(smp.h) +#include INC_GLUE(init.h) +#include INC_GLUE(mapping.h) +#include INC_SUBARCH(cpu.h) +#include INC_SUBARCH(proc.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_ARCH(linker.h) +#include INC_ARCH(io.h) +#include + +unsigned long secondary_run_signal; + + +void __smp_start(void); + +void smp_start_cores(void) +{ + void (*smp_start_func)(int) = + (void (*)(int))virt_to_phys(__smp_start); + + /* FIXME: Check why this high-level version doesn't work */ + // v7_up_dcache_op_setway(CACHE_SETWAY_CLEAN); + v7_clean_invalidate_setway(); + + /* We dont probably need this, it is not listed as a requirement */ + arm_smp_inval_icache_entirely(); + + /* Start other cpus */ + for (int i = 1; i < CONFIG_NCPU; i++) { + printk("%s: Bringing up CPU%d\n", __KERNELNAME__, i); + if ((platform_smp_start(i, smp_start_func)) < 0) { + printk("FATAL: Could not start secondary cpu. " + "cpu=%d\n", i); + BUG(); + } + wfi(); /* wait for other cpu send IPI to core0 */ + } + + scu_print_state(); +} + +void init_smp(void) +{ + /* Start_secondary_cpus */ + if (CONFIG_NCPU > 1) { + + /* This sets IPI function pointer at bare minimum */ + platform_smp_init(CONFIG_NCPU); + } +} + +void secondary_setup_idle_task(void) +{ + /* This also has its spid allocated by primary */ + current->space = &init_space; + TASK_PGD(current) = &init_pgd; + + /* We need a thread id */ + current->tid = id_new(&kernel_resources.ktcb_ids); +} + +/* + * Idle wait before any tasks become available for running. + * + * FIXME: This should be changed such that tasks running on other + * cpus can be killed and secondaries wait on an idle task. + * + * Currently the tasks are held in wfi() even if asked to be killed + * until a new runnable task becomes runnable. This may be problematic + * for a pager who issued a kill request and is waiting for it to finish. + */ +void sched_secondary_start(void) +{ + while (!secondary_run_signal) + dmb(); + + secondary_setup_idle_task(); + + setup_idle_caps(); + + idle_task(); + + BUG(); +} + + +/* + * this is where it jumps from secondary_start(), which is called from + * board_smp_start() to align each core to start here + */ + +void smp_secondary_init(void) +{ + /* Print early core start message */ + // print_early("Secondary core started.\n"); + + /* Start virtual memory */ + start_virtual_memory(); + + arm_smp_inval_tlb_entirely(); + arm_smp_inval_bpa_entirely(); + dsb(); + isb(); + + printk("%s: CPU%d: Virtual memory enabled.\n", + __KERNELNAME__, smp_get_cpuid()); + + /* Mostly initialize GIC CPU interface */ + secondary_init_platform(); + + printk("%s: CPU%d: Initialized.\n", + __KERNELNAME__, smp_get_cpuid()); + + sched_init(); + + dsb(); + + gic_send_ipi(CPUID_TO_MASK(0), 0); + + /* + * Wait for the first runnable task to become available + */ + sched_secondary_start(); +} + diff --git a/src/glue/arm/smp_test.c b/src/glue/arm/smp_test.c new file mode 100644 index 0000000..4bc2dca --- /dev/null +++ b/src/glue/arm/smp_test.c @@ -0,0 +1,99 @@ + +#include +#include + +#include INC_GLUE(smp.h) +#include INC_SUBARCH(cpu.h) + +DECLARE_SPINLOCK(smp_lock); + +static unsigned long smp_var = 0; +static unsigned long signal_finished; + +static unsigned long basic_var = 0; + +void test_basic_coherent(void) +{ + dmb(); + if (smp_get_cpuid() == 0) { + if (basic_var != 5555) { + printk("FATAL: variable update not seen. var = %lu\n", basic_var); + BUG(); + } + } else { + basic_var = 5555; + dmb(); + } +} + +void test_smp_coherent(void) +{ + int other; + + if (smp_get_cpuid() == 1) + other = 0; + else + other = 1; + + /* Increment var */ + for (int i = 0; i < 1000; i++) { + spin_lock(&smp_lock); + smp_var++; + spin_unlock(&smp_lock); + } + + /* Signal finished */ + spin_lock(&smp_lock); + signal_finished |= (1 << smp_get_cpuid()); + spin_unlock(&smp_lock); + + /* Wait for other to finish */ + while (!(signal_finished & (1 << other))) { + dmb(); + } + if (smp_get_cpuid() == 0) { + printk("Total result: %lu\n", smp_var); + if (smp_var != 2000) { + printk("FATAL: Total result not as expected\n"); + BUG(); + } + printk("%s: Success.\n", __FUNCTION__); + } + +} + + +static u32 make_mask(int ncpus) +{ + u32 mask = 0; + while(--ncpus){ + mask |= CPUID_TO_MASK(ncpus); + } + mask |= CPUID_TO_MASK(0); + + return mask; +} + +#ifndef MAX_IPIS +#define MAX_IPIS 15 +#endif + +void test_ipi(void) +{ + int ipi, cpu; + for (ipi = 0; ipi <= MAX_IPIS; ipi++) { + for (cpu = 0; cpu < CONFIG_NCPU; cpu++) { + if (cpu == smp_get_cpuid()) + continue; + printk("IPI %d from %d to %d\n", ipi, smp_get_cpuid(), cpu); + arch_send_ipi(CPUID_TO_MASK(cpu), ipi); + } + } + /* Send IPI to all cores at once */ + cpu = make_mask(CONFIG_NCPU); + printk("IPI from %d to all\n", smp_get_cpuid()); + arch_send_ipi(cpu, 1); + + printk("IPI from %d to self\n", smp_get_cpuid()); + arch_send_ipi(0, 1); /* Send IPI to self */ +} diff --git a/src/glue/arm/systable.c b/src/glue/arm/systable.c index d099bc8..433e87d 100644 --- a/src/glue/arm/systable.c +++ b/src/glue/arm/systable.c @@ -7,11 +7,15 @@ #include #include #include +#include #include #include #include INC_GLUE(memlayout.h) #include INC_GLUE(syscall.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(debug.h) #include INC_SUBARCH(mm.h) +#include INC_SUBARCH(perfmon.h) #include INC_API(syscall.h) #include INC_API(kip.h) @@ -31,6 +35,7 @@ void kip_init_syscalls(void) kip.container_control = ARM_SYSCALL_PAGE + sys_container_control_offset; kip.time = ARM_SYSCALL_PAGE + sys_time_offset; kip.mutex_control = ARM_SYSCALL_PAGE + sys_mutex_control_offset; + kip.cache_control = ARM_SYSCALL_PAGE + sys_cache_control_offset; } /* Jump table for all system calls. */ @@ -119,6 +124,12 @@ int arch_sys_mutex_control(syscall_context_t *regs) return sys_mutex_control((unsigned long)regs->r0, (int)regs->r1); } +int arch_sys_cache_control(syscall_context_t *regs) +{ + return sys_cache_control((unsigned long)regs->r0, + (unsigned long)regs->r1, + (unsigned int)regs->r2); +} /* * Initialises the system call jump table, for kernel to use. @@ -140,9 +151,10 @@ void syscall_init() syscall_table[sys_container_control_offset >> 2] = (syscall_fn_t)arch_sys_container_control; syscall_table[sys_time_offset >> 2] = (syscall_fn_t)arch_sys_time; syscall_table[sys_mutex_control_offset >> 2] = (syscall_fn_t)arch_sys_mutex_control; + syscall_table[sys_cache_control_offset >> 2] = (syscall_fn_t)arch_sys_cache_control; add_boot_mapping(virt_to_phys(&__syscall_page_start), - ARM_SYSCALL_PAGE, PAGE_SIZE, MAP_USR_RO_FLAGS); + ARM_SYSCALL_PAGE, PAGE_SIZE, MAP_USR_RX); } /* Checks a syscall is legitimate and dispatches to appropriate handler. */ @@ -155,8 +167,20 @@ int syscall(syscall_context_t *regs, unsigned long swi_addr) /* Check within syscall offset boundary */ if (((swi_addr & syscall_offset_mask) >= 0) && ((swi_addr & syscall_offset_mask) <= syscalls_end_offset)) { + + /* Do system call accounting, if enabled */ + system_account_syscall(); + system_account_syscall_type(swi_addr); + + /* Start measure syscall timing, if enabled */ + system_measure_syscall_start(); + /* Quick jump, rather than compare each */ ret = (*syscall_table[(swi_addr & 0xFF) >> 2])(regs); + + /* End measure syscall timing, if enabled */ + system_measure_syscall_end(swi_addr); + } else { printk("System call received from call @ 0x%lx." "Instruction: 0x%lx.\n", swi_addr, @@ -172,9 +196,6 @@ int syscall(syscall_context_t *regs, unsigned long swi_addr) if (current->flags & TASK_SUSPENDING) { BUG_ON(current->nlocks); sched_suspend_sync(); - } else if (current->flags & TASK_EXITING) { - BUG_ON(current->nlocks); - sched_exit_sync(); } return ret; diff --git a/src/lib/printk.c b/src/lib/printk.c index 1eba116..cf766df 100644 --- a/src/lib/printk.c +++ b/src/lib/printk.c @@ -29,6 +29,8 @@ ********************************************************************/ #include /* for va_list, ... comes with gcc */ #include +#include + /* FIXME: LICENSE LICENCE */ typedef unsigned int word_t; @@ -422,6 +424,8 @@ int do_printk(char* format_p, va_list args) return n; } +DECLARE_SPINLOCK(printk_lock); + /** * Flexible print function * @@ -435,9 +439,14 @@ int printk(char *format, ...) { va_list args; int i; + unsigned long irqstate; va_start(args, format); + + spin_lock_irq(&printk_lock, &irqstate); i = do_printk(format, args); + spin_unlock_irq(&printk_lock, irqstate); + va_end(args); return i; }; diff --git a/src/lib/putc.c b/src/lib/putc.c index 42b4909..66128a7 100644 --- a/src/lib/putc.c +++ b/src/lib/putc.c @@ -3,12 +3,11 @@ * * Copyright (C) 2007 Bahadir Balban */ - #include INC_PLAT(uart.h) void putc(char c) { if (c == '\n') - uart_putc('\r'); - uart_putc(c); + uart_tx_char(PLATFORM_CONSOLE_VBASE, '\r'); + uart_tx_char(PLATFORM_CONSOLE_VBASE, c); } diff --git a/src/lib/string.c b/src/lib/string.c index 67d7c3f..b8e7dd6 100644 --- a/src/lib/string.c +++ b/src/lib/string.c @@ -1,30 +1,18 @@ +/* + * Copyright 2008-2010 B Labs Ltd. + */ +void *_memset(void *p, int c, int size); +void *_memcpy(void *d, void *s, int size); void *memset(void *p, int c, int size) { - char ch; - char *pp; - - pp = (char *)p; - ch = (char)c; - - for (int i = 0; i < size; i++) { - *pp++ = ch; - } - return p; + return _memset(p, c, size); } void *memcpy(void *d, void *s, int size) { - char *dst = (char *)d; - char *src = (char *)s; - - for (int i = 0; i < size; i++) { - *dst = *src; - dst++; - src++; - } - return d; + return _memcpy(d, s, size); } diff --git a/src/lib/wait.c b/src/lib/wait.c index 97ddc48..89f2e83 100644 --- a/src/lib/wait.c +++ b/src/lib/wait.c @@ -15,10 +15,12 @@ void task_set_wqh(struct ktcb *task, struct waitqueue_head *wqh, struct waitqueue *wq) { - spin_lock(&task->waitlock); + unsigned long irqflags; + + spin_lock_irq(&task->waitlock, &irqflags); task->waiting_on = wqh; task->wq = wq; - spin_unlock(&task->waitlock); + spin_unlock_irq(&task->waitlock, irqflags); } @@ -28,10 +30,12 @@ void task_set_wqh(struct ktcb *task, struct waitqueue_head *wqh, */ void task_unset_wqh(struct ktcb *task) { - spin_lock(&task->waitlock); + unsigned long irqflags; + + spin_lock_irq(&task->waitlock, &irqflags); task->waiting_on = 0; task->wq = 0; - spin_unlock(&task->waitlock); + spin_unlock_irq(&task->waitlock, irqflags); } @@ -69,17 +73,19 @@ int wait_on_prepared_wait(void) */ int wait_on_prepare(struct waitqueue_head *wqh, struct waitqueue *wq) { + unsigned long irqflags; + /* Disable to protect from sleeping by preemption */ preempt_disable(); - spin_lock(&wqh->slock); + spin_lock_irq(&wqh->slock, &irqflags); wqh->sleepers++; list_insert_tail(&wq->task_list, &wqh->task_list); task_set_wqh(current, wqh, wq); sched_prepare_sleep(); //printk("(%d) waiting on wqh at: 0x%p\n", // current->tid, wqh); - spin_unlock(&wqh->slock); + spin_unlock_irq(&wqh->slock, irqflags); return 0; } @@ -87,15 +93,17 @@ int wait_on_prepare(struct waitqueue_head *wqh, struct waitqueue *wq) /* Sleep without any condition */ int wait_on(struct waitqueue_head *wqh) { + unsigned long irqsave; + CREATE_WAITQUEUE_ON_STACK(wq, current); - spin_lock(&wqh->slock); + spin_lock_irq(&wqh->slock, &irqsave); wqh->sleepers++; list_insert_tail(&wq.task_list, &wqh->task_list); task_set_wqh(current, wqh, &wq); sched_prepare_sleep(); //printk("(%d) waiting on wqh at: 0x%p\n", // current->tid, wqh); - spin_unlock(&wqh->slock); + spin_unlock_irq(&wqh->slock, irqsave); schedule(); /* Did we wake up normally or get interrupted */ @@ -110,7 +118,9 @@ int wait_on(struct waitqueue_head *wqh) /* Wake up all in the queue */ void wake_up_all(struct waitqueue_head *wqh, unsigned int flags) { - spin_lock(&wqh->slock); + unsigned long irqsave; + + spin_lock_irq(&wqh->slock, &irqsave); BUG_ON(wqh->sleepers < 0); while (wqh->sleepers > 0) { struct waitqueue *wq = link_to_struct(wqh->task_list.next, @@ -124,27 +134,31 @@ void wake_up_all(struct waitqueue_head *wqh, unsigned int flags) if (flags & WAKEUP_INTERRUPT) sleeper->flags |= TASK_INTERRUPTED; // printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid); - spin_unlock(&wqh->slock); + spin_unlock_irq(&wqh->slock, irqsave); if (flags & WAKEUP_SYNC) sched_resume_sync(sleeper); else sched_resume_async(sleeper); - spin_lock(&wqh->slock); + spin_lock_irq(&wqh->slock, &irqsave); } - spin_unlock(&wqh->slock); + spin_unlock_irq(&wqh->slock, irqsave); } /* Wake up single waiter */ void wake_up(struct waitqueue_head *wqh, unsigned int flags) { + unsigned long irqflags; + BUG_ON(wqh->sleepers < 0); - spin_lock(&wqh->slock); + + spin_lock_irq(&wqh->slock, &irqflags); + if (wqh->sleepers > 0) { struct waitqueue *wq = link_to_struct(wqh->task_list.next, - struct waitqueue, - task_list); + struct waitqueue, + task_list); struct ktcb *sleeper = wq->task; BUG_ON(list_empty(&wqh->task_list)); list_remove_init(&wq->task_list); @@ -152,8 +166,8 @@ void wake_up(struct waitqueue_head *wqh, unsigned int flags) task_unset_wqh(sleeper); if (flags & WAKEUP_INTERRUPT) sleeper->flags |= TASK_INTERRUPTED; - //printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid); - spin_unlock(&wqh->slock); + // printk("(%d) Waking up (%d)\n", current->tid, sleeper->tid); + spin_unlock_irq(&wqh->slock, irqflags); if (flags & WAKEUP_SYNC) sched_resume_sync(sleeper); @@ -161,7 +175,7 @@ void wake_up(struct waitqueue_head *wqh, unsigned int flags) sched_resume_async(sleeper); return; } - spin_unlock(&wqh->slock); + spin_unlock_irq(&wqh->slock, irqflags); } /* @@ -171,12 +185,13 @@ void wake_up(struct waitqueue_head *wqh, unsigned int flags) */ int wake_up_task(struct ktcb *task, unsigned int flags) { + unsigned long irqflags[2]; struct waitqueue_head *wqh; struct waitqueue *wq; - spin_lock(&task->waitlock); + spin_lock_irq(&task->waitlock, &irqflags[0]); if (!task->waiting_on) { - spin_unlock(&task->waitlock); + spin_unlock_irq(&task->waitlock, irqflags[0]); return -1; } wqh = task->waiting_on; @@ -184,25 +199,29 @@ int wake_up_task(struct ktcb *task, unsigned int flags) /* * We have found the waitqueue head. + * * That needs to be locked first to conform with * lock order and avoid deadlocks. Release task's * waitlock and take the wqh's one. */ - spin_unlock(&task->waitlock); + spin_unlock_irq(&task->waitlock, irqflags[0]); - /* -- Task can be woken up by someone else here -- */ + /* + * Task can be woken up by someone else here. + */ - spin_lock(&wqh->slock); + spin_lock_irq(&wqh->slock, &irqflags[0]); /* * Now lets check if the task is still - * waiting and in the same queue + * waiting and in the same queue. Not irq version + * as we called that once already (so irqs are disabled) */ - spin_lock(&task->waitlock); + spin_lock_irq(&task->waitlock, &irqflags[1]); if (task->waiting_on != wqh) { /* No, task has been woken by someone else */ - spin_unlock(&wqh->slock); - spin_unlock(&task->waitlock); + spin_unlock_irq(&wqh->slock, irqflags[0]); + spin_unlock_irq(&task->waitlock, irqflags[1]); return -1; } @@ -213,8 +232,8 @@ int wake_up_task(struct ktcb *task, unsigned int flags) task->wq = 0; if (flags & WAKEUP_INTERRUPT) task->flags |= TASK_INTERRUPTED; - spin_unlock(&wqh->slock); - spin_unlock(&task->waitlock); + spin_unlock_irq(&wqh->slock, irqflags[0]); + spin_unlock_irq(&task->waitlock, irqflags[1]); /* * Task is removed from its waitqueue. Now we can diff --git a/src/platform/beagle/SConscript b/src/platform/beagle/SConscript new file mode 100644 index 0000000..6c87597 --- /dev/null +++ b/src/platform/beagle/SConscript @@ -0,0 +1,11 @@ + + +# Inherit global environment +Import('env') + +# The set of source files associated with this SConscript file. +src_local = ['print-early.c', 'platform.c', 'perfmon.c', 'irq.c', 'cm.c'] + +obj = env.Object(src_local) + +Return('obj') diff --git a/src/platform/beagle/cm.c b/src/platform/beagle/cm.c new file mode 100644 index 0000000..0a33d1b --- /dev/null +++ b/src/platform/beagle/cm.c @@ -0,0 +1,45 @@ +/* + * Clock mangaer module of the beagleboard. + * + * Copyright (C) 2007 Bahadir Balban + * + */ + +#include INC_PLAT(cm.h) +#include INC_ARCH(io.h) + +/* + * Enable Interface clock of device (represented by bit) + * in CM module's(represented by CM_BASE) CM_FCLEN register + */ +void omap_cm_enable_iclk(unsigned long cm_base, int bit) +{ + unsigned int val = 0; + + val = read((cm_base + CM_FCLKEN_OFFSET)); + val |= (1 << bit); + write(val, (cm_base + CM_FCLKEN_OFFSET)); +} + +/* + * Enable Functional clock of device (represented by bit) + * in CM module's(represented by CM_BASE) CM_FCLEN register + */ +void omap_cm_enable_fclk(unsigned long cm_base, int bit) +{ + unsigned int val = 0; + + val = read((cm_base + CM_ICLKEN_OFFSET)); + val |= (1 << bit); + write(val, (cm_base + CM_FCLKEN_OFFSET)); +} + +/* Set clock source for device */ +void omap_cm_clk_select(unsigned long cm_base, int bit, int src) +{ + unsigned int val = 0; + + val = read((cm_base + CM_CLKSEL_OFFSET)); + val |= (src << bit); + write(val, (cm_base + CM_CLKSEL_OFFSET)); +} diff --git a/src/platform/beagle/irq.c b/src/platform/beagle/irq.c new file mode 100644 index 0000000..1f8fef0 --- /dev/null +++ b/src/platform/beagle/irq.c @@ -0,0 +1,66 @@ +/* + * Support for generic irq handling using platform irq controller (PL190) + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include INC_PLAT(irq.h) +#include INC_PLAT(platform.h) +#include INC_PLAT(timer.h) +#include INC_ARCH(exception.h) +#include + +struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { + [0] = { + .name = "OMAP 3 irq controller", + .level = 0, + .cascade = IRQ_NIL, + .start = 0, + .end = IRQS_MAX, + .ops = { + .init = omap3_intc_init, + .read_irq = omap3_intc_read_irq, + .ack_and_mask = omap3_intc_ack_and_mask, + .unmask = omap3_intc_unmask_irq, + }, + }, +}; + +static int platform_timer_handler(struct irq_desc *desc) +{ + timer_irq_clear(PLATFORM_TIMER0_VBASE); + + return do_timer_irq(); +} + +/* + * Timer handler for userspace + */ +static int platform_timer_user_handler(struct irq_desc *desc) +{ + /* Ack the device irq */ + timer_irq_clear(PLATFORM_TIMER1_VBASE); + + /* Notify the userspace */ + irq_thread_notify(desc); + + return 0; +} + +/* Built-in irq handlers initialised at compile time. + * Else register with register_irq() */ +struct irq_desc irq_desc_array[IRQS_MAX] = { + [IRQ_TIMER0] = { + .name = "Timer0", + .chip = &irq_chip_array[0], + .handler = platform_timer_handler, + }, + [IRQ_TIMER1] = { + .name = "Timer1", + .chip = &irq_chip_array[0], + .handler = platform_timer_user_handler, + }, +}; + diff --git a/src/platform/beagle/perfmon.c b/src/platform/beagle/perfmon.c new file mode 100644 index 0000000..b707471 --- /dev/null +++ b/src/platform/beagle/perfmon.c @@ -0,0 +1,89 @@ +/* + * Platform specific perfmon initialization + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include INC_PLAT(timer.h) +#include +#include INC_PLAT(offsets.h) +#include INC_SUBARCH(perfmon.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memlayout.h) +/* + * Current findings by these tests: + * + * Cpu cycle count and timer ticks are consistently showing 400Mhz + * with a reference timer tick of 1Mhz. So cycle counts are fixed + * with regard to the timer. + * + * Instruction execute count on the busy_loop however, is varying + * between x1, x2 combinations when compared to timer and cycle + * count values. This is happening by trivial changes in code such + * as adding a function call. (Other variables are ruled out, e.g. + * no concurrent memory accesses, caches are off) + * + * There may be two causes to this: + * - Due to missing dmb/dsb/isb instructions. + * - Due to BTC (busy_loop has one branch) which may describe + * the doubling in IPC, since out of the 2 instructions in the + * busy loop one is a branch. + * + * Disabling the BTC increased cycle counts per instruction + * significantly, advising us not to expect any accuracy in counting + * instructions in cycles. Hence instruction-based tests are + * commented out. It is wise to only rely upon timer and cycle counts. + */ +void platform_test_tick_cycles() +{ + /* Initialize the timer */ + const unsigned int load_value = 0xffffffff - 100000; + int mhz_top, mhz_bot, temp; + unsigned long timer_base = PLATFORM_TIMER1_VBASE; + int cyccnt; + + /* Make sure timer is disabled */ + timer_stop(timer_base); + + /* One shot, 32 bits, no irqs */ + timer_init_oneshot(timer_base); + + /* Load the timer with ticks value */ + timer_load(timer_base, load_value); + + /* Start the timer */ + timer_start(timer_base); + + /* Start counter */ + perfmon_reset_start_cyccnt(); + + /* Wait until 0 */ + while (timer_read(timer_base) != 0) + ; + + cyccnt = perfmon_read_cyccnt(); + + /* Fixed-point accuracy on bottom digit */ + temp = cyccnt * 64 * 10 * 13 / 100000; + mhz_top = temp / 10; + mhz_bot = temp - mhz_top * 10; + + printk("Perfmon: 0x%x cycle count \n", cyccnt); + printk("%s: %d.%d MHz CPU speed measured by timer REFCLK at 13MHz\n", + __KERNELNAME__, mhz_top, mhz_bot); +} + +void platform_test_cpucycles(void) +{ + /* + * Variable results: + * + * platform_test_loop_cycles(); + * platform_test_loop_ticks(); + */ + + /* Fixed result */ + platform_test_tick_cycles(); +} + diff --git a/src/platform/beagle/platform.c b/src/platform/beagle/platform.c new file mode 100644 index 0000000..ddead9c --- /dev/null +++ b/src/platform/beagle/platform.c @@ -0,0 +1,142 @@ +/* + * Beagle Board platform-specific initialisation and setup + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include +#include INC_ARCH(linker.h) +#include INC_SUBARCH(mm.h) +#include INC_GLUE(mapping.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_PLAT(platform.h) +#include INC_PLAT(uart.h) +#include INC_PLAT(timer.h) +#include INC_PLAT(irq.h) +#include INC_ARCH(asm.h) +#include INC_PLAT(cm.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 *timer[1]; + + /* Setup timer1 capability as free */ + timer[0] = alloc_bootmem(sizeof(*timer[0]), 0); + timer[0]->start = __pfn(PLATFORM_TIMER1_BASE); + timer[0]->end = timer[0]->start + 1; + timer[0]->size = timer[0]->end - timer[0]->start; + cap_set_devtype(timer[0], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[0], 1); + link_init(&timer[0]->list); + cap_list_insert(timer[0], &kres->devmem_free); + + return 0; +} + +/* + * Use UART2 for kernel as well as user tasks, + * so map it to kernel and user space, this only + * is provided by beagle board + */ +void init_platform_console(void) +{ + add_boot_mapping(PLATFORM_UART2_BASE, PLATFORM_CONSOLE_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + add_boot_mapping(PLATFORM_PERCM_BASE, PLATFORM_PERCM_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + /* + * Map same UART IO area to userspace so that primitive uart-based + * userspace printf can work. Note, this raw mapping is to be + * removed in the future, when file-based io is implemented. + */ + add_boot_mapping(PLATFORM_UART2_BASE, USERSPACE_CONSOLE_VBASE, + PAGE_SIZE, MAP_USR_IO); + + /* use 32KHz clock signal */ + omap_cm_clk_select(PLATFORM_PERCM_VBASE, 11, + OMAP_TIMER_CLKSRC_SYS_CLK); + + /* Enable Interface and Functional clock */ + omap_cm_enable_iclk(PLATFORM_PERCM_VBASE, 11); + omap_cm_enable_fclk(PLATFORM_PERCM_VBASE, 11); + + uart_init(PLATFORM_CONSOLE_VBASE); +} + +void platform_timer_start(void) +{ + /* Enable irq line for TIMER0 */ + irq_enable(IRQ_TIMER0); + + /* Enable timer */ + timer_start(PLATFORM_TIMER0_VBASE); +} + +/* + * We are using GPTIMER1 only, so we map GPTIMER1 base, + * incase any other timer is needed we need to map it + * to userspace or kernel space as needed + */ +void init_platform_timer(void) +{ + add_boot_mapping(PLATFORM_TIMER0_BASE, PLATFORM_TIMER0_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + add_boot_mapping(PLATFORM_WKUP_CM_BASE, PLATFORM_WKUP_CM_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + +#if 0 + /* use 32KHz clock signal */ + omap_cm_clk_select(PLATFORM_WKUP_CM_VBASE, 0, + OMAP_TIMER_CLKSRC_32KHZ_CLK); +#else + /* + * Assumption: Beagle board RevC manual says, + * it has 26MHz oscillator present, so we are + * assuming this oscillator is our system clock + */ + omap_cm_clk_select(PLATFORM_WKUP_CM_VBASE, 0, + OMAP_TIMER_CLKSRC_SYS_CLK); +#endif + + /* Enable Interface and Functional clock */ + omap_cm_enable_iclk(PLATFORM_WKUP_CM_VBASE, 0); + omap_cm_enable_fclk(PLATFORM_WKUP_CM_VBASE, 0); + + timer_init(PLATFORM_TIMER0_VBASE); +} + +void init_platform_irq_controller() +{ + add_boot_mapping(PLATFORM_INTC_BASE, PLATFORM_INTC_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + irq_controllers_init(); +} + +void init_platform_devices() +{ + /* Add userspace devices here as you develop their irq handlers */ + add_boot_mapping(PLATFORM_TIMER1_BASE, PLATFORM_TIMER1_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + +} + +void platform_init(void) +{ + init_platform_console(); + init_platform_timer(); + init_platform_irq_controller(); + init_platform_devices(); +} + diff --git a/src/platform/beagle/print-early.c b/src/platform/beagle/print-early.c new file mode 100644 index 0000000..dbf691f --- /dev/null +++ b/src/platform/beagle/print-early.c @@ -0,0 +1,75 @@ + +#include INC_PLAT(uart.h) +#include INC_PLAT(offsets.h) +#include INC_ARCH(io.h) + +void print_early(char *str) +{ + unsigned int reg = 0; + unsigned long uart_base; + + /* Check if mmu is on */ + __asm__ __volatile__ ( + "mrc p15, 0, %0, c1, c0" + : "=r" (reg) + : "r" (reg) + ); + + /* + * Get uart phys/virt base based on mmu on/off + * Also strings are linked at virtual address, so if + * we are running with mmu off we should translate + * string address to physical + */ + if (reg & 1) { + uart_base = PLATFORM_CONSOLE_VBASE; + } + else { + uart_base = PLATFORM_UART2_BASE; + str = (char *)(((unsigned long)str & ~KERNEL_AREA_START) | + PLATFORM_PHYS_MEM_START); + } + + /* call uart tx function */ + while (*str != '\0') { + uart_tx_char(uart_base, *str); + + if (*str == '\n') + uart_tx_char(uart_base, '\r'); + ++str; + } +} + +void printhex8(unsigned int val) +{ + char hexbuf[16]; + char *temp = hexbuf + 15; + int v; + + /* put end of string */ + *(temp--) = '\0'; + + if (!val) { + *temp = '0'; + } + else { + while (val) { + v = val & 0xf; + val = val >> 4; + --temp; + + /* convert decimal value to ascii */ + if (v >= 10) + v += ('a' - 10); + else + v = v + '0'; + + *temp = *((char *)&v); + } + } + + *(--temp) = 'x'; + *(--temp) = '0'; + print_early(temp); +} + diff --git a/src/platform/eb/SConscript b/src/platform/eb/SConscript index cd867bf..ae7a53e 100644 --- a/src/platform/eb/SConscript +++ b/src/platform/eb/SConscript @@ -1,10 +1,24 @@ # Inherit global environment -Import('env') + +import os, sys + +PROJRELROOT = '../../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import('env', 'platform', 'symbols') # The set of source files associated with this SConscript file. -src_local = ['printascii.S','platform.c', 'uart.c', 'timer.c', 'irq.c'] - +src_local = ['platform.c', 'irq.c'] obj = env.Object(src_local) + +# This is arealview platform, include corresponding files. +obj += SConscript(join(PROJROOT, 'src/platform/realview/SConscript'), exports = {'env' : env, 'symbols' : symbols}, + duplicate=0, build_dir='realview') + Return('obj') diff --git a/src/platform/eb/irq.c b/src/platform/eb/irq.c index f989812..9e97fbd 100644 --- a/src/platform/eb/irq.c +++ b/src/platform/eb/irq.c @@ -3,58 +3,61 @@ * * Copyright (C) 2007 Bahadir Balban */ -#include -#include -#include +#include #include INC_PLAT(irq.h) -#include INC_PLAT(platform.h) -#include INC_ARCH(exception.h) -#include -#include +#include -struct irq_chip irq_chip_array[IRQ_CHIPS_MAX]; -#if 0 +extern struct gic_data gic_data[IRQ_CHIPS_MAX]; + +#if defined (CONFIG_CPU_ARM11MPCORE) || defined (CONFIG_CPU_CORTEXA9) struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { - [0] = { - .name = "Vectored irq controller", + [0] = { + .name = "CoreTile GIC", .level = 0, - .cascade = IRQ_SIC, - .offset = 0, + .cascade = IRQ_NIL, + .start = 0, + .end = IRQS_MAX, + .data = &gic_data[0], .ops = { - .init = pl190_vic_init, - .read_irq = pl190_read_irq, - .ack_and_mask = pl190_mask_irq, - .unmask = pl190_unmask_irq, + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq }, - }, + }, +#if 0 [1] = { - .name = "Secondary irq controller", + .name = "EB GIC", .level = 1, .cascade = IRQ_NIL, - .offset = SIRQ_CHIP_OFFSET, + .start = EB_GIC_IRQ_OFFSET, + .end = EB_GIC_IRQ_OFFSET + IRQS_MAX, + .data = &gic_data[1], .ops = { - .init = pl190_sic_init, - .read_irq = pl190_sic_read_irq, - .ack_and_mask = pl190_sic_mask_irq, - .unmask = pl190_sic_unmask_irq, + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq, + }, + }, +#endif +}; +#else +struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { + [0] = { + .name = "EB GIC", + .level = 0, + .cascade = IRQ_NIL, + .start = 0, + .end = EB_GIC_IRQ_OFFSET + IRQS_MAX, + .data = &gic_data[1], + .ops = { + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq, }, }, }; #endif -static int platform_timer_handler(void) -{ - sp804_irq_handler(PLATFORM_TIMER0_BASE); - return do_timer_irq(); -} - -/* Built-in irq handlers initialised at compile time. - * Else register with register_irq() */ -struct irq_desc irq_desc_array[IRQS_MAX] = { - [IRQ_TIMER01] = { - .name = "Timer01", - .chip = &irq_chip_array[0], - .handler = platform_timer_handler, - }, -}; - diff --git a/src/platform/eb/platform.c b/src/platform/eb/platform.c index 8d2ffcd..dab0af0 100644 --- a/src/platform/eb/platform.c +++ b/src/platform/eb/platform.c @@ -1,64 +1,102 @@ /* * EB platform-specific initialisation and setup * - * Copyright (C) 2007 Bahadir Balban + * Copyright (C) 2009-2010 B Labs Ltd. + * Author: Prem Mallappa + * */ - #include +#include +#include INC_PLAT(offsets.h) +#include INC_ARCH(io.h) #include #include -#include INC_ARCH(linker.h) -#include INC_PLAT(printascii.h) -#include INC_SUBARCH(mm.h) -#include INC_SUBARCH(mmu_ops.h) -#include INC_GLUE(memory.h) -#include INC_GLUE(memlayout.h) -#include INC_PLAT(offsets.h) +#include #include INC_PLAT(platform.h) -#include INC_PLAT(uart.h) #include INC_PLAT(irq.h) -#include INC_ARCH(asm.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(smp.h) -void init_platform_console(void) +/* + * 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) { - add_boot_mapping(EB_UART0_BASE, PLATFORM_CONSOLE0_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + struct capability *uart[4], *timer[4]; - /* - * Map same UART IO area to userspace so that primitive uart-based - * userspace printf can work. Note, this raw mapping is to be - * removed in the future, when file-based io is implemented. - */ - add_boot_mapping(EB_UART0_BASE, USERSPACE_UART_BASE, PAGE_SIZE, - MAP_USR_IO_FLAGS); + /* Setup capabilities for userspace uarts and timers */ + uart[1] = alloc_bootmem(sizeof(*uart[1]), 0); + uart[1]->start = __pfn(PLATFORM_UART1_BASE); + uart[1]->end = uart[1]->start + 1; + uart[1]->size = uart[1]->end - uart[1]->start; + cap_set_devtype(uart[1], CAP_DEVTYPE_UART); + cap_set_devnum(uart[1], 1); + link_init(&uart[1]->list); + cap_list_insert(uart[1], &kres->devmem_free); - uart_init(); -} + uart[2] = alloc_bootmem(sizeof(*uart[2]), 0); + uart[2]->start = __pfn(PLATFORM_UART2_BASE); + uart[2]->end = uart[2]->start + 1; + uart[2]->size = uart[2]->end - uart[2]->start; + cap_set_devtype(uart[2], CAP_DEVTYPE_UART); + cap_set_devnum(uart[2], 2); + link_init(&uart[2]->list); + cap_list_insert(uart[2], &kres->devmem_free); -void init_platform_timer(void) -{ - add_boot_mapping(EB_TIMER01_BASE, PLATFORM_TIMER0_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - add_boot_mapping(EB_SYSCTRL_BASE, EB_SYSCTRL_VBASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - timer_init(); + uart[3] = alloc_bootmem(sizeof(*uart[3]), 0); + uart[3]->start = __pfn(PLATFORM_UART3_BASE); + uart[3]->end = uart[3]->start + 1; + uart[3]->size = uart[3]->end - uart[3]->start; + cap_set_devtype(uart[3], CAP_DEVTYPE_UART); + cap_set_devnum(uart[3], 3); + 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(PLATFORM_TIMER1_BASE); + timer[1]->end = timer[1]->start + 1; + timer[1]->size = timer[1]->end - timer[1]->start; + cap_set_devtype(timer[1], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[1], 1); + link_init(&timer[1]->list); + cap_list_insert(timer[1], &kres->devmem_free); + + return 0; } void init_platform_irq_controller() { -#if 0 - add_boot_mapping(PB926_VIC_BASE, PLATFORM_IRQCTRL_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - add_boot_mapping(PB926_SIC_BASE, PLATFORM_SIRQCTRL_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - irq_controllers_init(); + + unsigned int sysctrl = PLATFORM_SYSCTRL_VBASE; + write(SYSCTRL_UNLOCK, sysctrl + SYS_LOCK); + write(PLD_CTRL1_INTMOD_WITHOUT_DCC, sysctrl + SYS_PLDCTL1); + write(SYSCTRL_LOCK, sysctrl + SYS_LOCK); /* Lock again */ + +#if defined (CONFIG_CPU_ARM11MPCORE) || defined (CONFIG_CPU_CORTEXA9) + /* TODO: we need to map 64KB ?*/ + add_boot_mapping(MPCORE_PRIVATE_BASE, MPCORE_PRIVATE_VBASE, + PAGE_SIZE * 2, MAP_IO_DEFAULT); + + gic_dist_init(0, GIC0_DIST_VBASE); + gic_cpu_init(0, GIC0_CPU_VBASE); + +#else + add_boot_mapping(PLATFORM_GIC1_BASE, PLATFORM_GIC1_VBASE, PAGE_SIZE*2, + MAP_IO_DEFAULT); + + gic_dist_init(1, GIC1_DIST_VBASE); #endif + +#if !defined (CONFIG_CPU_ARM11MPCORE) && !defined (CONFIG_CPU_CORTEXA9) + gic_cpu_init(1, PLATFORM_GIC1_VBASE); +#endif + irq_controllers_init(); } -void platform_init(void) +void init_platform_devices() { - init_platform_console(); - init_platform_timer(); - init_platform_irq_controller(); -} +} diff --git a/src/platform/pb11mpcore/SConscript b/src/platform/pb11mpcore/SConscript index cd867bf..eddc49c 100644 --- a/src/platform/pb11mpcore/SConscript +++ b/src/platform/pb11mpcore/SConscript @@ -4,7 +4,10 @@ Import('env') # The set of source files associated with this SConscript file. -src_local = ['printascii.S','platform.c', 'uart.c', 'timer.c', 'irq.c'] - +src_local = ['platform.c', 'irq.c'] obj = env.Object(src_local) + +# This is arealview platform, include corresponding files. +obj += SConscript('../realview/SConscript', exports = {'env' : env}) + Return('obj') diff --git a/src/platform/pb11mpcore/irq.c b/src/platform/pb11mpcore/irq.c index f989812..6fa5ff3 100644 --- a/src/platform/pb11mpcore/irq.c +++ b/src/platform/pb11mpcore/irq.c @@ -9,8 +9,8 @@ #include INC_PLAT(irq.h) #include INC_PLAT(platform.h) #include INC_ARCH(exception.h) +#include INC_PLAT(timer.h) #include -#include struct irq_chip irq_chip_array[IRQ_CHIPS_MAX]; #if 0 @@ -42,19 +42,3 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { }; #endif -static int platform_timer_handler(void) -{ - sp804_irq_handler(PLATFORM_TIMER0_BASE); - return do_timer_irq(); -} - -/* Built-in irq handlers initialised at compile time. - * Else register with register_irq() */ -struct irq_desc irq_desc_array[IRQS_MAX] = { - [IRQ_TIMER01] = { - .name = "Timer01", - .chip = &irq_chip_array[0], - .handler = platform_timer_handler, - }, -}; - diff --git a/src/platform/pb11mpcore/platform.c b/src/platform/pb11mpcore/platform.c index 4246f43..71c2f36 100644 --- a/src/platform/pb11mpcore/platform.c +++ b/src/platform/pb11mpcore/platform.c @@ -3,12 +3,10 @@ * * Copyright (C) 2007 Bahadir Balban */ - #include #include #include #include INC_ARCH(linker.h) -#include INC_PLAT(printascii.h) #include INC_SUBARCH(mm.h) #include INC_SUBARCH(mmu_ops.h) #include INC_GLUE(memory.h) @@ -19,49 +17,101 @@ #include INC_PLAT(irq.h) #include INC_ARCH(asm.h) -void init_platform_console(void) +/* + * 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) { - add_boot_mapping(PB11MPCORE_UART0_BASE, PLATFORM_CONSOLE0_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + struct capability *uart[4], *timer[4]; - /* - * Map same UART IO area to userspace so that primitive uart-based - * userspace printf can work. Note, this raw mapping is to be - * removed in the future, when file-based io is implemented. - */ - add_boot_mapping(PB11MPCORE_UART0_BASE, USERSPACE_UART_BASE, PAGE_SIZE, - MAP_USR_IO_FLAGS); + /* Setup capabilities for userspace uarts and timers */ + uart[1] = alloc_bootmem(sizeof(*uart[1]), 0); + uart[1]->start = __pfn(PLATFORM_UART1_BASE); + uart[1]->end = uart[1]->start + 1; + uart[1]->size = uart[1]->end - uart[1]->start; + cap_set_devtype(uart[1], CAP_DEVTYPE_UART); + cap_set_devnum(uart[1], 1); + link_init(&uart[1]->list); + cap_list_insert(uart[1], &kres->devmem_free); - uart_init(); -} + uart[2] = alloc_bootmem(sizeof(*uart[2]), 0); + uart[2]->start = __pfn(PLATFORM_UART2_BASE); + uart[2]->end = uart[2]->start + 1; + uart[2]->size = uart[2]->end - uart[2]->start; + cap_set_devtype(uart[2], CAP_DEVTYPE_UART); + cap_set_devnum(uart[2], 2); + link_init(&uart[2]->list); + cap_list_insert(uart[2], &kres->devmem_free); -void init_platform_timer(void) -{ - add_boot_mapping(PB11MPCORE_TIMER01_BASE, PLATFORM_TIMER0_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - add_boot_mapping(PB11MPCORE_SYSCTRL0_BASE, PB11MPCORE_SYSCTRL0_VBASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - /* TODO: SYSCTRL1 mapping may be needed */ - add_boot_mapping(PB11MPCORE_SYSCTRL1_BASE, PB11MPCORE_SYSCTRL1_VBASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - timer_init(); + uart[3] = alloc_bootmem(sizeof(*uart[3]), 0); + uart[3]->start = __pfn(PLATFORM_UART3_BASE); + uart[3]->end = uart[3]->start + 1; + uart[3]->size = uart[3]->end - uart[3]->start; + cap_set_devtype(uart[3], CAP_DEVTYPE_UART); + cap_set_devnum(uart[3], 3); + 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(PLATFORM_TIMER1_BASE); + timer[1]->end = timer[1]->start + 1; + timer[1]->size = timer[1]->end - timer[1]->start; + cap_set_devtype(timer[1], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[1], 1); + 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(PLATFORM_TIMER2_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], 1); + 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(PLATFORM_TIMER3_BASE); + 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], 1); + link_init(&timer[3]->list); + cap_list_insert(timer[3], &kres->devmem_free); + + return 0; } void init_platform_irq_controller() { #if 0 add_boot_mapping(PB926_VIC_BASE, PLATFORM_IRQCTRL_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + MAP_IO_DEFAULT); add_boot_mapping(PB926_SIC_BASE, PLATFORM_SIRQCTRL_BASE, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + MAP_IO_DEFAULT); irq_controllers_init(); #endif } -void platform_init(void) +void init_platform_devices() { - init_platform_console(); - init_platform_timer(); - init_platform_irq_controller(); + /* We need SYSCTRL1 for initializing TIMER2 and 3 */ + add_boot_mapping(PLATFORM_SYSCTRL1_BASE, PLATFORM_SYSCTRL1_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + /* Add userspace devices here as you develop their irq handlers */ + add_boot_mapping(PLATFORM_TIMER1_BASE, PLATFORM_TIMER1_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + add_boot_mapping(PLATFORM_TIMER2_BASE, PLATFORM_TIMER2_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + add_boot_mapping(PLATFORM_TIMER3_BASE, PLATFORM_TIMER3_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); } diff --git a/src/platform/pb926/SConscript b/src/platform/pb926/SConscript index cd867bf..d16ecf3 100644 --- a/src/platform/pb926/SConscript +++ b/src/platform/pb926/SConscript @@ -4,7 +4,7 @@ Import('env') # The set of source files associated with this SConscript file. -src_local = ['printascii.S','platform.c', 'uart.c', 'timer.c', 'irq.c'] +src_local = ['print-early.c','platform.c', 'irq.c'] obj = env.Object(src_local) Return('obj') diff --git a/src/platform/pb926/irq.c b/src/platform/pb926/irq.c index e2e0c53..b5c451a 100644 --- a/src/platform/pb926/irq.c +++ b/src/platform/pb926/irq.c @@ -8,9 +8,9 @@ #include #include INC_PLAT(irq.h) #include INC_PLAT(platform.h) +#include INC_PLAT(timer.h) #include INC_ARCH(exception.h) #include -#include struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { [0] = { @@ -47,10 +47,25 @@ static int platform_timer_handler(struct irq_desc *desc) * Microkernel is using just TIMER0, * so we call handler with TIMER01 index */ - sp804_irq_handler(PLATFORM_TIMER0_VIRTUAL); + timer_irq_clear(PLATFORM_TIMER0_VBASE); return do_timer_irq(); } +/* + * Timer handler for userspace + */ +static int platform_timer_user_handler(struct irq_desc *desc) +{ + /* Ack the device irq */ + timer_irq_clear(PLATFORM_TIMER1_VBASE); + + /* Notify the userspace */ + irq_thread_notify(desc); + + return 0; +} + + /* * Built-in irq handlers initialised at compile time. * Else register with register_irq() @@ -61,5 +76,13 @@ struct irq_desc irq_desc_array[IRQS_MAX] = { .chip = &irq_chip_array[0], .handler = platform_timer_handler, }, + [IRQ_TIMER1] = { + .name = "Timer1", + .chip = &irq_chip_array[0], + .handler = platform_timer_user_handler, + }, }; + + + diff --git a/src/platform/pb926/platform.c b/src/platform/pb926/platform.c index 5ecdeee..ac81f9b 100644 --- a/src/platform/pb926/platform.c +++ b/src/platform/pb926/platform.c @@ -8,16 +8,20 @@ #include #include #include INC_ARCH(linker.h) -#include INC_PLAT(printascii.h) #include INC_SUBARCH(mm.h) #include INC_SUBARCH(mmu_ops.h) #include INC_GLUE(memory.h) +#include INC_GLUE(mapping.h) #include INC_GLUE(memlayout.h) #include INC_PLAT(offsets.h) #include INC_PLAT(platform.h) #include INC_PLAT(uart.h) +#include INC_PLAT(timer.h) #include INC_PLAT(irq.h) #include INC_ARCH(asm.h) +#include INC_ARCH(io.h) +#include +#include /* * The devices that are used by the kernel are mapped @@ -26,11 +30,11 @@ */ int platform_setup_device_caps(struct kernel_resources *kres) { - struct capability *uart[4], *timer[4], *clcd[1]; + struct capability *uart[4], *timer[2]; /* Setup capabilities for userspace uarts and timers */ uart[1] = alloc_bootmem(sizeof(*uart[1]), 0); - uart[1]->start = __pfn(PB926_UART1_BASE); + uart[1]->start = __pfn(PLATFORM_UART1_BASE); uart[1]->end = uart[1]->start + 1; uart[1]->size = uart[1]->end - uart[1]->start; cap_set_devtype(uart[1], CAP_DEVTYPE_UART); @@ -39,7 +43,7 @@ int platform_setup_device_caps(struct kernel_resources *kres) 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]->start = __pfn(PLATFORM_UART2_BASE); uart[2]->end = uart[2]->start + 1; uart[2]->size = uart[2]->end - uart[2]->start; cap_set_devtype(uart[2], CAP_DEVTYPE_UART); @@ -48,7 +52,7 @@ int platform_setup_device_caps(struct kernel_resources *kres) 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]->start = __pfn(PLATFORM_UART3_BASE); uart[3]->end = uart[3]->start + 1; uart[3]->size = uart[3]->end - uart[3]->start; cap_set_devtype(uart[3], CAP_DEVTYPE_UART); @@ -58,7 +62,7 @@ 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(PLATFORM_TIMER1_BASE); 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,34 +70,27 @@ int platform_setup_device_caps(struct kernel_resources *kres) link_init(&timer[1]->list); cap_list_insert(timer[1], &kres->devmem_free); - /* Setup clcd capability as free */ - clcd[0] = alloc_bootmem(sizeof(*clcd[0]), 0); - clcd[0]->start = __pfn(PB926_CLCD_BASE); - clcd[0]->end = clcd[0]->start + 1; - clcd[0]->size = clcd[0]->end - clcd[0]->start; - cap_set_devtype(clcd[0], CAP_DEVTYPE_CLCD); - cap_set_devnum(clcd[0], 0); - link_init(&clcd[0]->list); - cap_list_insert(clcd[0], &kres->devmem_free); - return 0; } -/* We will use UART0 for kernel as well as user tasks, so map it to kernel and user space */ +/* + * 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_CONSOLE_VIRTUAL, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + add_boot_mapping(PLATFORM_UART0_BASE, PLATFORM_CONSOLE_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); /* * Map same UART IO area to userspace so that primitive uart-based * userspace printf can work. Note, this raw mapping is to be * removed in the future, when file-based io is implemented. */ - add_boot_mapping(PB926_UART0_BASE, USERSPACE_CONSOLE_VIRTUAL, PAGE_SIZE, - MAP_USR_IO_FLAGS); + add_boot_mapping(PLATFORM_UART0_BASE, USERSPACE_CONSOLE_VBASE, + PAGE_SIZE, MAP_USR_IO); - uart_init(); + uart_init(PLATFORM_CONSOLE_VBASE); } /* @@ -103,28 +100,65 @@ void init_platform_console(void) */ void init_platform_timer(void) { - add_boot_mapping(PB926_TIMER01_BASE, PLATFORM_TIMER0_VIRTUAL, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + add_boot_mapping(PLATFORM_TIMER0_BASE, PLATFORM_TIMER0_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); - add_boot_mapping(PB926_SYSCTRL_BASE, PLATFORM_SYSCTRL_VIRTUAL, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - - timer_init(); + /* 1 Mhz means can tick up to 1,000,000 times a second */ + timer_init(PLATFORM_TIMER0_VBASE, 1000000 / CONFIG_SCHED_TICKS); } void init_platform_irq_controller() { - add_boot_mapping(PB926_VIC_BASE, PLATFORM_IRQCTRL0_VIRTUAL, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); - add_boot_mapping(PB926_SIC_BASE, PLATFORM_IRQCTRL1_VIRTUAL, PAGE_SIZE, - MAP_IO_DEFAULT_FLAGS); + add_boot_mapping(PLATFORM_VIC_BASE, PLATFORM_IRQCTRL0_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + add_boot_mapping(PLATFORM_SIC_BASE, PLATFORM_IRQCTRL1_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); irq_controllers_init(); } +void init_platform_devices() +{ + /* Add userspace devices here as you develop their irq handlers */ + add_boot_mapping(PLATFORM_TIMER1_BASE, PLATFORM_TIMER1_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); +} + +/* If these bits are off, 32Khz OSC source is used */ +#define TIMER3_SCTRL_1MHZ (1 << 21) +#define TIMER2_SCTRL_1MHZ (1 << 19) +#define TIMER1_SCTRL_1MHZ (1 << 17) +#define TIMER0_SCTRL_1MHZ (1 << 15) + +/* Set all timers to use 1Mhz OSC clock */ +void init_timer_osc(void) +{ + volatile u32 reg; + + add_boot_mapping(PLATFORM_SYSCTRL_BASE, PLATFORM_SYSCTRL_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + reg = read(SP810_SCCTRL); + + write(reg | TIMER0_SCTRL_1MHZ | TIMER1_SCTRL_1MHZ + | TIMER2_SCTRL_1MHZ | TIMER3_SCTRL_1MHZ, + SP810_SCCTRL); +} + +void platform_timer_start(void) +{ + /* Enable irq line for TIMER0 */ + irq_enable(IRQ_TIMER0); + + /* Enable timer */ + timer_start(PLATFORM_TIMER0_VBASE); +} + void platform_init(void) { + init_timer_osc(); init_platform_console(); init_platform_timer(); init_platform_irq_controller(); + init_platform_devices(); } diff --git a/src/platform/pb926/print-early.c b/src/platform/pb926/print-early.c new file mode 100644 index 0000000..3a35cce --- /dev/null +++ b/src/platform/pb926/print-early.c @@ -0,0 +1,75 @@ + +#include INC_PLAT(uart.h) +#include INC_PLAT(offsets.h) +#include INC_ARCH(io.h) + +void print_early(char *str) +{ + unsigned int reg = 0; + unsigned long uart_base; + + /* Check if mmu is on */ + __asm__ __volatile__ ( + "mrc p15, 0, %0, c1, c0" + : "=r" (reg) + : "r" (reg) + ); + + /* + * Get uart phys/virt base based on mmu on/off + * Also strings are linked at virtual address, so if + * we are running with mmu off we should translate + * string address to physical + */ + if (reg & 1) { + uart_base = PLATFORM_CONSOLE_VBASE; + } + else { + uart_base = PLATFORM_UART0_BASE; + str = (char *)(((unsigned long)str & ~KERNEL_AREA_START) | + PLATFORM_PHYS_MEM_START); + } + + /* call uart tx function */ + while (*str != '\0') { + uart_tx_char(uart_base, *str); + + if (*str == '\n') + uart_tx_char(uart_base, '\r'); + + ++str; + } +} + +void printhex8(unsigned int val) +{ + char hexbuf[16]; + char *temp = hexbuf + 15; + int v; + + /* put end of string */ + *(temp--) = '\0'; + + if (!val) { + *temp = '0'; + } + else { + while (val) { + v = val & 0xf; + val = val >> 4; + --temp; + + /* convert decimal value to ascii */ + if (v >= 10) + v += ('a' - 10); + else + v = v + '0'; + + *temp = *((char *)&v); + } + } + + *(--temp) = 'x'; + *(--temp) = '0'; + print_early(temp); +} diff --git a/src/platform/pba8/SConscript b/src/platform/pba8/SConscript new file mode 100644 index 0000000..ae7a53e --- /dev/null +++ b/src/platform/pba8/SConscript @@ -0,0 +1,24 @@ + + +# Inherit global environment + +import os, sys + +PROJRELROOT = '../../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import('env', 'platform', 'symbols') + +# The set of source files associated with this SConscript file. +src_local = ['platform.c', 'irq.c'] +obj = env.Object(src_local) + +# This is arealview platform, include corresponding files. +obj += SConscript(join(PROJROOT, 'src/platform/realview/SConscript'), exports = {'env' : env, 'symbols' : symbols}, + duplicate=0, build_dir='realview') + +Return('obj') diff --git a/src/platform/pba8/irq.c b/src/platform/pba8/irq.c new file mode 100644 index 0000000..d1a730f --- /dev/null +++ b/src/platform/pba8/irq.c @@ -0,0 +1,65 @@ +/* + * Support for generic irq handling using platform irq controller (PL190) + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include INC_PLAT(irq.h) +#include + +extern struct gic_data gic_data[IRQ_CHIPS_MAX]; + +struct irq_chip irq_chip_array[IRQ_CHIPS_MAX]; +#if 0 +#ifdef CONFIG_CPU_ARM11MPCORE +struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { + [0] = { + .name = "CoreTile GIC", + .level = 0, + .cascade = MPCORE_GIC_IRQ_EB_GIC1, + .start = 0, + .end = IRQS_MAX, + .data = &gic_data[0], + .ops = { + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq + }, + }, + + [1] = { + .name = "EB GIC", + .level = 1, + .cascade = IRQ_NIL, + .start = EB_GIC_IRQ_OFFSET, + .end = EB_GIC_IRQ_OFFSET + IRQS_MAX, + .data = &gic_data[1], + .ops = { + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq, + }, + }, + +}; +#else +struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { + [0] = { + .name = "EB GIC", + .level = 0, + .cascade = IRQ_NIL, + .start = 0, + .end = EB_GIC_IRQ_OFFSET + IRQS_MAX, + .data = &gic_data[1], + .ops = { + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq, + }, + }, +}; +#endif +#endif diff --git a/src/platform/pba8/platform.c b/src/platform/pba8/platform.c new file mode 100644 index 0000000..0dce1f7 --- /dev/null +++ b/src/platform/pba8/platform.c @@ -0,0 +1,97 @@ +/* + * EB platform-specific initialisation and setup + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include INC_PLAT(offsets.h) +#include INC_ARCH(io.h) +#include +#include +#include +#include INC_PLAT(platform.h) +#include INC_PLAT(irq.h) +#include INC_GLUE(mapping.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) +{ +#if 0 + struct capability *uart[4], *timer[4]; + + /* Setup capabilities for userspace uarts and timers */ + uart[1] = alloc_bootmem(sizeof(*uart[1]), 0); + uart[1]->start = __pfn(PLATFORM_UART1_BASE); + uart[1]->end = uart[1]->start + 1; + uart[1]->size = uart[1]->end - uart[1]->start; + cap_set_devtype(uart[1], CAP_DEVTYPE_UART); + cap_set_devnum(uart[1], 1); + 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(PLATFORM_UART2_BASE); + uart[2]->end = uart[2]->start + 1; + uart[2]->size = uart[2]->end - uart[2]->start; + cap_set_devtype(uart[2], CAP_DEVTYPE_UART); + cap_set_devnum(uart[2], 2); + 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(PLATFORM_UART3_BASE); + uart[3]->end = uart[3]->start + 1; + uart[3]->size = uart[3]->end - uart[3]->start; + cap_set_devtype(uart[3], CAP_DEVTYPE_UART); + cap_set_devnum(uart[3], 3); + 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(PLATFORM_TIMER1_BASE); + timer[1]->end = timer[1]->start + 1; + timer[1]->size = timer[1]->end - timer[1]->start; + cap_set_devtype(timer[1], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[1], 1); + link_init(&timer[1]->list); + cap_list_insert(timer[1], &kres->devmem_free); +#endif + return 0; +} + +void init_platform_irq_controller() +{ +#if 0 + unsigned int sysctrl = PLATFORM_SYSCTRL_VBASE; + write(SYSCTRL_UNLOCK, sysctrl + SYS_LOCK); + write(PLD_CTRL1_INTMOD_WITHOUT_DCC, sysctrl+SYS_PLDCTL1); + write(SYSCTRL_LOCK, sysctrl + SYS_LOCK); /* Lock again */ +#ifdef CONFIG_CPU_ARM11MPCORE + /* TODO: we need to map 64KB ?*/ + add_boot_mapping(ARM11MP_PRIVATE_MEM_BASE, EB_MPCORE_PRIV_MEM_VBASE, + PAGE_SIZE*2, MAP_IO_DEFAULT); + + gic_dist_init(0, GIC0_DIST_VBASE); + gic_cpu_init(0, GIC0_CPU_VBASE); + +#endif + add_boot_mapping(PLATFORM_GIC1_BASE, PLATFORM_GIC1_VBASE, PAGE_SIZE*2, + MAP_IO_DEFAULT); + + gic_dist_init(1, GIC1_DIST_VBASE); + gic_cpu_init(1, PLATFORM_GIC1_VBASE); + + irq_controllers_init(); +#endif +} + +void init_platform_devices() +{ + +} diff --git a/src/platform/pba9/SConscript b/src/platform/pba9/SConscript new file mode 100644 index 0000000..ae7a53e --- /dev/null +++ b/src/platform/pba9/SConscript @@ -0,0 +1,24 @@ + + +# Inherit global environment + +import os, sys + +PROJRELROOT = '../../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import('env', 'platform', 'symbols') + +# The set of source files associated with this SConscript file. +src_local = ['platform.c', 'irq.c'] +obj = env.Object(src_local) + +# This is arealview platform, include corresponding files. +obj += SConscript(join(PROJROOT, 'src/platform/realview/SConscript'), exports = {'env' : env, 'symbols' : symbols}, + duplicate=0, build_dir='realview') + +Return('obj') diff --git a/src/platform/pba9/irq.c b/src/platform/pba9/irq.c new file mode 100644 index 0000000..b844c89 --- /dev/null +++ b/src/platform/pba9/irq.c @@ -0,0 +1,32 @@ +/* + * Platform generic irq handling + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include INC_PLAT(irq.h) +#include INC_PLAT(platform.h) +#include INC_ARCH(exception.h) +#include + +extern struct gic_data gic_data[IRQ_CHIPS_MAX]; + +struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = { + [0] = { + .name = "VX-A9 GIC", + .level = 0, + .cascade = IRQ_NIL, + .start = 0, + .end = IRQ_OFFSET + IRQS_MAX, + .data = &gic_data[0], + .ops = { + .init = gic_dummy_init, + .read_irq = gic_read_irq, + .ack_and_mask = gic_ack_and_mask, + .unmask = gic_unmask_irq, + }, + }, +}; + diff --git a/src/platform/pba9/platform.c b/src/platform/pba9/platform.c new file mode 100644 index 0000000..a802b29 --- /dev/null +++ b/src/platform/pba9/platform.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include +#include +#include INC_ARCH(linker.h) +#include INC_SUBARCH(mm.h) +#include INC_SUBARCH(mmu_ops.h) +#include INC_GLUE(memory.h) +#include INC_GLUE(memlayout.h) +#include INC_PLAT(offsets.h) +#include INC_PLAT(platform.h) +#include INC_PLAT(irq.h) +#include INC_ARCH(asm.h) +#include INC_GLUE(mapping.h) +#include +#include +#include + +/* + * 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 *timer[2]; + + /* Setup timer1 capability as free */ + timer[1] = alloc_bootmem(sizeof(*timer[1]), 0); + timer[1]->start = __pfn(PLATFORM_TIMER1_BASE); + timer[1]->end = timer[1]->start + 1; + timer[1]->size = timer[1]->end - timer[1]->start; + cap_set_devtype(timer[1], CAP_DEVTYPE_TIMER); + cap_set_devnum(timer[1], 1); + link_init(&timer[1]->list); + cap_list_insert(timer[1], &kres->devmem_free); + + return 0; +} + +void init_platform_irq_controller() +{ + /* TODO: we need to map 64KB ?*/ + add_boot_mapping(MPCORE_PRIVATE_BASE, MPCORE_PRIVATE_VBASE, + PAGE_SIZE * 2, MAP_IO_DEFAULT); + + gic_dist_init(0, GIC0_DIST_VBASE); + gic_cpu_init(0, GIC0_CPU_VBASE); + irq_controllers_init(); +} + +void init_platform_devices() +{ +} + diff --git a/src/platform/realview/SConscript b/src/platform/realview/SConscript new file mode 100644 index 0000000..8be0e9d --- /dev/null +++ b/src/platform/realview/SConscript @@ -0,0 +1,22 @@ + +# Inherit global environment +import os, sys, glob + +PROJRELROOT = '../../' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from configure import * + +Import('env', 'symbols') + +# The set of source files associated with this SConscript file. +src_local = ['irq.c', 'platform.c', 'print-early.c', 'perfmon.c', 'cpuperf.S'] + +for name, val in symbols: + if 'CONFIG_SMP' == name: + src_local += ['smp.c'] + +obj = env.Object(src_local) +Return('obj') diff --git a/src/platform/realview/cpuperf.S b/src/platform/realview/cpuperf.S new file mode 100644 index 0000000..d09a7fe --- /dev/null +++ b/src/platform/realview/cpuperf.S @@ -0,0 +1,49 @@ +/* + * CPU cycles per timer tick + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ + +#define CPUOP_NOOP 0 +#define CPUOP_MEMORY 1 + +#include INC_ARCH(asm.h) + + .section .text +/* + * Default: + * Go for 1000 CPU cycles on no ops and calculate + * how many timer ticks it takes. + * + * By default timer is expected to tick per 1/1,000,000 second, + * has been preloaded, and initialized for enabling. All we do + * here is enable it, do our ops and read back the counter + * difference. + * + * r0 = timer enable address + * r1 = timer value address + * r2 = op type + * r3 = op count + * return = how many timer ticks + */ +BEGIN_PROC(cpu_do_cycles_and_tick) + stmfd sp!, {r4, lr} @ Make room for new data in r4-5 + ldr r4, [r1] @ Load timer value to r5 + str r2, [r0] @ Start the timer. +1: + subs r3, r3, #1 @ Decrement count + bhi 1b +finish: + ldr r0, [r1, #4] @ Load current value, from load register + 4 + sub r0, r4, r0 @ Return difference between original and read + ldmfd sp!, {r4, pc} @ Restore R4-R5, pc + + +BEGIN_PROC(busy_loop) + subs r0, r0, #1 + bhi busy_loop + mov pc, lr +END_PROC(busy_loop) + diff --git a/src/platform/realview/irq.c b/src/platform/realview/irq.c new file mode 100644 index 0000000..f47f9ed --- /dev/null +++ b/src/platform/realview/irq.c @@ -0,0 +1,30 @@ +/* + * Support for generic irq handling. + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include INC_PLAT(offsets.h) +#include INC_PLAT(irq.h) +#include + +static int platform_timer_handler(struct irq_desc *desc) +{ + timer_irq_clear(PLATFORM_TIMER0_VBASE); + + return do_timer_irq(); +} + +/* + * Built-in irq handlers initialised at compile time. + * Else register with register_irq() + */ +struct irq_desc irq_desc_array[IRQS_MAX] = { + [IRQ_TIMER0] = { + .name = "Timer0", + .chip = &irq_chip_array[0], + .handler = platform_timer_handler, + }, +}; + diff --git a/src/platform/realview/perfmon.c b/src/platform/realview/perfmon.c new file mode 100644 index 0000000..76ea891 --- /dev/null +++ b/src/platform/realview/perfmon.c @@ -0,0 +1,222 @@ +/* + * Platform specific perfmon initialization + * + * Copyright (C) 2010 B Labs Ltd. + * + * Author: Bahadir Balban + */ +#include +#include +#include INC_PLAT(offsets.h) +#include INC_SUBARCH(perfmon.h) +#include INC_SUBARCH(mmu_ops.h) + +/* + * Current findings by these tests: + * + * Cpu cycle count and timer ticks are consistently showing 400Mhz + * with a reference timer tick of 1Mhz. So cycle counts are fixed + * with regard to the timer. + * + * Instruction execute count on the busy_loop however, is varying + * between x1, x2 combinations when compared to timer and cycle + * count values. This is happening by trivial changes in code such + * as adding a function call. (Other variables are ruled out, e.g. + * no concurrent memory accesses, caches are off) + * + * There may be two causes to this: + * - Due to missing dmb/dsb/isb instructions. + * - Due to BTC (busy_loop has one branch) which may describe + * the doubling in IPC, since out of the 2 instructions in the + * busy loop one is a branch. + * + * Disabling the BTC increased cycle counts per instruction + * significantly, advising us not to expect any accuracy in counting + * instructions in cycles. Hence instruction-based tests are + * commented out. It is wise to only rely upon timer and cycle counts. + */ + +#if 0 +void busy_loop(int times); + +void platform_test_loop_cycles() +{ + const int looptotal = 1000000; + int cyccnt, loops = looptotal; + int inst_per_loop = 2; + int ipc_whole, ipc_decimal, temp; + + /* Test the basic cycle counter */ + perfmon_reset_start_cyccnt(); + isb(); + + busy_loop(loops); + + /* Finish all earlier instructions */ + isb(); + + cyccnt = perfmon_read_cyccnt(); + + /* Finish reading cyccnt */ + isb(); + + /* + * Do some fixed point division + * + * The idea is to multiply by 10, divide by 10 and + * get the remainder. Remainder becomes the decimal + * part. The division result is the whole part. + */ + temp = inst_per_loop * looptotal * 10 / (cyccnt * 64); + ipc_whole = temp / 10; + ipc_decimal = temp - ipc_whole * 10; + + printk("Perfmon: %d cycles/%d instructions\n", + cyccnt * 64, inst_per_loop * looptotal); + printk("Perfmon: %d.%d Inst/cycle\n", + ipc_whole, ipc_decimal); +} + +void platform_test_loop_ticks() +{ + /* Initialize the timer */ + unsigned long timer_base = + PLATFORM_TIMER0_VBASE + SP804_TIMER1_OFFSET; + volatile u32 reg = read(timer_base + SP804_CTRL); + + const int looptotal = 500000; + int ticks, loops = looptotal; + int inst_per_loop = 2; + const int timer_load = 0xFFFFFFFF; + int timer_read; + int ipm_whole, ipm_decimal, temp; + + /* Make sure timer is disabled */ + write(0, timer_base + SP804_CTRL); + + /* Load the timer with a full value */ + write(timer_load, timer_base + SP804_LOAD); + + /* One shot, 32 bits, no irqs */ + reg = SP804_32BIT | SP804_ONESHOT | SP804_ENABLE; + + /* Start the timer */ + write(reg, timer_base + SP804_CTRL); + dmb(); /* Make sure write occurs before looping */ + + busy_loop(loops); + + timer_read = read(timer_base + SP804_VALUE); + + ticks = timer_load - timer_read; + + temp = (inst_per_loop * looptotal) * 10 / ticks; + ipm_whole = temp / 10; + ipm_decimal = temp - ipm_whole * 10; + + printk("Perfmon: %d ticks/%d instructions\n", + ticks, inst_per_loop * looptotal); + + printk("Perfmon: %d%d instr/Mhz.\n", + ipm_whole, ipm_decimal); +} + + +void platform_test_tick_cycles() +{ + /* Initialize the timer */ + unsigned long timer_base = + PLATFORM_TIMER0_VBASE + SP804_TIMER1_OFFSET; + volatile u32 reg = read(timer_base + SP804_CTRL); + const int timer_load = 1000; + int mhz_top, mhz_bot, temp; + int cyccnt; + + /* Make sure timer is disabled */ + write(0, timer_base + SP804_CTRL); + + /* Load the timer with ticks value */ + write(timer_load, timer_base + SP804_LOAD); + + /* One shot, 32 bits, no irqs */ + reg = SP804_32BIT | SP804_ONESHOT | SP804_ENABLE; + + /* Start the timer */ + write(reg, timer_base + SP804_CTRL); + + /* Start counter */ + perfmon_reset_start_cyccnt(); + + /* Wait until 0 */ + while (read(timer_base + SP804_VALUE) != 0) + ; + + cyccnt = perfmon_read_cyccnt(); + + /* Fixed-point accuracy on bottom digit */ + temp = cyccnt * 64 * 10 / timer_load; + mhz_top = temp / 10; + mhz_bot = temp - mhz_top * 10; + + //printk("Perfmon: %u cycles/%dMhz\n", + // cyccnt * 64, timer_load); + printk("%s: %d.%d MHz CPU speed measured by timer REFCLK at 1MHz\n", + __KERNELNAME__, mhz_top, mhz_bot); +} + +#endif + +void platform_test_tick_cycles() +{ + /* Initialize the timer */ + const int load_value = 1000; + int mhz_top, mhz_bot, temp; + unsigned long timer_base = + timer_secondary_base(PLATFORM_TIMER0_VBASE); + int cyccnt; + + /* Make sure timer is disabled */ + timer_stop(timer_base); + + /* Load the timer with ticks value */ + timer_load(load_value, timer_base); + + /* One shot, 32 bits, no irqs */ + timer_init_oneshot(timer_base); + + /* Start the timer */ + timer_start(timer_base); + + /* Start counter */ + perfmon_reset_start_cyccnt(); + + /* Wait until 0 */ + while (timer_read(timer_base) != 0) + ; + + cyccnt = perfmon_read_cyccnt(); + + /* Fixed-point accuracy on bottom digit */ + temp = cyccnt * 64 * 10 / load_value; + mhz_top = temp / 10; + mhz_bot = temp - mhz_top * 10; + + //printk("Perfmon: %u cycles/%dMhz\n", + // cyccnt * 64, timer_load); + printk("%s: %d.%d MHz CPU speed measured by timer REFCLK at 1MHz\n", + __KERNELNAME__, mhz_top, mhz_bot); +} + +void platform_test_cpucycles(void) +{ + /* + * Variable results: + * + * platform_test_loop_cycles(); + * platform_test_loop_ticks(); + */ + + /* Fixed result */ + platform_test_tick_cycles(); +} + diff --git a/src/platform/realview/platform.c b/src/platform/realview/platform.c new file mode 100644 index 0000000..5f3ee7f --- /dev/null +++ b/src/platform/realview/platform.c @@ -0,0 +1,88 @@ +/* + * Realview generic initialisation and setup + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include INC_PLAT(offsets.h) +#include INC_GLUE(mapping.h) +#include INC_GLUE(smp.h) +#include +#include +#include +#include INC_PLAT(platform.h) +#include INC_ARCH(io.h) + +/* 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(PLATFORM_UART0_BASE, PLATFORM_CONSOLE_VBASE, PAGE_SIZE, + MAP_IO_DEFAULT); + + /* + * Map same UART IO area to userspace so that primitive uart-based + * userspace printf can work. Note, this raw mapping is to be + * removed in the future, when file-based io is implemented. + */ + add_boot_mapping(PLATFORM_UART0_BASE, USERSPACE_CONSOLE_VBASE, PAGE_SIZE, + MAP_USR_IO); + + uart_init(PLATFORM_CONSOLE_VBASE); +} + +void platform_timer_start(void) +{ + /* Enable irq line for TIMER0 */ + irq_enable(IRQ_TIMER0); + + /* Enable timer */ + timer_start(PLATFORM_TIMER0_VBASE); +} + +void init_platform_timer(void) +{ + add_boot_mapping(PLATFORM_TIMER0_BASE, PLATFORM_TIMER0_VBASE, PAGE_SIZE, + MAP_IO_DEFAULT); + + /* 1 Mhz means can tick up to 1,000,000 times a second */ + timer_init(PLATFORM_TIMER0_VBASE, 1000000 / CONFIG_SCHED_TICKS); +} + +/* If these bits are off, 32Khz OSC source is used */ +#define TIMER3_SCTRL_1MHZ (1 << 21) +#define TIMER2_SCTRL_1MHZ (1 << 19) +#define TIMER1_SCTRL_1MHZ (1 << 17) +#define TIMER0_SCTRL_1MHZ (1 << 15) + +/* Set all timers to use 1Mhz OSC clock */ +void init_timer_osc(void) +{ + volatile u32 reg; + + add_boot_mapping(PLATFORM_SYSCTRL_BASE, PLATFORM_SYSCTRL_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + + reg = read(SP810_SCCTRL); + + reg |= TIMER0_SCTRL_1MHZ | TIMER1_SCTRL_1MHZ + | TIMER2_SCTRL_1MHZ | TIMER3_SCTRL_1MHZ; + + write(reg, SP810_SCCTRL); + +} + +void platform_init(void) +{ + init_timer_osc(); + init_platform_console(); + init_platform_timer(); + init_platform_irq_controller(); + init_platform_devices(); + +#if defined (CONFIG_SMP) + init_smp(); + scu_init(); +#endif +} + diff --git a/src/platform/realview/print-early.c b/src/platform/realview/print-early.c new file mode 100644 index 0000000..05e598d --- /dev/null +++ b/src/platform/realview/print-early.c @@ -0,0 +1,82 @@ + +#include +#include +#include INC_PLAT(offsets.h) +#include INC_ARCH(io.h) + +extern struct spinlock printk_lock; + +void print_early(char *str) +{ + unsigned int reg = 0; + unsigned long uart_base; + unsigned long irq_state; + + /* Check if mmu is on */ + __asm__ __volatile__ ( + "mrc p15, 0, %0, c1, c0" + : "=r" (reg) + : "r" (reg) + ); + + /* + * Get uart phys/virt base based on mmu on/off + * Also strings are linked at virtual address, so if + * we are running with mmu off we should translate + * string address to physical + */ + if (reg & 1) { + spin_lock_irq(&printk_lock, &irq_state); + uart_base = PLATFORM_CONSOLE_VBASE; + } + else { + uart_base = PLATFORM_UART0_BASE; + str = (char *)(((unsigned long)str & ~KERNEL_AREA_START) | + PLATFORM_PHYS_MEM_START); + } + + /* call uart tx function */ + while (*str != '\0') { + uart_tx_char(uart_base, *str); + + if (*str == '\n') + uart_tx_char(uart_base, '\r'); + + ++str; + } + if (reg & 1) + spin_unlock_irq(&printk_lock, irq_state); +} + +void printhex8(unsigned int val) +{ + char hexbuf[16]; + char *temp = hexbuf + 15; + int v; + + /* put end of string */ + *(temp--) = '\0'; + + if (!val) { + *temp = '0'; + } + else { + while (val) { + v = val & 0xf; + val = val >> 4; + --temp; + + /* convert decimal value to ascii */ + if (v >= 10) + v += ('a' - 10); + else + v = v + '0'; + + *temp = *((char *)&v); + } + } + + *(--temp) = 'x'; + *(--temp) = '0'; + print_early(temp); +} diff --git a/src/platform/realview/smp.c b/src/platform/realview/smp.c new file mode 100644 index 0000000..b46fb64 --- /dev/null +++ b/src/platform/realview/smp.c @@ -0,0 +1,94 @@ +/* + * Copyright 2010 B Labs.Ltd. + * + * Author: Prem Mallappa + * + * Description: SMP related platform definitions + */ +#include +#include INC_ARCH(io.h) +#include INC_SUBARCH(proc.h) +#include INC_PLAT(platform.h) +#include INC_PLAT(offsets.h) +#include INC_PLAT(sysctrl.h) +#include INC_GLUE(smp.h) +#include INC_GLUE(ipi.h) +#include INC_GLUE(mapping.h) +#include INC_SUBARCH(cpu.h) +#include +#include +#include + + +extern struct irq_desc irq_desc_array[IRQS_MAX]; + +/* Print some SCU information */ +void scu_print_state(void) +{ + volatile u32 scu_cfg = read(SCU_VBASE + SCU_CFG_REG); + int ncpu = (scu_cfg & SCU_CFG_NCPU_MASK) + 1; + printk("%s: SMP: %d CPU cluster, CPU", __KERNELNAME__, ncpu); + for (int i = 0; i < ncpu; i++) { + if ((1 << i) & (scu_cfg >> SCU_CFG_SMP_NCPU_SHIFT)) + printk("%d/", i); + } + printk(" are participating in SMP\n"); + +} + +void scu_init(void) +{ + volatile u32 scu_ctrl = read(SCU_VBASE + SCU_CTRL_REG); + + /* Enable the SCU */ + if (!(scu_ctrl & SCU_CTRL_EN)) + scu_ctrl |= SCU_CTRL_EN; + + write(scu_ctrl, SCU_VBASE + SCU_CTRL_REG); +} + +void platform_smp_init(int ncpus) +{ + unsigned int i; + + /* Add GIC SoftIRQ (aka IPI) */ + for (i = 0; i <= 15; i++) { + strncpy(irq_desc_array[i].name, "SoftInt", 8); + irq_desc_array[i].chip = &irq_chip_array[0]; + irq_desc_array[i].handler = &ipi_handler; + } + + add_boot_mapping(PLATFORM_SYSTEM_REGISTERS, PLATFORM_SYSREGS_VBASE, + PAGE_SIZE, MAP_IO_DEFAULT); + +} + +int platform_smp_start(int cpu, void (*smp_start_func)(int)) +{ + /* + * Wake up just one core by writing the starting address to FLAGS + * register in SYSCTRL + */ + write(0xffffffff, SYS_FLAGS_CLR + PLATFORM_SYSREGS_VBASE); + write((unsigned int)smp_start_func, SYS_FLAGS_SET + PLATFORM_SYSREGS_VBASE); + dsb(); /* Make sure the write occurs */ + + /* Wake up other core who is waiting on a WFI. */ + gic_send_ipi(CPUID_TO_MASK(cpu), 1); + + return 0; +} + +void secondary_init_platform(void) +{ + gic_cpu_init(0, GIC0_CPU_VBASE); + gic_ack_irq(1); + + gic_set_target(IRQ_TIMER0, 1 << smp_get_cpuid()); +} + +void arch_send_ipi(u32 cpu, int cmd) +{ + gic_send_ipi(cpu, cmd); +} + diff --git a/tools/cml2-tools/cmlconfigure.py b/tools/cml2-tools/cmlconfigure.py index 495252d..baf357b 100755 --- a/tools/cml2-tools/cmlconfigure.py +++ b/tools/cml2-tools/cmlconfigure.py @@ -3248,6 +3248,8 @@ if __name__ == '__main__': sys.exit(1) for (switch, val) in options: + if switch == "-b": + force_batch = 1 if switch == "-V": print "cmlconfigure", cml.version raise SystemExit @@ -3268,7 +3270,7 @@ if __name__ == '__main__': raise SystemExit # Probe the environment to see if we can use X for the front end. - if not force_tty and not force_debugger and not force_curses and not force_x and not force_q: + if not force_tty and not force_debugger and not force_curses and not force_x and not force_q and not force_batch: force_x = force_q = is_under_X() # Do we see X capability? @@ -3278,7 +3280,8 @@ if __name__ == '__main__': from Dialog import * except: print lang["NOTKINTER"] - time.sleep(5) + if not force_batch: + time.sleep(5) force_curses = 1 force_x = force_q = 0 diff --git a/tools/gdbinit b/tools/gdbinit index 49a1c11..0d4607e 100644 --- a/tools/gdbinit +++ b/tools/gdbinit @@ -4,5 +4,6 @@ stepi sym final.elf break break_virtual continue +sym kernel.elf stepi -sym /opt/codezero/build/kernel.elf + diff --git a/tools/run-qemu-insight b/tools/run-qemu-insight deleted file mode 100755 index 4a2dfab..0000000 --- a/tools/run-qemu-insight +++ /dev/null @@ -1,5 +0,0 @@ -cd build -qemu-system-arm -s -kernel final.elf -nographic -m 128 -M versatilepb & -arm-none-insight ; pkill qemu-system-arm -cd .. - diff --git a/tools/rvdebug.inc b/tools/rvdebug.inc new file mode 100644 index 0000000..eade2c2 --- /dev/null +++ b/tools/rvdebug.inc @@ -0,0 +1,4 @@ +load/r '/home/bahadir/codezero/build/final.elf' +load/ni/np '/home/bahadir/codezero/build/kernel.elf' +bexec smp_start_cores +bexec idle_task diff --git a/tools/tagsgen/tagsgen_all b/tools/tagsgen/tagsgen_all index 1b0cc45..0a8573b 100755 --- a/tools/tagsgen/tagsgen_all +++ b/tools/tagsgen/tagsgen_all @@ -11,6 +11,8 @@ find ./ -name '*.lds' >> tagfilelist # Use file list to include in tags. ctags --languages=C,C++,Asm --recurse -Ltagfilelist +# dont forget Emacs users :) +ctags -e --languages=C,C++,Asm --recurse -Ltagfilelist # exuberant-ctags --languages=C,C++,Asm --recurse -Ltagfilelist cscope -q -k -R -i tagfilelist diff --git a/tools/tagsgen/tagsgen_kernel.py b/tools/tagsgen/tagsgen_kernel.py index a129cae..6e507bc 100755 --- a/tools/tagsgen/tagsgen_kernel.py +++ b/tools/tagsgen/tagsgen_kernel.py @@ -28,6 +28,13 @@ def main(): ['api', 'arch/'+ arch, 'arch/'+ arch + '/' + subarch, 'drivers', \ 'generic', 'glue/' + arch, 'lib', 'platform/' + platform] + # Check if we need realview directory based on platform selected + if platform == "eb" or \ + platform == "pba8" or \ + platform == "pba9" or \ + platform == "pb11mpcore": + search_folder += ['platform/realview'] + # Put all sources into a file list. for extn in file_extn: for dir in search_folder: