Skip to content

Commit d60387b

Browse files
authoredAug 4, 2023
x86: crate finally builds with x86 and x86_64 (#29)
1 parent e1ee971 commit d60387b

File tree

7 files changed

+106
-43
lines changed

7 files changed

+106
-43
lines changed
 

‎.github/workflows/build.yml

+16-3
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,25 @@ jobs:
3030
rustc -Vv
3131
cargo -Vv
3232
33-
- name: "Run cargo build"
34-
run: cargo build
33+
- name: "Run cargo build (x86) [nightly]"
34+
run: |
35+
rustup toolchain add nightly-2023-07-09
36+
rustup component add rust-src --toolchain nightly-2023-07-09
37+
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
38+
39+
- name: "Run cargo build (x86_64)"
40+
run: |
41+
rustup target add x86_64-unknown-none
42+
cargo build --target x86_64-unknown-none
43+
44+
- name: "Run cargo build (aarch64)"
45+
run: |
46+
rustup target add aarch64-unknown-none
47+
cargo build --target aarch64-unknown-none
3548
3649
- name: "Run cargo test"
3750
run: cargo test
38-
51+
3952
- name: "Run cargo build for stable"
4053
run: cargo build --no-default-features --features stable
4154
if: runner.os != 'Windows'

‎Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ edition = "2018"
1111
bitflags = "1.1.0"
1212
rustversion = "1.0.5"
1313

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

1717
[features]
1818
default = []

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![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/)
44

5-
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.
5+
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.
66

77
## Usage
88

‎src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! through [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter)
44
//! devices, which are compatible to the [16550 UART](https://en.wikipedia.org/wiki/16550_UART).
55
//!
6-
//! This crate supports port-mapped and memory mapped UARTS.
6+
//! This crate supports I/O port-mapped (x86 only) and memory-mapped UARTS.
77
//!
88
//! ## Usage
99
//!

‎src/mmio.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use core::{
66
use crate::LineStsFlags;
77

88
/// A memory-mapped UART.
9+
#[derive(Debug)]
910
pub struct MmioSerialPort {
1011
data: AtomicPtr<u8>,
1112
int_en: AtomicPtr<u8>,

‎src/port.rs

+69-36
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,67 @@
11
use core::fmt;
22

3-
use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
4-
53
use crate::LineStsFlags;
64

7-
/// A port-mapped UART.
5+
/// A x86 I/O port-mapped UART.
86
#[cfg_attr(docsrs, doc(cfg(any(target_arch = "x86", target_arch = "x86_64"))))]
9-
pub struct SerialPort {
10-
data: Port<u8>,
11-
int_en: PortWriteOnly<u8>,
12-
fifo_ctrl: PortWriteOnly<u8>,
13-
line_ctrl: PortWriteOnly<u8>,
14-
modem_ctrl: PortWriteOnly<u8>,
15-
line_sts: PortReadOnly<u8>,
16-
}
7+
#[derive(Debug)]
8+
pub struct SerialPort(u16 /* base port */);
179

1810
impl SerialPort {
19-
/// Creates a new serial port interface on the given I/O port.
11+
/// Base port.
12+
fn port_base(&self) -> u16 {
13+
self.0
14+
}
15+
16+
/// Data port.
17+
///
18+
/// Read and write.
19+
fn port_data(&self) -> u16 {
20+
self.port_base()
21+
}
22+
23+
/// Interrupt enable port.
24+
///
25+
/// Write only.
26+
fn port_int_en(&self) -> u16 {
27+
self.port_base() + 1
28+
}
29+
30+
/// Fifo control port.
31+
///
32+
/// Write only.
33+
fn port_fifo_ctrl(&self) -> u16 {
34+
self.port_base() + 2
35+
}
36+
37+
/// Line control port.
38+
///
39+
/// Write only.
40+
fn port_line_ctrl(&self) -> u16 {
41+
self.port_base() + 3
42+
}
43+
44+
/// Modem control port.
45+
///
46+
/// Write only.
47+
fn port_modem_ctrl(&self) -> u16 {
48+
self.port_base() + 4
49+
}
50+
51+
/// Line status port.
52+
///
53+
/// Read only.
54+
fn port_line_sts(&self) -> u16 {
55+
self.port_base() + 5
56+
}
57+
58+
/// Creates a new serial port interface on the given I/O base port.
2059
///
2160
/// This function is unsafe because the caller must ensure that the given base address
22-
/// really points to a serial port device.
61+
/// really points to a serial port device and that the caller has the necessary rights
62+
/// to perform the I/O operation.
2363
pub const unsafe fn new(base: u16) -> Self {
24-
Self {
25-
data: Port::new(base),
26-
int_en: PortWriteOnly::new(base + 1),
27-
fifo_ctrl: PortWriteOnly::new(base + 2),
28-
line_ctrl: PortWriteOnly::new(base + 3),
29-
modem_ctrl: PortWriteOnly::new(base + 4),
30-
line_sts: PortReadOnly::new(base + 5),
31-
}
64+
Self(base)
3265
}
3366

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

4275
// Enable DLAB
43-
self.line_ctrl.write(0x80);
76+
x86::io::outb(self.port_line_ctrl(), 0x80);
4477

4578
// Set maximum speed to 38400 bps by configuring DLL and DLM
46-
self.data.write(0x03);
47-
self.int_en.write(0x00);
79+
x86::io::outb(self.port_data(), 0x03);
80+
x86::io::outb(self.port_int_en(), 0x00);
4881

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

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

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

6093
// Enable interrupts
61-
self.int_en.write(0x01);
94+
x86::io::outb(self.port_int_en(), 0x01);
6295
}
6396
}
6497

6598
fn line_sts(&mut self) -> LineStsFlags {
66-
unsafe { LineStsFlags::from_bits_truncate(self.line_sts.read()) }
99+
unsafe { LineStsFlags::from_bits_truncate(x86::io::inb(self.port_line_sts())) }
67100
}
68101

69102
/// Sends a byte on the serial port.
@@ -72,15 +105,15 @@ impl SerialPort {
72105
match data {
73106
8 | 0x7F => {
74107
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
75-
self.data.write(8);
108+
x86::io::outb(self.port_data(), 8);
76109
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
77-
self.data.write(b' ');
110+
x86::io::outb(self.port_data(), b' ');
78111
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
79-
self.data.write(8)
112+
x86::io::outb(self.port_data(), 8);
80113
}
81114
_ => {
82115
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
83-
self.data.write(data);
116+
x86::io::outb(self.port_data(), data);
84117
}
85118
}
86119
}
@@ -90,15 +123,15 @@ impl SerialPort {
90123
pub fn send_raw(&mut self, data: u8) {
91124
unsafe {
92125
wait_for!(self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY));
93-
self.data.write(data);
126+
x86::io::outb(self.port_data(), data);
94127
}
95128
}
96129

97130
/// Receives a byte on the serial port.
98131
pub fn receive(&mut self) -> u8 {
99132
unsafe {
100133
wait_for!(self.line_sts().contains(LineStsFlags::INPUT_FULL));
101-
self.data.read()
134+
x86::io::inb(self.port_data())
102135
}
103136
}
104137
}

‎test/x86-unknown-none.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"llvm-target": "i686-unknown-none",
3+
"data-layout": "e-m:e-i32:32-f80:128-n8:16:32-S128-p:32:32",
4+
"arch": "x86",
5+
"target-endian": "little",
6+
"target-pointer-width": "32",
7+
"target-c-int-width": "32",
8+
"os": "none",
9+
"executables": true,
10+
"linker-flavor": "ld.lld",
11+
"linker": "rust-lld",
12+
"panic-strategy": "abort",
13+
"disable-redzone": true,
14+
"relocation-model": "static",
15+
"features": "+soft-float,-x87,-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-fma,-3dnow,-3dnowa"
16+
}

0 commit comments

Comments
 (0)
Please sign in to comment.