-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from rageagainsthepc/add-ffi
add a C compatible interface
- Loading branch information
Showing
15 changed files
with
364 additions
and
7 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 @@ | ||
CC = gcc | ||
CFLAGS = -lmicrovmi -L../target/debug | ||
CWD := $(shell pwd) | ||
|
||
.PHONY: all clean | ||
|
||
all: mem-dump pause regs-dump | ||
|
||
libmicrovmi.h: ../target/debug/libmicrovmi.so | ||
cd ..; \ | ||
cbindgen --config cbindgen.toml --crate microvmi --output "${CWD}/libmicrovmi.h" | ||
|
||
mem-dump: libmicrovmi.h mem-dump.c | ||
$(CC) $(CFLAGS) -o mem-dump mem-dump.c | ||
|
||
pause: libmicrovmi.h pause.c | ||
$(CC) $(CFLAGS) -o pause pause.c | ||
|
||
regs-dump: libmicrovmi.h regs-dump.c | ||
$(CC) $(CFLAGS) -o regs-dump regs-dump.c | ||
|
||
clean: | ||
rm -f libmicrovmi.h mem-dump pause regs-dump |
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,20 @@ | ||
# C Interoperability | ||
|
||
It is possible to call *libmicrovmi* functions from C code. To this end, a header file has to be generated. | ||
This requires the `cbindgen` tool which can be installed via the following command: | ||
|
||
~~~ | ||
cargo install --force cbindgen | ||
~~~ | ||
|
||
## Building the examples | ||
|
||
To build the examples just use the makefile located in `c_examples`. | ||
It will also generate the header file for you provided you have installed `cbindgen`. | ||
You just have to make sure that you have already built *libmicrovmi*. | ||
|
||
## Executing the examples | ||
|
||
~~~ | ||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:../target/debug" <example> <vm_name> | ||
~~~ |
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,47 @@ | ||
#include "libmicrovmi.h" | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
size_t PAGE_SIZE = 4096; | ||
|
||
void dump_memory(MicrovmiContext* driver, const char* vm_name) { | ||
if (microvmi_pause(driver) == MicrovmiSuccess) { | ||
printf("Paused.\n"); | ||
} else { | ||
printf("Unable to pause VM.\n"); | ||
return; | ||
} | ||
uint64_t max_address; | ||
if (microvmi_get_max_physical_addr(driver, &max_address) == MicrovmiSuccess) { | ||
printf("Max physical address: %llx\n", max_address); | ||
} else { | ||
printf("Unable to retrieve the max physical address.\n"); | ||
return; | ||
} | ||
FILE* dump_file = fopen("vm.dump", "wb"); | ||
uint8_t buffer[PAGE_SIZE]; | ||
for (int i = 0; i <= max_address / PAGE_SIZE; i++) { | ||
memset(buffer, 0, PAGE_SIZE); | ||
if (microvmi_read_physical(driver, i * PAGE_SIZE, buffer, PAGE_SIZE) == MicrovmiSuccess) { | ||
fwrite(buffer, sizeof(uint8_t), PAGE_SIZE, dump_file); | ||
} | ||
} | ||
fclose(dump_file); | ||
if (microvmi_resume(driver) == MicrovmiSuccess) { | ||
printf("Resumed.\n"); | ||
} else { | ||
printf("Unable to resume VM.\n"); | ||
} | ||
} | ||
|
||
|
||
int main(int argc, char* argv[]) { | ||
if (argc < 2) { | ||
printf("No domain name given.\n"); | ||
return 1; | ||
} | ||
MicrovmiContext* driver = microvmi_init(argv[1], NULL); | ||
dump_memory(driver, argv[1]); | ||
microvmi_destroy(driver); | ||
return 0; | ||
} |
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,35 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include "libmicrovmi.h" | ||
#include <unistd.h> | ||
|
||
void pause_vm(MicrovmiContext* driver, unsigned long sleep_duration) { | ||
if (microvmi_pause(driver) == MicrovmiSuccess) { | ||
printf("Paused.\n"); | ||
} else { | ||
printf("Unable to pause VM.\n"); | ||
return; | ||
} | ||
usleep(sleep_duration); | ||
if (microvmi_resume(driver) == MicrovmiSuccess) { | ||
printf("Resumed.\n"); | ||
} else { | ||
printf("Unable to resume VM.\n"); | ||
} | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
if (argc < 3) { | ||
printf("Usage: regs-dump <vm_name> <sleep_seconds>.\n"); | ||
return 1; | ||
} | ||
unsigned long sleep_duration_sec = strtoul(argv[2], NULL, 0); | ||
if (sleep_duration_sec == 0) { | ||
printf("Unable to parse sleep duration or zero provided.\n"); | ||
return 1; | ||
} | ||
MicrovmiContext* driver = microvmi_init(argv[1], NULL); | ||
pause_vm(driver, sleep_duration_sec * 1000000); | ||
microvmi_destroy(driver); | ||
return 0; | ||
} |
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,44 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include "libmicrovmi.h" | ||
|
||
void read_registers(MicrovmiContext* driver, const char* vm_name) { | ||
if (microvmi_pause(driver) == MicrovmiSuccess) { | ||
printf("Paused.\n"); | ||
} else { | ||
printf("Unable to pause VM.\n"); | ||
return; | ||
} | ||
Registers regs; | ||
memset(®s, 0, sizeof(regs)); | ||
if (microvmi_read_registers(driver, 0, ®s) == MicrovmiSuccess) { | ||
printf("rax: 0x%llx\n", regs.x86._0.rax); | ||
printf("rbx: 0x%llx\n", regs.x86._0.rbx); | ||
printf("rcx: 0x%llx\n", regs.x86._0.rcx); | ||
printf("rdx: 0x%llx\n", regs.x86._0.rdx); | ||
printf("rsi: 0x%llx\n", regs.x86._0.rsi); | ||
printf("rdi: 0x%llx\n", regs.x86._0.rdi); | ||
printf("rsp: 0x%llx\n", regs.x86._0.rsp); | ||
printf("rbp: 0x%llx\n", regs.x86._0.rbp); | ||
printf("rip: 0x%llx\n", regs.x86._0.rip); | ||
printf("rflags: 0x%llx\n", regs.x86._0.rflags); | ||
} else { | ||
printf("Unable to read registers.\n"); | ||
} | ||
if (microvmi_resume(driver) == MicrovmiSuccess) { | ||
printf("Resumed.\n"); | ||
} else { | ||
printf("Unable to resume VM.\n"); | ||
} | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
if (argc < 2) { | ||
printf("No domain name given.\n"); | ||
return 1; | ||
} | ||
MicrovmiContext* driver = microvmi_init(argv[1], NULL); | ||
read_registers(driver, argv[1]); | ||
microvmi_destroy(driver); | ||
return 0; | ||
} |
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,6 @@ | ||
language = "C" | ||
tab_width = 4 | ||
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" | ||
include_guard = "LIBMICROVMI_H" | ||
no_includes = true | ||
sys_includes = ["stddef.h", "stdint.h"] |
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,153 @@ | ||
use crate::api::{DriverType, Introspectable, Registers}; | ||
use crate::driver::dummy::Dummy; | ||
#[cfg(feature = "hyper-v")] | ||
use crate::driver::hyperv::HyperV; | ||
#[cfg(feature = "kvm")] | ||
use crate::driver::kvm::Kvm; | ||
#[cfg(feature = "virtualbox")] | ||
use crate::driver::virtualbox::VBox; | ||
#[cfg(feature = "xen")] | ||
use crate::driver::xen::Xen; | ||
use crate::init; | ||
use cty::{c_char, size_t, uint16_t, uint64_t, uint8_t}; | ||
use std::ffi::{c_void, CStr}; | ||
use std::slice; | ||
|
||
#[repr(C)] | ||
pub struct MicrovmiContext { | ||
driver: *mut c_void, | ||
driver_type: DriverType, | ||
} | ||
|
||
#[repr(C)] | ||
pub enum MicrovmiStatus { | ||
MicrovmiSuccess, | ||
MicrovmiFailure, | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_init( | ||
domain_name: *const c_char, | ||
driver_type: *const DriverType, | ||
) -> *mut MicrovmiContext { | ||
let safe_domain_name = CStr::from_ptr(domain_name).to_string_lossy().into_owned(); | ||
let optional_driver_type: Option<DriverType> = if driver_type.is_null() { | ||
None | ||
} else { | ||
Some(driver_type.read()) | ||
}; | ||
let driver = init(&safe_domain_name, optional_driver_type); | ||
let inferred_driver_type = driver.get_driver_type(); | ||
Box::into_raw(Box::new(MicrovmiContext { | ||
driver: Box::into_raw(driver) as *mut c_void, | ||
driver_type: inferred_driver_type, | ||
})) | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_destroy(context: *mut MicrovmiContext) { | ||
let boxed_context = Box::from_raw(context); | ||
let _ = get_driver_box(&boxed_context); | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_pause(context: *mut MicrovmiContext) -> MicrovmiStatus { | ||
let driver = get_driver_mut_ptr(context.as_ref().unwrap()); | ||
match (*driver).pause() { | ||
Ok(_) => MicrovmiStatus::MicrovmiSuccess, | ||
Err(_) => MicrovmiStatus::MicrovmiFailure, | ||
} | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_resume(context: *mut MicrovmiContext) -> MicrovmiStatus { | ||
let driver = get_driver_mut_ptr(context.as_ref().unwrap()); | ||
match (*driver).resume() { | ||
Ok(_) => MicrovmiStatus::MicrovmiSuccess, | ||
Err(_) => MicrovmiStatus::MicrovmiFailure, | ||
} | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_read_physical( | ||
context: *mut MicrovmiContext, | ||
physical_address: uint64_t, | ||
buffer: *mut uint8_t, | ||
size: size_t, | ||
) -> MicrovmiStatus { | ||
let driver = get_driver_mut_ptr(context.as_ref().unwrap()); | ||
match (*driver).read_physical(physical_address, slice::from_raw_parts_mut(buffer, size)) { | ||
Ok(_) => MicrovmiStatus::MicrovmiSuccess, | ||
Err(_) => MicrovmiStatus::MicrovmiFailure, | ||
} | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_get_max_physical_addr( | ||
context: *mut MicrovmiContext, | ||
address_ptr: *mut uint64_t, | ||
) -> MicrovmiStatus { | ||
let driver = get_driver_mut_ptr(context.as_ref().unwrap()); | ||
match (*driver).get_max_physical_addr() { | ||
Ok(max_addr) => { | ||
address_ptr.write(max_addr); | ||
MicrovmiStatus::MicrovmiSuccess | ||
} | ||
Err(_) => MicrovmiStatus::MicrovmiFailure, | ||
} | ||
} | ||
|
||
#[allow(clippy::missing_safety_doc)] | ||
#[no_mangle] | ||
pub unsafe extern "C" fn microvmi_read_registers( | ||
context: *mut MicrovmiContext, | ||
vcpu: uint16_t, | ||
registers: *mut Registers, | ||
) -> MicrovmiStatus { | ||
let driver = get_driver_mut_ptr(context.as_ref().unwrap()); | ||
match (*driver).read_registers(vcpu) { | ||
Ok(regs) => { | ||
registers.write(regs); | ||
MicrovmiStatus::MicrovmiSuccess | ||
} | ||
Err(_) => MicrovmiStatus::MicrovmiFailure, | ||
} | ||
} | ||
|
||
unsafe fn get_driver_mut_ptr(context: &MicrovmiContext) -> *mut dyn Introspectable { | ||
match context.driver_type { | ||
DriverType::Dummy => context.driver as *mut Dummy as *mut dyn Introspectable, | ||
#[cfg(feature = "kvm")] | ||
DriverType::KVM => context.driver as *mut Kvm as *mut dyn Introspectable, | ||
#[cfg(feature = "virtualbox")] | ||
DriverType::VirtualBox => context.driver as *mut VBox as *mut dyn Introspectable, | ||
#[cfg(feature = "xen")] | ||
DriverType::Xen => context.driver as *mut Xen as *mut dyn Introspectable, | ||
#[cfg(feature = "hyper-v")] | ||
DriverType::HyperV => context.driver as *mut HyperV as *mut dyn Introspectable, | ||
} | ||
} | ||
|
||
unsafe fn get_driver_box(context: &MicrovmiContext) -> Box<dyn Introspectable> { | ||
match context.driver_type { | ||
DriverType::Dummy => Box::from_raw(context.driver as *mut Dummy) as Box<dyn Introspectable>, | ||
#[cfg(feature = "kvm")] | ||
DriverType::KVM => Box::from_raw(context.driver as *mut Kvm) as Box<dyn Introspectable>, | ||
#[cfg(feature = "virtualbox")] | ||
DriverType::VirtualBox => { | ||
Box::from_raw(context.driver as *mut VBox) as Box<dyn Introspectable> | ||
} | ||
#[cfg(feature = "xen")] | ||
DriverType::Xen => Box::from_raw(context.driver as *mut Xen) as Box<dyn Introspectable>, | ||
#[cfg(feature = "hyper-v")] | ||
DriverType::HyperV => { | ||
Box::from_raw(context.driver as *mut HyperV) as Box<dyn Introspectable> | ||
} | ||
} | ||
} |
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
Oops, something went wrong.