diff --git a/so3/Makefile b/so3/Makefile index b5254eb804..41b92c194f 100644 --- a/so3/Makefile +++ b/so3/Makefile @@ -302,13 +302,9 @@ OBJDUMP = $(CROSS_COMPILE)objdump gccincdir := $(shell $(CC) -print-file-name=include) -SO3INCLUDE := -I.include -I. \ - $(if $(KBUILD_SRC), -I./include) \ - -include include/generated/autoconf.h - KBUILD_CPPFLAGS := -D__KERNEL__ -D__SO3__ -KBUILD_CPPFLAGS += -I$(saved-output)include -I$(srctree)/include -I$(srctree)/include/net +KBUILD_CPPFLAGS += -I$(saved-output)include -I$(srctree)/include -I$(srctree)/include/net -I$(srctree)/avz/include KBUILD_CPPFLAGS += -fno-builtin -ffreestanding -nostdinc -isystem $(gccincdir) KBUILD_CFLAGS := -g -O0 -fno-common -Wall -Wstrict-prototypes $(KBUILD_CPPFLAGS) @@ -343,7 +339,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL UTS_MACHINE export CPP AR NM STRIP OBJCOPY OBJDUMP export TARGET -export KBUILD_CPPFLAGS NOSTDINC_FLAGS SO3INCLUDE OBJCOPYFLAGS LDFLAGS +export KBUILD_CPPFLAGS NOSTDINC_FLAGS OBJCOPYFLAGS LDFLAGS export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL export KBUILD_ARFLAGS @@ -375,6 +371,8 @@ all: $(BIN) dtbs objs-y := arch/$(SRCARCH) kernel mm fs ipc devices apps net +objs-$(CONFIG_AVZ) += avz + ifeq ($(CONFIG_AVZ),) objs-$(CONFIG_SOO) += soo @@ -407,6 +405,7 @@ KBUILD_CFLAGS_KERNEL += -I$(srctree)/arch/$(SRCARCH)/include/ -I$(srctree)/arch/ KBUILD_AFLAGS_KERNEL += -I$(srctree)/arch/$(SRCARCH)/include/ -I$(srctree)/arch/$(SRCARCH)/$(TARGET)/include/ ifdef CONFIG_SOO +KBUILD_CPPFLAGS += -Isoo/include KBUILD_CFLAGS_KERNEL += -Isoo/include KBUILD_AFLAGS_KERNEL += -Isoo/include endif diff --git a/so3/apps/Kconfig b/so3/apps/Kconfig index c2ac8fe255..7b7744ebc2 100644 --- a/so3/apps/Kconfig +++ b/so3/apps/Kconfig @@ -4,4 +4,7 @@ menu "SO3 Applications" config APP_SAMPLE bool "Sample application with thread environment" + config APP_REFSO3 + bool "Simple example of a SO3 container" + endmenu diff --git a/so3/apps/Makefile b/so3/apps/Makefile index 1de2615b27..d519c4f7c1 100644 --- a/so3/apps/Makefile +++ b/so3/apps/Makefile @@ -1,3 +1,5 @@ +obj-$(CONFIG_APP_REFSO3) += refso3/ + obj-$(CONFIG_APP_SAMPLE) += sample.o diff --git a/so3/soo/me/refso3/Makefile b/so3/apps/refso3/Makefile similarity index 100% rename from so3/soo/me/refso3/Makefile rename to so3/apps/refso3/Makefile diff --git a/so3/soo/me/refso3/callbacks.c b/so3/apps/refso3/callbacks.c similarity index 52% rename from so3/soo/me/refso3/callbacks.c rename to so3/apps/refso3/callbacks.c index 26043564b9..97a661412b 100644 --- a/so3/soo/me/refso3/callbacks.c +++ b/so3/apps/refso3/callbacks.c @@ -40,47 +40,7 @@ static LIST_HEAD(known_soo_list); /* Reference to the shared content helpful during synergy with other MEs */ sh_refso3_t *sh_refso3; - -/** - * PRE-ACTIVATE - * - * Should receive local information through args - */ -void cb_pre_activate(soo_domcall_arg_t *args) { - - DBG(">> ME %d: cb_pre_activate...\n", ME_domID()); - -#if 0 /* To be implemented... */ - logmsg("[soo:me:SOO.refSO3] ME %d: cb_pre_activate..\n", ME_domID()); -#endif - -} - -/** - * PRE-PROPAGATE - * - * The callback is executed in first stage to give a chance to a resident ME to stay or disappear, for example. - */ -void cb_pre_propagate(soo_domcall_arg_t *args) { - - pre_propagate_args_t *pre_propagate_args = (pre_propagate_args_t *) &args->u.pre_propagate_args; - - DBG(">> ME %d: cb_pre_propagate...\n", ME_domID()); - - pre_propagate_args->propagate_status = PROPAGATE_STATUS_YES; -} - -/** - * Kill domcall - if another ME tries to kill us. - */ -void cb_kill_me(soo_domcall_arg_t *args) { - - DBG(">> ME %d: cb_kill_me...\n", ME_domID()); - - /* Do we accept to be killed? yes... */ - set_ME_state(ME_state_killed); -} - + /** * PRE_SUSPEND * @@ -90,60 +50,7 @@ void cb_kill_me(soo_domcall_arg_t *args) { void cb_pre_suspend(soo_domcall_arg_t *args) { DBG(">> ME %d: cb_pre_suspend...\n", ME_domID()); } - -/** - * COOPERATE - * - * This callback is executed when an arriving ME (initiator) decides to cooperate with a residing ME (target). - */ -void cb_cooperate(soo_domcall_arg_t *args) { - cooperate_args_t *cooperate_args = (cooperate_args_t *) &args->u.cooperate_args; - agency_ctl_args_t agency_ctl_args; - - lprintk("[soo:me:SOO.refSO3] ME %d: cb_cooperate...\n", ME_domID()); - - switch (cooperate_args->role) { - case COOPERATE_INITIATOR: - - if (cooperate_args->alone) - return ; - - /* Collaboration ... */ - - /* Update the list of hosts */ - sh_refso3->me_common.soohost_nr = concat_hosts(&visits, (uint8_t *) sh_refso3->me_common.soohosts); - - agency_ctl_args.u.cooperate_args.pfn = phys_to_pfn(virt_to_phys_pt((addr_t) sh_refso3)); - agency_ctl_args.u.cooperate_args.slotID = ME_domID(); /* Will be copied in initiator_cooperate_args */ - - /* This pattern enables the cooperation with the target ME */ - - agency_ctl_args.cmd = AG_COOPERATE; - agency_ctl_args.slotID = cooperate_args->u.target_coop.slotID; - - /* Perform the cooperate in the target ME */ - args->__agency_ctl(&agency_ctl_args); -#if 0 - set_ME_state(ME_state_killed); -#endif - break; - - case COOPERATE_TARGET: - DBG("Cooperate: Target %d\n", ME_domID()); -#if 1 - /* Destroy us */ - set_ME_state(ME_state_terminated); -#endif - - break; - - default: - lprintk("Cooperate: Bad role %d\n", cooperate_args->role); - BUG(); - } - -} - + /** * PRE_RESUME * @@ -193,9 +100,6 @@ void callbacks_init(void) { /* Initialize the shared content page used to exchange information between other MEs */ memset(sh_refso3, 0, PAGE_SIZE); - /* Set the SPAD capabilities (currently not used) */ - memset(&get_ME_desc()->spad, 0, sizeof(spad_t)); - } diff --git a/so3/soo/me/refso3/refso3.c b/so3/apps/refso3/refso3.c similarity index 92% rename from so3/soo/me/refso3/refso3.c rename to so3/apps/refso3/refso3.c index 3e54ea400d..7d7ef6e518 100644 --- a/so3/soo/me/refso3/refso3.c +++ b/so3/apps/refso3/refso3.c @@ -36,8 +36,6 @@ #include #include #include -#include -#include #include #include @@ -54,10 +52,7 @@ * */ void *app_thread_main(void *args) { - - /* The ME can cooperate with the others. */ - spad_enable_cooperate(); - + sh_refso3->cur_letter = 'A'; while (1) { diff --git a/so3/arch/arm32/domain.c b/so3/arch/arm32/domain.c deleted file mode 100644 index 0cc78816eb..0000000000 --- a/so3/arch/arm32/domain.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2014-2021 Daniel Rossier - * Copyright (C) 2016-2019 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include - -#include - -#include -#include -#include - -void arch_setup_domain_frame(struct domain *d, struct cpu_regs *domain_frame, addr_t fdt_addr, addr_t start_stack, addr_t start_pc) { - - domain_frame->r2 = fdt_addr; - domain_frame->ip = (unsigned long) d->avz_shared; - - domain_frame->sp = start_stack; - domain_frame->pc = start_pc; - - domain_frame->psr = 0x93; /* IRQs disabled initially */ - - d->cpu_regs.sp = (unsigned long) domain_frame; - d->cpu_regs.lr = (unsigned long) pre_ret_to_user; -} - -/* - * Setup of domain consists in setting up the 1st-level and 2nd-level page tables within the domain. - */ -void __setup_dom_pgtable(struct domain *d, addr_t v_start, unsigned long map_size, addr_t p_start) { - u32 *new_pt; - addr_t vaddr; - - ASSERT(d); - - /* Make sure that the size is 1 MB-aligned */ - map_size = ALIGN_UP(map_size, TTB_SECT_SIZE); - - printk("*** Setup page tables of the domain: ***\n"); - printk(" v_start : 0x%lx\n", v_start); - printk(" map size (bytes) : 0x%lx\n", map_size); - printk(" phys address : 0x%lx\n", p_start); - - /* Initial L0 page table for the domain for AArch32 */ - new_pt = (u32 *) __lva(p_start + TTB_L1_SYS_OFFSET); - - d->avz_shared->pagetable_vaddr = (addr_t) new_pt; - d->avz_shared->pagetable_paddr = p_start + TTB_L1_SYS_OFFSET; - - /* copy page table of idle domain to guest domain */ - memcpy(new_pt, __sys_root_pgtable, TTB_L1_SIZE); - - /* Clear the area below hypervisor */ - for (vaddr = 0; vaddr < CONFIG_KERNEL_VADDR; vaddr += TTB_SECT_SIZE) - *((uint32_t *) l1pte_offset(new_pt, vaddr)) = 0; - - /* Do the mapping of new domain at its virtual address location */ - create_mapping(new_pt, v_start, p_start, map_size, false); -} - -void arch_domain_create(struct domain *d, int cpu_id) { - - if (is_idle_domain(d)) - d->avz_shared->pagetable_paddr = __pa(__sys_root_pgtable); -} - diff --git a/so3/arch/arm32/exception.S b/so3/arch/arm32/exception.S index dfaf521333..02d03537b6 100644 --- a/so3/arch/arm32/exception.S +++ b/so3/arch/arm32/exception.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2019 Daniel Rossier + * Copyright (C) 2014-2025 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,15 +32,6 @@ #include -#ifdef CONFIG_AVZ - -#include - -.global pseudo_usr_mode -.global hypervisor_stack - -#endif - #include .global ret_from_fork @@ -69,10 +60,10 @@ .macro MEM t, a, l stmfd sp!, {r0-r12, lr} - mov r0, #\t + mov r0, #\t mov r1, \a - mov r2, #\l - bl __mem + mov r2, #\l + bl __mem ldmfd sp!, {r0-r12, lr} .endm @@ -80,52 +71,28 @@ str \b, .LClog stmfd sp!, {r0-r12, lr} - mov r0, #\a - ldr r1, .LClog - bl __log + mov r0, #\a + ldr r1, .LClog + bl __log ldmfd sp!, {r0-r12, lr} .endm #endif /* 0 */ -/* - * The following macros helps to manage the stack pointer when - * avz issues a syscall. The first handling is made in avz - * and the return address is saved under the stack frame - */ - -.macro SET_REAL_STACK_FRAME - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - @ The real stack frame base in the interrupt context - add sp, sp, #8 -#endif - -.endm - -.macro SET_AVZ_STACK_FRAME - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - @ To preserve the return address in avz - sub sp, sp, #8 -#endif - -.endm - /* use the special section (.vectors.text), to enable fine-tuning * of the placement of this section inside the linker script */ .section ".vectors.text", "ax" ENTRY(__vectors) - b __start @ reset - ldr pc, _undefined_instruction - ldr pc, _syscall_interrupt - ldr pc, _prefetch_abort - ldr pc, _data_abort - ldr pc, _not_used - ldr pc, _irq - ldr pc, _fiq + b __start @ reset + ldr pc, _undefined_instruction + ldr pc, _syscall_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq _undefined_instruction: .word undefined_instruction _syscall_interrupt: .word syscall_interrupt @@ -140,7 +107,7 @@ _pad: .word 0x12345678 @ now 16*4=64 .align 5 undefined_instruction: - b __undefined_instruction + b __undefined_instruction @ Prepare to call a handler associated to a pending signal @ r0 contains the reference to the sigaction_t structure related to the signal to be processed. @@ -148,74 +115,52 @@ undefined_instruction: __prepare_sig_handler: @ Alignment guard - tst sp, #0x7 @ 8-bytes aligned - bne __stack_alignment_fault + tst sp, #0x7 @ 8-bytes aligned + bne __stack_alignment_fault - str sp, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_SP)] @ save sp + str sp, [sp, #(-SVC_STACK_FRAME_SIZE + OFFSET_SP)] @ save sp @ Build a new stack frame based on the current - sub sp, sp, #SVC_STACK_FRAME_SIZE + sub sp, sp, #SVC_STACK_FRAME_SIZE @ Make sure the spsr is with Thumb de-activated to perform normal execution of the handler - mov r1, #PSR_USR_MODE @ Ensure the handler will run in user mode (situation where + mov r1, #PSR_USR_MODE @ Ensure the handler will run in user mode (situation where @ the current frame inherits from code running in SVC). - str r1, [sp, #OFFSET_PSR] @ Save the updated SPSR + str r1, [sp, #OFFSET_PSR] @ Save the updated SPSR @ Set the argument (signum, handler) to r0 & r1 - ldr r1, [r0, #OFFSET_SYS_SIGNUM] - str r1, [sp, #OFFSET_R0] + ldr r1, [r0, #OFFSET_SYS_SIGNUM] + str r1, [sp, #OFFSET_R0] ldr r0, [r0, #OFFSET_SYS_SA] - ldr r1, [r0, #OFFSET_SA_HANDLER] - str r1, [sp, #OFFSET_R1] + ldr r1, [r0, #OFFSET_SA_HANDLER] + str r1, [sp, #OFFSET_R1] - ldr r1, [r0, #OFFSET_SA_RESTORER] - str r1, [sp, #OFFSET_PC] @ Set the handler to the PC + ldr r1, [r0, #OFFSET_SA_RESTORER] + str r1, [sp, #OFFSET_PC] @ Set the handler to the PC /* Set the current sp_usr to have a valid stack in the user space */ ldr r0, .LCcurrent - ldr r0, [r0] + ldr r0, [r0] ldr r0, [r0, #(OFFSET_TCB_CPU_REGS + OFFSET_SP_USR)] - str r0, [sp, #OFFSET_SP_USR] - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) + str r0, [sp, #OFFSET_SP_USR] - @ We shortcut the return to avz for this kind of processing. - @ The signal handler can be called directly from here. - @ It will return back to the kernel via the sigreturn() syscall. - - ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer - msr spsr, lr - - @ Restoring user mode registers (sp_usr, lr_usr) - add lr, sp, #OFFSET_SP_USR - ldmia lr, {sp, lr}^ - - ldmia sp, {r0-r12} - add sp, sp, #OFFSET_SP - - dsb - isb - - ldmia sp, {sp, lr, pc}^ - -#else - mov pc, lr @ Back to the caller -#endif + mov pc, lr @ Back to the caller .macro check_pending_signal @ Is there any pending signals for this process? - bl sig_check + @ The return value will be the __sigaction_t pointeur or 0 (NULL) if no signal pending + bl sig_check - cmp r0, #0 - beq 1f + cmp r0, #0 + beq 1f @ Configure a stack frame to manage the user handler - bl __prepare_sig_handler + bl __prepare_sig_handler 1: .endm @@ -224,71 +169,54 @@ __prepare_sig_handler: @ ARM EABI: the syscall nr is stored in r7 .align 5 syscall_interrupt: - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - - @ Preserve the return address of avz - str lr, [sp, #-8] - - @ Temporary, we let sp unchanged even if we pushed the return address - @ since sp will be manipulated by the "standard" handler below. - -#else - + @ At the exception entry, the stack must be 8-byte aligned. @ If it is not the case (gcc might not respect the AAPCS convention for optimization purposes), @ sp will be adjusted. The original sp is preserved and will be correctly restored at the exit. - tst sp, #0x7 @ 8-bytes aligned + tst sp, #0x7 @ 8-bytes aligned strne sp, [sp, #(OFFSET_SP-SVC_STACK_FRAME_SIZE - 4)] @ save sp subne sp, sp, #4 streq sp, [sp, #(OFFSET_SP-SVC_STACK_FRAME_SIZE)] @ save sp @ Alignment guard - tst sp, #0x7 @ 8-bytes aligned - bne __stack_alignment_fault + tst sp, #0x7 @ 8-bytes aligned + bne __stack_alignment_fault @ Build the stack frame to store registers - sub sp, sp, #SVC_STACK_FRAME_SIZE + sub sp, sp, #SVC_STACK_FRAME_SIZE - str lr, [sp, #OFFSET_LR] @ save lr in lr - str lr, [sp, #OFFSET_PC] @ save lr in pc + str lr, [sp, #OFFSET_LR] @ save lr in lr + str lr, [sp, #OFFSET_PC] @ save lr in pc stmia sp, {r0-r12} @ Store registers - mrs lr, spsr @ Get spsr - str lr, [sp, #OFFSET_PSR] @ Store spsr + mrs lr, spsr @ Get spsr + str lr, [sp, #OFFSET_PSR] @ Store spsr @ Saving user mode registers (sp_usr, lr_usr) - add lr, sp, #OFFSET_SP_USR + add lr, sp, #OFFSET_SP_USR stmia lr, {sp, lr}^ -#endif - -#ifdef CONFIG_AVZ - ldr lr, =ME_VOFFSET + L_TEXT_OFFSET - add lr, lr, #0x8 @ SWI interrupt - - blx lr - -#else /* !CONFIG_AVZ */ - - ldr r0, [sp, #OFFSET_SP_USR] + cmp r7, #SYSCALL_SIGRETURN + beq __after_push_sp_usr + + ldr r0, [sp, #OFFSET_SP_USR] ldr r1, .LCcurrent ldr r1, [r1] str r0, [r1, #(OFFSET_TCB_CPU_REGS + OFFSET_SP_USR)] +__after_push_sp_usr: + @ Restore r0-r2 ldmia sp, {r0-r2} - SET_AVZ_STACK_FRAME - #ifdef CONFIG_MMU @ Give a chance to a ptrace tracer to monitor us (before the syscall) stmfd sp!, {r0-r4} - bl __check_ptrace_syscall + bl __check_ptrace_syscall ldmfd sp!, {r0-r4} #endif @@ -300,13 +228,11 @@ syscall_interrupt: @ Check if sigreturn has been called. In this case, we @ clean the stack frame which has been used to manage the user handler. - cmp r7, #SYSCALL_SIGRETURN - bne __no_sigreturn - - SET_REAL_STACK_FRAME + cmp r7, #SYSCALL_SIGRETURN + bne __no_sigreturn @ Reset the stack frame by removing the one issued from sigreturn - add sp, sp, #SVC_STACK_FRAME_SIZE + add sp, sp, #SVC_STACK_FRAME_SIZE __no_sigreturn: @@ -319,77 +245,39 @@ __no_sigreturn: __ret_from_fork: - SET_REAL_STACK_FRAME - @ Store the return value on the stack frame - cmp r7, #SYSCALL_SIGRETURN + cmp r7, #SYSCALL_SIGRETURN strne r0, [sp, #OFFSET_R0] - SET_AVZ_STACK_FRAME - #ifdef CONFIG_IPC_SIGNAL @ Is there any pending signals for this process? check_pending_signal #endif /* CONFIG_IPC_SIGNAL */ -#endif /* !CONFIG_AVZ */ - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - - ldr lr, [sp], #8 - mov pc, lr - -#else - @ get the saved spsr and adjust the stack pointer - ldr lr, [sp, #OFFSET_PSR] - msr spsr, lr + ldr lr, [sp, #OFFSET_PSR] + msr spsr, lr @ Restoring user mode registers (sp_usr, lr_usr) - add lr, sp, #OFFSET_SP_USR + add lr, sp, #OFFSET_SP_USR ldmia lr, {sp, lr}^ ldmia sp, {r0-r12} - add sp, sp, #OFFSET_SP + add sp, sp, #OFFSET_SP dsb isb ldmia sp, {sp, lr, pc}^ -#endif + @ Used at entry point of a fork'd process (setting the return value to 0) ret_from_fork: - mov r0, #0 - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - - str r0, [sp, #OFFSET_R0] - - ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer - msr spsr, lr - - @ Restoring user mode registers (sp_usr, lr_usr) - add lr, sp, #OFFSET_SP_USR - ldmia lr, {sp, lr}^ - - ldmia sp, {r0-r12} - add sp, sp, #OFFSET_SP - - dsb - isb - - ldmia sp, {sp, lr, pc}^ - -#else - -#ifndef CONFIG_AVZ - b __ret_from_fork -#endif - -#endif + mov r0, #0 + b __ret_from_fork + .align 5 prefetch_abort: @@ -398,9 +286,9 @@ prefetch_abort: mrc p15, 0, r0, c6, c0, 2 @ get IFAR mrc p15, 0, r1, c5, c0, 1 @ get IFSR - mov r2, lr + mov r2, lr - b __prefetch_abort + b __prefetch_abort .align 5 data_abort: @@ -410,122 +298,79 @@ data_abort: mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR - mov r2, lr + mov r2, lr - b __data_abort + b __data_abort .align 5 not_used: - b not_used + b not_used .align 5 irq: - @ IRQ mode (lr_irq, sp_irq, cpsr_irq) + @ IRQ mode (lr_irq, sp_irq, cpsr_irq) - @ Store original r0, and lr_irq in the IRQ stack sp = sp_irq - @ sp_irq is a simple array declared in arch/arm/setup.c (so address can be ascending) + @ Store original r0, and lr_irq in the IRQ stack sp = sp_irq + @ sp_irq is a simple array declared in arch/arm/setup.c (so address can be ascending) - str r0, [sp] @ original r0 - str lr, [sp, #4] @ lr_irq + str r0, [sp] @ original r0 + str lr, [sp, #4] @ lr_irq - mrs r0, spsr @ to preserve irq bit - str r0, [sp, #8] @ spsr_irq + mrs r0, spsr @ to preserve irq bit + str r0, [sp, #8] @ spsr_irq - mov r0, sp @ to maintain a reference on sp_irq; r0 will not be affected after mode switch + mov r0, sp @ to maintain a reference on sp_irq; r0 will not be affected after mode switch - @ Now switch back to SVC. IRQs are disabled - mrs lr, cpsr + @ Now switch back to SVC. IRQs are disabled + mrs lr, cpsr - bic lr, lr, #PSR_MODE_MASK - orr lr, lr, #PSR_SVC_MODE + bic lr, lr, #PSR_MODE_MASK + orr lr, lr, #PSR_SVC_MODE - @ switch to SVC - msr cpsr, lr + @ switch to SVC + msr cpsr, lr - @ --- SVC mode from now on --- + @ --- SVC mode from now on --- @ At the exception entry, the stack must be 8-byte aligned. @ If it is not the case (gcc might not respect the AAPCS convention for optimization purposes), @ sp will be adjusted. The original sp is preserved and will be correctly restored at the exit. - tst sp, #0x7 @ 8-bytes aligned + tst sp, #0x7 @ 8-bytes aligned strne sp, [sp, #(OFFSET_SP-SVC_STACK_FRAME_SIZE - 4)] @ save sp subne sp, sp, #4 streq sp, [sp, #(OFFSET_SP-SVC_STACK_FRAME_SIZE)] @ save sp @ Alignment guard - tst sp, #0x7 @ 8-bytes aligned - bne __stack_alignment_fault + tst sp, #0x7 @ 8-bytes aligned + bne __stack_alignment_fault - sub sp, sp, #SVC_STACK_FRAME_SIZE + sub sp, sp, #SVC_STACK_FRAME_SIZE @ Store the lr_svc (before the irq) - str lr, [sp, #OFFSET_LR] @ current lr_svc + str lr, [sp, #OFFSET_LR] @ current lr_svc - @ preserve spsr for future IRQ enabling - ldr lr, [r0, #8] @ retrieve spsr_irq - str lr, [sp, #OFFSET_PSR] @ location of spsr_svc (hence cpsr right before the interrupt) + @ preserve spsr for future IRQ enabling + ldr lr, [r0, #8] @ retrieve spsr_irq + str lr, [sp, #OFFSET_PSR] @ location of spsr_svc (hence cpsr right before the interrupt) @ Check if it is necessary to preserve sp_usr and lr_usr - and lr, lr, #PSR_MODE_MASK - cmp lr, #PSR_USR_MODE + and lr, lr, #PSR_MODE_MASK + cmp lr, #PSR_USR_MODE @ Saving user mode registers (sp_usr, lr_usr) addeq lr, sp, #OFFSET_SP_USR stmeqia lr, {sp, lr}^ @ Retrieve the lr_irq to set the pc out of this routine - ldr lr, [r0, #4] @ retrieve lr_irq to set lr_svc - sub lr, lr, #4 @ Adjust the lr since it is automatically set from pc (in advance of 2 instructions due to the pipeline) + ldr lr, [r0, #4] @ retrieve lr_irq to set lr_svc + sub lr, lr, #4 @ Adjust the lr since it is automatically set from pc (in advance of 2 instructions due to the pipeline) str lr, [sp, #OFFSET_PC] @ future pc at exit - ldr r0, [r0] @ original r0 - - stmia sp, {r0-r12} - -#ifdef CONFIG_AVZ - - @ Now process the IRQ differentiating execution according to the source (dom/hyp) - @ for managing the stack correctly - - current_cpu r10 - - ldr r0, .LCpseudo_usr_mode - ldr r1, [r0, r10, lsl #2] - cmp r1, #0 @ svc ? - - beq hyp_path + ldr r0, [r0] @ original r0 - mov r1, #0 @ setting svc - str r1, [r0, r10, lsl #2] - - mov r1, sp - ldr r0, .LChypervisor_stack @ Get the running hypervisor SVC stack - ldr r0, [r0, r10, lsl #2] - - mov sp, r0 - - curdom r0, r2 - str r1, [r0, #OFFSET_G_SP] - - @ Make sure r0 refers to the base of the stack frame - mov r0, sp - - bl irq_handle - - b ret_to_user - -/* Hypervisor path or *idle* domain path */ -hyp_path: - - mov r0, sp - - bl irq_handle - - b out_irq - -#else /* CONFIG_AVZ */ + stmia sp, {r0-r12} @ cpsr is still up-to-date regarding the comparison against CPU mode. ldreq r0, [sp, #OFFSET_SP_USR] @@ -534,21 +379,21 @@ hyp_path: streq r0, [r1, #(OFFSET_TCB_CPU_REGS + OFFSET_SP_USR)] @ Make sure r0 refers to the base of the stack frame - mov r0, sp + mov r0, sp - bl irq_handle + bl irq_handle #ifdef CONFIG_IPC_SIGNAL @ Is there any pending signals for this process? check_pending_signal #endif /* CONFIG_IPC_SIGNAL */ - ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer - msr spsr, lr + ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer + msr spsr, lr @ Check if it is necessary to restore sp_usr and lr_usr - and lr, lr, #PSR_MODE_MASK - cmp lr, #PSR_USR_MODE + and lr, lr, #PSR_MODE_MASK + cmp lr, #PSR_USR_MODE @ Restoring user mode registers (sp_usr, lr_usr) addeq lr, sp, #OFFSET_SP_USR @@ -557,297 +402,13 @@ hyp_path: @ Restore registers ldmia sp, {r0-r12} - add sp, sp, #OFFSET_SP + add sp, sp, #OFFSET_SP dsb isb - @ Now, we retrieve the final registers, sp will be adjusted automatically - ldmia sp, {sp, lr, pc}^ -#endif /* !CONFIG_AVZ */ - -#ifdef CONFIG_SO3VIRT - -.align 5 - - /* - * Hypercall trampoline has the following arguments: - * - r0: hypercall number - * - r1: first arg (-> r0) - * - r2: second arg - * - r3: third arg - * - r4: fourth arg - * - r5: work register - * - r7: hypecall number (ABI) - * - r11: cpsr - */ -ENTRY(hypercall_trampoline) - @ Stack alignment must stay on 8 bytes. - sub sp, sp, #16*4 - stmia sp, {r1-r12, lr} - - mov r7, r0 - mov r0, r1 - mov r1, r2 - mov r2, r3 - mov r3, r4 - mov r4, r5 - - mrs r11, cpsr - - ldr r5, .LChypercall_addr - ldr r5, [r5] - - bl __trampoline - - ldmia sp, {r1-r12, lr} - add sp, sp, #16*4 - - mov pc, lr - -__trampoline: - mov pc, r5 - nop - nop - nop - -.LChypercall_addr: - .long HYPERVISOR_hypercall_addr - -#endif /* CONFIG_SO3VIRT */ - -#if !defined(CONFIG_AVZ) && defined(CONFIG_SOO) - - -@ The cpu_regs_t from avz remains compatible in the range of -@ ARM registers with the SPSR stored after r15. -.align 5 -ENTRY(avz_vector_callback) - - @ r0 is set to cpu_regs_t by avz - bl irq_handle - - ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer - msr spsr, lr - - @ Check if it is necessary to restore sp_usr and lr_usr - and lr, lr, #PSR_MODE_MASK - cmp lr, #PSR_USR_MODE - - @ Restoring user mode registers (sp_usr, lr_usr) - addeq lr, sp, #OFFSET_SP_USR - ldmeqia lr, {sp, lr}^ - - @ Restore registers - ldmia sp, {r0-r12} - - add sp, sp, #OFFSET_SP - - dsb - isb - - @ Now, we retrieve the final registers, sp will be adjusted automatically - ldmia sp, {sp, lr, pc}^ - -#endif - -#ifdef CONFIG_AVZ - -/* - * The following function is used to restore the migrated domain. - * Indeed, the receiver environment has not saved anything on its stack regarding - * a context switch. We can not pursue on right-after-context-switch in the schedule function! - * But we do not start from boot either. So, we have an appropriate restore glue code to perform - * an upcall in the newly migrated ME. A first timer IRQ has been set in domain_migration_restore() to - * avoid a problem in the guest when testing for upcall pending. - * - * - */ -ENTRY(after_migrate_to_user) - - b do_upcall - -.align 5 - -@ This function is called at bootstrap and -@ reboot time. It initializes some registers -ENTRY(pre_ret_to_user) - disable_irq - - curdom r10, r6 - mov r6, #0 - ldr r6, [r10, #OFFSET_AVZ_SHARED] - str r6, [r6, #OFFSET_HYPERVISOR_CALLBACK] - - current_cpu r3 - - @ Prepare to switch to the guest stack in order to prepare - @ its stack frame required along the upcall (restore) path. - - ldr r0, .LChypervisor_stack - str sp, [r0, r3, lsl #2] - - ldr r6, [sp, #OFFSET_PC] @ entry point of the guess / r6 is used because not altered by save_svc_context - ldr r7, [sp, #OFFSET_PSR] @ CPSR flags - ldr r8, [sp, #OFFSET_IP] @ start_info (r12) - ldr r9, [sp, #OFFSET_R2] @ arg (devtree/atags) - - ldr sp, [sp, #OFFSET_SP] @ get the guest stack - sub sp, sp, #S_FRAME_SIZE - - str sp, [r10, #OFFSET_G_SP] - - @ Configure the G-stack frame - - str r6, [sp, #OFFSET_PC] @ put the entry point on the guess stack - str r7, [sp, #OFFSET_PSR] - str r8, [sp, #OFFSET_IP] - str r9, [sp, #OFFSET_R2] - - @ Finally switch back to H-stack - ldr r0, .LChypervisor_stack - ldr sp, [r0, r3, lsl #2] - - @ Restore r3 used by current_cpu above - ldr r3, [sp, #OFFSET_R3] - - b restore - -.align 5 - -ENTRY(ret_to_user) - - disable_irq @ ensure IRQs are disabled - - curdom r10, r11 - ldr r11, [r10, #OFFSET_AVZ_SHARED] - - @ If the softirq handling leads to trigger an interrupt in the guest, - @ it will be processed by do_evtchn_do_upcall. The way how to - @ process an interrupt with potentially IRQs off is under the - @ responsibility of the guest - - @ are some IRQs pending? - ldrb r12, [r11, #OFFSET_EVTCHN_UPCALL_PENDING] - tst r12, #0xff - - beq restore - - /* Fallback to do_upcall */ - -/* - * Process pending events along the upcall path to the domain. - */ -do_upcall: - disable_irq - - current_cpu r11 - - curdom r10, r0 - - ldr r0, [r10, #OFFSET_AVZ_SHARED] - ldr lr, [r0, #OFFSET_HYPERVISOR_CALLBACK] - cmp lr, #0 - beq restore - - ldr r0, .LChypervisor_stack @ running SVC hypervisor stack - str sp, [r0, r11, lsl #2] - - @ get guest stack (already stacked from save_svc_context) - ldr sp, [r10, #OFFSET_G_SP] - - @ setting pseudo_usr_mode / r0, r1 re-assigned right after - ldr r0, .LCpseudo_usr_mode - mov r1, #1 - str r1, [r0, r11, lsl #2] - - @ r0 contains a reference to the stack pointer - mov r0, sp - - mov pc, lr - -restore: - - current_cpu r11 - - @ setting pseudo_usr_mode / r0, r1 re-assigned right after - ldr r0, .LCpseudo_usr_mode - mov r1, #1 - str r1, [r0, r11, lsl #2] - - @ restore saved registers - - ldr r0, .LChypervisor_stack @ running SVC hypervisor stack - str sp, [r0, r11, lsl #2] - - curdom r10, r0 - - @ get guest stack (already stacked from save_svc_context) - ldr sp, [r10, #OFFSET_G_SP] - -out_irq: - - ldr lr, [sp, #OFFSET_PSR] @ get the saved spsr and adjust the stack pointer - msr spsr, lr - - @ Check if it is necessary to restore sp_usr and lr_usr - and lr, lr, #PSR_MODE_MASK - cmp lr, #PSR_USR_MODE - - @ Restoring user mode registers (sp_usr, lr_usr) - addeq lr, sp, #OFFSET_SP_USR - ldmeqia lr, {sp, lr}^ - - @ Restore registers - ldmia sp, {r0-r12} - - add sp, sp, #OFFSET_SP - - dsb - isb - - @ Now, we retrieve the final registers, sp will be adjusted automatically - ldmia sp, {sp, lr, pc}^ - - .ltorg - - -/** Area of memory reserved to manage domain stack and hypervisor stack (G-stack/H-stack) **/ - -.align 5 -pseudo_usr_mode: - .space CONFIG_NR_CPUS * 4 - -@ Hypervisor stack is used for the *current* (running) domain svc stack address -hypervisor_stack: - .space CONFIG_NR_CPUS * 4 - -.LCpseudo_usr_mode: - .word pseudo_usr_mode - -.LChypervisor_stack: - .word hypervisor_stack - -#endif /* CONFIG_AVZ */ - -#if defined(CONFIG_SOO) && !defined(CONFIG_AVZ) - -@ Inject the real syscall vector used by SO3 -@ Modified registers: r0, r1 -ENTRY(inject_syscall_vector) - - ldr r0, =__vectors - ldr r1, [r0, #8] @ Vector location of swi in standard ARM vector table - ldr r2, [r0, #36] @ And the re-direction stored in the same page, at this position (+36), following the vector table. - - ldr r0, =VECTOR_VADDR - - str r1, [r0, #8] - str r2, [r0, #36] - - mov pc, lr - -#endif + @ Now, we retrieve the final registers, sp will be adjusted automatically + ldmia sp, {sp, lr, pc}^ .align 5 fiq: diff --git a/so3/arch/arm32/ptrace.c b/so3/arch/arm32/ptrace.c index 89410bdb1c..8af9aa9fac 100644 --- a/so3/arch/arm32/ptrace.c +++ b/so3/arch/arm32/ptrace.c @@ -20,6 +20,29 @@ #include #include +/* + * Can be used for debugging purposes. + * + */ +void __dump_regs(void *regs) { + unsigned long *cpuregs = (unsigned long *) regs; + + printk("r4: %x ", *cpuregs); + printk("r5: %x ", *(cpuregs+1)); + printk("r6: %x ", *(cpuregs+2)); + printk("r7: %x ", *(cpuregs+3)); + printk("r8: %x ", *(cpuregs+4)); + printk("r9: %x ", *(cpuregs+5)); + printk("r10: %x ", *(cpuregs+6)); + printk("fp: %x ", *(cpuregs+7)); + printk("ip: %x ", *(cpuregs+8)); + printk("sp: %x ", *(cpuregs+9)); + printk("lr: %x ", *(cpuregs+10)); + printk("pc: %x ", *(cpuregs+11)); + printk("psr: %x ", *(cpuregs+12)); + printk("\n"); +} + /** * Update the CPU registers of the TCB belonging * to the current thread. diff --git a/so3/arch/arm64/Makefile b/so3/arch/arm64/Makefile index f5f4e10469..e7159d1594 100644 --- a/so3/arch/arm64/Makefile +++ b/so3/arch/arm64/Makefile @@ -10,7 +10,7 @@ obj-y += backtrace.o backtrace_asm.o obj-y += cache_v8.o cache.o context.o obj-y += semihosting.o semicall.o -obj-$(CONFIG_AVZ) += hypercalls.o domain.o migration.o +obj-$(CONFIG_AVZ) += domain.o mmio.o obj-y += smccc-call.o @@ -22,7 +22,5 @@ obj-$(CONFIG_ARM64VT) += #smmu.o obj-y += lib/ -obj-$(CONFIG_SO3VIRT) += setup.o - obj-y += $(TARGET)/ diff --git a/so3/arch/arm64/asm-offsets.c b/so3/arch/arm64/asm-offsets.c index e620b7f73b..3b72615b51 100644 --- a/so3/arch/arm64/asm-offsets.c +++ b/so3/arch/arm64/asm-offsets.c @@ -45,15 +45,9 @@ int main(void) #ifdef CONFIG_AVZ DEFINE(OFFSET_AVZ_SHARED, offsetof(struct domain, avz_shared)); - DEFINE(OFFSET_EVTCHN_UPCALL_PENDING, offsetof(struct avz_shared, evtchn_upcall_pending)); - DEFINE(OFFSET_HYPERVISOR_CALLBACK, offsetof(struct avz_shared, vectors_vaddr)); - DEFINE(OFFSET_DOMCALL_CALLBACK, offsetof(struct avz_shared, domcall_vaddr)); - - DEFINE(OFFSET_G_SP, offsetof(struct domain, g_sp)); - - DEFINE(OFFSET_CPU_REGS, offsetof(struct domain, cpu_regs)); + DEFINE(OFFSET_CPU_REGS, offsetof(struct domain, vcpu.regs)); #endif BLANK(); @@ -100,9 +94,20 @@ int main(void) DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); + BLANK(); + + DEFINE(OFFSET_TCB_CPU_REGS, offsetof(tcb_t, cpu_regs)); + DEFINE(OFFSET_SP_USR, offsetof(cpu_regs_t, sp_usr)); + + BLANK(); + + DEFINE(OFFSET_SYS_SIGNUM, offsetof(__sigaction_t, signum)); + DEFINE(OFFSET_SYS_SA, offsetof(__sigaction_t, sa)); + BLANK(); - DEFINE(OFFSET_TCB_CPU_REGS, offsetof(tcb_t, cpu_regs)); + DEFINE(OFFSET_SA_HANDLER, offsetof(sigaction_t, sa_handler)); + DEFINE(OFFSET_SA_RESTORER, offsetof(sigaction_t, sa_restorer)); return 0; } diff --git a/so3/arch/arm64/backtrace.c b/so3/arch/arm64/backtrace.c index 49c1379ae4..3d9d3d062e 100644 --- a/so3/arch/arm64/backtrace.c +++ b/so3/arch/arm64/backtrace.c @@ -1,3 +1,4 @@ + /* * Copyright (C) 2016,2017 Daniel Rossier * diff --git a/so3/arch/arm64/cache_v8.c b/so3/arch/arm64/cache_v8.c index d29f9064e0..2710e81e2b 100644 --- a/so3/arch/arm64/cache_v8.c +++ b/so3/arch/arm64/cache_v8.c @@ -51,7 +51,7 @@ void mmu_setup(void *pgtable) #error "Wrong VA_BITS configuration." #endif -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ asm volatile("msr tcr_el2, %0" : : "r" (tcr) : "memory"); /* Prepare the stage-2 configuration */ @@ -77,7 +77,7 @@ void mmu_setup(void *pgtable) /* Enable the mmu and set the sctlr & ttbr register correctly. */ __mmu_setup(pgtable); -#else /* !CONFIG_ARM64VT */ +#else /* !CONFIG_AVZ */ attr = MAIR_EL1_SET; diff --git a/so3/arch/arm64/context.S b/so3/arch/arm64/context.S index 8ad901a61e..09e00fc41c 100644 --- a/so3/arch/arm64/context.S +++ b/so3/arch/arm64/context.S @@ -51,45 +51,47 @@ #ifdef CONFIG_AVZ // Switch from a domain to another -// Requires to re-configure the vbar_el1 vector table address ENTRY(__switch_domain_to) - mov x10, #(OFFSET_CPU_REGS + OFFSET_X19) + mov x10, #(OFFSET_CPU_REGS + OFFSET_X19) b ____switch_to #endif /* CONFIG_AVZ */ +// We preserve the registers which are not save on the stack but +// are necessary to keep this running context. ENTRY(__switch_to) - mov x10, #(OFFSET_TCB_CPU_REGS + OFFSET_X19) + mov x10, #(OFFSET_TCB_CPU_REGS + OFFSET_X19) ____switch_to: cbz x0, load_ctx - add x8, x0, x10 + add x8, x0, x10 save_ctx: + // store callee-saved registers + stp x19, x20, [x8], #16 + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, lr, [x8], #16 - stp x19, x20, [x8], #16 // store callee-saved registers - stp x21, x22, [x8], #16 - stp x23, x24, [x8], #16 - stp x25, x26, [x8], #16 - stp x27, x28, [x8], #16 - stp x29, lr, [x8], #16 - - mov x9, sp - str x9, [x8] + mov x9, sp + str x9, [x8] load_ctx: // Prepare to retrieve the regs from the stack - add x8, x1, x10 + add x8, x1, x10 - ldp x19, x20, [x8], #16 // restore callee-saved registers - ldp x21, x22, [x8], #16 - ldp x23, x24, [x8], #16 - ldp x25, x26, [x8], #16 - ldp x27, x28, [x8], #16 - ldp x29, lr, [x8], #16 + // restore callee-saved registers + ldp x19, x20, [x8], #16 + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, lr, [x8], #16 - ldr x9, [x8] - mov sp, x9 + ldr x9, [x8] + mov sp, x9 ret @@ -119,18 +121,12 @@ ENTRY(__mmu_switch_ttbr0) // Ensure synchronization with previous code changes isb #ifdef CONFIG_AVZ - -#ifdef CONFIG_ARM64VT - msr ttbr0_el2, x0 -#else - msr ttbr1_el1, x0 -#endif /* !CONFIG_ARM64VT */ - + msr ttbr0_el2, x0 #else /* !CONFIG_AVZ */ - msr ttbr0_el1, x0 + msr ttbr0_el1, x0 #endif - isb + isb ret @@ -144,7 +140,10 @@ ENTRY(__mmu_switch_ttbr1) // Ensure synchronization with previous code changes isb - msr ttbr1_el1, x0 + msr ttbr1_el1, x0 + + tlbi alle1 + isb ret @@ -154,15 +153,17 @@ ENTRY(__mmu_switch_vttbr) dsb sy // Ensure synchronization with previous code changes - isb + isb /* Switch the vttbr to map the correct guest */ msr vttbr_el2, x0 - isb + isb - tlbi alle2 - dsb nsh + tlbi vmalls12e1is + tlbi alle2 + dsb nsh + ret ENTRY(cpu_do_idle) @@ -179,8 +180,8 @@ ENTRY(cpu_do_idle) __get_syscall_args_ext: - str x8, [x0] - str x9, [x1] + str x8, [x0] + str x9, [x1] ret @@ -190,8 +191,8 @@ __get_syscall_args_ext: __thread_prologue_kernel: // Prepare to jump into C code - mov x0, x19 // tcb->th_fn - mov x1, x20 // tcb->th_arg + mov x0, x19 // tcb->th_fn + mov x1, x20 // tcb->th_arg enable_irq @@ -204,52 +205,31 @@ __thread_prologue_kernel: __thread_prologue_user: - msr elr_el1, x19 + msr elr_el1, x19 - msr sp_el0, x21 + msr sp_el0, x21 - mov x0, #PSR_MODE_EL0t + mov x0, #PSR_MODE_EL0t - msr spsr_el1, x0 + msr spsr_el1, x0 // Prepare to jump into C code - mov x0, x20 + mov x0, x20 #if 0 - at s1e0r, x19 + at s1e0r, x19 isb - mrs x0, par_el1 + mrs x0, par_el1 #endif eret #if 0 - // Prepare to jump into C code - mov r0, r4 // tcb->th_fn - mov r1, r5 // tcb->th_arg - - #ifdef CONFIG_MMU // Check if the thread must stopped because of ptrace/tracee - stmfd sp!, {r0, r1} + stmfd sp!, {r0, r1} bl __check_ptrace_traceme - ldmfd sp!, {r0, r1} + ldmfd sp!, {r0, r1} #endif - - // IRQ enabling - must be done in SVC mode of course ;-) - // We should take care about protecting against signal receipt: - // since the stack is not initialized yet, the signal processing should be kept disabled. - cpsie i - - // Switch into user mode - mrs r4, cpsr - bic r4, r4, #PSR_MODE_MASK - orr r4, r4, #PSR_USR_MODE - msr cpsr, r4 - - // User stack initialisation - mov sp, r6 - - bl thread_prologue #endif // Store the current registers into a cpu_regs structure passed in r0 (as first argument) @@ -262,27 +242,27 @@ __save_context: // it refers to this stack and not the one issue from the copy // as during fork(). - sub x1, x1, #S_FRAME_SIZE + sub x1, x1, #S_FRAME_SIZE - // Prepare to configure sp during the context switch. - str x1, [x0, #(OFFSET_TCB_CPU_REGS + OFFSET_SP)] + // Prepare to configure sp during the context switch + str x1, [x0, #(OFFSET_TCB_CPU_REGS + OFFSET_SP)] // Prepare the lr to branch to ret_from_fork - ldr x1, .LCret_from_fork - str x1, [x0, #(OFFSET_TCB_CPU_REGS + OFFSET_LR)] + ldr x1, .LCret_from_fork + str x1, [x0, #(OFFSET_TCB_CPU_REGS + OFFSET_LR)] // Preserve x8 which contains the syscall number (used to compare against SIG_RETURN) - str x8, [x0, #(OFFSET_TCB_CPU_REGS + OFFSET_X8)] + str x8, [x0, #(OFFSET_TCB_CPU_REGS + OFFSET_X8)] // The other registers are not important. ret .LCret_from_fork: - .quad ret_from_fork + .quad ret_from_fork .LCcurrent: - .quad current_thread + .quad current_thread // This section contains all data and code which will be // mapped in the user space as initial process to be executed. @@ -313,12 +293,12 @@ ENTRY(__root_proc) // write(stdout, buf, len) mov x0, #STDOUT - adr x1, .LC_welcome - mov x2, welcome_len - mov x8, #SYSCALL_WRITE + adr x1, .LC_welcome + mov x2, welcome_len + mov x8, #SYSCALL_WRITE // No errno - mov x9, xzr + mov x9, xzr // Invoke the syscall - kernel side svc 0 @@ -328,26 +308,26 @@ ENTRY(__root_proc) adr x0, .LC_exec // No args - mov x1, xzr - mov x2, xzr + mov x1, xzr + mov x2, xzr // No errno - mov x9, xzr + mov x9, xzr mov x8, #SYSCALL_EXECVE - svc 0 + svc 0 // If we are here, exec() has failed... mov x0, #STDOUT - adr x1, .LCnoshell - mov x2, noshell_len - mov x8, #SYSCALL_WRITE + adr x1, .LCnoshell + mov x2, noshell_len + mov x8, #SYSCALL_WRITE // No errno - mov x9, xzr + mov x9, xzr - svc 0 + svc 0 - b kernel_panic + b kernel_panic diff --git a/so3/arch/arm64/domain.c b/so3/arch/arm64/domain.c index 563444084b..287479158e 100644 --- a/so3/arch/arm64/domain.c +++ b/so3/arch/arm64/domain.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2014-2021 Daniel Rossier - * Copyright (C) 2016-2019 Baptiste Delporte + * Copyright (C) 2014-2024 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,6 +18,7 @@ #include #include +#include #include #include @@ -30,19 +30,49 @@ #include #endif -void arch_setup_domain_frame(struct domain *d, struct cpu_regs *domain_frame, addr_t fdt_addr, addr_t start_stack, addr_t start_pc) { +/** + * @brief Initialize the content of the EL2 stack associated to this domain. + * + * @param d + * @param domain_frame + * @param fdt_addr + * @param start_stack + * @param start_pc + */ +void initialize_hyp_dom_stack(struct domain *d, addr_t fdt_paddr, addr_t entry_addr) { + void *dom_stack; + struct cpu_regs *frame; + + /* The stack must be aligned at STACK_SIZE bytes so that it is + * possible to retrieve the cpu_info structure at the bottom + * of the stack with a simple operation on the current stack pointer value. + */ + dom_stack = memalign(DOMAIN_STACK_SIZE, DOMAIN_STACK_SIZE); + BUG_ON(!dom_stack); - domain_frame->x21 = fdt_addr; - domain_frame->x22 = (unsigned long) d->avz_shared; + /* Keep the reference for fu16ture removal */ + d->domain_stack = dom_stack; - domain_frame->sp = start_stack; - domain_frame->pc = start_pc; + /* Reserve the frame which will be restored later */ + frame = dom_stack + DOMAIN_STACK_SIZE - sizeof(cpu_regs_t); - d->cpu_regs.sp = (unsigned long) domain_frame; - d->cpu_regs.lr = (unsigned long) pre_ret_to_user; -} + /* Device tree */ + frame->x0 = fdt_paddr; -#ifdef CONFIG_ARM64VT + /* According to boot protocol */ + frame->x1 = 0; + frame->x2 = 0; + frame->x3 = 0; + + // domain_frame->sp = start_stack; + frame->lr = entry_addr; + + /* As we will be resumed from the schedule function, we need to update the + * vital registers from the VCPU regs. + */ + d->vcpu.regs.sp = (unsigned long) frame; + d->vcpu.regs.lr = (unsigned long) pre_ret_to_user; +} /** * Setup the stage 2 translation page table to translate Intermediate Physical address (IPA) to to PA addresses. @@ -53,11 +83,15 @@ void arch_setup_domain_frame(struct domain *d, struct cpu_regs *domain_frame, ad * @param p_start */ void __setup_dom_pgtable(struct domain *d, addr_t paddr_start, unsigned long map_size) { - u64 *new_pt; + addr_t *new_pt; + int slotID; + int i; + + ASSERT(d); - ASSERT(d); + slotID = ((d->avz_shared->domID == DOMID_AGENCY) ? MEMSLOT_AGENCY : d->avz_shared->domID); - /* Make sure that the size is 2 MB block aligned */ + /* Make sure that the size is 2 MB block aligned */ map_size = ALIGN_UP(map_size, SZ_2M); /* Initial L0 page table for the domain */ @@ -68,76 +102,48 @@ void __setup_dom_pgtable(struct domain *d, addr_t paddr_start, unsigned long map printk(" Real physical address : 0x%lx\n", paddr_start); printk(" Map size (bytes) : 0x%lx\n", map_size); - printk(" Intermediate phys address : 0x%lx\n", memslot[MEMSLOT_AGENCY].ipa_addr); - printk(" Stage-2 vttbr : (va) 0x%lx - (pa) 0x%lx\n", new_pt, __pa(new_pt)); + printk(" Intermediate phys address : 0x%lx\n", memslot[slotID].ipa_addr); + printk(" Stage-2 vttbr : (va) 0x%lx - (pa) 0x%lx\n", new_pt, __pa(new_pt)); - d->avz_shared->pagetable_vaddr = (addr_t) new_pt; - d->avz_shared->pagetable_paddr = __pa(new_pt); + d->pagetable_vaddr = (addr_t) new_pt; + d->pagetable_paddr = __pa(new_pt); /* Prepare the IPA -> PA translation for this domain */ - __create_mapping(new_pt, memslot[MEMSLOT_AGENCY].ipa_addr, paddr_start, map_size, false, S2); - - do_ipamap(new_pt, ipamap, ARRAY_SIZE(ipamap)); - - /* Map the shared page in the IPA space; the shared page is located right after the domain area - * in the IPA space. + __create_mapping(new_pt, memslot[slotID].ipa_addr, paddr_start, map_size, false, S2); + + if (d->avz_shared->domID == DOMID_AGENCY) + do_ipamap(new_pt, linux_ipamap, ARRAY_SIZE(linux_ipamap)); + else + do_ipamap(new_pt, guest_ipamap, ARRAY_SIZE(guest_ipamap)); + + /* Map the shared page in the IPA space; the shared page is located right after the domain area + * in the IPA space, and if any, the RT shared page follows the shared page (in IPA space). */ - __create_mapping(new_pt, memslot[MEMSLOT_AGENCY].ipa_addr + map_size, __pa(d->avz_shared), PAGE_SIZE, true, S2); + __create_mapping(new_pt, memslot[slotID].ipa_addr + map_size, __pa(d->avz_shared), PAGE_SIZE, true, S2); - if (d->avz_shared->subdomain_shared) { + if (d->avz_shared->subdomain_shared) { - __create_mapping(new_pt, memslot[MEMSLOT_AGENCY].ipa_addr + map_size + PAGE_SIZE, - __pa(d->avz_shared->subdomain_shared_paddr), PAGE_SIZE, true, S2); + /* We map the RT domain shared page using our vaddr since it is the IPA address. */ - /* will be used by the guest only. The AGENCY_RT domain has + __create_mapping(new_pt, memslot[slotID].ipa_addr + map_size + PAGE_SIZE, + __pa(d->avz_shared->subdomain_shared), PAGE_SIZE, true, S2); + + /* will be used by the guest only. The AGENCY_RT domain has * its own shared page, so we will be able to use it via the domain descriptor in avz. */ - d->avz_shared->subdomain_shared_paddr = memslot[MEMSLOT_AGENCY].ipa_addr + map_size + PAGE_SIZE; + d->avz_shared->subdomain_shared_paddr = memslot[slotID].ipa_addr + map_size + PAGE_SIZE; } -} -#else /* !CONFIG_ARM64VT */ - -/* - * Setup of domain consists in setting up the 1st-level and 2nd-level page tables within the domain. - */ -void __setup_dom_pgtable(struct domain *d, addr_t v_start, unsigned long map_size, addr_t p_start) { - u64 *new_pt; - - ASSERT(d); - - /* Make sure that the size is 2 MB block aligned */ - map_size = ALIGN_UP(map_size, SZ_2M); - - printk("*** Setup page tables of the domain: ***\n"); - printk(" v_start : 0x%lx\n", v_start); - printk(" map size (bytes) : 0x%lx\n", map_size); - printk(" phys address : 0x%lx\n", p_start); - - /* Initial L0 page table for the domain */ - new_pt = new_root_pgtable(); - - d->avz_shared->pagetable_vaddr = (addr_t) new_pt; - d->avz_shared->pagetable_paddr = __pa(new_pt); - - /* Copy the hypervisor area */ -#ifdef CONFIG_VA_BITS_48 - *l0pte_offset(new_pt, CONFIG_KERNEL_VADDR) = *l0pte_offset(__sys_root_pgtable, CONFIG_KERNEL_VADDR); -#elif CONFIG_VA_BITS_39 - *(new_pt + l1pte_index(CONFIG_KERNEL_VADDR)) = *(__sys_root_pgtable + l1pte_index(CONFIG_KERNEL_VADDR)); -#else -#error "Wrong VA_BITS configuration." -#endif - - /* Do the mapping of new domain at its virtual address location */ - create_mapping(new_pt, v_start, p_start, map_size, false); + /* Initialize the grant pfn (ipa address) area */ + for (i = 0; i < NR_GRANT_PFN; i++) { + d->grant_pfn[i].pfn = phys_to_pfn(memslot[slotID].ipa_addr + map_size + 2 * PAGE_SIZE) + i; + d->grant_pfn[i].free = true; + } } -#endif /* !CONFIG_ARM64VT */ - void arch_domain_create(struct domain *d, int cpu_id) { if (is_idle_domain(d)) - d->avz_shared->pagetable_paddr = __pa(__sys_root_pgtable); + d->pagetable_paddr = __pa(__sys_root_pgtable); } diff --git a/so3/arch/arm64/exception.S b/so3/arch/arm64/exception.S index 31cc07df7e..bde52f61b9 100644 --- a/so3/arch/arm64/exception.S +++ b/so3/arch/arm64/exception.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Daniel Rossier + * Copyright (C) 2021-2024 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,32 +21,25 @@ #include #include +#include #include #include #ifdef CONFIG_AVZ -#include +#include -#ifdef CONFIG_ARM64VT +#include .global cpu_entrypoint -#else /* CONFIG_ARM64VT */ - -.extern do_upcall -.globl pseudo_usr_mode - -#endif /* !ARM64VT */ - -.globl hypervisor_stack -.global upcall_path - #endif /* CONFIG_AVZ */ .globl ret_from_fork .global __call_sig_handler + +.extern current_thread .extern __sync_serror .extern do_exit .extern __check_ptrace_syscall @@ -108,192 +101,144 @@ ENTRY(__vectors) // Current EL with SP0 / Synchronous .align 7 - mov x0, lr + mov x0, lr b trap_handle_error // Current EL with SP0 / IRQ .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Current EL with SP0 / FIQ .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Current EL with SP0 / SError .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Current EL with SPx / Synchronous .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Current EL with SPx / IRQ .align 7 #ifdef CONFIG_AVZ - -#ifdef CONFIG_ARM64VT - b el1_2_12_irq_handler -#else - b avz_el01_1_irq_handler -#endif /* CONFIG_ARM64VT */ - + b el12_2_irq_handler #else /* CONFIG_AVZ */ - - b el1_irq_handler - + b el01_1_irq_handler #endif /* !CONFIG_AVZ */ // Current EL with SPx / FIQ .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Current EL with SPx / SError .align 7 - mov x0, lr - mrs x1, esr_el1 + mov x0, lr + mrs x1, esr_el1 - b __sync_serror + b __sync_serror // Lower EL using AArch64 / Synchronous .align 7 // This vector is concerned with the syscall interrupt. -#ifdef CONFIG_ARM64VT - b el12_sync_handler -#else /* CONFIG_ARM64VT */ - b el01_sync_handler -#endif /* !CONFIG_ARM64VT */ +#ifdef CONFIG_AVZ + b el12_sync_handler +#else + b el01_sync_handler +#endif // Lower EL using AArch64 / IRQ .align 7 -#ifdef CONFIG_AVZ - -#ifdef CONFIG_ARM64VT - b el1_2_12_irq_handler -#else /* CONFIG_ARM64VT */ - b avz_el01_1_irq_handler -#endif /* !CONFIG_ARM64VT */ +#ifdef CONFIG_AVZ + b el12_2_irq_handler #else /* CONFIG_AVZ */ - b el0_irq_handler + b el01_1_irq_handler #endif /* !CONFIG_AVZ */ // Lower EL using AArch64 / FIQ .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Lower EL using AArch64 / SError .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Lower EL using AArch32 / Synchronous .align 7 - mov x0, lr + mov x0, lr b trap_handle_error // Lower EL using AArch32 / IRQ .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Lower EL using AArch32 / FIQ .align 7 - mov x0, lr - b trap_handle_error + mov x0, lr + b trap_handle_error // Lower EL using AArch32 / SError .align 7 - mov x0, lr - b trap_handle_error - -__prepare_sig_handler: -#if 0 - str sp, [sp, #(OFFSET_SP-S_FRAME_SIZE)] // save sp - - // Build a new stack frame based on the current - sub sp, sp, #S_STACK_FRAME_SIZE - - // Make sure the spsr is with Thumb de-activated to perform normal execution of the handler - - mov r1, #PSR_USR_MODE // Ensure the handler will run in user mode (situation where - // the current frame inherits from code running in SVC). - - str r1, [sp, #OFFSET_PSR] // Save the updated SPSR - - // Set the argument (signum, handler) to r0 & r1 - ldr r1, [r0, #OFFSET_SYS_SIGNUM] - str r1, [sp, #OFFSET_R0] - - ldr r0, [r0, #OFFSET_SYS_SA] - ldr r1, [r0, #OFFSET_SA_HANDLER] - str r1, [sp, #OFFSET_R1] - - ldr r1, [r0, #OFFSET_SA_RESTORER] - str r1, [sp, #OFFSET_PC] // Set the handler to the PC - - /* Set the current sp_usr to have a valid stack in the user space */ - - ldr r0, .LCcurrent - ldr r0, [r0] - ldr r0, [r0, #(OFFSET_TCB_CPU_REGS + OFFSET_SP_USR)] - str r0, [sp, #OFFSET_SP_USR] - - mov pc, lr // Back to the caller -#endif - ret + mov x0, lr + b trap_handle_error + #ifdef CONFIG_CPU_SPIN_TABLE ENTRY(pre_ret_to_el1_with_spin) - mov x1, x0 - str xzr, [x1] + mov x1, x0 + str xzr, [x1] 1: wfe - ldr x0, [x1] + ldr x0, [x1] - cbz x0, 1b + cbz x0, 1b - // Branch to the given address - msr elr_el2, x0 + // Branch to the given address + msr elr_el2, x0 // Set the CPU in EL1 mode to proceed with // the bootstrap of the domain - mov x2, #PSR_MODE_EL1t + mov x2, #PSR_MODE_EL1t // Make sure no interrupt coming from CPU #0 is // interferring with other CPU bootstrap - orr x2, x2, #PSR_I_BIT + orr x2, x2, #PSR_I_BIT - msr spsr_el2, x2 + msr spsr_el2, x2 // According to boot protocol - mov x1, #0 - mov x1, #0 - mov x2, #0 - mov x3, #0 + mov x1, #0 + mov x1, #0 + mov x2, #0 + mov x3, #0 // Ready to jump into the Linux domain... @@ -313,7 +258,7 @@ ENTRY(pre_ret_to_el1_with_spin) nop #endif /* CONFIG_CPU_SPIN_TABLE */ -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ #ifdef CONFIG_CPU_PSCI ENTRY(pre_ret_to_el1) @@ -321,24 +266,24 @@ ENTRY(pre_ret_to_el1) wfi ldr x0, cpu_entrypoint - msr elr_el2, x0 + msr elr_el2, x0 // Set the CPU in EL1 mode to proceed with // the bootstrap of the domain - mov x2, #PSR_MODE_EL1t + mov x2, #PSR_MODE_EL1t // Make sure no interrupt coming from CPU #0 is // interferring with other CPU bootstrap - orr x2, x2, #PSR_I_BIT + orr x2, x2, #PSR_I_BIT - msr spsr_el2, x2 + msr spsr_el2, x2 // According to boot protocol - mov x1, #0 - mov x1, #0 - mov x2, #0 - mov x3, #0 + mov x1, #0 + mov x1, #0 + mov x2, #0 + mov x3, #0 // Ready to jump into the Linux domain... @@ -359,96 +304,127 @@ ENTRY(pre_ret_to_el1) #endif /* CONFIG_CPU_PSCI */ -.align 5 -el12_sync_handler: +// Enter macro to jump into EL1 from EL0 *or* from EL1 +.macro prepare_to_enter_to_el2 + mrs x0, elr_el2 + str x0, [sp, #OFFSET_PC] - kernel_entry + mrs x0, sp_el1 + str x0, [sp, #OFFSET_SP_USR] - mrs x0, spsr_el2 - str x0, [sp, #OFFSET_PSTATE] + mrs x0, spsr_el2 + str x0, [sp, #OFFSET_PSTATE] +.endm - mrs x0, sp_el1 - str x0, [sp, #OFFSET_SP] - mrs x0, elr_el2 - str x0, [sp, #OFFSET_PC] +// Exit macro at the end of an exception routine +// It restores the sp_el0 as well. +.macro prepare_to_exit_to_el1 + ldr x0, [sp, #OFFSET_PC] + msr elr_el2, x0 - mov x0, sp - bl trap_handle + ldr x0, [sp, #OFFSET_SP_USR] + msr sp_el1, x0 - str x0, [sp, #OFFSET_X0] + ldr x0, [sp, #OFFSET_PSTATE] + msr spsr_el2, x0 +.endm - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el2, x0 +.align 5 +el12_sync_handler: - ldr x0, [sp, #OFFSET_SP] - msr sp_el1, x0 + kernel_entry + prepare_to_enter_to_el2 - ldr x0, [sp, #OFFSET_PC] - msr elr_el2, x0 + mov x0, sp + bl trap_handle + + ldr x0, [sp, #OFFSET_X0] + ldr x1, =AVZ_HYPERCALL_SIGRETURN + + cmp x0, x1 + bne __nosigreturn + + // Reset the stack frame by removing the one issued from sigreturn + add sp, sp, #S_FRAME_SIZE +__nosigreturn: + prepare_to_exit_to_el1 kernel_exit eret + .align 5 -el1_2_12_irq_handler: +el12_2_irq_handler: kernel_entry + prepare_to_enter_to_el2 -#ifdef CONFIG_ARM64VT - mrs x0, elr_el2 - str x0, [sp, #OFFSET_PC] + // Make sure r0 refers to the base of the stack frame + mov x0, sp + bl irq_handle - mrs x0, spsr_el2 - str x0, [sp, #OFFSET_PSTATE] + prepare_to_exit_to_el1 + kernel_exit - mrs x0, sp_el1 - str x0, [sp, #OFFSET_SP] -#else - mrs x0, elr_el1 - str x0, [sp, #OFFSET_PC] + eret - mrs x0, spsr_el1 - str x0, [sp, #OFFSET_PSTATE] -#endif +cpu_entrypoint: + .quad 0x0 - // Make sure r0 refers to the base of the stack frame - mov x0, sp +__prepare_to_sig_el1_handler: + + /* Preserve the SP_EL2 in the new stack frame used by + * the signal handler. + */ - // The stack must stay 16-byte aligned + ldr x0, [sp, #OFFSET_SP_USR] + str x0, [sp, #(OFFSET_SP_USR - S_FRAME_SIZE)] - str lr, [sp, #-16]! - bl irq_handle - ldr lr, [sp], #16 + ldr x0, [sp, #OFFSET_PSTATE] + str x0, [sp, #(OFFSET_PSTATE - S_FRAME_SIZE)] -#ifdef CONFIG_ARM64VT - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el2, x0 + // Build a new stack frame based on the current + sub sp, sp, #S_FRAME_SIZE + + // Set the handler to the PC + str x21, [sp, #OFFSET_PC] - ldr x0, [sp, #OFFSET_PC] - msr elr_el2, x0 + ret - ldr x0, [sp, #OFFSET_SP] - msr sp_el1, x0 -#else - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 +/* + * This glue code will be called to prepare a resuming + * of a ME. + */ +ENTRY(resume_to_guest) - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 -#endif + bl __prepare_to_sig_el1_handler + + ldr x0, [sp, #OFFSET_PSTATE] + msr spsr_el2, x0 + + ldr x0, [sp, #OFFSET_PC] + msr elr_el2, x0 + + ldr x0, [sp, #OFFSET_SP_USR] + msr sp_el1, x0 kernel_exit eret -cpu_entrypoint: - .quad 0x0 - -#endif /* CONFIG_ARM64VT */ + /* + * Mitigate Straight-line Speculation. + * Guard against Speculating past an ERET instruction and + * potentially perform speculative accesses to memory before + * processing the exception return + */ + dsb nsh + isb -#ifdef CONFIG_AVZ +999: + b 999b /* * This function is called at bootstrap and @@ -459,57 +435,31 @@ ENTRY(pre_ret_to_user) // Initial state - IRQs off disable_irq - // Get a reference to our domain descriptor - curdom x10, x11 + ldr x2, [sp, #OFFSET_LR] // Entry point of the guest + msr elr_el2, x2 -#ifdef CONFIG_ARM64VT + /* + * The MMU must be disabled so that the guest can keep its initial boot code. + * Make sure CPU EL1 has MMU disabled. + */ - ldr x2, [sp, #OFFSET_PC] // Entry point of the guest - msr elr_el2, x2 + mrs x2, sctlr_el1 + bic x2, x2, #SCTLR_ELx_M + msr sctlr_el1, x2 // Set the CPU in EL1 mode to proceed with // the bootstrap of the domain - mov x2, #PSR_MODE_EL1t - msr spsr_el2, x2 + mov x2, #(PSR_MODE_EL1h | PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT) - ldr x0, [sp, #OFFSET_X21] // Device tree (fdt_addr) + msr spsr_el2, x2 - // According to boot protocol - mov x1, #0 - mov x2, #0 - mov x3, #0 - - // Ready to jump into the agency domain... + kernel_exit + + // Ready to jump into the domain... eret -#else /* CONFIG_ARM64VT */ - - ldr x11, [x10, #OFFSET_AVZ_SHARED] - str xzr, [x11, #OFFSET_HYPERVISOR_CALLBACK] - - current_cpu x11 - - // Switch to the guest stack - ldr x0, .LChypervisor_stack - mov x12, sp - str x12, [x0, x11, lsl #3] - - // Setting pseudo_usr_mode - ldr x0, .LCpseudo_usr_mode - mov x1, #1 - str x1, [x0, x11, lsl #3] - - ldr x2, [sp, #OFFSET_PC] // Entry point of the guest - ldr x21, [sp, #OFFSET_X21] // Device tree (fdt_addr) - ldr x22, [sp, #OFFSET_X22] // Address of start_info - - // Ready to jump into the Linux domain... - blr x2 - -#endif /* !CONFIG_ARM64VT */ - /* * Mitigate Straight-line Speculation. * Guard against Speculating past an ERET instruction and @@ -519,420 +469,138 @@ ENTRY(pre_ret_to_user) dsb nsh isb -__crash: - b __crash - -#ifndef CONFIG_ARM64VT - -.align 5 -avz_el01_1_irq_handler: - - kernel_entry - - mrs x0, spsr_el1 - str x0, [sp, #OFFSET_PSTATE] - - mrs x0, sp_el0 - str x0, [sp, #OFFSET_SP] - - mrs x0, elr_el1 - str x0, [sp, #OFFSET_PC] - - // Now process the IRQ differentiating execution according to the source (dom/hyp) - // for managing the stack correctly - - current_cpu x10 - - ldr x0, .LCpseudo_usr_mode - ldr x1, [x0, x10, lsl #3] - cmp x1, #0 // svc ? - - b.eq svc_path - - mov x1, #0 // setting svc - str x1, [x0, x10, lsl #3] - - mov x1, sp - ldr x0, .LChypervisor_stack // Get the running hypervisor SVC stack - ldr x0, [x0, x10, lsl #3] - - mov sp, x0 - - curdom x0, x2 - str x1, [x0, #OFFSET_G_SP] - - // Make sure r0 refers to the base of the stack frame - mov x0, sp - - str lr, [sp, #-16]! - bl irq_handle - ldr lr, [sp], #16 - - curdom x10, x11 - ldr x11, [x10, #OFFSET_AVZ_SHARED] - - // If the softirq handling leads to trigger an interrupt in the guest, - // it will be processed by do_evtchn_do_upcall. The way how to - // process an interrupt with potentially IRQs off is under the - // responsibility of the guest - - // are some IRQs pending? - ldrb w12, [x11, #OFFSET_EVTCHN_UPCALL_PENDING] - tst w12, #0xff - - b.eq restore - -upcall_path: - - current_cpu x11 - - curdom x10, x12 - ldr x12, [x10, #OFFSET_AVZ_SHARED] - ldr lr, [x12, #OFFSET_HYPERVISOR_CALLBACK] - - cmp lr, #0 - beq restore - - ldr x0, .LChypervisor_stack // running L1 hypervisor stack - mov x12, sp - str x12, [x0, x11, lsl #3] - - // Get guest stack - ldr x12, [x10, #OFFSET_G_SP] - mov sp, x12 - - // setting pseudo_usr_mode / x0, x1 re-assigned right after - ldr x0, .LCpseudo_usr_mode - mov x1, #1 - str x1, [x0, x11, lsl #3] - - // x0 contains a reference to the stack pointer - mov x0, sp - - // Go up to the guest for evtchn processing - br lr - -restore: - - current_cpu x11 - - // Setting pseudo_usr_mode / x0, x1 re-assigned right after - ldr x0, .LCpseudo_usr_mode - mov x1, #1 - str x1, [x0, x11, lsl #3] - - // Restore saved registers - - ldr x0, .LChypervisor_stack // running SVC hypervisor stack - mov x10, sp - str x10, [x0, x11, lsl #3] - - curdom x10, x11 - - // Get guest stack - ldr x11, [x10, #OFFSET_G_SP] - mov sp, x11 - -out_irq: - - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 - - ldr x0, [sp, #OFFSET_SP] - msr sp_el0, x0 - - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 - - kernel_exit - - eret - - -/* - * The following function is used to restore the migrated domain. - * Indeed, the receiver environment has not saved anything on its stack regarding - * a context switch. We can not pursue on right-after-context-switch in the schedule function! - * But we do not start from boot either. So, we have an appropriate restore glue code to perform - * an upcall in the newly migrated ME. A first timer IRQ has been set in domain_migration_restore() to - * avoid a problem in the guest when testing for upcall pending. - * - * - */ -ENTRY(after_migrate_to_user) - - b upcall_path - -// Hypervisor stack is used for the *current* (running) vcpu svc stack address -svc_path: - - mov x0, sp +999: + b 999b - // The stack must stay 16-byte aligned - - str lr, [sp, #-16]! - bl irq_handle - ldr lr, [sp], #16 - - b out_irq +#endif /* CONFIG_AVZ */ -pseudo_usr_mode: - .space CONFIG_NR_CPUS * 8 +__prepare_sig_handler: -.LCpseudo_usr_mode: - .quad pseudo_usr_mode + /* Preserve the SP_EL1 in the new stack frame used by + * the signal handler + */ + ldr x2, [sp, #OFFSET_SP_USR] + str x2, [sp, #(OFFSET_SP_USR - S_FRAME_SIZE)] -#endif /* !CONFIG_ARM64VT */ + // Build a new stack frame based on the current + sub sp, sp, #S_FRAME_SIZE -hypervisor_stack: - .space CONFIG_NR_CPUS * 8 + mov x2, #PSR_MODE_EL0t + bic x2, x2, #PSR_I_BIT + str x2, [sp, #OFFSET_PSTATE] + + ldr x1, [x0, #OFFSET_SYS_SIGNUM] + str x1, [sp, #OFFSET_X0] + + ldr x1, [x0, #OFFSET_SYS_SA] + ldr x2, [x1, #OFFSET_SA_HANDLER] + str x2, [sp, #OFFSET_X1] -.LChypervisor_stack: - .quad hypervisor_stack + // Set the handler to the PC + ldr x2, [x1, #OFFSET_SA_RESTORER] + str x2, [sp, #OFFSET_PC] -#endif /* CONFIG_AVZ */ + ret +// x0 will be altered .macro check_pending_signal - // Is there any pending signals for this process? - bl sig_check - cmp x0, #0 + //The return value will be the __sigaction_t pointer or 0 (NULL) if no signal pending + bl sig_check + + cmp x0, #0 b.eq 1f // Configure a stack frame to manage the user handler - bl __prepare_sig_handler + bl __prepare_sig_handler 1: .endm -el01_sync_handler: - -// If the syscall interrupt occurs with the SO3-on-avz configuration, -// the stack frame is built in AVZ (interrupt vector at this level). -// Hence, the SO3 domain (guest) will just need to preserve the -// return address and make the local processing. +// Enter macro to jump into EL1 from EL0 *or* from EL1 +.macro prepare_to_enter_to_el1 + mrs x0, elr_el1 + str x0, [sp, #OFFSET_PC] -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) + mrs x0, sp_el0 + str x0, [sp, #OFFSET_SP_USR] - // x0 contains the reference to the stack frame at the entry - // of the syscall + mrs x0, spsr_el1 + str x0, [sp, #OFFSET_PSTATE] +.endm - // Preserve the return address from avz call - str lr, [sp, #-8]! -#else +// Exit macro at the end of an exception routine +// It restores the sp_el0 as well. +.macro prepare_to_exit_to_el0 + ldr x0, [sp, #OFFSET_PC] + msr elr_el1, x0 - kernel_entry + ldr x0, [sp, #OFFSET_SP_USR] + msr sp_el0, x0 - mrs x0, elr_el1 - str x0, [sp, #OFFSET_PC] + ldr x0, [sp, #OFFSET_PSTATE] + msr spsr_el1, x0 +.endm - mrs x0, sp_el0 - str x0, [sp, #OFFSET_SP] - mrs x0, spsr_el1 - str x0, [sp, #OFFSET_PSTATE] +/* Syscalls */ +el01_sync_handler: - // Make sure r0 refers to the base of the stack frame - mov x0, sp + kernel_entry + prepare_to_enter_to_el1 -#endif + // Make sure x0 refers to the base of the stack frame + mov x0, sp + bl trap_handle - bl trap_handle + // Check if sigreturn has been called. In this case, we + // clean the stack frame which has been used to manage the user handler. + cmp x8, #SYSCALL_SIGRETURN + bne __ret_from_fork + + // Reset the stack frame by removing the one issued from sigreturn + add sp, sp, #S_FRAME_SIZE + __ret_from_fork: #ifdef CONFIG_IPC_SIGNAL - // Is there any pending signals for this process? check_pending_signal - #endif /* CONFIG_IPC_SIGNAL */ - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - - // Back to avz - ldr lr, [sp], #8 - ret - -#else - - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 - - ldr x0, [sp, #OFFSET_SP] - msr sp_el0, x0 - - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 - + prepare_to_exit_to_el0 kernel_exit eret -#endif - .align 5 -el0_irq_handler: +el01_1_irq_handler: kernel_entry - - mrs x0, elr_el1 - str x0, [sp, #OFFSET_PC] - - mrs x0, sp_el0 - str x0, [sp, #OFFSET_SP] - - mrs x0, spsr_el1 - str x0, [sp, #OFFSET_PSTATE] + prepare_to_enter_to_el1 // Make sure r0 refers to the base of the stack frame - mov x0, sp - - bl irq_handle - - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 + mov x0, sp + bl irq_handle - ldr x0, [sp, #OFFSET_SP] - msr sp_el0, x0 - - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 +#ifdef CONFIG_IPC_SIGNAL + // Is there any pending signals for this process? + check_pending_signal +#endif /* CONFIG_IPC_SIGNAL */ + prepare_to_exit_to_el0 kernel_exit eret - -.align 5 -el1_irq_handler: - - kernel_entry - - mrs x0, elr_el1 - str x0, [sp, #OFFSET_PC] - - mrs x0, spsr_el1 - str x0, [sp, #OFFSET_PSTATE] - - // Make sure r0 refers to the base of the stack frame - mov x0, sp - - // The stack must stay 16-byte aligned - - bl irq_handle - - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 - - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 - - kernel_exit - - eret - - // Used at entry point of a fork'd process (setting the return value to 0) ret_from_fork: + str xzr, [sp, #OFFSET_X0] + b __ret_from_fork - str xzr, [sp, #OFFSET_X0] - -// With the SO3-on-avz configuration, the creation of new process remains -// identical as other configurations, and prepare the stack frame to -// be correctly processed along the upcall path, even if, for such a configuration, -// the guest does not handle the stack frame (see the sync interrupt handling below). -// Therefore, and only for this case, we need to handle that. - -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_SOO) - - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 - - ldr x0, [sp, #OFFSET_SP] - msr sp_el0, x0 - - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 - - kernel_exit - - eret - -#else - b __ret_from_fork -#endif - - -// IRQs are off -// ARM EABI: the syscall nr is stored in x8 -.align 5 -syscall_interrupt: - -#if 0 /* Still to be ported in ARM64 */ - - // At the exception entry, the stack must be 8-byte aligned. - // If it is not the case (gcc might not respect the AAPCS convention for optimization purposes), - // sp will be adjusted. The original sp is preserved and will be correctly restored at the exit. - - tst sp, #0x7 // 8-bytes aligned - strne sp, [sp, #(OFFSET_SP-SVC_STACK_FRAME_SIZE - 4)] // save sp - subne sp, sp, #4 - streq sp, [sp, #(OFFSET_SP-SVC_STACK_FRAME_SIZE)] // save sp - - // Alignment guard - tst sp, #0x7 // 8-bytes aligned - bne __stack_alignment_fault - - // Build the stack frame to store registers - - sub sp, sp, #SVC_STACK_FRAME_SIZE - - str lr, [sp, #OFFSET_LR] // save lr in lr - str lr, [sp, #OFFSET_PC] // save lr in pc - - stmia sp, {r0-r12} // Store registers - - mrs lr, spsr // Get spsr - str lr, [sp, #OFFSET_PSR] // Store spsr - - // Saving user mode registers (sp_usr, lr_usr) - add lr, sp, #OFFSET_SP_USR - stmia lr, {sp, lr}^ - - ldr r0, [sp, #OFFSET_SP_USR] - ldr r1, .LCcurrent - ldr r1, [r1] - - str r0, [r1, #(OFFSET_TCB_CPU_REGS + OFFSET_SP_USR)] - - // Restore r0-r2 - ldmia sp, {r0-r2} - -#ifdef CONFIG_MMU - // Give a chance to a ptrace tracer to monitor us (before the syscall) - stmfd sp!, {r0-r4} - bl __check_ptrace_syscall - ldmfd sp!, {r0-r4} -#endif - - cpsie i // Re-enable interrupts - bl syscall_handle - cpsid i // Re-disable interrupts to be safe in regs manipulation - - // Check if sigreturn has been called. In this case, we - // clean the stack frame which has been used to manage the user handler. - cmp r7, #SYSCALL_SIGRETURN - bne __no_sigreturn - - // Reset the stack frame by removing the one issued from sigreturn - add sp, sp, #SVC_STACK_FRAME_SIZE -#endif - -__no_sigreturn: #if 0 #ifdef CONFIG_MMU @@ -942,102 +610,16 @@ __no_sigreturn: ldmfd sp!, {r0-r4} #endif #endif - -#ifdef CONFIG_SO3VIRT - -.align 5 -/* - * Hypercall trampoline has the following arguments: - * - x0: hypercall number - * - x1: first arg (-> r0) - * - x2: second arg - * - x3: third arg - * - x4: fourth arg - * - x5: work register - * - x7: hypecall number (ABI) - * - * - x8 will contain 0 if no pending evtchn, 1 otherwise - * - x9 will contain the PSTATE at the hypercall entry and exit - */ -ENTRY(hypercall_trampoline) - - // Stack alignment must stay on 16 bytes. - sub sp, sp, #12*8 - - stp x1, x2, [sp, #16 * 0] - stp x3, x4, [sp, #16 * 1] - stp x5, x6, [sp, #16 * 2] - stp x7, x8, [sp, #16 * 3] - stp x9, x10, [sp, #16 * 4] - stp x11, lr, [sp, #16 * 5] - - mov x7, x0 - mov x0, x1 - mov x1, x2 - mov x2, x3 - mov x3, x4 - mov x4, x5 - - ldr x5, =HYPERVISOR_hypercall_addr - ldr x5, [x5] - - blr x5 - - cmp x8, #0 - b.eq out_upcall - - kernel_entry - - // Update PSTATE accordingly - str x9, [sp, #OFFSET_PSTATE] - - // Set x0 to sp - mov x0, sp - bl irq_handle - kernel_exit - - // Restore original PSTATE - msr daif, x9 - -out_upcall: - - ldp x1, x2, [sp, #16 * 0] - ldp x3, x4, [sp, #16 * 1] - ldp x5, x6, [sp, #16 * 2] - ldp x7, x8, [sp, #16 * 3] - ldp x9, x10, [sp, #16 * 4] - ldp x11, lr, [sp, #16 * 5] - - add sp, sp, #12*8 - - ret - -#endif /* CONFIG_SO3VIRT */ + #if !defined(CONFIG_AVZ) && defined(CONFIG_SOO) - -// We may reach this point only during along the upcall -// path of a hypercall return. - .align 5 -ENTRY(avz_vector_callback) - - // x0 is set to cpu_regs_t by avz - bl irq_handle - - ldr x0, [sp, #OFFSET_PSTATE] - msr spsr_el1, x0 - - ldr x0, [sp, #OFFSET_SP] - msr sp_el0, x0 - ldr x0, [sp, #OFFSET_PC] - msr elr_el1, x0 +ENTRY(__avz_hypercall) - kernel_exit - - eret + hvc #0 + ret #endif diff --git a/so3/arch/arm64/head.S b/so3/arch/arm64/head.S index 115263cd98..5662ee636d 100644 --- a/so3/arch/arm64/head.S +++ b/so3/arch/arm64/head.S @@ -55,24 +55,19 @@ __pre_head: __start: -#ifndef CONFIG_SO3VIRT // Preserve the fdt addr (device tree) which is stored in x0 by U-boot - mov x9, x0 -#else - // From AVZ, the device tree address is stored in x21 - mov x9, x21 -#endif - + mov x9, x0 + // Store the DT addr in a safe place which can be accessed on a relocatable address adr x8, .LCfdt_addr_temp str x9, [x8] - -#ifndef CONFIG_SO3VIRT + + // If SO3 is running as guest on top of AVZ, it must not setup EL2 mode + // TODO: enable trap of EL2 inst. to avoid this test. +#if defined(CONFIG_AVZ) || !defined(CONFIG_SOO) // CPU configuration - bl el2_setup // Drop to EL1, w0=cpu_boot_mode - -#endif /* !CONFIG_SO3VIRT */ - + bl el2_setup // Drop to EL1, w0=cpu_boot_mode +#endif /* Clear the BSS */ adrp x0, __bss_start @@ -80,7 +75,7 @@ __start: 1: strb wzr, [x0], #1 - cmp x0, x1 + cmp x0, x1 b.cc 1b // Enable FP/ASIMD @@ -90,60 +85,45 @@ __start: // Initialize stack pointers for current mode (normal case if no MMU is used) adrp x0, __stack_top - mov sp, x0 + mov sp, x0 - // Up to here, a stack should be initialized + // Up to here, a stack should be initialized -#ifdef CONFIG_SO3VIRT - ldr x10, =avz_shared - str x22, [x10] -#endif /* CONFIG_SO3VIRT */ /* Basic low-level initialization */ #ifdef CONFIG_AVZ mov x0, x9 - bl __get_avz_fdt_paddr + bl __get_avz_fdt_paddr // x0 now contains the right paddr of the AVZ device tree #else - mov x0, x9 // FDT paddr + mov x0, x9 // FDT paddr #endif - bl early_memory_init - -#ifdef CONFIG_SO3VIRT - bl avz_setup -#endif /* CONFIG_SO3VIRT */ + bl early_memory_init - // Set up the MMU - b setup_mmu + // Set up the MMU + b setup_mmu __kernel_main: -#if !defined(CONFIG_SOO) || defined(CONFIG_AVZ) - // Enable the interrupt - adrp x0, __vectors // Virtual address as required + adrp x0, __vectors // Virtual address as required -#ifdef CONFIG_ARM64VT - msr vbar_el2, x0 +#ifdef CONFIG_AVZ + msr vbar_el2, x0 #else - msr vbar_el1, x0 -#endif /* !CONFIG_ARM64VT */ + msr vbar_el1, x0 +#endif /* !CONFIG_AVZ */ -#endif /* !CONFIG_SOO */ - -#ifndef CONFIG_SO3VIRT // Store the device tree paddr - adr x8, .LCfdt_addr_temp - ldr x9, [x8] + adr x8, .LCfdt_addr_temp + ldr x9, [x8] ldr x0, =__fdt_addr str x9, [x0] -#endif /* CONFIG_SO3VIRT */ - // C main entry point #ifdef CONFIG_AVZ b avz_start @@ -164,87 +144,85 @@ __kernel_main: .align 2 -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ __mmu_setup: - // The code to configure tcr_el2 - // is borrowed from jailhouse hypervisor + // The code to configure tcr_el2 + // is borrowed from jailhouse hypervisor - mrs x1, tcr_el2 + mrs x1, tcr_el2 - /* - * set TCR.(I)PS to the highest supported ID_AA64MMFR0_EL1.PARange value - */ + /* + * set TCR.(I)PS to the highest supported ID_AA64MMFR0_EL1.PARange value + */ - mrs x2, id_aa64mmfr0_el1 + mrs x2, id_aa64mmfr0_el1 - /* Narrow PARange to fit the PS field in TCR_ELx */ - ubfx x2, x2, #ID_AA64MMFR0_PARANGE_SHIFT, #3 - bfi x1, x2, #TCR_PS_SHIFT, #3 + /* Narrow PARange to fit the PS field in TCR_ELx */ + ubfx x2, x2, #ID_AA64MMFR0_PARANGE_SHIFT, #3 + bfi x1, x2, #TCR_PS_SHIFT, #3 - msr tcr_el2, x1 + msr tcr_el2, x1 - /* - * The state of the TLBs is unknown before turning on the MMU. - * Flush them to avoid stale one. - */ - tlbi alle2 /* Flush hypervisor TLBs */ - dsb nsh + /* + * The state of the TLBs is unknown before turning on the MMU. + * Flush them to avoid stale one. + */ + tlbi alle2 /* Flush hypervisor TLBs */ + dsb nsh - msr ttbr0_el2, x0 - isb + msr ttbr0_el2, x0 + isb - ldr x0, =(SCTLR_I_BIT | SCTLR_C_BIT | SCTLR_M_BIT | SCTLR_EL2_RES1) + ldr x0, =(SCTLR_I_BIT | SCTLR_C_BIT | SCTLR_M_BIT | SCTLR_EL2_RES1) - dsb sy /* Flush PTE writes and finish reads */ - msr sctlr_el2, x0 /* now paging is enabled */ - isb /* Now, flush the icache */ + dsb sy /* Flush PTE writes and finish reads */ + msr sctlr_el2, x0 /* now paging is enabled */ + isb /* Now, flush the icache */ - ret + ret setup_mmu: - // Use a temporary stack - adrp x0, temp_stack - mov sp, x0 - - mov x0, x9 // fdt addr + // Use a temporary stack + adrp x0, temp_stack + mov sp, x0 + mov x0, x9 // fdt addr - bl mmu_configure + bl mmu_configure - // Readjust the stack - ldr x0, =__stack_top - mov sp, x0 + // Readjust the stack + ldr x0, =__stack_top + mov sp, x0 - // Keep executing in the kernel space + // Keep executing in the kernel space - // Store the virtual address which will be used to continue - // the execution after the MMU enabled. - ldr x0, .LCvirt_entry + // Store the virtual address which will be used to continue + // the execution after the MMU enabled. + ldr x0, .LCvirt_entry - blr x0 + blr x0 el2_setup: + msr sctlr_el1, xzr - /* Populate ID registers. */ - mrs x0, midr_el1 - mrs x1, mpidr_el1 - msr vpidr_el2, x0 - msr vmpidr_el2, x1 - - msr sctlr_el1, xzr + /* Populate ID registers. */ + mrs x0, midr_el1 + mrs x1, mpidr_el1 + msr vpidr_el2, x0 + msr vmpidr_el2, x1 - /* Hyp configuration. */ - and x1, x1, #3 + /* Hyp configuration. */ + and x1, x1, #3 #ifdef CONFIG_SOO - cmp x1, #AGENCY_RT_CPU - bgt ME + cmp x1, #AGENCY_RT_CPU + bgt guest #endif /* CONFIG_SOO */ agency: - ldr x0, =HCR_AGENCY_FLAGS + ldr x0, =HCR_AGENCY_FLAGS b 99f -ME: - ldr x0, =HCR_ME_FLAGS +guest: + ldr x0, =HCR_ME_FLAGS 99: msr hcr_el2, x0 @@ -252,16 +230,16 @@ ME: msr cntvoff_el2, xzr // Clear virtual offset - /* - * Ensure that any exceptions encountered at EL2 - * are handled using the EL2 stack pointer, rather - * than SP_EL0. - */ - msr spsel, #1 + /* + * Ensure that any exceptions encountered at EL2 + * are handled using the EL2 stack pointer, rather + * than SP_EL0. + */ + msr spsel, #1 ret -#else /* CONFIG_ARM64VT */ +#else /* CONFIG_AVZ */ setup_mmu: @@ -269,9 +247,7 @@ setup_mmu: adrp x0, temp_stack mov sp, x0 -#ifndef CONFIG_SO3VIRT bl mmu_configure -#endif // Readjust the stack ldr x0, =__stack_top @@ -306,7 +282,7 @@ el2_setup: isb ret -1: ldr x0, =(SCTLR_EL2_RES1 | ENDIAN_SET_EL2) +1: ldr x0, =(SCTLR_EL2_RES1 | ENDIAN_SET_EL2) msr sctlr_el2, x0 /* @@ -315,12 +291,12 @@ el2_setup: * kernel is intended to run at EL2. */ mrs x2, id_aa64mmfr1_el1 - ubfx x2, x2, #ID_AA64MMFR1_VHE_SHIFT, #4 + ubfx x2, x2, #ID_AA64MMFR1_VHE_SHIFT, #4 /* Hyp configuration. */ - ldr x0, =HCR_HOST_NVHE_FLAGS + ldr x0, =HCR_HOST_NVHE_FLAGS cbz x2, set_hcr - ldr x0, =HCR_HOST_VHE_FLAGS + ldr x0, =HCR_HOST_VHE_FLAGS set_hcr: msr hcr_el2, x0 @@ -439,11 +415,11 @@ install_el2_stub: msr_s SYS_ZCR_EL2, x1 // length for EL1. /* Hypervisor stub */ -7: adrp x0, __hyp_stub_vectors +7: adrp x0, __hyp_stub_vectors msr vbar_el2, x0 /* spsr */ - mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT | PSR_MODE_EL1h) + mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT | PSR_MODE_EL1t) msr spsr_el2, x0 msr elr_el2, lr mov w0, #BOOT_CPU_MODE_EL2 // This CPU booted in EL2 @@ -454,7 +430,7 @@ install_el2_stub: nop nop -#endif /* !CONFIG_ARM64VT */ +#endif /* !CONFIG_AVZ */ #ifdef CONFIG_SMP @@ -465,23 +441,16 @@ __secondary_kernel_main: // Enable the interrupt adrp x0, __vectors // Virtual address as required -#ifdef CONFIG_ARM64VT - msr vbar_el2, x0 -#else - msr vbar_el1, x0 -#endif /* !CONFIG_ARM64VT */ - -#endif /* !CONFIG_SOO */ - - // C main entry point - #ifdef CONFIG_AVZ + msr vbar_el2, x0 - ldr x19, .LC_secondary_final_start_kernel - blr x19 - + ldr x19, .LC_secondary_final_start_kernel + blr x19 #else + msr vbar_el1, x0 b kernel_start +#endif /* !CONFIG_AVZ */ + #endif nop @@ -502,8 +471,8 @@ ENTRY(secondary_startup) mov x0, #3 << 20 msr cpacr_el1, x0 - // Up to here, a stack should be initialized - adr x4, __secondary_data + // Up to here, a stack should be initialized + adr x4, __secondary_data ldr x5, [x4] ldr x19, [x4, #8] @@ -534,21 +503,18 @@ ENTRY(secondary_startup) // Initialize the vector table // The vector table address is the virtual address -#ifndef CONFIG_SO3VIRT - // Initialize the vector table adrp x0, __vectors -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ msr vbar_el2, x0 #else msr vbar_el1, x0 -#endif /* !CONFIG_ARM64VT */ +#endif /* !CONFIG_AVZ */ -#endif /* !CONFIG_SO3VIRT */ // Store the virtual address which will be used to continue - // execution after the MMU enabled. + // execution after the MMU enabled. ldr x19, .LC_virt_secondary_entry blr x19 diff --git a/so3/arch/arm64/hypercalls.S b/so3/arch/arm64/hypercalls.S index 11cffeaba2..fb2617ea8d 100644 --- a/so3/arch/arm64/hypercalls.S +++ b/so3/arch/arm64/hypercalls.S @@ -23,254 +23,17 @@ #include -.extern hypervisor_stack - -.align 5 -ENTRY(ret_from_hypercall) - - disable_irq - - /* Store the x0 value in the stack frame of G-stack */ - curdom x8, x11 - ldr x9, [x8, #OFFSET_G_SP] - str x0, [x9, #OFFSET_X0] - - bl do_softirq - - curdom x10, x11 - ldr x11, [x10, #OFFSET_AVZ_SHARED] - - // If the softirq handling leads to trigger an interrupt in the guest, - // it will be processed by do_evtchn_do_upcall. The way how to - // process an interrupt with potentially IRQs off is under the - // responsibility of the guest - - mov x8, #0 - - // are some IRQs pending? - ldrb w12, [x11, #OFFSET_EVTCHN_UPCALL_PENDING] - tst w12, #0xff - - b.eq restore - - // Will go ahead with evtchn_do_upcall in the domain - mov x8, #1 - -restore: - disable_irq - - current_cpu x11 - -#ifndef CONFIG_ARM64VT - // Setting pseudo_usr_mode / x0, x1 re-assigned right after - ldr x0, .LCpseudo_usr_mode - mov x1, #1 - str x1, [x0, x11, lsl #3] -#endif - - // Restore saved registers - - ldr x0, .LChypervisor_stack // running SVC hypervisor stack - mov x10, sp - str x10, [x0, x11, lsl #3] - - curdom x10, x11 - - // Get guest stack - ldr x11, [x10, #OFFSET_G_SP] - mov sp, x11 - - // Store the evtchn pending state to give - // the domain the possiblity to call evtchn_do_upcall() - str x8, [sp, #OFFSET_X8] - - ldr lr, [sp, #OFFSET_PC] - - // PSTATE contains the daif state at the entry in - // the hypervisor. - - ldr x9, [sp, #OFFSET_PSTATE] // Get PSTATE - - cmp x8, #0 - b.ne save_pstate - -restore_pstate: - - // Restore the IRQ status before the hypercall - msr daif, x9 - b cont - -save_pstate: - str x9, [sp, #OFFSET_X9] - -cont: - - ldp x0, x1, [sp, #OFFSET_X0] - ldp x2, x3, [sp, #OFFSET_X2] - ldp x4, x5, [sp, #OFFSET_X4] - ldp x6, x7, [sp, #OFFSET_X6] - ldp x8, x9, [sp, #OFFSET_X8] - ldp x10, x11, [sp, #OFFSET_X10] - ldp x12, x13, [sp, #OFFSET_X12] - ldp x14, x15, [sp, #OFFSET_X14] - ldp x16, x17, [sp, #OFFSET_X16] - ldp x18, x19, [sp, #OFFSET_X18] - ldp x20, x21, [sp, #OFFSET_X20] - ldp x22, x23, [sp, #OFFSET_X22] - ldp x24, x25, [sp, #OFFSET_X24] - ldp x26, x27, [sp, #OFFSET_X26] - ldp x28, x29, [sp, #OFFSET_X28] - - add sp, sp, #S_FRAME_SIZE - - ret - .align 5 -// Hypercall generated by the domain -// Always issued from a guest trampoline or from avz directly. -// Hence, we preserve the daif state at the entry in order -// to reconfigure correctly at the hypercall exit. - -ENTRY(hypercall_entry) - - // According to AArch64 ABI, x8 is preserved by the caller if used. - mrs x8, daif - - disable_irq - - sub sp, sp, #S_FRAME_SIZE - - str x8, [sp, #OFFSET_PSTATE] - - stp x0, x1, [sp, #OFFSET_X0] - stp x2, x3, [sp, #OFFSET_X2] - stp x4, x5, [sp, #OFFSET_X4] - stp x6, x7, [sp, #OFFSET_X6] - stp x8, x9, [sp, #OFFSET_X8] - stp x10, x11, [sp, #OFFSET_X10] - stp x12, x13, [sp, #OFFSET_X12] - stp x14, x15, [sp, #OFFSET_X14] - stp x16, x17, [sp, #OFFSET_X16] - stp x18, x19, [sp, #OFFSET_X18] - stp x20, x21, [sp, #OFFSET_X20] - stp x22, x23, [sp, #OFFSET_X22] - stp x24, x25, [sp, #OFFSET_X24] - stp x26, x27, [sp, #OFFSET_X26] - stp x28, x29, [sp, #OFFSET_X28] - - mov x22, lr - - str lr, [sp, #OFFSET_LR] - str x22, [sp, #OFFSET_PC] - - current_cpu x10 - -#ifndef CONFIG_ARM64VT - - // Check if we are coming from avz or the guest - ldr x8, .LCpseudo_usr_mode - - ldr x9, [x8, x10, lsl #3] - cmp x9, #0 -#endif - - b.eq __do_hypercall_from_avz - - // readjust stack for future restore - add x8, sp, #S_FRAME_SIZE - - str x8, [sp, #OFFSET_SP] - - str lr, [sp, #OFFSET_LR] - -#ifndef CONFIG_ARM64VT - ldr x8, .LCpseudo_usr_mode - mov x9, #0 - str x9, [x8, x10, lsl #3] -#endif - - mov x8, sp - ldr x9, .LChypervisor_stack // Get the running hypervisor EL1 stack - ldr x11, [x9, x10, lsl #3] - mov sp, x11 - - curdom x9, x11 - str x8, [x9, #OFFSET_G_SP] - - -process_hypercalls: - - adr lr, ret_from_hypercall - adr x11, hypercall_table - add x11, x11, x7, lsl #3 - ldr x10, [x11] - - br x10 // Perform the hypercall - - // x0 has the return value of the hypercall - -// This is the entry point in case an hypercall is issued from the hypervisor -__do_hypercall_from_avz: - - adr lr, __end_hypercall_from_avz - - adr x11, hypercall_table - add x11, x11, x7, lsl #3 - - ldr x10, [x11] - - br x10 // Perform the hypercall - - // x0 has the return value of the hypercall - -// Fast return path to the caller (in avz) -__end_hypercall_from_avz: - - ldr lr, [sp, #OFFSET_PC] - - ldr x1, [sp, #OFFSET_X1] - ldp x2, x3, [sp, #OFFSET_X2] - ldp x4, x5, [sp, #OFFSET_X4] - ldp x6, x7, [sp, #OFFSET_X6] - ldp x8, x9, [sp, #OFFSET_X8] - ldp x10, x11, [sp, #OFFSET_X10] - ldp x12, x13, [sp, #OFFSET_X12] - ldp x14, x15, [sp, #OFFSET_X14] - ldp x16, x17, [sp, #OFFSET_X16] - ldp x18, x19, [sp, #OFFSET_X18] - ldp x20, x21, [sp, #OFFSET_X20] - ldp x22, x23, [sp, #OFFSET_X22] - ldp x24, x25, [sp, #OFFSET_X24] - ldp x26, x27, [sp, #OFFSET_X26] - ldp x28, x29, [sp, #OFFSET_X28] - - add sp, sp, #S_FRAME_SIZE - - ret - /* * hypercall_table */ .type hypercall_table, #object -ENTRY(hypercall_table) - -__hypercall_entry: - .quad do_event_channel_op - .quad do_console_io - .quad do_physdev_op - .quad do_sched_op - .quad do_domctl - .quad do_soo_hypercall +ENTRY(__avz_hypercall) -__hypercall_end: - -#ifndef CONFIG_ARM64VT -.LCpseudo_usr_mode: - .quad pseudo_usr_mode -#endif + hvc #0 + ret -.LChypervisor_stack: - .quad hypervisor_stack + diff --git a/so3/arch/arm64/include/asm/bitops.h b/so3/arch/arm64/include/asm/bitops.h index f2ee6b8a9e..50df79d50f 100644 --- a/so3/arch/arm64/include/asm/bitops.h +++ b/so3/arch/arm64/include/asm/bitops.h @@ -28,6 +28,14 @@ #define __L16(_x) (((_x) & 0x0000ff00) ? ( 8 + __L8( (_x)>> 8)) : __L8( _x)) #define LOG_2(_x) (((_x) & 0xffff0000) ? (16 + __L16((_x)>>16)) : __L16(_x)) +/* create 64-bit mask with all bits in [last:first] set */ +#define BIT_MASK(last, first) \ + ((0xffffffffffffffffULL >> (64 - ((last) + 1 - (first)))) << (first)) + +/* extract the field value at [last:first] from an input of up to 64 bits */ +#define GET_FIELD(value, last, first) \ + (((value) & BIT_MASK((last), (first))) >> (first)) + #ifndef __ASSEMBLY__ #define smp_mb__before_clear_bit() mb() @@ -46,8 +54,6 @@ static inline int test_bit(int nr, const volatile unsigned long *addr) return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); } - - /* * These functions are the basis of our bit ops. * @@ -60,7 +66,7 @@ static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long * p += bit >> 5; - local_irq_save(flags); + flags = local_irq_save(); *p |= mask; local_irq_restore(flags); } @@ -72,7 +78,7 @@ static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long p += bit >> 5; - local_irq_save(flags); + flags = local_irq_save(); *p &= ~mask; local_irq_restore(flags); } @@ -84,7 +90,7 @@ static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned lon p += bit >> 5; - local_irq_save(flags); + flags = local_irq_save(); *p ^= mask; local_irq_restore(flags); } @@ -98,7 +104,7 @@ ____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p) p += bit >> 5; - local_irq_save(flags); + flags = local_irq_save(); res = *p; *p = res | mask; local_irq_restore(flags); @@ -115,7 +121,7 @@ ____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p) p += bit >> 5; - local_irq_save(flags); + flags = local_irq_save(); res = *p; *p = res & ~mask; local_irq_restore(flags); @@ -132,7 +138,7 @@ ____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p) p += bit >> 5; - local_irq_save(flags); + flags = local_irq_save(); res = *p; *p = res ^ mask; local_irq_restore(flags); @@ -200,6 +206,22 @@ extern int _test_and_change_bit_le(int nr, volatile unsigned long * p); #define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p) #define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p) +/* Count leading zeroes */ +static inline unsigned long clz(unsigned long word) { + unsigned long val; + + asm volatile("clz %0, %1" : "=r"(val) : "r"(word)); + return val; +} + +/* Returns the position of the least significant 1, MSB=31, LSB=0*/ +static inline unsigned long ffsl(unsigned long word) { + if (!word) + return 0; + asm volatile("rbit %0, %0" : "+r"(word)); + return clz(word); +} + #endif /*__ASSEMBLY__ */ #endif /* ASM_BITOPS_H */ diff --git a/so3/arch/arm64/include/asm/mmu.h b/so3/arch/arm64/include/asm/mmu.h index 4dec6c8492..74b0023a67 100644 --- a/so3/arch/arm64/include/asm/mmu.h +++ b/so3/arch/arm64/include/asm/mmu.h @@ -60,31 +60,22 @@ #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ + +/* Start of the container memory base */ +#define ME_BASE UL(0x0000200000000000) +#define ME_ID_SHIFT 32 #ifdef CONFIG_VA_BITS_48 #define AGENCY_VOFFSET UL(0x0000110000000000) -#define ME_VOFFSET UL(0x0000200100000000) + #elif CONFIG_VA_BITS_39 #define AGENCY_VOFFSET UL(0xffffffc010000000) -#define ME_VOFFSET UL(0xffffffc000000000) #else #error "Wrong VA_BITS configuration." #endif -#else /* CONFIG_ARM64VT */ - -#ifdef CONFIG_VA_BITS_48 -#define AGENCY_VOFFSET UL(0xffff800010000000) -#define ME_VOFFSET UL(0xffff800010000000) -#elif CONFIG_VA_BITS_39 -#define AGENCY_VOFFSET UL(0xffffffc010000000) -#define ME_VOFFSET UL(0xffffffc000000000) -#else -#error "Wrong VA_BITS configuration." -#endif - -#endif /* !CONFIG_ARM64VT */ +#endif /* CONFIG_AVZ */ /* Order of size which makes sense in block mapping */ #define BLOCK_256G_OFFSET (SZ_256G - 1) @@ -524,11 +515,6 @@ typedef enum { S2 } mmu_stage_t; -#define mrs(spr) ({ u64 rval; asm volatile(\ - "mrs %0," #spr :"=r"(rval)); rval; }) - -#define msr(spr, val) asm volatile("msr " #spr ", %0" ::"r"(val)); - /* VA to PA Address Translation */ #define VA2PA_STAGE1 "s1" diff --git a/so3/arch/arm64/include/asm/processor.h b/so3/arch/arm64/include/asm/processor.h index 9c6f2d66e1..d6e560ee74 100644 --- a/so3/arch/arm64/include/asm/processor.h +++ b/so3/arch/arm64/include/asm/processor.h @@ -161,6 +161,13 @@ #define ESR_ELx_EC_MASK (UL(0x3F) << ESR_ELx_EC_SHIFT) #define ESR_ELx_EC(esr) (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT) +/* exception level in SPSR_ELx */ +#define SPSR_EL(spsr) (((spsr) & 0xc) >> 2) +/* instruction length */ +#define ESR_IL(esr) GET_FIELD((esr), 25, 25) +/* Instruction specific syndrome */ +#define ESR_ISS(esr) GET_FIELD((esr), 24, 0) + /* * PSR bits */ @@ -865,7 +872,7 @@ /* The stack must be 16-byte aligned */ -#define S_FRAME_SIZE (8 * 34) +#define S_FRAME_SIZE (8 * 36) #ifdef __ASSEMBLY__ @@ -943,8 +950,7 @@ #else -static inline int cpu_mode(void) -{ +static inline int cpu_mode(void) { uint32_t el; asm volatile( @@ -1024,6 +1030,27 @@ static inline int cpu_mode(void) asm volatile(__msr_s(r, "%x0") : : "rZ" (__val)); \ } while (0) +#define mrs(__spr) \ + ({ \ + u64 __v; \ + asm volatile("mrs %0," stringify(__spr) : "=r"(__v)); \ + __v; \ + }) + +#define msr(__spr, __v) \ + do { \ + asm volatile("msr " stringify(__spr) ", %0" : : "r"(__v)); \ + } while (0) + +#define msr_sync(__spr, __v) \ + do { \ + asm volatile("msr " stringify(__spr) ", %0\n\t" \ + "dsb sy\n\t" \ + "isb\n\t" \ + : \ + : "r"(__v)); \ + } while (0) + /* * Modify bits in a sysreg. Bits in the clear mask are zeroed, then bits in the * set mask are set. Other bits are left as-is. @@ -1035,6 +1062,12 @@ static inline int cpu_mode(void) write_sysreg(__scs_new, sysreg); \ } while (0) +enum trap_return { + TRAP_HANDLED = 1, + TRAP_UNHANDLED = 0, + TRAP_FORBIDDEN = -1, +}; + /* * PMR values used to mask/unmask interrupts. * @@ -1053,8 +1086,11 @@ static inline int cpu_mode(void) #define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80) #define GIC_PRIO_PSR_I_SET (1 << 4) -typedef struct cpu_regs { - u64 x0; +/* The structure is packed since we may refer as a linear space + * addressed by index + */ +typedef struct __attribute__((packed, aligned(8))) cpu_regs { + u64 x0; u64 x1; u64 x2; u64 x3; @@ -1088,8 +1124,32 @@ typedef struct cpu_regs { u64 sp; u64 pc; u64 pstate; + + /* is used to keep track of the sp at the higher EL - used for signal-like handler */ + u64 sp_usr; + u64 padding; } cpu_regs_t; +#ifdef CONFIG_AVZ + +/* Fields related to the underlying CPU */ +typedef struct vcpu { + cpu_regs_t regs; /* All CPU registers */ + + /* System registers at EL1 */ + u64 sctlr_el1; + u64 vbar_el1; + u64 ttbr0_el1; + u64 ttbr1_el1; + u64 tcr_el1; + u64 mair_el1; + +} vcpu_t; + +void resume_to_guest(void); + +#endif /* CONFIG_AVZ */ + static inline int smp_processor_id(void) { int cpu; @@ -1191,7 +1251,6 @@ typedef struct cpu_sys_regs { void cpu_on(unsigned long cpuid, addr_t entry_point); -struct vcpu_guest_context; struct domain; void __switch_domain_to(struct domain *prev, struct domain *next); @@ -1206,7 +1265,7 @@ void pre_ret_to_el1_with_spin(addr_t release_addr); struct tcb; void __switch_to(struct tcb *prev, struct tcb *next); -int trap_handle(cpu_regs_t *regs); +void trap_handle(cpu_regs_t *regs); void cpu_do_idle(void); diff --git a/so3/arch/arm64/include/asm/smccc.h b/so3/arch/arm64/include/asm/smccc.h index f7e69b688b..9aa0cfb9aa 100644 --- a/so3/arch/arm64/include/asm/smccc.h +++ b/so3/arch/arm64/include/asm/smccc.h @@ -5,17 +5,7 @@ #ifndef SMCCC_H #define SMCCC_H -#ifdef __ASSEMBLY__ -#define _AC(X,Y) X -#define _AT(T,X) X -#else -#define __AC(X,Y) (X##Y) -#define _AC(X,Y) __AC(X,Y) -#define _AT(T,X) ((T)(X)) -#endif - -#define _UL(x) (_AC(x, UL)) -#define _ULL(x) (_AC(x, ULL)) +#include #define _BITUL(x) (_UL(1) << (x)) #define _BITULL(x) (_ULL(1) << (x)) diff --git a/so3/arch/arm64/include/asm/virt.h b/so3/arch/arm64/include/asm/virt.h index fdc1ae51f6..563a35bdf7 100644 --- a/so3/arch/arm64/include/asm/virt.h +++ b/so3/arch/arm64/include/asm/virt.h @@ -21,6 +21,10 @@ #include +#ifndef __ASSEMBLY__ +#include +#endif + /* * The arm64 hcall implementation uses x0 to specify the hcall * number. A value less than HVC_STUB_HCALL_NR indicates a special @@ -85,49 +89,92 @@ #define CPTR_EL2_RES1 0x000032ff /* known RES1 bits in CPTR_EL2 */ #define CPTR_EL2_DEFAULT CPTR_EL2_RES1 -/* Hyp Configuration Register (HCR) bits */ -#define HCR_FWB (UL(1) << 46) -#define HCR_API (UL(1) << 41) -#define HCR_APK (UL(1) << 40) -#define HCR_TEA (UL(1) << 37) -#define HCR_TERR (UL(1) << 36) -#define HCR_TLOR (UL(1) << 35) -#define HCR_E2H (UL(1) << 34) -#define HCR_ID (UL(1) << 33) -#define HCR_CD (UL(1) << 32) -#define HCR_RW_SHIFT 31 -#define HCR_RW (UL(1) << HCR_RW_SHIFT) -#define HCR_TRVM (UL(1) << 30) -#define HCR_HCD (UL(1) << 29) -#define HCR_TDZ (UL(1) << 28) -#define HCR_TGE (UL(1) << 27) -#define HCR_TVM (UL(1) << 26) -#define HCR_TTLB (UL(1) << 25) -#define HCR_TPU (UL(1) << 24) -#define HCR_TPC (UL(1) << 23) -#define HCR_TSW (UL(1) << 22) -#define HCR_TAC (UL(1) << 21) -#define HCR_TIDCP (UL(1) << 20) -#define HCR_TSC (UL(1) << 19) -#define HCR_TID3 (UL(1) << 18) -#define HCR_TID2 (UL(1) << 17) -#define HCR_TID1 (UL(1) << 16) -#define HCR_TID0 (UL(1) << 15) -#define HCR_TWE (UL(1) << 14) -#define HCR_TWI (UL(1) << 13) -#define HCR_DC (UL(1) << 12) -#define HCR_BSU (3 << 10) -#define HCR_BSU_IS (UL(1) << 10) -#define HCR_FB (UL(1) << 9) -#define HCR_VSE (UL(1) << 8) -#define HCR_VI (UL(1) << 7) -#define HCR_VF (UL(1) << 6) -#define HCR_AMO (UL(1) << 5) -#define HCR_IMO (UL(1) << 4) -#define HCR_FMO (UL(1) << 3) -#define HCR_PTW (UL(1) << 2) -#define HCR_SWIO (UL(1) << 1) -#define HCR_VM (UL(1) << 0) +//* HCR_EL2 */ +#define HCR_INITVAL 0x000000000 +#define HCR_FWB_MASK _AC(0x400000000000, UL) +#define HCR_FWB_SHIFT 46 +#define HCR_API_MASK _AC(0x20000000000, UL) +#define HCR_API_SHIFT 41 +#define HCR_APK_MASK _AC(0x10000000000, UL) +#define HCR_APK_SHIFT 40 +#define HCR_TEA_MASK _AC(0x2000000000, UL) +#define HCR_TEA_SHIFT 37 +#define HCR_TERR_MASK _AC(0x1000000000, UL) +#define HCR_TERR_SHIFT 36 +#define HCR_TLOR_MASK _AC(0x800000000, UL) +#define HCR_TLOR_SHIFT 35 +#define HCR_E2H_MASK _AC(0x400000000, UL) +#define HCR_E2H_SHIFT 34 +#define HCR_ID_MASK _AC(0x200000000, UL) +#define HCR_ID_SHIFT 33 +#define HCR_CD_MASK _AC(0x100000000, UL) +#define HCR_CD_SHIFT 32 +#define HCR_RW_MASK 0x080000000 +#define HCR_RW_SHIFT 31 +#define HCR_TRVM_MASK 0x040000000 +#define HCR_TRVM_SHIFT 30 +#define HCR_HCD_MASK 0x020000000 +#define HCR_HCD_SHIFT 29 +#define HCR_TDZ_MASK 0x010000000 +#define HCR_TDZ_SHIFT 28 +#define HCR_TGE_MASK 0x008000000 +#define HCR_TGE_SHIFT 27 +#define HCR_TVM_MASK 0x004000000 +#define HCR_TVM_SHIFT 26 +#define HCR_TTLB_MASK 0x002000000 +#define HCR_TTLB_SHIFT 25 +#define HCR_TPU_MASK 0x001000000 +#define HCR_TPU_SHIFT 24 +#define HCR_TPC_MASK 0x000800000 +#define HCR_TPC_SHIFT 23 +#define HCR_TSW_MASK 0x000400000 +#define HCR_TSW_SHIFT 22 +#define HCR_TACR_MASK 0x000200000 +#define HCR_TACR_SHIFT 21 +#define HCR_TIDCP_MASK 0x000100000 +#define HCR_TIDCP_SHIFT 20 +#define HCR_TSC_MASK 0x000080000 +#define HCR_TSC_SHIFT 19 +#define HCR_TID3_MASK 0x000040000 +#define HCR_TID3_SHIFT 18 +#define HCR_TID2_MASK 0x000020000 +#define HCR_TID2_SHIFT 17 +#define HCR_TID1_MASK 0x000010000 +#define HCR_TID1_SHIFT 16 +#define HCR_TID0_MASK 0x000008000 +#define HCR_TID0_SHIFT 15 +#define HCR_TWE_MASK 0x000004000 +#define HCR_TWE_SHIFT 14 +#define HCR_TWI_MASK 0x000002000 +#define HCR_TWI_SHIFT 13 +#define HCR_DC_MASK 0x000001000 +#define HCR_DC_SHIFT 12 +#define HCR_BSU_MASK 0x000000C00 +#define HCR_BSU_SHIFT 10 +#define HCR_FB_MASK 0x000000200 +#define HCR_FB_SHIFT 9 +#define HCR_VSE_MASK 0x000000100 +#define HCR_VSE_SHIFT 8 +#define HCR_VI_MASK 0x000000080 +#define HCR_VI_SHIFT 7 +#define HCR_VF_MASK 0x000000040 +#define HCR_VF_SHIFT 6 +#define HCR_AMO_MASK 0x000000020 +#define HCR_AMO_SHIFT 5 +#define HCR_IMO_MASK 0x000000010 +#define HCR_IMO_SHIFT 4 +#define HCR_FMO_MASK 0x000000008 +#define HCR_FMO_SHIFT 3 +#define HCR_PTW_MASK 0x000000004 +#define HCR_PTW_SHIFT 2 +#define HCR_SWIO_MASK 0x000000002 +#define HCR_SWIO_SHIFT 1 +#define HCR_VM_MASK 0x000000001 +#define HCR_VM_SHIFT 0 +#define HCR_DEFAULT_BITS (HCR_AMO_MASK | \ + HCR_IMO_MASK | \ + HCR_FMO_MASK | \ + HCR_VM_MASK) /* * The bits we set in HCR: @@ -147,69 +194,19 @@ * FMO: Override CPSR.F and enable signaling with VF * SWIO: Turn set/way invalidates into set/way clean+invalidate */ -#define HCR_AGENCY_FLAGS (HCR_VM | HCR_API | HCR_APK | HCR_RW) +#define HCR_AGENCY_FLAGS (HCR_VM_MASK | HCR_API_MASK | HCR_APK_MASK | HCR_RW_MASK) -#define HCR_ME_FLAGS (HCR_VM | HCR_API | HCR_APK \ - | HCR_AMO | HCR_RW \ - | HCR_FMO | HCR_IMO) +#define HCR_ME_FLAGS (HCR_VM_MASK | HCR_API_MASK | HCR_APK_MASK \ + | HCR_AMO_MASK | HCR_RW_MASK \ + | HCR_FMO_MASK | HCR_IMO_MASK) #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \ HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \ HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \ HCR_FMO | HCR_IMO) -#define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF) -#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK) -#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) - - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -/* - * __boot_cpu_mode records what mode CPUs were booted in. - * A correctly-implemented bootloader must start all CPUs in the same mode: - * In this case, both 32bit halves of __boot_cpu_mode will contain the - * same value (either 0 if booted in EL1, BOOT_CPU_MODE_EL2 if booted in EL2). - * - * Should the bootloader fail to do this, the two values will be different. - * This allows the kernel to flag an error when the secondaries have come up. - */ -extern u32 __boot_cpu_mode[2]; - -void __hyp_set_vectors(phys_addr_t phys_vector_base); -void __hyp_reset_vectors(void); - -/* Reports the availability of HYP mode */ -static inline bool is_hyp_mode_available(void) -{ - return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 && - __boot_cpu_mode[1] == BOOT_CPU_MODE_EL2); -} - -/* Check if the bootloader has booted CPUs in different modes */ -static inline bool is_hyp_mode_mismatched(void) -{ - return __boot_cpu_mode[0] != __boot_cpu_mode[1]; -} - -static inline bool is_kernel_in_hyp_mode(void) -{ - return read_sysreg(CurrentEL) == CurrentEL_EL2; -} - -static inline bool has_vhe(void) -{ - if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN)) - return true; - - return false; -} - -#endif /* __ASSEMBLY__ */ +#define HCR_VIRT_EXCP_MASK (HCR_VSE_MASK | HCR_VI_MASK | HCR_VF_MASK) +#define HCR_HOST_NVHE_FLAGS (HCR_RW_MASK | HCR_API_MASK | HCR_APK_MASK) +#define HCR_HOST_VHE_FLAGS (HCR_RW_MASK | HCR_TGE_MASK | HCR_E2H_MASK) #endif /* ! VIRT_H */ diff --git a/so3/arch/arm64/migration.c b/so3/arch/arm64/migration.c deleted file mode 100644 index c79330ef38..0000000000 --- a/so3/arch/arm64/migration.c +++ /dev/null @@ -1,112 +0,0 @@ - -/* - * Copyright (C) 2014-2022 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include - -#include - -#include -#include -#include - -/** - * Adjust the output address contained in a pte at any level - * - * @param pte - * @param addr_mask - */ -static void adjust_pte(uint64_t *pte, uint64_t addr_mask) { - - uint64_t old_pfn; - - old_pfn = phys_to_pfn(*pte & addr_mask); - *pte = (*pte & ~addr_mask) | (pfn_to_phys(old_pfn + pfn_offset) & addr_mask); -} - -/** - * fix_page_table_ME - * Fix the ME system page table to fit new physical address space. - * - * - * @param ME_slotID slotID hosting the ME - */ -void fix_kernel_boot_page_table_ME(unsigned int ME_slotID) -{ - struct domain *me = domains[ME_slotID]; - uint64_t *pgtable_ME; - uint64_t *l0pte, *l1pte, *l2pte, *l3pte; - int l0, l1, l2, l3; - - /* Locate the system ME (L0) page table */ - me->avz_shared->pagetable_paddr = pfn_to_phys(phys_to_pfn(me->avz_shared->pagetable_paddr) + pfn_offset); - - pgtable_ME = (uint64_t *) __lva(me->avz_shared->pagetable_paddr); - - /* Walk through L0 page table */ - for (l0 = l0pte_index(ME_VOFFSET); l0 < TTB_L0_ENTRIES; l0++) { - - l0pte = pgtable_ME + l0; - if (!*l0pte) - continue; - - adjust_pte(l0pte, TTB_L0_TABLE_ADDR_MASK); - - /* Walk through L1 page table */ - for (l1 = 0; l1 < TTB_L1_ENTRIES; l1++) { - - l1pte = ((uint64_t *) __lva(*l0pte & TTB_L0_TABLE_ADDR_MASK)) + l1; - - if (!*l1pte) - continue; - - if (pte_type(l1pte) == PTE_TYPE_BLOCK) - adjust_pte(l1pte, TTB_L1_BLOCK_ADDR_MASK); - else { - adjust_pte(l1pte, TTB_L1_TABLE_ADDR_MASK); - - for (l2 = 0; l2 < TTB_L2_ENTRIES; l2++) { - - l2pte = ((uint64_t *) __lva(*l1pte & TTB_L1_TABLE_ADDR_MASK)) + l2; - - if (!*l2pte) - continue; - - if (pte_type(l2pte) == PTE_TYPE_BLOCK) - adjust_pte(l2pte, TTB_L2_BLOCK_ADDR_MASK); - else { - adjust_pte(l2pte, TTB_L2_TABLE_ADDR_MASK); - - for (l3 = 0; l3 < TTB_L3_ENTRIES; l3++) { - l3pte = ((uint64_t *) __lva(*l2pte & TTB_L2_TABLE_ADDR_MASK)) + l3; - - if (!*l3pte) - continue; - - adjust_pte(l3pte, TTB_L3_PAGE_ADDR_MASK); - } - } - } - } - } - } - - /* Fixup the hypervisor */ - *l0pte_offset(pgtable_ME, CONFIG_KERNEL_VADDR) = *l0pte_offset(__sys_root_pgtable, CONFIG_KERNEL_VADDR); -} diff --git a/so3/arch/arm64/mmio.c b/so3/arch/arm64/mmio.c new file mode 100644 index 0000000000..4d80d965fa --- /dev/null +++ b/so3/arch/arm64/mmio.c @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2024 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 Generd2aal 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#include + +#include + +/* + * These definitions are heavly borrowed from jailhouse hypervisor + */ + +void mmio_perform_access(void *base, struct mmio_access *mmio) { + void *addr = base + mmio->address; + + if (mmio->is_write) + switch (mmio->size) { + case 1: + iowrite8(addr, mmio->value); + break; + case 2: + iowrite16(addr, mmio->value); + break; + case 4: + iowrite32(addr, mmio->value); + break; +#if BITS_PER_LONG == 64 + case 8: + iowrite64(addr, mmio->value); + break; +#endif + } + else + switch (mmio->size) { + case 1: + mmio->value = ioread8(addr); + break; + case 2: + mmio->value = ioread16(addr); + break; + case 4: + mmio->value = ioread32(addr); + break; +#if BITS_PER_LONG == 64 + case 8: + mmio->value = ioread64(addr); + break; +#endif + } +} + +/** + * Dispatch MMIO access of a CPU. + * @param mmio MMIO access description. @a mmio->value will receive the + * result of a successful read access. All @a mmio fields + * may have been modified on return. + * + * @return MMIO_HANDLED on success, MMIO_UNHANDLED if no region is registered + * for the access address and size, or MMIO_ERROR if an access error was detected. + * + */ +enum mmio_result mmio_handle_access(struct mmio_access *mmio) +{ + /* Currently, only GIC access is handled via a data abort exception */ + mmio->address -= (addr_t) gic->gicd_paddr; + + return gic_handle_dist_access(mmio); +} + +/* AARCH64_TODO: we can use SXTB, SXTH, SXTW */ +/* Extend the value of 'size' bits to a signed long */ +static inline unsigned long sign_extend(unsigned long val, unsigned int size) { + unsigned long mask = 1UL << (size - 1); + + return (val ^ mask) - mask; +} + +int mmio_dabt_decode(cpu_regs_t *regs, unsigned long esr) { + enum mmio_result mmio_result; + struct mmio_access mmio; + unsigned long hpfar; + unsigned long hdfar; + u64 *__regs = (u64 *) regs; + + /* Decode the syndrome fields */ + u32 iss = ESR_ISS(esr); + u32 isv = iss >> 24; + u32 sas = iss >> 22 & 0x3; + u32 sse = iss >> 21 & 0x1; + + /* Syndrom Register Transfer */ + u32 srt = iss >> 16 & 0x1f; + + u32 ea = iss >> 9 & 0x1; + u32 cm = iss >> 8 & 0x1; + u32 s1ptw = iss >> 7 & 0x1; + u32 is_write = iss >> 6 & 0x1; + u32 size = 1 << sas; + + hpfar = read_sysreg(hpfar_el2); + hdfar = read_sysreg(far_el2); + + mmio.address = hpfar << 8; + mmio.address |= hdfar & 0xfff; + /* + * Invalid instruction syndrome means multiple access or writeback, + * there is nothing we can do. + */ + if (!isv) + goto error_unhandled; + + /* Re-inject abort during page walk, cache maintenance or external */ + if (s1ptw || ea || cm) { + panic("Not handled\n"); + } + + if (is_write) { + /* Load the value to write from the src register */ + mmio.value = (srt == 31) ? 0 : __regs[srt]; + if (sse && size < sizeof(unsigned long)) + mmio.value = sign_extend(mmio.value, 8 * size); + } else { + mmio.value = 0; + } + + mmio.is_write = is_write; + mmio.size = size; + + mmio_result = mmio_handle_access(&mmio); + if (mmio_result == MMIO_ERROR) + return TRAP_FORBIDDEN; + + if (mmio_result == MMIO_UNHANDLED) + goto error_unhandled; + + /* Put the read value into the dest register */ + if (!is_write && (srt != 31)) { + if (sse && size < sizeof(unsigned long)) + mmio.value = sign_extend(mmio.value, 8 * size); + __regs[srt] = mmio.value; + } + + /* Skip instruction */ + regs->pc += ESR_IL(esr) ? 4 : 2; + + return TRAP_HANDLED; + +error_unhandled: + panic("Unhandled data %s at 0x%lx(%d)\n", (is_write ? "write" : "read"), mmio.address, size); + + return TRAP_UNHANDLED; +} \ No newline at end of file diff --git a/so3/arch/arm64/mmu.c b/so3/arch/arm64/mmu.c index 9145a9bc9d..da4e369e11 100644 --- a/so3/arch/arm64/mmu.c +++ b/so3/arch/arm64/mmu.c @@ -33,10 +33,6 @@ #include #include -#ifdef CONFIG_SO3VIRT -#include -#endif - void *__current_pgtable = NULL; void *current_pgtable(void) { @@ -426,7 +422,7 @@ void release_mapping(void *pgtable, addr_t vaddr, size_t size) { uint64_t *l1pte, *l2pte, *l3pte; size_t free_size = 0; - /* If l1pgtable is NULL, we consider the system page table */ + /* If pgtable is NULL, we consider the system page table */ if (pgtable == NULL) pgtable = __sys_root_pgtable; @@ -434,6 +430,7 @@ void release_mapping(void *pgtable, addr_t vaddr, size_t size) { size = ALIGN_UP(size + (vaddr & ~PAGE_MASK), PAGE_SIZE); while (free_size < size) { + #ifdef CONFIG_VA_BITS_48 l0pte = l0pte_offset(pgtable, vaddr); if (!*l0pte) @@ -451,36 +448,41 @@ void release_mapping(void *pgtable, addr_t vaddr, size_t size) { #endif BUG_ON(!*l1pte); + if (pte_type(l1pte) == PTE_TYPE_BLOCK) { - *l1pte = 0; - flush_pte_entry(vaddr, l1pte); + + *l1pte = 0; + flush_pte_entry(vaddr, l1pte); - free_size += BLOCK_1G_OFFSET; - vaddr += BLOCK_1G_OFFSET; + free_size += SZ_1G; + vaddr += SZ_1G; #ifdef CONFIG_VA_BITS_48 if (empty_table(l0pte)) free(l0pte); #endif } else { + BUG_ON(pte_type(l1pte) != PTE_TYPE_TABLE); - l2pte = l2pte_offset(l1pte, vaddr); - BUG_ON(!*l2pte); - if (pte_type(l2pte) == PTE_TYPE_BLOCK) { - *l2pte = 0; - flush_pte_entry(vaddr, l2pte); + l2pte = l2pte_offset(l1pte, vaddr); + BUG_ON(!*l2pte); - free_size += BLOCK_2M_OFFSET; - vaddr += BLOCK_2M_OFFSET; + if (pte_type(l2pte) == PTE_TYPE_BLOCK) { + + *l2pte = 0; + flush_pte_entry(vaddr, l2pte); - if (empty_table(l1pte)) + free_size += SZ_2M; + vaddr += SZ_2M; + + if (empty_table(l1pte)) free(l1pte); } else { BUG_ON(pte_type(l2pte) != PTE_TYPE_TABLE); l3pte = l3pte_offset(l2pte, vaddr); BUG_ON(!*l3pte); - + *l3pte = 0; flush_pte_entry(vaddr, l3pte); @@ -527,12 +529,6 @@ void *new_root_pgtable(void) { void copy_root_pgtable(void *dst, void *src) { memcpy(dst, src, TTB_L0_SIZE); - -#ifdef CONFIG_SO3VIRT - *l0pte_offset(dst, avz_shared->hypervisor_vaddr) = - *l0pte_offset(avz_shared->pagetable_vaddr, avz_shared->hypervisor_vaddr); -#endif /* CONFIG_SO3VIRT */ - } /** @@ -708,10 +704,6 @@ void mmu_configure(addr_t fdt_addr) { */ void __mmu_switch_kernel(void *pgtable_paddr, bool vttbr) { -#ifdef CONFIG_SO3VIRT - avz_shared->pagetable_paddr = (addr_t) pgtable_paddr; -#endif - flush_dcache_all(); #ifdef CONFIG_AVZ @@ -758,6 +750,9 @@ void dump_pgtable(void *l0pgtable) { lprintk(" ***** Page table dump *****\n"); + if (__l0pgtable == NULL) + __l0pgtable = __sys_root_pgtable; + for (i = 0; i < TTB_L0_ENTRIES; i++) { l0pte = __l0pgtable + i; if ((i != 0xe0) && *l0pte) { @@ -852,7 +847,7 @@ void duplicate_pgtable_entry(u64 *from, u64 *to, int level, u64 vaddr, pcb_t *pc memset(__to, 0, PAGE_SIZE); - to[i] = (from[i] & ~mask) | (__pa(__to) & mask); + to[i] = (from[i] & ~mask) | ((addr_t) __pa(__to) & mask); switch(level) { case 0: diff --git a/so3/arch/arm64/ptrace.c b/so3/arch/arm64/ptrace.c index 7838e6e691..73ddeeebe9 100644 --- a/so3/arch/arm64/ptrace.c +++ b/so3/arch/arm64/ptrace.c @@ -20,6 +20,22 @@ #include #include +/* + * Can be used for debugging purposes. + * + */ +void __dump_regs(void *regs) { + unsigned long *cpuregs = (unsigned long *) regs; + int i; + + printk("---------- CPU regs ----------\n"); + + for (i = 0; i <= 30; i++) + printk("x%d = %x\n", i, *(cpuregs+i)); + + printk("\n"); +} + /** * Update the CPU registers of the TCB belonging * to the current thread. diff --git a/so3/arch/arm64/rpi4_64/include/mach/ipamap.h b/so3/arch/arm64/rpi4_64/include/mach/ipamap.h index 2f90a65fdb..0cea252c6b 100644 --- a/so3/arch/arm64/rpi4_64/include/mach/ipamap.h +++ b/so3/arch/arm64/rpi4_64/include/mach/ipamap.h @@ -66,7 +66,7 @@ ipamap_t ipamap[] = { .ipa_addr = 0x600000000, .phys_addr = 0x600000000, .size = 0x1000, - } + }, }; #endif /* MACH_IPAMAP_H */ diff --git a/so3/arch/arm64/setup.c b/so3/arch/arm64/setup.c deleted file mode 100644 index f7ee8279d8..0000000000 --- a/so3/arch/arm64/setup.c +++ /dev/null @@ -1,48 +0,0 @@ - -/* - * Copyright (C) 2023 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* Force the variable to be stored in .data section so that the BSS can be freely cleared. - * The value is set during the head.S execution before clear_bss(). - */ - -#include - -#include - -#include - -avz_shared_t *avz_shared = (avz_shared_t *) 0xbeef; - -void (*__printch)(char c); - -volatile uint32_t *HYPERVISOR_hypercall_addr; - -#ifndef CONFIG_SOO - -/** - * This function is called at early bootstrap stage along head.S. - */ -void avz_setup(void) { - - __printch = avz_shared->printch; - - HYPERVISOR_hypercall_addr = (uint32_t *) avz_shared->hypercall_vaddr; -} - -#endif /* CONFIG_SOO */ diff --git a/so3/arch/arm64/traps.c b/so3/arch/arm64/traps.c index 6010f90db3..eceb3c82fd 100644 --- a/so3/arch/arm64/traps.c +++ b/so3/arch/arm64/traps.c @@ -19,24 +19,28 @@ #include #include #include +#include +#include #ifdef CONFIG_AVZ -#include -#include -#include -#include +#include +#include #include #include -#else +#ifdef CONFIG_SOO +#include +#endif /* CONFIG_SOO */ + +#else /* CONFIG_AVZ */ #include -#endif +#endif /* !CONFIG_AVZ */ #include -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ const char entry_error_messages[19][32] = { @@ -102,7 +106,7 @@ void show_invalid_entry_message(u32 type, u64 esr, u64 address) } void trap_handle_error(addr_t lr) { -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ unsigned long esr = read_sysreg(esr_el2); #else unsigned long esr = read_sysreg(esr_el1); @@ -111,48 +115,68 @@ void trap_handle_error(addr_t lr) { show_invalid_entry_message(ESR_ELx_EC(esr), esr, lr); } -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_SMP extern addr_t cpu_entrypoint; #endif +/** + * @brief Handling the dabt condition + * + * @param regs + * @param esr + * @return int + */ +int dabt_handle(cpu_regs_t *regs, unsigned long esr) { + +#ifdef CONFIG_AVZ + return mmio_dabt_decode(regs, esr); +#else + return -1; +#endif + +} + /** * This is the entry point for all exceptions currently managed by SO3. + * + * Regarding the SOO hypercalls, all addresses got from arguments + * *must* be physical addresses. * * @param regs Pointer to the stack frame */ typedef void(*vector_fn_t)(cpu_regs_t *); -int trap_handle(cpu_regs_t *regs) { +void trap_handle(cpu_regs_t *regs) { #ifndef CONFIG_AVZ syscall_args_t sys_args; #endif #ifdef CONFIG_ARM64VT + unsigned long esr = read_sysreg(esr_el2); unsigned long hvc_code; + +#ifdef CONFIG_SOO + unsigned int memslotID = ((current_domain->avz_shared->domID == DOMID_AGENCY) ? MEMSLOT_AGENCY : current_domain->avz_shared->domID); +#endif /* CONFIG_SOO */ + #else unsigned long esr = read_sysreg(esr_el1); -#endif +#endif /* CONFIG_ARM64VT */ -#if defined(CONFIG_AVZ) && defined(CONFIG_SOO) - vector_fn_t vector_fn = (vector_fn_t) (ME_VOFFSET + L_TEXT_OFFSET + PAGE_SIZE + SYSCALL_VECTOR_OFFSET); -#endif + switch (ESR_ELx_EC(esr)) { - switch (ESR_ELx_EC(esr)) { + case ESR_ELx_EC_DABT_LOW: - /* SVC used for syscalls */ + dabt_handle(regs, esr); + break; + + /* SVC used for syscalls */ case ESR_ELx_EC_SVC64: #ifdef CONFIG_AVZ - -#ifdef CONFIG_SOO - /* Jump to the guest vector */ - - vector_fn(regs); - return 0; -#else + /* No syscall can be issued fron the hypervisor. */ BUG(); -#endif #else /* CONFIG_AVZ */ @@ -166,53 +190,49 @@ int trap_handle(cpu_regs_t *regs) { local_irq_enable(); regs->x0 = syscall_handle(&sys_args); local_irq_disable(); + #endif /* !CONFIG_AVZ */ - return 0; + break; -#ifdef CONFIG_ARM64VT +#ifdef CONFIG_AVZ case ESR_ELx_EC_HVC64: hvc_code = regs->x0; - switch (hvc_code) { + switch (hvc_code) { - /* PSCI hypercalls */ +#ifdef CONFIG_SMP + /* PSCI hypercalls */ case PSCI_0_2_FN_PSCI_VERSION: - return PSCI_VERSION(1, 1); + regs->x0 = PSCI_VERSION(1, 1); + break; - case PSCI_0_2_FN64_CPU_ON: - printk("Power on CPU #%d...\n", regs->x1 & 3); + case PSCI_0_2_FN64_CPU_ON: + printk("Power on CPU #%d starting at %x...\n", regs->x1 & 3, regs->x2); cpu_entrypoint = regs->x2; smp_trigger_event(regs->x1 & 3); - return PSCI_RET_SUCCESS; - - /* AVZ Hypercalls */ - case __HYPERVISOR_console_io: - printk("%c", regs->x1); - return ESUCCESS; - - case __HYPERVISOR_domctl: - - do_domctl((domctl_t *) ipa_to_lva(memslot[MEMSLOT_AGENCY], regs->x1)); - flush_dcache_all(); - - return ESUCCESS; - - case __HYPERVISOR_event_channel_op: - - do_event_channel_op(regs->x1, (void *) ipa_to_lva(memslot[MEMSLOT_AGENCY], regs->x2)); - flush_dcache_all(); - - return ESUCCESS; - - default: - return ESUCCESS; - } - break; -#endif /* CONFIG_ARM64VT */ - + regs->x0 = PSCI_RET_SUCCESS; + break; + + case PSCI_0_2_FN_MIGRATE_INFO_TYPE: + case PSCI_1_0_FN_PSCI_FEATURES: + regs->x0 = PSCI_RET_SUCCESS; + break; +#endif /* CONFIG_SMP */ + + case AVZ_HYPERCALL_TRAP: + do_avz_hypercall((avz_hyp_t *) ipa_to_va(memslotID, regs->x1)); + break; + + case AVZ_HYPERCALL_SIGRETURN: + __sigreturn(); + break; + } + break; +#endif /* CONFIG_AVZ */ + #if 0 case ESR_ELx_EC_DABT_LOW: break; @@ -257,7 +277,5 @@ int trap_handle(cpu_regs_t *regs) { lprintk("### On CPU %d: ESR_Elx_EC(esr): 0x%lx\n", smp_processor_id(), ESR_ELx_EC(esr)); trap_handle_error(regs->lr); kernel_panic(); - } - - return -1; + } } diff --git a/so3/arch/arm64/virt64/include/mach/ipamap.h b/so3/arch/arm64/virt64/include/mach/ipamap.h index 21fdef582e..a0939e9509 100644 --- a/so3/arch/arm64/virt64/include/mach/ipamap.h +++ b/so3/arch/arm64/virt64/include/mach/ipamap.h @@ -21,12 +21,29 @@ #include -ipamap_t ipamap[] = { - { - .ipa_addr = 0x8000000, - .phys_addr = 0x8000000, - .size = 0x3000000, - }, +ipamap_t linux_ipamap[] = { + { + .ipa_addr = 0x08000000, + .phys_addr = 0x08000000, + .size = 0x3000000, + }, +}; + +/** + * In the guest environment, the access to the GIC distributor must lead to a data abort + * which will be trapped and handled by the hypervisor. + */ + +ipamap_t guest_ipamap[] = { + + { + /* Only mapping the CPU interface to the vGIC CPU interface. + * Access to the distributor must lead to a trap and be handled by the hypervisor. + */ + .ipa_addr = 0x08010000, + .phys_addr = 0x08040000, + .size = 0x10000, + }, }; #endif /* MACH_IPAMAP_H */ diff --git a/so3/avz/Makefile b/so3/avz/Makefile new file mode 100644 index 0000000000..235c68b724 --- /dev/null +++ b/so3/avz/Makefile @@ -0,0 +1,2 @@ + +obj-y += kernel/ mm/ diff --git a/so3/include/avz/asf.h b/so3/avz/include/avz/asf.h similarity index 100% rename from so3/include/avz/asf.h rename to so3/avz/include/avz/asf.h diff --git a/so3/soo/kernel/debug/logbool.c b/so3/avz/include/avz/avz.h similarity index 69% rename from so3/soo/kernel/debug/logbool.c rename to so3/avz/include/avz/avz.h index 39a31d8985..96598ebac7 100644 --- a/so3/soo/kernel/debug/logbool.c +++ b/so3/avz/include/avz/avz.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2019 Daniel Rossier + * Copyright (C) 2016-2025 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,12 +16,12 @@ * */ -#include -ht_set_t __ht_set; +#ifndef AVZ_H +#define AVZ_H -void ht_set(logbool_hashtable_t *hashtable, char *key, logbool_t value) { +#include - /* Trampoline function for AVZ logbool hashtable support. */ - __ht_set(hashtable, key, value); -} +#define avz_shared __avz_shared + +#endif /* AVZ_H */ diff --git a/so3/soo/include/soo/debug/packchk.h b/so3/avz/include/avz/capsule.h similarity index 54% rename from so3/soo/include/soo/debug/packchk.h rename to so3/avz/include/avz/capsule.h index 1180ed9f50..4deca2efa3 100644 --- a/so3/soo/include/soo/debug/packchk.h +++ b/so3/avz/include/avz/capsule.h @@ -1,5 +1,6 @@ + /* - * Copyright (C) 2018 Baptiste Delporte + * Copyright (C) 2016-2025 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,23 +17,13 @@ * */ -#ifndef PACKCHK_H -#define PACKCHK_H - -#ifdef __KERNEL__ -#include -#endif /* __KERNEL__ */ - -#include +#ifndef AVZ_CAPSULE_H +#define AVZ_CAPSULE_H -typedef struct { - int (*recv_success)(void *buffer, size_t size); - int (*recv_failure)(void *buffer, size_t size); -} packchk_callbacks_t; +#include -void packchk_register(packchk_callbacks_t *callbacks, size_t size); -void packchk_enable_multi(void); -void packchk_send_next_packet(void); -void packchk_process_received_packet(void *data, size_t size); +void inject_me(avz_hyp_t *args); +void read_ME_snapshot(avz_hyp_t *args); +void write_ME_snapshot(avz_hyp_t *args); -#endif /* PACKCHK_H */ +#endif /* AVZ_CAPSULE_H */ \ No newline at end of file diff --git a/so3/include/avz/console.h b/so3/avz/include/avz/console.h similarity index 51% rename from so3/include/avz/console.h rename to so3/avz/include/avz/console.h index 7d4de8db0e..1259ed7fa4 100644 --- a/so3/include/avz/console.h +++ b/so3/avz/include/avz/console.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Daniel Rossier + * Copyright (C) 2016-2025 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,22 +16,12 @@ * */ -#ifndef UAPI_CONSOLE_H -#define UAPI_CONSOLE_H - -/* SOO.tech */ -#if !defined(__SO3__) -#include -#endif +#ifndef AVZ_CONSOLE_H +#define AVZ_CONSOLE_H #include -#define CONSOLEIO_BUFFER_SIZE 256 - -struct pt_regs; - -void avzcons_rx(char *buf, unsigned len, struct pt_regs *regs); -void avzcons_tx(void); +#include void init_console(void); @@ -55,27 +45,6 @@ void lprintch(char c); void lprintk_int64_post(s64 number, char *post); void lprintk_int64(s64 number); -/* Return the current active domain for the uart console */ -int avzcons_get_focus(void); - -/* Set the active domain to next_domain for the uart console and return the current active domain. */ -int avzcons_set_focus(int next_domain); - -#define avzcons_NEXT_FOCUS() (avzcons_set_focus((avzcons_get_focus() + 1) % 4)) - -/* Return the current active domain for the graphic console */ -int vfb_get_focus(void); - -/* Set the active domain to next_domain for the graphic console and return the current active domain. */ -int vfb_set_focus(int next_domain); - -#define VFB_NEXT_FOCUS() (vfb_set_focus((vfb_get_focus() + 1) % 3)) - -/* Temporary helper until the vfbback interaction have been cleared up */ -#define VFB_TRIG_IRQ() \ - ({\ - extern irqreturn_t vfb_interrupt(int irq, void *dev_id); \ - vfb_interrupt(0, NULL); \ - }) +void do_console_io(console_t *console); -#endif /* UAPI_CONSOLE_H */ +#endif /* AVZ_CONSOLE_H */ diff --git a/so3/include/avz/dcm.h b/so3/avz/include/avz/dcm.h similarity index 100% rename from so3/include/avz/dcm.h rename to so3/avz/include/avz/dcm.h diff --git a/so3/include/avz/debug.h b/so3/avz/include/avz/debug.h similarity index 100% rename from so3/include/avz/debug.h rename to so3/avz/include/avz/debug.h diff --git a/so3/include/avz/domain.h b/so3/avz/include/avz/domain.h similarity index 78% rename from so3/include/avz/domain.h rename to so3/avz/include/avz/domain.h index 9273be8084..67941024a2 100644 --- a/so3/include/avz/domain.h +++ b/so3/avz/include/avz/domain.h @@ -20,15 +20,11 @@ #define DOMAIN_H #ifndef __ASSEMBLY__ -#include +#include #endif #include -#ifdef CONFIG_ARCH_ARM32 -#include -#endif - /* We keep the STACK_SIZE to 8192 in order to have a similar stack_size as guest OS in SVC mode */ #define DOMAIN_STACK_SIZE (PAGE_SIZE << 1) @@ -50,9 +46,17 @@ #include #include +#include #include +#define NR_GRANT_PFN 32 + +typedef struct { + addr_t pfn; + bool free; +} grant_pfn_t; + struct evtchn { u8 state; /* ECS_* */ @@ -74,9 +78,8 @@ struct evtchn }; -struct domain -{ - /* The spinlocks are placed here to have a 8-byte alignement +struct domain { + /* The spinlocks are placed here to have a 8-byte alignement * required by ldaxr instruction. */ @@ -84,18 +87,17 @@ struct domain spinlock_t event_lock; spinlock_t virq_lock; - /* Fields related to the underlying CPU */ - cpu_regs_t cpu_regs; - addr_t g_sp; /* G-stack */ + vcpu_t vcpu; addr_t event_callback; addr_t domcall; -#ifdef CONFIG_ARCH_ARM32 - struct vfp_state vfp; -#endif avz_shared_t *avz_shared; /* shared data area between AVZ and the domain */ + /* Physical and virtual address of the page table used when the domain is bootstraping */ + addr_t pagetable_paddr; + addr_t pagetable_vaddr; /* Required when bootstrapping the domain */ + unsigned int max_pages; /* maximum value for tot_pages */ /* Event channel information. */ @@ -108,7 +110,13 @@ struct domain /* Domain is paused by controller software? */ bool is_paused_by_controller; - int processor; + /* Grant table to store the pages granted by this domain to the other */ + struct list_head gnttab; + + /* IPA reserved page frame numbers for mapping granted pages belonging to other domains */ + grant_pfn_t grant_pfn[NR_GRANT_PFN]; + + int processor; bool need_periodic_timer; struct timer oneshot_timer; @@ -123,10 +131,10 @@ struct domain unsigned long pause_flags; atomic_t pause_count; - unsigned long domain_stack; + /* Hypervisor stack for this domain */ + void *domain_stack; }; - #define USE_NORMAL_PGTABLE 0 #define USE_SYSTEM_PGTABLE 1 @@ -136,28 +144,25 @@ extern struct domain *domains[MAX_DOMAINS]; extern int construct_agency(struct domain *d); extern int construct_ME(struct domain *d); -extern void new_thread(struct domain *d, unsigned long start_pc, unsigned long r2_arg, unsigned long start_stack); -void *setup_dom_stack(struct domain *d); +ME_state_t get_ME_state(unsigned int ME_slotID); -extern void domain_call(struct domain *target_dom, int cmd, void *arg); +void do_domctl(domctl_t *args); +void *setup_dom_stack(struct domain *d); + void machine_halt(void); void arch_domain_create(struct domain *d, int cpu_id); -void arch_setup_domain_frame(struct domain *d, cpu_regs_t *domain_frame, addr_t fdt_addr, addr_t start_stack, addr_t start_pc); + +void initialize_hyp_dom_stack(struct domain *d, addr_t fdt_paddr, addr_t entry_addr); /* * setup_page_table_guestOS() is setting up the 1st-level and 2nd-level page tables within the domain. */ -#ifdef CONFIG_ARM64VT + void __setup_dom_pgtable(struct domain *d, addr_t ipa_start, unsigned long map_size); -#else -void __setup_dom_pgtable(struct domain *d, addr_t v_start, unsigned long map_size, addr_t p_start); -#endif -/* - * Arch-specifics. - */ +void domain_unpause_by_systemcontroller(struct domain *d); /* Allocate/free a domain structure. */ struct domain *alloc_domain_struct(void); @@ -170,11 +175,7 @@ void free_vcpu_struct(struct vcpu *v); void vcpu_destroy(struct vcpu *v); void arch_domain_destroy(struct domain *d); - -int domain_relinquish_resources(struct domain *d); - -void dump_pageframe_info(struct domain *d); - + void arch_dump_vcpu_info(struct vcpu *v); void arch_dump_domain_info(struct domain *d); diff --git a/so3/avz/include/avz/evtchn.h b/so3/avz/include/avz/evtchn.h new file mode 100644 index 0000000000..75b2e52252 --- /dev/null +++ b/so3/avz/include/avz/evtchn.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef EVTCHN_H +#define EVTCHN_H + +#include +#include +#include + +#include + +/* + * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ. + * @v: VCPU to which virtual IRQ should be sent + * @virq: Virtual IRQ number (VIRQ_*) + */ +void send_guest_virq(struct domain *d, int virq); + +/* Send a notification from a given domain's event-channel port. */ +void evtchn_send(struct domain *d, unsigned int lport); + +/* Bind a local event-channel port to the specified VCPU. */ +long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); + +void do_event_channel_op(avz_hyp_t *args); + +void event_channel_init(void); + +void evtchn_bind_existing_interdomain(struct domain *ld, struct domain *remote, int levtchn, int revtchn); + +#endif /* EVTCHN_H */ diff --git a/so3/avz/include/avz/gnttab.h b/so3/avz/include/avz/gnttab.h new file mode 100644 index 0000000000..d1c265a317 --- /dev/null +++ b/so3/avz/include/avz/gnttab.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef GNTTAB_H +#define GNTTAB_H + +#include + +#include + +struct gnttab { + + struct list_head list; /* List of grant pages */ + + domid_t origin_domid; /* Domain which provides the grant */ + domid_t target_domid; /* Target domain (granted to) */ + + /* (Real) physical frame number to be granted */ + addr_t pfn; + + /* Unique ref ID used by the domain which refers to this page */ + grant_ref_t ref; + +}; +typedef struct gnttab gnttab_t; + +void gnttab_init(struct domain *d); +void do_gnttab(gnttab_op_t *args); +addr_t map_vbstore_pfn(int target_domid, int pfn); + +#endif /* GNTTAB_H */ + + + diff --git a/so3/include/avz/migration.h b/so3/avz/include/avz/injector.h similarity index 71% rename from so3/include/avz/migration.h rename to so3/avz/include/avz/injector.h index 9f6527445b..9c655d19b0 100644 --- a/so3/include/avz/migration.h +++ b/so3/avz/include/avz/injector.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2018 Daniel Rossier + * Copyright (C) 2024-2025 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,14 +16,14 @@ * */ -#ifndef __MIGRATION_H__ -#define __MIGRATION_H__ +#ifndef INJECTOR_H +#define INJECTOR_H #include #include -struct domain_migration_info +struct dom_context { /* * Event channel struct information. @@ -50,27 +50,33 @@ struct domain_migration_info /* IRQ-safe virq_lock protects against delivering VIRQ to stale evtchn. */ u16 virq_to_evtchn[NR_VIRQS]; - /* Fields related to the CPU state */ - cpu_regs_t cpu_regs; - addr_t g_sp; /* G-stack */ + /* IPA physical address */ + addr_t ipa_addr; + + /* IPA reserved page frame numbers for granted pages */ + grant_pfn_t grant_pfn[NR_GRANT_PFN]; + + /* Stack frame of this domain */ + struct cpu_regs stack_frame; -#ifdef CONFIG_ARCH_ARM32 - struct vfp_state vfp; -#endif + /* Fields related to the CPU state */ + vcpu_t vcpu; }; + void mig_restore_domain_migration_info(unsigned int ME_slotID, struct domain *me); void after_migrate_to_user(void); -void migration_init(soo_hyp_t *op); -void migration_final(soo_hyp_t *op); +void migration_init(avz_hyp_t *args); +void migration_final(avz_hyp_t *args); -void read_migration_structures(soo_hyp_t *op); -void write_migration_structures(soo_hyp_t *op); +void read_migration_structures(avz_hyp_t *args); +void write_migration_structures(avz_hyp_t *args); void restore_migrated_domain(unsigned int ME_slotID); void restore_injected_domain(unsigned int ME_slotID); -void inject_me(soo_hyp_t *op); +void inject_me(avz_hyp_t *args); + -#endif /* __MIGRATION_H__ */ +#endif /* INJECTOR_H */ \ No newline at end of file diff --git a/so3/include/avz/keyhandler.h b/so3/avz/include/avz/keyhandler.h similarity index 100% rename from so3/include/avz/keyhandler.h rename to so3/avz/include/avz/keyhandler.h diff --git a/so3/include/avz/memslot.h b/so3/avz/include/avz/memslot.h similarity index 86% rename from so3/include/avz/memslot.h rename to so3/avz/include/avz/memslot.h index 92d6594392..52d47e865c 100644 --- a/so3/include/avz/memslot.h +++ b/so3/avz/include/avz/memslot.h @@ -18,8 +18,6 @@ #ifndef MEMSLOT_H #define MEMSLOT_H -#include - /* Number of possible MEs in the local SOO */ #define MEMSLOT_BASE 2 #define MEMSLOT_NR (MEMSLOT_BASE + MAX_ME_DOMAINS) @@ -28,24 +26,26 @@ #define MEMSLOT_AVZ 0 #define MEMSLOT_AGENCY 1 +#define DOM_TO_MEMSLOT(domid) (((domid == DOMID_AGENCY) || (domid == DOMID_AGENCY_RT)) ? MEMSLOT_AGENCY : domid) + /* * Memslot management * * Describes how domains are mapped in physical memory */ typedef struct { - addr_t base_paddr; /* Kernel physical start address */ - size_t size; + addr_t base_paddr; /* Guest physical start address */ + addr_t base_vaddr; /* Guest virtual start address */ + + size_t size; unsigned int busy; /* Indicate if a memslot is available or not */ addr_t fdt_paddr; /* Device Tree */ addr_t entry_addr; -#ifdef CONFIG_ARM64VT /* Intermediate physical address (address of the virtual RAM as exposed to the guest) */ unsigned long ipa_addr; -#endif } memslot_entry_t; diff --git a/so3/include/avz/physdev.h b/so3/avz/include/avz/physdev.h similarity index 100% rename from so3/include/avz/physdev.h rename to so3/avz/include/avz/physdev.h diff --git a/so3/include/avz/sched-if.h b/so3/avz/include/avz/sched-if.h similarity index 98% rename from so3/include/avz/sched-if.h rename to so3/avz/include/avz/sched-if.h index 63bdd72e78..e11985eaa5 100644 --- a/so3/include/avz/sched-if.h +++ b/so3/avz/include/avz/sched-if.h @@ -19,8 +19,6 @@ #ifndef __SCHED_IF_H__ #define __SCHED_IF_H__ -#include - struct schedule_data { spinlock_t schedule_lock; /* spinlock protecting curr */ struct timer s_timer; /* scheduling timer */ diff --git a/so3/include/avz/sched.h b/so3/avz/include/avz/sched.h similarity index 90% rename from so3/include/avz/sched.h rename to so3/avz/include/avz/sched.h index acb2a3bb6d..682552345a 100644 --- a/so3/include/avz/sched.h +++ b/so3/avz/include/avz/sched.h @@ -26,13 +26,26 @@ #include #include +#include + #include -#include #include #include +/* VCPU is currently running on a physical CPU. */ +#define RUNSTATE_running 0 + +/* VCPU is runnable, but not currently scheduled on any physical CPU. */ +#define RUNSTATE_runnable 1 + +/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */ +#define RUNSTATE_blocked 2 + +/* VCPU is offline, not blocked and not runnable */ +#define RUNSTATE_offline 3 + /* * Voluntarily yield the CPU. * @arg == NULL. @@ -132,6 +145,9 @@ void domain_unpause(struct domain *d); void domain_pause_by_systemcontroller(struct domain *d); void domain_unpause_by_systemcontroller(struct domain *d); +void vcpu_save_context(struct domain *d); +void vcpu_restore_context(struct domain *d); + struct task_slice flip_do_schedule(void); #endif /* __SCHED_H__ */ diff --git a/so3/include/avz/schedop.h b/so3/avz/include/avz/schedop.h similarity index 100% rename from so3/include/avz/schedop.h rename to so3/avz/include/avz/schedop.h diff --git a/so3/soo/include/soo/domctl.h b/so3/avz/include/avz/soo.h similarity index 51% rename from so3/soo/include/soo/domctl.h rename to so3/avz/include/avz/soo.h index 6767eac34f..c45f68ff47 100644 --- a/so3/soo/include/soo/domctl.h +++ b/so3/avz/include/avz/soo.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2016-2018 Daniel Rossier - * + * Copyright (C) 2014-2025 Daniel Rossier * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -16,35 +15,19 @@ * */ -#ifndef __DOMCTL_H__ -#define __DOMCTL_H__ - -#include - -/* - * There are two main scheduling policies: the one used for normal (standard) ME, and - * a second one used for realtime ME. - */ -#define AVZ_SCHEDULER_FLIP 0 -#define AVZ_SCHEDULER_RT 1 - -struct domctl_unpause_ME { - uint32_t store_mfn; -}; +#ifndef SOO_H +#define SOO_H -struct domctl { - uint32_t cmd; +#include -#define DOMCTL_pauseME 1 -#define DOMCTL_unpauseME 2 +/* Device tree features */ +#define ME_FEAT_ROOT "/me_features" - domid_t domain; - union { - struct domctl_unpause_ME unpause_ME; - } u; -}; -typedef struct domctl domctl_t; +void soo_activity_init(void); +void shutdown_ME(unsigned int ME_slotID); -#endif /* __DOMCTL_H__ */ +ME_state_t get_ME_state(uint32_t ME_slotID); +void set_ME_state(uint32_t slotID, ME_state_t state); +#endif /* SOO_H */ diff --git a/so3/avz/include/avz/uapi/avz.h b/so3/avz/include/avz/uapi/avz.h new file mode 100644 index 0000000000..39cb58efc1 --- /dev/null +++ b/so3/avz/include/avz/uapi/avz.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016-2022 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef UAPI_AVZ_H +#define UAPI_AVZ_H + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_SOO +#include +#endif + +#include + +#endif /* __ASSEMBLY__ */ + +/* + * VIRTUAL INTERRUPTS + * + * Virtual interrupts that a guest OS may receive from the hypervisor. + * + */ +#define NR_VIRQS 256 + +#define VIRQ_TIMER 0 /* System timer tick virtualized interrupt */ +#define VIRQ_TIMER_RT 1 /* Timer tick issued from the oneshot timer (for RT agency and MEs */ + +/**************************************************/ + +/* + * Commands to HYPERVISOR_console_io(). + */ +#define CONSOLEIO_write_string 0 +#define CONSOLEIO_process_char 1 + +/* Idle domain. */ +#define DOMID_IDLE (0x7FFFU) + +/* DOMID_SELF is used in certain contexts to refer to oneself. */ +#define DOMID_SELF (0x7FF0U) + +/* Agency */ +#define DOMID_AGENCY 0 + +/* Realtime agency subdomain */ +#define DOMID_AGENCY_RT 1 + +#define DOMID_INVALID (0x7FF4U) + +#define AVZ_HYPERCALL_TRAP 0x2605 +#define AVZ_HYPERCALL_SIGRETURN 0x2606 + +#ifndef __ASSEMBLY__ + +/* Assembly low-level code to raise up hypercall */ +extern long __avz_hypercall(int vector, long avz_hyp_args); + +/* Generic function to raise up hypercall */ +void avz_hypercall(avz_hyp_t *avz_hyp); + +/* + * 128 event channels per domain + */ +#define NR_EVTCHN 128 + +#ifndef DOMID_T +#define DOMID_T +typedef uint16_t domid_t; +typedef unsigned long addr_t; +#endif + +/* + * Shared info page, shared between AVZ and the domain. + */ +struct avz_shared { + + domid_t domID; + + /* Domain related information */ + unsigned long nr_pages; /* Total pages allocated to this domain. */ + + addr_t fdt_paddr; + + /* Other fields related to domain life */ + + unsigned long domain_stack; + uint8_t evtchn_upcall_pending; + + /* + * A domain can create "event channels" on which it can send and receive + * asynchronous event notifications. + * Each event channel is assigned a bit in evtchn_pending and its modification has to be + * kept atomic. + */ + + volatile bool evtchn_pending[NR_EVTCHN]; + + atomic_t dc_event; + + /* This field is used when taking a snapshot of us. It will be + * useful to restore later. Some timer deadlines are based on it and + * will need to be updated accordingly. + */ + u64 current_s_time; + + /* Agency or ME descriptor */ + dom_desc_t dom_desc; + + /* Keep the physical address so that the guest can map within in its address space. */ + addr_t subdomain_shared_paddr; + + struct avz_shared *subdomain_shared; + + /* Used to store a signature for consistency checking, for example after a migration/restoration */ + char signature[4]; +}; + +typedef struct avz_shared avz_shared_t; + +extern volatile avz_shared_t *__avz_shared; + +void do_avz_hypercall(avz_hyp_t *args); +void __sigreturn(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* UAPI_AVZ_H */ + diff --git a/so3/kernel/avz/ME_build.c b/so3/avz/kernel/ME_build.c similarity index 68% rename from so3/kernel/avz/ME_build.c rename to so3/avz/kernel/ME_build.c index 9b340cfbfc..ba421ee45a 100644 --- a/so3/kernel/avz/ME_build.c +++ b/so3/avz/kernel/ME_build.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2019 Daniel Rossier + * Copyright (C) 2016-2024 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -31,18 +31,17 @@ #include #include -#include - /* * construct_ME sets up a new Mobile Entity. */ + int construct_ME(struct domain *d) { - unsigned int slotID; + unsigned int slotID; unsigned long alloc_spfn; slotID = d->avz_shared->domID; - printk("***************************** Loading Mobile Entity (ME) *****************************\n"); + printk("***************************** Loading SO3 Guest Container *****************************\n"); if (memslot[slotID].size == 0) panic("No ME image supplied\n"); @@ -65,27 +64,13 @@ int construct_ME(struct domain *d) { clear_bit(_VPF_down, &d->pause_flags); -#ifdef CONFIG_ARM64VT __setup_dom_pgtable(d, memslot[slotID].base_paddr, memslot[slotID].size); -#else - __setup_dom_pgtable(d, ME_VOFFSET, memslot[slotID].size, memslot[slotID].base_paddr); -#endif - - d->avz_shared->dom_phys_offset = alloc_spfn << PAGE_SHIFT; - d->avz_shared->hypercall_vaddr = (unsigned long) hypercall_entry; - d->avz_shared->logbool_ht_set_addr = (unsigned long) ht_set; - d->avz_shared->fdt_paddr = memslot[slotID].fdt_paddr; - d->avz_shared->hypervisor_vaddr = CONFIG_KERNEL_VADDR; + d->avz_shared->fdt_paddr = pa_to_ipa(slotID, memslot[slotID].fdt_paddr); printk("ME FDT device tree: 0x%lx (phys)\n", d->avz_shared->fdt_paddr); - d->avz_shared->printch = printch; - - /* Create the first thread associated to this domain. */ - - new_thread(d, ME_VOFFSET + L_TEXT_OFFSET, d->avz_shared->fdt_paddr, ME_VOFFSET + memslot[slotID].size); + initialize_hyp_dom_stack(d, d->avz_shared->fdt_paddr, memslot[slotID].ipa_addr + L_TEXT_OFFSET); return 0; } - diff --git a/so3/kernel/avz/Makefile b/so3/avz/kernel/Makefile similarity index 80% rename from so3/kernel/avz/Makefile rename to so3/avz/kernel/Makefile index 998bb9d222..655ed32af0 100644 --- a/so3/kernel/avz/Makefile +++ b/so3/avz/kernel/Makefile @@ -5,21 +5,19 @@ obj-y += console.o obj-y += agency_build.o ME_build.o obj-y += domain.o -obj-y += physdev.o obj-y += setup.o obj-y += event_channel.o obj-y += keyhandler.o obj-y += timer.o obj-y += sched_flip.o obj-y += schedule.o -obj-y += migration.o -obj-y += domctl.o obj-y += soo_activity.o +obj-y += gnttab.o obj-y += image-fit.o obj-y += domain_utils.o obj-y += injector.o -obj-y += logbool.o + diff --git a/so3/avz/kernel/agency_build.c b/so3/avz/kernel/agency_build.c new file mode 100644 index 0000000000..1e609c6e21 --- /dev/null +++ b/so3/avz/kernel/agency_build.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016-2024 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +int construct_agency(struct domain *d) { + + printk("***************************** Loading Guest Domain *****************************\n"); + + /* Map the agency slot to the physical memory */ + create_mapping(NULL, memslot[MEMSLOT_AGENCY].base_vaddr, memslot[MEMSLOT_AGENCY].base_paddr, memslot[MEMSLOT_AGENCY].size, false); + + /* Now the slot is busy. */ + memslot[MEMSLOT_AGENCY].busy = true; + + if (memslot[MEMSLOT_AGENCY].size == 0) { + printk("No agency image supplied\n"); + kernel_panic(); + } + + d->max_pages = ~0U; + + printk("-> Agency base address from ITB: %lx\n", memslot[MEMSLOT_AGENCY].base_paddr); + printk("-> Max dom size %d\n", memslot[MEMSLOT_AGENCY].size); + + ASSERT(d); + + d->avz_shared->nr_pages = memslot[MEMSLOT_AGENCY].size >> PAGE_SHIFT; + + clear_bit(_VPF_down, &d->pause_flags); + +#ifdef CONFIG_SOO + + /* + * The RT domain has its own shared page. + */ + agency->avz_shared->subdomain_shared = domains[DOMID_AGENCY_RT]->avz_shared; + +#endif /* CONFIG_SOO */ + + __setup_dom_pgtable(d, memslot[MEMSLOT_AGENCY].base_paddr, memslot[MEMSLOT_AGENCY].size); + + /* Propagate the virtual address of the shared info page for this domain */ + + d->avz_shared->fdt_paddr = memslot[MEMSLOT_AGENCY].fdt_paddr; + + printk("AVZ Hypervisor vaddr: 0x%lx\n", CONFIG_KERNEL_VADDR); + printk("Agency FDT device tree: 0x%lx (phys)\n", d->avz_shared->fdt_paddr); + + printk("Shared AVZ page is located at: %lx\n", d->avz_shared); + +#ifdef CONFIG_SOO + + /* Domain related information */ + domains[DOMID_AGENCY_RT]->avz_shared->nr_pages = d->avz_shared->nr_pages; + domains[DOMID_AGENCY_RT]->avz_shared->fdt_paddr = d->avz_shared->fdt_paddr; + domains[DOMID_AGENCY_RT]->pagetable_paddr = d->pagetable_paddr; + +#endif /* CONFIG_SOO */ + + initialize_hyp_dom_stack(d, pa_to_ipa(MEMSLOT_AGENCY, d->avz_shared->fdt_paddr), memslot[MEMSLOT_AGENCY].entry_addr); + + return 0; +} + diff --git a/so3/kernel/avz/console.c b/so3/avz/kernel/console.c similarity index 86% rename from so3/kernel/avz/console.c rename to so3/avz/kernel/console.c index 0306c95e01..4051d1d1e9 100644 --- a/so3/kernel/avz/console.c +++ b/so3/avz/kernel/console.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include @@ -62,35 +62,25 @@ static void sercon_puts(const char *s) { serial_puts(s); } - -/* (DRE) Perform hypercall to process char addressed to the keyhandler mechanism */ -void process_char(char ch) { - handle_keypress(ch); -} - -void do_console_io(int cmd, int count, char *buffer) + +void do_console_io(console_t *console) { - char kbuf; - - switch (cmd) { - - case CONSOLEIO_process_char: - memcpy(&kbuf, buffer, sizeof(char)); - - process_char(kbuf); - break; - - case CONSOLEIO_write_string: - - printk("%s", buffer); - break; - - default: - BUG(); + switch (console->cmd) { + case CONSOLE_IO_KEYHANDLER: + handle_keypress(console->u.c); + break; + + case CONSOLE_IO_PRINTCH: + printch(console->u.c); + break; + + case CONSOLE_IO_PRINTSTR: + sercon_puts(console->u.str); + break; + } } - /* * ***************************************************** * *************** GENERIC CONSOLE I/O ***************** diff --git a/so3/kernel/avz/domain.c b/so3/avz/kernel/domain.c similarity index 59% rename from so3/kernel/avz/domain.c rename to so3/avz/kernel/domain.c index b097678705..e4587615a2 100644 --- a/so3/kernel/avz/domain.c +++ b/so3/avz/kernel/domain.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2014-2019 Daniel Rossier - * Copyright (C) 2016-2019 Baptiste Delporte + * Copyright (C) 2014-2025 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -38,10 +37,12 @@ #include #include #include -#include +#include #include +static DEFINE_SPINLOCK(domctl_lock); + /* * We don't care of the IDLE domain here... * In the domain table, the index 0 and 1 are dedicated to the non-RT and RT agency domains. @@ -55,7 +56,7 @@ struct domain *agency; * Creation of new domain context associated to the agency or a Mobile Entity. * * @domid is the domain number - * @partial tells if the domain creation remains partial, without the creation of the vcpu structure which may intervene in a second step + * @cpu_id the CPU on which this domain is allowed to run */ struct domain *domain_create(domid_t domid, int cpu_id) { @@ -66,12 +67,25 @@ struct domain *domain_create(domid_t domid, int cpu_id) memset(d, 0, sizeof(struct domain)); + /* + * Allocate the shared memory page which is shared between the hypervisor + * and the domain. + */ d->avz_shared = memalign(PAGE_SIZE, PAGE_SIZE); - BUG_ON(!d); + BUG_ON(!d->avz_shared); memset(d->avz_shared, 0, PAGE_SIZE); - d->avz_shared->domID = domid; + /* + * Grant table and grant pages + * Each domain has pre-defined number of pages used to share data + * between domains, especially between the Linux domain and the SO3 containers. + * + */ + + gnttab_init(d); + + d->avz_shared->domID = domid; if (!is_idle_domain(d)) { d->is_paused_by_controller = 1; @@ -80,10 +94,6 @@ struct domain *domain_create(domid_t domid, int cpu_id) evtchn_init(d); } - /* Create a logbool hashtable associated to this domain */ - d->avz_shared->logbool_ht = ht_create(LOGBOOL_HT_SIZE); - BUG_ON(!d->avz_shared->logbool_ht); - arch_domain_create(d, cpu_id); d->processor = cpu_id; @@ -133,12 +143,12 @@ static void complete_domain_destroy(struct domain *d) { sched_destroy_domain(d); - /* Free the logbool hashtable associated to this domain */ - ht_destroy((logbool_hashtable_t *) d->avz_shared->logbool_ht); + /* Remove the root page table */ + reset_root_pgtable((void *) d->pagetable_vaddr, true); - /* Restore allocated memory for this domain */ + /* Restore allocated memory for this domain */ - free((void *) d->avz_shared); + free((void *) d->avz_shared); free((void *) d->domain_stack); free(d); @@ -200,6 +210,13 @@ void domain_unpause_by_systemcontroller(struct domain *d) domain_unpause(d); } +/** + * @brief Perform a context switch between domains. It is equivalent + * to say that we switch the VM. + * + * @param prev + * @param next + */ void context_switch(struct domain *prev, struct domain *next) { local_irq_disable(); @@ -207,22 +224,13 @@ void context_switch(struct domain *prev, struct domain *next) if (!is_idle_domain(current_domain)) { local_irq_disable(); /* Again, if the guest re-enables the IRQ */ - -#ifdef CONFIG_ARCH_ARM32 - /* Save the VFP context */ - vfp_save_state(prev); -#endif - } - - if (!is_idle_domain(next)) { - -#ifdef CONFIG_ARCH_ARM32 - /* Restore the VFP context of the next guest */ - vfp_restore_state(next); -#endif } + + vcpu_save_context(prev); switch_mm_domain(next); + + vcpu_restore_context(next); /* Clear running flag /after/ writing context to memory. */ smp_mb(); @@ -238,48 +246,6 @@ void context_switch(struct domain *prev, struct domain *next) } -/* - * Initialize the domain stack used by the hypervisor. - * This is the H-stack and contains a reference to the domain as the bottom (base) of the stack. - */ -void *setup_dom_stack(struct domain *d) { - void *domain_stack; - - /* The stack must be aligned at STACK_SIZE bytes so that it is - * possible to retrieve the cpu_info structure at the bottom - * of the stack with a simple operation on the current stack pointer value. - */ - domain_stack = memalign(DOMAIN_STACK_SIZE, DOMAIN_STACK_SIZE); - BUG_ON(!domain_stack); - - d->domain_stack = (unsigned long) domain_stack; - - /* Put the address of the domain descriptor at the base of this stack */ - *((addr_t *) domain_stack) = (addr_t) d; - - /* Reserve the frame which will be restored later */ - domain_stack += DOMAIN_STACK_SIZE - sizeof(cpu_regs_t); - - /* Returns the reference to the H-stack frame of this domain */ - - return domain_stack; -} - -/* - * Set up the first thread of a domain. - */ -void new_thread(struct domain *d, addr_t start_pc, addr_t fdt_addr, addr_t start_stack) -{ - cpu_regs_t *domain_frame; - - domain_frame = (cpu_regs_t *) setup_dom_stack(d); - - if (domain_frame == NULL) - panic("Could not set up a new domain stack.n"); - - arch_setup_domain_frame(d, domain_frame, fdt_addr, start_stack, start_pc); -} - static void continue_cpu_idle_loop(void) { while (1) { @@ -320,42 +286,37 @@ void machine_restart(unsigned int delay_millisecs) while (1); } -/* - * dommain_call - * Run a domain routine from hypervisor - * @target_dom is the domain which routine is executed - * @current_mapped is the domain which page table is currently loaded. - * @current_mapped_mode indicates if we consider the swapper pgdir or the normal page table (see switch_mm() for complete description) - */ -void domain_call(struct domain *target_dom, int cmd, void *arg) +void do_domctl(domctl_t *args) { - struct domain *__current; - addr_t prev; - - /* IRQs are always disabled during a domcall */ - BUG_ON(local_irq_is_enabled()); + struct domain *d; - /* Switch the current domain to the target so that preserving the page table during - * subsequent memory context switch will not affect the original one. - */ - - __current = current_domain; + spin_lock(&domctl_lock); - /* Preserve the current pgtable address on the AGENCY CPU - * since we are about to move to the ME memory context. - */ - mmu_get_current_pgtable(&prev); + d = domains[args->domain]; - switch_mm_domain(target_dom); + switch (args->cmd) + { + case DOMCTL_pauseME: - BUG_ON(!target_dom->avz_shared->domcall_vaddr); + domain_pause_by_systemcontroller(d); + break; - /* Perform the domcall execution */ - ((domcall_t) target_dom->avz_shared->domcall_vaddr)(cmd, arg); + case DOMCTL_unpauseME: + + DBG("%s: unpausing ME\n", __func__); - set_current_domain(__current); + domain_unpause_by_systemcontroller(d); + break; - /* Switch back to the same page table (and potential attributes) as at the entry */ - mmu_switch_kernel((void *) prev); + case DOMCTL_get_AVZ_shared: + if (current_domain->avz_shared->domID == DOMID_AGENCY) + args->avz_shared_paddr = memslot[MEMSLOT_AGENCY].ipa_addr + memslot[MEMSLOT_AGENCY].size; + else + args->avz_shared_paddr = + memslot[current_domain->avz_shared->domID].ipa_addr + memslot[current_domain->avz_shared->domID].size; + break; + } + spin_unlock(&domctl_lock); } + diff --git a/so3/kernel/avz/domain_utils.c b/so3/avz/kernel/domain_utils.c similarity index 63% rename from so3/kernel/avz/domain_utils.c rename to so3/avz/kernel/domain_utils.c index 26b2c449b4..b28a17301c 100644 --- a/so3/kernel/avz/domain_utils.c +++ b/so3/avz/kernel/domain_utils.c @@ -16,6 +16,7 @@ * */ +#include #include #include @@ -90,14 +91,6 @@ addr_t __get_avz_fdt_paddr(void *agency_fdt_paddr) { BUG(); } - /* Let us map this DT since it will be accessed by early_memory_init() */ -#ifdef CONFIG_ARCH_ARM32 - ((uint32_t *) __sys_root_pgtable)[l1pte_index(avz_dt_paddr)] = avz_dt_paddr; - set_l1_pte_sect_dcache(&((uint32_t *) __sys_root_pgtable)[l1pte_index(avz_dt_paddr)], L1_SECT_DCACHE_WRITEALLOC); - - mmu_page_table_flush((uint32_t) __sys_root_pgtable, (uint32_t) (__sys_root_pgtable + TTB_L1_ENTRIES)); -#endif /* CONFIG_ARM32 */ - /* Assign the agency DT addr to the general __fdt_addr here * since loadAgency() will need it to parse the complete device tree. * It will be re-adjusted at the end of loadAgency(). @@ -118,19 +111,15 @@ void loadAgency(void) u64 dom_addr, avz_dt_addr; int count; int nodeoffset, next_node; - uint8_t tmp[16]; addr_t base; - size_t size; - int len, depth, ret; + int depth, ret; const char *propstring; + mem_info_t guest_mem_info; + void *fdt_vaddr = __fdt_addr; - void *fdt_vaddr = __fdt_addr; - -#ifdef CONFIG_ARM64VT - const struct fdt_property *initrd_start, *initrd_end; + const struct fdt_property *initrd_start, *initrd_end; u64 entry_addr; int lenp; -#endif ret = fdt_check_header(fdt_vaddr); if (ret) { @@ -151,8 +140,6 @@ void loadAgency(void) /* Process the type "avz" to get the AVZ device tree */ if ((ret != -1) && !strcmp(propstring, "avz_dt")) { - /* According to U-boot, the and properties are both on 64-bit even for aarch32 configuration. */ - ret = fdt_property_read_u64(fdt_vaddr, nodeoffset, "load", (u64 *) &avz_dt_addr); if (ret == -1) { lprintk("!! Missing load-addr in the avz_dt node !!\n"); @@ -162,8 +149,8 @@ void loadAgency(void) count++; } - /* Process the type "avz" to get the agency image */ - if ((ret != -1) && !strcmp(propstring, "avz")) { + /* Process the type "avz" to get the guest image */ + if ((ret != -1) && !strcmp(propstring, "guest")) { /* According to U-boot, the and properties are both on 64-bit even for aarch32 configuration. */ @@ -173,14 +160,13 @@ void loadAgency(void) BUG(); } lprintk("ITB: Domain load addr = 0x%lx\n", dom_addr); -#ifdef CONFIG_ARM64VT + ret = fdt_property_read_u64(fdt_vaddr, nodeoffset, "entry", (u64 *) &entry_addr); if (ret == -1) { lprintk("!! Missing entry in the agency node !!\n"); BUG(); } lprintk("ITB: Domain entry addr = 0x%lx\n", entry_addr); -#endif count++; } @@ -192,50 +178,39 @@ void loadAgency(void) BUG(); } - memslot[MEMSLOT_AVZ].fdt_paddr = avz_dt_addr; + memslot[MEMSLOT_AVZ].fdt_paddr = avz_dt_addr; /* Set the memslot base address to a 2 MB block boundary to ease mapping with ARM64 */ + memslot[MEMSLOT_AGENCY].base_paddr = dom_addr & ~(SZ_2M - 1); + memslot[MEMSLOT_AGENCY].base_vaddr = AGENCY_VOFFSET; - memslot[MEMSLOT_AGENCY].base_paddr = dom_addr & ~(SZ_2M - 1); - memslot[MEMSLOT_AGENCY].fdt_paddr = (addr_t) __fdt_addr; - memslot[MEMSLOT_AGENCY].size = fdt_getprop_u32_default(fdt_vaddr, "/agency", "domain-size", 0); - - memslot[MEMSLOT_AGENCY].entry_addr = AGENCY_VOFFSET + (dom_addr & (SZ_1M - 1)); + memslot[MEMSLOT_AGENCY].fdt_paddr = (addr_t) __fdt_addr; - if (!memslot[MEMSLOT_AGENCY].size) { - lprintk("!! Property domain-size is found at 0, maybe the agency node is missing...\n"); - BUG(); - } - -#ifdef CONFIG_ARM64VT - memslot[MEMSLOT_AGENCY].entry_addr = entry_addr; - memslot[MEMSLOT_AGENCY].ipa_addr = entry_addr & ~(SZ_1M - 1); - lprintk("IPA Layout: device tree located at 0x%lx\n", memslot[MEMSLOT_AGENCY].fdt_paddr); -#endif - - /* Fixup the agency device tree */ + /* Retrieve the memory addr and size of the guest */ + get_mem_info(fdt_vaddr, &guest_mem_info); - /* find or create "/memory" node. */ - nodeoffset = fdt_find_or_add_subnode(fdt_vaddr, 0, "memory"); - BUG_ON(nodeoffset < 0); + memslot[MEMSLOT_AGENCY].ipa_addr = (addr_t) guest_mem_info.phys_base; + memslot[MEMSLOT_AGENCY].size = guest_mem_info.size; - fdt_setprop(fdt_vaddr, nodeoffset, "device_type", "memory", sizeof("memory")); + memslot[MEMSLOT_AGENCY].entry_addr = entry_addr; - size = memslot[MEMSLOT_AGENCY].size; - -#ifdef CONFIG_ARM64VT - base = memslot[MEMSLOT_AGENCY].ipa_addr; -#else - base = memslot[MEMSLOT_AGENCY].base_paddr; -#endif - len = fdt_pack_reg(fdt_vaddr, tmp, &base, &size); + if (!memslot[MEMSLOT_AGENCY].size) { + lprintk("!! Property memory of the guest has a size of 0 byte...\n"); + BUG(); + } - fdt_setprop(fdt_vaddr, nodeoffset, "reg", tmp, len); + lprintk("IPA Layout: device tree located at 0x%lx\n", memslot[MEMSLOT_AGENCY].fdt_paddr); -#ifdef CONFIG_ARM64VT - /* Fixup of initrd_start and initrd_end */ + /* + * Fixup of initrd_start and initrd_end + * These addresses are *real* physical address retrieved from the ITS. + * However, Linux needs physical address in its virtualized RAM (IPA addresses), + * so we need to fixup these addresses. + * + */ nodeoffset = 0; depth = 0; + while (nodeoffset >= 0) { next_node = fdt_next_node(fdt_vaddr, nodeoffset, &depth); @@ -246,13 +221,13 @@ void loadAgency(void) BUG_ON(!initrd_end); base = fdt64_to_cpu(((const fdt64_t *) initrd_start->data)[0]); - base = phys_to_ipa(memslot[MEMSLOT_AGENCY], base); + base = pa_to_ipa(MEMSLOT_AGENCY, base); lprintk("IPA Layout: initrd start at 0x%lx\n", base); fdt_setprop_u64(fdt_vaddr, nodeoffset, "linux,initrd-start", base); base = fdt64_to_cpu(((const fdt64_t *) initrd_end->data)[0]); - base = phys_to_ipa(memslot[MEMSLOT_AGENCY], base); + base = pa_to_ipa(MEMSLOT_AGENCY, base); lprintk("IPA Layout: initrd end at 0x%lx\n", base); fdt_setprop_u64(fdt_vaddr, nodeoffset, "linux,initrd-end", base); @@ -261,18 +236,10 @@ void loadAgency(void) } nodeoffset = next_node; } -#endif /* Update our reference to the AVZ device tree */ __fdt_addr = (void *) memslot[MEMSLOT_AVZ].fdt_paddr; -#ifdef CONFIG_ARCH_ARM32 - /* Lets map the AVZ DT in the identity mapping */ - ((uint32_t *) __sys_root_pgtable)[l1pte_index(__fdt_addr)] = (addr_t) __fdt_addr; - set_l1_pte_sect_dcache(&((uint32_t *) __sys_root_pgtable)[l1pte_index(__fdt_addr)], L1_SECT_DCACHE_WRITEALLOC); - -#endif - /* Retrieve the memory info in the AVZ DT */ /* Access to device tree */ /* __fdt_addr MUST BE mapped in an identity mapping */ @@ -284,29 +251,33 @@ void loadAgency(void) lprintk(" AVZ memory descriptor : found %d MB of RAM at 0x%08X\n", mem_info.size / SZ_1M, mem_info.phys_base); memslot[MEMSLOT_AVZ].base_paddr = mem_info.phys_base; - memslot[MEMSLOT_AVZ].size = mem_info.size; + memslot[MEMSLOT_AVZ].base_vaddr = CONFIG_KERNEL_VADDR; + + /* Here, the memory size corresponds to the whole RAM base available in the platform */ + memslot[MEMSLOT_AVZ].size = mem_info.size; + memslot[MEMSLOT_AVZ].busy = true; } /** * The ITB image will be parsed and the components placed in their target memory location. + * This work only with ARM64VT support. * * @param slotID * @param itb ITB image */ void loadME(unsigned int slotID, void *itb) { void *ME_vaddr; - size_t ME_size, size, fdt_size, initrd_size; + uint32_t dom_addr, entry_addr, fdt_paddr; + size_t ME_size, fdt_size, initrd_size; void *fdt_vaddr, *initrd_vaddr; void *dest_ME_vaddr; uint32_t initrd_start, initrd_end; int nodeoffset, next_node, depth = 0; int ret; const char *propstring; - uint8_t tmp[16]; - addr_t base; - int len; + mem_info_t guest_mem_info; /* Look for a node of ME type in the fit image */ nodeoffset = 0; @@ -315,7 +286,21 @@ void loadME(unsigned int slotID, void *itb) { next_node = fdt_next_node(itb, nodeoffset, &depth); ret = fdt_property_read_string(itb, nodeoffset, "type", &propstring); - if ((ret != -1) && !strcmp(propstring, "ME")) { + if ((ret != -1) && !strcmp(propstring, "guest")) { + + ret = fdt_property_read_u32(itb, nodeoffset, "load", &dom_addr); + if (ret == -1) { + lprintk("!! Missing load-addr in the agency node !!\n"); + BUG(); + } + lprintk("ITB: Domain load addr = 0x%lx\n", dom_addr); + + ret = fdt_property_read_u32(itb, nodeoffset, "entry", &entry_addr); + if (ret == -1) { + lprintk("!! Missing entry in the agency node !!\n"); + BUG(); + } + lprintk("ITB: Domain entry addr = 0x%lx\n", entry_addr); /* Get the pointer to the OS binary image from the ITB we got from the user space. */ ret = fit_image_get_data_and_size(itb, nodeoffset, (const void **) &ME_vaddr, &ME_size); @@ -325,22 +310,30 @@ void loadME(unsigned int slotID, void *itb) { } else break; } + nodeoffset = next_node; } if (nodeoffset < 0) { lprintk("!! Unable to find a node with type ME in the FIT image... !!\n"); BUG(); - } + }; - /* Look for a node of flat_dt type in the fit image */ - nodeoffset = 0; + /* Look for a node of flat_dt type in the fit image */ + nodeoffset = 0; depth = 0; while (nodeoffset >= 0) { next_node = fdt_next_node(itb, nodeoffset, &depth); ret = fdt_property_read_string(itb, nodeoffset, "type", &propstring); + if ((ret != -1) && !strcmp(propstring, "flat_dt")) { + ret = fdt_property_read_u32(itb, nodeoffset, "load", &fdt_paddr); + if (ret == -1) { + lprintk("!! Missing load-addr in the agency node !!\n"); + BUG(); + } + /* Get the associated device tree. */ ret = fit_image_get_data_and_size(itb, nodeoffset, (const void **) &fdt_vaddr, &fdt_size); if (ret) { @@ -349,6 +342,7 @@ void loadME(unsigned int slotID, void *itb) { } else break; } + nodeoffset = next_node; } @@ -357,26 +351,13 @@ void loadME(unsigned int slotID, void *itb) { BUG(); } - /* Fixup the ME device tree */ - - /* find or create "/memory" node. */ - nodeoffset = fdt_find_or_add_subnode(fdt_vaddr, 0, "memory"); - BUG_ON(nodeoffset < 0); - - fdt_setprop(fdt_vaddr, nodeoffset, "device_type", "memory", sizeof("memory")); - - size = memslot[slotID].size; - -#ifdef CONFIG_ARM64VT - base = memslot[slotID].ipa_addr; -#else - base = memslot[slotID].base_paddr; -#endif - len = fdt_pack_reg(fdt_vaddr, tmp, &base, &size); - - fdt_setprop(fdt_vaddr, nodeoffset, "reg", tmp, len); + /* Retrieve the guest memory information */ + get_mem_info(fdt_vaddr, &guest_mem_info); + + /* From the DTS here, we consider the physical address as the IPA base address. */ + memslot[slotID].ipa_addr = guest_mem_info.phys_base; - /* Look for a possible node of ramdisk type in the fit image */ + /* Look for a possible node of ramdisk type in the fit image */ nodeoffset = 0; depth = 0; while (nodeoffset >= 0) { @@ -384,7 +365,13 @@ void loadME(unsigned int slotID, void *itb) { ret = fdt_property_read_string(itb, nodeoffset, "type", &propstring); if ((ret != -1) && !strcmp(propstring, "ramdisk")) { - /* Get the associated device tree. */ + ret = fdt_property_read_u32(itb, nodeoffset, "load", &initrd_start); + if (ret == -1) { + lprintk("!! Missing load-addr in the agency node !!\n"); + BUG(); + } + + /* Get the associated initrd ramfs */ ret = fit_image_get_data_and_size(itb, nodeoffset, (const void **) &initrd_vaddr, &initrd_size); if (ret) { lprintk("!! The properties in the ramdisk node does not look good !!\n"); @@ -392,53 +379,41 @@ void loadME(unsigned int slotID, void *itb) { } else break; } - nodeoffset = next_node; + + nodeoffset = next_node; } - dest_ME_vaddr = (void *) __lva(memslot[slotID].base_paddr); + dest_ME_vaddr = (void *) memslot[slotID].base_vaddr; - dest_ME_vaddr += L_TEXT_OFFSET; + dest_ME_vaddr += L_TEXT_OFFSET; - /* Move the kernel binary within the domain slotID. */ + /* Move the kernel binary within the domain slotID. */ memcpy(dest_ME_vaddr, ME_vaddr, ME_size); - /* Put the FDT device tree close to the top of memory allocated to the domain. - * Since there is the initial domain stack at the top, we put the FDT one page (PAGE_SIZE) lower. - */ - memslot[slotID].fdt_paddr = memslot[slotID].base_paddr + memslot[slotID].size - PAGE_SIZE; - - memcpy((void *) __lva(memslot[slotID].fdt_paddr), fdt_vaddr, fdt_size); + memslot[slotID].fdt_paddr = ipa_to_pa(slotID, fdt_paddr); - /* We put then the initrd (if any) right under the device tree. */ + memcpy((void *) __xva(slotID, memslot[slotID].fdt_paddr), fdt_vaddr, fdt_size); - if (ret == 0) { + /* still has the result of the ramdisk presence (see above). */ + if (ret == 0) { /* Expand the device tree */ - fdt_open_into((void *) __lva(memslot[slotID].fdt_paddr), (void *) __lva(memslot[slotID].fdt_paddr), fdt_size+128); + fdt_open_into((void *) __xva(slotID, memslot[slotID].fdt_paddr), + (void *) __xva(slotID, memslot[slotID].fdt_paddr), fdt_size+128); /* find or create "/chosen" node. */ - nodeoffset = fdt_find_or_add_subnode((void *) __lva(memslot[slotID].fdt_paddr), 0, "chosen"); + nodeoffset = fdt_find_or_add_subnode((void *) __xva(slotID, memslot[slotID].fdt_paddr), 0, "chosen"); BUG_ON(nodeoffset < 0); - - initrd_start = memslot[slotID].fdt_paddr - initrd_size; - initrd_start = ALIGN_DOWN(initrd_start, PAGE_SIZE); + initrd_end = initrd_start + initrd_size; -#ifdef CONFIG_ARCH_ARM32 - ret = fdt_setprop_u32((void *) __lva(memslot[slotID].fdt_paddr), nodeoffset, "linux,initrd-start", (uint32_t) initrd_start); + ret = fdt_setprop_u64((void *) __xva(slotID, memslot[slotID].fdt_paddr), nodeoffset, "linux,initrd-start", (uint32_t) initrd_start); BUG_ON(ret != 0); - ret = fdt_setprop_u32((void *) __lva(memslot[slotID].fdt_paddr), nodeoffset, "linux,initrd-end", (uint32_t) initrd_end); - BUG_ON(ret != 0); -#else - ret = fdt_setprop_u64((void *) __lva(memslot[slotID].fdt_paddr), nodeoffset, "linux,initrd-start", (uint32_t) initrd_start); + ret = fdt_setprop_u64((void *) __xva(slotID, memslot[slotID].fdt_paddr), nodeoffset, "linux,initrd-end", (uint32_t) initrd_end); BUG_ON(ret != 0); - ret = fdt_setprop_u64((void *) __lva(memslot[slotID].fdt_paddr), nodeoffset, "linux,initrd-end", (uint32_t) initrd_end); - BUG_ON(ret != 0); -#endif - - memcpy((void *) __lva(initrd_start), initrd_vaddr, initrd_size); - } + memcpy((void *) ipa_to_va(slotID, initrd_start), initrd_vaddr, initrd_size); + } } diff --git a/so3/kernel/avz/event_channel.c b/so3/avz/kernel/event_channel.c similarity index 76% rename from so3/kernel/avz/event_channel.c rename to so3/avz/kernel/event_channel.c index 7254e0fc58..1123884acd 100644 --- a/so3/kernel/avz/event_channel.c +++ b/so3/avz/kernel/event_channel.c @@ -20,19 +20,21 @@ #include #include -#include +#include #include #include #include #include - #include -#include #include #include +#if 1 +#define DEBUG +#endif + #define ERROR_EXIT(_errno) \ do { \ printk("EVTCHNOP failure: error %d\n", \ @@ -116,10 +118,10 @@ static void evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) { lchn = &ld->evtchn[levtchn]; rchn = &rd->evtchn[revtchn]; + + valid = ((rchn->state == ECS_INTERDOMAIN) && (rchn->interdomain.remote_dom == NULL)); - valid = ((rchn->state == ECS_INTERDOMAIN) && (rchn->interdomain.remote_dom == NULL)); - - if (!valid && ((rchn->state != ECS_UNBOUND) || (rchn->unbound.remote_domid != ld->avz_shared->domID))) + if (!valid && ((rchn->state != ECS_UNBOUND) || (rchn->unbound.remote_domid != ld->avz_shared->domID))) ERROR_EXIT_DOM(-EINVAL, rd); lchn->interdomain.remote_dom = rd; @@ -139,8 +141,8 @@ static void evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) { } /* - * Special routine called directly from hypervisor during post-migration sync to bind two event channels that we know exist and should now be connected! - * as well as from guest kernel in case of ME IMEC setup. In this latter case, event channels have been previously allocated with a remote_domid equal to local_domid. + * Special routine called directly from hypervisor during resuming to bind two event channels that we know exist and should now be connected! + * as * */ void evtchn_bind_existing_interdomain(struct domain *ld, struct domain *remote, int levtchn, int revtchn) { @@ -344,11 +346,7 @@ static void evtchn_set_pending(struct domain *d, int evtchn) { smp_mb(); -#ifndef CONFIG_ARM64VT - /* Because the return path is different than with full VT support */ - if (smp_processor_id() != d->processor) -#endif - smp_trigger_event(d->processor); + smp_trigger_event(d->processor); } void send_guest_virq(struct domain *d, int virq) { @@ -380,126 +378,40 @@ void send_guest_virq(struct domain *d, int virq) { spin_unlock_irqrestore(&d->virq_lock, flags); } -static void evtchn_status(evtchn_status_t *status) { - struct domain *d = domains[status->dom]; - int evtchn = status->evtchn; - struct evtchn *chn; - - spin_lock(&d->event_lock); - - chn = &d->evtchn[evtchn]; - - switch (chn->state) { - case ECS_FREE: - case ECS_RESERVED: - status->status = EVTCHNSTAT_closed; - break; +void do_event_channel_op(avz_hyp_t *args) { - case ECS_UNBOUND: - status->status = EVTCHNSTAT_unbound; - status->u.unbound.dom = chn->unbound.remote_domid; - break; - - case ECS_INTERDOMAIN: - status->status = EVTCHNSTAT_interdomain; - status->u.interdomain.dom = chn->interdomain.remote_dom->avz_shared->domID; - status->u.interdomain.evtchn = chn->interdomain.remote_evtchn; - break; - - case ECS_VIRQ: - status->status = EVTCHNSTAT_virq; - status->u.virq = chn->virq; - break; - - default: - BUG(); - } - - spin_unlock(&d->event_lock); -} - -void do_event_channel_op(int cmd, void *args) { - struct evtchn_alloc_unbound alloc_unbound; - - switch (cmd) { - case EVTCHNOP_alloc_unbound: { - - memcpy(&alloc_unbound, args, sizeof(struct evtchn_alloc_unbound)); - - evtchn_alloc_unbound(&alloc_unbound); - memcpy(args, &alloc_unbound, sizeof(struct evtchn_alloc_unbound)); - break; - } + switch (args->u.avz_evtchn.evtchn_op.cmd) { - case EVTCHNOP_bind_interdomain: { - - struct evtchn_bind_interdomain bind_interdomain; - - memcpy(&bind_interdomain, args, sizeof(struct evtchn_bind_interdomain)); + case EVTCHNOP_alloc_unbound: + evtchn_alloc_unbound(&args->u.avz_evtchn.evtchn_op.u.alloc_unbound); + break; + - evtchn_bind_interdomain(&bind_interdomain); - memcpy(args, &bind_interdomain, sizeof(struct evtchn_bind_interdomain)); + case EVTCHNOP_bind_interdomain: + evtchn_bind_interdomain(&args->u.avz_evtchn.evtchn_op.u.bind_interdomain); break; - } - - case EVTCHNOP_bind_existing_interdomain: { - - struct evtchn_bind_interdomain bind_interdomain; - - memcpy(&bind_interdomain, args, sizeof(struct evtchn_bind_interdomain)); + + case EVTCHNOP_bind_existing_interdomain: evtchn_bind_existing_interdomain(current_domain, - domains[bind_interdomain.remote_dom], - bind_interdomain.local_evtchn, - bind_interdomain.remote_evtchn); - - memcpy(args, &bind_interdomain, sizeof(struct evtchn_bind_interdomain)); - break; - } - - case EVTCHNOP_bind_virq: { - - struct evtchn_bind_virq bind_virq; - - memcpy(&bind_virq, args, sizeof(struct evtchn_bind_virq)); - - evtchn_bind_virq(&bind_virq); - memcpy(args, &bind_virq, sizeof(struct evtchn_bind_virq)); - break; - } + domains[args->u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_dom], + args->u.avz_evtchn.evtchn_op.u.bind_interdomain.local_evtchn, + args->u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_evtchn); + break; - case EVTCHNOP_close: { - - struct evtchn_close close; - - memcpy(&close, args, sizeof(struct evtchn_close)); - - evtchn_close(&close); + case EVTCHNOP_bind_virq: + evtchn_bind_virq(&args->u.avz_evtchn.evtchn_op.u.bind_virq); break; - } - - case EVTCHNOP_send: { - struct evtchn_send send; - - memcpy(&send, args, sizeof(struct evtchn_send)); - - evtchn_send(current_domain, send.evtchn); + case EVTCHNOP_close: + evtchn_close(&args->u.avz_evtchn.evtchn_op.u.close); + break; + + case EVTCHNOP_send: + evtchn_send(current_domain, args->u.avz_evtchn.evtchn_op.u.send.evtchn); break; - } - - case EVTCHNOP_status: { - - struct evtchn_status status; - - memcpy(&status, args, sizeof(struct evtchn_status)); - - evtchn_status(&status); - memcpy(args, &status, sizeof(struct evtchn_status)); - break; - } - - default: + + default: BUG(); break; } diff --git a/so3/avz/kernel/gnttab.c b/so3/avz/kernel/gnttab.c new file mode 100644 index 0000000000..ab87948d51 --- /dev/null +++ b/so3/avz/kernel/gnttab.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024-2025 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static DEFINE_SPINLOCK(gnttab_lock); + +void gnttab_init(struct domain *d) { + INIT_LIST_HEAD(&d->gnttab); +} + +/** + * @brief Get the highest value of ref of a grant table + * + * @param gnttab + * @return grant_ref_t : The highest reference + */ +grant_ref_t get_ref_max(struct list_head *gnttab) { + gnttab_t *cur; + grant_ref_t ref = GRANT_INVALID_REF; + + list_for_each_entry(cur, gnttab, list) + ref = ((cur->ref > ref) ? cur->ref : ref); + + ref = ((ref == GRANT_INVALID_REF) ? 1 : ref); + + return ref; +} + +/** + * @brief Find a granted page from a specific domain + * + * @param ref reference to the granted page + * @param origin_domid granted by this domain (ref is not unique accross granting domains) + * @return gnttab_t* + */ +gnttab_t *pick_granted_entry(grant_ref_t ref, domid_t origin_domid) { + gnttab_t *cur; + + list_for_each_entry(cur, &domains[origin_domid]->gnttab, list) { + + if ((cur->ref == ref) && (cur->origin_domid == origin_domid) && + (cur->target_domid == current_domain->avz_shared->domID)) + return cur; /* Found! */ + } + + return NULL; +} + +/** + * @brief Create a new grant table entry in the gnttab of a domain + * + * @param d The domain containing the grant table + * @param target_domid The domain concerned by this grant + * @param pfn The real frame number of the page to be granted + */ +gnttab_t *new_gnttab_entry(struct domain *d, domid_t target_domid, addr_t pfn) { + gnttab_t *gnttab; + + gnttab = malloc(sizeof(gnttab_t)); + BUG_ON(!gnttab); + + gnttab->origin_domid = d->avz_shared->domID; + gnttab->target_domid = target_domid; + gnttab->pfn = pfn; + + /* Determine the ref number for this entry */ + gnttab->ref = get_ref_max(&d->gnttab) + 1; + + list_add_tail(&gnttab->list, &d->gnttab); + + return gnttab; +} + +void revoke_gnttab_entry(struct domain *d, grant_ref_t ref) { + gnttab_t *cur; + + list_for_each_entry(cur, &d->gnttab, list) { + + if (cur->ref == ref) { + list_del(&cur->list); + free(cur); + return; + } + } + + /* In case of resuming, the list of gnttab is empty. */ +} + + +/** + * @brief Find a free grant pfn + * + * @param d + * @return addr_t pfn free to be used for mapping to granted page + */ +addr_t allocate_grant_pfn(struct domain *d) { + int i; + + for (i = 0; i < NR_GRANT_PFN; i++) + if (d->grant_pfn[i].free) { + d->grant_pfn[i].free = false; + return d->grant_pfn[i].pfn; + } + + /* Now, we don't consider no free grant pfn */ + BUG(); + + return 0; /* Make gcc happy :-) */ +} + +/** + * @brief Map the grant page associated to vbstore in the IPA domain of the ME + * + * @param target_domid the ME which needs the vbstore pfn + * @param pfn + * @return + */ +addr_t map_vbstore_pfn(int target_domid, int pfn) { + gnttab_t *cur; + addr_t grant_paddr; + struct domain *d; + + d = domains[target_domid]; + + list_for_each_entry(cur, &agency->gnttab, list) { + + if (cur->target_domid == target_domid) { + + /* Here, we get an IPA address corresponding to the grant page */ + if (pfn == 0) + grant_paddr = pfn_to_phys(allocate_grant_pfn(d)); + else + grant_paddr = pfn_to_phys(pfn); + + __create_mapping((addr_t *) d->pagetable_vaddr, grant_paddr, pfn_to_phys(cur->pfn), PAGE_SIZE, true, S2); + + return phys_to_pfn(grant_paddr); + } + } + + BUG(); + + return 0; +} + +/** + * @brief Hypercall entry for grant table related operations. + * + * @param args gnttab detail structure + */ +void do_gnttab(gnttab_op_t *args) +{ + struct domain *d; + addr_t paddr, grant_paddr; + gnttab_t *gnttab; + + spin_lock(&gnttab_lock); + + d = current_domain; + + switch (args->cmd) + { + case GNTTAB_grant_page: + + /* Create a new entry in the list of gnttab page */ + + paddr = ipa_to_pa(DOM_TO_MEMSLOT(d->avz_shared->domID), pfn_to_phys(args->pfn)); + + gnttab = new_gnttab_entry(d, args->domid, phys_to_pfn(paddr)); + + args->ref = gnttab->ref; + + break; + + case GNTTAB_revoke_page: + revoke_gnttab_entry(d, args->ref); + break; + + case GNTTAB_map_page: + + /* Retrieve the original granted page */ + gnttab = pick_granted_entry(args->ref, args->domid); + BUG_ON(!gnttab); + + /* Here, we get an IPA address corresponding to the grant page */ + grant_paddr = pfn_to_phys(allocate_grant_pfn(d)); + + /* This pfn will be exported to the domain */ + args->pfn = phys_to_pfn(grant_paddr); + + __create_mapping((addr_t *) d->pagetable_vaddr, grant_paddr, pfn_to_phys(gnttab->pfn), PAGE_SIZE, true, S2); + + break; + + case GNTTAB_unmap_page: + /* to be completed */ + break; + } + + spin_unlock(&gnttab_lock); +} + diff --git a/so3/kernel/avz/image-fit.c b/so3/avz/kernel/image-fit.c similarity index 100% rename from so3/kernel/avz/image-fit.c rename to so3/avz/kernel/image-fit.c diff --git a/so3/avz/kernel/injector.c b/so3/avz/kernel/injector.c new file mode 100644 index 0000000000..429655dde1 --- /dev/null +++ b/so3/avz/kernel/injector.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2014-2022 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +/* + * Structures to store domain context. Must be here and not locally in function, + * since the maximum stack size is 8 KB + */ +static struct dom_context domain_context = {0}; + +/** + * @brief Inject a SO3 container (capsule) as guest domain. + * + * At the entry of this function, the ME ITB could have been allocated in the user space (via the injector application) + * or in the vmalloc'd area of the Linux kernel in case of a BT transfer from the tablet (using vuihandler). + * + * To get rid of the way how the page tables are managed by Linux, we perform a copy of the ME ITB in the + * AVZ heap, assuming that the 8-MB heap is sufficient to host the ITB ME (< 2 MB in most cases). + * + * If the ITB should become larger, it is still possible to compress (and enhance AVZ with a uncompressor invoked + * at loading time). Wouldn't be still not enough, a temporary fixmap mapping combined with get_free_pages should be envisaged + * to have the ME ITB accessible from the AVZ user space area. + * + * @param args args received from the guest + */ +void inject_me(avz_hyp_t *args) +{ + int slotID; + size_t fdt_size; + void *fdt_vaddr; + struct domain *domME, *__current; + void *itb_vaddr; + mem_info_t guest_mem_info; + + DBG("%s: Preparing ME injection, source image vaddr = %lx\n", __func__, + ipa_to_va(MEMSLOT_AGENCY, args->u.avz_inject_me_args.itb_paddr)); + + BUG_ON(local_irq_is_enabled()); + + itb_vaddr = (void *) ipa_to_va(MEMSLOT_AGENCY, args->u.avz_inject_me_args.itb_paddr); + + DBG("%s: ITB vaddr: %lx\n", __func__, itb_vaddr); + + /* Retrieve the domain size of this ME through its device tree. */ + fit_image_get_data_and_size(itb_vaddr, fit_image_get_node(itb_vaddr, "fdt"), (const void **) &fdt_vaddr, &fdt_size); + if (!fdt_vaddr) { + printk("### %s: wrong device tree.\n", __func__); + BUG(); + } + + get_mem_info(fdt_vaddr, &guest_mem_info); + + /* Find a slotID to store this ME. */ + slotID = get_ME_free_slot(guest_mem_info.size); + if (slotID == -1) + goto out; + + domME = domains[slotID]; + + /* At the beginning, the capsule is booting */ + domME->avz_shared->dom_desc.u.ME.state = ME_state_booting; + + /* Set the size of this ME in its own descriptor with the dom_context size */ + domME->avz_shared->dom_desc.u.ME.size = memslot[slotID].size; + + __current = current_domain; + + /* Clear the RAM allocated to this ME */ + memset((void *) __xva(slotID, memslot[slotID].base_paddr), 0, memslot[slotID].size); + + loadME(slotID, itb_vaddr); + + if (construct_ME(domains[slotID]) != 0) + panic("Could not set up ME guest OS\n"); + +out: + /* Prepare to return the slotID to the caller. */ + args->u.avz_inject_me_args.slotID = slotID; + + raise_softirq(SCHEDULE_SOFTIRQ); + + domME->avz_shared->dom_desc.u.ME.vbstore_pfn = map_vbstore_pfn(slotID, 0); + domME->avz_shared->dom_desc.u.ME.vbstore_revtchn = agency->avz_shared->dom_desc.u.agency.vbstore_evtchn[slotID]; + + domain_unpause_by_systemcontroller(domME); +} + +/*------------------------------------------------------------------------------ +build_domain_migration_info +build_vcpu_migration_info + Build the structures holding the key info to be migrated over +------------------------------------------------------------------------------*/ +static void build_domain_context(unsigned int ME_slotID, struct domain *me, struct dom_context *domctxt) +{ + /* Event channel info */ + memcpy(domctxt->evtchn, me->evtchn, sizeof(me->evtchn)); + + /* Preserve the current system time to facilitate resuming after hibernation */ + me->avz_shared->current_s_time = NOW(); + + /* Get the start_info structure */ + domctxt->avz_shared = *(me->avz_shared); + strcpy(domctxt->avz_shared.signature, SOO_ME_SIGNATURE); + + /* Update the state for the ME instance which will migrate. */ + domctxt->avz_shared.dom_desc.u.ME.state = ME_state_hibernate; + + domctxt->pause_count = me->pause_count; + + domctxt->need_periodic_timer = me->need_periodic_timer; + + /* Pause */ + domctxt->pause_flags = me->pause_flags; + + memcpy(&domctxt->grant_pfn, &me->grant_pfn, sizeof(me->grant_pfn)); + + memcpy(&(domctxt->pause_count), &(me->pause_count), sizeof(me->pause_count)); + + /* VIRQ mapping */ + memcpy(domctxt->virq_to_evtchn, me->virq_to_evtchn, sizeof((me->virq_to_evtchn))); + + /* Store the IPA physical address base */ + domctxt->ipa_addr = memslot[ME_slotID].ipa_addr; + + /* + * CPU regs context along the exception path in the hypervisor + * right before the context switch. During the context switch, + * By far not all registers are preserved. + */ + domctxt->vcpu = me->vcpu; + + /* Store the stack frame of this domain */ + memcpy(&domctxt->stack_frame, + (void *) (me->domain_stack + DOMAIN_STACK_SIZE - sizeof(struct cpu_regs)), + sizeof(struct cpu_regs)); +} + +/** + * Read the ME snapshot. + */ +void read_ME_snapshot(avz_hyp_t *args) { + unsigned int slotID = args->u.avz_snapshot_args.slotID; + struct domain *domME = domains[slotID]; + void *snapshot_buffer = (void *) ipa_to_va(MEMSLOT_AGENCY, args->u.avz_snapshot_args.snapshot_paddr); + + /* If the size is 0, we return the snapshot size. */ + if (args->u.avz_snapshot_args.size == 0) { + args->u.avz_snapshot_args.size = sizeof(uint32_t) + memslot[slotID].size + sizeof(domain_context); + return; + } + + BUG_ON(domME->avz_shared->dom_desc.u.ME.state != ME_state_suspended); + + /* Pause the ME */ + domain_pause_by_systemcontroller(domME); + + /* Gather all the info we need into structures */ + build_domain_context(slotID, domME, &domain_context); + + /* Copy the size of the payload which is made of the dom_info structure and the ME */ + args->u.avz_snapshot_args.size = memslot[slotID].size + sizeof(domain_context); + + memcpy(snapshot_buffer, &args->u.avz_snapshot_args.size, sizeof(uint32_t)); + args->u.avz_snapshot_args.size += sizeof(uint32_t); + + /* Copy the dom_info structure */ + memcpy(snapshot_buffer + sizeof(uint32_t), &domain_context, sizeof(domain_context)); + + /* Finally copy the ME */ + memcpy(snapshot_buffer + sizeof(uint32_t) + sizeof(domain_context), (void *) __xva(slotID, memslot[slotID].base_paddr), memslot[slotID].size); + + /* Now, this ME is suspended and must be resumed by the agency */ + domME->avz_shared->dom_desc.u.ME.state = ME_state_resuming; + + domain_unpause_by_systemcontroller(domME); +} + +/*------------------------------------------------------------------------------ +restore_domain_migration_info +restore_vcpu_migration_info + Restore the migration info in the new ME structure + Those function are actually exported and called in domain_migrate_restore.c + They were kept in this file because they are the symmetric functions of + build_domain_migration_info() and build_vcpu_migration_info() +------------------------------------------------------------------------------*/ + +void restore_domain_context(unsigned int ME_slotID, struct domain *me, struct dom_context *domctxt) +{ + int i; + + DBG("%s\n", __func__); + + *(me->avz_shared) = domctxt->avz_shared; + + /* Check that our signature is valid so that the image transfer should be good. */ + if (strcmp(me->avz_shared->signature, SOO_ME_SIGNATURE)) + panic("%s: Cannot find the correct signature in the shared page (" SOO_ME_SIGNATURE ")...\n", __func__); + + /* Update the domID of course */ + me->avz_shared->domID = ME_slotID; + + memcpy(me->evtchn, domctxt->evtchn, sizeof(me->evtchn)); + + /* + * We reconfigure the inter-domain event channel so that we unbind the link to the previous + * remote domain (the agency in most cases), but we keep the state as it is since we do not + * want that the local event channel gets changed. + * + * Re-binding is performed during the resuming via vbus (backend side) OR + * if the ME gets killed, the event channel will be closed without any effect to a remote domain. + */ + + for (i = 0; i < NR_EVTCHN; i++) + if (me->evtchn[i].state == ECS_INTERDOMAIN) + me->evtchn[i].interdomain.remote_dom = NULL; + + me->pause_count = domctxt->pause_count; + me->need_periodic_timer = domctxt->need_periodic_timer; + + /* Pause */ + me->pause_flags = domctxt->pause_flags; + + memcpy(&me->grant_pfn, &domctxt->grant_pfn, sizeof(me->grant_pfn)); + + memcpy(&(me->pause_count), &(domctxt->pause_count), sizeof(me->pause_count)); + + /* VIRQ mapping */ + memcpy(me->virq_to_evtchn, domctxt->virq_to_evtchn, sizeof((me->virq_to_evtchn))); + + /* IPA physical address base */ + memslot[ME_slotID].ipa_addr = domctxt->ipa_addr; + + /* Fields related to CPU */ + me->vcpu = domctxt->vcpu; +} + +void write_ME_snapshot(avz_hyp_t *args) { + uint32_t snapshot_size; + void *snapshot_buffer; + uint32_t slotID; + struct domain *domME; + struct dom_context *domctxt; + void *dom_stack; + struct cpu_regs *frame; + + slotID = args->u.avz_snapshot_args.slotID; + snapshot_size = args->u.avz_snapshot_args.size; + + /* Ask for available slot and perform the reservation */ + if (slotID == 0) { + slotID = get_ME_free_slot(snapshot_size - sizeof(uint32_t) - sizeof(struct dom_context)); + if (slotID > 0) + args->u.avz_snapshot_args.slotID = slotID; + return ; + } + + snapshot_buffer = (void *) ipa_to_va(MEMSLOT_AGENCY, args->u.avz_snapshot_args.snapshot_paddr); + + domME = domains[slotID]; + domctxt = (struct dom_context *) (snapshot_buffer + sizeof(uint32_t)); + + restore_domain_context(slotID, domME, domctxt); + + __setup_dom_pgtable(domME, memslot[slotID].base_paddr, memslot[slotID].size); + + /* Copy the ME content */ + memcpy((void *) __xva(slotID, memslot[slotID].base_paddr), snapshot_buffer + sizeof(uint32_t) + sizeof(struct dom_context), + memslot[slotID].size); + + /* Create a stack devoted to this restored domain */ + + dom_stack = memalign(DOMAIN_STACK_SIZE, DOMAIN_STACK_SIZE); + BUG_ON(!dom_stack); + + /* Keep the reference for future removal */ + domME->domain_stack = dom_stack; + + /* Reserve the frame which will be restored later */ + frame = dom_stack + DOMAIN_STACK_SIZE - sizeof(cpu_regs_t); + + /* Restore the EL2 frame */ + memcpy(frame, &domctxt->stack_frame, sizeof(struct cpu_regs)); + + /* We need to re-map the vbstore page corresponding to this slotID */ + map_vbstore_pfn(domME->avz_shared->domID, domME->avz_shared->dom_desc.u.ME.vbstore_pfn); + + /* As we will be resumed from the schedule function, we need to update the + * CPU registers from the VCPU regs. + */ + domME->vcpu.regs.sp = (unsigned long) frame; + domME->vcpu.regs.x21 = (unsigned long) domME->avz_shared->dom_desc.u.ME.resume_fn; + + domME->vcpu.regs.lr = (unsigned long) resume_to_guest; + + /* Now restoring event channel configuration */ + evtchn_bind_existing_interdomain(domME, agency, domME->avz_shared->dom_desc.u.ME.vbstore_levtchn, + agency->avz_shared->dom_desc.u.agency.vbstore_evtchn[slotID]); + + DBG("[soo:avz] %s: Rebinding directcomm event channels: %d (agency) <-> %d (ME)\n", __func__, + agency->avz_shared->dom_desc.u.agency.dc_evtchn[slotID], + domME->avz_shared->dom_desc.u.ME.dc_evtchn); + + evtchn_bind_existing_interdomain(domME, agency, domME->avz_shared->dom_desc.u.ME.dc_evtchn, agency->avz_shared->dom_desc.u.agency.dc_evtchn[slotID]); + + DBG("%s: Now, resuming ME slotID %d...\n", __func__, slotID); + + domain_unpause_by_systemcontroller(domME); +} + +void __sigreturn(void) { + current_domain->avz_shared->dom_desc.u.ME.state = ME_state_awakened; + + send_timer_event(current_domain); +} \ No newline at end of file diff --git a/so3/kernel/avz/keyhandler.c b/so3/avz/kernel/keyhandler.c similarity index 99% rename from so3/kernel/avz/keyhandler.c rename to so3/avz/kernel/keyhandler.c index b35243eabb..956ec660ef 100644 --- a/so3/kernel/avz/keyhandler.c +++ b/so3/avz/kernel/keyhandler.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/so3/kernel/avz/sched_flip.c b/so3/avz/kernel/sched_flip.c similarity index 94% rename from so3/kernel/avz/sched_flip.c rename to so3/avz/kernel/sched_flip.c index 6cbe0e7fb1..b47c257627 100644 --- a/so3/kernel/avz/sched_flip.c +++ b/so3/avz/kernel/sched_flip.c @@ -28,7 +28,6 @@ #include #include #include -#include DEFINE_SPINLOCK(schedflip_lock); @@ -73,7 +72,11 @@ struct task_slice flip_do_schedule(void) sd->current_dom = (sd->current_dom + 1) % MAX_DOMAINS; ret.d = domains_runnable[sd->current_dom]; - loopmax--; + /* Currently, a domain is attached to a dedicated CPU */ + if ((ret.d != NULL) && (ret.d->processor != smp_processor_id())) + ret.d = NULL; + + loopmax--; } while ((ret.d == NULL) && loopmax); if (ret.d == NULL) diff --git a/so3/kernel/avz/schedule.c b/so3/avz/kernel/schedule.c similarity index 78% rename from so3/kernel/avz/schedule.c rename to so3/avz/kernel/schedule.c index bb9e45558a..cbc745df0b 100644 --- a/so3/kernel/avz/schedule.c +++ b/so3/avz/kernel/schedule.c @@ -24,7 +24,9 @@ #include -#include +#include + +#include #include #include #include @@ -81,6 +83,44 @@ void vcpu_wake(struct domain *d) } +/** + * @brief Save the CPU-related parameters which are specific to the domain + * The TTBRx registers are updated during memory context switch. + * @param d + */ +void vcpu_save_context(struct domain *d) { + d->vcpu.sctlr_el1 = read_sysreg(sctlr_el1); + d->vcpu.vbar_el1 = read_sysreg(vbar_el1); + d->vcpu.ttbr0_el1 = read_sysreg(ttbr0_el1); + d->vcpu.ttbr1_el1 = read_sysreg(ttbr1_el1); + d->vcpu.tcr_el1 = read_sysreg(tcr_el1); + d->vcpu.mair_el1 = read_sysreg(mair_el1); +} + + +/** + * @brief Restore the CPU-related parameters which are specific to the domain + * + * @param d + */ +void vcpu_restore_context(struct domain *d) { + + /* Restore the CPU control register state */ + write_sysreg(d->vcpu.sctlr_el1, sctlr_el1); + write_sysreg(d->vcpu.vbar_el1, vbar_el1); + write_sysreg(d->vcpu.ttbr0_el1, ttbr0_el1); + write_sysreg(d->vcpu.ttbr1_el1, ttbr1_el1); + write_sysreg(d->vcpu.tcr_el1, tcr_el1); + write_sysreg(d->vcpu.mair_el1, mair_el1); + + gic_clear_pending_irqs(); + + /* Check for pending vIRQs for this domain */ + if (current_domain->avz_shared->evtchn_upcall_pending) + gic_set_pending(IPI_EVENT_CHECK); + +} + void sched_destroy_domain(struct domain *d) { kill_timer(&d->oneshot_timer); @@ -164,9 +204,9 @@ static void domain_schedule(void) struct schedule_data *sd; struct task_slice next_slice; - ASSERT(local_irq_is_disabled()); + ASSERT(local_irq_is_disabled()); - ASSERT(prev->runstate == RUNSTATE_running); + ASSERT(prev->runstate == RUNSTATE_running); /* To avoid that another CPU manipulates scheduler data structures */ /* Maybe the lock is already acquired from do_sleep() for example */ @@ -183,7 +223,7 @@ static void domain_schedule(void) next = next_slice.d; #ifdef CONFIG_SOO - if (next_slice.time > 0ull) + if (next_slice.time > 0ull) set_timer(&next->sched->sched_data.s_timer, NOW() + MILLISECS(next_slice.time)); #endif /* CONFIG_SOO */ @@ -201,12 +241,12 @@ static void domain_schedule(void) ASSERT(next->runstate != RUNSTATE_running); domain_runstate_change(next, RUNSTATE_running); - ASSERT(!next->is_running); + ASSERT(!next->is_running); next->is_running = 1; -#if 0 +#if 0 /* debug */ printk("### running on cpu: %d prev: %d next: %d\n", smp_processor_id(), prev->avz_shared->domID, next->avz_shared->domID); -#endif +#endif /* 0 */ /* We do not unlock the schedulder_lock until everything has been processed */ @@ -221,10 +261,15 @@ static struct task_slice agency_schedule(void) { struct task_slice ts; - ts.d = domains[0]; - ts.time = 0; + /* No domain must be scheduled on CPU #1 since it is fully handled by Linux */ + if (smp_processor_id() == AGENCY_CPU) + ts.d = domains[0]; + else + ts.d = idle_domain[smp_processor_id()]; + + ts.time = 0; - return ts; + return ts; } static void agency_wake(struct domain *d) { diff --git a/so3/kernel/avz/setup.c b/so3/avz/kernel/setup.c similarity index 97% rename from so3/kernel/avz/setup.c rename to so3/avz/kernel/setup.c index 701f479277..0020fe531d 100644 --- a/so3/kernel/avz/setup.c +++ b/so3/avz/kernel/setup.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include @@ -148,11 +148,6 @@ void avz_start(void) smp_init(); -#ifdef CONFIG_ARCH_ARM32 - /* Enabling VFP module on this CPU */ - vfp_enable(); -#endif - printk("Now, unpausing the agency domain and doing its bootstrap...\n"); domain_unpause_by_systemcontroller(agency); diff --git a/so3/avz/kernel/soo_activity.c b/so3/avz/kernel/soo_activity.c new file mode 100644 index 0000000000..a5ca25e5ae --- /dev/null +++ b/so3/avz/kernel/soo_activity.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2014-2018 Daniel Rossier + * Copyright (C) 2018 Baptiste Delporte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Return the state of the ME corresponding to the ME_slotID. + * If the ME does not exist anymore (for example, following a KILL_ME), + * the state is set to ME_state_dead. + */ +ME_state_t get_ME_state(unsigned int ME_slotID) { + if (domains[ME_slotID] == NULL) + return ME_state_dead; + else + return domains[ME_slotID]->avz_shared->dom_desc.u.ME.state; + +} + +void set_ME_state(unsigned int ME_slotID, ME_state_t state) { + domains[ME_slotID]->avz_shared->dom_desc.u.ME.state = state; +} + +void shutdown_ME(unsigned int ME_slotID) +{ + struct domain *dom; + + dom = domains[ME_slotID]; + + /* Perform a removal of ME */ + dom->is_dying = DOMDYING_dead; + DBG("Shutdowning slotID: %d - Domain pause nosync ...\n", ME_slotID); + + vcpu_pause(dom); + + DBG("Destroy evtchn if necessary - state: %d\n", get_ME_state(ME_slotID)); + evtchn_destroy(dom); + + DBG("Wiping domain area...\n"); + + memset((void *) memslot[ME_slotID].base_vaddr, 0, memslot[ME_slotID].size); + + DBG("Destroying domain structure ...\n"); + + domain_destroy(dom); + + DBG("Now resetting domains to NULL.\n"); + + /* bye bye dear ME ! */ + domains[ME_slotID] = NULL; + + /* Reset the slot availability */ + put_ME_slot(ME_slotID); +} + +/** + * Return the descriptor of a domain (agency or ME). + * A size of 0 means there is no ME in the slot. + */ +void get_dom_desc(uint32_t slotID, dom_desc_t *dom_desc) { + /* Check for authorization... (to be done) */ + + /* + * If no ME is present in the slot specified by slotID, we assign a size of 0 in the ME descriptor. + * We presume that the slotID of agency is never free... + */ + + if ((slotID > 1) && !memslot[slotID].busy) + dom_desc->u.ME.size = 0; + else + /* Copy the content to the target desc */ + memcpy(dom_desc, &domains[slotID]->avz_shared->dom_desc, sizeof(dom_desc_t)); + +} + +/** + * SOO hypercall processing. + */ +void do_avz_hypercall(avz_hyp_t *args) { + struct domain *dom; + + /* Dispatch the hypercall to the appropriate handler + * or do the local processing. + */ + + switch (args->cmd) { + + case AVZ_CONSOLE_IO_OP: + do_console_io(&args->u.avz_console_io_args.console); + break; + + case AVZ_DOMAIN_CONTROL_OP: + do_domctl(&args->u.avz_domctl_args.domctl); + break; + + case AVZ_EVENT_CHANNEL_OP: + do_event_channel_op(args); + break; + + case AVZ_GRANT_TABLE_OP: + do_gnttab(&args->u.avz_gnttab_args.gnttab_op); + break; + + case AVZ_GET_DOM_DESC: + get_dom_desc(args->u.avz_dom_desc_args.slotID, &args->u.avz_dom_desc_args.dom_desc); + break; + + case AVZ_ME_READ_SNAPSHOT: + read_ME_snapshot(args); + break; + + case AVZ_ME_WRITE_SNAPSHOT: + write_ME_snapshot(args); + break; + + case AVZ_INJECT_ME: + inject_me(args); + break; + + case AVZ_DC_EVENT_SET: + /* + * AVZ_DC_SET is used to assign a new dc_event number in the (target) domain shared info page. + * This has to be done atomically so that if there is still a "pending" value in the field, + * the hypercall must return with -BUSY; in this case, the caller has to busy-loop (using schedule preferably) + * until the field gets free, i.e. set to DC_NO_EVENT. + */ + + dom = domains[args->u.avz_dc_event_args.domID]; + BUG_ON(dom == NULL); + + /* The shared info page is set as non cacheable, i.e. if a CPU tries to update it, it becomes visible to other CPUs */ + if (atomic_cmpxchg(&dom->avz_shared->dc_event, DC_NO_EVENT, args->u.avz_dc_event_args.dc_event) != DC_NO_EVENT) + args->u.avz_dc_event_args.state = -EBUSY; + else + args->u.avz_dc_event_args.state = ESUCCESS; + break; + + case AVZ_KILL_ME: + + shutdown_ME(args->u.avz_kill_me_args.slotID); + + break; + + case AVZ_GET_ME_STATE: + args->u.avz_me_state_args.state = get_ME_state(args->u.avz_me_state_args.slotID); + break; + + case AVZ_SET_ME_STATE: + { + set_ME_state(args->u.avz_me_state_args.slotID, args->u.avz_me_state_args.state); + break; + } + + default: + printk("%s: Unrecognized hypercall: %d\n", __func__, args->cmd); + BUG(); + break; + } + + flush_dcache_all(); +} + +void soo_activity_init(void) { + + DBG("Setting SOO avz up ...\n"); +} + diff --git a/so3/kernel/avz/timer.c b/so3/avz/kernel/timer.c similarity index 85% rename from so3/kernel/avz/timer.c rename to so3/avz/kernel/timer.c index 682bffaba4..5cf27007a2 100644 --- a/so3/kernel/avz/timer.c +++ b/so3/avz/kernel/timer.c @@ -21,7 +21,6 @@ #include #include -#include #include void timer_interrupt(bool periodic) { @@ -29,7 +28,7 @@ void timer_interrupt(bool periodic) { if (periodic) { - /* Now check for ticking the non-realtime domains which need periodic ticks. */ + /* Now check for ticking the guest containers which need periodic ticks. */ for (i = 2; i < MAX_DOMAINS; i++) { /* * We have to check if the domain exists and its VCPU has been created. If not, @@ -37,17 +36,15 @@ void timer_interrupt(bool periodic) { */ if ((domains[i] != NULL) && !domains[i]->is_dying) { if ((domains[i]->runstate == RUNSTATE_running) || (domains[i]->runstate == RUNSTATE_runnable)) { - if (domains[i]->need_periodic_timer) - + if (domains[i]->need_periodic_timer) + /* Forward to the guest */ send_timer_event(domains[i]); } } } } - - /* Raise a softirq on the CPU which is processing the interrupt. */ - raise_softirq(TIMER_SOFTIRQ); + raise_softirq(TIMER_SOFTIRQ); } extern void send_guest_virq(struct domain *d, int virq); diff --git a/so3/mm/avz/Makefile b/so3/avz/mm/Makefile similarity index 100% rename from so3/mm/avz/Makefile rename to so3/avz/mm/Makefile diff --git a/so3/mm/avz/memory.c b/so3/avz/mm/memory.c similarity index 60% rename from so3/mm/avz/memory.c rename to so3/avz/mm/memory.c index 6219dfcaa0..7a9fe97181 100644 --- a/so3/mm/avz/memory.c +++ b/so3/avz/mm/memory.c @@ -28,6 +28,10 @@ #include #include +#include + +#include + #include #define ME_MEMCHUNK_SIZE 2 * 1024 * 1024 @@ -67,37 +71,23 @@ unsigned int get_power_from_size(unsigned int bits_NR) { * * Returns the physical start address or 0 if no slot available. */ -unsigned int allocate_memslot(unsigned int order) { +static unsigned int allocate_memslot(unsigned int order) { int pos; pos = bitmap_find_free_region((unsigned long *) &memchunk_bitmap, ME_MEMCHUNK_NR, order); if (pos < 0) return 0; -#ifdef DEBUG - printk("allocate_memslot param %d\n", order); - printk("allocate_memslot pos %d\n", pos); - printk("allocate_memslot memslot1start %08x\n", (unsigned int) memslot[1].base_paddr); - printk("allocate_memslot memslot1size %d\n", memslot[1].size); - printk("allocate_memslot pos*MEMCHUNK_SIZE %d\n", pos*ME_MEMCHUNK_SIZE); -#endif - return memslot[1].base_paddr + memslot[1].size + pos*ME_MEMCHUNK_SIZE; } -void release_memslot(unsigned int addr, unsigned int order) { +static void release_memslot(unsigned int addr, unsigned int order) { int pos; pos = addr - memslot[1].base_paddr - memslot[1].size; pos /= ME_MEMCHUNK_SIZE; -#ifdef DEBUG - printk("release_memslot addr %08x\n", addr); - printk("release_memslot order %d\n", order); - printk("release_memslot pos %d\n", pos); -#endif - - bitmap_release_region((unsigned long *) &memchunk_bitmap, pos, order); + bitmap_release_region((unsigned long *) &memchunk_bitmap, pos, order); } /* @@ -108,21 +98,16 @@ void release_memslot(unsigned int addr, unsigned int order) { */ void switch_mm_domain(struct domain *d) { addr_t current_pgtable_paddr; + + mmu_get_current_pgtable(¤t_pgtable_paddr); - mmu_get_current_pgtable(¤t_pgtable_paddr); - - if (current_pgtable_paddr == d->avz_shared->pagetable_paddr) + if (current_pgtable_paddr == d->pagetable_paddr) /* Check if the current page table is identical to the next one. */ return ; - set_current_domain(d); - -#ifdef CONFIG_ARM64VT - __mmu_switch_kernel((void *) d->avz_shared->pagetable_paddr, true); -#else - mmu_switch_kernel((void *) d->avz_shared->pagetable_paddr); -#endif + set_current_domain(d); + __mmu_switch_kernel((void *) d->pagetable_paddr, true); } /** @@ -132,7 +117,7 @@ void switch_mm_domain(struct domain *d) { * @param ME_state Initial state of the ME * @return -1 if no slot is available or if a slot is available. */ -int get_ME_free_slot(unsigned int size, ME_state_t ME_state) { +int get_ME_free_slot(unsigned int size) { unsigned int order, addr; int slotID; unsigned int bits_NR; @@ -156,62 +141,20 @@ int get_ME_free_slot(unsigned int size, ME_state_t ME_state) { if (!addr) return -1; /* No available memory */ - memslot[slotID].base_paddr = addr; - memslot[slotID].size = (1 << order) * ME_MEMCHUNK_SIZE; /* Readjust size */ - memslot[slotID].busy = true; - -#ifdef DEBUG - printk("get_ME_slot param %d\n", size); - printk("get_ME_slot bits_NR %d\n", bits_NR); - printk("get_ME_slot slotID %d\n", slotID); - printk("get_ME_slot start %08x\n", (unsigned int) memslot[slotID].base_paddr); - printk("get_ME_slot size %d\n", memslot[slotID].size); -#endif - - /* Create a domain context including the ME descriptor before the ME gets injected. */ - - domains[slotID] = domain_create(slotID, ME_CPU); - - /* Initialize the ME descriptor */ - set_ME_state(slotID, ME_state); - - return slotID; -} - -int prepare_ME_slot(int slotID, unsigned int size, ME_state_t ME_state) { - unsigned int order, addr; - unsigned int bits_NR; - - /* memslot[slotID] is available */ - - bits_NR = DIV_ROUND_UP(size, ME_MEMCHUNK_SIZE); - - order = get_power_from_size(bits_NR); - - addr = allocate_memslot(order); + /* Determine the phys/virt start addresses of the guest */ + + memslot[slotID].base_paddr = addr; + memslot[slotID].base_vaddr = ME_BASE + ((addr_t) (slotID - 1) << ME_ID_SHIFT); - if (!addr) - return -1; /* No available memory */ - - memslot[slotID].base_paddr = addr; - memslot[slotID].size = (1 << order) * ME_MEMCHUNK_SIZE; /* Readjust size */ + memslot[slotID].size = (1 << order) * ME_MEMCHUNK_SIZE; /* Readjust size */ memslot[slotID].busy = true; -#ifdef DEBUG - printk("get_ME_slot param %d\n", size); - printk("get_ME_slot bits_NR %d\n", bits_NR); - printk("get_ME_slot slotID %d\n", slotID); - printk("get_ME_slot start %08x\n", (unsigned int) memslot[slotID].base_paddr); - printk("get_ME_slot size %d\n", memslot[slotID].size); -#endif + /* Map the L2 virtual address space of ME #(slotID-1) to the physical RAM */ + create_mapping(NULL, memslot[slotID].base_vaddr, memslot[slotID].base_paddr, memslot[slotID].size, false); /* Create a domain context including the ME descriptor before the ME gets injected. */ - domains[slotID] = domain_create(slotID, ME_CPU); - /* Initialize the ME descriptor */ - set_ME_state(slotID, ME_state); - return slotID; } @@ -220,14 +163,12 @@ int prepare_ME_slot(int slotID, unsigned int size, ME_state_t ME_state) { */ void put_ME_slot(unsigned int slotID) { + release_mapping(NULL, memslot[slotID].base_vaddr, memslot[slotID].size); + /* Release the allocated memchunks */ release_memslot(memslot[slotID].base_paddr, get_power_from_size(DIV_ROUND_UP(memslot[slotID].size, ME_MEMCHUNK_SIZE))); - memslot[slotID].busy = false; - -#ifdef DEBUG - printk("put_ME_slot param %d\n", slotID); -#endif + memslot[slotID].busy = false; } void dump_page(unsigned int pfn) { @@ -242,7 +183,7 @@ void dump_page(unsigned int pfn) { for (i = 0; i < PAGE_SIZE; i += 16) { printk(" [%x]: ", i); for (j = 0; j < 16; j++) { - printk("%02x ", *((unsigned char *) __lva(addr))); + printk("%02x ", *((unsigned char *) __xva(MEMSLOT_AVZ, addr))); addr++; } printk("\n"); diff --git a/so3/configs/refso3_64_defconfig b/so3/configs/refso3_64_defconfig deleted file mode 100644 index 29c87449d5..0000000000 --- a/so3/configs/refso3_64_defconfig +++ /dev/null @@ -1,98 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -CONFIG_SO3VIRT=y -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff800010000000 - -# -# Platform -# -CONFIG_VIRT64=y -# CONFIG_RPI4_64 is not set -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -CONFIG_THREAD_ENV=y - -# -# Kernel & CPU features -# -# CONFIG_SMP is not set -CONFIG_NR_CPUS=1 -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff900000000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -# CONFIG_PL011_UART is not set -CONFIG_UART_LL_PADDR=0x09000000 -CONFIG_SOO_SERIAL=y -# CONFIG_MMC is not set -# CONFIG_RAMDEV is not set -# CONFIG_ARM_TIMER is not set -CONFIG_SOO_TIMER=y -# CONFIG_GIC is not set -CONFIG_SOO_IRQ=y -# CONFIG_PL111_CLCD is not set -# CONFIG_SOO_FB is not set -# CONFIG_PL050_KMI is not set -# CONFIG_SOO_INPUT is not set - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set - -# -# Filesystems -# -CONFIG_ROOTFS_NONE=y -# CONFIG_ROOTFS_MMC is not set -# CONFIG_ROOTFS_RAMDEV is not set - -# -# IPC -# -# CONFIG_IPC_SIGNAL is not set -# CONFIG_IPC_PIPE is not set -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -# CONFIG_AVZ is not set -CONFIG_SOO=y -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set - -# -# SOO Mobile Entity - Smart Object Oriented subsystem -# -CONFIG_SOO_REFSO3=y - -# -# SOO Mobile Entity frontend drivers -# -# CONFIG_VDUMMY_FRONTEND is not set -CONFIG_VUART_FRONTEND=y - -# -# CONFIG_VSENSELED_FRONTEND is not set -# CONFIG_VSENSEJ_FRONTEND is not set diff --git a/so3/configs/refso3_defconfig b/so3/configs/refso3_defconfig deleted file mode 100644 index 3e2134748e..0000000000 --- a/so3/configs/refso3_defconfig +++ /dev/null @@ -1,103 +0,0 @@ -# -# Automatically generated file; DO NOT EDIT. -# SO3 Configuration -# - -# -# General -# -CONFIG_CROSS_COMPILE="arm-none-linux-gnueabihf-" -# end of General - -# -# Platform -# -CONFIG_STANDALONE=y -# CONFIG_VEXPRESS is not set -# CONFIG_RPI4 is not set -CONFIG_SO3VIRT=y -# end of Platform - -CONFIG_THREAD_ENV=y -# CONFIG_PROC_ENV is not set - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y -# end of SO3 Scheduling configuration - -# -# Drivers -# -CONFIG_UART=y -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_DW_APB_UART is not set -CONFIG_SO3VIRT_SERIAL=y -# CONFIG_MMC is not set -# CONFIG_RAMDEV is not set -# CONFIG_ARM_TIMER is not set -# CONFIG_GIC is not set -CONFIG_VIRQ=y -# end of Drivers - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set -# end of SO3 Applications - -CONFIG_KERNEL_VIRT_ADDR=0xc0000000 - -# -# Filesystems -# -CONFIG_ROOTFS_NONE=y -# CONFIG_ROOTFS_MMC is not set -# CONFIG_ROOTFS_RAMDEV is not set -# end of Filesystems - -# -# IPC -# -# CONFIG_IPC_SIGNAL is not set -# CONFIG_IPC_PIPE is not set -# end of IPC - -# -# SOO Mobile Entity - Smart Object Oriented subsystem -# -CONFIG_SOO_REFSO3=y -# CONFIG_SOO_BLIND is not set -# CONFIG_SOO_OUTDOOR is not set -# CONFIG_SOO_AGENCY is not set -# CONFIG_SOO_NET is not set - -# -# SOO Mobile Entity frontend drivers -# -CONFIG_VDUMMY_FRONTEND=y -CONFIG_VUART_FRONTEND=y -# CONFIG_VFB_FRONTEND is not set -# CONFIG_VINPUT_FRONTEND is not set -# CONFIG_VDOGA12V6NM_FRONTEND is not set -# CONFIG_VWEATHER_FRONTEND is not set -# CONFIG_VUIHANDLER_FRONTEND is not set -# end of SOO Mobile Entity frontend drivers -# end of SOO Mobile Entity - Smart Object Oriented subsystem - -# CONFIG_RTOS is not set -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set - -# -# Generated files -# -CONFIG_ELF=y -CONFIG_BIN=y -# end of Generated files diff --git a/so3/configs/refso3_ramfs_defconfig b/so3/configs/refso3_ramfs_defconfig deleted file mode 100644 index 51e3b3dbae..0000000000 --- a/so3/configs/refso3_ramfs_defconfig +++ /dev/null @@ -1,98 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -CONFIG_ARCH_ARM32=y -# CONFIG_ARCH_ARM64 is not set -CONFIG_SO3VIRT=y -CONFIG_ARCH="arm32" -CONFIG_CROSS_COMPILE="arm-none-eabi-" -# CONFIG_ARM_TRUSTZONE is not set - -# -# Platform -# -CONFIG_KERNEL_VADDR=0xc0000000 -CONFIG_VIRT32=y -# CONFIG_RPI4 is not set -# CONFIG_THREAD_ENV is not set -CONFIG_PROC_ENV=y - -# -# Kernel & CPU features -# -# CONFIG_SMP is not set -CONFIG_NR_CPUS=4 -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xe0000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -# CONFIG_PL011_UART is not set -CONFIG_UART_LL_PADDR=0x09000000 -CONFIG_SOO_SERIAL=y -# CONFIG_MMC is not set -CONFIG_RAMDEV=y -# CONFIG_SP804 is not set -# CONFIG_ARM_TIMER is not set -CONFIG_SOO_TIMER=y -# CONFIG_GIC is not set -CONFIG_SOO_IRQ=y -# CONFIG_PL111_CLCD is not set -# CONFIG_QEMU_RAMFB is not set -# CONFIG_SOO_FB is not set -# CONFIG_PL050_KMI is not set -# CONFIG_SOO_INPUT is not set - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set - -# -# Filesystems -# -CONFIG_FS_FAT=y -# CONFIG_ROOTFS_NONE is not set -# CONFIG_ROOTFS_MMC is not set -CONFIG_ROOTFS_RAMDEV=y - -# -# IPC -# -CONFIG_IPC_SIGNAL=y -CONFIG_IPC_PIPE=y -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -# CONFIG_AVZ is not set -CONFIG_SOO=y -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set - -# -# SOO Mobile Entity - Smart Object Oriented subsystem -# -CONFIG_SOO_REFSO3=y - -# -# SOO Mobile Entity frontend drivers -# -# CONFIG_VDUMMY_FRONTEND is not set -CONFIG_VUART_FRONTEND=y -# CONFIG_VSENSELED_FRONTEND is not set -# CONFIG_VSENSEJ_FRONTEND is not set diff --git a/so3/configs/rpi4_64_avz_pv_defconfig b/so3/configs/rpi4_64_avz_pv_defconfig deleted file mode 100644 index a2097147c0..0000000000 --- a/so3/configs/rpi4_64_avz_pv_defconfig +++ /dev/null @@ -1,79 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -# CONFIG_SO3VIRT is not set -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff700000000000 - -# -# Platform -# -# CONFIG_ARM64VT is not set -# CONFIG_VIRT64 is not set -CONFIG_RPI4_64=y -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -CONFIG_THREAD_ENV=y - -# -# Kernel & CPU features -# -CONFIG_SMP=y -CONFIG_NR_CPUS=4 -# CONFIG_CPU_PSCI is not set -CONFIG_CPU_SPIN_TABLE=y -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff700010000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -CONFIG_BCM283x_MU_UART=y -CONFIG_UART_LL_PADDR=0xfe215040 -# CONFIG_MMC is not set -# CONFIG_RAMDEV is not set -CONFIG_ARM_TIMER=y -CONFIG_GIC=y - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set - -# -# Filesystems -# -CONFIG_ROOTFS_NONE=y -# CONFIG_ROOTFS_MMC is not set -# CONFIG_ROOTFS_RAMDEV is not set - -# -# IPC -# -# CONFIG_IPC_SIGNAL is not set -# CONFIG_IPC_PIPE is not set -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -CONFIG_AVZ=y -# CONFIG_SOO is not set -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set diff --git a/so3/configs/rpi4_64_avz_pv_soo_defconfig b/so3/configs/rpi4_64_avz_pv_soo_defconfig deleted file mode 100644 index 0cb83185f0..0000000000 --- a/so3/configs/rpi4_64_avz_pv_soo_defconfig +++ /dev/null @@ -1,80 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff700000000000 -CONFIG_RAM_BASE=0x00000000 -CONFIG_RAM_SIZE=0x3f000000 - -# -# Platform -# -# CONFIG_ARM64VT is not set -# CONFIG_VIRT64 is not set -CONFIG_RPI4_64=y -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -CONFIG_THREAD_ENV=y - -# -# Kernel & CPU features -# -CONFIG_SMP=y -CONFIG_NR_CPUS=4 -# CONFIG_CPU_PSCI is not set -CONFIG_CPU_SPIN_TABLE=y -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff700010000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -CONFIG_BCM283x_MU_UART=y -CONFIG_UART_LL_PADDR=0xfe215040 -# CONFIG_MMC is not set -# CONFIG_RAMDEV is not set -CONFIG_ARM_TIMER=y -CONFIG_GIC=y - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set - -# -# Filesystems -# -CONFIG_ROOTFS_NONE=y -# CONFIG_ROOTFS_MMC is not set -# CONFIG_ROOTFS_RAMDEV is not set - -# -# IPC -# -# CONFIG_IPC_SIGNAL is not set -# CONFIG_IPC_PIPE is not set -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -CONFIG_AVZ=y -CONFIG_SOO=y -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set diff --git a/so3/configs/rpi4_64_pv_defconfig b/so3/configs/rpi4_64_pv_defconfig deleted file mode 100644 index 3e8277afe4..0000000000 --- a/so3/configs/rpi4_64_pv_defconfig +++ /dev/null @@ -1,80 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -CONFIG_SO3VIRT=y -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff800010000000 -CONFIG_RAM_BASE=0x00000000 -CONFIG_RAM_SIZE=0x3f000000 - -# -# Platform -# -# CONFIG_VIRT64 is not set -CONFIG_RPI4_64=y -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -# CONFIG_THREAD_ENV is not set -CONFIG_PROC_ENV=y - -# -# Kernel & CPU features -# -# CONFIG_SMP is not set -CONFIG_NR_CPUS=1 -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff900000000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -CONFIG_BCM283x_MU_UART=y -CONFIG_UART_LL_PADDR=0xfe215040 -# CONFIG_MMC is not set -CONFIG_RAMDEV=y -CONFIG_ARM_TIMER=y -CONFIG_GIC=y - -# -# SO3 Applications -# -CONFIG_APP_SAMPLE=y - -# -# Filesystems -# -CONFIG_FS_FAT=y -# CONFIG_ROOTFS_NONE is not set -# CONFIG_ROOTFS_MMC is not set -CONFIG_ROOTFS_RAMDEV=y - -# -# IPC -# -CONFIG_IPC_SIGNAL=y -CONFIG_IPC_PIPE=y -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -# CONFIG_AVZ is not set -# CONFIG_SOO is not set -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set diff --git a/so3/configs/virt32_pv_defconfig b/so3/configs/virt32_pv_defconfig deleted file mode 100644 index b93224e979..0000000000 --- a/so3/configs/virt32_pv_defconfig +++ /dev/null @@ -1,80 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -CONFIG_ARCH_ARM32=y -# CONFIG_ARCH_ARM64 is not set -CONFIG_SO3VIRT=y -CONFIG_ARCH="arm32" -CONFIG_CROSS_COMPILE="arm-none-eabi-" -# CONFIG_ARM_TRUSTZONE is not set - -# -# Platform -# -CONFIG_KERNEL_VADDR=0xc0000000 -CONFIG_VIRT32=y -# CONFIG_RPI4 is not set -# CONFIG_THREAD_ENV is not set -CONFIG_PROC_ENV=y - -# -# Kernel & CPU features -# -# CONFIG_SMP is not set -CONFIG_NR_CPUS=1 -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xe0000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -CONFIG_FB=y -CONFIG_INPUT=y -# CONFIG_NS16550 is not set -CONFIG_PL011_UART=y -CONFIG_UART_LL_PADDR=0x9000000 -# CONFIG_MMC is not set -CONFIG_RAMDEV=y -# CONFIG_SP804 is not set -CONFIG_ARM_TIMER=y -CONFIG_GIC=y -CONFIG_PL111_CLCD=y -# CONFIG_QEMU_RAMFB is not set -CONFIG_PL050_KMI=y - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set - -# -# Filesystems -# -CONFIG_FS_FAT=y -# CONFIG_ROOTFS_NONE is not set -# CONFIG_ROOTFS_MMC is not set -CONFIG_ROOTFS_RAMDEV=y - -# -# IPC -# -CONFIG_IPC_SIGNAL=y -CONFIG_IPC_PIPE=y -CONFIG_HEAP_SIZE=32 -# CONFIG_RTOS is not set -# CONFIG_AVZ is not set -# CONFIG_SOO is not set -CONFIG_MMU=y -CONFIG_DEBUG_PRINTK=y diff --git a/so3/configs/virt64_avz_pv_defconfig b/so3/configs/virt64_avz_pv_defconfig deleted file mode 100644 index 85159b1e96..0000000000 --- a/so3/configs/virt64_avz_pv_defconfig +++ /dev/null @@ -1,84 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -# CONFIG_SO3VIRT is not set -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff700000000000 -CONFIG_RAM_BASE=0x40000000 - -# -# Platform -# -# CONFIG_ARM64VT is not set -CONFIG_VIRT64=y -# CONFIG_RPI4_64 is not set -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -CONFIG_THREAD_ENV=y - -# -# Kernel & CPU features -# -CONFIG_SMP=y -CONFIG_NR_CPUS=4 -CONFIG_CPU_PSCI=y -# CONFIG_CPU_SPIN_TABLE is not set -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff700010000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_VEXT is not set -# CONFIG_NS16550 is not set -CONFIG_PL011_UART=y -CONFIG_UART_LL_PADDR=0x09000000 -# CONFIG_MMC is not set -# CONFIG_RAMDEV is not set -CONFIG_ARM_TIMER=y -CONFIG_GIC=y -# CONFIG_PL111_CLCD is not set -# CONFIG_PL050_KMI is not set - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set -# CONFIG_APP_TEST_MALLOC is not set -CONFIG_APP_DEFAULT=y - -# -# Filesystems -# -CONFIG_ROOTFS_NONE=y -# CONFIG_ROOTFS_MMC is not set -# CONFIG_ROOTFS_RAMDEV is not set - -# -# IPC -# -# CONFIG_IPC_SIGNAL is not set -# CONFIG_IPC_PIPE is not set -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -CONFIG_AVZ=y -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set diff --git a/so3/configs/virt64_avz_pv_soo_defconfig b/so3/configs/virt64_avz_pv_soo_defconfig deleted file mode 100644 index 59cb84f393..0000000000 --- a/so3/configs/virt64_avz_pv_soo_defconfig +++ /dev/null @@ -1,102 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -# CONFIG_SO3VIRT is not set -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff700000000000 -CONFIG_RAM_BASE=0x40000000 -CONFIG_RAM_SIZE=0x3f000000 - -# -# Platform -# -# CONFIG_ARM64VT is not set -CONFIG_VIRT64=y -# CONFIG_RPI4_64 is not set -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -CONFIG_THREAD_ENV=y - -# -# Kernel & CPU features -# -CONFIG_SMP=y -CONFIG_NR_CPUS=4 -CONFIG_CPU_PSCI=y -# CONFIG_CPU_SPIN_TABLE is not set -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff700010000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -CONFIG_PL011_UART=y -CONFIG_UART_LL_PADDR=0x09000000 -# CONFIG_SOO_SERIAL is not set -# CONFIG_MMC is not set -# CONFIG_RAMDEV is not set -CONFIG_ARM_TIMER=y -# CONFIG_SOO_TIMER is not set -CONFIG_GIC=y -# CONFIG_SOO_IRQ is not set -# CONFIG_PL111_CLCD is not set -# CONFIG_SOO_FB is not set -# CONFIG_PL050_KMI is not set -# CONFIG_SOO_INPUT is not set - -# -# SO3 Applications -# -# CONFIG_APP_SAMPLE is not set - -# -# Filesystems -# -CONFIG_ROOTFS_NONE=y -# CONFIG_ROOTFS_MMC is not set -# CONFIG_ROOTFS_RAMDEV is not set - -# -# IPC -# -# CONFIG_IPC_SIGNAL is not set -# CONFIG_IPC_PIPE is not set -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -CONFIG_AVZ=y -CONFIG_SOO=y -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set - -# -# SOO Mobile Entity - Smart Object Oriented subsystem -# -CONFIG_SOO_REFSO3=y - -# -# SOO Mobile Entity frontend drivers -# -# CONFIG_VDUMMY_FRONTEND is not set -# CONFIG_VUART_FRONTEND is not set - -# CONFIG_VSENSELED_FRONTEND is not set -# CONFIG_VSENSEJ_FRONTEND is not set diff --git a/so3/configs/refso3_ramfs_64_defconfig b/so3/configs/virt64_guest_defconfig similarity index 83% rename from so3/configs/refso3_ramfs_64_defconfig rename to so3/configs/virt64_guest_defconfig index 7c88a7c6d0..cef4c039c0 100644 --- a/so3/configs/refso3_ramfs_64_defconfig +++ b/so3/configs/virt64_guest_defconfig @@ -4,11 +4,11 @@ # # CONFIG_ARCH_ARM32 is not set CONFIG_ARCH_ARM64=y -CONFIG_SO3VIRT=y +# CONFIG_SO3VIRT is not set CONFIG_ARCH="arm64" CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" # CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff800010000000 +CONFIG_KERNEL_VADDR=0xffff800000000000 # # Platform @@ -24,7 +24,7 @@ CONFIG_PROC_ENV=y # Kernel & CPU features # # CONFIG_SMP is not set -CONFIG_NR_CPUS=4 +CONFIG_NR_CPUS=1 CONFIG_HZ=100 CONFIG_SCHED_FLIP_SCHEDFREQ=30 @@ -45,25 +45,24 @@ CONFIG_IO_MAPPING_BASE=0xffff900000000000 # CONFIG_FB is not set # CONFIG_INPUT is not set # CONFIG_NS16550 is not set -# CONFIG_PL011_UART is not set CONFIG_UART_LL_PADDR=0x09000000 CONFIG_SOO_SERIAL=y # CONFIG_MMC is not set CONFIG_RAMDEV=y -# CONFIG_ARM_TIMER is not set CONFIG_SOO_TIMER=y -# CONFIG_GIC is not set -CONFIG_SOO_IRQ=y +CONFIG_GIC=y +# CONFIG_SOO_IRQ is not set # CONFIG_PL111_CLCD is not set # CONFIG_QEMU_RAMFB is not set # CONFIG_SOO_FB is not set # CONFIG_PL050_KMI is not set -# CONFIG_SOO_INPUT is not set +CONFIG_SOO_INPUT=y # # SO3 Applications # # CONFIG_APP_SAMPLE is not set +CONFIG_APP_REFSO3=y # # Filesystems @@ -88,10 +87,12 @@ CONFIG_MMU=y # # SOO Mobile Entity - Smart Object Oriented subsystem # -CONFIG_SOO_REFSO3=y -# CONFIG_SOO_AGENCY is not set + # # SOO Mobile Entity frontend drivers # -# CONFIG_VDUMMY_FRONTEND is not set +CONFIG_VDUMMY_FRONTEND=y CONFIG_VUART_FRONTEND=y +# CONFIG_VUIHANDLER_FRONTEND is not set +# CONFIG_VSENSELED_FRONTEND is not set +# CONFIG_VSENSEJ_FRONTEND is not set diff --git a/so3/configs/virt64_pv_defconfig b/so3/configs/virt64_pv_defconfig deleted file mode 100644 index c512d8aaeb..0000000000 --- a/so3/configs/virt64_pv_defconfig +++ /dev/null @@ -1,83 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -CONFIG_SO3VIRT=y -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff800010000000 -CONFIG_RAM_BASE=0x41000000 - -# -# Platform -# -CONFIG_VIRT64=y -# CONFIG_RPI4_64 is not set -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -# CONFIG_THREAD_ENV is not set -CONFIG_PROC_ENV=y - -# -# Kernel & CPU features -# -# CONFIG_SMP is not set -CONFIG_NR_CPUS=1 -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff900000000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_VEXT is not set -# CONFIG_NS16550 is not set -CONFIG_PL011_UART=y -CONFIG_UART_LL_PADDR=0x09000000 -# CONFIG_MMC is not set -CONFIG_RAMDEV=y -CONFIG_ARM_TIMER=y -CONFIG_GIC=y -# CONFIG_PL111_CLCD is not set -# CONFIG_PL050_KMI is not set - -# -# SO3 Applications -# -CONFIG_APP_SAMPLE=y -# CONFIG_APP_TEST_MALLOC is not set -CONFIG_APP_DEFAULT=y - -# -# Filesystems -# -CONFIG_FS_FAT=y -# CONFIG_ROOTFS_NONE is not set -# CONFIG_ROOTFS_MMC is not set -CONFIG_ROOTFS_RAMDEV=y - -# -# IPC -# -CONFIG_IPC_SIGNAL=y -CONFIG_IPC_PIPE=y -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -# CONFIG_AVZ is not set -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set diff --git a/so3/configs/virt64_vt_defconfig b/so3/configs/virt64_vt_defconfig deleted file mode 100644 index 6a35c73006..0000000000 --- a/so3/configs/virt64_vt_defconfig +++ /dev/null @@ -1,82 +0,0 @@ -# -# Automatically generated make config: don't edit -# SO3 Polymorphic OS Configuration -# -# CONFIG_ARCH_ARM32 is not set -CONFIG_ARCH_ARM64=y -# CONFIG_SO3VIRT is not set -CONFIG_ARCH="arm64" -CONFIG_CROSS_COMPILE="aarch64-none-linux-gnu-" -# CONFIG_ARM_TRUSTZONE is not set -CONFIG_KERNEL_VADDR=0xffff800010000000 -CONFIG_RAM_BASE=0x41000000 -CONFIG_RAM_SIZE=0x3f000000 - -# -# Platform -# -CONFIG_VIRT64=y -# CONFIG_RPI4_64 is not set -# CONFIG_VA_BITS_39 is not set -CONFIG_VA_BITS_48=y -# CONFIG_THREAD_ENV is not set -CONFIG_PROC_ENV=y - -# -# Kernel & CPU features -# -# CONFIG_SMP is not set -CONFIG_NR_CPUS=1 -CONFIG_HZ=100 -CONFIG_SCHED_FLIP_SCHEDFREQ=30 - -# -# SO3 Scheduling configuration -# -CONFIG_SCHED_RR=y -# CONFIG_SCHED_PRIO is not set -CONFIG_SCHED_FREQ_PREEMPTION=y - -# -# Drivers -# -CONFIG_UART=y -CONFIG_IO_MAPPING_BASE=0xffff900000000000 -# CONFIG_I2C is not set -# CONFIG_NET is not set -# CONFIG_FB is not set -# CONFIG_INPUT is not set -# CONFIG_NS16550 is not set -CONFIG_PL011_UART=y -CONFIG_UART_LL_PADDR=0x09000000 -# CONFIG_MMC is not set -CONFIG_RAMDEV=y -CONFIG_ARM_TIMER=y -CONFIG_GIC=y -# CONFIG_PL111_CLCD is not set -# CONFIG_PL050_KMI is not set - -# -# SO3 Applications -# -CONFIG_APP_SAMPLE=y - -# -# Filesystems -# -CONFIG_FS_FAT=y -# CONFIG_ROOTFS_NONE is not set -# CONFIG_ROOTFS_MMC is not set -CONFIG_ROOTFS_RAMDEV=y - -# -# IPC -# -CONFIG_IPC_SIGNAL=y -CONFIG_IPC_PIPE=y -CONFIG_HEAP_SIZE=8 -# CONFIG_RTOS is not set -# CONFIG_AVZ is not set -# CONFIG_SOO is not set -CONFIG_MMU=y -# CONFIG_DEBUG_PRINTK is not set diff --git a/so3/devices/irq.c b/so3/devices/irq.c index 5f7f081e83..ec4d92ad04 100644 --- a/so3/devices/irq.c +++ b/so3/devices/irq.c @@ -25,9 +25,12 @@ #include +#define DEBUG + static irqdesc_t irqdesc[NR_IRQS]; volatile bool __in_interrupt = false; +/* By default IRQ chip operations */ irq_ops_t irq_ops; irqdesc_t *irq_to_desc(uint32_t irq) { @@ -75,13 +78,13 @@ void *__irq_deferred_fn(void *args) { /* * Process interrupt with top & bottom halves processing. */ -int irq_process(uint32_t irq) { +void irq_process(uint32_t irq) { int ret; char th_name[THREAD_NAME_LEN]; int *args; if (boot_stage < BOOT_STAGE_IRQ_INIT) - return IRQ_COMPLETED; /* Ignore it */ + return ; /* Ignore it */ /* Immediate (top half) processing */ @@ -112,8 +115,16 @@ int irq_process(uint32_t irq) { kernel_thread(__irq_deferred_fn, th_name, args, 0); } } +} - return ret; +/** + * @brief Attach a specific IRQ chip to a specific IRQ + * + * @param irq + * @param irq_ops + */ +void irq_set_irq_ops(int irq, irq_ops_t *irq_ops) { + irqdesc[irq].irq_ops = irq_ops; } /* @@ -129,7 +140,7 @@ void irq_bind(int irq, irq_handler_t handler, irq_handler_t irq_deferred_fn, voi irqdesc[irq].irq_deferred_fn = irq_deferred_fn; irqdesc[irq].data = data; - irq_ops.enable(irq); + irqdesc[irq].irq_ops->enable(irq); } void irq_unbind(int irq) { @@ -140,25 +151,26 @@ void irq_unbind(int irq) { } void irq_mask(int irq) { - - irq_ops.mask(irq); + if (irq_to_desc(irq)->irq_ops->mask) + irq_to_desc(irq)->irq_ops->mask(irq); } void irq_unmask(int irq) { - - irq_ops.unmask(irq); + if (irq_to_desc(irq)->irq_ops->unmask) + irq_to_desc(irq)->irq_ops->unmask(irq); } void irq_enable(int irq) { - - irq_ops.enable(irq); - irq_ops.unmask(irq); + if (irq_to_desc(irq)->irq_ops->enable) + irq_to_desc(irq)->irq_ops->enable(irq); + irq_unmask(irq); } void irq_disable(int irq) { - - irq_ops.mask(irq); - irq_ops.disable(irq); + + irq_mask(irq); + if (irq_to_desc(irq)->irq_ops->disable) + irq_to_desc(irq)->irq_ops->disable(irq); } void irq_handle(cpu_regs_t *regs) { @@ -169,7 +181,7 @@ void irq_handle(cpu_regs_t *regs) { __in_interrupt = true; - irq_ops.handle(regs); + irq_ops.handle_low(regs); /* Out of this interrupt routine, IRQs must be enabled otherwise the thread * will block all interrupts. @@ -198,15 +210,19 @@ void irq_init(void) { memset(&irq_ops, 0, sizeof(irq_ops_t)); - for (i = 0; i < NR_IRQS; i++) { - irqdesc[i].action = NULL; + irq_ops.handle_high = irq_process; + + for (i = 0; i < NR_IRQS; i++) { + irqdesc[i].action = NULL; irqdesc[i].irq_deferred_fn = NULL; - atomic_set(&irqdesc[i].deferred_pending, 0); + irqdesc[i].irq_ops = &irq_ops; + + atomic_set(&irqdesc[i].deferred_pending, 0); irqdesc[i].thread_active = false; - } + } - /* Initialize the softirq subsystem */ + /* Initialize the softirq subsystem */ softirq_init(); } diff --git a/so3/devices/irq/Kconfig b/so3/devices/irq/Kconfig index ad9519b992..9ca4a07f52 100644 --- a/so3/devices/irq/Kconfig +++ b/so3/devices/irq/Kconfig @@ -3,8 +3,4 @@ config GIC bool "Generic IRQ Controller" -config SOO_IRQ - bool "SOO Virtualized IRQ controller device" - depends on SOO && !AVZ - - + \ No newline at end of file diff --git a/so3/devices/irq/Makefile b/so3/devices/irq/Makefile index 0ad592714c..62a0d35c84 100644 --- a/so3/devices/irq/Makefile +++ b/so3/devices/irq/Makefile @@ -1,5 +1,8 @@ obj-$(CONFIG_GIC) += gic.o -obj-$(CONFIG_SOO_IRQ) += soo_irq.o + +obj-$(CONFIG_AVZ) += vgic.o + + diff --git a/so3/devices/irq/gic.c b/so3/devices/irq/gic.c index 65099ef0c4..a343e0a419 100644 --- a/so3/devices/irq/gic.c +++ b/so3/devices/irq/gic.c @@ -43,72 +43,74 @@ #define DEBUG #endif -#include #include +#include +#include #include -#include #include -#include #include +#include -#include #include #include +#include #include #include #include -#include #include +#include -typedef struct { - /* Distributor */ - struct gicd_regs *gicd; - - /* CPU interface */ - struct gicc_regs *gicc; - -#ifdef CONFIG_ARM64VT - /* Hypervisor related */ - struct gich_regs *gich; +#ifdef CONFIG_ARM64 +#include +#endif /* CONFIG_ARM64 */ - unsigned int gic_num_lr; +#ifdef CONFIG_AVZ +#include #endif -} gic_t; -static gic_t *gic; +gic_t *gic; DEFINE_PER_CPU(spinlock_t, intc_lock); #ifdef CONFIG_ARM64VT -#define MAX_PENDING_IRQS 256 +#define MAX_PENDING_IRQS 256 struct pending_irqs { - /* synchronizes parallel insertions of SGIs into the pending ring */ - spinlock_t lock; + /* synchronizes parallel insertions of SGIs into the pending ring */ + spinlock_t lock; - u16 irqs[MAX_PENDING_IRQS]; + u16 irqs[MAX_PENDING_IRQS]; - /* contains the calling CPU ID in case of a SGI */ - unsigned int head; + /* contains the calling CPU ID in case of a SGI */ + unsigned int head; - /* removal from the ring happens lockless, thus tail is volatile */ - volatile unsigned int tail; + /* removal from the ring happens lockless, thus tail is volatile */ + volatile unsigned int tail; }; struct pending_irqs pending_irqs; -static u32 gic_read_lr(unsigned int n) -{ - return ioread32(&gic->gich->lrbase[n]); +static u32 gic_read_lr(unsigned int n) { + return ioread32(&gic->gich->lr[n]); } -static void gic_write_lr(unsigned int n, u32 value) -{ - iowrite32(&gic->gich->lrbase[n], value); +void gic_write_lr(unsigned int n, u32 value) { + iowrite32(&gic->gich->lr[n], value); +} + +void display_lr(unsigned int n) { + u32 lr = gic_read_lr(n); + + printk("LR state: \n"); + printk(" - virq: %x\n", lr & GICH_LR_VIRT_ID_MASK); + printk(" - prio: %x\n", (lr >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK); + printk(" - pending: %x\n", lr & GICH_LR_PENDING_BIT); + printk(" - active: %x\n", lr & GICH_LR_ACTIVE_BIT); + printk(" - hw: %x\n", lr & GICH_LR_HW_BIT); } #endif /* CONFIG_ARM64VT */ @@ -120,280 +122,354 @@ static void gic_write_lr(unsigned int n, u32 value) * @param irq_def */ void fdt_interrupt_node(int fdt_offset, irq_def_t *irq_def) { - int prop_len; - const struct fdt_property *prop; - const fdt32_t *p; + int prop_len; + const struct fdt_property *prop; + const fdt32_t *p; - /* Interrupts - as described in the bindings - have 3 specific cells */ - prop = fdt_get_property(__fdt_addr, fdt_offset, "interrupts", &prop_len); - BUG_ON(!prop); + /* Interrupts - as described in the bindings - have 3 specific cells */ + prop = fdt_get_property(__fdt_addr, fdt_offset, "interrupts", &prop_len); + BUG_ON(!prop); - p = (const fdt32_t *) prop->data; + p = (const fdt32_t *) prop->data; - if (prop_len == 3 * sizeof(uint32_t)) { + if (prop_len == 3 * sizeof(uint32_t)) { - /* Retrieve the 3-cell values */ - irq_def->irq_class = fdt32_to_cpu(p[0]); - irq_def->irqnr = fdt32_to_cpu(p[1]); - irq_def->irq_type = fdt32_to_cpu(p[2]); + /* Retrieve the 3-cell values */ + irq_def->irq_class = fdt32_to_cpu(p[0]); + irq_def->irqnr = fdt32_to_cpu(p[1]); + irq_def->irq_type = fdt32_to_cpu(p[2]); - /* Not all combinations are currently handled. */ + /* Not all combinations are currently handled. */ - if (irq_def->irq_class != GIC_IRQ_TYPE_SGI) - irq_def->irqnr += 16; /* Possibly for a Private Peripheral Interrupt (PPI) */ + if (irq_def->irq_class != GIC_IRQ_TYPE_SGI) + irq_def->irqnr += 16; /* Possibly for a Private Peripheral Interrupt (PPI) */ - if (irq_def->irq_class == GIC_IRQ_TYPE_SPI) /* It is a Shared Peripheral Interrupt (SPI) */ - irq_def->irqnr += 16; - - } else { - /* Unsupported size of interrupts property */ - lprintk("%s: unsupported size of interrupts property\n"); - BUG(); - } + if (irq_def->irq_class == GIC_IRQ_TYPE_SPI) /* It is a Shared Peripheral Interrupt (SPI) */ + irq_def->irqnr += 16; + } else { + /* Unsupported size of interrupts property */ + lprintk("%s: unsupported size of interrupts property\n"); + BUG(); + } } -static void gic_mask(unsigned int irq) -{ - int cpu = smp_processor_id(); +static void gic_mask(unsigned int irq) { + int cpu = smp_processor_id(); + + spin_lock(&per_cpu(intc_lock, cpu)); - spin_lock(&per_cpu(intc_lock, cpu)); + /* Disable/mask IRQ using the clear-enable register */ + iowrite32(&gic->gicd->icenabler[irq / 32], 1 << (irq % 32)); - /* Disable/mask IRQ using the clear-enable register */ - iowrite32(&gic->gicd->icenabler[irq/32], 1 << (irq % 32)); - - spin_unlock(&per_cpu(intc_lock, cpu)); + spin_unlock(&per_cpu(intc_lock, cpu)); } -static void gic_unmask(unsigned int irq) -{ - int cpu = smp_processor_id(); +static void gic_unmask(unsigned int irq) { + int cpu = smp_processor_id(); - spin_lock(&per_cpu(intc_lock, cpu)); - - /* Enable/unmask IRQ using the set-enable register */ - iowrite32(&gic->gicd->isenabler[irq/32], 1 << (irq % 32)); + spin_lock(&per_cpu(intc_lock, cpu)); - spin_unlock(&per_cpu(intc_lock, cpu)); + /* Enable/unmask IRQ using the set-enable register */ + iowrite32(&gic->gicd->isenabler[irq / 32], 1 << (irq % 32)); + spin_unlock(&per_cpu(intc_lock, cpu)); } -void gic_set_prio(unsigned int irq, unsigned char prio) -{ - int cpu = smp_processor_id(); - u32 primask = 0xff << (irq % 4) * 8; - u32 prival = prio << (irq % 4) * 8; - u32 prioff = (irq / 4); - u32 val; +void gic_set_prio(unsigned int irq, unsigned char prio) { + int cpu = smp_processor_id(); + u32 primask = 0xff << (irq % 4) * 8; + u32 prival = prio << (irq % 4) * 8; + u32 prioff = (irq / 4); + u32 val; - spin_lock(&per_cpu(intc_lock, cpu)); + spin_lock(&per_cpu(intc_lock, cpu)); - val = ioread32(&gic->gicd->ipriorityr[prioff]); - val &= ~primask; - val |= prival; - iowrite32(&gic->gicd->ipriorityr[prioff], val); + val = ioread32(&gic->gicd->ipriorityr[prioff]); + val &= ~primask; + val |= prival; + iowrite32(&gic->gicd->ipriorityr[prioff], val); - spin_unlock(&per_cpu(intc_lock, cpu)); + spin_unlock(&per_cpu(intc_lock, cpu)); } -int irq_set_affinity(unsigned int irq, int cpu) -{ - volatile void *reg = &gic->gicd->itargetsr[(irq & ~3)/4]; - unsigned int shift = (irq % 4) * 8; - u32 val; - struct irqdesc *desc; - int __cpu = smp_processor_id(); - - spin_lock(&per_cpu(intc_lock, __cpu)); - desc = irq_to_desc(irq); - if (desc == NULL) { - spin_unlock(&per_cpu(intc_lock, __cpu)); - BUG(); - } - - val = ioread32(reg) & ~(0xff << shift); - val |= 1 << (cpu + shift); - iowrite32(reg, val); - spin_unlock(&per_cpu(intc_lock, __cpu)); - - return 0; +int irq_set_affinity(unsigned int irq, int cpu) { + volatile void *reg = &gic->gicd->itargetsr[(irq & ~3) / 4]; + unsigned int shift = (irq % 4) * 8; + u32 val; + struct irqdesc *desc; + int __cpu = smp_processor_id(); + + spin_lock(&per_cpu(intc_lock, __cpu)); + desc = irq_to_desc(irq); + if (desc == NULL) { + spin_unlock(&per_cpu(intc_lock, __cpu)); + BUG(); + } + + val = ioread32(reg) & ~(0xff << shift); + val |= 1 << (cpu + shift); + iowrite32(reg, val); + spin_unlock(&per_cpu(intc_lock, __cpu)); + + return 0; } -void gicc_init(void) -{ - unsigned int cpu = smp_processor_id(); - u32 bypass = 0; - int i; - - spin_lock_init(&per_cpu(intc_lock, cpu)); - - /* - * Deal with the banked PPI and SGI interrupts - disable all - * PPI interrupts, ensure all SGI interrupts are enabled. - */ - iowrite32(&gic->gicd->icenabler, GICD_INT_EN_CLR_PPI); - iowrite32(&gic->gicd->isenabler, GICD_INT_EN_SET_SGI); +#ifdef CONFIG_ARM64VT - /* Priority for all SGI and PPI interrupts is the highest (value 0) */ - for (i = 0; i < 32; i += 4) - iowrite32(&gic->gicd->ipriorityr[i/4], 0); +static void gic_enable_maint_irq(bool enable) { + u32 hcr; - /* Allow all priorities */ - iowrite32(&gic->gicc->pmr, GICC_INT_PRI_THRESHOLD); + hcr = ioread32(&gic->gich->hcr); + if (enable) + hcr |= GICH_HCR_UIE; + else + hcr &= ~GICH_HCR_UIE; - /* - * Preserve bypass disable bits to be written back later - */ - bypass = ioread32(&gic->gicc->ctlr); - bypass &= GICC_DIS_BYPASS_MASK; + iowrite32(&gic->gich->hcr, hcr); +} - iowrite32(&gic->gicc->ctlr, bypass | GICC_ENABLE | GIC_CPU_EOI); +static int gic_inject_irq(u16 irq_id) { + unsigned int n; + int first_free = -1; + u32 lr; + unsigned long elsr[2]; + + elsr[0] = ioread32(&gic->gich->elsr0); + elsr[1] = ioread32(&gic->gich->elsr1); + + for (n = 0; n < gic->gic_num_lr; n++) { + if (test_bit(n, elsr)) { + /* Entry is available */ + if (first_free == -1) + first_free = n; + continue; + } + + /* Check that there is no overlapping */ + lr = gic_read_lr(n); + if ((lr & GICH_LR_VIRT_ID_MASK) == irq_id) + return -EEXIST; + } + + if (first_free == -1) + return -EBUSY; + + /* Inject group 0 interrupt (seen as IRQ by the guest) */ + lr = irq_id; + lr |= GICH_LR_PENDING_BIT; + + if (is_sgi(irq_id)) { + lr |= (smp_processor_id() & 0x7) << GICH_LR_CPUID_SHIFT; + } else { + lr |= GICH_LR_HW_BIT; + lr |= (u32) irq_id << GICH_LR_PHYS_ID_SHIFT; + } + + gic_write_lr(first_free, lr); + + return 0; } -#ifdef CONFIG_ARM64VT +void gic_inject_pending(void) { + u16 irq_id; + + while (pending_irqs.head != pending_irqs.tail) { + irq_id = pending_irqs.irqs[pending_irqs.head]; + + if (gic_inject_irq(irq_id) == -EBUSY) { + /* + * The list registers are full, trigger maintenance + * interrupt and leave. + */ + gic_enable_maint_irq(true); + return; + } + + /* + * Ensure that the entry was read before updating the head + * index. + */ + dmb(ish); + + pending_irqs.head = (pending_irqs.head + -1) % MAX_PENDING_IRQS; + } + + /* + * The software interrupt queue is empty - turn off the maintenance + * interrupt. + */ + gic_enable_maint_irq(false); +} -static void gic_enable_maint_irq(bool enable) -{ - u32 hcr; +void gic_set_pending(u16 irq_id) { + unsigned int new_tail; - hcr = ioread32(&gic->gich->hcr); - if (enable) - hcr |= GICH_HCR_UIE; - else - hcr &= ~GICH_HCR_UIE; + if (gic_inject_irq(irq_id) != -EBUSY) + return; - iowrite32(&gic->gich->hcr, hcr); -} + spin_lock(&pending_irqs.lock); -static int gic_inject_irq(u16 irq_id) -{ - unsigned int n; - int first_free = -1; - u32 lr; - unsigned long elsr[2]; + new_tail = (pending_irqs.tail + 1) % MAX_PENDING_IRQS; - elsr[0] = ioread32(&gic->gich->elsr0); - elsr[1] = ioread32(&gic->gich->elsr1); + /* Queue space available? */ + if (new_tail != pending_irqs.head) { + pending_irqs.irqs[pending_irqs.tail] = irq_id; - for (n = 0; n < gic->gic_num_lr; n++) { - if (test_bit(n, elsr)) { - /* Entry is available */ - if (first_free == -1) - first_free = n; - continue; - } + /* + * Make the entry content is visible before updating the tail + * index. + */ + dmb(ish); - /* Check that there is no overlapping */ - lr = gic_read_lr(n); - if ((lr & GICH_LR_VIRT_ID_MASK) == irq_id) - return -EEXIST; - } + pending_irqs.tail = new_tail; + } - if (first_free == -1) - return -EBUSY; + /* + * The unlock has memory barrier semantic on ARM v7 and v8. Therefore + * the change to tail will be visible when sending SGI_INJECT later on. + */ + spin_unlock(&pending_irqs.lock); - /* Inject group 0 interrupt (seen as IRQ by the guest) */ - lr = irq_id; - lr |= GICH_LR_PENDING_BIT; + /* + * The list registers are full, trigger maintenance interrupt if we are + * on the target CPU. In the other case, send SGI_INJECT to the target + * CPU. + */ - lr |= GICH_LR_HW_BIT; - lr |= (u32)irq_id << GICH_LR_PHYS_ID_SHIFT; + gic_enable_maint_irq(true); +} - gic_write_lr(first_free, lr); +void gic_clear_pending_irqs(void) { + unsigned int n; - return 0; -} + /* Clear list registers. */ + for (n = 0; n < gic->gic_num_lr; n++) + gic_write_lr(n, 0); -void gic_inject_pending(void) -{ - u16 irq_id; - - while (pending_irqs.head != pending_irqs.tail) { - irq_id = pending_irqs.irqs[pending_irqs.head]; - - if (gic_inject_irq(irq_id) == -EBUSY) { - /* - * The list registers are full, trigger maintenance - * interrupt and leave. - */ - gic_enable_maint_irq(true); - return; - } - - /* - * Ensure that the entry was read before updating the head - * index. - */ - dmb(ish); - - pending_irqs.head = (pending_irqs.head + 1) % MAX_PENDING_IRQS; - } - - /* - * The software interrupt queue is empty - turn off the maintenance - * interrupt. - */ - gic_enable_maint_irq(false); + /* Clear active priority bits. */ + iowrite32(&gic->gich->apr, 0); + } -void gic_set_pending(u16 irq_id) -{ - unsigned int new_tail; +#endif /* CONFIG_ARM64VT */ - if (gic_inject_irq(irq_id) != -EBUSY) - return; +#ifdef CONFIG_AVZ +void gich_init(void) { + u32 gicc_ctlr, gicc_pmr; + u32 vtr, vmcr; + int n; + + gicc_ctlr = ioread32(&gic->gicc->ctlr); + gicc_pmr = ioread32(&gic->gicc->pmr); + + iowrite32(&gic->gich->vmcr, 0); + + vtr = ioread32(&gic->gich->vtr); + + /* Reveals to be 4 for virt64 board */ + gic->gic_num_lr = (vtr & 0x3f) + 1; + + /* VMCR only contains 5 bits of priority */ + vmcr = (gicc_pmr >> GICV_PMR_PRIORITY_SHIFT) << GICH_VMCR_PRIMASK_SHIFT; + + /* + * All virtual interrupts are group 0 in this driver since the GICV + * layout seen by the guest corresponds to GICC without security + * extensions: + * + * - A read from GICV_IAR doesn't acknowledge group 1 interrupts + * (GICV_AIAR does it, but the guest never attempts to accesses it) + * - A write to GICV_CTLR.GRP0EN corresponds to the GICC_CTLR.GRP1EN bit + * Since the guest's driver thinks that it is accessing a GIC with + * security extensions, a write to GPR1EN will enable group 0 + * interrupts. + * - Group 0 interrupts are presented as virtual IRQs (FIQEn = 0) + */ + + if (gicc_ctlr & GICC_CTLR_GRPEN1) + vmcr |= GICH_VMCR_ENABLE_GRP0_MASK; + if (gicc_ctlr & GICC_CTLR_EOImode) + vmcr |= GICH_VMCR_EOI_MODE_MASK; + + iowrite32(&gic->gich->vmcr, vmcr); + + pending_irqs.head = 0; + pending_irqs.tail = 0; + + /* + * Clear pending virtual IRQs in case anything is left from previous + * use. Physically pending IRQs will be forwarded to Linux once we + * enable interrupts for the hypervisor, except for SGIs, see below. + */ + + gic_clear_pending_irqs(); + + iowrite32(&gic->gich->hcr, GICH_HCR_EN); + + /* + * Forward any pending physical SGIs to the virtual queue. + * We will convert them into self-inject SGIs, ignoring the original + * source. But Linux doesn't care about that anyway. + */ + for (n = 0; n < 16; n++) { + if (ioread8(((u8 *) &gic->gicd->cpendsgirn) + n)) { + iowrite8(((u8 *) &gic->gicd->cpendsgirn) + n, 0xff); + gic_set_pending(n); + } + } +} +#endif /* CONFIG_AVZ */ - spin_lock(&pending_irqs.lock); +void gicc_init(void) { + unsigned int cpu = smp_processor_id(); + u32 bypass = 0; + int i; - new_tail = (pending_irqs.tail + 1) % MAX_PENDING_IRQS; + spin_lock_init(&per_cpu(intc_lock, cpu)); - /* Queue space available? */ - if (new_tail != pending_irqs.head) { - pending_irqs.irqs[pending_irqs.tail] = irq_id; + /* + * Deal with the banked PPI and SGI interrupts - disable all + * PPI interrupts, ensure all SGI interrupts are enabled. + */ + iowrite32(&gic->gicd->icenabler, GICD_INT_EN_CLR_PPI); + iowrite32(&gic->gicd->isenabler, GICD_INT_EN_SET_SGI); - /* - * Make the entry content is visible before updating the tail - * index. - */ - dmb(ish); + /* Priority for all SGI and PPI interrupts is the highest (value 0) */ + for (i = 0; i < 32; i += 4) + iowrite32(&gic->gicd->ipriorityr[i / 4], 0); - pending_irqs.tail = new_tail; - } + /* Allow all priorities */ + iowrite32(&gic->gicc->pmr, GICC_INT_PRI_THRESHOLD); - /* - * The unlock has memory barrier semantic on ARM v7 and v8. Therefore - * the change to tail will be visible when sending SGI_INJECT later on. - */ - spin_unlock(&pending_irqs.lock); + /* + * Preserve bypass disable bits to be written back later + */ + bypass = ioread32(&gic->gicc->ctlr); + bypass &= GICC_DIS_BYPASS_MASK; - /* - * The list registers are full, trigger maintenance interrupt if we are - * on the target CPU. In the other case, send SGI_INJECT to the target - * CPU. - */ + iowrite32(&gic->gicc->ctlr, bypass | GICC_ENABLE | GIC_CPU_EOI); - gic_enable_maint_irq(true); +#ifdef CONFIG_AVZ + gich_init(); +#endif } - -#endif /* CONFIG_ARM64VT */ - -static void gic_eoi_irq(u32 irq_id, bool deactivate) -{ - /* - * The GIC doesn't seem to care about the CPUID value written to EOIR, - * which is rather convenient... - */ - iowrite32(&gic->gicc->eoir, irq_id); - if (deactivate) - iowrite32(&gic->gicc->dir, irq_id); +static void gic_eoi_irq(u32 irq_id, bool deactivate) { + /* + * The GIC doesn't seem to care about the CPUID value written to EOIR, + * which is rather convenient... + */ + iowrite32(&gic->gicc->eoir, irq_id); + if (deactivate) + iowrite32(&gic->gicc->dir, irq_id); } static void gic_enable(unsigned int irq) { - gic_unmask(irq); + gic_unmask(irq); } static void gic_disable(unsigned int irq) { - gic_mask(irq); + gic_mask(irq); } /* @@ -415,291 +491,210 @@ static void gic_disable(unsigned int irq) { * valid range for an IRQ (30-1020 inclusive). * */ - -static void gic_handle(cpu_regs_t *cpu_regs) { - int irq_nr; - int irqstat; - -#ifdef CONFIG_ARM64VT - arm_timer_t *arm_timer = (arm_timer_t *) dev_get_drvdata(periodic_timer.dev); -#endif - - do { - irqstat = ioread32(&gic->gicc->iar); - irq_nr = irqstat & GICC_IAR_INT_ID_MASK; - - if (irq_nr > 1021) - break; - - if (irq_nr < 16) - /* At this level, IPI are used to trigger a guest because - * an event has been raised. So, the domain will check for - * this event along the return path. - */ - - gic_eoi_irq(irq_nr, false); - else { - -#ifdef CONFIG_ARM64VT - if (irq_nr == arm_timer->irq_def.irqnr) { - irq_process(irq_nr); - gic_eoi_irq(irq_nr, false); - } else { - - if (irq_nr == IRQ_ARCH_ARM_MAINT) { - gic_inject_pending(); - gic_eoi_irq(irq_nr, true); - continue; - } else { - gic_set_pending(irq_nr); - gic_eoi_irq(irq_nr, false); - } - } +static void gic_handle(void *data) { + int irq_nr; + int irqstat; + + do { + irqstat = ioread32(&gic->gicc->iar); + irq_nr = irqstat & GICC_IAR_INT_ID_MASK; + + if (irq_nr > 1021) + break; + + if (irq_nr < 16) { +#ifdef CONFIG_AVZ + if ((smp_processor_id() == ME_CPU) && current_domain->avz_shared->evtchn_upcall_pending) + gic_set_pending(irq_nr); + #else - irq_process(irq_nr); + /* Forward the IRQ processing to another logical IRQ chip */ + irq_to_desc(irq_nr)->irq_ops->handle_high(irq_nr); - gic_eoi_irq(irq_nr, false); #endif - } + gic_eoi_irq(irq_nr, false); + } else { + +#ifdef CONFIG_AVZ + if (irq_nr == IRQ_ARCH_ARM_MAINT) { + gic_inject_pending(); + gic_eoi_irq(irq_nr, true); + continue; + } +#endif + irq_to_desc(irq_nr)->irq_ops->handle_high(irq_nr); + gic_eoi_irq(irq_nr, false); + } - } while (true); + } while (true); } -#ifdef CONFIG_ARM64VT +void smp_cross_call(long cpu_mask, unsigned int irq) { + unsigned long flags; + int cpu = smp_processor_id(); -static void gic_clear_pending_irqs(void) -{ - unsigned int n; + flags = spin_lock_irqsave(&per_cpu(intc_lock, cpu)); - /* Clear list registers. */ - for (n = 0; n < gic->gic_num_lr; n++) - gic_write_lr(n, 0); + /* + * Ensure that stores to Normal memory are visible to the + * other CPUs before they observe us issuing the IPI. + */ + smp_mb(); - /* Clear active priority bits. */ - iowrite32(&gic->gich->apr, 0); + /* This always happens on GIC0 */ + iowrite32(&gic->gicd->sgir, (cpu_mask << 16) | irq); + + spin_unlock_irqrestore(&per_cpu(intc_lock, cpu), flags); } -#endif /* CONFIG_ARM64VT */ +void gic_set_type(unsigned int irq, unsigned int type) { + u32 confmask = 0x2 << ((irq % 16) * 2); + u32 val, oldval; -void smp_cross_call(long cpu_mask, unsigned int irq) -{ - unsigned long flags; - int cpu = smp_processor_id(); + /* + * Read current configuration register, and insert the config + * for "irq", depending on "type". + */ - flags = spin_lock_irqsave(&per_cpu(intc_lock, cpu)); + val = oldval = ioread32(&gic->gicd->icfgr[irq / 16]); - /* - * Ensure that stores to Normal memory are visible to the - * other CPUs before they observe us issuing the IPI. - */ - smp_mb(); + if (type & IRQ_TYPE_LEVEL_MASK) + val &= ~confmask; + else if (type & IRQ_TYPE_EDGE_BOTH) + val |= confmask; - /* This always happens on GIC0 */ - iowrite32(&gic->gicd->sgir, (cpu_mask << 16) | irq); + /* If the current configuration is the same, then we are done */ + if (val == oldval) + return; - spin_unlock_irqrestore(&per_cpu(intc_lock, cpu), flags); + iowrite32(&gic->gicd->icfgr[irq / 16], val); } -void gic_set_type(unsigned int irq, unsigned int type) -{ - u32 confmask = 0x2 << ((irq % 16) * 2); - u32 val, oldval; +/** + * @brief Reset the GIC - for instance after resuming + * + */ + void gic_hw_reset(void) { + unsigned int n; + u32 gicd_isacter; - /* - * Read current configuration register, and insert the config - * for "irq", depending on "type". - */ + iowrite32(&gic->gicd->icenabler, 0xffff0000); - val = oldval = ioread32(&gic->gicd->icfgr[irq/16]); + /* Deactivate all active SGIs */ + gicd_isacter = ioread32(&gic->gicd->isactiver); + iowrite32(&gic->gicd->isactiver, gicd_isacter & 0xffff); - if (type & IRQ_TYPE_LEVEL_MASK) - val &= ~confmask; - else if (type & IRQ_TYPE_EDGE_BOTH) - val |= confmask; + /* Initialize distributor and CPU interface of GIC. + * See Linux implementation as reference: http://lxr.free-electrons.com/source/arch/arm/common/gic.c?v=3.2 + */ - /* If the current configuration is the same, then we are done */ - if (val == oldval) - return ; + /* Distributor interface initialization */ - iowrite32(&gic->gicd->icfgr[irq/16], val); + /* Disable distributor */ + iowrite32(&gic->gicd->ctlr, ioread32(((void *) &gic->gicd->ctlr) + INTC_CPU_CTRL_REG0) & ~INTC_DISABLE); + + /* All interrupts level triggered, active high by default */ + for (n = 32; n < NR_IRQS; n++) + gic_set_type(n, IRQ_TYPE_LEVEL_HIGH); -} + /* Target CPU for all IRQs is CPU0 */ + for (n = 32; n < NR_IRQS; n += 4) { + iowrite32(&gic->gicd->itargetsr[n / 4], 0x01010101); + } -static int gic_init(dev_t *dev, int fdt_offset) { - const struct fdt_property *prop; - int prop_len; - u32 gicc_ctlr, gicc_pmr; - u32 gicd_isacter; - unsigned int n; + /* Priority for all interrupts is the highest (value 0) */ + for (n = 32; n < NR_IRQS; n += 4) { + iowrite32(&gic->gicd->ipriorityr[n / 4], 0); + } -#ifdef CONFIG_ARM64VT - u32 vtr, vmcr; -#endif + /* Disable all interrupts */ + for (n = 32; n < NR_IRQS; n += 32) { + iowrite32(&gic->gicd->icenabler[n / 32], 0xffffffff); + } - gic = (gic_t *) malloc(sizeof(gic_t)); - BUG_ON(!gic); + /* Enable distributor */ + iowrite32(&gic->gicd->ctlr, GICD_ENABLE); - DBG("%s\n", __FUNCTION__); + /* CPU interface initialization */ - prop = fdt_get_property(__fdt_addr, fdt_offset, "reg", &prop_len); - BUG_ON(!prop); + /* Handle SGI (0-15) and PPI interrupts (16-31) separately */ + /* Disable all PPI and SGI interrupts */ + iowrite32(&gic->gicd->icenabler[0], 0xffffffff); -#if defined(CONFIG_AVZ) && defined(CONFIG_ARM64VT) - BUG_ON(prop_len != 6 * sizeof(unsigned long)); -#else - BUG_ON(prop_len != 4 * sizeof(unsigned long)); -#endif - - /* Mapping the two mem area of GIC (distributor & CPU interface) */ -#ifdef CONFIG_ARCH_ARM32 - gic->gicd = (struct gicd_regs *) io_map(fdt32_to_cpu(((const fdt32_t *) prop->data)[0]), fdt32_to_cpu(((const fdt32_t *) prop->data)[1])); - gic->gicc = (struct gicc_regs *) io_map(fdt32_to_cpu(((const fdt32_t *) prop->data)[2]), fdt32_to_cpu(((const fdt32_t *) prop->data)[3])); -#else - gic->gicd = (struct gicd_regs *) io_map(fdt64_to_cpu(((const fdt64_t *) prop->data)[0]), fdt64_to_cpu(((const fdt64_t *) prop->data)[1])); - gic->gicc = (struct gicc_regs *) io_map(fdt64_to_cpu(((const fdt64_t *) prop->data)[2]), fdt64_to_cpu(((const fdt64_t *) prop->data)[3])); -#endif - -#ifdef CONFIG_ARM64VT - gic->gich = (void *) io_map(fdt64_to_cpu(((const fdt64_t *) prop->data)[4]), fdt64_to_cpu(((const fdt64_t *) prop->data)[5])); + /* Priority for all SGI and PPI interrupts is the highest (value 0) */ + for (n = 0; n < 32; n += 4) { + iowrite32(&gic->gicd->ipriorityr[n / 4], 0); + } - spin_lock_init(&pending_irqs.lock); + /* Allow all priorities */ + iowrite32(&gic->gicc->pmr, 0xff); - /* Disable PPIs, except for the maintenance interrupt. */ - iowrite32(&gic->gicd->isenabler, 0xffff0000 & ~(1 << IRQ_ARCH_ARM_MAINT)); + /* Enable CPU interface */ + iowrite32(&gic->gicc->ctlr, GICC_ENABLE); - /* Ensure all IPIs and the maintenance PPI are enabled */ - iowrite32(&gic->gicd->isenabler, 0x0000ffff & ~(1 << IRQ_ARCH_ARM_MAINT)); + } - /* Deactivate all active PPIs */ - iowrite32(&gic->gicd->icenabler, 0xffff0000); +/** + * @brief We always consider using a GICv2. Initialize GICv2 + * + * @param dev FDT device reference + * @param fdt_offset Offset in the DTS + * @return int + */ +static int gic_init(dev_t *dev, int fdt_offset) { + const struct fdt_property *prop; + int prop_len; - iowrite32(&gic->gich->vmcr, 0); + gic = (gic_t *) malloc(sizeof(gic_t)); + BUG_ON(!gic); - pending_irqs.head = 0; - pending_irqs.tail = 0; + DBG("%s\n", __FUNCTION__); - gic_clear_pending_irqs(); + prop = fdt_get_property(__fdt_addr, fdt_offset, "reg", &prop_len); + BUG_ON(!prop); +#if defined(CONFIG_AVZ) + BUG_ON(prop_len != 6 * sizeof(unsigned long)); +#else + BUG_ON(prop_len != 4 * sizeof(unsigned long)); #endif - gicc_ctlr = ioread32(&gic->gicc->ctlr); - gicc_pmr = ioread32(&gic->gicc->pmr); - -#ifdef CONFIG_ARM64VT + /* Mapping the two mem area of GIC (distributor & CPU interface) */ +#ifdef CONFIG_ARCH_ARM32 + gic->gicd = (struct gicd_regs *) io_map(fdt32_to_cpu(((const fdt32_t *) prop->data)[0]), fdt32_to_cpu(((const fdt32_t *) prop->data)[1])); + gic->gicd_paddr = (void *) fdt32_to_cpu(((const fdt32_t *) prop->data)[0]); - vtr = ioread32(&gic->gich->vtr); - gic->gic_num_lr = (vtr & 0x3f) + 1; - - /* VMCR only contains 5 bits of priority */ - vmcr = (gicc_pmr >> GICV_PMR_SHIFT) << GICH_VMCR_PMR_SHIFT; - /* - * All virtual interrupts are group 0 in this driver since the GICV - * layout seen by the guest corresponds to GICC without security - * extensions: - * - A read from GICV_IAR doesn't acknowledge group 1 interrupts - * (GICV_AIAR does it, but the guest never attempts to accesses it) - * - A write to GICV_CTLR.GRP0EN corresponds to the GICC_CTLR.GRP1EN bit - * Since the guest's driver thinks that it is accessing a GIC with - * security extensions, a write to GPR1EN will enable group 0 - * interrupts. - * - Group 0 interrupts are presented as virtual IRQs (FIQEn = 0) - */ - - if (gicc_ctlr & GICC_CTLR_GRPEN1) - vmcr |= GICH_VMCR_EN0; - if (gicc_ctlr & GICC_CTLR_EOImode) - vmcr |= GICH_VMCR_EOImode; - - iowrite32(&gic->gich->vmcr, vmcr); - - iowrite32(&gic->gich->hcr, GICH_HCR_EN); - - /* - * Clear pending virtual IRQs in case anything is left from previous - * use. Physically pending IRQs will be forwarded to Linux once we - * enable interrupts for the hypervisor, except for SGIs, see below. - */ - gic_clear_pending_irqs(); + gic->gicc = (struct gicc_regs *) io_map(fdt32_to_cpu(((const fdt32_t *) prop->data)[2]), fdt32_to_cpu(((const fdt32_t *) prop->data)[3])); +#else + gic->gicd = (struct gicd_regs *) io_map(fdt64_to_cpu(((const fdt64_t *) prop->data)[0]), fdt64_to_cpu(((const fdt64_t *) prop->data)[1])); + gic->gicd_paddr = (void *) fdt64_to_cpu(((const fdt64_t *) prop->data)[0]); + gic->gicc = (struct gicc_regs *) io_map(fdt64_to_cpu(((const fdt64_t *) prop->data)[2]), fdt64_to_cpu(((const fdt64_t *) prop->data)[3])); #endif - /* Deactivate all active SGIs */ - gicd_isacter = ioread32(&gic->gicd->isactiver); - iowrite32(&gic->gicd->isactiver, gicd_isacter & 0xffff); - -#ifdef CONFIG_ARM64VT - /* - * Forward any pending physical SGIs to the virtual queue. - * We will convert them into self-inject SGIs, ignoring the original - * source. But Linux doesn't care about that anyway. - */ - for (n = 0; n < 16; n++) { - if (ioread8(((u8 *) &gic->gicd->cpendsgirn) + n)) { - iowrite8(((u8 *) &gic->gicd->cpendsgirn) + n, 0xff); - gic_set_pending(n); - } - } - -#else /* CONFIG_ARM64VT */ +#ifdef CONFIG_AVZ - /* Initialize distributor and CPU interface of GIC. - * See Linux implementation as reference: http://lxr.free-electrons.com/source/arch/arm/common/gic.c?v=3.2 - */ + gic->gich = (struct gich_regs *) io_map(fdt64_to_cpu(((const fdt64_t *) prop->data)[4]), fdt64_to_cpu(((const fdt64_t *) prop->data)[5])); - /* Distributor interface initialization */ + spin_lock_init(&pending_irqs.lock); - /* Disable distributor */ - iowrite32(&gic->gicd->ctlr, ioread32(((void *) &gic->gicd->ctlr) + INTC_CPU_CTRL_REG0) & ~INTC_DISABLE); + /* Disable PPIs, except for the maintenance interrupt. */ + iowrite32(&gic->gicd->isenabler, 0xffff0000 & ~(1 << IRQ_ARCH_ARM_MAINT)); - /* All interrupts level triggered, active high by default */ - for (n = 32; n < NR_IRQS; n++) - gic_set_type(n, IRQ_TYPE_LEVEL_HIGH); + /* Ensure all IPIs and the maintenance PPI are enabled */ + iowrite32(&gic->gicd->isenabler, 0x0000ffff & ~(1 << IRQ_ARCH_ARM_MAINT)); - /* Target CPU for all IRQs is CPU0 */ - for (n = 32; n < NR_IRQS; n += 4) { - iowrite32(&gic->gicd->itargetsr[n/4], 0x01010101); - } - - /* Priority for all interrupts is the highest (value 0) */ - for (n = 32; n < NR_IRQS; n += 4) { - iowrite32(&gic->gicd->ipriorityr[n/4], 0); - } - - /* Disable all interrupts */ - for (n = 32; n < NR_IRQS; n += 32) { - iowrite32(&gic->gicd->icenabler[n/32], 0xffffffff); - } - - /* Enable distributor */ - iowrite32(&gic->gicd->ctlr, GICD_ENABLE); - - /* CPU interface initialization */ - - /* Handle SGI (0-15) and PPI interrupts (16-31) separately */ - /* Disable all PPI and SGI interrupts */ - iowrite32(&gic->gicd->icenabler[0], 0xffffffff); - - /* Priority for all SGI and PPI interrupts is the highest (value 0) */ - for (n = 0; n < 32; n += 4) { - iowrite32(&gic->gicd->ipriorityr[n/4], 0); - } - - /* Allow all priorities */ - iowrite32(&gic->gicc->pmr, 0xff); - - /* Enable CPU interface */ - iowrite32(&gic->gicc->ctlr, GICC_ENABLE); +#endif -#endif /* !CONFIG_ARM64VT */ + gic_hw_reset(); - irq_ops.enable = gic_enable; - irq_ops.disable = gic_disable; - irq_ops.mask = gic_mask; - irq_ops.unmask = gic_unmask; - irq_ops.handle = gic_handle; + irq_ops.enable = gic_enable; + irq_ops.disable = gic_disable; + irq_ops.mask = gic_mask; + irq_ops.unmask = gic_unmask; + irq_ops.handle_low = gic_handle; - return 0; + return 0; } REGISTER_DRIVER_CORE("intc,gic", gic_init); - diff --git a/so3/devices/irq/soo_irq.c b/so3/devices/irq/soo_irq.c deleted file mode 100644 index cfc28a5d21..0000000000 --- a/so3/devices/irq/soo_irq.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2016-2023 Daniel Rossier - * Copyright (C) 2016-2018 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#if 0 -#define DEBUG -#endif - -#include - -#include -#include -#include - -#include - -#include - -#include - -/* - * Interface to generic handling in irq.c - */ - -static void dynirq_handle(cpu_regs_t *regs) { - - /* Perform the VIRQ interrupt processing */ - evtchn_do_upcall(regs); - -} - -void mask_dynirq(uint32_t irq) { - mask_evtchn(evtchn_from_irq(irq)); -} - -void unmask_dynirq(uint32_t irq) { - unmask_evtchn(evtchn_from_irq(irq)); -} - -static void enable_dynirq(unsigned int irq) { - unmask_dynirq(irq); -} - -static void disable_dynirq(unsigned int irq) { - mask_dynirq(irq); -} - -static int soo_irq_init(dev_t *dev, int fdt_offset) { - - DBG("%s\n", __FUNCTION__); - - DBG("%s 0x%08x bit %d\n", __func__, (unsigned int) ®s->gicd_spendsgirn[54/32], 54 % 32); - - irq_ops.mask = mask_dynirq; - irq_ops.unmask = unmask_dynirq; - - irq_ops.enable = enable_dynirq; - irq_ops.disable = disable_dynirq; - - irq_ops.handle = dynirq_handle; - - return 0; -} - -REGISTER_DRIVER_POSTCORE("soo-irq", soo_irq_init); - diff --git a/so3/devices/irq/vgic.c b/so3/devices/irq/vgic.c new file mode 100644 index 0000000000..c7410b8424 --- /dev/null +++ b/so3/devices/irq/vgic.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2024-2025 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#include + +#include +#include + +DEFINE_SPINLOCK(dist_lock); + +static enum mmio_result gicv2_handle_dist_access(struct mmio_access *mmio) { + unsigned long val = mmio->value; + struct sgi; + + switch (mmio->address) { + case GICD_SGIR: + if (!mmio->is_write) + return MMIO_HANDLED; + + smp_cross_call((val >> 16) & 0xff, val & 0xf); + + return MMIO_HANDLED; + + case GICD_CTLR: + case GICD_TYPER: + case GICD_IIDR: + case REG_RANGE(GICDv2_PIDR0, 4, 4): + case REG_RANGE(GICDv2_PIDR4, 4, 4): + case REG_RANGE(GICDv2_CIDR0, 4, 4): + /* Allow read access, ignore write */ + if (!mmio->is_write) + mmio_perform_access(gic->gicd, mmio); + + /* fall through */ + default: + /* Ignore access. */ + return MMIO_HANDLED; + } +} + +/* + * GICv2 uses 8bit values for each IRQ in the ITARGETSR registers + */ +static enum mmio_result gicv2_handle_irq_target(struct mmio_access *mmio, + unsigned int irq) +{ + /* + * ITARGETSR contain one byte per IRQ, so the first one affected by this + * access corresponds to the reg index + */ + unsigned int irq_base = irq & ~0x3; + unsigned int offset; + u32 access_mask = 0; + unsigned int n; + u8 targets; + u32 itargetsr; + + /* + * Let the guest freely access its SGIs and PPIs, which may be used to + * fill its CPU interface map. + */ + if (!is_spi(irq)) { + mmio_perform_access(gic->gicd, mmio); + return MMIO_HANDLED; + } + + /* + * The registers are byte-accessible, but we always do word accesses. + */ + offset = irq % 4; + mmio->address &= ~0x3; + mmio->value <<= 8 * offset; + + for (n = offset; n < mmio->size + offset; n++) { + access_mask |= 0xff << (8 * n); + + if (!mmio->is_write) + continue; + + targets = (mmio->value >> (8 * n)) & 0xff; + } + + mmio->size = 4; + + if (mmio->is_write) { + spin_lock(&dist_lock); + + itargetsr = ioread32((void *) gic->gicd + GICD_ITARGETSR + irq_base); + mmio->value &= access_mask; + + /* Combine with external SPIs */ + mmio->value |= (itargetsr & ~access_mask); + + /* And do the access */ + mmio_perform_access(gic->gicd, mmio); + spin_unlock(&dist_lock); + + } else { + + mmio_perform_access(gic->gicd, mmio); + mmio->value &= access_mask; + mmio->value >>= 8 * offset; + } + + return MMIO_HANDLED; +} + +enum mmio_result gic_handle_dist_access(struct mmio_access *mmio) { + unsigned long reg = mmio->address; + enum mmio_result ret; + + switch (reg) { + case REG_RANGE(GICD_IROUTER, 1024, 8): + /* doesn't exist in v2 - ignore access */ + return MMIO_HANDLED; + + case REG_RANGE(GICD_ITARGETSR, 1024, 1): + ret = gicv2_handle_irq_target(mmio, reg - GICD_ITARGETSR); + break; + + case REG_RANGE(GICD_ICENABLER, 32, 4): + case REG_RANGE(GICD_ISENABLER, 32, 4): + case REG_RANGE(GICD_ICPENDR, 32, 4): + case REG_RANGE(GICD_ISPENDR, 32, 4): + case REG_RANGE(GICD_ICACTIVER, 32, 4): + case REG_RANGE(GICD_ISACTIVER, 32, 4): + + /* Currently, the guest has no way to handle a physical IRQ*/ + ret = gicv2_handle_dist_access(mmio); + break; + + default: + ret = gicv2_handle_dist_access(mmio); + } + + return ret; +} \ No newline at end of file diff --git a/so3/devices/serial/Kconfig b/so3/devices/serial/Kconfig index 915c50664b..4ba64b6d6f 100644 --- a/so3/devices/serial/Kconfig +++ b/so3/devices/serial/Kconfig @@ -5,6 +5,7 @@ config NS16550 config PL011_UART bool "PL011 UART serial interface" depends on VIRT32 || VIRT64 + depends on !SOO_SERIAL config BCM283x_MU_UART bool "BCM283x mini-UART" diff --git a/so3/devices/timer/Kconfig b/so3/devices/timer/Kconfig index 86f77e06ef..2a6d71d250 100644 --- a/so3/devices/timer/Kconfig +++ b/so3/devices/timer/Kconfig @@ -5,6 +5,7 @@ config SP804 config ARM_TIMER bool "ARM architected CP15 timer for clocksource & clockevent" + depends on !SOO_TIMER config SOO_TIMER bool "SOO Virtualized timer device" diff --git a/so3/devices/timer/soo_timer.c b/so3/devices/timer/soo_timer.c index 8d318dc078..fa046e4335 100644 --- a/so3/devices/timer/soo_timer.c +++ b/so3/devices/timer/soo_timer.c @@ -54,11 +54,9 @@ u64 clocksource_read(void) { return arch_counter_get_cntvct(); } -/* Called after a migration. */ -void postmig_adjust_timer(void) { - +void clocksource_timer_reset(void) { + clocksource_timer.rate = arch_timer_get_cntfrq(); clocksource_timer.cycle_last = clocksource_timer.read(); - } /* @@ -71,8 +69,8 @@ static int clocksource_timer_init(dev_t *dev, int fdt_offset) { clocksource_timer.read = clocksource_read; clocksource_timer.rate = arch_timer_get_cntfrq(); clocksource_timer.mask = CLOCKSOURCE_MASK(56); - - return 0; + + return 0; } void periodic_timer_start(void) { diff --git a/so3/dts/Makefile b/so3/dts/Makefile index c398e43168..b3f6da5119 100644 --- a/so3/dts/Makefile +++ b/so3/dts/Makefile @@ -1,7 +1,7 @@ dtb-$(CONFIG_RPI4) += rpi4.dtb rpi4_avz.dtb -dtb-$(CONFIG_RPI4_64) += rpi4_64.dtb rpi4_64_avz_pv.dtb rpi4_64_avz_vt.dtb -dtb-$(CONFIG_VIRT64) += virt64.dtb virt64_avz_pv.dtb virt64_avz_vt.dtb +dtb-$(CONFIG_RPI4_64) += rpi4_64.dtb rpi4_64_avz_vt.dtb +dtb-$(CONFIG_VIRT64) += virt64.dtb virt64_avz_vt.dtb virt64_guest.dtb dtb-$(CONFIG_VIRT32) += virt32.dtb virt32_avz.dtb ifeq ($(CONFIG_SOO),y) diff --git a/so3/dts/virt64.dts b/so3/dts/virt64.dts index e128be26e9..95defa2da2 100644 --- a/so3/dts/virt64.dts +++ b/so3/dts/virt64.dts @@ -35,10 +35,6 @@ reg = <0x0 0x41000000 0x0 0x20000000>; /* 512 MB */ }; - agency { - domain-size = <0x10000000>; - }; - /* GIC interrupt controller */ gic:interrupt-controller@0x08000000 { compatible = "intc,gic"; diff --git a/so3/dts/virt64_avz_pv.dts b/so3/dts/virt64_guest.dts similarity index 50% rename from so3/dts/virt64_avz_pv.dts rename to so3/dts/virt64_guest.dts index 7e0efd9eda..0a6951bcdd 100644 --- a/so3/dts/virt64_avz_pv.dts +++ b/so3/dts/virt64_guest.dts @@ -32,43 +32,81 @@ memory { device_type = "memory"; - reg = <0x0 0x40000000 0x0 0x40000000>; + reg = <0x0 0x41000000 0x0 0x4000000>; /* 64 MB */ + }; + + soo-serial { + compatible = "soo-serial"; + status = "ok"; + }; + + /* SO3 virtual timer managed by AVZ */ + + soo-timer { + compatible = "soo-timer,periodic-timer"; + status = "ok"; + }; + + /* Free-running clocksource */ + clocksource-timer { + compatible = "soo-timer,clocksource-timer"; + status = "ok"; + }; + + oneshot-timer { + compatible = "soo-timer,oneshot-timer"; + status = "ok"; }; /* GIC interrupt controller */ - gic:interrupt-controller@0x08000000 { + gic: interrupt-controller@0x08000000 { compatible = "intc,gic"; interrupt-controller; #interrupt-cells = <3>; - /* GIC dist, cpu */ - reg = <0x0 0x08000000 0x0 0x10000 + + /* GIC dist, cpu, hyp */ + reg = <0x0 0x08000000 0x0 0x10000 0x0 0x08010000 0x0 0x10000>; - - status = "ok"; - }; - - /* virt64 console UART */ - serial@09000000 { - compatible = "serial,pl011"; - reg = <0x0 0x09000000 0x0 0x1000>; - interrupt-parent = <&gic>; - interrupts = <0 1 4>; - status = "ok"; - }; - /* Periodic timer based on ARM CP15 timer */ - periodic-timer { - compatible = "arm,periodic-timer"; - interrupt-parent = <&gic>; - - /* IRQ 10 with VT support or 11 without */ - interrupts = <1 11 4>; status = "ok"; }; - /* Clocksource free-running timer based on ARM CP15 timer */ - clocksource-timer { - compatible = "arm,clocksource-timer"; + mydev { + compatible = "arm,mydev"; status = "ok"; }; + + ME { + /* SPID on 64-bit encoding */ + spid = /bits/ 64 <0x0030000000000003>; + + /* Name of this ME */ + me_name = "SOO.refso3"; + + /* Short description */ + me_shortdesc = + + "This is the standard reference ME that can be used as template or simply to \ + perform various tests. This variant includes a rootfs with some user space \ + applications."; + + frontends { + + /* Enabling vdummy for testing purposes */ + vdummy { + compatible = "vdummy,frontend"; + status = "disabled"; + }; + + /* Enabling the console */ + vuart { + compatible = "vuart,frontend"; + status = "ok"; + }; + + + }; + }; + + }; diff --git a/so3/include/arm-smccc.h b/so3/include/arm-smccc.h index 6b04b5ee07..e6f7186c83 100644 --- a/so3/include/arm-smccc.h +++ b/so3/include/arm-smccc.h @@ -14,7 +14,7 @@ #ifndef __ARM_SMCCC_H #define __ARM_SMCCC_H -#include +#include /* * This file provides common defines for ARM SMC Calling Convention as diff --git a/so3/include/avz/domctl.h b/so3/include/avz/domctl.h deleted file mode 100644 index eebb950a53..0000000000 --- a/so3/include/avz/domctl.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016-2018 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __DOMCTL_H__ -#define __DOMCTL_H__ - -#include - -/* - * There are two main scheduling policies: the one used for normal (standard) ME, and - * a second one used for realtime ME. - */ -#define AVZ_SCHEDULER_FLIP 0 -#define AVZ_SCHEDULER_RT 1 - -#define DOMCTL_pauseME 1 -#define DOMCTL_unpauseME 2 -#define DOMCTL_get_AVZ_shared 3 - -struct domctl_unpause_ME { - uint32_t vbstore_pfn; -}; - -struct domctl { - uint32_t cmd; - domid_t domain; - union { - struct domctl_unpause_ME unpause_ME; - addr_t avz_shared_paddr; - } u; -}; -typedef struct domctl domctl_t; - -#endif /* __DOMCTL_H__ */ - - diff --git a/so3/include/avz/event.h b/so3/include/avz/event.h deleted file mode 100644 index 873a040404..0000000000 --- a/so3/include/avz/event.h +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * event.h - * - * A nice interface for passing asynchronous events to guest OSes. - * - * Copyright (c) 2002-2006, K A Fraser - */ - -#ifndef __EVENT_H__ -#define __EVENT_H__ - -#include -#include -#include - -#include - -/* - * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ. - * @v: VCPU to which virtual IRQ should be sent - * @virq: Virtual IRQ number (VIRQ_*) - */ -void send_guest_virq(struct domain *d, int virq); - -/* - * send_guest_pirq: - * @d: Domain to which physical IRQ should be sent - * @pirq: Physical IRQ number - * Returns TRUE if the delivery port was already pending. - */ -int send_guest_pirq(struct domain *d, int pirq); - -/* Send a notification from a given domain's event-channel port. */ -void evtchn_send(struct domain *d, unsigned int lport); - -/* Bind a local event-channel port to the specified VCPU. */ -long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); - -/* Unmask a local event-channel port. */ -int evtchn_unmask(unsigned int port); - -bool handle_guest_bound_irq(unsigned int irq); - -void do_event_channel_op(int cmd, void *args); - -void event_channel_init(void); - -#endif /* __EVENT_H__ */ diff --git a/so3/include/avz/hypercall.h b/so3/include/avz/hypercall.h deleted file mode 100644 index 7abd8776a9..0000000000 --- a/so3/include/avz/hypercall.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 2022 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#ifndef HYPERCALL_H -#define HYPERCALL_H - -#include - -void do_domctl(domctl_t *args); - -#endif /* HYPERCALL_H */ diff --git a/so3/include/avz/injector.h b/so3/include/avz/injector.h deleted file mode 100644 index 139597f9cb..0000000000 --- a/so3/include/avz/injector.h +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/so3/include/avz/logbool.h b/so3/include/avz/logbool.h deleted file mode 100644 index a4247cf51f..0000000000 --- a/so3/include/avz/logbool.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2018 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef LOGBOOL_H -#define LOGBOOL_H - -#include - -/* Number of (key, value) pair in the hashtable. The number is taken from the code example. */ -#define LOGBOOL_HT_SIZE 4096 - -/* Maximal size of the logbool string */ -#define LOGBOOL_STR_SIZE 160 - -#if 0 -#define ENABLE_LOGBOOL -#endif - -typedef struct { - bool section_state; /* on / off */ - int cpu; - int count; /* Number of visits in this section */ -} logbool_t; - -struct entry_s { - char *key; - logbool_t value; - struct entry_s *next; -}; - -typedef struct entry_s entry_t; - -struct hashtable_s { - int size; - struct entry_s **table; -}; - -typedef struct hashtable_s logbool_hashtable_t; - -#ifdef __AVZ__ -extern logbool_hashtable_t *avz_logbool_ht; -extern void logbool_init(void); -#define logbool_hashtable avz_logbool_ht -#else /* !__AVZ__ */ -typedef void(*ht_set_t)(logbool_hashtable_t *, char *, logbool_t); -extern ht_set_t __ht_set; -#define logbool_hashtable avz_shared_info->logbool_ht -#endif - -extern void ht_set(logbool_hashtable_t *hashtable, char *key, logbool_t value); -extern int sprintf(char * buf, const char *fmt, ...); - -#ifdef ENABLE_LOGBOOL -#define __LOGBOOL_ON \ - { \ - char __logbool_str[LOGBOOL_STR_SIZE]; \ - static logbool_t logbool = { 0 }; \ - sprintf(__logbool_str, "%s:%s:%d", __FILE__, __func__, __LINE__); \ - logbool.section_state = true; \ - logbool.cpu = smp_processor_id(); \ - logbool.count++; \ - ht_set(logbool_hashtable, __logbool_str, logbool); - -#define __LOGBOOL_OFF \ - logbool.section_state = false; \ - ht_set(logbool_hashtable, __logbool_str, logbool); \ - } -#else -#define __LOGBOOL_ON -#define __LOGBOOL_OFF -#endif /* ENABLE_LOGBOOL */ - -void *ht_create(int size); -void ht_destroy(logbool_hashtable_t *hashtable); - -void dump_all_logbool(unsigned char key); - - -#endif /* LOGBOOL_H */ - diff --git a/so3/include/avz/uapi/avz.h b/so3/include/avz/uapi/avz.h deleted file mode 100644 index 9fcbf05a5a..0000000000 --- a/so3/include/avz/uapi/avz.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2016-2022 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef AVZ_H -#define AVZ_H - -#include - -#include - -/* - * AVZ HYPERCALLS - */ - -#define __HYPERVISOR_event_channel_op 0 -#define __HYPERVISOR_console_io 1 -#define __HYPERVISOR_physdev_op 2 -#define __HYPERVISOR_sched_op 3 -#define __HYPERVISOR_domctl 4 -#define __HYPERVISOR_soo_hypercall 5 - -/* - * VIRTUAL INTERRUPTS - * - * Virtual interrupts that a guest OS may receive from the hypervisor. - * - */ -#define NR_VIRQS 8 - -#define VIRQ_TIMER 0 /* System timer tick virtualized interrupt */ -#define VIRQ_TIMER_RT 1 /* Timer tick issued from the oneshot timer (for RT agency and MEs */ - -/**************************************************/ - -/* - * Commands to HYPERVISOR_console_io(). - */ -#define CONSOLEIO_write_string 0 -#define CONSOLEIO_process_char 1 - -/* Idle domain. */ -#define DOMID_IDLE (0x7FFFU) - -/* DOMID_SELF is used in certain contexts to refer to oneself. */ -#define DOMID_SELF (0x7FF0U) - -/* Agency */ -#define DOMID_AGENCY 0 - -/* Realtime agency subdomain */ -#define DOMID_AGENCY_RT 1 - -extern int hypercall_trampoline(int hcall, long a0, long a2, long a3, long a4); - -/* - * 128 event channels per domain - */ -#define NR_EVTCHN 128 - -/* - * Shared info page, shared between AVZ and the domain. - */ -struct avz_shared { - - domid_t domID; - - /* Domain related information */ - unsigned long nr_pages; /* Total pages allocated to this domain. */ - - /* Hypercall vector addr for direct branching without syscall */ - addr_t hypercall_vaddr; - - /* Interrupt routine in the domain */ - addr_t vectors_vaddr; - - /* Domcall routine in the domain */ - addr_t domcall_vaddr; - - addr_t fdt_paddr; - - /* Low-level print function mainly for debugging purpose */ - void (*printch)(char c); - - /* VBstore pfn */ - unsigned long vbstore_pfn; - - unsigned long dom_phys_offset; - - /* Physical and virtual address of the page table used when the domain is bootstraping */ - addr_t pagetable_paddr; - addr_t pagetable_vaddr; /* Required when bootstrapping the domain */ - - /* Address of the logbool ht_set function which can be used in the domain. */ - unsigned long logbool_ht_set_addr; - - /* We inform the domain about the hypervisor memory region so that the - * domain can re-map correctly. - */ - addr_t hypervisor_vaddr; - - /* Other fields related to domain life */ - - unsigned long domain_stack; - uint8_t evtchn_upcall_pending; - - /* - * A domain can create "event channels" on which it can send and receive - * asynchronous event notifications. - * Each event channel is assigned a bit in evtchn_pending and its modification has to be - * kept atomic. - */ - - volatile bool evtchn_pending[NR_EVTCHN]; - - atomic_t dc_event; - - /* Agency or ME descriptor */ - dom_desc_t dom_desc; - - /* Keep the physical address so that the guest can map within in its address space. */ - addr_t subdomain_shared_paddr; - - struct avz_shared *subdomain_shared; - - /* Reference to the logbool hashtable (one per each domain) */ - void *logbool_ht; - - /* Used to store a signature for consistency checking, for example after a migration/restoration */ - char signature[4]; -}; - -typedef struct avz_shared avz_shared_t; - -extern avz_shared_t *avz_shared; - -/* - * DOMCALLs - */ -typedef void (*domcall_t)(int cmd, void *arg); - -#define DOMCALL_sync_vbstore 1 -#define DOMCALL_post_migration_sync_ctrl 2 -#define DOMCALL_sync_domain_interactions 3 -#define DOMCALL_presetup_adjust_variables 4 -#define DOMCALL_postsetup_adjust_variables 5 -#define DOMCALL_fix_other_page_tables 6 -#define DOMCALL_sync_directcomm 7 -#define DOMCALL_soo 8 - -struct DOMCALL_presetup_adjust_variables_args { - avz_shared_t *avz_shared; /* IN */ -}; - -struct DOMCALL_postsetup_adjust_variables_args { - long pfn_offset; -}; - -struct DOMCALL_fix_page_tables_args { - long pfn_offset; /* Offset with which to fix the page table entries */ - unsigned int min_pfn, nr_pages; /* min_pfn is the physical start address of the target RAM, nr_pages the number of pages */ -}; - -struct DOMCALL_directcomm_args { - unsigned int directcomm_evtchn; -}; - -struct DOMCALL_sync_vbstore_args { - unsigned int vbstore_pfn; /* OUT */ - unsigned int vbstore_revtchn; /* Agency side */ -}; - -struct DOMCALL_sync_domain_interactions_args { - unsigned int vbstore_pfn; /* IN */ - unsigned int vbstore_levtchn; -}; - -void postmig_adjust_timer(void); - -#ifndef CONFIG_AVZ -#define ME_domID() (avz_shared->domID) -#endif - -#endif /* AVZ_H */ - diff --git a/so3/include/avz/uapi/event_channel.h b/so3/include/avz/uapi/event_channel.h deleted file mode 100644 index 1f99f59d93..0000000000 --- a/so3/include/avz/uapi/event_channel.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2016-2018 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __EVENT_CHANNEL_H__ -#define __EVENT_CHANNEL_H__ - -#include - -#define ECS_FREE 0 /* Channel is available for use. */ -#define ECS_RESERVED 1 /* Channel is reserved. */ -#define ECS_UNBOUND 2 /* Channel is waiting to bind to a remote domain. */ -#define ECS_INTERDOMAIN 3 /* Channel is bound to another domain. */ -#define ECS_VIRQ 4 /* Channel is bound to a virtual IRQ line. */ - -#define EVTCHNSTAT_closed 0 /* Channel is not in use. */ -#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/ -#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ -#define EVTCHNSTAT_virq 3 /* Channel is bound to a virtual IRQ line */ -/* - * EVTCHNOP_alloc_unbound: Allocate a evtchn in domain and mark as - * accepting interdomain bindings from domain . A fresh evtchn - * is allocated in and returned as . - * NOTES: - * 1. If the caller is unprivileged then must be DOMID_SELF. - * 2. may be DOMID_SELF, allowing loopback connections. - */ -#define EVTCHNOP_alloc_unbound 6 -struct evtchn_alloc_unbound { - /* IN parameters */ - domid_t dom, remote_dom; - /* OUT parameters */ - uint32_t evtchn; - uint32_t use; -}; -typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t; - -/* - * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between - * the calling domain and . must identify - * a evtchn that is unbound and marked as accepting bindings from the calling - * domain. A fresh evtchn is allocated in the calling domain and returned as - * . - * NOTES: - * 2. may be DOMID_SELF, allowing loopback connections. - */ -#define EVTCHNOP_bind_interdomain 0 -#define EVTCHNOP_bind_existing_interdomain 7 -#define EVTCHNOP_unbind_domain 12 - -struct evtchn_bind_interdomain { - /* IN parameters. */ - domid_t remote_dom; - uint32_t remote_evtchn; - uint32_t use; - /* OUT parameters. */ - uint32_t local_evtchn; -}; -typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t; - -#define EVTCHNOP_bind_virq 1 -struct evtchn_bind_virq { - /* IN parameters. */ - uint32_t virq; - /* OUT parameters. */ - uint32_t evtchn; -}; -typedef struct evtchn_bind_virq evtchn_bind_virq_t; - - -/* - * EVTCHNOP_close: Close a local event channel . If the channel is - * interdomain then the remote end is placed in the unbound state - * (EVTCHNSTAT_unbound), awaiting a new connection. - */ -#define EVTCHNOP_close 3 -struct evtchn_close { - /* IN parameters. */ - uint32_t evtchn; -}; -typedef struct evtchn_close evtchn_close_t; - -/* - * EVTCHNOP_send: Send an event to the remote end of the channel whose local - * endpoint is . - */ -#define EVTCHNOP_send 4 -struct evtchn_send { - /* IN parameters. */ - uint32_t evtchn; -}; -typedef struct evtchn_send evtchn_send_t; - -/* - * EVTCHNOP_status: Get the current status of the communication channel which - * has an endpoint at . - * NOTES: - * 1. may be specified as DOMID_SELF. - * 2. Only a sufficiently-privileged domain may obtain the status of an event - * channel for which is not DOMID_SELF. - */ -#define EVTCHNOP_status 5 -struct evtchn_status { - /* IN parameters */ - domid_t dom; - uint32_t evtchn; - /* OUT parameters */ - - uint32_t status; - - union { - struct { - domid_t dom; - } unbound; /* EVTCHNSTAT_unbound */ - struct { - domid_t dom; - uint32_t evtchn; - } interdomain; /* EVTCHNSTAT_interdomain */ - - uint32_t virq; /* EVTCHNSTAT_virq */ - } u; -}; -typedef struct evtchn_status evtchn_status_t; - -/* - * EVTCHNOP_unmask: Unmask the specified local event-channel evtchn and deliver - * a notification to the appropriate VCPU if an event is pending. - */ -#define EVTCHNOP_unmask 9 -struct evtchn_unmask { - /* IN parameters. */ - uint32_t evtchn; -}; -typedef struct evtchn_unmask evtchn_unmask_t; - -/* - * EVTCHNOP_reset: Close all event channels associated with specified domain. - * NOTES: - * 1. may be specified as DOMID_SELF. - * 2. Only a sufficiently-privileged domain may specify other than DOMID_SELF. - */ -#define EVTCHNOP_reset 10 -struct evtchn_reset { - /* IN parameters. */ - domid_t dom; -}; -typedef struct evtchn_reset evtchn_reset_t; - -struct evtchn_op { - uint32_t cmd; /* EVTCHNOP_* */ - union { - struct evtchn_alloc_unbound alloc_unbound; - struct evtchn_bind_interdomain bind_interdomain; - struct evtchn_bind_virq bind_virq; - struct evtchn_close close; - struct evtchn_send send; - struct evtchn_status status; - struct evtchn_unmask unmask; - } u; -}; -typedef struct evtchn_op evtchn_op_t; - -#endif /* __EVENT_CHANNEL_H__ */ - diff --git a/so3/include/avz/uapi/me_access.h b/so3/include/avz/uapi/me_access.h deleted file mode 100644 index 444a26bc7d..0000000000 --- a/so3/include/avz/uapi/me_access.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2016-2021 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef ME_ACCESS_H -#define ME_ACCESS_H - -#ifndef __KERNEL__ - -#include -#include - -#else - -#include - -#ifdef CONFIG_AVZ -#include -#endif - -#endif - -#ifndef CONFIG_AVZ - -#ifndef __SO3__ -#include -typedef uint64_t addr_t; -#endif - -#endif - -#include - -/* - * Capabilities for the Species Aptitude Descriptor (SPAD) structure - * - */ - -#define SPADCAP_HEATING_CONTROL (1 << 0) - -/* - * Species Aptitude Descriptor (SPAD) - */ -typedef struct { - - /* Indicate if the ME accepts to collaborate with other ME */ - bool valid; - - /* SPAD capabilities */ - uint64_t spadcaps; - -} spad_t; - -/* This structure is used as the first field of the ME buffer frame header */ -typedef struct { - - uint32_t ME_size; - uint32_t size_mig_structure; - -} ME_info_transfer_t; - -/* - * ME states: - * - ME_state_booting: ME is currently booting... - * - ME_state_preparing: ME is being paused during the boot process, in the case of an injection, before the frontend initialization - * - ME_state_living: ME is full-functional and activated (all frontend devices are consistent) - * - ME_state_suspended: ME is suspended before migrating. This state is maintained for the resident ME instance - * - ME_state_migrating: ME just arrived in SOO - * - ME_state_dormant: ME is resident, but not living (running) - all frontends are closed/shutdown - * - ME_state_killed: ME has been killed before to be resumed - * - ME_state_terminated: ME has been terminated (by a force_terminate) - * - ME_state_dead: ME does not exist - */ -typedef enum { - ME_state_booting, - ME_state_preparing, - ME_state_living, - ME_state_suspended, - ME_state_migrating, - ME_state_dormant, - ME_state_killed, - ME_state_terminated, - ME_state_dead -} ME_state_t; - -/* Keep information about slot availability - * FREE: the slot is available (no ME) - * BUSY: the slot is allocated a ME - */ -typedef enum { - ME_SLOT_FREE, - ME_SLOT_BUSY -} ME_slotState_t; - -/* - * ME descriptor - * - * WARNING !! Be careful when modifying this structure. It *MUST* be aligned with - * the same structure used in the ME. - */ -typedef struct { - unsigned int slotID; - - ME_state_t state; - - unsigned int size; /* Size of the ME */ - unsigned int pfn; - - uint64_t spid; /* Species ID */ - spad_t spad; /* ME Species Aptitude Descriptor */ -} ME_desc_t; - -/* ME ID related information */ -#define ME_NAME_SIZE 40 -#define ME_SHORTDESC_SIZE 1024 - -/* - * Definition of ME ID information used by functions which need - * to get a list of running MEs with their information. - */ -typedef struct { - uint32_t slotID; - ME_state_t state; - - uint64_t spid; - uint64_t spadcaps; - - char name[ME_NAME_SIZE]; - char shortdesc[ME_SHORTDESC_SIZE]; -} ME_id_t; - -/* Fixed size for the header of the ME buffer frame (max.) */ -#define ME_EXTRA_BUFFER_SIZE (1024 * 1024) - -#ifndef CONFIG_AVZ - -int get_ME_state(void); -void set_ME_state(ME_state_t state); - -int32_t get_ME_free_slot(uint32_t size); - -bool get_ME_id(uint32_t slotID, ME_id_t *ME_id); - -void get_ME_id_array(ME_id_t *ME_id_array); -char *xml_prepare_id_array(ME_id_t *ME_id_array); - -ME_desc_t *get_ME_desc(void); - -#endif /* !CONFIG_AVZ */ - -#endif /* ME_ACCESS_H */ - - diff --git a/so3/include/avz/uapi/soo.h b/so3/include/avz/uapi/soo.h deleted file mode 100644 index 0cff964eeb..0000000000 --- a/so3/include/avz/uapi/soo.h +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2014-2019 Daniel Rossier - * Copyright (C) 2016, 2018 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef UAPI_SOO_H -#define UAPI_SOO_H - -#ifndef __ASSEMBLY__ - -#include - -/* This signature is used to check the coherency of the ME image, after a migration - * or a restoration for example. - */ -#define SOO_ME_SIGNATURE "SooZ" - -#define MAX_ME_DOMAINS 5 - -/* We include the (non-RT & RT) agency domain */ -#define MAX_DOMAINS (2 + MAX_ME_DOMAINS) -#endif /* __ASSEMBLY__ */ - -#define AGENCY_CPU 0 -#define AGENCY_RT_CPU 1 - -#ifndef __ASSEMBLY__ - -#include - -#include - -#ifdef CONFIG_AVZ - -/* Device tree features */ -#define ME_FEAT_ROOT "/me_features" - -void soo_activity_init(void); -void soo_pre_activate(unsigned int slotID); -void soo_cooperate(unsigned int slotID); -void shutdown_ME(unsigned int ME_slotID); - -ME_state_t get_ME_state(unsigned int ME_slotID); -void set_ME_state(unsigned int ME_slotID, ME_state_t state); - -#endif /* CONFIG_AVZ */ - -struct work_struct; -struct semaphore; - -typedef uint16_t domid_t; - -/* - * Directcomm event management - */ -typedef enum { - DC_NO_EVENT, - DC_PRE_SUSPEND, - DC_SUSPEND, - DC_RESUME, - DC_FORCE_TERMINATE, - DC_POST_ACTIVATE, - DC_TRIGGER_DEV_PROBE, - DC_TRIGGER_LOCAL_COOPERATION, - - DC_EVENT_MAX /* Used to determine the number of DC events */ -} dc_event_t; - -/* - * Callback function associated to dc_event. - */ -typedef void(dc_event_fn_t)(dc_event_t dc_event); - -#ifdef __KERNEL__ - -extern atomic_t dc_outgoing_domID[DC_EVENT_MAX]; -extern atomic_t dc_incoming_domID[DC_EVENT_MAX]; - -#endif /* __KERNEL__ */ - -#ifdef __KERNEL__ - -void set_pfn_offset(long pfn_offset); -long get_pfn_offset(void); - -#endif /* __KERNEL__ */ - -/* - * IOCTL commands for migration. - * This part is shared between the kernel and user spaces. - */ - -/* - * IOCTL codes - */ -#define AGENCY_IOCTL_INIT_MIGRATION _IOWR('S', 0, agency_ioctl_args_t) -#define AGENCY_IOCTL_GET_ME_FREE_SLOT _IOWR('S', 1, agency_ioctl_args_t) -#define AGENCY_IOCTL_READ_SNAPSHOT _IOWR('S', 2, agency_ioctl_args_t) -#define AGENCY_IOCTL_WRITE_SNAPSHOT _IOW('S', 3, agency_ioctl_args_t) -#define AGENCY_IOCTL_FINAL_MIGRATION _IOW('S', 4, agency_ioctl_args_t) -#define AGENCY_IOCTL_FORCE_TERMINATE _IOW('S', 5, agency_ioctl_args_t) -#define AGENCY_IOCTL_INJECT_ME _IOWR('S', 6, agency_ioctl_args_t) -#define AGENCY_IOCTL_GET_ME_ID _IOWR('S', 7, agency_ioctl_args_t) -#define AGENCY_IOCTL_GET_UPGRADE_IMG _IOR('S', 8, agency_ioctl_args_t) -#define AGENCY_IOCTL_STORE_VERSIONS _IOW('S', 9, agency_ioctl_args_t) -#define AGENCY_IOCTL_GET_ME_SNAPSHOT _IOWR('S', 10, agency_ioctl_args_t) -#define AGENCY_IOCTL_GET_ME_ID_ARRAY _IOR('S', 11, agency_ioctl_args_t) -#define AGENCY_IOCTL_BLACKLIST_SOO _IOW('S', 12, agency_ioctl_args_t) - -#define SOO_NAME_SIZE 16 - -#ifdef __KERNEL__ - -/* - * Agency descriptor - */ -typedef struct { - - /* - * SOO agencyUID unique 64-bit ID - Allowing to identify a SOO device. - * agencyUID 0 is NOT valid. - */ - - uint64_t agencyUID; /* Agency UID */ - -} agency_desc_t; - -#endif /* __KERNEL__ */ - -/* This part is shared between the kernel and user spaces */ - -#ifdef __KERNEL__ - -/* - * Device Capabilities (Devcaps) - * - * The agency holds a table of devcaps (device capabilities). - - * A device capability is a 32-bit number. - * - * DEVCAPS are organized in classes and attributes. For each devcaps, the 8 first higher bits are the - * class number while attributes are encoded in the 24 lower bits. - * - * A devcap class represents a global functionality while devcap attributes are the *real* devcaps belongig to a specific class. - * - */ - -#define DEVCAPS_CLASS_FRAMEBUFFER 0x01000000 -#define DEVCAP_FRAMEBUFFER_FB0 (1 << 0) - -#define DEVCAPS_CLASS_INPUT 0x02000000 -#define DEVCAP_INPUT_EVENT (1 << 0) -#define DEVCAP_REMOTE_TABLET (1 << 1) - -#define DEVCAPS_CLASS_COMM 0x03000000 -#define DEVCAP_COMM_UIHANDLER (1 << 0) - -#define DEVCAPS_CLASS_LED 0x04000000 -#define DEVCAP_LED_RGB_SHIELD (1 << 0) -#define DEVCAP_LED_6LED (1 << 1) - -#define DEVCAPS_CLASS_NET 0x05000000 - -#define DEVCAPS_CLASS_DOMOTICS 0x06000000 -#define DEVCAP_BLIND_MOTOR (1 << 0) -#define DEVCAP_WEATHER_DATA (1 << 1) - -/* - * This devcap class is intended to be replaced by a generic framebuffer devcap in a near future. - */ -#define DEVCAPS_CLASS_APP 0x07000000 -#define DEVCAP_APP_BLIND (1 << 0) -#define DEVCAP_APP_OUTDOOR (1 << 1) - -#define DEVCAPS_CLASS_NR 16 - -/* - * SOO agency & ME descriptor - This structure is used in the shared info page of the agency or ME domain. - */ - -typedef struct { - union { - agency_desc_t agency; - ME_desc_t ME; - } u; -} dom_desc_t; - -#endif /* __KERNEL__ */ - -/* struct agency_ioctl_args used in IOCTLs */ -typedef struct agency_ioctl_args { - void *buffer; /* IN/OUT */ - int slotID; - long value; /* IN/OUT */ -} agency_ioctl_args_t; - -typedef struct { - unsigned int itb; - unsigned int uboot; - unsigned int rootfs; -} upgrade_versions_args_t; - -#ifdef __KERNEL__ - -/* - * SOO hypercall management - */ - -typedef struct { - unsigned int domID; - dc_event_t dc_event; - int state; -} soo_hyp_dc_event_t; - - -typedef struct { - unsigned int pid; - unsigned int addr; -} dump_page_t; - - -#endif /* __KERNEL__ */ - -/* This part is shared between the kernel and user spaces */ - -/* - * ME uevent-type events - */ - -#define ME_EVENT_NR 6 - -#define ME_FORCE_TERMINATE 0 -#define ME_PRE_SUSPEND 1 -#define ME_PRE_RESUME 2 -#define ME_LOCALINFO_UPDATE 3 -#define ME_POST_ACTIVATE 4 -#define ME_IMEC_SETUP_PEER 5 - -#define NSECS 1000000000ull -#define SECONDS(_s) ((u64)((_s) * 1000000000ull)) -#define MILLISECS(_ms) ((u64)((_ms) * 1000000ull)) -#define MICROSECS(_us) ((u64)((_us) * 1000ull)) - -/* Periods are expressed in ns as it is used by the function APIs */ - -#define SL_TX_REQUEST_TASK_PRIO 50 -#define SL_SEND_TASK_PRIO 50 -#define SL_RECV_TASK_PRIO 50 - -#define SL_PLUGIN_WLAN_TASK_PRIO 50 -#define SL_PLUGIN_ETHERNET_TASK_PRIO 50 -#define SL_PLUGIN_TCP_TASK_PRIO 50 -#define SL_PLUGIN_BLUETOOTH_TASK_PRIO 50 -#define SL_PLUGIN_LOOPBACK_TASK_PRIO 50 - -#define VBUS_TASK_PRIO 50 - -/* - * The priority of the Directcomm thread must be higher than the priority of the SDIO - * thread to make the Directcomm thread process a DC event and release it before any new - * request by the SDIO's side thus avoiding a deadlock. - */ -#define DC_ISR_TASK_PRIO 55 - -#define SDIO_IRQ_TASK_PRIO 50 -#define SDHCI_FINISH_TASK_PRIO 50 - -/* Soolink definition */ - -/* Discovery */ - -#define DISCOVERY_TASK_PRIO 50 -#define DISCOVERY_TASK_PERIOD_MS 1000 - -/* Soolink Coder */ - -#define CODER_TASK_PRIO 50 - -/* Soolink Decoder */ - -#define DECODER_WATCHDOG_TASK_PRIO 50 -#define DECODER_WATCHDOG_TASK_PERIOD_MS 1000 - -/* Soolink Winenet Datalink */ - -#define WINENET_TASK_PRIO 50 - -/* Tests related */ -#define PLUGIN_TEST_TASK_PRIO 50 -#define TRANSCODER_TEST_TASK_PRIO 50 -#define DISCOVERY_TEST_TASK_PRIO 50 - -#ifndef __ASSEMBLY__ - -extern volatile bool __cobalt_ready; - -void rtdm_register_dc_event_callback(dc_event_t dc_event, dc_event_fn_t *callback); - -#endif /* __ASSEMBLY__ */ - -/* Hypercall commands */ -#define AVZ_MIG_PRE_PROPAGATE 0 -#define AVZ_MIG_PRE_ACTIVATE 1 -#define AVZ_MIG_INIT 2 -#define AVZ_MIG_PUT_ME_INFO 3 -#define AVZ_GET_ME_FREE_SLOT 4 -#define AVZ_MIG_PUT_ME_SLOT 5 -#define AVZ_MIG_READ_MIGRATION_STRUCT 6 -#define AVZ_MIG_WRITE_MIGRATION_STRUCT 7 -#define AVZ_MIG_FINAL 8 -#define AVZ_INJECT_ME 9 -#define AVZ_KILL_ME 10 -#define AVZ_DC_SET 11 -#define AVZ_DC_RELEASE 12 -#define AVZ_GET_ME_STATE 13 -#define AVZ_SET_ME_STATE 14 -#define AVZ_AGENCY_CTL 15 -#define AVZ_GET_DOM_DESC 16 -#define AVZ_TRIGGER_LOCAL_COOPERATION 17 - -/* - * General structure to use with the SOO migration hypercall - */ -typedef struct migrate_op { - int cmd; - unsigned long vaddr; - unsigned long paddr; - void *p_val1; - void *p_val2; -} soo_hyp_t; - -/* - * SOO domcalls management - */ - -typedef struct { - void *val; -} pre_activate_args_t; - -/* - * pre_propagate to tell the agency if the ME must be propagated or not. - */ -#define PROPAGATE_STATUS_YES 1 -#define PROPAGATE_STATUS_NO 0 - -typedef struct { - int propagate_status; -} pre_propagate_args_t; - -/* Cooperate roles */ -#define COOPERATE_INITIATOR 0x1 -#define COOPERATE_TARGET 0x2 - -typedef struct { - uint32_t slotID; - uint64_t spid; - spad_t spad; - addr_t pfn; -} coop_t; - -typedef struct { - - int role; /* Specific to each ME (see drivers/soo/soo_core.c */ - - bool alone; /* true if there is no ME in this SOO */ - - union { - coop_t target_coop; - coop_t initiator_coop; - } u; - -} cooperate_args_t; - -typedef struct { - void *val; -} pre_suspend_args_t; - -typedef struct { - void *val; -} pre_resume_args_t; - -typedef struct { - void *val; -} post_activate_args_t; - -/* - * Further agency ctl commands that may be used by MEs. - * !! WARNING !! The ME must implement the same definitions. - */ - -#define AG_AGENCY_UPGRADE 0x10 -#define AG_INJECT_ME 0x11 -#define AG_KILL_ME 0x12 -#define AG_COOPERATE 0x13 -#define AG_LOCAL_COOPERATE 0x14 - -#define AG_AGENCY_UID 0x20 -#define AG_SOO_NAME 0x21 - -#define AG_CHECK_DEVCAPS_CLASS 0x30 -#define AG_CHECK_DEVCAPS 0x31 - -/* AG_SKIP_ACTIVATION args */ - -typedef struct { - unsigned int delay; /* at the moment, 0 means definitively, otherwise during a certain time (unit to be defined) */ - void *pfn; /* pfn of the ME's data buffer */ -} skip_activation_args_t; - -typedef struct { - uint32_t class; - uint8_t devcaps; - bool supported; /* OUT */ -} devcaps_args_t; - -typedef struct { - char soo_name[SOO_NAME_SIZE]; -} soo_name_args_t; - -typedef struct { - addr_t buffer_pfn; - uint32_t buffer_len; -} agency_upgrade_args_t; - -/* agency_ctl args */ - -typedef struct { - unsigned int slotID; - unsigned int cmd; - - union { - coop_t cooperate_args; - uint64_t agencyUID; - devcaps_args_t devcaps_args; - soo_name_args_t soo_name_args; - agency_upgrade_args_t agency_upgrade_args; - } u; - -} agency_ctl_args_t; - -/* - * SOO callback functions. - * The following definitions are used as argument in domcalls or in the - * agency_ctl() function as a callback to be propagated to a specific ME. - * - */ - -#define CB_PRE_PROPAGATE 1 -#define CB_PRE_ACTIVATE 2 -#define CB_COOPERATE 3 -#define CB_PRE_SUSPEND 4 -#define CB_PRE_RESUME 5 -#define CB_POST_ACTIVATE 6 -#define CB_DUMP_BACKTRACE 7 -#define CB_DUMP_VBSTORE 8 -#define CB_AGENCY_CTL 9 -#define CB_KILL_ME 10 - -typedef struct soo_domcall_arg { - - /* Stores the agency ctl function. - * Possibly, the agency_ctl function can be associated to a callback operation asked by a ME - */ - unsigned int cmd; - unsigned int slotID; /* Origin of the domcall */ - - union { - pre_propagate_args_t pre_propagate_args; - pre_activate_args_t pre_activate_args; - cooperate_args_t cooperate_args; - - pre_suspend_args_t pre_suspend_args; - pre_resume_args_t pre_resume_args; - - post_activate_args_t post_activate_args; - ME_state_t set_me_state_args; - - agency_ctl_args_t agency_ctl_args; - } u; - - /* Reference to the agency_ctl() function implemented in AVZ. - * Used for some function calls initiated by the ME. In this context, - * this function can be considered as a short-path-hypercall. - */ - void (*__agency_ctl)(agency_ctl_args_t *); - -} soo_domcall_arg_t; - -extern struct semaphore usr_feedback; -extern struct semaphore injection_sem; - -void soo_hypercall(int cmd, void *vaddr, void *paddr, void *p_val1, void *p_val2); - -void cb_pre_propagate(soo_domcall_arg_t *args); - -/* Specific ME callbacks issued from the Agency */ -void cb_pre_activate(soo_domcall_arg_t *args); - -/* Callbacks initiated by agency ping */ -void cb_pre_resume(soo_domcall_arg_t *args); -void cb_pre_suspend(soo_domcall_arg_t *args); - -void cb_cooperate(soo_domcall_arg_t *args); -void cb_post_activate(soo_domcall_arg_t *args); -void cb_kill_me(soo_domcall_arg_t *args); - -void cb_force_terminate(void); - -void callbacks_init(void); - -void set_dc_event(domid_t domid, dc_event_t dc_event); - -void do_soo_activity(void *arg); - -void soo_guest_activity_init(void); - -void dc_stable(int dc_event); -void tell_dc_stable(int dc_event); - -void do_sync_dom(int slotID, dc_event_t); -void do_async_dom(int slotID, dc_event_t); - -void perform_task(dc_event_t dc_event); - -int pick_next_uevent(void); - -void shutdown_ME(unsigned int ME_slotID); - -void cache_flush_all(void); - -void check_terminated_ME(void); - -#endif /* __ASSEMBLY__ */ - -#endif /* UAPI_SOO_H */ diff --git a/so3/include/avz/vcpu.h b/so3/include/avz/vcpu.h deleted file mode 100644 index 9dd344dcc8..0000000000 --- a/so3/include/avz/vcpu.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2016 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __VCPU_H__ -#define __VCPU_H__ - -#include - -/* - * Initialise a VCPU. Each VCPU can be initialised only once. A - * newly-initialised VCPU will not run until it is brought up by VCPUOP_up. - * - * @extra_arg == pointer to vcpu_guest_context structure containing initial - * state for the VCPU. - */ -#define VCPUOP_initialise 0 - -/* - * Bring up a VCPU. This makes the VCPU runnable. This operation will fail - * if the VCPU has not been initialised (VCPUOP_initialise). - */ -#define VCPUOP_up 1 - -/* - * Bring down a VCPU (i.e., make it non-runnable). - * There are a few caveats that callers should observe: - * 1. This operation may return, and VCPU_is_up may return false, before the - * VCPU stops running (i.e., the command is asynchronous). It is a good - * idea to ensure that the VCPU has entered a non-critical loop before - * bringing it down. Alternatively, this operation is guaranteed - * synchronous if invoked by the VCPU itself. - * 2. After a VCPU is initialised, there is currently no way to drop all its - * references to domain memory. Even a VCPU that is down still holds - * memory references via its pagetable base pointer and GDT. It is good - * practise to move a VCPU onto an 'idle' or default page table, LDT and - * GDT before bringing it down. - */ -#define VCPUOP_down 2 - -/* Returns 1 if the given VCPU is up. */ -#define VCPUOP_is_up 3 - -/* VCPU is currently running on a physical CPU. */ -#define RUNSTATE_running 0 - -/* VCPU is runnable, but not currently scheduled on any physical CPU. */ -#define RUNSTATE_runnable 1 - -/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */ -#define RUNSTATE_blocked 2 - -/* VCPU is offline, not blocked and not runnable */ -#define RUNSTATE_offline 3 - -/* - * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer - * which can be set via these commands. Periods smaller than one millisecond - * may not be supported. - */ -#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */ -#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */ -struct vcpu_set_periodic_timer { - uint64_t period_ns; -}; -typedef struct vcpu_set_periodic_timer vcpu_set_periodic_timer_t; - -/* - * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot - * timer which can be set via these commands. - */ -#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */ -#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */ -struct vcpu_set_singleshot_timer { - uint64_t timeout_abs_ns; /* Absolute system time value in nanoseconds. */ - uint32_t flags; /* VCPU_SSHOTTMR_??? */ -}; -typedef struct vcpu_set_singleshot_timer vcpu_set_singleshot_timer_t; - - -#endif /* __VCPU_H__ */ - diff --git a/so3/include/common.h b/so3/include/common.h index 77cb45da51..db703080b8 100644 --- a/so3/include/common.h +++ b/so3/include/common.h @@ -26,7 +26,7 @@ #include #include #include - + #endif /* __ASSEMBLY__ */ #ifdef CONFIG_AVZ @@ -52,8 +52,6 @@ extern addr_t __end[]; #ifdef CONFIG_AVZ -#include - /* * Pseudo-usr mode allows the hypervisor to switch back to the right stack (G-stach/H-stack) depending on whether * the guest issued a hypercall or if an interrupt occurred during some processing in the hypervisor. @@ -150,7 +148,7 @@ do { \ do { if ( unlikely(!(p)) ) assert_failed(#p); } while (0) typedef enum { - BOOT_STAGE_INIT, BOOT_STAGE_IRQ_INIT, BOOT_STAGE_SCHED, BOOT_STAGE_IRQ_ENABLE, BOOT_STAGE_COMPLETED + BOOT_STAGE_INIT, BOOT_STAGE_HEAP_READY, BOOT_STAGE_IRQ_INIT, BOOT_STAGE_SCHED, BOOT_STAGE_IRQ_ENABLE, BOOT_STAGE_COMPLETED } boot_stage_t; extern boot_stage_t boot_stage; diff --git a/so3/include/const.h b/so3/include/const.h deleted file mode 100644 index cdc9a0ba6c..0000000000 --- a/so3/include/const.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* const.h: Macros for dealing with constants. */ - -#ifndef CONST_H -#define CONST_H - -/* Some constant macros are used in both assembler and - * C code. Therefore we cannot annotate them always with - * 'UL' and other type specifiers unilaterally. We - * use the following macros to deal with this. - * - * Similarly, _AT() will cast an expression with a type in C, but - * leave it unchanged in asm. - */ - -#ifdef __ASSEMBLY__ -#define _AC(X,Y) X -#define _AT(T,X) X -#else -#define __AC(X,Y) (X##Y) -#define _AC(X,Y) __AC(X,Y) -#define _AT(T,X) ((T)(X)) -#endif - -#define _BITUL(x) (_AC(1,UL) << (x)) -#define _BITULL(x) (_AC(1,ULL) << (x)) - -#endif /* CONST_H */ diff --git a/so3/include/device/arch/gic.h b/so3/include/device/arch/gic.h index 000692a0bf..1702530d09 100644 --- a/so3/include/device/arch/gic.h +++ b/so3/include/device/arch/gic.h @@ -155,23 +155,22 @@ struct gicc_regs { }; -struct gich_regs { - volatile uint32_t hcr; /* 0x000 */ - volatile uint32_t vtr; /* 0x004 */ - volatile uint32_t vmcr; /* 0x008 */ - volatile uint32_t _res0; /* 0x00c */ - volatile uint32_t misr; /* 0x010 */ - volatile uint32_t _res1[3]; /* 0x14-0x1c */ - volatile uint32_t eisr0; /* 0x020 */ - volatile uint32_t eisr1; /* 0x024 */ - volatile uint32_t _res2[2]; /* 0x28-0x2c */ - volatile uint32_t elsr0; /* 0x030 */ - volatile uint32_t elsr1; /* 0x034 */ - volatile uint32_t _res3[45]; /* 0x38-0xec */ - volatile uint32_t apr; /* 0x0f0 */ - volatile uint32_t _res4[3]; /* 0xf4-0xfc */ - volatile uint32_t lrbase[63]; /* 0x100 (lr0) - ox1f8 */ - volatile uint32_t lr63; /* 0x1fc */ +struct __attribute__((packed)) gich_regs { + volatile uint32_t hcr; /* 0x000: Hypervisor Control Register */ + volatile uint32_t vtr; /* 0x004: Virtualization Control Register */ + volatile uint32_t vmcr; /* 0x008: Virtual Machine Control Register */ + volatile uint32_t _res0; /* 0x00c: Reserved */ + volatile uint32_t misr; /* 0x010: Maintenance Interrupt Status Register */ + volatile uint32_t _res1[3]; /* 0x014-0x01c: Reserved */ + volatile uint32_t eisr0; /* 0x020: Empty List Status Register 0 */ + volatile uint32_t eisr1; /* 0x024: Empty List Status Register 1 */ + volatile uint32_t _res2[2]; /* 0x028-0x02c: Reserved */ + volatile uint32_t elsr0; /* 0x030: Empty List Register 0 */ + volatile uint32_t elsr1; /* 0x034: Empty List Register 1 */ + volatile uint32_t _res3[46];/* 0x038-0x0ec: Reserved */ + volatile uint32_t apr; /* 0x0f0: Active Priorities Register */ + volatile uint32_t _res4[3]; /* 0x0f4-0x0fc: Reserved */ + volatile uint32_t lr[64]; /* 0x100: List Registers 0-63 (0x100 to 0x1FC) */ }; #endif /* __ASSEMBLY__ */ @@ -200,6 +199,25 @@ struct gich_regs { (GICD_INT_DEF_PRI << 16) |\ (GICD_INT_DEF_PRI << 8) |\ GICD_INT_DEF_PRI) +#define GICD_CTLR 0x0000 +#define GICD_CTLR_ARE_NS (1 << 4) +#define GICD_TYPER 0x0004 +#define GICD_IIDR 0x0008 +#define GICD_IGROUPR 0x0080 +#define GICD_ISENABLER 0x0100 +#define GICD_ICENABLER 0x0180 +#define GICD_ISPENDR 0x0200 +#define GICD_ICPENDR 0x0280 +#define GICD_ISACTIVER 0x0300 +#define GICD_ICACTIVER 0x0380 +#define GICD_IPRIORITYR 0x0400 +#define GICD_ITARGETSR 0x0800 +#define GICD_ICFGR 0x0c00 +#define GICD_NSACR 0x0e00 +#define GICD_SGIR 0x0f00 +#define GICD_CPENDSGIR 0x0f10 +#define GICD_SPENDSGIR 0x0f20 +#define GICD_IROUTER 0x6000 #define GICC_SIZE 0x2000 #define GICH_SIZE 0x2000 @@ -214,12 +232,28 @@ struct gich_regs { #define GICC_PMR_DEFAULT 0xf0 -#define GICV_PMR_SHIFT 3 -#define GICH_VMCR_PMR_SHIFT 27 -#define GICH_VMCR_EN0 (1 << 0) -#define GICH_VMCR_EN1 (1 << 1) -#define GICH_VMCR_ACKCtl (1 << 2) -#define GICH_VMCR_EOImode (1 << 9) +#define GICH_VMCR_ENABLE_GRP0_SHIFT 0 +#define GICH_VMCR_ENABLE_GRP0_MASK (1 << GICH_VMCR_ENABLE_GRP0_SHIFT) +#define GICH_VMCR_ENABLE_GRP1_SHIFT 1 +#define GICH_VMCR_ENABLE_GRP1_MASK (1 << GICH_VMCR_ENABLE_GRP1_SHIFT) +#define GICH_VMCR_ACK_CTL_SHIFT 2 +#define GICH_VMCR_ACK_CTL_MASK (1 << GICH_VMCR_ACK_CTL_SHIFT) +#define GICH_VMCR_FIQ_EN_SHIFT 3 +#define GICH_VMCR_FIQ_EN_MASK (1 << GICH_VMCR_FIQ_EN_SHIFT) +#define GICH_VMCR_CBPR_SHIFT 4 +#define GICH_VMCR_CBPR_MASK (1 << GICH_VMCR_CBPR_SHIFT) +#define GICH_VMCR_EOI_MODE_SHIFT 9 +#define GICH_VMCR_EOI_MODE_MASK (1 << GICH_VMCR_EOI_MODE_SHIFT) + +#define GICH_VMCR_PRIMASK_SHIFT 27 +#define GICH_VMCR_PRIMASK_MASK (0x1f << GICH_VMCR_PRIMASK_SHIFT) +#define GICH_VMCR_BINPOINT_SHIFT 21 +#define GICH_VMCR_BINPOINT_MASK (0x7 << GICH_VMCR_BINPOINT_SHIFT) +#define GICH_VMCR_ALIAS_BINPOINT_SHIFT 18 +#define GICH_VMCR_ALIAS_BINPOINT_MASK (0x7 << GICH_VMCR_ALIAS_BINPOINT_SHIFT) + +#define GICV_PMR_PRIORITY_SHIFT 3 +#define GICV_PMR_PRIORITY_MASK (0x1f << GICV_PMR_PRIORITY_SHIFT) #define GICH_HCR_EN (1 << 0) #define GICH_HCR_UIE (1 << 1) @@ -236,6 +270,7 @@ struct gich_regs { #define GICH_LR_ACTIVE_BIT (1 << 29) #define GICH_LR_PENDING_BIT (1 << 28) #define GICH_LR_PRIORITY_SHIFT 23 +#define GICH_LR_PRIORITY_MASK 0x1f #define GICH_LR_SGI_EOI_BIT (1 << 19) #define GICH_LR_CPUID_SHIFT 10 #define GICH_LR_PHYS_ID_SHIFT 10 @@ -251,7 +286,37 @@ struct gich_regs { void gicc_init(void); void gic_raise_softirq(int cpu, unsigned int irq); +void gic_hw_reset(void); -#endif +#define is_sgi(irqn) ((u32) (irqn) < 16) +#define is_ppi(irqn) ((irqn) > 15 && (irqn) < 32) +#define is_spi(irqn) ((irqn) > 31 && (irqn) < 1020) + +typedef struct __attribute__((packed)) { + /* Distributor */ + struct gicd_regs *gicd; + + void *gicd_paddr; + + /* CPU interface */ + struct gicc_regs *gicc; + +#ifdef CONFIG_AVZ + /* Hypervisor related */ + struct gich_regs *gich; + + unsigned int gic_num_lr; +#endif /* CONFIG_AVZ */ +} gic_t; +#ifdef CONFIG_AVZ + +void gic_set_pending(u16 irq_id); +void gic_clear_pending_irqs(void); + +#endif /* CONFIG_AVZ */ + +extern gic_t *gic; + +#endif diff --git a/so3/soo/include/soo/debug/packgen.h b/so3/include/device/arch/vgic.h similarity index 59% rename from so3/soo/include/soo/debug/packgen.h rename to so3/include/device/arch/vgic.h index 6906863abf..7854ecd991 100644 --- a/so3/soo/include/soo/debug/packgen.h +++ b/so3/include/device/arch/vgic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Baptiste Delporte + * Copyright (C) 2024 Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,21 +16,15 @@ * */ -#ifndef PACKGEN_H -#define PACKGEN_H +#ifndef VGIC_H +#define VGIC_H -#ifdef __KERNEL__ -#include -#endif /* __KERNEL__ */ +#include -#include +#include -typedef struct { - int (*send)(void *data, size_t size); -} packgen_callbacks_t; +#define REG_RANGE(base, n, size) (base)...((base) + (n - 1) * (size)) -void packgen_register(packgen_callbacks_t *callbacks, size_t size); -void packgen_enable_multi(unsigned int id); -void packgen_send_next_packet(void); +enum mmio_result gic_handle_dist_access(struct mmio_access *mmio); -#endif /* PACKGEN_H */ +#endif /* VGIC_H */ diff --git a/so3/include/device/irq.h b/so3/include/device/irq.h index 2de9495192..5d66c696e0 100644 --- a/so3/include/device/irq.h +++ b/so3/include/device/irq.h @@ -56,6 +56,19 @@ typedef struct { typedef irq_return_t(*irq_handler_t)(int irq, void *data); +/* IRQ controller */ +typedef struct { + + void (*enable)(unsigned int irq); + void (*disable)(unsigned int irq); + void (*mask)(unsigned int irq); + void (*unmask)(unsigned int irq); + + void (*handle_low)(void *data); + void (*handle_high)(unsigned int irq); + +} irq_ops_t; + typedef struct irqdesc { irq_handler_t action; @@ -64,8 +77,11 @@ typedef struct irqdesc { atomic_t deferred_pending; bool thread_active; - /* Private data */ - void *data; + /* Specific IRQ chip (phys/virt) */ + irq_ops_t *irq_ops; + + /* Private data */ + void *data; /* Multi-processing scenarios */ spinlock_t lock; @@ -77,21 +93,9 @@ extern volatile bool __in_interrupt; extern int arch_irq_init(void); extern void setup_arch(void); -/* IRQ controller */ -typedef struct { - - void (*enable)(unsigned int irq); - void (*disable)(unsigned int irq); - void (*mask)(unsigned int irq); - void (*unmask)(unsigned int irq); - - void (*handle)(cpu_regs_t *regs); - -} irq_ops_t; - extern irq_ops_t irq_ops; -int irq_process(uint32_t irq); +void irq_process(uint32_t irq); void irq_init(void); @@ -103,6 +107,8 @@ void irq_unmask(int irq); void irq_bind(int irq, irq_handler_t handler, irq_handler_t irq_deferred_fn, void *data); void irq_unbind(int irq); +void irq_set_irq_ops(int irq, irq_ops_t *irq_ops); + void fdt_interrupt_node(int fdt_offset, irq_def_t *irq_def); #endif /* IRQ_H */ diff --git a/so3/include/linkage.h b/so3/include/linkage.h index 7f313c4b30..5848e4a8be 100644 --- a/so3/include/linkage.h +++ b/so3/include/linkage.h @@ -33,22 +33,31 @@ .size name, .-name #endif -#endif - #ifndef ENDPROC #define ENDPROC(name) \ .type name, %function; \ END(name) #endif + +#endif -/* - * Allow for constants defined here to be used from assembly code - * by prepending the UL suffix only with actual C code compilation. - */ -#ifndef __ASSEMBLY__ -#define UL(x) (x##UL) +#ifdef __ASSEMBLY__ +#define _AC(X, Y) X +#define _AT(T, X) X #else -#define UL(x) (x) +#define __AC(X, Y) (X##Y) +#define _AC(X, Y) __AC(X, Y) +#define _AT(T, X) ((T) (X)) #endif +#define _UL(x) (_AC(x, UL)) +#define _ULL(x) (_AC(x, ULL)) + +#define _BITUL(x) (_UL(1) << (x)) +#define _BITULL(x) (_ULL(1) << (x)) + +#define UL(x) (_UL(x)) +#define ULL(x) (_ULL(x)) + + #endif /* LINKAGE_H */ diff --git a/so3/include/memory.h b/so3/include/memory.h index 02b2562ea2..eaa7421d2f 100644 --- a/so3/include/memory.h +++ b/so3/include/memory.h @@ -82,37 +82,43 @@ typedef struct page page_t; extern page_t *frame_table; extern volatile addr_t pfn_start; +/* TODO: Redefine __lva() which is used only in EL2 (hypervisor) mode */ + #ifdef CONFIG_AVZ /* * We add two functions for retrieving virt and phys address relative to - * Linux offset according to the memory map (used to access guest mem) + * the hypervisor or guest offset. */ -#define __lpa(vaddr) ((vaddr) - AGENCY_VOFFSET + memslot[MEMSLOT_AGENCY].base_paddr) -#define __lva(paddr) ((paddr) - memslot[MEMSLOT_AGENCY].base_paddr + AGENCY_VOFFSET) -void put_ME_slot(unsigned int ME_slotID); -int get_ME_free_slot(unsigned int size, ME_state_t ME_state); -int prepare_ME_slot(int slotID, unsigned int size, ME_state_t ME_state); +#define __xpa(x, vaddr) (addr_t) (((addr_t) vaddr) - memslot[x].base_vaddr + memslot[x].base_paddr) +#define __xva(x, paddr) (addr_t) (((addr_t) paddr) - memslot[x].base_paddr + memslot[x].base_vaddr) -#endif /* CONFIG_AVZ */ +#define __pa(vaddr) (__xpa(MEMSLOT_AVZ, vaddr)) +#define __va(paddr) (__xva(MEMSLOT_AVZ, paddr)) -#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) -#define phys_to_pfn(phys) (((addr_t) phys) >> PAGE_SHIFT) -#define virt_to_pfn(virt) (phys_to_pfn(__va((addr_t) virt))) +#define ipa_offset(x) (memslot[x].ipa_addr - memslot[x].base_paddr) -#define ipa_offset(memslot) (memslot.ipa_addr - memslot.base_paddr) +#define va_to_ipa(x, va) (phys_to_ipa(memslot, __pa(va))) +#define pa_to_ipa(x, pa) (((addr_t) pa) + ipa_offset(x)) -#define virt_to_ipa(memslot, va) (phys_to_ipa(memslot, __pa(va))) -#define phys_to_ipa(memslot, pa) (((addr_t) pa) + ipa_offset(memslot)) +#define ipa_to_pa(x, ipa) (((addr_t) ipa) - ipa_offset(x)) +#define ipa_to_va(x, ipa) (__xva(x, ipa_to_pa(x, ipa))) -#define ipa_to_phys(memslot, ipa) (((addr_t) ipa) - ipa_offset(memslot)) +void put_ME_slot(unsigned int ME_slotID); +int get_ME_free_slot(unsigned int size); -#define ipa_to_lva(memslot, ipa) (__lva(ipa_to_phys(memslot, ipa))) +#else /* CONFIG_AVZ */ #define __pa(vaddr) (((addr_t) vaddr) - CONFIG_KERNEL_VADDR + mem_info.phys_base) #define __va(paddr) (((addr_t) paddr) - mem_info.phys_base + CONFIG_KERNEL_VADDR) +#endif /* !CONFIG_AVZ */ + +#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) +#define phys_to_pfn(phys) (((addr_t) phys) >> PAGE_SHIFT) +#define virt_to_pfn(virt) (phys_to_pfn(__va((addr_t) virt))) + #define page_to_pfn(page) ((addr_t) ((addr_t) (page - frame_table) + pfn_start)) #define pfn_to_page(pfn) (&frame_table[pfn - pfn_start]) @@ -188,10 +194,6 @@ static inline int get_order_from_bytes(addr_t size) void clear_bss(void); -#ifdef CONFIG_SOO -void readjust_io_map(long pfn_offset); -#endif /* CONFIG_SOO */ - #endif /* __ASSEMBLY__ */ #endif /* MEMORY_H */ diff --git a/so3/include/mmio.h b/so3/include/mmio.h new file mode 100644 index 0000000000..179c4e5bae --- /dev/null +++ b/so3/include/mmio.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + * These definitions are heavly borrowed from jailhouse hypervisor + */ + +#ifndef MMIO_H +#define MMIO_H + +#include + +#include + +/** MMIO access result. */ +enum mmio_result {MMIO_ERROR = -1, MMIO_UNHANDLED, MMIO_HANDLED}; + +/** MMIO access description. */ +struct mmio_access { + + /** Address to access, depending on the context, an absolute address or + * relative offset to region start. */ + unsigned long address; + + /** Size of the access. */ + unsigned int size; + + /** True if write access. */ + bool is_write; + + /** The value to be written or the read value to return. */ + unsigned long value; +}; + +int mmio_dabt_decode(cpu_regs_t *regs, unsigned long esr); +void mmio_perform_access(void *base, struct mmio_access *mmio); + +#endif /* MMIO_H */ diff --git a/so3/include/ptrace.h b/so3/include/ptrace.h index 8ba01f1640..17791726d8 100644 --- a/so3/include/ptrace.h +++ b/so3/include/ptrace.h @@ -217,5 +217,6 @@ struct user; void update_cpu_regs(void); void retrieve_cpu_regs(struct user *uregs, struct pcb *pcb); +void __dump_regs(void *regs); #endif diff --git a/so3/include/smp.h b/so3/include/smp.h index 014a16d3bc..1b894a84e2 100644 --- a/so3/include/smp.h +++ b/so3/include/smp.h @@ -20,7 +20,7 @@ void psci_smp_boot_secondary(unsigned int cpu); * Initial data for bringing up a secondary CPU. */ struct secondary_data { - unsigned long pgdir; + addr_t pgdir; void *stack; }; diff --git a/so3/include/stringify.h b/so3/include/stringify.h index b7b2ba49ff..6311bf2654 100644 --- a/so3/include/stringify.h +++ b/so3/include/stringify.h @@ -9,5 +9,8 @@ #define __stringify_1(x...) #x #define __stringify(x...) __stringify_1(x) +#define tostring(s...) #s +#define stringify(s...) tostring(s) + #endif /* !__LINUX_STRINGIFY_H */ diff --git a/so3/include/timer.h b/so3/include/timer.h index 3fca3c2ef3..0cdbb1dc66 100644 --- a/so3/include/timer.h +++ b/so3/include/timer.h @@ -117,9 +117,11 @@ extern void kill_timer(struct timer *timer); */ extern void timer_init(void); +extern void apply_timer_offset(u64 offset); /* Arch-defined function to reprogram timer hardware for new deadline. */ extern void reprogram_timer(u64 deadline); +void clocksource_timer_reset(void); void clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec); diff --git a/so3/ipc/signal.c b/so3/ipc/signal.c index fcc778550b..a9e675495d 100755 --- a/so3/ipc/signal.c +++ b/so3/ipc/signal.c @@ -67,9 +67,9 @@ __sigaction_t *sig_check(void) { current()->pcb->__sa[i].signum = i; current()->pcb->sigset_map.sigmap[(i-1) / (8*sizeof(long))] &= ~(1UL << (i-1) % (8*sizeof(long))); - - return ¤t()->pcb->__sa[i]; - } + + return ¤t()->pcb->__sa[i]; + } } } diff --git a/so3/kernel/Makefile b/so3/kernel/Makefile index 773ead40a4..41c6025e69 100644 --- a/so3/kernel/Makefile +++ b/so3/kernel/Makefile @@ -23,8 +23,6 @@ obj-y += bitmap.o obj-y += softirq.o obj-y += spinlock.o -obj-$(CONFIG_AVZ) += avz/ - obj-$(CONFIG_MMU) += process.o ptrace.o EXTRA_CFLAGS += -I$(srctree)/include/net diff --git a/so3/kernel/avz/agency_build.c b/so3/kernel/avz/agency_build.c deleted file mode 100644 index 43421e8abf..0000000000 --- a/so3/kernel/avz/agency_build.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2016-2023 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -int construct_agency(struct domain *d) { - -#ifdef CONFIG_SOO - unsigned long domain_stack; - extern addr_t *hypervisor_stack; - static addr_t *__hyp_stack = (unsigned long *) &hypervisor_stack; - -#ifndef CONFIG_ARM64VT - static addr_t *__pseudo_usr_mode = (unsigned long *) &pseudo_usr_mode; -#endif - -#endif - - printk("***************************** Loading Agency Domain *****************************\n"); - - /* The agency is always in slot 1 */ - - /* Now the slot is busy. */ - memslot[MEMSLOT_AGENCY].busy = true; - - if (memslot[MEMSLOT_AGENCY].size == 0) { - printk("No agency image supplied\n"); - kernel_panic(); - } - - d->max_pages = ~0U; - - printk("-> Agency base address from ITB: %lx\n", memslot[MEMSLOT_AGENCY].base_paddr); - printk("-> Max dom size %d\n", memslot[MEMSLOT_AGENCY].size); - - ASSERT(d); - - d->avz_shared->nr_pages = memslot[MEMSLOT_AGENCY].size >> PAGE_SHIFT; - d->avz_shared->dom_phys_offset = memslot[MEMSLOT_AGENCY].base_paddr; - - clear_bit(_VPF_down, &d->pause_flags); - -#ifdef CONFIG_SOO - - /* - * Keep a reference in the primary agency domain to its sub-domain. - * Indeed, there is only one shared page mapped in the guest. - */ - agency->avz_shared->subdomain_shared = domains[DOMID_AGENCY_RT]->avz_shared; - -#endif /* CONFIG_SOO */ - -#ifdef CONFIG_ARM64VT - __setup_dom_pgtable(d, memslot[MEMSLOT_AGENCY].base_paddr, memslot[MEMSLOT_AGENCY].size); -#else - __setup_dom_pgtable(d, AGENCY_VOFFSET, memslot[MEMSLOT_AGENCY].size, memslot[MEMSLOT_AGENCY].base_paddr); -#endif - - /* Propagate the virtual address of the shared info page for this domain */ - - d->avz_shared->hypercall_vaddr = (unsigned long) hypercall_entry; - d->avz_shared->fdt_paddr = memslot[MEMSLOT_AGENCY].fdt_paddr; - d->avz_shared->hypervisor_vaddr = CONFIG_KERNEL_VADDR; - - printk("AVZ Hypervisor vaddr: 0x%lx\n", CONFIG_KERNEL_VADDR); - printk("Agency FDT device tree: 0x%lx (phys)\n", d->avz_shared->fdt_paddr); - - printk("Shared AVZ page is located at: %lx\n", d->avz_shared); - - /* HW details on the CPU: processor ID, cache ID and ARM architecture version */ - - d->avz_shared->printch = printch; - -#ifdef CONFIG_SOO - /* Set up a new domain stack for the RT domain */ - domain_stack = (unsigned long) setup_dom_stack(domains[DOMID_AGENCY_RT]); - - /* Store the stack address for further needs in hypercalls/interrupt context */ - __hyp_stack[AGENCY_RT_CPU] = domain_stack; - -#ifndef CONFIG_ARM64VT - /* We set the realtime domain in pseudo-usr mode since the primary domain will start it, not us. */ - __pseudo_usr_mode[AGENCY_RT_CPU] = 1; -#endif - - /* Domain related information */ - domains[DOMID_AGENCY_RT]->avz_shared->nr_pages = d->avz_shared->nr_pages; - domains[DOMID_AGENCY_RT]->avz_shared->hypercall_vaddr = d->avz_shared->hypercall_vaddr; - domains[DOMID_AGENCY_RT]->avz_shared->fdt_paddr = d->avz_shared->fdt_paddr; - domains[DOMID_AGENCY_RT]->avz_shared->dom_phys_offset = d->avz_shared->dom_phys_offset; - domains[DOMID_AGENCY_RT]->avz_shared->pagetable_paddr = d->avz_shared->pagetable_paddr; - domains[DOMID_AGENCY_RT]->avz_shared->logbool_ht_set_addr = d->avz_shared->logbool_ht_set_addr; - domains[DOMID_AGENCY_RT]->avz_shared->hypervisor_vaddr = d->avz_shared->hypervisor_vaddr; - domains[DOMID_AGENCY_RT]->avz_shared->printch = d->avz_shared->printch; - -#endif /* CONFIG_SOO */ - - /* - * Create the first thread associated to this domain. - * The initial stack of the domain is put at the top of the domain memory area. - */ - -#ifdef CONFIG_ARM64VT - new_thread(d, memslot[MEMSLOT_AGENCY].entry_addr, - phys_to_ipa(memslot[MEMSLOT_AGENCY], d->avz_shared->fdt_paddr), - memslot[MEMSLOT_AGENCY].ipa_addr + memslot[MEMSLOT_AGENCY].size); - -#else - new_thread(d, memslot[MEMSLOT_AGENCY].entry_addr, d->avz_shared->fdt_paddr, AGENCY_VOFFSET + memslot[MEMSLOT_AGENCY].size); -#endif - - return 0; -} - diff --git a/so3/kernel/avz/domctl.c b/so3/kernel/avz/domctl.c deleted file mode 100644 index 95e0e67e57..0000000000 --- a/so3/kernel/avz/domctl.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2014-2019 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#if 0 -#define DEBUG -#endif - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -static DEFINE_SPINLOCK(domctl_lock); - -void do_domctl(domctl_t *args) -{ - struct domain *d; - - spin_lock(&domctl_lock); - - d = domains[args->domain]; - - switch (args->cmd) - { - case DOMCTL_pauseME: - - domain_pause_by_systemcontroller(d); - - break; - - case DOMCTL_unpauseME: - /* Retrieve info from hypercall parameter structure */ - d->avz_shared->vbstore_pfn = args->u.unpause_ME.vbstore_pfn; - - DBG("%s: unpausing ME\n", __func__); - - domain_unpause_by_systemcontroller(d); - - break; - -#ifdef CONFIG_ARM64VT - case DOMCTL_get_AVZ_shared: - args->u.avz_shared_paddr = - memslot[(current_domain->avz_shared->domID == DOMID_AGENCY) ? 1 : current_domain->avz_shared->domID].ipa_addr + memslot[MEMSLOT_AGENCY].size; - break; -#endif /* CONFIG_ARM64VT */ - - } - - spin_unlock(&domctl_lock); -} - diff --git a/so3/kernel/avz/injector.c b/so3/kernel/avz/injector.c deleted file mode 100644 index 001de2d180..0000000000 --- a/so3/kernel/avz/injector.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2014-2022 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include - -/** - * Inject a ME within a SOO device. This is the only possibility to load a ME within a Smart Object. - * - * At the entry of this function, the ME ITB could have been allocated in the user space (via the injector application) - * or in the vmalloc'd area of the Linux kernel in case of a BT transfer from the tablet (using vuihandler). - * - * To get rid of the way how the page tables are managed by Linux, we perform a copy of the ME ITB in the - * AVZ heap, assuming that the 8-MB heap is sufficient to host the ITB ME (< 2 MB in most cases). - * - * If the ITB should become larger, it is still possible to compress (and enhance AVZ with a uncompressor invoked - * at loading time). Wouldn't be still not enough, a temporary fixmap mapping combined with get_free_pages should be envisaged - * to have the ME ITB accessible from the AVZ user space area. - * - * @param op (op->vaddr is the ITB buffer, op->p_val1 will contain the slodID in return (-1 if no space), op->p_val2 is the ITB buffer size_ - */ -void inject_me(soo_hyp_t *op) -{ - int slotID; - size_t fdt_size; - void *fdt_vaddr; - int dom_size; - struct domain *domME, *__current; - addr_t current_pgtable_paddr; - unsigned long flags; - void *itb_vaddr; -#ifdef CONFIG_ARCH_ARM64 - uint32_t itb_size; -#endif - -#ifdef CONFIG_ARCH_ARM32 - int section_nr; -#endif - - DBG("%s: Preparing ME injection, source image = %lx\n", __func__, op->vaddr); - - flags = local_irq_save(); - - slotID = *(int *)op->p_val1; - -#ifdef CONFIG_ARCH_ARM64 - - /* First, we do a copy of the ME ITB into the avz heap to get independent from Linux mapping (either - * in the user space, or in the vmalloc'd area). - */ - itb_size = *((uint32_t *) op->p_val2); - - itb_vaddr = malloc(itb_size); - BUG_ON(!itb_vaddr); - - /* op->vaddr: vaddr of itb */ - memcpy(itb_vaddr, (void *) op->vaddr, itb_size); -#else - itb_vaddr = (void *) op->vaddr; -#endif - - /* Retrieve the domain size of this ME through its device tree. */ - fit_image_get_data_and_size(itb_vaddr, fit_image_get_node(itb_vaddr, "fdt"), (const void **) &fdt_vaddr, &fdt_size); - if (!fdt_vaddr) { - printk("### %s: wrong device tree.\n", __func__); - BUG(); - } - - dom_size = fdt_getprop_u32_default(fdt_vaddr, "/ME", "domain-size", 0); - if (dom_size < 0) { - printk("### %s: wrong domain-size prop/value.\n", __func__); - BUG(); - } - - if (slotID == -1) { - /* Find a slotID to store this ME. */ - slotID = get_ME_free_slot(dom_size, ME_state_booting); - if (slotID == -1) - goto out; - } else { - prepare_ME_slot(slotID, dom_size, ME_state_booting); - } - - domME = domains[slotID]; - - /* Set the size of this ME in its own descriptor */ - domME->avz_shared->dom_desc.u.ME.size = memslot[slotID].size; - - /* Now set the pfn base of this ME; this will be useful for the Agency Core subsystem */ - domME->avz_shared->dom_desc.u.ME.pfn = phys_to_pfn(memslot[slotID].base_paddr); - - __current = current_domain; - - mmu_get_current_pgtable(¤t_pgtable_paddr); - -#ifdef CONFIG_ARCH_ARM32 - /* Get the visibility on the domain image stored in the agency user space area */ - for (section_nr = 0x0; section_nr < 0xc00; section_nr++) - ((uint32_t *) __sys_root_pgtable)[section_nr] = ((uint32_t *) __lva(current_pgtable_paddr & TTBR0_BASE_ADDR_MASK))[section_nr]; - - flush_dcache_all(); -#endif /* CONFIG_ARCH_ARM32 */ - - mmu_switch((void *) idle_domain[smp_processor_id()]->avz_shared->pagetable_paddr); - - /* Clear the RAM allocated to this ME */ - memset((void *) __lva(memslot[slotID].base_paddr), 0, memslot[slotID].size); - - loadME(slotID, itb_vaddr); - - if (construct_ME(domains[slotID]) != 0) - panic("Could not set up ME guest OS\n"); - - /* Switch back to the agency address space */ - set_current_domain(__current); - - mmu_switch((void *) current_pgtable_paddr); - -out: - /* Prepare to return the slotID to the caller. */ - *((unsigned int *) op->p_val1) = slotID; - -#ifdef CONFIG_ARCH_ARM64 - free(itb_vaddr); -#endif /* CONFIG_ARCH_ARM64 */ - - local_irq_restore(flags); -} diff --git a/so3/kernel/avz/logbool.c b/so3/kernel/avz/logbool.c deleted file mode 100644 index 5fbb6aefd4..0000000000 --- a/so3/kernel/avz/logbool.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2018 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -typedef entry_t * entryp_t; - -logbool_hashtable_t *avz_logbool_ht; - -/* Create a new hashtable. */ -void *ht_create(int size) { - - logbool_hashtable_t *hashtable = NULL; - int i; - - /* Allocate the table itself. */ - hashtable = malloc(sizeof(logbool_hashtable_t)); - BUG_ON(!hashtable); - - /* Allocate pointers to the head nodes. */ - hashtable->table = malloc(size * sizeof(entryp_t)); - BUG_ON(!hashtable->table); - - for (i = 0; i < size; i++) - hashtable->table[i] = NULL; - - hashtable->size = size; - - return hashtable; -} - -/* Hash a string for a particular hash table. */ -int ht_hash(logbool_hashtable_t *hashtable, char *key) { - - unsigned long int hashval = 0; - int i = 0; - - /* Convert our string to an integer */ - while ((hashval < ULONG_MAX) && (i < strlen(key))) { - hashval = hashval << 8; - hashval += key[i]; - i++; - } - - return hashval % hashtable->size; -} - -/* Create a key-value pair. */ -entry_t *ht_newpair(char *key, logbool_t value) { - entry_t *newpair; - - if ((newpair = malloc(sizeof(entry_t))) == NULL) - return NULL; - - if ((newpair->key = strdup(key)) == NULL) - return NULL; - - value.count = 0; - - newpair->value = value; - newpair->next = NULL; - - return newpair; -} - -/* Insert a key-value pair into a hash table. */ -void ht_set(logbool_hashtable_t *hashtable, char *key, logbool_t value) { - int bin = 0; - entry_t *newpair = NULL; - entry_t *next = NULL; - entry_t *last = NULL; - - bin = ht_hash(hashtable, key); - - next = hashtable->table[bin]; - - while ((next != NULL) && (next->key != NULL) && strcmp(key, next->key) > 0) { - last = next; - next = next->next; - } - - /* There's already a pair. Let's replace that string. */ - if ((next != NULL) && (next->key != NULL) && strcmp(key, next->key) == 0) - next->value = value; - - /* Nope, could't find it. Time to grow a pair. */ - else { - - newpair = ht_newpair(key, value); - - /* We're at the start of the linked list in this bin. */ - if (next == hashtable->table[bin]) { - newpair->next = next; - hashtable->table[bin] = newpair; - - /* We're at the end of the linked list in this bin. */ - } else if (next == NULL) { - last->next = newpair; - - /* We're in the middle of the list. */ - } else { - newpair->next = next; - last->next = newpair; - } - } -} - -/* Retrieve a key-value pair from a hash table. */ -logbool_t *ht_get(logbool_hashtable_t *hashtable, char *key) { - int bin = 0; - entry_t *pair; - - bin = ht_hash(hashtable, key); - - /* Step through the bin, looking for our value. */ - pair = hashtable->table[bin]; - while ((pair != NULL) && (pair->key != NULL) && strcmp(key, pair->key) > 0) - pair = pair->next; - - /* Did we actually find anything? */ - if ((pair == NULL) || (pair->key == NULL) || (strcmp(key, pair->key) != 0)) - return NULL; - else - return &pair->value; - -} - -void ht_destroy(logbool_hashtable_t *hashtable) { - BUG_ON(!hashtable->table); - - free(hashtable->table); - free(hashtable); -} - -void dump_logbool(logbool_hashtable_t *ht) { - int i; - - for (i = 0; i < ht->size; i++) - if (ht->table[i] != NULL) - printk(" %d: %s: on CPU: %d state: %d - # visits: %d\n", i, ht->table[i]->key, ht->table[i]->value.cpu, ht->table[i]->value.section_state, - ht->table[i]->value.count); -} - -void dump_all_logbool(unsigned char key) { - int i; - - printk("***** Dumping logbool of AVZ *****\n"); - dump_logbool(avz_logbool_ht); - - /* Dump logbool hashtable of all domains including avz */ - - printk("***** Dumping non-RT Agency *****\n"); - dump_logbool(domains[DOMID_AGENCY]->avz_shared->logbool_ht); - - printk("***** Dumping RT Agency *****\n"); - dump_logbool(domains[DOMID_AGENCY_RT]->avz_shared->logbool_ht); - - printk("***** Dumping ME logbool activities *****\n"); - for (i = 1; i < MAX_DOMAINS; i++) { - if (domains[i] != NULL) { - printk("***** Dumping logbool of domain %d *****\n", i); - dump_logbool(domains[i]->avz_shared->logbool_ht); - } - } -} - -struct keyhandler dump_logbool_keyhandler = { - .fn = dump_all_logbool, - .desc = "dump logbool hashtable" -}; - - -void logbool_init(void) { - - /* Create a logbool hashtable for AVZ */ - avz_logbool_ht = ht_create(LOGBOOL_HT_SIZE); - - register_keyhandler('x', &dump_logbool_keyhandler); -} diff --git a/so3/kernel/avz/migration.c b/so3/kernel/avz/migration.c deleted file mode 100644 index eeb9faad95..0000000000 --- a/so3/kernel/avz/migration.c +++ /dev/null @@ -1,544 +0,0 @@ - -/* - * Copyright (C) 2014-2022 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#if 0 -#define DEBUG -#endif - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include - -#include -#include - -/* PFN offset on the target platform */ -volatile long pfn_offset = 0; - -/* Start of ME RAM in virtual address space of idle domain (extern) */ -unsigned long vaddr_start_ME = 0; - -/* - * Structures to store domain infos. Must be here and not locally in function, - * since the maximum stack size is 8 KB - */ -static struct domain_migration_info dom_info = {0}; - -void evtchn_bind_existing_interdomain(struct domain *ld, struct domain *remote, int lport, int rport); - -/*------------------------------------------------------------------------------ -build_domain_migration_info -build_vcpu_migration_info - Build the structures holding the key info to be migrated over -------------------------------------------------------------------------------*/ -static void build_domain_migration_info(unsigned int ME_slotID, struct domain *me, struct domain_migration_info *mig_info) -{ - - /* Event channel info */ - memcpy(mig_info->evtchn, me->evtchn, sizeof(me->evtchn)); - - /* Get the start_info structure */ - mig_info->avz_shared = *(me->avz_shared); - - /* Update the state for the ME instance which will migrate. The resident ME keeps its current state. */ - mig_info->avz_shared.dom_desc.u.ME.state = ME_state_migrating; - - mig_info->pause_count = me->pause_count; - - mig_info->need_periodic_timer = me->need_periodic_timer; - - /* Pause */ - mig_info->pause_flags = me->pause_flags; - - memcpy(&(mig_info->pause_count), &(me->pause_count), sizeof(me->pause_count)); - - /* VIRQ mapping */ - memcpy(mig_info->virq_to_evtchn, me->virq_to_evtchn, sizeof((me->virq_to_evtchn))); - - /* Arch & address space */ - - mig_info->cpu_regs = me->cpu_regs; - mig_info->g_sp = me->g_sp; - -#ifdef CONFIG_ARCH_ARM32 - mig_info->vfp = me->vfp; -#endif -} - -/** - * Read the migration info structures. - */ -void read_migration_structures(soo_hyp_t *op) { - unsigned int ME_slotID = *((unsigned int *) op->p_val1); - struct domain *domME = domains[ME_slotID]; - - /* Gather all the info we need into structures */ - build_domain_migration_info(ME_slotID, domME, &dom_info); - - /* Copy structures to buffer */ - memcpy((void *) op->vaddr, &dom_info, sizeof(dom_info)); - - /* Update op->avz_sharedze with valid data size */ - *((unsigned int *) op->p_val2) = sizeof(dom_info); -} - -/*------------------------------------------------------------------------------ -restore_domain_migration_info -restore_vcpu_migration_info - Restore the migration info in the new ME structure - Those function are actually exported and called in domain_migrate_restore.c - They were kept in this file because they are the symmetric functions of - build_domain_migration_info() and build_vcpu_migration_info() -------------------------------------------------------------------------------*/ - -static void restore_domain_migration_info(unsigned int ME_slotID, struct domain *me, struct domain_migration_info *mig_info) -{ - int i; - void *logbool_ht; - - DBG("%s\n", __func__); - - /* For the time being, the logbool hashtable is re-initialized in the migrating ME. */ - logbool_ht = me->avz_shared->logbool_ht; - - *(me->avz_shared) = mig_info->avz_shared; - - /* Check that our signature is valid so that the image transfer should be good. */ - if (strcmp(me->avz_shared->signature, SOO_ME_SIGNATURE)) - panic("%s: Cannot find the correct signature in the shared page (" SOO_ME_SIGNATURE ")...\n", __func__); - - me->avz_shared->logbool_ht = logbool_ht; - - /* Update the domID of course */ - me->avz_shared->domID = ME_slotID; - - memcpy(me->evtchn, mig_info->evtchn, sizeof(me->evtchn)); - - /* - * We reconfigure the inter-domain event channel so that we unbind the link to the previous - * remote domain (the agency in most cases), but we keep the state as it is since we do not - * want that the local event channel gets changed. - * - * Re-binding is performed during the resuming via vbus (backend side) OR - * if the ME gets killed, the event channel will be closed without any effect to a remote domain. - */ - - for (i = 0; i < NR_EVTCHN; i++) - if (me->evtchn[i].state == ECS_INTERDOMAIN) - me->evtchn[i].interdomain.remote_dom = NULL; - - /* Update the pfn of the ME in its host Smart Object */ - me->avz_shared->dom_desc.u.ME.pfn = phys_to_pfn(memslot[ME_slotID].base_paddr); - - /* start pfn can differ from the initiator according to the physical memory layout */ - me->avz_shared->dom_phys_offset = memslot[ME_slotID].base_paddr; - - pfn_offset = phys_to_pfn(me->avz_shared->dom_phys_offset) - phys_to_pfn(mig_info->avz_shared.dom_phys_offset); - - me->avz_shared->hypercall_vaddr = (unsigned long) hypercall_entry; - - me->avz_shared->printch = printch; - me->pause_count = mig_info->pause_count; - me->need_periodic_timer = mig_info->need_periodic_timer; - - /* Pause */ - me->pause_flags = mig_info->pause_flags; - - memcpy(&(me->pause_count), &(mig_info->pause_count), sizeof(me->pause_count)); - - /* VIRQ mapping */ - memcpy(me->virq_to_evtchn, mig_info->virq_to_evtchn, sizeof((me->virq_to_evtchn))); - - /* Fields related to CPU */ - me->cpu_regs = mig_info->cpu_regs; - me->g_sp = mig_info->g_sp; - -#ifdef CONFIG_ARCH_ARM32 - me->vfp = mig_info->vfp; -#endif -} - - -/** - * Write the migration info structures. - */ -void write_migration_structures(soo_hyp_t *op) { - - /* Get the migration info structures */ - memcpy(&dom_info, (void *) op->vaddr, sizeof(dom_info)); -} - -/** - * Initiate the last stage of the migration process of a ME, so called "migration finalization". - */ -void migration_final(soo_hyp_t *op) { - unsigned int slotID = *((unsigned int *) op->p_val1); - struct domain *me = domains[slotID]; - - DBG("ME state: %d\n", get_ME_state(slotID)); - - switch (get_ME_state(slotID)) { - - case ME_state_suspended: - DBG("ME state suspended\n"); - domain_unpause_by_systemcontroller(me); - break; - - case ME_state_migrating: - DBG("ME_state_migrating\n"); - - flush_dcache_all(); - - restore_migrated_domain(slotID); - break; - - case ME_state_preparing: - DBG("ME state preparing\n"); - - flush_dcache_all(); - - DBG("Calling cooperate()...\n"); - - soo_cooperate(me->avz_shared->domID); - break; - - default: - printk("Agency: %s:%d Invalid state at this point (%d)\n", __func__, __LINE__, get_ME_state(slotID)); - BUG(); - - break; - } -} - -/*------------------------------------------------------------------------------ - fix_page_tables_ME - Fix all page tables in ME (swapper_pg_dir + all processes) - We pass the current domain as argument as we need it to make the DOMCALLs. - ------------------------------------------------------------------------------*/ -static void fix_other_page_tables_ME(unsigned int ME_slotID) -{ - struct domain *me = domains[ME_slotID]; - struct DOMCALL_fix_page_tables_args fix_pt_args; - - fix_pt_args.pfn_offset = pfn_offset; - - fix_pt_args.min_pfn = me->avz_shared->dom_phys_offset >> PAGE_SHIFT; - fix_pt_args.nr_pages = me->avz_shared->nr_pages; - - DBG("DOMCALL_fix_other_page_tables called in ME with pfn_offset=%ld (%lx)\n", fix_pt_args.pfn_offset, fix_pt_args.pfn_offset); - - domain_call(me, DOMCALL_fix_other_page_tables, &fix_pt_args); - - /* Flush all cache */ - flush_dcache_all(); -} - -/*------------------------------------------------------------------------------ - sync_directcomm - This function updates the directcomm event channel in both domains - ------------------------------------------------------------------------------*/ -static void rebind_directcomm(unsigned int ME_slotID) -{ - struct domain *me = domains[ME_slotID]; - struct DOMCALL_directcomm_args agency_directcomm_args, ME_directcomm_args; - - DBG("Rebinding directcomm...\n"); - - /* Get the directcomm evtchn from agency */ - - memset(&agency_directcomm_args, 0, sizeof(struct DOMCALL_directcomm_args)); - - /* Pass the (remote) domID in directcomm_evtchn */ - agency_directcomm_args.directcomm_evtchn = ME_slotID; - - domain_call(agency, DOMCALL_sync_directcomm, &agency_directcomm_args); - - memset(&ME_directcomm_args, 0, sizeof(struct DOMCALL_directcomm_args)); - - /* Pass the domID in directcomm_evtchn */ - ME_directcomm_args.directcomm_evtchn = 0; - - domain_call(me, DOMCALL_sync_directcomm, &ME_directcomm_args); - - DBG("[soo:avz] %s: Rebinding directcomm event channels: %d (agency) <-> %d (ME)\n", __func__, agency_directcomm_args.directcomm_evtchn, ME_directcomm_args.directcomm_evtchn); - - evtchn_bind_existing_interdomain(me, agency, ME_directcomm_args.directcomm_evtchn, agency_directcomm_args.directcomm_evtchn); - -} - -/*------------------------------------------------------------------------------ - sync_domain_interactions - - Create the mmory mappings in ME which are normally done at boot time - This is done using DOMCALLs. We first have to retrieve info from agency - using DOMCALLs as well. - We pass the current domain as argument as we need it to make the DOMCALLs. - - Performs the rebinding of vbstore event channel - ------------------------------------------------------------------------------*/ -static void sync_domain_interactions(unsigned int ME_slotID) -{ - struct domain *me = domains[ME_slotID]; - struct DOMCALL_sync_vbstore_args xs_args; - struct DOMCALL_sync_domain_interactions_args sync_args; - - memset(&xs_args, 0, sizeof(struct DOMCALL_sync_vbstore_args)); - - /* Retrieve ME vbstore info from the agency */ - - /* Pass the ME_domID in vbstore_remote_ME_evtchn field */ - xs_args.vbstore_revtchn = me->avz_shared->domID; - - domain_call(agency, DOMCALL_sync_vbstore, &xs_args); - - /* Create the mappings in ME */ - sync_args.vbstore_pfn = xs_args.vbstore_pfn; - - domain_call(me, DOMCALL_sync_domain_interactions, &sync_args); - - /* - * Rebinding the event channel used to access vbstore in agency - */ - DBG("%s: Get the vbstore pfn %lx for this ME\n", __func__, xs_args.vbstore_pfn); - DBG("%s: Rebinding vbstore event channels: %d (agency) <-> %d (ME)\n", __func__, xs_args.vbstore_revtchn, sync_args.vbstore_levtchn); - - evtchn_bind_existing_interdomain(me, agency, sync_args.vbstore_levtchn, xs_args.vbstore_revtchn); - - rebind_directcomm(ME_slotID); -} - -/*------------------------------------------------------------------------------ - adjust_variables_in_ME - Adjust variables such as start_info in ME - ------------------------------------------------------------------------------*/ -static void presetup_adjust_variables_in_ME(unsigned int ME_slotID, avz_shared_t *avz_shared) -{ - struct domain *me = domains[ME_slotID]; - struct DOMCALL_presetup_adjust_variables_args adjust_variables; - - adjust_variables.avz_shared = avz_shared; - - domain_call(me, DOMCALL_presetup_adjust_variables, &adjust_variables); -} - -/*------------------------------------------------------------------------------ - adjust_variables_in_ME - Adjust variables such as start_info in ME - ------------------------------------------------------------------------------*/ -static void postsetup_adjust_variables_in_ME(unsigned int ME_slotID) -{ - struct domain *me = domains[ME_slotID]; - struct DOMCALL_postsetup_adjust_variables_args adjust_variables; - - adjust_variables.pfn_offset = pfn_offset; - - domain_call(me, DOMCALL_postsetup_adjust_variables, &adjust_variables); -} - -void restore_migrated_domain(unsigned int ME_slotID) { - struct domain *me = NULL; - addr_t current_pgtable_paddr; - - DBG("Restoring migrated domain on ME_slotID: %d\n", ME_slotID); - - me = domains[ME_slotID]; - - restore_domain_migration_info(ME_slotID, me, &dom_info); - - /* Init post-migration execution of ME */ - - /* Stack pointer (r13) should remain unchanged since on the receiver side we did not make any push on the SVC stack */ - me->cpu_regs.sp = (unsigned long) setup_dom_stack(me); - -#ifndef CONFIG_ARM64VT - /* Setting the (future) value of PC in r14 (LR). See code switch_to in entry-armv.S */ - me->cpu_regs.lr = (unsigned long) (void *) after_migrate_to_user; -#endif - - /* Issue a timer interrupt (first timer IRQ) avoiding some problems during the forced upcall in after_migrate_to_user */ - send_timer_event(me); - - mmu_get_current_pgtable(¤t_pgtable_paddr); - - /* Switch to idle domain address space which has a full mapping of the RAM */ - mmu_switch_kernel((void *) idle_domain[smp_processor_id()]->avz_shared->pagetable_paddr); - - /* Fix the ME kernel page table for domcalls to work */ - fix_kernel_boot_page_table_ME(ME_slotID); - - DBG0("DOMCALL_presetup_adjust_variables_in_ME\n"); - - /* Adjust variables in ME such as avz_shared */ - presetup_adjust_variables_in_ME(ME_slotID, me->avz_shared); - - /* Fix all page tables in the ME (all processes) via a domcall */ - DBG("%s: fix other page tables in the ME...\n", __func__); - fix_other_page_tables_ME(ME_slotID); - - DBG0("DOMCALL_postsetup_adjust_variables_in_ME\n"); - - /* Adjust variables in the ME such as re-adjusting pfns */ - postsetup_adjust_variables_in_ME(ME_slotID); - - /* - * Perform synchronization work like memory mappings & vbstore event channel restoration. - * - * Create the memory mappings in the ME that are normally done at boot - * time. We pass the current domain needed by the domcalls to correctly - * switch between address spaces */ - - DBG("%s: syncing domain interactions in agency...\n", __func__); - sync_domain_interactions(ME_slotID); - - /* We've done as much initialisation as we could here. */ - - ASSERT(smp_processor_id() == 0); - - /* Proceed with the SOO post-migration callbacks according to patent */ - - /* Pre-activate */ - soo_pre_activate(ME_slotID); - - /* - * We check if the ME has been killed during the pre_activate callback. - * If yes, we do not pursue our re-activation process. - */ - if (get_ME_state(ME_slotID) == ME_state_dead) { - - set_current_domain(agency); - mmu_switch_kernel((void *) current_pgtable_paddr); - - return ; - } - - ASSERT(smp_processor_id() == 0); - - /* - * Cooperate. - * We look for residing MEs which are ready to collaborate. - */ - - soo_cooperate(ME_slotID); - - /* - * We check if the ME has been killed or set to the dormant state during the cooperate - * callback. If yes, we do not pursue our re-activation process. - */ - if ((domains[ME_slotID] == NULL) || (get_ME_state(ME_slotID) == ME_state_dead) || (get_ME_state(ME_slotID) == ME_state_dormant)) { - - set_current_domain(agency); - mmu_switch_kernel((void *) current_pgtable_paddr); - - return ; - } - - /* Resume ... */ - - /* All sync-ed! Kick the ME alive! */ - - ASSERT(smp_processor_id() == 0); - - DBG("%s: Now, resuming ME slotID %d...\n", __func__, ME_slotID); - - domain_unpause_by_systemcontroller(me); - - set_current_domain(agency); - mmu_switch((void *) current_pgtable_paddr); - -} - -/** - * Initiate the migration process of a ME. - */ -void migration_init(soo_hyp_t *op) { - unsigned int slotID = *((unsigned int *) op->p_val1); - struct domain *domME = domains[slotID]; - - DBG("Initializing migration of ME slotID=%d\n", slotID); - - switch (get_ME_state(slotID)) { - - case ME_state_suspended: - DBG("ME state suspended\n"); - - /* Initiator's side: the ME must be suspended during the migration */ - domain_pause_by_systemcontroller(domME); - - DBG0("ME paused OK\n"); - DBG("Being migrated: preparing to copy in ME_slotID %d: ME @ paddr 0x%08x (mapped @ vaddr 0x%08x in eventhypervisor)\n", - slotID, (unsigned int) memslot[slotID].base_paddr, (unsigned int) vaddr_start_ME); - - break; - - case ME_state_booting: - - DBG("ME state booting\n"); - - /* Initialize the ME descriptor */ - set_ME_state(slotID, ME_state_booting); - - /* Set the size of this ME in its own descriptor */ - domME->avz_shared->dom_desc.u.ME.size = memslot[slotID].size; - - /* Now set the pfn base of this ME; this will be useful for the Agency Core subsystem */ - domME->avz_shared->dom_desc.u.ME.pfn = phys_to_pfn(memslot[slotID].base_paddr); - - break; - - case ME_state_migrating: - - /* Target's side: nothing to do in particular */ - DBG("ME state migrating\n"); - - /* Pre-init the basic information related to the ME */ - domME->avz_shared->dom_desc.u.ME.size = memslot[slotID].size; - domME->avz_shared->dom_desc.u.ME.pfn = phys_to_pfn(memslot[slotID].base_paddr); - - break; - - default: - printk("Agency: %s:%d Invalid state at this point (%d)\n", __func__, __LINE__, get_ME_state(slotID)); - BUG(); - } - - /* Used for future restore operation */ - vaddr_start_ME = (unsigned long) __lva(memslot[slotID].base_paddr); - - DBG("ME base physical address: %lx\n", memslot[slotID].base_paddr); - DBG("Agency virtual address of the ME: %lx\n", vaddr_start_ME); -} - diff --git a/so3/kernel/avz/physdev.c b/so3/kernel/avz/physdev.c deleted file mode 100644 index 1aaf793b4b..0000000000 --- a/so3/kernel/avz/physdev.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2014-2018 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -#if 0 -#define DEBUG -#endif - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -int do_physdev_op(int cmd, void *args) -{ - int val; - struct domain *__current; - addr_t current_pgtable_paddr; - send_ipi_args_t send_ipi_args; - - switch (cmd) { - - case PHYSDEVOP_dump_page: - { - memcpy(&val, args, sizeof(int)); - - __current = current_domain; - mmu_get_current_pgtable(¤t_pgtable_paddr); - -#ifndef CONFIG_ARM64VT - mmu_switch_kernel(idle_domain[smp_processor_id()]); -#endif - - dump_page(val); - - set_current_domain(__current); - -#ifndef CONFIG_ARM64VT - mmu_switch_kernel((void *) current_pgtable_paddr); -#endif - - break; - } - - case PHYSDEVOP_send_ipi: - - memcpy(&send_ipi_args, args, sizeof(send_ipi_args_t)); - - smp_cross_call(send_ipi_args.cpu_mask, send_ipi_args.ipinr); - break; - - default: - BUG(); - break; - } - - return 0; -} diff --git a/so3/kernel/avz/soo_activity.c b/so3/kernel/avz/soo_activity.c deleted file mode 100644 index f86ce01afb..0000000000 --- a/so3/kernel/avz/soo_activity.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - * Copyright (C) 2014-2018 Daniel Rossier - * Copyright (C) 2018 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#if 0 -#define DEBUG -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -/** - * Return the state of the ME corresponding to the ME_slotID. - * If the ME does not exist anymore (for example, following a KILL_ME), - * the state is set to ME_state_dead. - */ -ME_state_t get_ME_state(unsigned int ME_slotID) { - if (domains[ME_slotID] == NULL) - return ME_state_dead; - else - return domains[ME_slotID]->avz_shared->dom_desc.u.ME.state; - -} - -void set_ME_state(unsigned int ME_slotID, ME_state_t state) { - domains[ME_slotID]->avz_shared->dom_desc.u.ME.state = state; -} - -void shutdown_ME(unsigned int ME_slotID) -{ - struct domain *dom; - struct domain *__current_domain; - addr_t current_pgtable_paddr; - - dom = domains[ME_slotID]; - - /* Perform a removal of ME */ - dom->is_dying = DOMDYING_dead; - DBG("Shutdowning slotID: %d - Domain pause nosync ...\n", ME_slotID); - - vcpu_pause(dom); - - DBG("Destroy evtchn if necessary - state: %d\n", get_ME_state(ME_slotID)); - evtchn_destroy(dom); - - DBG("Switching address space ...\n"); - - __current_domain = current_domain; - mmu_get_current_pgtable(¤t_pgtable_paddr); - - mmu_switch_kernel((void *) idle_domain[smp_processor_id()]->avz_shared->pagetable_paddr); - - memset((void *) __lva(memslot[ME_slotID].base_paddr), 0, memslot[ME_slotID].size); - - set_current_domain(__current_domain); - mmu_switch_kernel((void *) current_pgtable_paddr); - - DBG("Destroying domain structure ...\n"); - - domain_destroy(dom); - - DBG("Now resetting domains to NULL.\n"); - - /* bye bye dear ME ! */ - domains[ME_slotID] = NULL; - - /* Reset the slot availability */ - put_ME_slot(ME_slotID); - -} - -/* - * Check if some ME need to be killed. - */ -void check_killed_ME(void) { - int i; - - for (i = MEMSLOT_BASE; i < MEMSLOT_NR; i++) { - - if (memslot[i].busy && (get_ME_state(i) == ME_state_killed)) - shutdown_ME(i); - - } -} - -/***** SOO post-migration callbacks *****/ - -/* - * Forward a domcall to the ME corresponding to - * - */ -/* - * agency_ctl() - * - * Request a specific action to the agency (issued from a ME for example) - * - */ -void agency_ctl(agency_ctl_args_t *args) -{ - struct domain *target_dom; - soo_domcall_arg_t domcall_args; - int cpu; - - memset(&domcall_args, 0, sizeof(soo_domcall_arg_t)); - - /* Prepare the agency ctl args and the domcall args */ - memcpy(&domcall_args.u.agency_ctl_args, args, sizeof(agency_ctl_args_t)); - domcall_args.__agency_ctl = agency_ctl; - - /* Perform a domcall on the target ME */ - DBG("Processing agency_ctl function, cmd=0x%08x\n", args->cmd); - - switch (args->cmd) { - - case AG_KILL_ME: - - /* Performs a domcall in the ME to validate its removal. */ - - domcall_args.cmd = CB_KILL_ME; - target_dom = domains[args->slotID]; - - /* Final shutdown of the ME if the state is set to killed will be performed elsewhere, - * by the caller. - */ - break; - - case AG_AGENCY_UID: - args->u.agencyUID = domains[0]->avz_shared->dom_desc.u.agency.agencyUID; - return ; - - case AG_LOCAL_COOPERATE: - soo_cooperate(args->u.cooperate_args.slotID); - return; - - case AG_COOPERATE: - domcall_args.cmd = CB_COOPERATE; - - /* Initiator slotID must be filled by the ME - during the cooperation - through the target slotID */ - domcall_args.u.cooperate_args.u.initiator_coop.slotID = args->u.cooperate_args.slotID; - - /* target_cooperate_args must be provided by the initiator ME during the cooperation */ - domcall_args.u.cooperate_args.u.initiator_coop.pfn = args->u.cooperate_args.pfn; - - /* Transfer the capabilities of the target ME */ - memcpy(&domcall_args.u.cooperate_args.u.initiator_coop.spad, &domains[args->slotID]->avz_shared->dom_desc.u.ME.spad, sizeof(spad_t)); - - /* Transfer the SPID of the target ME */ - domcall_args.u.cooperate_args.u.initiator_coop.spid = domains[args->u.cooperate_args.slotID]->avz_shared->dom_desc.u.ME.spid; - - domcall_args.u.cooperate_args.role = COOPERATE_TARGET; - target_dom = domains[args->slotID]; - - break; - - default: - - domcall_args.cmd = CB_AGENCY_CTL; - - target_dom = domains[0]; /* Agency */ - - } - - /* - * current_mapped_domain is associated to each CPU. - */ - cpu = smp_processor_id(); - - /* Originating ME */ - domcall_args.slotID = current_domain->avz_shared->domID; - - domain_call(target_dom, DOMCALL_soo, &domcall_args); - - DBG("Ending forward callback now, back to the originater...\n"); - - /* Copy the agency ctl args back */ - memcpy(args, &domcall_args.u.agency_ctl_args, sizeof(agency_ctl_args_t)); -} - -/** - * Initiate the pre-propagate callback on a ME. - */ -static void soo_pre_propagate(unsigned int slotID, int *propagate_status) { - soo_domcall_arg_t domcall_args; - - memset(&domcall_args, 0, sizeof(domcall_args)); - - domcall_args.cmd = CB_PRE_PROPAGATE; - domcall_args.__agency_ctl = agency_ctl; - -#if 0 - DBG("Pre-propagate callback being issued...\n"); -#endif - - domcall_args.slotID = slotID; - - domain_call(domains[slotID], DOMCALL_soo, &domcall_args); - - *propagate_status = domcall_args.u.pre_propagate_args.propagate_status; - - /* If the ME decides itself to be removed */ - check_killed_ME(); -} - -void soo_pre_activate(unsigned int slotID) -{ - soo_domcall_arg_t domcall_args; - - memset(&domcall_args, 0, sizeof(domcall_args)); - - domcall_args.cmd = CB_PRE_ACTIVATE; - domcall_args.__agency_ctl = agency_ctl; - - domcall_args.slotID = slotID; - - /* Perform a domcall on the specific ME */ - DBG("Pre-activate callback being issued...\n"); - - domain_call(domains[slotID], DOMCALL_soo, &domcall_args); - - check_killed_ME(); -} - -/* - * soo_cooperate() - * - * Perform a cooperate callback in the target (incoming) ME with a set of target ready-to-cooperate MEs. - * - */ -void soo_cooperate(unsigned int slotID) -{ - soo_domcall_arg_t domcall_args; - int i, avail_ME; - bool itself; /* Used to detect a ME of a same SPID */ - - /* Are we OK to collaborate ? */ - if (!domains[slotID]->avz_shared->dom_desc.u.ME.spad.valid) - return; - - /* Reset anything in the cooperate_args */ - memset(&domcall_args, 0, sizeof(domcall_args)); - - domcall_args.cmd = CB_COOPERATE; - domcall_args.__agency_ctl = agency_ctl; - - domcall_args.u.cooperate_args.role = COOPERATE_INITIATOR; - - avail_ME = 0; - - domcall_args.u.cooperate_args.alone = true; - - for (i = MEMSLOT_BASE; i < MEMSLOT_NR; i++) { - - /* Look for resident ME */ - if ((i != slotID) && memslot[i].busy) { - - /* We are not alone in this smart object */ - domcall_args.u.cooperate_args.alone = false; - - /* - * Check if this residing ME has the same SPID than the initiator ME (arrived ME). If the residing ME is not ready - * to cooperate, the spid is passed as argument anyway so that the arrived ME can be aware of its presence and decide - * to do something accordingly. - */ - itself = ((domains[i]->avz_shared->dom_desc.u.ME.spid == domains[slotID]->avz_shared->dom_desc.u.ME.spid) ? true : false); - - /* If the ME authorizes us to enter into a cooperation process... */ - if (domains[i]->avz_shared->dom_desc.u.ME.spad.valid || itself) { - - /* target_coop.slotID contains the slotID of the ME initiator in the cooperation process. */ - domcall_args.u.cooperate_args.u.target_coop.slotID = i; - - domcall_args.u.cooperate_args.u.target_coop.spad = domains[i]->avz_shared->dom_desc.u.ME.spad; - - /* Transfer the SPID of the target ME */ - domcall_args.u.cooperate_args.u.target_coop.spid = domains[i]->avz_shared->dom_desc.u.ME.spid; - - /* Perform a domcall on the specific ME */ - DBG("Cooperate callback being issued...\n"); - - domcall_args.slotID = slotID; - - domain_call(domains[slotID], DOMCALL_soo, &domcall_args); - } - } - } - - /* Check if some ME got killed during the cooperation process. - * If the initiatore kills itself, the cooperation is done with other residing ME - * even if the initiatior is killed. - */ - - check_killed_ME(); -} - -static void dump_backtrace(unsigned char key) -{ - soo_domcall_arg_t domcall_args; - unsigned long flags; - - printk("'%c' pressed -> dumping backtrace in guest\n", key); - - memset(&domcall_args, 0, sizeof(domcall_args)); - - domcall_args.cmd = CB_DUMP_BACKTRACE; - - flags = local_irq_save(); - - printk("Agency:\n\n"); - - domain_call(domains[0], DOMCALL_soo, &domcall_args); - - printk("ME (dom 1):\n\n"); - - domain_call(domains[1], DOMCALL_soo, &domcall_args); - - local_irq_restore(flags); -} - -static void dump_vbstore(unsigned char key) -{ - soo_domcall_arg_t domcall_args; - unsigned long flags; - - printk("'%c' pressed -> dumping vbstore (agency) ...\n", key); - - memset(&domcall_args, 0, sizeof(domcall_args)); - - domcall_args.cmd = CB_DUMP_VBSTORE; - - flags = local_irq_save(); - - domain_call(domains[0], DOMCALL_soo, &domcall_args); - - local_irq_restore(flags); -} - - -static struct keyhandler dump_backtrace_keyhandler = { - .fn = dump_backtrace, - .desc = "dump backtrace" -}; - -static struct keyhandler dump_vbstore_keyhandler = { - .fn = dump_vbstore, - .desc = "dump vbstore" -}; - -/** - * Return the descriptor of a domain (agency or ME). - * A size of 0 means there is no ME in the slot. - */ -void get_dom_desc(unsigned int slotID, dom_desc_t *dom_desc) { - /* Check for authorization... (to be done) */ - - /* - * If no ME is present in the slot specified by slotID, we assign a size of 0 in the ME descriptor. - * We presume that the slotID of agency is never free... - */ - - if ((slotID > 1) && !memslot[slotID].busy) - dom_desc->u.ME.size = 0; - else - /* Copy the content to the target desc */ - memcpy(dom_desc, &domains[slotID]->avz_shared->dom_desc, sizeof(dom_desc_t)); - -} - -/** - * SOO hypercall processing. - */ -void do_soo_hypercall(soo_hyp_t *args) { - soo_hyp_t op; - struct domain *dom; - soo_hyp_dc_event_t *dc_event_args; - soo_domcall_arg_t domcall_args; - uint32_t slotID; - - memset(&domcall_args, 0, sizeof(soo_domcall_arg_t)); - - /* Get argument from guest */ - memcpy(&op, args, sizeof(soo_hyp_t)); - - /* - * Execute the hypercall - * The usage of args and returns depend on the hypercall itself. - * This has to be aligned with the guest which performs the hypercall. - */ - - switch (op.cmd) { - case AVZ_MIG_PRE_PROPAGATE: - soo_pre_propagate(*((unsigned int *) op.p_val1), op.p_val2); - break; - - case AVZ_MIG_PRE_ACTIVATE: - soo_pre_activate(*((unsigned int *) op.p_val1)); - break; - - case AVZ_MIG_INIT: - migration_init(&op); - break; - - case AVZ_MIG_FINAL: - migration_final(&op); - break; - - /* The following hypercall is used during receive operation */ - case AVZ_GET_ME_FREE_SLOT: - { - unsigned int ME_size = *((unsigned int *) op.p_val1); - int slotID; - - /* - * Try to get an available slot for a ME with this size. - * It will return -1 if no slot is available. - */ - slotID = get_ME_free_slot(ME_size, ME_state_migrating); - - *((int *) op.p_val1) = slotID; - - break; - } - - case AVZ_GET_DOM_DESC: - get_dom_desc(*((unsigned int *) op.p_val1), (dom_desc_t *) op.p_val2); - break; - - case AVZ_MIG_READ_MIGRATION_STRUCT: - read_migration_structures(&op); - break; - - case AVZ_MIG_WRITE_MIGRATION_STRUCT: - write_migration_structures(&op); - break; - - case AVZ_INJECT_ME: - inject_me(&op); - break; - - case AVZ_DC_SET: - /* - * AVZ_DC_SET is used to assign a new dc_event number in the (target) domain shared info page. - * This has to be done atomically so that if there is still a "pending" value in the field, - * the hypercall must return with -BUSY; in this case, the caller has to busy-loop (using schedule preferably) - * until the field gets free, i.e. set to DC_NO_EVENT. - */ - dc_event_args = (soo_hyp_dc_event_t *) op.p_val1; - - dom = domains[dc_event_args->domID]; - BUG_ON(dom == NULL); - - /* The shared info page is set as non cacheable, i.e. if a CPU tries to update it, it becomes visible to other CPUs */ - if (atomic_cmpxchg(&dom->avz_shared->dc_event, DC_NO_EVENT, dc_event_args->dc_event) != DC_NO_EVENT) - dc_event_args->state = -EBUSY; - else - dc_event_args->state = ESUCCESS; - - break; - - case AVZ_KILL_ME: - - slotID = *((unsigned int *) op.p_val1); - shutdown_ME(slotID); - - break; - - case AVZ_GET_ME_STATE: - - *((unsigned int *) op.p_val1) = get_ME_state(*((unsigned int *) op.p_val1)); - - break; - - case AVZ_SET_ME_STATE: - { - unsigned int *state = (unsigned int *) op.p_val1; - - set_ME_state(state[0], state[1]); - - break; - } - - case AVZ_TRIGGER_LOCAL_COOPERATION: - slotID = *((unsigned int *) op.p_val1); - soo_cooperate(slotID); - break; - - case AVZ_AGENCY_CTL: - /* - * Primary agency ctl processing- The args contains the slotID of the ME the agency_ctl is issued from. - */ - - agency_ctl((agency_ctl_args_t *) op.p_val1); - - break; - - default: - printk("%s: Unrecognized hypercall: %d\n", __func__, op.cmd); - BUG(); - break; - } - - /* If all OK, copy updated structure to guest */ - memcpy(args, &op, sizeof(soo_hyp_t)); - - flush_dcache_all(); -} - -void soo_activity_init(void) { - - DBG("Setting SOO avz up ...\n"); - - register_keyhandler('b', &dump_backtrace_keyhandler); - register_keyhandler('v', &dump_vbstore_keyhandler); -} - diff --git a/so3/kernel/main.c b/so3/kernel/main.c index 5d8432f8fe..980a782edd 100644 --- a/so3/kernel/main.c +++ b/so3/kernel/main.c @@ -38,6 +38,10 @@ #include +#if defined(CONFIG_SOO) && !defined(CONFIG_AVZ) +#include +#endif /* CONFIG_SOO */ + boot_stage_t boot_stage = BOOT_STAGE_INIT; /** @@ -103,9 +107,13 @@ void kernel_start(void) { /* Memory manager subsystem initialization */ memory_init(); - devices_init(); + devices_init(); + +#if defined(CONFIG_SOO) && !defined(CONFIG_AVZ) + avz_setup(); +#endif /* CONFIG_SOO */ - /* At this point of time, we are able to use the standard printk() */ + /* At this point of time, we are able to use the standard printk() */ timer_init(); diff --git a/so3/kernel/schedule.c b/so3/kernel/schedule.c index cd00d9f513..3029cf1b0c 100644 --- a/so3/kernel/schedule.c +++ b/so3/kernel/schedule.c @@ -429,7 +429,7 @@ void schedule(void) { next = next_thread(); #ifdef CONFIG_SCHED_FREQ_PREEMPTION - set_timer(&schedule_timer, NOW() + MILLISECS(SCHEDULE_FREQ)); + set_timer(&schedule_timer, NOW() + MILLISECS(SCHEDULE_FREQ)); #endif /* prev may be NULL at the very beginning (current is set to NULL at init). */ @@ -439,6 +439,8 @@ void schedule(void) { if (next && (next != prev)) { DBG("Now scheduling thread ID: %d name: %s PID: %d prio: %d\n", next->tid, next->name, ((next->pcb != NULL) ? next->pcb->pid : -1), next->prio); + if (prev) + DBG("Previous was threadID: %d name: %s PID: %d\n", prev->tid, prev->name); /* * The current threads (here prev) can be in different states, not only running; it may be in *waiting* or *zombie* @@ -479,29 +481,6 @@ void schedule(void) { local_irq_restore(flags); } -/* - * Can be used for debugging purposes. - * - */ -void __dump_regs(unsigned long regs) { - unsigned long *cpuregs = (unsigned long *) regs; - - lprintk("r4: %x ", *cpuregs); - lprintk("r5: %x ", *(cpuregs+1)); - lprintk("r6: %x ", *(cpuregs+2)); - lprintk("r7: %x ", *(cpuregs+3)); - lprintk("r8: %x ", *(cpuregs+4)); - lprintk("r9: %x ", *(cpuregs+5)); - lprintk("r10: %x ", *(cpuregs+6)); - lprintk("fp: %x ", *(cpuregs+7)); - lprintk("ip: %x ", *(cpuregs+8)); - lprintk("sp: %x ", *(cpuregs+9)); - lprintk("lr: %x ", *(cpuregs+10)); - lprintk("pc: %x ", *(cpuregs+11)); - lprintk("psr: %x ", *(cpuregs+12)); - lprintk("\n"); -} - static inline void raise_schedule(void *__dummy) { raise_softirq(SCHEDULE_SOFTIRQ); } diff --git a/so3/kernel/smp.c b/so3/kernel/smp.c index 8e52de13cf..65f57be6f1 100644 --- a/so3/kernel/smp.c +++ b/so3/kernel/smp.c @@ -24,7 +24,7 @@ #include #ifdef CONFIG_AVZ -#include +#include #include #endif @@ -114,13 +114,13 @@ void secondary_start_kernel(void) printk("CPU%u: Booted secondary processor\n", cpu); -#if defined(CONFIG_AVZ) && defined(CONFIG_ARM64VT) +#if defined(CONFIG_AVZ) #ifdef CONFIG_SOO if (cpu == AGENCY_RT_CPU) { - __mmu_switch_kernel((void *) current_domain->avz_shared->pagetable_paddr, true); + __mmu_switch_kernel((void *) current_domain->pagetable_paddr, true); #else - __mmu_switch_kernel((void *) domains[DOMID_AGENCY]->avz_shared->pagetable_paddr, true); + __mmu_switch_kernel((void *) domains[DOMID_AGENCY]->pagetable_paddr, true); #endif /* CONFIG_SOO */ booted[cpu] = 1; @@ -139,16 +139,18 @@ void secondary_start_kernel(void) default: printk("%s: trying to start CPU %d that is not supported.\n", __func__, cpu); } - -#else - pre_ret_to_el1(); #endif #ifdef CONFIG_SOO } + + /* If no spin table is used, CPU #1 */ + if (cpu == AGENCY_RT_CPU) + pre_ret_to_el1(); + #endif /* CONFIG_SOO */ -#endif /* CONFIG_AVZ+ARM64VT */ +#endif /* CONFIG_AVZ */ secondary_timer_init(); @@ -169,8 +171,12 @@ void secondary_start_kernel(void) printk("%s: entering idle loop...\n", __func__); + /* On CPU running containers, the timer IRQ is catched by + * the hypervisor and forwarded to guests as virtual IRQ + */ periodic_timer_start(); + #ifdef CONFIG_AVZ /* Prepare an idle domain and starts the idle loop */ startup_cpu_idle_loop(); @@ -219,7 +225,7 @@ void cpu_up(unsigned int cpu) while (!booted[cpu]) ; - printk("%s finished waiting...\n", __func__); + printk("%s CPU %d finished waiting...\n", __func__, smp_processor_id()); secondary_data.stack = NULL; secondary_data.pgdir = 0; diff --git a/so3/kernel/syscalls.c b/so3/kernel/syscalls.c index 8f6cdf7566..b29b20f9c6 100644 --- a/so3/kernel/syscalls.c +++ b/so3/kernel/syscalls.c @@ -72,7 +72,7 @@ long syscall_handle(syscall_args_t *a) set_errno_addr(__errno_addr); - switch (syscall_no) { + switch (syscall_no) { #ifdef CONFIG_MMU case SYSCALL_GETPID: @@ -310,7 +310,7 @@ long syscall_handle(syscall_args_t *a) default: printk("%s: unhandled syscall: %d\n", __func__, syscall_no); break; - } + } #warning do_softirq? diff --git a/so3/kernel/timer.c b/so3/kernel/timer.c index 303bd62064..e8d1cb6772 100644 --- a/so3/kernel/timer.c +++ b/so3/kernel/timer.c @@ -190,6 +190,25 @@ static inline void timer_unlock(struct timer *timer) { spin_unlock(&per_cpu(timers, timer->cpu).lock); } +/** + * @brief Apply an offset to all pending timer. Typically used when the local host time changed after + * hybernating for example. + * + * @param offset + */ +void apply_timer_offset(u64 offset) { + struct timer *curr; + struct timers *ts; + + ts = &this_cpu(timers); + + curr = ts->list; + while (curr != NULL) { + curr->expires += offset; + curr = curr->list_next; + } +} + /* * Stop a timer, i.e. remove from the timer list. */ diff --git a/so3/mm/Makefile b/so3/mm/Makefile index 86d05737b7..f047f873f2 100644 --- a/so3/mm/Makefile +++ b/so3/mm/Makefile @@ -5,5 +5,3 @@ obj-y += memory.o obj-y += heap.o obj-y += percpu.o - -obj-$(CONFIG_AVZ) += avz/ diff --git a/so3/mm/heap.c b/so3/mm/heap.c index 67a5e44e89..a1db9a8124 100644 --- a/so3/mm/heap.c +++ b/so3/mm/heap.c @@ -59,9 +59,11 @@ void heap_init(void) quick_list->size = HEAP_SIZE - sizeof(mem_chunk_t); quick_list->padding_bytes = 0; - printk("SO3: allocating a kernel heap of %d bytes at address %p.\n", quick_list->size, quick_list); + boot_stage = BOOT_STAGE_HEAP_READY; + + printk("SO3: allocating a kernel heap of %d bytes at address %p.\n", quick_list->size, quick_list); - DBG("[list_init] List initialized. sizeof(mem_chunk_t) = %d bytes, sizeof(int) = %d bytes\n", sizeof(mem_chunk_t), sizeof(int)); + DBG("[list_init] List initialized. sizeof(mem_chunk_t) = %d bytes, sizeof(int) = %d bytes\n", sizeof(mem_chunk_t), sizeof(int)); } uint32_t heap_size(void) { diff --git a/so3/mm/memory.c b/so3/mm/memory.c index b7db4c29f2..aabf6c10f6 100644 --- a/so3/mm/memory.c +++ b/so3/mm/memory.c @@ -57,14 +57,7 @@ void early_memory_init(void *fdt_paddr) { int offset; /* Access to device tree */ -#ifdef CONFIG_SO3VIRT - - mem_info.phys_base = avz_shared->dom_phys_offset; - mem_info.size = avz_shared->nr_pages << PAGE_SHIFT; - -#else offset = get_mem_info((void *) fdt_paddr, &mem_info); -#endif #ifndef CONFIG_AVZ __fdt_addr = (void *) __va(fdt_paddr); @@ -466,33 +459,13 @@ void memory_init(void) { #ifdef CONFIG_AVZ #warning For ARM64VT we still need fo address the ME in the hypervisor... -#ifdef CONFIG_SOO - /* Actually, with SOO, the agency must also be able to access the ME memory area, so we - * need to expand to the total RAM. - */ -#ifdef CONFIG_ARCH_ARM32 - - /* At maximum, the RAM mapping cannot exceed 1 GB minus the space dedicated to the hypervisor. */ - if (memslot[MEMSLOT_AVZ].size > CONFIG_KERNEL_VADDR - AGENCY_VOFFSET) - create_mapping(new_sys_root_pgtable, AGENCY_VOFFSET, memslot[MEMSLOT_AGENCY].base_paddr, - CONFIG_KERNEL_VADDR - AGENCY_VOFFSET, false); - else - create_mapping(new_sys_root_pgtable, AGENCY_VOFFSET, memslot[MEMSLOT_AGENCY].base_paddr, - memslot[MEMSLOT_AVZ].size, false); - -#else /* CONFIG_ARCH_ARM32 */ - - create_mapping(new_sys_root_pgtable, AGENCY_VOFFSET, memslot[MEMSLOT_AGENCY].base_paddr, - memslot[MEMSLOT_AVZ].size, false); - -#endif /* !CONFIG_ARCH_ARM32 */ +#ifndef CONFIG_SOO -#else /* Finally, create the agency domain area and for being able to read the device tree.*/ create_mapping(new_sys_root_pgtable, AGENCY_VOFFSET, memslot[MEMSLOT_AGENCY].base_paddr, memslot[MEMSLOT_AGENCY].size, false); -#endif /* !CONFIG_SOO */ +#endif /* !CONFIG_SOO */ #endif /* CONFIG_AVZ */ @@ -506,16 +479,6 @@ void memory_init(void) { flush_dcache_all(); -#if defined(CONFIG_SO3VIRT) && defined(CONFIG_ARCH_ARM64) - - /* Leave the root pgtable allocated by AVZ */ - mmu_switch_kernel((void *) __pa(__sys_root_pgtable)); - - avz_shared->pagetable_vaddr = (addr_t) __sys_root_pgtable; - avz_shared->pagetable_paddr = __pa(__sys_root_pgtable); - -#endif /* CONFIG_SO3VIRT */ - #if (defined(CONFIG_AVZ) || !defined(CONFIG_SOO)) && defined(CONFIG_ARCH_ARM32) /* Finally, prepare the vector page at its correct location */ diff --git a/so3/soo/Kconfig b/so3/soo/Kconfig index 7308d33b73..bb28ce1652 100644 --- a/so3/soo/Kconfig +++ b/so3/soo/Kconfig @@ -5,7 +5,6 @@ if SOO && !AVZ menu "SOO Mobile Entity - Smart Object Oriented subsystem" -source "soo/me/Kconfig" source "soo/drivers/Kconfig" endmenu diff --git a/so3/soo/Makefile b/so3/soo/Makefile index 25b49cf9bd..b3c28156d8 100644 --- a/so3/soo/Makefile +++ b/so3/soo/Makefile @@ -1,5 +1,4 @@ -obj-y += me/ obj-y += drivers/ obj-y += kernel/ diff --git a/so3/soo/drivers/vdummyfront/vdummy.c b/so3/soo/drivers/vdummyfront/vdummy.c index 5292239ef1..196ba2a214 100644 --- a/so3/soo/drivers/vdummyfront/vdummy.c +++ b/so3/soo/drivers/vdummyfront/vdummy.c @@ -165,7 +165,7 @@ static void vdummy_reconfiguring(struct vbus_device *vdev) { /* The shared page already exists */ /* Re-init */ - gnttab_end_foreign_access_ref(vdummy_priv->vdummy.ring_ref); + gnttab_end_foreign_access(vdummy_priv->vdummy.ring_ref); DBG("Frontend: Setup ring\n"); diff --git a/so3/soo/drivers/vuartfront/vuart.c b/so3/soo/drivers/vuartfront/vuart.c index 727ecfa5bd..3c6085c255 100644 --- a/so3/soo/drivers/vuartfront/vuart.c +++ b/so3/soo/drivers/vuartfront/vuart.c @@ -75,6 +75,7 @@ void vuart_write(char *buffer, int count) { vuart_request_t *ring_req; vuart_priv_t *vuart_priv; + if (!vdev_console) return ; @@ -190,7 +191,7 @@ void vuart_reconfiguring(struct vbus_device *vdev) { /* The shared page already exists */ /* Re-init */ - gnttab_end_foreign_access_ref(vuart_priv->vuart.ring_ref); + gnttab_end_foreign_access(vuart_priv->vuart.ring_ref); DBG("Frontend: Setup ring\n"); diff --git a/so3/soo/include/me/common.h b/so3/soo/include/me/common.h index 5a4b10fa73..95f85bb0be 100644 --- a/so3/soo/include/me/common.h +++ b/so3/soo/include/me/common.h @@ -19,7 +19,7 @@ #ifndef ME_COMMON_H #define ME_COMMON_H -#include +#include typedef struct { uint64_t uid; diff --git a/so3/soo/include/soo/avz.h b/so3/soo/include/soo/avz.h index f91c0693aa..0d5c86e761 100644 --- a/so3/soo/include/soo/avz.h +++ b/so3/soo/include/soo/avz.h @@ -20,3 +20,5 @@ #define ME_domID() (avz_shared->domID) +void avz_setup(void); + diff --git a/so3/soo/include/soo/console.h b/so3/soo/include/soo/console.h index 5b0e46bd5f..0234e0bcb1 100644 --- a/so3/soo/include/soo/console.h +++ b/so3/soo/include/soo/console.h @@ -32,7 +32,8 @@ void avzcons_tx(void); void init_console(void); -extern void (*__printch)(char c); +void avz_printch(char c); +void avz_printstr(char *str); void lprintk(char *format, ...); void lprintk_buffer(void *buffer, uint32_t n); diff --git a/so3/soo/include/soo/debug/dbgvar.h b/so3/soo/include/soo/debug/dbgvar.h deleted file mode 100644 index 1acce0d0ac..0000000000 --- a/so3/soo/include/soo/debug/dbgvar.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2018 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef DBGVAR_H -#define DBGVAR_H - -#define DBGEVENT_SIZE 8192 -#define DBGLIST_SIZE 8192 - -typedef enum { - DBGVAR_NR -} dbgvar_t; - -extern int dbgvar[DBGVAR_NR]; - -/* - * List mode: - * - DBGLIST_DISABLED: the list is not used, thus inactive. - * - DBGLIST_CLEAR: the list is cleared when it is full, that is, when there are DBG*_SIZE. - * - DBGLIST_CONTINUOUS: the list is a circular buffer. - */ -typedef enum { - DBGLIST_DISABLED, - DBGLIST_CLEAR, - DBGLIST_CONTINUOUS -} dbglist_mode_t; - -/* - * Clear the event list. - */ -void clear_dbgevent(void); - -/* - * Log an event. - * Each event is associated to an arbitrary one-char key. - */ -void log_dbgevent(char c); - -/* - * Change the event logging mode. - */ -void set_dbgevent_mode(dbglist_mode_t mode); - -/* - * Show the event list. - */ -void show_dbgevent(void); - -/* - * Initialize the event list. - */ -void init_dbgevent(void); - -/* - * Clear the event list. - */ -void clear_dbglist(void); - -/* - * Log an event. - * Each element is a 32 bit integer (signed or unsigned). - */ -void log_dbglist(int i); - -/* - * Change the integer logging mode. - */ -void set_dbglist_mode(dbglist_mode_t mode); - -/* - * Show the event list. The elements are printed in hexadecimal format. - */ -void show_dbglist(void); - -/* - * Clear the integer list. - */ -void init_dbglist(void); - -#endif /* DBGVAR_H */ diff --git a/so3/soo/include/soo/debug/logbool.h b/so3/soo/include/soo/debug/logbool.h deleted file mode 100644 index 0c010714cb..0000000000 --- a/so3/soo/include/soo/debug/logbool.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2018-2019 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef LOGBOOL_H -#define LOGBOOL_H - -#include - -/* Number of (key, value) pair in the hashtable. The number is taken from the code example. */ -#define LOGBOOL_HT_SIZE 4096 - -/* Maximal size of the logbool string */ -#define LOGBOOL_STR_SIZE 160 - -#if 0 -#define ENABLE_LOGBOOL -#endif - -typedef struct { - bool section_state; /* on / off */ - int cpu; - int count; /* Number of visits in this section */ -} logbool_t; - -struct entry_s { - char *key; - logbool_t value; - struct entry_s *next; -}; - -typedef struct entry_s entry_t; - -struct hashtable_s { - int size; - struct entry_s **table; -}; - -typedef struct hashtable_s logbool_hashtable_t; - -#ifdef __AVZ__ -extern logbool_hashtable_t *avz_logbool_ht; -extern void logbool_init(void); -#define logbool_hashtable avz_logbool_ht -#else /* !__AVZ__ */ -typedef void(*ht_set_t)(logbool_hashtable_t *, char *, logbool_t); -extern ht_set_t __ht_set; -#define logbool_hashtable avz_shared_info->logbool_ht -#endif - -extern void ht_set(logbool_hashtable_t *hashtable, char *key, logbool_t value); -extern int sprintf(char * buf, const char *fmt, ...); - -#ifdef ENABLE_LOGBOOL -#define __LOGBOOL_ON \ - { \ - char __logbool_str[LOGBOOL_STR_SIZE]; \ - static logbool_t logbool = { 0 }; \ - sprintf(__logbool_str, "%s:%s:%d", __FILE__, __func__, __LINE__); \ - logbool.section_state = true; \ - logbool.cpu = smp_processor_id(); \ - logbool.count++; \ - ht_set(logbool_hashtable, __logbool_str, logbool); - -#define __LOGBOOL_OFF \ - logbool.section_state = false; \ - ht_set(logbool_hashtable, __logbool_str, logbool); \ - } -#else -#define __LOGBOOL_ON -#define __LOGBOOL_OFF -#endif /* ENABLE_LOGBOOL */ - -void *ht_create(int size); -void ht_destroy(logbool_hashtable_t *hashtable); - -void dump_all_logbool(unsigned char key); - -#endif /* LOGBOOL_H */ diff --git a/so3/soo/include/soo/debug/packcommon.h b/so3/soo/include/soo/debug/packcommon.h deleted file mode 100644 index 6700bad4d5..0000000000 --- a/so3/soo/include/soo/debug/packcommon.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2018 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef PACKCOMMON_H -#define PACKCOMMON_H - -#ifdef __KERNEL__ -#include -#include -#include -#else -#include -#include -#endif /* __KERNEL__ */ - -#define PACKGENCHK_N_PREDEF_PACKETS 16 -#define PACKGENCHK_MAX_SOOS 16 - -#ifdef __KERNEL__ -#define packcommon_alloc(size) kzalloc(size, GFP_KERNEL) -#else -#define packcommon_alloc(size) malloc(size) -#endif /* __KERNEL__ */ - -void pack_prepare_predef_packets(unsigned char *predef_packets[PACKGENCHK_N_PREDEF_PACKETS], size_t size); -void pack_patch_predef_packets(unsigned char *predef_packets[PACKGENCHK_N_PREDEF_PACKETS], unsigned char *prefix, size_t prefix_size); - -#endif /* PACKCOMMON_H */ diff --git a/so3/soo/include/soo/dev/vdummy.h b/so3/soo/include/soo/dev/vdummy.h index 83d03c2846..e6596b7b62 100644 --- a/so3/soo/include/soo/dev/vdummy.h +++ b/so3/soo/include/soo/dev/vdummy.h @@ -20,7 +20,7 @@ #define VDUMMY_H #include -#include +#include #include #define VDUMMY_PACKET_SIZE 32 @@ -53,7 +53,7 @@ typedef struct { unsigned int irq; grant_ref_t ring_ref; - grant_handle_t handle; + uint32_t evtchn; } vdummy_t; diff --git a/so3/soo/include/soo/dev/vuart.h b/so3/soo/include/soo/dev/vuart.h index c670f8c2b5..0173d0f72a 100644 --- a/so3/soo/include/soo/dev/vuart.h +++ b/so3/soo/include/soo/dev/vuart.h @@ -21,8 +21,8 @@ #define VUART_H #include -#include #include +#include #define VUART_NAME "vuart" #define VUART_PREFIX "[" VUART_NAME "] " @@ -45,7 +45,6 @@ typedef struct { unsigned int irq; grant_ref_t ring_ref; - grant_handle_t handle; uint32_t evtchn; } vuart_t; diff --git a/so3/soo/include/soo/evtchn.h b/so3/soo/include/soo/evtchn.h index f05b63c93d..6dd92f7d64 100644 --- a/so3/soo/include/soo/evtchn.h +++ b/so3/soo/include/soo/evtchn.h @@ -19,16 +19,21 @@ #ifndef EVTCHN_H #define EVTCHN_H +#include +#include + #include +#include #include +#include + #include #include #include #include -#include extern unsigned int type_from_irq(int irq); @@ -39,12 +44,6 @@ enum { IRQT_UNBOUND, IRQT_PIRQ, IRQT_VIRQ, IRQT_IPI, IRQT_EVTCHN }; -/* Inline Functions */ -/* Constructor for packed IRQ information. */ -static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn) { - return ((type << 24) | (index << 16) | evtchn); -} - static inline void clear_evtchn(u32 evtchn) { avz_shared->evtchn_pending[evtchn] = false; @@ -52,15 +51,21 @@ static inline void clear_evtchn(u32 evtchn) { smp_mb(); } -static inline void notify_remote_via_evtchn(uint32_t evtchn) { - evtchn_send_t op; - op.evtchn = evtchn; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_send, (long) &op, 0, 0); +static inline void notify_remote_via_evtchn(uint32_t evtchn) +{ + avz_hyp_t args; + + args.cmd = AVZ_EVENT_CHANNEL_OP; + + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_send; + args.u.avz_evtchn.evtchn_op.u.send.evtchn = evtchn; + + avz_hypercall(&args); } /* Entry point for notifications into Linux subsystems. */ -void evtchn_do_upcall(cpu_regs_t *regs); +void evtchn_do_upcall(void *data); /* * LOW-LEVEL DEFINITIONS @@ -80,7 +85,6 @@ extern void bind_virq_to_irqhandler(unsigned int virq, irq_handler_t handler, ir extern int bind_existing_interdomain_evtchn(unsigned int local_channel, unsigned int remote_domain, unsigned int remote_evtchn); - /* * Common unbind function for all event sources. Takes IRQ to unbind from. * Automatically closes the underlying event channel (even for bindings diff --git a/so3/soo/include/soo/gnttab.h b/so3/soo/include/soo/gnttab.h index fbc776418e..a6d989197a 100644 --- a/so3/soo/include/soo/gnttab.h +++ b/so3/soo/include/soo/gnttab.h @@ -21,30 +21,14 @@ #include -#include - -#define NR_GRANT_FRAMES 4 -#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t)) - -struct gnttab_free_callback { - struct gnttab_free_callback *next; - void (*fn)(void *); - void *arg; - u16 count; -}; +#include int gnttab_suspend(void); int gnttab_resume(void); -int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly); - -/* - * End access through the given grant reference, iff the grant entry is no - * longer in use. Return 1 if the grant entry was freed, 0 if it is still in - * use. - */ -void gnttab_end_foreign_access_ref(grant_ref_t ref); +int gnttab_grant_foreign_access(domid_t domid, unsigned long frame); + /* * Eventually end access through the given grant reference, and once that * access has been ended, free the given page too. Access will be ended @@ -53,73 +37,7 @@ void gnttab_end_foreign_access_ref(grant_ref_t ref); */ void gnttab_end_foreign_access(grant_ref_t ref); -int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn); - -unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref); -unsigned long gnttab_end_foreign_transfer(grant_ref_t ref); - -int gnttab_query_foreign_access(grant_ref_t ref); - -/* - * operations on reserved batches of grant references - */ -int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head); - -void gnttab_free_grant_reference(grant_ref_t ref); - -void gnttab_free_grant_references(grant_ref_t head); - -void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, unsigned long frame, int readonly); - -static inline void gnttab_set_map_op(struct gnttab_map_grant_ref *map, addr_t addr, uint32_t flags, grant_ref_t ref, domid_t domid, unsigned int offset, unsigned int size) -{ - map->host_addr = addr; - map->flags = flags; - map->ref = ref; - map->dom = domid; - - map->handle = 0; - - map->dev_bus_addr = 0; - map->status = 0; - - map->size = size; /* By default... */ - map->offset = offset; - -} - -static inline void gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, addr_t addr, uint32_t flags, grant_handle_t handle) -{ - unmap->host_addr = addr; - unmap->dev_bus_addr = 0; - unmap->flags = flags; - unmap->ref = 0; - - unmap->handle = handle; - - unmap->dev_bus_addr = 0; - unmap->status = 0; - - unmap->size = PAGE_SIZE; /* By default... */ - unmap->offset = 0; - -} - -void gnttab_init(void); - -int grant_table_op(unsigned int cmd, void *uop, unsigned int count); - -extern int gnttab_map(struct gnttab_map_grant_ref *op); -extern int gnttab_unmap(struct gnttab_unmap_grant_ref *op); -extern int gnttab_copy(struct gnttab_copy *op); -extern int gnttab_map_with_copy(struct gnttab_map_grant_ref *op); -extern int gnttab_unmap_with_copy(struct gnttab_unmap_grant_ref *op); -extern int gnttab_map_sync_copy(unsigned int handle, unsigned int flags, unsigned int offset, unsigned int size); - -int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, struct gnttab_map_grant_ref *kmap_ops, struct page **pages, unsigned int count); -int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, struct gnttab_map_grant_ref *kmap_ops, struct page **pages, unsigned int count); - -#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) +void gnttab_map(domid_t domid, grant_ref_t grant_ref, void **vaddr); void postmig_gnttab_update(void); diff --git a/so3/soo/include/soo/grant_table.h b/so3/soo/include/soo/grant_table.h deleted file mode 100644 index 8f9485d213..0000000000 --- a/so3/soo/include/soo/grant_table.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2016-2019 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __GRANT_TABLE_H__ -#define __GRANT_TABLE_H__ - -#include - -#include - -#define GRANT_INVALID_REF 0 - -struct grant_entry { - /* GTF_xxx: various type and flag information. */ - uint16_t flags; - /* The domain being granted foreign privileges. */ - domid_t domid; - /* - * GTF_permit_access: Frame that @domid is allowed to map and access. - * GTF_accept_transfer: Frame whose ownership transferred by @domid. - */ - uint32_t frame; -}; -typedef struct grant_entry grant_entry_t; - -/* - * Type of grant entry. - * GTF_invalid: This grant entry grants no privileges. - - */ -#define GTF_invalid (0U<<0) -#define GTF_permit_access (1U<<0) - -/* - * Subflags for GTF_permit_access. - * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST] - * GTF_reading: Grant entry is currently mapped for reading by @domid. - * GTF_writing: Grant entry is currently mapped for writing by @domid. - */ -#define _GTF_readonly (2) -#define GTF_readonly (1U<<_GTF_readonly) -#define _GTF_reading (3) -#define GTF_reading (1U<<_GTF_reading) -#define _GTF_writing (4) -#define GTF_writing (1U<<_GTF_writing) - - - - -/*********************************** - * GRANT TABLE QUERIES AND USES - */ - -/* - * Reference to a grant entry in a specified domain's grant table. - */ -typedef uint32_t grant_ref_t; - -/* - * Handle to track a mapping created via a grant reference. - */ -typedef uint32_t grant_handle_t; - -/* - * GNTTABOP_map_grant_ref: Map the grant entry (,) for access - * by devices and/or host CPUs. If successful, is a tracking number - * that must be presented later to destroy the mapping(s). On error, - * is a negative status code. - * NOTES: - * 1. If GNTMAP_device_map is specified then is the address - * via which I/O devices may access the granted frame. - * 2. If GNTMAP_host_map is specified then a mapping will be added at - * either a host virtual address in the current address space, or at - * a PTE at the specified machine address. The type of mapping to - * perform is selected through the GNTMAP_contains_pte flag, and the - * address is specified in . - * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a - * host mapping is destroyed by other means then it is *NOT* guaranteed - * to be accounted to the correct grant reference! - */ -#define GNTTABOP_map_grant_ref 0 -struct gnttab_map_grant_ref { - /* IN parameters. */ - uint64_t host_addr; - uint32_t flags; /* GNTMAP_* */ - grant_ref_t ref; - domid_t dom; - /* OUT parameters. */ - int16_t status; /* GNTST_* */ - grant_handle_t handle; - uint64_t dev_bus_addr; - - uint32_t offset; - uint32_t size; -}; -typedef struct gnttab_map_grant_ref gnttab_map_grant_ref_t; - -/* - * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings - * tracked by . If or is zero, that - * field is ignored. If non-zero, they must refer to a device/host mapping - * that is tracked by - * NOTES: - * 1. The call may fail in an undefined manner if either mapping is not - * tracked by . - * 3. After executing a batch of unmaps, it is guaranteed that no stale - * mappings will remain in the device or host TLBs. - */ -#define GNTTABOP_unmap_grant_ref 1 -struct gnttab_unmap_grant_ref { - /* IN parameters. */ - uint32_t flags; - grant_ref_t ref; - domid_t dom; - uint64_t host_addr; - uint64_t dev_bus_addr; - grant_handle_t handle; - /* OUT parameters. */ - int16_t status; /* GNTST_* */ - - uint32_t offset; - uint32_t size; -}; -typedef struct gnttab_unmap_grant_ref gnttab_unmap_grant_ref_t; - -/* - * GNTTABOP_copy: Hypervisor based copy - * source and destinations can be eithers MFNs or, for foreign domains, - * grant references. the foreign domain has to grant read/write access - * in its grant table. - * - * The flags specify what type source and destinations are (either MFN - * or grant reference). - * - * Note that this can also be used to copy data between two domains - * via a third party if the source and destination domains had previously - * grant appropriate access to their pages to the third party. - * - * source_offset specifies an offset in the source frame, dest_offset - * the offset in the target frame and len specifies the number of - * bytes to be copied. - */ - -#define _GNTCOPY_source_gref (0) -#define GNTCOPY_source_gref (1 << _GNTCOPY_source_gref) -#define _GNTCOPY_dest_gref (1) -#define GNTCOPY_dest_gref (1 << _GNTCOPY_dest_gref) -#define _GNTCOPY_sync_ref (2) -#define GNTCOPY_sync_ref (1 << _GNTCOPY_sync_ref) - -#define GNTTABOP_copy 5 -typedef struct gnttab_copy { - /* IN parameters. */ - struct { - union { - grant_ref_t ref; - unsigned int gmfn; - } u; - domid_t domid; - uint16_t offset; - } source, dest; - uint16_t len; - uint16_t flags; /* GNTCOPY_* */ - /* OUT parameters. */ - int16_t status; - unsigned int handle; -} gnttab_copy_t; - - -/* Map the grant entry for access by host CPUs. */ -#define _GNTMAP_host_map (1) -#define GNTMAP_host_map (1<<_GNTMAP_host_map) -/* Accesses to the granted frame will be restricted to read-only access. */ -#define _GNTMAP_readonly (2) -#define GNTMAP_readonly (1<<_GNTMAP_readonly) - -#define _GNTMAP_with_copy (5) -#define GNTMAP_with_copy (1 << _GNTMAP_with_copy) - - -/* - * Values for error status returns. All errors are -ve. - */ -#define GNTST_okay (0) /* Normal return. */ -#define GNTST_general_error (-1) /* General undefined error. */ -#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */ -#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */ -#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */ -#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */ -#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/ -#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */ -#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */ -#define GNTST_bad_page (-9) /* Specified page was invalid for op. */ -#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary. */ -#define GNTST_address_too_big (-11) /* transfer page address too large. */ -#define GNTST_eagain (-12) /* Operation not done; try again. */ - -#define GNTTABOP_error_msgs { \ - "okay", \ - "undefined error", \ - "unrecognised domain id", \ - "invalid grant reference", \ - "invalid mapping handle", \ - "invalid virtual address", \ - "invalid device address", \ - "no spare translation slot in the I/O MMU", \ - "permission denied", \ - "bad page", \ - "copy arguments cross page boundary", \ - "page address size too large" \ -} - -#endif /* __GRANT_TABLE_H__ */ - diff --git a/so3/soo/include/soo/hypervisor.h b/so3/soo/include/soo/hypervisor.h index b399340f40..2c71397435 100644 --- a/so3/soo/include/soo/hypervisor.h +++ b/so3/soo/include/soo/hypervisor.h @@ -32,7 +32,9 @@ int do_postsetup_adjust_variables(void *arg); int do_sync_domain_interactions(void *arg); int do_sync_directcomm(void *arg); -void inject_syscall_vector(void); -void avz_vector_callback(void); +void avz_get_shared(void); +void avz_gnttab(gnttab_op_t *op); + +void avz_sig_terminate(void); #endif /* __HYPERVISOR_H__ */ diff --git a/so3/soo/include/soo/ring.h b/so3/soo/include/soo/ring.h index 72b959b7c1..5f77196890 100644 --- a/so3/soo/include/soo/ring.h +++ b/so3/soo/include/soo/ring.h @@ -205,12 +205,12 @@ static inline __req_t *__name##_get_ring_request(__name##_back_ring_t *__name##_ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) #define RING_PUSH_REQUESTS(_r) do { \ - smp_mb(); /* back sees requests /before/ updated producer index */ \ + smp_wmb(); /* back sees requests /before/ updated producer index */ \ (_r)->sring->req_prod = (_r)->req_prod_pvt; \ } while (0) #define RING_PUSH_RESPONSES(_r) do { \ - smp_mb(); /* front sees responses /before/ updated producer index */ \ + smp_wmb(); /* front sees responses /before/ updated producer index */ \ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ } while (0) @@ -220,5 +220,4 @@ static inline __req_t *__name##_get_ring_request(__name##_back_ring_t *__name##_ #define RING_RESP_FULL(_r) \ (RING_FREE_RESPONSES(_r) == 0) - #endif /* __RING_H__ */ diff --git a/so3/soo/include/soo/soo.h b/so3/soo/include/soo/soo.h index 56ccf15f42..38ad67c202 100644 --- a/so3/soo/include/soo/soo.h +++ b/so3/soo/include/soo/soo.h @@ -22,6 +22,20 @@ #include +#include + +int get_ME_state(void); +void set_ME_state(ME_state_t state); + +int32_t get_ME_free_slot(uint32_t size); + +bool get_ME_id(uint32_t slotID, ME_id_t *ME_id); + +void get_ME_id_array(ME_id_t *ME_id_array); +char *xml_prepare_id_array(ME_id_t *ME_id_array); + +ME_desc_t *get_ME_desc(void); + /* ME ID management */ const char *get_me_shortdesc(void); const char *get_me_name(void); diff --git a/so3/soo/include/soo/uapi/soo.h b/so3/soo/include/soo/uapi/soo.h new file mode 100644 index 0000000000..7914591fda --- /dev/null +++ b/so3/soo/include/soo/uapi/soo.h @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2014-2025 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef UAPI_SOO_H +#define UAPI_SOO_H + +#ifndef __ASSEMBLY__ + +/* This signature is used to check the coherency of the ME image, after a migration + * or a restoration for example. + */ +#define SOO_ME_SIGNATURE "SooZ" + +#define MAX_ME_DOMAINS 5 + +/* We include the (non-RT & RT) agency domain */ +#define MAX_DOMAINS (2 + MAX_ME_DOMAINS) +#endif /* __ASSEMBLY__ */ + +#define AGENCY_CPU 0 +#define AGENCY_RT_CPU 1 + +#ifndef __ASSEMBLY__ + +#include + +#ifndef DOMID_T +#define DOMID_T +typedef uint16_t domid_t; +typedef unsigned long addr_t; +#endif + +typedef uint32_t grant_ref_t; + +/* Grant table management */ +#define GRANT_INVALID_REF 0 + +/* List of grant table commands which are processed by the hypervisor */ + +#define GNTTAB_grant_page 1 +#define GNTTAB_revoke_page 2 +#define GNTTAB_map_page 3 +#define GNTTAB_unmap_page 4 + +struct gnttab_op { + + /* Command to be processed in the hypercall */ + uint32_t cmd; + + /* Peer domain */ + domid_t domid; + + /* pfn to be granted or pfn associated to an existing ref */ + addr_t pfn; + + /* Grant reference */ + grant_ref_t ref; + +}; +typedef struct gnttab_op gnttab_op_t; + +void do_gnttab(gnttab_op_t *args); + +/* Event channel management */ + +#define ECS_FREE 0 /* Channel is available for use. */ +#define ECS_RESERVED 1 /* Channel is reserved. */ +#define ECS_UNBOUND 2 /* Channel is waiting to bind to a remote domain. */ +#define ECS_INTERDOMAIN 3 /* Channel is bound to another domain. */ +#define ECS_VIRQ 4 /* Channel is bound to a virtual IRQ line. */ + +#define EVTCHNSTAT_closed 0 /* Channel is not in use. */ +#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/ +#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ +#define EVTCHNSTAT_virq 3 /* Channel is bound to a virtual IRQ line */ +/* + * EVTCHNOP_alloc_unbound: Allocate a evtchn in domain and mark as + * accepting interdomain bindings from domain . A fresh evtchn + * is allocated in and returned as . + * NOTES: + * 1. If the caller is unprivileged then must be DOMID_SELF. + * 2. may be DOMID_SELF, allowing loopback connections. + */ +#define EVTCHNOP_alloc_unbound 6 +struct evtchn_alloc_unbound { + /* IN parameters */ + domid_t dom, remote_dom; + /* OUT parameters */ + uint32_t evtchn; + uint32_t use; +}; +typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t; + +/* + * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between + * the calling domain and . must identify + * a evtchn that is unbound and marked as accepting bindings from the calling + * domain. A fresh evtchn is allocated in the calling domain and returned as + * . + * NOTES: + * 2. may be DOMID_SELF, allowing loopback connections. + */ +#define EVTCHNOP_bind_interdomain 0 +#define EVTCHNOP_bind_existing_interdomain 7 +#define EVTCHNOP_unbind_domain 12 + +struct evtchn_bind_interdomain { + /* IN parameters. */ + domid_t remote_dom; + uint32_t remote_evtchn; + uint32_t use; + /* OUT parameters. */ + uint32_t local_evtchn; +}; +typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t; + +#define EVTCHNOP_bind_virq 1 +struct evtchn_bind_virq { + /* IN parameters. */ + uint32_t virq; + /* OUT parameters. */ + uint32_t evtchn; +}; +typedef struct evtchn_bind_virq evtchn_bind_virq_t; + +/* + * EVTCHNOP_close: Close a local event channel . If the channel is + * interdomain then the remote end is placed in the unbound state + * (EVTCHNSTAT_unbound), awaiting a new connection. + */ +#define EVTCHNOP_close 3 +struct evtchn_close { + /* IN parameters. */ + uint32_t evtchn; +}; +typedef struct evtchn_close evtchn_close_t; + +/* + * EVTCHNOP_send: Send an event to the remote end of the channel whose local + * endpoint is . + */ +#define EVTCHNOP_send 4 +struct evtchn_send { + /* IN parameters. */ + uint32_t evtchn; +}; +typedef struct evtchn_send evtchn_send_t; + +struct evtchn_op { + uint32_t cmd; /* EVTCHNOP_* */ + union { + struct evtchn_alloc_unbound alloc_unbound; + struct evtchn_bind_interdomain bind_interdomain; + struct evtchn_bind_virq bind_virq; + struct evtchn_close close; + struct evtchn_send send; + } u; +}; +typedef struct evtchn_op evtchn_op_t; + +/* Domain control management */ +/* + * There are two main scheduling policies: the one used for normal (standard) ME, and + * a second one used for realtime ME. + */ +#define AVZ_SCHEDULER_FLIP 0 +#define AVZ_SCHEDULER_RT 1 + +#define DOMCTL_pauseME 1 +#define DOMCTL_unpauseME 2 +#define DOMCTL_get_AVZ_shared 3 + +struct domctl { + uint32_t cmd; + domid_t domain; + addr_t avz_shared_paddr; +}; +typedef struct domctl domctl_t; + +/* + * ME states: + * - ME_state_booting: ME is currently booting... + * - ME_state_living: ME is full-functional and activated (all frontend devices are consistent) + * - ME_state_suspended: ME is suspended before migrating. This state is maintained for the resident ME instance + * - ME_state_hibernate: ME is in a state of hibernate snapshot + * - ME_state_resuming: ME ready to perform resuming (after recovering) + * - ME_state_awakened: ME is just being awakened + * - ME_state_terminated: ME has been terminated (by a force_terminate) + * - ME_state_dead: ME does not exist + */ +typedef enum { + ME_state_booting, + ME_state_living, + ME_state_suspended, + ME_state_hibernate, + ME_state_resuming, + ME_state_awakened, + ME_state_killed, + ME_state_terminated, + ME_state_dead +} ME_state_t; + +/* Keep information about slot availability + * FREE: the slot is available (no ME) + * BUSY: the slot is allocated a ME + */ +typedef enum { + ME_SLOT_FREE, + ME_SLOT_BUSY +} ME_slotState_t; + +/* ME ID related information */ +#define ME_NAME_SIZE 40 +#define ME_SHORTDESC_SIZE 1024 + +/* + * Definition of ME ID information used by functions which need + * to get a list of running MEs with their information. + */ +typedef struct { + uint32_t slotID; + ME_state_t state; + + uint64_t spid; + + char name[ME_NAME_SIZE]; + char shortdesc[ME_SHORTDESC_SIZE]; +} ME_id_t; + +struct work_struct; +struct semaphore; + +/* + * Directcomm event management + */ +typedef enum { + DC_NO_EVENT, + DC_PRE_SUSPEND, + DC_SUSPEND, + DC_RESUME, + DC_FORCE_TERMINATE, + DC_POST_ACTIVATE, + DC_TRIGGER_DEV_PROBE, + DC_TRIGGER_LOCAL_COOPERATION, + + DC_EVENT_MAX /* Used to determine the number of DC events */ +} dc_event_t; + +/* + * Callback function associated to dc_event. + */ +typedef void(dc_event_fn_t)(dc_event_t dc_event); + +extern atomic_t dc_outgoing_domID[DC_EVENT_MAX]; +extern atomic_t dc_incoming_domID[DC_EVENT_MAX]; + +/* + * IOCTL commands for migration. + * This part is shared between the kernel and user spaces. + */ + +/* + * IOCTL codes + */ +#define AGENCY_IOCTL_INIT_MIGRATION _IOWR('S', 0, agency_ioctl_args_t) +#define AGENCY_IOCTL_GET_ME_FREE_SLOT _IOWR('S', 1, agency_ioctl_args_t) +#define AGENCY_IOCTL_READ_SNAPSHOT _IOWR('S', 2, agency_ioctl_args_t) +#define AGENCY_IOCTL_WRITE_SNAPSHOT _IOW('S', 3, agency_ioctl_args_t) +#define AGENCY_IOCTL_FINAL_MIGRATION _IOW('S', 4, agency_ioctl_args_t) +#define AGENCY_IOCTL_FORCE_TERMINATE _IOW('S', 5, agency_ioctl_args_t) +#define AGENCY_IOCTL_INJECT_ME _IOWR('S', 6, agency_ioctl_args_t) +#define AGENCY_IOCTL_GET_ME_ID _IOWR('S', 7, agency_ioctl_args_t) +#define AGENCY_IOCTL_GET_ME_ID_ARRAY _IOR('S', 11, agency_ioctl_args_t) +#define AGENCY_IOCTL_BLACKLIST_SOO _IOW('S', 12, agency_ioctl_args_t) + +#define SOO_NAME_SIZE 16 + +/* + * ME descriptor + * + * WARNING !! Be careful when modifying this structure. It *MUST* be aligned with + * the same structure used in the ME. + */ +typedef struct { + unsigned int slotID; + uint64_t spid; + + ME_state_t state; + + unsigned int size; /* Size of the ME with the struct dom_context size */ + unsigned int dc_evtchn; + + unsigned int vbstore_revtchn, vbstore_levtchn; + addr_t vbstore_pfn; + + void (*resume_fn)(void); + +} ME_desc_t; + +/* + * Agency descriptor + */ +typedef struct { + + /* + * SOO agencyUID unique 64-bit ID - Allowing to identify a SOO device. + * agencyUID 0 is NOT valid. + */ + + uint64_t agencyUID; /* Agency UID */ + + /* Event channels used for directcomm channel between agency and agency-RT or ME */ + unsigned int dc_evtchn[MAX_DOMAINS]; + + /* Event channels used by vbstore */ + unsigned int vbstore_evtchn[MAX_DOMAINS]; + + /* Local agency event channel for vbstore */ + uint32_t vbstore_levtchn; + +} agency_desc_t; + +/* + * SOO agency & ME descriptor - This structure is used in the shared info page of the agency or ME domain. + */ + +typedef struct { + union { + agency_desc_t agency; + ME_desc_t ME; + } u; +} dom_desc_t; + +/* struct agency_ioctl_args used in IOCTLs */ +typedef struct agency_ioctl_args { + void *buffer; /* IN/OUT */ + int slotID; + long value; /* IN/OUT */ +} agency_ioctl_args_t; + + +#define NSECS 1000000000ull +#define SECONDS(_s) ((u64)((_s) * 1000000000ull)) +#define MILLISECS(_ms) ((u64)((_ms) * 1000000ull)) +#define MICROSECS(_us) ((u64)((_us) * 1000ull)) + +#define VBUS_TASK_PRIO 50 + +/* + * The priority of the Directcomm thread must be higher than the priority of the SDIO + * thread to make the Directcomm thread process a DC event and release it before any new + * request by the SDIO's side thus avoiding a deadlock. + */ +#define DC_ISR_TASK_PRIO 55 + +#define SDIO_IRQ_TASK_PRIO 50 +#define SDHCI_FINISH_TASK_PRIO 50 + +#ifndef __ASSEMBLY__ + +extern volatile bool __cobalt_ready; + +void rtdm_register_dc_event_callback(dc_event_t dc_event, dc_event_fn_t *callback); + +#endif /* __ASSEMBLY__ */ + +/* Console management */ + +#define CONSOLE_IO_KEYHANDLER 0 +#define CONSOLE_IO_PRINTCH 1 +#define CONSOLE_IO_PRINTSTR 2 + +#define CONSOLE_STR_MAX_LEN 128 + +typedef struct { + int cmd; + union { + char c; + char str[CONSOLE_STR_MAX_LEN]; + } u; +} console_t; + +/* + * SOO hypercall management + */ + +/* AVZ hypercalls devoted to SOO */ +#define AVZ_ME_READ_SNAPSHOT 6 +#define AVZ_ME_WRITE_SNAPSHOT 7 +#define AVZ_INJECT_ME 9 +#define AVZ_KILL_ME 10 +#define AVZ_DC_EVENT_SET 11 +#define AVZ_GET_ME_STATE 13 +#define AVZ_SET_ME_STATE 14 +#define AVZ_GET_DOM_DESC 16 +#define AVZ_EVENT_CHANNEL_OP 17 +#define AVZ_CONSOLE_IO_OP 18 +#define AVZ_DOMAIN_CONTROL_OP 19 +#define AVZ_GRANT_TABLE_OP 20 + +/* AVZ_EVENT_CHANNEL_OP */ +typedef struct { + evtchn_op_t evtchn_op; +} avz_evtchn_t; + +/* AVZ_INJECT_ME */ +typedef struct { + void *itb_paddr; + int slotID; +} avz_inject_me_t; + +/* AVZ_DC_EVENT_SET */ +typedef struct { + unsigned int domID; + dc_event_t dc_event; + int state; +} avz_dc_event_t; + +/* AVZ_GET_ME_STATE */ +/* AVZ_SET_ME_STATE */ +typedef struct { + uint32_t slotID; + int state; +} avz_me_state_t; + +/* AVZ_GET_DOM_DESC */ +typedef struct { + uint32_t slotID; + dom_desc_t dom_desc; +} avz_dom_desc_t; + +/* AVZ_GET_ME_FREE_SLOT */ +typedef struct { + int slotID; + int size; +} avz_free_slot_t; + +/* AVZ_MIG_INIT */ +typedef struct { + int slotID; +} avz_mig_init_t; + +/* AVZ_READ_SNAPSHOT */ +/* AVZ_WRITE_SNAPSHOT */ +typedef struct { + void *snapshot_paddr; + uint32_t slotID; + int size; +} avz_snapshot_t; + +/* AVZ_MIG_FINAL */ +typedef struct { + uint32_t slotID; +} avz_mig_final_t; + +/* AVZ_KILL_ME */ +typedef struct { + uint32_t slotID; +} avz_kill_me_t; + +/* AVZ_CONSOLE_IO_OP */ +typedef struct { + console_t console; +} avz_console_io_t; + +/* AVZ_DOMAIN_CONTROL_OP */ +typedef struct { + domctl_t domctl; +} avz_domctl_t; + +/* AVZ_GRANT_TABLE_OP */ +typedef struct { + gnttab_op_t gnttab_op; +} avz_gnttab_t; + +/* + * AVZ hypercall argument + */ +typedef struct { + int cmd; + union { + avz_evtchn_t avz_evtchn; + avz_inject_me_t avz_inject_me_args; + avz_dc_event_t avz_dc_event_args; + avz_me_state_t avz_me_state_args; + avz_dom_desc_t avz_dom_desc_args; + avz_free_slot_t avz_free_slot_args; + avz_mig_init_t avz_mig_init_args; + avz_snapshot_t avz_snapshot_args; + avz_mig_final_t avz_mig_final_args; + avz_kill_me_t avz_kill_me_args; + avz_console_io_t avz_console_io_args; + avz_domctl_t avz_domctl_args; + avz_gnttab_t avz_gnttab_args; + } u; +} avz_hyp_t; + +typedef struct { + void *val; +} pre_suspend_args_t; + +typedef struct { + void *val; +} pre_resume_args_t; + +typedef struct { + void *val; +} post_activate_args_t; + +/* + * Further agency ctl commands that may be used by MEs. + * !! WARNING !! The ME must implement the same definitions. + */ + +#define AG_INJECT_ME 0x11 +#define AG_KILL_ME 0x12 + +typedef struct { + char soo_name[SOO_NAME_SIZE]; +} soo_name_args_t; + + +/* + * SOO callback functions. + * The following definitions are used as argument in domcalls or in the + * agency_ctl() function as a callback to be propagated to a specific ME. + * + */ + +#define CB_PRE_SUSPEND 4 +#define CB_PRE_RESUME 5 +#define CB_POST_ACTIVATE 6 +#define CB_AGENCY_CTL 9 + +typedef struct soo_domcall_arg { + + /* Stores the agency ctl function. + * Possibly, the agency_ctl function can be associated to a callback operation asked by a ME + */ + unsigned int cmd; + unsigned int slotID; /* Origin of the domcall */ + + union { + pre_suspend_args_t pre_suspend_args; + pre_resume_args_t pre_resume_args; + + post_activate_args_t post_activate_args; + ME_state_t set_me_state_args; + } u; + +} soo_domcall_arg_t; + +extern struct semaphore usr_feedback; +extern struct semaphore injection_sem; + +/* Callbacks initiated by agency ping */ +void cb_pre_resume(soo_domcall_arg_t *args); +void cb_pre_suspend(soo_domcall_arg_t *args); + +void cb_cooperate(soo_domcall_arg_t *args); +void cb_post_activate(soo_domcall_arg_t *args); + +void cb_force_terminate(void); + +void callbacks_init(void); + +void set_dc_event(domid_t domid, dc_event_t dc_event); + +void do_soo_activity(void *arg); + +void soo_guest_activity_init(void); + +void dc_stable(int dc_event); +void tell_dc_stable(int dc_event); + +void do_sync_dom(int slotID, dc_event_t); +void do_async_dom(int slotID, dc_event_t); + +void perform_task(dc_event_t dc_event); + +void shutdown_ME(unsigned int ME_slotID); + +void cache_flush_all(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* UAPI_SOO_H */ diff --git a/so3/soo/include/soo/vbstore.h b/so3/soo/include/soo/vbstore.h index f8be516627..e5860f826d 100644 --- a/so3/soo/include/soo/vbstore.h +++ b/so3/soo/include/soo/vbstore.h @@ -82,7 +82,7 @@ struct vbstore_domain_interface { volatile VBSTORE_RING_IDX req_cons, req_prod, req_pvt; volatile VBSTORE_RING_IDX rsp_cons, rsp_prod, rsp_pvt; - uint32_t levtchn, revtchn; + domid_t domid; }; typedef volatile struct vbstore_domain_interface vbstore_intf_t; diff --git a/so3/soo/include/soo/vbus.h b/so3/soo/include/soo/vbus.h index 3cb48a1f72..e962161586 100644 --- a/so3/soo/include/soo/vbus.h +++ b/so3/soo/include/soo/vbus.h @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -167,8 +166,6 @@ void frontend_for_each(void *data, int (*fn)(struct vbus_device *, void *)); int vbus_dev_remove(struct vbus_device *dev); -extern unsigned int dc_evtchn; - void add_new_dev(struct vbus_device *dev); extern int vbus_dev_probe(struct vbus_device *dev); @@ -208,10 +205,8 @@ void vbus_watch_path(struct vbus_device *dev, char *path, struct vbus_watch *wat void vbus_watch_pathfmt(struct vbus_device *dev, struct vbus_watch *watch, void (*callback)(struct vbus_watch *), const char *pathfmt, ...) __attribute__ ((format (printf, 4, 5))); -int vbus_grant_ring(struct vbus_device *dev, unsigned long ring_mfn); -int vbus_map_ring_valloc(struct vbus_device *dev, int gnt_ref, void **vaddr); -int vbus_map_ring(struct vbus_device *dev, int gnt_ref, grant_handle_t *handle, void *vaddr); - +int vbus_grant_ring(struct vbus_device *dev, unsigned long ring_pfn); + void vbus_alloc_evtchn(struct vbus_device *dev, uint32_t *port); void vbus_bind_evtchn(struct vbus_device *dev, uint32_t remote_port, uint32_t *port); void vbus_free_evtchn(struct vbus_device *dev, uint32_t port); @@ -246,7 +241,6 @@ void vbstore_trigger_dev_probe(void); int vbstore_uart_remove(unsigned int domID); -void postmig_setup(void); int gnttab_remove(bool with_vbus); void device_shutdown(void); @@ -254,8 +248,6 @@ void remove_devices(void); void vbus_init(void); -void postmig_vbstore_setup(struct DOMCALL_sync_domain_interactions_args *args); - #ifdef DEBUG #undef DBG #define DBG(fmt, ...) \ diff --git a/so3/soo/kernel/Makefile b/so3/soo/kernel/Makefile index d15c00abdd..f018d0dc69 100644 --- a/so3/soo/kernel/Makefile +++ b/so3/soo/kernel/Makefile @@ -4,7 +4,7 @@ # obj-y += setup.o -obj-y += domcall.o +obj-y += hypervisor.o obj-y += evtchn.o obj-y += gnttab.o obj-y += soo_guest_activity.o diff --git a/so3/soo/kernel/console/lprintk.c b/so3/soo/kernel/console/lprintk.c index 713df4cd49..4a9f9f3669 100644 --- a/so3/soo/kernel/console/lprintk.c +++ b/so3/soo/kernel/console/lprintk.c @@ -27,7 +27,6 @@ extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); void lprintk(char *format, ...) { char buf[CONSOLEIO_BUFFER_SIZE]; - int i; va_list va; uint32_t flags; @@ -39,11 +38,9 @@ void lprintk(char *format, ...) { BUG_ON(strlen(buf) > CONSOLEIO_BUFFER_SIZE); - for (i = 0; i < strlen(buf); i++) - __printch(buf[i]); + avz_printstr(buf); local_irq_restore(flags); - } /** diff --git a/so3/soo/kernel/debug/Makefile b/so3/soo/kernel/debug/Makefile index 2b8ba4a232..d183c6aa6e 100644 --- a/so3/soo/kernel/debug/Makefile +++ b/so3/soo/kernel/debug/Makefile @@ -1,3 +1,2 @@ -obj-y += logbool.o time.o dbgvar.o obj-$(CONFIG_GPIO_DEBUG) += gpio.o \ No newline at end of file diff --git a/so3/soo/kernel/debug/dbgvar.c b/so3/soo/kernel/debug/dbgvar.c deleted file mode 100644 index 0e50ad7126..0000000000 --- a/so3/soo/kernel/debug/dbgvar.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2016-2019 Daniel Rossier - * Copyright (C) 2016-2019 Baptiste Delporte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * Debugging interface that provides event logging and integer logging features. Two lists are provided: - * - a list of events, composed of a unique one-character desscriptor - * - a list of integers, composed of 32 bit integers - * Each new element is added to the dedicated list. The list can be printed afterwards. - * - * This variable list management facility may be used for debugging purposes. There are two possible ways to monitor variables and to display their content via sysfs: - * 1) Static variable which can be added as an enum part of dbgvar_t typedef. The variable is stored in the dbgvar[] array. - * 2) Dynamic logging using the *_dbgevent() function. - */ - - -#include -#include -#include - -#include -#include - -/* The following debug variable is used to monitor entry/exit in various functions called in a path. */ -int dbgvar[DBGVAR_NR]; - -static dbglist_mode_t dbgevent_mode = DBGLIST_DISABLED; -static char *dbgevent; -static char *dbgevent_print; -static unsigned int dbgevent_count = 0; - -static dbglist_mode_t dbglist_mode = DBGLIST_DISABLED; -static int *dbglist; -static int *dbglist_print; -static unsigned int dbglist_count = 0; - -void clear_dbgevent(void) { - if (dbgevent_mode != DBGLIST_DISABLED) - memset(dbgevent, 0, DBGEVENT_SIZE); -} - -void log_dbgevent(char c) { - if (dbgevent_mode == DBGLIST_DISABLED) - return; - - dbgevent[dbgevent_count] = c; - - if (unlikely(dbgevent_count >= DBGEVENT_SIZE)) - dbgevent_count = 0; - else - dbgevent_count++; - if (unlikely((dbgevent_mode == DBGLIST_CLEAR) && (dbgevent_count == 0))) - clear_dbgevent(); -} - -void set_dbgevent_mode(dbglist_mode_t mode) { - dbgevent_mode = mode; -} - -void show_dbgevent(void) { - int i; - unsigned int cur_dbgevent_count = dbgevent_count; - memcpy(dbgevent_print, dbgevent, DBGEVENT_SIZE); - - if (dbgevent_mode == DBGLIST_CLEAR) { - for (i = 0 ; i < DBGEVENT_SIZE ; i++) { - if (dbgevent_print[i] != 0) - lprintk("%c", dbgevent_print[i]); - } - } - else if (dbgevent_mode == DBGLIST_CONTINUOUS) { - i = (cur_dbgevent_count + 1) % DBGEVENT_SIZE; - while (i != cur_dbgevent_count) { - if (dbgevent_print[i] != 0) - lprintk("%c", dbgevent_print[i]); - i = (i + 1) % DBGEVENT_SIZE; - } - } - lprintk("\n"); -} - -void init_dbgevent(void) { - /* Initialize the debugging list */ - dbgevent = (char *) malloc(DBGEVENT_SIZE); - dbgevent_print = (char *) malloc(DBGEVENT_SIZE); -} - -void delete_dbgevent(void) { - free(dbgevent); - free(dbgevent_print); -} - -void clear_dbglist(void) { - if (dbglist_mode != DBGLIST_DISABLED) - memset(dbglist, 0, DBGLIST_SIZE * sizeof(int)); -} - -void log_dbglist(int i) { - if (dbglist_mode == DBGLIST_DISABLED) - return; - - dbglist[dbglist_count] = i; - - if (unlikely(dbglist_count >= DBGLIST_SIZE)) - dbglist_count = 0; - else - dbglist_count++; - if (unlikely((dbglist_mode == DBGLIST_CLEAR) && (dbglist_count == 0))) - clear_dbglist(); -} - -void set_dbglist_mode(dbglist_mode_t mode) { - dbglist_mode = mode; -} - -void show_dbglist(void) { - int i; - unsigned int cur_dbglist_count = dbglist_count; - memcpy(dbglist_print, dbglist, DBGLIST_SIZE * sizeof(int)); - - if (dbglist_mode == DBGLIST_CLEAR) { - for (i = 0 ; i < DBGLIST_SIZE ; i++) { - if (dbglist_print[i] != 0) - lprintk("%08x\n", dbglist_print[i]); - } - } - else if (dbglist_mode == DBGLIST_CONTINUOUS) { - i = (cur_dbglist_count + 1) % DBGLIST_SIZE; - while (i != cur_dbglist_count) { - if (dbglist_print[i] != 0) - lprintk("%08x\n", dbglist_print[i]); - i = (i + 1) % DBGLIST_SIZE; - } - } -} - -void init_dbglist(void) { - /* Initialize the debugging list */ - dbglist = (int *) malloc(DBGLIST_SIZE * sizeof(int)); - dbglist_print = (int *) malloc(DBGLIST_SIZE * sizeof(int)); -} - -void delete_dbglist(void) { - free(dbglist); - free(dbglist_print); -} diff --git a/so3/soo/kernel/domcall.c b/so3/soo/kernel/domcall.c deleted file mode 100644 index 5947efa965..0000000000 --- a/so3/soo/kernel/domcall.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2016-2018 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include - -/** - * Keep track of already updated base address entries for L2 page tables. - * A base address is encoded on 22 bits, since we have to keep track of such addr (coarse page table). - * - * All L2 page tables are allocated in the heap. So, to determine the position in the bitmap, - * we get the offset between the heap base address and the page table base address. - * - * Furthermore, a L2 page table may contain up to 256 entries. It means that the base address - * is always aligned on 1 KB (256 * 4). - */ - -/* We are able to keep track of base addresses for 2 MB RAM with 4 KB pages (1 bit per page) */ - -/* - * If the heap is sized to 2 MB, 2*2^20 >> 10 = 2*2^10 = 2'048 bits, for max 2'048 possible base addresses. - * 2'048 / 8 = 256 bytes. - * - */ -#define BASEADDR_BITMAP_BYTES 256 - -#if 0 -extern addr_t __heap_base_addr; -static addr_t heap_base_vaddr = (addr_t ) &__heap_base_addr; - - -static unsigned char baseaddr_2nd_bitmap[BASEADDR_BITMAP_BYTES]; - -/* Init the bitmap */ -static void init_baseaddr_2nd_bitmap(void) { - int i; - - for (i = 0; i < BASEADDR_BITMAP_BYTES; i++) - baseaddr_2nd_bitmap[i] = 0; -} - -/* - * Page tables can start at 1 KB-aligned address - */ -static void set_baseaddr_2nd_bitmap(unsigned int baseaddr) { - unsigned int pos, mod; - - baseaddr = (baseaddr - (mem_info.phys_base + (heap_base_vaddr - CONFIG_KERNEL_VADDR))) >> 10; - - pos = baseaddr >> 3; - mod = baseaddr % 8; - - BUG_ON(pos >= BASEADDR_BITMAP_BYTES); - - baseaddr_2nd_bitmap[pos] |= (1 << (7 - mod)); - -} - -static unsigned int is_set_baseaddr_2nd_bitmap(unsigned int baseaddr) { - unsigned int pos, mod; - - baseaddr = (baseaddr - (mem_info.phys_base + (heap_base_vaddr - CONFIG_KERNEL_VADDR))) >> 10; - - pos = baseaddr >> 3; - mod = baseaddr % 8; - - BUG_ON(pos >= BASEADDR_BITMAP_BYTES); - - return (baseaddr_2nd_bitmap[pos] & (1 << (7 - mod))); - -} - - -/****************************************************/ - -/* Page walking */ - -static void set_l2pte(uint32_t *l2pte, struct DOMCALL_fix_page_tables_args *args) { - unsigned int base = 0; - - base = *l2pte & PAGE_MASK; - base += pfn_to_phys(args->pfn_offset); - - /* - * Check if the physical address is really within the RAM (subject to be adujsted). - * I/O addresses must not be touched. - */ - if ((phys_to_pfn(base) >= args->min_pfn) && (phys_to_pfn(base) < args->min_pfn + args->nr_pages)) { - - *l2pte = (*l2pte & ~PAGE_MASK) | base; - - flush_pte_entry(l2pte); - } -} - -/* Process all PTEs of a 2nd-level page table */ -static void process_pte_pgtable(uint32_t *l1pte, struct DOMCALL_fix_page_tables_args *args) { - - uint32_t *l2pte; - int i; - - l2pte = (uint32_t *) __va(*l1pte & TTB_L1_PAGE_ADDR_MASK); - - /* Walk through the L2 PTEs. */ - - for (i = 0; i < TTB_L2_ENTRIES; i++, l2pte++) - if (*l2pte) - set_l2pte(l2pte, args); -} - -static void set_l1pte(uint32_t *l1pte, struct DOMCALL_fix_page_tables_args *args) { - volatile unsigned int base; - - if (l1pte_is_sect(*l1pte)) - base = *l1pte & TTB_L1_SECT_ADDR_MASK; - else { - ASSERT(l1pte_is_pt(*l1pte)); - base = (*l1pte & TTB_L1_PAGE_ADDR_MASK); - } - - base += pfn_to_phys(args->pfn_offset); - - /* - * Check if the physical address is really within the RAM (subject to be adjusted). - * I/O addresses must not be touched. - */ - if ((phys_to_pfn(base) >= args->min_pfn) && (phys_to_pfn(base) < args->min_pfn + args->nr_pages)) { - - if (l1pte_is_sect(*l1pte)) - *l1pte = (*l1pte & ~TTB_L1_SECT_ADDR_MASK) | base; - else - *l1pte = (*l1pte & ~TTB_L1_PAGE_ADDR_MASK) | base; - - - flush_pte_entry(l1pte); - } - -} - -int adjust_l1_page_tables(unsigned long addr, unsigned long end, uint32_t *pgtable, struct DOMCALL_fix_page_tables_args *args) -{ - uint32_t *l1pte; - unsigned int sect_addr; - - l1pte = l1pte_offset(pgtable, addr); - - sect_addr = (addr >> 20) - 1; - - do { - sect_addr++; - - if (*l1pte) - set_l1pte(l1pte, args); - - l1pte++; - - } while (sect_addr != ((end-1) >> 20)); - - return 0; -} - -int adjust_l2_page_tables(unsigned long addr, unsigned long end, uint32_t *pgtable, struct DOMCALL_fix_page_tables_args *args) -{ - uint32_t *l1pte; - unsigned int base; - unsigned int sect_addr; - - l1pte = l1pte_offset(pgtable, addr); - sect_addr = (addr >> 20) - 1; - - do { - sect_addr++; - - if (l1pte_is_pt(*l1pte)) { - base = *l1pte & TTB_L1_PAGE_ADDR_MASK; - - if (!is_set_baseaddr_2nd_bitmap(base)) { - - process_pte_pgtable(l1pte, args); - - /* We keep track of one pfn only, since they are always processed simultaneously */ - set_baseaddr_2nd_bitmap(base); - } - } - - l1pte++; - - } while (sect_addr != ((end-1) >> TTB_I1_SHIFT)); - - return 0; -} - -/****************************************************/ - -/** - * Fixup the page tables belonging to processes (user & kernel space). - * - * @param args arguments of this domcall - */ -static void do_fix_other_page_tables(struct DOMCALL_fix_page_tables_args *args) { - pcb_t *pcb; - uint32_t vaddr; - uint32_t *l1pte, *l1pte_current; - - set_pfn_offset(args->pfn_offset); - - init_baseaddr_2nd_bitmap(); - - /* All page tables used by processes must be adapted. */ - - list_for_each_entry(pcb, &proc_list, list) - { - - for (vaddr = CONFIG_KERNEL_VADDR; ((vaddr != 0) && (vaddr < 0xffffffff)); vaddr += TTB_SECT_SIZE) { - l1pte = l1pte_offset(pcb->pgtable, vaddr); - l1pte_current = l1pte_offset(__sys_root_pgtable, vaddr); - - *l1pte = *l1pte_current; - - flush_pte_entry((void *) l1pte); - } - - /* Finally, remap the whole user space */ - - adjust_l1_page_tables(0, CONFIG_KERNEL_VADDR, pcb->pgtable, args); - adjust_l2_page_tables(0, CONFIG_KERNEL_VADDR, pcb->pgtable, args); - - mmu_page_table_flush((uint32_t) pcb->pgtable, (uint32_t) (pcb->pgtable + TTB_L1_ENTRIES)); - } - -} - -#endif - -/* Main callback function used by AVZ */ -void domcall(int cmd, void *arg) -{ - switch (cmd) { - - case DOMCALL_presetup_adjust_variables: - do_presetup_adjust_variables(arg); - break; - - case DOMCALL_postsetup_adjust_variables: - do_postsetup_adjust_variables(arg); - break; - - case DOMCALL_fix_other_page_tables: - //do_fix_other_page_tables((struct DOMCALL_fix_page_tables_args *) arg); - break; - - case DOMCALL_sync_domain_interactions: - do_sync_domain_interactions(arg); - break; - - case DOMCALL_sync_directcomm: - do_sync_directcomm(arg); - break; - - case DOMCALL_soo: - do_soo_activity(arg); - break; - - default: - printk("Unknowmn domcall %#x\n", cmd); - BUG(); - break; - } -} - - -/** - * Enable the cooperation between this ME and the other. - */ -void spad_enable_cooperate(void) { - avz_shared->dom_desc.u.ME.spad.valid = true; -} - -/** - * Enable the cooperation between this ME and the other. - */ -void spad_disable_cooperate(void) { - avz_shared->dom_desc.u.ME.spad.valid = false; -} - diff --git a/so3/soo/kernel/evtchn.c b/so3/soo/kernel/evtchn.c index 1d31394730..376da6fa46 100644 --- a/so3/soo/kernel/evtchn.c +++ b/so3/soo/kernel/evtchn.c @@ -22,8 +22,8 @@ #define DEBUG #endif -#include #include +#include #include @@ -34,7 +34,6 @@ #include #include #include -#include /* * This lock protects updates to the following mapping and reference-count @@ -87,10 +86,9 @@ void dump_evtchn_pending(void) { * -> For VIRQ_TIMER_IRQ, avoid change the bind_virq_to_irqhandler..... * */ -void evtchn_do_upcall(cpu_regs_t *regs) -{ - unsigned int evtchn; - int l1, irq; +void virq_handle(unsigned irq_nr) { + unsigned int evtchn; + int l1, virq; int loopmax = 0; @@ -103,28 +101,19 @@ void evtchn_do_upcall(cpu_regs_t *regs) */ if (in_upcall_progress) - return ; - - /* Check if the (local) IRQs are off. In this case, pending events are not processed at this time, - * but will be once the local IRQs will be re-enabled (either by the GIC loop or an active assert - * of the IRQ line). - */ - - if (irqs_disabled_flags(regs)) - return ; + return; - in_upcall_progress = true; + in_upcall_progress = true; retry: - l1 = xchg(&avz_shared->evtchn_upcall_pending, 0); BUG_ON(l1 == 0); while (true) { - for (evtchn = 0; evtchn < NR_EVTCHN; evtchn++) + for (evtchn = 0; evtchn < NR_EVTCHN; evtchn++) if ((avz_shared->evtchn_pending[evtchn]) && !evtchn_is_masked(evtchn)) break; - + /* Found an evtchn? */ if (evtchn == NR_EVTCHN) break; @@ -137,16 +126,16 @@ void evtchn_do_upcall(cpu_regs_t *regs) printk("%s: Warning trying to process evtchn: %d IRQ: %d for quite a long time (dom ID: %d) on CPU %d / masked: %d...\n", __func__, evtchn, evtchn_info.evtchn_to_irq[evtchn], ME_domID(), smp_processor_id(), evtchn_is_masked(evtchn)); - irq = evtchn_info.evtchn_to_irq[evtchn]; - clear_evtchn(evtchn_from_irq(irq)); + virq = evtchn_info.evtchn_to_irq[evtchn]; + clear_evtchn(evtchn_from_irq(virq)); /* Mask the VIRQ event */ - irq_mask(irq); + irq_mask(virq); + + irq_process(virq); - irq_process(irq); - - /* Unmask the VIRQ event channel */ - irq_unmask(irq); + /* Unmask the VIRQ event channel */ + irq_unmask(virq); BUG_ON(local_irq_is_enabled()); @@ -200,53 +189,71 @@ static int bind_evtchn_to_virq(unsigned int evtchn) void unbind_domain_evtchn(unsigned int domID, unsigned int evtchn) { - struct evtchn_bind_interdomain bind_interdomain; + avz_hyp_t args; + + args.cmd = AVZ_EVENT_CHANNEL_OP; + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_unbind_domain; - bind_interdomain.remote_dom = domID; - bind_interdomain.local_evtchn = evtchn; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_dom = domID; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.local_evtchn = evtchn; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_unbind_domain, (long) &bind_interdomain, 0, 0); + avz_hypercall(&args); - evtchn_info.valid[evtchn] = false; + evtchn_info.valid[evtchn] = false; } static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain, unsigned int remote_evtchn) { - struct evtchn_bind_interdomain bind_interdomain; + avz_hyp_t args; + int virq; - bind_interdomain.remote_dom = remote_domain; - bind_interdomain.remote_evtchn = remote_evtchn; + args.cmd = AVZ_EVENT_CHANNEL_OP; + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_bind_interdomain; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_bind_interdomain, (long) &bind_interdomain, 0, 0); + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_dom = remote_domain; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_evtchn = remote_evtchn; - return bind_evtchn_to_virq(bind_interdomain.local_evtchn); + avz_hypercall(&args); + + virq = bind_evtchn_to_virq(args.u.avz_evtchn.evtchn_op.u.bind_interdomain.local_evtchn); + + return virq; } int bind_existing_interdomain_evtchn(unsigned local_evtchn, unsigned int remote_domain, unsigned int remote_evtchn) { - struct evtchn_bind_interdomain bind_interdomain; + avz_hyp_t args; + + args.cmd = AVZ_EVENT_CHANNEL_OP; + + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_bind_existing_interdomain; - bind_interdomain.local_evtchn = local_evtchn; - bind_interdomain.remote_dom = remote_domain; - bind_interdomain.remote_evtchn = remote_evtchn; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.local_evtchn = local_evtchn; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_dom = remote_domain; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_evtchn = remote_evtchn; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_bind_existing_interdomain, (long) &bind_interdomain, 0, 0); + avz_hypercall(&args); - return bind_evtchn_to_virq(bind_interdomain.local_evtchn); + return bind_evtchn_to_virq(args.u.avz_evtchn.evtchn_op.u.bind_interdomain.local_evtchn); } void bind_virq(unsigned int virq) { - evtchn_bind_virq_t bind_virq; + avz_hyp_t args; + int evtchn; unsigned long flags; - flags = spin_lock_irqsave(&irq_mapping_update_lock); + flags = spin_lock_irqsave(&irq_mapping_update_lock); - bind_virq.virq = virq; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_bind_virq, (long) &bind_virq, 0, 0); + args.cmd = AVZ_EVENT_CHANNEL_OP; - evtchn = bind_virq.evtchn; + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_bind_virq; + args.u.avz_evtchn.evtchn_op.u.bind_virq.virq = virq; + + avz_hypercall(&args); + + evtchn = args.u.avz_evtchn.evtchn_op.u.bind_virq.evtchn; evtchn_info.evtchn_to_irq[evtchn] = virq; evtchn_info.irq_to_evtchn[virq] = evtchn; @@ -256,24 +263,29 @@ void bind_virq(unsigned int virq) virq_bindcount[virq]++; - spin_unlock_irqrestore(&irq_mapping_update_lock, flags); + spin_unlock_irqrestore(&irq_mapping_update_lock, flags); } static void unbind_from_irq(unsigned int irq) { - evtchn_close_t op; - int evtchn = evtchn_from_irq(irq); + avz_hyp_t args; - spin_lock(&irq_mapping_update_lock); + int evtchn = evtchn_from_irq(irq); - if (--virq_bindcount[irq] == 0) { - op.evtchn = evtchn; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_close, (long) &op, 0, 0); + spin_lock(&irq_mapping_update_lock); + + args.cmd = AVZ_EVENT_CHANNEL_OP; + + if (--virq_bindcount[irq] == 0) { + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_close; + args.u.avz_evtchn.evtchn_op.u.close.evtchn = evtchn; + + avz_hypercall(&args); evtchn_info.evtchn_to_irq[evtchn] = -1; evtchn_info.valid[evtchn] = false; - } - + } + spin_unlock(&irq_mapping_update_lock); } @@ -343,9 +355,25 @@ void unmask_evtchn(int evtchn) evtchn_info.evtchn_mask[evtchn] = false; } -void virq_init(void) -{ - int i; +void virq_mask(unsigned int virq) { + mask_evtchn(evtchn_from_irq(virq)); +} + +void virq_unmask(unsigned int virq) { + unmask_evtchn(evtchn_from_irq(virq)); +} + + +static irq_ops_t virq_ops = { + .mask = virq_mask, + .unmask = virq_unmask, + .handle_high = virq_handle, + .enable = virq_unmask, + .disable = virq_mask +}; + +void virq_init(void) { + int i; irqdesc_t *irqdesc; /* @@ -372,8 +400,9 @@ void virq_init(void) irqdesc->action = NULL; irqdesc->irq_deferred_fn = NULL; - } - + irq_set_irq_ops(i, &virq_ops); + } + /* Now reserve the pre-defined VIRQ used by AVZ */ - virq_bindcount[VIRQ_TIMER]++; + virq_bindcount[VIRQ_TIMER]++; } diff --git a/so3/soo/kernel/gnttab.c b/so3/soo/kernel/gnttab.c index 2af139cb52..7d34dd4e86 100644 --- a/so3/soo/kernel/gnttab.c +++ b/so3/soo/kernel/gnttab.c @@ -21,289 +21,66 @@ #define DEBUG #endif -#include -#include #include -#include /* cache flushing ops */ -#include - -#include - -#include #include -#include #include -#include -#include -#include - -static grant_entry_t *gnttab; - -/* External tools reserve first few grant table entries. -> TO BE REMOVED IN A NEAR FUTURE ! */ -#define NR_RESERVED_ENTRIES 8 -#define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1) - -static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; -static int gnttab_free_count; -static grant_ref_t gnttab_free_head; -static DEFINE_SPINLOCK(gnttab_list_lock); - -static inline int get_order_from_pages(unsigned long nr_pages) -{ - int order; - nr_pages--; - for (order = 0; nr_pages; order++) - nr_pages >>= 1; - - return order; -} - -struct handle_grant { - grant_ref_t gref; - unsigned int domid; - unsigned int handle; - uint64_t host_addr; - - /* Sub-page mapping...*/ - unsigned int offset; - unsigned int size; - - struct list_head list; -}; - -/* - * Number of associations pfn<->frame table entry - * Basically, number of foreign pages + number of pages necessary for the foreign grant table - */ -#define NR_FRAME_TABLE_ENTRIES (NR_GRANT_FRAMES + 2) - -static inline u32 atomic_cmpxchg_u16(volatile u16 *v, u16 old, u16 new) -{ - u16 ret; - unsigned long flags; - - flags = local_irq_save(); - - ret = *v; - if (likely(ret == old)) - *v = new; - - local_irq_restore(flags); - - return ret; -} - -static int get_free_entries(int count) -{ - unsigned long flags; - int ref; - grant_ref_t head; - - flags = spin_lock_irqsave(&gnttab_list_lock); - - if (gnttab_free_count < count) { - spin_unlock_irqrestore(&gnttab_list_lock, flags); - return -1; - } - - ref = head = gnttab_free_head; - gnttab_free_count -= count; - - while (count-- > 1) - head = gnttab_list[head]; - - gnttab_free_head = gnttab_list[head]; - gnttab_list[head] = GNTTAB_LIST_END; - - spin_unlock_irqrestore(&gnttab_list_lock, flags); - return ref; -} - -#define get_free_entry() get_free_entries(1) - -static void put_free_entry(grant_ref_t ref) -{ - unsigned long flags; - - flags = spin_lock_irqsave(&gnttab_list_lock); - - gnttab_list[ref] = gnttab_free_head; - gnttab_free_head = ref; - gnttab_free_count++; - - spin_unlock_irqrestore(&gnttab_list_lock, flags); -} /* * Public grant-issuing interface functions */ -int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly) -{ - int ref; - - if (unlikely((ref = get_free_entry()) == -1)) - BUG(); - - gnttab[ref].frame = frame; - gnttab[ref].domid = domid; - wmb(); - gnttab[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); - - DBG("%s(%d, %08x), ref=%u\n", __func__, domid, frame, ref); - - return ref; -} - -void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, unsigned long frame, int readonly) -{ - gnttab[ref].frame = frame; - gnttab[ref].domid = domid; - wmb(); - gnttab[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); - -} - -int gnttab_query_foreign_access(grant_ref_t ref) -{ - u16 nflags; - - nflags = gnttab[ref].flags; - - return (nflags & (GTF_reading|GTF_writing)); -} - -void gnttab_end_foreign_access_ref(grant_ref_t ref) -{ - u16 flags, nflags; - - nflags = gnttab[ref].flags; - do { - if ((flags = nflags) & (GTF_reading|GTF_writing)) { - printk("WARNING: g.e. still in use!\n"); - BUG(); - } - } - while ((nflags = atomic_cmpxchg_u16(&gnttab[ref].flags, flags, 0)) != flags) ; -} - -void gnttab_end_foreign_access(grant_ref_t ref) -{ - gnttab_end_foreign_access_ref(ref); - put_free_entry(ref); - -} - -void gnttab_free_grant_reference(grant_ref_t ref) -{ - put_free_entry(ref); -} - -void gnttab_free_grant_references(grant_ref_t head) -{ - grant_ref_t ref; - unsigned long flags; - int count = 1; - if (head == GNTTAB_LIST_END) - return; - flags = spin_lock_irqsave(&gnttab_list_lock); - ref = head; - while (gnttab_list[ref] != GNTTAB_LIST_END) { - ref = gnttab_list[ref]; - count++; - } - gnttab_list[ref] = gnttab_free_head; - gnttab_free_head = head; - gnttab_free_count += count; - - spin_unlock_irqrestore(&gnttab_list_lock, flags); -} - -int gnttab_alloc_grant_references(u16 count, grant_ref_t *head) +/** + * @brief Request a grant for a specific pfn to the hypervisor intended to + * be used by a peer domain. + * + * @param domid Peer domain which will access the granted page + * @param pfn The page to be granted + * @return The unique reference enabling access to the grant page + */ +int gnttab_grant_foreign_access(domid_t domid, unsigned long pfn) { - int h = get_free_entries(count); - - if (h == -1) - return -ENOSPC; + gnttab_op_t gnttab_op; - *head = h; + /* Invoke the hypercall to grant access to domid */ + gnttab_op.cmd = GNTTAB_grant_page; + gnttab_op.domid = domid; + gnttab_op.pfn = pfn; + + avz_gnttab(&gnttab_op); - return 0; + return gnttab_op.ref; } - -/* - * Remove the grant table and all foreign entries. + +/** + * @brief Query the hypervisor to retrieve a pfn from a grant reference and + * do a mapping and return a vaddr + * + * @param domid + * @param grant_ref + * @param vaddr */ -int gnttab_remove(bool with_vbus) { - char path[20]; - - DBG("Removing grant table ...\n"); +void gnttab_map(domid_t domid, grant_ref_t grant_ref, void **vaddr) { + gnttab_op_t gnttab_op; - /* Free previous entries */ - free_contig_vpages((addr_t) gnttab, NR_GRANT_FRAMES); + gnttab_op.cmd = GNTTAB_map_page; + gnttab_op.domid = domid; + gnttab_op.ref = grant_ref; + + avz_gnttab(&gnttab_op); - if (with_vbus) { - sprintf(path, "domain/gnttab/%i", ME_domID()); - vbus_rm(VBT_NIL, path, "pfn"); - } - - return 0; + *vaddr = (void *) io_map(pfn_to_phys(gnttab_op.pfn), PAGE_SIZE); + BUG_ON(!*vaddr); } -/* - * Grant table initialization function. - */ -void gnttab_init(void) +void gnttab_end_foreign_access(grant_ref_t ref) { - struct vbus_transaction vbt; - char buf[VBS_KEY_LENGTH], path[VBS_KEY_LENGTH]; - int i; - - DBG("%s: setting up...\n", __func__); - - /* First allocate the current domain grant table. */ - gnttab = (void *) get_contig_free_vpages(NR_GRANT_FRAMES); - - if (gnttab == NULL) - { - printk("%s/%d: Failed to alloc grant table\n", __FILE__, __LINE__); - BUG(); - } - - DBG("Exporting grant_ref table pfn %05lx virt %p \n", phys_to_pfn(virt_to_phys_pt((addr_t) gnttab)), gnttab); - - for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) - gnttab_list[i] = i + 1; - - gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES; - gnttab_free_head = NR_RESERVED_ENTRIES; - - /* Write our shared page address of our grant table into vbstore */ - DBG0("Writing our grant table pfn to vbstore ...\n"); - - vbus_transaction_start(&vbt); - - sprintf(buf, "%lX", phys_to_pfn(virt_to_phys_pt((addr_t) gnttab))); - sprintf(path, "domain/gnttab/%i", ME_domID()); - - vbus_write(vbt, path, "pfn", buf); - - vbus_transaction_end(vbt); - - DBG0("End of gnttab_init. Well done!\n"); -} - -/* - * Update the grant table for the post-migrated domain. - * Update the watches as well. - */ -void postmig_gnttab_update(void) { - - gnttab_remove(false); + gnttab_op_t gnttab_op; - /* At the moment, perform a full rebuild of grant table */ - gnttab_init(); + gnttab_op.cmd = GNTTAB_revoke_page; + gnttab_op.ref = ref; + avz_gnttab(&gnttab_op); } + \ No newline at end of file diff --git a/so3/soo/kernel/hypervisor.c b/so3/soo/kernel/hypervisor.c new file mode 100644 index 0000000000..89d8513083 --- /dev/null +++ b/so3/soo/kernel/hypervisor.c @@ -0,0 +1,122 @@ + +/* + * Copyright (C) 2014-2024 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#include + +#include +#include +#include +#include + +/* When the heap is not available yet, we use this temporary buffer + * to pass the hypervisor args. + */ +avz_hyp_t __avz_hyp_static; + +void avz_get_shared(void) { + avz_hyp_t args; + + args.cmd = AVZ_DOMAIN_CONTROL_OP; + args.u.avz_domctl_args.domctl.cmd = DOMCTL_get_AVZ_shared; + + avz_hypercall(&args); + + BUG_ON(!args.u.avz_domctl_args.domctl.avz_shared_paddr); + + avz_shared = (avz_shared_t *) io_map(args.u.avz_domctl_args.domctl.avz_shared_paddr, PAGE_SIZE); + BUG_ON(!avz_shared); +} + +void avz_printch(char c) { + avz_hyp_t args; + + args.cmd = AVZ_CONSOLE_IO_OP; + + args.u.avz_console_io_args.console.cmd = CONSOLE_IO_PRINTCH; + args.u.avz_console_io_args.console.u.c = c; + + avz_hypercall(&args); +} + +void avz_printstr(char *s) { + avz_hyp_t args; + + args.cmd = AVZ_CONSOLE_IO_OP; + args.u.avz_console_io_args.console.cmd = CONSOLE_IO_PRINTSTR; + + strncpy(args.u.avz_console_io_args.console.u.str, s, CONSOLE_STR_MAX_LEN); + + avz_hypercall(&args); +} + +void avz_gnttab(gnttab_op_t *op) { + avz_hyp_t args; + + args.cmd = AVZ_GRANT_TABLE_OP; + + memcpy(&args.u.avz_gnttab_args.gnttab_op, op, sizeof(gnttab_op_t)); + avz_hypercall(&args); + memcpy(op, &args.u.avz_gnttab_args.gnttab_op, sizeof(gnttab_op_t)); + +} + + +/* + * SOO hypercall + * + * Mandatory arguments: + * - cmd: hypercall + * - addr: a virtual address used within the hypervisor + * - p_val1: a (virtual) address to a first value + * - p_val2: a (virtual) address to a second value + */ + +void avz_hypercall(avz_hyp_t *avz_hyp) +{ + avz_hyp_t *__avz_hyp; + + if (boot_stage < BOOT_STAGE_HEAP_READY) { + __avz_hyp = &__avz_hyp_static; + } else { + + /* Make sure the avz_hyp details are in a linear-mapped zone + * to be able to pass the physical address to the hypervisor. + */ + __avz_hyp = malloc(sizeof(avz_hyp_t)); + BUG_ON(!__avz_hyp); + } + + memcpy(__avz_hyp, avz_hyp, sizeof(avz_hyp_t)); + + __asm_flush_dcache_range((addr_t) __avz_hyp, sizeof(avz_hyp_t)); + __avz_hypercall(AVZ_HYPERCALL_TRAP, __pa(__avz_hyp)); + __asm_invalidate_dcache_range((addr_t) __avz_hyp, sizeof(avz_hyp_t)); + + memcpy(avz_hyp, __avz_hyp, sizeof(avz_hyp_t)); + + if (boot_stage > BOOT_STAGE_HEAP_READY) + free(__avz_hyp); +} + +void avz_sig_terminate(void) { + __avz_hypercall(AVZ_HYPERCALL_SIGRETURN, 0); +} \ No newline at end of file diff --git a/so3/soo/kernel/setup.c b/so3/soo/kernel/setup.c index b96ae902bd..2693805e73 100644 --- a/so3/soo/kernel/setup.c +++ b/so3/soo/kernel/setup.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -34,127 +36,70 @@ #include #include -#include +#include #include -extern volatile uint32_t *HYPERVISOR_hypercall_addr; +volatile avz_shared_t *avz_shared; + + /** + * @brief Signal-like handler called from AVZ during the recovering operation + * + */ + static void resume_fn(void) { + u64 time_offset; -int do_presetup_adjust_variables(void *arg) -{ - struct DOMCALL_presetup_adjust_variables_args *args = arg; + /* Init the local GIC */ + gic_hw_reset(); - /* Normally, avz_shared virt address is retrieved from r12 at guest bootstrap (head.S) - * We need to readjust this address after migration. - */ - avz_shared = args->avz_shared; - - /* Re-adjust the meminfo descriptor */ - mem_info.phys_base = avz_shared->dom_phys_offset; - - HYPERVISOR_hypercall_addr = (uint32_t *) avz_shared->hypercall_vaddr; - - __printch = avz_shared->printch; - - /* Adjust timer information */ - postmig_adjust_timer(); - - return 0; -} - -int do_postsetup_adjust_variables(void *arg) -{ - struct DOMCALL_postsetup_adjust_variables_args *args = arg; - - /* Updating pfns where used. */ - readjust_io_map(args->pfn_offset); - - return 0; -} - -int do_sync_domain_interactions(void *arg) -{ - struct DOMCALL_sync_domain_interactions_args *args = arg; - - io_unmap((addr_t) __intf); + /* Init the timer too */ + clocksource_timer_reset(); - __intf = (struct vbstore_domain_interface *) io_map(args->vbstore_pfn << PAGE_SHIFT, PAGE_SIZE); - BUG_ON(!__intf); + /* Now, we need to update the list of all existing timers since our + * host clock will be different. We stored the current system time when saving, + * so we compute the offset according to the current time. + */ + time_offset = NOW() - avz_shared->current_s_time; + apply_timer_offset(time_offset); - postmig_vbstore_setup(args); + raise_softirq(SCHEDULE_SOFTIRQ); - return 0; -} + /* We finished with the signal handler processing */ + avz_sig_terminate(); + } /** * This function is called at early bootstrap stage along head.S. */ void avz_setup(void) { - __printch = avz_shared->printch; + avz_get_shared(); - /* Immediately prepare for hypercall processing */ - HYPERVISOR_hypercall_addr = (uint32_t *) avz_shared->hypercall_vaddr; + avz_shared->dom_desc.u.ME.resume_fn = resume_fn; - lprintk("SOO Virtualizer (avz) shared page:\n\n"); + lprintk("SOO Virtualizer (avz) shared page:\n\n"); - lprintk("- Virtual address of printch() function: %lx\n", __printch); - lprintk("- Hypercall addr: %lx\n", (addr_t) HYPERVISOR_hypercall_addr); lprintk("- Dom phys offset: %lx\n\n", (addr_t) mem_info.phys_base); - - __ht_set = (ht_set_t) avz_shared->logbool_ht_set_addr; - - avz_shared->domcall_vaddr = (unsigned long) domcall; - avz_shared->vectors_vaddr = (unsigned long) avz_vector_callback; - + virq_init(); } - void post_init_setup(void) { - printk("VBstore shared page with agency at pfn 0x%x\n", avz_shared->vbstore_pfn); + printk("Mapping VBstore shared page pfn %d\n", avz_shared->dom_desc.u.ME.vbstore_pfn); - __intf = (struct vbstore_domain_interface *) io_map(avz_shared->vbstore_pfn << PAGE_SHIFT, PAGE_SIZE); - BUG_ON(!__intf); + __intf = (void *) io_map(pfn_to_phys(avz_shared->dom_desc.u.ME.vbstore_pfn), PAGE_SIZE); + BUG_ON(!__intf); - printk("SOO Mobile Entity booting ...\n"); + printk("SOO Mobile Entity booting ...\n"); - soo_guest_activity_init(); + soo_guest_activity_init(); callbacks_init(); /* Initialize the Vbus subsystem */ vbus_init(); - gnttab_init(); - - /* - * Now, the ME requests to be paused by setting its state to ME_state_preparing. As a consequence, - * the agency will pause it. - * The state is moving from ME_state_booting to ME_state_preparing. - */ - set_ME_state(ME_state_preparing); - - /* - * There are two scenarios. - * 1. Classical injection scheme: Wait for the agency to perform the pause+unpause. It should set the ME - * state to ME_state_booting to allow the ME to continue. - * 2. ME that has migrated on a Smart Object: The ME state is ME_state_migrating, so it is different from - * ME_state_preparing. - */ - - while (1) { - schedule(); - - if (get_ME_state() != ME_state_preparing) { - DBG("ME state changed: %d, continuing...\n", get_ME_state()); - break; - } - } - - BUG_ON(get_ME_state() != ME_state_booting); - /* Write the entries related to the ME ID in vbstore */ vbstore_ME_ID_populate(); diff --git a/so3/soo/kernel/soo_guest_activity.c b/so3/soo/kernel/soo_guest_activity.c index e43d38371e..3d31cf40de 100644 --- a/so3/soo/kernel/soo_guest_activity.c +++ b/so3/soo/kernel/soo_guest_activity.c @@ -35,8 +35,7 @@ #include #include #include -#include - + /* * Used to keep track of the target domain for a certain (outgoing) dc_event. * Value -1 means no dc_event in progress. @@ -50,8 +49,6 @@ atomic_t dc_incoming_domID[DC_EVENT_MAX]; static struct completion dc_stable_lock[DC_EVENT_MAX]; -long __pfn_offset = 0; - void dc_stable(int dc_event) { /* It may happen that the thread which performs the down did not have time to perform the call and is not suspended. @@ -63,7 +60,6 @@ void dc_stable(int dc_event) atomic_set(&dc_incoming_domID[dc_event], -1); } - /* * Sends a ping event to a remote domain in order to get synchronized. * Various types of event (dc_event) can be sent. @@ -87,8 +83,8 @@ void do_sync_dom(int domID, dc_event_t dc_event) set_dc_event(domID, dc_event); - DBG("%s: notifying via evtchn %d...\n", __func__, dc_evtchn); - notify_remote_via_evtchn(dc_evtchn); + DBG("%s: notifying via evtchn %d...\n", __func__, avz_shared->dom_desc.u.ME.dc_evtchn); + notify_remote_via_evtchn(avz_shared->dom_desc.u.ME.dc_evtchn); /* Wait for the response from the outgoing domain */ DBG("%s: waiting for completion on dc_event %d...\n", __func__, dc_event); @@ -120,7 +116,7 @@ void tell_dc_stable(int dc_event) { atomic_set(&dc_incoming_domID[dc_event], -1); - notify_remote_via_evtchn(dc_evtchn); + notify_remote_via_evtchn(avz_shared->dom_desc.u.ME.dc_evtchn); } @@ -130,58 +126,23 @@ void tell_dc_stable(int dc_event) { */ void set_dc_event(domid_t domID, dc_event_t dc_event) { - soo_hyp_dc_event_t dc_event_args; + avz_hyp_t args; DBG("%s(%d, %d)\n", __func__, domID, dc_event); - dc_event_args.domID = domID; - dc_event_args.dc_event = dc_event; + args.cmd = AVZ_DC_EVENT_SET; + args.u.avz_dc_event_args.domID = domID; + args.u.avz_dc_event_args.dc_event = dc_event; + + avz_hypercall(&args); - soo_hypercall(AVZ_DC_SET, NULL, NULL, &dc_event_args, NULL); - while (dc_event_args.state == -EBUSY) { + while (args.u.avz_dc_event_args.state == -EBUSY) { schedule(); - soo_hypercall(AVZ_DC_SET, NULL, NULL, &dc_event_args, NULL); + avz_hypercall(&args); } } - -/* - * SOO Migration hypercall - * - * Mandatory arguments: - * - cmd: hypercall - * - vaddr: a virtual address used within the hypervisor - * - paddr: a physical address used within the hypervisor - * - p_val1: a (virtual) address to a first value - * - p_val2: a (virtual) address to a second value - */ - -void soo_hypercall(int cmd, void *vaddr, void *paddr, void *p_val1, void *p_val2) -{ - soo_hyp_t soo_hyp; - - soo_hyp.cmd = cmd; - soo_hyp.vaddr = (unsigned long) vaddr; - soo_hyp.paddr = (unsigned long) paddr; - soo_hyp.p_val1 = p_val1; - soo_hyp.p_val2 = p_val2; - - hypercall_trampoline(__HYPERVISOR_soo_hypercall, (long) &soo_hyp, 0, 0, 0); -} - -/* - * Set the pfn offset after migration - */ -void set_pfn_offset(long pfn_offset) -{ - __pfn_offset = pfn_offset; -} - -long get_pfn_offset(void) -{ - return __pfn_offset; -} - + /* * Get the state of a ME. */ @@ -201,6 +162,7 @@ void set_ME_state(ME_state_t state) avz_shared->dom_desc.u.ME.state = state; } +void postmig_setup(void); void perform_task(dc_event_t dc_event) { soo_domcall_arg_t args; @@ -226,45 +188,42 @@ void perform_task(dc_event_t dc_event) /* Remove vbstore entries related to this ME */ DBG("Removing vbstore entries ...\n"); - remove_vbstore_entries(); - - /* Remove grant table entries */ - DBG("Removing grant references ...\n"); - gnttab_remove(true); - } + remove_vbstore_entries(); + } - break; + break; case DC_RESUME: - DBG("resuming vbstore...\n"); - /* Giving a chance to perform actions before resuming devices */ - args.cmd = CB_PRE_RESUME; + BUG_ON((get_ME_state() != ME_state_resuming) && (get_ME_state() != ME_state_awakened)); + + /* Giving a chance to perform actions before resuming devices */ + args.cmd = CB_PRE_RESUME; do_soo_activity(&args); DBG("Now resuming vbstore...\n"); vbs_resume(); - - /* After a migration, re-init watch for device/ */ - if (get_ME_state() == ME_state_migrating) + + /* During a resuming after an awakened snapshot, re-init watch for device/ */ + if (get_ME_state() == ME_state_awakened) postmig_setup(); DBG("vbstore resumed.\n"); break; case DC_SUSPEND: - DBG("Suspending vbstore...\n"); - vbs_suspend(); + vbs_suspend(); DBG("vbstore suspended.\n"); + break; case DC_PRE_SUSPEND: DBG("Pre-suspending...\n"); - /* Giving a chance to perform actions before resuming devices */ + /* Giving a chance to perform actions before suspending devices */ args.cmd = CB_PRE_SUSPEND; do_soo_activity(&args); break; @@ -285,8 +244,7 @@ void perform_task(dc_event_t dc_event) /* - * do_soo_activity() may be called from the hypervisor as a DOMCALL, but not necessary. - * The function may also be called as a deferred work during the ME kernel execution. + * This function is called as a deferred work during the container kernel execution. */ void do_soo_activity(void *arg) { @@ -305,60 +263,14 @@ void do_soo_activity(void *arg) cb_pre_resume(arg); break; - - case CB_PRE_ACTIVATE: /* DOMCALL */ - - /* Allow to pass local information of this SOO to this ME - * and to decide what to do next... - */ - cb_pre_activate(arg); - break; - - case CB_PRE_PROPAGATE: /* DOMCALL */ - - cb_pre_propagate(arg); - break; - - case CB_KILL_ME: /* Kill domcall */ - - /* If the ME agrees to be killed (immediately being shutdown, it has to change its state to killed) */ - cb_kill_me(arg); - break; - - case CB_COOPERATE: /* Both DOMCALL and called by perform_cooperate() */ - - /* - * Enable possible exchange of data between MEs - * and make further actions - */ - - cb_cooperate(arg); - break; - + case CB_POST_ACTIVATE: /* Called by perform_post_activate() */ DBG("Post_activate callback for ME %d\n", ME_domID()); cb_post_activate(args); break; - - case CB_DUMP_BACKTRACE: /* DOMCALL */ - - dump_sched(); - break; } - -} - -/* - * Agency ctl operations - */ - -void agency_ctl(agency_ctl_args_t *agency_ctl_args) -{ - agency_ctl_args->slotID = ME_domID(); - - soo_hypercall(AVZ_AGENCY_CTL, NULL, NULL, agency_ctl_args, NULL); } ME_desc_t *get_ME_desc(void) diff --git a/so3/soo/kernel/soo_id.c b/so3/soo/kernel/soo_id.c index f217c926f3..2015e47a9b 100644 --- a/so3/soo/kernel/soo_id.c +++ b/so3/soo/kernel/soo_id.c @@ -23,11 +23,13 @@ #include -#include #include #include #include +#include + + /* ME ID related information management */ /** @@ -72,10 +74,10 @@ const char *get_me_name(void) { * Get the SPID related to this ME. * (mandatory) * - * @param what Either "spid" or "spad" + * @param what Either "spid" * @return SPID on 64-bit encoding */ -u64 get_spid_spad(char *what) { +u64 get_spid(void) { u64 val; int node; @@ -86,36 +88,30 @@ u64 get_spid_spad(char *what) { BUG(); } - node = fdt_property_read_u64(__fdt_addr, node, what, &val); + node = fdt_property_read_u64(__fdt_addr, node, "spid", &val); if (node < 0) { - printk("%s: node \"%s\" not found\n", __func__, what); + printk("%s: node \"%s\" not found\n", __func__, "spid"); BUG(); } return val; } -u64 get_spid(void) { - return get_spid_spad("spid"); -} - /** * Write the entries related to the ME ID in vbstore */ void vbstore_ME_ID_populate(void) { const char *name, *shortdesc; - u64 spid, spadcaps; - char rootname[VBS_KEY_LENGTH], entry[VBS_KEY_LENGTH]; + u64 spid; + char rootname[VBS_KEY_LENGTH], entry[VBS_KEY_LENGTH]; - /* Set all ME ID related information */ + /* Set all ME ID related information */ /* Set the SPID of this ME */ - spid = get_spid_spad("spid"); - spadcaps = get_spid_spad("spadcaps"); - + spid = get_spid(); + avz_shared->dom_desc.u.ME.spid = spid; - avz_shared->dom_desc.u.ME.spad.spadcaps = spadcaps; - + /* Set the name */ name = get_me_name(); @@ -132,10 +128,6 @@ void vbstore_ME_ID_populate(void) { vbus_write(VBT_NIL, rootname, "spid", entry); - sprintf(entry, "%llx", spadcaps); - - vbus_write(VBT_NIL, rootname, "spadcaps", entry); - vbus_write(VBT_NIL, rootname, "name", name); vbus_write(VBT_NIL, rootname, "shortdesc", shortdesc); diff --git a/so3/soo/kernel/vbstore/vbstore_me.c b/so3/soo/kernel/vbstore/vbstore_me.c index 7e825cb24e..1503015c2b 100644 --- a/so3/soo/kernel/vbstore/vbstore_me.c +++ b/so3/soo/kernel/vbstore/vbstore_me.c @@ -31,7 +31,6 @@ #include #include -#include static void vbs_me_rmdir(const char *dir, const char *node) { vbus_rm(VBT_NIL, dir, node); diff --git a/so3/soo/kernel/vbus/vbus.c b/so3/soo/kernel/vbus/vbus.c index 8f29e0620f..549479cbd5 100644 --- a/so3/soo/kernel/vbus/vbus.c +++ b/so3/soo/kernel/vbus/vbus.c @@ -36,9 +36,7 @@ #include #include #include -#include -#include - + #define SYNC_BACKFRONT_COMPLETE 0 #define SYNC_BACKFRONT_SUSPEND 1 #define SYNC_BACKFRONT_RESUME 2 @@ -47,7 +45,6 @@ #define VBUS_TIMEOUT 120 /* Event channels used for directcomm channel between agency and ME */ -unsigned int dc_evtchn; spinlock_t dc_lock; /* List of device drivers */ @@ -543,7 +540,7 @@ void vbus_init(void) sprintf(buf, "soo/directcomm/%d", ME_domID()); - res = vbus_scanf(vbt, buf, "event-channel", "%d", &dc_evtchn); + res = vbus_scanf(vbt, buf, "event-channel", "%d", &avz_shared->dom_desc.u.ME.dc_evtchn); if (res != 1) { printk("%s: reading soo/directcomm failed. Error code: %d\n", __func__, res); @@ -553,28 +550,20 @@ void vbus_init(void) vbus_transaction_end(vbt); /* Binding the irqhandler to the eventchannel */ - DBG("%s: setting up the direct comm event channel (%d) ...\n", __func__, dc_evtchn); - res = bind_interdomain_evtchn_to_irqhandler(DOMID_AGENCY, dc_evtchn, directcomm_isr, directcomm_isr_thread, NULL); + DBG("%s: setting up the direct comm event channel (%d) ...\n", __func__, avz_shared->dom_desc.u.ME.dc_evtchn); + res = bind_interdomain_evtchn_to_irqhandler(DOMID_AGENCY, + avz_shared->dom_desc.u.ME.dc_evtchn, + directcomm_isr, + directcomm_isr_thread, + NULL); if (res <= 0) { printk("Error: bind_evtchn_to_irqhandler failed"); BUG(); } - dc_evtchn = evtchn_from_irq(res); - DBG("%s: local event channel bound to directcomm towards non-RT Agency : %d\n", __func__, dc_evtchn); + avz_shared->dom_desc.u.ME.dc_evtchn = evtchn_from_irq(res); + DBG("%s: local event channel bound to directcomm towards non-RT Agency : %d\n", __func__, avz_shared->dom_desc.u.ME.dc_evtchn); DBG("vbus_init OK!\n"); } - -/* - * DOMCALL_sync_directcomm - */ -int do_sync_directcomm(void *arg) -{ - struct DOMCALL_directcomm_args *args = arg; - - args->directcomm_evtchn = dc_evtchn; - - return 0; -} diff --git a/so3/soo/kernel/vbus/vbus_client.c b/so3/soo/kernel/vbus/vbus_client.c index 71eb64b1df..7b901bac03 100644 --- a/so3/soo/kernel/vbus/vbus_client.c +++ b/so3/soo/kernel/vbus/vbus_client.c @@ -23,15 +23,15 @@ #include #include +#include #include -#include #include #include #include #include -#include +#include const char *vbus_strstate(enum vbus_state state) { @@ -112,13 +112,13 @@ void vbus_watch_pathfmt(struct vbus_device *dev, struct vbus_watch *watch, void * @dev: vbus device * @ring_mfn: mfn of ring to grant - * Grant access to the given @ring_mfn to the peer of the given device. Return + * Grant access to the given @rinfg_mfn to the peer of the given device. Return * 0 on success, or -errno on error. On error, the device will switch to * VbusStateClosing, and the error will be saved in the store. */ int vbus_grant_ring(struct vbus_device *dev, unsigned long ring_pfn) { - return gnttab_grant_foreign_access(dev->otherend_id, ring_pfn, 0); + return gnttab_grant_foreign_access(dev->otherend_id, ring_pfn); } /** @@ -129,18 +129,17 @@ int vbus_grant_ring(struct vbus_device *dev, unsigned long ring_pfn) */ void vbus_alloc_evtchn(struct vbus_device *dev, uint32_t *evtchn) { - struct evtchn_alloc_unbound alloc_unbound; + avz_hyp_t args; - alloc_unbound.dom = DOMID_SELF; + args.cmd = AVZ_EVENT_CHANNEL_OP; - if (dev->realtime) - alloc_unbound.remote_dom = DOMID_AGENCY_RT; - else - alloc_unbound.remote_dom = dev->otherend_id; + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_alloc_unbound; + args.u.avz_evtchn.evtchn_op.u.alloc_unbound.dom = DOMID_SELF; + args.u.avz_evtchn.evtchn_op.u.alloc_unbound.remote_dom = dev->otherend_id; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_alloc_unbound, (long) &alloc_unbound, 0, 0); + avz_hypercall(&args); - *evtchn = alloc_unbound.evtchn; + *evtchn = args.u.avz_evtchn.evtchn_op.u.alloc_unbound.evtchn; } @@ -151,15 +150,19 @@ void vbus_alloc_evtchn(struct vbus_device *dev, uint32_t *evtchn) */ void vbus_bind_evtchn(struct vbus_device *dev, uint32_t remote_evtchn, uint32_t *evtchn) { - struct evtchn_bind_interdomain bind_interdomain; + avz_hyp_t args; - bind_interdomain.remote_dom = dev->otherend_id; - bind_interdomain.remote_evtchn = remote_evtchn; + args.cmd = AVZ_EVENT_CHANNEL_OP; + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_bind_interdomain; + + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_dom = dev->otherend_id; + args.u.avz_evtchn.evtchn_op.u.bind_interdomain.remote_evtchn = remote_evtchn; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_bind_interdomain, (long) &bind_interdomain, 0, 0); + avz_hypercall(&args); + + *evtchn = args.u.avz_evtchn.evtchn_op.u.bind_interdomain.local_evtchn; - *evtchn = bind_interdomain.local_evtchn; - DBG("%s: got local evtchn: %d for remote evtchn: %d\n", __func__, *evtchn, remote_evtchn); + DBG("%s: got local evtchn: %d for remote evtchn: %d\n", __func__, *evtchn, remote_evtchn); } /** @@ -167,11 +170,14 @@ void vbus_bind_evtchn(struct vbus_device *dev, uint32_t remote_evtchn, uint32_t */ void vbus_free_evtchn(struct vbus_device *dev, uint32_t evtchn) { - struct evtchn_close close; + avz_hyp_t args; - close.evtchn = evtchn; + args.cmd = AVZ_EVENT_CHANNEL_OP; - hypercall_trampoline(__HYPERVISOR_event_channel_op, EVTCHNOP_close, (long) &close, 0, 0); + args.u.avz_evtchn.evtchn_op.cmd = EVTCHNOP_close; + args.u.avz_evtchn.evtchn_op.u.close.evtchn = evtchn; + + avz_hypercall(&args); } /** diff --git a/so3/soo/kernel/vbus/vbus_frontend.c b/so3/soo/kernel/vbus/vbus_frontend.c index 54b169641f..97a35c0532 100644 --- a/so3/soo/kernel/vbus/vbus_frontend.c +++ b/so3/soo/kernel/vbus/vbus_frontend.c @@ -27,14 +27,13 @@ #include #include -#include -#include #include #include - #include #include +#include + /* List of frontend */ struct list_head frontends; @@ -212,8 +211,8 @@ void postmig_setup(void) { * First, we need to take care about local watches on vbstore entries to be ready * on property changes. */ - - DBG0("Waiting for vbstore dev to be populated\n"); + + DBG0("Waiting for vbstore dev to be populated\n"); sprintf(root_name, "%s/%d", initial_rootname, ME_domID()); DBG("vbus_frontend: %s ... for domID: %d\n", root_name, ME_domID()); @@ -223,19 +222,11 @@ void postmig_setup(void) { /* Walk through all devices and readjust watches */ frontend_for_each(NULL, remove_dev_watches); - DBG0("Updating gnttab...\n"); - - /* Update gnttab for this slot */ - postmig_gnttab_update(); - - /* Re-create the vbstore entries for devices. - * During the creation of vbstore entries on the agency side - and after migration - only the existing entries will be updated - * Otherwise, the frontend will staid suspended. - */ - /* Write the entries related to the ME ID in vbstore */ vbstore_ME_ID_populate(); + /* Re-create the vbstore entries for devices */ + DBG0("Re-creating all vbstore entries & watches for all required (frontend) devices...\n"); vbstore_devices_populate(); diff --git a/so3/soo/kernel/vbus/vbus_vbstore.c b/so3/soo/kernel/vbus/vbus_vbstore.c index 048b21709f..59e1f55d80 100644 --- a/so3/soo/kernel/vbus/vbus_vbstore.c +++ b/so3/soo/kernel/vbus/vbus_vbstore.c @@ -39,8 +39,7 @@ #include #include #include -#include - + #define PRINTF_BUFFER_SIZE 4096 struct vbs_handle { @@ -77,9 +76,6 @@ struct vbs_handle { }; static struct vbs_handle vbs_state; -/* Used to keep the levtchn during migration */ -static unsigned int __vbstore_levtchn; - /* List of registered watches, and a lock to protect it. */ static LIST_HEAD(watches); static LIST_HEAD(vbus_msg_standby_list); @@ -240,7 +236,7 @@ static void *vbs_talkv(struct vbus_transaction t, vbus_msg_type_t type, const ms smp_mb(); - notify_remote_via_evtchn(__intf->levtchn); + notify_remote_via_evtchn(avz_shared->dom_desc.u.ME.vbstore_levtchn); /* Now we are waiting for the answer from vbstore */ DBG("Now, we wait for the reply / msg ID: %d (0x%lx)\n", msg.id, &msg.list); @@ -896,7 +892,6 @@ void vbus_vbstore_init(void) { tcb_t *task; struct vbus_device dev; - uint32_t evtchn; int vbus_irq; /* @@ -906,20 +901,13 @@ void vbus_vbstore_init(void) /* dev temporary used to set up event channel used by vbstore. */ dev.otherend_id = 0; - DBG("%s: binding a local event channel to the remote evtchn %d in Agency (intf: %lx) ...\n", __func__, __intf->revtchn, __intf); - - vbus_bind_evtchn(&dev, __intf->revtchn, &evtchn); - - /* This is our local event channel */ - __intf->levtchn = evtchn; - - DBG("Local vbstore_evtchn is %d (remote is %d)\n", __intf->levtchn, __intf->revtchn); - - /* - * Save the (local) levtchn event channel used to communicate with vbstore. - * This evtchn will be rebound after migration with the new agency. - */ - __vbstore_levtchn = __intf->levtchn; + DBG("%s: binding a local event channel to the remote evtchn %d in Agency (intf: %lx) ...\n", __func__, + avz_shared->dom_desc.u.ME.vbstore_revtchn, __intf); + + vbus_bind_evtchn(&dev, avz_shared->dom_desc.u.ME.vbstore_revtchn, + (uint32_t *) &avz_shared->dom_desc.u.ME.vbstore_levtchn); + + DBG("Local vbstore_evtchn is %d (remote is %d)\n", avz_shared->dom_desc.u.ME.vbstore_levtchn, avz_shared->dom_desc.u.ME.vbstore_revtchn); INIT_LIST_HEAD(&vbs_state.reply_list); @@ -935,7 +923,7 @@ void vbus_vbstore_init(void) init_completion(&vbs_state.watch_wait); /* Initialize the shared memory rings to talk to vbstore */ - vbus_irq = bind_evtchn_to_irq_handler(__intf->levtchn, vbus_vbstore_isr, NULL, NULL); + vbus_irq = bind_evtchn_to_irq_handler(avz_shared->dom_desc.u.ME.vbstore_levtchn, vbus_vbstore_isr, NULL, NULL); if (vbus_irq < 0) { printk("VBus request irq failed %i\n", vbus_irq); BUG(); @@ -948,15 +936,4 @@ void vbus_vbstore_init(void) DBG("vbs_init OK!\n"); } -void postmig_vbstore_setup(struct DOMCALL_sync_domain_interactions_args *args) { - DBG("__vbstore_levtchn=%d\n", __vbstore_levtchn); - - /* Re-assign the levtchn in the intf shared page (seen by the agency too) */ - __intf->levtchn = __vbstore_levtchn; - - DBG("__intf->levtchn=%d\n", __intf->levtchn); - - /* And pass the levtchn to avz for re-binding the existing event channel. */ - args->vbstore_levtchn = __vbstore_levtchn; -} - + \ No newline at end of file diff --git a/so3/soo/me/Kconfig b/so3/soo/me/Kconfig deleted file mode 100644 index 38396f965e..0000000000 --- a/so3/soo/me/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ - -choice - - prompt "SOO Mobile Entity environment" - - config SOO_REFSO3 - bool "SO3 ME Reference" - help - The SO3 ME is a reference mobile entity which is used for debugging and testing purposes. - It helps in the test & debug of interactions between the Agency and the ME for example. - -endchoice - diff --git a/so3/soo/me/Makefile b/so3/soo/me/Makefile deleted file mode 100644 index 839eef2cee..0000000000 --- a/so3/soo/me/Makefile +++ /dev/null @@ -1,9 +0,0 @@ - -obj-y += common.o - -obj-$(CONFIG_SOO_REFSO3) += refso3/ - - - - - diff --git a/so3/soo/me/common.c b/so3/soo/me/common.c deleted file mode 100644 index 69ef728962..0000000000 --- a/so3/soo/me/common.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2021 Daniel Rossier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -#include - -#include - -#include - -/** - * Build an array containing the list of hosts (visited soo) - * - * @param hosts_array - * @return the number of hosts - */ -int concat_hosts(struct list_head *hosts, uint8_t *hosts_array) { - host_t *host; - uint8_t *pos = hosts_array; - int nr = 0; - - list_for_each_entry(host, hosts, list) { - - memcpy(pos, &host->host_entry, sizeof(host_entry_t)-sizeof(void *)); - memcpy(pos+sizeof(host_entry_t)-sizeof(void *), host->host_entry.priv, host->host_entry.priv_len); - - pos += sizeof(host_entry_t)-sizeof(void *)+host->host_entry.priv_len; - - nr++; - } - - return nr; -} - -/** - * Remove a specific host from our list. - * - * @param agencyUID - */ -void del_host(struct list_head *hosts, uint64_t agencyUID) { - host_t *host; - - list_for_each_entry(host, hosts, list) { - if (host->host_entry.uid == agencyUID) { - list_del(&host->list); - - if (host->host_entry.priv_len) - free(host->host_entry.priv); - - free(host); - - return ; - } - } -} - -/** - * Add a new entry in the host list. - * - * @param me_common - * @param agencyUID - */ -void new_host(struct list_head *hosts, uint64_t agencyUID, void *priv, int priv_len) { - host_t *host; - - host = malloc(sizeof(host_t)); - BUG_ON(!host); - - host->host_entry.uid = agencyUID; - - if (priv_len) { - host->host_entry.priv = malloc(priv_len); - BUG_ON(!host->host_entry.priv); - - memcpy(host->host_entry.priv, priv, priv_len); - } - - host->host_entry.priv_len = priv_len; - - list_add_tail(&host->list, hosts); -} - -/** - * Retrieve the list of host from an array. - * - * @param hosts_array - * @param nr - */ -void expand_hosts(struct list_head *hosts, uint8_t *hosts_array, int nr) { - int i; - host_entry_t *host_entry; - - if (!nr) - return ; - - for (i = 0; i < nr; i++) { - - host_entry = (host_entry_t *) hosts_array; - - new_host(hosts, host_entry->uid, hosts_array+sizeof(host_entry_t)-sizeof(void *), host_entry->priv_len); - - hosts_array += sizeof(host_entry_t)-sizeof(void *)+host_entry->priv_len; - } -} - -/** - * Reset the list of host - */ -void clear_hosts(struct list_head *hosts) { - host_t *host, *tmp; - - list_for_each_entry_safe(host, tmp, hosts, list) { - - list_del(&host->list); - - if (host->host_entry.priv_len) - free(host->host_entry.priv); - - free(host); - } -} - - -/** - * Search for a host corresponding to a specific agencyUID - * - * @param agencyUID UID to compare - * @return reference to the host_entry or NULL - */ -host_entry_t *find_host(struct list_head *hosts, uint64_t agencyUID) { - host_t *host; - - list_for_each_entry(host, hosts, list) - if (host->host_entry.uid == agencyUID) - return &host->host_entry; - - return NULL; -} - -/** - * Duplicate a list of hosts - * - * @param src The list to be copied - * @param dst The copied list - */ -void duplicate_hosts(struct list_head *src, struct list_head *dst) { - host_t *host; - - list_for_each_entry(host, src, list) - new_host(dst, host->host_entry.uid, host->host_entry.priv, host->host_entry.priv_len); -} - -int cmpUID_fn(void *priv, struct list_head *a, struct list_head *b) { - host_t *host_a, *host_b; - - host_a = list_entry(a, host_t, list); - host_b = list_entry(b, host_t, list); - - return (host_a->host_entry.uid != host_b->host_entry.uid); -} - -/** - * Sort a list of host by its agencyUID - * - * @param hosts - */ -void sort_hosts(struct list_head *hosts) { - list_sort(NULL, hosts, cmpUID_fn); -} - -/** - * Compare two list of hosts - * - * @param incoming_hosts - * @param visits - * @return - */ -bool hosts_equals(struct list_head *a, struct list_head *b) { - LIST_HEAD(tmp_a); - LIST_HEAD(tmp_b); - - host_t *host_a, *host_b; - - duplicate_hosts(a, &tmp_a); - duplicate_hosts(b, &tmp_b); - - sort_hosts(&tmp_a); - sort_hosts(&tmp_b); - - host_b = list_entry(tmp_b.next, host_t, list); - list_for_each_entry(host_a, &tmp_a, list) { - - if ((&host_b->list == &tmp_b) || (host_a->host_entry.uid != host_b->host_entry.uid)) { - clear_hosts(&tmp_a); - clear_hosts(&tmp_b); - return false; - } - - host_b = list_entry(host_b->list.next, host_t, list); - } - - /* The second list must be the same size. */ - if (&host_b->list != &tmp_b) { - clear_hosts(&tmp_a); - clear_hosts(&tmp_b); - return false; - } - - clear_hosts(&tmp_a); - clear_hosts(&tmp_b); - - /* Successful */ - return true; -} - -/** - * Merge the "b" list of hosts in the "a" list of hosts. - * if a host of list "b" is already in list "a", it is simply ignored. - * - * @param a - * @param b - */ -void merge_hosts(struct list_head *a, struct list_head *b) { - - host_t *host_b; - - list_for_each_entry(host_b, b, list) { - if (!find_host(a, host_b->host_entry.uid)) - new_host(a, host_b->host_entry.uid, host_b->host_entry.priv, host_b->host_entry.priv_len); - } -} - -/** - * Dump the contents of a list of hosts. - * - * @param hosts - */ -void dump_hosts(struct list_head *hosts) { - host_t *host; - - lprintk("## Dump of host list:\n\n"); - - list_for_each_entry(host, hosts, list) { - lprintk(" * "); lprintk_printlnUID(host->host_entry.uid); - } - - lprintk("\n--- End of list ---\n"); -} - -/** - * Perform a local cooperation in target domain - * - * @param domID - */ -void do_local_cooperation(int domID) { - do_sync_dom(DOMID_AGENCY, DC_TRIGGER_LOCAL_COOPERATION); -} diff --git a/target/virt64_so3_guest.its b/target/virt64_so3_guest.its new file mode 100644 index 0000000000..30a0ff85d1 --- /dev/null +++ b/target/virt64_so3_guest.its @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/dts-v1/; + +/ { + description = "Kernel and rootfs components for virt64 (armv8) environment"; + + images { + + so3 { + description = "SO3 OS kernel"; + data = /incbin/("../so3/so3.bin"); + type = "guest"; + arch = "arm64"; + os = "linux"; + compression = "none"; + load = <0x41080000>; + entry = <0x41080000>; + }; + + fdt { + description = "Flattened Device Tree blob"; + data = /incbin/("../so3/dts/virt64_guest.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x43000000>; + }; + + ramfs { + description = "SO3 environment minimal rootfs"; + data = /incbin/("../rootfs/rootfs.fat"); + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + compression = "none"; + load = <0x43500000>; + }; + +}; + + configurations { + default = "so3_ramfs"; + + so3_ramfs { + description = "SO3 kernel image including device tree"; + kernel = "so3"; + fdt = "fdt"; + ramdisk = "ramfs"; + }; + + so3_mmc { + description = "SO3 kernel image including device tree"; + kernel = "so3"; + fdt = "fdt"; + }; + }; + +}; diff --git a/usr/lib/libc/include/sys/ptrace.h b/usr/lib/libc/include/sys/ptrace.h index 2c4fb7b9ab..b54e448b1a 100644 --- a/usr/lib/libc/include/sys/ptrace.h +++ b/usr/lib/libc/include/sys/ptrace.h @@ -1,7 +1,6 @@ #ifndef _SYS_PTRACE_H #define _SYS_PTRACE_H - #include /* Type of the REQUEST argument to `ptrace.' */ diff --git a/usr/lib/libc/malloc.c b/usr/lib/libc/malloc.c index 5218975b7e..da1629693e 100644 --- a/usr/lib/libc/malloc.c +++ b/usr/lib/libc/malloc.c @@ -70,9 +70,9 @@ void heap_init(void) quick_list->size = HEAP_SIZE - sizeof(mem_chunk_t); quick_list->padding_bytes = 0; - DBG("SO3: allocating a kernel heap of %d bytes.\n", quick_list->size); + DBG("SO3: allocating a kernel heap of %d bytes.\n", quick_list->size); - DBG("[list_init] List initialized. sizeof(mem_chunk_t) = %d bytes, sizeof(int) = %d bytes\n", sizeof(mem_chunk_t), sizeof(int)); + DBG("[list_init] List initialized. sizeof(mem_chunk_t) = %d bytes, sizeof(int) = %d bytes\n", sizeof(mem_chunk_t), sizeof(int)); } /* diff --git a/usr/src/sh.c b/usr/src/sh.c index 24fef8181b..3c95a51755 100644 --- a/usr/src/sh.c +++ b/usr/src/sh.c @@ -323,10 +323,10 @@ void process_cmd(void) { */ void sigint_sh_handler(int sig) { - printf("%s", prompt); - fflush(stdout); + printf("%s", prompt); + fflush(stdout); } -/* +/*d * Main entry point of the shell application. */ int main(int argc, char *argv[]) {