diff options
Diffstat (limited to 'include')
54 files changed, 1191 insertions, 358 deletions
diff --git a/include/block/aio.h b/include/block/aio.h index cc77771c46..2efdf416cf 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -14,10 +14,12 @@ #ifndef QEMU_AIO_H #define QEMU_AIO_H +#include "qemu/typedefs.h" #include "qemu-common.h" #include "qemu/queue.h" #include "qemu/event_notifier.h" #include "qemu/thread.h" +#include "qemu/timer.h" typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); @@ -42,7 +44,7 @@ typedef struct AioHandler AioHandler; typedef void QEMUBHFunc(void *opaque); typedef void IOHandler(void *opaque); -typedef struct AioContext { +struct AioContext { GSource source; /* The list of registered AIO handlers */ @@ -72,10 +74,10 @@ typedef struct AioContext { /* Thread pool for performing work and receiving completion callbacks */ struct ThreadPool *thread_pool; -} AioContext; -/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ -typedef int (AioFlushEventNotifierHandler)(EventNotifier *e); + /* TimerLists for calling timers - one per clock type */ + QEMUTimerListGroup tlg; +}; /** * aio_context_new: Allocate a new AioContext. @@ -198,9 +200,6 @@ bool aio_pending(AioContext *ctx); bool aio_poll(AioContext *ctx, bool blocking); #ifdef CONFIG_POSIX -/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ -typedef int (AioFlushHandler)(void *opaque); - /* Register a file descriptor and associated callbacks. Behaves very similarly * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will * be invoked when using qemu_aio_wait(). @@ -212,7 +211,6 @@ void aio_set_fd_handler(AioContext *ctx, int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque); #endif @@ -225,8 +223,7 @@ void aio_set_fd_handler(AioContext *ctx, */ void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush); + EventNotifierHandler *io_read); /* Return a GSource that lets the main loop poll the file descriptors attached * to this AioContext. @@ -240,15 +237,56 @@ struct ThreadPool *aio_get_thread_pool(AioContext *ctx); bool qemu_aio_wait(void); void qemu_aio_set_event_notifier(EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush); + EventNotifierHandler *io_read); #ifdef CONFIG_POSIX void qemu_aio_set_fd_handler(int fd, IOHandler *io_read, IOHandler *io_write, - AioFlushHandler *io_flush, void *opaque); #endif +/** + * aio_timer_new: + * @ctx: the aio context + * @type: the clock type + * @scale: the scale + * @cb: the callback to call on timer expiry + * @opaque: the opaque pointer to pass to the callback + * + * Allocate a new timer attached to the context @ctx. + * The function is responsible for memory allocation. + * + * The preferred interface is aio_timer_init. Use that + * unless you really need dynamic memory allocation. + * + * Returns: a pointer to the new timer + */ +static inline QEMUTimer *aio_timer_new(AioContext *ctx, QEMUClockType type, + int scale, + QEMUTimerCB *cb, void *opaque) +{ + return timer_new_tl(ctx->tlg.tl[type], scale, cb, opaque); +} + +/** + * aio_timer_init: + * @ctx: the aio context + * @ts: the timer + * @type: the clock type + * @scale: the scale + * @cb: the callback to call on timer expiry + * @opaque: the opaque pointer to pass to the callback + * + * Initialise a new timer attached to the context @ctx. + * The caller is responsible for memory allocation. + */ +static inline void aio_timer_init(AioContext *ctx, + QEMUTimer *ts, QEMUClockType type, + int scale, + QEMUTimerCB *cb, void *opaque) +{ + timer_init(ts, ctx->tlg.tl[type], scale, cb, opaque); +} + #endif diff --git a/include/block/block_int.h b/include/block/block_int.h index c6ac871e21..8012e253c9 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -34,6 +34,7 @@ #include "monitor/monitor.h" #include "qemu/hbitmap.h" #include "block/snapshot.h" +#include "qemu/main-loop.h" #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 @@ -281,6 +282,9 @@ struct BlockDriverState { /* Whether the disk can expand beyond total_sectors */ int growable; + /* Whether produces zeros when read beyond eof */ + bool zero_beyond_eof; + /* the memory alignment required for the buffers handled by this driver */ int buffer_alignment; @@ -404,6 +408,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, * @bs: Block device to operate on. * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @sync_mode: What parts of the disk image should be copied to the destination. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. * @cb: Completion function for the job. @@ -413,7 +418,8 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, * until the job is cancelled or manually completed. */ void backup_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, BlockdevOnError on_source_error, + int64_t speed, MirrorSyncMode sync_mode, + BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); diff --git a/include/block/blockjob.h b/include/block/blockjob.h index c290d07bba..d530409ff5 100644 --- a/include/block/blockjob.h +++ b/include/block/blockjob.h @@ -141,7 +141,7 @@ void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, * Put the job to sleep (assuming that it wasn't canceled) for @ns * nanoseconds. Canceling the job will interrupt the wait immediately. */ -void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); +void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns); /** * block_job_completed: diff --git a/include/block/coroutine.h b/include/block/coroutine.h index 377805a3b0..4232569c53 100644 --- a/include/block/coroutine.h +++ b/include/block/coroutine.h @@ -16,6 +16,7 @@ #define QEMU_COROUTINE_H #include <stdbool.h> +#include "qemu/typedefs.h" #include "qemu/queue.h" #include "qemu/timer.h" @@ -130,12 +131,17 @@ void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue); * * Returns true if a coroutine was restarted, false if the queue is empty. */ -bool qemu_co_queue_next(CoQueue *queue); +bool coroutine_fn qemu_co_queue_next(CoQueue *queue); /** * Restarts all coroutines in the CoQueue and leaves the queue empty. */ -void qemu_co_queue_restart_all(CoQueue *queue); +void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue); + +/** + * Enter the next coroutine in the queue + */ +bool qemu_co_enter_next(CoQueue *queue); /** * Checks if the CoQueue is empty. @@ -207,7 +213,7 @@ void qemu_co_rwlock_unlock(CoRwlock *lock); * Note this function uses timers and hence only works when a main loop is in * use. See main-loop.h and do not use from qemu-tool programs. */ -void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns); +void coroutine_fn co_sleep_ns(QEMUClockType type, int64_t ns); /** * Yield until a file descriptor becomes readable diff --git a/include/elf.h b/include/elf.h index cf0d3e2bd6..58bfbf8817 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1348,11 +1348,17 @@ typedef struct elf64_shdr { /* Notes used in ET_CORE */ #define NT_PRSTATUS 1 +#define NT_FPREGSET 2 #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 #define NT_AUXV 6 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ /* Note header in a PT_NOTE section */ diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f2800ec682..a407b50f4a 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -210,11 +210,15 @@ extern unsigned long reserved_va; }) #endif -#define h2g(x) ({ \ +#define h2g_nocheck(x) ({ \ unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \ + (abi_ulong)__ret; \ +}) + +#define h2g(x) ({ \ /* Check if given address fits target address space */ \ assert(h2g_valid(x)); \ - (abi_ulong)__ret; \ + h2g_nocheck(x); \ }) #define saddr(x) g2h(x) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index b5b93db842..a5c028c536 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -154,8 +154,6 @@ typedef struct CPUWatchpoint { memory was accessed */ \ CPU_COMMON_TLB \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ - /* buffer for temporaries in the code generator */ \ - long temp_buf[CPU_TEMP_BUF_NLONGS]; \ \ int64_t icount_extra; /* Instructions until next timer event. */ \ /* Number of cycles left, with interrupt flag in high bit. \ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index b2162a4ec4..ffb69a4c70 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -326,18 +326,7 @@ extern uintptr_t tci_tb_ptr; (6) jump to corresponding code of the next of fast path */ # if defined(__i386__) || defined(__x86_64__) -/* To avoid broken disassembling, long jmp is used for embedding fast path pc, - so that the destination is the next code of fast path, though this jmp is - never executed. - - call MMU helper - jmp POST_PROC (2byte) <- GETRA() - jmp NEXT_CODE (5byte) - POST_PROCESS ... <- GETRA() + 7 - */ -# define GETRA() ((uintptr_t)__builtin_return_address(0)) -# define GETPC_LDST() ((uintptr_t)(GETRA() + 7 + \ - *(int32_t *)((void *)GETRA() + 3) - 1)) +# define GETPC_EXT() GETPC() # elif defined (_ARCH_PPC) && !defined (_ARCH_PPC64) # define GETRA() ((uintptr_t)__builtin_return_address(0)) # define GETPC_LDST() ((uintptr_t) ((*(int32_t *)(GETRA() - 4)) - 1)) @@ -358,11 +347,27 @@ static inline uintptr_t tcg_getpc_ldst(uintptr_t ra) not the start of the next opcode */ return ra; } +# elif defined(__aarch64__) +# define GETRA() ((uintptr_t)__builtin_return_address(0)) +# define GETPC_LDST() tcg_getpc_ldst(GETRA()) +static inline uintptr_t tcg_getpc_ldst(uintptr_t ra) +{ + int32_t b; + ra += 4; /* skip one instruction */ + b = *(int32_t *)ra; /* load the branch insn */ + b = (b << 6) >> (6 - 2); /* extract the displacement */ + ra += b; /* apply the displacement */ + ra -= 4; /* return a pointer into the current opcode, + not the start of the next opcode */ + return ra; +} # else # error "CONFIG_QEMU_LDST_OPTIMIZATION needs GETPC_LDST() implementation!" # endif bool is_tcg_gen_code(uintptr_t pc_ptr); -# define GETPC_EXT() (is_tcg_gen_code(GETRA()) ? GETPC_LDST() : GETPC()) +# ifndef GETPC_EXT +# define GETPC_EXT() (is_tcg_gen_code(GETRA()) ? GETPC_LDST() : GETPC()) +# endif #else # define GETPC_EXT() GETPC() #endif diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 1bd00aea23..a608a26c30 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -32,13 +32,50 @@ void gdb_register_coprocessor(CPUState *cpu, static inline int cpu_index(CPUState *cpu) { -#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) +#if defined(CONFIG_USER_ONLY) return cpu->host_tid; #else return cpu->cpu_index + 1; #endif } +/* The GDB remote protocol transfers values in target byte order. This means + * we can use the raw memory access routines to access the value buffer. + * Conveniently, these also handle the case where the buffer is mis-aligned. + */ + +static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val) +{ + stb_p(mem_buf, val); + return 1; +} + +static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val) +{ + stw_p(mem_buf, val); + return 2; +} + +static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val) +{ + stl_p(mem_buf, val); + return 4; +} + +static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val) +{ + stq_p(mem_buf, val); + return 8; +} + +#if TARGET_LONG_BITS == 64 +#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val) +#define ldtul_p(addr) ldq_p(addr) +#else +#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val) +#define ldtul_p(addr) ldl_p(addr) +#endif + #endif #ifdef CONFIG_USER_ONLY @@ -47,6 +84,14 @@ int gdbserver_start(int); int gdbserver_start(const char *port); #endif +/** + * gdb_has_xml: + * This is an ugly hack to cope with both new and old gdb. + * If gdb sends qXfer:features:read then assume we're talking to a newish + * gdb that understands target descriptions. + */ +extern bool gdb_has_xml; + /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ extern const char *const xml_builtin[][2]; diff --git a/include/exec/poison.h b/include/exec/poison.h index 2341a75041..a4b1eca24f 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -36,7 +36,6 @@ #pragma GCC poison TARGET_PAGE_ALIGN #pragma GCC poison CPUArchState -#pragma GCC poison env #pragma GCC poison lduw_phys #pragma GCC poison ldl_phys diff --git a/include/exec/softmmu_defs.h b/include/exec/softmmu_defs.h index 1f25e33ce4..e55e7178c6 100644 --- a/include/exec/softmmu_defs.h +++ b/include/exec/softmmu_defs.h @@ -9,29 +9,41 @@ #ifndef SOFTMMU_DEFS_H #define SOFTMMU_DEFS_H +uint8_t helper_ret_ldb_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); +uint16_t helper_ret_ldw_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); +uint32_t helper_ret_ldl_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); +uint64_t helper_ret_ldq_mmu(CPUArchState *env, target_ulong addr, + int mmu_idx, uintptr_t retaddr); + +void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, + int mmu_idx, uintptr_t retaddr); +void helper_ret_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, + int mmu_idx, uintptr_t retaddr); +void helper_ret_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx, uintptr_t retaddr); +void helper_ret_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx, uintptr_t retaddr); + uint8_t helper_ldb_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, - int mmu_idx); uint16_t helper_ldw_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, - int mmu_idx); uint32_t helper_ldl_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, - int mmu_idx); uint64_t helper_ldq_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, - int mmu_idx); + +void helper_stb_mmu(CPUArchState *env, target_ulong addr, + uint8_t val, int mmu_idx); +void helper_stw_mmu(CPUArchState *env, target_ulong addr, + uint16_t val, int mmu_idx); +void helper_stl_mmu(CPUArchState *env, target_ulong addr, + uint32_t val, int mmu_idx); +void helper_stq_mmu(CPUArchState *env, target_ulong addr, + uint64_t val, int mmu_idx); uint8_t helper_ldb_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stb_cmmu(CPUArchState *env, target_ulong addr, uint8_t val, -int mmu_idx); uint16_t helper_ldw_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stw_cmmu(CPUArchState *env, target_ulong addr, uint16_t val, - int mmu_idx); uint32_t helper_ldl_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stl_cmmu(CPUArchState *env, target_ulong addr, uint32_t val, - int mmu_idx); uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); -void helper_stq_cmmu(CPUArchState *env, target_ulong addr, uint64_t val, - int mmu_idx); -#endif + +#endif /* SOFTMMU_DEFS_H */ diff --git a/include/exec/softmmu_template.h b/include/exec/softmmu_template.h index 8584902cbe..eaca9e1035 100644 --- a/include/exec/softmmu_template.h +++ b/include/exec/softmmu_template.h @@ -54,10 +54,6 @@ #define ADDR_READ addr_read #endif -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - int mmu_idx, - uintptr_t retaddr); static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, hwaddr physaddr, target_ulong addr, @@ -78,123 +74,86 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, } /* handle all cases except unaligned access which span two pages */ +#ifdef SOFTMMU_CODE_ACCESS +static +#endif DATA_TYPE -glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, - int mmu_idx) +glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, int mmu_idx, + uintptr_t retaddr) { - DATA_TYPE res; - int index; - target_ulong tlb_addr; - hwaddr ioaddr; - uintptr_t retaddr; + int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; + uintptr_t haddr; - /* test if there is match for unaligned or IO access */ - /* XXX: could done more in memory macro in a non portable way */ - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - retaddr = GETPC_EXT(); - ioaddr = env->iotlb[mmu_idx][index]; - res = glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - /* slow unaligned access (it spans two pages or IO) */ - do_unaligned_access: - retaddr = GETPC_EXT(); + /* If the TLB entry is for a different page, reload and try again. */ + if ((addr & TARGET_PAGE_MASK) + != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); -#endif - res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr, - mmu_idx, retaddr); - } else { - /* unaligned/aligned access in the same page */ - uintptr_t addend; -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) { - retaddr = GETPC_EXT(); - do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); - } -#endif - addend = env->tlb_table[mmu_idx][index].addend; - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend)); } - } else { - /* the page is not in the TLB : fill it */ - retaddr = GETPC_EXT(); -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); #endif tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); - goto redo; + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; } - return res; -} -/* handle all unaligned cases */ -static DATA_TYPE -glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - int mmu_idx, - uintptr_t retaddr) -{ - DATA_TYPE res, res1, res2; - int index, shift; - hwaddr ioaddr; - target_ulong tlb_addr, addr1, addr2; + /* Handle an IO access. */ + if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { + hwaddr ioaddr; + if ((addr & (DATA_SIZE - 1)) != 0) { + goto do_unaligned_access; + } + ioaddr = env->iotlb[mmu_idx][index]; + return glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); + } - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - ioaddr = env->iotlb[mmu_idx][index]; - res = glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - do_unaligned_access: - /* slow unaligned access (it spans two pages) */ - addr1 = addr & ~(DATA_SIZE - 1); - addr2 = addr1 + DATA_SIZE; - res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr1, - mmu_idx, retaddr); - res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr2, - mmu_idx, retaddr); - shift = (addr & (DATA_SIZE - 1)) * 8; + /* Handle slow unaligned access (it spans two pages or IO). */ + if (DATA_SIZE > 1 + && unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1 + >= TARGET_PAGE_SIZE)) { + target_ulong addr1, addr2; + DATA_TYPE res1, res2, res; + unsigned shift; + do_unaligned_access: +#ifdef ALIGNED_ONLY + do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); +#endif + addr1 = addr & ~(DATA_SIZE - 1); + addr2 = addr1 + DATA_SIZE; + res1 = glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(env, addr1, + mmu_idx, retaddr); + res2 = glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(env, addr2, + mmu_idx, retaddr); + shift = (addr & (DATA_SIZE - 1)) * 8; #ifdef TARGET_WORDS_BIGENDIAN - res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); + res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); #else - res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); + res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); #endif - res = (DATA_TYPE)res; - } else { - /* unaligned/aligned access in the same page */ - uintptr_t addend = env->tlb_table[mmu_idx][index].addend; - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend)); - } - } else { - /* the page is not in the TLB : fill it */ - tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); - goto redo; + return res; + } + + /* Handle aligned access or unaligned access in the same page. */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } - return res; +#endif + + haddr = addr + env->tlb_table[mmu_idx][index].addend; + return glue(glue(ld, USUFFIX), _raw)((uint8_t *)haddr); } -#ifndef SOFTMMU_CODE_ACCESS +DATA_TYPE +glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, + int mmu_idx) +{ + return glue(glue(helper_ret_ld, SUFFIX), MMUSUFFIX)(env, addr, mmu_idx, + GETPC_EXT()); +} -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - DATA_TYPE val, - int mmu_idx, - uintptr_t retaddr); +#ifndef SOFTMMU_CODE_ACCESS static inline void glue(io_write, SUFFIX)(CPUArchState *env, hwaddr physaddr, @@ -214,107 +173,79 @@ static inline void glue(io_write, SUFFIX)(CPUArchState *env, io_mem_write(mr, physaddr, val, 1 << SHIFT); } -void glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, DATA_TYPE val, - int mmu_idx) +void +glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, DATA_TYPE val, + int mmu_idx, uintptr_t retaddr) { - hwaddr ioaddr; - target_ulong tlb_addr; - uintptr_t retaddr; - int index; + int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + uintptr_t haddr; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - retaddr = GETPC_EXT(); - ioaddr = env->iotlb[mmu_idx][index]; - glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - do_unaligned_access: - retaddr = GETPC_EXT(); + /* If the TLB entry is for a different page, reload and try again. */ + if ((addr & TARGET_PAGE_MASK) + != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { do_unaligned_access(env, addr, 1, mmu_idx, retaddr); -#endif - glue(glue(slow_st, SUFFIX), MMUSUFFIX)(env, addr, val, - mmu_idx, retaddr); - } else { - /* aligned/unaligned access in the same page */ - uintptr_t addend; -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) { - retaddr = GETPC_EXT(); - do_unaligned_access(env, addr, 1, mmu_idx, retaddr); - } -#endif - addend = env->tlb_table[mmu_idx][index].addend; - glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend), val); } - } else { - /* the page is not in the TLB : fill it */ - retaddr = GETPC_EXT(); -#ifdef ALIGNED_ONLY - if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(env, addr, 1, mmu_idx, retaddr); #endif tlb_fill(env, addr, 1, mmu_idx, retaddr); - goto redo; + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; } -} -/* handles all unaligned cases */ -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, - target_ulong addr, - DATA_TYPE val, - int mmu_idx, - uintptr_t retaddr) -{ - hwaddr ioaddr; - target_ulong tlb_addr; - int index, i; + /* Handle an IO access. */ + if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { + hwaddr ioaddr; + if ((addr & (DATA_SIZE - 1)) != 0) { + goto do_unaligned_access; + } + ioaddr = env->iotlb[mmu_idx][index]; + glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); + return; + } - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - redo: - tlb_addr = env->tlb_table[mmu_idx][index].addr_write; - if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - if (tlb_addr & ~TARGET_PAGE_MASK) { - /* IO access */ - if ((addr & (DATA_SIZE - 1)) != 0) - goto do_unaligned_access; - ioaddr = env->iotlb[mmu_idx][index]; - glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); - } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { - do_unaligned_access: - /* XXX: not efficient, but simple */ - /* Note: relies on the fact that tlb_fill() does not remove the - * previous page from the TLB cache. */ - for(i = DATA_SIZE - 1; i >= 0; i--) { + /* Handle slow unaligned access (it spans two pages or IO). */ + if (DATA_SIZE > 1 + && unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1 + >= TARGET_PAGE_SIZE)) { + int i; + do_unaligned_access: +#ifdef ALIGNED_ONLY + do_unaligned_access(env, addr, 1, mmu_idx, retaddr); +#endif + /* XXX: not efficient, but simple */ + /* Note: relies on the fact that tlb_fill() does not remove the + * previous page from the TLB cache. */ + for (i = DATA_SIZE - 1; i >= 0; i--) { #ifdef TARGET_WORDS_BIGENDIAN - glue(slow_stb, MMUSUFFIX)(env, addr + i, - val >> (((DATA_SIZE - 1) * 8) - (i * 8)), - mmu_idx, retaddr); + uint8_t val8 = val >> (((DATA_SIZE - 1) * 8) - (i * 8)); #else - glue(slow_stb, MMUSUFFIX)(env, addr + i, - val >> (i * 8), - mmu_idx, retaddr); + uint8_t val8 = val >> (i * 8); #endif - } - } else { - /* aligned/unaligned access in the same page */ - uintptr_t addend = env->tlb_table[mmu_idx][index].addend; - glue(glue(st, SUFFIX), _raw)((uint8_t *)(intptr_t) - (addr + addend), val); + glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8, + mmu_idx, retaddr); } - } else { - /* the page is not in the TLB : fill it */ - tlb_fill(env, addr, 1, mmu_idx, retaddr); - goto redo; + return; + } + + /* Handle aligned access or unaligned access in the same page. */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + do_unaligned_access(env, addr, 1, mmu_idx, retaddr); } +#endif + + haddr = addr + env->tlb_table[mmu_idx][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)haddr, val); +} + +void +glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, + DATA_TYPE val, int mmu_idx) +{ + glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)(env, addr, val, mmu_idx, + GETPC_EXT()); } #endif /* !defined(SOFTMMU_CODE_ACCESS) */ diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index 635be7be10..51733d3390 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -136,7 +136,7 @@ void acpi_pm_tmr_reset(ACPIREGS *ar); #include "qemu/timer.h" static inline int64_t acpi_pm_tmr_get_clock(void) { - return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, get_ticks_per_sec()); } diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h index bae87c6273..ecbbba871e 100644 --- a/include/hw/arm/arm.h +++ b/include/hw/arm/arm.h @@ -14,11 +14,6 @@ #include "exec/memory.h" #include "hw/irq.h" -/* The CPU is also modelled as an interrupt controller. */ -#define ARM_PIC_CPU_IRQ 0 -#define ARM_PIC_CPU_FIQ 1 -qemu_irq *arm_pic_init_cpu(ARMCPU *cpu); - /* armv7m.c */ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, int flash_size, int sram_size, diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h index bda3213317..2742d70ea0 100644 --- a/include/hw/char/escc.h +++ b/include/hw/char/escc.h @@ -2,6 +2,7 @@ #define HW_ESCC_H 1 /* escc.c */ +#define TYPE_ESCC "escc" #define ESCC_SIZE 4 MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, CharDriverState *chrA, CharDriverState *chrB, diff --git a/include/hw/lm32/lm32_juart.h b/include/hw/char/lm32_juart.h index 67fc5866ea..70dc416e9f 100644 --- a/include/hw/lm32/lm32_juart.h +++ b/include/hw/char/lm32_juart.h @@ -1,7 +1,9 @@ -#ifndef QEMU_HW_LM32_JUART_H -#define QEMU_HW_LM32_JUART_H +#ifndef QEMU_HW_CHAR_LM32_JUART_H +#define QEMU_HW_CHAR_LM32_JUART_H -#include "qemu-common.h" +#include "hw/qdev.h" + +#define TYPE_LM32_JUART "lm32-juart" uint32_t lm32_juart_get_jtx(DeviceState *d); uint32_t lm32_juart_get_jrx(DeviceState *d); diff --git a/include/hw/i386/ioapic.h b/include/hw/i386/ioapic.h index 86e63dac74..6245388c5d 100644 --- a/include/hw/i386/ioapic.h +++ b/include/hw/i386/ioapic.h @@ -21,6 +21,7 @@ #define HW_IOAPIC_H #define IOAPIC_NUM_PINS 24 +#define IO_APIC_DEFAULT_ADDRESS 0xfec00000 void ioapic_eoi_broadcast(int vector); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 7fb97b08a2..f79d4782c1 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -18,8 +18,8 @@ typedef struct PcPciInfo { } PcPciInfo; struct PcGuestInfo { - PcPciInfo pci_info; bool has_pci_info; + bool isapc_ram_fw; FWCfgState *fw_cfg; }; @@ -101,6 +101,16 @@ void pc_acpi_init(const char *default_dsdt); PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size); +#define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" +#define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end" +#define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start" +#define PCI_HOST_PROP_PCI_HOLE64_END "pci-hole64-end" +#define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size" +#define DEFAULT_PCI_HOLE64_SIZE (1ULL << 31) + +void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start, + uint64_t pci_hole64_size); + FWCfgState *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline, @@ -150,8 +160,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, ram_addr_t ram_size, hwaddr pci_hole_start, hwaddr pci_hole_size, - hwaddr pci_hole64_start, - hwaddr pci_hole64_size, + ram_addr_t above_4g_mem_size, MemoryRegion *pci_memory, MemoryRegion *ram_memory); @@ -192,7 +201,8 @@ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) } /* pc_sysfw.c */ -void pc_system_firmware_init(MemoryRegion *rom_memory); +void pc_system_firmware_init(MemoryRegion *rom_memory, + bool isapc_ram_fw); /* pvpanic.c */ void pvpanic_init(ISABus *bus); @@ -235,6 +245,10 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); .driver = "virtio-net-pci",\ .property = "any_layout",\ .value = "off",\ + },{\ + .driver = TYPE_X86_CPU,\ + .property = "pmu",\ + .value = "on",\ } #define PC_COMPAT_1_4 \ diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index e1bf96ca69..495bcf3a08 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -92,9 +92,6 @@ static inline ISABus *isa_bus_from_device(ISADevice *d) extern hwaddr isa_mem_base; -void isa_mmio_setup(MemoryRegion *mr, hwaddr size); -void isa_mmio_init(hwaddr base, hwaddr size); - /* dma.c */ int DMA_get_channel_mode (int nchan); int DMA_read_memory (int nchan, void *buf, int pos, int size); diff --git a/include/hw/loader.h b/include/hw/loader.h index eb9c9a3612..61457360f6 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -36,6 +36,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source); +extern bool rom_file_in_ram; int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex); diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h index 291e85f6b9..2a7a9c9f42 100644 --- a/include/hw/mips/mips.h +++ b/include/hw/mips/mips.h @@ -2,6 +2,9 @@ #define HW_MIPS_H /* Definitions for mips board emulation. */ +/* Kernels can be configured with 64KB pages */ +#define INITRD_PAGE_MASK (~((1 << 16) - 1)) + #include "exec/memory.h" /* gt64xxx.c */ diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 3cb631eeae..6eb7ab676f 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -55,9 +55,11 @@ typedef struct MCHPCIState { MemoryRegion smram_region; MemoryRegion pci_hole; MemoryRegion pci_hole_64bit; + PcPciInfo pci_info; uint8_t smm_enabled; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; + uint64_t pci_hole64_size; PcGuestInfo *guest_info; } MCHPCIState; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1e23dbfb4a..93f9511325 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -52,14 +52,14 @@ typedef struct sPAPRPHBState { sPAPRTCETable *tcet; AddressSpace iommu_as; - struct { + struct spapr_pci_lsi { uint32_t irq; } lsi_table[PCI_NUM_PINS]; - struct { + struct spapr_pci_msi { uint32_t config_addr; uint32_t irq; - int nvec; + uint32_t nvec; } msi_table[SPAPR_MSIX_MAX_DEVS]; QLIST_ENTRY(sPAPRPHBState) list; diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 66762f6d5e..9df17885ec 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -53,8 +53,13 @@ struct PCIBridgeWindows { MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS]; }; +#define TYPE_PCI_BRIDGE "base-pci-bridge" +#define PCI_BRIDGE(obj) OBJECT_CHECK(PCIBridge, (obj), TYPE_PCI_BRIDGE) + struct PCIBridge { - PCIDevice dev; + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ /* private member */ PCIBus sec_bus; diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index d7933bfd16..3ddaf6aad5 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -143,8 +143,9 @@ #define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 -#define PCI_VENDOR_ID_XEN 0x5853 -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 +#define PCI_VENDOR_ID_XEN 0x5853 +#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 +#define PCI_DEVICE_ID_XEN_PVDEVICE 0x0002 #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_UPD720200 0x0194 diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index d89aa615c5..e167bf7520 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -24,8 +24,13 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" +#define TYPE_PCIE_PORT "pcie-port" +#define PCIE_PORT(obj) OBJECT_CHECK(PCIEPort, (obj), TYPE_PCIE_PORT) + struct PCIEPort { - PCIBridge br; + /*< private >*/ + PCIBridge parent_obj; + /*< public >*/ /* pci express switch port */ uint8_t port; @@ -33,8 +38,13 @@ struct PCIEPort { void pcie_port_init_reg(PCIDevice *d); +#define TYPE_PCIE_SLOT "pcie-slot" +#define PCIE_SLOT(obj) OBJECT_CHECK(PCIESlot, (obj), TYPE_PCIE_SLOT) + struct PCIESlot { - PCIEPort port; + /*< private >*/ + PCIEPort parent_obj; + /*< public >*/ /* pci express switch port with slot */ uint8_t chassis; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index de95480734..9fc197286c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -7,30 +7,36 @@ struct VIOsPAPRBus; struct sPAPRPHBState; struct sPAPRNVRAM; -struct icp_state; + +#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; QLIST_HEAD(, sPAPRPHBState) phbs; struct sPAPRNVRAM *nvram; - struct icp_state *icp; + XICSState *icp; hwaddr ram_limit; void *htab; - long htab_shift; + uint32_t htab_shift; hwaddr rma_size; int vrma_adjust; hwaddr fdt_addr, rtas_addr; long rtas_size; void *fdt_skel; target_ulong entry_point; - int next_irq; - int rtc_offset; + uint32_t next_irq; + uint64_t rtc_offset; char *cpu_model; bool has_graphics; uint32_t epow_irq; Notifier epow_notifier; + + /* Migration state */ + int htab_save_index; + bool htab_first_pass; + int htab_fd; } sPAPREnvironment; #define H_SUCCESS 0 @@ -334,10 +340,6 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, #define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT) #define SPAPR_TCE_PAGE_MASK (SPAPR_TCE_PAGE_SIZE - 1) -typedef struct sPAPRTCE { - uint64_t tce; -} sPAPRTCE; - #define SPAPR_VIO_BASE_LIOBN 0x00000000 #define SPAPR_PCI_BASE_LIOBN 0x80000000 @@ -345,14 +347,27 @@ typedef struct sPAPRTCE { typedef struct sPAPRTCETable sPAPRTCETable; -void spapr_iommu_init(void); +#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" +#define SPAPR_TCE_TABLE(obj) \ + OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE) + +struct sPAPRTCETable { + DeviceState parent; + uint32_t liobn; + uint32_t window_size; + uint32_t nb_table; + uint64_t *table; + bool bypass; + int fd; + MemoryRegion iommu; + QLIST_ENTRY(sPAPRTCETable) list; +}; + void spapr_events_init(sPAPREnvironment *spapr); void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size); MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet); -void spapr_tce_free(sPAPRTCETable *tcet); -void spapr_tce_reset(sPAPRTCETable *tcet); void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass); int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size); diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 36093270e6..46edc2a20c 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -134,4 +134,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); void spapr_vio_quiesce(void); +extern const VMStateDescription vmstate_spapr_vio; + +#define VMSTATE_SPAPR_VIO(_f, _s) \ + VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice) + #endif /* _HW_SPAPR_VIO_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 6bce0424df..66364c5faf 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -27,15 +27,77 @@ #if !defined(__XICS_H__) #define __XICS_H__ +#include "hw/sysbus.h" + +#define TYPE_XICS "xics" +#define XICS(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) + #define XICS_IPI 0x2 -#define XICS_IRQ_BASE 0x10 +#define XICS_BUID 0x1 +#define XICS_IRQ_BASE (XICS_BUID << 12) + +/* + * We currently only support one BUID which is our interrupt base + * (the kernel implementation supports more but we don't exploit + * that yet) + */ +typedef struct XICSState XICSState; +typedef struct ICPState ICPState; +typedef struct ICSState ICSState; +typedef struct ICSIRQState ICSIRQState; + +struct XICSState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t nr_servers; + uint32_t nr_irqs; + ICPState *ss; + ICSState *ics; +}; + +#define TYPE_ICP "icp" +#define ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_ICP) + +struct ICPState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; +}; + +#define TYPE_ICS "ics" +#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) + +struct ICSState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t nr_irqs; + uint32_t offset; + qemu_irq *qirqs; + bool *islsi; + ICSIRQState *irqs; + XICSState *icp; +}; -struct icp_state; +struct ICSIRQState { + uint32_t server; + uint8_t priority; + uint8_t saved_priority; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; +}; -qemu_irq xics_get_qirq(struct icp_state *icp, int irq); -void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); +qemu_irq xics_get_qirq(XICSState *icp, int irq); +void xics_set_irq_type(XICSState *icp, int irq, bool lsi); -struct icp_state *xics_system_init(int nr_servers, int nr_irqs); -void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu); +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu); #endif /* __XICS_H__ */ diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 7fbffcbaad..46972f4961 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -4,6 +4,7 @@ #include "qemu/queue.h" #include "qemu/option.h" #include "qemu/typedefs.h" +#include "qemu/bitmap.h" #include "qom/object.h" #include "hw/irq.h" #include "qapi/error.h" @@ -17,6 +18,34 @@ enum { #define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) #define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) +typedef enum DeviceCategory { + DEVICE_CATEGORY_BRIDGE, + DEVICE_CATEGORY_USB, + DEVICE_CATEGORY_STORAGE, + DEVICE_CATEGORY_NETWORK, + DEVICE_CATEGORY_INPUT, + DEVICE_CATEGORY_DISPLAY, + DEVICE_CATEGORY_SOUND, + DEVICE_CATEGORY_MISC, + DEVICE_CATEGORY_MAX +} DeviceCategory; + +static inline const char *qdev_category_get_name(DeviceCategory category) +{ + static const char *category_names[DEVICE_CATEGORY_MAX] = { + [DEVICE_CATEGORY_BRIDGE] = "Controller/Bridge/Hub", + [DEVICE_CATEGORY_USB] = "USB", + [DEVICE_CATEGORY_STORAGE] = "Storage", + [DEVICE_CATEGORY_NETWORK] = "Network", + [DEVICE_CATEGORY_INPUT] = "Input", + [DEVICE_CATEGORY_DISPLAY] = "Display", + [DEVICE_CATEGORY_SOUND] = "Sound", + [DEVICE_CATEGORY_MISC] = "Misc", + }; + + return category_names[category]; +}; + typedef int (*qdev_initfn)(DeviceState *dev); typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); @@ -80,6 +109,7 @@ typedef struct DeviceClass { ObjectClass parent_class; /*< public >*/ + DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX); const char *fw_name; const char *desc; Property *props; diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 39448b716c..692f82e935 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -15,6 +15,7 @@ extern PropertyInfo qdev_prop_uint64; extern PropertyInfo qdev_prop_hex8; extern PropertyInfo qdev_prop_hex32; extern PropertyInfo qdev_prop_hex64; +extern PropertyInfo qdev_prop_size; extern PropertyInfo qdev_prop_string; extern PropertyInfo qdev_prop_chr; extern PropertyInfo qdev_prop_ptr; @@ -116,6 +117,8 @@ extern PropertyInfo qdev_prop_arraylen; DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) #define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) +#define DEFINE_PROP_SIZE(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_size, uint64_t) #define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 8c17165cf2..bb50a877cc 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -42,7 +42,10 @@ typedef struct SysBusDeviceClass { } SysBusDeviceClass; struct SysBusDevice { - DeviceState qdev; + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + int num_irq; qemu_irq irqs[QDEV_MAX_IRQ]; qemu_irq *irqp[QDEV_MAX_IRQ]; @@ -55,10 +58,6 @@ struct SysBusDevice { pio_addr_t pio[QDEV_MAX_PIO]; }; -/* Macros to compensate for lack of type inheritance in C. */ -#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev) - -void *sysbus_new(void); void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory); MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n); void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p); diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h index 59337faaad..8217522291 100644 --- a/include/hw/timer/m48t59.h +++ b/include/hw/timer/m48t59.h @@ -21,6 +21,9 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, uint32_t initrd_image, uint32_t initrd_size, uint32_t NVRAM_image, int width, int height, int depth); + +#define TYPE_SYSBUS_M48T59 "m48t59" + typedef struct M48t59State M48t59State; void m48t59_write (void *private, uint32_t addr, uint32_t val); diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index fc71853eb4..b87cf490b1 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -125,6 +125,7 @@ typedef struct VirtIOBlock { unsigned short sector_mask; VMChangeStateEntry *change; #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + Notifier migration_state_notifier; struct VirtIOBlockDataPlane *dataplane; #endif } VirtIOBlock; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index d7e9e0fc8a..a90522d6d6 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -237,6 +237,7 @@ hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n); uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); +void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n); VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); uint16_t virtio_get_queue_index(VirtQueue *vq); int virtio_queue_get_id(VirtQueue *vq); diff --git a/include/migration/migration.h b/include/migration/migration.h index 08c772d4dc..140e6b471c 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -90,7 +90,7 @@ int migrate_fd_close(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); -bool migration_is_active(MigrationState *); +bool migration_in_setup(MigrationState *); bool migration_has_finished(MigrationState *); bool migration_has_failed(MigrationState *); MigrationState *migrate_get_current(void); diff --git a/include/qapi/opts-visitor.h b/include/qapi/opts-visitor.h index 5939eeebc7..fd48c14ec8 100644 --- a/include/qapi/opts-visitor.h +++ b/include/qapi/opts-visitor.h @@ -16,6 +16,12 @@ #include "qapi/visitor.h" #include "qemu/option.h" +/* Inclusive upper bound on the size of any flattened range. This is a safety + * (= anti-annoyance) measure; wrong ranges should not cause long startup + * delays nor exhaust virtual memory. + */ +#define OPTS_VISITOR_RANGE_MAX 65536 + typedef struct OptsVisitor OptsVisitor; /* Contrarily to qemu-option.c::parse_option_number(), OptsVisitor's "int" diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 685b2e3fcb..d6855d112e 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -65,5 +65,6 @@ int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value); const char *qdict_get_try_str(const QDict *qdict, const char *key); QDict *qdict_clone_shallow(const QDict *src); +void qdict_flatten(QDict *qdict); #endif /* QDICT_H */ diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index 9124649ed2..d0bbc7c4a6 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -44,6 +44,7 @@ typedef enum { QTYPE_QFLOAT, QTYPE_QBOOL, QTYPE_QERROR, + QTYPE_MAX, } qtype_code; struct QObject; diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index 5159964863..f3fa420245 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -22,12 +22,18 @@ struct Visitor const char *name, size_t size, Error **errp); void (*end_struct)(Visitor *v, Error **errp); + void (*start_implicit_struct)(Visitor *v, void **obj, size_t size, + Error **errp); + void (*end_implicit_struct)(Visitor *v, Error **errp); + void (*start_list)(Visitor *v, const char *name, Error **errp); GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp); void (*end_list)(Visitor *v, Error **errp); void (*type_enum)(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp); + void (*get_next_type)(Visitor *v, int *kind, const int *qobjects, + const char *name, Error **errp); void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error **errp); void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp); diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 28c21d8338..48a2a2edfd 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -13,6 +13,7 @@ #ifndef QAPI_VISITOR_CORE_H #define QAPI_VISITOR_CORE_H +#include "qapi/qmp/qobject.h" #include "qapi/error.h" #include <stdlib.h> @@ -33,12 +34,17 @@ void visit_end_handle(Visitor *v, Error **errp); void visit_start_struct(Visitor *v, void **obj, const char *kind, const char *name, size_t size, Error **errp); void visit_end_struct(Visitor *v, Error **errp); +void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, + Error **errp); +void visit_end_implicit_struct(Visitor *v, Error **errp); void visit_start_list(Visitor *v, const char *name, Error **errp); GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp); void visit_end_list(Visitor *v, Error **errp); void visit_start_optional(Visitor *v, bool *present, const char *name, Error **errp); void visit_end_optional(Visitor *v, Error **errp); +void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, + const char *name, Error **errp); void visit_type_enum(Visitor *v, int *obj, const char *strings[], const char *kind, const char *name, Error **errp); void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp); diff --git a/include/qemu/option.h b/include/qemu/option.h index a83c700323..7a58e477d9 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -73,6 +73,8 @@ QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest, QEMUOptionParameter *list); QEMUOptionParameter *parse_option_parameters(const char *param, QEMUOptionParameter *list, QEMUOptionParameter *dest); +void parse_option_size(const char *name, const char *value, + uint64_t *ret, Error **errp); void free_option_parameters(QEMUOptionParameter *list); void print_option_parameters(QEMUOptionParameter *list); void print_option_help(QEMUOptionParameter *list); @@ -120,6 +122,7 @@ bool qemu_opt_has_help_opt(QemuOpts *opts); bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval); uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval); uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval); +int qemu_opt_unset(QemuOpts *opts, const char *name); int qemu_opt_set(QemuOpts *opts, const char *name, const char *value); void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, Error **errp); diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h index d1610f135b..d413a4a696 100644 --- a/include/qemu/ratelimit.h +++ b/include/qemu/ratelimit.h @@ -23,7 +23,7 @@ typedef struct { static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n) { - int64_t now = qemu_get_clock_ns(rt_clock); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); if (limit->next_slice_time < now) { limit->next_slice_time = now + limit->slice_ns; diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h index 0f30dccb53..361566abc4 100644 --- a/include/qemu/thread-posix.h +++ b/include/qemu/thread-posix.h @@ -15,7 +15,7 @@ struct QemuSemaphore { #if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_t lock; pthread_cond_t cond; - int count; + unsigned int count; #else sem_t sem; #endif diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 9dd206ce7f..e4934dd61b 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -1,8 +1,8 @@ #ifndef QEMU_TIMER_H #define QEMU_TIMER_H +#include "qemu/typedefs.h" #include "qemu-common.h" -#include "qemu/main-loop.h" #include "qemu/notify.h" /* timers */ @@ -11,80 +11,643 @@ #define SCALE_US 1000 #define SCALE_NS 1 -typedef struct QEMUClock QEMUClock; +/** + * QEMUClockType: + * + * The following clock types are available: + * + * @QEMU_CLOCK_REALTIME: Real time clock + * + * The real time clock should be used only for stuff which does not + * change the virtual machine state, as it is run even if the virtual + * machine is stopped. The real time clock has a frequency of 1000 + * Hz. + * + * @QEMU_CLOCK_VIRTUAL: virtual clock + * + * The virtual clock is only run during the emulation. It is stopped + * when the virtual machine is stopped. Virtual timers use a high + * precision clock, usually cpu cycles (use ticks_per_sec). + * + * @QEMU_CLOCK_HOST: host clock + * + * The host clock should be use for device models that emulate accurate + * real time sources. It will continue to run when the virtual machine + * is suspended, and it will reflect system time changes the host may + * undergo (e.g. due to NTP). The host clock has the same precision as + * the virtual clock. + */ + +typedef enum { + QEMU_CLOCK_REALTIME = 0, + QEMU_CLOCK_VIRTUAL = 1, + QEMU_CLOCK_HOST = 2, + QEMU_CLOCK_MAX +} QEMUClockType; + +typedef struct QEMUTimerList QEMUTimerList; + +struct QEMUTimerListGroup { + QEMUTimerList *tl[QEMU_CLOCK_MAX]; +}; + typedef void QEMUTimerCB(void *opaque); +typedef void QEMUTimerListNotifyCB(void *opaque); + +struct QEMUTimer { + int64_t expire_time; /* in nanoseconds */ + QEMUTimerList *timer_list; + QEMUTimerCB *cb; + void *opaque; + QEMUTimer *next; + int scale; +}; + +extern QEMUTimerListGroup main_loop_tlg; + +/* + * QEMUClockType + */ + +/* + * qemu_clock_get_ns; + * @type: the clock type + * + * Get the nanosecond value of a clock with + * type @type + * + * Returns: the clock value in nanoseconds + */ +int64_t qemu_clock_get_ns(QEMUClockType type); + +/** + * qemu_clock_get_ms; + * @type: the clock type + * + * Get the millisecond value of a clock with + * type @type + * + * Returns: the clock value in milliseconds + */ +static inline int64_t qemu_clock_get_ms(QEMUClockType type) +{ + return qemu_clock_get_ns(type) / SCALE_MS; +} + +/** + * qemu_clock_get_us; + * @type: the clock type + * + * Get the microsecond value of a clock with + * type @type + * + * Returns: the clock value in microseconds + */ +static inline int64_t qemu_clock_get_us(QEMUClockType type) +{ + return qemu_clock_get_ns(type) / SCALE_US; +} + +/** + * qemu_clock_has_timers: + * @type: the clock type + * + * Determines whether a clock's default timer list + * has timers attached + * + * Returns: true if the clock's default timer list + * has timers attached + */ +bool qemu_clock_has_timers(QEMUClockType type); + +/** + * qemu_clock_expired: + * @type: the clock type + * + * Determines whether a clock's default timer list + * has an expired clock. + * + * Returns: true if the clock's default timer list has + * an expired timer + */ +bool qemu_clock_expired(QEMUClockType type); + +/** + * qemu_clock_use_for_deadline: + * @type: the clock type + * + * Determine whether a clock should be used for deadline + * calculations. Some clocks, for instance vm_clock with + * use_icount set, do not count in nanoseconds. Such clocks + * are not used for deadline calculations, and are presumed + * to interrupt any poll using qemu_notify/aio_notify + * etc. + * + * Returns: true if the clock runs in nanoseconds and + * should be used for a deadline. + */ +bool qemu_clock_use_for_deadline(QEMUClockType type); + +/** + * qemu_clock_deadline_ns_all: + * @type: the clock type + * + * Calculate the deadline across all timer lists associated + * with a clock (as opposed to just the default one) + * in nanoseconds, or -1 if no timer is set to expire. + * + * Returns: time until expiry in nanoseconds or -1 + */ +int64_t qemu_clock_deadline_ns_all(QEMUClockType type); + +/** + * qemu_clock_get_main_loop_timerlist: + * @type: the clock type + * + * Return the default timer list assocatiated with a clock. + * + * Returns: the default timer list + */ +QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type); -/* The real time clock should be used only for stuff which does not - change the virtual machine state, as it is run even if the virtual - machine is stopped. The real time clock has a frequency of 1000 - Hz. */ -extern QEMUClock *rt_clock; - -/* The virtual clock is only run during the emulation. It is stopped - when the virtual machine is stopped. Virtual timers use a high - precision clock, usually cpu cycles (use ticks_per_sec). */ -extern QEMUClock *vm_clock; - -/* The host clock should be use for device models that emulate accurate - real time sources. It will continue to run when the virtual machine - is suspended, and it will reflect system time changes the host may - undergo (e.g. due to NTP). The host clock has the same precision as - the virtual clock. */ -extern QEMUClock *host_clock; - -int64_t qemu_get_clock_ns(QEMUClock *clock); -int64_t qemu_clock_has_timers(QEMUClock *clock); -int64_t qemu_clock_expired(QEMUClock *clock); -int64_t qemu_clock_deadline(QEMUClock *clock); -void qemu_clock_enable(QEMUClock *clock, bool enabled); -void qemu_clock_warp(QEMUClock *clock); - -void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier); -void qemu_unregister_clock_reset_notifier(QEMUClock *clock, +/** + * qemu_clock_nofify: + * @type: the clock type + * + * Call the notifier callback connected with the default timer + * list linked to the clock, or qemu_notify() if none. + */ +void qemu_clock_notify(QEMUClockType type); + +/** + * qemu_clock_enable: + * @type: the clock type + * @enabled: true to enable, false to disable + * + * Enable or disable a clock + */ +void qemu_clock_enable(QEMUClockType type, bool enabled); + +/** + * qemu_clock_warp: + * @type: the clock type + * + * Warp a clock to a new value + */ +void qemu_clock_warp(QEMUClockType type); + +/** + * qemu_clock_register_reset_notifier: + * @type: the clock type + * @notifier: the notifier function + * + * Register a notifier function to call when the clock + * concerned is reset. + */ +void qemu_clock_register_reset_notifier(QEMUClockType type, + Notifier *notifier); + +/** + * qemu_clock_unregister_reset_notifier: + * @type: the clock type + * @notifier: the notifier function + * + * Unregister a notifier function to call when the clock + * concerned is reset. + */ +void qemu_clock_unregister_reset_notifier(QEMUClockType type, Notifier *notifier); -QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, - QEMUTimerCB *cb, void *opaque); -void qemu_free_timer(QEMUTimer *ts); -void qemu_del_timer(QEMUTimer *ts); -void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time); -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); -bool qemu_timer_pending(QEMUTimer *ts); -bool qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); -uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts); - -void qemu_run_timers(QEMUClock *clock); -void qemu_run_all_timers(void); -void configure_alarms(char const *opt); -void init_clocks(void); -int init_timer_alarm(void); +/** + * qemu_clock_run_timers: + * @type: clock on which to operate + * + * Run all the timers associated with the default timer list + * of a clock. + * + * Returns: true if any timer ran. + */ +bool qemu_clock_run_timers(QEMUClockType type); -int64_t cpu_get_ticks(void); -void cpu_enable_ticks(void); -void cpu_disable_ticks(void); +/** + * qemu_clock_run_all_timers: + * + * Run all the timers associated with the default timer list + * of every clock. + * + * Returns: true if any timer ran. + */ +bool qemu_clock_run_all_timers(void); + +/* + * QEMUTimerList + */ + +/** + * timerlist_new: + * @type: the clock type to associate with the timerlist + * @cb: the callback to call on notification + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timerlist associated with the clock of + * type @type. + * + * Returns: a pointer to the QEMUTimerList created + */ +QEMUTimerList *timerlist_new(QEMUClockType type, + QEMUTimerListNotifyCB *cb, void *opaque); + +/** + * timerlist_free: + * @timer_list: the timer list to free + * + * Frees a timer_list. It must have no active timers. + */ +void timerlist_free(QEMUTimerList *timer_list); + +/** + * timerlist_has_timers: + * @timer_list: the timer list to operate on + * + * Determine whether a timer list has active timers + * + * Returns: true if the timer list has timers. + */ +bool timerlist_has_timers(QEMUTimerList *timer_list); + +/** + * timerlist_expired: + * @timer_list: the timer list to operate on + * + * Determine whether a timer list has any timers which + * are expired. + * + * Returns: true if the timer list has timers which + * have expired. + */ +bool timerlist_expired(QEMUTimerList *timer_list); + +/** + * timerlist_deadline_ns: + * @timer_list: the timer list to operate on + * + * Determine the deadline for a timer_list, i.e. + * the number of nanoseconds until the first timer + * expires. Return -1 if there are no timers. + * + * Returns: the number of nanoseconds until the earliest + * timer expires -1 if none + */ +int64_t timerlist_deadline_ns(QEMUTimerList *timer_list); + +/** + * timerlist_get_clock: + * @timer_list: the timer list to operate on + * + * Determine the clock type associated with a timer list. + * + * Returns: the clock type associated with the + * timer list. + */ +QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list); + +/** + * timerlist_run_timers: + * @timer_list: the timer list to use + * + * Call all expired timers associated with the timer list. + * + * Returns: true if any timer expired + */ +bool timerlist_run_timers(QEMUTimerList *timer_list); + +/** + * timerlist_notify: + * @timer_list: the timer list to use + * + * call the notifier callback associated with the timer list. + */ +void timerlist_notify(QEMUTimerList *timer_list); + +/* + * QEMUTimerListGroup + */ + +/** + * timerlistgroup_init: + * @tlg: the timer list group + * @cb: the callback to call when a notify is required + * @opaque: the opaque pointer to be passed to the callback. + * + * Initialise a timer list group. This must already be + * allocated in memory and zeroed. The notifier callback is + * called whenever a clock in the timer list group is + * reenabled or whenever a timer associated with any timer + * list is modified. If @cb is specified as null, qemu_notify() + * is used instead. + */ +void timerlistgroup_init(QEMUTimerListGroup *tlg, + QEMUTimerListNotifyCB *cb, void *opaque); + +/** + * timerlistgroup_deinit: + * @tlg: the timer list group + * + * Deinitialise a timer list group. This must already be + * initialised. Note the memory is not freed. + */ +void timerlistgroup_deinit(QEMUTimerListGroup *tlg); + +/** + * timerlistgroup_run_timers: + * @tlg: the timer list group + * + * Run the timers associated with a timer list group. + * This will run timers on multiple clocks. + * + * Returns: true if any timer callback ran + */ +bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg); + +/** + * timerlistgroup_deadline_ns: + * @tlg: the timer list group + * + * Determine the deadline of the soonest timer to + * expire associated with any timer list linked to + * the timer list group. Only clocks suitable for + * deadline calculation are included. + * + * Returns: the deadline in nanoseconds or -1 if no + * timers are to expire. + */ +int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg); + +/* + * QEMUTimer + */ + +/** + * timer_init: + * @ts: the timer to be initialised + * @timer_list: the timer list to attach the timer to + * @scale: the scale value for the tiemr + * @cb: the callback to be called when the timer expires + * @opaque: the opaque pointer to be passed to the callback + * + * Initialise a new timer and associate it with @timer_list. + * The caller is responsible for allocating the memory. + * + * You need not call an explicit deinit call. Simply make + * sure it is not on a list with timer_del. + */ +void timer_init(QEMUTimer *ts, + QEMUTimerList *timer_list, int scale, + QEMUTimerCB *cb, void *opaque); + +/** + * timer_new_tl: + * @timer_list: the timer list to attach the timer to + * @scale: the scale value for the tiemr + * @cb: the callback to be called when the timer expires + * @opaque: the opaque pointer to be passed to the callback + * + * Creeate a new timer and associate it with @timer_list. + * The memory is allocated by the function. + * + * This is not the preferred interface unless you know you + * are going to call timer_free. Use timer_init instead. + * + * Returns: a pointer to the timer + */ +static inline QEMUTimer *timer_new_tl(QEMUTimerList *timer_list, + int scale, + QEMUTimerCB *cb, + void *opaque) +{ + QEMUTimer *ts = g_malloc0(sizeof(QEMUTimer)); + timer_init(ts, timer_list, scale, cb, opaque); + return ts; +} -static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb, - void *opaque) +/** + * timer_new: + * @type: the clock type to use + * @scale: the scale value for the tiemr + * @cb: the callback to be called when the timer expires + * @opaque: the opaque pointer to be passed to the callback + * + * Creeate a new timer and associate it with the default + * timer list for the clock type @type. + * + * Returns: a pointer to the timer + */ +static inline QEMUTimer *timer_new(QEMUClockType type, int scale, + QEMUTimerCB *cb, void *opaque) { - return qemu_new_timer(clock, SCALE_NS, cb, opaque); + return timer_new_tl(main_loop_tlg.tl[type], scale, cb, opaque); } -static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, QEMUTimerCB *cb, - void *opaque) +/** + * timer_new_ns: + * @clock: the clock to associate with the timer + * @callback: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timer with nanosecond scale on the default timer list + * associated with the clock. + * + * Returns: a pointer to the newly created timer + */ +static inline QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb, + void *opaque) { - return qemu_new_timer(clock, SCALE_MS, cb, opaque); + return timer_new(type, SCALE_NS, cb, opaque); } -static inline int64_t qemu_get_clock_ms(QEMUClock *clock) +/** + * timer_new_us: + * @clock: the clock to associate with the timer + * @callback: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timer with microsecond scale on the default timer list + * associated with the clock. + * + * Returns: a pointer to the newly created timer + */ +static inline QEMUTimer *timer_new_us(QEMUClockType type, QEMUTimerCB *cb, + void *opaque) { - return qemu_get_clock_ns(clock) / SCALE_MS; + return timer_new(type, SCALE_US, cb, opaque); } +/** + * timer_new_ms: + * @clock: the clock to associate with the timer + * @callback: the callback to call when the timer expires + * @opaque: the opaque pointer to pass to the callback + * + * Create a new timer with millisecond scale on the default timer list + * associated with the clock. + * + * Returns: a pointer to the newly created timer + */ +static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb, + void *opaque) +{ + return timer_new(type, SCALE_MS, cb, opaque); +} + +/** + * timer_free: + * @ts: the timer + * + * Free a timer (it must not be on the active list) + */ +void timer_free(QEMUTimer *ts); + +/** + * timer_del: + * @ts: the timer + * + * Delete a timer from the active list. + */ +void timer_del(QEMUTimer *ts); + +/** + * timer_mod_ns: + * @ts: the timer + * @expire_time: the expiry time in nanoseconds + * + * Modify a timer to expire at @expire_time + */ +void timer_mod_ns(QEMUTimer *ts, int64_t expire_time); + +/** + * timer_mod: + * @ts: the timer + * @expire_time: the expire time in the units associated with the timer + * + * Modify a timer to expiry at @expire_time, taking into + * account the scale associated with the timer. + */ +void timer_mod(QEMUTimer *ts, int64_t expire_timer); + +/** + * timer_pending: + * @ts: the timer + * + * Determines whether a timer is pending (i.e. is on the + * active list of timers, whether or not it has not yet expired). + * + * Returns: true if the timer is pending + */ +bool timer_pending(QEMUTimer *ts); + +/** + * timer_expired: + * @ts: the timer + * + * Determines whether a timer has expired. + * + * Returns: true if the timer has expired + */ +bool timer_expired(QEMUTimer *timer_head, int64_t current_time); + +/** + * timer_expire_time_ns: + * @ts: the timer + * + * Determine the expiry time of a timer + * + * Returns: the expiry time in nanoseconds + */ +uint64_t timer_expire_time_ns(QEMUTimer *ts); + +/** + * timer_get: + * @f: the file + * @ts: the timer + * + * Read a timer @ts from a file @f + */ +void timer_get(QEMUFile *f, QEMUTimer *ts); + +/** + * timer_put: + * @f: the file + * @ts: the timer + */ +void timer_put(QEMUFile *f, QEMUTimer *ts); + +/* + * General utility functions + */ + +/** + * qemu_timeout_ns_to_ms: + * @ns: nanosecond timeout value + * + * Convert a nanosecond timeout value (or -1) to + * a millisecond value (or -1), always rounding up. + * + * Returns: millisecond timeout value + */ +int qemu_timeout_ns_to_ms(int64_t ns); + +/** + * qemu_poll_ns: + * @fds: Array of file descriptors + * @nfds: number of file descriptors + * @timeout: timeout in nanoseconds + * + * Perform a poll like g_poll but with a timeout in nanoseconds. + * See g_poll documentation for further details. + * + * Returns: number of fds ready + */ +int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout); + +/** + * qemu_soonest_timeout: + * @timeout1: first timeout in nanoseconds (or -1 for infinite) + * @timeout2: second timeout in nanoseconds (or -1 for infinite) + * + * Calculates the soonest of two timeout values. -1 means infinite, which + * is later than any other value. + * + * Returns: soonest timeout value in nanoseconds (or -1 for infinite) + */ +static inline int64_t qemu_soonest_timeout(int64_t timeout1, int64_t timeout2) +{ + /* we can abuse the fact that -1 (which means infinite) is a maximal + * value when cast to unsigned. As this is disgusting, it's kept in + * one inline function. + */ + return ((uint64_t) timeout1 < (uint64_t) timeout2) ? timeout1 : timeout2; +} + +/** + * initclocks: + * + * Initialise the clock & timer infrastructure + */ +void init_clocks(void); + +int64_t cpu_get_ticks(void); +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + static inline int64_t get_ticks_per_sec(void) { return 1000000000LL; } +/* + * Low level clock functions + */ + /* real time host monotonic timer */ static inline int64_t get_clock_realtime(void) { @@ -128,9 +691,6 @@ static inline int64_t get_clock(void) } #endif -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); - /* icount */ int64_t cpu_get_icount(void); int64_t cpu_get_clock(void); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index ac9f8d41a3..3205540059 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -4,9 +4,12 @@ /* A load of opaque types so that device init declarations don't have to pull in all the real definitions. */ typedef struct QEMUTimer QEMUTimer; +typedef struct QEMUTimerListGroup QEMUTimerListGroup; typedef struct QEMUFile QEMUFile; typedef struct QEMUBH QEMUBH; +typedef struct AioContext AioContext; + struct Monitor; typedef struct Monitor Monitor; typedef struct MigrationParams MigrationParams; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index daf1835c1a..3e4993661a 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -80,7 +80,11 @@ struct TranslationBlock; * @synchronize_from_tb: Callback for synchronizing state from a TCG * #TranslationBlock. * @get_phys_page_debug: Callback for obtaining a physical address. + * @gdb_read_register: Callback for letting GDB read a register. + * @gdb_write_register: Callback for letting GDB write a register. * @vmsd: State description for migration. + * @gdb_num_core_regs: Number of core registers accessible to GDB. + * @gdb_core_xml_file: File name for core registers GDB XML description. * * Represents a CPU family or model. */ @@ -108,8 +112,9 @@ typedef struct CPUClass { void (*set_pc)(CPUState *cpu, vaddr value); void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb); hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr); + int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg); + int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg); - const struct VMStateDescription *vmsd; int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu, int cpuid, void *opaque); int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, @@ -118,6 +123,10 @@ typedef struct CPUClass { int cpuid, void *opaque); int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu, void *opaque); + + const struct VMStateDescription *vmsd; + int gdb_num_core_regs; + const char *gdb_core_xml_file; } CPUClass; struct KVMState; @@ -142,6 +151,8 @@ struct kvm_run; * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @gdb_regs: Additional GDB registers. + * @gdb_num_regs: Number of total registers accessible to GDB. + * @gdb_num_g_regs: Number of registers in GDB 'g' packets. * @next_cpu: Next CPU sharing TB cache. * @kvm_fd: vCPU file descriptor for KVM. * @@ -177,6 +188,8 @@ struct CPUState { void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; struct GDBRegisterState *gdb_regs; + int gdb_num_regs; + int gdb_num_g_regs; CPUState *next_cpu; int kvm_fd; diff --git a/include/qom/object.h b/include/qom/object.h index 23fc048088..9b69065b7a 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -398,6 +398,8 @@ struct Object * @instance_init: This function is called to initialize an object. The parent * class will have already been initialized so the type is only responsible * for initializing its own members. + * @instance_post_init: This function is called to finish initialization of + * an object, after all @instance_init functions were called. * @instance_finalize: This function is called during object destruction. This * is called before the parent @instance_finalize function has been called. * An object should only free the members that are unique to its type in this @@ -433,6 +435,7 @@ struct TypeInfo size_t instance_size; void (*instance_init)(Object *obj); + void (*instance_post_init)(Object *obj); void (*instance_finalize)(Object *obj); bool abstract; diff --git a/include/sysemu/char.h b/include/sysemu/char.h index e65e4a4844..8053130a97 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -77,6 +77,7 @@ struct CharDriverState { int explicit_fe_open; int explicit_be_open; int avail_connections; + int is_mux; QemuOpts *opts; QTAILQ_ENTRY(CharDriverState) next; }; diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h index b8c770f8d9..19fafb2cf9 100644 --- a/include/sysemu/dump.h +++ b/include/sysemu/dump.h @@ -20,7 +20,9 @@ typedef struct ArchDumpInfo { int d_class; /* ELFCLASS32 or ELFCLASS64 */ } ArchDumpInfo; -int cpu_get_dump_info(ArchDumpInfo *info); +struct GuestPhysBlockList; /* memory_mapping.h */ +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks); ssize_t cpu_get_note_size(int class, int machine, int nr_cpus); #endif diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index ce3efaf210..8e7668524b 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -174,7 +174,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, target_ulong len, int type); void kvm_remove_all_breakpoints(CPUState *cpu); -int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap); +int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap); #ifndef _WIN32 int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset); #endif diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 6dfb68ddcd..a75d59a55d 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -17,6 +17,25 @@ #include "qemu/queue.h" #include "qemu/typedefs.h" +typedef struct GuestPhysBlock { + /* visible to guest, reflects PCI hole, etc */ + hwaddr target_start; + + /* implies size */ + hwaddr target_end; + + /* points into host memory */ + uint8_t *host_addr; + + QTAILQ_ENTRY(GuestPhysBlock) next; +} GuestPhysBlock; + +/* point-in-time snapshot of guest-visible physical mappings */ +typedef struct GuestPhysBlockList { + unsigned num; + QTAILQ_HEAD(GuestPhysBlockHead, GuestPhysBlock) head; +} GuestPhysBlockList; + /* The physical and virtual address in the memory mapping are contiguous. */ typedef struct MemoryMapping { hwaddr phys_addr; @@ -45,10 +64,17 @@ void memory_mapping_list_free(MemoryMappingList *list); void memory_mapping_list_init(MemoryMappingList *list); -void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp); +void guest_phys_blocks_free(GuestPhysBlockList *list); +void guest_phys_blocks_init(GuestPhysBlockList *list); +void guest_phys_blocks_append(GuestPhysBlockList *list); + +void qemu_get_guest_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks, + Error **errp); /* get guest's memory mapping without do paging(virtual address is 0). */ -void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list); +void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list, + const GuestPhysBlockList *guest_phys_blocks); void memory_mapping_filter(MemoryMappingList *list, int64_t begin, int64_t length); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 3caeb66eb2..b1aa059102 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -103,7 +103,6 @@ typedef enum { extern int vga_interface_type; #define xenfb_enabled (vga_interface_type == VGA_XENFB) -#define qxl_enabled (vga_interface_type == VGA_QXL) extern int graphic_width; extern int graphic_height; @@ -125,7 +124,7 @@ extern int boot_menu; extern uint8_t *boot_splash_filedata; extern size_t boot_splash_filedata_size; extern uint8_t qemu_extra_params_fw[2]; -extern QEMUClock *rtc_clock; +extern QEMUClockType rtc_clock; #define MAX_NODES 64 #define MAX_CPUMASK_BITS 255 diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index eba6d77d1d..c6c756b23d 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -27,6 +27,7 @@ #include "monitor/monitor.h" extern int using_spice; +extern int spice_displays; void qemu_spice_init(void); void qemu_spice_input_init(void); @@ -57,6 +58,7 @@ static inline CharDriverState *qemu_chr_open_spice_port(const char *name) #include "monitor/monitor.h" #define using_spice 0 +#define spice_displays 0 static inline int qemu_spice_set_passwd(const char *passwd, bool fail_if_connected, bool disconnect_if_connected) |