grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 4/7] Rust: add the rust_hello module


From: Daniel Axtens
Subject: [RFC PATCH 4/7] Rust: add the rust_hello module
Date: Tue, 24 Aug 2021 23:32:40 +1000

Build an actual module with Rust!

This module, built whenever COND_RUST is enabled, does the following:

 - Prints a message when the module is loaded.

 - Registers a command which prints hello when run.

 - Deregisters the command when the module is unloaded.

You can build it with the usual make, no special magic required.

A test is supplied.

A few outstanding to-dos:

 - The Rust source doesn't get preprocessed in such a way as to allow the
   normal module to insert the little shim command that loads the module
   when called. (the command.lst stuff)

 - I haven't looked at how to specify sections etc in Rust so I use wrap.c
   to specify a license.

 - Bindgen uses the 'cty' module to specify c-types. That's MIT licensed, which
   is GPLv3 compatible (AIUI) but maybe we want to write our own. The linux
   kernel has one of it's own which is GPLv2 only, I'm hoping to ask if they
   can dual-license it so we can borrow it.

 - The module does somewhat expose that more idiomatic layers around the 
bindings
   would be very nice.

Signed-off-by: Daniel Axtens <dja@axtens.net>
---
 .gitignore                               |  1 +
 Makefile.util.def                        |  6 +++
 grub-core/Makefile.core.def              |  9 ++++
 grub-core/commands/rust-hello/.gitignore |  1 +
 grub-core/commands/rust-hello/Cargo.lock | 24 ++++++++++
 grub-core/commands/rust-hello/Cargo.toml | 16 +++++++
 grub-core/commands/rust-hello/src/lib.rs | 57 ++++++++++++++++++++++++
 grub-core/commands/rust-hello/wrap.c     |  8 ++++
 tests/test_rust.in                       | 19 ++++++++
 9 files changed, 141 insertions(+)
 create mode 100644 grub-core/commands/rust-hello/.gitignore
 create mode 100644 grub-core/commands/rust-hello/Cargo.lock
 create mode 100644 grub-core/commands/rust-hello/Cargo.toml
 create mode 100644 grub-core/commands/rust-hello/src/lib.rs
 create mode 100644 grub-core/commands/rust-hello/wrap.c
 create mode 100644 tests/test_rust.in

diff --git a/.gitignore b/.gitignore
index f6a1bd051752..68288d6481e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -264,6 +264,7 @@ widthspec.bin
 /stamp-h1
 /syslinux_test
 /tar_test
+/test_rust
 /test_sha512sum
 /test_unset
 /tests/syslinux/ubuntu10.04_grub.cfg
diff --git a/Makefile.util.def b/Makefile.util.def
index f8b356cc1fa4..bca56493f189 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -1211,6 +1211,12 @@ script = {
   common = tests/syslinux_test.in;
 };
 
+script = {
+  testcase;
+  name = test_rust;
+  common = tests/test_rust.in;
+};
+
 program = {
   testcase;
   name = example_unit_test;
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 8022e1c0a794..8c3f1be4495e 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2527,3 +2527,12 @@ module = {
   common = commands/i386/wrmsr.c;
   enable = x86;
 };
+
+module = {
+  name = rust_hello;
+  common = commands/rust-hello/wrap.c;
+  rust = commands/rust-hello/src/lib.rs;
+  crate = commands/rust-hello;
+
+  condition = COND_RUST;
+};
diff --git a/grub-core/commands/rust-hello/.gitignore 
b/grub-core/commands/rust-hello/.gitignore
new file mode 100644
index 000000000000..eb5a316cbd19
--- /dev/null
+++ b/grub-core/commands/rust-hello/.gitignore
@@ -0,0 +1 @@
+target
diff --git a/grub-core/commands/rust-hello/Cargo.lock 
b/grub-core/commands/rust-hello/Cargo.lock
new file mode 100644
index 000000000000..af55da87ad9a
--- /dev/null
+++ b/grub-core/commands/rust-hello/Cargo.lock
@@ -0,0 +1,24 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cty"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3"
+
+[[package]]
+name = "grub"
+version = "0.1.0"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "rust-hello"
+version = "0.1.0"
+dependencies = [
+ "cty",
+ "grub",
+]
diff --git a/grub-core/commands/rust-hello/Cargo.toml 
b/grub-core/commands/rust-hello/Cargo.toml
new file mode 100644
index 000000000000..81535262c3db
--- /dev/null
+++ b/grub-core/commands/rust-hello/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "rust-hello"
+version = "0.1.0"
+authors = ["Daniel Axtens <dja@axtens.net>"]
+edition = "2018"
+
+[lib]
+crate_type = ["staticlib"]
+
+[profile.release]
+panic="abort"
+lto = true
+
+[dependencies]
+grub = { path = "../../lib/rust/grub" }
+cty = "^0.2"
diff --git a/grub-core/commands/rust-hello/src/lib.rs 
b/grub-core/commands/rust-hello/src/lib.rs
new file mode 100644
index 000000000000..db0f43046d5e
--- /dev/null
+++ b/grub-core/commands/rust-hello/src/lib.rs
@@ -0,0 +1,57 @@
+#![no_std]
+
+use core::mem::replace;
+use cty;
+use grub::command::GrubCommand;
+
+/* See https://docs.rust-embedded.org/book/peripherals/singletons.html */
+struct ModuleData {
+    command: Option<GrubCommand>,
+}
+
+impl ModuleData {
+    fn take_command(&mut self) -> GrubCommand {
+        let c = replace(&mut self.command, None);
+        c.unwrap()
+    }
+}
+
+static mut MODULEDATA: ModuleData = ModuleData { command: None };
+
+// This _doesn't_ need no-mangle because it's called via a function
+// pointer. It does, AIUI, need extern "C" to get the ABI right.
+extern "C" fn rust_hello_cmd(
+    _cmd: *mut grub::bindings::grub_command,
+    _argc: cty::c_int,
+    _argv: *mut *mut cty::c_char,
+) -> grub::bindings::grub_err_t {
+    unsafe {
+        grub::bindings::grub_printf("Hello from command written in 
Rust\n\0".as_ptr() as *const _)
+    };
+
+    grub::bindings::grub_err_t_GRUB_ERR_NONE
+}
+
+#[no_mangle]
+pub extern "C" fn grub_rust_hello_init() {
+    let hello = GrubCommand::new(
+        "rust_hello\0",
+        rust_hello_cmd,
+        "\0",
+        "say hello from rust\0",
+    );
+
+    unsafe {
+        MODULEDATA.command = Some(hello);
+    };
+
+    unsafe { grub::bindings::grub_printf("Hello from Rust\n\0".as_ptr() as 
*const _) };
+}
+
+#[no_mangle]
+pub extern "C" fn grub_rust_hello_fini() {
+    // this causes the command to go out of scope, leading to it being 
unregistered
+    unsafe {
+        MODULEDATA.take_command();
+    };
+}
diff --git a/grub-core/commands/rust-hello/wrap.c 
b/grub-core/commands/rust-hello/wrap.c
new file mode 100644
index 000000000000..97775d6840ae
--- /dev/null
+++ b/grub-core/commands/rust-hello/wrap.c
@@ -0,0 +1,8 @@
+#define RUST_WRAPPER
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE("GPLv3+");
+/* rust code defines grub_rust_hello_{init,fini}, this is just for the
+   scripts that determine modules */
+GRUB_MOD_INIT(rust_hello);
+GRUB_MOD_FINI(rust_hello);
diff --git a/tests/test_rust.in b/tests/test_rust.in
new file mode 100644
index 000000000000..b2ceb6f56898
--- /dev/null
+++ b/tests/test_rust.in
@@ -0,0 +1,19 @@
+#! @BUILD_SHEBANG@
+
+. "@builddir@/grub-core/modinfo.sh"
+
+out=`echo "insmod rust_hello; rust_hello;" | @builddir@/grub-shell`
+
+if [ ${grub_modinfo_platform} != emu ]; then
+    if ! echo $out | grep "Hello from Rust" > /dev/null; then
+       echo "Did not see hello from rust module"
+       exit 1
+    fi
+fi
+
+if echo $out | grep "Hello from command written in Rust" > /dev/null; then
+    exit 0;
+else
+    echo "Did not see hello from rust command"
+    exit 1;
+fi
-- 
2.30.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]