Changes to allow for detection and init of ASPs
This commit is contained in:
		
							parent
							
								
									7b2acdd79c
								
							
						
					
					
						commit
						08900d56c8
					
				
					 9 changed files with 343 additions and 48 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -10,7 +10,7 @@ bochs: build/harddrive.bin | |||
| 	bochs -f bochs.$(ARCH) | ||||
| 
 | ||||
| qemu: build/harddrive.bin | ||||
| 	qemu-system-$(ARCH) -enable-kvm -cpu host -machine q35 \
 | ||||
| 	qemu-system-$(ARCH) -enable-kvm -cpu host -smp 4 -machine q35 \
 | ||||
| 				-serial mon:stdio -drive file=$<,format=raw,index=0,media=disk \
 | ||||
| 				-nographic -d guest_errors | ||||
| 				#-device intel-iommu | ||||
|  |  | |||
							
								
								
									
										51
									
								
								arch/x86_64/src/acpi/local_apic.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								arch/x86_64/src/acpi/local_apic.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | |||
| use x86::msr::*; | ||||
| 
 | ||||
| bitflags! { | ||||
|     pub flags LocalApicIcr: u64 { | ||||
|         const ICR_VECTOR = 0xFF, | ||||
| 
 | ||||
|         const ICR_FIXED = 0b000 << 8, | ||||
|         const ICR_SMI = 0b010 << 8, | ||||
|         const ICR_NMI = 0b100 << 8, | ||||
|         const ICR_INIT = 0b101 << 8, | ||||
|         const ICR_START = 0b110 << 8, | ||||
| 
 | ||||
|         const ICR_PHYSICAL = 0 << 11, | ||||
|         const ICR_LOGICAL = 1 << 11, | ||||
| 
 | ||||
|         const ICR_DEASSERT = 0 << 14, | ||||
|         const ICR_ASSERT = 1 << 14, | ||||
| 
 | ||||
|         const ICR_EDGE = 0 << 15, | ||||
|         const ICR_LEVEL = 1 << 15, | ||||
| 
 | ||||
|         const ICR_DESTINATION = 0b1111 << 56, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Local APIC
 | ||||
| #[repr(packed)] | ||||
| pub struct LocalApic; | ||||
| 
 | ||||
| impl LocalApic { | ||||
|     pub fn new() -> Self { | ||||
|         unsafe { wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10) } | ||||
|         LocalApic | ||||
|     } | ||||
| 
 | ||||
|     pub fn id(&self) -> u32 { | ||||
|         unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } | ||||
|     } | ||||
| 
 | ||||
|     pub fn version(&self) -> u32 { | ||||
|         unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } | ||||
|     } | ||||
| 
 | ||||
|     pub fn icr(&self) -> u64 { | ||||
|         unsafe { rdmsr(IA32_X2APIC_ICR) } | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_icr(&mut self, value: u64) { | ||||
|         unsafe { wrmsr(IA32_X2APIC_ICR, value) } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										133
									
								
								arch/x86_64/src/acpi/madt.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								arch/x86_64/src/acpi/madt.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,133 @@ | |||
| use core::mem; | ||||
| 
 | ||||
| use super::sdt::Sdt; | ||||
| 
 | ||||
| /// The Multiple APIC Descriptor Table
 | ||||
| #[derive(Debug)] | ||||
| pub struct Madt { | ||||
|     sdt: &'static Sdt, | ||||
|     pub local_address: u32, | ||||
|     pub flags: u32 | ||||
| } | ||||
| 
 | ||||
| impl Madt { | ||||
|     pub fn new(sdt: &'static Sdt) -> Option<Madt> { | ||||
|         if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags
 | ||||
|             let local_address = unsafe { *(sdt.data_address() as *const u32) }; | ||||
|             let flags = unsafe { *(sdt.data_address() as *const u32).offset(1) }; | ||||
| 
 | ||||
|             Some(Madt { | ||||
|                 sdt: sdt, | ||||
|                 local_address: local_address, | ||||
|                 flags: flags | ||||
|             }) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn iter(&self) -> MadtIter { | ||||
|         MadtIter { | ||||
|             sdt: self.sdt, | ||||
|             i: 8 // Skip local controller address and flags
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ///
 | ||||
| 
 | ||||
| /// MADT Local APIC
 | ||||
| #[derive(Debug)] | ||||
| #[repr(packed)] | ||||
| pub struct MadtLocalApic { | ||||
|     /// Processor ID
 | ||||
|     pub processor: u8, | ||||
|     /// Local APIC ID
 | ||||
|     pub id: u8, | ||||
|     /// Flags. 1 means that the processor is enabled
 | ||||
|     pub flags: u32 | ||||
| } | ||||
| 
 | ||||
| /// MADT I/O APIC
 | ||||
| #[derive(Debug)] | ||||
| #[repr(packed)] | ||||
| pub struct MadtIoApic { | ||||
|     /// I/O APIC ID
 | ||||
|     pub id: u8, | ||||
|     /// reserved
 | ||||
|     reserved: u8, | ||||
|     /// I/O APIC address
 | ||||
|     pub address: u32, | ||||
|     /// Global system interrupt base
 | ||||
|     pub gsi_base: u32 | ||||
| } | ||||
| 
 | ||||
| /// MADT Interrupt Source Override
 | ||||
| #[derive(Debug)] | ||||
| #[repr(packed)] | ||||
| pub struct MadtIntSrcOverride { | ||||
|     /// Bus Source
 | ||||
|     pub bus_source: u8, | ||||
|     /// IRQ Source
 | ||||
|     pub irq_source: u8, | ||||
|     /// Global system interrupt base
 | ||||
|     pub gsi_base: u32, | ||||
|     /// Flags
 | ||||
|     pub flags: u16 | ||||
| } | ||||
| 
 | ||||
| /// MADT Entries
 | ||||
| #[derive(Debug)] | ||||
| pub enum MadtEntry { | ||||
|     LocalApic(&'static MadtLocalApic), | ||||
|     InvalidLocalApic(usize), | ||||
|     IoApic(&'static MadtIoApic), | ||||
|     InvalidIoApic(usize), | ||||
|     IntSrcOverride(&'static MadtIntSrcOverride), | ||||
|     InvalidIntSrcOverride(usize), | ||||
|     Unknown | ||||
| } | ||||
| 
 | ||||
| pub struct MadtIter { | ||||
|     sdt: &'static Sdt, | ||||
|     i: usize | ||||
| } | ||||
| 
 | ||||
| impl Iterator for MadtIter { | ||||
|     type Item = MadtEntry; | ||||
|     fn next(&mut self) -> Option<Self::Item> { | ||||
|         if self.i + 1 < self.sdt.data_len() { | ||||
|             let entry_type = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize) }; | ||||
|             let entry_len = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize + 1) } as usize; | ||||
| 
 | ||||
|             if self.i + entry_len <= self.sdt.data_len() { | ||||
|                 let item = match entry_type { | ||||
|                     0 => if entry_len == mem::size_of::<MadtLocalApic>() + 2 { | ||||
|                         MadtEntry::LocalApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalApic) }) | ||||
|                     } else { | ||||
|                         MadtEntry::InvalidLocalApic(entry_len) | ||||
|                     }, | ||||
|                     1 => if entry_len == mem::size_of::<MadtIoApic>() + 2 { | ||||
|                         MadtEntry::IoApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIoApic) }) | ||||
|                     } else { | ||||
|                         MadtEntry::InvalidIoApic(entry_len) | ||||
|                     }, | ||||
|                     2 => if entry_len == mem::size_of::<MadtIntSrcOverride>() + 2 { | ||||
|                         MadtEntry::IntSrcOverride(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIntSrcOverride) }) | ||||
|                     } else { | ||||
|                         MadtEntry::InvalidIntSrcOverride(entry_len) | ||||
|                     }, | ||||
|                     _ => MadtEntry::Unknown | ||||
|                 }; | ||||
| 
 | ||||
|                 self.i += entry_len; | ||||
| 
 | ||||
|                 Some(item) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -4,18 +4,74 @@ | |||
| use memory::{Frame, FrameAllocator}; | ||||
| use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; | ||||
| 
 | ||||
| use self::rsdt::RSDT; | ||||
| use self::sdt::SDT; | ||||
| use self::xsdt::XSDT; | ||||
| use self::local_apic::{LocalApic, LocalApicIcr}; | ||||
| use self::madt::{Madt, MadtEntry}; | ||||
| use self::rsdt::Rsdt; | ||||
| use self::sdt::Sdt; | ||||
| use self::xsdt::Xsdt; | ||||
| 
 | ||||
| pub mod local_apic; | ||||
| pub mod madt; | ||||
| pub mod rsdt; | ||||
| pub mod sdt; | ||||
| pub mod xsdt; | ||||
| 
 | ||||
| pub fn init_sdt(sdt: &'static Sdt) { | ||||
|     print!("  "); | ||||
|     for &c in sdt.signature.iter() { | ||||
|         print!("{}", c as char); | ||||
|     } | ||||
|     println!(":"); | ||||
| 
 | ||||
|     if let Some(madt) = Madt::new(sdt) { | ||||
|         println!("    {:>016X}: {}", madt.local_address, madt.flags); | ||||
| 
 | ||||
|         let mut local_apic = LocalApic::new(); | ||||
| 
 | ||||
|         let me = local_apic.id() as u8; | ||||
| 
 | ||||
|         for madt_entry in madt.iter() { | ||||
|             println!("      {:?}", madt_entry); | ||||
|             match madt_entry { | ||||
|                 MadtEntry::LocalApic(asp_local_apic) => if asp_local_apic.id == me { | ||||
|                     println!("        This is my local APIC"); | ||||
|                 } else { | ||||
|                     if asp_local_apic.flags & 1 == 1 { | ||||
|                         { | ||||
|                             let icr = 0x00004500 | (asp_local_apic.id as u64) << 32; | ||||
|                             println!("        Sending IPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr)); | ||||
|                             local_apic.set_icr(icr); | ||||
|                         } | ||||
|                         { | ||||
|                             let icr = 0x00004600 | (asp_local_apic.id as u64) << 32; | ||||
|                             println!("        Sending SIPI to {}: {:>016X} {:?}", asp_local_apic.id, icr, LocalApicIcr::from_bits(icr)); | ||||
|                             local_apic.set_icr(icr); | ||||
|                         } | ||||
|                     } else { | ||||
|                         println!("        CPU Disabled"); | ||||
|                     } | ||||
|                 }, | ||||
|                 _ => () | ||||
|             } | ||||
|         } | ||||
|     }else { | ||||
|         println!("    {:?}", sdt); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Parse the ACPI tables to gather CPU, interrupt, and timer information
 | ||||
| pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> Option<Acpi> | ||||
|     where A: FrameAllocator | ||||
| { | ||||
|     // Stupidity of enormous proportion. Write the halt opcode to the 0'th physical address
 | ||||
|     // so that START IPI's can halt the processor
 | ||||
|     { | ||||
|         if active_table.translate_page(Page::containing_address(VirtualAddress::new(0))).is_none() { | ||||
|             active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0)), entry::PRESENT | entry::WRITABLE, allocator); | ||||
|         } | ||||
|         unsafe { *(0 as *mut u8) = 0xF4 }; | ||||
|     } | ||||
| 
 | ||||
|     let start_addr = 0xE0000; | ||||
|     let end_addr = 0xFFFFF; | ||||
| 
 | ||||
|  | @ -34,12 +90,12 @@ pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> | |||
|     if let Some(rsdp) = RSDP::search(start_addr, end_addr) { | ||||
|         println!("{:?}", rsdp); | ||||
| 
 | ||||
|         let mut get_sdt = |sdt_address: usize| -> &'static SDT { | ||||
|         let mut get_sdt = |sdt_address: usize| -> &'static Sdt { | ||||
|             if active_table.translate_page(Page::containing_address(VirtualAddress::new(sdt_address))).is_none() { | ||||
|                 let sdt_frame = Frame::containing_address(PhysicalAddress::new(sdt_address)); | ||||
|                 active_table.identity_map(sdt_frame, entry::PRESENT | entry::NO_EXECUTE, allocator); | ||||
|             } | ||||
|             unsafe { &*(sdt_address as *const SDT) } | ||||
|             &*(sdt_address as *const Sdt) | ||||
|         }; | ||||
| 
 | ||||
|         let rxsdt = get_sdt(rsdp.sdt_address()); | ||||
|  | @ -48,25 +104,13 @@ pub unsafe fn init<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> | |||
|             print!("{}", c as char); | ||||
|         } | ||||
|         println!(":"); | ||||
|         if let Some(rsdt) = RSDT::new(rxsdt) { | ||||
|             println!("{:?}", rsdt); | ||||
|         if let Some(rsdt) = Rsdt::new(rxsdt) { | ||||
|             for sdt_address in rsdt.iter() { | ||||
|                 let sdt = get_sdt(sdt_address); | ||||
|                 for &c in sdt.signature.iter() { | ||||
|                     print!("{}", c as char); | ||||
|                 } | ||||
|                 println!(":"); | ||||
|                 println!("{:?}", sdt); | ||||
|                 init_sdt(get_sdt(sdt_address)); | ||||
|             } | ||||
|         } else if let Some(xsdt) = XSDT::new(rxsdt) { | ||||
|             println!("{:?}", xsdt); | ||||
|         } else if let Some(xsdt) = Xsdt::new(rxsdt) { | ||||
|             for sdt_address in xsdt.iter() { | ||||
|                 let sdt = get_sdt(sdt_address); | ||||
|                 for &c in sdt.signature.iter() { | ||||
|                     print!("{}", c as char); | ||||
|                 } | ||||
|                 println!(":"); | ||||
|                 println!("{:?}", sdt); | ||||
|                 init_sdt(get_sdt(sdt_address)); | ||||
|             } | ||||
|         } else { | ||||
|             println!("UNKNOWN RSDT OR XSDT SIGNATURE"); | ||||
|  | @ -99,7 +143,7 @@ impl RSDP { | |||
|     /// Search for the RSDP
 | ||||
|     pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> { | ||||
|         for i in 0 .. (end_addr + 1 - start_addr)/16 { | ||||
|             let mut rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) }; | ||||
|             let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) }; | ||||
|             if &rsdp.signature == b"RSD PTR " { | ||||
|                 return Some(*rsdp); | ||||
|             } | ||||
|  |  | |||
|  | @ -1,33 +1,33 @@ | |||
| use core::mem; | ||||
| 
 | ||||
| use super::sdt::SDT; | ||||
| use super::sdt::Sdt; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct RSDT(&'static SDT); | ||||
| pub struct Rsdt(&'static Sdt); | ||||
| 
 | ||||
| impl RSDT { | ||||
|     pub fn new(sdt: &'static SDT) -> Option<RSDT> { | ||||
| impl Rsdt { | ||||
|     pub fn new(sdt: &'static Sdt) -> Option<Rsdt> { | ||||
|         if &sdt.signature == b"RSDT" { | ||||
|             Some(RSDT(sdt)) | ||||
|             Some(Rsdt(sdt)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn iter(&self) -> RSDTIter { | ||||
|         RSDTIter { | ||||
|     pub fn iter(&self) -> RsdtIter { | ||||
|         RsdtIter { | ||||
|             sdt: self.0, | ||||
|             i: 0 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct RSDTIter { | ||||
|     sdt: &'static SDT, | ||||
| pub struct RsdtIter { | ||||
|     sdt: &'static Sdt, | ||||
|     i: usize | ||||
| } | ||||
| 
 | ||||
| impl Iterator for RSDTIter { | ||||
| impl Iterator for RsdtIter { | ||||
|     type Item = usize; | ||||
|     fn next(&mut self) -> Option<Self::Item> { | ||||
|         if self.i < self.sdt.data_len()/mem::size_of::<u32>() { | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ use core::mem; | |||
| 
 | ||||
| #[derive(Copy, Clone, Debug)] | ||||
| #[repr(packed)] | ||||
| pub struct SDT { | ||||
| pub struct Sdt { | ||||
|   pub signature: [u8; 4], | ||||
|   pub length: u32, | ||||
|   pub revision: u8, | ||||
|  | @ -14,16 +14,16 @@ pub struct SDT { | |||
|   pub creator_revision: u32 | ||||
| } | ||||
| 
 | ||||
| impl SDT { | ||||
| impl Sdt { | ||||
|     /// Get the address of this tables data
 | ||||
|     pub fn data_address(&'static self) -> usize { | ||||
|         self as *const _ as usize + mem::size_of::<SDT>() | ||||
|         self as *const _ as usize + mem::size_of::<Sdt>() | ||||
|     } | ||||
| 
 | ||||
|     /// Get the length of this tables data
 | ||||
|     pub fn data_len(&'static self) -> usize { | ||||
|         let total_size = self.length as usize; | ||||
|         let header_size = mem::size_of::<SDT>(); | ||||
|         let header_size = mem::size_of::<Sdt>(); | ||||
|         if total_size >= header_size { | ||||
|             total_size - header_size | ||||
|         } else { | ||||
|  |  | |||
|  | @ -1,33 +1,33 @@ | |||
| use core::mem; | ||||
| 
 | ||||
| use super::sdt::SDT; | ||||
| use super::sdt::Sdt; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct XSDT(&'static SDT); | ||||
| pub struct Xsdt(&'static Sdt); | ||||
| 
 | ||||
| impl XSDT { | ||||
|     pub fn new(sdt: &'static SDT) -> Option<XSDT> { | ||||
| impl Xsdt { | ||||
|     pub fn new(sdt: &'static Sdt) -> Option<Xsdt> { | ||||
|         if &sdt.signature == b"XSDT" { | ||||
|             Some(XSDT(sdt)) | ||||
|             Some(Xsdt(sdt)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn iter(&self) -> XSDTIter { | ||||
|         XSDTIter { | ||||
|     pub fn iter(&self) -> XsdtIter { | ||||
|         XsdtIter { | ||||
|             sdt: self.0, | ||||
|             i: 0 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct XSDTIter { | ||||
|     sdt: &'static SDT, | ||||
| pub struct XsdtIter { | ||||
|     sdt: &'static Sdt, | ||||
|     i: usize | ||||
| } | ||||
| 
 | ||||
| impl Iterator for XSDTIter { | ||||
| impl Iterator for XsdtIter { | ||||
|     type Item = usize; | ||||
|     fn next(&mut self) -> Option<Self::Item> { | ||||
|         if self.i < self.sdt.data_len()/mem::size_of::<u64>() { | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| use core::mem; | ||||
| 
 | ||||
| use interrupt::halt; | ||||
| 
 | ||||
| pub static mut IDTR: IdtDescriptor = IdtDescriptor { | ||||
|     size: 0, | ||||
|     offset: 0 | ||||
|  | @ -12,6 +14,8 @@ pub unsafe fn init() { | |||
|         entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT); | ||||
|         entry.set_offset(8, exception as usize); | ||||
|     } | ||||
|     IDT[13].set_offset(8, protection_fault as usize); | ||||
|     IDT[14].set_offset(8, page_fault as usize); | ||||
|     for entry in IDT[32..].iter_mut() { | ||||
|         entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT); | ||||
|         entry.set_offset(8, blank as usize); | ||||
|  | @ -26,7 +30,24 @@ interrupt!(blank, { | |||
| }); | ||||
| 
 | ||||
| interrupt!(exception, { | ||||
|     panic!("EXCEPTION"); | ||||
|     println!("EXCEPTION"); | ||||
|     loop { | ||||
|         halt(); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| interrupt_error!(protection_fault, { | ||||
|     println!("PROTECTION FAULT"); | ||||
|     loop { | ||||
|         halt(); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| interrupt_error!(page_fault, { | ||||
|     println!("PAGE FAULT"); | ||||
|     loop { | ||||
|         halt(); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| bitflags! { | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ macro_rules! interrupt { | |||
|     ($name:ident, $func:block) => { | ||||
|         #[naked] | ||||
|         pub unsafe extern fn $name () { | ||||
|             #[inline(never)] | ||||
|             unsafe fn inner() { | ||||
|                 $func | ||||
|             } | ||||
|  | @ -76,6 +77,51 @@ macro_rules! interrupt { | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| #[macro_export] | ||||
| macro_rules! interrupt_error { | ||||
|     ($name:ident, $func:block) => { | ||||
|         #[naked] | ||||
|         pub unsafe extern fn $name () { | ||||
|             #[inline(never)] | ||||
|             unsafe fn inner() { | ||||
|                 $func | ||||
|             } | ||||
| 
 | ||||
|             asm!("xchg bx, bx" : : : : "intel", "volatile"); | ||||
| 
 | ||||
|             // Push scratch registers, grab stack pointer
 | ||||
|             asm!("push rax
 | ||||
|                 push rcx | ||||
|                 push rdx | ||||
|                 push rdi | ||||
|                 push rsi | ||||
|                 push r8 | ||||
|                 push r9 | ||||
|                 push r10 | ||||
|                 push r11" | ||||
|                 : : : : "intel", "volatile"); | ||||
| 
 | ||||
| 
 | ||||
|             // Call inner rust function
 | ||||
|             inner(); | ||||
| 
 | ||||
|             // Pop scratch registers, error code, and return
 | ||||
|             asm!("pop r11
 | ||||
|                 pop r10 | ||||
|                 pop r9 | ||||
|                 pop r8 | ||||
|                 pop rsi | ||||
|                 pop rdi | ||||
|                 pop rdx | ||||
|                 pop rcx | ||||
|                 pop rax | ||||
|                 add rsp, 8 | ||||
|                 iretq" | ||||
|                 : : : : "intel", "volatile"); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| /// ACPI table parsing
 | ||||
| pub mod acpi; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Soller
						Jeremy Soller