Skip to content

Commit ee33d34

Browse files
misc: minor pty fixes
Signed-off-by: Anhad Singh <[email protected]>
1 parent 592f96a commit ee33d34

File tree

10 files changed

+149
-70
lines changed

10 files changed

+149
-70
lines changed

aero.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,8 @@
2424
import shutil
2525
import subprocess
2626
import sys
27-
import tarfile
2827
import time
2928

30-
from typing import List
31-
3229

3330
def log_info(msg):
3431
"""
@@ -598,6 +595,14 @@ def main():
598595
run_command(['cargo', 'fmt'], cwd="src")
599596
return
600597

598+
if os.path.exists(BUILD_DIR):
599+
system_root = os.path.join(SYSROOT_DIR, 'system-root')
600+
sysroot_mod = max(os.path.getmtime(os.path.join(system_root, file)) for file in os.listdir(system_root))
601+
build_mod = os.path.getmtime(BUILD_DIR)
602+
if sysroot_mod > build_mod:
603+
log_info("sysroot modified, rebuilding")
604+
os.rmdir(BUILD_DIR)
605+
601606
t0 = time.time()
602607
# arch-aero_os
603608
target_arch = args.target.split('-')[0]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// TODO: Is it worth adding a GDB stub to facilitate userland debugging?
2+
pub fn init() {}
3+
4+
crate::module_init!(init, ModuleType::Other);

src/aero_kernel/src/drivers/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub mod keyboard;
2727
pub mod lai;
2828
// FIXME: aarch64 port
2929
pub mod e1000;
30+
// #[cfg(feature = "gdbstub")]
31+
pub mod gdbstub;
3032
pub mod mouse;
3133
#[cfg(target_arch = "x86_64")]
3234
pub mod pci;

src/aero_kernel/src/drivers/pty.rs

Lines changed: 37 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::mem::paging::VirtAddr;
3535
use crate::userland::scheduler;
3636
use crate::userland::scheduler::ExitStatus;
3737
use crate::userland::task::Task;
38-
use crate::userland::terminal::{LineDiscipline, TerminalDevice};
38+
use crate::userland::terminal::{LineControl, LineDiscipline, TerminalDevice};
3939
use crate::utils::sync::{Mutex, WaitQueue};
4040

4141
lazy_static::lazy_static! {
@@ -50,60 +50,21 @@ struct Master {
5050
wq: WaitQueue,
5151
window_size: Mutex<WinSize>,
5252
buffer: Mutex<Vec<u8>>,
53-
termios: Mutex<Termios>,
54-
5553
discipline: LineDiscipline,
5654
}
5755

5856
impl Master {
5957
pub fn new() -> Self {
6058
use aero_syscall::*;
6159

62-
// converts `^X` into `X`
63-
let ctrl = |c| (c as u8 - 0x40);
64-
65-
let mut termios = Termios {
66-
c_iflag: aero_syscall::TermiosIFlag::empty(),
67-
c_oflag: aero_syscall::TermiosOFlag::ONLCR,
68-
c_cflag: aero_syscall::TermiosCFlag::empty(),
69-
c_lflag: TermiosLFlag::ECHOKE
70-
| TermiosLFlag::ECHOE
71-
| TermiosLFlag::ECHOK
72-
| TermiosLFlag::ECHO
73-
| TermiosLFlag::ECHOCTL
74-
| TermiosLFlag::ISIG
75-
| TermiosLFlag::ICANON
76-
| TermiosLFlag::IEXTEN,
77-
c_line: 0,
78-
c_cc: [0; 32],
79-
c_ispeed: 0,
80-
c_ospeed: 0,
81-
};
82-
83-
termios.c_cc[VINTR] = ctrl('C');
84-
termios.c_cc[VQUIT] = ctrl('\\');
85-
termios.c_cc[VERASE] = 127; // DEL character
86-
termios.c_cc[VKILL] = ctrl('U');
87-
termios.c_cc[VEOF] = ctrl('D');
88-
termios.c_cc[VMIN] = 1;
89-
termios.c_cc[VSTART] = ctrl('Q');
90-
termios.c_cc[VSTOP] = ctrl('S');
91-
termios.c_cc[VSUSP] = ctrl('Z');
92-
9360
Self {
9461
id: PTY_ID.fetch_add(1, Ordering::SeqCst),
9562
wq: WaitQueue::new(),
9663
window_size: Mutex::new(WinSize::default()),
9764
buffer: Mutex::new(Vec::new()),
98-
termios: Mutex::new(termios),
99-
10065
discipline: LineDiscipline::new(),
10166
}
10267
}
103-
104-
pub fn is_cooked(&self) -> bool {
105-
self.termios.lock_irq().is_cooked()
106-
}
10768
}
10869

10970
impl INodeInterface for Master {
@@ -120,7 +81,10 @@ impl INodeInterface for Master {
12081
}
12182

12283
fn write_at(&self, _offset: usize, buffer: &[u8]) -> fs::Result<usize> {
123-
self.discipline.write(buffer);
84+
self.discipline.write(buffer, |ctrl| match ctrl {
85+
LineControl::Echo(c) => self.buffer.lock_irq().push(c),
86+
});
87+
self.wq.notify_all();
12488
Ok(buffer.len())
12589
}
12690

@@ -150,7 +114,7 @@ impl INodeInterface for Master {
150114
}
151115

152116
_ => {
153-
log::warn!("ptmx: unknown ioctl (command={command:#x})")
117+
panic!("ptmx: unknown ioctl (command={command:#x})")
154118
}
155119
}
156120

@@ -168,13 +132,13 @@ impl TerminalDevice for Slave {
168132
use aero_syscall::signal::*;
169133
use aero_syscall::*;
170134

171-
if !self.master.is_cooked() {
135+
if !self.master.discipline.termios.lock().is_cooked() {
172136
return;
173137
}
174138

175139
if let ExitStatus::Signal(signo) = task.exit_status() {
176140
let mut buffer = self.master.buffer.lock_irq();
177-
let termios = self.master.termios.lock_irq();
141+
let termios = self.master.discipline.termios.lock();
178142

179143
// converts `X` into `^X` and pushes the result into the master PTY buffer.
180144
let mut ctrl = |c| {
@@ -208,12 +172,7 @@ impl Slave {
208172

209173
impl INodeInterface for Slave {
210174
fn metadata(&self) -> fs::Result<fs::inode::Metadata> {
211-
Ok(fs::inode::Metadata {
212-
id: 0,
213-
file_type: FileType::Device,
214-
children_len: 0,
215-
size: 0,
216-
})
175+
Ok(fs::inode::Metadata::with_file_type(FileType::Device))
217176
}
218177

219178
fn stat(&self) -> fs::Result<aero_syscall::Stat> {
@@ -229,16 +188,32 @@ impl INodeInterface for Slave {
229188
Ok(0)
230189
}
231190

191+
aero_syscall::TIOCSWINSZ => {
192+
*self.master.window_size.lock_irq() = *VirtAddr::new(arg as u64).read_mut()?;
193+
Ok(0)
194+
}
195+
232196
aero_syscall::TCGETS => {
233197
let termios = VirtAddr::new(arg as u64).read_mut::<Termios>()?;
234-
*termios = *self.master.termios.lock_irq();
198+
*termios = self.master.discipline.termios();
235199

236200
Ok(0)
237201
}
238202

239203
aero_syscall::TCSETSF => {
240204
let termios = VirtAddr::new(arg as u64).read_mut::<Termios>()?;
241-
*self.master.termios.lock_irq() = *termios;
205+
self.master.discipline.set_termios(termios.clone());
206+
207+
Ok(0)
208+
}
209+
210+
aero_syscall::TCSETSW => {
211+
// TODO: Allow the output buffer to drain and then set the current serial port
212+
// settings.
213+
//
214+
// Equivalent to tcsetattr(fd, TCSADRAIN, argp).
215+
let termios = VirtAddr::new(arg as u64).read_mut::<Termios>()?;
216+
self.master.discipline.set_termios(termios.clone());
242217

243218
Ok(0)
244219
}
@@ -251,7 +226,11 @@ impl INodeInterface for Slave {
251226
Ok(0)
252227
}
253228

254-
_ => Err(FileSystemError::NotSupported),
229+
// TIOCGPGRP - Get the process group ID of the foreground process group on this
230+
// terminal.
231+
0x540f => Err(FileSystemError::NotSupported),
232+
233+
_ => panic!("pty: unknown ioctl: {command}"),
255234
}
256235
}
257236

@@ -271,14 +250,16 @@ impl INodeInterface for Slave {
271250
}
272251

273252
fn read_at(&self, _offset: usize, buffer: &mut [u8]) -> fs::Result<usize> {
274-
Ok(self.master.discipline.read(buffer)?)
253+
let x = self.master.discipline.read(buffer)?;
254+
dbg!(core::str::from_utf8(&buffer[..x]));
255+
Ok(x)
275256
}
276257

277258
fn write_at(&self, _offset: usize, buffer: &[u8]) -> fs::Result<usize> {
278259
if self
279260
.master
280-
.termios
281-
.lock_irq()
261+
.discipline
262+
.termios()
282263
.c_oflag
283264
.contains(aero_syscall::TermiosOFlag::ONLCR)
284265
{

src/aero_kernel/src/fs/file_table.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,6 @@ impl FileTable {
302302
let files = self.0.read();
303303

304304
for handle in files.iter().flatten() {
305-
let flags = *handle.flags.read();
306-
307305
handle
308306
.inode
309307
.inode()

src/aero_kernel/src/mem/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ pub mod pti;
2121
mod slab;
2222
mod vmalloc;
2323

24-
use core::alloc::Layout;
25-
2624
use ::alloc::boxed::Box;
2725

2826
use crate::mem::paging::*;

src/aero_kernel/src/mem/paging/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ mod page_table;
2323

2424
pub use self::addr::*;
2525
pub use self::frame::*;
26-
pub use self::mapper::{MapperFlush, *};
26+
pub use self::mapper::*;
2727
pub use self::page::*;
2828
pub use self::page_table::*;
2929

src/aero_kernel/src/userland/terminal.rs

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// You should have received a copy of the GNU General Public License
1616
// along with Aero. If not, see <https://www.gnu.org/licenses/>.
1717

18-
use aero_syscall::signal;
18+
use aero_syscall::{signal, Termios, TermiosIFlag, TermiosLFlag};
1919

2020
use alloc::sync::{Arc, Weak};
2121
use alloc::vec::Vec;
@@ -40,6 +40,11 @@ pub trait TerminalDevice: Send + Sync + INodeInterface {
4040
fn detach(&self, task: Arc<Task>);
4141
}
4242

43+
#[derive(Debug, Copy, Clone)]
44+
pub enum LineControl {
45+
Echo(u8),
46+
}
47+
4348
/// Line Discipline
4449
///
4550
/// The middle terminal subsystem layer, used to implement behavior common to terminal devices.
@@ -51,41 +56,108 @@ pub struct LineDiscipline {
5156
wq: WaitQueue,
5257
buffer: Mutex<Vec<u8>>,
5358
foreground: RwLock<Weak<Group>>,
59+
// TODO: Make this private.
60+
pub termios: Mutex<Termios>,
5461
}
5562

5663
impl LineDiscipline {
5764
/// Creates a new line discipline.
5865
pub fn new() -> Self {
66+
use aero_syscall::{TermiosCFlag, TermiosOFlag};
67+
68+
// converts `^X` into `X`
69+
let ctrl = |c| (c as u8 - 0x40);
70+
71+
let mut termios = Termios {
72+
c_iflag: TermiosIFlag::ICRNL | TermiosIFlag::IXON,
73+
c_oflag: TermiosOFlag::OPOST | TermiosOFlag::ONLCR,
74+
c_cflag: TermiosCFlag::CS6 | TermiosCFlag::CS7 | TermiosCFlag::CREAD,
75+
c_lflag: TermiosLFlag::ECHOKE
76+
| TermiosLFlag::ECHOE
77+
| TermiosLFlag::ECHOK
78+
| TermiosLFlag::ECHO
79+
| TermiosLFlag::ECHOCTL
80+
| TermiosLFlag::ISIG
81+
| TermiosLFlag::ICANON
82+
| TermiosLFlag::IEXTEN,
83+
c_line: 0,
84+
c_cc: [0; 32],
85+
c_ispeed: 0,
86+
c_ospeed: 0,
87+
};
88+
89+
termios.c_cc[aero_syscall::VINTR] = ctrl('C');
90+
termios.c_cc[aero_syscall::VQUIT] = ctrl('\\');
91+
termios.c_cc[aero_syscall::VERASE] = 127; // DEL character
92+
termios.c_cc[aero_syscall::VKILL] = ctrl('U');
93+
termios.c_cc[aero_syscall::VEOF] = ctrl('D');
94+
termios.c_cc[aero_syscall::VMIN] = 1;
95+
termios.c_cc[aero_syscall::VSTART] = ctrl('Q');
96+
termios.c_cc[aero_syscall::VSTOP] = ctrl('S');
97+
termios.c_cc[aero_syscall::VSUSP] = ctrl('Z');
98+
5999
Self {
60100
wq: WaitQueue::new(),
61101
buffer: Mutex::new(Vec::new()),
62102
foreground: RwLock::new(Weak::default()),
103+
termios: Mutex::new(termios),
63104
}
64105
}
65106

66-
/// Reads data from the line discipline buffer.
107+
#[inline]
108+
pub fn termios(&self) -> Termios {
109+
self.termios.lock().clone()
110+
}
111+
112+
#[inline]
113+
pub fn set_termios(&self, termios: Termios) {
114+
*self.termios.lock() = termios;
115+
}
116+
67117
pub fn read(&self, target: &mut [u8]) -> Result<usize, SignalError> {
68-
let mut buffer = self.wq.block_on(&self.buffer, |e| !e.is_empty())?;
118+
let mut buffer = self.wq.block_on(&self.buffer, |buf| !buf.is_empty())?;
69119

70120
let size = core::cmp::min(target.len(), buffer.len());
71121
target[..size].copy_from_slice(&buffer.drain(..size).collect::<Vec<_>>());
72122

73123
Ok(size)
74124
}
75125

76-
/// Writes data to the line discipline buffer.
77-
pub fn write(&self, target: &[u8]) {
126+
pub fn write<F>(&self, target: &[u8], callback: F)
127+
where
128+
F: Fn(LineControl),
129+
{
78130
let mut buffer = self.buffer.lock_irq();
131+
let termios = self.termios.lock();
132+
let should_echo = termios.c_lflag.contains(TermiosLFlag::ECHO);
79133

80134
for byte in target {
81135
match byte {
82136
// ETX: End of Text (`Ctrl+C`)
83-
0x3 => {
137+
0x3 if termios.is_cooked() => {
84138
if let Some(foreground) = self.foreground() {
85139
foreground.signal(signal::SIGINT);
86140
}
87141
}
88142

143+
b'\r' if termios.c_iflag.contains(TermiosIFlag::ICRNL) => {
144+
buffer.push(b'\n');
145+
146+
if should_echo {
147+
callback(LineControl::Echo(b'\r'));
148+
callback(LineControl::Echo(b'\n'));
149+
}
150+
}
151+
152+
byte if termios.is_cooked() => {
153+
buffer.push(*byte);
154+
155+
if should_echo {
156+
callback(LineControl::Echo(*byte))
157+
}
158+
}
159+
160+
// In raw mode:
89161
_ => buffer.push(*byte),
90162
}
91163
}

src/aero_syscall/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ impl From<usize> for SeekWhence {
294294
pub const TIOCGWINSZ: usize = 0x5413;
295295
pub const TIOCSWINSZ: usize = 0x5414;
296296
pub const TCGETS: usize = 0x5401;
297+
pub const TCSETSW: usize = 0x5403;
297298
pub const TCSETSF: usize = 0x5404;
298299
pub const TIOCSCTTY: usize = 0x540e;
299300
pub const TIOCNOTTY: usize = 0x5422;

0 commit comments

Comments
 (0)