Import QEMU upstream snapshot d2e570c

Upstream: https://gitlab.com/qemu-project/qemu.git

Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
This commit is contained in:
2026-08-31 02:15:30 +02:00
commit cf256aa081
11315 changed files with 3598369 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
/*
* Accelerator per-vCPU handlers
*
* Copyright 2021 SUSE LLC
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_ACCEL_CPU_OPS_H
#define QEMU_ACCEL_CPU_OPS_H
#include "qemu/accel.h"
#include "exec/vaddr.h"
#include "qom/object.h"
#include "gdbstub/enums.h"
#define ACCEL_OPS_SUFFIX "-ops"
#define TYPE_ACCEL_OPS "accel" ACCEL_OPS_SUFFIX
#define ACCEL_OPS_NAME(name) (name "-" TYPE_ACCEL_OPS)
DECLARE_CLASS_CHECKERS(AccelOpsClass, ACCEL_OPS, TYPE_ACCEL_OPS)
/**
* struct AccelOpsClass - accelerator interfaces
*
* This structure is used to abstract accelerator differences from the
* core CPU code. Not all have to be implemented.
*/
struct AccelOpsClass {
/*< private >*/
ObjectClass parent_class;
/*< public >*/
/* initialization function called when accel is chosen */
void (*ops_init)(AccelClass *ac);
bool (*cpu_target_realize)(CPUState *cpu, Error **errp);
bool (*cpus_are_resettable)(void);
void (*cpu_reset_hold)(CPUState *cpu);
void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY NON-NULL */
void (*kick_vcpu_thread)(CPUState *cpu);
bool (*cpu_thread_is_idle)(CPUState *cpu);
/**
* synchronize_post_reset:
* synchronize_post_init:
* @cpu: The vCPU to synchronize.
*
* Request to synchronize QEMU vCPU registers to the hardware accelerator
* (QEMU is the reference).
*/
void (*synchronize_post_reset)(CPUState *cpu);
void (*synchronize_post_init)(CPUState *cpu);
/**
* synchronize_state:
* synchronize_pre_loadvm:
* @cpu: The vCPU to synchronize.
*
* Request to synchronize QEMU vCPU registers from the hardware accelerator
* (the hardware accelerator is the reference).
*/
void (*synchronize_state)(CPUState *cpu);
void (*synchronize_pre_loadvm)(CPUState *cpu);
/* handle_interrupt is mandatory. */
void (*handle_interrupt)(CPUState *cpu, int mask);
/* get_vcpu_stats: Append statistics of this @cpu to @buf */
void (*get_vcpu_stats)(CPUState *cpu, GString *buf);
/**
* @get_virtual_clock: fetch virtual clock
* @set_virtual_clock: set virtual clock
*
* These allow the timer subsystem to defer to the accelerator to
* fetch time. The set function is needed if the accelerator wants
* to track the changes to time as the timer is warped through
* various timer events.
*/
int64_t (*get_virtual_clock)(void);
void (*set_virtual_clock)(int64_t time);
int64_t (*get_elapsed_ticks)(void);
/* gdbstub hooks */
int (*update_guest_debug)(CPUState *cpu);
int (*insert_gdbstub_breakpoint)(CPUState *cpu, GdbBreakpointType type,
vaddr addr, vaddr len);
int (*remove_gdbstub_breakpoint)(CPUState *cpu, GdbBreakpointType type,
vaddr addr, vaddr len);
void (*remove_all_gdbstub_breakpoints)(CPUState *cpu);
};
void generic_handle_interrupt(CPUState *cpu, int mask);
#endif /* QEMU_ACCEL_CPU_OPS_H */
+31
View File
@@ -0,0 +1,31 @@
/*
* Accelerator interface, specializes CPUClass
* This header is used only by target-specific code.
*
* Copyright 2021 SUSE LLC
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef ACCEL_CPU_TARGET_H
#define ACCEL_CPU_TARGET_H
/*
* This header is used to define new accelerator-specific target-specific
* accelerator cpu subclasses.
* It uses CPU_RESOLVING_TYPE, so this is clearly target-specific.
*
* Do not try to use for any other purpose than the implementation of new
* subclasses in target/, or the accel implementation itself in accel/
*/
#include "qom/object.h"
#include "accel/accel-cpu.h"
#include "cpu.h"
#define TYPE_ACCEL_CPU "accel-" CPU_RESOLVING_TYPE
#define ACCEL_CPU_NAME(name) (name "-" TYPE_ACCEL_CPU)
DECLARE_CLASS_CHECKERS(AccelCPUClass, ACCEL_CPU, TYPE_ACCEL_CPU)
#endif /* ACCEL_CPU_H */
+23
View File
@@ -0,0 +1,23 @@
/*
* Accelerator interface, specializes CPUClass
*
* Copyright 2021 SUSE LLC
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ACCEL_CPU_H
#define ACCEL_CPU_H
#include "qom/object.h"
#include "hw/core/cpu.h"
typedef struct AccelCPUClass {
ObjectClass parent_class;
void (*cpu_class_init)(CPUClass *cc);
void (*cpu_instance_init)(CPUState *cpu);
bool (*cpu_target_realize)(CPUState *cpu, Error **errp);
} AccelCPUClass;
#endif /* ACCEL_CPU_H */
+52
View File
@@ -0,0 +1,52 @@
/*
* Accelerator handlers
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ACCEL_OPS_H
#define ACCEL_OPS_H
#include "exec/hwaddr.h"
#include "qemu/accel.h"
#include "qom/object.h"
struct AccelState {
Object parent_obj;
AccelGdbConfig gdbstub;
};
struct AccelClass {
ObjectClass parent_class;
const char *name;
/* Cached by accel_init_ops_interfaces() when created */
AccelOpsClass *ops;
int (*init_machine)(AccelState *as, MachineState *ms);
/* used mainly by confidential guests to rebuild guest state upon reset */
int (*rebuild_guest)(MachineState *ms);
bool (*cpu_common_realize)(CPUState *cpu, Error **errp);
void (*cpu_common_unrealize)(CPUState *cpu);
/* get_stats: Append statistics to @buf */
void (*get_stats)(AccelState *as, GString *buf);
/* system related hooks */
void (*setup_post)(AccelState *as);
void (*pre_resume_vm)(AccelState *as, bool step_pending);
bool (*has_memory)(AccelState *accel, AddressSpace *as,
hwaddr start_addr, hwaddr size);
bool *allowed;
/*
* Array of global properties that would be applied when specific
* accelerator is chosen. It works like MachineClass.compat_props
* but it's for accelerators not machines. Accelerator-provided
* global properties may be overridden by machine-type
* compat_props or user-provided global properties.
*/
GPtrArray *compat_props;
};
#endif /* ACCEL_OPS_H */
+17
View File
@@ -0,0 +1,17 @@
/*
* Accelerator MSI route change tracking
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ACCEL_ROUTE_H
#define ACCEL_ROUTE_H
#include "qemu/accel.h"
typedef struct AccelRouteChange {
AccelState *accel;
int changes;
} AccelRouteChange;
#endif /* ACCEL_ROUTE_H */
+120
View File
@@ -0,0 +1,120 @@
/*
* Software MMU support
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_CPU_LDST_COMMON_H
#define ACCEL_TCG_CPU_LDST_COMMON_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "exec/memopidx.h"
#include "exec/vaddr.h"
#include "exec/mmu-access-type.h"
#include "qemu/int128.h"
uint8_t cpu_ldb_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra);
uint16_t cpu_ldw_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldl_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra);
uint64_t cpu_ldq_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra);
Int128 cpu_ld16_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra);
void cpu_stb_mmu(CPUArchState *env, vaddr ptr, uint8_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stw_mmu(CPUArchState *env, vaddr ptr, uint16_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stl_mmu(CPUArchState *env, vaddr ptr, uint32_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stq_mmu(CPUArchState *env, vaddr ptr, uint64_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, vaddr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, vaddr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, vaddr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, vaddr addr,
uint64_t cmpv, uint64_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, vaddr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, vaddr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, vaddr addr,
uint64_t cmpv, uint64_t newv,
MemOpIdx oi, uintptr_t retaddr);
#define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \
TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \
(CPUArchState *env, vaddr addr, TYPE val, \
MemOpIdx oi, uintptr_t retaddr);
#define GEN_ATOMIC_HELPER_ALL(NAME) \
GEN_ATOMIC_HELPER(NAME, uint32_t, b) \
GEN_ATOMIC_HELPER(NAME, uint32_t, w_le) \
GEN_ATOMIC_HELPER(NAME, uint32_t, w_be) \
GEN_ATOMIC_HELPER(NAME, uint32_t, l_le) \
GEN_ATOMIC_HELPER(NAME, uint32_t, l_be) \
GEN_ATOMIC_HELPER(NAME, uint64_t, q_le) \
GEN_ATOMIC_HELPER(NAME, uint64_t, q_be)
GEN_ATOMIC_HELPER_ALL(fetch_add)
GEN_ATOMIC_HELPER_ALL(fetch_sub)
GEN_ATOMIC_HELPER_ALL(fetch_and)
GEN_ATOMIC_HELPER_ALL(fetch_or)
GEN_ATOMIC_HELPER_ALL(fetch_xor)
GEN_ATOMIC_HELPER_ALL(fetch_smin)
GEN_ATOMIC_HELPER_ALL(fetch_umin)
GEN_ATOMIC_HELPER_ALL(fetch_smax)
GEN_ATOMIC_HELPER_ALL(fetch_umax)
GEN_ATOMIC_HELPER_ALL(add_fetch)
GEN_ATOMIC_HELPER_ALL(sub_fetch)
GEN_ATOMIC_HELPER_ALL(and_fetch)
GEN_ATOMIC_HELPER_ALL(or_fetch)
GEN_ATOMIC_HELPER_ALL(xor_fetch)
GEN_ATOMIC_HELPER_ALL(smin_fetch)
GEN_ATOMIC_HELPER_ALL(umin_fetch)
GEN_ATOMIC_HELPER_ALL(smax_fetch)
GEN_ATOMIC_HELPER_ALL(umax_fetch)
GEN_ATOMIC_HELPER_ALL(xchg)
Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, vaddr addr,
Int128 cmpv, Int128 newv,
MemOpIdx oi, uintptr_t retaddr);
Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, vaddr addr,
Int128 cmpv, Int128 newv,
MemOpIdx oi, uintptr_t retaddr);
GEN_ATOMIC_HELPER(xchg, Int128, o_le)
GEN_ATOMIC_HELPER(xchg, Int128, o_be)
GEN_ATOMIC_HELPER(fetch_and, Int128, o_le)
GEN_ATOMIC_HELPER(fetch_and, Int128, o_be)
GEN_ATOMIC_HELPER(fetch_or, Int128, o_le)
GEN_ATOMIC_HELPER(fetch_or, Int128, o_be)
#undef GEN_ATOMIC_HELPER_ALL
#undef GEN_ATOMIC_HELPER
uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr,
MemOpIdx oi, uintptr_t ra);
uint16_t cpu_ldw_code_mmu(CPUArchState *env, vaddr addr,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr,
MemOpIdx oi, uintptr_t ra);
uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr,
MemOpIdx oi, uintptr_t ra);
#endif /* ACCEL_TCG_CPU_LDST_COMMON_H */
+474
View File
@@ -0,0 +1,474 @@
/*
* Software MMU support (per-target)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Generate inline load/store functions for all MMU modes (typically
* at least _user and _kernel) as well as _data versions, for all data
* sizes.
*
* Used by target op helpers.
*
* The syntax for the accessors is:
*
* load: cpu_ld{sign}{size}{end}_{mmusuffix}(env, ptr)
* cpu_ld{sign}{size}{end}_{mmusuffix}_ra(env, ptr, retaddr)
* cpu_ld{sign}{size}{end}_mmuidx_ra(env, ptr, mmu_idx, retaddr)
* cpu_ld{sign}{size}{end}_mmu(env, ptr, oi, retaddr)
*
* store: cpu_st{size}{end}_{mmusuffix}(env, ptr, val)
* cpu_st{size}{end}_{mmusuffix}_ra(env, ptr, val, retaddr)
* cpu_st{size}{end}_mmuidx_ra(env, ptr, val, mmu_idx, retaddr)
* cpu_st{size}{end}_mmu(env, ptr, val, oi, retaddr)
*
* sign is:
* (empty): for 32 and 64 bit sizes
* u : unsigned
* s : signed
*
* size is:
* b: 8 bits
* w: 16 bits
* l: 32 bits
* q: 64 bits
*
* end is:
* (empty): for target native endian, or for 8 bit access
* _be: for forced big endian
* _le: for forced little endian
*
* mmusuffix is one of the generic suffixes "data" or "mmuidx".
* The "mmuidx" suffix carries an extra mmu_idx argument that specifies
* the index to use; the "data" suffix take the index from cpu_mmu_index().
*
* The "mmu" suffix carries the full MemOpIdx, with both mmu_idx and the
* MemOp including alignment requirements. The alignment will be enforced.
*/
#ifndef ACCEL_TCG_CPU_LDST_H
#define ACCEL_TCG_CPU_LDST_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "exec/cpu-common.h"
#include "accel/tcg/cpu-ldst-common.h"
#include "accel/tcg/cpu-mmu-index.h"
#include "exec/abi_ptr.h"
static inline uint32_t
cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
return cpu_ldb_mmu(env, addr, oi, ra);
}
static inline int
cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra)
{
return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra);
}
static inline uint32_t
cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
return cpu_ldw_mmu(env, addr, oi, ra);
}
static inline int
cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra);
}
static inline uint32_t
cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
return cpu_ldl_mmu(env, addr, oi, ra);
}
static inline uint64_t
cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
return cpu_ldq_mmu(env, addr, oi, ra);
}
static inline uint32_t
cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
return cpu_ldw_mmu(env, addr, oi, ra);
}
static inline int
cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra);
}
static inline uint32_t
cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
return cpu_ldl_mmu(env, addr, oi, ra);
}
static inline uint64_t
cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
return cpu_ldq_mmu(env, addr, oi, ra);
}
static inline void
cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
cpu_stb_mmu(env, addr, val, oi, ra);
}
static inline void
cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
cpu_stw_mmu(env, addr, val, oi, ra);
}
static inline void
cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
cpu_stl_mmu(env, addr, val, oi, ra);
}
static inline void
cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
cpu_stq_mmu(env, addr, val, oi, ra);
}
static inline void
cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
cpu_stw_mmu(env, addr, val, oi, ra);
}
static inline void
cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
cpu_stl_mmu(env, addr, val, oi, ra);
}
static inline void
cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
cpu_stq_mmu(env, addr, val, oi, ra);
}
/*--------------------------*/
static inline uint32_t
cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_ldub_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline int
cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return (int8_t)cpu_ldub_data_ra(env, addr, ra);
}
static inline uint32_t
cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_lduw_be_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline int
cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return (int16_t)cpu_lduw_be_data_ra(env, addr, ra);
}
static inline uint32_t
cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_ldl_be_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline uint64_t
cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_ldq_be_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline uint32_t
cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_lduw_le_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline int
cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return (int16_t)cpu_lduw_le_data_ra(env, addr, ra);
}
static inline uint32_t
cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_ldl_le_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline uint64_t
cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
return cpu_ldq_le_mmuidx_ra(env, addr, mmu_index, ra);
}
static inline void
cpu_stb_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stb_mmuidx_ra(env, addr, val, mmu_index, ra);
}
static inline void
cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stw_be_mmuidx_ra(env, addr, val, mmu_index, ra);
}
static inline void
cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stl_be_mmuidx_ra(env, addr, val, mmu_index, ra);
}
static inline void
cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr, uint64_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stq_be_mmuidx_ra(env, addr, val, mmu_index, ra);
}
static inline void
cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stw_le_mmuidx_ra(env, addr, val, mmu_index, ra);
}
static inline void
cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stl_le_mmuidx_ra(env, addr, val, mmu_index, ra);
}
static inline void
cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr, uint64_t val, uintptr_t ra)
{
int mmu_index = cpu_mmu_index(env_cpu(env), false);
cpu_stq_le_mmuidx_ra(env, addr, val, mmu_index, ra);
}
/*--------------------------*/
static inline uint32_t
cpu_ldub_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldub_data_ra(env, addr, 0);
}
static inline int
cpu_ldsb_data(CPUArchState *env, abi_ptr addr)
{
return (int8_t)cpu_ldub_data(env, addr);
}
static inline uint32_t
cpu_lduw_be_data(CPUArchState *env, abi_ptr addr)
{
return cpu_lduw_be_data_ra(env, addr, 0);
}
static inline int
cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr)
{
return (int16_t)cpu_lduw_be_data(env, addr);
}
static inline uint32_t
cpu_ldl_be_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldl_be_data_ra(env, addr, 0);
}
static inline uint64_t
cpu_ldq_be_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldq_be_data_ra(env, addr, 0);
}
static inline uint32_t
cpu_lduw_le_data(CPUArchState *env, abi_ptr addr)
{
return cpu_lduw_le_data_ra(env, addr, 0);
}
static inline int
cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr)
{
return (int16_t)cpu_lduw_le_data(env, addr);
}
static inline uint32_t
cpu_ldl_le_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldl_le_data_ra(env, addr, 0);
}
static inline uint64_t
cpu_ldq_le_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldq_le_data_ra(env, addr, 0);
}
static inline void
cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stb_data_ra(env, addr, val, 0);
}
static inline void
cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stw_be_data_ra(env, addr, val, 0);
}
static inline void
cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stl_be_data_ra(env, addr, val, 0);
}
static inline void
cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val)
{
cpu_stq_be_data_ra(env, addr, val, 0);
}
static inline void
cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stw_le_data_ra(env, addr, val, 0);
}
static inline void
cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stl_le_data_ra(env, addr, val, 0);
}
static inline void
cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val)
{
cpu_stq_le_data_ra(env, addr, val, 0);
}
#ifndef TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API
#if TARGET_BIG_ENDIAN
# define cpu_lduw_data cpu_lduw_be_data
# define cpu_ldsw_data cpu_ldsw_be_data
# define cpu_ldl_data cpu_ldl_be_data
# define cpu_ldq_data cpu_ldq_be_data
# define cpu_lduw_data_ra cpu_lduw_be_data_ra
# define cpu_ldsw_data_ra cpu_ldsw_be_data_ra
# define cpu_ldl_data_ra cpu_ldl_be_data_ra
# define cpu_ldq_data_ra cpu_ldq_be_data_ra
# define cpu_lduw_mmuidx_ra cpu_lduw_be_mmuidx_ra
# define cpu_ldsw_mmuidx_ra cpu_ldsw_be_mmuidx_ra
# define cpu_ldl_mmuidx_ra cpu_ldl_be_mmuidx_ra
# define cpu_ldq_mmuidx_ra cpu_ldq_be_mmuidx_ra
# define cpu_stw_data cpu_stw_be_data
# define cpu_stl_data cpu_stl_be_data
# define cpu_stq_data cpu_stq_be_data
# define cpu_stw_data_ra cpu_stw_be_data_ra
# define cpu_stl_data_ra cpu_stl_be_data_ra
# define cpu_stq_data_ra cpu_stq_be_data_ra
# define cpu_stw_mmuidx_ra cpu_stw_be_mmuidx_ra
# define cpu_stl_mmuidx_ra cpu_stl_be_mmuidx_ra
# define cpu_stq_mmuidx_ra cpu_stq_be_mmuidx_ra
#else
# define cpu_lduw_data cpu_lduw_le_data
# define cpu_ldsw_data cpu_ldsw_le_data
# define cpu_ldl_data cpu_ldl_le_data
# define cpu_ldq_data cpu_ldq_le_data
# define cpu_lduw_data_ra cpu_lduw_le_data_ra
# define cpu_ldsw_data_ra cpu_ldsw_le_data_ra
# define cpu_ldl_data_ra cpu_ldl_le_data_ra
# define cpu_ldq_data_ra cpu_ldq_le_data_ra
# define cpu_lduw_mmuidx_ra cpu_lduw_le_mmuidx_ra
# define cpu_ldsw_mmuidx_ra cpu_ldsw_le_mmuidx_ra
# define cpu_ldl_mmuidx_ra cpu_ldl_le_mmuidx_ra
# define cpu_ldq_mmuidx_ra cpu_ldq_le_mmuidx_ra
# define cpu_stw_data cpu_stw_le_data
# define cpu_stl_data cpu_stl_le_data
# define cpu_stq_data cpu_stq_le_data
# define cpu_stw_data_ra cpu_stw_le_data_ra
# define cpu_stl_data_ra cpu_stl_le_data_ra
# define cpu_stq_data_ra cpu_stq_le_data_ra
# define cpu_stw_mmuidx_ra cpu_stw_le_mmuidx_ra
# define cpu_stl_mmuidx_ra cpu_stl_le_mmuidx_ra
# define cpu_stq_mmuidx_ra cpu_stq_le_mmuidx_ra
#endif
#endif /* TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API */
#endif /* ACCEL_TCG_CPU_LDST_H */
+76
View File
@@ -0,0 +1,76 @@
/*
* QEMU TCG CPU loop API
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ACCEL_TCG_CPU_LOOP_COMMON_H
#define ACCEL_TCG_CPU_LOOP_COMMON_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
/**
* cpu_exec:
* @cpu: the cpu context
*
* Returns one of the EXCP_* definitions (see "exec/cpu-common.h").
*/
int cpu_exec(CPUState *cpu);
void cpu_exec_step_atomic(CPUState *cpu);
/**
* cpu_unwind_state_data:
* @cpu: the cpu context
* @host_pc: the host pc within the translation
* @data: output data
*
* Attempt to load the unwind state for a host pc occurring in
* translated code. If @host_pc is not in translated code, the
* function returns false; otherwise @data is loaded.
* This is the same unwind info as given to restore_state_to_opc.
*/
bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data);
/**
* cpu_restore_state:
* @cpu: the cpu context
* @host_pc: the host pc within the translation
* @return: true if state was restored, false otherwise
*
* Attempt to restore the state for a fault occurring in translated
* code. If @host_pc is not in translated code no state is
* restored and the function returns false.
*/
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc);
/**
* cpu_loop_exit_noexc:
* @cpu: the cpu context
*
* Exit the current TB, but without causing any exception to be raised.
*/
G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu);
/**
* cpu_loop_exit_restore:
* @cpu: the cpu context
* @host_pc: the host pc within the translation
*
* Attempt to restore the state for a fault occurring in translated
* code. If @host_pc is not in translated code no state is
* restored. Finally, exit the current TB.
*/
G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t host_pc);
G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t host_pc);
/**
* cpu_loop_exit:
* @cpu: the cpu context
*
* Exit the current TB.
*/
G_NORETURN void cpu_loop_exit(CPUState *cpu);
#endif
+46
View File
@@ -0,0 +1,46 @@
/*
* cpu_mmu_index()
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_CPU_MMU_INDEX_H
#define ACCEL_TCG_CPU_MMU_INDEX_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "hw/core/cpu.h"
#include "accel/tcg/cpu-ops.h"
#include "tcg/debug-assert.h"
#ifdef COMPILING_PER_TARGET
# ifdef CONFIG_USER_ONLY
# include "cpu.h"
# endif
#endif
/**
* cpu_mmu_index:
* @env: The cpu environment
* @ifetch: True for code access, false for data access.
*
* Return the core mmu index for the current translation regime.
* This function is used by generic TCG code paths.
*/
static inline int cpu_mmu_index(CPUState *cs, bool ifetch)
{
#ifdef COMPILING_PER_TARGET
# ifdef CONFIG_USER_ONLY
return MMU_USER_IDX;
# endif
#endif
int ret = cs->cc->tcg_ops->mmu_index(cs, ifetch);
tcg_debug_assert(ret >= 0 && ret < NB_MMU_MODES);
return ret;
}
#endif /* ACCEL_TCG_CPU_MMU_INDEX_H */
+319
View File
@@ -0,0 +1,319 @@
/*
* TCG CPU-specific operations
*
* Copyright 2021 SUSE LLC
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef TCG_CPU_OPS_H
#define TCG_CPU_OPS_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "exec/breakpoint.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
#include "exec/memop.h"
#include "exec/mmu-access-type.h"
#include "exec/vaddr.h"
#include "accel/tcg/tb-cpu-state.h"
#include "tcg/tcg-mo.h"
struct TCGCPUOps {
/**
* mttcg_supported: multi-threaded TCG is supported
*
* Target (TCG frontend) supports:
* - atomic instructions
* - memory ordering primitives (barriers)
*/
bool mttcg_supported;
/**
* @precise_smc: Stores which modify code within the current TB force
* the TB to exit; the next executed instruction will see
* the result of the store.
*/
bool precise_smc;
/**
* @guest_default_memory_order: default barrier that is required
* for the guest memory ordering.
*/
TCGBar guest_default_memory_order;
/**
* @initialize: Initialize TCG state
*
* Called when the first CPU is realized.
*/
void (*initialize)(void);
/**
* @translate_code: Translate guest instructions to TCGOps
* @cpu: cpu context
* @tb: translation block
* @max_insns: max number of instructions to translate
* @pc: guest virtual program counter address
* @host_pc: host physical program counter address
*
* This function must be provided by the target, which should create
* the target-specific DisasContext, and then invoke translator_loop.
*/
void (*translate_code)(CPUState *cpu, TranslationBlock *tb,
int *max_insns, vaddr pc, void *host_pc);
/**
* @get_tb_cpu_state: Extract CPU state for a TCG #TranslationBlock
*
* Fill in all data required to select or compile a TranslationBlock.
*/
TCGTBCPUState (*get_tb_cpu_state)(CPUState *cs);
/**
* @synchronize_from_tb: Synchronize state from a TCG #TranslationBlock
*
* This is called when we abandon execution of a TB before starting it,
* and must set all parts of the CPU state which the previous TB in the
* chain may not have updated.
* By default, when this is NULL, a call is made to @set_pc(tb->pc).
*
* If more state needs to be restored, the target must implement a
* function to restore all the state, and register it here.
*/
void (*synchronize_from_tb)(CPUState *cpu, const TranslationBlock *tb);
/**
* @restore_state_to_opc: Synchronize state from INDEX_op_start_insn
*
* This is called when we unwind state in the middle of a TB,
* usually before raising an exception. Set all part of the CPU
* state which are tracked insn-by-insn in the target-specific
* arguments to start_insn, passed as @data.
*/
void (*restore_state_to_opc)(CPUState *cpu, const TranslationBlock *tb,
const uint64_t *data);
/** @cpu_exec_enter: Callback for cpu_exec preparation */
void (*cpu_exec_enter)(CPUState *cpu);
/** @cpu_exec_exit: Callback for cpu_exec cleanup */
void (*cpu_exec_exit)(CPUState *cpu);
/** @debug_excp_handler: Callback for handling debug exceptions */
void (*debug_excp_handler)(CPUState *cpu);
/** @mmu_index: Callback for choosing softmmu mmu index */
int (*mmu_index)(CPUState *cpu, bool ifetch);
#ifdef CONFIG_USER_ONLY
/**
* @fake_user_interrupt: Callback for 'fake exception' handling.
*
* Simulate 'fake exception' which will be handled outside the
* cpu execution loop (hack for x86 user mode).
*/
void (*fake_user_interrupt)(CPUState *cpu);
/**
* record_sigsegv:
* @cpu: cpu context
* @addr: faulting guest address
* @access_type: access was read/write/execute
* @maperr: true for invalid page, false for permission fault
* @ra: host pc for unwinding
*
* We are about to raise SIGSEGV with si_code set for @maperr,
* and si_addr set for @addr. Record anything further needed
* for the signal ucontext_t.
*
* If the emulated kernel does not provide anything to the signal
* handler with anything besides the user context registers, and
* the siginfo_t, then this hook need do nothing and may be omitted.
* Otherwise, record the data and return; the caller will raise
* the signal, unwind the cpu state, and return to the main loop.
*
* If it is simpler to re-use the sysemu tlb_fill code, @ra is provided
* so that a "normal" cpu exception can be raised. In this case,
* the signal must be raised by the architecture cpu_loop.
*/
void (*record_sigsegv)(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
bool maperr, uintptr_t ra);
/**
* record_sigbus:
* @cpu: cpu context
* @addr: misaligned guest address
* @access_type: access was read/write/execute
* @ra: host pc for unwinding
*
* We are about to raise SIGBUS with si_code BUS_ADRALN,
* and si_addr set for @addr. Record anything further needed
* for the signal ucontext_t.
*
* If the emulated kernel does not provide the signal handler with
* anything besides the user context registers, and the siginfo_t,
* then this hook need do nothing and may be omitted.
* Otherwise, record the data and return; the caller will raise
* the signal, unwind the cpu state, and return to the main loop.
*
* If it is simpler to re-use the sysemu do_unaligned_access code,
* @ra is provided so that a "normal" cpu exception can be raised.
* In this case, the signal must be raised by the architecture cpu_loop.
*/
void (*record_sigbus)(CPUState *cpu, vaddr addr,
MMUAccessType access_type, uintptr_t ra);
/**
* untagged_addr: Remove an ignored tag from an address
* @cpu: cpu context
* @addr: tagged guest address
*/
vaddr (*untagged_addr)(CPUState *cs, vaddr addr);
#else
/** @do_interrupt: Callback for interrupt handling. */
void (*do_interrupt)(CPUState *cpu);
/** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
/** @cpu_exec_reset: Callback for reset in cpu_exec. */
void (*cpu_exec_reset)(CPUState *cpu);
/**
* @cpu_exec_halt: Callback for handling halt in cpu_exec.
*
* The target CPU should do any special processing here that it needs
* to do when the CPU is in the halted state.
*
* Return true to indicate that the CPU should now leave halt, false
* if it should remain in the halted state. (This should generally
* be the same value that cpu_has_work() would return.)
*
* This method must be provided. If the target does not need to
* do anything special for halt, the same function used for its
* SysemuCPUOps::has_work method can be used here, as they have the
* same function signature.
*/
bool (*cpu_exec_halt)(CPUState *cpu);
/**
* @tlb_fill_align: Handle a softmmu tlb miss
* @cpu: cpu context
* @out: output page properties
* @addr: virtual address
* @access_type: read, write or execute
* @mmu_idx: mmu context
* @memop: memory operation for the access
* @size: memory access size, or 0 for whole page
* @probe: test only, no fault
* @ra: host return address for exception unwind
*
* If the access is valid, fill in @out and return true.
* Otherwise if probe is true, return false.
* Otherwise raise an exception and do not return.
*
* The alignment check for the access is deferred to this hook,
* so that the target can determine the priority of any alignment
* fault with respect to other potential faults from paging.
* Zero may be passed for @memop to skip any alignment check
* for non-memory-access operations such as probing.
*/
bool (*tlb_fill_align)(CPUState *cpu, CPUTLBEntryFull *out, vaddr addr,
MMUAccessType access_type, int mmu_idx,
MemOp memop, int size, bool probe, uintptr_t ra);
/**
* @tlb_fill: Handle a softmmu tlb miss
*
* If the access is valid, call tlb_set_page and return true;
* if the access is invalid and probe is true, return false;
* otherwise raise an exception and do not return.
*/
bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
/**
* @pointer_wrap:
*
* We have incremented @base to @result, resulting in a page change.
* For the current cpu state, adjust @result for possible overflow.
*/
vaddr (*pointer_wrap)(CPUState *cpu, int mmu_idx, vaddr result, vaddr base);
/**
* @do_transaction_failed: Callback for handling failed memory transactions
* (ie bus faults or external aborts; not MMU faults)
*/
void (*do_transaction_failed)(CPUState *cpu, hwaddr physaddr, vaddr addr,
unsigned size, MMUAccessType access_type,
int mmu_idx, MemTxAttrs attrs,
MemTxResult response, uintptr_t retaddr);
/**
* @do_unaligned_access: Callback for unaligned access handling
* The callback must exit via raising an exception.
*/
G_NORETURN void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr);
/**
* @adjust_watchpoint_address: hack for cpu_check_watchpoint (used by ARM)
*/
vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len);
/**
* @debug_check_watchpoint: return true if the architectural
* watchpoint whose address has matched should really fire.
*/
bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
/**
* @debug_check_breakpoint: return true if the architectural
* breakpoint whose PC has matched should really fire.
*/
bool (*debug_check_breakpoint)(CPUState *cpu);
/**
* @io_recompile_replay_branch: Callback for cpu_io_recompile.
*
* The cpu has been stopped, and cpu_restore_state_from_tb has been
* called. If the faulting instruction is in a delay slot, and the
* target architecture requires re-execution of the branch, then
* adjust the cpu state as required and return true.
*/
bool (*io_recompile_replay_branch)(CPUState *cpu,
const TranslationBlock *tb);
/**
* @need_replay_interrupt: Return %true if @interrupt_request
* needs to be recorded for replay purposes.
*/
bool (*need_replay_interrupt)(int interrupt_request);
#endif /* !CONFIG_USER_ONLY */
};
/**
* cpu_check_watchpoint:
* @cpu: cpu context
* @addr: guest virtual address
* @len: access length
* @attrs: memory access attributes
* @flags: watchpoint access type
* @ra: unwind return address
*
* Check for a watchpoint hit in [addr, addr+len) of the type
* specified by @flags. Exit via exception with a hit.
*/
void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
MemTxAttrs attrs, int flags, uintptr_t ra);
/**
* cpu_watchpoint_address_matches:
* @cpu: cpu context
* @addr: guest virtual address
* @len: access length
*
* Return the watchpoint flags that apply to [addr, addr+len).
* If no watchpoint is registered for the range, the result is 0.
*/
int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len);
/*
* Common pointer_wrap implementations.
*/
vaddr cpu_pointer_wrap_notreached(CPUState *, int, vaddr, vaddr);
vaddr cpu_pointer_wrap_uint32(CPUState *, int, vaddr, vaddr);
#endif /* TCG_CPU_OPS_H */
+24
View File
@@ -0,0 +1,24 @@
/*
* Get host pc for helper unwinding.
*
* Copyright (c) 2003 Fabrice Bellard
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_GETPC_H
#define ACCEL_TCG_GETPC_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
/* GETPC is the true target of the return instruction that we'll execute. */
#ifdef CONFIG_TCG_INTERPRETER
extern __thread uintptr_t tci_tb_ptr;
# define GETPC() tci_tb_ptr
#else
# define GETPC() \
((uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0)))
#endif
#endif /* ACCEL_TCG_GETPC_H */
+47
View File
@@ -0,0 +1,47 @@
/*
* Get user helper pc for memory unwinding.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_HELPER_RETADDR_H
#define ACCEL_TCG_HELPER_RETADDR_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
/*
* For user-only, helpers that use guest to host address translation
* must protect the actual host memory access by recording 'retaddr'
* for the signal handler. This is required for a race condition in
* which another thread unmaps the page between a probe and the
* actual access.
*/
#ifdef CONFIG_USER_ONLY
extern __thread uintptr_t helper_retaddr;
static inline void set_helper_retaddr(uintptr_t ra)
{
helper_retaddr = ra;
/*
* Ensure that this write is visible to the SIGSEGV handler that
* may be invoked due to a subsequent invalid memory operation.
*/
signal_barrier();
}
static inline void clear_helper_retaddr(void)
{
/*
* Ensure that previous memory operations have succeeded before
* removing the data visible to the signal handler.
*/
signal_barrier();
helper_retaddr = 0;
}
#else
#define set_helper_retaddr(ra) do { } while (0)
#define clear_helper_retaddr() do { } while (0)
#endif
#endif /* ACCEL_TCG_HELPER_RETADDR_H */
+33
View File
@@ -0,0 +1,33 @@
/*
* TCG IOMMU translations.
*
* Copyright (c) 2003 Fabrice Bellard
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_IOMMU_H
#define ACCEL_TCG_IOMMU_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#ifdef CONFIG_USER_ONLY
#error Cannot include accel/tcg/iommu.h from user emulation
#endif
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
void tcg_iommu_init_notifier_list(CPUState *cpu);
void tcg_iommu_free_notifier_list(CPUState *cpu);
MemoryRegionSection *address_space_translate_for_iotlb(CPUState *cpu,
int asidx,
hwaddr addr,
hwaddr *xlat,
hwaddr *plen,
MemTxAttrs attrs,
int *prot);
#endif
+126
View File
@@ -0,0 +1,126 @@
/*
* Probe guest virtual addresses for access permissions.
*
* Copyright (c) 2003 Fabrice Bellard
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_PROBE_H
#define ACCEL_TCG_PROBE_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "exec/mmu-access-type.h"
#include "exec/vaddr.h"
/**
* probe_access:
* @env: CPUArchState
* @addr: guest virtual address to look up
* @size: size of the access
* @access_type: read, write or execute permission
* @mmu_idx: MMU index to use for lookup
* @retaddr: return address for unwinding
*
* Look up the guest virtual address @addr. Raise an exception if the
* page does not satisfy @access_type. Raise an exception if the
* access (@addr, @size) hits a watchpoint. For writes, mark a clean
* page as dirty.
*
* Finally, return the host address for a page that is backed by RAM,
* or NULL if the page requires I/O.
*/
void *probe_access(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr);
static inline void *probe_write(CPUArchState *env, vaddr addr, int size,
int mmu_idx, uintptr_t retaddr)
{
return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr);
}
static inline void *probe_read(CPUArchState *env, vaddr addr, int size,
int mmu_idx, uintptr_t retaddr)
{
return probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr);
}
/**
* probe_access_flags:
* @env: CPUArchState
* @addr: guest virtual address to look up
* @size: size of the access
* @access_type: read, write or execute permission
* @mmu_idx: MMU index to use for lookup
* @nonfault: suppress the fault
* @phost: return value for host address
* @retaddr: return address for unwinding
*
* Similar to probe_access, loosely returning the TLB_FLAGS_MASK for
* the page, and storing the host address for RAM in @phost.
*
* If @nonfault is set, do not raise an exception but return TLB_INVALID_MASK.
* Do not handle watchpoints, but include TLB_WATCHPOINT in the returned flags.
* Do handle clean pages, so exclude TLB_NOTDIRY from the returned flags.
* For simplicity, all "mmio-like" flags are folded to TLB_MMIO.
*/
int probe_access_flags(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
bool nonfault, void **phost, uintptr_t retaddr);
#ifndef CONFIG_USER_ONLY
/**
* probe_access_full:
* Like probe_access_flags, except also return into @pfull.
*
* The CPUTLBEntryFull structure returned via @pfull is transient
* and must be consumed or copied immediately, before any further
* access or changes to TLB @mmu_idx.
*
* This function will not fault if @nonfault is set, but will
* return TLB_INVALID_MASK if the page is not mapped, or is not
* accessible with @access_type.
*
* This function will return TLB_MMIO in order to force the access
* to be handled out-of-line if plugins wish to instrument the access.
*/
int probe_access_full(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
bool nonfault, void **phost,
CPUTLBEntryFull **pfull, uintptr_t retaddr);
/**
* probe_access_full_mmu:
* Like probe_access_full, except:
*
* This function is intended to be used for page table accesses by
* the target mmu itself. Since such page walking happens while
* handling another potential mmu fault, this function never raises
* exceptions (akin to @nonfault true for probe_access_full).
* Likewise this function does not trigger plugin instrumentation.
*/
int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
void **phost, CPUTLBEntryFull **pfull);
#endif /* !CONFIG_USER_ONLY */
/**
* tlb_vaddr_to_host:
* @env: CPUArchState
* @addr: guest virtual address to look up
* @access_type: 0 for read, 1 for write, 2 for execute
* @mmu_idx: MMU index to use for lookup
*
* Look up the specified guest virtual index in the TCG softmmu TLB.
* If we can translate a host virtual address suitable for direct RAM
* access, without causing a guest exception, then return it.
* Otherwise (TLB entry is for an I/O access, guest software
* TLB fill required, etc) return NULL.
*/
void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr,
MMUAccessType access_type, int mmu_idx);
#endif
+22
View File
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Definition of TCGTBCPUState.
*/
#ifndef EXEC_TB_CPU_STATE_H
#define EXEC_TB_CPU_STATE_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "exec/vaddr.h"
typedef struct TCGTBCPUState {
vaddr pc;
uint32_t flags;
uint32_t cflags;
uint64_t cs_base;
} TCGTBCPUState;
#endif
+101
View File
@@ -0,0 +1,101 @@
/*
* QEMU authorization framework base class
*
* Copyright (c) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QAUTHZ_BASE_H
#define QAUTHZ_BASE_H
#include "qapi/error.h"
#include "qom/object.h"
#define TYPE_QAUTHZ "authz"
OBJECT_DECLARE_TYPE(QAuthZ, QAuthZClass,
QAUTHZ)
/**
* QAuthZ:
*
* The QAuthZ class defines an API contract to be used
* for providing an authorization driver for services
* with user identities.
*/
struct QAuthZ {
Object parent_obj;
};
struct QAuthZClass {
ObjectClass parent_class;
bool (*is_allowed)(QAuthZ *authz,
const char *identity,
Error **errp);
};
/**
* qauthz_is_allowed:
* @authz: the authorization object
* @identity: the user identity to authorize
* @errp: pointer to a NULL initialized error object
*
* Check if a user @identity is authorized. If an error
* occurs this method will return false to indicate
* denial, as well as setting @errp to contain the details.
* Callers are recommended to treat the denial and error
* scenarios identically. Specifically the error info in
* @errp should never be fed back to the user being
* authorized, it is merely for benefit of administrator
* debugging.
*
* Returns: true if @identity is authorized, false if denied or if
* an error occurred.
*/
bool qauthz_is_allowed(QAuthZ *authz,
const char *identity,
Error **errp);
/**
* qauthz_is_allowed_by_id:
* @authzid: ID of the authorization object
* @identity: the user identity to authorize
* @errp: pointer to a NULL initialized error object
*
* Check if a user @identity is authorized. If an error
* occurs this method will return false to indicate
* denial, as well as setting @errp to contain the details.
* Callers are recommended to treat the denial and error
* scenarios identically. Specifically the error info in
* @errp should never be fed back to the user being
* authorized, it is merely for benefit of administrator
* debugging.
*
* Returns: true if @identity is authorized, false if denied or if
* an error occurred.
*/
bool qauthz_is_allowed_by_id(const char *authzid,
const char *identity,
Error **errp);
#endif /* QAUTHZ_BASE_H */
+94
View File
@@ -0,0 +1,94 @@
/*
* QEMU list authorization driver
*
* Copyright (c) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QAUTHZ_LIST_H
#define QAUTHZ_LIST_H
#include "authz/base.h"
#include "qapi/qapi-types-authz.h"
#include "qom/object.h"
#define TYPE_QAUTHZ_LIST "authz-list"
OBJECT_DECLARE_SIMPLE_TYPE(QAuthZList,
QAUTHZ_LIST)
/**
* QAuthZList:
*
* This authorization driver provides a list mechanism
* for granting access by matching user names against a
* list of globs. Each match rule has an associated policy
* and a catch all policy applies if no rule matches
*
* To create an instance of this class via QMP:
*
* {
* "execute": "object-add",
* "arguments": {
* "qom-type": "authz-list",
* "id": "authz0",
* "props": {
* "rules": [
* { "match": "fred", "policy": "allow", "format": "exact" },
* { "match": "bob", "policy": "allow", "format": "exact" },
* { "match": "danb", "policy": "deny", "format": "exact" },
* { "match": "dan*", "policy": "allow", "format": "glob" }
* ],
* "policy": "deny"
* }
* }
* }
*
*/
struct QAuthZList {
QAuthZ parent_obj;
QAuthZListPolicy policy;
QAuthZListRuleList *rules;
};
QAuthZList *qauthz_list_new(const char *id,
QAuthZListPolicy policy,
Error **errp);
ssize_t qauthz_list_append_rule(QAuthZList *auth,
const char *match,
QAuthZListPolicy policy,
QAuthZListFormat format,
Error **errp);
ssize_t qauthz_list_insert_rule(QAuthZList *auth,
const char *match,
QAuthZListPolicy policy,
QAuthZListFormat format,
size_t index,
Error **errp);
ssize_t qauthz_list_delete_rule(QAuthZList *auth,
const char *match);
#endif /* QAUTHZ_LIST_H */
+97
View File
@@ -0,0 +1,97 @@
/*
* QEMU list file authorization driver
*
* Copyright (c) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QAUTHZ_LISTFILE_H
#define QAUTHZ_LISTFILE_H
#include "authz/list.h"
#include "qemu/filemonitor.h"
#include "qom/object.h"
#define TYPE_QAUTHZ_LIST_FILE "authz-list-file"
OBJECT_DECLARE_SIMPLE_TYPE(QAuthZListFile,
QAUTHZ_LIST_FILE)
/**
* QAuthZListFile:
*
* This authorization driver provides a file mechanism
* for granting access by matching user names against a
* file of globs. Each match rule has an associated policy
* and a catch all policy applies if no rule matches
*
* To create an instance of this class via QMP:
*
* {
* "execute": "object-add",
* "arguments": {
* "qom-type": "authz-list-file",
* "id": "authz0",
* "props": {
* "filename": "/etc/qemu/myvm-vnc.acl",
* "refresh": true
* }
* }
* }
*
* If 'refresh' is 'yes', inotify is used to monitor for changes
* to the file and auto-reload the rules.
*
* The myvm-vnc.acl file should contain the parameters for
* the QAuthZList object in JSON format:
*
* {
* "rules": [
* { "match": "fred", "policy": "allow", "format": "exact" },
* { "match": "bob", "policy": "allow", "format": "exact" },
* { "match": "danb", "policy": "deny", "format": "exact" },
* { "match": "dan*", "policy": "allow", "format": "glob" }
* ],
* "policy": "deny"
* }
*
* The object can be created on the command line using
*
* -object authz-list-file,id=authz0,\
* filename=/etc/qemu/myvm-vnc.acl,refresh=on
*
*/
struct QAuthZListFile {
QAuthZ parent_obj;
QAuthZ *list;
char *filename;
bool refresh;
QFileMonitor *file_monitor;
int64_t file_watch;
};
QAuthZListFile *qauthz_list_file_new(const char *id,
const char *filename,
bool refresh,
Error **errp);
#endif /* QAUTHZ_LISTFILE_H */
+88
View File
@@ -0,0 +1,88 @@
/*
* QEMU PAM authorization driver
*
* Copyright (c) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QAUTHZ_PAMACCT_H
#define QAUTHZ_PAMACCT_H
#include "authz/base.h"
#include "qom/object.h"
#define TYPE_QAUTHZ_PAM "authz-pam"
OBJECT_DECLARE_SIMPLE_TYPE(QAuthZPAM,
QAUTHZ_PAM)
/**
* QAuthZPAM:
*
* This authorization driver provides a PAM mechanism
* for granting access by matching user names against a
* list of globs. Each match rule has an associated policy
* and a catch all policy applies if no rule matches
*
* To create an instance of this class via QMP:
*
* {
* "execute": "object-add",
* "arguments": {
* "qom-type": "authz-pam",
* "id": "authz0",
* "parameters": {
* "service": "qemu-vnc-tls"
* }
* }
* }
*
* The driver only uses the PAM "account" verification
* subsystem. The above config would require a config
* file /etc/pam.d/qemu-vnc-tls. For a simple file
* lookup it would contain
*
* account requisite pam_listfile.so item=user sense=allow \
* file=/etc/qemu/vnc.allow
*
* The external file would then contain a list of usernames.
* If x509 cert was being used as the username, a suitable
* entry would match the distinguish name:
*
* CN=laptop.berrange.com,O=Berrange Home,L=London,ST=London,C=GB
*
* On the command line it can be created using
*
* -object authz-pam,id=authz0,service=qemu-vnc-tls
*
*/
struct QAuthZPAM {
QAuthZ parent_obj;
char *service;
};
QAuthZPAM *qauthz_pam_new(const char *id,
const char *service,
Error **errp);
#endif /* QAUTHZ_PAMACCT_H */
+72
View File
@@ -0,0 +1,72 @@
/*
* QEMU simple authorization driver
*
* Copyright (c) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QAUTHZ_SIMPLE_H
#define QAUTHZ_SIMPLE_H
#include "authz/base.h"
#include "qom/object.h"
#define TYPE_QAUTHZ_SIMPLE "authz-simple"
OBJECT_DECLARE_SIMPLE_TYPE(QAuthZSimple,
QAUTHZ_SIMPLE)
/**
* QAuthZSimple:
*
* This authorization driver provides a simple mechanism
* for granting access based on an exact matched username.
*
* To create an instance of this class via QMP:
*
* {
* "execute": "object-add",
* "arguments": {
* "qom-type": "authz-simple",
* "id": "authz0",
* "props": {
* "identity": "fred"
* }
* }
* }
*
* Or via the command line
*
* -object authz-simple,id=authz0,identity=fred
*
*/
struct QAuthZSimple {
QAuthZ parent_obj;
char *identity;
};
QAuthZSimple *qauthz_simple_new(const char *id,
const char *identity,
Error **errp);
#endif /* QAUTHZ_SIMPLE_H */
+126
View File
@@ -0,0 +1,126 @@
/*
* QEMU System Emulator block accounting
*
* Copyright (c) 2011 Christoph Hellwig
* Copyright (c) 2015 Igalia, S.L.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_ACCOUNTING_H
#define BLOCK_ACCOUNTING_H
#include "qemu/timed-average.h"
#include "qemu/thread.h"
#include "qapi/qapi-types-common.h"
typedef struct BlockAcctTimedStats BlockAcctTimedStats;
typedef struct BlockAcctStats BlockAcctStats;
enum BlockAcctType {
BLOCK_ACCT_NONE = 0,
BLOCK_ACCT_READ,
BLOCK_ACCT_WRITE,
BLOCK_ACCT_FLUSH,
BLOCK_ACCT_ZONE_APPEND,
BLOCK_ACCT_UNMAP,
BLOCK_MAX_IOTYPE,
};
struct BlockAcctTimedStats {
BlockAcctStats *stats;
TimedAverage latency[BLOCK_MAX_IOTYPE];
unsigned interval_length; /* in seconds */
QSLIST_ENTRY(BlockAcctTimedStats) entries;
};
typedef struct BlockLatencyHistogram {
/* The following histogram is represented like this:
*
* 5| *
* 4| *
* 3| * *
* 2| * * *
* 1| * * * *
* +------------------
* 10 50 100
*
* BlockLatencyHistogram histogram = {
* .nbins = 4,
* .boundaries = {10, 50, 100},
* .bins = {3, 1, 5, 2},
* };
*
* @boundaries array define histogram intervals as follows:
* [0, boundaries[0]), [boundaries[0], boundaries[1]), ...
* [boundaries[nbins-2], +inf)
*
* So, for example above, histogram intervals are:
* [0, 10), [10, 50), [50, 100), [100, +inf)
*/
int nbins;
uint64_t *boundaries; /* @nbins-1 numbers here
(all boundaries, except 0 and +inf) */
uint64_t *bins;
} BlockLatencyHistogram;
struct BlockAcctStats {
QemuMutex lock;
uint64_t nr_bytes[BLOCK_MAX_IOTYPE];
uint64_t nr_ops[BLOCK_MAX_IOTYPE];
uint64_t invalid_ops[BLOCK_MAX_IOTYPE];
uint64_t failed_ops[BLOCK_MAX_IOTYPE];
uint64_t total_time_ns[BLOCK_MAX_IOTYPE];
uint64_t merged[BLOCK_MAX_IOTYPE];
int64_t last_access_time_ns;
QSLIST_HEAD(, BlockAcctTimedStats) intervals;
bool account_invalid;
bool account_failed;
BlockLatencyHistogram latency_histogram[BLOCK_MAX_IOTYPE];
};
typedef struct BlockAcctCookie {
int64_t bytes;
int64_t start_time_ns;
enum BlockAcctType type;
} BlockAcctCookie;
void block_acct_init(BlockAcctStats *stats);
bool block_acct_setup(BlockAcctStats *stats, enum OnOffAuto account_invalid,
enum OnOffAuto account_failed, uint32_t *stats_intervals,
uint32_t num_stats_intervals, Error **errp);
void block_acct_cleanup(BlockAcctStats *stats);
void block_acct_add_interval(BlockAcctStats *stats, unsigned interval_length);
BlockAcctTimedStats *block_acct_interval_next(BlockAcctStats *stats,
BlockAcctTimedStats *s);
void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
int64_t bytes, enum BlockAcctType type);
void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie);
void block_acct_failed(BlockAcctStats *stats, BlockAcctCookie *cookie);
void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type);
void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
int num_requests);
int64_t block_acct_idle_time_ns(BlockAcctStats *stats);
/* Caller must hold stats->stats->lock. */
double block_acct_queue_depth(BlockAcctTimedStats *stats,
enum BlockAcctType type);
int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type,
uint64List *boundaries);
void block_latency_histograms_clear(BlockAcctStats *stats);
#endif
+50
View File
@@ -0,0 +1,50 @@
/*
* Aio tasks loops
*
* Copyright (c) 2019 Virtuozzo International GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_AIO_TASK_H
#define BLOCK_AIO_TASK_H
typedef struct AioTaskPool AioTaskPool;
typedef struct AioTask AioTask;
typedef int coroutine_fn (*AioTaskFunc)(AioTask *task);
struct AioTask {
AioTaskPool *pool;
AioTaskFunc func;
int ret;
};
AioTaskPool *coroutine_fn aio_task_pool_new(int max_busy_tasks);
void aio_task_pool_free(AioTaskPool *);
/* error code of failed task or 0 if all is OK */
int aio_task_pool_status(AioTaskPool *pool);
/* User provides filled @task, however task->pool will be set automatically */
void coroutine_fn aio_task_pool_start_task(AioTaskPool *pool, AioTask *task);
void coroutine_fn aio_task_pool_wait_slot(AioTaskPool *pool);
void coroutine_fn aio_task_pool_wait_one(AioTaskPool *pool);
void coroutine_fn aio_task_pool_wait_all(AioTaskPool *pool);
#endif /* BLOCK_AIO_TASK_H */
+587
View File
@@ -0,0 +1,587 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_COMMON_H
#define BLOCK_COMMON_H
#include "qapi/qapi-types-block-core.h"
#include "qemu/queue.h"
/*
* co_wrapper{*}: Function specifiers used by block-coroutine-wrapper.py
*
* Function specifiers, which do nothing but mark functions to be
* generated by scripts/block-coroutine-wrapper.py
*
* Usage: read docs/devel/block-coroutine-wrapper.rst
*
* There are 4 kind of specifiers:
* - co_wrapper functions can be called by only non-coroutine context, because
* they always generate a new coroutine.
* - co_wrapper_mixed functions can be called by both coroutine and
* non-coroutine context.
* - co_wrapper_bdrv_rdlock are co_wrapper functions but automatically take and
* release the graph rdlock when creating a new coroutine
* - co_wrapper_mixed_bdrv_rdlock are co_wrapper_mixed functions but
* automatically take and release the graph rdlock when creating a new
* coroutine.
*
* These functions should not be called from a coroutine_fn; instead,
* call the wrapped function directly.
*/
#define co_wrapper no_coroutine_fn
#define co_wrapper_mixed no_coroutine_fn coroutine_mixed_fn
#define co_wrapper_bdrv_rdlock no_coroutine_fn
#define co_wrapper_mixed_bdrv_rdlock no_coroutine_fn coroutine_mixed_fn
/*
* no_co_wrapper: Function specifier used by block-coroutine-wrapper.py
*
* Function specifier which does nothing but mark functions to be generated by
* scripts/block-coroutine-wrapper.py.
*
* A no_co_wrapper function declaration creates a coroutine_fn wrapper around
* functions that must not be called in coroutine context. It achieves this by
* scheduling a BH in the bottom half that runs the respective non-coroutine
* function. The coroutine yields after scheduling the BH and is reentered when
* the wrapped function returns.
*
* A no_co_wrapper_bdrv_rdlock function is a no_co_wrapper function that
* automatically takes the graph rdlock when calling the wrapped function. In
* the same way, no_co_wrapper_bdrv_wrlock functions automatically take the
* graph wrlock.
*/
#define no_co_wrapper
#define no_co_wrapper_bdrv_rdlock
#define no_co_wrapper_bdrv_wrlock
#include "block/blockjob.h"
/* block.c */
typedef struct BlockDriver BlockDriver;
typedef struct BdrvChild BdrvChild;
typedef struct BdrvChildClass BdrvChildClass;
typedef enum BlockZoneOp {
BLK_ZO_OPEN,
BLK_ZO_CLOSE,
BLK_ZO_FINISH,
BLK_ZO_RESET,
} BlockZoneOp;
typedef enum BlockZoneModel {
BLK_Z_NONE = 0x0, /* Regular block device */
BLK_Z_HM = 0x1, /* Host-managed zoned block device */
BLK_Z_HA = 0x2, /* Host-aware zoned block device */
} BlockZoneModel;
typedef enum BlockZoneState {
BLK_ZS_NOT_WP = 0x0,
BLK_ZS_EMPTY = 0x1,
BLK_ZS_IOPEN = 0x2,
BLK_ZS_EOPEN = 0x3,
BLK_ZS_CLOSED = 0x4,
BLK_ZS_RDONLY = 0xD,
BLK_ZS_FULL = 0xE,
BLK_ZS_OFFLINE = 0xF,
} BlockZoneState;
typedef enum BlockZoneType {
BLK_ZT_CONV = 0x1, /* Conventional random writes supported */
BLK_ZT_SWR = 0x2, /* Sequential writes required */
BLK_ZT_SWP = 0x3, /* Sequential writes preferred */
} BlockZoneType;
/*
* Zone descriptor data structure.
* Provides information on a zone with all position and size values in bytes.
*/
typedef struct BlockZoneDescriptor {
uint64_t start;
uint64_t length;
uint64_t cap;
uint64_t wp;
BlockZoneType type;
BlockZoneState state;
} BlockZoneDescriptor;
/*
* Track write pointers of a zone in bytes.
*/
typedef struct BlockZoneWps {
CoMutex colock;
uint64_t wp[];
} BlockZoneWps;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
int cluster_size;
/*
* A fraction of cluster_size, if supported (currently QCOW2 only); if
* disabled or unsupported, set equal to cluster_size.
*/
int subcluster_size;
/* offset at which the VM state can be saved (0 if not possible) */
int64_t vm_state_offset;
bool is_dirty;
/*
* True if this block driver only supports compressed writes
*/
bool needs_compressed_writes;
} BlockDriverInfo;
typedef struct BlockFragInfo {
uint64_t allocated_clusters;
uint64_t total_clusters;
uint64_t fragmented_clusters;
uint64_t compressed_clusters;
} BlockFragInfo;
typedef enum {
BDRV_REQ_COPY_ON_READ = 0x1,
BDRV_REQ_ZERO_WRITE = 0x2,
/*
* The BDRV_REQ_MAY_UNMAP flag is used in write_zeroes requests to indicate
* that the block driver should unmap (discard) blocks if it is guaranteed
* that the result will read back as zeroes. The flag is only passed to the
* driver if the block device is opened with BDRV_O_UNMAP.
*/
BDRV_REQ_MAY_UNMAP = 0x4,
/*
* An optimization hint when all QEMUIOVector elements are within
* previously registered bdrv_register_buf() memory ranges.
*
* Code that replaces the user's QEMUIOVector elements with bounce buffers
* must take care to clear this flag.
*/
BDRV_REQ_REGISTERED_BUF = 0x8,
BDRV_REQ_FUA = 0x10,
BDRV_REQ_WRITE_COMPRESSED = 0x20,
/*
* Signifies that this write request will not change the visible disk
* content.
*/
BDRV_REQ_WRITE_UNCHANGED = 0x40,
/*
* Forces request serialisation. Use only with write requests.
*/
BDRV_REQ_SERIALISING = 0x80,
/*
* Execute the request only if the operation can be offloaded or otherwise
* be executed efficiently, but return an error instead of using a slow
* fallback.
*/
BDRV_REQ_NO_FALLBACK = 0x100,
/*
* BDRV_REQ_PREFETCH makes sense only in the context of copy-on-read
* (i.e., together with the BDRV_REQ_COPY_ON_READ flag or when a COR
* filter is involved), in which case it signals that the COR operation
* need not read the data into memory (qiov) but only ensure they are
* copied to the top layer (i.e., that COR operation is done).
*/
BDRV_REQ_PREFETCH = 0x200,
/*
* If we need to wait for other requests, just fail immediately. Used
* only together with BDRV_REQ_SERIALISING. Used only with requests aligned
* to request_alignment (corresponding assertions are in block/io.c).
*/
BDRV_REQ_NO_WAIT = 0x400,
/*
* Used between blk_co_start_request() and blk_end_request() to avoid
* that the request waits in a drained BlockBackend until the drained
* section ends. Waiting would cause a deadlock because drain waits for
* blk_end_request() to be called, but the request never completes
* because it waits for the drain to end.
*/
BDRV_REQ_NO_QUEUE = 0x800,
/* Mask of valid flags */
BDRV_REQ_MASK = 0xfff,
} BdrvRequestFlags;
#define BDRV_O_NO_SHARE 0x0001 /* don't share permissions */
#define BDRV_O_RDWR 0x0002
#define BDRV_O_RESIZE 0x0004 /* request permission for resizing the node */
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save
writes in a snapshot */
#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the
thread pool */
#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
#define BDRV_O_INACTIVE 0x0800 /* consistency hint for migration handoff */
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */
#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */
#define BDRV_O_PROTOCOL 0x8000 /* if no block driver is explicitly given:
select an appropriate protocol driver,
ignoring the format layer */
#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */
#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening
read-write fails */
#define BDRV_O_IO_URING 0x40000 /* use io_uring instead of the thread pool */
#define BDRV_O_CBW_DISCARD_SOURCE 0x80000 /* for copy-before-write filter */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
/* Option names of options parsed by the block layer */
#define BDRV_OPT_CACHE_WB "cache.writeback"
#define BDRV_OPT_CACHE_DIRECT "cache.direct"
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
#define BDRV_OPT_READ_ONLY "read-only"
#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only"
#define BDRV_OPT_DISCARD "discard"
#define BDRV_OPT_FORCE_SHARE "force-share"
#define BDRV_OPT_ACTIVE "active"
#define BDRV_SECTOR_BITS 9
#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS)
/*
* Get the first most significant bit of wp. If it is zero, then
* the zone type is SWR.
*/
#define BDRV_ZT_IS_CONV(wp) (wp & (1ULL << 63))
#define BDRV_REQUEST_MAX_SECTORS MIN_CONST(SIZE_MAX >> BDRV_SECTOR_BITS, \
INT_MAX >> BDRV_SECTOR_BITS)
#define BDRV_REQUEST_MAX_BYTES (BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS)
/*
* We want allow aligning requests and disk length up to any 32bit alignment
* and don't afraid of overflow.
* To achieve it, and in the same time use some pretty number as maximum disk
* size, let's define maximum "length" (a limit for any offset/bytes request and
* for disk size) to be the greatest power of 2 less than INT64_MAX.
*/
#define BDRV_MAX_ALIGNMENT (1L << 30)
#define BDRV_MAX_LENGTH (QEMU_ALIGN_DOWN(INT64_MAX, BDRV_MAX_ALIGNMENT))
/*
* Allocation status flags for bdrv_block_status() and friends.
*
* Public flags:
* BDRV_BLOCK_DATA: allocation for data at offset is tied to this layer
* BDRV_BLOCK_ZERO: offset reads as zero
* BDRV_BLOCK_OFFSET_VALID: an associated offset exists for accessing raw data
* BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
* layer rather than any backing, set by block layer
* BDRV_BLOCK_EOF: the returned pnum covers through end of file for this
* layer, set by block layer
* BDRV_BLOCK_COMPRESSED: the underlying data is compressed; only valid for
* the formats supporting compression: qcow, qcow2
*
* Internal flags:
* BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request
* that the block layer recompute the answer from the returned
* BDS; must be accompanied by just BDRV_BLOCK_OFFSET_VALID.
* BDRV_BLOCK_RECURSE: request that the block layer will recursively search for
* zeroes in file child of current block node inside
* returned region. Only valid together with both
* BDRV_BLOCK_DATA and BDRV_BLOCK_OFFSET_VALID. Should not
* appear with BDRV_BLOCK_ZERO.
*
* If BDRV_BLOCK_OFFSET_VALID is set, the map parameter represents the
* host offset within the returned BDS that is allocated for the
* corresponding raw guest data. However, whether that offset
* actually contains data also depends on BDRV_BLOCK_DATA, as follows:
*
* DATA ZERO OFFSET_VALID
* t t t sectors read as zero, returned file is zero at offset
* t f t sectors read as valid from file at offset
* f t t sectors preallocated, read as zero, returned file not
* necessarily zero at offset
* f f t sectors preallocated but read from backing_hd,
* returned file contains garbage at offset
* t t f sectors preallocated, read as zero, unknown offset
* t f f sectors read from unknown file or offset
* f t f not allocated or unknown offset, read as zero
* f f f not allocated or unknown offset, read from backing_hd
*/
#define BDRV_BLOCK_DATA 0x01
#define BDRV_BLOCK_ZERO 0x02
#define BDRV_BLOCK_OFFSET_VALID 0x04
#define BDRV_BLOCK_RAW 0x08
#define BDRV_BLOCK_ALLOCATED 0x10
#define BDRV_BLOCK_EOF 0x20
#define BDRV_BLOCK_RECURSE 0x40
#define BDRV_BLOCK_COMPRESSED 0x80
/*
* Block status hints: the bitwise-or of these flags emphasize what
* the caller hopes to learn, and some drivers may be able to give
* faster answers by doing less work when the hint permits.
*/
#define BDRV_WANT_ZERO BDRV_BLOCK_ZERO
#define BDRV_WANT_OFFSET_VALID BDRV_BLOCK_OFFSET_VALID
#define BDRV_WANT_ALLOCATED BDRV_BLOCK_ALLOCATED
#define BDRV_WANT_PRECISE (BDRV_WANT_ZERO | BDRV_WANT_OFFSET_VALID | \
BDRV_WANT_OFFSET_VALID)
typedef QTAILQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
typedef struct BDRVReopenState {
BlockDriverState *bs;
int flags;
BlockdevDetectZeroesOptions detect_zeroes;
bool backing_missing;
BlockDriverState *old_backing_bs; /* keep pointer for permissions update */
BlockDriverState *old_file_bs; /* keep pointer for permissions update */
QDict *options;
QDict *explicit_options;
void *opaque;
} BDRVReopenState;
/*
* Block operation types
*/
typedef enum BlockOpType {
BLOCK_OP_TYPE_BACKUP_SOURCE,
BLOCK_OP_TYPE_BACKUP_TARGET,
BLOCK_OP_TYPE_CHANGE,
BLOCK_OP_TYPE_COMMIT_SOURCE,
BLOCK_OP_TYPE_COMMIT_TARGET,
BLOCK_OP_TYPE_DRIVE_DEL,
BLOCK_OP_TYPE_EJECT,
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
BLOCK_OP_TYPE_MIRROR_SOURCE,
BLOCK_OP_TYPE_MIRROR_TARGET,
BLOCK_OP_TYPE_RESIZE,
BLOCK_OP_TYPE_STREAM,
BLOCK_OP_TYPE_REPLACE,
BLOCK_OP_TYPE_MAX,
} BlockOpType;
/* Block node permission constants */
enum {
/**
* A user that has the "permission" of consistent reads is guaranteed that
* their view of the contents of the block device is complete and
* self-consistent, representing the contents of a disk at a specific
* point.
*
* For most block devices (including their backing files) this is true, but
* the property cannot be maintained in a few situations like for
* intermediate nodes of a commit block job.
*/
BLK_PERM_CONSISTENT_READ = 0x01,
/** This permission is required to change the visible disk contents. */
BLK_PERM_WRITE = 0x02,
/**
* This permission (which is weaker than BLK_PERM_WRITE) is both enough and
* required for writes to the block node when the caller promises that
* the visible disk content doesn't change.
*
* As the BLK_PERM_WRITE permission is strictly stronger, either is
* sufficient to perform an unchanging write.
*/
BLK_PERM_WRITE_UNCHANGED = 0x04,
/** This permission is required to change the size of a block node. */
BLK_PERM_RESIZE = 0x08,
/**
* There was a now-removed bit BLK_PERM_GRAPH_MOD, with value of 0x10. QEMU
* 6.1 and earlier may still lock the corresponding byte in block/file-posix
* locking. So, implementing some new permission should be very careful to
* not interfere with this old unused thing.
*/
BLK_PERM_ALL = 0x0f,
DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ
| BLK_PERM_WRITE
| BLK_PERM_WRITE_UNCHANGED
| BLK_PERM_RESIZE,
DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH,
};
/*
* Flags that parent nodes assign to child nodes to specify what kind of
* role(s) they take.
*
* At least one of DATA, METADATA, FILTERED, or COW must be set for
* every child.
*
*
* = Connection with bs->children, bs->file and bs->backing fields =
*
* 1. Filters
*
* Filter drivers have drv->is_filter = true.
*
* Filter node has exactly one FILTERED|PRIMARY child, and may have other
* children which must not have these bits (one example is the
* copy-before-write filter, which also has its target DATA child).
*
* Filter nodes never have COW children.
*
* For most filters, the filtered child is linked in bs->file, bs->backing is
* NULL. For some filters (as an exception), it is the other way around; those
* drivers will have drv->filtered_child_is_backing set to true (see that
* fields documentation for what drivers this concerns)
*
* 2. "raw" driver (block/raw-format.c)
*
* Formally it's not a filter (drv->is_filter = false)
*
* bs->backing is always NULL
*
* Only has one child, linked in bs->file. Its role is either FILTERED|PRIMARY
* (like filter) or DATA|PRIMARY depending on options.
*
* 3. Other drivers
*
* Don't have any FILTERED children.
*
* May have at most one COW child. In this case it's linked in bs->backing.
* Otherwise bs->backing is NULL. COW child is never PRIMARY.
*
* May have at most one PRIMARY child. In this case it's linked in bs->file.
* Otherwise bs->file is NULL.
*
* May also have some other children that don't have the PRIMARY or COW bit set.
*/
enum BdrvChildRoleBits {
/*
* This child stores data.
* Any node may have an arbitrary number of such children.
*/
BDRV_CHILD_DATA = (1 << 0),
/*
* This child stores metadata.
* Any node may have an arbitrary number of metadata-storing
* children.
*/
BDRV_CHILD_METADATA = (1 << 1),
/*
* A child that always presents exactly the same visible data as
* the parent, e.g. by virtue of the parent forwarding all reads
* and writes.
* This flag is mutually exclusive with DATA, METADATA, and COW.
* Any node may have at most one filtered child at a time.
*/
BDRV_CHILD_FILTERED = (1 << 2),
/*
* Child from which to read all data that isn't allocated in the
* parent (i.e., the backing child); such data is copied to the
* parent through COW (and optionally COR).
* This field is mutually exclusive with DATA, METADATA, and
* FILTERED.
* Any node may have at most one such backing child at a time.
*/
BDRV_CHILD_COW = (1 << 3),
/*
* The primary child. For most drivers, this is the child whose
* filename applies best to the parent node.
* Any node may have at most one primary child at a time.
*/
BDRV_CHILD_PRIMARY = (1 << 4),
/* Useful combination of flags */
BDRV_CHILD_IMAGE = BDRV_CHILD_DATA
| BDRV_CHILD_METADATA
| BDRV_CHILD_PRIMARY,
};
/* Mask of BdrvChildRoleBits values */
typedef unsigned int BdrvChildRole;
typedef struct BdrvCheckResult {
int corruptions;
int leaks;
int check_errors;
int corruptions_fixed;
int leaks_fixed;
int64_t image_end_offset;
BlockFragInfo bfi;
} BdrvCheckResult;
typedef enum {
BDRV_FIX_LEAKS = 1,
BDRV_FIX_ERRORS = 2,
} BdrvCheckMode;
typedef struct BlockSizes {
uint32_t phys;
uint32_t log;
} BlockSizes;
typedef struct HDGeometry {
uint32_t heads;
uint32_t sectors;
uint32_t cylinders;
} HDGeometry;
/*
* Common functions that are neither I/O nor Global State.
*
* These functions must never call any function from other categories
* (I/O, "I/O or GS", Global State) except this one, but can be invoked by
* all of them.
*/
char *bdrv_perm_names(uint64_t perm);
uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
void bdrv_init_with_whitelist(void);
bool bdrv_uses_whitelist(void);
int bdrv_is_whitelisted(BlockDriver *drv, bool read_only);
int bdrv_parse_aio(const char *mode, int *flags);
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough);
int bdrv_parse_discard_flags(const char *mode, int *flags);
int path_has_protocol(const char *path);
int path_is_absolute(const char *path);
char *path_combine(const char *base_path, const char *filename);
char *bdrv_get_full_backing_filename_from_filename(const char *backed,
const char *backing,
Error **errp);
#endif /* BLOCK_COMMON_H */
+105
View File
@@ -0,0 +1,105 @@
/*
* block_copy API
*
* Copyright (C) 2013 Proxmox Server Solutions
* Copyright (c) 2019 Virtuozzo International GmbH.
*
* Authors:
* Dietmar Maurer ([email protected])
* Vladimir Sementsov-Ogievskiy <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef BLOCK_COPY_H
#define BLOCK_COPY_H
#include "block/block-common.h"
#include "block/graph-lock.h"
#include "qemu/progress_meter.h"
/* All APIs are thread-safe */
typedef void (*BlockCopyAsyncCallbackFunc)(void *opaque);
typedef struct BlockCopyState BlockCopyState;
typedef struct BlockCopyCallState BlockCopyCallState;
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
BlockDriverState *copy_bitmap_bs,
const BdrvDirtyBitmap *bitmap,
bool discard_source,
uint64_t min_cluster_size,
Error **errp);
/* Function should be called prior any actual copy request */
void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
bool compress);
void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm);
void block_copy_state_free(BlockCopyState *s);
void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes);
int64_t coroutine_fn GRAPH_RDLOCK
block_copy_reset_unallocated(BlockCopyState *s, int64_t offset, int64_t *count);
int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
bool ignore_ratelimit, uint64_t timeout_ns,
BlockCopyAsyncCallbackFunc cb,
void *cb_opaque);
/*
* Run block-copy in a coroutine, create corresponding BlockCopyCallState
* object and return pointer to it. Never returns NULL.
*
* Caller is responsible to call block_copy_call_free() to free
* BlockCopyCallState object.
*
* @max_workers means maximum of parallel coroutines to execute sub-requests,
* must be > 0.
*
* @max_chunk means maximum length for one IO operation. Zero means unlimited.
*/
BlockCopyCallState *block_copy_async(BlockCopyState *s,
int64_t offset, int64_t bytes,
int max_workers, int64_t max_chunk,
BlockCopyAsyncCallbackFunc cb,
void *cb_opaque);
/*
* Free finished BlockCopyCallState. Trying to free running
* block-copy will crash.
*/
void block_copy_call_free(BlockCopyCallState *call_state);
/*
* Note, that block-copy call is marked finished prior to calling
* the callback.
*/
bool block_copy_call_finished(BlockCopyCallState *call_state);
bool block_copy_call_succeeded(BlockCopyCallState *call_state);
bool block_copy_call_failed(BlockCopyCallState *call_state);
bool block_copy_call_cancelled(BlockCopyCallState *call_state);
int block_copy_call_status(BlockCopyCallState *call_state, bool *error_is_read);
void block_copy_set_speed(BlockCopyState *s, uint64_t speed);
void block_copy_kick(BlockCopyCallState *call_state);
/*
* Cancel running block-copy call.
*
* Cancel leaves block-copy state valid: dirty bits are correct and you may use
* cancel + <run block_copy with same parameters> to emulate pause/resume.
*
* Note also, that the cancel is async: it only marks block-copy call to be
* cancelled. So, the call may be cancelled (block_copy_call_cancelled() reports
* true) but not yet finished (block_copy_call_finished() reports false).
*/
void block_copy_call_cancel(BlockCopyCallState *call_state);
BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s);
int64_t block_copy_cluster_size(BlockCopyState *s);
void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip);
#endif /* BLOCK_COPY_H */
+321
View File
@@ -0,0 +1,321 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_GLOBAL_STATE_H
#define BLOCK_GLOBAL_STATE_H
#include "qemu/aiocb.h"
#include "block/graph-lock.h"
#include "block/block-common.h"
#include "qemu/coroutine.h"
#include "qemu/transactions.h"
/*
* Global state (GS) API. These functions run under the BQL.
*
* If a function modifies the graph, it also uses the graph lock to be sure it
* has unique access. The graph lock is needed together with BQL because of the
* thread-safe I/O API that concurrently runs and accesses the graph without
* the BQL.
*
* It is important to note that not all of these functions are
* necessarily limited to running under the BQL, but they would
* require additional auditing and many small thread-safety changes
* to move them into the I/O API. Often it's not worth doing that
* work since the APIs are only used with the BQL held at the
* moment, so they have been placed in the GS API (for now).
*
* These functions can call any function from this and other categories
* (I/O, "I/O or GS", Common), but must be invoked only by other GS APIs.
*
* All functions in this header must use the macro
* GLOBAL_STATE_CODE();
* to catch when they are accidentally called without the BQL.
*/
void bdrv_init(void);
BlockDriver *bdrv_find_protocol(const char *filename,
bool allow_protocol_prefix,
Error **errp);
BlockDriver *bdrv_find_format(const char *format_name);
int coroutine_fn GRAPH_UNLOCKED
bdrv_co_create(BlockDriver *drv, const char *filename, QemuOpts *opts,
Error **errp);
int co_wrapper bdrv_create(BlockDriver *drv, const char *filename,
QemuOpts *opts, Error **errp);
int coroutine_fn GRAPH_UNLOCKED
bdrv_co_create_file(const char *filename, QemuOpts *opts,
bool allow_protocol_prefix, Error **errp);
BlockDriverState *bdrv_new(void);
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
Error **errp);
int GRAPH_WRLOCK
bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp);
int GRAPH_UNLOCKED
bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, Error **errp);
BlockDriverState * GRAPH_UNLOCKED
bdrv_insert_node(BlockDriverState *bs, QDict *node_options, int flags,
Error **errp);
int bdrv_drop_filter(BlockDriverState *bs, Error **errp);
BdrvChild * no_coroutine_fn GRAPH_UNLOCKED
bdrv_open_child(const char *filename, QDict *options, const char *bdref_key,
BlockDriverState *parent, const BdrvChildClass *child_class,
BdrvChildRole child_role, bool allow_none, Error **errp);
BdrvChild * coroutine_fn no_co_wrapper
bdrv_co_open_child(const char *filename, QDict *options, const char *bdref_key,
BlockDriverState *parent, const BdrvChildClass *child_class,
BdrvChildRole child_role, bool allow_none, Error **errp);
int GRAPH_UNLOCKED
bdrv_open_file_child(const char *filename, QDict *options,
const char *bdref_key, BlockDriverState *parent,
Error **errp);
BlockDriverState * no_coroutine_fn
bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
BlockDriverState * coroutine_fn no_co_wrapper
bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp);
int GRAPH_WRLOCK
bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp);
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
const char *bdref_key, Error **errp);
BlockDriverState * no_coroutine_fn
bdrv_open(const char *filename, const char *reference, QDict *options,
int flags, Error **errp);
BlockDriverState * coroutine_fn no_co_wrapper
bdrv_co_open(const char *filename, const char *reference,
QDict *options, int flags, Error **errp);
BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv,
const char *node_name,
QDict *options, int flags,
Error **errp);
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
int flags, Error **errp);
BlockReopenQueue * GRAPH_UNLOCKED
bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs,
QDict *options, bool keep_old_opts);
void bdrv_reopen_queue_free(BlockReopenQueue *bs_queue);
int GRAPH_UNLOCKED
bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
int bdrv_reopen(BlockDriverState *bs, QDict *opts, bool keep_old_opts,
Error **errp);
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
Error **errp);
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file);
void GRAPH_RDLOCK bdrv_refresh_filename(BlockDriverState *bs);
void GRAPH_RDLOCK
bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp);
int bdrv_commit(BlockDriverState *bs);
int GRAPH_RDLOCK bdrv_make_empty(BdrvChild *c, Error **errp);
void bdrv_register(BlockDriver *bdrv);
int GRAPH_UNLOCKED
bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
const char *backing_file_str,
bool backing_mask_protocol);
BlockDriverState * GRAPH_RDLOCK
bdrv_find_overlay(BlockDriverState *active, BlockDriverState *bs);
BlockDriverState * GRAPH_RDLOCK bdrv_find_base(BlockDriverState *bs);
int GRAPH_RDLOCK
bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
Error **errp);
void GRAPH_RDLOCK
bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
/*
* The units of offset and total_work_size may be chosen arbitrarily by the
* block driver; total_work_size may change during the course of the amendment
* operation
*/
typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset,
int64_t total_work_size, void *opaque);
int GRAPH_RDLOCK
bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
bool force, Error **errp);
/* check if a named node can be replaced when doing drive-mirror */
BlockDriverState * GRAPH_RDLOCK
check_to_replace_node(BlockDriverState *parent_bs, const char *node_name,
Error **errp);
bool GRAPH_RDLOCK bdrv_is_inactive(BlockDriverState *bs);
int no_coroutine_fn GRAPH_RDLOCK
bdrv_activate(BlockDriverState *bs, Error **errp);
int coroutine_fn no_co_wrapper_bdrv_rdlock
bdrv_co_activate(BlockDriverState *bs, Error **errp);
int no_coroutine_fn GRAPH_RDLOCK
bdrv_inactivate(BlockDriverState *bs, Error **errp);
void bdrv_activate_all(Error **errp);
int GRAPH_UNLOCKED bdrv_inactivate_all(void);
int bdrv_flush_all(void);
void GRAPH_UNLOCKED bdrv_close_all(void);
void GRAPH_UNLOCKED bdrv_drain_all_begin(void);
void bdrv_drain_all_begin_nopoll(void);
void bdrv_drain_all_end(void);
void GRAPH_UNLOCKED bdrv_drain_all(void);
void bdrv_aio_cancel(BlockAIOCB *acb);
int bdrv_has_zero_init_1(BlockDriverState *bs);
int coroutine_mixed_fn GRAPH_RDLOCK bdrv_has_zero_init(BlockDriverState *bs);
BlockDriverState *bdrv_find_node(const char *node_name);
BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp);
XDbgBlockGraph * GRAPH_RDLOCK bdrv_get_xdbg_block_graph(Error **errp);
BlockDriverState *bdrv_lookup_bs(const char *device,
const char *node_name,
Error **errp);
bool GRAPH_RDLOCK
bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base);
BlockDriverState *bdrv_next_node(BlockDriverState *bs);
BlockDriverState *bdrv_next_all_states(BlockDriverState *bs);
typedef struct BdrvNextIterator {
enum {
BDRV_NEXT_BACKEND_ROOTS,
BDRV_NEXT_MONITOR_OWNED,
} phase;
BlockBackend *blk;
BlockDriverState *bs;
} BdrvNextIterator;
BlockDriverState * GRAPH_RDLOCK bdrv_first(BdrvNextIterator *it);
BlockDriverState * GRAPH_RDLOCK bdrv_next(BdrvNextIterator *it);
void bdrv_next_cleanup(BdrvNextIterator *it);
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque, bool read_only);
char * GRAPH_RDLOCK
bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
char * GRAPH_RDLOCK bdrv_dirname(BlockDriverState *bs, Error **errp);
void bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags,
bool quiet, Error **errp);
void bdrv_ref(BlockDriverState *bs);
void no_coroutine_fn bdrv_unref(BlockDriverState *bs);
void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs);
void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs);
void GRAPH_WRLOCK
bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
void coroutine_fn no_co_wrapper_bdrv_wrlock
bdrv_co_unref_child(BlockDriverState *parent, BdrvChild *child);
BdrvChild * GRAPH_WRLOCK
bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
const char *child_name,
const BdrvChildClass *child_class,
BdrvChildRole child_role,
Error **errp);
bool GRAPH_RDLOCK
bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason);
void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason);
bool bdrv_op_blocker_is_empty(BlockDriverState *bs);
int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
const char *tag);
int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag);
int bdrv_debug_resume(BlockDriverState *bs, const char *tag);
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);
bool GRAPH_RDLOCK
bdrv_child_change_aio_context(BdrvChild *c, AioContext *ctx,
GHashTable *visited, Transaction *tran,
Error **errp);
int GRAPH_UNLOCKED
bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
BdrvChild *ignore_child, Error **errp);
int GRAPH_RDLOCK
bdrv_try_change_aio_context_locked(BlockDriverState *bs, AioContext *ctx,
BdrvChild *ignore_child, Error **errp);
int GRAPH_RDLOCK bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
void GRAPH_WRLOCK
bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, Error **errp);
void GRAPH_WRLOCK
bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
/**
*
* bdrv_register_buf/bdrv_unregister_buf:
*
* Register/unregister a buffer for I/O. For example, VFIO drivers are
* interested to know the memory areas that would later be used for I/O, so
* that they can prepare IOMMU mapping etc., to get better performance.
*
* Buffers must not overlap and they must be unregistered with the same <host,
* size> values that they were registered with.
*
* Returns: true on success, false on failure
*/
bool bdrv_register_buf(BlockDriverState *bs, void *host, size_t size,
Error **errp);
void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size);
void bdrv_cancel_in_flight(BlockDriverState *bs);
#endif /* BLOCK_GLOBAL_STATE_H */
+56
View File
@@ -0,0 +1,56 @@
/*
* HMP commands related to the block layer
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2020 Red Hat, Inc.
* Copyright IBM, Corp. 2011
*
* Authors:
* Anthony Liguori <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#ifndef BLOCK_BLOCK_HMP_CMDS_H
#define BLOCK_BLOCK_HMP_CMDS_H
#include "qemu/coroutine.h"
void hmp_drive_add(Monitor *mon, const QDict *qdict);
void hmp_commit(Monitor *mon, const QDict *qdict);
void hmp_drive_del(Monitor *mon, const QDict *qdict);
void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
void hmp_drive_backup(Monitor *mon, const QDict *qdict);
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
void coroutine_fn hmp_block_resize(Monitor *mon, const QDict *qdict);
void hmp_block_stream(Monitor *mon, const QDict *qdict);
void hmp_block_passwd(Monitor *mon, const QDict *qdict);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
void hmp_eject(Monitor *mon, const QDict *qdict);
void hmp_qemu_io(Monitor *mon, const QDict *qdict);
void hmp_info_block(Monitor *mon, const QDict *qdict);
void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
#endif
+459
View File
@@ -0,0 +1,459 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_IO_H
#define BLOCK_IO_H
#include "qemu/aiocb.h"
#include "qemu/aio-wait.h"
#include "block/block-common.h"
#include "block/graph-lock.h"
#include "qemu/coroutine.h"
#include "qemu/iov.h"
/*
* I/O API functions. These functions are thread-safe, and therefore
* can run in any thread.
*
* These functions can only call functions from I/O and Common categories,
* but can be invoked by GS, "I/O or GS" and I/O APIs.
*
* All functions in this category must use the macro
* IO_CODE();
* to catch when they are accidentally called by the wrong API.
*/
int co_wrapper_mixed_bdrv_rdlock
bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes,
BdrvRequestFlags flags);
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
int co_wrapper_mixed_bdrv_rdlock
bdrv_pread(BdrvChild *child, int64_t offset, int64_t bytes, void *buf,
BdrvRequestFlags flags);
int co_wrapper_mixed_bdrv_rdlock
bdrv_pwrite(BdrvChild *child, int64_t offset,int64_t bytes,
const void *buf, BdrvRequestFlags flags);
int co_wrapper_mixed_bdrv_rdlock
bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes,
const void *buf, BdrvRequestFlags flags);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes,
const void *buf, BdrvRequestFlags flags);
/*
* Efficiently zero a region of the disk image. Note that this is a regular
* I/O request like read or write and should have a reasonable size. This
* function is not suitable for zeroing the entire image in a single request
* because it may allocate memory for the entire region.
*/
int coroutine_fn GRAPH_RDLOCK
bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes,
BdrvRequestFlags flags);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
int64_t coroutine_fn GRAPH_RDLOCK bdrv_co_nb_sectors(BlockDriverState *bs);
int64_t coroutine_mixed_fn bdrv_nb_sectors(BlockDriverState *bs);
int64_t coroutine_fn GRAPH_RDLOCK bdrv_co_getlength(BlockDriverState *bs);
int64_t co_wrapper_mixed_bdrv_rdlock bdrv_getlength(BlockDriverState *bs);
int64_t coroutine_fn GRAPH_RDLOCK
bdrv_co_get_allocated_file_size(BlockDriverState *bs);
int64_t co_wrapper_bdrv_rdlock
bdrv_get_allocated_file_size(BlockDriverState *bs);
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
BlockDriverState *in_bs, Error **errp);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_delete_file(BlockDriverState *bs, Error **errp);
void coroutine_fn GRAPH_RDLOCK
bdrv_co_delete_file_noerr(BlockDriverState *bs);
/* async block I/O */
void bdrv_aio_cancel_async(BlockAIOCB *acb);
/* sg packet commands */
int coroutine_fn GRAPH_RDLOCK
bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
/* Ensure contents are flushed to disk. */
int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
int64_t bytes);
/* Report zone information of zone block device. */
int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_report(BlockDriverState *bs,
int64_t offset,
unsigned int *nr_zones,
BlockZoneDescriptor *zones);
int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_mgmt(BlockDriverState *bs,
BlockZoneOp op,
int64_t offset, int64_t len);
int coroutine_fn GRAPH_RDLOCK bdrv_co_zone_append(BlockDriverState *bs,
int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags);
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map, BlockDriverState **file);
int co_wrapper_mixed_bdrv_rdlock
bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map, BlockDriverState **file);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_block_status_above(BlockDriverState *bs, BlockDriverState *base,
int64_t offset, int64_t bytes, int64_t *pnum,
int64_t *map, BlockDriverState **file);
int co_wrapper_mixed_bdrv_rdlock
bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
int64_t offset, int64_t bytes, int64_t *pnum,
int64_t *map, BlockDriverState **file);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum);
int co_wrapper_mixed_bdrv_rdlock
bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
int64_t bytes, int64_t *pnum);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
bool include_base, int64_t offset, int64_t bytes,
int64_t *pnum);
int co_wrapper_mixed_bdrv_rdlock
bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base,
bool include_base, int64_t offset,
int64_t bytes, int64_t *pnum);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_is_all_zeroes(BlockDriverState *bs);
int GRAPH_RDLOCK
bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
Error **errp);
bool bdrv_is_read_only(BlockDriverState *bs);
bool bdrv_is_writable(BlockDriverState *bs);
bool bdrv_is_sg(BlockDriverState *bs);
int bdrv_get_flags(BlockDriverState *bs);
bool coroutine_fn GRAPH_RDLOCK bdrv_co_is_inserted(BlockDriverState *bs);
bool co_wrapper_bdrv_rdlock bdrv_is_inserted(BlockDriverState *bs);
void coroutine_fn GRAPH_RDLOCK
bdrv_co_lock_medium(BlockDriverState *bs, bool locked);
void coroutine_fn GRAPH_RDLOCK
bdrv_co_eject(BlockDriverState *bs, bool eject_flag);
const char *bdrv_get_format_name(BlockDriverState *bs);
bool GRAPH_RDLOCK bdrv_supports_compressed_writes(BlockDriverState *bs);
const char *bdrv_get_node_name(const BlockDriverState *bs);
const char * GRAPH_RDLOCK
bdrv_get_device_name(const BlockDriverState *bs);
const char * GRAPH_RDLOCK
bdrv_get_device_or_node_name(const BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
int co_wrapper_mixed_bdrv_rdlock
bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
ImageInfoSpecific * GRAPH_RDLOCK
bdrv_get_specific_info(BlockDriverState *bs, Error **errp);
BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs);
void bdrv_round_to_subclusters(BlockDriverState *bs,
int64_t offset, int64_t bytes,
int64_t *cluster_offset,
int64_t *cluster_bytes);
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
const char *backing_fmt, bool warn);
int co_wrapper_bdrv_rdlock
bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
const char *backing_fmt, bool warn);
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size);
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);
/*
* Returns the alignment in bytes that is required so that no bounce buffer
* is required throughout the stack
*/
size_t bdrv_min_mem_align(BlockDriverState *bs);
/* Returns optimal alignment in bytes for bounce buffer */
size_t bdrv_opt_mem_align(BlockDriverState *bs);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
void *qemu_blockalign0(BlockDriverState *bs, size_t size);
void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
void bdrv_enable_copy_on_read(BlockDriverState *bs);
void bdrv_disable_copy_on_read(BlockDriverState *bs);
void coroutine_fn GRAPH_RDLOCK
bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event);
void co_wrapper_mixed_bdrv_rdlock
bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event);
#define BLKDBG_CO_EVENT(child, evt) \
do { \
if (child) { \
bdrv_co_debug_event(child->bs, evt); \
} \
} while (0)
#define BLKDBG_EVENT(child, evt) \
do { \
if (child) { \
bdrv_debug_event(child->bs, evt); \
} \
} while (0)
/**
* bdrv_get_aio_context:
*
* Returns: the currently bound #AioContext
*/
AioContext *bdrv_get_aio_context(BlockDriverState *bs);
AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c);
/**
* Move the current coroutine to the AioContext of @bs and return the old
* AioContext of the coroutine. Increase bs->in_flight so that draining @bs
* will wait for the operation to proceed until the corresponding
* bdrv_co_leave().
*
* Consequently, you can't call drain inside a bdrv_co_enter/leave() section as
* this will deadlock.
*/
AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs);
/**
* Ends a section started by bdrv_co_enter(). Move the current coroutine back
* to old_ctx and decrease bs->in_flight again.
*/
void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx);
AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
bool coroutine_fn GRAPH_RDLOCK
bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp);
bool co_wrapper_bdrv_rdlock
bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp);
/**
*
* bdrv_co_copy_range:
*
* Do offloaded copy between two children. If the operation is not implemented
* by the driver, or if the backend storage doesn't support it, a negative
* error code will be returned.
*
* Note: block layer doesn't emulate or fallback to a bounce buffer approach
* because usually the caller shouldn't attempt offloaded copy any more (e.g.
* calling copy_file_range(2)) after the first error, thus it should fall back
* to a read+write path in the caller level.
*
* @src: Source child to copy data from
* @src_offset: offset in @src image to read data
* @dst: Destination child to copy data to
* @dst_offset: offset in @dst image to write data
* @bytes: number of bytes to copy
* @flags: request flags. Supported flags:
* BDRV_REQ_ZERO_WRITE - treat the @src range as zero data and do zero
* write on @dst as if bdrv_co_pwrite_zeroes is
* called. Used to simplify caller code, or
* during BlockDriver.bdrv_co_copy_range_from()
* recursion.
* BDRV_REQ_NO_SERIALISING - do not serialize with other overlapping
* requests currently in flight.
*
* Returns: 0 if succeeded; negative error code if failed.
**/
int coroutine_fn GRAPH_RDLOCK
bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);
/*
* "I/O or GS" API functions. These functions can run without
* the BQL, but only in one specific iothread/main loop.
*
* More specifically, these functions use BDRV_POLL_WHILE(bs), which requires
* the caller to be either in the main thread or directly in the home thread
* that runs the bs AioContext. Calling them from another thread in another
* AioContext would cause deadlocks.
*
* Therefore, these functions are not proper I/O, because they
* can't run in *any* iothreads, but only in a specific one.
*
* These functions can call any function from I/O, Common and this
* categories, but must be invoked only by other "I/O or GS" and GS APIs.
*
* All functions in this category must use the macro
* IO_OR_GS_CODE();
* to catch when they are accidentally called by the wrong API.
*/
#define BDRV_POLL_WHILE(bs, cond) ({ \
BlockDriverState *bs_ = (bs); \
IO_OR_GS_CODE(); \
AIO_WAIT_WHILE(bdrv_get_aio_context(bs_), \
cond); })
void bdrv_drain(BlockDriverState *bs);
int co_wrapper_mixed_bdrv_rdlock
bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
int co_wrapper_mixed_bdrv_rdlock
bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
/* Invalidate any cached metadata used by image formats */
int co_wrapper_mixed_bdrv_rdlock
bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
int co_wrapper_mixed_bdrv_rdlock bdrv_flush(BlockDriverState *bs);
int co_wrapper_mixed_bdrv_rdlock
bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
int co_wrapper_mixed_bdrv_rdlock
bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
int co_wrapper_mixed_bdrv_rdlock
bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
/**
* bdrv_parent_drained_begin_single:
*
* Begin a quiesced section for the parent of @c.
*/
void GRAPH_RDLOCK bdrv_parent_drained_begin_single(BdrvChild *c);
/**
* bdrv_parent_drained_poll_single:
*
* Returns true if there is any pending activity to cease before @c can be
* called quiesced, false otherwise.
*/
bool GRAPH_RDLOCK bdrv_parent_drained_poll_single(BdrvChild *c);
/**
* bdrv_parent_drained_end_single:
*
* End a quiesced section for the parent of @c.
*/
void GRAPH_RDLOCK bdrv_parent_drained_end_single(BdrvChild *c);
/**
* bdrv_drain_poll:
*
* Poll for pending requests in @bs and its parents (except for @ignore_parent).
*
* If @ignore_bds_parents is true, parents that are BlockDriverStates must
* ignore the drain request because they will be drained separately (used for
* drain_all).
*
* This is part of bdrv_drained_begin.
*/
bool GRAPH_RDLOCK
bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
bool ignore_bds_parents);
/**
* bdrv_drained_begin:
*
* Begin a quiesced section for exclusive access to the BDS, by disabling
* external request sources including NBD server, block jobs, and device model.
*
* This function can only be invoked by the main loop or a coroutine
* (regardless of the AioContext where it is running).
* If the coroutine is running in an Iothread AioContext, this function will
* just schedule a BH to run in the main loop.
* However, it cannot be directly called by an Iothread.
*
* This function can be recursive.
*/
void GRAPH_UNLOCKED bdrv_drained_begin(BlockDriverState *bs);
/**
* bdrv_do_drained_begin_quiesce:
*
* Quiesces a BDS like bdrv_drained_begin(), but does not wait for already
* running requests to complete.
*/
void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, BdrvChild *parent);
/**
* bdrv_drained_end:
*
* End a quiescent section started by bdrv_drained_begin().
*
* This function can only be invoked by the main loop or a coroutine
* (regardless of the AioContext where it is running).
* If the coroutine is running in an Iothread AioContext, this function will
* just schedule a BH to run in the main loop.
* However, it cannot be directly called by an Iothread.
*/
void bdrv_drained_end(BlockDriverState *bs);
#endif /* BLOCK_IO_H */
+32
View File
@@ -0,0 +1,32 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_H
#define BLOCK_H
#include "block/block-global-state.h"
#include "block/block-io.h"
/* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */
#endif /* BLOCK_H */
+25
View File
@@ -0,0 +1,25 @@
/*
* QEMU backup
*
* Copyright (c) 2013 Proxmox Server Solutions
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
* Copyright (c) 2016 Intel Corporation
* Copyright (c) 2016 FUJITSU LIMITED
*
* Authors:
* Dietmar Maurer <[email protected]>
* Changlong Xie <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef BLOCK_BACKUP_H
#define BLOCK_BACKUP_H
#include "block/blockjob.h"
void backup_do_checkpoint(BlockJob *job, Error **errp);
#endif
File diff suppressed because it is too large Load Diff
+328
View File
@@ -0,0 +1,328 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_INT_GLOBAL_STATE_H
#define BLOCK_INT_GLOBAL_STATE_H
#include "block/blockjob.h"
#include "block/block_int-common.h"
#include "qemu/hbitmap.h"
#include "qemu/main-loop.h"
/*
* Global state (GS) API. These functions run under the BQL.
*
* See include/block/block-global-state.h for more information about
* the GS API.
*/
/**
* stream_start:
* @job_id: The id of the newly-created job, or %NULL to use the
* device name of @bs.
* @bs: Block device to operate on.
* @base: Block device that will become the new base, or %NULL to
* flatten the whole backing file chain onto @bs.
* @backing_file_str: The file name that will be written to @bs as the
* the new backing file if the job completes. Ignored if @base is %NULL.
* @backing_mask_protocol: Replace potential protocol name with 'raw' in
* 'backing file format' header
* @creation_flags: Flags that control the behavior of the Job lifetime.
* See @BlockJobCreateFlags
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @on_error: The action to take upon error.
* @filter_node_name: The node name that should be assigned to the filter
* driver that the stream job inserts into the graph above
* @bs. NULL means that a node name should be autogenerated.
* @errp: Error object.
*
* Start a streaming operation on @bs. Clusters that are unallocated
* in @bs, but allocated in any image between @base and @bs (both
* exclusive) will be written to @bs. At the end of a successful
* streaming job, the backing file of @bs will be changed to
* @backing_file_str in the written image and to @base in the live
* BlockDriverState.
*/
void stream_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *base, const char *backing_file_str,
bool backing_mask_protocol,
BlockDriverState *bottom,
int creation_flags, int64_t speed,
BlockdevOnError on_error,
const char *filter_node_name,
Error **errp);
/**
* commit_start:
* @job_id: The id of the newly-created job, or %NULL to use the
* device name of @bs.
* @bs: Active block device.
* @top: Top block device to be committed.
* @base: Block device that will be written into, and become the new top.
* @creation_flags: Flags that control the behavior of the Job lifetime.
* See @BlockJobCreateFlags
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @on_error: The action to take upon error.
* @backing_file_str: String to use as the backing file in @top's overlay
* @backing_mask_protocol: Replace potential protocol name with 'raw' in
* 'backing file format' header
* @filter_node_name: The node name that should be assigned to the filter
* driver that the commit job inserts into the graph above @top. NULL means
* that a node name should be autogenerated.
* @errp: Error object.
*
*/
void commit_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *base, BlockDriverState *top,
int creation_flags, int64_t speed,
BlockdevOnError on_error, const char *backing_file_str,
bool backing_mask_protocol,
const char *filter_node_name, Error **errp);
/**
* commit_active_start:
* @job_id: The id of the newly-created job, or %NULL to use the
* device name of @bs.
* @bs: Active block device to be committed.
* @base: Block device that will be written into, and become the new top.
* @creation_flags: Flags that control the behavior of the Job lifetime.
* See @BlockJobCreateFlags
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @on_error: The action to take upon error.
* @filter_node_name: The node name that should be assigned to the filter
* driver that the commit job inserts into the graph above @bs. NULL means that
* a node name should be autogenerated.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @auto_complete: Auto complete the job.
* @errp: Error object.
*
*/
BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *base, int creation_flags,
int64_t speed, BlockdevOnError on_error,
const char *filter_node_name,
BlockCompletionFunc *cb, void *opaque,
bool auto_complete, Error **errp);
/*
* mirror_start:
* @job_id: The id of the newly-created job, or %NULL to use the
* device name of @bs.
* @bs: Block device to operate on.
* @target: Block device to write to.
* @replaces: Block graph node name to replace once the mirror is done. Can
* only be used when full mirroring is selected.
* @creation_flags: Flags that control the behavior of the Job lifetime.
* See @BlockJobCreateFlags
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @granularity: The chosen granularity for the dirty bitmap.
* @buf_size: The amount of data that can be in flight at one time.
* @mode: Whether to collapse all images in the chain to the target.
* @backing_mode: How to establish the target's backing chain after completion.
* @target_is_zero: Whether the target already is zero-initialized.
* @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.
* @unmap: Whether to unmap target where source sectors only contain zeroes.
* @filter_node_name: The node name that should be assigned to the filter
* driver that the mirror job inserts into the graph above @bs. NULL means that
* a node name should be autogenerated.
* @copy_mode: When to trigger writes to the target.
* @errp: Error object.
*
* Start a mirroring operation on @bs. Clusters that are allocated
* in @bs will be written to @target until the job is cancelled or
* manually completed. At the end of a successful mirroring job,
* @bs will be switched to read from @target.
*/
void mirror_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, const char *replaces,
int creation_flags, int64_t speed,
uint32_t granularity, int64_t buf_size,
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
bool target_is_zero,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
bool unmap, const char *filter_node_name,
MirrorCopyMode copy_mode, Error **errp);
/*
* backup_job_create:
* @job_id: The id of the newly-created job, or %NULL to use the
* device name of @bs.
* @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.
* @sync_bitmap: The dirty bitmap if sync_mode is 'bitmap' or 'incremental'
* @bitmap_mode: The bitmap synchronization policy to use.
* @perf: Performance options. All actual fields assumed to be present,
* all ".has_*" fields are ignored.
* @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.
* @on_cbw_error: The action to take upon error in copy-before-write operations.
* @creation_flags: Flags that control the behavior of the Job lifetime.
* See @BlockJobCreateFlags
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @txn: Transaction that this job is part of (may be NULL).
*
* Create a backup operation on @bs. Clusters in @bs are written to @target
* until the job is cancelled or manually completed.
*/
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode,
BdrvDirtyBitmap *sync_bitmap,
BitmapSyncMode bitmap_mode,
bool compress, bool discard_source,
const char *filter_node_name,
BackupPerf *perf,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
OnCbwError on_cbw_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,
JobTxn *txn, Error **errp);
BdrvChild * GRAPH_WRLOCK
bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name,
const BdrvChildClass *child_class,
BdrvChildRole child_role,
uint64_t perm, uint64_t shared_perm,
void *opaque, Error **errp);
void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child);
void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
uint64_t *shared_perm);
/**
* Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use
* bdrv_child_refresh_perms() instead and make the parent's
* .bdrv_child_perm() implementation return the correct values.
*/
int GRAPH_RDLOCK
bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
Error **errp);
/**
* Calls bs->drv->bdrv_child_perm() and updates the child's permission
* masks with the result.
* Drivers should invoke this function whenever an event occurs that
* makes their .bdrv_child_perm() implementation return different
* values than before, but which will not result in the block layer
* automatically refreshing the permissions.
*/
int GRAPH_RDLOCK
bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp);
bool GRAPH_RDLOCK bdrv_recurse_can_replace(BlockDriverState *bs,
BlockDriverState *to_replace);
/*
* Default implementation for BlockDriver.bdrv_child_perm() that can
* be used by block filters and image formats, as long as they use the
* child_of_bds child class and set an appropriate BdrvChildRole.
*/
void bdrv_default_perms(BlockDriverState *bs, BdrvChild *c,
BdrvChildRole role, BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared);
void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp);
bool blk_dev_has_removable_media(BlockBackend *blk);
void blk_dev_eject_request(BlockBackend *blk, bool force);
bool blk_dev_is_medium_locked(BlockBackend *blk);
void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup);
void bdrv_set_monitor_owned(BlockDriverState *bs);
void blockdev_close_all_bdrv_states(void);
BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp);
/**
* Simple implementation of bdrv_co_create_opts for protocol drivers
* which only support creation via opening a file
* (usually existing raw storage device)
*/
int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv,
const char *filename,
QemuOpts *opts,
Error **errp);
BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
const char *name,
BlockDriverState **pbs,
Error **errp);
BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
BlockDirtyBitmapOrStrList *bms,
HBitmap **backup, Error **errp);
BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
bool release,
BlockDriverState **bitmap_bs,
Error **errp);
BlockDriverState * GRAPH_RDLOCK
bdrv_skip_implicit_filters(BlockDriverState *bs);
/**
* bdrv_add_aio_context_notifier:
*
* If a long-running job intends to be always run in the same AioContext as a
* certain BDS, it may use this function to be notified of changes regarding the
* association of the BDS to an AioContext.
*
* attached_aio_context() is called after the target BDS has been attached to a
* new AioContext; detach_aio_context() is called before the target BDS is being
* detached from its old AioContext.
*/
void bdrv_add_aio_context_notifier(BlockDriverState *bs,
void (*attached_aio_context)(AioContext *new_context, void *opaque),
void (*detach_aio_context)(void *opaque), void *opaque);
/**
* bdrv_remove_aio_context_notifier:
*
* Unsubscribe of change notifications regarding the BDS's AioContext. The
* parameters given here have to be the same as those given to
* bdrv_add_aio_context_notifier().
*/
void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
void (*aio_context_attached)(AioContext *,
void *),
void (*aio_context_detached)(void *),
void *opaque);
/**
* End all quiescent sections started by bdrv_drain_all_begin(). This is
* needed when deleting a BDS before bdrv_drain_all_end() is called.
*
* NOTE: this is an internal helper for bdrv_close() *only*. No one else
* should call it.
*/
void bdrv_drain_all_end_quiesce(BlockDriverState *bs);
#endif /* BLOCK_INT_GLOBAL_STATE_H */
+200
View File
@@ -0,0 +1,200 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_INT_IO_H
#define BLOCK_INT_IO_H
#include "block/block_int-common.h"
#include "qemu/hbitmap.h"
#include "qemu/main-loop.h"
/*
* I/O API functions. These functions are thread-safe.
*
* See include/block/block-io.h for more information about
* the I/O API.
*/
int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_snapshot(BdrvChild *child,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset);
int coroutine_fn GRAPH_RDLOCK bdrv_co_snapshot_block_status(
BlockDriverState *bs, unsigned int mode, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file);
int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs,
int64_t offset, int64_t bytes);
int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv(BdrvChild *child,
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags);
int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_part(BdrvChild *child,
int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
int coroutine_fn GRAPH_RDLOCK bdrv_co_pwritev(BdrvChild *child,
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags);
int coroutine_fn GRAPH_RDLOCK bdrv_co_pwritev_part(BdrvChild *child,
int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
static inline int coroutine_fn GRAPH_RDLOCK bdrv_co_pread(BdrvChild *child,
int64_t offset, int64_t bytes, void *buf, BdrvRequestFlags flags)
{
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
IO_CODE();
assert_bdrv_graph_readable();
return bdrv_co_preadv(child, offset, bytes, &qiov, flags);
}
static inline int coroutine_fn GRAPH_RDLOCK bdrv_co_pwrite(BdrvChild *child,
int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags)
{
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
IO_CODE();
assert_bdrv_graph_readable();
return bdrv_co_pwritev(child, offset, bytes, &qiov, flags);
}
void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
uint64_t align);
BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs);
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
const char *filename);
/**
* bdrv_wakeup:
* @bs: The BlockDriverState for which an I/O operation has been completed.
*
* Wake up the main thread if it is waiting on BDRV_POLL_WHILE. During
* synchronous I/O on a BlockDriverState that is attached to another
* I/O thread, the main thread lets the I/O thread's event loop run,
* waiting for the I/O operation to complete. A bdrv_wakeup will wake
* up the main thread if necessary.
*
* Manual calls to bdrv_wakeup are rarely necessary, because
* bdrv_dec_in_flight already calls it.
*/
void bdrv_wakeup(BlockDriverState *bs);
const char * GRAPH_RDLOCK bdrv_get_parent_name(const BlockDriverState *bs);
bool blk_dev_has_tray(BlockBackend *blk);
bool blk_dev_is_tray_open(BlockBackend *blk);
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
const BdrvDirtyBitmap *src,
HBitmap **backup, bool lock);
void bdrv_inc_in_flight(BlockDriverState *bs);
void bdrv_dec_in_flight(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
int co_wrapper_mixed_bdrv_rdlock
bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
BdrvChild * GRAPH_RDLOCK bdrv_cow_child(BlockDriverState *bs);
BdrvChild * GRAPH_RDLOCK bdrv_filter_child(BlockDriverState *bs);
BdrvChild * GRAPH_RDLOCK bdrv_filter_or_cow_child(BlockDriverState *bs);
BdrvChild * GRAPH_RDLOCK bdrv_primary_child(BlockDriverState *bs);
BlockDriverState * GRAPH_RDLOCK bdrv_skip_filters(BlockDriverState *bs);
BlockDriverState * GRAPH_RDLOCK bdrv_backing_chain_next(BlockDriverState *bs);
static inline BlockDriverState * GRAPH_RDLOCK
bdrv_cow_bs(BlockDriverState *bs)
{
IO_CODE();
return child_bs(bdrv_cow_child(bs));
}
static inline BlockDriverState * GRAPH_RDLOCK
bdrv_filter_bs(BlockDriverState *bs)
{
IO_CODE();
return child_bs(bdrv_filter_child(bs));
}
static inline BlockDriverState * GRAPH_RDLOCK
bdrv_filter_or_cow_bs(BlockDriverState *bs)
{
IO_CODE();
return child_bs(bdrv_filter_or_cow_child(bs));
}
static inline BlockDriverState * GRAPH_RDLOCK
bdrv_primary_bs(BlockDriverState *bs)
{
IO_CODE();
return child_bs(bdrv_primary_child(bs));
}
/**
* Check whether the given offset is in the cached block-status data
* region.
*
* If it is, and @pnum is not NULL, *pnum is set to
* `bsc.data_end - offset`, i.e. how many bytes, starting from
* @offset, are data (according to the cache).
* Otherwise, *pnum is not touched.
*/
bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum);
/**
* If [offset, offset + bytes) overlaps with the currently cached
* block-status region, invalidate the cache.
*
* (To be used by I/O paths that cause data regions to be zero or
* holes.)
*/
void bdrv_bsc_invalidate_range(BlockDriverState *bs,
int64_t offset, int64_t bytes);
/**
* Mark the range [offset, offset + bytes) as a data region.
*/
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
/*
* Notify all parents that the size of the child changed.
*/
void coroutine_fn GRAPH_RDLOCK
bdrv_co_parent_cb_resize(BlockDriverState *bs);
#endif /* BLOCK_INT_IO_H */
+33
View File
@@ -0,0 +1,33 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_INT_H
#define BLOCK_INT_H
#include "block/block_int-global-state.h"
#include "block/block_int-io.h"
#include "block/graph-lock.h"
/* DO NOT ADD ANYTHING IN HERE. USE ONE OF THE HEADERS INCLUDED ABOVE */
#endif /* BLOCK_INT_H */
+240
View File
@@ -0,0 +1,240 @@
/*
* Declarations for long-running block device operations
*
* Copyright (c) 2011 IBM Corp.
* Copyright (c) 2012 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCKJOB_H
#define BLOCKJOB_H
#include "qapi/qapi-types-block-core.h"
#include "qemu/job.h"
#include "qemu/ratelimit.h"
#define BLOCK_JOB_SLICE_TIME 100000000ULL /* ns */
typedef struct BlockJobDriver BlockJobDriver;
/**
* BlockJob:
*
* Long-running operation on a BlockDriverState.
*/
typedef struct BlockJob {
/**
* Data belonging to the generic Job infrastructure.
* Protected by job mutex.
*/
Job job;
/**
* Status that is published by the query-block-jobs QMP API.
* Protected by job mutex.
*/
BlockDeviceIoStatus iostatus;
/**
* Speed that was set with @block_job_set_speed.
* Always modified and read under the BQL (GLOBAL_STATE_CODE).
*/
int64_t speed;
/**
* Rate limiting data structure for implementing @speed.
* RateLimit API is thread-safe.
*/
RateLimit limit;
/**
* Block other operations when block job is running.
* Always modified and read under the BQL (GLOBAL_STATE_CODE).
*/
Error *blocker;
/** All notifiers are set once in block_job_create() and never modified. */
/** Called when a cancelled job is finalised. */
Notifier finalize_cancelled_notifier;
/** Called when a successfully completed job is finalised. */
Notifier finalize_completed_notifier;
/** Called when the job transitions to PENDING */
Notifier pending_notifier;
/** Called when the job transitions to READY */
Notifier ready_notifier;
/** Called when the job coroutine yields or terminates */
Notifier idle_notifier;
/**
* BlockDriverStates that are involved in this block job.
* Always modified and read under the BQL (GLOBAL_STATE_CODE).
*/
GSList *nodes;
} BlockJob;
/*
* Global state (GS) API. These functions run under the BQL.
*
* See include/block/block-global-state.h for more information about
* the GS API.
*/
/**
* block_job_next_locked:
* @job: A block job, or %NULL.
*
* Get the next element from the list of block jobs after @job, or the
* first one if @job is %NULL.
*
* Returns the requested job, or %NULL if there are no more jobs left.
* Called with job lock held.
*/
BlockJob *block_job_next_locked(BlockJob *job);
/**
* block_job_get:
* @id: The id of the block job.
*
* Get the block job identified by @id (which must not be %NULL).
*
* Returns the requested job, or %NULL if it doesn't exist.
* Called with job lock *not* held.
*/
BlockJob *block_job_get(const char *id);
/* Same as block_job_get(), but called with job lock held. */
BlockJob *block_job_get_locked(const char *id);
/**
* block_job_add_bdrv:
* @job: A block job
* @name: The name to assign to the new BdrvChild
* @bs: A BlockDriverState that is involved in @job
* @perm, @shared_perm: Permissions to request on the node
*
* Add @bs to the list of BlockDriverState that are involved in
* @job. This means that all operations will be blocked on @bs while
* @job exists.
*
* All block nodes must be drained.
*/
int GRAPH_WRLOCK
block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
uint64_t perm, uint64_t shared_perm, Error **errp);
/**
* block_job_remove_all_bdrv:
* @job: The block job
*
* Remove all BlockDriverStates from the list of nodes that are involved in the
* job. This removes the blockers added with block_job_add_bdrv().
*/
void GRAPH_UNLOCKED block_job_remove_all_bdrv(BlockJob *job);
/**
* block_job_has_bdrv:
* @job: The block job
*
* Searches for @bs in the list of nodes that are involved in the
* job.
*/
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs);
/**
* block_job_set_speed_locked:
* @job: The job to set the speed for.
* @speed: The new value
* @errp: Error object.
*
* Set a rate-limiting parameter for the job; the actual meaning may
* vary depending on the job type.
*
* Called with job lock held, but might release it temporarily.
*/
bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp);
/**
* block_job_change_locked:
* @job: The job to change.
* @opts: The new options.
* @errp: Error object.
*
* Change the job according to opts.
*/
void block_job_change_locked(BlockJob *job, BlockJobChangeOptions *opts,
Error **errp);
/**
* block_job_query_locked:
* @job: The job to get information about.
*
* Return information about a job.
*
* Called with job lock held.
*/
BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp);
/**
* block_job_iostatus_reset_locked:
* @job: The job whose I/O status should be reset.
*
* Reset I/O status on @job and on BlockDriverState objects it uses,
* other than job->blk.
*
* Called with job lock held.
*/
void block_job_iostatus_reset_locked(BlockJob *job);
/*
* block_job_get_aio_context:
*
* Returns aio context associated with a block job.
*/
AioContext *block_job_get_aio_context(BlockJob *job);
/*
* Common functions that are neither I/O nor Global State.
*
* See include/block/block-common.h for more information about
* the Common API.
*/
/**
* block_job_is_internal:
* @job: The job to determine if it is user-visible or not.
*
* Returns true if the job should not be visible to the management layer.
*/
bool block_job_is_internal(BlockJob *job);
/**
* block_job_driver:
*
* Returns the driver associated with a block job.
*/
const BlockJobDriver *block_job_driver(BlockJob *job);
#endif
+168
View File
@@ -0,0 +1,168 @@
/*
* Declarations for long-running block device operations
*
* Copyright (c) 2011 IBM Corp.
* Copyright (c) 2012 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCKJOB_INT_H
#define BLOCKJOB_INT_H
#include "block/blockjob.h"
/**
* BlockJobDriver:
*
* A class type for block job driver.
*/
struct BlockJobDriver {
/** Generic JobDriver callbacks and settings */
JobDriver job_driver;
/*
* I/O API functions. These functions are thread-safe.
*
* See include/block/block-io.h for more information about
* the I/O API.
*/
/*
* Returns whether the job has pending requests for the child or will
* submit new requests before the next pause point. This callback is polled
* in the context of draining a job node after requesting that the job be
* paused, until all activity on the child has stopped.
*/
bool (*drained_poll)(BlockJob *job);
/*
* Global state (GS) API. These functions run under the BQL.
*
* See include/block/block-global-state.h for more information about
* the GS API.
*/
/*
* If the callback is not NULL, it will be invoked before the job is
* resumed in a new AioContext. This is the place to move any resources
* besides job->blk to the new AioContext.
*/
void (*attached_aio_context)(BlockJob *job, AioContext *new_context);
void (*set_speed)(BlockJob *job, int64_t speed);
/*
* Change the @job's options according to @opts.
*
* Note that this can already be called before the job coroutine is running.
*/
void (*change)(BlockJob *job, BlockJobChangeOptions *opts, Error **errp);
/*
* Query information specific to this kind of block job.
*/
void (*query)(BlockJob *job, BlockJobInfo *info);
};
/*
* Global state (GS) API. These functions run under the BQL.
*
* See include/block/block-global-state.h for more information about
* the GS API.
*/
/**
* block_job_create:
* @job_id: The id of the newly-created job, or %NULL to have one
* generated automatically.
* @driver: The class object for the newly-created job.
* @txn: The transaction this job belongs to, if any. %NULL otherwise.
* @bs: The block
* @perm, @shared_perm: Permissions to request for @bs
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
* @flags: Creation flags for the Block Job. See @JobCreateFlags.
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
* @errp: Error object.
*
* Create a new long-running block device job and return it. The job
* will call @cb asynchronously when the job completes. Note that
* @bs may have been closed at the time the @cb it is called. If
* this is the case, the job may be reported as either cancelled or
* completed.
*
* This function is not part of the public job interface; it should be
* called from a wrapper that is specific to the job type.
*/
void * GRAPH_UNLOCKED
block_job_create(const char *job_id, const BlockJobDriver *driver,
JobTxn *txn, BlockDriverState *bs, uint64_t perm,
uint64_t shared_perm, int64_t speed, int flags,
BlockCompletionFunc *cb, void *opaque, Error **errp);
/**
* block_job_free:
* Callback to be used for JobDriver.free in all block jobs. Frees block job
* specific resources in @job.
*/
void block_job_free(Job *job);
/**
* block_job_user_resume:
* Callback to be used for JobDriver.user_resume in all block jobs. Resets the
* iostatus when the user resumes @job.
*/
void block_job_user_resume(Job *job);
/*
* I/O API functions. These functions are thread-safe.
*
* See include/block/block-io.h for more information about
* the I/O API.
*/
/**
* block_job_ratelimit_processed_bytes:
*
* To be called after some work has been done. Adjusts the delay for the next
* request. See the documentation of ratelimit_calculate_delay() for details.
*/
void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n);
/**
* Put the job to sleep (assuming that it wasn't canceled) to throttle it to the
* right speed according to its rate limiting.
*/
void block_job_ratelimit_sleep(BlockJob *job);
/**
* block_job_error_action:
* @job: The job to signal an error for.
* @on_err: The error action setting.
* @is_read: Whether the operation was a read.
* @error: The error that was reported.
*
* Report an I/O error for a block job and possibly stop the VM. Return the
* action that was selected based on @on_err and @error.
*/
BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
int is_read, int error);
#endif
+131
View File
@@ -0,0 +1,131 @@
#ifndef BLOCK_DIRTY_BITMAP_H
#define BLOCK_DIRTY_BITMAP_H
#include "block/block-common.h"
#include "block/graph-lock.h"
#include "qapi/qapi-types-block-core.h"
#include "qemu/hbitmap.h"
typedef enum BitmapCheckFlags {
BDRV_BITMAP_BUSY = 1,
BDRV_BITMAP_RO = 2,
BDRV_BITMAP_INCONSISTENT = 4,
} BitmapCheckFlags;
#define BDRV_BITMAP_DEFAULT (BDRV_BITMAP_BUSY | BDRV_BITMAP_RO | \
BDRV_BITMAP_INCONSISTENT)
#define BDRV_BITMAP_ALLOW_RO (BDRV_BITMAP_BUSY | BDRV_BITMAP_INCONSISTENT)
#define BDRV_BITMAP_MAX_NAME_SIZE 1023
bool bdrv_supports_persistent_dirty_bitmap(BlockDriverState *bs);
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
uint32_t granularity,
const char *name,
Error **errp);
int bdrv_dirty_bitmap_create_successor(BdrvDirtyBitmap *bitmap,
Error **errp);
BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BdrvDirtyBitmap *bitmap,
Error **errp);
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BdrvDirtyBitmap *bitmap,
Error **errp);
void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap);
BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
const char *name);
int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
Error **errp);
void bdrv_release_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK
bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
Error **errp);
int co_wrapper_bdrv_rdlock
bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
Error **errp);
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap);
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap);
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes);
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes);
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
uint64_t offset, uint64_t bytes);
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
uint64_t bdrv_dirty_bitmap_serialization_coverage(int serialized_chunk_size,
const BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
uint8_t *buf, uint64_t offset,
uint64_t bytes);
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
uint8_t *buf, uint64_t offset,
uint64_t bytes, bool finish);
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
uint64_t offset, uint64_t bytes,
bool finish);
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
uint64_t offset, uint64_t bytes,
bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap,
bool persistent);
void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy);
bool bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
HBitmap **backup, Error **errp);
void bdrv_dirty_bitmap_skip_store(BdrvDirtyBitmap *bitmap, bool skip);
bool bdrv_dirty_bitmap_get(BdrvDirtyBitmap *bitmap, int64_t offset);
/* Functions that require manual locking. */
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_get_locked(BdrvDirtyBitmap *bitmap, int64_t offset);
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes);
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes);
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
bool bdrv_has_named_bitmaps(BlockDriverState *bs);
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap);
BdrvDirtyBitmap *bdrv_dirty_bitmap_first(BlockDriverState *bs);
BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BdrvDirtyBitmap *bitmap);
#define FOR_EACH_DIRTY_BITMAP(bs, bitmap) \
for (bitmap = bdrv_dirty_bitmap_first(bs); bitmap; \
bitmap = bdrv_dirty_bitmap_next(bitmap))
char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
int64_t bdrv_dirty_bitmap_next_dirty(BdrvDirtyBitmap *bitmap, int64_t offset,
int64_t bytes);
int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, int64_t offset,
int64_t bytes);
bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
int64_t start, int64_t end, int64_t max_dirty_count,
int64_t *dirty_start, int64_t *dirty_count);
bool bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap, int64_t offset,
int64_t bytes, int64_t *count);
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
Error **errp);
#endif
+102
View File
@@ -0,0 +1,102 @@
/*
* Declarations for block exports
*
* Copyright (c) 2012, 2020 Red Hat, Inc.
*
* Authors:
* Paolo Bonzini <[email protected]>
* Kevin Wolf <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* later. See the COPYING file in the top-level directory.
*/
#ifndef BLOCK_EXPORT_H
#define BLOCK_EXPORT_H
#include "qapi/qapi-types-block-export.h"
#include "qemu/queue.h"
typedef struct BlockExport BlockExport;
typedef struct BlockExportDriver {
/* The export type that this driver services */
BlockExportType type;
/*
* The size of the driver-specific state that contains BlockExport as its
* first field.
*/
size_t instance_size;
/* True if the export type supports running on an inactive node */
bool supports_inactive;
/*
* Creates and starts a new block export.
*
* If the user passed a set of I/O threads for multi-threading, @multithread
* is a list of the @multithread_count corresponding contexts (freed by the
* caller). Note that @exp->ctx has no relation to that list.
*/
int (*create)(BlockExport *exp, BlockExportOptions *opts,
AioContext *const *multithread, size_t multithread_count,
Error **errp);
/*
* Frees a removed block export. This function is only called after all
* references have been dropped.
*/
void (*delete)(BlockExport *);
/*
* Start to disconnect all clients and drop other references held
* internally by the export driver. When the function returns, there may
* still be active references while the export is in the process of
* shutting down.
*/
void (*request_shutdown)(BlockExport *);
} BlockExportDriver;
struct BlockExport {
const BlockExportDriver *drv;
/* Unique identifier for the export */
char *id;
/*
* Reference count for this block export. This includes strong references
* both from the owner (qemu-nbd or the monitor) and clients connected to
* the export.
*
* Use atomics to access this field.
*/
int refcount;
/*
* True if one of the references in refcount belongs to the user. After the
* user has dropped their reference, they may not e.g. remove the same
* export a second time (which would decrease the refcount without having
* it incremented first).
*/
bool user_owned;
/* The AioContext whose lock protects this BlockExport object. */
AioContext *ctx;
/* The block device to export */
BlockBackend *blk;
/* List entry for block_exports */
QLIST_ENTRY(BlockExport) next;
};
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp);
BlockExport *blk_exp_find(const char *id);
void blk_exp_ref(BlockExport *exp);
void blk_exp_unref(BlockExport *exp);
void blk_exp_request_shutdown(BlockExport *exp);
void blk_exp_close_all(void);
void blk_exp_close_all_type(BlockExportType type);
#endif
+30
View File
@@ -0,0 +1,30 @@
/*
* Present a block device as a raw image through FUSE
*
* Copyright (c) 2020 Max Reitz <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; under version 2 or later of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BLOCK_FUSE_H
#define BLOCK_FUSE_H
#ifdef CONFIG_FUSE
#include "block/export.h"
extern const BlockExportDriver blk_exp_fuse;
#endif /* CONFIG_FUSE */
#endif
+294
View File
@@ -0,0 +1,294 @@
/*
* Graph lock: rwlock to protect block layer graph manipulations (add/remove
* edges and nodes)
*
* Copyright (c) 2022 Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRAPH_LOCK_H
#define GRAPH_LOCK_H
/**
* Graph Lock API
* This API provides a rwlock used to protect block layer
* graph modifications like edge (BdrvChild) and node (BlockDriverState)
* addition and removal.
* Currently we have 1 writer only, the Main loop, and many
* readers, mostly coroutines running in other AioContext thus other threads.
*
* We distinguish between writer (main loop, under BQL) that modifies the
* graph, and readers (all other coroutines running in various AioContext),
* that go through the graph edges, reading
* BlockDriverState ->parents and->children.
*
* The writer (main loop) has an "exclusive" access, so it first waits for
* current read to finish, and then prevents incoming ones from
* entering while it has the exclusive access.
*
* The readers (coroutines in multiple AioContext) are free to
* access the graph as long the writer is not modifying the graph.
* In case it is, they go in a CoQueue and sleep until the writer
* is done.
*
* If a coroutine changes AioContext, the counter in the original and new
* AioContext are left intact, since the writer does not care where is the
* reader, but only if there is one.
* As a result, some AioContexts might have a negative reader count, to
* balance the positive count of the AioContext that took the lock.
* This also means that when an AioContext is deleted it may have a nonzero
* reader count. In that case we transfer the count to a global shared counter
* so that the writer is always aware of all readers.
*/
typedef struct BdrvGraphRWlock BdrvGraphRWlock;
/* Dummy lock object to use for Thread Safety Analysis (TSA) */
typedef struct TSA_CAPABILITY("mutex") BdrvGraphLock {
} BdrvGraphLock;
extern BdrvGraphLock graph_lock;
/*
* clang doesn't check consistency in locking annotations between forward
* declarations and the function definition. Having the annotation on the
* definition, but not the declaration in a header file, may give the reader
* a false sense of security because the condition actually remains unchecked
* for callers in other source files.
*
* Therefore, as a convention, for public functions, GRAPH_RDLOCK and
* GRAPH_WRLOCK annotations should be present only in the header file.
*/
#define GRAPH_WRLOCK TSA_REQUIRES(graph_lock)
#define GRAPH_RDLOCK TSA_REQUIRES_SHARED(graph_lock)
#define GRAPH_UNLOCKED TSA_EXCLUDES(graph_lock)
/*
* TSA annotations are not part of function types, so checks are defeated when
* using a function pointer. As a workaround, annotate function pointers with
* this macro that will require that the lock is at least taken while reading
* the pointer. In most cases this is equivalent to actually protecting the
* function call.
*/
#define GRAPH_RDLOCK_PTR TSA_GUARDED_BY(graph_lock)
#define GRAPH_WRLOCK_PTR TSA_GUARDED_BY(graph_lock)
#define GRAPH_UNLOCKED_PTR
/*
* register_aiocontext:
* Add AioContext @ctx to the list of AioContext.
* This list is used to obtain the total number of readers
* currently running the graph.
*/
void register_aiocontext(AioContext *ctx);
/*
* unregister_aiocontext:
* Removes AioContext @ctx to the list of AioContext.
*/
void unregister_aiocontext(AioContext *ctx);
/*
* bdrv_graph_wrlock:
* Start an exclusive write operation to modify the graph. This means we are
* adding or removing an edge or a node in the block layer graph. Nobody else
* is allowed to access the graph.
*
* Must only be called from outside bdrv_graph_co_rdlock.
*
* The wrlock can only be taken from the main loop, with BQL held, as only the
* main loop is allowed to modify the graph.
*/
void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
bdrv_graph_wrlock(void);
/*
* bdrv_graph_wrlock_drained:
* Similar to bdrv_graph_wrlock, but will begin a drained section before
* locking.
*/
void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
bdrv_graph_wrlock_drained(void);
/*
* bdrv_graph_wrunlock:
* Write finished, reset global has_writer to 0 and restart
* all readers that are waiting.
*
* Also ends the drained section if bdrv_graph_wrlock_drained() was used to lock
* the graph.
*/
void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
bdrv_graph_wrunlock(void);
/*
* bdrv_graph_co_rdlock:
* Read the bs graph. This usually means traversing all nodes in
* the graph, therefore it can't happen while another thread is
* modifying it.
* Increases the reader counter of the current aiocontext,
* and if has_writer is set, it means that the writer is modifying
* the graph, therefore wait in a coroutine queue.
* The writer will then wake this coroutine once it is done.
*
* This lock should be taken from Iothreads (IO_CODE() class of functions)
* because it signals the writer that there are some
* readers currently running, or waits until the current
* write is finished before continuing.
* Calling this function from the Main Loop with BQL held
* is not necessary, since the Main Loop itself is the only
* writer, thus won't be able to read and write at the same time.
* The only exception to that is when we can't take the lock in the
* function/coroutine itself, and need to delegate the caller (usually main
* loop) to take it and wait that the coroutine ends, so that
* we always signal that a reader is running.
*/
void coroutine_fn TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA
bdrv_graph_co_rdlock(void);
/*
* bdrv_graph_rdunlock:
* Read terminated, decrease the count of readers in the current aiocontext.
* If the writer is waiting for reads to finish (has_writer == 1), signal
* the writer that we are done via aio_wait_kick() to let it continue.
*/
void coroutine_fn TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA
bdrv_graph_co_rdunlock(void);
/*
* bdrv_graph_rd{un}lock_main_loop:
* Just a placeholder to mark where the graph rdlock should be taken
* in the main loop. It is just asserting that we are not
* in a coroutine and in GLOBAL_STATE_CODE.
*/
void TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA
bdrv_graph_rdlock_main_loop(void);
void TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA
bdrv_graph_rdunlock_main_loop(void);
/*
* assert_bdrv_graph_readable:
* Make sure that the reader is either the main loop,
* or there is at least a reader helding the rdlock.
* In this way an incoming writer is aware of the read and waits.
*/
void GRAPH_RDLOCK assert_bdrv_graph_readable(void);
/*
* assert_bdrv_graph_writable:
* Make sure that the writer is the main loop and has set @has_writer,
* so that incoming readers will pause.
*/
void GRAPH_WRLOCK assert_bdrv_graph_writable(void);
/*
* Calling this function tells TSA that we know that the lock is effectively
* taken even though we cannot prove it (yet) with GRAPH_RDLOCK. This can be
* useful in intermediate stages of a conversion to using the GRAPH_RDLOCK
* macro.
*/
static inline void TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA
assume_graph_lock(void)
{
}
typedef struct GraphLockable { } GraphLockable;
/*
* In C, compound literals have the lifetime of an automatic variable.
* In C++ it would be different, but then C++ wouldn't need QemuLockable
* either...
*/
#define GML_OBJ_() (&(GraphLockable) { })
/*
* This is not marked as TSA_ACQUIRE_SHARED() because TSA doesn't understand the
* cleanup attribute and would therefore complain that the graph is never
* unlocked. TSA_ASSERT_SHARED() makes sure that the following calls know that
* we hold the lock while unlocking is left unchecked.
*/
static inline GraphLockable * TSA_ACQUIRE_SHARED(graph_lock) coroutine_fn
graph_lockable_auto_lock(GraphLockable *x)
{
bdrv_graph_co_rdlock();
return x;
}
static inline void TSA_RELEASE_SHARED(graph_lock) coroutine_fn
graph_lockable_auto_unlock(GraphLockable **x)
{
bdrv_graph_co_rdunlock();
}
#define GRAPH_AUTO_UNLOCK __attribute__((cleanup(graph_lockable_auto_unlock)))
/*
* @var is only used to break the loop after the first iteration.
* @unlock_var can't be unlocked and then set to NULL because TSA wants the lock
* to be held at the start of every iteration of the loop.
*/
#define WITH_GRAPH_RDLOCK_GUARD_(var) \
for (GraphLockable *unlock_var GRAPH_AUTO_UNLOCK = \
graph_lockable_auto_lock(GML_OBJ_()), \
*var = unlock_var; \
var; \
var = NULL)
#define WITH_GRAPH_RDLOCK_GUARD() \
WITH_GRAPH_RDLOCK_GUARD_(glue(graph_lockable_auto, __COUNTER__))
#define GRAPH_RDLOCK_GUARD(x) \
GraphLockable * GRAPH_AUTO_UNLOCK \
glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
graph_lockable_auto_lock(GML_OBJ_())
typedef struct GraphLockableMainloop { } GraphLockableMainloop;
/*
* In C, compound literals have the lifetime of an automatic variable.
* In C++ it would be different, but then C++ wouldn't need QemuLockable
* either...
*/
#define GMLML_OBJ_() (&(GraphLockableMainloop) { })
/*
* This is not marked as TSA_ACQUIRE_SHARED() because TSA doesn't understand the
* cleanup attribute and would therefore complain that the graph is never
* unlocked. TSA_ASSERT_SHARED() makes sure that the following calls know that
* we hold the lock while unlocking is left unchecked.
*/
static inline GraphLockableMainloop * TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA
graph_lockable_auto_lock_mainloop(GraphLockableMainloop *x)
{
bdrv_graph_rdlock_main_loop();
return x;
}
static inline void TSA_NO_TSA
graph_lockable_auto_unlock_mainloop(GraphLockableMainloop *x)
{
bdrv_graph_rdunlock_main_loop();
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockableMainloop,
graph_lockable_auto_unlock_mainloop)
#define GRAPH_RDLOCK_GUARD_MAINLOOP(x) \
g_autoptr(GraphLockableMainloop) \
glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
graph_lockable_auto_lock_mainloop(GMLML_OBJ_())
#endif /* GRAPH_LOCK_H */
+509
View File
@@ -0,0 +1,509 @@
/*
* Copyright Red Hat
* Copyright (C) 2005 Anthony Liguori <[email protected]>
*
* Network Block Device
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; under version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NBD_H
#define NBD_H
#include "block/export.h"
#include "io/channel-socket.h"
#include "crypto/tlscreds.h"
#include "qapi/error.h"
#include "qemu/bswap.h"
typedef struct NBDExport NBDExport;
typedef struct NBDClient NBDClient;
typedef struct NBDClientConnection NBDClientConnection;
typedef struct NBDMetaContexts NBDMetaContexts;
extern const BlockExportDriver blk_exp_nbd;
/*
* NBD_DEFAULT_HANDSHAKE_MAX_SECS: Number of seconds in which client must
* succeed at NBD_OPT_GO before being forcefully dropped as too slow.
*/
#define NBD_DEFAULT_HANDSHAKE_MAX_SECS 10
/*
* NBD_DEFAULT_MAX_CONNECTIONS: Number of client sockets to allow at
* once; must be large enough to allow a MULTI_CONN-aware client like
* nbdcopy to create its typical number of 8-16 sockets.
*/
#define NBD_DEFAULT_MAX_CONNECTIONS 100
/* Handshake phase structs - this struct is passed on the wire */
typedef struct NBDOption {
uint64_t magic; /* NBD_OPTS_MAGIC */
uint32_t option; /* NBD_OPT_* */
uint32_t length;
} QEMU_PACKED NBDOption;
typedef struct NBDOptionReply {
uint64_t magic; /* NBD_REP_MAGIC */
uint32_t option; /* NBD_OPT_* */
uint32_t type; /* NBD_REP_* */
uint32_t length;
} QEMU_PACKED NBDOptionReply;
typedef struct NBDOptionReplyMetaContext {
NBDOptionReply h; /* h.type = NBD_REP_META_CONTEXT, h.length > 4 */
uint32_t context_id;
/* metadata context name follows */
} QEMU_PACKED NBDOptionReplyMetaContext;
/* Track results of negotiation */
typedef enum NBDMode {
/* Keep this list in a continuum of increasing features. */
NBD_MODE_OLDSTYLE, /* server lacks newstyle negotiation */
NBD_MODE_EXPORT_NAME, /* newstyle but only OPT_EXPORT_NAME safe */
NBD_MODE_SIMPLE, /* newstyle but only simple replies */
NBD_MODE_STRUCTURED, /* newstyle, structured replies enabled */
NBD_MODE_EXTENDED, /* newstyle, extended headers enabled */
} NBDMode;
/* Transmission phase structs */
/*
* Note: NBDRequest is _NOT_ the same as the network representation of an NBD
* request!
*/
typedef struct NBDRequest {
uint64_t cookie;
uint64_t from; /* Offset touched by the command */
uint64_t len; /* Effect length; 32 bit limit without extended headers */
uint16_t flags; /* NBD_CMD_FLAG_* */
uint16_t type; /* NBD_CMD_* */
NBDMode mode; /* Determines which network representation to use */
NBDMetaContexts *contexts; /* Used by NBD_CMD_BLOCK_STATUS */
} NBDRequest;
typedef struct NBDSimpleReply {
uint32_t magic; /* NBD_SIMPLE_REPLY_MAGIC */
uint32_t error;
uint64_t cookie;
} QEMU_PACKED NBDSimpleReply;
/* Header of all structured replies */
typedef struct NBDStructuredReplyChunk {
uint32_t magic; /* NBD_STRUCTURED_REPLY_MAGIC */
uint16_t flags; /* combination of NBD_REPLY_FLAG_* */
uint16_t type; /* NBD_REPLY_TYPE_* */
uint64_t cookie; /* request handle */
uint32_t length; /* length of payload */
} QEMU_PACKED NBDStructuredReplyChunk;
typedef struct NBDExtendedReplyChunk {
uint32_t magic; /* NBD_EXTENDED_REPLY_MAGIC */
uint16_t flags; /* combination of NBD_REPLY_FLAG_* */
uint16_t type; /* NBD_REPLY_TYPE_* */
uint64_t cookie; /* request handle */
uint64_t offset; /* request offset */
uint64_t length; /* length of payload */
} QEMU_PACKED NBDExtendedReplyChunk;
typedef union NBDReply {
NBDSimpleReply simple;
NBDStructuredReplyChunk structured;
NBDExtendedReplyChunk extended;
struct {
/*
* @magic and @cookie fields have the same offset and size in all
* forms of replies, so let them be accessible without ".simple.",
* ".structured.", or ".extended." specifications.
*/
uint32_t magic;
uint32_t _skip;
uint64_t cookie;
};
} NBDReply;
QEMU_BUILD_BUG_ON(offsetof(NBDReply, simple.cookie) !=
offsetof(NBDReply, cookie));
QEMU_BUILD_BUG_ON(offsetof(NBDReply, structured.cookie) !=
offsetof(NBDReply, cookie));
QEMU_BUILD_BUG_ON(offsetof(NBDReply, extended.cookie) !=
offsetof(NBDReply, cookie));
/* Header of chunk for NBD_REPLY_TYPE_OFFSET_DATA */
typedef struct NBDStructuredReadData {
/* header's .length >= 9 */
uint64_t offset;
/* At least one byte of data payload follows, calculated from h.length */
} QEMU_PACKED NBDStructuredReadData;
/* Complete chunk for NBD_REPLY_TYPE_OFFSET_HOLE */
typedef struct NBDStructuredReadHole {
/* header's length == 12 */
uint64_t offset;
uint32_t length;
} QEMU_PACKED NBDStructuredReadHole;
/* Header of all NBD_REPLY_TYPE_ERROR* errors */
typedef struct NBDStructuredError {
/* header's length >= 6 */
uint32_t error;
uint16_t message_length;
} QEMU_PACKED NBDStructuredError;
/* Header of NBD_REPLY_TYPE_BLOCK_STATUS */
typedef struct NBDStructuredMeta {
/* header's length >= 12 (at least one extent) */
uint32_t context_id;
/* NBDExtent32 extents[] follows, array length implied by header */
} QEMU_PACKED NBDStructuredMeta;
/* Extent array element for NBD_REPLY_TYPE_BLOCK_STATUS */
typedef struct NBDExtent32 {
uint32_t length;
uint32_t flags; /* NBD_STATE_* */
} QEMU_PACKED NBDExtent32;
/* Header of NBD_REPLY_TYPE_BLOCK_STATUS_EXT */
typedef struct NBDExtendedMeta {
/* header's length >= 24 (at least one extent) */
uint32_t context_id;
uint32_t count; /* header length must be count * 16 + 8 */
/* NBDExtent64 extents[count] follows */
} QEMU_PACKED NBDExtendedMeta;
/* Extent array element for NBD_REPLY_TYPE_BLOCK_STATUS_EXT */
typedef struct NBDExtent64 {
uint64_t length;
uint64_t flags; /* NBD_STATE_* */
} QEMU_PACKED NBDExtent64;
/* Client payload for limiting NBD_CMD_BLOCK_STATUS reply */
typedef struct NBDBlockStatusPayload {
uint64_t effect_length;
/* uint32_t ids[] follows, array length implied by header */
} QEMU_PACKED NBDBlockStatusPayload;
/* Transmission (export) flags: sent from server to client during handshake,
but describe what will happen during transmission */
enum {
NBD_FLAG_HAS_FLAGS_BIT = 0, /* Flags are there */
NBD_FLAG_READ_ONLY_BIT = 1, /* Device is read-only */
NBD_FLAG_SEND_FLUSH_BIT = 2, /* Send FLUSH */
NBD_FLAG_SEND_FUA_BIT = 3, /* Send FUA (Force Unit Access) */
NBD_FLAG_ROTATIONAL_BIT = 4, /* Use elevator algorithm -
rotational media */
NBD_FLAG_SEND_TRIM_BIT = 5, /* Send TRIM (discard) */
NBD_FLAG_SEND_WRITE_ZEROES_BIT = 6, /* Send WRITE_ZEROES */
NBD_FLAG_SEND_DF_BIT = 7, /* Send DF (Do not Fragment) */
NBD_FLAG_CAN_MULTI_CONN_BIT = 8, /* Multi-client cache consistent */
NBD_FLAG_SEND_RESIZE_BIT = 9, /* Send resize */
NBD_FLAG_SEND_CACHE_BIT = 10, /* Send CACHE (prefetch) */
NBD_FLAG_SEND_FAST_ZERO_BIT = 11, /* FAST_ZERO flag for WRITE_ZEROES */
NBD_FLAG_BLOCK_STAT_PAYLOAD_BIT = 12, /* PAYLOAD flag for BLOCK_STATUS */
};
#define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT)
#define NBD_FLAG_READ_ONLY (1 << NBD_FLAG_READ_ONLY_BIT)
#define NBD_FLAG_SEND_FLUSH (1 << NBD_FLAG_SEND_FLUSH_BIT)
#define NBD_FLAG_SEND_FUA (1 << NBD_FLAG_SEND_FUA_BIT)
#define NBD_FLAG_ROTATIONAL (1 << NBD_FLAG_ROTATIONAL_BIT)
#define NBD_FLAG_SEND_TRIM (1 << NBD_FLAG_SEND_TRIM_BIT)
#define NBD_FLAG_SEND_WRITE_ZEROES (1 << NBD_FLAG_SEND_WRITE_ZEROES_BIT)
#define NBD_FLAG_SEND_DF (1 << NBD_FLAG_SEND_DF_BIT)
#define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT)
#define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT)
#define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT)
#define NBD_FLAG_SEND_FAST_ZERO (1 << NBD_FLAG_SEND_FAST_ZERO_BIT)
#define NBD_FLAG_BLOCK_STAT_PAYLOAD (1 << NBD_FLAG_BLOCK_STAT_PAYLOAD_BIT)
/* New-style handshake (global) flags, sent from server to client, and
control what will happen during handshake phase. */
#define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
#define NBD_FLAG_NO_ZEROES (1 << 1) /* End handshake without zeroes. */
/* New-style client flags, sent from client to server to control what happens
during handshake phase. */
#define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */
#define NBD_FLAG_C_NO_ZEROES (1 << 1) /* End handshake without zeroes. */
/* Option requests. */
#define NBD_OPT_EXPORT_NAME (1)
#define NBD_OPT_ABORT (2)
#define NBD_OPT_LIST (3)
/* #define NBD_OPT_PEEK_EXPORT (4) not in use */
#define NBD_OPT_STARTTLS (5)
#define NBD_OPT_INFO (6)
#define NBD_OPT_GO (7)
#define NBD_OPT_STRUCTURED_REPLY (8)
#define NBD_OPT_LIST_META_CONTEXT (9)
#define NBD_OPT_SET_META_CONTEXT (10)
#define NBD_OPT_EXTENDED_HEADERS (11)
/* Option reply types. */
#define NBD_REP_ERR(value) ((UINT32_C(1) << 31) | (value))
#define NBD_REP_ACK (1) /* Data sending finished. */
#define NBD_REP_SERVER (2) /* Export description. */
#define NBD_REP_INFO (3) /* NBD_OPT_INFO/GO. */
#define NBD_REP_META_CONTEXT (4) /* NBD_OPT_{LIST,SET}_META_CONTEXT */
#define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) /* Unknown option */
#define NBD_REP_ERR_POLICY NBD_REP_ERR(2) /* Server denied */
#define NBD_REP_ERR_INVALID NBD_REP_ERR(3) /* Invalid length */
#define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) /* Not compiled in */
#define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) /* TLS required */
#define NBD_REP_ERR_UNKNOWN NBD_REP_ERR(6) /* Export unknown */
#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) /* Server shutting down */
#define NBD_REP_ERR_BLOCK_SIZE_REQD NBD_REP_ERR(8) /* Need INFO_BLOCK_SIZE */
#define NBD_REP_ERR_TOO_BIG NBD_REP_ERR(9) /* Payload size overflow */
#define NBD_REP_ERR_EXT_HEADER_REQD NBD_REP_ERR(10) /* Need extended headers */
/* Info types, used during NBD_REP_INFO */
#define NBD_INFO_EXPORT 0
#define NBD_INFO_NAME 1
#define NBD_INFO_DESCRIPTION 2
#define NBD_INFO_BLOCK_SIZE 3
/* Request flags, sent from client to server during transmission phase */
#define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during write */
#define NBD_CMD_FLAG_NO_HOLE (1 << 1) /* don't punch hole on zero run */
#define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured read */
#define NBD_CMD_FLAG_REQ_ONE (1 << 3) \
/* only one extent in BLOCK_STATUS reply chunk */
#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) /* fail if WRITE_ZEROES is not fast */
#define NBD_CMD_FLAG_PAYLOAD_LEN (1 << 5) \
/* length describes payload, not effect; only with ext header */
/* Supported request types */
enum {
NBD_CMD_READ = 0,
NBD_CMD_WRITE = 1,
NBD_CMD_DISC = 2,
NBD_CMD_FLUSH = 3,
NBD_CMD_TRIM = 4,
NBD_CMD_CACHE = 5,
NBD_CMD_WRITE_ZEROES = 6,
NBD_CMD_BLOCK_STATUS = 7,
};
#define NBD_DEFAULT_PORT 10809
/* Maximum size of a single READ/WRITE data buffer */
#define NBD_MAX_BUFFER_SIZE (32 * 1024 * 1024)
/*
* Maximum size of a protocol string (export name, metadata context name,
* etc.). Use malloc rather than stack allocation for storage of a
* string.
*/
#define NBD_MAX_STRING_SIZE 4096
/* Two types of request structures, a given client will only use 1 */
#define NBD_REQUEST_MAGIC 0x25609513
#define NBD_EXTENDED_REQUEST_MAGIC 0x21e41c71
/*
* Three types of reply structures, but what a client expects depends
* on NBD_OPT_STRUCTURED_REPLY and NBD_OPT_EXTENDED_HEADERS.
*/
#define NBD_SIMPLE_REPLY_MAGIC 0x67446698
#define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef
#define NBD_EXTENDED_REPLY_MAGIC 0x6e8a278c
/* Chunk reply flags (for structured and extended replies) */
#define NBD_REPLY_FLAG_DONE (1 << 0) /* This reply-chunk is last */
/* Chunk reply types */
#define NBD_REPLY_ERR(value) ((1 << 15) | (value))
#define NBD_REPLY_TYPE_NONE 0
#define NBD_REPLY_TYPE_OFFSET_DATA 1
#define NBD_REPLY_TYPE_OFFSET_HOLE 2
#define NBD_REPLY_TYPE_BLOCK_STATUS 5
#define NBD_REPLY_TYPE_BLOCK_STATUS_EXT 6
#define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1)
#define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_ERR(2)
/* Extent flags for base:allocation in NBD_REPLY_TYPE_BLOCK_STATUS */
#define NBD_STATE_HOLE (1 << 0)
#define NBD_STATE_ZERO (1 << 1)
/* Extent flags for qemu:dirty-bitmap in NBD_REPLY_TYPE_BLOCK_STATUS */
#define NBD_STATE_DIRTY (1 << 0)
/* No flags needed for qemu:allocation-depth in NBD_REPLY_TYPE_BLOCK_STATUS */
static inline bool nbd_reply_type_is_error(int type)
{
return type & (1 << 15);
}
/* NBD errors are based on errno numbers, so there is a 1:1 mapping,
* but only a limited set of errno values is specified in the protocol.
* Everything else is squashed to EINVAL.
*/
#define NBD_SUCCESS 0
#define NBD_EPERM 1
#define NBD_EIO 5
#define NBD_ENOMEM 12
#define NBD_EINVAL 22
#define NBD_ENOSPC 28
#define NBD_EOVERFLOW 75
#define NBD_ENOTSUP 95
#define NBD_ESHUTDOWN 108
/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
typedef struct NBDExportInfo {
/* Set by client before nbd_receive_negotiate() */
bool request_sizes;
char *x_dirty_bitmap;
/* Set by client before nbd_receive_negotiate(), or by server results
* during nbd_receive_export_list() */
char *name; /* must be non-NULL */
/* In-out fields, set by client before nbd_receive_negotiate() and
* updated by server results during nbd_receive_negotiate() */
NBDMode mode; /* input maximum mode tolerated; output actual mode chosen */
bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */
/* Set by server results during nbd_receive_negotiate() and
* nbd_receive_export_list() */
uint64_t size;
uint16_t flags;
uint32_t min_block;
uint32_t opt_block;
uint32_t max_block;
uint32_t context_id;
/* Set by server results during nbd_receive_export_list() */
char *description;
int n_contexts;
char **contexts;
} NBDExportInfo;
int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
const char *hostname, QIOChannel **outioc,
NBDExportInfo *info, Error **errp);
void nbd_free_export_list(NBDExportInfo *info, int count);
int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
const char *hostname, NBDExportInfo **info,
Error **errp);
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp);
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc,
NBDReply *reply, NBDMode mode,
Error **errp);
int nbd_client(int fd);
int nbd_disconnect(int fd);
int nbd_errno_to_system_errno(int err);
void nbd_export_set_on_eject_blk(BlockExport *exp, BlockBackend *blk);
AioContext *nbd_export_aio_context(NBDExport *exp);
NBDExport *nbd_export_find(const char *name);
void nbd_client_new(QIOChannelSocket *sioc,
uint32_t handshake_max_secs,
QCryptoTLSCreds *tlscreds,
const char *tlsauthz,
void (*close_fn)(NBDClient *, bool),
void *owner);
void *nbd_client_owner(NBDClient *client);
void nbd_client_get(NBDClient *client);
void nbd_client_put(NBDClient *client);
void nbd_server_is_qemu_nbd(int max_connections);
bool nbd_server_is_running(void);
int nbd_server_max_connections(void);
void nbd_server_start(SocketAddress *addr, uint32_t handshake_max_secs,
const char *tls_creds, const char *tls_authz,
uint32_t max_connections, Error **errp);
void nbd_server_start_options(NbdServerOptions *arg, Error **errp);
/* nbd_read
* Reads @size bytes from @ioc. Returns 0 on success.
*/
static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size,
const char *desc, Error **errp)
{
ERRP_GUARD();
int ret = qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0;
if (ret < 0) {
if (desc) {
error_prepend(errp, "Failed to read %s: ", desc);
}
return ret;
}
return 0;
}
#define DEF_NBD_READ_N(bits) \
static inline int nbd_read##bits(QIOChannel *ioc, \
uint##bits##_t *val, \
const char *desc, Error **errp) \
{ \
int ret = nbd_read(ioc, val, sizeof(*val), desc, errp); \
if (ret < 0) { \
return ret; \
} \
*val = be##bits##_to_cpu(*val); \
return 0; \
}
DEF_NBD_READ_N(16) /* Defines nbd_read16(). */
DEF_NBD_READ_N(32) /* Defines nbd_read32(). */
DEF_NBD_READ_N(64) /* Defines nbd_read64(). */
#undef DEF_NBD_READ_N
static inline bool nbd_reply_is_simple(NBDReply *reply)
{
return reply->magic == NBD_SIMPLE_REPLY_MAGIC;
}
static inline bool nbd_reply_is_structured(NBDReply *reply)
{
return reply->magic == NBD_STRUCTURED_REPLY_MAGIC;
}
const char *nbd_reply_type_lookup(uint16_t type);
const char *nbd_opt_lookup(uint32_t opt);
const char *nbd_rep_lookup(uint32_t rep);
const char *nbd_info_lookup(uint16_t info);
const char *nbd_cmd_lookup(uint16_t info);
const char *nbd_err_lookup(int err);
const char *nbd_mode_lookup(NBDMode mode);
/* nbd/client-connection.c */
void nbd_client_connection_enable_retry(NBDClientConnection *conn);
NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr,
bool do_negotiation,
const char *export_name,
const char *x_dirty_bitmap,
QCryptoTLSCreds *tlscreds,
const char *tlshostname);
void nbd_client_connection_release(NBDClientConnection *conn);
QIOChannel *coroutine_fn
nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info,
bool blocking, Error **errp);
void nbd_co_establish_connection_cancel(NBDClientConnection *conn);
#endif
+2000
View File
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
/*
* Block layer qmp and info dump related functions
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef BLOCK_QAPI_H
#define BLOCK_QAPI_H
#include "block/graph-lock.h"
#include "block/snapshot.h"
#include "qapi/qapi-types-block-core.h"
BlockDeviceInfo * GRAPH_RDLOCK
bdrv_block_device_info(BlockBackend *blk, BlockDriverState *bs,
bool flat, Error **errp);
int GRAPH_RDLOCK
bdrv_query_snapshot_info_list(BlockDriverState *bs,
SnapshotInfoList **p_list,
Error **errp);
void GRAPH_RDLOCK
bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat,
bool skip_implicit_filters, Error **errp);
void GRAPH_RDLOCK
bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info,
bool limits, Error **errp);
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn);
void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
const char *prefix,
int indentation);
void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol);
#endif
+35
View File
@@ -0,0 +1,35 @@
/*
* Special QDict functions used by the block layer
*
* Copyright (c) 2013-2018 Red Hat, Inc.
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#ifndef BLOCK_QDICT_H
#define BLOCK_QDICT_H
#include "qobject/qdict.h"
QObject *qdict_crumple(const QDict *src, Error **errp);
void qdict_flatten(QDict *qdict);
void qdict_copy_default(QDict *dst, QDict *src, const char *key);
void qdict_set_default_str(QDict *dst, const char *key, const char *val);
void qdict_join(QDict *dest, QDict *src, bool overwrite);
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
void qdict_array_split(QDict *src, QList **dst);
int qdict_array_entries(QDict *src, const char *subqdict);
typedef struct QDictRenames {
const char *from;
const char *to;
} QDictRenames;
bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
Visitor *qobject_input_visitor_new_flat_confused(QDict *qdict,
Error **errp);
#endif
+105
View File
@@ -0,0 +1,105 @@
/*
* Declarations for AIO in the raw protocol
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef QEMU_RAW_AIO_H
#define QEMU_RAW_AIO_H
#include "qemu/aiocb.h"
#include "qemu/aio.h"
#include "block/block-common.h"
#include "qemu/iov.h"
/* AIO request types */
#define QEMU_AIO_READ 0x0001
#define QEMU_AIO_WRITE 0x0002
#define QEMU_AIO_IOCTL 0x0004
#define QEMU_AIO_FLUSH 0x0008
#define QEMU_AIO_DISCARD 0x0010
#define QEMU_AIO_WRITE_ZEROES 0x0020
#define QEMU_AIO_COPY_RANGE 0x0040
#define QEMU_AIO_TRUNCATE 0x0080
#define QEMU_AIO_ZONE_REPORT 0x0100
#define QEMU_AIO_ZONE_MGMT 0x0200
#define QEMU_AIO_ZONE_APPEND 0x0400
#define QEMU_AIO_TYPE_MASK \
(QEMU_AIO_READ | \
QEMU_AIO_WRITE | \
QEMU_AIO_IOCTL | \
QEMU_AIO_FLUSH | \
QEMU_AIO_DISCARD | \
QEMU_AIO_WRITE_ZEROES | \
QEMU_AIO_COPY_RANGE | \
QEMU_AIO_TRUNCATE | \
QEMU_AIO_ZONE_REPORT | \
QEMU_AIO_ZONE_MGMT | \
QEMU_AIO_ZONE_APPEND)
/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000
#define QEMU_AIO_BLKDEV 0x2000
#define QEMU_AIO_NO_FALLBACK 0x4000
/* linux-aio.c - Linux native implementation */
#ifdef CONFIG_LINUX_AIO
typedef struct LinuxAioState LinuxAioState;
LinuxAioState *laio_init(Error **errp);
void laio_cleanup(LinuxAioState *s);
/* laio_co_submit: submit I/O requests in the thread's current AioContext. */
int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
int type, BdrvRequestFlags flags,
uint64_t dev_max_batch);
bool laio_has_fdsync(int);
bool laio_has_fua(void);
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
#else
static inline bool laio_has_fua(void)
{
return false;
}
#endif
/* io_uring.c - Linux io_uring implementation */
#ifdef CONFIG_LINUX_IO_URING
/* luring_co_submit: submit I/O requests in the thread's current AioContext. */
int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
QEMUIOVector *qiov, int type,
BdrvRequestFlags flags);
bool luring_has_fua(void);
#else
static inline bool luring_has_fua(void)
{
return false;
}
#endif
#ifdef _WIN32
typedef struct QEMUWin32AIOState QEMUWin32AIOState;
QEMUWin32AIOState *win32_aio_init(void);
void win32_aio_cleanup(QEMUWin32AIOState *aio);
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
QEMUWin32AIOState *aio, HANDLE hfile,
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
BlockCompletionFunc *cb, void *opaque, int type);
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
AioContext *old_context);
void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
AioContext *new_context);
#endif
#endif /* QEMU_RAW_AIO_H */
+175
View File
@@ -0,0 +1,175 @@
/*
* Replication filter
*
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
* Copyright (c) 2016 Intel Corporation
* Copyright (c) 2016 FUJITSU LIMITED
*
* Author:
* Changlong Xie <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef REPLICATION_H
#define REPLICATION_H
#include "qapi/qapi-types-block-core.h"
#include "qemu/module.h"
#include "qemu/queue.h"
typedef struct ReplicationOps ReplicationOps;
typedef struct ReplicationState ReplicationState;
/**
* SECTION:block/replication.h
* @title:Base Replication System
* @short_description: interfaces for handling replication
*
* The Replication Model provides a framework for handling Replication
*
* <example>
* <title>How to use replication interfaces</title>
* <programlisting>
* #include "block/replication.h"
*
* typedef struct BDRVReplicationState {
* ReplicationState *rs;
* } BDRVReplicationState;
*
* static void replication_start(ReplicationState *rs, ReplicationMode mode,
* Error **errp);
* static void replication_do_checkpoint(ReplicationState *rs, Error **errp);
* static void replication_get_error(ReplicationState *rs, Error **errp);
* static void replication_stop(ReplicationState *rs, bool failover,
* Error **errp);
*
* static ReplicationOps replication_ops = {
* .start = replication_start,
* .checkpoint = replication_do_checkpoint,
* .get_error = replication_get_error,
* .stop = replication_stop,
* }
*
* static int replication_open(BlockDriverState *bs, QDict *options,
* int flags, Error **errp)
* {
* BDRVReplicationState *s = bs->opaque;
* s->rs = replication_new(bs, &replication_ops);
* return 0;
* }
*
* static void replication_close(BlockDriverState *bs)
* {
* BDRVReplicationState *s = bs->opaque;
* replication_remove(s->rs);
* }
*
* BlockDriver bdrv_replication = {
* .format_name = "replication",
* .instance_size = sizeof(BDRVReplicationState),
*
* .bdrv_open = replication_open,
* .bdrv_close = replication_close,
* };
*
* static void bdrv_replication_init(void)
* {
* bdrv_register(&bdrv_replication);
* }
*
* block_init(bdrv_replication_init);
* </programlisting>
* </example>
*
* We create an example about how to use replication interfaces in above.
* Then in migration, we can use replication_(start/stop/do_checkpoint/
* get_error)_all to handle all replication operations.
*/
/**
* ReplicationState:
* @opaque: opaque pointer value passed to this ReplicationState
* @ops: replication operation of this ReplicationState
* @node: node that we will insert into @replication_states QLIST
*/
struct ReplicationState {
void *opaque;
ReplicationOps *ops;
QLIST_ENTRY(ReplicationState) node;
};
/**
* ReplicationOps:
* @start: callback to start replication
* @stop: callback to stop replication
* @checkpoint: callback to do checkpoint
* @get_error: callback to check if error occurred during replication
*/
struct ReplicationOps {
void (*start)(ReplicationState *rs, ReplicationMode mode, Error **errp);
void (*stop)(ReplicationState *rs, bool failover, Error **errp);
void (*checkpoint)(ReplicationState *rs, Error **errp);
void (*get_error)(ReplicationState *rs, Error **errp);
};
/**
* replication_new:
* @opaque: opaque pointer value passed to ReplicationState
* @ops: replication operation of the new relevant ReplicationState
*
* Called to create a new ReplicationState instance, and then insert it
* into @replication_states QLIST
*
* Returns: the new ReplicationState instance
*/
ReplicationState *replication_new(void *opaque, ReplicationOps *ops);
/**
* replication_remove:
* @rs: the ReplicationState instance to remove
*
* Called to remove a ReplicationState instance, and then delete it from
* @replication_states QLIST
*/
void replication_remove(ReplicationState *rs);
/**
* replication_start_all:
* @mode: replication mode that could be "primary" or "secondary"
* @errp: returns an error if this function fails
*
* Start replication, called in migration/checkpoint thread
*
* Note: the caller of the function MUST make sure vm stopped
*/
void replication_start_all(ReplicationMode mode, Error **errp);
/**
* replication_do_checkpoint_all:
* @errp: returns an error if this function fails
*
* This interface is called after all VM state is transferred to Secondary QEMU
*/
void replication_do_checkpoint_all(Error **errp);
/**
* replication_get_error_all:
* @errp: returns an error if this function fails
*
* This interface is called to check if error occurred during replication
*/
void replication_get_error_all(Error **errp);
/**
* replication_stop_all:
* @failover: boolean value that indicates if we need do failover or not
* @errp: returns an error if this function fails
*
* It is called on failover. The vm should be stopped before calling it, if you
* use this API to shutdown the guest, or other things except failover
*/
void replication_stop_all(bool failover, Error **errp);
#endif /* REPLICATION_H */
+75
View File
@@ -0,0 +1,75 @@
/*
* reqlist API
*
* Copyright (C) 2013 Proxmox Server Solutions
* Copyright (c) 2021 Virtuozzo International GmbH.
*
* Authors:
* Dietmar Maurer ([email protected])
* Vladimir Sementsov-Ogievskiy <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef REQLIST_H
#define REQLIST_H
#include "qemu/coroutine.h"
/*
* The API is not thread-safe and shouldn't be. The struct is public to be part
* of other structures and protected by third-party locks, see
* block/block-copy.c for example.
*/
typedef struct BlockReq {
int64_t offset;
int64_t bytes;
CoQueue wait_queue; /* coroutines blocked on this req */
QLIST_ENTRY(BlockReq) list;
} BlockReq;
typedef QLIST_HEAD(, BlockReq) BlockReqList;
/*
* Initialize new request and add it to the list. Caller must be sure that
* there are no conflicting requests in the list.
*/
void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
int64_t bytes);
/* Search for request in the list intersecting with @offset/@bytes area. */
BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
int64_t bytes);
/*
* If there are no intersecting requests return false. Otherwise, wait for the
* first found intersecting request to finish and return true.
*
* @lock is passed to qemu_co_queue_wait()
* False return value proves that lock was released at no point.
*/
bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
int64_t bytes, CoMutex *lock);
/*
* Wait for all intersecting requests. It just calls reqlist_wait_one() in a
* loop, caller is responsible to stop producing new requests in this region
* in parallel, otherwise reqlist_wait_all() may never return.
*/
void coroutine_fn reqlist_wait_all(BlockReqList *reqs, int64_t offset,
int64_t bytes, CoMutex *lock);
/*
* Shrink request and wake all waiting coroutines (maybe some of them are not
* intersecting with shrunk request).
*/
void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes);
/*
* Remove request and wake all waiting coroutines. Do not release any memory.
*/
void coroutine_fn reqlist_remove_req(BlockReq *req);
#endif /* REQLIST_H */
+113
View File
@@ -0,0 +1,113 @@
/*
* Block layer snapshot related functions
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SNAPSHOT_H
#define SNAPSHOT_H
#include "block/graph-lock.h"
#include "qapi/qapi-builtin-types.h"
#define SNAPSHOT_OPT_BASE "snapshot."
#define SNAPSHOT_OPT_ID "snapshot.id"
#define SNAPSHOT_OPT_NAME "snapshot.name"
extern QemuOptsList internal_snapshot_opts;
typedef struct QEMUSnapshotInfo {
char id_str[128]; /* unique snapshot id */
/* the following fields are informative. They are not needed for
the consistency of the snapshot */
char name[256]; /* user chosen name */
uint64_t vm_state_size; /* VM state info size */
uint32_t date_sec; /* UTC date of the snapshot */
uint32_t date_nsec;
uint64_t vm_clock_nsec; /* VM clock relative to boot */
uint64_t icount; /* record/replay step */
} QEMUSnapshotInfo;
/*
* Global state (GS) API. These functions run under the BQL.
*
* See include/block/block-global-state.h for more information about
* the GS API.
*/
int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
const char *name);
bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
const char *id,
const char *name,
QEMUSnapshotInfo *sn_info,
Error **errp);
int GRAPH_RDLOCK bdrv_can_snapshot(BlockDriverState *bs);
int GRAPH_RDLOCK
bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
int GRAPH_UNLOCKED
bdrv_snapshot_goto(BlockDriverState *bs, const char *snapshot_id, Error **errp);
int GRAPH_RDLOCK
bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
const char *name, Error **errp);
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
const char *snapshot_id,
const char *name,
Error **errp);
int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
const char *id_or_name,
Error **errp);
/*
* Group operations. All block drivers are involved.
*/
bool bdrv_all_can_snapshot(bool has_devices, strList *devices,
Error **errp);
int GRAPH_UNLOCKED
bdrv_all_delete_snapshot(const char *name, bool has_devices, strList *devices,
Error **errp);
int bdrv_all_goto_snapshot(const char *name,
bool has_devices, strList *devices,
Error **errp);
int bdrv_all_has_snapshot(const char *name,
bool has_devices, strList *devices,
Error **errp);
int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
BlockDriverState *vm_state_bs,
uint64_t vm_state_size,
bool has_devices,
strList *devices,
Error **errp);
BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
bool has_devices, strList *devices,
Error **errp);
#endif
+94
View File
@@ -0,0 +1,94 @@
/*
* QEMU block layer thread pool
*
* Copyright IBM, Corp. 2008
* Copyright Red Hat, Inc. 2012
*
* Authors:
* Anthony Liguori <[email protected]>
* Paolo Bonzini <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef QEMU_THREAD_POOL_H
#define QEMU_THREAD_POOL_H
#include "qemu/aiocb.h"
#include "qemu/aio.h"
#define THREAD_POOL_MAX_THREADS_DEFAULT 64
typedef int ThreadPoolFunc(void *opaque);
typedef struct ThreadPoolAio ThreadPoolAio;
ThreadPoolAio *thread_pool_new_aio(struct AioContext *ctx);
void thread_pool_free_aio(ThreadPoolAio *pool);
/*
* thread_pool_submit_{aio,co} API: submit I/O requests in the thread's
* current AioContext.
*/
BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
BlockCompletionFunc *cb, void *opaque);
int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg);
void thread_pool_update_params(ThreadPoolAio *pool, struct AioContext *ctx);
/* ------------------------------------------- */
/* Generic thread pool types and methods below */
typedef struct ThreadPool ThreadPool;
/* Create a new thread pool. Never returns NULL. */
ThreadPool *thread_pool_new(void);
/*
* Free the thread pool.
* Waits for all the previously submitted work to complete before performing
* the actual freeing operation.
*/
void thread_pool_free(ThreadPool *pool);
/*
* Submit a new work (task) for the pool.
*
* @opaque_destroy is an optional GDestroyNotify for the @opaque argument
* to the work function at @func.
*/
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func,
void *opaque, GDestroyNotify opaque_destroy);
/*
* Submit a new work (task) for the pool, making sure it starts getting
* processed immediately, launching a new thread for it if necessary.
*
* @opaque_destroy is an optional GDestroyNotify for the @opaque argument
* to the work function at @func.
*/
void thread_pool_submit_immediate(ThreadPool *pool, ThreadPoolFunc *func,
void *opaque, GDestroyNotify opaque_destroy);
/*
* Wait for all previously submitted work to complete before returning.
*
* Can be used as a barrier between two sets of tasks executed on a thread
* pool without destroying it or in a performance sensitive path where the
* caller just wants to wait for all tasks to complete while deferring the
* pool free operation for later, less performance sensitive time.
*/
void thread_pool_wait(ThreadPool *pool);
/* Set the maximum number of threads in the pool. */
bool thread_pool_set_max_threads(ThreadPool *pool, int max_threads);
/*
* Adjust the maximum number of threads in the pool to give each task its
* own thread (exactly one thread per task).
*/
bool thread_pool_adjust_max_threads_to_work(ThreadPool *pool);
#endif
+90
View File
@@ -0,0 +1,90 @@
/*
* QEMU block throttling group infrastructure
*
* Copyright (C) Nodalink, EURL. 2014
* Copyright (C) Igalia, S.L. 2015
*
* Authors:
* Benoît Canet <[email protected]>
* Alberto Garcia <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef THROTTLE_GROUPS_H
#define THROTTLE_GROUPS_H
#include "qemu/coroutine.h"
#include "qemu/throttle.h"
#include "qom/object.h"
/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
* and holds related data.
*/
typedef struct ThrottleGroupMember {
AioContext *aio_context;
/* Protected by ThrottleGroup.lock */
CoQueue throttled_reqs[THROTTLE_MAX];
/* Nonzero if the I/O limits are currently being ignored; generally
* it is zero. Accessed with atomic operations.
*/
unsigned int io_limits_disabled;
/* Number of pending throttle_group_restart_queue_entry() coroutines.
* Accessed with atomic operations.
*/
unsigned int restart_pending;
/* The following fields are protected by the ThrottleGroup lock.
* See the ThrottleGroup documentation for details.
* throttle_state tells us if I/O limits are configured. */
ThrottleState *throttle_state;
ThrottleTimers throttle_timers;
unsigned pending_reqs[THROTTLE_MAX];
QLIST_ENTRY(ThrottleGroupMember) round_robin;
} ThrottleGroupMember;
#define TYPE_THROTTLE_GROUP "throttle-group"
OBJECT_DECLARE_SIMPLE_TYPE(ThrottleGroup, THROTTLE_GROUP)
const char *throttle_group_get_name(ThrottleGroupMember *tgm);
ThrottleState *throttle_group_incref(const char *name);
void throttle_group_unref(ThrottleState *ts);
void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
void throttle_group_register_tgm(ThrottleGroupMember *tgm,
const char *groupname,
AioContext *ctx);
void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
int64_t bytes,
ThrottleDirection direction);
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
AioContext *new_context);
void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
/*
* throttle_group_exists() must be called under the global
* mutex.
*/
bool throttle_group_exists(const char *name);
#endif
+1374
View File
File diff suppressed because it is too large Load Diff
+45
View File
@@ -0,0 +1,45 @@
/*
* QEMU System Emulator block write threshold notification
*
* Copyright Red Hat, Inc. 2014
*
* Authors:
* Francesco Romani <[email protected]>
*
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#ifndef BLOCK_WRITE_THRESHOLD_H
#define BLOCK_WRITE_THRESHOLD_H
/*
* bdrv_write_threshold_set:
*
* Set the write threshold for block devices, in bytes.
* Notify when a write exceeds the threshold, meaning the device
* is becoming full, so it can be transparently resized.
* To be used with thin-provisioned block devices.
*
* Use threshold_bytes == 0 to disable.
*/
void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes);
/*
* bdrv_write_threshold_get
*
* Get the configured write threshold, in bytes.
* Zero means no threshold configured.
*/
uint64_t bdrv_write_threshold_get(const BlockDriverState *bs);
/*
* bdrv_write_threshold_check_write
*
* Check whether the specified request exceeds the write threshold.
* If so, send a corresponding event and disable write threshold checking.
*/
void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset,
int64_t bytes);
#endif
+47
View File
@@ -0,0 +1,47 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_FD_H
#define CHAR_FD_H
#include "io/channel.h"
#include "chardev/char.h"
#include "qom/object.h"
struct FDChardev {
Chardev parent;
QIOChannel *ioc_in, *ioc_out;
int max_size;
};
typedef struct FDChardev FDChardev;
#define TYPE_CHARDEV_FD "chardev-fd"
DECLARE_INSTANCE_CHECKER(FDChardev, FD_CHARDEV,
TYPE_CHARDEV_FD)
bool qemu_chr_open_fd(Chardev *chr, int fd_in, int fd_out, Error **errp);
int qmp_chardev_open_file_source(char *src, int flags, Error **errp);
#endif /* CHAR_FD_H */
+324
View File
@@ -0,0 +1,324 @@
#ifndef QEMU_CHAR_FE_H
#define QEMU_CHAR_FE_H
#include "chardev/char.h"
#include "qemu/main-loop.h"
typedef void IOEventHandler(void *opaque, QEMUChrEvent event);
typedef int BackendChangeHandler(void *opaque);
/**
* struct CharFrontend - Chardev as seen by front end
* @fe_is_open: the front end is ready for IO
*
* The actual backend is Chardev
*/
struct CharFrontend {
Chardev *chr;
IOEventHandler *chr_event;
IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read;
BackendChangeHandler *chr_be_change;
void *opaque;
unsigned int tag;
bool fe_is_open;
};
/**
* qemu_chr_fe_init:
*
* Initializes the frontend @c for the given Chardev backend @s. Call
* qemu_chr_fe_deinit() to remove the association and release the backend.
*
* Returns: false on error.
*/
bool qemu_chr_fe_init(CharFrontend *c, Chardev *be, Error **errp);
/**
* qemu_chr_fe_deinit:
* @c: a CharFrontend
* @del: if true, delete the chardev backend
*
* Dissociate the CharFrontend from the Chardev.
*
* Safe to call without associated Chardev.
*/
void qemu_chr_fe_deinit(CharFrontend *c, bool del);
/**
* qemu_chr_fe_get_driver:
*
* Returns: the driver associated with a CharFrontend or NULL if no
* associated Chardev.
* Note: avoid this function as the driver should never be accessed directly,
* especially by the frontends that support chardevice hotswap.
* Consider qemu_chr_fe_backend_connected() to check for driver
* existence or qemu_chr_fe_backend_name() if you need the name.
*/
Chardev *qemu_chr_fe_get_driver(CharFrontend *c);
/**
* qemu_chr_fe_backend_connected:
*
* Returns: true if there is a backend associated with @c.
*/
bool qemu_chr_fe_backend_connected(CharFrontend *c);
/**
* qemu_chr_fe_backend_open:
*
* Returns: true if the backend associated with @c is open.
*/
bool qemu_chr_fe_backend_open(CharFrontend *c);
/**
* qemu_chr_fe_backend_name:
*
* Returns: caller freeable string or NULL
*/
static inline char *qemu_chr_fe_backend_name(CharFrontend *c)
{
return (c->chr && c->chr->label) ? g_strdup(c->chr->label) : NULL;
}
/**
* qemu_chr_fe_set_handlers_full:
* @c: a CharFrontend
* @fd_can_read: callback to get the amount of data the frontend may
* receive
* @fd_read: callback to receive data from char
* @fd_event: event callback
* @be_change: backend change callback; passing NULL means hot backend change
* is not supported and will not be attempted
* @opaque: an opaque pointer for the callbacks
* @context: a main loop context or NULL for the default
* @set_open: whether to call qemu_chr_fe_set_open() implicitly when
* any of the handler is non-NULL
* @sync_state: whether to issue event callback with updated state
*
* Set the front end char handlers. The front end takes the focus if
* any of the handler is non-NULL.
*
* Without associated Chardev, nothing is changed.
*/
void qemu_chr_fe_set_handlers_full(CharFrontend *c,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
BackendChangeHandler *be_change,
void *opaque,
GMainContext *context,
bool set_open,
bool sync_state);
/**
* qemu_chr_fe_set_handlers:
*
* Version of qemu_chr_fe_set_handlers_full() with sync_state = true.
*/
void qemu_chr_fe_set_handlers(CharFrontend *c,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
BackendChangeHandler *be_change,
void *opaque,
GMainContext *context,
bool set_open);
/**
* qemu_chr_fe_take_focus:
*
* Take the focus (if the front end is muxed).
*
* Without associated Chardev, nothing is changed.
*/
void qemu_chr_fe_take_focus(CharFrontend *c);
/**
* qemu_chr_fe_accept_input:
*
* Notify that the frontend is ready to receive data
*/
void qemu_chr_fe_accept_input(CharFrontend *c);
/**
* qemu_chr_fe_disconnect:
*
* Close a fd accepted by character backend.
* Without associated Chardev, do nothing.
*/
void qemu_chr_fe_disconnect(CharFrontend *c);
/**
* qemu_chr_fe_wait_connected:
*
* Wait for character backend to be connected, return < 0 on error or
* if no associated Chardev.
*/
int qemu_chr_fe_wait_connected(CharFrontend *c, Error **errp);
/**
* qemu_chr_fe_set_echo:
* @echo: true to enable echo, false to disable echo
*
* Ask the backend to override its normal echo setting. This only really
* applies to the stdio backend and is used by the QMP server such that you
* can see what you type if you try to type QMP commands.
* Without associated Chardev, do nothing.
*/
void qemu_chr_fe_set_echo(CharFrontend *c, bool echo);
/**
* qemu_chr_fe_set_open:
* @c: a CharFrontend
* @is_open: the front end open status
*
* This is an indication that the front end is ready (or not) to begin
* doing I/O. Without associated Chardev, do nothing.
*/
void qemu_chr_fe_set_open(CharFrontend *c, bool is_open);
/**
* qemu_chr_fe_printf:
* @fmt: see #printf
*
* Write to a character backend using a printf style interface. This
* function is thread-safe. It does nothing without associated
* Chardev.
*/
void qemu_chr_fe_printf(CharFrontend *c, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);
/**
* FEWatchFunc: a #GSourceFunc called when any conditions requested by
* qemu_chr_fe_add_watch() is satisfied.
* @do_not_use: depending on the underlying chardev, a GIOChannel or a
* QIOChannel. DO NOT USE!
* @cond: bitwise combination of conditions watched and satisfied
* before calling this callback.
* @data: user data passed at creation to qemu_chr_fe_add_watch(). Can
* be NULL.
*
* Returns: G_SOURCE_REMOVE if the GSource should be removed from the
* main loop, or G_SOURCE_CONTINUE to leave the GSource in
* the main loop.
*/
typedef gboolean (*FEWatchFunc)(void *do_not_use, GIOCondition condition, void *data);
/**
* qemu_chr_fe_add_watch:
* @cond: the condition to poll for
* @func: the function to call when the condition happens
* @user_data: the opaque pointer to pass to @func
*
* If the backend is connected, create and add a #GSource that fires
* when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP)
* is active; return the #GSource's tag. If it is disconnected,
* or without associated Chardev, return 0.
*
* Note that you are responsible to update the front-end sources if
* you are switching the main context with qemu_chr_fe_set_handlers().
*
* Warning: DO NOT use the first callback argument (it may be either
* a GIOChannel or a QIOChannel, depending on the underlying chardev)
*
* Returns: the source tag
*/
guint qemu_chr_fe_add_watch(CharFrontend *c, GIOCondition cond,
FEWatchFunc func, void *user_data);
/**
* qemu_chr_fe_write:
* @buf: the data
* @len: the number of bytes to send
*
* Write data to a character backend from the front end. This function
* will send data from the front end to the back end. This function
* is thread-safe.
*
* Returns: the number of bytes consumed (0 if no associated Chardev)
* or -1 on error.
*/
int qemu_chr_fe_write(CharFrontend *c, const uint8_t *buf, int len);
/**
* qemu_chr_fe_write_all:
* @buf: the data
* @len: the number of bytes to send
*
* Write data to a character backend from the front end. This function will
* send data from the front end to the back end. Unlike @qemu_chr_fe_write,
* this function will block if the back end cannot consume all of the data
* attempted to be written. This function is thread-safe.
*
* Returns: the number of bytes consumed (0 if no associated Chardev)
* or -1 on error.
*/
int qemu_chr_fe_write_all(CharFrontend *c, const uint8_t *buf, int len);
/**
* qemu_chr_fe_read_all:
* @buf: the data buffer
* @len: the number of bytes to read
*
* Read data to a buffer from the back end.
*
* Returns: the number of bytes read (0 if no associated Chardev)
* or -1 on error.
*/
int qemu_chr_fe_read_all(CharFrontend *c, uint8_t *buf, int len);
/**
* qemu_chr_fe_ioctl:
* @cmd: see CHR_IOCTL_*
* @arg: the data associated with @cmd
*
* Issue a device specific ioctl to a backend. This function is thread-safe.
*
* Returns: if @cmd is not supported by the backend or there is no
* associated Chardev, -ENOTSUP, otherwise the return
* value depends on the semantics of @cmd
*/
int qemu_chr_fe_ioctl(CharFrontend *c, int cmd, void *arg);
/**
* qemu_chr_fe_get_msgfd:
*
* For backends capable of fd passing, return the latest file descriptor passed
* by a client.
*
* Returns: -1 if fd passing isn't supported or there is no pending file
* descriptor. If a file descriptor is returned, subsequent calls to
* this function will return -1 until a client sends a new file
* descriptor.
*/
int qemu_chr_fe_get_msgfd(CharFrontend *c);
/**
* qemu_chr_fe_get_msgfds:
*
* For backends capable of fd passing, return the number of file received
* descriptors and fills the fds array up to num elements
*
* Returns: -1 if fd passing isn't supported or there are no pending file
* descriptors. If file descriptors are returned, subsequent calls to
* this function will return -1 until a client sends a new set of file
* descriptors.
*/
int qemu_chr_fe_get_msgfds(CharFrontend *c, int *fds, int num);
/**
* qemu_chr_fe_set_msgfds:
*
* For backends capable of fd passing, set an array of fds to be passed with
* the next send operation.
* A subsequent call to this function before calling a write function will
* result in overwriting the fd array with the new value without being send.
* Upon writing the message the fd array is freed.
*
* Returns: -1 if fd passing isn't supported or no associated Chardev.
*/
int qemu_chr_fe_set_msgfds(CharFrontend *c, int *fds, int num);
#endif /* QEMU_CHAR_FE_H */
+48
View File
@@ -0,0 +1,48 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_IO_H
#define CHAR_IO_H
#include "io/channel.h"
#include "chardev/char.h"
#include "qemu/main-loop.h"
/* Can only be used for read */
GSource *io_add_watch_poll(Chardev *chr,
QIOChannel *ioc,
IOCanReadHandler *fd_can_read,
QIOChannelFunc fd_read,
gpointer user_data,
GMainContext *context);
void remove_fd_in_watch(Chardev *chr);
int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);
int io_channel_send_full(QIOChannel *ioc, const void *buf, size_t len,
int *fds, size_t nfds);
void remove_listener_fd_in_watch(Chardev *chr);
#endif /* CHAR_IO_H */
+45
View File
@@ -0,0 +1,45 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_PARALLEL_H
#define CHAR_PARALLEL_H
#include "chardev/char.h"
#define CHR_IOCTL_PP_READ_DATA 3
#define CHR_IOCTL_PP_WRITE_DATA 4
#define CHR_IOCTL_PP_READ_CONTROL 5
#define CHR_IOCTL_PP_WRITE_CONTROL 6
#define CHR_IOCTL_PP_READ_STATUS 7
#define CHR_IOCTL_PP_EPP_READ_ADDR 8
#define CHR_IOCTL_PP_EPP_READ 9
#define CHR_IOCTL_PP_EPP_WRITE_ADDR 10
#define CHR_IOCTL_PP_EPP_WRITE 11
#define CHR_IOCTL_PP_DATA_DIR 12
struct ParallelIOArg {
void *buffer;
int count;
};
#endif /* CHAR_PARALLEL_H */
+49
View File
@@ -0,0 +1,49 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_SERIAL_H
#define CHAR_SERIAL_H
#include "chardev/char.h"
#define CHR_IOCTL_SERIAL_SET_PARAMS 1
typedef struct {
int speed;
int parity;
int data_bits;
int stop_bits;
} QEMUSerialSetParams;
#define CHR_IOCTL_SERIAL_SET_BREAK 2
#define CHR_IOCTL_SERIAL_SET_TIOCM 13
#define CHR_IOCTL_SERIAL_GET_TIOCM 14
#define CHR_TIOCM_CTS 0x020
#define CHR_TIOCM_CAR 0x040
#define CHR_TIOCM_DSR 0x100
#define CHR_TIOCM_RI 0x080
#define CHR_TIOCM_DTR 0x002
#define CHR_TIOCM_RTS 0x004
#endif
+87
View File
@@ -0,0 +1,87 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_SOCKET_H
#define CHAR_SOCKET_H
#include "io/channel-socket.h"
#include "io/channel-tls.h"
#include "io/net-listener.h"
#include "chardev/char.h"
#include "qom/object.h"
#define TCP_MAX_FDS 16
typedef struct {
char buf[21];
size_t buflen;
} TCPChardevTelnetInit;
typedef enum {
TCP_CHARDEV_STATE_DISCONNECTED,
TCP_CHARDEV_STATE_CONNECTING,
TCP_CHARDEV_STATE_CONNECTED,
} TCPChardevState;
typedef ChardevClass SocketChardevClass;
struct SocketChardev {
Chardev parent;
QIOChannel *ioc; /* Client I/O channel */
QIOChannelSocket *sioc; /* Client master channel */
QIONetListener *listener;
GSource *hup_source;
QCryptoTLSCreds *tls_creds;
char *tls_authz;
TCPChardevState state;
int max_size;
int do_telnetopt;
int do_nodelay;
int *read_msgfds;
size_t read_msgfds_num;
int *write_msgfds;
size_t write_msgfds_num;
bool registered_yank;
SocketAddress *addr;
bool is_listen;
bool is_telnet;
bool is_tn3270;
GSource *telnet_source;
TCPChardevTelnetInit *telnet_init;
bool is_websock;
GSource *reconnect_timer;
int64_t reconnect_time_ms;
bool connect_err_reported;
QIOTask *connect_task;
};
typedef struct SocketChardev SocketChardev;
DECLARE_INSTANCE_CHECKER(SocketChardev, SOCKET_CHARDEV,
TYPE_CHARDEV_SOCKET)
#endif /* CHAR_SOCKET_H */
+29
View File
@@ -0,0 +1,29 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_WIN_STDIO_H
#define CHAR_WIN_STDIO_H
#define TYPE_CHARDEV_WIN_STDIO "chardev-win-stdio"
#endif /* CHAR_WIN_STDIO_H */
+54
View File
@@ -0,0 +1,54 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CHAR_WIN_H
#define CHAR_WIN_H
#include "chardev/char.h"
#include "qom/object.h"
struct WinChardev {
Chardev parent;
bool keep_open; /* console do not close file */
HANDLE file, hrecv, hsend;
OVERLAPPED orecv;
BOOL fpipe;
/* Protected by the Chardev chr_write_lock. */
OVERLAPPED osend;
};
typedef struct WinChardev WinChardev;
#define NSENDBUF 2048
#define NRECVBUF 2048
#define TYPE_CHARDEV_WIN "chardev-win"
DECLARE_INSTANCE_CHECKER(WinChardev, WIN_CHARDEV,
TYPE_CHARDEV_WIN)
void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open);
int win_chr_serial_init(Chardev *chr, const char *filename, Error **errp);
int win_chr_pipe_poll(void *opaque);
#endif /* CHAR_WIN_H */
+354
View File
@@ -0,0 +1,354 @@
#ifndef QEMU_CHAR_H
#define QEMU_CHAR_H
#include "qapi/qapi-types-char.h"
#include "qemu/bitmap.h"
#include "qemu/thread.h"
#include "qom/object.h"
#define IAC_EOR 239
#define IAC_SE 240
#define IAC_NOP 241
#define IAC_BREAK 243
#define IAC_IP 244
#define IAC_SB 250
#define IAC 255
/* character device */
typedef struct CharFrontend CharFrontend;
typedef enum {
CHR_EVENT_BREAK, /* serial break char */
CHR_EVENT_OPENED, /* new connection established */
CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
CHR_EVENT_MUX_OUT, /* mux-focus will move on */
CHR_EVENT_CLOSED /* connection closed. NOTE: currently this event
* is only bound to the read port of the chardev.
* Normally the read port and write port of a
* chardev should be the same, but it can be
* different, e.g., for fd chardevs, when the two
* fds are different. So when we received the
* CLOSED event it's still possible that the out
* port is still open. TODO: we should only send
* the CLOSED event when both ports are closed.
*/
} QEMUChrEvent;
#define CHR_READ_BUF_LEN 4096
typedef enum {
/* Whether the chardev peer is able to close and
* reopen the data channel, thus requiring support
* for qemu_chr_wait_connected() to wait for a
* valid connection */
QEMU_CHAR_FEATURE_RECONNECTABLE,
/* Whether it is possible to send/recv file descriptors
* over the data channel */
QEMU_CHAR_FEATURE_FD_PASS,
/* Whether replay or record mode is enabled */
QEMU_CHAR_FEATURE_REPLAY,
/* Whether the gcontext can be changed after calling
* qemu_chr_be_update_read_handlers() */
QEMU_CHAR_FEATURE_GCONTEXT,
QEMU_CHAR_FEATURE_LAST,
} ChardevFeature;
#define qemu_chr_replay(chr) qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_REPLAY)
struct Chardev {
Object parent_obj;
QemuMutex chr_write_lock;
CharFrontend *fe;
char *label;
int logfd;
bool logtimestamp;
bool log_line_start;
int be_open;
/* used to coordinate the chardev-change special-case: */
bool handover_yank_instance;
GSource *gsource;
GMainContext *gcontext;
DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
};
/**
* qemu_chr_new_from_opts:
* @opts: see qemu-config.c for a list of valid options
* @context: the #GMainContext to be used at initialization time
*
* Create a new character backend from a QemuOpts list.
*
* Returns: on success: a new character backend
* otherwise: NULL; @errp specifies the error
* or left untouched in case of help option
*/
Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
GMainContext *context,
Error **errp);
/**
* qemu_chr_parse_common:
* @opts: the options that still need parsing
* @backend: a new backend
*
* Parse the common options available to all character backends.
*/
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
/**
* qemu_chr_parse_opts:
*
* Parse the options to the ChardevBackend struct.
*
* Returns: a new backend or NULL on error
*/
ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts,
Error **errp);
/**
* qemu_chr_new:
* @label: the name of the backend
* @filename: the URI
* @context: the #GMainContext to be used at initialization time
*
* Create a new character backend from a URI.
* Do not implicitly initialize a monitor if the chardev is muxed.
*
* Returns: a new character backend
*/
Chardev *qemu_chr_new(const char *label, const char *filename,
GMainContext *context);
/**
* qemu_chr_new_mux_mon:
* @label: the name of the backend
* @filename: the URI
* @context: the #GMainContext to be used at initialization time
*
* Create a new character backend from a URI.
* Implicitly initialize a monitor if the chardev is muxed.
*
* Returns: a new character backend
*/
Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename,
GMainContext *context);
/**
* qemu_chr_change:
* @opts: the new backend options
*
* Change an existing character backend
*/
void qemu_chr_change(QemuOpts *opts, Error **errp);
/**
* qemu_chr_cleanup:
*
* Delete all chardevs (when leaving qemu)
*/
void qemu_chr_cleanup(void);
/**
* qemu_chr_new_noreplay:
* @label: the name of the backend
* @filename: the URI
* @permit_mux_mon: if chardev is muxed, initialize a monitor
* @context: the #GMainContext to be used at initialization time
*
* Create a new character backend from a URI.
* Character device communications are not written
* into the replay log.
*
* Returns: a new character backend
*/
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
bool permit_mux_mon, GMainContext *context);
/**
* qemu_chr_be_can_write:
*
* Determine how much data the front end can currently accept. This function
* returns the number of bytes the front end can accept. If it returns 0, the
* front end cannot receive data at the moment. The function must be polled
* to determine when data can be received.
*
* Returns: the number of bytes the front end can receive via @qemu_chr_be_write
*/
int qemu_chr_be_can_write(Chardev *s);
/**
* qemu_chr_be_write:
* @buf: a buffer to receive data from the front end
* @len: the number of bytes to receive from the front end
*
* Write data from the back end to the front end. Before issuing this call,
* the caller should call @qemu_chr_be_can_write to determine how much data
* the front end can currently accept.
*/
void qemu_chr_be_write(Chardev *s, const uint8_t *buf, int len);
/**
* qemu_chr_be_write_impl:
* @buf: a buffer to receive data from the front end
* @len: the number of bytes to receive from the front end
*
* Implementation of back end writing. Used by replay module.
*/
void qemu_chr_be_write_impl(Chardev *s, const uint8_t *buf, int len);
/**
* qemu_chr_be_update_read_handlers:
* @context: the gcontext that will be used to attach the watch sources
*
* Invoked when frontend read handlers are setup
*/
void qemu_chr_be_update_read_handlers(Chardev *s,
GMainContext *context);
/**
* qemu_chr_be_event:
* @event: the event to send
*
* Send an event from the back end to the front end.
*/
void qemu_chr_be_event(Chardev *s, QEMUChrEvent event);
int qemu_chr_add_client(Chardev *s, int fd);
Chardev *qemu_chr_find(const char *name);
bool qemu_chr_has_feature(Chardev *chr,
ChardevFeature feature);
void qemu_chr_set_feature(Chardev *chr,
ChardevFeature feature);
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
bool permit_mux_mon);
int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all);
#define qemu_chr_write_all(s, buf, len) qemu_chr_write(s, buf, len, true)
int qemu_chr_wait_connected(Chardev *chr, Error **errp);
#define TYPE_CHARDEV "chardev"
OBJECT_DECLARE_TYPE(Chardev, ChardevClass, CHARDEV)
#define TYPE_CHARDEV_NULL "chardev-null"
#define TYPE_CHARDEV_MUX "chardev-mux"
#define TYPE_CHARDEV_HUB "chardev-hub"
#define TYPE_CHARDEV_RINGBUF "chardev-ringbuf"
#define TYPE_CHARDEV_PTY "chardev-pty"
#define TYPE_CHARDEV_CONSOLE "chardev-console"
#define TYPE_CHARDEV_STDIO "chardev-stdio"
#define TYPE_CHARDEV_PIPE "chardev-pipe"
#define TYPE_CHARDEV_MEMORY "chardev-memory"
#define TYPE_CHARDEV_PARALLEL "chardev-parallel"
#define TYPE_CHARDEV_FILE "chardev-file"
#define TYPE_CHARDEV_SERIAL "chardev-serial"
#define TYPE_CHARDEV_SOCKET "chardev-socket"
#define TYPE_CHARDEV_UDP "chardev-udp"
#define CHARDEV_IS_RINGBUF(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF)
struct ChardevClass {
ObjectClass parent_class;
bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
bool supports_yank;
bool supports_size_opts;
bool supports_encoding_opts;
/* parse command line options and populate QAPI @backend */
void (*chr_parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
/* called after construction, open/starts the backend */
bool (*chr_open)(Chardev *chr, ChardevBackend *backend, Error **errp);
/* write buf to the backend */
int (*chr_write)(Chardev *s, const uint8_t *buf, int len);
/*
* Read from the backend (blocking). A typical front-end will instead rely
* on chr_can_read/chr_read being called when polling/looping.
*/
int (*chr_sync_read)(Chardev *s, const uint8_t *buf, int len);
/* create a watch on the backend */
GSource *(*chr_add_watch)(Chardev *s, GIOCondition cond);
/* update the backend internal sources */
void (*chr_update_read_handler)(Chardev *s);
/* send an ioctl to the backend */
int (*chr_ioctl)(Chardev *s, int cmd, void *arg);
/* get ancillary-received fds during last read */
int (*chr_get_msgfds)(Chardev *s, int* fds, int num);
/* set ancillary fds to be sent with next write */
int (*chr_set_msgfds)(Chardev *s, int *fds, int num);
/* accept the given fd */
int (*chr_add_client)(Chardev *chr, int fd);
/* wait for a connection */
int (*chr_wait_connected)(Chardev *chr, Error **errp);
/* disconnect a connection */
void (*chr_disconnect)(Chardev *chr);
/* called by frontend when it can read */
void (*chr_accept_input)(Chardev *chr);
/* set terminal echo */
void (*chr_set_echo)(Chardev *chr, bool echo);
/* notify the backend of frontend open state */
void (*chr_set_fe_open)(Chardev *chr, int fe_open);
/* handle various events */
void (*chr_be_event)(Chardev *s, QEMUChrEvent event);
void (*chr_listener_cleanup)(Chardev *chr);
/* return PTY name if available */
char *(*chr_get_pty_name)(Chardev *s);
/* get filename for reporting */
char *(*chr_get_filename)(Chardev *s);
};
Chardev *qemu_chardev_new(const char *id, const char *typename,
ChardevBackend *backend, GMainContext *context,
Error **errp);
extern int term_escape_char;
GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms,
GSourceFunc func, void *private);
void suspend_mux_open(void);
void resume_mux_open(void);
char *qemu_chr_get_pty_name(Chardev *chr);
char *qemu_chr_get_filename(Chardev *chr);
#define CHARDEV_VC_ENCODING_PROPERTY_DEFINE(cast_func) \
static int get_encoding(Object *obj, Error **errp) \
{ \
return cast_func(obj)->encoding; \
} \
\
static void set_encoding(Object *obj, int value, Error **errp) \
{ \
cast_func(obj)->encoding = value; \
}
static inline void chardev_vc_add_encoding_prop(ObjectClass *oc,
int (*get)(Object *, Error **),
void (*set)(Object *, int, Error **))
{
object_class_property_add_enum(oc, "encoding", "ChardevVCEncoding",
&ChardevVCEncoding_lookup, get, set);
}
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef CHARDEV_SPICE_H
#define CHARDEV_SPICE_H
#include <spice.h>
#include "chardev/char-fe.h"
#include "qom/object.h"
struct SpiceChardev {
Chardev parent;
SpiceCharDeviceInstance sin;
bool active;
bool blocked;
const uint8_t *datapos;
int datalen;
};
typedef struct SpiceChardev SpiceChardev;
#define TYPE_CHARDEV_SPICE "chardev-spice"
#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc"
#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport"
DECLARE_INSTANCE_CHECKER(SpiceChardev, SPICE_CHARDEV,
TYPE_CHARDEV_SPICE)
#endif
+164
View File
@@ -0,0 +1,164 @@
/*
* AES round fragments, generic version
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2023 Linaro, Ltd.
*/
#ifndef CRYPTO_AES_ROUND_H
#define CRYPTO_AES_ROUND_H
/* Hosts with acceleration will usually need a 16-byte vector type. */
typedef uint8_t AESStateVec __attribute__((vector_size(16)));
typedef union {
uint8_t b[16];
uint32_t w[4];
uint64_t d[2];
AESStateVec v;
} AESState;
#include "host/crypto/aes-round.h"
/*
* Perform MixColumns.
*/
void aesenc_MC_gen(AESState *ret, const AESState *st);
void aesenc_MC_genrev(AESState *ret, const AESState *st);
static inline void aesenc_MC(AESState *r, const AESState *st, bool be)
{
if (HAVE_AES_ACCEL) {
aesenc_MC_accel(r, st, be);
} else if (HOST_BIG_ENDIAN == be) {
aesenc_MC_gen(r, st);
} else {
aesenc_MC_genrev(r, st);
}
}
/*
* Perform SubBytes + ShiftRows + AddRoundKey.
*/
void aesenc_SB_SR_AK_gen(AESState *ret, const AESState *st,
const AESState *rk);
void aesenc_SB_SR_AK_genrev(AESState *ret, const AESState *st,
const AESState *rk);
static inline void aesenc_SB_SR_AK(AESState *r, const AESState *st,
const AESState *rk, bool be)
{
if (HAVE_AES_ACCEL) {
aesenc_SB_SR_AK_accel(r, st, rk, be);
} else if (HOST_BIG_ENDIAN == be) {
aesenc_SB_SR_AK_gen(r, st, rk);
} else {
aesenc_SB_SR_AK_genrev(r, st, rk);
}
}
/*
* Perform SubBytes + ShiftRows + MixColumns + AddRoundKey.
*/
void aesenc_SB_SR_MC_AK_gen(AESState *ret, const AESState *st,
const AESState *rk);
void aesenc_SB_SR_MC_AK_genrev(AESState *ret, const AESState *st,
const AESState *rk);
static inline void aesenc_SB_SR_MC_AK(AESState *r, const AESState *st,
const AESState *rk, bool be)
{
if (HAVE_AES_ACCEL) {
aesenc_SB_SR_MC_AK_accel(r, st, rk, be);
} else if (HOST_BIG_ENDIAN == be) {
aesenc_SB_SR_MC_AK_gen(r, st, rk);
} else {
aesenc_SB_SR_MC_AK_genrev(r, st, rk);
}
}
/*
* Perform InvMixColumns.
*/
void aesdec_IMC_gen(AESState *ret, const AESState *st);
void aesdec_IMC_genrev(AESState *ret, const AESState *st);
static inline void aesdec_IMC(AESState *r, const AESState *st, bool be)
{
if (HAVE_AES_ACCEL) {
aesdec_IMC_accel(r, st, be);
} else if (HOST_BIG_ENDIAN == be) {
aesdec_IMC_gen(r, st);
} else {
aesdec_IMC_genrev(r, st);
}
}
/*
* Perform InvSubBytes + InvShiftRows + AddRoundKey.
*/
void aesdec_ISB_ISR_AK_gen(AESState *ret, const AESState *st,
const AESState *rk);
void aesdec_ISB_ISR_AK_genrev(AESState *ret, const AESState *st,
const AESState *rk);
static inline void aesdec_ISB_ISR_AK(AESState *r, const AESState *st,
const AESState *rk, bool be)
{
if (HAVE_AES_ACCEL) {
aesdec_ISB_ISR_AK_accel(r, st, rk, be);
} else if (HOST_BIG_ENDIAN == be) {
aesdec_ISB_ISR_AK_gen(r, st, rk);
} else {
aesdec_ISB_ISR_AK_genrev(r, st, rk);
}
}
/*
* Perform InvSubBytes + InvShiftRows + AddRoundKey + InvMixColumns.
*/
void aesdec_ISB_ISR_AK_IMC_gen(AESState *ret, const AESState *st,
const AESState *rk);
void aesdec_ISB_ISR_AK_IMC_genrev(AESState *ret, const AESState *st,
const AESState *rk);
static inline void aesdec_ISB_ISR_AK_IMC(AESState *r, const AESState *st,
const AESState *rk, bool be)
{
if (HAVE_AES_ACCEL) {
aesdec_ISB_ISR_AK_IMC_accel(r, st, rk, be);
} else if (HOST_BIG_ENDIAN == be) {
aesdec_ISB_ISR_AK_IMC_gen(r, st, rk);
} else {
aesdec_ISB_ISR_AK_IMC_genrev(r, st, rk);
}
}
/*
* Perform InvSubBytes + InvShiftRows + InvMixColumns + AddRoundKey.
*/
void aesdec_ISB_ISR_IMC_AK_gen(AESState *ret, const AESState *st,
const AESState *rk);
void aesdec_ISB_ISR_IMC_AK_genrev(AESState *ret, const AESState *st,
const AESState *rk);
static inline void aesdec_ISB_ISR_IMC_AK(AESState *r, const AESState *st,
const AESState *rk, bool be)
{
if (HAVE_AES_ACCEL) {
aesdec_ISB_ISR_IMC_AK_accel(r, st, rk, be);
} else if (HOST_BIG_ENDIAN == be) {
aesdec_ISB_ISR_IMC_AK_gen(r, st, rk);
} else {
aesdec_ISB_ISR_IMC_AK_genrev(r, st, rk);
}
}
#endif /* CRYPTO_AES_ROUND_H */
+40
View File
@@ -0,0 +1,40 @@
#ifndef QEMU_AES_H
#define QEMU_AES_H
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
struct aes_key_st {
uint32_t rd_key[4 *(AES_MAXNR + 1)];
int rounds;
};
typedef struct aes_key_st AES_KEY;
/* FreeBSD/OpenSSL have their own AES functions with the same names in -lcrypto
* (which might be pulled in via curl), so redefine to avoid conflicts. */
#define AES_set_encrypt_key QEMU_AES_set_encrypt_key
#define AES_set_decrypt_key QEMU_AES_set_decrypt_key
#define AES_encrypt QEMU_AES_encrypt
#define AES_decrypt QEMU_AES_decrypt
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
extern const uint8_t AES_sbox[256];
extern const uint8_t AES_isbox[256];
/*
AES_Te0[x] = S [x].[02, 01, 01, 03];
AES_Td0[x] = Si[x].[0e, 09, 0d, 0b];
*/
extern const uint32_t AES_Te0[256], AES_Td0[256];
#endif
+134
View File
@@ -0,0 +1,134 @@
/*
* QEMU Crypto anti forensic information splitter
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QCRYPTO_AFSPLIT_H
#define QCRYPTO_AFSPLIT_H
#include "crypto/hash.h"
/**
* This module implements the anti-forensic splitter that is specified
* as part of the LUKS format:
*
* http://clemens.endorphin.org/cryptography
* http://clemens.endorphin.org/TKS1-draft.pdf
*
* The core idea is to take a short piece of data (key material)
* and process it to expand it to a much larger piece of data.
* The expansion process is reversible, to obtain the original
* short data. The key property of the expansion is that if any
* byte in the larger data set is changed / missing, it should be
* impossible to recreate the original short data.
*
* <example>
* <title>Creating a large split key for storage</title>
* <programlisting>
* size_t nkey = 32;
* uint32_t stripes = 32768; // To produce a 1 MB split key
* uint8_t *masterkey = ....a 32-byte AES key...
* uint8_t *splitkey;
*
* splitkey = g_new0(uint8_t, nkey * stripes);
*
* if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALGO_SHA256,
* nkey, stripes,
* masterkey, splitkey, errp) < 0) {
* g_free(splitkey);
* g_free(masterkey);
* return -1;
* }
*
* ...store splitkey somewhere...
*
* g_free(splitkey);
* g_free(masterkey);
* </programlisting>
* </example>
*
* <example>
* <title>Retrieving a master key from storage</title>
* <programlisting>
* size_t nkey = 32;
* uint32_t stripes = 32768; // To produce a 1 MB split key
* uint8_t *masterkey;
* uint8_t *splitkey = .... read in 1 MB of data...
*
* masterkey = g_new0(uint8_t, nkey);
*
* if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALGO_SHA256,
* nkey, stripes,
* splitkey, masterkey, errp) < 0) {
* g_free(splitkey);
* g_free(masterkey);
* return -1;
* }
*
* ..decrypt data with masterkey...
*
* g_free(splitkey);
* g_free(masterkey);
* </programlisting>
* </example>
*/
/**
* qcrypto_afsplit_encode:
* @hash: the hash algorithm to use for data expansion
* @blocklen: the size of @in in bytes
* @stripes: the number of times to expand @in in size
* @in: the master key to be expanded in size
* @out: preallocated buffer to hold the split key
* @errp: pointer to a NULL-initialized error object
*
* Split the data in @in, which is @blocklen bytes in
* size, to form a larger piece of data @out, which is
* @blocklen * @stripes bytes in size.
*
* Returns: 0 on success, -1 on error;
*/
int qcrypto_afsplit_encode(QCryptoHashAlgo hash,
size_t blocklen,
uint32_t stripes,
const uint8_t *in,
uint8_t *out,
Error **errp);
/**
* qcrypto_afsplit_decode:
* @hash: the hash algorithm to use for data compression
* @blocklen: the size of @out in bytes
* @stripes: the number of times to decrease @in in size
* @in: the split key to be recombined
* @out: preallocated buffer to hold the master key
* @errp: pointer to a NULL-initialized error object
*
* Join the data in @in, which is @blocklen * @stripes
* bytes in size, to form the original small piece of
* data @out, which is @blocklen bytes in size.
*
* Returns: 0 on success, -1 on error;
*/
int qcrypto_afsplit_decode(QCryptoHashAlgo hash,
size_t blocklen,
uint32_t stripes,
const uint8_t *in,
uint8_t *out,
Error **errp);
#endif /* QCRYPTO_AFSPLIT_H */
+179
View File
@@ -0,0 +1,179 @@
/*
* QEMU Crypto asymmetric algorithms
*
* Copyright (c) 2022 Bytedance
* Author: zhenwei pi <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_AKCIPHER_H
#define QCRYPTO_AKCIPHER_H
#include "qapi/qapi-types-crypto.h"
typedef struct QCryptoAkCipher QCryptoAkCipher;
/**
* qcrypto_akcipher_supports:
* @opts: the asymmetric key algorithm and related options
*
* Determine if asymmetric key cipher described with @opts is
* supported by the current configured build
*
* Returns: true if it is supported, false otherwise.
*/
bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts);
/**
* qcrypto_akcipher_new:
* @opts: specify the algorithm and the related arguments
* @type: private or public key type
* @key: buffer to store the key
* @key_len: the length of key buffer
* @errp: error pointer
*
* Create akcipher context
*
* Returns: On success, a new QCryptoAkCipher initialized with @opt
* is created and returned, otherwise NULL is returned.
*/
QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
QCryptoAkCipherKeyType type,
const uint8_t *key, size_t key_len,
Error **errp);
/**
* qcrypto_akcipher_encrypt:
* @akcipher: akcipher context
* @in: plaintext pending to be encrypted
* @in_len: length of plaintext, less or equal to the size reported
* by a call to qcrypto_akcipher_max_plaintext_len()
* @out: buffer to store the ciphertext
* @out_len: length of ciphertext, less or equal to the size reported
* by a call to qcrypto_akcipher_max_ciphertext_len()
* @errp: error pointer
*
* Encrypt @in and write ciphertext into @out
*
* Returns: length of ciphertext if encrypt succeed,
* otherwise -1 is returned
*/
int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher,
const void *in, size_t in_len,
void *out, size_t out_len, Error **errp);
/**
* qcrypto_akcipher_decrypt:
* @akcipher: akcipher context
* @in: ciphertext to be decrypted
* @in_len: the length of ciphertext, less or equal to the size reported
* by a call to qcrypto_akcipher_max_ciphertext_len()
* @out: buffer to store the plaintext
* @out_len: length of the plaintext buffer, less or equal to the size
* reported by a call to qcrypto_akcipher_max_plaintext_len()
* @errp: error pointer
*
* Decrypt @in and write plaintext into @out
*
* Returns: length of plaintext if decrypt succeed,
* otherwise -1 is returned
*/
int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher,
const void *in, size_t in_len,
void *out, size_t out_len, Error **errp);
/**
* qcrypto_akcipher_sign:
* @akcipher: akcipher context
* @in: data to be signed
* @in_len: the length of data, less or equal to the size reported
* by a call to qcrypto_akcipher_max_dgst_len()
* @out: buffer to store the signature
* @out_len: length of the signature buffer, less or equal to the size
* by a call to qcrypto_akcipher_max_signature_len()
* @errp: error pointer
*
* Generate signature for @in, write into @out
*
* Returns: length of signature if succeed,
* otherwise -1 is returned
*/
int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher,
const void *in, size_t in_len,
void *out, size_t out_len, Error **errp);
/**
* qcrypto_akcipher_verify:
* @akcipher: akcipher context
* @in: pointer to the signature
* @in_len: length of signature, ess or equal to the size reported
* by a call to qcrypto_akcipher_max_signature_len()
* @in2: pointer to original data
* @in2_len: the length of original data, less or equal to the size
* by a call to qcrypto_akcipher_max_dgst_len()
* @errp: error pointer
*
* Verify @in and @in2 match or not
*
* Returns: 0 for succeed,
* otherwise -1 is returned
*/
int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher,
const void *in, size_t in_len,
const void *in2, size_t in2_len, Error **errp);
int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher);
int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher);
int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher);
int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher);
/**
* qcrypto_akcipher_free:
* @akcipher: akcipher context
*
* Free the akcipher context
*
*/
void qcrypto_akcipher_free(QCryptoAkCipher *akcipher);
/**
* qcrypto_akcipher_export_p8info:
* @opts: the options of the akcipher to be exported.
* @key: the original key of the akcipher to be exported.
* @keylen: length of the 'key'
* @dst: output parameter, if export succeed, *dst is set to the
* PKCS#8 encoded private key, caller MUST free this key with
* g_free after use.
* @dst_len: output parameter, indicates the length of PKCS#8 encoded
* key.
*
* Export the akcipher into DER encoded pkcs#8 private key info, expects
* |key| stores a valid asymmetric PRIVATE key.
*
* Returns: 0 for succeed, otherwise -1 is returned.
*/
int qcrypto_akcipher_export_p8info(const QCryptoAkCipherOptions *opts,
uint8_t *key, size_t keylen,
uint8_t **dst, size_t *dst_len,
Error **errp);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoAkCipher, qcrypto_akcipher_free)
#endif /* QCRYPTO_AKCIPHER_H */
+329
View File
@@ -0,0 +1,329 @@
/*
* QEMU Crypto block device encryption
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_BLOCK_H
#define QCRYPTO_BLOCK_H
#include "crypto/cipher.h"
#include "crypto/ivgen.h"
typedef struct QCryptoBlock QCryptoBlock;
/* See also QCryptoBlockFormat, QCryptoBlockCreateOptions
* and QCryptoBlockOpenOptions in qapi/crypto.json */
typedef int (*QCryptoBlockReadFunc)(QCryptoBlock *block,
size_t offset,
uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp);
typedef int (*QCryptoBlockInitFunc)(QCryptoBlock *block,
size_t headerlen,
void *opaque,
Error **errp);
typedef int (*QCryptoBlockWriteFunc)(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp);
/**
* qcrypto_block_has_format:
* @format: the encryption format
* @buf: the data from head of the volume
* @len: the length of @buf in bytes
*
* Given @len bytes of data from the head of a storage volume
* in @buf, probe to determine if the volume has the encryption
* format specified in @format.
*
* Returns: true if the data in @buf matches @format
*/
bool qcrypto_block_has_format(QCryptoBlockFormat format,
const uint8_t *buf,
size_t buflen);
typedef enum {
QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0),
QCRYPTO_BLOCK_OPEN_DETACHED = (1 << 1),
} QCryptoBlockOpenFlags;
/**
* qcrypto_block_open:
* @options: the encryption options
* @optprefix: name prefix for options
* @readfunc: callback for reading data from the volume
* @opaque: data to pass to @readfunc
* @flags: bitmask of QCryptoBlockOpenFlags values
* @errp: pointer to a NULL-initialized error object
*
* Create a new block encryption object for an existing
* storage volume encrypted with format identified by
* the parameters in @options.
*
* This will use @readfunc to initialize the encryption
* context based on the volume header(s), extracting the
* master key(s) as required.
*
* If @flags contains QCRYPTO_BLOCK_OPEN_NO_IO then
* the open process will be optimized to skip any parts
* that are only required to perform I/O. In particular
* this would usually avoid the need to decrypt any
* master keys. The only thing that can be done with
* the resulting QCryptoBlock object would be to query
* metadata such as the payload offset. There will be
* no cipher or ivgen objects available.
*
* If @flags contains QCRYPTO_BLOCK_OPEN_DETACHED then
* the open process will be optimized to skip the LUKS
* payload overlap check.
*
* If any part of initializing the encryption context
* fails an error will be returned. This could be due
* to the volume being in the wrong format, a cipher
* or IV generator algorithm that is not supported,
* or incorrect passphrases.
*
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
const char *optprefix,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
Error **errp);
typedef enum {
QCRYPTO_BLOCK_CREATE_DETACHED = (1 << 0),
} QCryptoBlockCreateFlags;
/**
* qcrypto_block_create:
* @options: the encryption options
* @optprefix: name prefix for options
* @initfunc: callback for initializing volume header
* @writefunc: callback for writing data to the volume header
* @opaque: data to pass to @initfunc and @writefunc
* @flags: bitmask of QCryptoBlockCreateFlags values
* @errp: pointer to a NULL-initialized error object
*
* Create a new block encryption object for initializing
* a storage volume to be encrypted with format identified
* by the parameters in @options.
*
* This method will allocate space for a new volume header
* using @initfunc and then write header data using @writefunc,
* generating new master keys, etc as required. Any existing
* data present on the volume will be irrevocably destroyed.
*
* If @flags contains QCRYPTO_BLOCK_CREATE_DETACHED then
* the open process will set the payload_offset_sector to 0
* to specify the starting point for the read/write of a
* detached LUKS header image.
*
* If any part of initializing the encryption context
* fails an error will be returned. This could be due
* to the volume being in the wrong format, a cipher
* or IV generator algorithm that is not supported,
* or incorrect passphrases.
*
* Returns: a block encryption format, or NULL on error
*/
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
const char *optprefix,
QCryptoBlockInitFunc initfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
unsigned int flags,
Error **errp);
/**
* qcrypto_block_amend_options:
* @block: the block encryption object
*
* @readfunc: callback for reading data from the volume header
* @writefunc: callback for writing data to the volume header
* @opaque: data to pass to @readfunc and @writefunc
* @options: the new/amended encryption options
* @force: hint for the driver to allow unsafe operation
* @errp: error pointer
*
* Changes the crypto options of the encryption format
*
*/
int qcrypto_block_amend_options(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
QCryptoBlockAmendOptions *options,
bool force,
Error **errp);
/**
* qcrypto_block_calculate_payload_offset:
* @create_opts: the encryption options
* @optprefix: name prefix for options
* @len: output for number of header bytes before payload
* @errp: pointer to a NULL-initialized error object
*
* Calculate the number of header bytes before the payload in an encrypted
* storage volume. The header is an area before the payload that is reserved
* for encryption metadata.
*
* Returns: true on success, false on error
*/
bool
qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
const char *optprefix,
size_t *len,
Error **errp);
/**
* qcrypto_block_get_info:
* @block: the block encryption object
* @errp: pointer to a NULL-initialized error object
*
* Get information about the configuration options for the
* block encryption object. This includes details such as
* the cipher algorithms, modes, and initialization vector
* generators.
*
* Returns: a block encryption info object, or NULL on error
*/
QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
Error **errp);
/**
* @qcrypto_block_decrypt:
* @block: the block encryption object
* @offset: the position at which @iov was read
* @buf: the buffer to decrypt
* @len: the length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Decrypt @len bytes of cipher text in @buf, writing
* plain text back into @buf. @len and @offset must be
* a multiple of the encryption format sector size.
*
* Returns 0 on success, -1 on failure
*/
int qcrypto_block_decrypt(QCryptoBlock *block,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
/**
* @qcrypto_block_encrypt:
* @block: the block encryption object
* @offset: the position at which @iov will be written
* @buf: the buffer to decrypt
* @len: the length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Encrypt @len bytes of plain text in @buf, writing
* cipher text back into @buf. @len and @offset must be
* a multiple of the encryption format sector size.
*
* Returns 0 on success, -1 on failure
*/
int qcrypto_block_encrypt(QCryptoBlock *block,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
/**
* qcrypto_block_get_cipher:
* @block: the block encryption object
*
* Get the cipher to use for payload encryption
*
* Returns: the cipher object
*/
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block);
/**
* qcrypto_block_get_ivgen:
* @block: the block encryption object
*
* Get the initialization vector generator to use for
* payload encryption
*
* Returns: the IV generator object
*/
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block);
/**
* qcrypto_block_get_kdf_hash:
* @block: the block encryption object
*
* Get the hash algorithm used with the key derivation
* function
*
* Returns: the hash algorithm
*/
QCryptoHashAlgo qcrypto_block_get_kdf_hash(QCryptoBlock *block);
/**
* qcrypto_block_get_payload_offset:
* @block: the block encryption object
*
* Get the offset to the payload indicated by the
* encryption header, in bytes.
*
* Returns: the payload offset in bytes
*/
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
/**
* qcrypto_block_get_sector_size:
* @block: the block encryption object
*
* Get the size of sectors used for payload encryption. A new
* IV is used at the start of each sector. The encryption
* sector size is not required to match the sector size of the
* underlying storage. For example LUKS will always use a 512
* byte sector size, even if the volume is on a disk with 4k
* sectors.
*
* Returns: the sector in bytes
*/
uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
/**
* qcrypto_block_free:
* @block: the block encryption object
*
* Release all resources associated with the encryption
* object
*/
void qcrypto_block_free(QCryptoBlock *block);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoBlock, qcrypto_block_free)
#endif /* QCRYPTO_BLOCK_H */
+274
View File
@@ -0,0 +1,274 @@
/*
* QEMU Crypto cipher algorithms
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_CIPHER_H
#define QCRYPTO_CIPHER_H
#include "qapi/qapi-types-crypto.h"
typedef struct QCryptoCipher QCryptoCipher;
typedef struct QCryptoCipherDriver QCryptoCipherDriver;
/* See also "QCryptoCipherAlgo" and "QCryptoCipherMode"
* enums defined in qapi/crypto.json */
/**
* QCryptoCipher:
*
* The QCryptoCipher object provides a way to perform encryption
* and decryption of data, with a standard API, regardless of the
* algorithm used. It further isolates the calling code from the
* details of the specific underlying implementation, whether
* built-in, libgcrypt or nettle.
*
* Each QCryptoCipher object is capable of performing both
* encryption and decryption, and can operate in a number
* or modes including ECB, CBC.
*
* <example>
* <title>Encrypting data with AES-128 in CBC mode</title>
* <programlisting>
* QCryptoCipher *cipher;
* uint8_t key = ....;
* size_t keylen = 16;
* uint8_t iv = ....;
*
* if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128)) {
* error_report(errp, "Feature <blah> requires AES cipher support");
* return -1;
* }
*
* cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_CBC,
* key, keylen,
* errp);
* if (!cipher) {
* return -1;
* }
*
* if (qcrypto_cipher_set_iv(cipher, iv, keylen, errp) < 0) {
* return -1;
* }
*
* if (qcrypto_cipher_encrypt(cipher, rawdata, encdata, datalen, errp) < 0) {
* return -1;
* }
*
* qcrypto_cipher_free(cipher);
* </programlisting>
* </example>
*
*/
struct QCryptoCipher {
QCryptoCipherAlgo alg;
QCryptoCipherMode mode;
const QCryptoCipherDriver *driver;
};
/**
* qcrypto_cipher_supports:
* @alg: the cipher algorithm
* @mode: the cipher mode
*
* Determine if @alg cipher algorithm in @mode is supported by the
* current configured build
*
* Returns: true if the algorithm is supported, false otherwise
*/
bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode);
/**
* qcrypto_cipher_get_block_len:
* @alg: the cipher algorithm
*
* Get the required data block size in bytes. When
* encrypting data, it must be a multiple of the
* block size.
*
* Returns: the block size in bytes
*/
size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgo alg);
/**
* qcrypto_cipher_get_key_len:
* @alg: the cipher algorithm
*
* Get the required key size in bytes.
*
* Returns: the key size in bytes
*/
size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgo alg);
/**
* qcrypto_cipher_get_iv_len:
* @alg: the cipher algorithm
* @mode: the cipher mode
*
* Get the required initialization vector size
* in bytes, if one is required.
*
* Returns: the IV size in bytes, or 0 if no IV is permitted
*/
size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgo alg,
QCryptoCipherMode mode);
/**
* qcrypto_cipher_new:
* @alg: the cipher algorithm
* @mode: the cipher usage mode
* @key: the private key bytes
* @nkey: the length of @key
* @errp: pointer to a NULL-initialized error object
*
* Creates a new cipher object for encrypting/decrypting
* data with the algorithm @alg in the usage mode @mode.
*
* The @key parameter provides the bytes representing
* the encryption/decryption key to use. The @nkey parameter
* specifies the length of @key in bytes. Each algorithm has
* one or more valid key lengths, and it is an error to provide
* a key of the incorrect length.
*
* The returned cipher object must be released with
* qcrypto_cipher_free() when no longer required
*
* Returns: a new cipher object, or NULL on error
*/
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp);
/**
* qcrypto_cipher_free:
* @cipher: the cipher object
*
* Release the memory associated with @cipher that
* was previously allocated by qcrypto_cipher_new()
*/
void qcrypto_cipher_free(QCryptoCipher *cipher);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoCipher, qcrypto_cipher_free)
/**
* qcrypto_cipher_encrypt:
* @cipher: the cipher object
* @in: buffer holding the plain text input data
* @out: buffer to fill with the cipher text output data
* @len: the length of @in and @out buffers
* @errp: pointer to a NULL-initialized error object
*
* Encrypts the plain text stored in @in, filling
* @out with the resulting ciphered text. Both the
* @in and @out buffers must have the same size,
* given by @len.
*
* Returns: 0 on success, or -1 on error
*/
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp);
/**
* qcrypto_cipher_decrypt:
* @cipher: the cipher object
* @in: buffer holding the cipher text input data
* @out: buffer to fill with the plain text output data
* @len: the length of @in and @out buffers
* @errp: pointer to a NULL-initialized error object
*
* Decrypts the cipher text stored in @in, filling
* @out with the resulting plain text. Both the
* @in and @out buffers must have the same size,
* given by @len.
*
* Returns: 0 on success, or -1 on error
*/
int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp);
/**
* qcrypto_cipher_setiv:
* @cipher: the cipher object
* @iv: the initialization vector or counter (CTR mode) bytes
* @niv: the length of @iv
* @errpr: pointer to a NULL-initialized error object
*
* If the @cipher object is setup to use a mode that requires
* initialization vectors or counter, this sets the @niv
* bytes. The @iv data should have the same length as the
* cipher key used when originally constructing the cipher
* object. It is an error to set an initialization vector
* or counter if the cipher mode does not require one.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp);
/**
* qcrypto_cipher_setaad:
* @cipher: the cipher object
* @aad: the associated data to authenticate
* @len: the length of @aad
* @errp: pointer to a NULL-initialized error object
*
* For AEAD modes such as GCM, feed the associated data (AAD) that is
* authenticated but not encrypted. It must be called after
* qcrypto_cipher_setiv() and before the first encrypt/decrypt call. It is
* an error to call this on a mode that is not an AEAD mode.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_cipher_setaad(QCryptoCipher *cipher,
const uint8_t *aad, size_t len,
Error **errp);
/**
* qcrypto_cipher_gettag:
* @cipher: the cipher object
* @tag: buffer to receive the authentication tag
* @len: the length of @tag
* @errp: pointer to a NULL-initialized error object
*
* For AEAD modes such as GCM, read back the authentication tag computed
* over the associated data and the message. It must be called after the
* encrypt/decrypt operation. It is an error to call this on a mode that is
* not an AEAD mode.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_cipher_gettag(QCryptoCipher *cipher,
uint8_t *tag, size_t len,
Error **errp);
#endif /* QCRYPTO_CIPHER_H */
+83
View File
@@ -0,0 +1,83 @@
/*
* Carry-less multiply operations.
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2023 Linaro, Ltd.
*/
#ifndef CRYPTO_CLMUL_H
#define CRYPTO_CLMUL_H
#include "qemu/int128.h"
#include "host/crypto/clmul.h"
/**
* clmul_8x8_low:
*
* Perform eight 8x8->8 carry-less multiplies.
*/
uint64_t clmul_8x8_low(uint64_t, uint64_t);
/**
* clmul_8x4_even:
*
* Perform four 8x8->16 carry-less multiplies.
* The odd bytes of the inputs are ignored.
*/
uint64_t clmul_8x4_even(uint64_t, uint64_t);
/**
* clmul_8x4_odd:
*
* Perform four 8x8->16 carry-less multiplies.
* The even bytes of the inputs are ignored.
*/
uint64_t clmul_8x4_odd(uint64_t, uint64_t);
/**
* clmul_8x4_packed:
*
* Perform four 8x8->16 carry-less multiplies.
*/
uint64_t clmul_8x4_packed(uint32_t, uint32_t);
/**
* clmul_16x2_even:
*
* Perform two 16x16->32 carry-less multiplies.
* The odd words of the inputs are ignored.
*/
uint64_t clmul_16x2_even(uint64_t, uint64_t);
/**
* clmul_16x2_odd:
*
* Perform two 16x16->32 carry-less multiplies.
* The even words of the inputs are ignored.
*/
uint64_t clmul_16x2_odd(uint64_t, uint64_t);
/**
* clmul_32:
*
* Perform a 32x32->64 carry-less multiply.
*/
uint64_t clmul_32(uint32_t, uint32_t);
/**
* clmul_64:
*
* Perform a 64x64->128 carry-less multiply.
*/
Int128 clmul_64_gen(uint64_t, uint64_t);
static inline Int128 clmul_64(uint64_t a, uint64_t b)
{
if (HAVE_CLMUL_ACCEL) {
return clmul_64_accel(a, b);
} else {
return clmul_64_gen(a, b);
}
}
#endif /* CRYPTO_CLMUL_H */
+50
View File
@@ -0,0 +1,50 @@
/*
* This is D3DES (V5.09) by Richard Outerbridge with the double and
* triple-length support removed for use in VNC.
*
* These changes are:
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef QCRYPTO_DESRFB_H
#define QCRYPTO_DESRFB_H
/* d3des.h -
*
* Headers and defines for d3des.c
* Graven Imagery, 1992.
*
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
* (GEnie : OUTER; CIS : [71755,204])
*/
#define EN0 0 /* MODE == encrypt */
#define DE1 1 /* MODE == decrypt */
void deskey(unsigned char *, int);
/* hexkey[8] MODE
* Sets the internal key register according to the hexadecimal
* key contained in the 8 bytes of hexkey, according to the DES,
* for encryption or decryption according to MODE.
*/
void usekey(unsigned long *);
/* cookedkey[32]
* Loads the internal key register with the data in cookedkey.
*/
void des(unsigned char *, unsigned char *);
/* from[8] to[8]
* Encrypts/Decrypts (according to the key currently loaded in the
* internal key register) one block of eight bytes at address 'from'
* into the block at address 'to'. They can be the same.
*/
/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
********************************************************************/
#endif
+343
View File
@@ -0,0 +1,343 @@
/*
* QEMU Crypto hash algorithms
*
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_HASH_H
#define QCRYPTO_HASH_H
#include "qapi/qapi-types-crypto.h"
#define QCRYPTO_HASH_DIGEST_LEN_MD5 16
#define QCRYPTO_HASH_DIGEST_LEN_SHA1 20
#define QCRYPTO_HASH_DIGEST_LEN_SHA224 28
#define QCRYPTO_HASH_DIGEST_LEN_SHA256 32
#define QCRYPTO_HASH_DIGEST_LEN_SHA384 48
#define QCRYPTO_HASH_DIGEST_LEN_SHA512 64
#define QCRYPTO_HASH_DIGEST_LEN_RIPEMD160 20
#define QCRYPTO_HASH_DIGEST_LEN_SM3 32
/* See also "QCryptoHashAlgo" defined in qapi/crypto.json */
typedef struct QCryptoHash QCryptoHash;
struct QCryptoHash {
QCryptoHashAlgo alg;
void *opaque;
void *driver;
};
/**
* qcrypto_hash_supports:
* @alg: the hash algorithm
*
* Determine if @alg hash algorithm is supported by the
* current configured build.
*
* Returns: true if the algorithm is supported, false otherwise
*/
gboolean qcrypto_hash_supports(QCryptoHashAlgo alg);
/**
* qcrypto_hash_digest_len:
* @alg: the hash algorithm
*
* Determine the size of the hash digest in bytes
*
* Returns: the digest length in bytes
*/
size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg);
/**
* qcrypto_hash_bytesv:
* @alg: the hash algorithm
* @iov: the array of memory regions to hash
* @niov: the length of @iov
* @result: pointer to hold output hash
* @resultlen: pointer to hold length of @result
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory regions
* present in @iov.
*
* If @result_len is set to a non-zero value by the caller, then
* @result must hold a pointer that is @result_len in size, and
* @result_len match the size of the hash output. The digest will
* be written into @result.
*
* If @result_len is set to zero, then this function will allocate
* a buffer to hold the hash output digest, storing a pointer to
* the buffer in @result, and setting @result_len to its size.
* The memory referenced in @result must be released with a call
* to g_free() when no longer required by the caller.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_hash_bytes:
* @alg: the hash algorithm
* @buf: the memory region to hash
* @len: the length of @buf
* @result: pointer to hold output hash
* @resultlen: pointer to hold length of @result
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory region
* @buf of length @len.
*
* If @result_len is set to a non-zero value by the caller, then
* @result must hold a pointer that is @result_len in size, and
* @result_len match the size of the hash output. The digest will
* be written into @result.
*
* If @result_len is set to zero, then this function will allocate
* a buffer to hold the hash output digest, storing a pointer to
* the buffer in @result, and setting @result_len to its size.
* The memory referenced in @result must be released with a call
* to g_free() when no longer required by the caller.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_bytes(QCryptoHashAlgo alg,
const void *buf,
size_t len,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_hash_digestv:
* @alg: the hash algorithm
* @iov: the array of memory regions to hash
* @niov: the length of @iov
* @digest: pointer to hold output hash
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory regions
* present in @iov. The @digest pointer will be
* filled with the printable hex digest of the computed
* hash, which will be terminated by '\0'. The
* memory pointer in @digest must be released
* with a call to g_free() when no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_digestv(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
char **digest,
Error **errp);
/**
* qcrypto_hash_updatev:
* @hash: hash object from qcrypto_hash_new
* @iov: the array of memory regions to hash
* @niov: the length of @iov
* @errp: pointer to a NULL-initialized error object
*
* Updates the given hash object with all the memory regions
* present in @iov.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_updatev(QCryptoHash *hash,
const struct iovec *iov,
size_t niov,
Error **errp);
/**
* qcrypto_hash_update:
* @hash: hash object from qcrypto_hash_new
* @buf: the memory region to hash
* @len: the length of @buf
* @errp: pointer to a NULL-initialized error object
*
* Updates the given hash object with the data from
* the given buffer.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_update(QCryptoHash *hash,
const void *buf,
size_t len,
Error **errp);
/**
* qcrypto_hash_finalize_digest:
* @hash: the hash object to finalize
* @digest: pointer to hold output hash
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash from the given hash object. Hash object
* is expected to have its data updated from the qcrypto_hash_update function.
* The @digest pointer will be filled with the printable hex digest of the
* computed hash, which will be terminated by '\0'. The memory pointer
* in @digest must be released with a call to g_free() when
* no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_finalize_digest(QCryptoHash *hash,
char **digest,
Error **errp);
/**
* qcrypto_hash_finalize_base64:
* @hash_ctx: hash object to finalize
* @base64: pointer to store the hash result in
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash from the given hash object. Hash object
* is expected to have it's data updated from the qcrypto_hash_update function.
* The @base64 pointer will be filled with the base64 encoding of the computed
* hash, which will be terminated by '\0'. The memory pointer in @base64
* must be released with a call to g_free() when no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_finalize_base64(QCryptoHash *hash,
char **base64,
Error **errp);
/**
* qcrypto_hash_finalize_bytes:
* @hash_ctx: hash object to finalize
* @result: pointer to store the hash result in
* @result_len: Pointer to store the length of the result in
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash from the given hash object. Hash object
* is expected to have it's data updated from the qcrypto_hash_update function.
*
* If @result_len is set to a non-zero value by the caller, then
* @result must hold a pointer that is @result_len in size, and
* @result_len match the size of the hash output. The digest will
* be written into @result.
*
* If @result_len is set to zero, then this function will allocate
* a buffer to hold the hash output digest, storing a pointer to
* the buffer in @result, and setting @result_len to its size.
* The memory referenced in @result must be released with a call
* to g_free() when no longer required by the caller.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
uint8_t **result,
size_t *result_len,
Error **errp);
/**
* qcrypto_hash_new:
* @alg: the hash algorithm
* @errp: pointer to a NULL-initialized error object
*
* Creates a new hashing context for the chosen algorithm for
* usage with qcrypto_hash_update.
*
* Returns: New hash object with the given algorithm, or NULL on error.
*/
QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp);
/**
* qcrypto_hash_free:
* @hash: hash object to free
*
* Frees a hashing context for the chosen algorithm.
*/
void qcrypto_hash_free(QCryptoHash *hash);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHash, qcrypto_hash_free)
/**
* qcrypto_hash_digest:
* @alg: the hash algorithm
* @buf: the memory region to hash
* @len: the length of @buf
* @digest: pointer to hold output hash
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory region
* @buf of length @len. The @digest pointer will be
* filled with the printable hex digest of the computed
* hash, which will be terminated by '\0'. The
* memory pointer in @digest must be released
* with a call to g_free() when no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_digest(QCryptoHashAlgo alg,
const void *buf,
size_t len,
char **digest,
Error **errp);
/**
* qcrypto_hash_base64v:
* @alg: the hash algorithm
* @iov: the array of memory regions to hash
* @niov: the length of @iov
* @base64: pointer to hold output hash
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory regions
* present in @iov. The @base64 pointer will be
* filled with the base64 encoding of the computed
* hash, which will be terminated by '\0'. The
* memory pointer in @base64 must be released
* with a call to g_free() when no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_base64v(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
char **base64,
Error **errp);
/**
* qcrypto_hash_base64:
* @alg: the hash algorithm
* @buf: the memory region to hash
* @len: the length of @buf
* @base64: pointer to hold output hash
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory region
* @buf of length @len. The @base64 pointer will be
* filled with the base64 encoding of the computed
* hash, which will be terminated by '\0'. The
* memory pointer in @base64 must be released
* with a call to g_free() when no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hash_base64(QCryptoHashAlgo alg,
const void *buf,
size_t len,
char **base64,
Error **errp);
#endif /* QCRYPTO_HASH_H */
+195
View File
@@ -0,0 +1,195 @@
/*
* QEMU Crypto hmac algorithms
*
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*
*/
#ifndef QCRYPTO_HMAC_H
#define QCRYPTO_HMAC_H
#include "qapi/qapi-types-crypto.h"
typedef struct QCryptoHmac QCryptoHmac;
struct QCryptoHmac {
QCryptoHashAlgo alg;
void *opaque;
void *driver;
};
/**
* qcrypto_hmac_supports:
* @alg: the hmac algorithm
*
* Determine if @alg hmac algorithm is supported by
* the current configured build
*
* Returns:
* true if the algorithm is supported, false otherwise
*/
bool qcrypto_hmac_supports(QCryptoHashAlgo alg);
/**
* qcrypto_hmac_new:
* @alg: the hmac algorithm
* @key: the key bytes
* @nkey: the length of @key
* @errp: pointer to a NULL-initialized error object
*
* Creates a new hmac object with the algorithm @alg
*
* The @key parameter provides the bytes representing
* the secret key to use. The @nkey parameter specifies
* the length of @key in bytes
*
* Note: must use qcrypto_hmac_free() to release the
* returned hmac object when no longer required
*
* Returns:
* a new hmac object, or NULL on error
*/
QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp);
/**
* qcrypto_hmac_free:
* @hmac: the hmac object
*
* Release the memory associated with @hmac that was
* previously allocated by qcrypto_hmac_new()
*/
void qcrypto_hmac_free(QCryptoHmac *hmac);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHmac, qcrypto_hmac_free)
/**
* qcrypto_hmac_bytesv:
* @hmac: the hmac object
* @iov: the array of memory regions to hmac
* @niov: the length of @iov
* @result: pointer to hold output hmac
* @resultlen: pointer to hold length of @result
* @errp: pointer to a NULL-initialized error object
*
* Computes the hmac across all the memory regions
* present in @iov.
*
* If @result_len is set to a non-zero value by the caller, then
* @result must hold a pointer that is @result_len in size, and
* @result_len match the size of the hash output. The digest will
* be written into @result.
*
* If @result_len is set to zero, then this function will allocate
* a buffer to hold the hash output digest, storing a pointer to
* the buffer in @result, and setting @result_len to its size.
* The memory referenced in @result must be released with a call
* to g_free() when no longer required by the caller.
*
* If @result_len is set to a NULL pointer, no result will be returned, and
* the hmac object can be used for further invocations of qcrypto_hmac_bytes()
* or qcrypto_hmac_bytesv() until a non-NULL pointer is provided. This allows
* to build the hmac across memory regions that are not available at the same
* time.
*
* Returns:
* 0 on success, -1 on error
*/
int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_hmac_bytes:
* @hmac: the hmac object
* @buf: the memory region to hmac
* @len: the length of @buf
* @result: pointer to hold output hmac
* @resultlen: pointer to hold length of @result
* @errp: pointer to a NULL-initialized error object
*
* Computes the hmac across all the memory region
* @buf of length @len.
*
* If @result_len is set to a non-zero value by the caller, then
* @result must hold a pointer that is @result_len in size, and
* @result_len match the size of the hash output. The digest will
* be written into @result.
*
* If @result_len is set to zero, then this function will allocate
* a buffer to hold the hash output digest, storing a pointer to
* the buffer in @result, and setting @result_len to its size.
* The memory referenced in @result must be released with a call
* to g_free() when no longer required by the caller.
*
* If @result_len is set to a NULL pointer, no result will be returned, and
* the hmac object can be used for further invocations of qcrypto_hmac_bytes()
* or qcrypto_hmac_bytesv() until a non-NULL pointer is provided. This allows
* to build the hmac across memory regions that are not available at the same
* time.
*
* Returns:
* 0 on success, -1 on error
*/
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
const void *buf,
size_t len,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_hmac_digestv:
* @hmac: the hmac object
* @iov: the array of memory regions to hmac
* @niov: the length of @iov
* @digest: pointer to hold output hmac
* @errp: pointer to a NULL-initialized error object
*
* Computes the hmac across all the memory regions
* present in @iov. The @digest pointer will be
* filled with the printable hex digest of the computed
* hmac, which will be terminated by '\0'. The
* memory pointer in @digest must be released
* with a call to g_free() when no longer required.
*
* Returns:
* 0 on success, -1 on error
*/
int qcrypto_hmac_digestv(QCryptoHmac *hmac,
const struct iovec *iov,
size_t niov,
char **digest,
Error **errp);
/**
* qcrypto_hmac_digest:
* @hmac: the hmac object
* @buf: the memory region to hmac
* @len: the length of @buf
* @digest: pointer to hold output hmac
* @errp: pointer to a NULL-initialized error object
*
* Computes the hmac across all the memory region
* @buf of length @len. The @digest pointer will be
* filled with the printable hex digest of the computed
* hmac, which will be terminated by '\0'. The
* memory pointer in @digest must be released
* with a call to g_free() when no longer required.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_hmac_digest(QCryptoHmac *hmac,
const void *buf,
size_t len,
char **digest,
Error **errp);
#endif
+28
View File
@@ -0,0 +1,28 @@
/*
* QEMU Crypto initialization
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_INIT_H
#define QCRYPTO_INIT_H
#include "qapi/error.h"
int qcrypto_init(Error **errp);
#endif /* QCRYPTO_INIT_H */
+208
View File
@@ -0,0 +1,208 @@
/*
* QEMU Crypto block IV generator
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_IVGEN_H
#define QCRYPTO_IVGEN_H
#include "crypto/cipher.h"
#include "crypto/hash.h"
/**
* This module provides a framework for generating initialization
* vectors for block encryption schemes using chained cipher modes
* CBC. The principle is that each disk sector is assigned a unique
* initialization vector for use for encryption of data in that
* sector.
*
* <example>
* <title>Encrypting block data with initialization vectors</title>
* <programlisting>
* uint8_t *data = ....data to encrypt...
* size_t ndata = XXX;
* uint8_t *key = ....some encryption key...
* size_t nkey = XXX;
* uint8_t *iv;
* size_t niv;
* size_t sector = 0;
*
* g_assert((ndata % 512) == 0);
*
* QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IV_GEN_ALGO_ESSIV,
* QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_HASH_ALGO_SHA256,
* key, nkey, errp);
* if (!ivgen) {
* return -1;
* }
*
* QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_CBC,
* key, nkey, errp);
* if (!cipher) {
* goto error;
* }
*
* niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_CBC);
* iv = g_new0(uint8_t, niv);
*
*
* while (ndata) {
* if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp) < 0) {
* goto error;
* }
* if (qcrypto_cipher_setiv(cipher, iv, niv, errp) < 0) {
* goto error;
* }
* if (qcrypto_cipher_encrypt(cipher,
* data + (sector * 512),
* data + (sector * 512),
* 512, errp) < 0) {
* goto error;
* }
* sector++;
* ndata -= 512;
* }
*
* g_free(iv);
* qcrypto_ivgen_free(ivgen);
* qcrypto_cipher_free(cipher);
* return 0;
*
*error:
* g_free(iv);
* qcrypto_ivgen_free(ivgen);
* qcrypto_cipher_free(cipher);
* return -1;
* </programlisting>
* </example>
*/
typedef struct QCryptoIVGen QCryptoIVGen;
/* See also QCryptoIVGenAlgo enum in qapi/crypto.json */
/**
* qcrypto_ivgen_new:
* @alg: the initialization vector generation algorithm
* @cipheralg: the cipher algorithm or 0
* @hash: the hash algorithm or 0
* @key: the encryption key or NULL
* @nkey: the size of @key in bytes
*
* Create a new initialization vector generator that uses
* the algorithm @alg. Whether the remaining parameters
* are required or not depends on the choice of @alg
* requested.
*
* - QCRYPTO_IV_GEN_ALGO_PLAIN
*
* The IVs are generated by the 32-bit truncated sector
* number. This should never be used for block devices
* that are larger than 2^32 sectors in size.
* All the other parameters are unused.
*
* - QCRYPTO_IV_GEN_ALGO_PLAIN64
*
* The IVs are generated by the 64-bit sector number.
* All the other parameters are unused.
*
* - QCRYPTO_IV_GEN_ALGO_ESSIV:
*
* The IVs are generated by encrypting the 64-bit sector
* number with a hash of an encryption key. The @cipheralg,
* @hash, @key and @nkey parameters are all required.
*
* Returns: a new IV generator, or NULL on error
*/
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgo alg,
QCryptoCipherAlgo cipheralg,
QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
Error **errp);
/**
* qcrypto_ivgen_calculate:
* @ivgen: the IV generator object
* @sector: the 64-bit sector number
* @iv: a pre-allocated buffer to hold the generated IV
* @niv: the number of bytes in @iv
* @errp: pointer to a NULL-initialized error object
*
* Calculate a new initialization vector for the data
* to be stored in sector @sector. The IV will be
* written into the buffer @iv of size @niv.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
uint64_t sector,
uint8_t *iv, size_t niv,
Error **errp);
/**
* qcrypto_ivgen_get_algorithm:
* @ivgen: the IV generator object
*
* Get the algorithm used by this IV generator
*
* Returns: the IV generator algorithm
*/
QCryptoIVGenAlgo qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
/**
* qcrypto_ivgen_get_cipher:
* @ivgen: the IV generator object
*
* Get the cipher algorithm used by this IV generator (if
* applicable)
*
* Returns: the cipher algorithm
*/
QCryptoCipherAlgo qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
/**
* qcrypto_ivgen_get_hash:
* @ivgen: the IV generator object
*
* Get the hash algorithm used by this IV generator (if
* applicable)
*
* Returns: the hash algorithm
*/
QCryptoHashAlgo qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
/**
* qcrypto_ivgen_free:
* @ivgen: the IV generator object
*
* Release all resources associated with @ivgen, or a no-op
* if @ivgen is NULL
*/
void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoIVGen, qcrypto_ivgen_free)
#endif /* QCRYPTO_IVGEN_H */
+156
View File
@@ -0,0 +1,156 @@
/*
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_PBKDF_H
#define QCRYPTO_PBKDF_H
#include "crypto/hash.h"
/**
* This module provides an interface to the PBKDF2 algorithm
*
* https://en.wikipedia.org/wiki/PBKDF2
*
* <example>
* <title>Generating an AES encryption key from a user password</title>
* <programlisting>
* #include "crypto/cipher.h"
* #include "crypto/random.h"
* #include "crypto/pbkdf.h"
*
* ....
*
* char *password = "a-typical-awful-user-password";
* size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALGO_AES_128);
* uint8_t *salt = g_new0(uint8_t, nkey);
* uint8_t *key = g_new0(uint8_t, nkey);
* int iterations;
* QCryptoCipher *cipher;
*
* if (qcrypto_random_bytes(salt, nkey, errp) < 0) {
* g_free(key);
* g_free(salt);
* return -1;
* }
*
* iterations = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALGO_SHA256,
* (const uint8_t *)password,
* strlen(password),
* salt, nkey, errp);
* if (iterations < 0) {
* g_free(key);
* g_free(salt);
* return -1;
* }
*
* if (qcrypto_pbkdf2(QCRYPTO_HASH_ALGO_SHA256,
* (const uint8_t *)password, strlen(password),
* salt, nkey, iterations, key, nkey, errp) < 0) {
* g_free(key);
* g_free(salt);
* return -1;
* }
*
* g_free(salt);
*
* cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_ECB,
* key, nkey, errp);
* g_free(key);
*
* ....encrypt some data...
*
* qcrypto_cipher_free(cipher);
* </programlisting>
* </example>
*
*/
/**
* qcrypto_pbkdf2_supports:
* @hash: the hash algorithm
*
* Determine if the current build supports the PBKDF2 algorithm
* in combination with the hash @hash.
*
* Returns true if supported, false otherwise
*/
bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash);
/**
* qcrypto_pbkdf2:
* @hash: the hash algorithm to use
* @key: the user password / key
* @nkey: the length of @key in bytes
* @salt: a random salt
* @nsalt: length of @salt in bytes
* @iterations: the number of iterations to compute
* @out: pointer to pre-allocated buffer to hold output
* @nout: length of @out in bytes
* @errp: pointer to a NULL-initialized error object
*
* Apply the PBKDF2 algorithm to derive an encryption
* key from a user password provided in @key. The
* @salt parameter is used to perturb the algorithm.
* The @iterations count determines how many times
* the hashing process is run, which influences how
* hard it is to crack the key. The number of @iterations
* should be large enough such that the algorithm takes
* 1 second or longer to derive a key. The derived key
* will be stored in the preallocated buffer @out.
*
* Returns: 0 on success, -1 on error
*/
int qcrypto_pbkdf2(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp);
/**
* qcrypto_pbkdf2_count_iters:
* @hash: the hash algorithm to use
* @key: the user password / key
* @nkey: the length of @key in bytes
* @salt: a random salt
* @nsalt: length of @salt in bytes
* @nout: size of desired derived key
* @errp: pointer to a NULL-initialized error object
*
* Time the PBKDF2 algorithm to determine how many
* iterations are required to derive an encryption
* key from a user password provided in @key in 1
* second of compute time. The result of this can
* be used as a the @iterations parameter of a later
* call to qcrypto_pbkdf2(). The value of @nout should
* match that value that will later be provided with
* a call to qcrypto_pbkdf2().
*
* Returns: number of iterations in 1 second, -1 on error
*/
uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
Error **errp);
#endif /* QCRYPTO_PBKDF_H */
+50
View File
@@ -0,0 +1,50 @@
/*
* QEMU Crypto random number provider
*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_RANDOM_H
#define QCRYPTO_RANDOM_H
/**
* qcrypto_random_bytes:
* @buf: the buffer to fill
* @buflen: length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Fill @buf with @buflen bytes of cryptographically strong
* random data
*
* Returns 0 on success, -1 on error
*/
int qcrypto_random_bytes(void *buf,
size_t buflen,
Error **errp);
/**
* qcrypto_random_init:
* @errp: pointer to a NULL-initialized error object
*
* Initializes the handles used by qcrypto_random_bytes
*
* Returns 0 on success, -1 on error
*/
int qcrypto_random_init(Error **errp);
#endif /* QCRYPTO_RANDOM_H */
+133
View File
@@ -0,0 +1,133 @@
/*
* QEMU crypto secret support
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_SECRET_H
#define QCRYPTO_SECRET_H
#include "qapi/qapi-types-crypto.h"
#include "qom/object.h"
#include "crypto/secret_common.h"
#define TYPE_QCRYPTO_SECRET "secret"
typedef struct QCryptoSecret QCryptoSecret;
DECLARE_INSTANCE_CHECKER(QCryptoSecret, QCRYPTO_SECRET,
TYPE_QCRYPTO_SECRET)
typedef struct QCryptoSecretClass QCryptoSecretClass;
/**
* QCryptoSecret:
*
* The QCryptoSecret object provides storage of secrets,
* which may be user passwords, encryption keys or any
* other kind of sensitive data that is represented as
* a sequence of bytes.
*
* The sensitive data associated with the secret can
* be provided directly via the 'data' property, or
* indirectly via the 'file' property. In the latter
* case there is support for file descriptor passing
* via the usual /dev/fdset/NN syntax that QEMU uses.
*
* The data for a secret can be provided in two formats,
* either as a UTF-8 string (the default), or as base64
* encoded 8-bit binary data. The latter is appropriate
* for raw encryption keys, while the former is appropriate
* for user entered passwords.
*
* The data may be optionally encrypted with AES-256-CBC,
* and the decryption key provided by another
* QCryptoSecret instance identified by the 'keyid'
* property. When passing sensitive data directly
* via the 'data' property it is strongly recommended
* to use the AES encryption facility to prevent the
* sensitive data being exposed in the process listing
* or system log files.
*
* Providing data directly, insecurely (suitable for
* ad hoc developer testing only)
*
* $QEMU -object secret,id=sec0,data=letmein
*
* Providing data indirectly:
*
* # printf "letmein" > password.txt
* # $QEMU \
* -object secret,id=sec0,file=password.txt
*
* Using a master encryption key with data.
*
* The master key needs to be created as 32 secure
* random bytes (optionally base64 encoded)
*
* # openssl rand -base64 32 > key.b64
* # KEY=$(base64 -d key.b64 | hexdump -v -e '/1 "%02X"')
*
* Each secret to be encrypted needs to have a random
* initialization vector generated. These do not need
* to be kept secret
*
* # openssl rand -base64 16 > iv.b64
* # IV=$(base64 -d iv.b64 | hexdump -v -e '/1 "%02X"')
*
* A secret to be defined can now be encrypted
*
* # SECRET=$(printf "letmein" |
* openssl enc -aes-256-cbc -a -K $KEY -iv $IV)
*
* When launching QEMU, create a master secret pointing
* to key.b64 and specify that to be used to decrypt
* the user password
*
* # $QEMU \
* -object secret,id=secmaster0,format=base64,file=key.b64 \
* -object secret,id=sec0,keyid=secmaster0,format=base64,\
* data=$SECRET,iv=$(<iv.b64)
*
* When encrypting, the data can still be provided via an
* external file, in which case it is possible to use either
* raw binary data, or base64 encoded. This example uses
* raw format
*
* # printf "letmein" |
* openssl enc -aes-256-cbc -K $KEY -iv $IV -o pw.aes
* # $QEMU \
* -object secret,id=secmaster0,format=base64,file=key.b64 \
* -object secret,id=sec0,keyid=secmaster0,\
* file=pw.aes,iv=$(<iv.b64)
*
* Note that the ciphertext can be in either raw or base64
* format, as indicated by the 'format' parameter, but the
* plaintext resulting from decryption is expected to always
* be in raw format.
*/
struct QCryptoSecret {
QCryptoSecretCommon parent_obj;
char *data;
char *file;
};
struct QCryptoSecretClass {
QCryptoSecretCommonClass parent_class;
};
#endif /* QCRYPTO_SECRET_H */
+58
View File
@@ -0,0 +1,58 @@
/*
* QEMU crypto secret support
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_SECRET_COMMON_H
#define QCRYPTO_SECRET_COMMON_H
#include "qapi/qapi-types-crypto.h"
#include "qom/object.h"
#define TYPE_QCRYPTO_SECRET_COMMON "secret_common"
OBJECT_DECLARE_TYPE(QCryptoSecretCommon, QCryptoSecretCommonClass,
QCRYPTO_SECRET_COMMON)
struct QCryptoSecretCommon {
Object parent_obj;
uint8_t *rawdata;
size_t rawlen;
QCryptoSecretFormat format;
char *keyid;
char *iv;
};
struct QCryptoSecretCommonClass {
ObjectClass parent_class;
void (*load_data)(QCryptoSecretCommon *secret,
uint8_t **output,
size_t *outputlen,
Error **errp);
};
int qcrypto_secret_lookup(const char *secretid,
uint8_t **data,
size_t *datalen,
Error **errp);
char *qcrypto_secret_lookup_as_utf8(const char *secretid, Error **errp);
char *qcrypto_secret_lookup_as_base64(const char *secretid, Error **errp);
#endif /* QCRYPTO_SECRET_COMMON_H */
+40
View File
@@ -0,0 +1,40 @@
/*
* QEMU crypto secret support
*
* Copyright 2020 Yandex N.V.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_SECRET_KEYRING_H
#define QCRYPTO_SECRET_KEYRING_H
#include "qapi/qapi-types-crypto.h"
#include "qom/object.h"
#include "crypto/secret_common.h"
#define TYPE_QCRYPTO_SECRET_KEYRING "secret_keyring"
OBJECT_DECLARE_SIMPLE_TYPE(QCryptoSecretKeyring,
QCRYPTO_SECRET_KEYRING)
struct QCryptoSecretKeyring {
QCryptoSecretCommon parent;
int32_t serial;
};
#endif /* QCRYPTO_SECRET_KEYRING_H */
+15
View File
@@ -0,0 +1,15 @@
#ifndef QEMU_SM4_H
#define QEMU_SM4_H
extern const uint8_t sm4_sbox[256];
extern const uint32_t sm4_ck[32];
static inline uint32_t sm4_subword(uint32_t word)
{
return sm4_sbox[word & 0xff] |
sm4_sbox[(word >> 8) & 0xff] << 8 |
sm4_sbox[(word >> 16) & 0xff] << 16 |
sm4_sbox[(word >> 24) & 0xff] << 24;
}
#endif
+34
View File
@@ -0,0 +1,34 @@
/*
* QEMU TLS Cipher Suites Registry (RFC8447)
*
* Copyright (c) 2018-2020 Red Hat, Inc.
*
* Author: Philippe Mathieu-Daudé
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef QCRYPTO_TLS_CIPHER_SUITES_H
#define QCRYPTO_TLS_CIPHER_SUITES_H
#include "qom/object.h"
#include "crypto/tlscreds.h"
#define TYPE_QCRYPTO_TLS_CIPHER_SUITES "tls-cipher-suites"
typedef struct QCryptoTLSCipherSuites QCryptoTLSCipherSuites;
DECLARE_INSTANCE_CHECKER(QCryptoTLSCipherSuites, QCRYPTO_TLS_CIPHER_SUITES,
TYPE_QCRYPTO_TLS_CIPHER_SUITES)
/**
* qcrypto_tls_cipher_suites_get_data:
* @obj: pointer to a TLS cipher suites object
* @errp: pointer to a NULL-initialized error object
*
* Returns: reference to a byte array containing the data.
* The caller should release the reference when no longer
* required.
*/
GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj,
Error **errp);
#endif /* QCRYPTO_TLS_CIPHER_SUITES_H */
+93
View File
@@ -0,0 +1,93 @@
/*
* QEMU crypto TLS credential support
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_TLSCREDS_H
#define QCRYPTO_TLSCREDS_H
#include "qapi/qapi-types-crypto.h"
#include "qom/object.h"
#define TYPE_QCRYPTO_TLS_CREDS "tls-creds"
typedef struct QCryptoTLSCreds QCryptoTLSCreds;
typedef struct QCryptoTLSCredsClass QCryptoTLSCredsClass;
DECLARE_OBJ_CHECKERS(QCryptoTLSCreds, QCryptoTLSCredsClass, QCRYPTO_TLS_CREDS,
TYPE_QCRYPTO_TLS_CREDS)
#define QCRYPTO_TLS_CREDS_DH_PARAMS "dh-params.pem"
typedef bool (*CryptoTLSCredsReload)(QCryptoTLSCreds *, Error **);
/**
* QCryptoTLSCreds:
*
* The QCryptoTLSCreds object is an abstract base for different
* types of TLS handshake credentials. Most commonly the
* QCryptoTLSCredsX509 subclass will be used to provide x509
* certificate credentials.
*/
struct QCryptoTLSCredsClass {
ObjectClass parent_class;
CryptoTLSCredsReload reload;
const char *prioritySuffix;
};
/**
* qcrypto_tls_creds_check_endpoint:
* @creds: pointer to a TLS credentials object
* @endpoint: type of network endpoint that will be using the credentials
* @errp: pointer to a NULL-initialized error object
*
* Check whether the credentials is setup according to
* the type of @endpoint argument.
*
* Returns true if the credentials is setup for the endpoint, false otherwise
*/
bool qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds *creds,
QCryptoTLSCredsEndpoint endpoint,
Error **errp);
/**
* qcrypto_tls_creds_get_priority:
* @creds: pointer to a TLS credentials object
*
* Get the TLS credentials priority string. The caller
* must free the returned string when no longer required.
*
* Returns: a non-NULL priority string
*/
char *qcrypto_tls_creds_get_priority(QCryptoTLSCreds *creds);
/**
* qcrypto_tls_creds_reload:
* @creds: pointer to a TLS credentials object
* @errp: pointer to a NULL-initialized error object
*
* Request a reload of the TLS credentials, if supported
*
* Returns: true on success, false on error or if not supported
*/
bool qcrypto_tls_creds_reload(QCryptoTLSCreds *creds,
Error **errp);
#endif /* QCRYPTO_TLSCREDS_H */
+100
View File
@@ -0,0 +1,100 @@
/*
* QEMU crypto TLS anonymous credential support
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_TLSCREDSANON_H
#define QCRYPTO_TLSCREDSANON_H
#include "crypto/tlscreds.h"
#include "qom/object.h"
#define TYPE_QCRYPTO_TLS_CREDS_ANON "tls-creds-anon"
typedef struct QCryptoTLSCredsAnon QCryptoTLSCredsAnon;
DECLARE_INSTANCE_CHECKER(QCryptoTLSCredsAnon, QCRYPTO_TLS_CREDS_ANON,
TYPE_QCRYPTO_TLS_CREDS_ANON)
typedef struct QCryptoTLSCredsAnonClass QCryptoTLSCredsAnonClass;
/**
* QCryptoTLSCredsAnon:
*
* The QCryptoTLSCredsAnon object provides a representation
* of anonymous credentials used perform a TLS handshake.
* This is primarily provided for backwards compatibility and
* its use is discouraged as it has poor security characteristics
* due to lacking MITM attack protection amongst other problems.
*
* This is a user creatable object, which can be instantiated
* via object_new_propv():
*
* <example>
* <title>Creating anonymous TLS credential objects in code</title>
* <programlisting>
* Object *obj;
* Error *err = NULL;
* obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_ANON,
* "tlscreds0",
* &err,
* "endpoint", "server",
* "dir", "/path/x509/cert/dir",
* "verify-peer", "yes",
* NULL);
* </programlisting>
* </example>
*
* Or via QMP:
*
* <example>
* <title>Creating anonymous TLS credential objects via QMP</title>
* <programlisting>
* {
* "execute": "object-add", "arguments": {
* "id": "tlscreds0",
* "qom-type": "tls-creds-anon",
* "props": {
* "endpoint": "server",
* "dir": "/path/to/x509/cert/dir",
* "verify-peer": false
* }
* }
* }
* </programlisting>
* </example>
*
*
* Or via the CLI:
*
* <example>
* <title>Creating anonymous TLS credential objects via CLI</title>
* <programlisting>
* qemu-system-x86_64 -object tls-creds-anon,id=tlscreds0,\
* endpoint=server,verify-peer=off,\
* dir=/path/to/x509/certdir/
* </programlisting>
* </example>
*
*/
struct QCryptoTLSCredsAnonClass {
QCryptoTLSCredsClass parent_class;
};
#endif /* QCRYPTO_TLSCREDSANON_H */
+95
View File
@@ -0,0 +1,95 @@
/*
* QEMU crypto TLS Pre-Shared Key (PSK) support
*
* Copyright (c) 2018 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_TLSCREDSPSK_H
#define QCRYPTO_TLSCREDSPSK_H
#include "crypto/tlscreds.h"
#include "qom/object.h"
#define TYPE_QCRYPTO_TLS_CREDS_PSK "tls-creds-psk"
typedef struct QCryptoTLSCredsPSK QCryptoTLSCredsPSK;
DECLARE_INSTANCE_CHECKER(QCryptoTLSCredsPSK, QCRYPTO_TLS_CREDS_PSK,
TYPE_QCRYPTO_TLS_CREDS_PSK)
typedef struct QCryptoTLSCredsPSKClass QCryptoTLSCredsPSKClass;
#define QCRYPTO_TLS_CREDS_PSKFILE "keys.psk"
/**
* QCryptoTLSCredsPSK:
*
* The QCryptoTLSCredsPSK object provides a representation
* of the Pre-Shared Key credential used to perform a TLS handshake.
*
* This is a user creatable object, which can be instantiated
* via object_new_propv():
*
* <example>
* <title>Creating TLS-PSK credential objects in code</title>
* <programlisting>
* Object *obj;
* Error *err = NULL;
* obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_PSK,
* "tlscreds0",
* &err,
* "dir", "/path/to/dir",
* "endpoint", "client",
* NULL);
* </programlisting>
* </example>
*
* Or via QMP:
*
* <example>
* <title>Creating TLS-PSK credential objects via QMP</title>
* <programlisting>
* {
* "execute": "object-add", "arguments": {
* "id": "tlscreds0",
* "qom-type": "tls-creds-psk",
* "props": {
* "dir": "/path/to/dir",
* "endpoint": "client"
* }
* }
* }
* </programlisting>
* </example>
*
* Or via the CLI:
*
* <example>
* <title>Creating TLS-PSK credential objects via CLI</title>
* <programlisting>
* qemu-system-x86_64 --object tls-creds-psk,id=tlscreds0,\
* endpoint=client,dir=/path/to/dir[,username=qemu]
* </programlisting>
* </example>
*
* The PSK file can be created and managed using psktool.
*/
struct QCryptoTLSCredsPSKClass {
QCryptoTLSCredsClass parent_class;
};
#endif /* QCRYPTO_TLSCREDSPSK_H */
+110
View File
@@ -0,0 +1,110 @@
/*
* QEMU crypto TLS x509 credential support
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_TLSCREDSX509_H
#define QCRYPTO_TLSCREDSX509_H
#include "crypto/tlscreds.h"
#include "qom/object.h"
#define TYPE_QCRYPTO_TLS_CREDS_X509 "tls-creds-x509"
typedef struct QCryptoTLSCredsX509 QCryptoTLSCredsX509;
DECLARE_INSTANCE_CHECKER(QCryptoTLSCredsX509, QCRYPTO_TLS_CREDS_X509,
TYPE_QCRYPTO_TLS_CREDS_X509)
typedef struct QCryptoTLSCredsX509Class QCryptoTLSCredsX509Class;
#define QCRYPTO_TLS_CREDS_X509_CA_CERT "ca-cert.pem"
#define QCRYPTO_TLS_CREDS_X509_CA_CRL "ca-crl.pem"
#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY "server-key.pem"
#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT "server-cert.pem"
#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY "client-key.pem"
#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT "client-cert.pem"
#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY_N "server-key-%zu.pem"
#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT_N "server-cert-%zu.pem"
#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY_N "client-key-%zu.pem"
#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT_N "client-cert-%zu.pem"
/* Max number of additional cert/key pairs (ie _N constants) */
#define QCRYPTO_TLS_CREDS_X509_IDENTITY_MAX 4
/**
* QCryptoTLSCredsX509:
*
* The QCryptoTLSCredsX509 object provides a representation
* of x509 credentials used to perform a TLS handshake.
*
* This is a user creatable object, which can be instantiated
* via object_new_propv():
*
* <example>
* <title>Creating x509 TLS credential objects in code</title>
* <programlisting>
* Object *obj;
* Error *err = NULL;
* obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_X509,
* "tlscreds0",
* &err,
* "endpoint", "server",
* "dir", "/path/x509/cert/dir",
* "verify-peer", "yes",
* NULL);
* </programlisting>
* </example>
*
* Or via QMP:
*
* <example>
* <title>Creating x509 TLS credential objects via QMP</title>
* <programlisting>
* {
* "execute": "object-add", "arguments": {
* "id": "tlscreds0",
* "qom-type": "tls-creds-x509",
* "props": {
* "endpoint": "server",
* "dir": "/path/to/x509/cert/dir",
* "verify-peer": false
* }
* }
* }
* </programlisting>
* </example>
*
*
* Or via the CLI:
*
* <example>
* <title>Creating x509 TLS credential objects via CLI</title>
* <programlisting>
* qemu-system-x86_64 -object tls-creds-x509,id=tlscreds0,\
* endpoint=server,verify-peer=off,\
* dir=/path/to/x509/certdir/
* </programlisting>
* </example>
*
*/
struct QCryptoTLSCredsX509Class {
QCryptoTLSCredsClass parent_class;
};
#endif /* QCRYPTO_TLSCREDSX509_H */
+372
View File
@@ -0,0 +1,372 @@
/*
* QEMU crypto TLS session support
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QCRYPTO_TLSSESSION_H
#define QCRYPTO_TLSSESSION_H
#include "crypto/tlscreds.h"
/**
* QCryptoTLSSession:
*
* The QCryptoTLSSession object encapsulates the
* logic to integrate with a TLS providing library such
* as GNUTLS, to setup and run TLS sessions.
*
* The API is designed such that it has no assumption about
* the type of transport it is running over. It may be a
* traditional TCP socket, or something else entirely. The
* only requirement is a full-duplex stream of some kind.
*
* <example>
* <title>Using TLS session objects</title>
* <programlisting>
* static ssize_t mysock_send(const char *buf, size_t len,
* void *opaque)
* {
* int fd = GPOINTER_TO_INT(opaque);
*
* return write(*fd, buf, len);
* }
*
* static ssize_t mysock_recv(const char *buf, size_t len,
* void *opaque)
* {
* int fd = GPOINTER_TO_INT(opaque);
*
* return read(*fd, buf, len);
* }
*
* static int mysock_run_tls(int sockfd,
* QCryptoTLSCreds *creds,
* Error **errp)
* {
* QCryptoTLSSession *sess;
*
* sess = qcrypto_tls_session_new(creds,
* "vnc.example.com",
* NULL,
* QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
* errp);
* if (sess == NULL) {
* return -1;
* }
*
* qcrypto_tls_session_set_callbacks(sess,
* mysock_send,
* mysock_recv
* GINT_TO_POINTER(fd));
*
* while (1) {
* int ret = qcrypto_tls_session_handshake(sess, errp);
*
* if (ret < 0) {
* qcrypto_tls_session_free(sess);
* return -1;
* }
*
* switch(ret) {
* case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
* if (qcrypto_tls_session_check_credentials(sess, errp) < )) {
* qcrypto_tls_session_free(sess);
* return -1;
* }
* goto done;
* case QCRYPTO_TLS_HANDSHAKE_RECVING:
* ...wait for GIO_IN event on fd...
* break;
* case QCRYPTO_TLS_HANDSHAKE_SENDING:
* ...wait for GIO_OUT event on fd...
* break;
* }
* }
* done:
*
* ....send/recv payload data on sess...
*
* qcrypto_tls_session_free(sess):
* }
* </programlisting>
* </example>
*/
typedef struct QCryptoTLSSession QCryptoTLSSession;
#define QCRYPTO_TLS_SESSION_ERR_BLOCK -2
#define QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION -3
/**
* qcrypto_tls_session_new:
* @creds: pointer to a TLS credentials object
* @hostname: optional hostname to validate
* @aclname: optional ACL to validate peer credentials against
* @endpoint: role of the TLS session, client or server
* @errp: pointer to a NULL-initialized error object
*
* Create a new TLS session object that will be used to
* negotiate a TLS session over an arbitrary data channel.
* The session object can operate as either the server or
* client, according to the value of the @endpoint argument.
*
* For clients, the @hostname parameter should hold the full
* unmodified hostname as requested by the user. This will
* be used to verify the against the hostname reported in
* the server's credentials (aka x509 certificate).
*
* The @aclname parameter (optionally) specifies the name
* of an access control list that will be used to validate
* the peer's credentials. For x509 credentials, the ACL
* will be matched against the CommonName shown in the peer's
* certificate. If the session is acting as a server, setting
* an ACL will require that the client provide a validate
* x509 client certificate.
*
* After creating the session object, the I/O callbacks
* must be set using the qcrypto_tls_session_set_callbacks()
* method. A TLS handshake sequence must then be completed
* using qcrypto_tls_session_handshake(), before payload
* data is permitted to be sent/received.
*
* The session object must be released by calling
* qcrypto_tls_session_free() when no longer required
*
* Returns: a TLS session object, or NULL on error.
*/
QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds,
const char *hostname,
const char *aclname,
QCryptoTLSCredsEndpoint endpoint,
Error **errp);
/**
* qcrypto_tls_session_free:
* @sess: the TLS session object
*
* Release all memory associated with the TLS session
* object previously allocated by qcrypto_tls_session_new()
*/
void qcrypto_tls_session_free(QCryptoTLSSession *sess);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
/**
* qcrypto_tls_session_require_thread_safety:
* @sess: the TLS session object
*
* Mark that this TLS session will require thread safety
* for concurrent I/O in both directions. This must be
* called before the handshake is performed.
*
* This will activate a workaround for GNUTLS thread
* safety issues, where appropriate for the negotiated
* TLS session parameters.
*/
void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess);
/**
* qcrypto_tls_session_check_credentials:
* @sess: the TLS session object
* @errp: pointer to a NULL-initialized error object
*
* Validate the peer's credentials after a successful
* TLS handshake. It is an error to call this before
* qcrypto_tls_session_handshake() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
* Returns 0 if the credentials validated, -1 on error
*/
int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
Error **errp);
/*
* These must return QCRYPTO_TLS_SESSION_ERR_BLOCK if the I/O
* would block, but on other errors, must fill 'errp'
*/
typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const void *buf,
size_t len,
void *opaque,
Error **errp);
typedef ssize_t (*QCryptoTLSSessionReadFunc)(void *buf,
size_t len,
void *opaque,
Error **errp);
/**
* qcrypto_tls_session_set_callbacks:
* @sess: the TLS session object
* @writeFunc: callback for sending data
* @readFunc: callback to receiving data
* @opaque: data to pass to callbacks
*
* Sets the callback functions that are to be used for sending
* and receiving data on the underlying data channel. Typically
* the callbacks to write/read to/from a TCP socket, but there
* is no assumption made about the type of channel used.
*
* The @writeFunc callback will be passed the encrypted
* data to send to the remote peer.
*
* The @readFunc callback will be passed a pointer to fill
* with encrypted data received from the remote peer
*/
void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
QCryptoTLSSessionWriteFunc writeFunc,
QCryptoTLSSessionReadFunc readFunc,
void *opaque);
/**
* qcrypto_tls_session_write:
* @sess: the TLS session object
* @buf: the plain text to send
* @len: the length of @buf
* @errp: pointer to hold returned error object
*
* Encrypt @len bytes of the data in @buf and send
* it to the remote peer using the callback previously
* registered with qcrypto_tls_session_set_callbacks()
*
* It is an error to call this before
* qcrypto_tls_session_handshake() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
* Returns: the number of bytes sent,
* or QCRYPTO_TLS_SESSION_ERR_BLOCK if the write would block,
* or -1 on error.
*/
ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
const char *buf,
size_t len,
Error **errp);
/**
* qcrypto_tls_session_read:
* @sess: the TLS session object
* @buf: to fill with plain text received
* @len: the length of @buf
* @errp: pointer to hold returned error object
*
* Receive up to @len bytes of data from the remote peer
* using the callback previously registered with
* qcrypto_tls_session_set_callbacks(), decrypt it and
* store it in @buf.
*
* It is an error to call this before
* qcrypto_tls_session_handshake() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
* Returns: the number of bytes received,
* or QCRYPTO_TLS_SESSION_ERR_BLOCK if the receive would block,
* or QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION if a premature termination
* is detected, or -1 on error.
*/
ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
char *buf,
size_t len,
Error **errp);
/**
* qcrypto_tls_session_check_pending:
* @sess: the TLS session object
*
* Check if there are unread data in the TLS buffers that have
* already been read from the underlying data source.
*
* Returns: the number of bytes available or zero
*/
size_t qcrypto_tls_session_check_pending(QCryptoTLSSession *sess);
/**
* qcrypto_tls_session_handshake:
* @sess: the TLS session object
* @errp: pointer to a NULL-initialized error object
*
* Start, or continue, a TLS handshake sequence. If
* the underlying data channel is non-blocking, then
* this method may return control before the handshake
* is complete. On non-blocking channels the
* return value determines whether the handshake
* has completed, or is waiting to send or receive
* data. In the latter cases, the caller should setup
* an event loop watch and call this method again
* once the underlying data channel is ready to read
* or write again
*/
int qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
Error **errp);
typedef enum {
QCRYPTO_TLS_HANDSHAKE_COMPLETE,
QCRYPTO_TLS_HANDSHAKE_SENDING,
QCRYPTO_TLS_HANDSHAKE_RECVING,
} QCryptoTLSSessionHandshakeStatus;
typedef enum {
QCRYPTO_TLS_BYE_COMPLETE,
QCRYPTO_TLS_BYE_SENDING,
QCRYPTO_TLS_BYE_RECVING,
} QCryptoTLSSessionByeStatus;
/**
* qcrypto_tls_session_bye:
* @session: the TLS session object
* @errp: pointer to a NULL-initialized error object
*
* Start, or continue, a TLS termination sequence. If the underlying
* data channel is non-blocking, then this method may return control
* before the termination is complete. The return value will indicate
* whether the termination has completed, or is waiting to send or
* receive data. In the latter cases, the caller should setup an event
* loop watch and call this method again once the underlying data
* channel is ready to read or write again.
*/
int
qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp);
/**
* qcrypto_tls_session_get_key_size:
* @sess: the TLS session object
* @errp: pointer to a NULL-initialized error object
*
* Check the size of the data channel encryption key
*
* Returns: the length in bytes of the encryption key
* or -1 on error
*/
int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
Error **errp);
/**
* qcrypto_tls_session_get_peer_name:
* @sess: the TLS session object
*
* Get the identified name of the remote peer. If the
* TLS session was negotiated using x509 certificate
* credentials, this will return the CommonName from
* the peer's certificate. If no identified name is
* available it will return NULL.
*
* The returned data must be released with g_free()
* when no longer required.
*
* Returns: the peer's name or NULL.
*/
char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess);
#endif /* QCRYPTO_TLSSESSION_H */
+135
View File
@@ -0,0 +1,135 @@
/*
* X.509 certificate related helpers
*
* Copyright (c) 2024 Dorjoy Chowdhury <[email protected]>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#ifndef QCRYPTO_X509_UTILS_H
#define QCRYPTO_X509_UTILS_H
#include "crypto/hash.h"
int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
QCryptoHashAlgo hash,
uint8_t *result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_x509_convert_cert_der
* @cert: pointer to the raw certificate data in PEM format
* @size: size of the certificate
* @result: output location for the allocated buffer for the certificate
* in DER format
* (the function allocates memory which must be freed by the caller)
* @resultlen: pointer to the size of the buffer (will be updated with the
* actual size of the DER-encoded certificate)
* @errp: error pointer
*
* Convert the given @cert from PEM to DER format.
*
* Returns: 0 on success,
* -1 on error.
*/
int qcrypto_x509_convert_cert_der(uint8_t *cert, size_t size,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_x509_check_cert_times
* @cert: pointer to the raw certificate data
* @size: size of the certificate
* @errp: error pointer
*
* Check whether the activation and expiration times of @cert
* are valid at the current time.
*
* Returns: 0 if the certificate times are valid,
* -1 on error.
*/
int qcrypto_x509_check_cert_times(uint8_t *cert, size_t size, Error **errp);
/**
* qcrypto_x509_get_cert_key_id
* @cert: pointer to the raw certificate data
* @size: size of the certificate
* @hash_alg: the hash algorithm flag
* @result: output location for the allocated buffer for key ID
* (the function allocates memory which must be freed by the caller)
* @resultlen: pointer to the size of the buffer
* (will be updated with the actual size of key id)
* @errp: error pointer
*
* Retrieve the key ID from the @cert based on the specified @hash_alg.
*
* Returns: 0 if key ID was successfully stored in @result,
* -1 on error.
*/
int qcrypto_x509_get_cert_key_id(uint8_t *cert, size_t size,
QCryptoHashAlgo hash_alg,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_x509_check_ecc_curve_p521
* @cert: pointer to the raw certificate data
* @size: size of the certificate
* @errp: error pointer
*
* Determine whether the ECC public key in the given certificate uses the P-521
* curve.
*
* Returns: 0 if ECC public key does not use P521 curve.
* 1 if ECC public key uses P521 curve.
* -1 on error.
*/
int qcrypto_x509_check_ecc_curve_p521(uint8_t *cert, size_t size, Error **errp);
/**
* qcrypto_pkcs7_convert_sig_pem
* @sig: pointer to the PKCS#7 signature in DER format
* @sig_size: size of the signature
* @result: output location for the allocated buffer for the signature in
* PEM format
* (the function allocates memory which must be freed by the caller)
* @resultlen: pointer to the size of the buffer
* (will be updated with the actual size of the PEM-encoded
* signature)
* @errp: error pointer
*
* Convert given PKCS#7 @sig from DER to PEM format.
*
* Returns: 0 if PEM-encoded signature was successfully stored in @result,
* -1 on error.
*/
int qcrypto_pkcs7_convert_sig_pem(uint8_t *sig, size_t sig_size,
uint8_t **result,
size_t *resultlen,
Error **errp);
/**
* qcrypto_x509_verify_sig
* @cert: pointer to the raw certificate data
* @cert_size: size of the certificate
* @comp: pointer to the component to be verified
* @comp_size: size of the component
* @sig: pointer to the signature
* @sig_size: size of the signature
* @errp: error pointer
*
* Verify the provided @comp against the @sig and @cert.
*
* Returns: 0 on success,
* -1 on error.
*/
int qcrypto_x509_verify_sig(uint8_t *cert, size_t cert_size,
uint8_t *comp, size_t comp_size,
uint8_t *sig, size_t sig_size, Error **errp);
#endif
+143
View File
@@ -0,0 +1,143 @@
#ifndef QEMU_CAPSTONE_H
#define QEMU_CAPSTONE_H
#ifdef CONFIG_CAPSTONE
#define CAPSTONE_AARCH64_COMPAT_HEADER
#include <capstone.h>
#else
/* Just enough to allow backends to init without ifdefs. */
#define CS_API_MAJOR 0
#define CS_ARCH_ARM -1
#define CS_ARCH_ARM64 -1
#define CS_ARCH_M68K -1
#define CS_ARCH_MIPS -1
#define CS_ARCH_X86 -1
#define CS_ARCH_PPC -1
#define CS_ARCH_SPARC -1
#define CS_MODE_LITTLE_ENDIAN 0
#define CS_MODE_BIG_ENDIAN 0
#define CS_MODE_ARM 0
#define CS_MODE_16 0
#define CS_MODE_32 0
#define CS_MODE_64 0
#define CS_MODE_THUMB 0
#define CS_MODE_MCLASS 0
#define CS_MODE_V8 0
#define CS_MODE_V9 0
#define CS_MODE_M68K_000 0
#define CS_MODE_M68K_010 0
#define CS_MODE_M68K_020 0
#define CS_MODE_M68K_030 0
#define CS_MODE_M68K_040 0
#define CS_MODE_M68K_060 0
#define CS_MODE_MICRO 0
#define CS_MODE_MIPS2 0
#define CS_MODE_MIPS3 0
#define CS_MODE_MIPS32 0
#define CS_MODE_MIPS32R6 0
#define CS_MODE_MIPS64 0
#endif /* CONFIG_CAPSTONE */
#if CS_API_MAJOR < 6
#define CS_ARCH_LOONGARCH -1
#define CS_MODE_LOONGARCH32 0
#define CS_MODE_LOONGARCH64 0
#endif
#if CS_API_MAJOR < 6
#define CS_MODE_M68K_CF_ISA_A 0
#define CS_MODE_M68K_CF_ISA_A_PLUS 0
#define CS_MODE_M68K_CF_ISA_B 0
#define CS_MODE_M68K_CF_ISA_C 0
#define CS_MODE_M68K_CF_USP 0
#define CS_MODE_M68K_CF_DIV 0
#define CS_MODE_M68K_CF_MAC 0
#define CS_MODE_M68K_CF_EMAC 0
#define CS_MODE_M68K_CF_EMAC_B 0
#define CS_MODE_M68K_CF_FPU 0
#endif
#if CS_API_MAJOR < 6
#define CS_MODE_MIPS16 0
#define CS_MODE_MIPS1 0
#define CS_MODE_MIPS32R2 0
#define CS_MODE_MIPS32R3 0
#define CS_MODE_MIPS32R5 0
#define CS_MODE_MIPS4 0
#define CS_MODE_MIPS5 0
#define CS_MODE_MIPS64R2 0
#define CS_MODE_MIPS64R3 0
#define CS_MODE_MIPS64R5 0
#define CS_MODE_MIPS64R6 0
#define CS_MODE_OCTEON 0
#define CS_MODE_OCTEONP 0
#define CS_MODE_NANOMIPS 0
#define CS_MODE_MIPS_PTR64 0
#endif
#if CS_API_MAJOR < 5
#define CS_ARCH_RISCV -1
#define CS_MODE_RISCV32 0
#define CS_MODE_RISCV64 0
#define CS_MODE_RISCV_C 0
#elif CS_API_MAJOR == 5
/* The C symbol name changed between v5 and v6 */
#define CS_MODE_RISCV_C CS_MODE_RISCVC
#endif
#if CS_API_MAJOR < 6
#define CS_MODE_RISCV_FD 0
#define CS_MODE_RISCV_V 0
#define CS_MODE_RISCV_ZFINX 0
#define CS_MODE_RISCV_ZCMP_ZCMT_ZCE 0
#define CS_MODE_RISCV_ZICFISS 0
#define CS_MODE_RISCV_E 0
#define CS_MODE_RISCV_A 0
#define CS_MODE_RISCV_COREV 0
#define CS_MODE_RISCV_THEAD 0
#define CS_MODE_RISCV_SIFIVE 0
#define CS_MODE_RISCV_BITMANIP 0
#define CS_MODE_RISCV_ZBA 0
#define CS_MODE_RISCV_ZBB 0
#define CS_MODE_RISCV_ZBC 0
#define CS_MODE_RISCV_ZBKB 0
#define CS_MODE_RISCV_ZBKC 0
#define CS_MODE_RISCV_ZBKX 0
#define CS_MODE_RISCV_ZBS 0
#define CS_MODE_RISCV_VENTANA 0
#endif
#if CS_API_MAJOR < 5
#define CS_ARCH_SH -1
#define CS_MODE_SHFPU 0
#define CS_MODE_SH4 0
#define CS_MODE_SH4A 0
#endif
#if CS_API_MAJOR == 0
#define CS_ARCH_SYSTEMZ -1
#elif CS_API_MAJOR < 6
#define CS_ARCH_SYSTEMZ CS_ARCH_SYSZ
#endif
#if CS_API_MAJOR < 6
#define CS_MODE_SYSTEMZ_ARCH14 0
#endif
#if CS_API_MAJOR < 5
#define CS_ARCH_TRICORE -1
#define CS_MODE_TRICORE_110 0
#define CS_MODE_TRICORE_120 0
#define CS_MODE_TRICORE_130 0
#define CS_MODE_TRICORE_131 0
#define CS_MODE_TRICORE_160 0
#define CS_MODE_TRICORE_161 0
#define CS_MODE_TRICORE_162 0
#endif
#endif /* QEMU_CAPSTONE_H */
+502
View File
@@ -0,0 +1,502 @@
/* Interface between the opcode library and its callers.
Written by Cygnus Support, 1993.
The opcode library (libopcodes.a) provides instruction decoders for
a large variety of instruction sets, callable with an identical
interface, for making instruction-processing programs more independent
of the instruction set being processed. */
#ifndef DISAS_DIS_ASM_H
#define DISAS_DIS_ASM_H
#include "qemu/bswap.h"
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_vma;
typedef uint8_t bfd_byte;
#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x)
#define snprintf_vma(s,ss,x) snprintf (s, ss, "%0" PRIx64, x)
#define BFD64
enum bfd_flavour {
bfd_target_unknown_flavour,
bfd_target_aout_flavour,
bfd_target_coff_flavour,
bfd_target_ecoff_flavour,
bfd_target_elf_flavour,
bfd_target_ieee_flavour,
bfd_target_nlm_flavour,
bfd_target_oasys_flavour,
bfd_target_tekhex_flavour,
bfd_target_srec_flavour,
bfd_target_ihex_flavour,
bfd_target_som_flavour,
bfd_target_os9k_flavour,
bfd_target_versados_flavour,
bfd_target_msdos_flavour,
bfd_target_evax_flavour
};
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
enum bfd_architecture
{
bfd_arch_unknown, /* File arch not known */
bfd_arch_obscure, /* Arch known, not one of these */
bfd_arch_m68k, /* Motorola 68xxx */
#define bfd_mach_m68000 1
#define bfd_mach_m68008 2
#define bfd_mach_m68010 3
#define bfd_mach_m68020 4
#define bfd_mach_m68030 5
#define bfd_mach_m68040 6
#define bfd_mach_m68060 7
#define bfd_mach_cpu32 8
#define bfd_mach_mcf5200 9
#define bfd_mach_mcf5206e 10
#define bfd_mach_mcf5307 11
#define bfd_mach_mcf5407 12
#define bfd_mach_mcf528x 13
#define bfd_mach_mcfv4e 14
#define bfd_mach_mcf521x 15
#define bfd_mach_mcf5249 16
#define bfd_mach_mcf547x 17
#define bfd_mach_mcf548x 18
bfd_arch_vax, /* DEC Vax */
bfd_arch_i960, /* Intel 960 */
/* The order of the following is important.
lower number indicates a machine type that
only accepts a subset of the instructions
available to machines with higher numbers.
The exception is the "ca", which is
incompatible with all other machines except
"core". */
#define bfd_mach_i960_core 1
#define bfd_mach_i960_ka_sa 2
#define bfd_mach_i960_kb_sb 3
#define bfd_mach_i960_mc 4
#define bfd_mach_i960_xa 5
#define bfd_mach_i960_ca 6
#define bfd_mach_i960_jx 7
#define bfd_mach_i960_hx 8
bfd_arch_a29k, /* AMD 29000 */
bfd_arch_sparc, /* SPARC */
#define bfd_mach_sparc 1
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
#define bfd_mach_sparc_sparclet 2
#define bfd_mach_sparc_sparclite 3
#define bfd_mach_sparc_v8plus 4
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_sparclite_le 6
#define bfd_mach_sparc_v9 7
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v9_p(mach) \
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
&& (mach) != bfd_mach_sparc_sparclite_le)
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
#define bfd_mach_mips4000 4000
#define bfd_mach_mips4010 4010
#define bfd_mach_mips4100 4100
#define bfd_mach_mips4300 4300
#define bfd_mach_mips4400 4400
#define bfd_mach_mips4600 4600
#define bfd_mach_mips4650 4650
#define bfd_mach_mips5000 5000
#define bfd_mach_mips6000 6000
#define bfd_mach_mips8000 8000
#define bfd_mach_mips10000 10000
#define bfd_mach_mips16 16
bfd_arch_i386, /* Intel 386 */
#define bfd_mach_i386_i386 0
#define bfd_mach_i386_i8086 1
#define bfd_mach_i386_i386_intel_syntax 2
#define bfd_mach_x86_64 3
#define bfd_mach_x86_64_intel_syntax 4
bfd_arch_we32k, /* AT&T WE32xxx */
bfd_arch_tahoe, /* CCI/Harris Tahoe */
bfd_arch_i860, /* Intel 860 */
bfd_arch_romp, /* IBM ROMP PC/RT */
bfd_arch_alliant, /* Alliant */
bfd_arch_convex, /* Convex */
bfd_arch_m88k, /* Motorola 88xxx */
bfd_arch_pyramid, /* Pyramid Technology */
bfd_arch_h8300, /* Hitachi H8/300 */
#define bfd_mach_h8300 1
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
#define bfd_mach_ppc 0
#define bfd_mach_ppc64 1
#define bfd_mach_ppc_403 403
#define bfd_mach_ppc_403gc 4030
#define bfd_mach_ppc_e500 500
#define bfd_mach_ppc_505 505
#define bfd_mach_ppc_601 601
#define bfd_mach_ppc_602 602
#define bfd_mach_ppc_603 603
#define bfd_mach_ppc_ec603e 6031
#define bfd_mach_ppc_604 604
#define bfd_mach_ppc_620 620
#define bfd_mach_ppc_630 630
#define bfd_mach_ppc_750 750
#define bfd_mach_ppc_860 860
#define bfd_mach_ppc_a35 35
#define bfd_mach_ppc_rs64ii 642
#define bfd_mach_ppc_rs64iii 643
#define bfd_mach_ppc_7400 7400
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
#define bfd_mach_hppa10 10
#define bfd_mach_hppa11 11
#define bfd_mach_hppa20 20
#define bfd_mach_hppa20w 25
bfd_arch_d10v, /* Mitsubishi D10V */
bfd_arch_z8k, /* Zilog Z8000 */
#define bfd_mach_z8001 1
#define bfd_mach_z8002 2
bfd_arch_h8500, /* Hitachi H8/500 */
bfd_arch_sh, /* Hitachi SH */
#define bfd_mach_sh 1
#define bfd_mach_sh2 0x20
#define bfd_mach_sh_dsp 0x2d
#define bfd_mach_sh2a 0x2a
#define bfd_mach_sh2a_nofpu 0x2b
#define bfd_mach_sh2e 0x2e
#define bfd_mach_sh3 0x30
#define bfd_mach_sh3_nommu 0x31
#define bfd_mach_sh3_dsp 0x3d
#define bfd_mach_sh3e 0x3e
#define bfd_mach_sh4 0x40
#define bfd_mach_sh4_nofpu 0x41
#define bfd_mach_sh4_nommu_nofpu 0x42
#define bfd_mach_sh4a 0x4a
#define bfd_mach_sh4a_nofpu 0x4b
#define bfd_mach_sh4al_dsp 0x4d
#define bfd_mach_sh5 0x50
bfd_arch_alpha, /* Dec Alpha */
#define bfd_mach_alpha 1
#define bfd_mach_alpha_ev4 0x10
#define bfd_mach_alpha_ev5 0x20
#define bfd_mach_alpha_ev6 0x30
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_unknown 0
#define bfd_mach_arm_2 1
#define bfd_mach_arm_2a 2
#define bfd_mach_arm_3 3
#define bfd_mach_arm_3M 4
#define bfd_mach_arm_4 5
#define bfd_mach_arm_4T 6
#define bfd_mach_arm_5 7
#define bfd_mach_arm_5T 8
#define bfd_mach_arm_5TE 9
#define bfd_mach_arm_XScale 10
#define bfd_mach_arm_ep9312 11
#define bfd_mach_arm_iWMMXt 12
#define bfd_mach_arm_iWMMXt2 13
bfd_arch_ns32k, /* National Semiconductors ns32000 */
bfd_arch_w65, /* WDC 65816 */
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
bfd_arch_v850, /* NEC V850 */
#define bfd_mach_v850 0
bfd_arch_arc, /* Argonaut RISC Core */
#define bfd_mach_arc_base 0
bfd_arch_m32r, /* Mitsubishi M32R/D */
#define bfd_mach_m32r 0 /* backwards compatibility */
bfd_arch_mn10200, /* Matsushita MN10200 */
bfd_arch_mn10300, /* Matsushita MN10300 */
bfd_arch_avr, /* AVR microcontrollers */
#define bfd_mach_avr1 1
#define bfd_mach_avr2 2
#define bfd_mach_avr25 25
#define bfd_mach_avr3 3
#define bfd_mach_avr31 31
#define bfd_mach_avr35 35
#define bfd_mach_avr4 4
#define bfd_mach_avr5 5
#define bfd_mach_avr51 51
#define bfd_mach_avr6 6
#define bfd_mach_avrtiny 100
#define bfd_mach_avrxmega1 101
#define bfd_mach_avrxmega2 102
#define bfd_mach_avrxmega3 103
#define bfd_mach_avrxmega4 104
#define bfd_mach_avrxmega5 105
#define bfd_mach_avrxmega6 106
#define bfd_mach_avrxmega7 107
bfd_arch_microblaze, /* Xilinx MicroBlaze. */
bfd_arch_moxie, /* The Moxie core. */
bfd_arch_ia64, /* HP/Intel ia64 */
#define bfd_mach_ia64_elf64 64
#define bfd_mach_ia64_elf32 32
bfd_arch_rx, /* Renesas RX */
#define bfd_mach_rx 0x75
#define bfd_mach_rx_v2 0x76
#define bfd_mach_rx_v3 0x77
bfd_arch_loongarch,
bfd_arch_last
};
#define bfd_mach_s390_31 31
#define bfd_mach_s390_64 64
typedef struct symbol_cache_entry
{
const char *name;
union
{
PTR p;
bfd_vma i;
} udata;
} asymbol;
typedef int (*fprintf_function)(FILE *f, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);
enum dis_insn_type {
dis_noninsn, /* Not a valid instruction */
dis_nonbranch, /* Not a branch instruction */
dis_branch, /* Unconditional branch */
dis_condbranch, /* Conditional branch */
dis_jsr, /* Jump to subroutine */
dis_condjsr, /* Conditional jump to subroutine */
dis_dref, /* Data reference instruction */
dis_dref2 /* Two data references in instruction */
};
/* This struct is passed into the instruction decoding routine,
and is passed back out into each callback. The various fields are used
for conveying information from your main routine into your callbacks,
for passing information into the instruction decoders (such as the
addresses of the callback functions), or for passing information
back from the instruction decoders to their callers.
It must be initialized before it is first passed; this can be done
by hand, or using one of the initialization macros below. */
typedef struct disassemble_info {
fprintf_function fprintf_func;
FILE *stream;
PTR application_data;
/* Target description. We could replace this with a pointer to the bfd,
but that would require one. There currently isn't any such requirement
so to avoid introducing one we record these explicitly. */
/* The bfd_flavour. This can be bfd_target_unknown_flavour. */
enum bfd_flavour flavour;
/* The bfd_arch value. */
enum bfd_architecture arch;
/* The bfd_mach value. */
unsigned long mach;
/* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */
enum bfd_endian endian;
/* An array of pointers to symbols either at the location being disassembled
or at the start of the function being disassembled. The array is sorted
so that the first symbol is intended to be the one used. The others are
present for any misc. purposes. This is not set reliably, but if it is
not NULL, it is correct. */
asymbol **symbols;
/* Number of symbols in array. */
int num_symbols;
/* For use by the disassembler.
The top 16 bits are reserved for public use (and are documented here).
The bottom 16 bits are for the internal use of the disassembler. */
unsigned long flags;
#define INSN_HAS_RELOC 0x80000000
#define INSN_ARM_BE32 0x00010000
PTR private_data;
/* Function used to get bytes to disassemble. MEMADDR is the
address of the stuff to be disassembled, MYADDR is the address to
put the bytes in, and LENGTH is the number of bytes to read.
INFO is a pointer to this struct.
Returns an errno value or 0 for success. */
int (*read_memory_func)
(bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info);
/* Function which should be called if we get an error that we can't
recover from. STATUS is the errno value from read_memory_func and
MEMADDR is the address that we were trying to read. INFO is a
pointer to this struct. */
void (*memory_error_func)
(int status, bfd_vma memaddr, struct disassemble_info *info);
/* Function called to print ADDR. */
void (*print_address_func)
(bfd_vma addr, struct disassemble_info *info);
/* Function called to print an instruction. The function is architecture
* specific.
*/
int (*print_insn)(bfd_vma addr, struct disassemble_info *info);
/* Function called to determine if there is a symbol at the given ADDR.
If there is, the function returns 1, otherwise it returns 0.
This is used by ports which support an overlay manager where
the overlay number is held in the top part of an address. In
some circumstances we want to include the overlay number in the
address, (normally because there is a symbol associated with
that address), but sometimes we want to mask out the overlay bits. */
int (* symbol_at_address_func)
(bfd_vma addr, struct disassemble_info * info);
/* These are for buffer_read_memory. */
const bfd_byte *buffer;
bfd_vma buffer_vma;
int buffer_length;
/* This variable may be set by the instruction decoder. It suggests
the number of bytes objdump should display on a single line. If
the instruction decoder sets this, it should always set it to
the same value in order to get reasonable looking output. */
int bytes_per_line;
/* the next two variables control the way objdump displays the raw data */
/* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
/* output will look like this:
00: 00000000 00000000
with the chunks displayed according to "display_endian". */
int bytes_per_chunk;
enum bfd_endian display_endian;
/* Results from instruction decoders. Not all decoders yet support
this information. This info is set each time an instruction is
decoded, and is only valid for the last such instruction.
To determine whether this decoder supports this information, set
insn_info_valid to 0, decode an instruction, then check it. */
char insn_info_valid; /* Branch info has been set. */
char branch_delay_insns; /* How many sequential insn's will run before
a branch takes effect. (0 = normal) */
char data_size; /* Size of data reference in insn, in bytes */
enum dis_insn_type insn_type; /* Type of instruction */
bfd_vma target; /* Target address of branch or dref, if known;
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
/* Command line options specific to the target disassembler. */
char * disassembler_options;
/*
* When true instruct the disassembler it may preface the
* disassembly with the opcodes values if it wants to. This is
* mainly for the benefit of the plugin interface which doesn't want
* that.
*/
bool show_opcodes;
/* Field intended to be used by targets in any way they deem suitable. */
const void *target_info;
/* Options for Capstone disassembly. */
int cap_arch;
int cap_mode;
int cap_insn_unit;
int cap_insn_split;
} disassemble_info;
/* Standard disassemblers. Disassemble one instruction at the given
target address. Return number of bytes processed. */
typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
int print_insn_tci(bfd_vma, disassemble_info*);
int print_insn_big_mips (bfd_vma, disassemble_info*);
int print_insn_little_mips (bfd_vma, disassemble_info*);
int print_insn_nanomips (bfd_vma, disassemble_info*);
int print_insn_m68k (bfd_vma, disassemble_info*);
int print_insn_z8001 (bfd_vma, disassemble_info*);
int print_insn_z8002 (bfd_vma, disassemble_info*);
int print_insn_h8300 (bfd_vma, disassemble_info*);
int print_insn_h8300h (bfd_vma, disassemble_info*);
int print_insn_h8300s (bfd_vma, disassemble_info*);
int print_insn_h8500 (bfd_vma, disassemble_info*);
int print_insn_arm_a64 (bfd_vma, disassemble_info*);
int print_insn_alpha (bfd_vma, disassemble_info*);
disassembler_ftype arc_get_disassembler (int, int);
int print_insn_sparc (bfd_vma, disassemble_info*);
int print_insn_big_a29k (bfd_vma, disassemble_info*);
int print_insn_little_a29k (bfd_vma, disassemble_info*);
int print_insn_i960 (bfd_vma, disassemble_info*);
int print_insn_sh (bfd_vma, disassemble_info*);
int print_insn_shl (bfd_vma, disassemble_info*);
int print_insn_hppa (bfd_vma, disassemble_info*);
int print_insn_m32r (bfd_vma, disassemble_info*);
int print_insn_m88k (bfd_vma, disassemble_info*);
int print_insn_mn10200 (bfd_vma, disassemble_info*);
int print_insn_mn10300 (bfd_vma, disassemble_info*);
int print_insn_ns32k (bfd_vma, disassemble_info*);
int print_insn_big_powerpc (bfd_vma, disassemble_info*);
int print_insn_little_powerpc (bfd_vma, disassemble_info*);
int print_insn_rs6000 (bfd_vma, disassemble_info*);
int print_insn_w65 (bfd_vma, disassemble_info*);
int print_insn_d10v (bfd_vma, disassemble_info*);
int print_insn_v850 (bfd_vma, disassemble_info*);
int print_insn_tic30 (bfd_vma, disassemble_info*);
int print_insn_microblaze (bfd_vma, disassemble_info*);
int print_insn_ia64 (bfd_vma, disassemble_info*);
int print_insn_xtensa (bfd_vma, disassemble_info*);
int print_insn_riscv32 (bfd_vma, disassemble_info*);
int print_insn_riscv64 (bfd_vma, disassemble_info*);
int print_insn_riscv128 (bfd_vma, disassemble_info*);
int print_insn_rx(bfd_vma, disassemble_info *);
int print_insn_hexagon(bfd_vma, disassemble_info *);
int print_insn_loongarch(bfd_vma, disassemble_info *);
#ifdef CONFIG_CAPSTONE
bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size);
bool cap_disas_host(disassemble_info *info, const void *code, size_t size);
bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count);
bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size);
#else
# define cap_disas_target(i, p, s) false
# define cap_disas_host(i, p, s) false
# define cap_disas_monitor(i, p, c) false
# define cap_disas_plugin(i, p, c) false
#endif /* CONFIG_CAPSTONE */
#ifndef ATTRIBUTE_UNUSED
#define ATTRIBUTE_UNUSED __attribute__((unused))
#endif
/* from libbfd */
static inline bfd_vma bfd_getl64(const bfd_byte *addr)
{
return ldq_le_p(addr);
}
static inline bfd_vma bfd_getl32(const bfd_byte *addr)
{
return (uint32_t)ldl_le_p(addr);
}
static inline bfd_vma bfd_getl16(const bfd_byte *addr)
{
return lduw_le_p(addr);
}
static inline bfd_vma bfd_getb32(const bfd_byte *addr)
{
return (uint32_t)ldl_be_p(addr);
}
static inline bfd_vma bfd_getb16(const bfd_byte *addr)
{
return lduw_be_p(addr);
}
typedef bool bfd_boolean;
#endif /* DISAS_DIS_ASM_H */
+41
View File
@@ -0,0 +1,41 @@
#ifndef QEMU_DISAS_H
#define QEMU_DISAS_H
/* Disassemble this for me please... (debugging). */
#ifdef CONFIG_TCG
void disas(FILE *out, const void *code, size_t size);
void target_disas(FILE *out, CPUState *cpu, const DisasContextBase *db);
#endif
void monitor_disas(Monitor *mon, CPUState *cpu, uint64_t pc,
int nb_insn, bool is_physical);
#ifdef CONFIG_PLUGIN
char *plugin_disas(CPUState *cpu, const DisasContextBase *db,
uint64_t addr, size_t size);
#endif
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(uint64_t orig_addr);
struct syminfo;
struct elf32_sym;
struct elf64_sym;
typedef const char *(*lookup_symbol_t)(struct syminfo *s, uint64_t orig_addr);
struct syminfo {
lookup_symbol_t lookup_symbol;
unsigned int disas_num_syms;
union {
struct elf32_sym *elf32;
struct elf64_sym *elf64;
} disas_symtab;
const char *disas_strtab;
struct syminfo *next;
};
/* Filled in by elfload.c. Simplistic, but will do for now. */
extern struct syminfo *syminfos;
#endif /* QEMU_DISAS_H */
+1819
View File
File diff suppressed because it is too large Load Diff
+33
View File
@@ -0,0 +1,33 @@
/*
* QEMU abi_ptr type definitions
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef EXEC_ABI_PTR_H
#define EXEC_ABI_PTR_H
#include "cpu-param.h"
#if defined(CONFIG_USER_ONLY)
/*
* sparc32plus has 64bit long but 32bit space address
* this can make bad result with g2h() and h2g()
*/
#if TARGET_VIRT_ADDR_SPACE_BITS <= 32
typedef uint32_t abi_ptr;
#define TARGET_ABI_FMT_ptr "%x"
#else
typedef uint64_t abi_ptr;
#define TARGET_ABI_FMT_ptr "%"PRIx64
#endif
#else /* !CONFIG_USER_ONLY */
#include "exec/target_long.h"
typedef target_ulong abi_ptr;
#define TARGET_ABI_FMT_ptr TARGET_FMT_lx
#endif /* !CONFIG_USER_ONLY */
#endif
+44
View File
@@ -0,0 +1,44 @@
/*
* QEMU breakpoint & watchpoint definitions
*
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef EXEC_BREAKPOINT_H
#define EXEC_BREAKPOINT_H
#include "qemu/queue.h"
#include "exec/vaddr.h"
#include "exec/memattrs.h"
/* Breakpoint/watchpoint flags */
#define BP_MEM_READ 0x01
#define BP_MEM_WRITE 0x02
#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE)
#define BP_STOP_BEFORE_ACCESS 0x04
/* 0x08 currently unused */
#define BP_GDB 0x10
#define BP_CPU 0x20
#define BP_ANY (BP_GDB | BP_CPU)
#define BP_HIT_SHIFT 6
#define BP_WATCHPOINT_HIT_READ (BP_MEM_READ << BP_HIT_SHIFT)
#define BP_WATCHPOINT_HIT_WRITE (BP_MEM_WRITE << BP_HIT_SHIFT)
#define BP_WATCHPOINT_HIT (BP_MEM_ACCESS << BP_HIT_SHIFT)
typedef struct CPUBreakpoint {
vaddr pc;
int flags; /* BP_* */
QTAILQ_ENTRY(CPUBreakpoint) entry;
} CPUBreakpoint;
typedef struct CPUWatchpoint {
vaddr vaddr;
vaddr len;
vaddr hitaddr;
MemTxAttrs hitattrs;
int flags; /* BP_* */
QTAILQ_ENTRY(CPUWatchpoint) entry;
} CPUWatchpoint;
#endif
+115
View File
@@ -0,0 +1,115 @@
/*
* CPU interfaces that are target independent.
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef CPU_COMMON_H
#define CPU_COMMON_H
#include "qemu/thread.h"
#include "hw/core/cpu.h"
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */
#define REAL_HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_real_host_page_size())
/* The CPU list lock nests outside page_(un)lock or mmap_(un)lock */
extern QemuMutex qemu_cpu_list_lock;
void qemu_init_cpu_list(void);
void cpu_list_lock(void);
void cpu_list_unlock(void);
unsigned int cpu_list_generation_id_get(void);
int cpu_get_free_index(void);
/**
* cpu_address_space_init:
* @cpu: CPU to add this address space to
* @asidx: integer index of this address space
* @prefix: prefix to be used as name of address space
* @mr: the root memory region of address space
*
* Add the specified address space to the CPU's cpu_ases list.
* The address space added with @asidx 0 is the one used for the
* convenience pointer cpu->as.
* The target-specific code which registers ASes is responsible
* for defining what semantics address space 0, 1, 2, etc have.
*
* Note that with KVM only one address space is supported.
*/
void cpu_address_space_init(CPUState *cpu, int asidx,
const char *prefix, MemoryRegion *mr);
/**
* cpu_destroy_address_spaces:
* @cpu: CPU for which address spaces need to be destroyed
*
* Destroy all address spaces associated with this CPU; this
* is called as part of unrealizing the CPU.
*/
void cpu_destroy_address_spaces(CPUState *cpu);
/* vl.c */
void list_cpus(void);
#ifdef CONFIG_TCG
#include "qemu/atomic.h"
/**
* cpu_loop_exit_requested:
* @cpu: The CPU state to be tested
*
* Indicate if somebody asked for a return of the CPU to the main loop
* (e.g., via cpu_exit() or cpu_interrupt()).
*
* This is helpful for architectures that support interruptible
* instructions. After writing back all state to registers/memory, this
* call can be used to check if it makes sense to return to the main loop
* or to continue executing the interruptible instruction.
*/
static inline bool cpu_loop_exit_requested(const CPUState *cpu)
{
return (int32_t)qatomic_read(&cpu->neg.icount_decr.u32) < 0;
}
#endif /* CONFIG_TCG */
/**
* env_archcpu(env)
* @env: The architecture environment
*
* Return the ArchCPU associated with the environment.
*/
static inline ArchCPU *env_archcpu(CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
/**
* env_cpu_const(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline const CPUState *env_cpu_const(const CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
/**
* env_cpu(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline CPUState *env_cpu(CPUArchState *env)
{
return (CPUState *)env_cpu_const(env);
}
#endif /* CPU_COMMON_H */
+40
View File
@@ -0,0 +1,40 @@
/*
* common defines for all CPUs
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPU_DEFS_H
#define CPU_DEFS_H
#ifndef COMPILING_PER_TARGET
#error cpu.h included from common code
#endif
#include "cpu-param.h"
#ifndef TARGET_LONG_BITS
# error TARGET_LONG_BITS must be defined in cpu-param.h
#endif
#ifndef TARGET_VIRT_ADDR_SPACE_BITS
# error TARGET_VIRT_ADDR_SPACE_BITS must be defined in cpu-param.h
#endif
#if !defined(TARGET_PAGE_BITS) && !defined(TARGET_PAGE_BITS_VARY)
# error TARGET_PAGE_BITS must be defined in cpu-param.h
#endif
#include "exec/target_long.h"
#endif
+70
View File
@@ -0,0 +1,70 @@
/*
* Flags for use with cpu_interrupt()
*
* Copyright (c) 2003 Fabrice Bellard
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef CPU_INTERRUPT_H
#define CPU_INTERRUPT_H
/*
* The numbers assigned here are non-sequential in order to preserve binary
* compatibility with the vmstate dump. Bit 0 (0x0001) was previously used
* for CPU_INTERRUPT_EXIT, and is cleared when loading the vmstate dump.
*/
/*
* External hardware interrupt pending.
* This is typically used for interrupts from devices.
*/
#define CPU_INTERRUPT_HARD 0x0002
/*
* Exit the current TB. This is typically used when some system-level device
* makes some change to the memory mapping. E.g. the a20 line change.
*/
#define CPU_INTERRUPT_EXITTB 0x0004
/* Halt the CPU. */
#define CPU_INTERRUPT_HALT 0x0020
/* Debug event pending. */
#define CPU_INTERRUPT_DEBUG 0x0080
/* Reset signal. */
#define CPU_INTERRUPT_RESET 0x0400
/*
* Several target-specific external hardware interrupts. Each target/cpu.h
* should define proper names based on these defines.
*/
#define CPU_INTERRUPT_TGT_EXT_0 0x0008
#define CPU_INTERRUPT_TGT_EXT_1 0x0010
#define CPU_INTERRUPT_TGT_EXT_2 0x0040
#define CPU_INTERRUPT_TGT_EXT_3 0x0200
#define CPU_INTERRUPT_TGT_EXT_4 0x1000
/*
* Several target-specific internal interrupts. These differ from the
* preceding target-specific interrupts in that they are intended to
* originate from within the cpu itself, typically in response to some
* instruction being executed. These, therefore, are not masked while
* single-stepping within the debugger.
*/
#define CPU_INTERRUPT_TGT_INT_0 0x0100
#define CPU_INTERRUPT_TGT_INT_1 0x0800
#define CPU_INTERRUPT_TGT_INT_2 0x2000
/* First unused bit: 0x4000. */
/* The set of all bits that should be masked when single-stepping. */
#define CPU_INTERRUPT_SSTEP_MASK \
(CPU_INTERRUPT_HARD \
| CPU_INTERRUPT_TGT_EXT_0 \
| CPU_INTERRUPT_TGT_EXT_1 \
| CPU_INTERRUPT_TGT_EXT_2 \
| CPU_INTERRUPT_TGT_EXT_3 \
| CPU_INTERRUPT_TGT_EXT_4)
#endif /* CPU_INTERRUPT_H */
+283
View File
@@ -0,0 +1,283 @@
/*
* Common CPU TLB handling
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPUTLB_H
#define CPUTLB_H
#include "exec/cpu-common.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
#include "exec/vaddr.h"
#ifndef CONFIG_USER_ONLY
#include "system/ram_addr.h"
void tlb_reset_dirty(CPUState *cpu, uintptr_t start, uintptr_t length);
void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length);
#endif
/**
* tlb_set_page_full:
* @cpu: CPU context
* @mmu_idx: mmu index of the tlb to modify
* @addr: virtual address of the entry to add
* @full: the details of the tlb entry
*
* Add an entry to @cpu tlb index @mmu_idx. All of the fields of
* @full must be filled, except for xlat_offset & section, and
* constitute the complete description of the translated page.
*
* This is generally called by the target tlb_fill function after
* having performed a successful page table walk to find the physical
* address and attributes for the translation.
*
* At most one entry for a given virtual address is permitted. Only a
* single TARGET_PAGE_SIZE region is mapped; @full->lg_page_size is only
* used by tlb_flush_page.
*/
void tlb_set_page_full(CPUState *cpu, int mmu_idx, vaddr addr,
CPUTLBEntryFull *full);
/**
* tlb_set_page_with_attrs:
* @cpu: CPU to add this TLB entry for
* @addr: virtual address of page to add entry for
* @paddr: physical address of the page
* @attrs: memory transaction attributes
* @prot: access permissions (PAGE_READ/PAGE_WRITE/PAGE_EXEC bits)
* @mmu_idx: MMU index to insert TLB entry for
* @size: size of the page in bytes
*
* Add an entry to this CPU's TLB (a mapping from virtual address
* @addr to physical address @paddr) with the specified memory
* transaction attributes. This is generally called by the target CPU
* specific code after it has been called through the tlb_fill()
* entry point and performed a successful page table walk to find
* the physical address and attributes for the virtual address
* which provoked the TLB miss.
*
* At most one entry for a given virtual address is permitted. Only a
* single TARGET_PAGE_SIZE region is mapped; the supplied @size is only
* used by tlb_flush_page.
*/
void tlb_set_page_with_attrs(CPUState *cpu, vaddr addr,
hwaddr paddr, MemTxAttrs attrs,
int prot, int mmu_idx, vaddr size);
/**
* tlb_set_page:
*
* This function is equivalent to calling tlb_set_page_with_attrs()
* with an @attrs argument of MEMTXATTRS_UNSPECIFIED. It's provided
* as a convenience for CPUs which don't use memory transaction attributes.
*/
void tlb_set_page(CPUState *cpu, vaddr addr,
hwaddr paddr, int prot,
int mmu_idx, vaddr size);
#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
/**
* tlb_flush_page:
* @cpu: CPU whose TLB should be flushed
* @addr: virtual address of page to be flushed
*
* Flush one page from the TLB of the specified CPU, for all
* MMU indexes.
*/
void tlb_flush_page(CPUState *cpu, vaddr addr);
/**
* tlb_flush_page_all_cpus_synced:
* @cpu: src CPU of the flush
* @addr: virtual address of page to be flushed
*
* Flush one page from the TLB of all CPUs, for all
* MMU indexes.
*
* When this function returns, no CPUs will subsequently perform
* translations using the flushed TLBs.
*/
void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr);
/**
* tlb_flush:
* @cpu: CPU whose TLB should be flushed
*
* Flush the entire TLB for the specified CPU. Most CPU architectures
* allow the implementation to drop entries from the TLB at any time
* so this is generally safe. If more selective flushing is required
* use one of the other functions for efficiency.
*/
void tlb_flush(CPUState *cpu);
/**
* tlb_flush_all_cpus_synced:
* @cpu: src CPU of the flush
*
* Flush the entire TLB for all CPUs, for all MMU indexes.
*
* When this function returns, no CPUs will subsequently perform
* translations using the flushed TLBs.
*/
void tlb_flush_all_cpus_synced(CPUState *src_cpu);
/**
* tlb_flush_page_by_mmuidx:
* @cpu: CPU whose TLB should be flushed
* @addr: virtual address of page to be flushed
* @idxmap: bitmap of MMU indexes to flush
*
* Flush one page from the TLB of the specified CPU, for the specified
* MMU indexes.
*/
void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr,
MMUIdxMap idxmap);
/**
* tlb_flush_page_by_mmuidx_all_cpus_synced:
* @cpu: Originating CPU of the flush
* @addr: virtual address of page to be flushed
* @idxmap: bitmap of MMU indexes to flush
*
* Flush one page from the TLB of all CPUs, for the specified
* MMU indexes.
*
* When this function returns, no CPUs will subsequently perform
* translations using the flushed TLBs.
*/
void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr,
MMUIdxMap idxmap);
/**
* tlb_flush_by_mmuidx:
* @cpu: CPU whose TLB should be flushed
* @wait: If true ensure synchronisation by exiting the cpu_loop
* @idxmap: bitmap of MMU indexes to flush
*
* Flush all entries from the TLB of the specified CPU, for the specified
* MMU indexes.
*/
void tlb_flush_by_mmuidx(CPUState *cpu, MMUIdxMap idxmap);
/**
* tlb_flush_by_mmuidx_all_cpus_synced:
* @cpu: Originating CPU of the flush
* @idxmap: bitmap of MMU indexes to flush
*
* Flush all entries from the TLB of all CPUs, for the specified
* MMU indexes.
*
* When this function returns, no CPUs will subsequently perform
* translations using the flushed TLBs.
*/
void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, MMUIdxMap idxmap);
/**
* tlb_flush_page_bits_by_mmuidx
* @cpu: CPU whose TLB should be flushed
* @addr: virtual address of page to be flushed
* @idxmap: bitmap of mmu indexes to flush
* @bits: number of significant bits in address
*
* Similar to tlb_flush_page_mask, but with a bitmap of indexes.
*/
void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr,
MMUIdxMap idxmap, unsigned bits);
/* Similarly, with broadcast and syncing. */
void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr,
MMUIdxMap idxmap,
unsigned bits);
/**
* tlb_flush_range_by_mmuidx
* @cpu: CPU whose TLB should be flushed
* @addr: virtual address of the start of the range to be flushed
* @len: length of range to be flushed
* @idxmap: bitmap of mmu indexes to flush
* @bits: number of significant bits in address
*
* For each mmuidx in @idxmap, flush all pages within [@addr,@addr+@len),
* comparing only the low @bits worth of each virtual page.
*/
void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
vaddr len, MMUIdxMap idxmap,
unsigned bits);
/* Similarly, with broadcast and syncing. */
void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu,
vaddr addr,
vaddr len,
MMUIdxMap idxmap,
unsigned bits);
#else
static inline void tlb_flush_page(CPUState *cpu, vaddr addr)
{
}
static inline void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr)
{
}
static inline void tlb_flush(CPUState *cpu)
{
}
static inline void tlb_flush_all_cpus_synced(CPUState *src_cpu)
{
}
static inline void tlb_flush_page_by_mmuidx(CPUState *cpu,
vaddr addr, MMUIdxMap idxmap)
{
}
static inline void tlb_flush_by_mmuidx(CPUState *cpu, MMUIdxMap idxmap)
{
}
static inline void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu,
vaddr addr,
MMUIdxMap idxmap)
{
}
static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu,
MMUIdxMap idxmap)
{
}
static inline void tlb_flush_page_bits_by_mmuidx(CPUState *cpu,
vaddr addr,
MMUIdxMap idxmap,
unsigned bits)
{
}
static inline void
tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr,
MMUIdxMap idxmap, unsigned bits)
{
}
static inline void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr,
vaddr len, MMUIdxMap idxmap,
unsigned bits)
{
}
static inline void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu,
vaddr addr,
vaddr len,
MMUIdxMap idxmap,
unsigned bits)
{
}
#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
#endif /* CPUTLB_H */
+161
View File
@@ -0,0 +1,161 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
typedef struct GDBFeature {
const char *xmlname;
const char *xml;
const char *name;
const char * const *regs;
int base_reg;
int num_regs;
} GDBFeature;
typedef struct GDBFeatureBuilder {
GDBFeature *feature;
GPtrArray *xml;
GPtrArray *regs;
int base_reg;
} GDBFeatureBuilder;
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_get_reg_cb)(CPUState *cpu, GByteArray *buf, int reg);
typedef int (*gdb_set_reg_cb)(CPUState *cpu, uint8_t *buf, int reg);
/**
* gdb_init_cpu(): Initialize the CPU for gdbstub.
* @cpu: The CPU to be initialized.
*/
void gdb_init_cpu(CPUState *cpu);
/**
* gdb_register_coprocessor() - register a supplemental set of registers
* @cpu - the CPU associated with registers
* @get_reg - get function (gdb reading)
* @set_reg - set function (gdb modifying)
* @num_regs - number of registers in set
* @xml - xml name of set
*/
void gdb_register_coprocessor(CPUState *cpu,
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
const GDBFeature *feature);
/**
* gdb_unregister_coprocessor_all() - unregisters supplemental set of registers
* @cpu - the CPU associated with registers
*/
void gdb_unregister_coprocessor_all(CPUState *cpu);
/**
* gdbserver_start: start the gdb server
* @port_or_device: connection spec for gdb
* @errp: error handle
*
* For CONFIG_USER this is either a tcp port or a path to a fifo. For
* system emulation you can use a full chardev spec for your gdbserver
* port.
*
* Returns true when server successfully started.
*/
bool gdbserver_start(const char *port_or_device, Error **errp);
/**
* gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
* @builder: The builder to be initialized.
* @feature: The feature to be filled.
* @name: The name of the feature.
* @xmlname: The name of the XML.
* @base_reg: The base number of the register ID.
*/
void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
const char *name, const char *xmlname,
int base_reg);
/**
* gdb_feature_builder_append_tag() - Append a tag.
* @builder: The builder.
* @format: The format of the tag.
* @...: The values to be formatted.
*/
void G_GNUC_PRINTF(2, 3)
gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
const char *format, ...);
/**
* gdb_feature_builder_append_reg() - Append a register.
* @builder: The builder.
* @name: The register's name; it must be unique within a CPU.
* @bitsize: The register's size, in bits.
* @regnum: The offset of the register's number in the feature.
* @type: The type of the register.
* @group: The register group to which this register belongs; it can be NULL.
*/
void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
const char *name,
int bitsize,
int regnum,
const char *type,
const char *group);
/**
* gdb_feature_builder_end() - End building GDBFeature.
* @builder: The builder.
*/
void gdb_feature_builder_end(const GDBFeatureBuilder *builder);
/**
* gdb_find_static_feature() - Find a static feature.
* @xmlname: The name of the XML.
*
* Return: The static feature.
*/
const GDBFeature *gdb_find_static_feature(const char *xmlname);
/**
* gdb_read_register() - Read a register associated with a CPU.
* @cpu: The CPU associated with the register.
* @buf: The buffer that the read register will be appended to.
* @reg: The register's number returned by gdb_find_feature_register().
*
* Return: The number of read bytes.
*/
int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
/**
* gdb_write_register() - Write a register associated with a CPU.
* @cpu: The CPU associated with the register.
* @buf: The buffer that the register contents will be set to.
* @reg: The register's number returned by gdb_find_feature_register().
*
* The size of @buf must be at least the size of the register being
* written.
*
* Return: The number of written bytes, or 0 if an error occurred (for
* example, an unknown register was provided).
*/
int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg);
/**
* typedef GDBRegDesc - a register description from gdbstub
*/
typedef struct {
int gdb_reg;
const char *name;
const char *feature_name;
} GDBRegDesc;
/**
* gdb_get_register_list() - Return list of all registers for CPU
* @cpu: The CPU being searched
*
* Returns a GArray of GDBRegDesc, caller frees array but not the
* const strings.
*/
GArray *gdb_get_register_list(CPUState *cpu);
void gdb_set_stop_cpu(CPUState *cpu);
/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
extern const GDBFeature gdb_static_features[];
#endif /* GDBSTUB_H */
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands generation functions for tcg opcodes.
*/
#ifndef HELPER_GEN_COMMON_H
#define HELPER_GEN_COMMON_H
#define HELPER_H "accel/tcg/tcg-runtime.h"
#include "exec/helper-gen.h.inc"
#undef HELPER_H
#endif /* HELPER_GEN_COMMON_H */
+16
View File
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands generation functions for tcg opcodes.
*/
#ifndef HELPER_GEN_H
#define HELPER_GEN_H
#include "exec/helper-gen-common.h"
#define HELPER_H "helper.h"
#include "exec/helper-gen.h.inc"
#undef HELPER_H
#endif /* HELPER_GEN_H */
+110
View File
@@ -0,0 +1,110 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands generation functions for tcg opcodes.
* Define HELPER_H for the header file to be expanded,
* and static inline to change from global file scope.
*/
#include "tcg/tcg.h"
#include "tcg/helper-info.h"
#include "exec/helper-head.h.inc"
#define DEF_HELPER_FLAGS_0(name, flags, ret) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
{ \
tcg_gen_call0(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret)); \
}
#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1)) \
{ \
tcg_gen_call1(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1)); \
}
#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2)) \
{ \
tcg_gen_call2(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2)); \
}
#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
{ \
tcg_gen_call3(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3)); \
}
#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), \
dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
{ \
tcg_gen_call4(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), \
dh_arg(t3, 3), dh_arg(t4, 4)); \
}
#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \
{ \
tcg_gen_call5(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5)); \
}
#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6)) \
{ \
tcg_gen_call6(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6)); \
}
#define DEF_HELPER_FLAGS_7(name, flags, ret, t1, t2, t3, t4, t5, t6, t7)\
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6), \
dh_arg_decl(t7, 7)) \
{ \
tcg_gen_call7(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6), \
dh_arg(t7, 7)); \
}
#include HELPER_H
#undef DEF_HELPER_FLAGS_0
#undef DEF_HELPER_FLAGS_1
#undef DEF_HELPER_FLAGS_2
#undef DEF_HELPER_FLAGS_3
#undef DEF_HELPER_FLAGS_4
#undef DEF_HELPER_FLAGS_5
#undef DEF_HELPER_FLAGS_6
#undef DEF_HELPER_FLAGS_7

Some files were not shown because too many files have changed in this diff Show More