Import QEMU upstream snapshot d2e570c
Upstream: https://gitlab.com/qemu-project/qemu.git Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
This commit is contained in:
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
* field’s 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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
Reference in New Issue
Block a user