diff options
author | Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> | 2019-09-24 01:14:15 +0200 |
---|---|---|
committer | Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> | 2020-09-04 23:36:48 +0200 |
commit | 40cbc3f043eeea8b8f27ece943f42437a264239b (patch) | |
tree | 12724d003fde303aa06a7f94d40992fdd71cd23e /rust/kernel/src/printk.rs | |
parent | d012a7190fc1fd72ed48911e77ca97ba4521bccd (diff) |
Initial Rust support
Currently we have several lines of work:
- Integrating with the kernel tree and build system (Nick's & mine,
both uploaded as branches, based on `rustc`; and another one I have
been working on, based on `cargo`).
- Bindings and the first bits of functionality (Alex's & Geoffrey's,
based on `cargo`).
This patch effectively merges the work we have been doing and
integrates it in the latest mainline kernel tree.
This does *not* mean anything needs to stay as-is, but this gives us
a working, common base to work and experiment upon. Hopefully, it will
also attract external people to join!
As a summary, I added:
- `cargo` integration with the kernel `Makefile`s:
+ Virtual `cargo` workspace to have a single lock file and to share
deps between `cargo` jobs.
+ Picks the same optimization level as configured for C.
+ Verbose output on `V=1`.
+ A `cargoclean` target to clean all the Rust-related artifacts.
- Initial support for built-in modules (i.e. `Y` as well as `M`):
+ It is a hack, we need to implement a few things (see the `TODO`s),
but it is enough to start playing with things that depend on `MODULE`.
+ Passes `--cfg module` to built-in modules to be able to compile
conditionally inside Rust.
+ Increased `KSYM_NAME_LEN` length to avoid warnings due to Rust
long mangled symbols.
- Rust infrastructure in a new top level folder `rust/`:
+ A `kernel` package which contains the sources from Alex &
Geoffrey's work plus some changes:
* Adapted `build.rs`.
* Removed the `THIS_MODULE` emulation until it is implemented.
* Removed `Makefile` logic and the code that `cfg`-depended
on kernel version (no need in mainline).
* Moved the helpers to be triggered via normal compilation,
renamed them under `rust_*` and exported via
`EXPORT_SYMBOL` instead.
* Added a prelude.
+ A `shlex` package which serves as an example of an "inline"
dependency (i.e. package checked out copy to avoid the network)
- The example driver was setup at `drivers/char/rust_example/`.
- Misc
+ The beginning of `Documentation/rust/` with a quick start guide.
+ `MAINTAINERS` entry.
+ SPDXs for all files.
Other notes that aren't in `TODO`s:
- We could minimize the network requirements (use `bindgen` binary, use more
inline dependencies...), but it is not clear it would be a good idea for
the moment due to `core`/`alloc`/`compiler-builtins`.
- The intention of `rust/` is to have a place to put extra dependencies
and split the `kernel` package into several in the future if it grows.
It could resemble the usual kernel tree structure.
- With several drivers being built-in, `cargo` recompiles `kernel`
and triggers duplicate symbol errors when merging thin archives.
We need to make it only compile `kernel` once.
- When the above works, then `make`'s `-j` calling concurrent `cargo`s
(e.g. several drivers at the same time) should be OK, I think.
According to https://github.com/rust-lang/cargo/pull/2486 it shouldn't
miscompile anything, but if they start locking on each other
we will have make jobs waiting that could have been doing something else.
Signed-off-by: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Diffstat (limited to 'rust/kernel/src/printk.rs')
-rw-r--r-- | rust/kernel/src/printk.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/rust/kernel/src/printk.rs b/rust/kernel/src/printk.rs new file mode 100644 index 000000000000..1a27c034258a --- /dev/null +++ b/rust/kernel/src/printk.rs @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 + +use core::cmp; +use core::fmt; + +use crate::bindings; +use crate::c_types::c_int; + +#[doc(hidden)] +pub fn printk(s: &[u8]) { + // Don't copy the trailing NUL from `KERN_INFO`. + let mut fmt_str = [0; bindings::KERN_INFO.len() - 1 + b"%.*s\0".len()]; + fmt_str[..bindings::KERN_INFO.len() - 1] + .copy_from_slice(&bindings::KERN_INFO[..bindings::KERN_INFO.len() - 1]); + fmt_str[bindings::KERN_INFO.len() - 1..].copy_from_slice(b"%.*s\0"); + + // TODO: I believe printk never fails + unsafe { bindings::printk(fmt_str.as_ptr() as _, s.len() as c_int, s.as_ptr()) }; +} + +// From kernel/print/printk.c +const LOG_LINE_MAX: usize = 1024 - 32; + +#[doc(hidden)] +pub struct LogLineWriter { + data: [u8; LOG_LINE_MAX], + pos: usize, +} + +#[allow(clippy::new_without_default)] +impl LogLineWriter { + pub fn new() -> LogLineWriter { + LogLineWriter { + data: [0u8; LOG_LINE_MAX], + pos: 0, + } + } + + pub fn as_bytes(&self) -> &[u8] { + &self.data[..self.pos] + } +} + +impl fmt::Write for LogLineWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + let copy_len = cmp::min(LOG_LINE_MAX - self.pos, s.as_bytes().len()); + self.data[self.pos..self.pos + copy_len].copy_from_slice(&s.as_bytes()[..copy_len]); + self.pos += copy_len; + Ok(()) + } +} + +/// [`println!`] functions the same as it does in `std`, except instead of +/// printing to `stdout`, it writes to the kernel console at the `KERN_INFO` +/// level. +/// +/// [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html +#[macro_export] +macro_rules! println { + () => ({ + $crate::printk::printk("\n".as_bytes()); + }); + ($fmt:expr) => ({ + $crate::printk::printk(concat!($fmt, "\n").as_bytes()); + }); + ($fmt:expr, $($arg:tt)*) => ({ + use ::core::fmt; + let mut writer = $crate::printk::LogLineWriter::new(); + let _ = fmt::write(&mut writer, format_args!(concat!($fmt, "\n"), $($arg)*)).unwrap(); + $crate::printk::printk(writer.as_bytes()); + }); +} |