11use crate :: apic;
22use crate :: emulate;
33use crate :: error:: { self , Error , Result } ;
4+ use crate :: interrupt;
5+ use crate :: ioapic;
46use crate :: memory:: Raw4kPage ;
57use crate :: percore;
68use crate :: registers:: { GdtrBase , IdtrBase } ;
@@ -33,14 +35,11 @@ pub fn mp_entry_point() -> ! {
3335 }
3436
3537 let vm = unsafe {
36- vm:: VM_MAP
37- . as_ref ( )
38- . unwrap ( )
39- . get ( & apic:: get_local_apic ( ) . id ( ) )
40- . expect ( "Failed to find VM for core" )
41- . clone ( )
38+ let id = apic:: get_local_apic ( ) . id ( ) ;
39+ vm:: get_vm_for_apic_id ( id)
40+ . expect ( & format ! ( "Failed to find VM associated with 0x{:x}" , id) )
4241 } ;
43- let vcpu = VCpu :: new ( vm. clone ( ) ) . expect ( "Failed to create vcpu" ) ;
42+ let vcpu = VCpu :: new ( vm) . expect ( "Failed to create vcpu" ) ;
4443 vcpu. launch ( ) . expect ( "Failed to launch vm" )
4544}
4645
@@ -507,17 +506,26 @@ impl VCpu {
507506 vmexit:: ExitInformation :: InterruptWindow => { }
508507 vmexit:: ExitInformation :: ExternalInterrupt ( info) => unsafe {
509508 match info. vector {
510- 0x24 => self . handle_uart_keypress ( & mut responses) ?,
509+ interrupt:: UART_VECTOR => {
510+ self . handle_uart_keypress ( & mut responses) ?
511+ }
512+ interrupt:: IPC_VECTOR => {
513+ let msg =
514+ vm:: recv_vm_msg ( ) . ok_or_else ( || Error :: NotFound ) ?;
515+ match msg {
516+ vm:: VirtualMachineMsg :: GrantConsole ( serial) => {
517+ let mut vm = self . vm . write ( ) ;
518+ vm. config . physical_devices_mut ( ) . serial =
519+ Some ( serial) ;
520+ }
521+ }
522+ }
511523 _ => ( ) ,
512524 }
513525
514- // Ack the interrupt via PIC or APIC based on the vector
515- if info. vector < 48 {
516- //TODO: this should be a call to the physical PIC
517- x86:: io:: outb ( 0x20 , 0x20 ) ;
518- } else {
519- apic:: get_local_apic_mut ( ) . eoi ( ) ;
520- }
526+ // We don't use the PIC, so any interrupt must be ACKed through
527+ // the local apic
528+ apic:: get_local_apic_mut ( ) . eoi ( ) ;
521529 } ,
522530 _ => {
523531 info ! ( "{}" , self . vmcs) ;
@@ -530,6 +538,38 @@ impl VCpu {
530538 virtdev:: DeviceEventResponse :: Interrupt ( ( vector, kind) ) => {
531539 self . inject_interrupt ( vector, kind) ;
532540 }
541+ virtdev:: DeviceEventResponse :: NextConsole => {
542+ info ! ( "Received Ctrl-a three times. Switching console to next VM" ) ;
543+
544+ let mut vm = self . vm . write ( ) ;
545+ let serial = vm
546+ . config
547+ . physical_devices_mut ( )
548+ . serial
549+ . take ( )
550+ . ok_or_else ( || Error :: NotFound ) ?;
551+ let vmid = vm. id ;
552+ drop ( vm) ;
553+
554+ let next_vmid = ( vmid + 1 ) % vm:: max_vm_id ( ) ;
555+
556+ vm:: send_vm_msg (
557+ vm:: VirtualMachineMsg :: GrantConsole ( serial) ,
558+ next_vmid,
559+ ) ?;
560+
561+ //FIXME(alschwalm): this should use the vm's bsp apicid
562+ ioapic:: map_gsi_vector (
563+ 4 ,
564+ interrupt:: UART_VECTOR ,
565+ next_vmid as u8 ,
566+ )
567+ . map_err ( |_| {
568+ Error :: DeviceError (
569+ "Failed to update console GSI mapping" . into ( ) ,
570+ )
571+ } ) ?;
572+ }
533573 virtdev:: DeviceEventResponse :: GuestUartTransmitted ( val) => {
534574 let vm = self . vm . read ( ) ;
535575 if vm. config . physical_devices ( ) . serial . is_some ( ) {
0 commit comments