1use core::fmt::Write;
6use core::mem::MaybeUninit;
7
8use kernel::component::Component;
9use kernel::platform::chip::Chip;
10
11use x86::mpu::PagingMPU;
12use x86::registers::bits32::paging::{PD, PT};
13use x86::support;
14use x86::{Boundary, InterruptPoller};
15
16use crate::pit::{Pit, RELOAD_1KHZ};
17use crate::serial::{SerialPort, SerialPortComponent, COM1_BASE, COM2_BASE, COM3_BASE, COM4_BASE};
18
19mod interrupt {
21 use crate::pic::PIC1_OFFSET;
22
23 pub(super) const PIT: u32 = PIC1_OFFSET as u32;
25
26 pub(super) const COM2_COM4: u32 = (PIC1_OFFSET as u32) + 3;
28
29 pub(super) const COM1_COM3: u32 = (PIC1_OFFSET as u32) + 4;
31}
32
33pub struct Pc<'a, const PR: u16 = RELOAD_1KHZ> {
41 pub com1: &'a SerialPort<'a>,
43
44 pub com2: &'a SerialPort<'a>,
46
47 pub com3: &'a SerialPort<'a>,
49
50 pub com4: &'a SerialPort<'a>,
52
53 pub pit: Pit<'a, PR>,
55
56 syscall: Boundary,
58 paging: PagingMPU<'a>,
59}
60
61impl<'a, const PR: u16> Chip for Pc<'a, PR> {
62 type MPU = PagingMPU<'a>;
63 fn mpu(&self) -> &Self::MPU {
64 &self.paging
65 }
66
67 type UserspaceKernelBoundary = Boundary;
68 fn userspace_kernel_boundary(&self) -> &Self::UserspaceKernelBoundary {
69 &self.syscall
70 }
71
72 fn service_pending_interrupts(&self) {
73 InterruptPoller::access(|poller| {
74 while let Some(num) = poller.next_pending() {
75 match num {
76 interrupt::PIT => self.pit.handle_interrupt(),
77 interrupt::COM2_COM4 => {
78 self.com2.handle_interrupt();
79 self.com4.handle_interrupt();
80 }
81 interrupt::COM1_COM3 => {
82 self.com1.handle_interrupt();
83 self.com3.handle_interrupt();
84 }
85 _ => unimplemented!("interrupt {num}"),
86 }
87
88 poller.clear_pending(num);
89 }
90 })
91 }
92
93 fn has_pending_interrupts(&self) -> bool {
94 InterruptPoller::access(|poller| poller.next_pending().is_some())
95 }
96
97 #[cfg(target_arch = "x86")]
98 fn sleep(&self) {
99 use x86::registers::bits32::eflags::{self, EFLAGS};
100
101 let eflags = unsafe { eflags::read() };
105 let enabled = eflags.0.is_set(EFLAGS::FLAGS_IF);
106
107 if enabled {
108 unsafe {
112 x86::halt();
113 }
114 } else {
115 unsafe {
130 core::arch::asm!("sti; hlt; cli");
131 }
132 }
133 }
134
135 #[cfg(not(target_arch = "x86"))]
136 fn sleep(&self) {
137 unimplemented!()
138 }
139
140 unsafe fn atomic<F, R>(&self, f: F) -> R
141 where
142 F: FnOnce() -> R,
143 {
144 support::atomic(f)
145 }
146
147 unsafe fn print_state(&self, writer: &mut dyn Write) {
148 let _ = writeln!(writer);
149 let _ = writeln!(writer, "---| PC State |---");
150 let _ = writeln!(writer);
151
152 let _ = writeln!(writer, "(placeholder)");
155 }
156}
157
158pub struct PcComponent<'a> {
164 pd: &'a mut PD,
165 pt: &'a mut PT,
166}
167
168impl<'a> PcComponent<'a> {
169 pub unsafe fn new(pd: &'a mut PD, pt: &'a mut PT) -> Self {
181 Self { pd, pt }
182 }
183}
184
185impl Component for PcComponent<'static> {
186 type StaticInput = (
187 <SerialPortComponent as Component>::StaticInput,
188 <SerialPortComponent as Component>::StaticInput,
189 <SerialPortComponent as Component>::StaticInput,
190 <SerialPortComponent as Component>::StaticInput,
191 &'static mut MaybeUninit<Pc<'static>>,
192 );
193 type Output = &'static Pc<'static>;
194
195 fn finalize(self, s: Self::StaticInput) -> Self::Output {
196 unsafe {
199 x86::init();
200 crate::pic::init();
201 }
202
203 let com1 = unsafe { SerialPortComponent::new(COM1_BASE).finalize(s.0) };
204 let com2 = unsafe { SerialPortComponent::new(COM2_BASE).finalize(s.1) };
205 let com3 = unsafe { SerialPortComponent::new(COM3_BASE).finalize(s.2) };
206 let com4 = unsafe { SerialPortComponent::new(COM4_BASE).finalize(s.3) };
207
208 let pit = unsafe { Pit::new() };
209
210 let paging = unsafe {
211 let pd_addr = core::ptr::from_ref(self.pd) as usize;
212 let pt_addr = core::ptr::from_ref(self.pt) as usize;
213 PagingMPU::new(self.pd, pd_addr, self.pt, pt_addr)
214 };
215
216 paging.init();
217
218 let syscall = Boundary::new();
219
220 let pc = s.4.write(Pc {
221 com1,
222 com2,
223 com3,
224 com4,
225 pit,
226 syscall,
227 paging,
228 });
229
230 pc
231 }
232}
233
234#[macro_export]
236macro_rules! x86_q35_component_static {
237 () => {{
238 (
239 $crate::serial_port_component_static!(),
240 $crate::serial_port_component_static!(),
241 $crate::serial_port_component_static!(),
242 $crate::serial_port_component_static!(),
243 kernel::static_buf!($crate::Pc<'static>),
244 )
245 };};
246}