-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide C++ FFI interface, bindings, meson integration
- Loading branch information
1 parent
5889b99
commit 2dfa194
Showing
5 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#[cfg(feature = "generate-bindings")] | ||
use {std::env, std::path::PathBuf}; | ||
|
||
fn main() { | ||
#[cfg(feature = "generate-bindings")] | ||
{ | ||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); | ||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); | ||
|
||
// Not ideal to navigate by .. but there isn't a good alternative until cargo provides some | ||
// sort of artifacts dir, see https://github.com/rust-lang/cargo/issues/9096 | ||
let bindings_path = out_path.join("../../../include/nic-emu.hpp"); | ||
|
||
cbindgen::Builder::new() | ||
.with_crate(crate_dir) | ||
.with_pragma_once(true) | ||
.with_include_version(true) | ||
.exclude_item("DESCRIPTOR_BUFFER_SIZE") | ||
.generate() | ||
.expect("Unable to generate bindings") | ||
.write_to_file(bindings_path); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Not meant for standalone usage! The crate is still compiled via cargo! | ||
# Only provided for easing integration of the library in meson parent projects. | ||
# Exposing cargo's output as a prebuilt binary dependency | ||
|
||
# Example subproject integration: | ||
# nic_emu = subproject('nic-emu') | ||
# nic_emu_dep = nic_emu.get_variable('nic_emu_dep') | ||
# executable(..., dependencies : [nic_emu_dep, ...]) | ||
|
||
project( | ||
'nic-emu', | ||
version: '0.0.1', | ||
license: 'MIT', | ||
) | ||
|
||
if not meson.is_subproject() | ||
warning('nic-emu is not a standalone meson project!') | ||
endif | ||
|
||
cargo = find_program('cargo') | ||
cargo_command = [ | ||
cargo, | ||
'build', | ||
'--lib', | ||
'--no-default-features', | ||
'--features', | ||
'generate-bindings' | ||
] | ||
|
||
buildtype = get_option('buildtype') | ||
rust_buildtype = 'debug' | ||
if buildtype == 'release' or buildtype == 'minsize' | ||
rust_buildtype = 'release' | ||
cargo_command += '--release' | ||
endif | ||
|
||
message('Building nic-emu using cargo') | ||
run_command( | ||
cargo_command, | ||
check: true | ||
) | ||
|
||
nic_emu_build_path = 'target' / rust_buildtype | ||
|
||
cc = meson.get_compiler('cpp') | ||
nic_emu_lib = cc.find_library( | ||
'nic_emu', | ||
dirs: meson.current_source_dir() / nic_emu_build_path, | ||
) | ||
|
||
# Include this dependency in your executable | ||
nic_emu_dep = declare_dependency( | ||
dependencies: [nic_emu_lib], | ||
include_directories: include_directories(nic_emu_build_path / 'include'), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use crate::e1000::E1000; | ||
use crate::NicContext; | ||
use log::error; | ||
use std::slice::from_raw_parts_mut; | ||
|
||
// General FFI interface | ||
|
||
type SendCallback = unsafe extern "C" fn(buffer: *const u8, len: usize); | ||
type DmaReadCallback = unsafe extern "C" fn(dma_address: usize, buffer: *mut u8, len: usize); | ||
type DmaWriteCallback = unsafe extern "C" fn(dma_address: usize, buffer: *const u8, len: usize); | ||
type IssueInterruptCallback = unsafe extern "C" fn(); | ||
|
||
#[repr(C)] | ||
struct FfiCallbacks { | ||
send_cb: SendCallback, | ||
dma_read_cb: DmaReadCallback, | ||
dma_write_cb: DmaWriteCallback, | ||
issue_interrupt_cb: IssueInterruptCallback, | ||
} | ||
|
||
impl NicContext for FfiCallbacks { | ||
fn send(&mut self, buffer: &[u8]) -> anyhow::Result<usize> { | ||
unsafe { | ||
(self.send_cb)(buffer.as_ptr(), buffer.len()); | ||
} | ||
|
||
// Assume everything went well... | ||
Ok(buffer.len()) | ||
} | ||
|
||
fn dma_read(&mut self, address: usize, buffer: &mut [u8]) { | ||
unsafe { | ||
(self.dma_read_cb)(address, buffer.as_mut_ptr(), buffer.len()); | ||
} | ||
} | ||
|
||
fn dma_write(&mut self, address: usize, buffer: &[u8]) { | ||
unsafe { | ||
(self.dma_write_cb)(address, buffer.as_ptr(), buffer.len()); | ||
} | ||
} | ||
|
||
fn trigger_interrupt(&mut self) { | ||
unsafe { (self.issue_interrupt_cb)() } | ||
} | ||
} | ||
|
||
// E1000 FFI Interface | ||
|
||
struct E1000FFI { | ||
e1000: E1000<FfiCallbacks>, | ||
} | ||
|
||
impl E1000FFI { | ||
#[no_mangle] | ||
pub extern "C" fn new_e1000(callbacks: FfiCallbacks) -> *mut E1000FFI { | ||
let e1000_ffi = E1000FFI { | ||
e1000: E1000::new(callbacks), | ||
}; | ||
Box::into_raw(Box::new(e1000_ffi)) | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn drop_e1000(e1000_ffi: *mut E1000FFI) { | ||
unsafe { | ||
// Box will free on drop | ||
let _ = Box::from_raw(e1000_ffi); | ||
} | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn e1000_region_access( | ||
&mut self, bar: u8, offset: usize, data_ptr: *const u8, data_len: usize, write: bool, | ||
) -> bool { | ||
let data = unsafe { from_raw_parts_mut(data_ptr as *mut u8, data_len) }; | ||
|
||
let result = match bar { | ||
0 => self.e1000.region_access_bar0(offset, data, write), | ||
1 => self.e1000.region_access_bar1(offset, data, write), | ||
_ => { | ||
error!("Unknown bar {}", bar); | ||
return false; | ||
} | ||
}; | ||
|
||
if let Err(e) = result { | ||
error!("Error accessing bar {}: {}", bar, e); | ||
false | ||
} else { | ||
true | ||
} | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn e1000_reset(&mut self) { | ||
self.e1000.reset_e1000(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
use anyhow::Result; | ||
|
||
pub mod e1000; | ||
mod ffi; | ||
mod util; | ||
|
||
pub trait NicContext { | ||
|