mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 02:55:45 +00:00
vmm: cpu: Implement CPU removal
When the running OS has been told that a CPU should be removed it will shutdown the CPU and then signal to the hypervisor via the "_EJ0" method on the device that ultimately writes into an I/O port than the vCPU should be shutdown. Upon notification the hypervisor signals to the individual thread that it should shutdown and waits for that thread to end. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
7b3fc72aea
commit
a6878accd5
@ -390,6 +390,7 @@ pub struct CpuManager {
|
|||||||
const CPU_ENABLE_FLAG: usize = 0;
|
const CPU_ENABLE_FLAG: usize = 0;
|
||||||
const CPU_INSERTING_FLAG: usize = 1;
|
const CPU_INSERTING_FLAG: usize = 1;
|
||||||
const CPU_REMOVING_FLAG: usize = 2;
|
const CPU_REMOVING_FLAG: usize = 2;
|
||||||
|
const CPU_EJECT_FLAG: usize = 3;
|
||||||
|
|
||||||
const CPU_STATUS_OFFSET: u64 = 4;
|
const CPU_STATUS_OFFSET: u64 = 4;
|
||||||
const CPU_SELECTION_OFFSET: u64 = 0;
|
const CPU_SELECTION_OFFSET: u64 = 0;
|
||||||
@ -438,6 +439,12 @@ impl BusDevice for CpuManager {
|
|||||||
{
|
{
|
||||||
state.removing = false;
|
state.removing = false;
|
||||||
}
|
}
|
||||||
|
// Trigger removal of vCPU
|
||||||
|
if data[0] & (1 << CPU_EJECT_FLAG) == 1 << CPU_EJECT_FLAG {
|
||||||
|
if let Err(e) = self.remove_vcpu(self.selected_cpu) {
|
||||||
|
error!("Error removing vCPU: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!(
|
warn!(
|
||||||
@ -454,6 +461,7 @@ struct VcpuState {
|
|||||||
inserting: bool,
|
inserting: bool,
|
||||||
removing: bool,
|
removing: bool,
|
||||||
handle: Option<thread::JoinHandle<()>>,
|
handle: Option<thread::JoinHandle<()>>,
|
||||||
|
kill: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VcpuState {
|
impl VcpuState {
|
||||||
@ -568,6 +576,7 @@ impl CpuManager {
|
|||||||
let vcpu_kill_signalled = self.vcpus_kill_signalled.clone();
|
let vcpu_kill_signalled = self.vcpus_kill_signalled.clone();
|
||||||
let vcpu_pause_signalled = self.vcpus_pause_signalled.clone();
|
let vcpu_pause_signalled = self.vcpus_pause_signalled.clone();
|
||||||
|
|
||||||
|
let vcpu_kill = self.vcpu_states[usize::from(cpu_id)].kill.clone();
|
||||||
let vm_memory = self.vm_memory.clone();
|
let vm_memory = self.vm_memory.clone();
|
||||||
let cpuid = self.cpuid.clone();
|
let cpuid = self.cpuid.clone();
|
||||||
|
|
||||||
@ -601,7 +610,9 @@ impl CpuManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We've been told to terminate
|
// We've been told to terminate
|
||||||
if vcpu_kill_signalled.load(Ordering::SeqCst) {
|
if vcpu_kill_signalled.load(Ordering::SeqCst)
|
||||||
|
|| vcpu_kill.load(Ordering::SeqCst)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,6 +650,15 @@ impl CpuManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_vcpu(&mut self, cpu_id: u8) -> Result<()> {
|
||||||
|
let mut state = &mut self.vcpu_states[usize::from(cpu_id)];
|
||||||
|
state.kill.store(true, Ordering::SeqCst);
|
||||||
|
state.signal_thread();
|
||||||
|
state.join_thread()?;
|
||||||
|
state.handle = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Starts all the vCPUs that the VM is booting with. Blocks until all vCPUs are running.
|
// Starts all the vCPUs that the VM is booting with. Blocks until all vCPUs are running.
|
||||||
pub fn start_boot_vcpus(&mut self, entry_addr: GuestAddress) -> Result<()> {
|
pub fn start_boot_vcpus(&mut self, entry_addr: GuestAddress) -> Result<()> {
|
||||||
self.activate_vcpus(self.boot_vcpus(), Some(entry_addr))
|
self.activate_vcpus(self.boot_vcpus(), Some(entry_addr))
|
||||||
@ -781,6 +801,17 @@ impl Aml for CPU {
|
|||||||
// containing the LAPIC for this processor with the enabled bit set
|
// containing the LAPIC for this processor with the enabled bit set
|
||||||
// even it if is disabled in the MADT (non-boot CPU)
|
// even it if is disabled in the MADT (non-boot CPU)
|
||||||
&aml::Name::new("_MAT".into(), &aml::Buffer::new(mat_data)),
|
&aml::Name::new("_MAT".into(), &aml::Buffer::new(mat_data)),
|
||||||
|
// Trigger CPU ejection
|
||||||
|
&aml::Method::new(
|
||||||
|
"_EJ0".into(),
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
// Call into CEJ0 method which will actually eject device
|
||||||
|
vec![&aml::Return::new(&aml::MethodCall::new(
|
||||||
|
"CEJ0".into(),
|
||||||
|
vec![&self.cpu_id],
|
||||||
|
))],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.to_aml_bytes()
|
.to_aml_bytes()
|
||||||
@ -851,6 +882,23 @@ impl Aml for CPUMethods {
|
|||||||
&aml::Method::new("CTFY".into(), 2, true, cpu_notifies_refs).to_aml_bytes(),
|
&aml::Method::new("CTFY".into(), 2, true, cpu_notifies_refs).to_aml_bytes(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bytes.extend_from_slice(
|
||||||
|
&aml::Method::new(
|
||||||
|
"CEJ0".into(),
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
vec![
|
||||||
|
&aml::Acquire::new("\\_SB_.PRES.CPLK".into(), 0xfff),
|
||||||
|
// Write CPU number (in first argument) to I/O port via field
|
||||||
|
&aml::Store::new(&aml::Path::new("\\_SB_.PRES.CSEL"), &aml::Arg(0)),
|
||||||
|
// Set CEJ0 bit
|
||||||
|
&aml::Store::new(&aml::Path::new("\\_SB_.PRES.CEJ0"), &aml::ONE),
|
||||||
|
&aml::Release::new("\\_SB_.PRES.CPLK".into()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.to_aml_bytes(),
|
||||||
|
);
|
||||||
|
|
||||||
bytes.extend_from_slice(
|
bytes.extend_from_slice(
|
||||||
&aml::Method::new(
|
&aml::Method::new(
|
||||||
"CSCN".into(),
|
"CSCN".into(),
|
||||||
|
Loading…
Reference in New Issue
Block a user