diff --git a/bsp/realview-a8/.gitignore b/bsp/realview-a8/.gitignore new file mode 100644 index 0000000000..f0bbbc4965 --- /dev/null +++ b/bsp/realview-a8/.gitignore @@ -0,0 +1,26 @@ +# Object files +*.o +*.bin +*.pyc +*.map +*.elf + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app + +.scons* + +# directory +build/* diff --git a/bsp/realview-a8/README.md b/bsp/realview-a8/README.md new file mode 100644 index 0000000000..b9ee2d06d3 --- /dev/null +++ b/bsp/realview-a8/README.md @@ -0,0 +1,11 @@ +VMM BSP on realview-pb-a8 + +This is a demo program that run RT-Thread VMM(Virtual Machine Module) on +the single core RealView-PB-A8. + +To compile it, you need buildroot and a linux 3.8.x source tree. You should +build the patched Linux kernel and builroot before building the VMM. This +directory has a "mk.sh" helper script to build both the RT-Thread, Linux kernel +module and the ramdisk. + +Linux console is serial0 and RT-Thread console is serial1. diff --git a/bsp/realview-a8/SConscript b/bsp/realview-a8/SConscript new file mode 100644 index 0000000000..fe0ae941ae --- /dev/null +++ b/bsp/realview-a8/SConscript @@ -0,0 +1,14 @@ +# for module compiling +import os +Import('RTT_ROOT') + +cwd = str(Dir('#')) +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/realview-a8/SConstruct b/bsp/realview-a8/SConstruct new file mode 100644 index 0000000000..e67d72291f --- /dev/null +++ b/bsp/realview-a8/SConstruct @@ -0,0 +1,38 @@ +import os +import sys +import rtconfig + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = os.path.normpath(os.getcwd() + '/../..') + +sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] +from building import * + +TARGET = 'rtthread-realview.' + rtconfig.TARGET_EXT + +env = Environment(tools = ['mingw'], + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', + LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS) +env.PrependENVPath('PATH', rtconfig.EXEC_PATH) + +Export('RTT_ROOT') +Export('rtconfig') + +# prepare building environment +objs = PrepareBuilding(env, RTT_ROOT) + +if GetDepend('RT_USING_VMM'): + if os.system('{cppcmd} -P -C -E -I. -D__ASSEMBLY__ {ldfile}.S -o {ldfile}'.format( + cppcmd = os.path.join(rtconfig.EXEC_PATH, 'arm-none-eabi-gcc'), + ldfile = rtconfig.LINK_SCRIPT)) != 0: + print 'failed to generate linker script %s' % rtconfig.LINK_SCRIPT + sys.exit(255) +# if the linker script changed, relink the target +Depends(TARGET, rtconfig.LINK_SCRIPT) + +# make a building +DoBuilding(TARGET, objs) diff --git a/bsp/realview-a8/applications/SConscript b/bsp/realview-a8/applications/SConscript new file mode 100644 index 0000000000..01eb940dfb --- /dev/null +++ b/bsp/realview-a8/applications/SConscript @@ -0,0 +1,11 @@ +Import('RTT_ROOT') +Import('rtconfig') +from building import * + +cwd = os.path.join(str(Dir('#')), 'applications') +src = Glob('*.c') +CPPPATH = [cwd, str(Dir('#'))] + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/realview-a8/applications/application.c b/bsp/realview-a8/applications/application.c new file mode 100644 index 0000000000..e65878bce5 --- /dev/null +++ b/bsp/realview-a8/applications/application.c @@ -0,0 +1,47 @@ +/* + * File : application.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-11-20 Bernard the first version + */ + +#include +#include + +#include + +void *test_task(void *parameter) +{ + int count = 0; + + while (1) + { + rt_thread_delay(RT_TICK_PER_SECOND); + rt_kprintf("count = %d\n", count ++); + } + + return RT_NULL; +} + +int rt_application_init() +{ + // pthread_t tid; + + /* do component initialization */ + rt_components_init(); +#ifdef RT_USING_NEWLIB + libc_system_init(RT_CONSOLE_DEVICE_NAME); +#endif + + // pthread_create(&tid, RT_NULL, test_task, RT_NULL); + + return 0; +} + diff --git a/bsp/realview-a8/applications/startup.c b/bsp/realview-a8/applications/startup.c new file mode 100644 index 0000000000..fa17c0571b --- /dev/null +++ b/bsp/realview-a8/applications/startup.c @@ -0,0 +1,72 @@ +/* + * File : startup.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-12-05 Bernard the first version + */ + +#include +#include + +#include + +extern int rt_application_init(void); +extern void rt_hw_board_init(void); + +/** + * This function will startup RT-Thread RTOS. + */ +void rtthread_startup(void) +{ + /* initialzie hardware interrupt */ + rt_hw_interrupt_init(); + + /* initialize board */ + rt_hw_board_init(); + + /* show RT-Thread version */ + rt_show_version(); + + /* initialize memory system */ +#ifdef RT_USING_HEAP + rt_system_heap_init(HEAP_BEGIN, HEAP_END); +#endif + + /* initialize scheduler system */ + rt_system_scheduler_init(); + + /* initialize timer and soft timer thread */ + rt_system_timer_init(); + rt_system_timer_thread_init(); + + /* initialize application */ + rt_application_init(); + + /* initialize idle thread */ + rt_thread_idle_init(); + + /* start scheduler */ + rt_system_scheduler_start(); + + /* never reach here */ + return ; +} + +int main(void) +{ + /* disable interrupt first */ + rt_hw_interrupt_disable(); + + /* invoke rtthread_startup */ + rtthread_startup(); + + return 0; +} + diff --git a/bsp/realview-a8/boot.sh b/bsp/realview-a8/boot.sh new file mode 100644 index 0000000000..eaafa6524c --- /dev/null +++ b/bsp/realview-a8/boot.sh @@ -0,0 +1,3 @@ +#!/bin/sh -e +scons -j12 +qemu-system-arm -M realview-pb-a8 -kernel rtthread-realview.elf -serial vc -serial stdio diff --git a/bsp/realview-a8/drivers/SConscript b/bsp/realview-a8/drivers/SConscript new file mode 100644 index 0000000000..a630c8a7c4 --- /dev/null +++ b/bsp/realview-a8/drivers/SConscript @@ -0,0 +1,22 @@ +import copy +Import('RTT_ROOT') +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + +# remove no need file. +if GetDepend('RT_USING_LWIP') == False: + src_need_remove = ['dm9000.c'] # need remove file list. + SrcRemove(src, src_need_remove) + +if GetDepend('RT_USING_DFS') == False: + src_need_remove = ['sd.c'] # need remove file list. + SrcRemove(src, src_need_remove) + +CPPPATH = [cwd] + +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/realview-a8/drivers/board.c b/bsp/realview-a8/drivers/board.c new file mode 100644 index 0000000000..8312a4e85f --- /dev/null +++ b/bsp/realview-a8/drivers/board.c @@ -0,0 +1,104 @@ +/* + * File : board.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-11-20 Bernard the first version + */ + +#include +#include +#include + +#include "board.h" + +#define TIMER_LOAD(hw_base) __REG32(hw_base + 0x00) +#define TIMER_VALUE(hw_base) __REG32(hw_base + 0x04) +#define TIMER_CTRL(hw_base) __REG32(hw_base + 0x08) +#define TIMER_CTRL_ONESHOT (1 << 0) +#define TIMER_CTRL_32BIT (1 << 1) +#define TIMER_CTRL_DIV1 (0 << 2) +#define TIMER_CTRL_DIV16 (1 << 2) +#define TIMER_CTRL_DIV256 (2 << 2) +#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable (versatile only) */ +#define TIMER_CTRL_PERIODIC (1 << 6) +#define TIMER_CTRL_ENABLE (1 << 7) + +#define TIMER_INTCLR(hw_base) __REG32(hw_base + 0x0c) +#define TIMER_RIS(hw_base) __REG32(hw_base + 0x10) +#define TIMER_MIS(hw_base) __REG32(hw_base + 0x14) +#define TIMER_BGLOAD(hw_base) __REG32(hw_base + 0x18) + +#define SYS_CTRL __REG32(REALVIEW_SCTL_BASE) + +#ifdef RT_USING_VMM + #include + static rt_uint32_t timer_hw_base = 0; + #define TIMER_HW_BASE (timer_hw_base) +#else + #define TIMER_HW_BASE REALVIEW_TIMER2_3_BASE +#endif + +void rt_hw_timer_ack(void) +{ + /* clear interrupt */ + TIMER_INTCLR(TIMER_HW_BASE) = 0x01; +} + +static void rt_hw_timer_isr(int vector, void *param) +{ + rt_tick_increase(); + + rt_hw_timer_ack(); +} + +int rt_hw_timer_init(void) +{ + rt_uint32_t val; + +#ifdef RT_USING_VMM + { + rt_uint32_t sys_ctrl; + sys_ctrl = vmm_find_iomap("SYS_CTRL"); + __REG32(sys_ctrl) |= REALVIEW_REFCLK; + } + + timer_hw_base = vmm_find_iomap("TIMER"); +#else + SYS_CTRL |= REALVIEW_REFCLK; +#endif + + /* Setup Timer0 for generating irq */ + val = TIMER_CTRL(TIMER_HW_BASE); + val &= ~TIMER_CTRL_ENABLE; + val |= (TIMER_CTRL_32BIT | TIMER_CTRL_PERIODIC | TIMER_CTRL_IE); + TIMER_CTRL(TIMER_HW_BASE) = val; + + TIMER_LOAD(TIMER_HW_BASE) = 1000; + + /* enable timer */ + TIMER_CTRL(TIMER_HW_BASE) |= TIMER_CTRL_ENABLE; + + rt_hw_interrupt_install(IRQ_PBA8_TIMER2_3, rt_hw_timer_isr, RT_NULL, "tick"); + rt_hw_interrupt_umask(IRQ_PBA8_TIMER2_3); + + return 0; +} +INIT_BOARD_EXPORT(rt_hw_timer_init); + +/** + * This function will initialize beaglebone board + */ +void rt_hw_board_init(void) +{ + rt_components_board_init(); + rt_console_set_device(RT_CONSOLE_DEVICE_NAME); +} + +/*@}*/ diff --git a/bsp/realview-a8/drivers/board.h b/bsp/realview-a8/drivers/board.h new file mode 100644 index 0000000000..89ba3cbe03 --- /dev/null +++ b/bsp/realview-a8/drivers/board.h @@ -0,0 +1,32 @@ +/* + * File : board.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-06 Bernard the first version + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +#include + +#if defined(__CC_ARM) +extern int Image$$RW_IRAM1$$ZI$$Limit; +#define HEAP_BEGIN ((void*)&Image$$RW_IRAM1$$ZI$$Limit) +#elif defined(__GNUC__) +extern int __bss_end; +#define HEAP_BEGIN ((void*)&__bss_end) +#endif + +#define HEAP_END (void*)(0x70000000 + 8 * 1024 * 1024) + +void rt_hw_board_init(void); + +#endif diff --git a/bsp/realview-a8/drivers/realview.h b/bsp/realview-a8/drivers/realview.h new file mode 100644 index 0000000000..159f2244ea --- /dev/null +++ b/bsp/realview-a8/drivers/realview.h @@ -0,0 +1,324 @@ +#ifndef __AM33XX_H__ +#define __AM33XX_H__ + +#define __REG32(x) (*((volatile unsigned int *)(x))) +#define __REG16(x) (*((volatile unsigned short *)(x))) + +/* + * Peripheral addresses + */ +#define REALVIEW_UART0_BASE 0x10009000 /* UART 0 */ +#define REALVIEW_UART1_BASE 0x1000A000 /* UART 1 */ +#define REALVIEW_UART2_BASE 0x1000B000 /* UART 2 */ +#define REALVIEW_UART3_BASE 0x1000C000 /* UART 3 */ +#define REALVIEW_SSP_BASE 0x1000D000 /* Synchronous Serial Port */ +#define REALVIEW_WATCHDOG0_BASE 0x1000F000 /* Watchdog 0 */ +#define REALVIEW_WATCHDOG_BASE 0x10010000 /* watchdog interface */ +#define REALVIEW_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */ +#define REALVIEW_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */ +#define REALVIEW_GPIO0_BASE 0x10013000 /* GPIO port 0 */ +#define REALVIEW_RTC_BASE 0x10017000 /* Real Time Clock */ +#define REALVIEW_TIMER4_5_BASE 0x10018000 /* Timer 4/5 */ +#define REALVIEW_TIMER6_7_BASE 0x10019000 /* Timer 6/7 */ +#define REALVIEW_SCTL_BASE 0x1001A000 /* System Controller */ +#define REALVIEW_CLCD_BASE 0x10020000 /* CLCD */ +#define REALVIEW_ONB_SRAM_BASE 0x10060000 /* On-board SRAM */ +#define REALVIEW_DMC_BASE 0x100E0000 /* DMC configuration */ +#define REALVIEW_SMC_BASE 0x100E1000 /* SMC configuration */ +#define REALVIEW_CAN_BASE 0x100E2000 /* CAN bus */ +#define REALVIEW_GIC_CPU_BASE 0x1E000000 /* Generic interrupt controller CPU interface */ +#define REALVIEW_FLASH0_BASE 0x40000000 +#define REALVIEW_FLASH0_SIZE SZ_64M +#define REALVIEW_FLASH1_BASE 0x44000000 +#define REALVIEW_FLASH1_SIZE SZ_64M +#define REALVIEW_ETH_BASE 0x4E000000 /* Ethernet */ +#define REALVIEW_USB_BASE 0x4F000000 /* USB */ +#define REALVIEW_GIC_DIST_BASE 0x1E001000 /* Generic interrupt controller distributor */ +#define REALVIEW_LT_BASE 0xC0000000 /* Logic Tile expansion */ +#define REALVIEW_SDRAM6_BASE 0x70000000 /* SDRAM bank 6 256MB */ +#define REALVIEW_SDRAM7_BASE 0x80000000 /* SDRAM bank 7 256MB */ + +#define REALVIEW_SYS_PLD_CTRL1 0x74 + +/* + * PCI regions + */ +#define REALVIEW_PCI_BASE 0x90040000 /* PCI-X Unit base */ +#define REALVIEW_PCI_IO_BASE 0x90050000 /* IO Region on AHB */ +#define REALVIEW_PCI_MEM_BASE 0xA0000000 /* MEM Region on AHB */ + +#define REALVIEW_PCI_BASE_SIZE 0x10000 /* 16 Kb */ +#define REALVIEW_PCI_IO_SIZE 0x1000 /* 4 Kb */ +#define REALVIEW_PCI_MEM_SIZE 0x20000000 /* 512 MB */ + +/* + * Memory definitions + */ +#define REALVIEW_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)... */ +#define REALVIEW_BOOT_ROM_HI 0x30000000 +#define REALVIEW_BOOT_ROM_BASE REALVIEW_BOOT_ROM_HI /* Normal position */ +#define REALVIEW_BOOT_ROM_SIZE SZ_64M + +#define REALVIEW_SSRAM_BASE /* REALVIEW_SSMC_BASE ? */ +#define REALVIEW_SSRAM_SIZE SZ_2M + +/* + * SDRAM + */ +#define REALVIEW_SDRAM_BASE 0x00000000 + +/* + * Logic expansion modules + * + */ +#define IRQ_PBA8_GIC_START 32 + +/* + * PB-A8 on-board gic irq sources + */ +#define IRQ_PBA8_WATCHDOG (IRQ_PBA8_GIC_START + 0) /* Watchdog timer */ +#define IRQ_PBA8_SOFT (IRQ_PBA8_GIC_START + 1) /* Software interrupt */ +#define IRQ_PBA8_COMMRx (IRQ_PBA8_GIC_START + 2) /* Debug Comm Rx interrupt */ +#define IRQ_PBA8_COMMTx (IRQ_PBA8_GIC_START + 3) /* Debug Comm Tx interrupt */ +#define IRQ_PBA8_TIMER0_1 (IRQ_PBA8_GIC_START + 4) /* Timer 0/1 (default timer) */ +#define IRQ_PBA8_TIMER2_3 (IRQ_PBA8_GIC_START + 5) /* Timer 2/3 */ +#define IRQ_PBA8_GPIO0 (IRQ_PBA8_GIC_START + 6) /* GPIO 0 */ +#define IRQ_PBA8_GPIO1 (IRQ_PBA8_GIC_START + 7) /* GPIO 1 */ +#define IRQ_PBA8_GPIO2 (IRQ_PBA8_GIC_START + 8) /* GPIO 2 */ +/* 9 reserved */ +#define IRQ_PBA8_RTC (IRQ_PBA8_GIC_START + 10) /* Real Time Clock */ +#define IRQ_PBA8_SSP (IRQ_PBA8_GIC_START + 11) /* Synchronous Serial Port */ +#define IRQ_PBA8_UART0 (IRQ_PBA8_GIC_START + 12) /* UART 0 on development chip */ +#define IRQ_PBA8_UART1 (IRQ_PBA8_GIC_START + 13) /* UART 1 on development chip */ +#define IRQ_PBA8_UART2 (IRQ_PBA8_GIC_START + 14) /* UART 2 on development chip */ +#define IRQ_PBA8_UART3 (IRQ_PBA8_GIC_START + 15) /* UART 3 on development chip */ +#define IRQ_PBA8_SCI (IRQ_PBA8_GIC_START + 16) /* Smart Card Interface */ +#define IRQ_PBA8_MMCI0A (IRQ_PBA8_GIC_START + 17) /* Multimedia Card 0A */ +#define IRQ_PBA8_MMCI0B (IRQ_PBA8_GIC_START + 18) /* Multimedia Card 0B */ +#define IRQ_PBA8_AACI (IRQ_PBA8_GIC_START + 19) /* Audio Codec */ +#define IRQ_PBA8_KMI0 (IRQ_PBA8_GIC_START + 20) /* Keyboard/Mouse port 0 */ +#define IRQ_PBA8_KMI1 (IRQ_PBA8_GIC_START + 21) /* Keyboard/Mouse port 1 */ +#define IRQ_PBA8_CHARLCD (IRQ_PBA8_GIC_START + 22) /* Character LCD */ +#define IRQ_PBA8_CLCD (IRQ_PBA8_GIC_START + 23) /* CLCD controller */ +#define IRQ_PBA8_DMAC (IRQ_PBA8_GIC_START + 24) /* DMA controller */ +#define IRQ_PBA8_PWRFAIL (IRQ_PBA8_GIC_START + 25) /* Power failure */ +#define IRQ_PBA8_PISMO (IRQ_PBA8_GIC_START + 26) /* PISMO interface */ +#define IRQ_PBA8_DoC (IRQ_PBA8_GIC_START + 27) /* Disk on Chip memory controller */ +#define IRQ_PBA8_ETH (IRQ_PBA8_GIC_START + 28) /* Ethernet controller */ +#define IRQ_PBA8_USB (IRQ_PBA8_GIC_START + 29) /* USB controller */ +#define IRQ_PBA8_TSPEN (IRQ_PBA8_GIC_START + 30) /* Touchscreen pen */ +#define IRQ_PBA8_TSKPAD (IRQ_PBA8_GIC_START + 31) /* Touchscreen keypad */ + +#define IRQ_PBA8_PMU (IRQ_PBA8_GIC_START + 47) /* Cortex-A8 PMU */ + +/* ... */ +#define IRQ_PBA8_PCI0 (IRQ_PBA8_GIC_START + 50) +#define IRQ_PBA8_PCI1 (IRQ_PBA8_GIC_START + 51) +#define IRQ_PBA8_PCI2 (IRQ_PBA8_GIC_START + 52) +#define IRQ_PBA8_PCI3 (IRQ_PBA8_GIC_START + 53) + +#define IRQ_PBA8_SMC -1 +#define IRQ_PBA8_SCTL -1 + +#define NR_GIC_PBA8 1 + +/* + * Only define NR_IRQS if less than NR_IRQS_PBA8 + */ +#define NR_IRQS_PBA8 (IRQ_PBA8_GIC_START + 64) + +/* ------------------------------------------------------------------------ + * RealView Registers + * ------------------------------------------------------------------------ + * + */ +#define REALVIEW_SYS_ID_OFFSET 0x00 +#define REALVIEW_SYS_SW_OFFSET 0x04 +#define REALVIEW_SYS_LED_OFFSET 0x08 +#define REALVIEW_SYS_OSC0_OFFSET 0x0C + +#define REALVIEW_SYS_OSC1_OFFSET 0x10 +#define REALVIEW_SYS_OSC2_OFFSET 0x14 +#define REALVIEW_SYS_OSC3_OFFSET 0x18 +#define REALVIEW_SYS_OSC4_OFFSET 0x1C /* OSC1 for RealView/AB */ + +#define REALVIEW_SYS_LOCK_OFFSET 0x20 +#define REALVIEW_SYS_100HZ_OFFSET 0x24 +#define REALVIEW_SYS_CFGDATA1_OFFSET 0x28 +#define REALVIEW_SYS_CFGDATA2_OFFSET 0x2C +#define REALVIEW_SYS_FLAGS_OFFSET 0x30 +#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 +#define REALVIEW_SYS_FLAGSCLR_OFFSET 0x34 +#define REALVIEW_SYS_NVFLAGS_OFFSET 0x38 +#define REALVIEW_SYS_NVFLAGSSET_OFFSET 0x38 +#define REALVIEW_SYS_NVFLAGSCLR_OFFSET 0x3C +#define REALVIEW_SYS_RESETCTL_OFFSET 0x40 +#define REALVIEW_SYS_PCICTL_OFFSET 0x44 +#define REALVIEW_SYS_MCI_OFFSET 0x48 +#define REALVIEW_SYS_FLASH_OFFSET 0x4C +#define REALVIEW_SYS_CLCD_OFFSET 0x50 +#define REALVIEW_SYS_CLCDSER_OFFSET 0x54 +#define REALVIEW_SYS_BOOTCS_OFFSET 0x58 +#define REALVIEW_SYS_24MHz_OFFSET 0x5C +#define REALVIEW_SYS_MISC_OFFSET 0x60 +#define REALVIEW_SYS_IOSEL_OFFSET 0x70 +#define REALVIEW_SYS_PROCID_OFFSET 0x84 +#define REALVIEW_SYS_TEST_OSC0_OFFSET 0xC0 +#define REALVIEW_SYS_TEST_OSC1_OFFSET 0xC4 +#define REALVIEW_SYS_TEST_OSC2_OFFSET 0xC8 +#define REALVIEW_SYS_TEST_OSC3_OFFSET 0xCC +#define REALVIEW_SYS_TEST_OSC4_OFFSET 0xD0 + +#define REALVIEW_SYS_BASE 0x10000000 +#define REALVIEW_SYS_ID (REALVIEW_SYS_BASE + REALVIEW_SYS_ID_OFFSET) +#define REALVIEW_SYS_SW (REALVIEW_SYS_BASE + REALVIEW_SYS_SW_OFFSET) +#define REALVIEW_SYS_LED (REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET) +#define REALVIEW_SYS_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC0_OFFSET) +#define REALVIEW_SYS_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC1_OFFSET) + +#define REALVIEW_SYS_LOCK (REALVIEW_SYS_BASE + REALVIEW_SYS_LOCK_OFFSET) +#define REALVIEW_SYS_100HZ (REALVIEW_SYS_BASE + REALVIEW_SYS_100HZ_OFFSET) +#define REALVIEW_SYS_CFGDATA1 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA1_OFFSET) +#define REALVIEW_SYS_CFGDATA2 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA2_OFFSET) +#define REALVIEW_SYS_FLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGS_OFFSET) +#define REALVIEW_SYS_FLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSSET_OFFSET) +#define REALVIEW_SYS_FLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSCLR_OFFSET) +#define REALVIEW_SYS_NVFLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGS_OFFSET) +#define REALVIEW_SYS_NVFLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSSET_OFFSET) +#define REALVIEW_SYS_NVFLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSCLR_OFFSET) +#define REALVIEW_SYS_RESETCTL (REALVIEW_SYS_BASE + REALVIEW_SYS_RESETCTL_OFFSET) +#define REALVIEW_SYS_PCICTL (REALVIEW_SYS_BASE + REALVIEW_SYS_PCICTL_OFFSET) +#define REALVIEW_SYS_MCI (REALVIEW_SYS_BASE + REALVIEW_SYS_MCI_OFFSET) +#define REALVIEW_SYS_FLASH (REALVIEW_SYS_BASE + REALVIEW_SYS_FLASH_OFFSET) +#define REALVIEW_SYS_CLCD (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCD_OFFSET) +#define REALVIEW_SYS_CLCDSER (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCDSER_OFFSET) +#define REALVIEW_SYS_BOOTCS (REALVIEW_SYS_BASE + REALVIEW_SYS_BOOTCS_OFFSET) +#define REALVIEW_SYS_24MHz (REALVIEW_SYS_BASE + REALVIEW_SYS_24MHz_OFFSET) +#define REALVIEW_SYS_MISC (REALVIEW_SYS_BASE + REALVIEW_SYS_MISC_OFFSET) +#define REALVIEW_SYS_IOSEL (REALVIEW_SYS_BASE + REALVIEW_SYS_IOSEL_OFFSET) +#define REALVIEW_SYS_PROCID (REALVIEW_SYS_BASE + REALVIEW_SYS_PROCID_OFFSET) +#define REALVIEW_SYS_TEST_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC0_OFFSET) +#define REALVIEW_SYS_TEST_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC1_OFFSET) +#define REALVIEW_SYS_TEST_OSC2 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC2_OFFSET) +#define REALVIEW_SYS_TEST_OSC3 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC3_OFFSET) +#define REALVIEW_SYS_TEST_OSC4 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC4_OFFSET) + +#define REALVIEW_SYS_CTRL_LED (1 << 0) + +/* ------------------------------------------------------------------------ + * RealView control registers + * ------------------------------------------------------------------------ + */ + +/* + * REALVIEW_IDFIELD + * + * 31:24 = manufacturer (0x41 = ARM) + * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus) + * 15:12 = FPGA (0x3 = XVC600 or XVC600E) + * 11:4 = build value + * 3:0 = revision number (0x1 = rev B (AHB)) + */ + +/* + * REALVIEW_SYS_LOCK + * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL, + * SYS_CLD, SYS_BOOTCS + */ +#define REALVIEW_SYS_LOCK_LOCKED (1 << 16) +#define REALVIEW_SYS_LOCKVAL 0xA05F +#define REALVIEW_SYS_LOCKVAL_MASK 0xFFFF /* write 0xA05F to enable write access */ + +/* + * REALVIEW_SYS_FLASH + */ +#define REALVIEW_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */ + +/* + * REALVIEW_INTREG + * - used to acknowledge and control MMCI and UART interrupts + */ +#define REALVIEW_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */ +#define REALVIEW_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */ +#define REALVIEW_INTREG_CARDIN 0x08 /* MMCI card in detect */ +/* write 1 to acknowledge and clear */ +#define REALVIEW_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */ +#define REALVIEW_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */ + +/* + * LED settings, bits [7:0] + */ +#define REALVIEW_SYS_LED0 (1 << 0) +#define REALVIEW_SYS_LED1 (1 << 1) +#define REALVIEW_SYS_LED2 (1 << 2) +#define REALVIEW_SYS_LED3 (1 << 3) +#define REALVIEW_SYS_LED4 (1 << 4) +#define REALVIEW_SYS_LED5 (1 << 5) +#define REALVIEW_SYS_LED6 (1 << 6) +#define REALVIEW_SYS_LED7 (1 << 7) + +#define ALL_LEDS 0xFF + +#define LED_BANK REALVIEW_SYS_LED + +/* + * Control registers + */ +#define REALVIEW_IDFIELD_OFFSET 0x0 /* RealView build information */ +#define REALVIEW_FLASHPROG_OFFSET 0x4 /* Flash devices */ +#define REALVIEW_INTREG_OFFSET 0x8 /* Interrupt control */ +#define REALVIEW_DECODE_OFFSET 0xC /* Fitted logic modules */ + +/* + * Clean base - dummy + * + */ +#define CLEAN_BASE REALVIEW_BOOT_ROM_HI + +/* + * System controller bit assignment + */ +#define REALVIEW_REFCLK 0 +#define REALVIEW_TIMCLK 1 + +#define REALVIEW_TIMER1_EnSel 15 +#define REALVIEW_TIMER2_EnSel 17 +#define REALVIEW_TIMER3_EnSel 19 +#define REALVIEW_TIMER4_EnSel 21 + +/* + *struct rt_hw_register + *{ + * unsigned long r0; + * unsigned long r1; + * unsigned long r2; + * unsigned long r3; + * unsigned long r4; + * unsigned long r5; + * unsigned long r6; + * unsigned long r7; + * unsigned long r8; + * unsigned long r9; + * unsigned long r10; + * unsigned long fp; + * unsigned long ip; + * unsigned long sp; + * unsigned long lr; + * unsigned long pc; + * unsigned long cpsr; + * unsigned long ORIG_r0; + *}; + */ + +#include + +/* Interrupt Control Interface */ +#define ARM_GIC_CPU_BASE 0x1E000000 + +/* number of interrupts on board */ +#define ARM_GIC_NR_IRQS 96 +/* only one GIC available */ +#define ARM_GIC_MAX_NR 1 + +#endif + diff --git a/bsp/realview-a8/drivers/serial.c b/bsp/realview-a8/drivers/serial.c new file mode 100644 index 0000000000..0af03b2759 --- /dev/null +++ b/bsp/realview-a8/drivers/serial.c @@ -0,0 +1,207 @@ +/* + * serial.c UART driver + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-03-30 Bernard the first verion + */ + +#include +#include + +#include "serial.h" +#ifdef RT_USING_VMM + #include +#endif + +struct hw_uart_device +{ + rt_uint32_t hw_base; + rt_uint32_t irqno; +}; + +#define UART_DR(base) __REG32(base + 0x00) +#define UART_FR(base) __REG32(base + 0x18) +#define UART_CR(base) __REG32(base + 0x30) +#define UART_IMSC(base) __REG32(base + 0x38) +#define UART_ICR(base) __REG32(base + 0x44) + +#define UARTFR_RXFE 0x10 +#define UARTFR_TXFF 0x20 +#define UARTIMSC_RXIM 0x10 +#define UARTIMSC_TXIM 0x20 +#define UARTICR_RXIC 0x10 +#define UARTICR_TXIC 0x20 + +static void rt_hw_uart_isr(int irqno, void *param) +{ + struct rt_serial_device *serial = (struct rt_serial_device *)param; + + rt_hw_serial_isr(serial); +} + +static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) +{ + return RT_EOK; +} + +static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) +{ + struct hw_uart_device *uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device *)serial->parent.user_data; + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + /* disable rx irq */ + UART_IMSC(uart->hw_base) &= ~UARTIMSC_RXIM; + break; + + case RT_DEVICE_CTRL_SET_INT: + /* enable rx irq */ + UART_IMSC(uart->hw_base) |= UARTIMSC_RXIM; + rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, "uart"); + rt_hw_interrupt_umask(uart->irqno); + break; + } + + return RT_EOK; +} + +static int uart_putc(struct rt_serial_device *serial, char c) +{ + struct hw_uart_device *uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device *)serial->parent.user_data; + + while (UART_FR(uart->hw_base) & UARTFR_TXFF); + UART_DR(uart->hw_base) = c; + + return 1; +} + +static int uart_getc(struct rt_serial_device *serial) +{ + int ch; + struct hw_uart_device *uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device *)serial->parent.user_data; + + ch = -1; + if (!(UART_FR(uart->hw_base) & UARTFR_RXFE)) + { + ch = UART_DR(uart->hw_base) & 0xff; + } + + return ch; +} + +static const struct rt_uart_ops _uart_ops = +{ + uart_configure, + uart_control, + uart_putc, + uart_getc, +}; + +#ifdef RT_USING_UART0 +/* UART device driver structure */ +static struct serial_ringbuffer _uart0_int_rx; +static struct hw_uart_device _uart0_device = +{ + REALVIEW_UART0_BASE, + IRQ_PBA8_UART0, +}; +static struct rt_serial_device _serial0; +#endif + +#ifdef RT_USING_UART1 +/* UART1 device driver structure */ +static struct serial_ringbuffer _uart1_int_rx; +static struct hw_uart_device _uart1_device = +{ + REALVIEW_UART1_BASE, + IRQ_PBA8_UART1, +}; +static struct rt_serial_device _serial1; +#endif + +int uart_isr_test(void) +{ + return uart_getc(&_serial1); +} + +int rt_hw_uart_init(void) +{ + struct hw_uart_device *uart; + struct serial_configure config; + + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + +#ifdef RT_USING_UART0 + uart = &_uart0_device; +#ifdef RT_USING_VMM + uart->hw_base = vmm_find_iomap("UART0"); +#endif + + _serial0.ops = &_uart_ops; + _serial0.int_rx = &_uart0_int_rx; + _serial0.config = config; + + /* register UART1 device */ + rt_hw_serial_register(&_serial0, "uart0", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, + uart); + /* enable Rx and Tx of UART */ + UART_CR(uart->hw_base) = (1 << 0) | (1 << 8) | (1 << 9); +#endif + +#ifdef RT_USING_UART1 + uart = &_uart1_device; +#ifdef RT_USING_VMM + uart->hw_base = vmm_find_iomap("UART1"); +#endif + _serial1.ops = &_uart_ops; + _serial1.int_rx = &_uart1_int_rx; + _serial1.config = config; + + /* register UART1 device */ + rt_hw_serial_register(&_serial1, "uart1", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, uart); + /* enable Rx and Tx of UART */ + UART_CR(uart->hw_base) = (1 << 0) | (1 << 8) | (1 << 9); +#endif + + return 0; +} +INIT_BOARD_EXPORT(rt_hw_uart_init); diff --git a/bsp/realview-a8/drivers/serial.h b/bsp/realview-a8/drivers/serial.h new file mode 100644 index 0000000000..52e6f07ea3 --- /dev/null +++ b/bsp/realview-a8/drivers/serial.h @@ -0,0 +1,39 @@ +/* + * UART driver + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-03-30 Bernard the first verion + */ + +#ifndef __UART_H__ +#define __UART_H__ + +#include + +int rt_hw_uart_init(void); + +#endif + + diff --git a/bsp/realview-a8/linux_vmm/.gitignore b/bsp/realview-a8/linux_vmm/.gitignore new file mode 100644 index 0000000000..f508c5d65e --- /dev/null +++ b/bsp/realview-a8/linux_vmm/.gitignore @@ -0,0 +1,10 @@ +*.o +*.o.cmd +*.ko +*.ko.cmd +*.mod.c + +Module.symvers +modules.order + +.tmp_versions/ diff --git a/bsp/realview-a8/linux_vmm/Makefile b/bsp/realview-a8/linux_vmm/Makefile new file mode 100644 index 0000000000..9520dce92f --- /dev/null +++ b/bsp/realview-a8/linux_vmm/Makefile @@ -0,0 +1,6 @@ +ccflags-y := -I$(VMM_HDR_DIR) + +obj-m += rtvmm.o + +rtvmm-objs := vmm_linux.o + diff --git a/bsp/realview-a8/linux_vmm/build.sh b/bsp/realview-a8/linux_vmm/build.sh new file mode 100644 index 0000000000..f385a17f11 --- /dev/null +++ b/bsp/realview-a8/linux_vmm/build.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +# local variable +TISDK_DIR=/home/grissiom/ti-sdk-am335x-evm-06.00.00.00/ + +# external variable {{{ +ROOTFS_DIR=${ROOTFS_DIR:-~/remotedir/buildroot-rootfs/} +KDIR=${KDIR:-$PWD/../../bfm-kernel/} + +TOOLCHAIN_DIR=${TOOLCHAIN_DIR:-${TISDK_DIR}/linux-devkit/sysroots/i686-arago-linux/usr/bin} +TOOLCHAIN_PREFIX=${TOOLCHAIN_PREFIX:-"arm-linux-gnueabihf-"} +# }}} + +export PATH="${TOOLCHAIN_DIR}:$PATH" + +make -C $KDIR M=$PWD ARCH=arm CROSS_COMPILE="${TOOLCHAIN_PREFIX}" V=0 + +#sudo PATH="${TOOLCHAIN_DIR}:$PATH" \ + #make -C $KDIR M=$PWD ARCH=arm CROSS_COMPILE=${TOOLCHAIN_PREFIX} \ + #INSTALL_MOD_PATH=${ROOTFS_DIR} modules_install diff --git a/bsp/realview-a8/linux_vmm/vmm_linux.c b/bsp/realview-a8/linux_vmm/vmm_linux.c new file mode 100644 index 0000000000..110a4f40fa --- /dev/null +++ b/bsp/realview-a8/linux_vmm/vmm_linux.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vmm_linux.h" + +#define IOMAP_NUM 3 +#define BUFF_SZ (4 * 1024) + +struct vmm_iomap *_linux_iomap = NULL; + +const char *uart_name = "uart"; + +/* some exported Linux Kernel patch */ +extern void vmm_set_status(int status); +extern void vmm_context_init(void *context_addr); +extern unsigned long vmm_save_irq(void); +extern void vmm_restore_irq(unsigned long flags); + +static struct vmm_domain domain = +{ + .kernel = DOMAIN_KERNEL, + .user = DOMAIN_USER, + .io = DOMAIN_IO, + .vmm = DOMAIN_RTVMM, + .vmm_share = DOMAIN_RTVMM_SHR, +}; + +static struct vmm_iomap iomap[RT_VMM_IOMAP_MAXNR] = +{ + {.name = "UART1", .pa = 0x1000A000, .size = 4096}, + {.name = "TIMER", .pa = 0x10012000, .size = 4096}, + {.name = "GIC_CPU", .pa = 0x1E000000, .size = 4096}, + {.name = "GIC_DIST", .pa = 0x1E001000, .size = 4096}, + {.name = "SYS_CTRL", .pa = 0x1001A000, .size = 4096}, + {.pa = 0}, +}; + +void vmm_iomap_init(void) +{ + int index; + + _linux_iomap = &iomap[0]; + + BUILD_BUG_ON(ARRAY_SIZE(iomap) > RT_VMM_IOMAP_MAXNR); + + for (index = 0; index < ARRAY_SIZE(iomap); index++) { + if (_linux_iomap[index].pa == 0) + break; + + if (_linux_iomap[index].size != 0) + _linux_iomap[index].va = + ioremap_nocache(_linux_iomap[index].pa, + _linux_iomap[index].size); + + printk("%s: 0x%08lx --> 0x%p, size %u\n", + _linux_iomap[index].name, + _linux_iomap[index].pa, + _linux_iomap[index].va, + _linux_iomap[index].size); + } + + printk("vmm: init iomap done!\n"); +} + +#if 0 +void trap_set_vector(unsigned long start, unsigned int length) +{ + int sctrl; + + /* C12-C0 is only active when SCTLR.V = 0 */ + asm volatile ("mrc p15, #0, %0, c1, c0, #0" + :"=r" (sctrl)); + sctrl &= ~(1 << 13); + asm volatile ("mcr p15, #0, %0, c1, c0, #0" + : + :"r" (sctrl)); + + asm volatile ("mcr p15, #0, %0, c12, c0, #0" + : + :"r" (start)); + rmb(); +} +#else +extern void trap_set_vector(unsigned long start, unsigned int length); +#endif + +static void vmm_open_domain(void) +{ + unsigned long dval; + asm volatile ("mrc p15, 0, %0, c3, c0\n" + : "=r" (dval)); + dval |= (0x1 << (DOMAIN_RTVMM * 2)) | + (0x1 << (DOMAIN_RTVMM_SHR * 2)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" + : : "r" (dval)); +} + +static void vmm_close_domain(void) +{ + unsigned long dval; + asm volatile ("mrc p15, 0, %0, c3, c0\n" + : "=r" (dval)); + /* we still need access tp DOMAIN_RTVMM_SHR because the IRQ stack is + * there. */ + dval &= ~(0x3 << (DOMAIN_RTVMM * 2)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" + : : "r" (dval)); +} + +static DEFINE_SPINLOCK(init_lock); +void vmm_entry(void) +{ + vmm_entry_t entry; + unsigned long flags; + struct vmm_entry_param eparam = { + .iomap = &iomap[0], + .domain = &domain, + }; + + printk("Entry VMM:0x%08x with iomap 0x%p\n", VMM_BEGIN, _linux_iomap); + + spin_lock_irqsave(&init_lock, flags); + + memcpy((void*)(LINUX_VECTOR_POS), (void*)0xFFFF0000, + LINUX_VECTOR_PGSZ); + flush_icache_range(LINUX_VECTOR_POS, + LINUX_VECTOR_POS + LINUX_VECTOR_PGSZ); + + /*dump_vector(0xFFFF0000);*/ + /* set the interrupt vector to RTT */ + trap_set_vector(VMM_BEGIN, 16 * 4); + /*dump_vector(VMM_END-LINUX_VECTOR_PGSZ);*/ + + entry = (vmm_entry_t)VMM_BEGIN; + + vmm_context_init(&RT_VMM_SHARE->ctx); + vmm_set_status(0x01); + + pr_info("Linux domain: kernel: %d, user: %d, io: %d\n", + DOMAIN_KERNEL, DOMAIN_USER, DOMAIN_IO); + + /* switch to RTT and Good Luck */ + entry(&eparam); + + spin_unlock_irqrestore(&init_lock, flags); + + /* we now switched to virtual IRQ but the hardware IRQ is disabled + * before entering RT-Thread. So we have to enabled it by hand. */ + { + asm volatile ("cpsie i":::"memory", "cc"); + } + + printk("come back to Linux.\n"); + +} + +int vmm_load_fw(const char* filename) +{ + mm_segment_t oldfs = {0}; + unsigned long len; + unsigned long file_sz; + loff_t pos = 0; + struct file *flp = NULL; + char *buf_ptr = (char*)VMM_BEGIN; + + printk("loading RT-Thread:%s ....", filename); + /* FIXME: we should not need this actually. But currently Linux would + * hang without this. Let's just proceed and I will go back to handle + * this in the future. */ + memset((void*)VMM_BEGIN, 0, VMM_SIZE); + + flp = filp_open(filename, O_RDONLY, S_IRWXU); + if (IS_ERR(flp)) + { + printk("vmm loader: open file failed. " + "Return 0x%p\n", flp); + return -1; + } + + /* get file size */ + file_sz = vfs_llseek(flp, 0, SEEK_END); + vfs_llseek(flp, 0, SEEK_SET); + + oldfs = get_fs(); + set_fs(get_ds()); + while (file_sz > 0) + { + // len = vfs_read(flp, (void __user __force *)buff, BUFF_SZ, &pos); + len = vfs_read(flp, (void __user __force*)buf_ptr, BUFF_SZ, &pos); + file_sz -= len; + buf_ptr += len; + } + set_fs(oldfs); + + filp_close(flp, NULL); + + printk("done!\n"); + + /* flush RT-Thread memory */ + flush_cache_vmap(VMM_BEGIN, VMM_END); + + return 0; +} + +static int __init vmm_init(void) +{ + printk("VMM started.\n"); + + vmm_iomap_init(); + /* Open the domain permission so we could write firmware to it */ + vmm_open_domain(); + if (vmm_load_fw("/vmm/rtthread.bin") == 0) + vmm_entry(); + + return 0; +} + +static void __exit vmm_exit(void) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&init_lock, flags); + vmm_set_status(0x00); + trap_set_vector(LINUX_VECTOR_POS, 16 * 4); + spin_unlock_irqrestore(&init_lock, flags); + + for (i = 0; i < ARRAY_SIZE(iomap); i++) + { + if (iomap[i].pa == 0) + break; + + printk("iounmap %s(0x%p)\n", + iomap[i].name, + iomap[i].va); + iounmap(iomap[i].va); + } + + vmm_close_domain(); + + printk("vmm exit\n"); +} + +module_init(vmm_init); +module_exit(vmm_exit); + +MODULE_AUTHOR("bernard.xiong "); +MODULE_DESCRIPTION("RT-VMM"); +MODULE_LICENSE("GPL"); diff --git a/bsp/realview-a8/linux_vmm/vmm_linux.h b/bsp/realview-a8/linux_vmm/vmm_linux.h new file mode 100644 index 0000000000..395a807751 --- /dev/null +++ b/bsp/realview-a8/linux_vmm/vmm_linux.h @@ -0,0 +1,8 @@ +#ifndef __VMM_H__ +#define __VMM_H__ + +#include + +#define RT_VMM_ON_AM335X + +#endif diff --git a/bsp/realview-a8/mk.sh b/bsp/realview-a8/mk.sh new file mode 100644 index 0000000000..540f41c654 --- /dev/null +++ b/bsp/realview-a8/mk.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +KDIR=~/linux-git +BUILD_ROOT_DIR=/temp-build/buildroot-2014.02/ + +scons -j20 +cp rtthread.bin $BUILD_ROOT_DIR/output/target/vmm + +( +cd ./linux_vmm/ +export PATH=/opt/gcc-linaro-arm-linux-gnueabihf-4.8-2013.10_linux/bin/:"$PATH" +make -C $KDIR M=$PWD VMM_HDR_DIR=$PWD/../ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- +cp rtvmm.ko $BUILD_ROOT_DIR/output/target/root/ +) + +make -C $BUILD_ROOT_DIR diff --git a/bsp/realview-a8/qemu.sh b/bsp/realview-a8/qemu.sh new file mode 100644 index 0000000000..539a608c60 --- /dev/null +++ b/bsp/realview-a8/qemu.sh @@ -0,0 +1 @@ +qemu-system-arm -M realview-pb-a8 -kernel rtthread-realview.elf -serial vc -serial vc diff --git a/bsp/realview-a8/realview.lds b/bsp/realview-a8/realview.lds new file mode 100644 index 0000000000..ceaead6969 --- /dev/null +++ b/bsp/realview-a8/realview.lds @@ -0,0 +1,91 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +SECTIONS +{ + . = 0x70000000; + + __text_start = .; + .text : + { + *(.vectors) + *(.text) + *(.text.*) + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + + /* section information for initialization */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + } =0 + __text_end = .; + + __rodata_start = .; + .rodata : { *(.rodata) *(.rodata.*) } + __rodata_end = .; + + . = ALIGN(4); + .ctors : + { + PROVIDE(__ctors_start__ = .); + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + PROVIDE(__ctors_end__ = .); + } + + .dtors : + { + PROVIDE(__dtors_start__ = .); + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + PROVIDE(__dtors_end__ = .); + } + + __data_start = .; + . = ALIGN(4); + .data : + { + *(.data) + *(.data.*) + } + __data_end = .; + + . = ALIGN(4); + __bss_start = __data_end; + .bss : + { + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + } + . = ALIGN(4); + __bss_end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + _end = .; +} diff --git a/bsp/realview-a8/realview_vmm.lds.S b/bsp/realview-a8/realview_vmm.lds.S new file mode 100644 index 0000000000..09cb9a302c --- /dev/null +++ b/bsp/realview-a8/realview_vmm.lds.S @@ -0,0 +1,140 @@ +#include + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +SECTIONS +{ + . = VMM_BEGIN; + + __text_start = .; + .text.share : + { + KEEP(*(.vectors)) + *(.text.isr) + *(.vmm_glue) + } + ASSERT(SIZEOF(.text.share) <= VMM_SHARE_TEXT_PGSZ, ".text.share too big") + + . = VMM_BEGIN + VMM_SHARE_TEXT_PGSZ; + /* the vectore page is saved here + * { + * } + */ + + . = VMM_SHARE_DATA_POS; + .data.share : + { + __data_share_start = .; + *(.data.share*) + __data_share_end = .; + } + ASSERT(SIZEOF(.data.share) <= (VMM_SHARE_DATA_PGSZ), ".data.share is too big") + + . = VMM_SHARE_BSS_POS; + .bss.share : + { + __bss_share_start = .; + *(.bss.share*) + __bss_share_end = .; + } + ASSERT(SIZEOF(.bss.share) <= (VMM_SHARE_BSS_PGSZ), ".bss.share is too big") + + . = VMM_SHARE_CTX_POS; + .vmm.share : + { + /* the vmm context goes here */ + __vmm_share_start = .; + *(.vmm.share*) + __vmm_share_end = .; + } + ASSERT(SIZEOF(.vmm.share) <= (VMM_SHARE_CTX_PGSZ), "vmm share context is too big") + + . = VMM_BEGIN + VMM_SHARE_PGSZ; + .text : + { + *(.vmm_init) + *(.text) + *(.text.*) + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + + /* section information for initialization */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + } + __text_end = .; + + __rodata_start = .; + .rodata : { *(.rodata) *(.rodata.*) } + __rodata_end = .; + + . = ALIGN(4); + .ctors : + { + PROVIDE(__ctors_start__ = .); + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + PROVIDE(__ctors_end__ = .); + } + + .dtors : + { + PROVIDE(__dtors_start__ = .); + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + PROVIDE(__dtors_end__ = .); + } + + __data_start = .; + . = ALIGN(8); + .data : + { + *(.data) + *(.data.*) + } + __data_end = .; + + . = ALIGN(8); + __bss_start = __data_end; + .bss : + { + vmm_stack_start = .; + . = vmm_stack_start + RT_VMM_STACK_SIZE; + vmm_stack_end = .; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + } + . = ALIGN(4); + __bss_end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + _end = .; +} diff --git a/bsp/realview-a8/rtconfig.h b/bsp/realview-a8/rtconfig.h new file mode 100644 index 0000000000..b32ae454ce --- /dev/null +++ b/bsp/realview-a8/rtconfig.h @@ -0,0 +1,153 @@ +/* RT-Thread config file */ +#ifndef __RTTHREAD_CFG_H__ +#define __RTTHREAD_CFG_H__ + +// + +// +#define RT_NAME_MAX 6 +// +#define RT_ALIGN_SIZE 4 +// +// 8 +// 32 +// 256 +// +#define RT_THREAD_PRIORITY_MAX 32 +// +#define RT_TICK_PER_SECOND 1000 +// +#define IDLE_THREAD_STACK_SIZE 512 +//
+#define RT_DEBUG +// +// #define RT_THREAD_DEBUG +// +// #define RT_USING_OVERFLOW_CHECK +//
+ +// +#define RT_USING_HOOK +//
+// #define RT_USING_TIMER_SOFT +// +#define RT_TIMER_THREAD_PRIO 4 +// +#define RT_TIMER_THREAD_STACK_SIZE 512 +// +#define RT_TIMER_TICK_PER_SECOND 10 +//
+ +//
+// +#define RT_USING_SEMAPHORE +// +#define RT_USING_MUTEX +// +#define RT_USING_EVENT +// +#define RT_USING_MAILBOX +// +#define RT_USING_MESSAGEQUEUE +//
+ +//
+// +#define RT_USING_MEMPOOL +// +// #define RT_USING_MEMHEAP +// +#define RT_USING_HEAP +// +// #define RT_USING_MEMHEAP_AS_HEAP +// +#define RT_USING_SMALL_MEM +// +// #define RT_USING_SLAB +//
+ +//
+#define RT_USING_DEVICE +// +#define RT_USING_DEVICE_IPC +// +#define RT_USING_SERIAL +// +#define RT_UART_RX_BUFFER_SIZE 64 +// +#define RT_USING_INTERRUPT_INFO +// +// #define RT_USING_UART0 +// +#define RT_USING_UART1 +//
+ +//
+#define RT_USING_CONSOLE +// +#define RT_CONSOLEBUF_SIZE 128 +// +#define RT_CONSOLE_DEVICE_NAME "uart1" +//
+ +// +#define RT_USING_COMPONENTS_INIT +//
+#define RT_USING_FINSH +// +#define FINSH_USING_MSH +// +#define FINSH_USING_MSH_DEFAULT +// +#define FINSH_USING_SYMTAB +// +#define FINSH_USING_DESCRIPTION +// +#define FINSH_THREAD_STACK_SIZE 4096 +//
+ +//
+// +#define RT_USING_NEWLIB +// +#define RT_USING_PTHREADS +//
+ +//
+// #define RT_USING_DFS +// +// #define DFS_USING_WORKDIR +// +#define DFS_FILESYSTEMS_MAX 2 +// +#define DFS_FD_MAX 4 +// +#define RT_USING_DFS_ELMFAT +// +// 1 +// 2 +// +#define RT_DFS_ELM_USE_LFN 1 +// +#define RT_DFS_ELM_MAX_LFN 64 +// +// #define RT_USING_DFS_YAFFS2 +// +// #define RT_USING_DFS_UFFS +// +// #define RT_USING_DFS_DEVFS +// +// #define RT_USING_DFS_NFS +// +#define RT_NFS_HOST_EXPORT "192.168.1.5:/" +//
+ +//
+ +#define RT_USING_LOGTRACE + +//
+#define RT_USING_VMM +//
+ +#endif diff --git a/bsp/realview-a8/rtconfig.py b/bsp/realview-a8/rtconfig.py new file mode 100644 index 0000000000..85f36831b3 --- /dev/null +++ b/bsp/realview-a8/rtconfig.py @@ -0,0 +1,109 @@ +import os + +# toolchains options +ARCH='arm' +CPU='realview-a8-vmm' +CROSS_TOOL='gcc' + +if os.getenv('RTT_CC'): + CROSS_TOOL = os.getenv('RTT_CC') + +if CROSS_TOOL == 'gcc': + PLATFORM = 'gcc' + # EXEC_PATH = r'/opt/arm-2012.09/bin' + EXEC_PATH = r'C:\Program Files (x86)\CodeSourcery\Sourcery_CodeBench_Lite_for_ARM_EABI\bin' + EXEC_PATH = '/opt/gcc-arm-none-eabi-4_8-2014q1_gri/bin' +elif CROSS_TOOL == 'keil': + PLATFORM = 'armcc' + EXEC_PATH = 'C:/Keil' + +if os.getenv('RTT_EXEC_PATH'): + EXEC_PATH = os.getenv('RTT_EXEC_PATH') + +BUILD = 'debug' +VMM = True +#VMM = False + +if PLATFORM == 'gcc': + # toolchains + PREFIX = 'arm-none-eabi-' + CC = PREFIX + 'gcc' + CXX = PREFIX + 'g++' + AS = PREFIX + 'gcc' + AR = PREFIX + 'ar' + LINK = PREFIX + 'gcc' + TARGET_EXT = 'elf' + SIZE = PREFIX + 'size' + OBJDUMP = PREFIX + 'objdump' + OBJCPY = PREFIX + 'objcopy' + + DEVICE = ' -march=armv7-a -mtune=cortex-a8 -mfpu=vfpv3-d16 -ftree-vectorize -ffast-math -mfloat-abi=softfp' + CFLAGS = DEVICE + ' -Wall' + AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__' + if VMM: + LINK_SCRIPT = 'realview_vmm.lds' + else: + LINK_SCRIPT = 'realview.lds' + LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=realview.map,-cref,-u,system_vectors'+\ + ' -T %s' % LINK_SCRIPT + + CPATH = '' + LPATH = '' + + # generate debug info in all cases + AFLAGS += ' -gdwarf-2' + CFLAGS += ' -g -gdwarf-2' + + if BUILD == 'debug': + CFLAGS += ' -O0' + else: + CFLAGS += ' -O2' + + POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' +\ + SIZE + ' $TARGET \n' +\ + OBJDUMP + ' -S $TARGET > rtt.S\n' + +elif PLATFORM == 'armcc': + # toolchains + CC = 'armcc' + CXX = 'armcc' + AS = 'armasm' + AR = 'armar' + LINK = 'armlink' + TARGET_EXT = 'axf' + + DEVICE = ' --device DARMP' + CFLAGS = DEVICE + ' --apcs=interwork' + AFLAGS = DEVICE + LFLAGS = DEVICE + ' --info sizes --info totals --info unused --info veneers --list rtthread-realview.map --scatter realview.sct' + + CFLAGS += ' -I' + EXEC_PATH + '/ARM/RV31/INC' + LFLAGS += ' --libpath ' + EXEC_PATH + '/ARM/RV31/LIB' + + EXEC_PATH += '/arm/bin40/' + + if BUILD == 'debug': + CFLAGS += ' -g -O0' + AFLAGS += ' -g' + else: + CFLAGS += ' -O2' + + POST_ACTION = 'fromelf --bin $TARGET --output rtthread.bin \nfromelf -z $TARGET' + +elif PLATFORM == 'iar': + # toolchains + CC = 'iccarm' + AS = 'iasmarm' + AR = 'iarchive' + LINK = 'ilinkarm' + TARGET_EXT = 'out' + + DEVICE = ' --cpu DARMP' + + CFLAGS = '' + AFLAGS = '' + LFLAGS = ' --config realview.icf' + + EXEC_PATH += '/arm/bin/' + RT_USING_MINILIBC = False + POST_ACTION = '' diff --git a/bsp/realview-a8/rtt_api.h b/bsp/realview-a8/rtt_api.h new file mode 100644 index 0000000000..815e06e3a0 --- /dev/null +++ b/bsp/realview-a8/rtt_api.h @@ -0,0 +1,154 @@ +#ifndef __RTT_API_H__ +#define __RTT_API_H__ + +/* 4MB in size */ +#define VMM_SIZE 0x400000 +#define VMM_END 0xc8000000 +#define VMM_BEGIN (VMM_END - VMM_SIZE) + +/* VMM Memory Map: + * + * --- VMM_BEGIN --- +------+ + * .vectors | 4KB | + * .text.share | | + * ----------------- + | + * guest vector page | 4KB | + * ----------------- + | + * .data.share | 4KB | + * ----------------- + | + * .bss.share | 4KB | + * -- SHARE_BASE -- + | 1MB + * shared context | shared region + * ----------------- | + * blabla... | + * ----------------- +------+ + * vmm text | + * rodata | + * blabla... | + * ----------------- | private region + * vmm data | + * ----------------- | + * vmm bss | + * ---- VMM_END ---- +------+ + * + */ + +/* 1MB is one level one page table entry, if we want to page table to be + * simple(avoid TLB miss), we could allocate 1MB for shared memory. */ +#define VMM_SHARE_PGSZ (1024*1024) + +/* the size and position of shared code text */ +#define VMM_SHARE_TEXT_PGSZ 4096 + +/* the size and position of vector's page size in Linux */ +#define LINUX_VECTOR_PGSZ 4096 +#define LINUX_VECTOR_POS (VMM_BEGIN + VMM_SHARE_TEXT_PGSZ) + +/* the size and position of shared code data */ +#define VMM_SHARE_DATA_PGSZ 4096 +#define VMM_SHARE_DATA_POS (LINUX_VECTOR_POS + LINUX_VECTOR_PGSZ) + +/* the size and position of shared code bss */ +#define VMM_SHARE_BSS_PGSZ 4096 +#define VMM_SHARE_BSS_POS (VMM_SHARE_DATA_POS + VMM_SHARE_DATA_PGSZ) + +/* the size and position of shared code bss */ +#define VMM_SHARE_CTX_PGSZ (VMM_SHARE_PGSZ - \ + LINUX_VECTOR_PGSZ - \ + VMM_SHARE_TEXT_PGSZ - \ + VMM_SHARE_DATA_PGSZ - \ + VMM_SHARE_BSS_PGSZ) +#if VMM_SHARE_CTX_PGSZ <= 0 +#error +#endif + +#define VMM_SHARE_CTX_POS (VMM_SHARE_BSS_POS + VMM_SHARE_BSS_PGSZ) + +/* the size of FIQ stack page size in RT-Thread */ +#define RT_FIQ_STACK_PGSZ 0 + +/* the size of IRQ stack page size in RT-Thread */ +#define RT_IRQ_STACK_PGSZ 4096 + +#ifdef HEAP_END +#undef HEAP_END +#endif +#define HEAP_END (VMM_END) + +#define RT_VMM_VIRQ_TRIGGER 10 + +#define RT_VMM_STACK_SIZE 1024 + +/* the max number of iomap entries */ +#define RT_VMM_IOMAP_MAXNR 16 + +#ifndef __iomem +#define __iomem +#endif + +#define IRQS_NR_32 ((96 + 31)/32) + +/*#define RT_VMM_USING_DOMAIN*/ + +#ifndef __ASSEMBLY__ + +/* keep consistent with linux/arch/arm/include/vmm/vmm.h */ +struct vmm_context +{ + /* the status of vGuest irq, read only for RT-Thread */ + volatile unsigned long virq_status; + + /* has interrupt pended on vGuest OS IRQ */ + volatile unsigned long virq_pended; + + /* pending interrupt for vGuest OS */ + volatile unsigned long virq_pending[IRQS_NR_32]; +}; + +struct vmm_domain +{ + /* the number of kernel domain */ + char kernel; + /* the number of user domain */ + char user; + /* the number of io domain */ + char io; + /* the number of vmm domain */ + char vmm; + /* the number of vmm_share domain */ + char vmm_share; +}; + +struct vmm_iomap +{ + const char name[16]; /* iomap name */ + + unsigned long pa; /* physical address */ + volatile void __iomem * va; /* virtual address */ + size_t size; /* memory size */ +}; + +struct vmm_entry_param +{ + struct vmm_iomap *iomap; + struct vmm_domain *domain; +}; + +typedef void (*vmm_entry_t)(struct vmm_entry_param* param); + +struct rt_vmm_share_layout +{ + struct vmm_context ctx; +}; + +#ifndef __KERNEL__ +/* not in Linux, use better type check */ +extern struct rt_vmm_share_layout rt_vmm_share; +#define RT_VMM_SHARE (&rt_vmm_share) +#else +#define RT_VMM_SHARE ((struct rt_vmm_share_layout*)VMM_SHARE_CTX_POS) +#endif + +#endif + +#endif /* end of include guard: __RTT_API_H__ */ diff --git a/components/vmm/SConscript b/components/vmm/SConscript new file mode 100644 index 0000000000..d67d2ee1aa --- /dev/null +++ b/components/vmm/SConscript @@ -0,0 +1,15 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +src += Glob('utilities/rshell.c') +if GetDepend('RT_USING_VMM_RFS'): + src += Glob('utilities/rfs.c') + +CPPPATH = [cwd, os.path.join(cwd, 'share_hdr')] + +group = DefineGroup('VMM', src, depend = ['RT_USING_VMM'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/vmm/linux_patch-v3.8/0001-RTT-VMM-implement-dual-system-running-on-realview-pb.patch b/components/vmm/linux_patch-v3.8/0001-RTT-VMM-implement-dual-system-running-on-realview-pb.patch new file mode 100644 index 0000000000..283b62dbdb --- /dev/null +++ b/components/vmm/linux_patch-v3.8/0001-RTT-VMM-implement-dual-system-running-on-realview-pb.patch @@ -0,0 +1,1211 @@ +From d001bd8483c805c45a42d9bd0468a96722e72875 Mon Sep 17 00:00:00 2001 +From: Grissiom +Date: Thu, 1 Aug 2013 14:59:56 +0800 +Subject: [PATCH 1/2] RTT-VMM: implement dual system running on realview-pb-a8 + +Signed-off-by: Grissiom +Signed-off-by: Bernard.Xiong +--- + arch/arm/Kconfig | 1 + + arch/arm/Makefile | 1 + + arch/arm/common/gic.c | 67 +++++++++++++- + arch/arm/include/asm/assembler.h | 8 +- + arch/arm/include/asm/domain.h | 7 ++ + arch/arm/include/asm/irqflags.h | 84 ++++++++++++----- + arch/arm/include/asm/mach/map.h | 5 + + arch/arm/include/vmm/vmm.h | 35 +++++++ + arch/arm/include/vmm/vmm_config.h | 7 ++ + arch/arm/kernel/entry-armv.S | 30 +++++- + arch/arm/kernel/entry-common.S | 3 + + arch/arm/kernel/entry-header.S | 15 ++- + arch/arm/mach-omap2/irq.c | 12 +++ + arch/arm/mm/fault.c | 9 ++ + arch/arm/mm/init.c | 8 ++ + arch/arm/mm/mmu.c | 44 +++++++++ + arch/arm/vmm/Kconfig | 49 ++++++++++ + arch/arm/vmm/Makefile | 10 ++ + arch/arm/vmm/README | 1 + + arch/arm/vmm/am33xx/intc.h | 13 +++ + arch/arm/vmm/am33xx/softirq.c | 14 +++ + arch/arm/vmm/am33xx/virq.c | 48 ++++++++++ + arch/arm/vmm/realview_a8/softirq.c | 12 +++ + arch/arm/vmm/vmm.c | 32 +++++++ + arch/arm/vmm/vmm_traps.c | 37 ++++++++ + arch/arm/vmm/vmm_virhw.h | 59 ++++++++++++ + arch/arm/vmm/vmm_virq.c | 183 +++++++++++++++++++++++++++++++++++++ + 27 files changed, 767 insertions(+), 27 deletions(-) + create mode 100644 arch/arm/include/vmm/vmm.h + create mode 100644 arch/arm/include/vmm/vmm_config.h + create mode 100644 arch/arm/vmm/Kconfig + create mode 100644 arch/arm/vmm/Makefile + create mode 100644 arch/arm/vmm/README + create mode 100644 arch/arm/vmm/am33xx/intc.h + create mode 100644 arch/arm/vmm/am33xx/softirq.c + create mode 100644 arch/arm/vmm/am33xx/virq.c + create mode 100644 arch/arm/vmm/realview_a8/softirq.c + create mode 100644 arch/arm/vmm/vmm.c + create mode 100644 arch/arm/vmm/vmm_traps.c + create mode 100644 arch/arm/vmm/vmm_virhw.h + create mode 100644 arch/arm/vmm/vmm_virq.c + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index 67874b8..eb82cd6 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1164,6 +1164,7 @@ config ARM_TIMER_SP804 + select HAVE_SCHED_CLOCK + + source arch/arm/mm/Kconfig ++source arch/arm/vmm/Kconfig + + config ARM_NR_BANKS + int +diff --git a/arch/arm/Makefile b/arch/arm/Makefile +index 30c443c..262c8e2 100644 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -252,6 +252,7 @@ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ + core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) + core-$(CONFIG_VFP) += arch/arm/vfp/ + core-$(CONFIG_XEN) += arch/arm/xen/ ++core-$(CONFIG_ARM_VMM) += arch/arm/vmm/ + + # If we have a machine-specific directory, then include it in the build. + core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ +diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c +index 87dfa90..a9d7357 100644 +--- a/arch/arm/common/gic.c ++++ b/arch/arm/common/gic.c +@@ -45,6 +45,11 @@ + #include + #include + ++#ifdef CONFIG_ARM_VMM ++#include ++#include "../vmm/vmm_virhw.h" ++#endif ++ + union gic_base { + void __iomem *common_base; + void __percpu __iomem **percpu_base; +@@ -276,12 +281,72 @@ static int gic_set_wake(struct irq_data *d, unsigned int on) + #define gic_set_wake NULL + #endif + ++#ifdef CONFIG_ARM_VMM ++void vmm_irq_handle(struct gic_chip_data *gic, struct pt_regs *regs) ++{ ++ unsigned long flags; ++ struct vmm_context* _vmm_context; ++ ++ _vmm_context = vmm_context_get(); ++ ++ while (_vmm_context->virq_pended) { ++ int index; ++ ++ flags = vmm_irq_save(); ++ _vmm_context->virq_pended = 0; ++ vmm_irq_restore(flags); ++ ++ /* get the pending interrupt */ ++ for (index = 0; index < IRQS_NR_32; index++) { ++ int pdbit; ++ ++ for (pdbit = __builtin_ffs(_vmm_context->virq_pending[index]); ++ pdbit != 0; ++ pdbit = __builtin_ffs(_vmm_context->virq_pending[index])) { ++ unsigned long inner_flag; ++ int irqnr, oirqnr; ++ ++ pdbit--; ++ ++ inner_flag = vmm_irq_save(); ++ _vmm_context->virq_pending[index] &= ~(1 << pdbit); ++ vmm_irq_restore(inner_flag); ++ ++ oirqnr = pdbit + index * 32; ++ if (likely(oirqnr > 15 && oirqnr < 1021)) { ++ irqnr = irq_find_mapping(gic->domain, oirqnr); ++ handle_IRQ(irqnr, regs); ++ } else if (oirqnr < 16) { ++ /* soft IRQs are EOIed by the host. */ ++#ifdef CONFIG_SMP ++ handle_IPI(oirqnr, regs); ++#endif ++ } ++ /* umask interrupt */ ++ /* FIXME: maybe we don't need this */ ++ writel_relaxed(1 << (oirqnr % 32), ++ gic_data_dist_base(gic) ++ + GIC_DIST_ENABLE_SET ++ + (oirqnr / 32) * 4); ++ ++ } ++ } ++ } ++} ++#endif ++ + asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) + { + u32 irqstat, irqnr; + struct gic_chip_data *gic = &gic_data[0]; + void __iomem *cpu_base = gic_data_cpu_base(gic); + ++#ifdef CONFIG_ARM_VMM ++ if (vmm_get_status()) { ++ vmm_irq_handle(gic, regs); ++ return; ++ } ++#endif + do { + irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); + irqnr = irqstat & ~0x1c00; +@@ -777,7 +842,7 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr) + gic_cpu_init(&gic_data[gic_nr]); + } + +-#ifdef CONFIG_SMP ++#if defined(CONFIG_SMP) || defined(CONFIG_ARM_VMM) + void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) + { + int cpu; +diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h +index eb87200..b646fa7 100644 +--- a/arch/arm/include/asm/assembler.h ++++ b/arch/arm/include/asm/assembler.h +@@ -82,11 +82,15 @@ + */ + #if __LINUX_ARM_ARCH__ >= 6 + .macro disable_irq_notrace +- cpsid i ++ stmdb sp!, {r0-r3, ip, lr} ++ bl irq_disable_asm ++ ldmia sp!, {r0-r3, ip, lr} + .endm + + .macro enable_irq_notrace +- cpsie i ++ stmdb sp!, {r0-r3, ip, lr} ++ bl irq_enable_asm ++ ldmia sp!, {r0-r3, ip, lr} + .endm + #else + .macro disable_irq_notrace +diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h +index 6ddbe44..bbc4470 100644 +--- a/arch/arm/include/asm/domain.h ++++ b/arch/arm/include/asm/domain.h +@@ -44,6 +44,13 @@ + #define DOMAIN_IO 0 + #endif + ++#ifdef CONFIG_ARM_VMM ++/* RT-Thread VMM memory space */ ++#define DOMAIN_RTVMM 3 ++/* shared memory with VMM and Linux */ ++#define DOMAIN_RTVMM_SHR 4 ++#endif ++ + /* + * Domain types + */ +diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h +index 1e6cca5..bfaedff 100644 +--- a/arch/arm/include/asm/irqflags.h ++++ b/arch/arm/include/asm/irqflags.h +@@ -9,34 +9,56 @@ + * CPU interrupt mask handling. + */ + #if __LINUX_ARM_ARCH__ >= 6 ++#include /* VMM only support ARMv7 right now */ + + static inline unsigned long arch_local_irq_save(void) + { + unsigned long flags; + +- asm volatile( +- " mrs %0, cpsr @ arch_local_irq_save\n" +- " cpsid i" +- : "=r" (flags) : : "memory", "cc"); ++ if (vmm_status) ++ { ++ flags = vmm_save_virq(); ++ } ++ else ++ { ++ asm volatile( ++ " mrs %0, cpsr @ arch_local_irq_save\n" ++ " cpsid i" ++ : "=r" (flags) : : "memory", "cc"); ++ } + return flags; + } + + static inline void arch_local_irq_enable(void) + { +- asm volatile( +- " cpsie i @ arch_local_irq_enable" +- : +- : +- : "memory", "cc"); ++ if (vmm_status) ++ { ++ vmm_enable_virq(); ++ } ++ else ++ { ++ asm volatile( ++ " cpsie i @ arch_local_irq_enable" ++ : ++ : ++ : "memory", "cc"); ++ } + } + + static inline void arch_local_irq_disable(void) + { +- asm volatile( +- " cpsid i @ arch_local_irq_disable" +- : +- : +- : "memory", "cc"); ++ if (vmm_status) ++ { ++ vmm_disable_virq(); ++ } ++ else ++ { ++ asm volatile( ++ " cpsid i @ arch_local_irq_disable" ++ : ++ : ++ : "memory", "cc"); ++ } + } + + #define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc") +@@ -128,9 +150,17 @@ static inline void arch_local_irq_disable(void) + static inline unsigned long arch_local_save_flags(void) + { + unsigned long flags; +- asm volatile( +- " mrs %0, cpsr @ local_save_flags" +- : "=r" (flags) : : "memory", "cc"); ++ ++ if (vmm_status) ++ { ++ flags = vmm_return_virq(); ++ } ++ else ++ { ++ asm volatile( ++ " mrs %0, cpsr @ local_save_flags" ++ : "=r" (flags) : : "memory", "cc"); ++ } + return flags; + } + +@@ -139,15 +169,25 @@ static inline unsigned long arch_local_save_flags(void) + */ + static inline void arch_local_irq_restore(unsigned long flags) + { +- asm volatile( +- " msr cpsr_c, %0 @ local_irq_restore" +- : +- : "r" (flags) +- : "memory", "cc"); ++ if (vmm_status) ++ { ++ vmm_restore_virq(flags); ++ } ++ else ++ { ++ asm volatile( ++ " msr cpsr_c, %0 @ local_irq_restore" ++ : ++ : "r" (flags) ++ : "memory", "cc"); ++ } + } + + static inline int arch_irqs_disabled_flags(unsigned long flags) + { ++ if (vmm_status) ++ return (flags == 0x01); ++ + return flags & PSR_I_BIT; + } + +diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h +index 2fe141f..502b341 100644 +--- a/arch/arm/include/asm/mach/map.h ++++ b/arch/arm/include/asm/mach/map.h +@@ -35,6 +35,11 @@ struct map_desc { + #define MT_MEMORY_SO 14 + #define MT_MEMORY_DMA_READY 15 + ++#ifdef CONFIG_ARM_VMM ++#define MT_RTVMM 16 ++#define MT_RTVMM_SHARE 17 ++#endif ++ + #ifdef CONFIG_MMU + extern void iotable_init(struct map_desc *, int); + extern void vm_reserve_area_early(unsigned long addr, unsigned long size, +diff --git a/arch/arm/include/vmm/vmm.h b/arch/arm/include/vmm/vmm.h +new file mode 100644 +index 0000000..3ff3f31 +--- /dev/null ++++ b/arch/arm/include/vmm/vmm.h +@@ -0,0 +1,35 @@ ++#ifndef __LINUX_VMM_H__ ++#define __LINUX_VMM_H__ ++ ++#include ++ ++#include "vmm_config.h" ++ ++struct irq_domain; ++struct pt_regs; ++ ++extern int vmm_status; ++extern struct vmm_context *_vmm_context; ++ ++/* VMM context routines */ ++void vmm_context_init(void* context); ++struct vmm_context* vmm_context_get(void); ++ ++void vmm_set_status(int status); ++int vmm_get_status(void); ++ ++void vmm_mem_init(void); ++void vmm_raise_softirq(int irq); ++ ++/* VMM vIRQ routines */ ++unsigned long vmm_save_virq(void); ++unsigned long vmm_return_virq(void); ++ ++void vmm_restore_virq(unsigned long flags); ++void vmm_enable_virq(void); ++void vmm_disable_virq(void); ++void vmm_enter_hw_noirq(void); ++ ++void vmm_raise_softirq(int irq); ++ ++#endif +diff --git a/arch/arm/include/vmm/vmm_config.h b/arch/arm/include/vmm/vmm_config.h +new file mode 100644 +index 0000000..cce5e8a +--- /dev/null ++++ b/arch/arm/include/vmm/vmm_config.h +@@ -0,0 +1,7 @@ ++#ifndef __LINUX_VMM_CONFIG_H__ ++#define __LINUX_VMM_CONFIG_H__ ++ ++#define HOST_VMM_ADDR_END CONFIG_HOST_VMM_ADDR_END ++#define HOST_VMM_ADDR_BEGIN (CONFIG_HOST_VMM_ADDR_END - CONFIG_HOST_VMM_SIZE) ++ ++#endif +diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S +index 0f82098..80f1681 100644 +--- a/arch/arm/kernel/entry-armv.S ++++ b/arch/arm/kernel/entry-armv.S +@@ -182,6 +182,15 @@ ENDPROC(__und_invalid) + @ + stmia r7, {r2 - r6} + ++ stmdb sp!, {r0-r3, ip, lr} ++ mov r0, r5 ++ add r1, sp, #4*6 ++ bl vmm_save_virq_spsr_asm ++ mov r5, r0 ++ bl vmm_switch_nohwirq_to_novirq ++ ldmia sp!, {r0-r3, ip, lr} ++ str r5, [sp, #S_PSR] @ fix the pushed SPSR ++ + #ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off + #endif +@@ -208,6 +217,23 @@ __dabt_svc: + UNWIND(.fnend ) + ENDPROC(__dabt_svc) + ++ .macro svc_exit_irq, rpsr ++ cpsid i ++ msr spsr_cxsf, \rpsr ++ mov r0, \rpsr ++ bl vmm_on_svc_exit_irq ++#if defined(CONFIG_CPU_V6) ++ ldr r0, [sp] ++ strex r1, r2, [sp] @ clear the exclusive monitor ++ ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr ++#elif defined(CONFIG_CPU_32v6K) ++ clrex @ clear the exclusive monitor ++ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr ++#else ++ ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr ++#endif ++ .endm ++ + .align 5 + __irq_svc: + svc_entry +@@ -228,7 +254,7 @@ __irq_svc: + @ the first place, so there's no point checking the PSR I bit. + bl trace_hardirqs_on + #endif +- svc_exit r5 @ return from exception ++ svc_exit_irq r5 @ return from exception + UNWIND(.fnend ) + ENDPROC(__irq_svc) + +@@ -393,6 +419,8 @@ ENDPROC(__pabt_svc) + @ + zero_fp + ++ bl vmm_switch_nohwirq_to_novirq ++ + #ifdef CONFIG_IRQSOFF_TRACER + bl trace_hardirqs_off + #endif +diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S +index a6c301e..325a26e 100644 +--- a/arch/arm/kernel/entry-common.S ++++ b/arch/arm/kernel/entry-common.S +@@ -349,6 +349,9 @@ ENTRY(vector_swi) + str lr, [sp, #S_PC] @ Save calling PC + str r8, [sp, #S_PSR] @ Save CPSR + str r0, [sp, #S_OLD_R0] @ Save OLD_R0 ++ stmdb sp!, {r0-r3, ip, lr} ++ bl vmm_switch_nohwirq_to_novirq ++ ldmia sp!, {r0-r3, ip, lr} + zero_fp + + /* +diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S +index 9a8531e..9e438dc 100644 +--- a/arch/arm/kernel/entry-header.S ++++ b/arch/arm/kernel/entry-header.S +@@ -75,7 +75,11 @@ + + #ifndef CONFIG_THUMB2_KERNEL + .macro svc_exit, rpsr +- msr spsr_cxsf, \rpsr ++ cpsid i ++ mov r0, \rpsr ++ bl vmm_restore_virq_asm @ restore the IRQ to emulate ++ @ the behavior of ldmia {}^ ++ msr spsr_cxsf, r0 + #if defined(CONFIG_CPU_V6) + ldr r0, [sp] + strex r1, r2, [sp] @ clear the exclusive monitor +@@ -90,6 +94,10 @@ + + .macro restore_user_regs, fast = 0, offset = 0 + ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr ++ @ protect the spsr *and* stack we push the registers into this stack ++ @ and if the sp is not point to the bottom of the stack, IRQ should be ++ @ disabled. ++ cpsid i + ldr lr, [sp, #\offset + S_PC]! @ get pc + msr spsr_cxsf, r1 @ save in spsr_svc + #if defined(CONFIG_CPU_V6) +@@ -105,6 +113,11 @@ + mov r0, r0 @ ARMv5T and earlier require a nop + @ after ldm {}^ + add sp, sp, #S_FRAME_SIZE - S_PC ++ @ TODO: in some conditions the call to vmm_on_ret_to_usr is useless. ++ stmdb sp!, {r0-r3, ip, lr} ++ mrs r0, spsr @ debug code ++ bl vmm_on_ret_to_usr ++ ldmia sp!, {r0-r3, ip, lr} + movs pc, lr @ return & move spsr_svc into cpsr + .endm + +diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c +index 3926f37..252577f 100644 +--- a/arch/arm/mach-omap2/irq.c ++++ b/arch/arm/mach-omap2/irq.c +@@ -23,6 +23,10 @@ + #include + #include + ++#ifdef CONFIG_ARM_VMM ++#include ++#endif ++ + #include "soc.h" + #include "iomap.h" + #include "common.h" +@@ -223,6 +227,14 @@ static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs + { + u32 irqnr; + ++#ifdef CONFIG_ARM_VMM ++ if (vmm_get_status()) ++ { ++ vmm_irq_handle(base_addr, domain, regs); ++ return; ++ } ++#endif ++ + do { + irqnr = readl_relaxed(base_addr + 0x98); + if (irqnr) +diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c +index 5dbf13f..e76ba74 100644 +--- a/arch/arm/mm/fault.c ++++ b/arch/arm/mm/fault.c +@@ -255,6 +255,10 @@ out: + return fault; + } + ++#ifdef CONFIG_ARM_VMM ++#include ++#endif ++ + static int __kprobes + do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + { +@@ -268,6 +272,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) + if (notify_page_fault(regs, fsr)) + return 0; + ++#ifdef CONFIG_ARM_VMMX ++ WARN(HOST_VMM_ADDR_BEGIN < regs->ARM_pc && ++ regs->ARM_pc < HOST_VMM_ADDR_END); ++#endif ++ + tsk = current; + mm = tsk->mm; + +diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c +index ad722f1..ebb4e7f 100644 +--- a/arch/arm/mm/init.c ++++ b/arch/arm/mm/init.c +@@ -34,6 +34,10 @@ + #include + #include + ++#ifdef CONFIG_ARM_VMM ++#include ++#endif ++ + #include "mm.h" + + static unsigned long phys_initrd_start __initdata = 0; +@@ -338,6 +342,10 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) + for (i = 0; i < mi->nr_banks; i++) + memblock_add(mi->bank[i].start, mi->bank[i].size); + ++#ifdef CONFIG_ARM_VMM ++ memblock_reserve(__pa(HOST_VMM_ADDR_BEGIN), HOST_VMM_ADDR_END - HOST_VMM_ADDR_BEGIN); ++#endif ++ + /* Register the kernel text, kernel data and initrd with memblock. */ + #ifdef CONFIG_XIP_KERNEL + memblock_reserve(__pa(_sdata), _end - _sdata); +diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c +index ce328c7..7e7d0ca 100644 +--- a/arch/arm/mm/mmu.c ++++ b/arch/arm/mm/mmu.c +@@ -294,6 +294,20 @@ static struct mem_type mem_types[] = { + .prot_l1 = PMD_TYPE_TABLE, + .domain = DOMAIN_KERNEL, + }, ++#ifdef CONFIG_ARM_VMM ++ [MT_RTVMM] = { ++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, ++ .domain = DOMAIN_RTVMM, ++ }, ++ [MT_RTVMM_SHARE] = { ++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, ++ .domain = DOMAIN_RTVMM_SHR, ++ }, ++#endif + }; + + const struct mem_type *get_mem_type(unsigned int type) +@@ -450,6 +464,9 @@ static void __init build_mem_type_table(void) + mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED; ++#ifdef CONFIG_ARM_VMM ++ /* FIXME */ ++#endif + mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED; +@@ -503,6 +520,12 @@ static void __init build_mem_type_table(void) + mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; + mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd; + mem_types[MT_MEMORY].prot_pte |= kern_pgprot; ++#ifdef CONFIG_ARM_VMM ++ mem_types[MT_RTVMM].prot_sect |= ecc_mask | cp->pmd; ++ mem_types[MT_RTVMM].prot_pte |= kern_pgprot; ++ mem_types[MT_RTVMM_SHARE].prot_sect |= ecc_mask | cp->pmd; ++ mem_types[MT_RTVMM_SHARE].prot_pte |= kern_pgprot; ++#endif + mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot; + mem_types[MT_MEMORY_NONCACHED].prot_sect |= ecc_mask; + mem_types[MT_ROM].prot_sect |= cp->pmd; +@@ -1152,6 +1175,27 @@ static void __init devicemaps_init(struct machine_desc *mdesc) + #endif + + /* ++ * Create mappings for RT-Thread VMM and it's shared memory with Linux ++ */ ++#ifdef CONFIG_ARM_VMM ++ /* the TEXCB attribute is not right yet */ ++ /* shared memory region comes first */ ++ map.pfn = __phys_to_pfn(virt_to_phys((void*)HOST_VMM_ADDR_BEGIN)); ++ map.virtual = HOST_VMM_ADDR_BEGIN; ++ map.length = CONFIG_RTVMM_SHARED_SIZE; ++ map.type = MT_RTVMM_SHARE; ++ create_mapping(&map); ++ ++ /* vmm private region comes next */ ++ map.pfn = __phys_to_pfn(virt_to_phys((void*)HOST_VMM_ADDR_BEGIN ++ + CONFIG_RTVMM_SHARED_SIZE)); ++ map.virtual = HOST_VMM_ADDR_BEGIN + CONFIG_RTVMM_SHARED_SIZE; ++ map.length = CONFIG_HOST_VMM_SIZE - CONFIG_RTVMM_SHARED_SIZE; ++ map.type = MT_RTVMM; ++ create_mapping(&map); ++#endif ++ ++ /* + * Create a mapping for the machine vectors at the high-vectors + * location (0xffff0000). If we aren't using high-vectors, also + * create a mapping at the low-vectors virtual address. +diff --git a/arch/arm/vmm/Kconfig b/arch/arm/vmm/Kconfig +new file mode 100644 +index 0000000..d852056 +--- /dev/null ++++ b/arch/arm/vmm/Kconfig +@@ -0,0 +1,49 @@ ++menu "RT-Thread VMM Features" ++ ++# ARM-VMM ++config ARM_VMM ++ bool "Support RT-Thread VMM on ARM Cortex-A8" ++ depends on MACH_REALVIEW_PBA8 ++ help ++ RT-Thread VMM implementation on ARM Cortex-A8 ++ ++ Say Y if you want support for the RT-Thread VMM. ++ Otherwise, say N. ++ ++if SOC_AM33XX ++config HOST_VMM_ADDR_END ++ hex "End address of VMM" ++ depends on ARM_VMM ++ default 0xE0000000 ++ help ++ The end address of VMM space. Normally, it's the ++ end address of DDR memory. ++endif ++ ++if MACH_REALVIEW_PBA8 ++config HOST_VMM_ADDR_END ++ hex "End address of VMM" ++ depends on ARM_VMM ++ default 0xE0000000 ++ help ++ The end address of VMM space. Normally, it's the ++ end address of DDR memory. ++endif ++ ++config HOST_VMM_SIZE ++ hex "Size of VMM space" ++ depends on ARM_VMM ++ default 0x400000 ++ help ++ The size of VMM space. ++ ++config RTVMM_SHARED_SIZE ++ hex "Size of shared memory space between rt-vmm and Linux" ++ depends on ARM_VMM ++ default 0x100000 ++ help ++ The size of shared memory space between rt-vmm and Linux. This shared ++ space is within the total size of the HOST_VMM_SIZE. So it is should ++ be smaller than HOST_VMM_SIZE. ++ ++endmenu +diff --git a/arch/arm/vmm/Makefile b/arch/arm/vmm/Makefile +new file mode 100644 +index 0000000..127e43a +--- /dev/null ++++ b/arch/arm/vmm/Makefile +@@ -0,0 +1,10 @@ ++# ++# Makefile for the linux arm-vmm ++# ++ ++obj-$(CONFIG_ARM_VMM) += vmm.o vmm_traps.o vmm_virq.o ++ ++ifeq ($(CONFIG_ARM_VMM),y) ++obj-$(CONFIG_SOC_AM33XX) += am33xx/softirq.o am33xx/virq.o ++obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_a8/softirq.o ++endif +diff --git a/arch/arm/vmm/README b/arch/arm/vmm/README +new file mode 100644 +index 0000000..24f1b42 +--- /dev/null ++++ b/arch/arm/vmm/README +@@ -0,0 +1 @@ ++Linux VMM kernel routines +diff --git a/arch/arm/vmm/am33xx/intc.h b/arch/arm/vmm/am33xx/intc.h +new file mode 100644 +index 0000000..6c24f8d +--- /dev/null ++++ b/arch/arm/vmm/am33xx/intc.h +@@ -0,0 +1,13 @@ ++#ifndef __INTC_H__ ++#define __INTC_H__ ++ ++#define OMAP34XX_IC_BASE 0x48200000 ++ ++#define INTC_SIR_SET0 0x0090 ++#define INTC_MIR_CLEAR0 0x0088 ++ ++#define OMAP2_L4_IO_OFFSET 0xb2000000 ++#define OMAP2_L4_IO_ADDRESS(pa) IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */ ++#define OMAP3_IRQ_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE) ++ ++#endif +diff --git a/arch/arm/vmm/am33xx/softirq.c b/arch/arm/vmm/am33xx/softirq.c +new file mode 100644 +index 0000000..5648496 +--- /dev/null ++++ b/arch/arm/vmm/am33xx/softirq.c +@@ -0,0 +1,14 @@ ++#include ++#include ++#include ++ ++#include ++#include "../vmm_virhw.h" ++#include "intc.h" ++ ++void vmm_raise_softirq(int irq) ++{ ++ writel_relaxed(1 << (irq % 32), ++ OMAP3_IRQ_BASE + INTC_SIR_SET0 + (irq / 32) * 4); ++} ++EXPORT_SYMBOL(vmm_raise_softirq); +diff --git a/arch/arm/vmm/am33xx/virq.c b/arch/arm/vmm/am33xx/virq.c +new file mode 100644 +index 0000000..4ef7671 +--- /dev/null ++++ b/arch/arm/vmm/am33xx/virq.c +@@ -0,0 +1,48 @@ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include "../vmm_virhw.h" ++#include "intc.h" ++ ++void vmm_irq_handle(void __iomem *base_addr, struct irq_domain *domain, ++ struct pt_regs *regs) ++{ ++ unsigned long flags; ++ struct vmm_context* _vmm_context; ++ ++ _vmm_context = vmm_context_get(); ++ ++ while (_vmm_context->virq_pended) { ++ int index; ++ ++ flags = vmm_irq_save(); ++ _vmm_context->virq_pended = 0; ++ vmm_irq_restore(flags); ++ ++ /* get the pending interrupt */ ++ for (index = 0; index < IRQS_NR_32; index++) { ++ int pdbit; ++ ++ for (pdbit = __builtin_ffs(_vmm_context->virq_pending[index]); ++ pdbit != 0; ++ pdbit = __builtin_ffs(_vmm_context->virq_pending[index])) { ++ unsigned long inner_flag; ++ int irqnr; ++ ++ pdbit--; ++ ++ inner_flag = vmm_irq_save(); ++ _vmm_context->virq_pending[index] &= ~(1 << pdbit); ++ vmm_irq_restore(inner_flag); ++ ++ irqnr = irq_find_mapping(domain, pdbit + index * 32); ++ handle_IRQ(irqnr, regs); ++ } ++ } ++ } ++} +diff --git a/arch/arm/vmm/realview_a8/softirq.c b/arch/arm/vmm/realview_a8/softirq.c +new file mode 100644 +index 0000000..a52b79c7 +--- /dev/null ++++ b/arch/arm/vmm/realview_a8/softirq.c +@@ -0,0 +1,12 @@ ++#include ++#include ++#include ++#include ++ ++#include ++ ++void vmm_raise_softirq(int irq) ++{ ++ gic_raise_softirq(cpumask_of(0), irq); ++} ++EXPORT_SYMBOL(vmm_raise_softirq); +diff --git a/arch/arm/vmm/vmm.c b/arch/arm/vmm/vmm.c +new file mode 100644 +index 0000000..3b1d202 +--- /dev/null ++++ b/arch/arm/vmm/vmm.c +@@ -0,0 +1,32 @@ ++#include ++#include ++ ++#include ++ ++struct vmm_context* _vmm_context = NULL; ++int vmm_status = 0; ++EXPORT_SYMBOL(vmm_status); ++ ++void vmm_set_status(int status) ++{ ++ vmm_status = status; ++} ++EXPORT_SYMBOL(vmm_set_status); ++ ++int vmm_get_status(void) ++{ ++ return vmm_status; ++} ++EXPORT_SYMBOL(vmm_get_status); ++ ++void vmm_context_init(void* context_addr) ++{ ++ _vmm_context = (struct vmm_context*)context_addr; ++} ++EXPORT_SYMBOL(vmm_context_init); ++ ++struct vmm_context* vmm_context_get(void) ++{ ++ return _vmm_context; ++} ++EXPORT_SYMBOL(vmm_context_get); +diff --git a/arch/arm/vmm/vmm_traps.c b/arch/arm/vmm/vmm_traps.c +new file mode 100644 +index 0000000..def0d90 +--- /dev/null ++++ b/arch/arm/vmm/vmm_traps.c +@@ -0,0 +1,37 @@ ++#include ++#include ++#include ++#include ++#include ++ ++void trap_set_vector(void *start, unsigned int length) ++{ ++ unsigned char *ptr; ++ unsigned char *vector; ++ ++ ptr = start; ++ vector = (unsigned char*)vectors_page; ++ ++ /* only set IRQ and FIQ */ ++#if defined(CONFIG_CPU_USE_DOMAINS) ++ /* IRQ */ ++ memcpy((void *)0xffff0018, (void*)(ptr + 0x18), 4); ++ memcpy((void *)(0xffff0018 + 0x20), (void*)(ptr + 0x18 + 0x20), 4); ++ ++ /* FIQ */ ++ memcpy((void *)0xffff001C, (void*)(ptr + 0x1C), 4); ++ memcpy((void *)(0xffff001C + 0x20), (void*)(ptr + 0x1C + 0x20), 4); ++#else ++ /* IRQ */ ++ memcpy(vector + 0x18, (void*)(ptr + 0x18), 4); ++ memcpy(vector + 0x18 + 0x20, (void*)(ptr + 0x18 + 0x20), 4); ++ ++ /* FIQ */ ++ memcpy(vector + 0x1C, (void*)(ptr + 0x1C), 4); ++ memcpy(vector + 0x1C + 0x20, (void*)(ptr + 0x1C + 0x20), 4); ++#endif ++ flush_icache_range(0xffff0000, 0xffff0000 + length); ++ if (!vectors_high()) ++ flush_icache_range(0x00, 0x00 + length); ++} ++EXPORT_SYMBOL(trap_set_vector); +diff --git a/arch/arm/vmm/vmm_virhw.h b/arch/arm/vmm/vmm_virhw.h +new file mode 100644 +index 0000000..363cc6e +--- /dev/null ++++ b/arch/arm/vmm/vmm_virhw.h +@@ -0,0 +1,59 @@ ++#ifndef __VMM_VIRTHWH__ ++#define __VMM_VIRTHWH__ ++ ++#define REALVIEW_NR_IRQS 96 ++#define IRQS_NR_32 ((REALVIEW_NR_IRQS + 31)/32) ++#define RTT_VMM_IRQ_TRIGGER 10 ++ ++struct vmm_context ++{ ++ /* the status of vGuest irq */ ++ volatile unsigned long virq_status; ++ ++ /* has interrupt pended on vGuest OS IRQ */ ++ volatile unsigned long virq_pended; ++ ++ /* pending interrupt for vGuest OS */ ++ volatile unsigned long virq_pending[IRQS_NR_32]; ++}; ++ ++/* IRQ operation under VMM */ ++static inline unsigned long vmm_irq_save(void) ++{ ++ unsigned long flags; ++ ++ asm volatile( ++ " mrs %0, cpsr @ arch_local_irq_save\n" ++ " cpsid i" ++ : "=r" (flags) : : "memory", "cc"); ++ return flags; ++} ++ ++static inline void vmm_irq_restore(unsigned long flags) ++{ ++ asm volatile( ++ " msr cpsr_c, %0 @ local_irq_restore" ++ : ++ : "r" (flags) ++ : "memory", "cc"); ++} ++ ++static inline void vmm_irq_enable(void) ++{ ++ asm volatile( ++ " cpsie i @ arch_local_irq_enable" ++ : ++ : ++ : "memory", "cc"); ++} ++ ++static inline void vmm_irq_disable(void) ++{ ++ asm volatile( ++ " cpsid i @ arch_local_irq_disable" ++ : ++ : ++ : "memory", "cc"); ++} ++ ++#endif +diff --git a/arch/arm/vmm/vmm_virq.c b/arch/arm/vmm/vmm_virq.c +new file mode 100644 +index 0000000..85886a2 +--- /dev/null ++++ b/arch/arm/vmm/vmm_virq.c +@@ -0,0 +1,183 @@ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "vmm_virhw.h" ++ ++/* VMM use the I bit in SPSR to save the virq status in the isr entry. So warn ++ * on the I bit set would gave some false negative result. */ ++//#define VMM_WARN_ON_I_BIT ++ ++extern struct vmm_context* _vmm_context; ++ ++void vmm_disable_virq(void) ++{ ++ unsigned long flags = vmm_irq_save(); ++ _vmm_context->virq_status = 0x01; ++ vmm_irq_restore(flags); ++} ++EXPORT_SYMBOL(vmm_disable_virq); ++ ++static void _vmm_raise_on_pended(void) ++{ ++ /* check any interrupt pended in vIRQ */ ++ if (_vmm_context->virq_pended) { ++ /* trigger an soft interrupt */ ++ vmm_raise_softirq(RTT_VMM_IRQ_TRIGGER); ++ return; ++ } ++ ++#if 0 ++ int i; ++ for (i = 0; i < ARRAY_SIZE(_vmm_context->virq_pending); i++) { ++ if (_vmm_context->virq_pending[i]) { ++ _vmm_context->virq_pended = 1; ++ pr_info("\n"); ++ vmm_raise_softirq(RTT_VMM_IRQ_TRIGGER); ++ return; ++ } ++ } ++#endif ++} ++ ++void vmm_enable_virq(void) ++{ ++ unsigned long flags = vmm_irq_save(); ++ _vmm_context->virq_status = 0x00; ++ _vmm_raise_on_pended(); ++ vmm_irq_restore(flags); ++} ++EXPORT_SYMBOL(vmm_enable_virq); ++ ++unsigned long vmm_return_virq(void) ++{ ++ unsigned long flags; ++ unsigned long level; ++ ++ level = vmm_irq_save(); ++ flags = _vmm_context->virq_status; ++ vmm_irq_restore(level); ++ ++ return flags; ++} ++EXPORT_SYMBOL(vmm_return_virq); ++ ++unsigned long vmm_save_virq(void) ++{ ++ int status; ++ unsigned long flags = vmm_irq_save(); ++ ++ status = _vmm_context->virq_status; ++ _vmm_context->virq_status = 0x01; ++ vmm_irq_restore(flags); ++ ++ return status; ++} ++EXPORT_SYMBOL(vmm_save_virq); ++ ++void vmm_restore_virq(unsigned long flags) ++{ ++ unsigned long level; ++ ++ level = vmm_irq_save(); ++ _vmm_context->virq_status = flags; ++ if (_vmm_context->virq_status == 0) ++ { ++ _vmm_raise_on_pended(); ++ } ++ vmm_irq_restore(level); ++} ++EXPORT_SYMBOL(vmm_restore_virq); ++ ++unsigned long vmm_save_virq_spsr_asm(unsigned long spsr, struct pt_regs *regs) ++{ ++ if (vmm_status) { ++ if (_vmm_context->virq_status) ++ return spsr | PSR_I_BIT; ++ } ++ return spsr; ++} ++ ++void irq_enable_asm(void) ++{ ++ if (vmm_status) { ++ vmm_enable_virq(); ++ } else { ++ asm volatile("cpsie i" : : : "memory", "cc"); ++ } ++} ++ ++void irq_disable_asm(void) ++{ ++ if (vmm_status) { ++ vmm_disable_virq(); ++ } else { ++ asm volatile("cpsid i" : : : "memory", "cc"); ++ } ++} ++ ++/* should be called when the guest entering the state that the IRQ is disabled ++ * by hardware, for example, entering SVC, PABT, DABT mode. ++ * ++ * It will the open the hardware IRQ, virtual IRQ remain unchanged. ++ */ ++void vmm_switch_nohwirq_to_novirq(void) ++{ ++ if (vmm_status) { ++ vmm_disable_virq(); ++ asm volatile("cpsie i" : : : "memory", "cc"); ++ } ++} ++ ++unsigned long vmm_restore_virq_asm(unsigned long spsr) ++{ ++ if (vmm_status) { ++#ifdef VMM_WARN_ON_I_BIT ++ WARN(spsr & PSR_I_BIT, "return to svc mode with I in SPSR set\n"); ++#endif ++ vmm_restore_virq(!!(spsr & PSR_I_BIT)); ++ return spsr & ~PSR_I_BIT; ++ } else { ++ return spsr; ++ } ++} ++ ++void vmm_on_ret_to_usr(unsigned long spsr) ++{ ++ if (vmm_status) { ++#ifdef VMM_WARN_ON_I_BIT ++ WARN(spsr & PSR_I_BIT, "return to user mode with I in SPSR set\n"); ++#endif ++ vmm_enable_virq(); ++ } ++} ++ ++void vmm_on_svc_exit_irq(unsigned long spsr) ++{ ++ if (vmm_status) { ++#ifdef VMM_WARN_ON_I_BIT ++ WARN(spsr & PSR_I_BIT, "exit IRQ with I in SPSR set\n"); ++#endif ++ vmm_enable_virq(); ++ } ++} ++ ++void vmm_dump_irq(void) ++{ ++ int i; ++ unsigned long cpsr; ++ ++ asm volatile ("mrs %0, cpsr": "=r"(cpsr)); ++ ++ printk("status: %08lx, pended: %08lx, cpsr: %08lx\n", ++ _vmm_context->virq_status, _vmm_context->virq_pended, cpsr); ++ printk("pending: "); ++ for (i = 0; i < ARRAY_SIZE(_vmm_context->virq_pending); i++) { ++ printk("%08lx, ", _vmm_context->virq_pending[i]); ++ } ++ printk("\n"); ++} ++ +-- +1.8.4 + diff --git a/components/vmm/linux_patch-v3.8/0002-arm-gic-correct-the-cpu-map-on-gic_raise_softirq-for.patch b/components/vmm/linux_patch-v3.8/0002-arm-gic-correct-the-cpu-map-on-gic_raise_softirq-for.patch new file mode 100644 index 0000000000..555b37f868 --- /dev/null +++ b/components/vmm/linux_patch-v3.8/0002-arm-gic-correct-the-cpu-map-on-gic_raise_softirq-for.patch @@ -0,0 +1,37 @@ +From 848bdea67f5fc201cd05687f207e5f8f42b0990d Mon Sep 17 00:00:00 2001 +From: Grissiom +Date: Thu, 3 Apr 2014 16:51:58 +0800 +Subject: [PATCH 2/2] arm: gic: correct the cpu map on gic_raise_softirq for UP + system + +The CPU mask on UP system is empty, so if we want to raise softirq on UP +system, designate CPU0 to the map. + +Maybe the more correct way is to fix the gic_get_cpumask. + +Signed-off-by: Grissiom +--- + arch/arm/common/gic.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c +index a9d7357..5da382b 100644 +--- a/arch/arm/common/gic.c ++++ b/arch/arm/common/gic.c +@@ -858,6 +858,13 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) + */ + dsb(); + ++ /* ++ * On UP system, realview-pb-a8 for example, the CPU mask is empty. The ++ * softirq are always handled on CPU0. ++ */ ++ if (map == 0) { ++ map = 1; ++ } + /* this always happens on GIC0 */ + writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); + } +-- +1.8.4 + diff --git a/components/vmm/vmm.c b/components/vmm/vmm.c new file mode 100644 index 0000000000..3905d6fbd2 --- /dev/null +++ b/components/vmm/vmm.c @@ -0,0 +1,205 @@ +/* + * VMM startup file. + * + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-06-15 Bernard the first verion + */ + +#include +#include + +#include "board.h" + +#include "vmm.h" +#include "vmm_context.h" + +extern void rt_hw_interrupt_init(void); +extern void rt_application_init(void); + +void vmm_entry(struct vmm_entry_param* param) SECTION(".vmm_init"); + +#ifdef RT_USING_LOGTRACE +#include +static struct log_trace_session _lgs = { + .id = {.name = "vmm"}, + .lvl = LOG_TRACE_LEVEL_VERBOSE, +}; +#endif + +struct rt_thread vmm_thread SECTION(".bss.share.vmm"); +extern rt_uint8_t vmm_stack_start; +extern rt_uint8_t vmm_stack_end; + +void vmm_thread_init(struct rt_thread *thread, const char *name) +{ + extern struct rt_thread *rt_current_thread; + + rt_thread_init(thread, name, RT_NULL, RT_NULL, + &vmm_stack_start, &vmm_stack_end - &vmm_stack_start, + RT_THREAD_PRIORITY_MAX - 1, 10); + + /* set thread to ready status but not switch to */ + rt_thread_startup(thread); + + /* set current thread as vmm thread */ + rt_current_thread = thread; +} + +#ifdef VMM_VERIFY_GUEST +static void _verify_guest(void *p) +{ + while (1) + { + rt_thread_delay(RT_TICK_PER_SECOND/4); + vmm_verify_guest_status(vmm_thread.sp); + } +} + +static void vmm_create_monitor(void) +{ + rt_thread_t tid; + + tid = rt_thread_create("vmon", + _verify_guest, RT_NULL, + 1024, 8, 20); + if (tid) + rt_thread_startup(tid); +} +#endif + +#ifdef RT_VMM_USING_DOMAIN +extern unsigned long guest_domain_val; +extern unsigned long vmm_domain_val; +#endif + +static void vmm_entry_glue(rt_uint32_t level, + unsigned int vmm_domain, + unsigned int kernel_domain) + /* inline would make the section setting meaningless */ + __attribute__((noinline)) + SECTION(".vmm_glue"); +static void vmm_entry_glue(rt_uint32_t level, + unsigned int vmm_domain, + unsigned int kernel_domain) +{ + rt_schedule(); + +#ifdef RT_VMM_USING_DOMAIN + /* protect us from the guest code, but leave the shared region permission + */ + guest_domain_val &= ~(0x3 << (vmm_domain * 2)); + + /* don't touch the guest kernel space */ + vmm_domain_val &= ~(0x3 << (kernel_domain * 2)); +#endif + + rt_hw_interrupt_enable(level); +} + +void vmm_entry(struct vmm_entry_param *param) +{ + rt_uint32_t level; + + level = rt_hw_interrupt_disable(); + + /* set iomap */ + vmm_iomap_init(param->iomap); + + /* set VMM context address */ + vmm_context_init(&RT_VMM_SHARE->ctx); + + /* init hardware interrupt */ + rt_hw_interrupt_init(); + + vmm_vector_init(); + + /* init board */ + rt_hw_board_init(); + +#ifdef RT_USING_LOGTRACE + /* Some parts of VMM use log_trace, so we need to init it right after + * board_init. */ + log_trace_init(); + log_trace_set_device(RT_CONSOLE_DEVICE_NAME); + + log_trace_register_session(&_lgs); +#endif + + /* show version */ + rt_show_version(); + rt_kprintf("share ctx: %p(%x)\n", + &RT_VMM_SHARE->ctx, sizeof(RT_VMM_SHARE->ctx)); + + /* init timer system */ + rt_system_timer_init(); + + { + rt_uint32_t ttbr; + asm volatile ("mrc p15, 0, %0, c2, c0, 0\n" + : "=r"(ttbr)); + rt_kprintf("Linux TTBR: 0x%08x\n", ttbr); + /* + *rt_hw_cpu_dump_page_table((void*)((ttbr & (0xffffc000)) + * - 0x80000000 + 0xC0000000)); + */ + /*rt_hw_cpu_dump_page_table((void*)(0xc0004000));*/ + } + +#ifdef RT_VMM_USING_DOMAIN + vmm_context_init_domain(param->domain); +#endif + + rt_kprintf("heap: 0x%p - 0x%p, %dKi bytes\n", + (void*)HEAP_BEGIN, (void*)HEAP_END, + ((int)HEAP_END - (int)HEAP_BEGIN) / 1024); + /* init heap memory system */ + rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END); + + /* init scheduler system */ + rt_system_scheduler_init(); + + rt_kprintf("user application init.\n"); + /* init application */ + rt_application_init(); + +#ifdef VMM_VERIFY_GUEST + vmm_create_monitor(); +#endif + + rt_system_timer_thread_init(); + + vmm_thread_init(&vmm_thread, "vmm"); + +#ifdef RT_VMM_USING_DOMAIN + rt_kprintf("domain protect present\n"); +#endif + /* start scheduler */ + rt_kprintf("do the first scheduling...\n"); + + vmm_entry_glue(level, + param->domain->vmm, + param->domain->kernel); +} + diff --git a/components/vmm/vmm.h b/components/vmm/vmm.h new file mode 100644 index 0000000000..a9582e1a90 --- /dev/null +++ b/components/vmm/vmm.h @@ -0,0 +1,65 @@ +/* + * VMM startup file. + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-06-15 Bernard the first verion + */ + +#ifndef __VMM_H__ +#define __VMM_H__ + +#ifndef __ASSEMBLY__ +#include // for size_t +#endif + +#define VMM_VERIFY_GUEST + +#include + +#ifndef __ASSEMBLY__ + +void vmm_iomap_init(struct vmm_iomap *iomap); +unsigned long vmm_find_iomap(const char *name); +unsigned long vmm_find_iomap_by_pa(unsigned long pa); + +void vmm_vector_init(void); + +#ifndef RT_USING_LOGTRACE +/* If the rshell is run, we could not rt_kprintf in some situation because + * write to a vbus channel *Would BLOCK*. So we cannot use it in interrupt + * context, we cannot use it within the context of idle(vmm). */ +#define vmm_debug(fmt, ...) +#define vmm_verbose(fmt, ...) +#define vmm_info(fmt, ...) +#else // have RT_USING_LOGTRACE +#define vmm_debug(fmt, ...) log_trace(LOG_TRACE_DEBUG "[vmm]"fmt, ##__VA_ARGS__) +#define vmm_verbose(fmt, ...) log_trace(LOG_TRACE_VERBOSE"[vmm]"fmt, ##__VA_ARGS__) +#define vmm_info(fmt, ...) log_trace(LOG_TRACE_INFO "[vmm]"fmt, ##__VA_ARGS__) +#endif // RT_USING_LOGTRACE +#endif + +#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0])) + +#endif diff --git a/components/vmm/vmm_context.c b/components/vmm/vmm_context.c new file mode 100644 index 0000000000..c39644901c --- /dev/null +++ b/components/vmm/vmm_context.c @@ -0,0 +1,334 @@ +/* + * guest context on VMM + * + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-11-04 Grissiom add comment + */ + +#include +#include +#include + +#include +#include + +#include "vmm_context.h" + +struct rt_vmm_share_layout rt_vmm_share SECTION(".vmm.share"); + +volatile struct vmm_context *_vmm_context = RT_NULL; + +void vmm_context_init(void *context_addr) +{ + _vmm_context = (struct vmm_context *)context_addr; + rt_memset((void *)_vmm_context, 0x00, sizeof(struct vmm_context)); + /* When loading RT-Thread, the IRQ on the guest should be disabled. */ + _vmm_context->virq_status = 1; +} + +#ifdef RT_VMM_USING_DOMAIN +unsigned long guest_domain_val SECTION(".bss.share"); +unsigned long vmm_domain_val SECTION(".bss.share"); +/* some RT-Thread code need to be called in the guest + * context(rt_thread_idle_excute for example). To simplify the code, we need a + * "super" domain mode to have access of both side. The code executed in super + * domain mode is restricted and should be harmless. */ +unsigned long super_domain_val SECTION(".bss.share"); +void vmm_context_init_domain(struct vmm_domain *domain) +{ + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (guest_domain_val)); + + rt_kprintf("Linux domain: kernel: %d, user: %d, io: %d\n" + "VMM domain: vmm: %d, share: %d\n", + domain->kernel, domain->user, domain->io, + domain->vmm, domain->vmm_share); + + if (domain->kernel == domain->vmm || + domain->io == domain->vmm) + { + rt_kprintf("VMM and the guest share the same domain\n"); + super_domain_val = vmm_domain_val = guest_domain_val; + return; + } + + vmm_domain_val = guest_domain_val; + + /* become client to our own territory */ + vmm_domain_val |= (1 << (domain->vmm * 2)) | (1 << (domain->vmm_share * 2)); + + super_domain_val = vmm_domain_val; + /* super domain has access to both side */ + super_domain_val |= (1 << (domain->kernel * 2)) | (1 << (domain->user * 2)); + + rt_kprintf("Original DAC: 0x%08x\n", guest_domain_val); +} + +unsigned long vmm_context_enter_domain(unsigned long domain_val) +{ + unsigned long old_domain; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); + + return old_domain; +} + +void vmm_context_restore_domain(unsigned long domain_val) +{ + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); +} +#endif + +void vmm_virq_pending(int irq) +{ + /* when running this piece of code, the guest is already suspended. So it's + * safe to set the bits without locks. */ + _vmm_context->virq_pending[irq / 32] |= (1 << (irq % 32)); + _vmm_context->virq_pended = 1; + /* mask this IRQ in host */ + rt_hw_interrupt_mask(irq); +} + +void vmm_virq_update(void) +{ + if ((!_vmm_context->virq_status) && + ( _vmm_context->virq_pended)) + { + rt_hw_interrupt_trigger(RT_VMM_VIRQ_TRIGGER); + } +} + +/** check the guest IRQ status + * + * @return 0 on guest should handle IRQ, -1 on should restore the guest context + * normally. + */ +int vmm_virq_check(void) +{ + if ((!_vmm_context->virq_status) && + ( _vmm_context->virq_pended)) + { + return 0; + } + + return -1; +} + +/* 10 = len("%08x, ") */ +static char _vmbuf[10*ARRAY_SIZE(_vmm_context->virq_pending)]; +void vmm_dump_virq(void) +{ + int i, s; + + vmm_info("---- virtual IRQ ----\n"); + vmm_info(" status: %08x, pended: %08x, pending:\n", + _vmm_context->virq_status, _vmm_context->virq_pended); + for (s = 0, i = 0; i < ARRAY_SIZE(_vmm_context->virq_pending); i++) + { + s += rt_snprintf(_vmbuf+s, sizeof(_vmbuf)-s, + "%08x, ", _vmm_context->virq_pending[i]); + } + vmm_info("%.*s\n", sizeof(_vmbuf), _vmbuf); + vmm_info("---- virtual IRQ ----\n"); +} + +int vmm_virq_coherence_ok(void) +{ + int i, res; + int should_pend = 0; + + for (i = 0; i < ARRAY_SIZE(_vmm_context->virq_pending); i++) + { + should_pend |= _vmm_context->virq_pending[i]; + } + + res = (_vmm_context->virq_pended == !!should_pend); + + if (!res) + { + vmm_info("--- %x %x, %x\n", + _vmm_context->virq_pended, should_pend, !!should_pend); + } + + return res; +} + +extern struct rt_thread vmm_thread; + +void vmm_show_guest_reg(void) +{ + struct rt_hw_stack *sp = vmm_thread.sp; +#ifdef RT_VMM_USING_DOMAIN + unsigned long old_domain; + + old_domain = vmm_context_enter_domain(super_domain_val); +#endif + + vmm_info("CPSR: %08x, PC: %08x, LR: %08x, SP: %08x\n", + sp->cpsr, sp->pc, sp->lr, sp+1); + +#ifdef RT_VMM_USING_DOMAIN + vmm_context_restore_domain(old_domain); +#endif +} + +void vmm_dump_domain(void) +{ + unsigned long dac; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (dac)); + vmm_info("current DAC: %08x\n", dac); +#ifdef RT_VMM_USING_DOMAIN + vmm_info("guest DAC: %08x, RTT DAC: %08x, super DAC: %08x\n", + guest_domain_val, vmm_domain_val, super_domain_val); +#endif +} + +void vmm_show_guest(void) +{ + vmm_show_guest_reg(); + vmm_dump_virq(); + vmm_dump_domain(); +} + +#ifdef RT_USING_FINSH +#include +FINSH_FUNCTION_EXPORT_ALIAS(vmm_show_guest, vmm, show vmm status); +#endif + +static int _bad_cpsr(unsigned long cpsr) +{ + int bad = 1; + + switch (cpsr & MODEMASK) + { + case USERMODE: + case FIQMODE: + case IRQMODE: + case SVCMODE: +#ifdef CPU_HAS_MONITOR_MODE + case MONITORMODE: +#endif + case ABORTMODE: +#ifdef CPU_HAS_HYP_MODE + case HYPMODE: +#endif + case UNDEFMODE: + case MODEMASK: + bad = 0; + break; + }; + return bad; +} + +void vmm_verify_guest_status(struct rt_hw_stack *sp) +{ + int dump_vmm = 0; + unsigned long cpsr; +#ifdef RT_VMM_USING_DOMAIN + unsigned long old_domain; + + old_domain = vmm_context_enter_domain(super_domain_val); +#endif + + cpsr = sp->cpsr; + if (_bad_cpsr(cpsr)) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: bad CPSR in guest\n"); + dump_vmm = 1; + } + else + { + if (cpsr & A_Bit && 0) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: A bit is set in guest\n"); + dump_vmm = 1; + } + if ((cpsr & I_Bit) && (sp->pc <= VMM_BEGIN)) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: IRQ disabled in guest\n"); + dump_vmm = 1; + } + if (cpsr & F_Bit) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: FIQ disabled in guest\n"); + dump_vmm = 1; + } + if ((cpsr & MODEMASK) == USERMODE) + { + if (_vmm_context->virq_status & 1) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: VIRQ disabled in user mode\n"); + dump_vmm = 1; + } + if ((sp->pc > 0xbf000000) && (sp->pc < 0xffff0000)) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: executing kernel code in usr mode\n"); + dump_vmm = 1; + } + /* FIXME: when the guest is suspended in user mode and its + * interrupts come, this can be misleading. */ +#if 0 + if (_vmm_context->virq_pended) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: VIRQ pended in user mode\n"); + dump_vmm = 1; + } +#endif + } + else if ((cpsr & MODEMASK) == SVCMODE && sp->pc < 0xbf000000) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: executing usr code in svc mode\n"); + dump_vmm = 1; + } + } + +#if 0 + if (!vmm_virq_coherence_ok()) + { + vmm_info("=================================\n"); + vmm_info("VMM WARING: bad VIRQ status\n"); + dump_vmm = 1; + } +#endif + + if (dump_vmm) + { + vmm_show_guest(); + vmm_info("=================================\n"); + } + +#ifdef RT_VMM_USING_DOMAIN + vmm_context_restore_domain(old_domain); +#endif +} + diff --git a/components/vmm/vmm_context.h b/components/vmm/vmm_context.h new file mode 100644 index 0000000000..07abea3c73 --- /dev/null +++ b/components/vmm/vmm_context.h @@ -0,0 +1,17 @@ +#ifndef __VMM_CONTEXT_H__ +#define __VMM_CONTEXT_H__ + +#include // for struct rt_hw_stack + +#include "vmm.h" + +void vmm_context_init(void *context_addr); +#ifdef RT_VMM_USING_DOMAIN +void vmm_context_init_domain(struct vmm_domain *domain); +#endif +void vmm_virq_pending(int irq); +void vmm_verify_guest_status(struct rt_hw_stack *sp); + +void vmm_show_guest(void); +#endif + diff --git a/components/vmm/vmm_iomap.c b/components/vmm/vmm_iomap.c new file mode 100644 index 0000000000..ec292ae616 --- /dev/null +++ b/components/vmm/vmm_iomap.c @@ -0,0 +1,65 @@ +/* + * VMM IO map table + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-06-15 Bernard the first verion + */ +#include +#include "vmm.h" + +static struct vmm_iomap _vmm_iomap[RT_VMM_IOMAP_MAXNR]; + +void vmm_iomap_init(struct vmm_iomap *iomap) +{ + rt_memcpy(_vmm_iomap, iomap, sizeof(_vmm_iomap)); +} + +/* find virtual address according to name */ +unsigned long vmm_find_iomap(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(_vmm_iomap); i++) + { + if (rt_strcmp(_vmm_iomap[i].name, name) == 0) + return (unsigned long)_vmm_iomap[i].va; + } + + return 0; +} + +/* find virtual address according to physcal address */ +unsigned long vmm_find_iomap_by_pa(unsigned long pa) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(_vmm_iomap); i++) + { + if (_vmm_iomap[i].pa == pa) + return (unsigned long)_vmm_iomap[i].va; + } + + return 0; +} diff --git a/components/vmm/vmm_vector.c b/components/vmm/vmm_vector.c new file mode 100644 index 0000000000..41cc39d282 --- /dev/null +++ b/components/vmm/vmm_vector.c @@ -0,0 +1,47 @@ +/* + * VMM vector handle + * + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-06-15 Bernard the first verion + */ +#include +#include +#include +#include "vmm.h" + +void vmm_guest_isr(int irqno, void* parameter) +{ + /* nothing, let GuestOS to handle it */ + rt_hw_interrupt_clear(irqno); +} + +void vmm_vector_init(void) +{ + rt_hw_interrupt_install(RT_VMM_VIRQ_TRIGGER, vmm_guest_isr, RT_NULL, "virq"); + rt_hw_interrupt_umask(RT_VMM_VIRQ_TRIGGER); + + return; +} + diff --git a/libcpu/arm/realview-a8-vmm/SConscript b/libcpu/arm/realview-a8-vmm/SConscript new file mode 100644 index 0000000000..61057c04cc --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/SConscript @@ -0,0 +1,17 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +if rtconfig.PLATFORM == 'iar': + src += Glob('*_iar.S') +elif rtconfig.PLATFORM == 'gcc': + src += Glob('*_gcc.S') +elif rtconfig.PLATFORM == 'armcc': + src += Glob('*_rvds.S') + +group = DefineGroup('AM335x', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/libcpu/arm/realview-a8-vmm/armv7.h b/libcpu/arm/realview-a8-vmm/armv7.h new file mode 100644 index 0000000000..69c556eb3c --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/armv7.h @@ -0,0 +1,64 @@ +#ifndef __ARMV7_H__ +#define __ARMV7_H__ + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; +}; + +struct rt_hw_stack +{ + unsigned long cpsr; + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long lr; + unsigned long pc; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define MONITORMODE 0x16 +#define ABORTMODE 0x17 +#define HYPMODE 0x1b +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define T_Bit (1<<5) +#define F_Bit (1<<6) +#define I_Bit (1<<7) +#define A_Bit (1<<8) +#define E_Bit (1<<9) +#define J_Bit (1<<24) + +#endif diff --git a/libcpu/arm/realview-a8-vmm/context_gcc.S b/libcpu/arm/realview-a8-vmm/context_gcc.S new file mode 100644 index 0000000000..9bb31e3f10 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/context_gcc.S @@ -0,0 +1,175 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +#include + +#ifdef RT_USING_VMM +#include +#endif + +.section .text, "ax" +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + cpsid i + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + bx lr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + bic r4, r4, #0x20 @ must be ARM mode + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +.section .bss.share.isr +_guest_switch_lvl: + .word 0 + +.globl vmm_virq_update + +.section .text.isr, "ax" +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + +#ifdef RT_USING_VMM +#ifdef RT_VMM_USING_DOMAIN + @ need to make sure we are in vmm domain as we would use rt_current_thread + ldr r2, =vmm_domain_val + ldr r7, [r2] + mcr p15, 0, r7, c3, c0 +#endif + + /* check whether vmm thread, otherwise, update vIRQ */ + ldr r3, =rt_current_thread + ldr r4, [r3] + ldr r5, =vmm_thread + cmp r4, r5 + beq switch_to_guest + + @ not falling into guest. Simple task ;-) + ldmfd sp!, {r6} @ pop new task cpsr to spsr + msr spsr_cxsf, r6 + ldmfd sp!, {r0-r12, lr, pc}^ + +switch_to_guest: +#ifdef RT_VMM_USING_DOMAIN + @ the stack is saved in the guest domain so we need to + @ come back to the guest domain to get the registers. + ldr r1, =super_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif + /* The user can do nearly anything in rt_thread_idle_excute because it will + call the thread->cleanup. One common thing is sending events and wake up + threads. So the guest thread will be preempted. This is the only point that + the guest thread would call rt_hw_context_switch and "yield". + + More over, rt_schedule will call this function and this function *will* + reentrant. If that happens, we need to make sure that call the + rt_thread_idle_excute and vmm_virq_update again and we are in super domain. + I use a "reference count" to achieve such behaviour. If you have better + idea, tell me. */ + ldr r4, =_guest_switch_lvl + ldr r5, [r4] + add r5, r5, #1 + str r5, [r4] + cmp r5, #1 + bne _switch_through + + bl rt_thread_idle_excute + bl vmm_virq_update + + /* we need _guest_switch_lvl to protect until _switch_through, but it's OK + * to cleanup the reference count here because the code below will not be + * reentrant. */ + sub r5, r5, #1 + str r5, [r4] + +#ifdef RT_VMM_USING_DOMAIN + ldr r1, =guest_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif +_switch_through: +#endif /* RT_USING_VMM */ + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1 + str r0, [ip] + str r3, [r2] +_reswitch: + ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread + str r1, [r2] + bx lr diff --git a/libcpu/arm/realview-a8-vmm/cp15.h b/libcpu/arm/realview-a8-vmm/cp15.h new file mode 100644 index 0000000000..ebea3f0fe3 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/cp15.h @@ -0,0 +1,12 @@ +#ifndef __CP15_H__ +#define __CP15_H__ + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_vector_set_base(unsigned int addr); + +#endif diff --git a/libcpu/arm/realview-a8-vmm/cp15_gcc.S b/libcpu/arm/realview-a8-vmm/cp15_gcc.S new file mode 100644 index 0000000000..f1ed6492aa --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/cp15_gcc.S @@ -0,0 +1,140 @@ +/* + * File : cp15_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.globl rt_cpu_get_smp_id +rt_cpu_get_smp_id: + mrc p15, #0, r0, c0, c0, #5 + bx lr + +.globl rt_cpu_vector_set_base +rt_cpu_vector_set_base: + mcr p15, #0, r0, c12, c0, #0 + dsb + bx lr + +.globl rt_hw_cpu_dcache_enable +rt_hw_cpu_dcache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_hw_cpu_icache_enable +rt_hw_cpu_icache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +_FLD_MAX_WAY: + .word 0x3ff +_FLD_MAX_IDX: + .word 0x7ff + +.globl rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + push {r4-r11} + dmb + mrc p15, #1, r0, c0, c0, #1 @ read clid register + ands r3, r0, #0x7000000 @ get level of coherency + mov r3, r3, lsr #23 + beq finished + mov r10, #0 +loop1: + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + cmp r1, #2 + blt skip + mcr p15, #2, r10, c0, c0, #0 + isb + mrc p15, #1, r1, c0, c0, #0 + and r2, r1, #7 + add r2, r2, #4 + ldr r4, _FLD_MAX_WAY + ands r4, r4, r1, lsr #3 + clz r5, r4 + ldr r7, _FLD_MAX_IDX + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 +loop3: + orr r11, r10, r9, lsl r5 + orr r11, r11, r7, lsl r2 + mcr p15, #0, r11, c7, c14, #2 + subs r9, r9, #1 + bge loop3 + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + cmp r3, r10 + bgt loop1 + +finished: + dsb + isb + pop {r4-r11} + bx lr + +.globl rt_hw_cpu_dcache_disable +rt_hw_cpu_dcache_disable: + push {r4-r11, lr} + bl rt_cpu_dcache_clean_flush + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + pop {r4-r11, lr} + bx lr + +.globl rt_hw_cpu_icache_disable +rt_hw_cpu_icache_disable: + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_mmu_disable +rt_cpu_mmu_disable: + mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit + dsb + bx lr + +.globl rt_cpu_mmu_enable +rt_cpu_mmu_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x001 + mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit + dsb + bx lr + +.globl rt_cpu_tlb_set +rt_cpu_tlb_set: + mcr p15, #0, r0, c2, c0, #0 + dmb + bx lr diff --git a/libcpu/arm/realview-a8-vmm/cpu.c b/libcpu/arm/realview-a8-vmm/cpu.c new file mode 100644 index 0000000000..7dd426e4dd --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/cpu.c @@ -0,0 +1,37 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + */ + +#include +#include +#include + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** shutdown CPU */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/libcpu/arm/realview-a8-vmm/gic.c b/libcpu/arm/realview-a8-vmm/gic.c new file mode 100644 index 0000000000..db26fc5dcf --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/gic.c @@ -0,0 +1,313 @@ +/* + * File : gic.c, ARM Generic Interrupt Controller + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + * 2014-04-03 Grissiom many enhancements + */ + +#include +#include + +#include "gic.h" +#include "cp15.h" + +struct arm_gic +{ + rt_uint32_t offset; + + rt_uint32_t dist_hw_base; + rt_uint32_t cpu_hw_base; +}; +static struct arm_gic _gic_table[ARM_GIC_MAX_NR]; + +#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00) +#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04) +#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08) +#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0c) +#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10) +#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14) +#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18) + +#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000) +#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004) +#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080 + ((n)/32) * 4) +#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100 + ((n)/32) * 4) +#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180 + ((n)/32) * 4) +#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200 + ((n)/32) * 4) +#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280 + ((n)/32) * 4) +#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300 + ((n)/32) * 4) +#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380 + ((n)/32) * 4) +#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400 + ((n)/4) * 4) +#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800 + ((n)/4) * 4) +#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00 + ((n)/16) * 4) +#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00) +#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10 + ((n)/4) * 4) +#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8) + +static unsigned int _gic_max_irq; + +int arm_gic_get_active_irq(rt_uint32_t index) +{ + int irq; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base); + irq += _gic_table[index].offset; + return irq; +} + +void arm_gic_ack(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; + GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq; + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_mask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_clear_pending(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_clear_active(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask) +{ + rt_uint32_t old_tgt; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq); + + old_tgt &= ~(0x0FFUL << ((irq % 4)*8)); + old_tgt |= cpumask << ((irq % 4)*8); + + GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt; +} + +void arm_gic_umask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_dump_type(rt_uint32_t index) +{ + unsigned int gic_type; + + gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base); + rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n", + (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf, + _gic_table[index].dist_hw_base, + _gic_max_irq, + gic_type & (1 << 10) ? "has" : "no", + gic_type); +} + +void arm_gic_dump(rt_uint32_t index) +{ + unsigned int i, k; + + k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base); + rt_kprintf("--- high pending priority: %d(%08x)\n", k, k); + rt_kprintf("--- hw mask ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n--- hw pending ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n--- hw active ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n"); +} +#ifdef RT_USING_FINSH +#include +FINSH_FUNCTION_EXPORT_ALIAS(arm_gic_dump, gic, show gic status); +#endif + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start) +{ + unsigned int gic_type, i; + rt_uint32_t cpumask = 1 << 0; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].dist_hw_base = dist_base; + _gic_table[index].offset = irq_start; + + /* Find out how many interrupts are supported. */ + gic_type = GIC_DIST_TYPE(dist_base); + _gic_max_irq = ((gic_type & 0x1f) + 1) * 32; + + /* + * The GIC only supports up to 1020 interrupt sources. + * Limit this to either the architected maximum, or the + * platform maximum. + */ + if (_gic_max_irq > 1020) + _gic_max_irq = 1020; + if (_gic_max_irq > ARM_GIC_NR_IRQS) + _gic_max_irq = ARM_GIC_NR_IRQS; + +#ifndef RT_PRETENT_AS_CPU0 + /* If we are run on the second core, the GIC should have already been setup + * by BootStrapProcessor. */ + if ((rt_cpu_get_smp_id() & 0xF) != 0) + return 0; +#endif +#ifdef RT_USING_VMM + return 0; +#endif + + cpumask |= cpumask << 8; + cpumask |= cpumask << 16; + + GIC_DIST_CTRL(dist_base) = 0x0; + + /* Set all global interrupts to be level triggered, active low. */ + for (i = 32; i < _gic_max_irq; i += 16) + GIC_DIST_CONFIG(dist_base, i) = 0x0; + + /* Set all global interrupts to this CPU only. */ + for (i = 32; i < _gic_max_irq; i += 4) + GIC_DIST_TARGET(dist_base, i) = cpumask; + + /* Set priority on all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 4) + GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0; + + /* Disable all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff; + /* All interrupts defaults to IGROUP1(IRQ). */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_IGROUP(dist_base, i) = 0xffffffff; + + return 0; +} + +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].cpu_hw_base = cpu_base; + +#ifndef RT_PRETENT_AS_CPU0 + /* If we are run on the second core, the GIC should have already been setup + * by BootStrapProcessor. */ + if ((rt_cpu_get_smp_id() & 0xF) != 0) + return 0; +#endif +#ifdef RT_USING_VMM + return 0; +#endif + + GIC_CPU_PRIMASK(cpu_base) = 0xf0; + /* Enable CPU interrupt */ + GIC_CPU_CTRL(cpu_base) = 0x01; + + return 0; +} + +void arm_gic_set_group(rt_uint32_t index, int vector, int group) +{ + /* As for GICv2, there are only group0 and group1. */ + RT_ASSERT(group <= 1); + RT_ASSERT(vector < _gic_max_irq); + + if (group == 0) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) &= ~(1 << (vector % 32)); + } + else if (group == 1) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) |= (1 << (vector % 32)); + } +} + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq) +{ + unsigned int reg; + + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + reg = (target_cpu << 16) | irq; + GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = reg; +} + +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq) +{ + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = target_cpu << (irq % 4); +} diff --git a/libcpu/arm/realview-a8-vmm/gic.h b/libcpu/arm/realview-a8-vmm/gic.h new file mode 100644 index 0000000000..41a7727da2 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/gic.h @@ -0,0 +1,35 @@ +/* + * File : gic.h, ARM Generic Interrupt Controller + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + */ + +#ifndef __GIC_H__ +#define __GIC_H__ + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start); +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base); + +void arm_gic_mask(rt_uint32_t index, int irq); +void arm_gic_umask(rt_uint32_t index, int irq); +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask); +void arm_gic_set_group(rt_uint32_t index, int vector, int group); + +int arm_gic_get_active_irq(rt_uint32_t index); +void arm_gic_ack(rt_uint32_t index, int irq); + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq); +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq); + +void arm_gic_dump_type(rt_uint32_t index); + +#endif + diff --git a/libcpu/arm/realview-a8-vmm/interrupt.c b/libcpu/arm/realview-a8-vmm/interrupt.c new file mode 100644 index 0000000000..ffb6c10a89 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/interrupt.c @@ -0,0 +1,144 @@ +/* + * File : interrupt.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-06 Bernard first version + * 2014-04-03 Grissiom port to VMM + */ + +#include +#include +#include "realview.h" +#include "gic.h" + +#ifdef RT_USING_VMM +#include +#endif + +#define MAX_HANDLERS NR_IRQS_PBA8 + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; + +/* Those varibles will be accessed in ISR, so we need to share them. */ +rt_uint32_t rt_interrupt_from_thread SECTION(".bss.share.int"); +rt_uint32_t rt_interrupt_to_thread SECTION(".bss.share.int"); +rt_uint32_t rt_thread_switch_interrupt_flag SECTION(".bss.share.int"); + +const unsigned int VECTOR_BASE = 0x00; +extern void rt_cpu_vector_set_base(unsigned int addr); +extern int system_vectors; + +static void rt_hw_vector_init(void) +{ +#ifndef RT_USING_VMM + unsigned int *dest = (unsigned int *)VECTOR_BASE; + unsigned int *src = (unsigned int *)&system_vectors; + + rt_memcpy(dest, src, 16 * 4); + rt_cpu_vector_set_base(VECTOR_BASE); +#endif +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_uint32_t gic_cpu_base; + rt_uint32_t gic_dist_base; + + /* initialize vector table */ + rt_hw_vector_init(); + + /* initialize exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + + /* initialize ARM GIC */ +#ifdef RT_USING_VMM + gic_dist_base = vmm_find_iomap("GIC_DIST"); + gic_cpu_base = vmm_find_iomap("GIC_CPU"); +#else + gic_dist_base = REALVIEW_GIC_DIST_BASE; + gic_cpu_base = REALVIEW_GIC_CPU_BASE; +#endif + arm_gic_dist_init(0, gic_dist_base, 0); + arm_gic_cpu_init(0, gic_cpu_base); + /*arm_gic_dump_type(0);*/ + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + arm_gic_mask(0, vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + arm_gic_umask(0, vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +/** + * Trigger a software IRQ + * + * Since we are running in single core, the target CPU are always CPU0. + */ +void rt_hw_interrupt_trigger(int vector) +{ + arm_gic_trigger(0, 1, vector); +} + +void rt_hw_interrupt_clear(int vector) +{ + arm_gic_clear_sgi(0, 1, vector); +} diff --git a/libcpu/arm/realview-a8-vmm/interrupt.h b/libcpu/arm/realview-a8-vmm/interrupt.h new file mode 100644 index 0000000000..d81f1c81ae --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/interrupt.h @@ -0,0 +1,50 @@ +/* + * File : interrupt.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-06 Bernard first version + */ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +#define INTC_REVISION(hw_base) REG32((hw_base) + 0x0) +#define INTC_SYSCONFIG(hw_base) REG32((hw_base) + 0x10) +#define INTC_SYSSTATUS(hw_base) REG32((hw_base) + 0x14) +#define INTC_SIR_IRQ(hw_base) REG32((hw_base) + 0x40) +#define INTC_SIR_FIQ(hw_base) REG32((hw_base) + 0x44) +#define INTC_CONTROL(hw_base) REG32((hw_base) + 0x48) +#define INTC_PROTECTION(hw_base) REG32((hw_base) + 0x4c) +#define INTC_IDLE(hw_base) REG32((hw_base) + 0x50) +#define INTC_IRQ_PRIORITY(hw_base) REG32((hw_base) + 0x60) +#define INTC_FIQ_PRIORITY(hw_base) REG32((hw_base) + 0x64) +#define INTC_THRESHOLD(hw_base) REG32((hw_base) + 0x68) +#define INTC_SICR(hw_base) REG32((hw_base) + 0x6c) +#define INTC_SCR(hw_base, n) REG32((hw_base) + 0x70 + ((n) * 0x04)) +#define INTC_ITR(hw_base, n) REG32((hw_base) + 0x80 + ((n) * 0x20)) +#define INTC_MIR(hw_base, n) REG32((hw_base) + 0x84 + ((n) * 0x20)) +#define INTC_MIR_CLEAR(hw_base, n) REG32((hw_base) + 0x88 + ((n) * 0x20)) +#define INTC_MIR_SET(hw_base, n) REG32((hw_base) + 0x8c + ((n) * 0x20)) +#define INTC_ISR_SET(hw_base, n) REG32((hw_base) + 0x90 + ((n) * 0x20)) +#define INTC_ISR_CLEAR(hw_base, n) REG32((hw_base) + 0x94 + ((n) * 0x20)) +#define INTC_PENDING_IRQ(hw_base, n) REG32((hw_base) + 0x98 + ((n) * 0x20)) +#define INTC_PENDING_FIQ(hw_base, n) REG32((hw_base) + 0x9c + ((n) * 0x20)) +#define INTC_ILR(hw_base, n) REG32((hw_base) + 0x100 + ((n) * 0x04)) + +void rt_hw_interrupt_control(int vector, int priority, int route); +int rt_hw_interrupt_get_active(int fiq_irq); +void rt_hw_interrupt_ack(int fiq_irq); +void rt_hw_interrupt_trigger(int vector); +void rt_hw_interrupt_clear(int vector); + +#endif diff --git a/libcpu/arm/realview-a8-vmm/mmu.c b/libcpu/arm/realview-a8-vmm/mmu.c new file mode 100644 index 0000000000..b2503e4260 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/mmu.c @@ -0,0 +1,207 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-01-10 bernard porting to AM1808 + */ + +#include +#include +#include + +#include "cp15.h" + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO +#define XN (1<<4) // eXecute Never + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +/* Read/Write, cache, write back */ +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +/* Read/Write, cache, write through */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +/* Read/Write without cache and write buffer */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +/* Read/Write without cache and write buffer, no execute */ +#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN) +/* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +/* dump 2nd level page table */ +void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + for (i = 0; i < 256; i++) + { + rt_uint32_t pte2 = ptb[i]; + if ((pte2 & 0x3) == 0) + { + if (fcnt == 0) + rt_kprintf(" "); + rt_kprintf("%04x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf(" %04x: %x: ", i, pte2); + if ((pte2 & 0x3) == 0x1) + { + rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, + (pte2 >> 15) & 0x1, + ((pte2 >> 10) | (pte2 >> 2)) & 0x1f); + } + else + { + rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1, + ((pte2 >> 4) | (pte2 >> 2)) & 0x1f); + } + } +} + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* level1 page table, each entry for 1MB memory. */ +volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024))); +void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, + rt_uint32_t vaddrEnd, + rt_uint32_t paddrStart, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +unsigned long rt_hw_set_domain_register(unsigned long domain_val) +{ + unsigned long old_domain; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); + + return old_domain; +} + +void rt_hw_mmu_init(void) +{ + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /* set page table */ + /* 4G 1:1 memory */ + rt_hw_mmu_setmtt(0, 0xffffffff-1, 0, RW_CB); + /* IO memory region */ + rt_hw_mmu_setmtt(0x44000000, 0x80000000-1, 0x44000000, RW_NCNBXN); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} + diff --git a/libcpu/arm/realview-a8-vmm/pmu.c b/libcpu/arm/realview-a8-vmm/pmu.c new file mode 100644 index 0000000000..07911a2db7 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/pmu.c @@ -0,0 +1,12 @@ +#include +#include "pmu.h" + +void rt_hw_pmu_dump_feature(void) +{ + unsigned long reg; + + reg = rt_hw_pmu_get_control(); + rt_kprintf("ARM PMU Implementor: %c, ID code: %02x, %d counters\n", + reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f); + RT_ASSERT(ARM_PMU_CNTER_NR == ((reg >> 11) & 0x1f)); +} diff --git a/libcpu/arm/realview-a8-vmm/pmu.h b/libcpu/arm/realview-a8-vmm/pmu.h new file mode 100644 index 0000000000..05c1420dd8 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/pmu.h @@ -0,0 +1,151 @@ +#ifndef __PMU_H__ +#define __PMU_H__ + +#include "board.h" + +/* Number of counters */ +#define ARM_PMU_CNTER_NR 4 + +enum rt_hw_pmu_event_type { + ARM_PMU_EVENT_PMNC_SW_INCR = 0x00, + ARM_PMU_EVENT_L1_ICACHE_REFILL = 0x01, + ARM_PMU_EVENT_ITLB_REFILL = 0x02, + ARM_PMU_EVENT_L1_DCACHE_REFILL = 0x03, + ARM_PMU_EVENT_L1_DCACHE_ACCESS = 0x04, + ARM_PMU_EVENT_DTLB_REFILL = 0x05, + ARM_PMU_EVENT_MEM_READ = 0x06, + ARM_PMU_EVENT_MEM_WRITE = 0x07, + ARM_PMU_EVENT_INSTR_EXECUTED = 0x08, + ARM_PMU_EVENT_EXC_TAKEN = 0x09, + ARM_PMU_EVENT_EXC_EXECUTED = 0x0A, + ARM_PMU_EVENT_CID_WRITE = 0x0B, +}; + +/* Enable bit */ +#define ARM_PMU_PMCR_E (0x01 << 0) +/* Event counter reset */ +#define ARM_PMU_PMCR_P (0x01 << 1) +/* Cycle counter reset */ +#define ARM_PMU_PMCR_C (0x01 << 2) +/* Cycle counter divider */ +#define ARM_PMU_PMCR_D (0x01 << 3) + +#ifdef __GNUC__ +rt_inline void rt_hw_pmu_enable_cnt(int divide64) +{ + unsigned long pmcr; + unsigned long pmcntenset; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_E | ARM_PMU_PMCR_P | ARM_PMU_PMCR_C; + if (divide64) + pmcr |= ARM_PMU_PMCR_D; + else + pmcr &= ~ARM_PMU_PMCR_D; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + + /* enable all the counters */ + pmcntenset = ~0; + asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(pmcntenset)); + /* clear overflows(just in case) */ + asm volatile ("mcr p15, 0, %0, c9, c12, 3" :: "r"(pmcntenset)); +} + +rt_inline unsigned long rt_hw_pmu_get_control(void) +{ + unsigned long pmcr; + asm ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + return pmcr; +} + +rt_inline unsigned long rt_hw_pmu_get_ceid(void) +{ + unsigned long reg; + /* only PMCEID0 is supported, PMCEID1 is RAZ. */ + asm ("mrc p15, 0, %0, c9, c12, 6" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_cnten(void) +{ + unsigned long pmcnt; + asm ("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcnt)); + return pmcnt; +} + +rt_inline void rt_hw_pmu_reset_cycle(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_C; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_reset_event(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_P; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline unsigned long rt_hw_pmu_get_cycle(void) +{ + unsigned long cyc; + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cyc)); + return cyc; +} + +rt_inline void rt_hw_pmu_select_counter(int idx) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + asm volatile ("mcr p15, 0, %0, c9, c12, 5" : : "r"(idx)); + /* Linux add an isb here, don't know why here. */ + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_select_event(int idx, + enum rt_hw_pmu_event_type eve) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + rt_hw_pmu_select_counter(idx); + asm volatile ("mcr p15, 0, %0, c9, c13, 1" : : "r"(eve)); +} + +rt_inline unsigned long rt_hw_pmu_read_counter(int idx) +{ + unsigned long reg; + + rt_hw_pmu_select_counter(idx); + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 2" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_ovsr(void) +{ + unsigned long reg; + asm volatile ("isb"); + asm ("mrc p15, 0, %0, c9, c12, 3" : "=r"(reg)); + return reg; +} + +rt_inline void rt_hw_pmu_clear_ovsr(unsigned long reg) +{ + asm ("mcr p15, 0, %0, c9, c12, 3" : : "r"(reg)); + asm volatile ("isb"); +} + +#endif + +void rt_hw_pmu_dump_feature(void); + +#endif /* end of include guard: __PMU_H__ */ + diff --git a/libcpu/arm/realview-a8-vmm/stack.c b/libcpu/arm/realview-a8-vmm/stack.c new file mode 100644 index 0000000000..4ae1536a20 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/stack.c @@ -0,0 +1,65 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + */ +#include +#include + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stk = (rt_uint32_t*)stack_addr; + *(stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0; /* r12 */ + *(--stk) = 0; /* r11 */ + *(--stk) = 0; /* r10 */ + *(--stk) = 0; /* r9 */ + *(--stk) = 0; /* r8 */ + *(--stk) = 0; /* r7 */ + *(--stk) = 0; /* r6 */ + *(--stk) = 0; /* r5 */ + *(--stk) = 0; /* r4 */ + *(--stk) = 0; /* r3 */ + *(--stk) = 0; /* r2 */ + *(--stk) = 0; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/libcpu/arm/realview-a8-vmm/start_gcc.S b/libcpu/arm/realview-a8-vmm/start_gcc.S new file mode 100644 index 0000000000..98f22ca1fe --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/start_gcc.S @@ -0,0 +1,366 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +#include + +#ifdef RT_USING_VMM +#include +.equ orig_irq_isr, LINUX_VECTOR_POS+0x18 +#else +#undef RT_VMM_USING_DOMAIN +#endif + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +#ifndef RT_USING_VMM +.equ UND_Stack_Size, 0x00000000 +.equ SVC_Stack_Size, 0x00000100 +.equ ABT_Stack_Size, 0x00000000 +.equ RT_FIQ_STACK_PGSZ, 0x00000000 +.equ RT_IRQ_STACK_PGSZ, 0x00000100 +.equ USR_Stack_Size, 0x00000100 + +#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) +#else +#define ISR_Stack_Size (RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) +#endif + +.section .data.share.isr +/* stack */ +.globl stack_start +.globl stack_top + +stack_start: +.rept ISR_Stack_Size +.byte 0 +.endr +stack_top: + +.text +/* reset entry */ +.globl _reset +_reset: +#ifdef RT_USING_VMM + /* save all the parameter and variable registers */ + stmfd sp!, {r0-r12, lr} +#endif + /* set the cpu to SVC32 mode and disable interrupt */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0x13 + msr cpsr_c, r0 + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + +#ifdef RT_USING_VMM + /* clear .bss.share */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_share_start /* bss start */ + ldr r2,=__bss_share_end /* bss end */ + +bss_share_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_share_loop /* loop until done */ +#endif + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ +#ifdef RT_USING_VMM + /* restore the parameter */ + ldmfd sp!, {r0-r3} + bl vmm_entry + ldmfd sp!, {r4-r12, pc} +#else + ldr pc, _rtthread_startup +_rtthread_startup: + .word rtthread_startup +#endif + +stack_setup: + ldr r0, =stack_top +#ifdef RT_USING_VMM + @ Linux use stmia to save r0, lr and spsr. To align to 8 byte boundary, + @ just allocate 16 bytes for it. + sub r0, r0, #16 +#endif + +#ifndef RT_USING_VMM + @ Set the startup stack for svc + mov sp, r0 +#endif + +#ifndef RT_USING_VMM + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size +#endif + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_FIQ_STACK_PGSZ + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_IRQ_STACK_PGSZ + + /* come back to SVC mode */ + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + bx lr + +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ +.section .text.isr, "ax" + .align 5 +.globl vector_fiq +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc, lr, #4 + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + +.globl rt_current_thread +.globl vmm_thread +.globl vmm_virq_check + + .align 5 +.globl vector_irq +vector_irq: + stmfd sp!, {r0-r12,lr} + +#ifdef RT_VMM_USING_DOMAIN + @ save the last domain + mrc p15, 0, r5, c3, c0 + @ switch to vmm domain as we are going to call vmm codes + ldr r1, =vmm_domain_val + ldr r4, [r1] + mcr p15, 0, r4, c3, c0 +#endif + + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + +#ifdef RT_VMM_USING_DOMAIN + @ restore the last domain. It do some redundant work but simplify the + @ logic. It might be the guest domain so rt_thread_switch_interrupt_flag + @ should lay in .bss.share + mcr p15, 0, r5, c3, c0 +#endif + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + +#ifndef RT_USING_VMM + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 +#else +#ifdef RT_VMM_USING_DOMAIN + @ r4 is vmm_domain_val + @ back to vmm domain as we need access rt_current_thread + mcr p15, 0, r4, c3, c0 +#endif + /* check whether we need to do IRQ routing + * ensure the int is disabled. Or there will be an infinite loop. */ + ldr r0, =rt_current_thread + ldr r0, [r0] + ldr r1, =vmm_thread + cmp r0, r1 + beq switch_to_guest + +#ifdef RT_VMM_USING_DOMAIN + @ r5 is domain of interrupted context + @ it might be super_domain_val or vmm_domain_val so we need to restore it. + mcr p15, 0, r5, c3, c0 +#endif + @ switch back if the interrupted thread is not vmm + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +switch_to_guest: +#ifdef RT_VMM_USING_DOMAIN + @ We are going to execute rt-thread code but accessing the content of the + @ guest. So switch to super domain. + ldr r1, =super_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif + /* check whether there is a pending interrupt for Guest OS */ + bl vmm_virq_check + +#ifdef RT_VMM_USING_DOMAIN + @ All done, restore the guest domain. + mcr p15, 0, r5, c3, c0 +#endif + + cmp r0, #0x0 + beq route_irq_to_guest + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +route_irq_to_guest: + ldmfd sp!, {r0-r12,lr} + b orig_irq_isr +#endif /* RT_USING_VMM */ + +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + mov r1, sp @ r1 point to {r0-r3} in stack + add sp, sp, #4*4 + ldmfd sp!, {r4-r12,lr}@ reload saved registers + mrs r0, spsr @ get cpsr of interrupt thread + sub r2, lr, #4 @ save old task's pc to r2 + + @ Switch to SVC mode with no interrupt. If the usr mode guest is + @ interrupted, this will just switch to the stack of kernel space. + @ save the registers in kernel space won't trigger data abort. + msr cpsr_c, #I_Bit|F_Bit|Mode_SVC + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4 + ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread + stmfd sp!, {r1-r4} @ push old task's r0-r3 + stmfd sp!, {r0} @ push old task's cpsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + +#ifdef RT_VMM_USING_DOMAIN + @ If a thread is wake up by interrupt, it should be RTT thread. + @ Make sure the domain is correct. + ldr r1, =vmm_domain_val + ldr r2, [r1] + mcr p15, 0, r2, c3, c0 +#endif + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr + +.macro push_svc_reg + sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr @/* Save CPSR */ + str lr, [r0, #15*4] @/* Push PC */ + str r6, [r0, #16*4] @/* Push CPSR */ + cps #Mode_SVC + str sp, [r0, #13*4] @/* Save calling SP */ + str lr, [r0, #14*4] @/* Save calling PC */ +.endm + + .align 5 + .globl vector_swi +vector_swi: + push_svc_reg + bl rt_hw_trap_swi + b . + + .align 5 + .globl vector_undef +vector_undef: + push_svc_reg + bl rt_hw_trap_undef + b . + + .align 5 + .globl vector_pabt +vector_pabt: + push_svc_reg + bl rt_hw_trap_pabt + b . + + .align 5 + .globl vector_dabt +vector_dabt: + push_svc_reg + bl rt_hw_trap_dabt + b . + + .align 5 + .globl vector_resv +vector_resv: + push_svc_reg + bl rt_hw_trap_resv + b . diff --git a/libcpu/arm/realview-a8-vmm/trap.c b/libcpu/arm/realview-a8-vmm/trap.c new file mode 100644 index 0000000000..a6397d20d2 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/trap.c @@ -0,0 +1,204 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + */ + +#include +#include +#include + +#include "armv7.h" + +#ifdef RT_USING_VMM +#include +#endif + +#include "gic.h" + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("undefined instruction:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("software interrupt:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("prefetch abort:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("data abort:"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("reserved trap:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +#define GIC_ACK_INTID_MASK 0x000003ff + +void rt_hw_trap_irq(void) +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + if (ir == 1023) + { + /* Spurious interrupt */ + return; + } + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; +#ifdef RT_USING_INTERRUPT_INFO + isr_table[ir].counter++; +#endif + if (isr_func) + { + /* Interrupt for myself. */ + param = isr_table[ir].param; + /* turn to interrupt service routine */ + isr_func(ir, param); + } +#ifdef RT_USING_VMM + else + { + /* We have to EOI before masking the interrupts */ + arm_gic_ack(0, fullir); + vmm_virq_pending(ir); + return; + } +#endif + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + +void rt_hw_trap_fiq(void) +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + param = isr_table[ir].param; + + /* turn to interrupt service routine */ + isr_func(ir, param); + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + diff --git a/libcpu/arm/realview-a8-vmm/vector_gcc.S b/libcpu/arm/realview-a8-vmm/vector_gcc.S new file mode 100644 index 0000000000..8d0ca27fee --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/vector_gcc.S @@ -0,0 +1,66 @@ +/* + * File : vector_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ +#include + +.section .vectors, "ax" +.code 32 + +.globl system_vectors +system_vectors: + ldr pc, _vector_reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +.globl _reset +.globl vector_undef +.globl vector_swi +.globl vector_pabt +.globl vector_dabt +.globl vector_resv +.globl vector_irq +.globl vector_fiq + +_vector_reset: + .word _reset +_vector_undef: + .word vector_undef +_vector_swi: + .word vector_swi +_vector_pabt: + .word vector_pabt +_vector_dabt: + .word vector_dabt +_vector_resv: + .word vector_resv +_vector_irq: + .word vector_irq +_vector_fiq: + .word vector_fiq + +.balignl 16,0xdeadbeef