Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x86: crate finally builds with x86 and x86_64 #29

Merged
merged 5 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,25 @@ jobs:
rustc -Vv
cargo -Vv

- name: "Run cargo build"
run: cargo build
- name: "Run cargo build (x86) [nightly]"
run: |
rustup toolchain add nightly-2023-07-09
rustup component add rust-src --toolchain nightly-2023-07-09
cargo +nightly-2023-07-09 build --target test/x86-unknown-none.json -Z build-std=core,alloc,compiler_builtins -Z build-std-features=compiler-builtins-mem

- name: "Run cargo build (x86_64)"
run: |
rustup target add x86_64-unknown-none
cargo build --target x86_64-unknown-none

- name: "Run cargo build (aarch64)"
run: |
rustup target add aarch64-unknown-none
cargo build --target aarch64-unknown-none

- name: "Run cargo test"
run: cargo test

- name: "Run cargo build for stable"
run: cargo build --no-default-features --features stable
if: runner.os != 'Windows'
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ edition = "2018"
bitflags = "1.1.0"
rustversion = "1.0.5"

[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = { version = "0.14.9", default-features = false, features = ["instructions"] }
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
x86 = "0.52"

[features]
default = []
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build Status](https://github.com/rust-osdev/uart_16550/workflows/Build/badge.svg)](https://github.com/rust-osdev/uart_16550/actions?query=workflow%3ABuild) [![Docs.rs Badge](https://docs.rs/uart_16550/badge.svg)](https://docs.rs/uart_16550/)

Minimal support for [serial communication](https://en.wikipedia.org/wiki/Asynchronous_serial_communication) through [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter) devices, which are compatible to the [16550 UART](https://en.wikipedia.org/wiki/16550_UART). This crate supports port-mapped and memory mapped UARTS.
Minimal support for [serial communication](https://en.wikipedia.org/wiki/Asynchronous_serial_communication) through [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter) devices, which are compatible to the [16550 UART](https://en.wikipedia.org/wiki/16550_UART). This crate supports I/O port-mapped (x86 only) and memory-mapped UARTS.

## Usage

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! through [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter)
//! devices, which are compatible to the [16550 UART](https://en.wikipedia.org/wiki/16550_UART).
//!
//! This crate supports port-mapped and memory mapped UARTS.
//! This crate supports I/O port-mapped (x86 only) and memory-mapped UARTS.
//!
//! ## Usage
//!
Expand Down
1 change: 1 addition & 0 deletions src/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use core::{
use crate::LineStsFlags;

/// A memory-mapped UART.
#[derive(Debug)]
pub struct MmioSerialPort {
data: AtomicPtr<u8>,
int_en: AtomicPtr<u8>,
Expand Down
105 changes: 69 additions & 36 deletions src/port.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,67 @@
use core::fmt;

use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};

use crate::LineStsFlags;

/// A port-mapped UART.
/// A x86 I/O port-mapped UART.
#[cfg_attr(docsrs, doc(cfg(any(target_arch = "x86", target_arch = "x86_64"))))]
pub struct SerialPort {
data: Port<u8>,
int_en: PortWriteOnly<u8>,
fifo_ctrl: PortWriteOnly<u8>,
line_ctrl: PortWriteOnly<u8>,
modem_ctrl: PortWriteOnly<u8>,
line_sts: PortReadOnly<u8>,
}
#[derive(Debug)]
pub struct SerialPort(u16 /* base port */);

impl SerialPort {
/// Creates a new serial port interface on the given I/O port.
/// Base port.
fn port_base(&self) -> u16 {
self.0
}

/// Data port.
///
/// Read and write.
fn port_data(&self) -> u16 {
self.port_base()
}

/// Interrupt enable port.
///
/// Write only.
fn port_int_en(&self) -> u16 {
self.port_base() + 1
}

/// Fifo control port.
///
/// Write only.
fn port_fifo_ctrl(&self) -> u16 {
self.port_base() + 2
}

/// Line control port.
///
/// Write only.
fn port_line_ctrl(&self) -> u16 {
self.port_base() + 3
}

/// Modem control port.
///
/// Write only.
fn port_modem_ctrl(&self) -> u16 {
self.port_base() + 4
}

/// Line status port.
///
/// Read only.
fn port_line_sts(&self) -> u16 {
self.port_base() + 5
}

/// Creates a new serial port interface on the given I/O base port.
///
/// This function is unsafe because the caller must ensure that the given base address
/// really points to a serial port device.
/// really points to a serial port device and that the caller has the necessary rights
/// to perform the I/O operation.
pub const unsafe fn new(base: u16) -> Self {
Self {
data: Port::new(base),
int_en: PortWriteOnly::new(base + 1),
fifo_ctrl: PortWriteOnly::new(base + 2),
line_ctrl: PortWriteOnly::new(base + 3),
modem_ctrl: PortWriteOnly::new(base + 4),
line_sts: PortReadOnly::new(base + 5),
}
Self(base)
}

/// Initializes the serial port.
Expand All @@ -37,33 +70,33 @@ impl SerialPort {
pub fn init(&mut self) {
unsafe {
// Disable interrupts
self.int_en.write(0x00);
x86::io::outb(self.port_int_en(), 0x00);

// Enable DLAB
self.line_ctrl.write(0x80);
x86::io::outb(self.port_line_ctrl(), 0x80);

// Set maximum speed to 38400 bps by configuring DLL and DLM
self.data.write(0x03);
self.int_en.write(0x00);
x86::io::outb(self.port_data(), 0x03);
x86::io::outb(self.port_int_en(), 0x00);

// Disable DLAB and set data word length to 8 bits
self.line_ctrl.write(0x03);
x86::io::outb(self.port_line_ctrl(), 0x03);

// Enable FIFO, clear TX/RX queues and
// set interrupt watermark at 14 bytes
self.fifo_ctrl.write(0xC7);
x86::io::outb(self.port_fifo_ctrl(), 0xc7);

// Mark data terminal ready, signal request to send
// and enable auxilliary output #2 (used as interrupt line for CPU)
self.modem_ctrl.write(0x0B);
x86::io::outb(self.port_modem_ctrl(), 0x0b);

// Enable interrupts
self.int_en.write(0x01);
x86::io::outb(self.port_int_en(), 0x01);
}
}

fn line_sts(&mut self) -> LineStsFlags {
unsafe { LineStsFlags::from_bits_truncate(self.line_sts.read()) }
unsafe { LineStsFlags::from_bits_truncate(x86::io::inb(self.port_line_sts())) }
}

/// Sends a byte on the serial port.
Expand All @@ -72,15 +105,15 @@ impl SerialPort {
match data {
8 | 0x7F => {
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
self.data.write(8);
x86::io::outb(self.port_data(), 8);
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
self.data.write(b' ');
x86::io::outb(self.port_data(), b' ');
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
self.data.write(8)
x86::io::outb(self.port_data(), 8);
}
_ => {
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
self.data.write(data);
x86::io::outb(self.port_data(), data);
}
}
}
Expand All @@ -90,15 +123,15 @@ impl SerialPort {
pub fn send_raw(&mut self, data: u8) {
unsafe {
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
self.data.write(data);
x86::io::outb(self.port_data(), data);
}
}

/// Receives a byte on the serial port.
pub fn receive(&mut self) -> u8 {
unsafe {
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
self.data.read()
x86::io::inb(self.port_data())
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions test/x86-unknown-none.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"llvm-target": "i686-unknown-none",
"data-layout": "e-m:e-i32:32-f80:128-n8:16:32-S128-p:32:32",
"arch": "x86",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"relocation-model": "static",
"features": "+soft-float,-x87,-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-fma,-3dnow,-3dnowa"
}