支持syscall快速系统调用指令 (#417)

* 支持syscall快速系统调用指令

---------

Co-authored-by: LoGin <longjin@DragonOS.org>
This commit is contained in:
GnoCiYeH 2023-11-04 21:39:44 +08:00 committed by GitHub
parent 2f6f547ae0
commit 1603395155
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 317 additions and 48 deletions

2
.gitignore vendored
View File

@ -18,4 +18,4 @@ cppcheck.xml
/target/
Cargo.lock
.cache
compile_commands.json
compile_commands.json

View File

@ -1,6 +1,8 @@
use crate::time::TimeArch;
use super::{driver::tsc::TSCManager, setup::setup_arch, CurrentTimeArch};
use super::{
driver::tsc::TSCManager, setup::setup_arch, syscall::init_syscall_64, CurrentTimeArch,
};
#[no_mangle]
unsafe extern "C" fn rs_setup_arch() -> i32 {
@ -19,3 +21,9 @@ unsafe extern "C" fn rs_get_cycles() -> u64 {
unsafe extern "C" fn rs_tsc_get_cpu_khz() -> u64 {
return TSCManager::cpu_khz();
}
/// syscall指令初始化
#[no_mangle]
pub unsafe extern "C" fn rs_init_syscall_64() {
init_syscall_64();
}

View File

@ -374,13 +374,13 @@ pub struct X86_64SignalArch;
impl SignalArch for X86_64SignalArch {
unsafe fn do_signal(frame: &mut TrapFrame) {
let pcb = ProcessManager::current_pcb();
let siginfo = pcb.try_siginfo(5);
// 检查sigpending是否为0
if ProcessManager::current_pcb()
.sig_info()
.sig_pending()
.signal()
.bits()
== 0
if siginfo
.map(|s| s.sig_pending().signal().bits() == 0)
.unwrap_or(true)
|| !frame.from_user()
{
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回

View File

@ -37,16 +37,13 @@ use self::{
table::{switch_fs_and_gs, KERNEL_DS, USER_DS},
};
use super::{fpu::FpState, interrupt::TrapFrame, CurrentIrqArch};
use super::{fpu::FpState, interrupt::TrapFrame, syscall::X86_64GSData, CurrentIrqArch};
mod c_adapter;
pub mod kthread;
pub mod syscall;
pub mod table;
pub const IA32_FS_BASE: u32 = 0xC000_0100;
pub const IA32_GS_BASE: u32 = 0xC000_0101;
extern "C" {
/// 从中断返回
fn ret_from_intr();
@ -66,7 +63,7 @@ static BSP_IDLE_STACK_SPACE: InitProcUnion = InitProcUnion {
};
/// PCB中与架构相关的信息
#[derive(Debug, Clone)]
#[derive(Debug)]
#[allow(dead_code)]
pub struct ArchPCBInfo {
rflags: usize,
@ -81,9 +78,10 @@ pub struct ArchPCBInfo {
cr2: usize,
fsbase: usize,
gsbase: usize,
fs: u16,
gs: u16,
fs: SegmentSelector,
gs: SegmentSelector,
/// 存储PCB系统调用栈以及在syscall过程中暂存用户态rsp的结构体
gsdata: X86_64GSData,
/// 浮点寄存器的状态
fp_state: Option<FpState>,
}
@ -99,7 +97,7 @@ impl ArchPCBInfo {
/// ## 返回值
///
/// 返回一个新的ArchPCBInfo
pub fn new(kstack: Option<&KernelStack>) -> Self {
pub fn new(kstack: &KernelStack) -> Self {
let mut r = Self {
rflags: 0,
rbx: 0,
@ -113,16 +111,17 @@ impl ArchPCBInfo {
cr2: 0,
fsbase: 0,
gsbase: 0,
fs: KERNEL_DS.bits(),
gs: KERNEL_DS.bits(),
gsdata: X86_64GSData {
kaddr: VirtAddr::new(0),
uaddr: VirtAddr::new(0),
},
fs: KERNEL_DS,
gs: KERNEL_DS,
fp_state: None,
};
if kstack.is_some() {
let kstack = kstack.unwrap();
r.rsp = kstack.stack_max_address().data();
r.rbp = kstack.stack_max_address().data();
}
r.rsp = kstack.stack_max_address().data() - 8;
r.rbp = kstack.stack_max_address().data();
return r;
}
@ -184,7 +183,7 @@ impl ArchPCBInfo {
if x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_FSGSBASE) {
self.fsbase = x86::current::segmentation::rdfsbase() as usize;
} else {
self.fsbase = x86::msr::rdmsr(IA32_FS_BASE) as usize;
self.fsbase = x86::msr::rdmsr(x86::msr::IA32_FS_BASE) as usize;
}
}
@ -192,7 +191,7 @@ impl ArchPCBInfo {
if x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_FSGSBASE) {
self.gsbase = x86::current::segmentation::rdgsbase() as usize;
} else {
self.gsbase = x86::msr::rdmsr(IA32_GS_BASE) as usize;
self.gsbase = x86::msr::rdmsr(x86::msr::IA32_GS_BASE) as usize;
}
}
@ -200,7 +199,7 @@ impl ArchPCBInfo {
if x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_FSGSBASE) {
x86::current::segmentation::wrfsbase(self.fsbase as u64);
} else {
x86::msr::wrmsr(IA32_FS_BASE, self.fsbase as u64);
x86::msr::wrmsr(x86::msr::IA32_FS_BASE, self.fsbase as u64);
}
}
@ -208,10 +207,23 @@ impl ArchPCBInfo {
if x86::controlregs::cr4().contains(Cr4::CR4_ENABLE_FSGSBASE) {
x86::current::segmentation::wrgsbase(self.gsbase as u64);
} else {
x86::msr::wrmsr(IA32_GS_BASE, self.gsbase as u64);
x86::msr::wrmsr(x86::msr::IA32_GS_BASE, self.gsbase as u64);
}
}
/// 将gsdata写入KernelGsbase寄存器
pub unsafe fn store_kernel_gsbase(&self) {
x86::msr::wrmsr(
x86::msr::IA32_KERNEL_GSBASE,
&self.gsdata as *const X86_64GSData as u64,
);
}
/// ### 初始化系统调用栈不得与PCB内核栈冲突(即传入的应该是一个新的栈,避免栈损坏)
pub fn init_syscall_stack(&mut self, stack: &KernelStack) {
self.gsdata.set_kstack(stack.stack_max_address() - 8);
}
pub fn fsbase(&self) -> usize {
self.fsbase
}
@ -227,6 +239,35 @@ impl ArchPCBInfo {
pub fn fp_state_mut(&mut self) -> &mut Option<FpState> {
&mut self.fp_state
}
/// ### 克隆ArchPCBInfo,需要注意gsdata也是对应clone的
pub fn clone_all(&self) -> Self {
Self {
rflags: self.rflags,
rbx: self.rbx,
r12: self.r12,
r13: self.r13,
r14: self.r14,
r15: self.r15,
rbp: self.rbp,
rsp: self.rsp,
rip: self.rip,
cr2: self.cr2,
fsbase: self.fsbase,
gsbase: self.gsbase,
fs: self.fs.clone(),
gs: self.gs.clone(),
gsdata: self.gsdata.clone(),
fp_state: self.fp_state,
}
}
// ### 从另一个ArchPCBInfo处clone,gsdata会被保留
pub fn clone_from(&mut self, from: &Self) {
let gsdata = self.gsdata.clone();
*self = from.clone_all();
self.gsdata = gsdata;
}
}
impl ProcessControlBlock {
@ -349,8 +390,7 @@ impl ProcessManager {
next.arch_info().restore_fsbase();
// 切换gsbase
prev.arch_info().save_gsbase();
next.arch_info().restore_gsbase();
Self::switch_gsbase(&prev, &next);
// 切换地址空间
let next_addr_space = next.basic().user_vm().as_ref().unwrap().clone();
@ -383,6 +423,15 @@ impl ProcessManager {
// 正式切换上下文
switch_to_inner(prev_arch, next_arch);
}
unsafe fn switch_gsbase(prev: &Arc<ProcessControlBlock>, next: &Arc<ProcessControlBlock>) {
asm!("swapgs", options(nostack, preserves_flags));
prev.arch_info().save_gsbase();
next.arch_info().restore_gsbase();
// 将下一个进程的kstack写入kernel_gsbase
next.arch_info().store_kernel_gsbase();
asm!("swapgs", options(nostack, preserves_flags));
}
}
/// 保存上下文然后切换进程接着jmp到`switch_finish_hook`钩子函数
@ -504,12 +553,15 @@ pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<Str
let mut arch_guard = current_pcb.arch_info_irqsave();
arch_guard.rsp = trap_frame_vaddr.data();
arch_guard.fs = USER_DS.bits();
arch_guard.gs = USER_DS.bits();
arch_guard.fs = USER_DS;
arch_guard.gs = USER_DS;
// 将内核gs数据压进cpu
arch_guard.store_kernel_gsbase();
switch_fs_and_gs(
SegmentSelector::from_bits_truncate(arch_guard.fs),
SegmentSelector::from_bits_truncate(arch_guard.gs),
SegmentSelector::from_bits_truncate(arch_guard.fs.bits()),
SegmentSelector::from_bits_truncate(arch_guard.gs.bits()),
);
arch_guard.rip = new_rip.data();
@ -548,6 +600,7 @@ unsafe extern "sysv64" fn ready_to_switch_to_user(
) -> ! {
*(trapframe_vaddr as *mut TrapFrame) = trap_frame;
asm!(
"swapgs",
"mov rsp, {trapframe_vaddr}",
"push {new_rip}",
"ret",

View File

@ -10,10 +10,11 @@ use crate::{
pub const KERNEL_CS: SegmentSelector = SegmentSelector::new(1, Ring::Ring0);
/// kernel data segment selector
pub const KERNEL_DS: SegmentSelector = SegmentSelector::new(2, Ring::Ring0);
/// user code segment selector
pub const USER_CS: SegmentSelector = SegmentSelector::new(5, Ring::Ring3);
/// user data segment selector
pub const USER_DS: SegmentSelector = SegmentSelector::new(6, Ring::Ring3);
pub const USER_DS: SegmentSelector = SegmentSelector::new(5, Ring::Ring3);
/// user code segment selector
/// 如果改这里记得改syscall_64里面写死的常量
pub const USER_CS: SegmentSelector = SegmentSelector::new(6, Ring::Ring3);
static mut TSS_MANAGER: TSSManager = TSSManager::new();

View File

@ -1,30 +1,59 @@
use core::ffi::c_void;
use alloc::string::String;
use crate::{
arch::ipc::signal::X86_64SignalArch,
arch::{ipc::signal::X86_64SignalArch, CurrentIrqArch},
exception::InterruptArch,
include::bindings::bindings::set_system_trap_gate,
ipc::signal_types::SignalArch,
libs::align::SafeForZero,
mm::VirtAddr,
syscall::{Syscall, SystemError, SYS_RT_SIGRETURN},
};
use alloc::string::String;
use super::{interrupt::TrapFrame, mm::barrier::mfence};
/// ### 存储PCB系统调用栈以及在syscall过程中暂存用户态rsp的结构体
///
/// 在syscall指令中将会从该结构体中读取系统调用栈和暂存rsp,
/// 使用`gsbase`寄存器实现后续如果需要使用gsbase寄存器需要相应设置正确的偏移量
#[repr(C)]
#[derive(Debug, Clone)]
pub(super) struct X86_64GSData {
pub(super) kaddr: VirtAddr,
pub(super) uaddr: VirtAddr,
}
impl X86_64GSData {
/// ### 设置系统调用栈将会在下一个调度后写入KernelGsbase
pub fn set_kstack(&mut self, kstack: VirtAddr) {
self.kaddr = kstack;
}
}
unsafe impl SafeForZero for X86_64GSData {}
extern "C" {
fn syscall_int();
fn syscall_64();
}
macro_rules! syscall_return {
($val:expr, $regs:expr) => {{
let ret = $val;
$regs.rax = ret as u64;
unsafe {
CurrentIrqArch::interrupt_disable();
}
return;
}};
}
#[no_mangle]
pub extern "C" fn syscall_handler(frame: &mut TrapFrame) -> () {
pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) -> () {
unsafe {
CurrentIrqArch::interrupt_enable();
}
let syscall_num = frame.rax as usize;
let args = [
frame.rdi as usize,
@ -54,6 +83,7 @@ pub extern "C" fn syscall_handler(frame: &mut TrapFrame) -> () {
pub fn arch_syscall_init() -> Result<(), SystemError> {
// kinfo!("arch_syscall_init\n");
unsafe { set_system_trap_gate(0x80, 0, syscall_int as *mut c_void) }; // 系统调用门
unsafe { init_syscall_64() };
return Ok(());
}
@ -69,3 +99,20 @@ pub extern "C" fn rs_exec_init_process(frame: &mut TrapFrame) -> usize {
// kdebug!("rs_exec_init_process: r: {:?}\n", r);
return r.map(|_| 0).unwrap_or_else(|e| e.to_posix_errno() as usize);
}
/// syscall指令初始化函数
pub(super) unsafe fn init_syscall_64() {
let mut efer = x86::msr::rdmsr(x86::msr::IA32_EFER);
efer |= 0x1;
x86::msr::wrmsr(x86::msr::IA32_EFER, efer);
let syscall_base = (1 as u16) << 3;
let sysret_base = ((4 as u16) << 3) | 3;
let high = (u32::from(sysret_base) << 16) | u32::from(syscall_base);
// 初始化STAR寄存器
x86::msr::wrmsr(x86::msr::IA32_STAR, u64::from(high) << 32);
// 初始化LSTAR,该寄存器存储syscall指令入口
x86::msr::wrmsr(x86::msr::IA32_LSTAR, syscall_64 as u64);
x86::msr::wrmsr(x86::msr::IA32_FMASK, 0xfffffffe);
}

View File

@ -412,6 +412,10 @@ int apic_init()
*/
void do_IRQ(struct pt_regs *rsp, ul number)
{
if((rsp->cs & 0x3) == 3)
{
asm volatile("swapgs":::"memory");
}
if (number < 0x80 && number >= 32) // 以0x80为界限低于0x80的是外部中断控制器高于0x80的是Local APIC
{
// ==========外部中断控制器========

View File

@ -69,6 +69,21 @@ ENTRY(ret_from_intr)
movq %rsp, %rdi
callq do_signal
__entry_ret_from_intr_before_gs_check_2:
push %rcx
addq $8, %rsp
movq CS(%rsp), %rcx
subq $8, %rsp
andq $0x3, %rcx
cmpq $0x3, %rcx
jne __entry_ret_from_intr_after_gs_check_2
swapgs
__entry_ret_from_intr_after_gs_check_2:
popq %rcx
//
jmp Restore_all
@ -109,7 +124,20 @@ Err_Code:
movq %rsp, %rdi // rdi
__entry_err_code_before_gs_check_1:
pushq %rcx
movq CS(%rdi), %rcx
and $0x3, %rcx
cmp $0x3, %rcx
jne __entry_err_code_after_gs_check_1
swapgs
__entry_err_code_after_gs_check_1:
popq %rcx
callq *%rdx // *
jmp ret_from_exception
@ -296,3 +324,87 @@ ENTRY(ignore_int)
xchgq %rax, (%rsp) // FUNC
jmp Err_Code
ENTRY(syscall_64)
//
swapgs
movq %rsp, %gs:0x8
movq %gs:0x0, %rsp
pushq $43 // USER_DS
pushq %gs:0x8 // rsp
pushq %r11 // RFLAGS
pushq $51 // USER_CS
pushq %rcx // RIP
pushq $0 // error code
pushq %rax
leaq syscall_handler(%rip), %rax // FUNC
xchgq %rax, (%rsp)
pushq %rax // rax
movq %es, %rax
pushq %rax // es
movq %ds, %rax
pushq %rax // ds
xorq %rax, %rax
pushq %rbp
pushq %rdi
pushq %rsi
pushq %rdx
pushq %rcx
pushq %rbx
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
cld
xorq %rsi, %rsi
movq FUNC(%rsp), %rdx
movq %rsp, %rdi // rdi
callq *%rdx //
cli
// === ===
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rbx
popq %rcx
popq %rdx
popq %rsi
popq %rdi
popq %rbp
popq %rax // popds
movq %rax, %ds
popq %rax
movq %rax, %es
popq %rax
addq $0x10, %rsp // FUNCerrcode
popq %rcx // pop riprcx
addq $0x8, %rsp // cs
popq %r11 // pop rflagsr11
popq %rsp // Restore rsp
swapgs
sysretq

View File

@ -515,8 +515,8 @@ GDT_Table:
.quad 0x0000920000000000 // 2 64 0x10
.quad 0x0000000000000000 // 3 32 0x18
.quad 0x0000000000000000 // 4 32 0x20
.quad 0x0020f80000000000 // 5 64 0x28
.quad 0x0000f20000000000 // 6 64 0x30
.quad 0x00cff3000000ffff // 5 64 0x28
.quad 0x00affb000000ffff // 6 64 0x30
.quad 0x00cf9a000000ffff // 7 32 0x38
.quad 0x00cf92000000ffff // 8 32 0x40
.fill 100, 8, 0 // 10-11 TSS(9) 80 TSS128bit

View File

@ -339,7 +339,9 @@ impl ProcessManager {
// TODO: 克隆前应该锁信号处理,等待克隆完成后再处理
// 克隆架构相关
*pcb.arch_info() = current_pcb.arch_info_irqsave().clone();
let guard = current_pcb.arch_info_irqsave();
pcb.arch_info().clone_from(&guard);
drop(guard);
// 为内核线程设置WorkerPrivate
if current_pcb.flags().contains(ProcessFlags::KTHREAD) {

View File

@ -510,6 +510,9 @@ pub struct ProcessControlBlock {
/// 进程的内核栈
kernel_stack: RwLock<KernelStack>,
/// 系统调用栈
syscall_stack: RwLock<KernelStack>,
/// 与调度相关的信息
sched_info: RwLock<ProcessSchedulerInfo>,
/// 与处理器架构相关的信息
@ -571,7 +574,7 @@ impl ProcessControlBlock {
let flags = SpinLock::new(ProcessFlags::empty());
let sched_info = ProcessSchedulerInfo::new(None);
let arch_info = SpinLock::new(ArchPCBInfo::new(Some(&kstack)));
let arch_info = SpinLock::new(ArchPCBInfo::new(&kstack));
let ppcb: Weak<ProcessControlBlock> = ProcessManager::find(ppid)
.map(|p| Arc::downgrade(&p))
@ -583,6 +586,7 @@ impl ProcessControlBlock {
preempt_count,
flags,
kernel_stack: RwLock::new(kstack),
syscall_stack: RwLock::new(KernelStack::new().unwrap()),
worker_private: SpinLock::new(None),
sched_info,
arch_info,
@ -594,11 +598,21 @@ impl ProcessControlBlock {
thread: RwLock::new(ThreadInfo::new()),
};
// 初始化系统调用栈
pcb.arch_info
.lock()
.init_syscall_stack(&pcb.syscall_stack.read());
let pcb = Arc::new(pcb);
// 设置进程的arc指针到内核栈的最低地址处
// 设置进程的arc指针到内核栈和系统调用栈的最低地址处
unsafe {
pcb.kernel_stack
.write()
.set_pcb(Arc::downgrade(&pcb))
.unwrap();
pcb.syscall_stack
.write()
.set_pcb(Arc::downgrade(&pcb))
.unwrap()
@ -788,6 +802,16 @@ impl ProcessControlBlock {
self.sig_info.read()
}
pub fn try_siginfo(&self, times: u8) -> Option<RwLockReadGuard<ProcessSignalInfo>> {
for _ in 0..times {
if let Some(r) = self.sig_info.try_read() {
return Some(r);
}
}
return None;
}
pub fn sig_info_mut(&self) -> RwLockWriteGuard<ProcessSignalInfo> {
self.sig_info.write()
}
@ -1026,7 +1050,7 @@ impl ProcessSchedulerInfo {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct KernelStack {
stack: Option<AlignedBox<[u8; KernelStack::SIZE], { KernelStack::ALIGN }>>,
/// 标记该内核栈是否可以被释放

View File

@ -10,8 +10,15 @@
#include <process/preempt.h>
#include <sched/sched.h>
#include <driver/acpi/acpi.h>
#include "exception/trap.h"
#include "ipi.h"
/* x86-64 specific MSRs */
#define MSR_EFER 0xc0000080 /* extended feature register */
#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */
#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */
#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */
static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
static void __smp__flush_tlb_ipi_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
@ -25,6 +32,7 @@ int num_cpu_started = 1;
extern void smp_ap_start();
extern uint64_t rs_get_idle_stack_top(uint32_t cpu_id);
extern void rs_init_syscall_64();
// 在head.S中定义的APU启动时要加载的页表
// 由于内存管理模块初始化的时候重置了页表因此我们要把当前的页表传给APU
@ -146,8 +154,11 @@ void smp_ap_start_stage2()
io_mfence();
spin_unlock_no_preempt(&multi_core_starting_lock);
rs_init_syscall_64();
apic_timer_ap_core_init();
sti();
sched();

View File

@ -424,6 +424,8 @@ pub const SYS_GET_DENTS_64: usize = 217;
#[allow(dead_code)]
pub const SYS_SET_TID_ADDR: usize = 218;
pub const SYS_EXIT_GROUP: usize = 231;
pub const SYS_UNLINK_AT: usize = 263;
pub const SYS_PIPE: usize = 293;
@ -1121,6 +1123,11 @@ impl Syscall {
Ok(0)
}
SYS_EXIT_GROUP => {
kwarn!("SYS_EXIT_GROUP has not yet been implemented");
Ok(0)
}
_ => panic!("Unsupported syscall ID: {}", syscall_num),
};
return r;

View File

@ -64,7 +64,7 @@ QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
# E1000E
#QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -net nic,model=e1000e,netdev=hostnet0,id=net0 -netdev user,id=hostnet1,hostfwd=tcp::12581-:12581 -device virtio-net-pci,vectors=5,netdev=hostnet1,id=net1 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
QEMU_ARGUMENT="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d -monitor ${QEMU_MONITOR} -d ${qemu_trace_std} "
QEMU_ARGUMENT+="-s -S -enable-kvm -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}"