From 80afcc8879605601f5c47998c320fae8395a0ed6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 28 Apr 2017 15:40:15 +0200 Subject: [PATCH 01/24] Implement listing all schemes using `:` scheme --- src/scheme/root.rs | 55 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index cd08fd3..f89f56e 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -10,11 +10,17 @@ use syscall::scheme::Scheme; use scheme::{self, SchemeNamespace, SchemeId}; use scheme::user::{UserInner, UserScheme}; +#[derive(Clone)] +enum UserOrListHandle { + User(Arc), + List(AtomicUsize) +} + pub struct RootScheme { scheme_ns: SchemeNamespace, scheme_id: SchemeId, next_id: AtomicUsize, - handles: RwLock>> + handles: RwLock>, } impl RootScheme { @@ -30,7 +36,17 @@ impl RootScheme { impl Scheme for RootScheme { fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + use syscall::*; if uid == 0 { + if flags & O_DIRECTORY = O_DIRECTORY { + if flags & O_ACCMODE != O_RDONLY { + return Err(Error::new(EACCES)); + } + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.ls_handles.write().insert(id, UserOrListHandle::List(0)); + return Ok(id); + } + let context = { let contexts = context::contexts(); let context = contexts.current().ok_or(Error::new(ESRCH))?; @@ -50,7 +66,7 @@ impl Scheme for RootScheme { inner }; - self.handles.write().insert(id, inner); + self.handles.write().insert(id, UserOrListHandler::User(inner)); Ok(id) } else { @@ -77,8 +93,32 @@ impl Scheme for RootScheme { let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; - - inner.read(buf) + + match &*inner { + UserOrListInner::User(ref inner) => inner.read(buf), + UserOrListInner::List(ref num) => { + let scheme_ns = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.ens + }; + + let schemes = scheme::schemes(); + + let scheme_name = schemes.iterName(scheme_ns).nth(num.load(Ordering::SeqCst)).0.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < scheme_name.len() { + buf[i] = scheme_name[i]; + i += 1; + } + + num.fetch_add(1, Ordering::SeqCst) + + Ok(i) + } + } } fn write(&self, file: usize, buf: &[u8]) -> Result { @@ -87,8 +127,11 @@ impl Scheme for RootScheme { let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; - - inner.write(buf) + + match &*inner { + UserOrListInner::User(ref inner) => inner.write(buf), + UserOrListInner::List(_) => Err(Error::new(::syscall::EBADF)) + } } fn fevent(&self, file: usize, flags: usize) -> Result { From 4c006bca48f2ba42358b8226be6bb03a039cfbd1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 28 Apr 2017 16:18:41 +0200 Subject: [PATCH 02/24] Remove UserOrListHandle --- src/scheme/root.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index f89f56e..40de21e 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -10,17 +10,12 @@ use syscall::scheme::Scheme; use scheme::{self, SchemeNamespace, SchemeId}; use scheme::user::{UserInner, UserScheme}; -#[derive(Clone)] -enum UserOrListHandle { - User(Arc), - List(AtomicUsize) -} - pub struct RootScheme { scheme_ns: SchemeNamespace, scheme_id: SchemeId, next_id: AtomicUsize, - handles: RwLock>, + handles: RwLock>>, + ls_handles: RwLock>, } impl RootScheme { @@ -29,21 +24,22 @@ impl RootScheme { scheme_ns: scheme_ns, scheme_id: scheme_id, next_id: AtomicUsize::new(0), - handles: RwLock::new(BTreeMap::new()) + handles: RwLock::new(BTreeMap::new()), + ls_handles: RwLock::new(BTreeMap::new()), } } } impl Scheme for RootScheme { fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - use syscall::*; + use syscall::syscall::*; if uid == 0 { - if flags & O_DIRECTORY = O_DIRECTORY { + if flags & O_DIRECTORY == O_DIRECTORY { if flags & O_ACCMODE != O_RDONLY { return Err(Error::new(EACCES)); } let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.ls_handles.write().insert(id, UserOrListHandle::List(0)); + self.ls_handles.write().insert(id, AtomicUsize::new(0)); return Ok(id); } @@ -56,6 +52,7 @@ impl Scheme for RootScheme { let id = self.next_id.fetch_add(1, Ordering::SeqCst); let inner = { + use scheme; let path_box = path.to_vec().into_boxed_slice(); let mut schemes = scheme::schemes_mut(); let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context)); @@ -66,7 +63,7 @@ impl Scheme for RootScheme { inner }; - self.handles.write().insert(id, UserOrListHandler::User(inner)); + self.handles.write().insert(id, inner); Ok(id) } else { @@ -114,7 +111,7 @@ impl Scheme for RootScheme { i += 1; } - num.fetch_add(1, Ordering::SeqCst) + num.fetch_add(1, Ordering::SeqCst); Ok(i) } @@ -128,10 +125,7 @@ impl Scheme for RootScheme { inner.clone() }; - match &*inner { - UserOrListInner::User(ref inner) => inner.write(buf), - UserOrListInner::List(_) => Err(Error::new(::syscall::EBADF)) - } + inner.write(buf) } fn fevent(&self, file: usize, flags: usize) -> Result { From c9fdc4beaec63c29295fae2197369e89370cfcbd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 28 Apr 2017 18:42:33 +0200 Subject: [PATCH 03/24] Make it working --- src/scheme/root.rs | 68 +++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 40de21e..e19ecd5 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -32,7 +32,8 @@ impl RootScheme { impl Scheme for RootScheme { fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - use syscall::syscall::*; + use syscall::flag::*; + if uid == 0 { if flags & O_DIRECTORY == O_DIRECTORY { if flags & O_ACCMODE != O_RDONLY { @@ -42,7 +43,7 @@ impl Scheme for RootScheme { self.ls_handles.write().insert(id, AtomicUsize::new(0)); return Ok(id); } - + let context = { let contexts = context::contexts(); let context = contexts.current().ok_or(Error::new(ESRCH))?; @@ -57,9 +58,9 @@ impl Scheme for RootScheme { let mut schemes = scheme::schemes_mut(); let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context)); schemes.insert(self.scheme_ns, path_box, |scheme_id| { - inner.scheme_id.store(scheme_id, Ordering::SeqCst); - Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner)))) - })?; + inner.scheme_id.store(scheme_id, Ordering::SeqCst); + Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner)))) + })?; inner }; @@ -87,33 +88,44 @@ impl Scheme for RootScheme { fn read(&self, file: usize, buf: &mut [u8]) -> Result { let inner = { let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::new(EBADF))?; - inner.clone() + handles.get(&file).map(Clone::clone) }; - - match &*inner { - UserOrListInner::User(ref inner) => inner.read(buf), - UserOrListInner::List(ref num) => { - let scheme_ns = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); - context.ens - }; - - let schemes = scheme::schemes(); - - let scheme_name = schemes.iterName(scheme_ns).nth(num.load(Ordering::SeqCst)).0.as_bytes(); - + + if let Some(inner) = inner { + inner.read(buf) + } else { + let scheme_ns = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.ens + }; + + let schemes = scheme::schemes(); + let mut schemes_iter = schemes.iter_name(scheme_ns); + + let num = { + let handles = self.ls_handles.read(); + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.load(Ordering::SeqCst) + }; + + if let Some(scheme) = schemes_iter.nth(num) { let mut i = 0; - while i < buf.len() && i < scheme_name.len() { - buf[i] = scheme_name[i]; + while i < buf.len() && i < scheme.0.len() { + buf[i] = scheme.0[i]; i += 1; } - - num.fetch_add(1, Ordering::SeqCst); - + + { + let handles = self.ls_handles.read(); + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.fetch_add(1, Ordering::SeqCst) + }; + Ok(i) + } else { + Ok(0) } } } @@ -124,7 +136,7 @@ impl Scheme for RootScheme { let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; - + inner.write(buf) } From 4441b750cf1b64c1b76446054c6efd4e633c9092 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 28 Apr 2017 18:43:39 +0200 Subject: [PATCH 04/24] Remove unnecessary change --- src/scheme/root.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index e19ecd5..9b84936 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -58,9 +58,9 @@ impl Scheme for RootScheme { let mut schemes = scheme::schemes_mut(); let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context)); schemes.insert(self.scheme_ns, path_box, |scheme_id| { - inner.scheme_id.store(scheme_id, Ordering::SeqCst); - Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner)))) - })?; + inner.scheme_id.store(scheme_id, Ordering::SeqCst); + Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner)))) + })?; inner }; From 8ffe704e7a7f47899c6d4e9f02e7b9e58bdfe51c Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 28 Apr 2017 18:44:37 +0200 Subject: [PATCH 05/24] Remove yet another unnecessary change --- src/scheme/root.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 9b84936..b34a504 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -53,7 +53,6 @@ impl Scheme for RootScheme { let id = self.next_id.fetch_add(1, Ordering::SeqCst); let inner = { - use scheme; let path_box = path.to_vec().into_boxed_slice(); let mut schemes = scheme::schemes_mut(); let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context)); From ca8b6f522eddd0e0e771f2b628c314c42bed1607 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 29 Apr 2017 10:43:50 +0200 Subject: [PATCH 06/24] Fix closing ls handle --- src/scheme/root.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/scheme/root.rs b/src/scheme/root.rs index b34a504..42bcaad 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -184,6 +184,9 @@ impl Scheme for RootScheme { } fn close(&self, file: usize) -> Result { - self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) + if self.handles.write().remove(&file).is_none() { + self.ls_handles.write().remove(&file).ok_or(Error::new(EBADF))?; + } + Ok(0) } } From 248cfa51ae6147c6380b6e0a4ffd3fcd7c07c652 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 29 Apr 2017 10:46:07 +0200 Subject: [PATCH 07/24] Remove PIT_TICKS assert --- src/context/switch.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/context/switch.rs b/src/context/switch.rs index c731929..4413d89 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -17,7 +17,6 @@ pub unsafe fn switch() -> bool { //set PIT Interrupt counter to 0, giving each process same amount of PIT ticks PIT_TICKS.store(0, Ordering::SeqCst); - assert_eq!(PIT_TICKS.load(Ordering::SeqCst), 0); // Set the global lock to avoid the unsafe operations below from causing issues while arch::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) { From 62d3f4bd93c425b263bd9b762632f4601e0ec1c5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 10 May 2017 21:38:40 -0600 Subject: [PATCH 08/24] Add Xargo support --- Xargo.toml | 3 +++ src/panic.rs | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 Xargo.toml diff --git a/Xargo.toml b/Xargo.toml new file mode 100644 index 0000000..bc268c0 --- /dev/null +++ b/Xargo.toml @@ -0,0 +1,3 @@ +[dependencies.alloc] + +[dependencies.collections] diff --git a/src/panic.rs b/src/panic.rs index 27d361d..8ec88a8 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -4,12 +4,13 @@ use interrupt; #[cfg(not(test))] #[lang = "eh_personality"] -extern "C" fn eh_personality() {} +pub extern "C" fn eh_personality() {} #[cfg(not(test))] /// Required to handle panics #[lang = "panic_fmt"] -extern "C" fn panic_fmt(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { +#[no_mangle] +pub extern "C" fn rust_begin_unwind(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { println!("PANIC: {}", fmt); println!("FILE: {}", file); println!("LINE: {}", line); From 32b0c06314363a4993db4cd308010a63bd261b7c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 11 May 2017 21:16:07 -0600 Subject: [PATCH 09/24] Remove hardcoded live filesystem --- src/scheme/live.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scheme/live.rs b/src/scheme/live.rs index 905921f..e434f8e 100644 --- a/src/scheme/live.rs +++ b/src/scheme/live.rs @@ -11,7 +11,7 @@ use syscall::error::*; use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::Scheme; -static FILESYSTEM: &'static [u8] = include_bytes!("../../../build/filesystem.bin"); +static FILESYSTEM: &'static [u8] = include_bytes!(env!("FILESYSTEM")); struct Handle { path: &'static [u8], From 4d2808a012de5b6d4247a5eeb3ca510034911c7f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 12 May 2017 21:04:52 -0600 Subject: [PATCH 10/24] Remove free count print --- src/memory/recycle.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/memory/recycle.rs b/src/memory/recycle.rs index f006ec5..d47bff2 100644 --- a/src/memory/recycle.rs +++ b/src/memory/recycle.rs @@ -27,7 +27,6 @@ impl RecycleAllocator { for free in self.free.iter() { count += free.1; } - println!("Free count: {} in {} entries", count, self.free.len()); count } From 3c5b262b0e4b6c24a1f71575d7e2c879fd107b0f Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sun, 21 May 2017 13:44:10 -0700 Subject: [PATCH 11/24] Update for changes in std::ptr::Unique API --- src/paging/mapper.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/paging/mapper.rs b/src/paging/mapper.rs index b3830bf..c530b9f 100644 --- a/src/paging/mapper.rs +++ b/src/paging/mapper.rs @@ -89,11 +89,11 @@ impl Mapper { } pub fn p4(&self) -> &Table { - unsafe { self.p4.get() } + unsafe { self.p4.as_ref() } } pub fn p4_mut(&mut self) -> &mut Table { - unsafe { self.p4.get_mut() } + unsafe { self.p4.as_mut() } } /// Map a page to a frame From 8d899258424f121df196ef38f2d3988e59339828 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 4 Jun 2017 18:34:45 -0600 Subject: [PATCH 12/24] Align ELF segments to avoid subtract overflow --- src/syscall/process.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index d202d46..8a86ba0 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -593,9 +593,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { let mut tls_option = None; for segment in elf.segments() { if segment.p_type == program_header::PT_LOAD { + let voff = segment.p_vaddr % 4096; + let vaddr = segment.p_vaddr - voff; + let mut memory = context::memory::Memory::new( - VirtualAddress::new(segment.p_vaddr as usize), - segment.p_memsz as usize, + VirtualAddress::new(vaddr as usize), + segment.p_memsz as usize + voff as usize, entry::NO_EXECUTE | entry::WRITABLE, true ); From e3020db04f239ed6c01ab127d9319120f9802c72 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 11 Jun 2017 08:40:27 -0600 Subject: [PATCH 13/24] Better messages on unmapping failure --- src/paging/mapper.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/paging/mapper.rs b/src/paging/mapper.rs index c530b9f..d0a5b29 100644 --- a/src/paging/mapper.rs +++ b/src/paging/mapper.rs @@ -137,50 +137,60 @@ impl Mapper { let frame; let p4 = self.p4_mut(); - { - let p3 = p4.next_table_mut(page.p4_index()).expect("unmap_inner: p3 not found"); - { - let p2 = p3.next_table_mut(page.p3_index()).expect("unmap_inner: p2 not found"); - { - let p1 = p2.next_table_mut(page.p2_index()).expect("unmap_inner: p1 not found"); + if let Some(p3) = p4.next_table_mut(page.p4_index()) { + if let Some(p2) = p3.next_table_mut(page.p3_index()) { + if let Some(p1) = p2.next_table_mut(page.p2_index()) { + frame = if let Some(frame) = p1[page.p1_index()].pointed_frame() { + frame + } else { + panic!("unmap_inner({:X}): frame not found", page.start_address().get()) + }; - frame = p1[page.p1_index()].pointed_frame().expect("unmap_inner: frame not found"); p1[page.p1_index()].set_unused(); if keep_parents || ! p1.is_unused() { return frame; } + } else { + panic!("unmap_inner({:X}): p1 not found", page.start_address().get()); } - { - let p1_frame = p2[page.p2_index()].pointed_frame().expect("unmap_inner: p1 frame not found"); + if let Some(p1_frame) = p2[page.p2_index()].pointed_frame() { //println!("Free p1 {:?}", p1_frame); p2[page.p2_index()].set_unused(); deallocate_frames(p1_frame, 1); + } else { + panic!("unmap_inner({:X}): p1_frame not found", page.start_address().get()); } if keep_parents || ! p2.is_unused() { return frame; } + } else { + panic!("unmap_inner({:X}): p2 not found", page.start_address().get()); } - { - let p2_frame = p3[page.p3_index()].pointed_frame().expect("unmap_inner: p2 frame not found"); + if let Some(p2_frame) = p3[page.p3_index()].pointed_frame() { //println!("Free p2 {:?}", p2_frame); p3[page.p3_index()].set_unused(); deallocate_frames(p2_frame, 1); + } else { + panic!("unmap_inner({:X}): p2_frame not found", page.start_address().get()); } if keep_parents || ! p3.is_unused() { return frame; } + } else { + panic!("unmap_inner({:X}): p3 not found", page.start_address().get()); } - { - let p3_frame = p4[page.p4_index()].pointed_frame().expect("unmap_inner: p3 frame not found"); + if let Some(p3_frame) = p4[page.p4_index()].pointed_frame() { //println!("Free p3 {:?}", p3_frame); p4[page.p4_index()].set_unused(); deallocate_frames(p3_frame, 1); + } else { + panic!("unmap_inner({:X}): p3_frame not found", page.start_address().get()); } frame From 8b05863ebbfcc1d854438e2cfd722f817dc714f3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 13 Jun 2017 19:10:32 -0600 Subject: [PATCH 14/24] Disable preemption until paging bug is fixed --- src/interrupt/irq.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/interrupt/irq.rs b/src/interrupt/irq.rs index b422036..23fb68c 100644 --- a/src/interrupt/irq.rs +++ b/src/interrupt/irq.rs @@ -52,9 +52,11 @@ interrupt!(pit, { pic::MASTER.ack(); + /* if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 { context::switch(); } + */ // Any better way of doing this? timeout::trigger(); From d6354aeb5644bc2ecefa295a8690bc10b4a21144 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 13 Jun 2017 20:42:04 -0600 Subject: [PATCH 15/24] Refactor kernel mapping so that symbol table is mapped --- linkers/x86_64.ld | 11 ++---- src/interrupt/mod.rs | 37 ++---------------- src/interrupt/trace.rs | 33 ++++++++++++++++ src/lib.rs | 1 + src/paging/mod.rs | 87 ++++++++++++++++++++++++++---------------- src/start.rs | 35 ++++------------- 6 files changed, 104 insertions(+), 100 deletions(-) create mode 100644 src/interrupt/trace.rs diff --git a/linkers/x86_64.ld b/linkers/x86_64.ld index 546adaa..55640ec 100644 --- a/linkers/x86_64.ld +++ b/linkers/x86_64.ld @@ -29,6 +29,10 @@ SECTIONS { *(.data*) . = ALIGN(4096); __data_end = .; + __bss_start = .; + *(.bss*) + . = ALIGN(4096); + __bss_end = .; } .tdata : AT(ADDR(.tdata) - KERNEL_OFFSET) { @@ -43,13 +47,6 @@ SECTIONS { __tbss_end = .; } - .bss : AT(ADDR(.bss) - KERNEL_OFFSET) { - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - __end = .; /DISCARD/ : { diff --git a/src/interrupt/mod.rs b/src/interrupt/mod.rs index 3cc5caa..85686d9 100644 --- a/src/interrupt/mod.rs +++ b/src/interrupt/mod.rs @@ -1,13 +1,12 @@ //! Interrupt instructions -use core::mem; - -use paging::{ActivePageTable, VirtualAddress}; - pub mod exception; pub mod ipi; pub mod irq; pub mod syscall; +pub mod trace; + +pub use self::trace::stack_trace; /// Clear interrupts #[inline(always)] @@ -53,33 +52,3 @@ pub unsafe fn halt() { pub fn pause() { unsafe { asm!("pause" : : : : "intel", "volatile"); } } - -/// Get a stack trace -//TODO: Check for stack being mapped before dereferencing -#[inline(never)] -pub unsafe fn stack_trace() { - let mut rbp: usize; - asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); - - println!("TRACE: {:>016X}", rbp); - //Maximum 64 frames - let active_table = ActivePageTable::new(); - for _frame in 0..64 { - if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { - if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { - let rip = *(rip_rbp as *const usize); - if rip == 0 { - println!(" {:>016X}: EMPTY RETURN", rbp); - break; - } - println!(" {:>016X}: {:>016X}", rbp, rip); - rbp = *(rbp as *const usize); - } else { - println!(" {:>016X}: GUARD PAGE", rbp); - break; - } - } else { - println!(" {:>016X}: RBP OVERFLOW", rbp); - } - } -} diff --git a/src/interrupt/trace.rs b/src/interrupt/trace.rs new file mode 100644 index 0000000..0778ac0 --- /dev/null +++ b/src/interrupt/trace.rs @@ -0,0 +1,33 @@ +use core::mem; + +use paging::{ActivePageTable, VirtualAddress}; + +/// Get a stack trace +//TODO: Check for stack being mapped before dereferencing +#[inline(never)] +pub unsafe fn stack_trace() { + let mut rbp: usize; + asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); + + println!("TRACE: {:>016X}", rbp); + //Maximum 64 frames + let active_table = ActivePageTable::new(); + for _frame in 0..64 { + if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { + if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { + let rip = *(rip_rbp as *const usize); + if rip == 0 { + println!(" {:>016X}: EMPTY RETURN", rbp); + break; + } + println!(" {:>016X}: {:>016X}", rbp, rip); + rbp = *(rbp as *const usize); + } else { + println!(" {:>016X}: GUARD PAGE", rbp); + break; + } + } else { + println!(" {:>016X}: RBP OVERFLOW", rbp); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index f200492..4e1c17b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![feature(alloc)] #![feature(asm)] #![feature(collections)] +#![feature(concat_idents)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drop_types_in_const)] diff --git a/src/paging/mod.rs b/src/paging/mod.rs index 2462fb9..319bcb1 100644 --- a/src/paging/mod.rs +++ b/src/paging/mod.rs @@ -78,7 +78,7 @@ unsafe fn init_tcb(cpu_id: usize) -> usize { /// Initialize paging /// /// Returns page table and thread control block offset -pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (ActivePageTable, usize) { +pub unsafe fn init(cpu_id: usize, kernel_start: usize, kernel_end: usize, stack_start: usize, stack_end: usize) -> (ActivePageTable, usize) { extern { /// The starting byte of the text (code) data segment. static mut __text_start: u8; @@ -118,6 +118,60 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti }; active_table.with(&mut new_table, &mut temporary_page, |mapper| { + // Remap stack writable, no execute + { + let start_frame = Frame::containing_address(PhysicalAddress::new(stack_start - ::KERNEL_OFFSET)); + let end_frame = Frame::containing_address(PhysicalAddress::new(stack_end - ::KERNEL_OFFSET - 1)); + for frame in Frame::range_inclusive(start_frame, end_frame) { + let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); + let result = mapper.map_to(page, frame, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); + // The flush can be ignored as this is not the active table. See later active_table.switch + unsafe { result.ignore(); } + } + } + + // Map all frames in kernel + { + let start_frame = Frame::containing_address(PhysicalAddress::new(kernel_start)); + let end_frame = Frame::containing_address(PhysicalAddress::new(kernel_end - 1)); + for frame in Frame::range_inclusive(start_frame, end_frame) { + let phys_addr = frame.start_address().get(); + let virt_addr = phys_addr + ::KERNEL_OFFSET; + + macro_rules! in_section { + ($n: ident) => ( + virt_addr >= & concat_idents!(__, $n, _start) as *const u8 as usize && + virt_addr < & concat_idents!(__, $n, _end) as *const u8 as usize + ); + } + + let flags = if in_section!(text) { + // Remap text read-only + PRESENT | GLOBAL + } else if in_section!(rodata) { + // Remap rodata read-only, no execute + PRESENT | GLOBAL | NO_EXECUTE + } else if in_section!(data) { + // Remap data writable, no execute + PRESENT | GLOBAL | NO_EXECUTE | WRITABLE + } else if in_section!(tdata) { + // Remap tdata master read-only, no execute + PRESENT | GLOBAL | NO_EXECUTE + } else if in_section!(bss) { + // Remap bss writable, no execute + PRESENT | GLOBAL | NO_EXECUTE | WRITABLE + } else { + // Remap anything else read-only, no execute + PRESENT | GLOBAL | NO_EXECUTE + }; + + let page = Page::containing_address(VirtualAddress::new(virt_addr)); + let result = mapper.map_to(page, frame, flags); + // The flush can be ignored as this is not the active table. See later active_table.switch + unsafe { result.ignore(); } + } + } + // Map tdata and tbss { let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize; @@ -133,37 +187,6 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti unsafe { result.ignore(); } } } - - let mut remap = |start: usize, end: usize, flags: EntryFlags| { - if end > start { - let start_frame = Frame::containing_address(PhysicalAddress::new(start)); - let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); - let result = mapper.map_to(page, frame, flags); - // The flush can be ignored as this is not the active table. See later active_table.switch - unsafe { result.ignore(); } - } - } - }; - - // Remap stack writable, no execute - remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - - // Remap a section with `flags` - let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| { - remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags); - }; - // Remap text read-only - remap_section(& __text_start, & __text_end, PRESENT | GLOBAL); - // Remap rodata read-only, no execute - remap_section(& __rodata_start, & __rodata_end, PRESENT | GLOBAL | NO_EXECUTE); - // Remap data writable, no execute - remap_section(& __data_start, & __data_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); - // Remap tdata master writable, no execute - remap_section(& __tdata_start, & __tdata_end, PRESENT | GLOBAL | NO_EXECUTE); - // Remap bss writable, no execute - remap_section(& __bss_start, & __bss_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE); }); // This switches the active table, which is setup by the bootloader, to a correct table diff --git a/src/start.rs b/src/start.rs index 2bf9f59..f95a1c3 100644 --- a/src/start.rs +++ b/src/start.rs @@ -3,7 +3,6 @@ /// It must create the IDT with the correct entries, those entries are /// defined in other files inside of the `arch` module -use core::ptr; use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use acpi; @@ -40,43 +39,25 @@ extern { /// The entry to Rust, all things must be initialized #[no_mangle] -pub unsafe extern fn kstart() -> ! { +pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base: usize, stack_size: usize) -> ! { { - extern { - /// The starting byte of the _.bss_ (uninitialized data) segment. - static mut __bss_start: u8; - /// The ending byte of the _.bss_ (uninitialized data) segment. - static mut __bss_end: u8; - /// The end of the kernel - static mut __end: u8; - } - - // Zero BSS, this initializes statics that are set to 0 + // BSS should already be zero { - let start_ptr = &mut __bss_start as *mut u8; - let end_ptr = & __bss_end as *const u8 as usize; - - if start_ptr as usize <= end_ptr { - let size = end_ptr - start_ptr as usize; - ptr::write_bytes(start_ptr, 0, size); - } - assert_eq!(BSS_TEST_ZERO, 0); assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); } - // Initialize memory management - memory::init(0, &__end as *const u8 as usize - ::KERNEL_OFFSET); + println!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size); + println!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size); - // TODO: allocate a stack - let stack_start = 0x00080000 + ::KERNEL_OFFSET; - let stack_end = 0x0009F000 + ::KERNEL_OFFSET; + // Initialize memory management + memory::init(0, kernel_base + ((kernel_size + 4095)/4096) * 4096); // Initialize paging - let (mut active_table, tcb_offset) = paging::init(0, stack_start, stack_end); + let (mut active_table, tcb_offset) = paging::init(0, kernel_base, kernel_base + kernel_size, stack_base, stack_base + stack_size); // Set up GDT - gdt::init(tcb_offset, stack_end); + gdt::init(tcb_offset, stack_base + stack_size); // Set up IDT idt::init(); From acab23d1e1fc1779b40caff0e710b352857ca7e8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 13 Jun 2017 21:43:37 -0600 Subject: [PATCH 16/24] Add symbol lookup (still very WIP) --- Cargo.toml | 2 +- src/elf.rs | 86 +++++++++++++++++++++++++++++++++++++++++- src/interrupt/trace.rs | 43 +++++++++++++++++++++ src/start.rs | 5 +++ 4 files changed, 133 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6b285a..bcc7579 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ raw-cpuid = { git = "https://github.com/gz/rust-cpuid", branch = "master" } redox_syscall = "0.1" [dependencies.goblin] -version = "0.0.8" +version = "0.0.10" default-features = false features = ["elf32", "elf64"] diff --git a/src/elf.rs b/src/elf.rs index bf484fe..240cf56 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -4,11 +4,13 @@ use collections::String; use core::str; +use goblin::elf::section_header::SHT_SYMTAB; + #[cfg(target_arch = "x86")] -pub use goblin::elf32::{header, program_header}; +pub use goblin::elf32::{header, program_header, section_header, sym}; #[cfg(target_arch = "x86_64")] -pub use goblin::elf64::{header, program_header}; +pub use goblin::elf64::{header, program_header, section_header, sym}; /// An ELF executable pub struct Elf<'a> { @@ -33,6 +35,14 @@ impl<'a> Elf<'a> { } } + pub fn sections(&'a self) -> ElfSections<'a> { + ElfSections { + data: self.data, + header: self.header, + i: 0 + } + } + pub fn segments(&'a self) -> ElfSegments<'a> { ElfSegments { data: self.data, @@ -41,12 +51,58 @@ impl<'a> Elf<'a> { } } + pub fn symbols(&'a self) -> Option> { + let mut symtab_opt = None; + for section in self.sections() { + if section.sh_type == SHT_SYMTAB { + symtab_opt = Some(section); + break; + } + } + + if let Some(symtab) = symtab_opt { + Some(ElfSymbols { + data: self.data, + header: self.header, + symtab: symtab, + i: 0 + }) + } else { + None + } + } + /// Get the entry field of the header pub fn entry(&self) -> usize { self.header.e_entry as usize } } +pub struct ElfSections<'a> { + data: &'a [u8], + header: &'a header::Header, + i: usize +} + +impl<'a> Iterator for ElfSections<'a> { + type Item = &'a section_header::SectionHeader; + fn next(&mut self) -> Option { + if self.i < self.header.e_shnum as usize { + let item = unsafe { + &* (( + self.data.as_ptr() as usize + + self.header.e_shoff as usize + + self.i * self.header.e_shentsize as usize + ) as *const section_header::SectionHeader) + }; + self.i += 1; + Some(item) + } else { + None + } + } +} + pub struct ElfSegments<'a> { data: &'a [u8], header: &'a header::Header, @@ -71,3 +127,29 @@ impl<'a> Iterator for ElfSegments<'a> { } } } + +pub struct ElfSymbols<'a> { + data: &'a [u8], + header: &'a header::Header, + symtab: &'a section_header::SectionHeader, + i: usize +} + +impl<'a> Iterator for ElfSymbols<'a> { + type Item = &'a sym::Sym; + fn next(&mut self) -> Option { + if self.i < (self.symtab.sh_size as usize) / sym::SIZEOF_SYM { + let item = unsafe { + &* (( + self.data.as_ptr() as usize + + self.symtab.sh_offset as usize + + self.i * sym::SIZEOF_SYM + ) as *const sym::Sym) + }; + self.i += 1; + Some(item) + } else { + None + } + } +} diff --git a/src/interrupt/trace.rs b/src/interrupt/trace.rs index 0778ac0..dcc1b44 100644 --- a/src/interrupt/trace.rs +++ b/src/interrupt/trace.rs @@ -22,6 +22,7 @@ pub unsafe fn stack_trace() { } println!(" {:>016X}: {:>016X}", rbp, rip); rbp = *(rbp as *const usize); + symbol_trace(rip); } else { println!(" {:>016X}: GUARD PAGE", rbp); break; @@ -31,3 +32,45 @@ pub unsafe fn stack_trace() { } } } + + +pub unsafe fn symbol_trace(addr: usize) { + use core::slice; + use core::sync::atomic::Ordering; + + use elf::Elf; + use start::{KERNEL_BASE, KERNEL_SIZE}; + + let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + ::KERNEL_OFFSET) as *const u8; + let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst)); + if let Ok(elf) = Elf::from(kernel_slice) { + let mut strtab_opt = None; + for section in elf.sections() { + if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB { + strtab_opt = Some(section); + break; + } + } + + if let Some(symbols) = elf.symbols() { + for sym in symbols { + if addr >= sym.st_value as usize && addr < (sym.st_value + sym.st_size) as usize { + println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize); + + if let Some(strtab) = strtab_opt { + print!(" "); + + for &b in elf.data[strtab.sh_offset as usize + sym.st_name as usize ..].iter() { + if b == 0 { + break; + } + print!("{}", b as char); + } + + println!(""); + } + } + } + } + } +} diff --git a/src/start.rs b/src/start.rs index f95a1c3..bf9deda 100644 --- a/src/start.rs +++ b/src/start.rs @@ -26,6 +26,8 @@ static mut TBSS_TEST_ZERO: usize = 0; #[thread_local] static mut TDATA_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF; +pub static KERNEL_BASE: AtomicUsize = ATOMIC_USIZE_INIT; +pub static KERNEL_SIZE: AtomicUsize = ATOMIC_USIZE_INIT; pub static CPU_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; pub static AP_READY: AtomicBool = ATOMIC_BOOL_INIT; static BSP_READY: AtomicBool = ATOMIC_BOOL_INIT; @@ -47,6 +49,9 @@ pub unsafe extern fn kstart(kernel_base: usize, kernel_size: usize, stack_base: assert_eq!(DATA_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF); } + KERNEL_BASE.store(kernel_base, Ordering::SeqCst); + KERNEL_SIZE.store(kernel_size, Ordering::SeqCst); + println!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size); println!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size); From 9b19ab9439712778333d5cad3aff379b0818f92f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 13 Jun 2017 21:56:20 -0600 Subject: [PATCH 17/24] Improve method of getting symbol name --- src/interrupt/trace.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/interrupt/trace.rs b/src/interrupt/trace.rs index dcc1b44..c44e44e 100644 --- a/src/interrupt/trace.rs +++ b/src/interrupt/trace.rs @@ -1,4 +1,4 @@ -use core::mem; +use core::{mem, str}; use paging::{ActivePageTable, VirtualAddress}; @@ -33,7 +33,9 @@ pub unsafe fn stack_trace() { } } - +/// Get a symbol +//TODO: Do not create Elf object for every symbol lookup +#[inline(never)] pub unsafe fn symbol_trace(addr: usize) { use core::slice; use core::sync::atomic::Ordering; @@ -58,16 +60,20 @@ pub unsafe fn symbol_trace(addr: usize) { println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize); if let Some(strtab) = strtab_opt { - print!(" "); - - for &b in elf.data[strtab.sh_offset as usize + sym.st_name as usize ..].iter() { + let start = strtab.sh_offset as usize + sym.st_name as usize; + let mut end = start; + while end < elf.data.len() { + let b = elf.data[end]; + end += 1; if b == 0 { break; } - print!("{}", b as char); } - println!(""); + if end > start { + let sym_name = str::from_utf8_unchecked(&elf.data[start .. end]); + println!(" {}", sym_name); + } } } } From 7ef2401db3f0b4ce38f87978daa8c35cc0bd82d4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 14 Jun 2017 20:25:38 -0600 Subject: [PATCH 18/24] Reenable preemption --- src/interrupt/irq.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/interrupt/irq.rs b/src/interrupt/irq.rs index 23fb68c..b422036 100644 --- a/src/interrupt/irq.rs +++ b/src/interrupt/irq.rs @@ -52,11 +52,9 @@ interrupt!(pit, { pic::MASTER.ack(); - /* if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 { context::switch(); } - */ // Any better way of doing this? timeout::trigger(); From c9cbdab9f1e2019a2461ef97136cd7224c16433e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 14 Jun 2017 20:25:49 -0600 Subject: [PATCH 19/24] Demangle symbols --- src/interrupt/trace.rs | 56 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/interrupt/trace.rs b/src/interrupt/trace.rs index c44e44e..a2997ad 100644 --- a/src/interrupt/trace.rs +++ b/src/interrupt/trace.rs @@ -1,4 +1,5 @@ use core::{mem, str}; +use goblin::elf::sym; use paging::{ActivePageTable, VirtualAddress}; @@ -56,7 +57,10 @@ pub unsafe fn symbol_trace(addr: usize) { if let Some(symbols) = elf.symbols() { for sym in symbols { - if addr >= sym.st_value as usize && addr < (sym.st_value + sym.st_size) as usize { + if sym::st_type(sym.st_info) == sym::STT_FUNC + && addr >= sym.st_value as usize + && addr < (sym.st_value + sym.st_size) as usize + { println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize); if let Some(strtab) = strtab_opt { @@ -71,8 +75,54 @@ pub unsafe fn symbol_trace(addr: usize) { } if end > start { - let sym_name = str::from_utf8_unchecked(&elf.data[start .. end]); - println!(" {}", sym_name); + let sym_name = &elf.data[start .. end]; + + print!(" "); + + if sym_name.starts_with(b"_ZN") { + // Skip _ZN + let mut i = 3; + let mut first = true; + while i < sym_name.len() { + // E is the end character + if sym_name[i] == b'E' { + break; + } + + // Parse length string + let mut len = 0; + while i < sym_name.len() { + let b = sym_name[i]; + if b >= b'0' && b <= b'9' { + i += 1; + len *= 10; + len += (b - b'0') as usize; + } else { + break; + } + } + + // Print namespace seperator, if required + if first { + first = false; + } else { + print!("::"); + } + + // Print name string + let end = i + len; + while i < sym_name.len() && i < end { + print!("{}", sym_name[i] as char); + i += 1; + } + } + } else { + for &b in sym_name.iter() { + print!("{}", b as char); + } + } + + println!(""); } } } From 85c02365c96e9f2b551edeb8f7c4b306ea4feb04 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 14 Jun 2017 20:26:05 -0600 Subject: [PATCH 20/24] Fix overallocation --- src/memory/recycle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memory/recycle.rs b/src/memory/recycle.rs index d47bff2..1f66b61 100644 --- a/src/memory/recycle.rs +++ b/src/memory/recycle.rs @@ -92,7 +92,7 @@ impl FrameAllocator for RecycleAllocator { if let Some(i) = small_i { let (address, remove) = { let free = &mut self.free[i]; - free.1 -= 1; + free.1 -= count; (free.0 + free.1 * 4096, free.1 == 0) }; From 73a71a7d85ee08566c6efbc6358db63f6d750958 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 17 Jun 2017 14:32:31 -0600 Subject: [PATCH 21/24] Increase size of kernel heap when live disk is loaded --- src/consts.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/consts.rs b/src/consts.rs index 743bee5..149c9b4 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -15,7 +15,10 @@ /// Offset to kernel heap pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET + PML4_SIZE/2; /// Size of kernel heap - pub const KERNEL_HEAP_SIZE: usize = 256 * 1024 * 1024; // 256 MB + #[cfg(not(feature = "live"))] + pub const KERNEL_HEAP_SIZE: usize = 128 * 1024 * 1024; // 128 MB + #[cfg(feature = "live")] + pub const KERNEL_HEAP_SIZE: usize = 640 * 1024 * 1024; // 640 MB - 128 default + 512 for the live disk /// Offset to kernel percpu variables //TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE; From bbcd5197a456b198750e35b085189e3e4b800c57 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 17 Jun 2017 18:47:27 -0600 Subject: [PATCH 22/24] Aml parser (#24) * Initial parser proof of concept * Added better error handling to the parser * Refactored into a better directory structure * Parse package length * Implemented named string, scope op * Properly bounds checked namestring * Fixed namestring regressions * Started work parsing DefRegionOp. NB: As TermArg is not yet implemented, a bug is present parsing the address offset and length. Additionally, a bug was fixed in NameString * Completed DefOpRegion implementation. TermArg remains unimplemented, stubbed out * Implemented TermArg parsing * Implemented integer parts of computational data * Implemented defField, and associated FieldList. FieldElement still remains stubbed * Implmenented FieldElement * Implmenented named field * Parsed DefMethod * Parsed ToHexString * Parsed ToBuffer * Parsed both subtract and sizeof * Fixed size bug in sizeof parsing * Parsed Store, fixed a parse bug where Target should be a SuperName not a TermArg * Parsed while * Parsed LLess * Parsed DerefOf * Parse Index * Parse increment * Parse device * Parse device * Parsed create dword field * Parsed if/else block * Properly parsed Target, rendered an AST from existing parse code, and stubbed out MethodInvocation parser method * Implemented deferred loading, and deferred method invocation parses * Parsed Or * Fixed a bunch of off-by-one errors. Shows what I get for copying code around * Parsed Return * Fixed a boolean logic error in the handling of the extended instruction namespace * Added DefBuffer to ComputationalData * Removed a temporary file * Parsed ReservedField * Parsed DefPackage, DefAnd, and ComputationalData::String * Parsed DefMutex * Parsed DefAlias and RevisionOp * Parsed DebugObj * Parsed DefRefOf * Parsed type 6 opcodes * Added ObjectReference and DDBHandle to DataRefObj parsing * Parsed DefVarPackage, in both Type2OpCode, and in DataObj * Parsed DefBankField * Parsed AccessField * Parsed ConnectField * Parsed CreateBitField * Parsed CreateByteField * Parsed CreateWordField * Parsed CreateQWordField * Parsed CreateField * Parsed DefDataRegion * Parsed DefEvent * Parsed IndexField * Parsed DefPowerRes * Parsed DefProcessor * Parsed DefThermalZone: * Parsed ExtendedAccessField * Parsed DefBreak, DefBreakPoint, DefContinue and DefNoop (all type 1 opcodes with no parameters and one byte) * Parsed DefFatal * Parsed DefLoad * Parsed DefNotify * Parsed DefRelease * Parsed DefReset * Parsed DefSignal * Parsed DefSleep * Parsed DefStall * Parsed DefUnload * Parsed DefAcquire * Parsed DefAnd * Parsed DefConcat * Parsed ConcatRes * Switched Concat and ConcatRes opcodes * Parsed CondRefOf * Parsed DefDecrement and DefCopyObject * Parsed DefDivide, fixed length calculation bug in a bunch of parse routines * Parsed DefFindSetLeftBit * Parsed DefFindSetRightBit * Parsed DefFromBCD * Parsed DefLAnd * Parsed DefLGreater * Parsed LNot * Parsed DefLOr * Parsed DefLoadTable * Parsed DefMatch * Parsed DefMid * Parsed DefMod * Parsed DefMultiply * Parsed DefNAnd * Parsed DefNOr * Parsed DefNot * Parsed DefObjectType * Parsed DefShiftLeft and DefShiftRight * Parsed DefTimer * Parsed DefToBCD, DefToDecimalString, DefToInteger and DefToString * Parsed DefXor * Parsed DefWait * Implemented a parser, abstract syntax tree, and basic infrastructure for the AML subsystem of the ACPI module. The entire AML grammar is parsed and placed into an abstract syntax tree, with one exception: method invocations, rather than parsing, defer the load until later on in the process, due to the way the grammar works. Still to be done: - Refactor the code: a lot of the parser is very repetitive, and could easily be refactored with the aid of macros. This would reduce the length and improve legibility, though not affect function. - More rigorous testing of parser: the parser has, thus far, only been tested on the DSDT in QEMU. There may be bugs present that are hidden. - Parse the SSDTs: the SSDTs should be parsed after the DSDT, and contain more AML bytecode to be treated as modifying the same namespace. Adding this would be simple, though not urgent. - Transform the AST into a concrete executable tree: the CET is what will hold all information necessary to execute control methods and evaluate namespace objects. While this could be done in the AST, due to the way AML is laid out this would be very inefficient and require a lot of repetitive transformations every time something is to be executed. Therefore, perform the transformations upfront. - Parse the deferred loads, and the method invocations contained within: Once the AST has been rendered into a CET, sufficient information will be present to parse method invocations and add those to the namespace. - Bytecode interpreter: Once the CET has been finalized with method invocation parsing, it can then be called and executed. - Control method executor: this should walk the namespace, locating the relevant control method, then calling the interpreter on it. - Namespace enumerator: the executor shall use this to walk the namespace, and it should also be publicly accessible to allow outside code to determine what devices are present in the system. - Memory accessor API: ACPI AML has a concept of memory access in certain device domains - for example, the PCI BAR registers. These are all device specific offsets, therefore device drivers, or more accurately bus drivers, should be capable of installing handlers to manage this memory access. - CET concatenation: The DSDT and SSDTs all affect the same namespace, therefore concatenating the resulting trees should be possible. - Type checking: some operations in AML are typed. This should be handled at tree transformation time or earlier, and could indeed done in the parse step with some modification to the parser. This is currently not the case. * Initial parser proof of concept * Added better error handling to the parser * Refactored into a better directory structure * Parse package length * Implemented named string, scope op * Properly bounds checked namestring * Fixed namestring regressions * Started work parsing DefRegionOp. NB: As TermArg is not yet implemented, a bug is present parsing the address offset and length. Additionally, a bug was fixed in NameString * Completed DefOpRegion implementation. TermArg remains unimplemented, stubbed out * Implemented TermArg parsing * Implemented integer parts of computational data * Implemented defField, and associated FieldList. FieldElement still remains stubbed * Implmenented FieldElement * Implmenented named field * Parsed DefMethod * Parsed ToHexString * Parsed ToBuffer * Parsed both subtract and sizeof * Fixed size bug in sizeof parsing * Parsed Store, fixed a parse bug where Target should be a SuperName not a TermArg * Parsed while * Parsed LLess * Parsed DerefOf * Parse Index * Parse increment * Parse device * Parse device * Parsed create dword field * Parsed if/else block * Properly parsed Target, rendered an AST from existing parse code, and stubbed out MethodInvocation parser method * Implemented deferred loading, and deferred method invocation parses * Parsed Or * Fixed a bunch of off-by-one errors. Shows what I get for copying code around * Parsed Return * Fixed a boolean logic error in the handling of the extended instruction namespace * Added DefBuffer to ComputationalData * Removed a temporary file * Parsed ReservedField * Parsed DefPackage, DefAnd, and ComputationalData::String * Parsed DefMutex * Parsed DefAlias and RevisionOp * Parsed DebugObj * Parsed DefRefOf * Parsed type 6 opcodes * Added ObjectReference and DDBHandle to DataRefObj parsing * Parsed DefVarPackage, in both Type2OpCode, and in DataObj * Parsed DefBankField * Parsed AccessField * Parsed ConnectField * Parsed CreateBitField * Parsed CreateByteField * Parsed CreateWordField * Parsed CreateQWordField * Parsed CreateField * Parsed DefDataRegion * Parsed DefEvent * Parsed IndexField * Parsed DefPowerRes * Parsed DefProcessor * Parsed DefThermalZone: * Parsed ExtendedAccessField * Parsed DefBreak, DefBreakPoint, DefContinue and DefNoop (all type 1 opcodes with no parameters and one byte) * Parsed DefFatal * Parsed DefLoad * Parsed DefNotify * Parsed DefRelease * Parsed DefReset * Parsed DefSignal * Parsed DefSleep * Parsed DefStall * Parsed DefUnload * Parsed DefAcquire * Parsed DefAnd * Parsed DefConcat * Parsed ConcatRes * Switched Concat and ConcatRes opcodes * Parsed CondRefOf * Parsed DefDecrement and DefCopyObject * Parsed DefDivide, fixed length calculation bug in a bunch of parse routines * Parsed DefFindSetLeftBit * Parsed DefFindSetRightBit * Parsed DefFromBCD * Parsed DefLAnd * Parsed DefLGreater * Parsed LNot * Parsed DefLOr * Parsed DefLoadTable * Parsed DefMatch * Parsed DefMid * Parsed DefMod * Parsed DefMultiply * Parsed DefNAnd * Parsed DefNOr * Parsed DefNot * Parsed DefObjectType * Parsed DefShiftLeft and DefShiftRight * Parsed DefTimer * Parsed DefToBCD, DefToDecimalString, DefToInteger and DefToString * Parsed DefXor * Parsed DefWait * Implemented a parser, abstract syntax tree, and basic infrastructure for the AML subsystem of the ACPI module. The entire AML grammar is parsed and placed into an abstract syntax tree, with one exception: method invocations, rather than parsing, defer the load until later on in the process, due to the way the grammar works. Still to be done: - Refactor the code: a lot of the parser is very repetitive, and could easily be refactored with the aid of macros. This would reduce the length and improve legibility, though not affect function. - More rigorous testing of parser: the parser has, thus far, only been tested on the DSDT in QEMU. There may be bugs present that are hidden. - Parse the SSDTs: the SSDTs should be parsed after the DSDT, and contain more AML bytecode to be treated as modifying the same namespace. Adding this would be simple, though not urgent. - Transform the AST into a concrete executable tree: the CET is what will hold all information necessary to execute control methods and evaluate namespace objects. While this could be done in the AST, due to the way AML is laid out this would be very inefficient and require a lot of repetitive transformations every time something is to be executed. Therefore, perform the transformations upfront. - Parse the deferred loads, and the method invocations contained within: Once the AST has been rendered into a CET, sufficient information will be present to parse method invocations and add those to the namespace. - Bytecode interpreter: Once the CET has been finalized with method invocation parsing, it can then be called and executed. - Control method executor: this should walk the namespace, locating the relevant control method, then calling the interpreter on it. - Namespace enumerator: the executor shall use this to walk the namespace, and it should also be publicly accessible to allow outside code to determine what devices are present in the system. - Memory accessor API: ACPI AML has a concept of memory access in certain device domains - for example, the PCI BAR registers. These are all device specific offsets, therefore device drivers, or more accurately bus drivers, should be capable of installing handlers to manage this memory access. - CET concatenation: The DSDT and SSDTs all affect the same namespace, therefore concatenating the resulting trees should be possible. - Type checking: some operations in AML are typed. This should be handled at tree transformation time or earlier, and could indeed done in the parse step with some modification to the parser. This is currently not the case. * Partial refactor of AML code * Further refactoring * Fully refactored type 2 opcode selector * Refactored type 6 opcode selector * Further refactored Type 2 opcode parsing * Implemented basic infrastructure in order to render the AST down to a namespace object * Resolved scopes into the namespace * Put OpRegion into namespace * Rendered field parsing to the namespace object * Methods now placed in namespace * Moved DefName into the namespace * Moved packages into the namespace * Converted shutdown sequence to use AML parser * Moved shutdown over to use AML parsing fully * Removed the no longer needed DSDT code * Better messages on unmapping failure * Disable preemption until paging bug is fixed * Refactor kernel mapping so that symbol table is mapped * Add symbol lookup (still very WIP) * Improve method of getting symbol name * Reenable preemption * Demangle symbols * Fix overallocation * Remove tilde files --- src/acpi/aml/dataobj.rs | 168 ++++++ src/acpi/aml/mod.rs | 85 +++ src/acpi/aml/namedobj.rs | 783 +++++++++++++++++++++++++ src/acpi/aml/namespace.rs | 225 ++++++++ src/acpi/aml/namespacemodifier.rs | 102 ++++ src/acpi/aml/namestring.rs | 188 ++++++ src/acpi/aml/parsermacros.rs | 49 ++ src/acpi/aml/pkglength.rs | 25 + src/acpi/aml/termlist.rs | 135 +++++ src/acpi/aml/type1opcode.rs | 259 +++++++++ src/acpi/aml/type2opcode.rs | 932 ++++++++++++++++++++++++++++++ src/acpi/dsdt.rs | 78 --- src/acpi/mod.rs | 23 +- src/acpi/sdt.rs | 5 + src/stop.rs | 14 +- 15 files changed, 2982 insertions(+), 89 deletions(-) create mode 100644 src/acpi/aml/dataobj.rs create mode 100644 src/acpi/aml/mod.rs create mode 100644 src/acpi/aml/namedobj.rs create mode 100644 src/acpi/aml/namespace.rs create mode 100644 src/acpi/aml/namespacemodifier.rs create mode 100644 src/acpi/aml/namestring.rs create mode 100644 src/acpi/aml/parsermacros.rs create mode 100644 src/acpi/aml/pkglength.rs create mode 100644 src/acpi/aml/termlist.rs create mode 100644 src/acpi/aml/type1opcode.rs create mode 100644 src/acpi/aml/type2opcode.rs delete mode 100644 src/acpi/dsdt.rs diff --git a/src/acpi/aml/dataobj.rs b/src/acpi/aml/dataobj.rs new file mode 100644 index 0000000..4400c8d --- /dev/null +++ b/src/acpi/aml/dataobj.rs @@ -0,0 +1,168 @@ +use collections::vec::Vec; +use collections::string::String; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; + +use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package, + DefBuffer, DefPackage, DefVarPackage}; +use super::termlist::{parse_term_arg, TermArg}; +use super::namestring::{parse_super_name, SuperName}; + +#[derive(Debug, Clone)] +pub enum DataObj { + ComputationalData(ComputationalData), + DefPackage(DefPackage), + DefVarPackage(DefVarPackage) +} + +#[derive(Debug, Clone)] +pub enum DataRefObj { + DataObj(DataObj), + ObjectReference(TermArg), + DDBHandle(SuperName) +} + +#[derive(Debug, Clone)] +pub struct ArgObj(u8); +#[derive(Debug, Clone)] +pub struct LocalObj(u8); +// Not actually doing anything to contain data, but does give us type guarantees, which is useful + +#[derive(Debug, Clone)] +pub enum ComputationalData { + Byte(u8), + Word(u16), + DWord(u32), + QWord(u64), + String(String), + Zero, + One, + Ones, + DefBuffer(DefBuffer), + RevisionOp +} + +impl AmlExecutable for DataRefObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + DataRefObj::DataObj(ref cd) => cd.execute(namespace, scope), + _ => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for DataObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + DataObj::ComputationalData(ref cd) => cd.execute(namespace, scope), + DataObj::DefPackage(ref pkg) => pkg.execute(namespace, scope), + _ => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for ComputationalData { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + ComputationalData::Byte(b) => Some(AmlValue::IntegerConstant(b as u64)), + ComputationalData::Word(w) => Some(AmlValue::IntegerConstant(w as u64)), + ComputationalData::DWord(d) => Some(AmlValue::IntegerConstant(d as u64)), + ComputationalData::QWord(q) => Some(AmlValue::IntegerConstant(q as u64)), + ComputationalData::Zero => Some(AmlValue::IntegerConstant(0)), + ComputationalData::One => Some(AmlValue::IntegerConstant(1)), + ComputationalData::Ones => Some(AmlValue::IntegerConstant(0xFFFFFFFFFFFFFFFF)), + _ => Some(AmlValue::Integer) + } + } +} + +pub fn parse_data_obj(data: &[u8]) -> Result<(DataObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(DataObj::ComputationalData, parse_computational_data), + parser_wrap!(DataObj::DefPackage, parse_def_package), + parser_wrap!(DataObj::DefVarPackage, parse_def_var_package) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_data_ref_obj(data: &[u8]) -> Result<(DataRefObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(DataRefObj::DataObj, parse_data_obj), + parser_wrap!(DataRefObj::ObjectReference, parse_term_arg), + parser_wrap!(DataRefObj::DDBHandle, parse_super_name) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_arg_obj(data: &[u8]) -> Result<(ArgObj, usize), AmlInternalError> { + match data[0] { + 0x68 ... 0x6E => Ok((ArgObj(data[0] - 0x68), 1 as usize)), + _ => Err(AmlInternalError::AmlInvalidOpCode) + } +} + +pub fn parse_local_obj(data: &[u8]) -> Result<(LocalObj, usize), AmlInternalError> { + match data[0] { + 0x60 ... 0x67 => Ok((LocalObj(data[0] - 0x60), 1 as usize)), + _ => Err(AmlInternalError::AmlInvalidOpCode) + } +} + +fn parse_computational_data(data: &[u8]) -> Result<(ComputationalData, usize), AmlInternalError> { + match data[0] { + 0x0A => Ok((ComputationalData::Byte(data[1]), 2 as usize)), + 0x0B => { + let res = (data[1] as u16) + + ((data[2] as u16) << 8); + Ok((ComputationalData::Word(res), 3 as usize)) + }, + 0x0C => { + let res = (data[1] as u32) + + ((data[2] as u32) << 8) + + ((data[3] as u32) << 16) + + ((data[4] as u32) << 24); + Ok((ComputationalData::DWord(res), 5 as usize)) + }, + 0x0D => { + let mut cur_ptr: usize = 1; + let mut cur_string: Vec = vec!(); + + while data[cur_ptr] != 0x00 { + cur_string.push(data[cur_ptr]); + cur_ptr += 1; + } + + match String::from_utf8(cur_string) { + Ok(s) => Ok((ComputationalData::String(s.clone()), s.clone().len() + 2)), + Err(_) => Err(AmlInternalError::AmlParseError("String data - invalid string")) + } + }, + 0x0E => { + let res = (data[1] as u64) + + ((data[2] as u64) << 8) + + ((data[3] as u64) << 16) + + ((data[4] as u64) << 24) + + ((data[5] as u64) << 32) + + ((data[6] as u64) << 40) + + ((data[7] as u64) << 48) + + ((data[8] as u64) << 56); + Ok((ComputationalData::QWord(res), 9 as usize)) + }, + 0x00 => Ok((ComputationalData::Zero, 1 as usize)), + 0x01 => Ok((ComputationalData::One, 1 as usize)), + 0x5B => if data[1] == 0x30 { + Ok((ComputationalData::RevisionOp, 2 as usize)) + } else { + Err(AmlInternalError::AmlInvalidOpCode) + }, + 0xFF => Ok((ComputationalData::Ones, 1 as usize)), + _ => match parse_def_buffer(data) { + Ok((res, size)) => Ok((ComputationalData::DefBuffer(res), size)), + Err(e) => Err(e) + } + } +} diff --git a/src/acpi/aml/mod.rs b/src/acpi/aml/mod.rs new file mode 100644 index 0000000..3d35395 --- /dev/null +++ b/src/acpi/aml/mod.rs @@ -0,0 +1,85 @@ +//! # AML +//! Code to parse and execute AML tables + +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; +use core::fmt::Debug; +use core::str::FromStr; + +use super::sdt::Sdt; + +#[macro_use] +mod parsermacros; + +mod namespace; +mod termlist; +mod namespacemodifier; +mod pkglength; +mod namestring; +mod namedobj; +mod dataobj; +mod type1opcode; +mod type2opcode; + +use self::termlist::{parse_term_list, TermObj}; +pub use self::namespace::{AmlNamespace, AmlValue}; +use self::namespace::AmlNamespaceContents; + +// TODO: This should be able to take parameters, and may also return multiple values +pub trait AmlExecutable { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option; +} + +// TODO: make private +pub enum AmlInternalError { + AmlParseError(&'static str), + AmlInvalidOpCode, + AmlDeferredLoad +} + +pub enum AmlError { + AmlParseError(&'static str) +} + +pub fn get_namespace_string(current: String, modifier: String) -> String { + if modifier.starts_with("\\") { + return modifier; + } + + if modifier.starts_with("^") { + // TODO + } + + let mut namespace = current.clone(); + namespace.push('.'); + namespace + &modifier +} + +pub fn parse_aml_table(sdt: &'static Sdt) -> Result { + let data = sdt.data(); + + let term_list = match parse_term_list(data) { + Ok(res) => res, + Err(AmlInternalError::AmlParseError(s)) => return Err(AmlError::AmlParseError(s)), + Err(AmlInternalError::AmlInvalidOpCode) => return Err(AmlError::AmlParseError("Unable to match opcode")), + Err(AmlInternalError::AmlDeferredLoad) => return Err(AmlError::AmlParseError("Deferred load reached top level")) + }; + + let global_namespace_specifier = String::from_str("\\").unwrap(); + // Unwrap is fine here. I mean come on, if this goes wrong you've got bigger problems than AML + // not loading... + + let mut global_namespace = AmlNamespace::new_namespace(&global_namespace_specifier); + term_list.execute(&mut global_namespace, global_namespace_specifier.clone()); + + Ok(global_namespace) +} + +pub fn is_aml_table(sdt: &'static Sdt) -> bool { + if &sdt.signature == b"DSDT" {//|| &sdt.signature == b"SSDT" { + true + } else { + false + } +} diff --git a/src/acpi/aml/namedobj.rs b/src/acpi/aml/namedobj.rs new file mode 100644 index 0000000..67c2e32 --- /dev/null +++ b/src/acpi/aml/namedobj.rs @@ -0,0 +1,783 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::namestring::{parse_name_string, parse_name_seg}; +use super::termlist::{parse_term_arg, parse_term_list, parse_object_list, TermArg, TermObj, Object}; +use super::pkglength::parse_pkg_length; +use super::type2opcode::{parse_def_buffer, DefBuffer}; + +#[derive(Debug, Clone)] +pub enum NamedObj { + DefBankField { + region_name: String, + bank_name: String, + bank_value: TermArg, + flags: FieldFlags, + field_list: Vec + }, + DefCreateBitField { + name: String, + source_buf: TermArg, + bit_index: TermArg + }, + DefCreateByteField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateDWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateQWordField { + name: String, + source_buf: TermArg, + byte_index: TermArg + }, + DefCreateField { + name: String, + source_buf: TermArg, + bit_index: TermArg, + num_bits: TermArg + }, + DefDataRegion { + name: String, + signature: TermArg, + oem_id: TermArg, + oem_table_id: TermArg + }, + DefDevice { + name: String, + obj_list: Vec + }, + DefEvent { + name: String + }, + DefOpRegion { + name: String, + region: RegionSpace, + offset: TermArg, + len: TermArg + }, + DefField { + name: String, + flags: FieldFlags, + field_list: Vec + }, + DefIndexField { + idx_name: String, + data_name: String, + flags: FieldFlags, + field_list: Vec + }, + DefMethod { + name: String, + method: Method + }, + DefMutex { + name: String, + sync_level: u8 + }, + DefPowerRes { + name: String, + system_level: u8, + resource_order: u16, + obj_list: Vec + }, + DefProcessor { + name: String, + proc_id: u8, + p_blk_addr: u32, + p_blk_len: u8, + obj_list: Vec + }, + DefThermalZone { + name: String, + obj_list: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub struct Method { + arg_count: u8, + serialized: bool, + sync_level: u8, + term_list: Vec +} + +impl AmlExecutable for NamedObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + NamedObj::DefOpRegion { ref name, ref region, ref offset, ref len } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + + let resolved_offset = match offset.execute(namespace, scope.clone()) { + Some(r) => r, + _ => return None + }; + + let resolved_len = match len.execute(namespace, scope.clone()) { + Some(r) => r, + _ => return None + }; + + namespace.push_to(local_scope_string, AmlNamespaceContents::OpRegion { + region: *region, + offset: resolved_offset, + len: resolved_len + }); + }, + NamedObj::DefField { ref name, ref flags, ref field_list } => { + let mut offset: usize = 0; + + for f in field_list { + match *f { + FieldElement::ReservedField { length } => offset += length, + FieldElement::NamedField { name: ref field_name, length } => { + let local_scope_string = get_namespace_string(scope.clone(), + field_name.clone()); + namespace.push_to(local_scope_string, AmlNamespaceContents::Field { + op_region: name.clone(), + flags: flags.clone(), + offset: offset.clone(), + length: length.clone() + }); + + offset += length; + }, + _ => () + } + } + }, + NamedObj::DefMethod { ref name, ref method } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + namespace.push_to(local_scope_string, AmlNamespaceContents::Value( + AmlValue::Method(method.clone()))); + }, + _ => () + } + + None + } +} + +#[derive(Debug, Copy, Clone)] +pub enum RegionSpace { + SystemMemory, + SystemIO, + PCIConfig, + EmbeddedControl, + SMBus, + SystemCMOS, + PciBarTarget, + IPMI, + GeneralPurposeIO, + GenericSerialBus, + UserDefined(u8) +} + +#[derive(Debug, Clone)] +pub struct FieldFlags { + access_type: AccessType, + lock_rule: bool, + update_rule: UpdateRule +} + +#[derive(Debug, Clone)] +pub enum AccessType { + AnyAcc, + ByteAcc, + WordAcc, + DWordAcc, + QWordAcc, + BufferAcc +} + +#[derive(Debug, Clone)] +pub enum UpdateRule { + Preserve, + WriteAsOnes, + WriteAsZeros +} + +#[derive(Debug, Clone)] +pub enum FieldElement { + NamedField { + name: String, + length: usize + }, + ReservedField { + length: usize + }, + AccessField { + access_type: AccessType, + access_attrib: AccessAttrib + }, + ConnectFieldNameString(String), + ConnectFieldBufferData(DefBuffer), +} + +#[derive(Debug, Clone)] +pub enum AccessAttrib { + AttribBytes(u8), + AttribRawBytes(u8), + AttribRawProcessBytes(u8), + AttribQuick, + AttribSendReceive, + AttribByte, + AttribWord, + AttribBlock, + AttribProcessCall, + AttribBlockProcessCall +} + +pub fn parse_named_obj(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_selector! { + data, + parse_def_bank_field, + parse_def_create_bit_field, + parse_def_create_byte_field, + parse_def_create_word_field, + parse_def_create_dword_field, + parse_def_create_qword_field, + parse_def_create_field, + parse_def_data_region, + parse_def_event, + parse_def_device, + parse_def_op_region, + parse_def_field, + parse_def_index_field, + parse_def_method, + parse_def_mutex, + parse_def_power_res, + parse_def_processor, + parse_def_thermal_zone + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_def_bank_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x87); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (region_name, region_name_len) = match parse_name_string( + &data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (bank_name, bank_name_len) = match parse_name_string( + &data[2 + pkg_length_len + region_name_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (bank_value, bank_value_len) = match parse_term_arg( + &data[2 + pkg_length_len + region_name_len .. 2 + pkg_length]) { + Ok(res) => res, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + region_name_len + bank_name_len + bank_value_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("BankField - invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("BankField - invalid update rule")) + } + }; + + let field_list = match parse_field_list( + &data[3 + pkg_length_len + region_name_len + bank_name_len + bank_value_len .. + 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefBankField {region_name, bank_name, bank_value, flags, field_list}, + 2 + pkg_length)) +} + +fn parse_def_create_bit_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8D); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (bit_index, bit_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + bit_index_len..])?; + + Ok((NamedObj::DefCreateBitField {name, source_buf, bit_index}, + 1 + source_buf_len + bit_index_len + name_len)) +} + +fn parse_def_create_byte_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8C); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateByteField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_word_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8B); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_dword_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8A); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateDWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_qword_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x8F); + + let (source_buf, source_buf_len) = parse_term_arg(&data[1..])?; + let (byte_index, byte_index_len) = parse_term_arg(&data[1 + source_buf_len..])?; + let (name, name_len) = parse_name_string(&data[1 + source_buf_len + byte_index_len..])?; + + Ok((NamedObj::DefCreateQWordField {name, source_buf, byte_index}, + 1 + source_buf_len + byte_index_len + name_len)) +} + +fn parse_def_create_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x13); + + let (source_buf, source_buf_len) = parse_term_arg(&data[2..])?; + let (bit_index, bit_index_len) = parse_term_arg(&data[2 + source_buf_len..])?; + let (num_bits, num_bits_len) = parse_term_arg(&data[2 + source_buf_len + bit_index_len..])?; + let (name, name_len) = parse_name_string( + &data[2 + source_buf_len + bit_index_len + num_bits_len..])?; + + Ok((NamedObj::DefCreateField {name, source_buf, bit_index, num_bits}, + 2 + source_buf_len + bit_index_len + num_bits_len + name_len)) +} + +fn parse_def_data_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x88); + + let (name, name_len) = parse_name_string(&data[2..])?; + let (signature, signature_len) = parse_term_arg(&data[2 + name_len..])?; + let (oem_id, oem_id_len) = parse_term_arg(&data[2 + name_len + signature_len..])?; + let (oem_table_id, oem_table_id_len) = parse_term_arg( + &data[2 + name_len + signature_len + oem_id_len..])?; + + Ok((NamedObj::DefDataRegion {name, signature, oem_id, oem_table_id}, + 2 + name_len + signature_len + oem_id_len + oem_table_id_len)) +} + +fn parse_def_event(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x02); + + let (name, name_len) = parse_name_string(&data[2..])?; + + Ok((NamedObj::DefEvent {name}, 2 + name_len)) +} + +fn parse_def_device(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x82); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let obj_list = match parse_object_list(&data[2 + pkg_length_len + name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefDevice {name, obj_list}, 2 + pkg_length_len)) +} + +fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x80); + + let (name, name_len) = parse_name_string(&data[2..])?; + let region = match data[2 + name_len] { + 0x00 => RegionSpace::SystemMemory, + 0x01 => RegionSpace::SystemIO, + 0x02 => RegionSpace::PCIConfig, + 0x03 => RegionSpace::EmbeddedControl, + 0x04 => RegionSpace::SMBus, + 0x05 => RegionSpace::SystemCMOS, + 0x06 => RegionSpace::PciBarTarget, + 0x07 => RegionSpace::IPMI, + 0x08 => RegionSpace::GeneralPurposeIO, + 0x09 => RegionSpace::GenericSerialBus, + 0x80 ... 0xFF => RegionSpace::UserDefined(data[2 + name_len]), + _ => return Err(AmlInternalError::AmlParseError("OpRegion - invalid region")) + }; + + let (offset, offset_len) = parse_term_arg(&data[3 + name_len..])?; + let (len, len_len) = parse_term_arg(&data[3 + name_len + offset_len..])?; + + Ok((NamedObj::DefOpRegion {name, region, offset, len}, 3 + name_len + offset_len + len_len)) +} + +fn parse_def_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x81); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + name_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("Field - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("Field - Invalid update rule")) + } + }; + + let field_list = match parse_field_list(&data[3 + pkg_length_len + name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefField {name, flags, field_list}, 2 + pkg_length)) +} + +fn parse_def_index_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x86); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let (idx_name, idx_name_len) = match parse_name_string( + &data[2 + pkg_length_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let (data_name, data_name_len) = match parse_name_string( + &data[2 + pkg_length_len + idx_name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + let flags_raw = data[2 + pkg_length_len + idx_name_len + data_name_len]; + let flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid update rule")) + } + }; + + let field_list = match parse_field_list( + &data[3 + pkg_length_len + idx_name_len + data_name_len .. 2 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefIndexField {idx_name, data_name, flags, field_list}, 2 + pkg_length)) +} + +fn parse_field_list(data: &[u8]) -> Result, AmlInternalError> { + let mut terms: Vec = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = match parse_field_element(&data[current_offset..]) { + Ok(r) => r, + Err(AmlInternalError::AmlInvalidOpCode) => + return Err(AmlInternalError::AmlParseError("FieldList - no valid field")), + Err(e) => return Err(e) + }; + + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +fn parse_field_element(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_selector! { + data, + parse_named_field, + parse_reserved_field, + parse_access_field, + parse_connect_field + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_named_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + let (name_seg, name_seg_len) = parse_name_seg(&data[0..4])?; + let name = match String::from_utf8(name_seg) { + Ok(s) => s, + Err(_) => return Err(AmlInternalError::AmlParseError("NamedField - invalid name")) + }; + let (length, length_len) = parse_pkg_length(&data[4..])?; + + Ok((FieldElement::NamedField {name, length}, 4 + length_len)) +} + +fn parse_reserved_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x00); + + let (length, length_len) = parse_pkg_length(&data[1..])?; + Ok((FieldElement::ReservedField {length}, 1 + length_len)) +} + +fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x01, 0x03); + + let flags_raw = data[1]; + let access_type = match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc, + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access type")) + }; + + let access_attrib = match (flags_raw & 0xC0) >> 6 { + 0 => match data[2] { + 0x02 => AccessAttrib::AttribQuick, + 0x04 => AccessAttrib::AttribSendReceive, + 0x06 => AccessAttrib::AttribByte, + 0x08 => AccessAttrib::AttribWord, + 0x0A => AccessAttrib::AttribBlock, + 0x0B => AccessAttrib::AttribBytes(data[3]), + 0x0C => AccessAttrib::AttribProcessCall, + 0x0D => AccessAttrib::AttribBlockProcessCall, + 0x0E => AccessAttrib::AttribRawBytes(data[3]), + 0x0F => AccessAttrib::AttribRawProcessBytes(data[3]), + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + }, + 1 => AccessAttrib::AttribBytes(data[2]), + 2 => AccessAttrib::AttribRawBytes(data[2]), + 3 => AccessAttrib::AttribRawProcessBytes(data[2]), + _ => return Err(AmlInternalError::AmlParseError("AccessField - Invalid access attrib")) + // This should never happen but the compiler bitches if I don't cover this + }; + + return Ok((FieldElement::AccessField {access_type, access_attrib}, if data[0] == 0x01 { + 3 as usize + } else { + 4 as usize + })) +} + +fn parse_connect_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { + parser_opcode!(data, 0x02); + + match parse_def_buffer(&data[1..]) { + Ok((buf, buf_len)) => return Ok((FieldElement::ConnectFieldBufferData(buf), buf_len + 1)), + Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + + match parse_name_string(&data[1..]) { + Ok((name, name_len)) => Ok((FieldElement::ConnectFieldNameString(name), name_len + 1)), + Err(AmlInternalError::AmlInvalidOpCode) => Err(AmlInternalError::AmlParseError("ConnectField - unable to match field")), + Err(e) => Err(e) + } +} + +fn parse_def_method(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode!(data, 0x14); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[1..])?; + let (name, name_len) = match parse_name_string(&data[1 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 1 + pkg_len].to_vec()), 1 + pkg_len)), + Err(e) => return Err(e) + }; + let flags = data[1 + pkg_len_len + name_len]; + + let arg_count = flags & 0x07; + let serialized = (flags & 0x08) == 0x08; + let sync_level = flags & 0xF0 >> 4; + + let term_list = match parse_term_list(&data[2 + pkg_len_len + name_len .. 1 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 1 + pkg_len].to_vec()), 1 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefMethod { + name: name, + method: Method { + arg_count, + serialized, + sync_level, + term_list + } + }, pkg_len + 1)) +} + +fn parse_def_mutex(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x01); + + let (name, name_len) = match parse_name_string(&data[2 ..]) { + Ok(p) => p, + Err(e) => return Err(e), + }; + let flags = data[2 + name_len]; + let sync_level = flags & 0x0F; + + Ok((NamedObj::DefMutex {name, sync_level}, name_len + 3)) +} + +fn parse_def_power_res(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x84); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let system_level = data[2 + pkg_len_len + name_len]; + let resource_order: u16 = (data[3 + pkg_len_len + name_len] as u16) + + ((data[4 + pkg_len_len + name_len] as u16) << 8); + + let obj_list = match parse_object_list(&data[5 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefPowerRes {name, system_level, resource_order, obj_list}, 2 + pkg_len)) +} + +fn parse_def_processor(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x83); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let proc_id = data[2 + pkg_len_len + name_len]; + let p_blk_addr: u32 = (data[3 + pkg_len_len + name_len] as u32) + + ((data[4 + pkg_len_len + name_len] as u32) << 8) + + ((data[5 + pkg_len_len + name_len] as u32) << 16) + + ((data[6 + pkg_len_len + name_len] as u32) << 24); + let p_blk_len = data[7 + pkg_len_len + name_len]; + + let obj_list = match parse_object_list(&data[8 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefProcessor {name, proc_id, p_blk_addr, p_blk_len, obj_list}, 2 + pkg_len)) +} + +fn parse_def_thermal_zone(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x85); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let (name, name_len) = match parse_name_string(&data[2 + pkg_len_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + let obj_list = match parse_object_list(&data[2 + pkg_len_len + name_len .. 2 + pkg_len]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), + Err(e) => return Err(e) + }; + + Ok((NamedObj::DefThermalZone {name, obj_list}, 2 + pkg_len)) +} diff --git a/src/acpi/aml/namespace.rs b/src/acpi/aml/namespace.rs new file mode 100644 index 0000000..8a0c6f9 --- /dev/null +++ b/src/acpi/aml/namespace.rs @@ -0,0 +1,225 @@ +use collections::string::String; +use collections::vec::Vec; +use collections::boxed::Box; + +use core::str::FromStr; + +use super::namedobj::{ RegionSpace, FieldFlags, Method }; + +#[derive(Debug, Clone)] +pub struct AmlNamespace { + name: String, + contents: AmlNamespaceContents +} + +#[derive(Debug, Clone)] +pub enum AmlNamespaceContents { + Value(AmlValue), + SubNamespace(Box), + Namespace(Vec), + OpRegion { + region: RegionSpace, + offset: AmlValue, + len: AmlValue + }, + Field { + op_region: String, + flags: FieldFlags, + offset: usize, + length: usize + } +} + +#[derive(Debug, Clone)] +pub enum AmlValue { + Uninitialized, + Buffer, + BufferField, + DDBHandle, + DebugObject, + Device, + Event, + FieldUnit, + Integer, + IntegerConstant(u64), + Method(Method), + Mutex, + ObjectReference, + OperationRegion, + Package(Vec), + String, + PowerResource, + Processor, + RawDataBuffer, + ThermalZone +} + +impl AmlValue { + pub fn get_as_package(&self) -> Option> { + match *self { + AmlValue::Package(ref p) => Some(p.clone()), + _ => None + } + } + + pub fn get_as_integer(&self) -> Option { + match *self { + AmlValue::IntegerConstant(ref i) => Some(i.clone()), + _ => None + } + } +} + +impl AmlNamespace { + pub fn new_namespace(name: &String) -> AmlNamespace { + AmlNamespace { + name: name.clone(), + contents: AmlNamespaceContents::Namespace(vec!()) + } + } + + pub fn find_str(&self, scope_str: &str) -> Option { + let scope_string = String::from_str(scope_str).unwrap(); + self.find(scope_string) + } + + pub fn find(&self, scope_string: String) -> Option { + if scope_string.len() == 0 { + match self.contents { + AmlNamespaceContents::Value(ref v) => return Some(v.clone()), + _ => return None + } + } + + let mut scope_string = scope_string.clone(); + + if scope_string.starts_with("\\") { + if self.name != "\\" { + return None; + } + + scope_string.remove(0); + } + + if scope_string.starts_with(".") { + scope_string.remove(0); + } + + if scope_string.len() == 0 { + match self.contents { + AmlNamespaceContents::Value(ref v) => return Some(v.clone()), + _ => return None + } + } + + let (current, nextset) = match scope_string.find(".") { + Some(s) => { + let (x, mut y) = scope_string.split_at(s); + y = &y[1..]; + + (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + }, + None => if scope_string.len() <= 4 { + (scope_string, String::from_str("").unwrap()) + } else { + return None; + } + }; + + match self.contents { + AmlNamespaceContents::Namespace(ref namespace) => { + // TODO: Remove this while loop here, there has to be a more elegant way + let mut current_index = 0; + while current_index < namespace.len() { + match namespace[current_index] { + AmlNamespaceContents::SubNamespace(ref ns) => if ns.name == current { + return ns.find(nextset); + }, + _ => () + } + + current_index += 1; + } + }, + _ => () + } + + None + } + + pub fn push(&mut self, val: AmlNamespaceContents) { + match self.contents { + AmlNamespaceContents::Namespace(ref mut v) => v.push(val), + _ => () // TODO: Error this + } + } + + pub fn push_to(&mut self, scope_string: String, contents: AmlNamespaceContents) { + if scope_string.len() == 0 { + return; + } + + let mut scope_string = scope_string.clone(); + + if scope_string.starts_with("\\") { + if self.name != "\\" { + return; + // TODO: Error this + } + + scope_string.remove(0); + } + + if scope_string.starts_with(".") { + scope_string.remove(0); + } + + if scope_string.len() == 0 { + return; + } + + let (current, nextset) = match scope_string.find(".") { + Some(s) => { + let (x, mut y) = scope_string.split_at(s); + y = &y[1..]; + + (String::from_str(x).unwrap(), String::from_str(y).unwrap()) + }, + None => if scope_string.len() <= 4 { + (scope_string, String::from_str("").unwrap()) + } else { + return; + } + }; + + match self.contents { + AmlNamespaceContents::Namespace(ref mut namespace) => { + // TODO: Remove this while loop here, there has to be a more elegant way + let mut current_index = 0; + while current_index < namespace.len() { + match namespace[current_index] { + AmlNamespaceContents::SubNamespace(ref mut ns) => if ns.name == current { + ns.push_to(nextset, contents); + return; + }, + _ => () + } + + current_index += 1; + } + + let mut next = AmlNamespace { + name: current, + contents: contents + }; + + namespace.push(AmlNamespaceContents::SubNamespace(Box::new(next))); + } + _ => () // TODO: Error this + } + } + + pub fn push_subordinate_namespace(&mut self, scope_string: String) { + self.push_to(scope_string, AmlNamespaceContents::Namespace(vec!())); + } +} diff --git a/src/acpi/aml/namespacemodifier.rs b/src/acpi/aml/namespacemodifier.rs new file mode 100644 index 0000000..a49e2bb --- /dev/null +++ b/src/acpi/aml/namespacemodifier.rs @@ -0,0 +1,102 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; +use super::pkglength::parse_pkg_length; +use super::namestring::parse_name_string; +use super::termlist::{parse_term_list, TermObj}; +use super::dataobj::{parse_data_ref_obj, DataRefObj}; + +#[derive(Debug, Clone)] +pub enum NamespaceModifier { + Name { + name: String, + data_ref_obj: DataRefObj + }, + Scope { + name: String, + terms: Vec + }, + Alias { + source_name: String, + alias_name: String + }, + DeferredLoad(Vec) +} + +impl AmlExecutable for NamespaceModifier { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + NamespaceModifier::Scope { name: ref name, terms: ref terms } => { + let local_scope_string = get_namespace_string(scope, name.clone()); + namespace.push_subordinate_namespace(local_scope_string.clone()); + + terms.execute(namespace, local_scope_string); + }, + NamespaceModifier::Name { ref name, ref data_ref_obj } => { + let local_scope_string = get_namespace_string(scope.clone(), name.clone()); + let dro = match data_ref_obj.execute(namespace, scope) { + Some(s) => s, + None => return None + }; + + namespace.push_to(local_scope_string, AmlNamespaceContents::Value(dro)); + }, + _ => () + } + + None + } +} + +pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_selector! { + data, + parse_alias_op, + parse_scope_op, + parse_name_op + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_alias_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x06); + + let (source_name, source_name_len) = parse_name_string(&data[1..])?; + let (alias_name, alias_name_len) = parse_name_string(&data[1 + source_name_len..])?; + + Ok((NamespaceModifier::Alias {source_name, alias_name}, 1 + source_name_len + alias_name_len)) +} + +fn parse_name_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x08); + + let (name, name_len) = parse_name_string(&data[1..])?; + let (data_ref_obj, data_ref_obj_len) = parse_data_ref_obj(&data[1 + name_len..])?; + + Ok((NamespaceModifier::Name {name, data_ref_obj}, 1 + name_len + data_ref_obj_len)) +} + +fn parse_scope_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { + parser_opcode!(data, 0x10); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (name, name_len) = match parse_name_string(&data[1 + pkg_length_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamespaceModifier::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + let terms = match parse_term_list(&data[1 + pkg_length_len + name_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((NamespaceModifier::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((NamespaceModifier::Scope {name, terms}, pkg_length + 1)) +} diff --git a/src/acpi/aml/namestring.rs b/src/acpi/aml/namestring.rs new file mode 100644 index 0000000..8015a8c --- /dev/null +++ b/src/acpi/aml/namestring.rs @@ -0,0 +1,188 @@ +use collections::vec::Vec; +use collections::string::String; + +use super::AmlInternalError; + +use super::dataobj::{parse_arg_obj, parse_local_obj, ArgObj, LocalObj}; +use super::type2opcode::{parse_type6_opcode, Type6OpCode}; + +#[derive(Debug, Clone)] +pub enum SuperName { + NameString(String), + ArgObj(ArgObj), + LocalObj(LocalObj), + DebugObj, + Type6OpCode(Type6OpCode) +} + +#[derive(Debug, Clone)] +pub enum Target { + SuperName(SuperName), + Null +} + +pub fn parse_name_string(data: &[u8]) -> Result<(String, usize), AmlInternalError> { + let mut characters: Vec = vec!(); + let mut starting_index: usize = 0; + + if data[0] == 0x5C { + characters.push(data[0]); + starting_index = 1; + } else if data[0] == 0x5E { + while data[starting_index] == 0x5E { + characters.push(data[starting_index]); + starting_index += 1; + } + } + + let sel = |data| { + parser_selector! { + data, + parse_dual_name_path, + parse_multi_name_path, + parse_null_name, + parse_name_seg + }; + + Err(AmlInternalError::AmlInvalidOpCode) + }; + let (mut chr, len) = sel(&data[starting_index..])?; + characters.append(&mut chr); + + let name_string = String::from_utf8(characters); + + match name_string { + Ok(s) => Ok((s.clone(), len + starting_index)), + Err(_) => Err(AmlInternalError::AmlParseError("Namestring - Name is invalid")) + } +} + +fn parse_null_name(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + parser_opcode!(data, 0x00); + Ok((vec!(), 1 as usize)) +} + +pub fn parse_name_seg(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + match data[0] { + 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[1] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[2] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + match data[3] { + 0x30 ... 0x39 | 0x41 ... 0x5A | 0x5F => (), + _ => return Err(AmlInternalError::AmlInvalidOpCode) + } + + let mut name_seg = vec!(data[0], data[1], data[2], data[3]); + while *(name_seg.last().unwrap()) == 0x5F { + name_seg.pop(); + } + + Ok((name_seg, 4 as usize)) +} + +fn parse_dual_name_path(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + parser_opcode!(data, 0x2E); + + let mut characters: Vec = vec!(); + let mut dual_len: usize = 1; + + match parse_name_seg(&data[1..5]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + match parse_name_seg(&data[5..9]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + Ok((characters, dual_len)) +} + +fn parse_multi_name_path(data: &[u8]) -> Result<(Vec, usize), AmlInternalError> { + parser_opcode!(data, 0x2F); + + let seg_count = data[1]; + if seg_count == 0x00 { + return Err(AmlInternalError::AmlParseError("MultiName Path - can't have zero name segments")); + } + + let mut current_seg = 0; + let mut characters: Vec = vec!(); + let mut multi_len: usize = 2; + + while current_seg < seg_count { + match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) { + Ok((mut v, len)) => { + characters.append(&mut v); + multi_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + current_seg += 1; + } + + characters.pop(); + + Ok((characters, multi_len)) +} + +pub fn parse_super_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_selector! { + data, + parse_simple_name, + parser_wrap!(SuperName::Type6OpCode, parse_type6_opcode), + parse_debug_obj + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_debug_obj(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x31); + Ok((SuperName::DebugObj, 2 as usize)) +} + +pub fn parse_simple_name(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(SuperName::NameString, parse_name_string), + parser_wrap!(SuperName::ArgObj, parse_arg_obj), + parser_wrap!(SuperName::LocalObj, parse_local_obj) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_target(data: &[u8]) -> Result<(Target, usize), AmlInternalError> { + if data[0] == 0x00 { + Ok((Target::Null, 1 as usize)) + } else { + match parse_super_name(data) { + Ok((name, name_len)) => Ok((Target::SuperName(name), name_len)), + Err(e) => Err(e) + } + } +} diff --git a/src/acpi/aml/parsermacros.rs b/src/acpi/aml/parsermacros.rs new file mode 100644 index 0000000..50e3aed --- /dev/null +++ b/src/acpi/aml/parsermacros.rs @@ -0,0 +1,49 @@ +#[macro_export] +macro_rules! parser_selector { + {$data:expr, $func:expr} => { + match $func($data) { + Ok(res) => return Ok(res), + Err(AmlInternalError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + }; + {$data:expr, $func:expr, $($funcs:expr),+} => { + parser_selector! {$data, $func}; + parser_selector! {$data, $($funcs),*}; + }; +} + +#[macro_export] +macro_rules! parser_wrap { + ($wrap:expr, $func:expr) => { + |data| { + match $func(data) { + Ok((res, size)) => Ok(($wrap(res), size)), + Err(e) => Err(e) + } + } + }; +} + +#[macro_export] +macro_rules! parser_opcode { + ($data:expr, $opcode:expr) => { + if $data[0] != $opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; + ($data:expr, $opcode:expr, $alternate_opcode:expr) => { + if $data[0] != $opcode && $data[0] != $alternate_opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; +} + +#[macro_export] +macro_rules! parser_opcode_extended { + ($data:expr, $opcode:expr) => { + if $data[0] != 0x5B || $data[1] != $opcode { + return Err(AmlInternalError::AmlInvalidOpCode); + } + }; +} diff --git a/src/acpi/aml/pkglength.rs b/src/acpi/aml/pkglength.rs new file mode 100644 index 0000000..7c4ace8 --- /dev/null +++ b/src/acpi/aml/pkglength.rs @@ -0,0 +1,25 @@ +use super::AmlInternalError; + +pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlInternalError> { + let lead_byte = data[0]; + let count_bytes: usize = (lead_byte >> 6) as usize; + + if count_bytes == 0 { + return Ok(((lead_byte & 0x3F) as usize, 1 as usize)); + } + + let upper_two = (lead_byte >> 4) & 0x03; + if upper_two != 0 { + return Err(AmlInternalError::AmlParseError("Invalid package length")); + } + + let mut current_byte = 0; + let mut pkg_len: usize = (lead_byte & 0x0F) as usize; + + while current_byte < count_bytes { + pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize; + current_byte += 1; + } + + return Ok((pkg_len, count_bytes + 1)); +} diff --git a/src/acpi/aml/termlist.rs b/src/acpi/aml/termlist.rs new file mode 100644 index 0000000..014bddb --- /dev/null +++ b/src/acpi/aml/termlist.rs @@ -0,0 +1,135 @@ +use collections::vec::Vec; +use collections::boxed::Box; +use collections::string::String; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; +use super::namespacemodifier::{parse_namespace_modifier, NamespaceModifier}; +use super::namedobj::{parse_named_obj, NamedObj}; +use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj, DataObj, ArgObj, LocalObj}; +use super::type1opcode::{parse_type1_opcode, Type1OpCode}; +use super::type2opcode::{parse_type2_opcode, Type2OpCode}; +use super::namestring::parse_name_string; + +#[derive(Debug, Clone)] +pub enum TermArg { + LocalObj(Box), + DataObj(Box), + ArgObj(Box), + Type2Opcode(Box) +} + +#[derive(Debug, Clone)] +pub enum TermObj { + NamespaceModifier(Box), + NamedObj(Box), + Type1Opcode(Box), + Type2Opcode(Box) +} + +#[derive(Debug, Clone)] +pub enum Object { + NamespaceModifier(Box), + NamedObj(Box) +} + +#[derive(Debug, Clone)] +pub struct MethodInvocation { + +} + +impl AmlExecutable for Vec { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + for term in self { + term.execute(namespace, scope.clone()); + } + + None + } +} + +impl AmlExecutable for TermArg { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + TermArg::LocalObj(ref l) => Some(AmlValue::Integer), + TermArg::DataObj(ref d) => d.execute(namespace, scope), + TermArg::ArgObj(ref a) => Some(AmlValue::Integer), + TermArg::Type2Opcode(ref o) => Some(AmlValue::Integer) + } + } +} + +impl AmlExecutable for TermObj { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + TermObj::NamespaceModifier(ref res) => res.execute(namespace, scope.clone()), + TermObj::NamedObj(ref res) => res.execute(namespace, scope.clone()), + TermObj::Type1Opcode(ref res) => res.execute(namespace, scope.clone()), + TermObj::Type2Opcode(ref res) => res.execute(namespace, scope.clone()) + } + } +} + +pub fn parse_term_list(data: &[u8]) -> Result, AmlInternalError> { + let mut terms: Vec = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = parse_term_obj(&data[current_offset..])?; + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +pub fn parse_term_arg(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(TermArg::LocalObj, parser_wrap!(Box::new, parse_local_obj)), + parser_wrap!(TermArg::DataObj, parser_wrap!(Box::new, parse_data_obj)), + parser_wrap!(TermArg::ArgObj, parser_wrap!(Box::new, parse_arg_obj)), + parser_wrap!(TermArg::Type2Opcode, parser_wrap!(Box::new, parse_type2_opcode)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_object_list(data: &[u8]) -> Result, AmlInternalError> { + let mut terms: Vec = vec!(); + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let (res, len) = parse_object(&data[current_offset..])?; + terms.push(res); + current_offset += len; + } + + Ok(terms) +} + +fn parse_object(data: &[u8]) -> Result<(Object, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(Object::NamespaceModifier, parser_wrap!(Box::new, parse_namespace_modifier)), + parser_wrap!(Object::NamedObj, parser_wrap!(Box::new, parse_named_obj)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_method_invocation(data: &[u8]) -> Result<(MethodInvocation, usize), AmlInternalError> { + let (name, name_len) = parse_name_string(data)?; + Err(AmlInternalError::AmlDeferredLoad) +} + +fn parse_term_obj(data: &[u8]) -> Result<(TermObj, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(TermObj::NamespaceModifier, parser_wrap!(Box::new, parse_namespace_modifier)), + parser_wrap!(TermObj::NamedObj, parser_wrap!(Box::new, parse_named_obj)), + parser_wrap!(TermObj::Type1Opcode, parser_wrap!(Box::new, parse_type1_opcode)), + parser_wrap!(TermObj::Type2Opcode, parser_wrap!(Box::new, parse_type2_opcode)) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} diff --git a/src/acpi/aml/type1opcode.rs b/src/acpi/aml/type1opcode.rs new file mode 100644 index 0000000..c6cc5ca --- /dev/null +++ b/src/acpi/aml/type1opcode.rs @@ -0,0 +1,259 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_term_list, TermObj, TermArg}; +use super::namestring::{parse_name_string, parse_super_name, SuperName}; + +#[derive(Debug, Clone)] +pub enum Type1OpCode { + DefBreak, + DefBreakPoint, + DefContinue, + DefFatal { + fatal_type: u8, + fatal_code: u16, + fatal_arg: TermArg + }, + DefNoop, + DefIfElse { + if_block: IfBlock, + else_block: IfBlock + }, + DefLoad { + name: String, + ddb_handle_object: SuperName + }, + DefNotify { + object: SuperName, + value: TermArg + }, + DefRelease(SuperName), + DefReset(SuperName), + DefSignal(SuperName), + DefSleep(TermArg), + DefStall(TermArg), + DefUnload(SuperName), + DefWhile { + predicate: TermArg, + block: Vec + }, + DefReturn(TermArg), + DeferredLoad(Vec) +} + +impl AmlExecutable for Type1OpCode { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub enum IfBlock { + If { + predicate: TermArg, + if_block: Vec + }, + Else(Vec), + NoBlock, + DeferredLoad(Vec) +} + +pub fn parse_type1_opcode(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + match data[0] { + 0xA5 => return Ok((Type1OpCode::DefBreak, 1 as usize)), + 0xCC => return Ok((Type1OpCode::DefBreakPoint, 1 as usize)), + 0x9F => return Ok((Type1OpCode::DefContinue, 1 as usize)), + 0xA3 => return Ok((Type1OpCode::DefNoop, 1 as usize)), + _ => () + } + + parser_selector! { + data, + parse_def_fatal, + parse_def_if_else, + parse_def_load, + parse_def_notify, + parse_def_release, + parse_def_reset, + parse_def_signal, + parse_def_sleep, + parse_def_stall, + parse_def_return, + parse_def_unload, + parse_def_while + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +fn parse_def_fatal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x32 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let fatal_type = data[2]; + let fatal_code: u16 = (data[3] as u16) + + ((data[4] as u16) << 8); + let (fatal_arg, fatal_arg_len) = parse_term_arg(&data[5..])?; + + Ok((Type1OpCode::DefFatal {fatal_type, fatal_code, fatal_arg}, fatal_arg_len + 5)) +} + +fn parse_def_load(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x20 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (name, name_len) = parse_name_string(&data[2..])?; + let (ddb_handle_object, ddb_handle_object_len) = parse_super_name(&data[2 + name_len..])?; + + Ok((Type1OpCode::DefLoad {name, ddb_handle_object}, 2 + name_len + ddb_handle_object_len)) +} + +fn parse_def_notify(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x86 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[1..])?; + let (value, value_len) = parse_term_arg(&data[1 + object_len..])?; + + Ok((Type1OpCode::DefNotify {object, value}, 1 + object_len + value_len)) +} + +fn parse_def_release(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x27 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefRelease(object), 2 + object_len)) +} + +fn parse_def_reset(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x26 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefReset(object), 2 + object_len)) +} + +fn parse_def_signal(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x24 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefSignal(object), 2 + object_len)) +} + +fn parse_def_sleep(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x22 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (time, time_len) = parse_term_arg(&data[2..])?; + + Ok((Type1OpCode::DefSleep(time), 2 + time_len)) +} + +fn parse_def_stall(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x21 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (time, time_len) = parse_term_arg(&data[2..])?; + + Ok((Type1OpCode::DefStall(time), 2 + time_len)) +} + +fn parse_def_unload(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x2A { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (object, object_len) = parse_super_name(&data[2..])?; + + Ok((Type1OpCode::DefUnload(object), 2 + object_len)) +} + +fn parse_def_if_else(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA0 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + + let if_block = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok((predicate, predicate_len)) => { + match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { + Ok(if_block) => IfBlock::If {predicate, if_block}, + Err(AmlInternalError::AmlDeferredLoad) => + IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + Err(e) => return Err(e) + } + }, + Err(AmlInternalError::AmlDeferredLoad) => + IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + Err(e) => return Err(e) + }; + + let (else_block, else_block_len) = parse_def_else(&data[1 + pkg_length..])?; + + return Ok((Type1OpCode::DefIfElse {if_block, else_block}, + pkg_length + else_block_len + 1)); +} + +fn parse_def_else(data: &[u8]) -> Result<(IfBlock, usize), AmlInternalError> { + if data.len() == 0 || data[0] != 0xA1 { + // We might be at the very end of a buffer, in which case there isn't an else + return Ok((IfBlock::NoBlock, 0)); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + match parse_term_list(&data[1 + pkg_length_len .. 1 + pkg_length]) { + Ok(term_list) => Ok((IfBlock::Else(term_list), 1 + pkg_length)), + Err(AmlInternalError::AmlDeferredLoad) => + Ok((IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + } +} + +fn parse_def_while(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA2 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (predicate, predicate_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((Type1OpCode::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + let block = match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { + Ok(p) => p, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((Type1OpCode::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((Type1OpCode::DefWhile {predicate, block}, pkg_length + 1)) +} + +fn parse_def_return(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalError> { + if data[0] != 0xA4 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (arg_object, arg_object_len) = parse_term_arg(&data[1..])?; + + Ok((Type1OpCode::DefReturn(arg_object), 1 + arg_object_len)) +} diff --git a/src/acpi/aml/type2opcode.rs b/src/acpi/aml/type2opcode.rs new file mode 100644 index 0000000..50d1ff2 --- /dev/null +++ b/src/acpi/aml/type2opcode.rs @@ -0,0 +1,932 @@ +use collections::vec::Vec; +use collections::string::String; +use collections::boxed::Box; + +use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_method_invocation, TermArg, MethodInvocation}; +use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name, + SuperName, Target}; +use super::dataobj::{parse_data_ref_obj, DataRefObj}; + +#[derive(Debug, Clone)] +pub enum Type2OpCode { + DefAcquire { + object: SuperName, + timeout: u16 + }, + DefBuffer(DefBuffer), + DefPackage(DefPackage), + DefVarPackage(DefVarPackage), + DefDerefOf(TermArg), + DefRefOf(SuperName), + DefIncrement(SuperName), + DefIndex(DefIndex), + DefDecrement(SuperName), + DefFindSetLeftBit { + operand: TermArg, + target: Target + }, + DefFindSetRightBit { + operand: TermArg, + target: Target + }, + DefFromBCD { + operand: TermArg, + target: Target + }, + DefDivide { + dividend: TermArg, + divisor: TermArg, + remainder: Target, + quotient: Target + }, + DefCondRefOf { + operand: SuperName, + target: Target + }, + DefCopyObject { + source: TermArg, + destination: SuperName + }, + DefLAnd { + lhs: TermArg, + rhs: TermArg + }, + DefLEqual { + lhs: TermArg, + rhs: TermArg + }, + DefLGreater { + lhs: TermArg, + rhs: TermArg + }, + DefLLess { + lhs: TermArg, + rhs: TermArg + }, + DefLNot(TermArg), + DefLOr { + lhs: TermArg, + rhs: TermArg + }, + DefSizeOf(SuperName), + DefStore { + operand: TermArg, + target: SuperName + }, + DefSubtract { + minuend: TermArg, + subtrahend: TermArg, + target: Target + }, + DefToBuffer { + operand: TermArg, + target: Target + }, + DefToHexString { + operand: TermArg, + target: Target + }, + DefToBCD { + operand: TermArg, + target: Target + }, + DefToDecimalString { + operand: TermArg, + target: Target + }, + DefToInteger { + operand: TermArg, + target: Target + }, + DefToString { + operand: TermArg, + length: TermArg, + target: Target + }, + DefConcat { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefConcatRes { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefShiftLeft { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefShiftRight { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefAdd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefMultiply { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefMod { + dividend: TermArg, + divisor: TermArg, + target: Target + }, + DefAnd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNAnd { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefOr { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefXor { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNOr { + lhs: TermArg, + rhs: TermArg, + target: Target + }, + DefNot { + operand: TermArg, + target: Target + }, + DefLoadTable { + signature: TermArg, + oem_id: TermArg, + oem_table_id: TermArg, + root_path: TermArg, + parameter_path: TermArg, + parameter_data: TermArg + }, + DefMatch { + search_pkg: TermArg, + first_operation: MatchOpcode, + first_operand: TermArg, + second_operation: MatchOpcode, + second_operand: TermArg, + start_index: TermArg + }, + DefMid { + source: TermArg, + index: TermArg, + length: TermArg, + target: Target + }, + DefWait { + event_object: SuperName, + operand: TermArg + }, + DefObjectType(DefObjectType), + DefTimer, + MethodInvocation(MethodInvocation) +} + +impl AmlExecutable for Type2OpCode { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub enum DefObjectType { + SuperName(SuperName), + DefIndex(DefIndex), + DefRefOf(SuperName), + DefDerefOf(TermArg) +} + +#[derive(Debug, Clone)] +pub enum MatchOpcode { + MTR, + MEQ, + MLE, + MLT, + MGE, + MGT +} + +#[derive(Debug, Clone)] +pub enum Type6OpCode { + DefDerefOf(TermArg), + DefRefOf(Box), + DefIndex(DefIndex), + MethodInvocation(MethodInvocation) +} + +#[derive(Debug, Clone)] +pub struct DefIndex { + obj: TermArg, + idx: TermArg, + target: Box +} + +#[derive(Debug, Clone)] +pub enum DefBuffer { + Buffer { + buffer_size: TermArg, + byte_list: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub enum DefPackage { + Package { + num_elements: u8, + elements: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub enum DefVarPackage { + Package { + num_elements: TermArg, + elements: Vec + }, + DeferredLoad(Vec) +} + +#[derive(Debug, Clone)] +pub enum PackageElement { + DataRefObj(DataRefObj), + NameString(String) +} + +impl AmlExecutable for DefPackage { + fn execute(&self, namespace: &mut AmlNamespace, scope: String) -> Option { + match *self { + DefPackage::Package { ref num_elements, ref elements } => { + let mut values: Vec = vec!(); + + for element in elements { + match *element { + PackageElement::DataRefObj(ref d) => { + let elem = match d.execute(namespace, scope.clone()) { + Some(e) => e, + None => continue + }; + + values.push(elem); + }, + _ => return None + } + } + + Some(AmlValue::Package(values)) + }, + _ => None + } + } +} + +pub fn parse_type2_opcode(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_selector! { + data, + parse_def_increment, + parse_def_acquire, + parse_def_wait, + parse_def_land, + parse_def_lequal, + parse_def_lgreater, + parse_def_lless, + parse_def_lnot, + parse_def_lor, + parse_def_size_of, + parse_def_store, + parse_def_subtract, + parse_def_to_buffer, + parse_def_to_hex_string, + parse_def_to_bcd, + parse_def_to_decimal_string, + parse_def_to_integer, + parse_def_to_string, + parse_def_add, + parse_def_xor, + parse_def_shift_left, + parse_def_shift_right, + parse_def_mod, + parse_def_and, + parse_def_or, + parse_def_concat_res, + parse_def_concat, + parse_def_cond_ref_of, + parse_def_copy_object, + parse_def_decrement, + parse_def_divide, + parse_def_find_set_left_bit, + parse_def_find_set_right_bit, + parse_def_from_bcd, + parse_def_load_table, + parse_def_match, + parse_def_mid, + parse_def_multiply, + parse_def_nand, + parse_def_nor, + parse_def_not, + parse_def_timer, + parser_wrap!(Type2OpCode::DefBuffer, parse_def_buffer), + parser_wrap!(Type2OpCode::DefPackage, parse_def_package), + parser_wrap!(Type2OpCode::DefVarPackage, parse_def_var_package), + parser_wrap!(Type2OpCode::DefObjectType, parse_def_object_type), + parser_wrap!(Type2OpCode::DefDerefOf, parse_def_deref_of), + parser_wrap!(Type2OpCode::DefRefOf, parse_def_ref_of), + parser_wrap!(Type2OpCode::DefIndex, parse_def_index), + parser_wrap!(Type2OpCode::MethodInvocation, parse_method_invocation) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_type6_opcode(data: &[u8]) -> Result<(Type6OpCode, usize), AmlInternalError> { + parser_selector! { + data, + parser_wrap!(Type6OpCode::DefDerefOf, parse_def_deref_of), + parser_wrap!(Type6OpCode::DefRefOf, parser_wrap!(Box::new, parse_def_ref_of)), + parser_wrap!(Type6OpCode::DefIndex, parse_def_index), + parser_wrap!(Type6OpCode::MethodInvocation, parse_method_invocation) + }; + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_def_object_type(data: &[u8]) -> Result<(DefObjectType, usize), AmlInternalError> { + parser_opcode!(data, 0x8E); + parser_selector! { + data, + parser_wrap!(DefObjectType::SuperName, parse_super_name), + parser_wrap!(DefObjectType::DefRefOf, parse_def_ref_of), + parser_wrap!(DefObjectType::DefDerefOf, parse_def_deref_of), + parser_wrap!(DefObjectType::DefIndex, parse_def_index) + } + + Err(AmlInternalError::AmlInvalidOpCode) +} + +pub fn parse_def_package(data: &[u8]) -> Result<(DefPackage, usize), AmlInternalError> { + parser_opcode!(data, 0x12); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let num_elements = data[1 + pkg_length_len]; + + let elements = match parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length]) { + Ok(e) => e, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((DefPackage::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((DefPackage::Package {num_elements, elements}, 1 + pkg_length)) +} + +pub fn parse_def_var_package(data: &[u8]) -> Result<(DefVarPackage, usize), AmlInternalError> { + parser_opcode!(data, 0x13); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (num_elements, num_elements_len) = parse_term_arg(&data[1 + pkg_length_len ..])?; + + let elements = match parse_package_elements_list(&data[1 + pkg_length_len + num_elements_len .. + 1 + pkg_length]) { + Ok(e) => e, + Err(AmlInternalError::AmlDeferredLoad) => + return Ok((DefVarPackage::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), + 1 + pkg_length)), + Err(e) => return Err(e) + }; + + Ok((DefVarPackage::Package {num_elements, elements}, 1 + pkg_length)) +} + +fn parse_package_elements_list(data: &[u8]) -> Result, AmlInternalError> { + let mut current_offset: usize = 0; + let mut elements: Vec = vec!(); + + while current_offset < data.len() { + match parse_data_ref_obj(&data[current_offset ..]) { + Ok((data_ref_obj, data_ref_obj_len)) => { + elements.push(PackageElement::DataRefObj(data_ref_obj)); + current_offset += data_ref_obj_len; + }, + Err(AmlInternalError::AmlInvalidOpCode) => + match parse_name_string(&data[current_offset ..]) { + Ok((name_string, name_string_len)) => { + elements.push(PackageElement::NameString(name_string)); + current_offset += name_string_len; + }, + Err(e) => return Err(e) + }, + Err(e) => return Err(e) + } + } + + Ok(elements) +} + +pub fn parse_def_buffer(data: &[u8]) -> Result<(DefBuffer, usize), AmlInternalError> { + parser_opcode!(data, 0x11); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let (buffer_size, buffer_size_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { + Ok(s) => s, + Err(AmlInternalError::AmlDeferredLoad) => return Ok((DefBuffer::DeferredLoad( + data[0 .. 1 + pkg_length].to_vec() + ), 1 + pkg_length)), + Err(e) => return Err(e), + }; + let byte_list = data[1 + pkg_length_len + buffer_size_len .. 1 + pkg_length].to_vec(); + + Ok((DefBuffer::Buffer {buffer_size, byte_list}, pkg_length + 1)) +} + +fn parse_def_ref_of(data: &[u8]) -> Result<(SuperName, usize), AmlInternalError> { + parser_opcode!(data, 0x71); + let (obj_reference, obj_reference_len) = parse_super_name(&data[1..])?; + + Ok((obj_reference, obj_reference_len + 1)) +} + +fn parse_def_deref_of(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> { + parser_opcode!(data, 0x83); + let (obj_reference, obj_reference_len) = parse_term_arg(&data[1..])?; + + Ok((obj_reference, obj_reference_len + 1)) +} + +fn parse_def_acquire(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x23); + + let (object, object_len) = parse_super_name(&data[2..])?; + let timeout = (data[2 + object_len] as u16) + + ((data[3 + object_len] as u16) << 8); + + Ok((Type2OpCode::DefAcquire {object, timeout}, object_len + 4)) +} + +fn parse_def_increment(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x75); + + let (obj, obj_len) = parse_super_name(&data[1..])?; + Ok((Type2OpCode::DefIncrement(obj), obj_len + 1)) +} + +fn parse_def_index(data: &[u8]) -> Result<(DefIndex, usize), AmlInternalError> { + parser_opcode!(data, 0x88); + + let (obj, obj_len) = parse_term_arg(&data[1..])?; + let (idx, idx_len) = parse_term_arg(&data[1 + obj_len..])?; + let (target, target_len) = parse_target(&data[1 + obj_len + idx_len..])?; + + Ok((DefIndex {obj, idx, target: Box::new(target)}, 1 + obj_len + idx_len + target_len)) +} + +fn parse_def_land(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x90); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLAnd {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lequal(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x93); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLEqual {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lgreater(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x94); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLGreater {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lless(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x95); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLLess {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_lnot(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x92); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + + Ok((Type2OpCode::DefLNot(operand), 1 + operand_len)) +} + +fn parse_def_lor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x91); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + + Ok((Type2OpCode::DefLOr {lhs, rhs}, 1 + lhs_len + rhs_len)) +} + +fn parse_def_to_hex_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x98); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToHexString {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_buffer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x96); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToBuffer {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x29); + + let (operand, operand_len) = parse_term_arg(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefToBCD {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_to_decimal_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x97); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToDecimalString {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_integer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x99); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefToInteger {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_to_string(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x9C); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (length, length_len) = parse_term_arg(&data[1 + operand_len..])?; + let (target, target_len) = parse_target(&data[1 + operand_len + length_len..])?; + + Ok((Type2OpCode::DefToString {operand, length, target}, 1 + operand_len + length_len + target_len)) +} + +fn parse_def_subtract(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x74); + + let (minuend, minuend_len) = parse_term_arg(&data[1..])?; + let (subtrahend, subtrahend_len) = parse_term_arg(&data[1 + minuend_len..])?; + let (target, target_len) = parse_target(&data[1 + minuend_len + subtrahend_len..])?; + + Ok((Type2OpCode::DefSubtract {minuend, subtrahend, target}, 1 + minuend_len + subtrahend_len + target_len)) +} + +fn parse_def_size_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x87); + + let (name, name_len) = parse_super_name(&data[1..])?; + Ok((Type2OpCode::DefSizeOf(name), name_len + 1)) +} + +fn parse_def_store(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x70); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_super_name(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefStore {operand, target}, operand_len + target_len + 1)) +} + +fn parse_def_or(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7D); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_shift_left(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x79); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefShiftLeft {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_shift_right(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7A); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefShiftRight {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_add(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x72); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefAdd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_and(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7B); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_xor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x7F); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefXor {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_concat_res(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x84); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefConcatRes {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_wait(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x25); + + let (event_object, event_object_len) = parse_super_name(&data[2..])?; + let (operand, operand_len) = parse_term_arg(&data[2 + event_object_len..])?; + + + Ok((Type2OpCode::DefWait {event_object, operand}, 2 + event_object_len + operand_len)) +} + +fn parse_def_cond_ref_of(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode_extended!(data, 0x12); + + let (operand, operand_len) = parse_super_name(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefCondRefOf {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_copy_object(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x9D); + + let (source, source_len) = parse_term_arg(&data[1..])?; + let (destination, destination_len) = parse_simple_name(&data[1 + source_len..])?; + + Ok((Type2OpCode::DefCopyObject {source, destination}, 1 + source_len + destination_len)) +} + +fn parse_def_concat(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x73); + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefConcat {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_decrement(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x76); + + let (target, target_len) = parse_super_name(&data[1..])?; + + Ok((Type2OpCode::DefDecrement(target), 1 + target_len)) +} + +fn parse_def_divide(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x78); + + let (dividend, dividend_len) = parse_term_arg(&data[1..])?; + let (divisor, divisor_len) = parse_term_arg(&data[1 + dividend_len..])?; + let (remainder, remainder_len) = parse_target(&data[1 + dividend_len + divisor_len..])?; + let (quotient, quotient_len) = parse_target(&data[1 + dividend_len + divisor_len + remainder_len..])?; + + Ok((Type2OpCode::DefDivide {dividend, divisor, remainder, quotient}, + 1 + dividend_len + divisor_len + remainder_len + quotient_len)) +} + +fn parse_def_find_set_left_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + parser_opcode!(data, 0x81); + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefFindSetLeftBit {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_find_set_right_bit(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x82 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefFindSetRightBit {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_load_table(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x1F { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (signature, signature_len) = parse_term_arg(&data[2..])?; + let (oem_id, oem_id_len) = parse_term_arg(&data[2 + signature_len..])?; + let (oem_table_id, oem_table_id_len) = parse_term_arg(&data[2 + signature_len + oem_id_len..])?; + let (root_path, root_path_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len..])?; + let (parameter_path, parameter_path_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len + root_path_len..])?; + let (parameter_data, parameter_data_len) = + parse_term_arg(&data[2 + signature_len + oem_id_len + oem_table_id_len + root_path_len + + parameter_path_len..])?; + + Ok((Type2OpCode::DefLoadTable {signature, oem_id, oem_table_id, root_path, + parameter_path, parameter_data}, + 2 + signature_len + oem_id_len + oem_table_id_len + root_path_len + + parameter_path_len + parameter_data_len)) +} + +fn parse_def_match(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x89 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (search_pkg, search_pkg_len) = parse_term_arg(&data[1..])?; + let first_operation = match data[1 + search_pkg_len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlInternalError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let (first_operand, first_operand_len) = parse_term_arg(&data[2 + search_pkg_len..])?; + + let second_operation = match data[2 + search_pkg_len + first_operand_len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlInternalError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let (second_operand, second_operand_len) = + parse_term_arg(&data[3 + search_pkg_len + first_operand_len..])?; + + let (start_index, start_index_len) = + parse_term_arg(&data[3 + search_pkg_len + first_operand_len + second_operand_len..])?; + + Ok((Type2OpCode::DefMatch {search_pkg, first_operation, first_operand, + second_operation, second_operand, start_index}, + 3 + search_pkg_len + first_operand_len + second_operand_len + start_index_len)) +} + +fn parse_def_from_bcd(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x28 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[2..])?; + let (target, target_len) = parse_target(&data[2 + operand_len..])?; + + Ok((Type2OpCode::DefFromBCD {operand, target}, 2 + operand_len + target_len)) +} + +fn parse_def_mid(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x9E { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (source, source_len) = parse_term_arg(&data[1..])?; + let (index, index_len) = parse_term_arg(&data[1 + source_len..])?; + let (length, length_len) = parse_term_arg(&data[1 + source_len + index_len..])?; + let (target, target_len) = parse_target(&data[1 + source_len + index_len + length_len..])?; + + Ok((Type2OpCode::DefMid {source, index, length, target}, + 1 + source_len + index_len + length_len + target_len)) +} + +fn parse_def_mod(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x85 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (dividend, dividend_len) = parse_term_arg(&data[1..])?; + let (divisor, divisor_len) = parse_term_arg(&data[1 + dividend_len..])?; + let (target, target_len) = parse_target(&data[1 + dividend_len + divisor_len..])?; + + Ok((Type2OpCode::DefMod {dividend, divisor, target}, 1 + dividend_len + divisor_len + target_len)) +} + +fn parse_def_multiply(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x77 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefMultiply {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_nand(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x7C { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefNAnd {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_nor(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x7E { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; + let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; + let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; + + Ok((Type2OpCode::DefNOr {lhs, rhs, target}, 1 + lhs_len + rhs_len + target_len)) +} + +fn parse_def_not(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x80 { + return Err(AmlInternalError::AmlInvalidOpCode); + } + + let (operand, operand_len) = parse_term_arg(&data[1..])?; + let (target, target_len) = parse_target(&data[1 + operand_len..])?; + + Ok((Type2OpCode::DefNot {operand, target}, 1 + operand_len + target_len)) +} + +fn parse_def_timer(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { + if data[0] != 0x5B || data[1] != 0x33 { + return Err(AmlInternalError::AmlInvalidOpCode) + } + + Ok((Type2OpCode::DefTimer, 2 as usize)) +} diff --git a/src/acpi/dsdt.rs b/src/acpi/dsdt.rs deleted file mode 100644 index 67bcb7f..0000000 --- a/src/acpi/dsdt.rs +++ /dev/null @@ -1,78 +0,0 @@ -use core::slice; - -use super::sdt::Sdt; - -#[derive(Debug)] -pub struct Dsdt(&'static Sdt); - -impl Dsdt { - pub fn new(sdt: &'static Sdt) -> Option { - if &sdt.signature == b"DSDT" { - Some(Dsdt(sdt)) - } else { - None - } - } - - pub fn data(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.0.data_address() as *const u8, self.0.data_len()) } - } - - pub fn slp_typ(&self) -> Option<(u16, u16)> { - // Code from http://forum.osdev.org/viewtopic.php?t=16990, should be adapted - - let mut i = 0; - let data = self.data(); - - // search the \_S5 package in the DSDT - let s5_a = b"\x08_S5_\x12"; - let s5_b = b"\x08\\_S5_\x12"; - while i < data.len() { - if data[i..].starts_with(s5_a) { - i += s5_a.len(); - break; - } else if data[i..].starts_with(s5_b) { - i += s5_b.len(); - break; - } else { - i += 1; - } - } - - if i >= data.len() { - return None; - } - - // check if \_S5 was found - let pkglen = ((data[i] & 0xC0) >> 6) + 2; - i += pkglen as usize; - if i >= data.len() { - return None; - } - - if data[i] == 0x0A { - i += 1; // skip byteprefix - if i >= data.len() { - return None; - } - } - - let a = (data[i] as u16) << 10; - i += 1; - if i >= data.len() { - return None; - } - - if data[i] == 0x0A { - i += 1; // skip byteprefix - if i >= data.len() { - return None; - } - } - - let b = (data[i] as u16) << 10; - - Some((a, b)) - } - -} diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index 751044a..54a55e5 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -13,20 +13,21 @@ use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; use start::{kstart_ap, CPU_COUNT, AP_READY}; use self::dmar::{Dmar, DmarEntry}; -use self::dsdt::Dsdt; use self::fadt::Fadt; use self::madt::{Madt, MadtEntry}; use self::rsdt::Rsdt; use self::sdt::Sdt; use self::xsdt::Xsdt; +use self::aml::{is_aml_table, parse_aml_table, AmlNamespace, AmlError}; + mod dmar; -mod dsdt; mod fadt; mod madt; mod rsdt; mod sdt; mod xsdt; +mod aml; const TRAMPOLINE: usize = 0x7E00; const AP_STARTUP: usize = TRAMPOLINE + 512; @@ -70,9 +71,6 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { let dsdt = get_sdt(fadt.dsdt as usize, active_table); parse_sdt(dsdt, active_table); ACPI_TABLE.lock().fadt = Some(fadt); - } else if let Some(dsdt) = Dsdt::new(sdt) { - println!(": {}", dsdt.data().len()); - ACPI_TABLE.lock().dsdt = Some(dsdt); } else if let Some(madt) = Madt::new(sdt) { println!(": {:>08X}: {}", madt.local_address, madt.flags); @@ -197,6 +195,17 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { _ => () } } + } else if is_aml_table(sdt) { + ACPI_TABLE.lock().namespace = match parse_aml_table(sdt) { + Ok(res) => { + println!(": Parsed"); + Some(res) + }, + Err(AmlError::AmlParseError(e)) => { + println!(": {}", e); + None + } + }; } else { println!(": Unknown"); } @@ -259,10 +268,10 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { pub struct Acpi { pub fadt: Option, - pub dsdt: Option, + pub namespace: Option, } -pub static ACPI_TABLE: Mutex = Mutex::new(Acpi { fadt: None, dsdt: None }); +pub static ACPI_TABLE: Mutex = Mutex::new(Acpi { fadt: None, namespace: None }); /// RSDP #[derive(Copy, Clone, Debug)] diff --git a/src/acpi/sdt.rs b/src/acpi/sdt.rs index 0d8cedd..62d55cf 100644 --- a/src/acpi/sdt.rs +++ b/src/acpi/sdt.rs @@ -1,4 +1,5 @@ use core::mem; +use core::slice; #[derive(Copy, Clone, Debug)] #[repr(packed)] @@ -30,4 +31,8 @@ impl Sdt { 0 } } + + pub fn data(&'static self) -> &[u8] { + unsafe { slice::from_raw_parts(self.data_address() as *const u8, self.data_len()) } + } } diff --git a/src/stop.rs b/src/stop.rs index db2dfd6..7a9ac75 100644 --- a/src/stop.rs +++ b/src/stop.rs @@ -11,12 +11,18 @@ pub unsafe extern fn kstop() -> ! { if let Some(ref fadt) = acpi.fadt { let port = fadt.pm1a_control_block as u16; let mut val = 1 << 13; - if let Some(ref dsdt) = acpi.dsdt { - if let Some((a, b)) = dsdt.slp_typ() { - println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", a, b); - val |= a; + if let Some(ref namespace) = acpi.namespace { + if let Some(s) = namespace.find_str("\\_S5") { + if let Some(p) = s.get_as_package() { + let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer"); + let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer"); + + println!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); + val |= slp_typa as u16; + } } } + println!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); Pio::::new(port).write(val); } From cd67aabd5aa1a16f1468c1f97eaf776425deb60a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 18 Jun 2017 20:05:19 -0600 Subject: [PATCH 23/24] Switch collections::boxed for alloc::boxed --- src/acpi/aml/mod.rs | 6 ++--- src/acpi/aml/namedobj.rs | 40 +++++++++++++++---------------- src/acpi/aml/namespace.rs | 22 ++++++++--------- src/acpi/aml/namespacemodifier.rs | 12 +++++----- src/acpi/aml/termlist.rs | 6 ++--- src/acpi/aml/type1opcode.rs | 12 +++++----- src/acpi/aml/type2opcode.rs | 40 +++++++++++++++---------------- 7 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/acpi/aml/mod.rs b/src/acpi/aml/mod.rs index 3d35395..296317d 100644 --- a/src/acpi/aml/mod.rs +++ b/src/acpi/aml/mod.rs @@ -1,9 +1,9 @@ //! # AML //! Code to parse and execute AML tables -use collections::vec::Vec; +use alloc::boxed::Box; use collections::string::String; -use collections::boxed::Box; +use collections::vec::Vec; use core::fmt::Debug; use core::str::FromStr; @@ -58,7 +58,7 @@ pub fn get_namespace_string(current: String, modifier: String) -> String { pub fn parse_aml_table(sdt: &'static Sdt) -> Result { let data = sdt.data(); - + let term_list = match parse_term_list(data) { Ok(res) => res, Err(AmlInternalError::AmlParseError(s)) => return Err(AmlError::AmlParseError(s)), diff --git a/src/acpi/aml/namedobj.rs b/src/acpi/aml/namedobj.rs index 67c2e32..26cca7b 100644 --- a/src/acpi/aml/namedobj.rs +++ b/src/acpi/aml/namedobj.rs @@ -1,6 +1,6 @@ -use collections::vec::Vec; +use alloc::boxed::Box; use collections::string::String; -use collections::boxed::Box; +use collections::vec::Vec; use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; use super::namestring::{parse_name_string, parse_name_seg}; @@ -129,7 +129,7 @@ impl AmlExecutable for NamedObj { Some(r) => r, _ => return None }; - + namespace.push_to(local_scope_string, AmlNamespaceContents::OpRegion { region: *region, offset: resolved_offset, @@ -138,7 +138,7 @@ impl AmlExecutable for NamedObj { }, NamedObj::DefField { ref name, ref flags, ref field_list } => { let mut offset: usize = 0; - + for f in field_list { match *f { FieldElement::ReservedField { length } => offset += length, @@ -165,7 +165,7 @@ impl AmlExecutable for NamedObj { }, _ => () } - + None } } @@ -313,7 +313,7 @@ fn parse_def_bank_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErr _ => return Err(AmlInternalError::AmlParseError("BankField - invalid update rule")) } }; - + let field_list = match parse_field_list( &data[3 + pkg_length_len + region_name_len + bank_name_len + bank_value_len .. 2 + pkg_length]) { @@ -322,7 +322,7 @@ fn parse_def_bank_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErr return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), Err(e) => return Err(e) }; - + Ok((NamedObj::DefBankField {region_name, bank_name, bank_value, flags, field_list}, 2 + pkg_length)) } @@ -439,7 +439,7 @@ fn parse_def_device(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { parser_opcode_extended!(data, 0x80); - + let (name, name_len) = parse_name_string(&data[2..])?; let region = match data[2 + name_len] { 0x00 => RegionSpace::SystemMemory, @@ -455,7 +455,7 @@ fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro 0x80 ... 0xFF => RegionSpace::UserDefined(data[2 + name_len]), _ => return Err(AmlInternalError::AmlParseError("OpRegion - invalid region")) }; - + let (offset, offset_len) = parse_term_arg(&data[3 + name_len..])?; let (len, len_len) = parse_term_arg(&data[3 + name_len + offset_len..])?; @@ -464,7 +464,7 @@ fn parse_def_op_region(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro fn parse_def_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { parser_opcode_extended!(data, 0x81); - + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; let (name, name_len) = match parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length]) { Ok(p) => p, @@ -492,7 +492,7 @@ fn parse_def_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalError> { _ => return Err(AmlInternalError::AmlParseError("Field - Invalid update rule")) } }; - + let field_list = match parse_field_list(&data[3 + pkg_length_len + name_len .. 2 + pkg_length]) { Ok(p) => p, Err(AmlInternalError::AmlDeferredLoad) => @@ -522,7 +522,7 @@ fn parse_def_index_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalEr return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_length].to_vec()), 2 + pkg_length)), Err(e) => return Err(e) }; - + let flags_raw = data[2 + pkg_length_len + idx_name_len + data_name_len]; let flags = FieldFlags { access_type: match flags_raw & 0x0F { @@ -542,7 +542,7 @@ fn parse_def_index_field(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalEr _ => return Err(AmlInternalError::AmlParseError("IndexField - Invalid update rule")) } }; - + let field_list = match parse_field_list( &data[3 + pkg_length_len + idx_name_len + data_name_len .. 2 + pkg_length]) { Ok(p) => p, @@ -565,7 +565,7 @@ fn parse_field_list(data: &[u8]) -> Result, AmlInternalError> return Err(AmlInternalError::AmlParseError("FieldList - no valid field")), Err(e) => return Err(e) }; - + terms.push(res); current_offset += len; } @@ -598,14 +598,14 @@ fn parse_named_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalEr fn parse_reserved_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { parser_opcode!(data, 0x00); - + let (length, length_len) = parse_pkg_length(&data[1..])?; Ok((FieldElement::ReservedField {length}, 1 + length_len)) } fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { parser_opcode!(data, 0x01, 0x03); - + let flags_raw = data[1]; let access_type = match flags_raw & 0x0F { 0 => AccessType::AnyAcc, @@ -647,7 +647,7 @@ fn parse_access_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalE fn parse_connect_field(data: &[u8]) -> Result<(FieldElement, usize), AmlInternalError> { parser_opcode!(data, 0x02); - + match parse_def_buffer(&data[1..]) { Ok((buf, buf_len)) => return Ok((FieldElement::ConnectFieldBufferData(buf), buf_len + 1)), Err(AmlInternalError::AmlInvalidOpCode) => (), @@ -718,7 +718,7 @@ fn parse_def_power_res(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), Err(e) => return Err(e) }; - + let system_level = data[2 + pkg_len_len + name_len]; let resource_order: u16 = (data[3 + pkg_len_len + name_len] as u16) + ((data[4 + pkg_len_len + name_len] as u16) << 8); @@ -743,7 +743,7 @@ fn parse_def_processor(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalErro return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), Err(e) => return Err(e) }; - + let proc_id = data[2 + pkg_len_len + name_len]; let p_blk_addr: u32 = (data[3 + pkg_len_len + name_len] as u32) + ((data[4 + pkg_len_len + name_len] as u32) << 8) + @@ -771,7 +771,7 @@ fn parse_def_thermal_zone(data: &[u8]) -> Result<(NamedObj, usize), AmlInternalE return Ok((NamedObj::DeferredLoad(data[0 .. 2 + pkg_len].to_vec()), 2 + pkg_len)), Err(e) => return Err(e) }; - + let obj_list = match parse_object_list(&data[2 + pkg_len_len + name_len .. 2 + pkg_len]) { Ok(p) => p, Err(AmlInternalError::AmlDeferredLoad) => diff --git a/src/acpi/aml/namespace.rs b/src/acpi/aml/namespace.rs index 8a0c6f9..dc3c1c8 100644 --- a/src/acpi/aml/namespace.rs +++ b/src/acpi/aml/namespace.rs @@ -1,6 +1,6 @@ +use alloc::boxed::Box; use collections::string::String; use collections::vec::Vec; -use collections::boxed::Box; use core::str::FromStr; @@ -82,7 +82,7 @@ impl AmlNamespace { let scope_string = String::from_str(scope_str).unwrap(); self.find(scope_string) } - + pub fn find(&self, scope_string: String) -> Option { if scope_string.len() == 0 { match self.contents { @@ -90,9 +90,9 @@ impl AmlNamespace { _ => return None } } - + let mut scope_string = scope_string.clone(); - + if scope_string.starts_with("\\") { if self.name != "\\" { return None; @@ -104,7 +104,7 @@ impl AmlNamespace { if scope_string.starts_with(".") { scope_string.remove(0); } - + if scope_string.len() == 0 { match self.contents { AmlNamespaceContents::Value(ref v) => return Some(v.clone()), @@ -146,7 +146,7 @@ impl AmlNamespace { None } - + pub fn push(&mut self, val: AmlNamespaceContents) { match self.contents { AmlNamespaceContents::Namespace(ref mut v) => v.push(val), @@ -158,9 +158,9 @@ impl AmlNamespace { if scope_string.len() == 0 { return; } - + let mut scope_string = scope_string.clone(); - + if scope_string.starts_with("\\") { if self.name != "\\" { return; @@ -173,7 +173,7 @@ impl AmlNamespace { if scope_string.starts_with(".") { scope_string.remove(0); } - + if scope_string.len() == 0 { return; } @@ -207,12 +207,12 @@ impl AmlNamespace { current_index += 1; } - + let mut next = AmlNamespace { name: current, contents: contents }; - + namespace.push(AmlNamespaceContents::SubNamespace(Box::new(next))); } _ => () // TODO: Error this diff --git a/src/acpi/aml/namespacemodifier.rs b/src/acpi/aml/namespacemodifier.rs index a49e2bb..217347a 100644 --- a/src/acpi/aml/namespacemodifier.rs +++ b/src/acpi/aml/namespacemodifier.rs @@ -1,6 +1,6 @@ -use collections::vec::Vec; +use alloc::boxed::Box; use collections::string::String; -use collections::boxed::Box; +use collections::vec::Vec; use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, AmlNamespaceContents, get_namespace_string}; use super::pkglength::parse_pkg_length; @@ -63,10 +63,10 @@ pub fn parse_namespace_modifier(data: &[u8]) -> Result<(NamespaceModifier, usize fn parse_alias_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { parser_opcode!(data, 0x06); - + let (source_name, source_name_len) = parse_name_string(&data[1..])?; let (alias_name, alias_name_len) = parse_name_string(&data[1 + source_name_len..])?; - + Ok((NamespaceModifier::Alias {source_name, alias_name}, 1 + source_name_len + alias_name_len)) } @@ -75,13 +75,13 @@ fn parse_name_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalE let (name, name_len) = parse_name_string(&data[1..])?; let (data_ref_obj, data_ref_obj_len) = parse_data_ref_obj(&data[1 + name_len..])?; - + Ok((NamespaceModifier::Name {name, data_ref_obj}, 1 + name_len + data_ref_obj_len)) } fn parse_scope_op(data: &[u8]) -> Result<(NamespaceModifier, usize), AmlInternalError> { parser_opcode!(data, 0x10); - + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; let (name, name_len) = match parse_name_string(&data[1 + pkg_length_len..]) { Ok(p) => p, diff --git a/src/acpi/aml/termlist.rs b/src/acpi/aml/termlist.rs index 014bddb..b236584 100644 --- a/src/acpi/aml/termlist.rs +++ b/src/acpi/aml/termlist.rs @@ -1,6 +1,6 @@ -use collections::vec::Vec; -use collections::boxed::Box; +use alloc::boxed::Box; use collections::string::String; +use collections::vec::Vec; use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace, get_namespace_string}; use super::namespacemodifier::{parse_namespace_modifier, NamespaceModifier}; @@ -103,7 +103,7 @@ pub fn parse_object_list(data: &[u8]) -> Result, AmlInternalError> { terms.push(res); current_offset += len; } - + Ok(terms) } diff --git a/src/acpi/aml/type1opcode.rs b/src/acpi/aml/type1opcode.rs index c6cc5ca..103e542 100644 --- a/src/acpi/aml/type1opcode.rs +++ b/src/acpi/aml/type1opcode.rs @@ -1,6 +1,6 @@ -use collections::vec::Vec; +use alloc::boxed::Box; use collections::string::String; -use collections::boxed::Box; +use collections::vec::Vec; use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; use super::pkglength::parse_pkg_length; @@ -195,18 +195,18 @@ fn parse_def_if_else(data: &[u8]) -> Result<(Type1OpCode, usize), AmlInternalErr Ok((predicate, predicate_len)) => { match parse_term_list(&data[1 + pkg_length_len + predicate_len .. 1 + pkg_length]) { Ok(if_block) => IfBlock::If {predicate, if_block}, - Err(AmlInternalError::AmlDeferredLoad) => + Err(AmlInternalError::AmlDeferredLoad) => IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), Err(e) => return Err(e) } }, - Err(AmlInternalError::AmlDeferredLoad) => + Err(AmlInternalError::AmlDeferredLoad) => IfBlock::DeferredLoad(data[0 .. 1 + pkg_length].to_vec()), Err(e) => return Err(e) }; - + let (else_block, else_block_len) = parse_def_else(&data[1 + pkg_length..])?; - + return Ok((Type1OpCode::DefIfElse {if_block, else_block}, pkg_length + else_block_len + 1)); } diff --git a/src/acpi/aml/type2opcode.rs b/src/acpi/aml/type2opcode.rs index 50d1ff2..744dbef 100644 --- a/src/acpi/aml/type2opcode.rs +++ b/src/acpi/aml/type2opcode.rs @@ -1,6 +1,6 @@ -use collections::vec::Vec; +use alloc::boxed::Box; use collections::string::String; -use collections::boxed::Box; +use collections::vec::Vec; use super::{AmlInternalError, AmlExecutable, AmlValue, AmlNamespace}; use super::pkglength::parse_pkg_length; @@ -277,7 +277,7 @@ impl AmlExecutable for DefPackage { match *self { DefPackage::Package { ref num_elements, ref elements } => { let mut values: Vec = vec!(); - + for element in elements { match *element { PackageElement::DataRefObj(ref d) => { @@ -353,7 +353,7 @@ pub fn parse_type2_opcode(data: &[u8]) -> Result<(Type2OpCode, usize), AmlIntern parser_wrap!(Type2OpCode::DefIndex, parse_def_index), parser_wrap!(Type2OpCode::MethodInvocation, parse_method_invocation) }; - + Err(AmlInternalError::AmlInvalidOpCode) } @@ -365,7 +365,7 @@ pub fn parse_type6_opcode(data: &[u8]) -> Result<(Type6OpCode, usize), AmlIntern parser_wrap!(Type6OpCode::DefIndex, parse_def_index), parser_wrap!(Type6OpCode::MethodInvocation, parse_method_invocation) }; - + Err(AmlInternalError::AmlInvalidOpCode) } @@ -387,7 +387,7 @@ pub fn parse_def_package(data: &[u8]) -> Result<(DefPackage, usize), AmlInternal let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; let num_elements = data[1 + pkg_length_len]; - + let elements = match parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length]) { Ok(e) => e, Err(AmlInternalError::AmlDeferredLoad) => @@ -415,18 +415,18 @@ pub fn parse_def_var_package(data: &[u8]) -> Result<(DefVarPackage, usize), AmlI Ok((DefVarPackage::Package {num_elements, elements}, 1 + pkg_length)) } - + fn parse_package_elements_list(data: &[u8]) -> Result, AmlInternalError> { let mut current_offset: usize = 0; let mut elements: Vec = vec!(); - + while current_offset < data.len() { match parse_data_ref_obj(&data[current_offset ..]) { Ok((data_ref_obj, data_ref_obj_len)) => { elements.push(PackageElement::DataRefObj(data_ref_obj)); current_offset += data_ref_obj_len; }, - Err(AmlInternalError::AmlInvalidOpCode) => + Err(AmlInternalError::AmlInvalidOpCode) => match parse_name_string(&data[current_offset ..]) { Ok((name_string, name_string_len)) => { elements.push(PackageElement::NameString(name_string)); @@ -440,10 +440,10 @@ fn parse_package_elements_list(data: &[u8]) -> Result, AmlIn Ok(elements) } - + pub fn parse_def_buffer(data: &[u8]) -> Result<(DefBuffer, usize), AmlInternalError> { parser_opcode!(data, 0x11); - + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; let (buffer_size, buffer_size_len) = match parse_term_arg(&data[1 + pkg_length_len..]) { Ok(s) => s, @@ -453,7 +453,7 @@ pub fn parse_def_buffer(data: &[u8]) -> Result<(DefBuffer, usize), AmlInternalEr Err(e) => return Err(e), }; let byte_list = data[1 + pkg_length_len + buffer_size_len .. 1 + pkg_length].to_vec(); - + Ok((DefBuffer::Buffer {buffer_size, byte_list}, pkg_length + 1)) } @@ -473,24 +473,24 @@ fn parse_def_deref_of(data: &[u8]) -> Result<(TermArg, usize), AmlInternalError> fn parse_def_acquire(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { parser_opcode_extended!(data, 0x23); - + let (object, object_len) = parse_super_name(&data[2..])?; let timeout = (data[2 + object_len] as u16) + ((data[3 + object_len] as u16) << 8); - + Ok((Type2OpCode::DefAcquire {object, timeout}, object_len + 4)) } fn parse_def_increment(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { parser_opcode!(data, 0x75); - + let (obj, obj_len) = parse_super_name(&data[1..])?; Ok((Type2OpCode::DefIncrement(obj), obj_len + 1)) } fn parse_def_index(data: &[u8]) -> Result<(DefIndex, usize), AmlInternalError> { parser_opcode!(data, 0x88); - + let (obj, obj_len) = parse_term_arg(&data[1..])?; let (idx, idx_len) = parse_term_arg(&data[1 + obj_len..])?; let (target, target_len) = parse_target(&data[1 + obj_len + idx_len..])?; @@ -500,7 +500,7 @@ fn parse_def_index(data: &[u8]) -> Result<(DefIndex, usize), AmlInternalError> { fn parse_def_land(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { parser_opcode!(data, 0x90); - + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; @@ -509,7 +509,7 @@ fn parse_def_land(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> fn parse_def_lequal(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { parser_opcode!(data, 0x93); - + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; @@ -518,7 +518,7 @@ fn parse_def_lequal(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalErro fn parse_def_lgreater(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { parser_opcode!(data, 0x94); - + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; @@ -664,7 +664,7 @@ fn parse_def_shift_right(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInterna fn parse_def_add(data: &[u8]) -> Result<(Type2OpCode, usize), AmlInternalError> { parser_opcode!(data, 0x72); - + let (lhs, lhs_len) = parse_term_arg(&data[1..])?; let (rhs, rhs_len) = parse_term_arg(&data[1 + lhs_len..])?; let (target, target_len) = parse_target(&data[1 + lhs_len + rhs_len..])?; From b9f659dadfffc9e705315139e7be5db2702b29ee Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 20 Jun 2017 15:56:44 -0700 Subject: [PATCH 24/24] Make env: return ENOENT on non-existent; support unlink() --- src/scheme/env.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/scheme/env.rs b/src/scheme/env.rs index d4a2973..062658c 100644 --- a/src/scheme/env.rs +++ b/src/scheme/env.rs @@ -7,7 +7,7 @@ use spin::{Mutex, RwLock}; use context; use syscall::data::Stat; use syscall::error::*; -use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END}; +use syscall::flag::{MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END, O_CREAT}; use syscall::scheme::Scheme; #[derive(Clone)] @@ -32,7 +32,7 @@ impl EnvScheme { } impl Scheme for EnvScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { + fn open(&self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { let path = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); let env_lock = { @@ -69,11 +69,13 @@ impl Scheme for EnvScheme { let mut env = env_lock.lock(); if env.contains_key(path.as_bytes()) { env[path.as_bytes()].clone() - } else /*if flags & O_CREAT == O_CREAT*/ { + } else if flags & O_CREAT == O_CREAT { let name = path.as_bytes().to_vec().into_boxed_slice(); let data = Arc::new(Mutex::new(Vec::new())); env.insert(name, data.clone()); data + } else { + return Err(Error::new(ENOENT)); } }; @@ -211,4 +213,21 @@ impl Scheme for EnvScheme { fn close(&self, id: usize) -> Result { self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } + + fn unlink(&self, path: &[u8], uid: u32, _gid: u32) -> Result { + let env_lock = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.env.clone() + }; + + let mut env = env_lock.lock(); + + if let Some(_) = env.remove(path) { + Ok(0) + } else { + Err(Error::new(ENOENT)) + } + } }