diff --git a/.gitignore b/.gitignore index da14fb016e..f4b3d67e92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +roms/vgabios/ qemu.creator qemu.files qemu.includes diff --git a/Makefile b/Makefile index 2da686be33..bc33c1fb80 100644 --- a/Makefile +++ b/Makefile @@ -770,7 +770,6 @@ distclean: clean rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp rm -f qemu-doc.vr qemu-doc.txt rm -f config.log - rm -f linux-headers/asm rm -f docs/version.texi rm -f docs/interop/qemu-ga-qapi.texi docs/interop/qemu-qmp-qapi.texi rm -f docs/interop/qemu-qmp-ref.7 docs/interop/qemu-ga-ref.7 diff --git a/Makefile.target b/Makefile.target index 4d56298bbf..e7637fbbcf 100644 --- a/Makefile.target +++ b/Makefile.target @@ -9,7 +9,7 @@ include $(SRC_PATH)/rules.mak $(call set-vpath, $(SRC_PATH):$(BUILD_DIR)) ifdef CONFIG_LINUX -QEMU_CFLAGS += -I../linux-headers +QEMU_CFLAGS += -Ilinux-headers endif QEMU_CFLAGS += -iquote .. -iquote $(SRC_PATH)/target/$(TARGET_BASE_ARCH) -DNEED_CPU_H diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 8f913b4639..102e8fc03b 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -44,6 +44,8 @@ #include "hw/boards.h" +#include "kvm_arm.h" + /* This check must be after config-host.h is included */ #ifdef CONFIG_EVENTFD #include @@ -2265,12 +2267,23 @@ int kvm_cpu_exec(CPUState *cpu) break; case KVM_EXIT_MMIO: DPRINTF("handle_mmio\n"); - /* Called outside BQL */ - address_space_rw(&address_space_memory, - run->mmio.phys_addr, attrs, - run->mmio.data, - run->mmio.len, - run->mmio.is_write); + qemu_mutex_lock_iothread(); + /* SCS region in armv7m space memory */ + if (run->mmio.phys_addr > 0xe0000000) { + address_space_rw(&armv7m_space_memory, + run->mmio.phys_addr, attrs, + run->mmio.data, + run->mmio.len, + run->mmio.is_write); + } + else { + address_space_rw(&address_space_memory, + run->mmio.phys_addr, attrs, + run->mmio.data, + run->mmio.len, + run->mmio.is_write); + } + qemu_mutex_unlock_iothread(); ret = 0; break; case KVM_EXIT_IRQ_WINDOW_OPEN: @@ -2336,6 +2349,12 @@ int kvm_cpu_exec(CPUState *cpu) qemu_mutex_unlock_iothread(); ret = 0; break; + case KVM_EXIT_SYNC_ARM_V7M_SREGS: + qemu_mutex_lock_iothread(); + kvm_cortex_m_get_regs(cpu); + qemu_mutex_unlock_iothread(); + ret = 0; + break; default: DPRINTF("kvm_arch_handle_exit\n"); ret = kvm_arch_handle_exit(cpu, run); @@ -2819,15 +2838,17 @@ bool kvm_device_supported(int vmfd, uint64_t type) return false; } + return (ioctl(vmfd, KVM_CREATE_DEVICE, &create_dev) >= 0); } - + int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source) { struct kvm_one_reg reg; int r; reg.id = id; + reg.addr = (uintptr_t) source; r = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (r) { diff --git a/configure b/configure index 2a7796ea80..0047a5bde0 100755 --- a/configure +++ b/configure @@ -191,7 +191,7 @@ supported_kvm_target() { test "$kvm" = "yes" || return 1 glob "$1" "*-softmmu" || return 1 case "${1%-softmmu}:$cpu" in - arm:arm | aarch64:aarch64 | \ + arm:arm | aarch64:aarch64 | arm:x86_64 |\ i386:i386 | i386:x86_64 | i386:x32 | \ x86_64:i386 | x86_64:x86_64 | x86_64:x32 | \ mips:mips | mipsel:mips | \ @@ -1908,6 +1908,7 @@ EOF if compile_prog "-fPIE -DPIE" "-pie"; then QEMU_CFLAGS="-fPIE -DPIE $QEMU_CFLAGS" LDFLAGS="-pie $LDFLAGS" + LDFLAGS="-rdynamic $LDFLAGS" pie="yes" if compile_prog "" "-Wl,-z,relro -Wl,-z,now" ; then LDFLAGS="-Wl,-z,relro -Wl,-z,now $LDFLAGS" @@ -6846,10 +6847,16 @@ if test "$docker" != "no"; then echo "HAVE_USER_DOCKER=y" >> $config_host_mak fi +for target in $target_list; do +target_dir="$target" +config_target_mak=$target_dir/config-target.mak +target_name=$(echo $target | cut -d '-' -f 1) +target_bigendian="no" + # use included Linux headers if test "$linux" = "yes" ; then - mkdir -p linux-headers - case "$cpu" in + mkdir -p $target_dir/linux-headers + case "$target_name" in i386|x86_64|x32) linux_arch=x86 ;; @@ -6865,6 +6872,9 @@ if test "$linux" = "yes" ; then mips64) linux_arch=mips ;; + arm) + linux_arch=arm + ;; *) # For most CPUs the kernel architecture name and QEMU CPU name match. linux_arch="$cpu" @@ -6872,15 +6882,11 @@ if test "$linux" = "yes" ; then esac # For non-KVM architectures we will not have asm headers if [ -e "$source_path/linux-headers/asm-$linux_arch" ]; then - symlink "$source_path/linux-headers/asm-$linux_arch" linux-headers/asm + symlink "$source_path/linux-headers/asm-$linux_arch" $target_dir/linux-headers/asm fi fi -for target in $target_list; do -target_dir="$target" -config_target_mak=$target_dir/config-target.mak -target_name=$(echo $target | cut -d '-' -f 1) -target_bigendian="no" + case "$target_name" in armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) diff --git a/exec.c b/exec.c index 022226b3be..7d0ae21704 100644 --- a/exec.c +++ b/exec.c @@ -85,6 +85,8 @@ static MemoryRegion *system_io; AddressSpace address_space_io; AddressSpace address_space_memory; +AddressSpace armv7m_space_memory; + MemoryRegion io_mem_rom, io_mem_notdirty; static MemoryRegion io_mem_unassigned; @@ -898,12 +900,12 @@ void cpu_address_space_init(CPUState *cpu, int asidx, const char *prefix, MemoryRegion *mr) { CPUAddressSpace *newas; - AddressSpace *as = g_new0(AddressSpace, 1); char *as_name; assert(mr); as_name = g_strdup_printf("%s-%d", prefix, cpu->cpu_index); - address_space_init(as, mr, as_name); + //armv7m_space_memory is only for cortex-m SCS memory region map + address_space_init(&armv7m_space_memory, mr, as_name); g_free(as_name); /* Target code should have set num_ases before calling us */ @@ -911,7 +913,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx, if (asidx == 0) { /* address space 0 gets the convenience alias */ - cpu->as = as; + cpu->as = &armv7m_space_memory; } /* KVM cannot currently support multiple address spaces. */ @@ -923,10 +925,10 @@ void cpu_address_space_init(CPUState *cpu, int asidx, newas = &cpu->cpu_ases[asidx]; newas->cpu = cpu; - newas->as = as; + newas->as = &armv7m_space_memory; if (tcg_enabled()) { newas->tcg_as_listener.commit = tcg_commit; - memory_listener_register(&newas->tcg_as_listener, as); + memory_listener_register(&newas->tcg_as_listener, &armv7m_space_memory); } } diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index c3946da317..880edd5b2c 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -37,6 +37,7 @@ #include "hw/misc/mps2-scc.h" #include "hw/devices.h" #include "net/net.h" +#include "sysemu/kvm.h" typedef enum MPS2FPGAType { FPGA_AN385, @@ -147,6 +148,8 @@ static void mps2_common_init(MachineState *machine) NULL, "mps.ram", 0x1000000); memory_region_add_subregion(system_memory, 0x21000000, &mms->psram); + kvm_register_fixed_memory_region("mps.ram", (uintptr_t) memory_region_get_ram_ptr(&mms->psram),0x1000000, 0); + switch (mmc->fpga_type) { case FPGA_AN385: make_ram(&mms->ssram1, "mps.ssram1", 0x0, 0x400000); @@ -164,9 +167,13 @@ static void mps2_common_init(MachineState *machine) break; case FPGA_AN511: make_ram(&mms->blockram, "mps.blockram", 0x0, 0x40000); + kvm_register_fixed_memory_region("mps.blockram", (uintptr_t) memory_region_get_ram_ptr(&mms->blockram),0x40000, 1); make_ram(&mms->ssram1, "mps.ssram1", 0x00400000, 0x00800000); + kvm_register_fixed_memory_region("mps.ssram1", (uintptr_t) memory_region_get_ram_ptr(&mms->ssram1),0x00800000, 1); make_ram(&mms->sram, "mps.sram", 0x20000000, 0x20000); + kvm_register_fixed_memory_region("mps.sram", (uintptr_t) memory_region_get_ram_ptr(&mms->sram),0x20000, 0); make_ram(&mms->ssram23, "mps.ssram23", 0x20400000, 0x400000); + kvm_register_fixed_memory_region("mps.ssram23", (uintptr_t) memory_region_get_ram_ptr(&mms->ssram23),0x400000, 0); break; default: g_assert_not_reached(); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index cd1e7f1729..d757ffca9d 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -363,7 +363,6 @@ static inline int nvic_exec_prio(NVICState *s) if (env->v7m.faultmask[M_REG_S]) { running = (env->v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) ? -3 : -1; } - /* consider priority of active handler */ return MIN(running, s->exception_prio); } @@ -400,8 +399,9 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure) bool armv7m_nvic_can_take_pending_exception(void *opaque) { NVICState *s = opaque; - - return nvic_exec_prio(s) > nvic_pending_prio(s); + const int running = nvic_exec_prio(s); + const int vectpending_prio = s->vectpending_prio; + return running > vectpending_prio; } int armv7m_nvic_raw_execution_priority(void *opaque) @@ -657,7 +657,7 @@ void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure) void armv7m_nvic_acknowledge_irq(void *opaque) { NVICState *s = (NVICState *)opaque; - CPUARMState *env = &s->cpu->env; + /* CPUARMState *env = &s->cpu->env; */ const int pending = s->vectpending; const int running = nvic_exec_prio(s); VecInfo *vec; @@ -672,7 +672,8 @@ void armv7m_nvic_acknowledge_irq(void *opaque) assert(vec->enabled); assert(vec->pending); - + // printf("check vectpending_prio=0x%x\n",s->vectpending_prio); + // printf("check running=0x%x\n",running); assert(s->vectpending_prio < running); trace_nvic_acknowledge_irq(pending, s->vectpending_prio); @@ -680,7 +681,9 @@ void armv7m_nvic_acknowledge_irq(void *opaque) vec->active = 1; vec->pending = 0; - write_v7m_exception(env, s->vectpending); + /*IoT s2e move to do_interrupt_v7m comment this function*/ + /* write_v7m_exception(env, s->vectpending); */ + nvic_irq_update(s); } diff --git a/include/exec/address-spaces.h b/include/exec/address-spaces.h index db8bfa9a92..d52346d5e4 100644 --- a/include/exec/address-spaces.h +++ b/include/exec/address-spaces.h @@ -34,6 +34,7 @@ MemoryRegion *get_system_memory(void); MemoryRegion *get_system_io(void); extern AddressSpace address_space_memory; +extern AddressSpace armv7m_space_memory; extern AddressSpace address_space_io; #endif diff --git a/include/nvic/nvic_interfaces.h b/include/nvic/nvic_interfaces.h new file mode 100644 index 0000000000..d609d5c486 --- /dev/null +++ b/include/nvic/nvic_interfaces.h @@ -0,0 +1,74 @@ +#include +/* Interface between CPU and Interrupt controller. */ +/** + * armv7m_nvic_set_pending: mark the specified exception as pending + * @opaque: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Marks the specified exception as pending. Note that we will assert() + * if @secure is true and @irq does not specify one of the fixed set + * of architecturally banked exceptions. + */ +void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); +/** + * armv7m_nvic_set_pending_derived: mark this derived exception as pending + * @opaque: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Similar to armv7m_nvic_set_pending(), but specifically for derived + * exceptions (exceptions generated in the course of trying to take + * a different exception). + */ +void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); +/** + * armv7m_nvic_get_pending_irq_info: return highest priority pending + * exception, and whether it targets Secure state + * @opaque: the NVIC + * @pirq: set to pending exception number + * @ptargets_secure: set to whether pending exception targets Secure + * + * This function writes the number of the highest priority pending + * exception (the one which would be made active by + * armv7m_nvic_acknowledge_irq()) to @pirq, and sets @ptargets_secure + * to true if the current highest priority pending exception should + * be taken to Secure state, false for NS. + */ +void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, + bool *ptargets_secure); +/** + * armv7m_nvic_acknowledge_irq: make highest priority pending exception active + * @opaque: the NVIC + * + * Move the current highest priority pending exception from the pending + * state to the active state, and update v7m.exception to indicate that + * it is the exception currently being handled. + */ +void armv7m_nvic_acknowledge_irq(void *opaque); +/** + * armv7m_nvic_complete_irq: complete specified interrupt or exception + * @opaque: the NVIC + * @irq: the exception number to complete + * @secure: true if this exception was secure + * + * Returns: -1 if the irq was not active + * 1 if completing this irq brought us back to base (no active irqs) + * 0 if there is still an irq active after this one was completed + * (Ignoring -1, this is the same as the RETTOBASE value before completion.) + */ +int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); + +/* Interface between CPU and Interrupt controller. */ +#ifndef CONFIG_USER_ONLY +bool armv7m_nvic_can_take_pending_exception(void *opaque); +#else +static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) +{ + return true; +} +#endif diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index 72aa226e6c..794b414830 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -22,7 +22,7 @@ #include #include -#include +#include #define __KVM_HAVE_GUEST_DEBUG #define __KVM_HAVE_IRQ_LINE @@ -104,8 +104,23 @@ struct kvm_vcpu_init { __u32 target; __u32 features[7]; }; +struct kvm_m_regs { + __u32 regs[16]; +}; +struct kvm_m_sregs { + __u32 other_sp; + __u32 vecbase; + __u32 basepri; + __u32 control; + int current_sp; + int exception; + int pending_exception; + __u32 thumb; + void *nvic; +}; struct kvm_sregs { + }; struct kvm_fpu { diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 99cb9ad14a..c2d362f78e 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -106,7 +106,21 @@ struct kvm_vcpu_init { __u32 target; __u32 features[7]; }; +struct kvm_m_regs { + __u32 regs[16]; +}; +struct kvm_m_sregs { + __u32 other_sp; + __u32 vecbase; + __u32 basepri; + __u32 control; + int current_sp; + int exception; + int pending_exception; + __u32 thumb; + void *nvic; +}; struct kvm_sregs { }; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index f76e214fcf..5a0933345d 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -236,12 +236,16 @@ struct kvm_hyperv_exit { #define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_HYPERV 27 +/* ARM Cortex-m exit codes */ +#define KVM_EXIT_SYNC_ARM_V7M_SREGS 40 + /* Symbolic execution exit codes */ #define KVM_EXIT_FLUSH_DISK 100 #define KVM_EXIT_SAVE_DEV_STATE 101 #define KVM_EXIT_RESTORE_DEV_STATE 102 #define KVM_EXIT_CLONE_PROCESS 103 + /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ #define KVM_INTERNAL_ERROR_EMULATION 1 @@ -1331,6 +1335,12 @@ struct kvm_s390_ucas_mapping { #define KVM_SET_REGS _IOW(KVMIO, 0x82, struct kvm_regs) #define KVM_GET_SREGS _IOR(KVMIO, 0x83, struct kvm_sregs) #define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs) +/* ioctls for rw regs and sregs on ARM cortex-m */ +#define KVM_GET_M_REGS _IOR(KVMIO, 0xc0, struct kvm_m_regs) +#define KVM_SET_M_REGS _IOW(KVMIO, 0xc1, struct kvm_m_regs) +#define KVM_GET_M_SREGS _IOR(KVMIO, 0xc2, struct kvm_m_sregs) +#define KVM_SET_M_SREGS _IOW(KVMIO, 0xc3, struct kvm_m_sregs) + #define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation) #define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt) /* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */ diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 64a8005a4b..f6996d8ea1 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1023,7 +1023,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->core_count = smp_cpus; } #endif - + /* Before Sync arm cortex-m kvm vcpu, we need to reset cpu first to set the init regs.*/ + if (arm_feature(&cpu->env, ARM_FEATURE_M)){ + cpu_reset(cs); + } qemu_init_vcpu(cs); cpu_reset(cs); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e310ffc29d..8267465360 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -22,6 +22,7 @@ #include "kvm-consts.h" #include "hw/registerfields.h" +#include "nvic/nvic_interfaces.h" #if defined(TARGET_AARCH64) /* AArch64 definitions */ @@ -1628,15 +1629,17 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure); +// The following 6 interfaces move to nvic/nvic_interfaces, +// since S2E ARM CPU and qemu client both will invokes these functions. /* Interface between CPU and Interrupt controller. */ -#ifndef CONFIG_USER_ONLY -bool armv7m_nvic_can_take_pending_exception(void *opaque); -#else -static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) -{ - return true; -} -#endif +/* #ifndef CONFIG_USER_ONLY */ +// bool armv7m_nvic_can_take_pending_exception(void *opaque); +// #else +// static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) +// { + // return true; +// } +/* #endif */ /** * armv7m_nvic_set_pending: mark the specified exception as pending * @opaque: the NVIC @@ -1649,7 +1652,7 @@ static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) * if @secure is true and @irq does not specify one of the fixed set * of architecturally banked exceptions. */ -void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); +//void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); /** * armv7m_nvic_set_pending_derived: mark this derived exception as pending * @opaque: the NVIC @@ -1662,7 +1665,7 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); * exceptions (exceptions generated in the course of trying to take * a different exception). */ -void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); +//void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); /** * armv7m_nvic_get_pending_irq_info: return highest priority pending * exception, and whether it targets Secure state @@ -1676,8 +1679,8 @@ void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); * to true if the current highest priority pending exception should * be taken to Secure state, false for NS. */ -void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, - bool *ptargets_secure); +//void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, +// bool *ptargets_secure); /** * armv7m_nvic_acknowledge_irq: make highest priority pending exception active * @opaque: the NVIC @@ -1686,7 +1689,7 @@ void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, * state to the active state, and update v7m.exception to indicate that * it is the exception currently being handled. */ -void armv7m_nvic_acknowledge_irq(void *opaque); +//void armv7m_nvic_acknowledge_irq(void *opaque); /** * armv7m_nvic_complete_irq: complete specified interrupt or exception * @opaque: the NVIC @@ -1698,7 +1701,7 @@ void armv7m_nvic_acknowledge_irq(void *opaque); * 0 if there is still an irq active after this one was completed * (Ignoring -1, this is the same as the RETTOBASE value before completion.) */ -int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); +//int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure); /** * armv7m_nvic_raw_execution_priority: return the raw execution priority * @opaque: the NVIC diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 65f867d569..d20e864606 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -37,6 +37,48 @@ static bool cap_has_mp_state; static ARMHostCPUFeatures arm_host_cpu_features; +int kvm_cortex_m_vcpu_init(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + struct kvm_m_regs regs; + struct kvm_m_sregs sregs; + + memcpy(regs.regs,env->regs,sizeof(regs.regs)); + sregs.thumb = env->thumb; + sregs.vecbase = env->v7m.vecbase[0]; + sregs.other_sp = env->v7m.other_sp; + sregs.basepri = env->v7m.basepri[0]; + sregs.control = env->v7m.control[0]; + sregs.exception = env->v7m.exception; + sregs.nvic = env->nvic; + + kvm_vcpu_ioctl(cs, KVM_SET_M_REGS, ®s); + kvm_vcpu_ioctl(cs, KVM_SET_M_SREGS, &sregs); + return 0; +} + +int kvm_cortex_m_get_regs(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env=&cpu->env; + + struct kvm_m_regs regs; + struct kvm_m_sregs sregs; + + kvm_vcpu_ioctl(cs, KVM_GET_M_REGS, ®s); + kvm_vcpu_ioctl(cs, KVM_GET_M_SREGS, &sregs); + memcpy(env->regs,regs.regs,sizeof(regs.regs)); + + env->v7m.vecbase[0] = sregs.vecbase; + env->v7m.other_sp = sregs.other_sp; + env->v7m.basepri[0] = sregs.basepri; + env->v7m.control[0] = sregs.control; + env->v7m.exception = sregs.exception; + return 0; +} + int kvm_arm_vcpu_init(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); @@ -470,14 +512,20 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu) /* Re-init VCPU so that all registers are set to * their respective reset values. */ - ret = kvm_arm_vcpu_init(CPU(cpu)); - if (ret < 0) { - fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret)); - abort(); + if (arm_feature(&cpu->env, ARM_FEATURE_M)){ + ret = kvm_cortex_m_vcpu_init(CPU(cpu)); } - if (!write_kvmstate_to_list(cpu)) { - fprintf(stderr, "write_kvmstate_to_list failed\n"); - abort(); + else { + ret = kvm_arm_vcpu_init(CPU(cpu)); + if (ret < 0) { + fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret)); + abort(); + } + if (!write_kvmstate_to_list(cpu)) { + fprintf(stderr, "write_kvmstate_to_list failed\n"); + abort(); + } + } } diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index 4e91c11796..fc81c37c92 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -173,51 +173,58 @@ int kvm_arch_init_vcpu(CPUState *cs) struct kvm_one_reg r; ARMCPU *cpu = ARM_CPU(cs); - if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) { - fprintf(stderr, "KVM is not supported for this guest CPU type\n"); - return -EINVAL; + if (arm_feature(&cpu->env, ARM_FEATURE_M)) { + return kvm_cortex_m_vcpu_init(cs); } + else { + if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) { + fprintf(stderr, "KVM is not supported for this guest CPU type\n"); + return -EINVAL; + } - /* Determine init features for this CPU */ - memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); - if (cpu->start_powered_off) { - cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF; - } - if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) { - cpu->psci_version = 2; - cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; - } + /* Determine init features for this CPU */ + memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); + if (cpu->start_powered_off) { + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF; + } + if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) { + cpu->psci_version = 2; + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; + } - /* Do KVM_ARM_VCPU_INIT ioctl */ - ret = kvm_arm_vcpu_init(cs); - if (ret) { - return ret; - } + /* Do KVM_ARM_VCPU_INIT ioctl */ + ret = kvm_arm_vcpu_init(cs); + if (ret) { + return ret; + } - /* Query the kernel to make sure it supports 32 VFP - * registers: QEMU's "cortex-a15" CPU is always a - * VFP-D32 core. The simplest way to do this is just - * to attempt to read register d31. - */ - r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31; - r.addr = (uintptr_t)(&v); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); - if (ret == -ENOENT) { - return -EINVAL; - } + /* Query the kernel to make sure it supports 32 VFP + * registers: QEMU's "cortex-a15" CPU is always a + * VFP-D32 core. The simplest way to do this is just + * to attempt to read register d31. + */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31; + r.addr = (uintptr_t)(&v); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret == -ENOENT) { + return -EINVAL; + } - /* - * When KVM is in use, PSCI is emulated in-kernel and not by qemu. - * Currently KVM has its own idea about MPIDR assignment, so we - * override our defaults with what we get from KVM. - */ - ret = kvm_get_one_reg(cs, ARM_CP15_REG32(ARM_CPU_ID_MPIDR), &mpidr); - if (ret) { - return ret; - } - cpu->mp_affinity = mpidr & ARM32_AFFINITY_MASK; + /* + * When KVM is in use, PSCI is emulated in-kernel and not by qemu. + * Currently KVM has its own idea about MPIDR assignment, so we + * override our defaults with what we get from KVM. + */ + ret = kvm_get_one_reg(cs, ARM_CP15_REG32(ARM_CPU_ID_MPIDR), &mpidr); + if (ret) { + return ret; + } + cpu->mp_affinity = mpidr & ARM32_AFFINITY_MASK; - return kvm_arm_init_cpreg_list(cpu); + return kvm_arm_init_cpreg_list(cpu); + + } + return -1; } typedef struct Reg { @@ -306,83 +313,87 @@ int kvm_arch_put_registers(CPUState *cs, int level) int ret, i; uint32_t cpsr, fpscr; - /* Make sure the banked regs are properly set */ - mode = env->uncached_cpsr & CPSR_M; - bn = bank_number(mode); - if (mode == ARM_CPU_MODE_FIQ) { - memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + if (arm_feature(&cpu->env, ARM_FEATURE_M)) { + return kvm_cortex_m_vcpu_init(cs); } else { - memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); - } - env->banked_r13[bn] = env->regs[13]; - env->banked_r14[bn] = env->regs[14]; - env->banked_spsr[bn] = env->spsr; - - /* Now we can safely copy stuff down to the kernel */ - for (i = 0; i < ARRAY_SIZE(regs); i++) { - r.id = regs[i].id; - r.addr = (uintptr_t)(env) + regs[i].offset; + /* Make sure the banked regs are properly set */ + mode = env->uncached_cpsr & CPSR_M; + bn = bank_number(mode); + if (mode == ARM_CPU_MODE_FIQ) { + memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + } else { + memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + } + env->banked_r13[bn] = env->regs[13]; + env->banked_r14[bn] = env->regs[14]; + env->banked_spsr[bn] = env->spsr; + + /* Now we can safely copy stuff down to the kernel */ + for (i = 0; i < ARRAY_SIZE(regs); i++) { + r.id = regs[i].id; + r.addr = (uintptr_t)(env) + regs[i].offset; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + } + + /* Special cases which aren't a single CPUARMState field */ + cpsr = cpsr_read(env); + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr); + r.addr = (uintptr_t)(&cpsr); ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); if (ret) { return ret; } - } - /* Special cases which aren't a single CPUARMState field */ - cpsr = cpsr_read(env); - r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | - KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr); - r.addr = (uintptr_t)(&cpsr); - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); - if (ret) { - return ret; - } + /* VFP registers */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; + for (i = 0; i < 32; i++) { + r.addr = (uintptr_t)aa32_vfp_dreg(env, i); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + r.id++; + } - /* VFP registers */ - r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; - for (i = 0; i < 32; i++) { - r.addr = (uintptr_t)aa32_vfp_dreg(env, i); + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | + KVM_REG_ARM_VFP_FPSCR; + fpscr = vfp_get_fpscr(env); + r.addr = (uintptr_t)&fpscr; ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); if (ret) { return ret; } - r.id++; - } - - r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | - KVM_REG_ARM_VFP_FPSCR; - fpscr = vfp_get_fpscr(env); - r.addr = (uintptr_t)&fpscr; - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); - if (ret) { - return ret; - } - /* Note that we do not call write_cpustate_to_list() - * here, so we are only writing the tuple list back to - * KVM. This is safe because nothing can change the - * CPUARMState cp15 fields (in particular gdb accesses cannot) - * and so there are no changes to sync. In fact syncing would - * be wrong at this point: for a constant register where TCG and - * KVM disagree about its value, the preceding write_list_to_cpustate() - * would not have had any effect on the CPUARMState value (since the - * register is read-only), and a write_cpustate_to_list() here would - * then try to write the TCG value back into KVM -- this would either - * fail or incorrectly change the value the guest sees. - * - * If we ever want to allow the user to modify cp15 registers via - * the gdb stub, we would need to be more clever here (for instance - * tracking the set of registers kvm_arch_get_registers() successfully - * managed to update the CPUARMState with, and only allowing those - * to be written back up into the kernel). - */ - if (!write_list_to_kvmstate(cpu, level)) { - return EINVAL; - } + /* Note that we do not call write_cpustate_to_list() + * here, so we are only writing the tuple list back to + * KVM. This is safe because nothing can change the + * CPUARMState cp15 fields (in particular gdb accesses cannot) + * and so there are no changes to sync. In fact syncing would + * be wrong at this point: for a constant register where TCG and + * KVM disagree about its value, the preceding write_list_to_cpustate() + * would not have had any effect on the CPUARMState value (since the + * register is read-only), and a write_cpustate_to_list() here would + * then try to write the TCG value back into KVM -- this would either + * fail or incorrectly change the value the guest sees. + * + * If we ever want to allow the user to modify cp15 registers via + * the gdb stub, we would need to be more clever here (for instance + * tracking the set of registers kvm_arch_get_registers() successfully + * managed to update the CPUARMState with, and only allowing those + * to be written back up into the kernel). + */ + if (!write_list_to_kvmstate(cpu, level)) { + return EINVAL; + } - kvm_arm_sync_mpstate_to_kvm(cpu); + kvm_arm_sync_mpstate_to_kvm(cpu); - return ret; + return ret; + } } int kvm_arch_get_registers(CPUState *cs) @@ -394,68 +405,73 @@ int kvm_arch_get_registers(CPUState *cs) int ret, i; uint32_t cpsr, fpscr; - for (i = 0; i < ARRAY_SIZE(regs); i++) { - r.id = regs[i].id; - r.addr = (uintptr_t)(env) + regs[i].offset; + if (arm_feature(&cpu->env, ARM_FEATURE_M)) { + return kvm_cortex_m_get_regs(cs); + } else { + for (i = 0; i < ARRAY_SIZE(regs); i++) { + r.id = regs[i].id; + r.addr = (uintptr_t)(env) + regs[i].offset; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + } + + /* Special cases which aren't a single CPUARMState field */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr); + r.addr = (uintptr_t)(&cpsr); ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); if (ret) { return ret; } - } - - /* Special cases which aren't a single CPUARMState field */ - r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | - KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr); - r.addr = (uintptr_t)(&cpsr); - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); - if (ret) { - return ret; - } - cpsr_write(env, cpsr, 0xffffffff, CPSRWriteRaw); + cpsr_write(env, cpsr, 0xffffffff, CPSRWriteRaw); + + /* Make sure the current mode regs are properly set */ + mode = env->uncached_cpsr & CPSR_M; + bn = bank_number(mode); + if (mode == ARM_CPU_MODE_FIQ) { + memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); + } else { + memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); + } + env->regs[13] = env->banked_r13[bn]; + env->regs[14] = env->banked_r14[bn]; + env->spsr = env->banked_spsr[bn]; + + /* VFP registers */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; + for (i = 0; i < 32; i++) { + r.addr = (uintptr_t)aa32_vfp_dreg(env, i); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + r.id++; + } - /* Make sure the current mode regs are properly set */ - mode = env->uncached_cpsr & CPSR_M; - bn = bank_number(mode); - if (mode == ARM_CPU_MODE_FIQ) { - memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); - } else { - memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); - } - env->regs[13] = env->banked_r13[bn]; - env->regs[14] = env->banked_r14[bn]; - env->spsr = env->banked_spsr[bn]; - - /* VFP registers */ - r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; - for (i = 0; i < 32; i++) { - r.addr = (uintptr_t)aa32_vfp_dreg(env, i); + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | + KVM_REG_ARM_VFP_FPSCR; + r.addr = (uintptr_t)&fpscr; ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); if (ret) { return ret; } - r.id++; - } + vfp_set_fpscr(env, fpscr); - r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | - KVM_REG_ARM_VFP_FPSCR; - r.addr = (uintptr_t)&fpscr; - ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); - if (ret) { - return ret; - } - vfp_set_fpscr(env, fpscr); + if (!write_kvmstate_to_list(cpu)) { + return EINVAL; + } - if (!write_kvmstate_to_list(cpu)) { - return EINVAL; - } - /* Note that it's OK to have registers which aren't in CPUState, - * so we can ignore a failure return here. - */ - write_list_to_cpustate(cpu); + /* Note that it's OK to have registers which aren't in CPUState, + * so we can ignore a failure return here. + */ + write_list_to_cpustate(cpu); - kvm_arm_sync_mpstate_to_qemu(cpu); + kvm_arm_sync_mpstate_to_qemu(cpu); - return 0; + return 0; + } } int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 863f205822..7527779815 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -15,6 +15,28 @@ #include "exec/memory.h" #include "qemu/error-report.h" +/** + * kvm_cortex_m_vcpu_init: + * @env: CPUARMState + * + * Initialize (or reinitialize) the cotex-m VCPU by invoking the + * cotex-m reg write ioctl with the CPUARMState + * + * Returns: 0 if success else < 0 error code + */ +int kvm_cortex_m_vcpu_init(CPUState *cs); + +/** + * kvm_cortex_m_vcpu_sync + * @env: CPUARMState + * + * get the cotex-m VCPU regs by invoking the + * cotex-m reg read ioctl with the CPUARMState + * + * Returns: 0 if success else < 0 error code + */ +int kvm_cortex_m_get_regs(CPUState *cs); + /** * kvm_arm_vcpu_init: * @cs: CPUState diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index a91e4f1313..56ff636f3b 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -3397,7 +3397,9 @@ static const int tcg_target_callee_save_regs[] = { #define PUSH_SIZE \ ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \ * (TCG_TARGET_REG_BITS / 8)) - +#ifdef FRAME_SIZE + #undef FRAME_SIZE +#endif /* endif FRAME_SIZE*/ #define FRAME_SIZE \ ((PUSH_SIZE \ + TCG_STATIC_CALL_ARGS_SIZE \