x86_64/instructions/
port.rs1use core::arch::asm;
4use core::fmt;
5use core::marker::PhantomData;
6
7pub use crate::structures::port::{PortRead, PortWrite};
8
9impl PortRead for u8 {
10 #[inline]
11 unsafe fn read_from_port(port: u16) -> u8 {
12 let value: u8;
13 unsafe {
14 asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags));
15 }
16 value
17 }
18}
19
20impl PortRead for u16 {
21 #[inline]
22 unsafe fn read_from_port(port: u16) -> u16 {
23 let value: u16;
24 unsafe {
25 asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags));
26 }
27 value
28 }
29}
30
31impl PortRead for u32 {
32 #[inline]
33 unsafe fn read_from_port(port: u16) -> u32 {
34 let value: u32;
35 unsafe {
36 asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags));
37 }
38 value
39 }
40}
41
42impl PortWrite for u8 {
43 #[inline]
44 unsafe fn write_to_port(port: u16, value: u8) {
45 unsafe {
46 asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags));
47 }
48 }
49}
50
51impl PortWrite for u16 {
52 #[inline]
53 unsafe fn write_to_port(port: u16, value: u16) {
54 unsafe {
55 asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags));
56 }
57 }
58}
59
60impl PortWrite for u32 {
61 #[inline]
62 unsafe fn write_to_port(port: u16, value: u32) {
63 unsafe {
64 asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags));
65 }
66 }
67}
68
69mod sealed {
70 pub trait Access {
71 const DEBUG_NAME: &'static str;
72 }
73}
74
75pub trait PortReadAccess: sealed::Access {}
77
78pub trait PortWriteAccess: sealed::Access {}
80
81#[derive(Debug)]
83pub struct ReadOnlyAccess(());
84
85impl sealed::Access for ReadOnlyAccess {
86 const DEBUG_NAME: &'static str = "ReadOnly";
87}
88impl PortReadAccess for ReadOnlyAccess {}
89
90#[derive(Debug)]
92pub struct WriteOnlyAccess(());
93
94impl sealed::Access for WriteOnlyAccess {
95 const DEBUG_NAME: &'static str = "WriteOnly";
96}
97impl PortWriteAccess for WriteOnlyAccess {}
98
99#[derive(Debug)]
101pub struct ReadWriteAccess(());
102
103impl sealed::Access for ReadWriteAccess {
104 const DEBUG_NAME: &'static str = "ReadWrite";
105}
106impl PortReadAccess for ReadWriteAccess {}
107impl PortWriteAccess for ReadWriteAccess {}
108
109pub struct PortGeneric<T, A> {
118 port: u16,
119 phantom: PhantomData<(T, A)>,
120}
121
122pub type Port<T> = PortGeneric<T, ReadWriteAccess>;
124
125pub type PortReadOnly<T> = PortGeneric<T, ReadOnlyAccess>;
127
128pub type PortWriteOnly<T> = PortGeneric<T, WriteOnlyAccess>;
130
131impl<T, A> PortGeneric<T, A> {
132 #[inline]
134 pub const fn new(port: u16) -> PortGeneric<T, A> {
135 PortGeneric {
136 port,
137 phantom: PhantomData,
138 }
139 }
140}
141
142impl<T: PortRead, A: PortReadAccess> PortGeneric<T, A> {
143 #[inline]
150 pub unsafe fn read(&mut self) -> T {
151 unsafe { T::read_from_port(self.port) }
152 }
153}
154
155impl<T: PortWrite, A: PortWriteAccess> PortGeneric<T, A> {
156 #[inline]
163 pub unsafe fn write(&mut self, value: T) {
164 unsafe { T::write_to_port(self.port, value) }
165 }
166}
167
168impl<T, A: sealed::Access> fmt::Debug for PortGeneric<T, A> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 f.debug_struct("PortGeneric")
171 .field("port", &self.port)
172 .field("size", &core::mem::size_of::<T>())
173 .field("access", &format_args!("{}", A::DEBUG_NAME))
174 .finish()
175 }
176}
177
178impl<T, A> Clone for PortGeneric<T, A> {
179 fn clone(&self) -> Self {
180 Self {
181 port: self.port,
182 phantom: PhantomData,
183 }
184 }
185}
186
187impl<T, A> PartialEq for PortGeneric<T, A> {
188 fn eq(&self, other: &Self) -> bool {
189 self.port == other.port
190 }
191}
192
193impl<T, A> Eq for PortGeneric<T, A> {}