mirror of
https://github.com/mii443/nel_os.git
synced 2025-08-22 16:15:38 +00:00
wip: external interrupt
This commit is contained in:
@ -1,9 +1,147 @@
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use pic8259::ChainedPics;
|
use pic8259::ChainedPics;
|
||||||
|
use spin::Mutex;
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
use crate::{gdt, print, println};
|
use crate::{gdt, print, println};
|
||||||
|
|
||||||
|
/// Interrupt context containing interrupt information
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterruptContext {
|
||||||
|
pub vector: u8,
|
||||||
|
pub instruction_pointer: u64,
|
||||||
|
pub code_segment: u64,
|
||||||
|
pub cpu_flags: u64,
|
||||||
|
pub stack_pointer: u64,
|
||||||
|
pub stack_segment: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subscriber callback function type (simple callback without context)
|
||||||
|
pub type SubscriberCallback = fn(&InterruptContext);
|
||||||
|
|
||||||
|
/// Advanced subscriber callback with user context
|
||||||
|
pub type AdvancedSubscriberCallback = fn(*mut core::ffi::c_void, &InterruptContext);
|
||||||
|
|
||||||
|
/// Interrupt subscriber variants
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Subscriber {
|
||||||
|
Simple {
|
||||||
|
callback: SubscriberCallback,
|
||||||
|
},
|
||||||
|
Advanced {
|
||||||
|
callback: AdvancedSubscriberCallback,
|
||||||
|
context: *mut core::ffi::c_void,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety: We ensure thread safety by using Mutex to protect the subscribers array
|
||||||
|
unsafe impl Send for Subscriber {}
|
||||||
|
unsafe impl Sync for Subscriber {}
|
||||||
|
|
||||||
|
const MAX_SUBSCRIBERS: usize = 10;
|
||||||
|
|
||||||
|
/// Global subscribers array
|
||||||
|
static SUBSCRIBERS: Mutex<[Option<Subscriber>; MAX_SUBSCRIBERS]> =
|
||||||
|
Mutex::new([None; MAX_SUBSCRIBERS]);
|
||||||
|
|
||||||
|
/// Subscribe to interrupts with a callback function
|
||||||
|
pub fn subscribe(callback: SubscriberCallback) -> Result<(), &'static str> {
|
||||||
|
let mut subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for i in 0..MAX_SUBSCRIBERS {
|
||||||
|
if subscribers[i].is_none() {
|
||||||
|
subscribers[i] = Some(Subscriber::Simple { callback });
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err("Subscriber array full")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subscribe to interrupts with an advanced callback that receives user context
|
||||||
|
pub fn subscribe_with_context(
|
||||||
|
callback: AdvancedSubscriberCallback,
|
||||||
|
context: *mut core::ffi::c_void,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
|
let mut subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for i in 0..MAX_SUBSCRIBERS {
|
||||||
|
if subscribers[i].is_none() {
|
||||||
|
subscribers[i] = Some(Subscriber::Advanced { callback, context });
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err("Subscriber array full")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unsubscribe from interrupts
|
||||||
|
pub fn unsubscribe(callback: SubscriberCallback) -> Result<(), &'static str> {
|
||||||
|
let mut subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for i in 0..MAX_SUBSCRIBERS {
|
||||||
|
if let Some(subscriber) = subscribers[i] {
|
||||||
|
match subscriber {
|
||||||
|
Subscriber::Simple { callback: cb } => {
|
||||||
|
if cb as *const () == callback as *const () {
|
||||||
|
subscribers[i] = None;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {} // Skip advanced subscribers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err("Subscriber not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unsubscribe from interrupts (advanced callback with context)
|
||||||
|
pub fn unsubscribe_with_context(
|
||||||
|
callback: AdvancedSubscriberCallback,
|
||||||
|
context: *mut core::ffi::c_void,
|
||||||
|
) -> Result<(), &'static str> {
|
||||||
|
let mut subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for i in 0..MAX_SUBSCRIBERS {
|
||||||
|
if let Some(subscriber) = subscribers[i] {
|
||||||
|
match subscriber {
|
||||||
|
Subscriber::Advanced {
|
||||||
|
callback: cb,
|
||||||
|
context: ctx,
|
||||||
|
} => {
|
||||||
|
if cb as *const () == callback as *const () && ctx == context {
|
||||||
|
subscribers[i] = None;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {} // Skip simple subscribers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err("Subscriber not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dispatch interrupt to all subscribers
|
||||||
|
fn dispatch_to_subscribers(context: &InterruptContext) {
|
||||||
|
let subscribers = SUBSCRIBERS.lock();
|
||||||
|
|
||||||
|
for subscriber in subscribers.iter().flatten() {
|
||||||
|
match subscriber {
|
||||||
|
Subscriber::Simple { callback } => {
|
||||||
|
callback(context);
|
||||||
|
}
|
||||||
|
Subscriber::Advanced {
|
||||||
|
callback,
|
||||||
|
context: user_context,
|
||||||
|
} => {
|
||||||
|
callback(*user_context, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref IDT: InterruptDescriptorTable = {
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
@ -28,6 +166,18 @@ pub fn init_idt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: 3, // Breakpoint exception vector
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment,
|
||||||
|
cpu_flags: stack_frame.cpu_flags,
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Notify subscribers first
|
||||||
|
dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +189,18 @@ extern "x86-interrupt" fn double_fault_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStackFrame) {
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: 6, // Invalid opcode exception vector
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment,
|
||||||
|
cpu_flags: stack_frame.cpu_flags,
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Notify subscribers first
|
||||||
|
dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
panic!("EXCEPTION: INVALID OPCODE\n{:#?}", stack_frame);
|
panic!("EXCEPTION: INVALID OPCODE\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +213,18 @@ extern "x86-interrupt" fn page_fault_handler(
|
|||||||
) {
|
) {
|
||||||
use x86_64::registers::control::Cr2;
|
use x86_64::registers::control::Cr2;
|
||||||
|
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: 14, // Page fault exception vector
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment,
|
||||||
|
cpu_flags: stack_frame.cpu_flags,
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Notify subscribers first
|
||||||
|
dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
println!("EXCEPTION: PAGE FAULT");
|
println!("EXCEPTION: PAGE FAULT");
|
||||||
println!("Accessed Address: {:?}", Cr2::read());
|
println!("Accessed Address: {:?}", Cr2::read());
|
||||||
println!("Error Code: {:?}", error_code);
|
println!("Error Code: {:?}", error_code);
|
||||||
@ -81,18 +255,43 @@ impl InterruptIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer_interrupt_handler(stack_frame: InterruptStackFrame) {
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: InterruptIndex::Timer.as_u8(),
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment,
|
||||||
|
cpu_flags: stack_frame.cpu_flags,
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Notify subscribers first
|
||||||
|
dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
|
// Then handle the interrupt normally
|
||||||
unsafe {
|
unsafe {
|
||||||
PICS.lock()
|
PICS.lock()
|
||||||
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn keyboard_interrupt_handler(stack_frame: InterruptStackFrame) {
|
||||||
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
|
let context = InterruptContext {
|
||||||
|
vector: InterruptIndex::Keyboard.as_u8(),
|
||||||
|
instruction_pointer: stack_frame.instruction_pointer.as_u64(),
|
||||||
|
code_segment: stack_frame.code_segment,
|
||||||
|
cpu_flags: stack_frame.cpu_flags,
|
||||||
|
stack_pointer: stack_frame.stack_pointer.as_u64(),
|
||||||
|
stack_segment: stack_frame.stack_segment,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Notify subscribers first
|
||||||
|
dispatch_to_subscribers(&context);
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||||
Mutex::new(Keyboard::new(
|
Mutex::new(Keyboard::new(
|
||||||
@ -121,7 +320,56 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn example_subscriber(context: &InterruptContext) {
|
||||||
|
println!(
|
||||||
|
"Subscriber: Interrupt {} occurred at {:#x}",
|
||||||
|
context.vector, context.instruction_pointer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vmm_subscriber(vcpu_ptr: *mut core::ffi::c_void, context: &InterruptContext) {
|
||||||
|
if !vcpu_ptr.is_null() {
|
||||||
|
let vcpu = unsafe { &mut *(vcpu_ptr as *mut crate::vmm::vcpu::VCpu) };
|
||||||
|
|
||||||
|
if 0x20 <= context.vector && context.vector < 0x20 + 16 {
|
||||||
|
let irq = context.vector - 0x20;
|
||||||
|
vcpu.pending_irq |= 1 << irq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test_case]
|
#[test_case]
|
||||||
fn test_breakpoint_exception() {
|
fn test_breakpoint_exception() {
|
||||||
x86_64::instructions::interrupts::int3();
|
x86_64::instructions::interrupts::int3();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_subscriber_functionality() {
|
||||||
|
// Test subscribing to interrupts
|
||||||
|
let result = subscribe(example_subscriber);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
// Test that subscriber array has limits
|
||||||
|
for _ in 0..MAX_SUBSCRIBERS {
|
||||||
|
let _ = subscribe(example_subscriber);
|
||||||
|
}
|
||||||
|
// This should fail because the array is full
|
||||||
|
let result = subscribe(example_subscriber);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_advanced_subscriber_functionality() {
|
||||||
|
// Test subscribing with context
|
||||||
|
let vcpu_dummy = 0x12345678usize as *mut core::ffi::c_void;
|
||||||
|
let result = subscribe_with_context(vmm_subscriber, vcpu_dummy);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
// Test unsubscribing with context
|
||||||
|
let result = unsubscribe_with_context(vmm_subscriber, vcpu_dummy);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
// Unsubscribing again should fail
|
||||||
|
let result = unsubscribe_with_context(vmm_subscriber, vcpu_dummy);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
@ -11,6 +11,12 @@ extern crate alloc;
|
|||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
|
|
||||||
|
// Re-export commonly used interrupt functionality
|
||||||
|
pub use interrupts::{
|
||||||
|
subscribe, unsubscribe, subscribe_with_context, unsubscribe_with_context,
|
||||||
|
InterruptContext, SubscriberCallback, AdvancedSubscriberCallback
|
||||||
|
};
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod vga_buffer;
|
pub mod vga_buffer;
|
||||||
|
@ -6,6 +6,8 @@ pub struct Serial {
|
|||||||
pub mcr: u8,
|
pub mcr: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
||||||
pub enum InitPhase {
|
pub enum InitPhase {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
Phase1,
|
Phase1,
|
||||||
|
109
src/vmm/vcpu.rs
109
src/vmm/vcpu.rs
@ -1,4 +1,5 @@
|
|||||||
use core::{
|
use core::{
|
||||||
|
arch::asm,
|
||||||
arch::x86_64::{_xgetbv, _xsetbv},
|
arch::x86_64::{_xgetbv, _xsetbv},
|
||||||
convert::TryInto,
|
convert::TryInto,
|
||||||
u64, u8,
|
u64, u8,
|
||||||
@ -18,15 +19,17 @@ use x86_64::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
info,
|
hlt_loop, info,
|
||||||
|
interrupts::vmm_subscriber,
|
||||||
memory::BootInfoFrameAllocator,
|
memory::BootInfoFrameAllocator,
|
||||||
|
subscribe_with_context,
|
||||||
vmm::{
|
vmm::{
|
||||||
cpuid, cr, fpu,
|
cpuid, cr, fpu,
|
||||||
io::{self, Serial, PIC},
|
io::{self, InitPhase, Serial, PIC},
|
||||||
msr,
|
msr,
|
||||||
qual::{QualCr, QualIo},
|
qual::{QualCr, QualIo},
|
||||||
vmcs::{
|
vmcs::{
|
||||||
DescriptorType, EntryControls, Granularity, PrimaryExitControls,
|
DescriptorType, EntryControls, EntryIntrInfo, Granularity, PrimaryExitControls,
|
||||||
PrimaryProcessorBasedVmExecutionControls, SecondaryProcessorBasedVmExecutionControls,
|
PrimaryProcessorBasedVmExecutionControls, SecondaryProcessorBasedVmExecutionControls,
|
||||||
SegmentRights, VmxExitReason,
|
SegmentRights, VmxExitReason,
|
||||||
},
|
},
|
||||||
@ -61,6 +64,7 @@ pub struct VCpu {
|
|||||||
pub io_bitmap_a: x86_64::structures::paging::PhysFrame,
|
pub io_bitmap_a: x86_64::structures::paging::PhysFrame,
|
||||||
pub io_bitmap_b: x86_64::structures::paging::PhysFrame,
|
pub io_bitmap_b: x86_64::structures::paging::PhysFrame,
|
||||||
pub pic: PIC,
|
pub pic: PIC,
|
||||||
|
pub pending_irq: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TEMP_STACK_SIZE: usize = 4096;
|
const TEMP_STACK_SIZE: usize = 4096;
|
||||||
@ -95,6 +99,7 @@ impl VCpu {
|
|||||||
io_bitmap_a,
|
io_bitmap_a,
|
||||||
io_bitmap_b,
|
io_bitmap_b,
|
||||||
pic: PIC::new(),
|
pic: PIC::new(),
|
||||||
|
pending_irq: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,6 +310,7 @@ impl VCpu {
|
|||||||
|
|
||||||
pin_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
|
pin_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
|
||||||
pin_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
|
pin_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
|
||||||
|
pin_exec_ctrl.set_external_interrupt_exiting(true);
|
||||||
|
|
||||||
pin_exec_ctrl.write();
|
pin_exec_ctrl.write();
|
||||||
|
|
||||||
@ -320,7 +326,7 @@ impl VCpu {
|
|||||||
|
|
||||||
primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
|
primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
|
||||||
primary_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
|
primary_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
|
||||||
primary_exec_ctrl.set_hlt(true);
|
primary_exec_ctrl.set_hlt(false);
|
||||||
primary_exec_ctrl.set_activate_secondary_controls(true);
|
primary_exec_ctrl.set_activate_secondary_controls(true);
|
||||||
primary_exec_ctrl.set_use_tpr_shadow(true);
|
primary_exec_ctrl.set_use_tpr_shadow(true);
|
||||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
primary_exec_ctrl.set_use_msr_bitmap(false);
|
||||||
@ -658,6 +664,11 @@ impl VCpu {
|
|||||||
pub fn vm_loop(&mut self) -> ! {
|
pub fn vm_loop(&mut self) -> ! {
|
||||||
info!("Entering VM loop");
|
info!("Entering VM loop");
|
||||||
|
|
||||||
|
let vcpu: &mut VCpu = self;
|
||||||
|
let vcpu_ptr = vcpu as *mut VCpu as *mut core::ffi::c_void;
|
||||||
|
subscribe_with_context(vmm_subscriber, vcpu_ptr)
|
||||||
|
.expect("Failed to subscribe to vmm_subscriber");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Err(err) = self.vmentry() {
|
if let Err(err) = self.vmentry() {
|
||||||
info!("VMEntry failed: {}", err.as_str());
|
info!("VMEntry failed: {}", err.as_str());
|
||||||
@ -735,6 +746,73 @@ impl VCpu {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inject_external_interrupt(&mut self) -> Result<bool, VmFail> {
|
||||||
|
info!("Injecting external interrupt");
|
||||||
|
let pending = self.pending_irq;
|
||||||
|
|
||||||
|
if pending == 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.pic.primary_phase != InitPhase::Initialized {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let eflags = unsafe { vmread(vmcs::guest::RFLAGS) }?;
|
||||||
|
if eflags >> 9 & 1 == 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_secondary_masked = (self.pic.primary_mask >> 2) & 1 != 0;
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
if is_secondary_masked && i >= 8 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let irq_bit = 1 << i;
|
||||||
|
if pending & irq_bit == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = if i < 8 { i } else { i - 8 };
|
||||||
|
let is_masked = if i < 8 {
|
||||||
|
(self.pic.primary_mask >> delta) & 1 != 0
|
||||||
|
} else {
|
||||||
|
let is_ieq_masked = (self.pic.secondary_mask >> delta) & 1 != 0;
|
||||||
|
is_secondary_masked || is_ieq_masked
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_masked {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut interrupt_info = EntryIntrInfo(0);
|
||||||
|
interrupt_info.set_vector(
|
||||||
|
delta as u32
|
||||||
|
+ if i < 8 {
|
||||||
|
self.pic.primary_base as u32
|
||||||
|
} else {
|
||||||
|
self.pic.secondary_base as u32
|
||||||
|
},
|
||||||
|
);
|
||||||
|
interrupt_info.set_type(0);
|
||||||
|
interrupt_info.set_ec_available(false);
|
||||||
|
interrupt_info.set_valid(true);
|
||||||
|
unsafe {
|
||||||
|
vmwrite(
|
||||||
|
vmcs::control::VMENTRY_INTERRUPTION_INFO_FIELD,
|
||||||
|
interrupt_info.0 as u64,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pending_irq &= !irq_bit;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn set_host_stack(rsp: u64) {
|
unsafe extern "C" fn set_host_stack(rsp: u64) {
|
||||||
vmwrite(vmcs::host::RSP, rsp).unwrap();
|
vmwrite(vmcs::host::RSP, rsp).unwrap();
|
||||||
@ -773,7 +851,19 @@ impl VCpu {
|
|||||||
let exit_reason: VmxExitReason = basic_reason.try_into().unwrap();
|
let exit_reason: VmxExitReason = basic_reason.try_into().unwrap();
|
||||||
match exit_reason {
|
match exit_reason {
|
||||||
VmxExitReason::HLT => {
|
VmxExitReason::HLT => {
|
||||||
info!("HLT instruction executed");
|
while self.inject_external_interrupt().is_err() {
|
||||||
|
unsafe {
|
||||||
|
asm!("sti");
|
||||||
|
asm!("nop");
|
||||||
|
asm!("cli");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
vmwrite(vmcs::guest::ACTIVITY_STATE, 0).unwrap();
|
||||||
|
vmwrite(vmcs::guest::INTERRUPTIBILITY_STATE, 0).unwrap();
|
||||||
|
}
|
||||||
|
self.step_next_inst().unwrap();
|
||||||
}
|
}
|
||||||
VmxExitReason::CPUID => {
|
VmxExitReason::CPUID => {
|
||||||
cpuid::handle_cpuid_exit(self);
|
cpuid::handle_cpuid_exit(self);
|
||||||
@ -812,6 +902,15 @@ impl VCpu {
|
|||||||
io::handle_io(self, qual_io);
|
io::handle_io(self, qual_io);
|
||||||
self.step_next_inst().unwrap();
|
self.step_next_inst().unwrap();
|
||||||
}
|
}
|
||||||
|
VmxExitReason::EXTERNAL_INTERRUPT => {
|
||||||
|
unsafe {
|
||||||
|
asm!("sti");
|
||||||
|
asm!("nop");
|
||||||
|
asm!("cli");
|
||||||
|
}
|
||||||
|
self.inject_external_interrupt().unwrap();
|
||||||
|
self.step_next_inst().unwrap();
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("VMExit reason: {:?}", exit_reason);
|
panic!("VMExit reason: {:?}", exit_reason);
|
||||||
}
|
}
|
||||||
|
@ -653,3 +653,38 @@ impl VmxLeaf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub const EntryIntrInfo = packed struct(u32) {
|
||||||
|
vector: u8,
|
||||||
|
type: Type,
|
||||||
|
ec_available: bool,
|
||||||
|
_notused: u19 = 0,
|
||||||
|
valid: bool,
|
||||||
|
|
||||||
|
const Type = enum(u3) {
|
||||||
|
external = 0,
|
||||||
|
_unused1 = 1,
|
||||||
|
nmi = 2,
|
||||||
|
hw = 3,
|
||||||
|
_unused2 = 4,
|
||||||
|
priviledged_sw = 5,
|
||||||
|
exception = 6,
|
||||||
|
_unused3 = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Kind = enum {
|
||||||
|
entry,
|
||||||
|
exit,
|
||||||
|
};
|
||||||
|
}; */
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct EntryIntrInfo(u32);
|
||||||
|
impl Debug;
|
||||||
|
|
||||||
|
pub vector, set_vector: 7, 0;
|
||||||
|
pub typ, set_type: 10, 8;
|
||||||
|
pub ec_available, set_ec_available: 11;
|
||||||
|
pub valid, set_valid: 31;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user