feat: 添加serial console,支持non-graphic启动 (#947)

Signed-off-by: longjin <longjin@dragonos.org>
This commit is contained in:
LoGin 2024-10-01 11:35:48 +08:00 committed by GitHub
parent 103f13024b
commit d031d46fd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 780 additions and 292 deletions

View File

@ -91,6 +91,11 @@ write_diskimage-uefi:
# 不编译直接启动QEMU
qemu:
sh -c "cd tools && bash run-qemu.sh --bios=legacy --display=window && cd .."
# 不编译直接启动QEMU,不显示图像
qemu-nographic:
sh -c "cd tools && bash run-qemu.sh --bios=legacy --display=nographic && cd .."
# 不编译直接启动QEMU(UEFI)
qemu-uefi:
sh -c "cd tools && bash run-qemu.sh --bios=uefi --display=window && cd .."

View File

@ -242,6 +242,7 @@ make run-docker
- Docker编译并写入磁盘镜像,: `make docker`
- Docker编译写入磁盘镜像并在QEMU中运行: `make run-docker`
- 不编译,直接从已有的磁盘镜像启动: `make qemu`
- 不编译,直接从已有的磁盘镜像启动(无图形模式): `make qemu-nographic`
- 清理编译产生的文件: `make clean`
- 编译文档: `make docs` 需要手动安装sphinx以及docs下的`requirements.txt`中的依赖)
- 清理文档: `make clean-docs`

View File

@ -403,7 +403,7 @@ pub fn ioapic_init(ignore: &'static [IrqNumber]) {
}
// 绑定irqchip
for i in 32..256 {
for i in IoApic::VECTOR_BASE as u32..256 {
let irq = IrqNumber::new(i);
if ignore.contains(&irq) {

View File

@ -58,7 +58,6 @@ macro_rules! interrupt_handler {
push rax
mov rsi, {irqnum}
jmp x86_64_do_irq
// jmp do_IRQ
"
),
irqnum = const($name),

View File

@ -3,22 +3,27 @@ use core::{fmt::Debug, sync::atomic::AtomicU32};
use alloc::sync::Arc;
use system_error::SystemError;
use crate::{driver::base::device::device_number::DeviceNumber, mm::VirtAddr};
use crate::mm::VirtAddr;
use self::serial8250::serial8250_manager;
use super::tty::{
termios::{ControlMode, InputMode, LocalMode, OutputMode, Termios, INIT_CONTORL_CHARACTERS},
tty_ldisc::LineDisciplineType,
};
pub mod serial8250;
#[allow(dead_code)]
pub trait UartDriver: Debug + Send + Sync {
fn device_number(&self) -> DeviceNumber;
/// 获取最大的设备数量
fn max_devs_num(&self) -> i32;
// todo: 获取指向console的指针在我们系统里面将来可能是改进后的Textui Window
}
pub const SERIAL_BAUDRATE: BaudRate = BaudRate::new(115200);
/// 串口端口应当实现的trait
///
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/serial_core.h#428
@ -43,16 +48,41 @@ pub trait UartPort {
int_like!(BaudRate, AtomicBaudRate, u32, AtomicU32);
int_like!(DivisorFraction, u32);
lazy_static! {
pub static ref TTY_SERIAL_DEFAULT_TERMIOS: Termios = {
Termios {
input_mode: InputMode::ICRNL | InputMode::IXON | InputMode::IUTF8,
output_mode: OutputMode::OPOST | OutputMode::ONLCR,
control_mode: ControlMode::B115200
| ControlMode::CREAD
| ControlMode::HUPCL
| ControlMode::CS8,
local_mode: LocalMode::ISIG
| LocalMode::ICANON
| LocalMode::ECHO
| LocalMode::ECHOE
| LocalMode::ECHOK
| LocalMode::ECHOCTL
| LocalMode::ECHOKE
| LocalMode::IEXTEN,
control_characters: INIT_CONTORL_CHARACTERS,
line: LineDisciplineType::NTty,
input_speed: SERIAL_BAUDRATE.data(),
output_speed: SERIAL_BAUDRATE.data(),
}
};
}
#[inline(always)]
#[allow(dead_code)]
pub(super) fn uart_manager() -> &'static UartManager {
&UartManager
}
#[derive(Debug)]
pub(super) struct UartManager;
impl UartManager {
pub const NR_TTY_SERIAL_MAX: u32 = 128;
/// todo: 把uart设备注册到tty层
///
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/serial_core.c?fi=uart_register_driver#2720

View File

@ -12,27 +12,35 @@ use log::error;
use system_error::SystemError;
use crate::{
driver::base::{
class::Class,
device::{
bus::Bus, device_manager, device_number::DeviceNumber, driver::Driver, Device,
DeviceCommonData, DeviceKObjType, DeviceState, DeviceType, IdTable,
},
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
kset::KSet,
platform::{
platform_device::{platform_device_manager, PlatformDevice},
platform_driver::{platform_driver_manager, PlatformDriver},
driver::{
base::{
class::Class,
device::{
bus::Bus, device_manager, device_number::Major, driver::Driver, Device,
DeviceCommonData, DeviceKObjType, DeviceState, DeviceType, IdTable,
},
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
kset::KSet,
platform::{
platform_device::{platform_device_manager, PlatformDevice},
platform_driver::{platform_driver_manager, PlatformDriver},
},
},
tty::tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType},
},
filesystem::kernfs::KernFSInode,
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use self::serial8250_pio::{send_to_serial8250_pio_com1, serial8250_pio_port_early_init};
#[cfg(target_arch = "x86_64")]
use self::serial8250_pio::{
send_to_default_serial8250_pio_port, serial8250_pio_port_early_init,
serial_8250_pio_register_tty_devices, Serial8250PIOTtyDriverInner,
};
use super::{uart_manager, UartDriver, UartPort};
use super::{uart_manager, UartDriver, UartManager, UartPort, TTY_SERIAL_DEFAULT_TERMIOS};
#[cfg(target_arch = "x86_64")]
mod serial8250_pio;
static mut SERIAL8250_ISA_DEVICES: Option<Arc<Serial8250ISADevices>> = None;
@ -62,6 +70,8 @@ static mut INITIALIZED: bool = false;
pub(super) struct Serial8250Manager;
impl Serial8250Manager {
pub const TTY_SERIAL_MINOR_START: u32 = 64;
/// 初始化串口设备(在内存管理初始化之前)
pub fn early_init(&self) -> Result<(), SystemError> {
// todo: riscv64: 串口设备初始化
@ -109,6 +119,7 @@ impl Serial8250Manager {
return e;
})?;
self.serial_tty_init()?;
unsafe {
INITIALIZED = true;
}
@ -116,6 +127,34 @@ impl Serial8250Manager {
return Ok(());
}
#[cfg(target_arch = "riscv64")]
fn serial_tty_init(&self) -> Result<(), SystemError> {
Ok(())
}
#[cfg(target_arch = "x86_64")]
fn serial_tty_init(&self) -> Result<(), SystemError> {
let serial8250_tty_driver = TtyDriver::new(
UartManager::NR_TTY_SERIAL_MAX,
"ttyS",
0,
Major::TTY_MAJOR,
Self::TTY_SERIAL_MINOR_START,
TtyDriverType::Serial,
*TTY_SERIAL_DEFAULT_TERMIOS,
Arc::new(Serial8250PIOTtyDriverInner::new()),
None,
);
TtyDriverManager::tty_register_driver(serial8250_tty_driver)?;
if let Err(e) = serial_8250_pio_register_tty_devices() {
if e != SystemError::ENODEV {
return Err(e);
}
}
Ok(())
}
/// 把uart端口与uart driver、uart device绑定
///
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/8250/8250_core.c?r=&mo=30224&fi=1169#553
@ -124,6 +163,7 @@ impl Serial8250Manager {
uart_driver: &Arc<Serial8250ISADriver>,
devs: &Arc<Serial8250ISADevices>,
) {
#[cfg(target_arch = "x86_64")]
self.bind_pio_ports(uart_driver, devs);
}
@ -394,10 +434,6 @@ impl Serial8250ISADriver {
}
impl UartDriver for Serial8250ISADriver {
fn device_number(&self) -> DeviceNumber {
todo!()
}
fn max_devs_num(&self) -> i32 {
todo!()
}
@ -522,7 +558,7 @@ impl KObject for Serial8250ISADriver {
/// 临时函数,用于向默认的串口发送数据
pub fn send_to_default_serial8250_port(s: &[u8]) {
#[cfg(target_arch = "x86_64")]
send_to_serial8250_pio_com1(s);
send_to_default_serial8250_pio_port(s);
#[cfg(target_arch = "riscv64")]
{

View File

@ -5,11 +5,33 @@ use core::{
sync::atomic::{AtomicBool, Ordering},
};
use alloc::sync::{Arc, Weak};
use alloc::{
string::ToString,
sync::{Arc, Weak},
};
use crate::{
arch::{io::PortIOArch, CurrentPortIOArch},
driver::serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort},
arch::{driver::apic::ioapic::IoApic, io::PortIOArch, CurrentPortIOArch},
driver::{
base::device::{
device_number::{DeviceNumber, Major},
DeviceId,
},
serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort},
tty::{
kthread::send_to_tty_refresh_thread,
termios::WindowSize,
tty_core::{TtyCore, TtyCoreData},
tty_driver::{TtyDriver, TtyDriverManager, TtyOperation},
virtual_terminal::{vc_manager, VirtConsole},
},
},
exception::{
irqdata::IrqHandlerData,
irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
manage::irq_manager,
IrqNumber,
},
libs::rwlock::RwLock,
};
use system_error::SystemError;
@ -19,6 +41,8 @@ use super::{Serial8250ISADevices, Serial8250ISADriver, Serial8250Manager, Serial
static mut PIO_PORTS: [Option<Serial8250PIOPort>; 8] =
[None, None, None, None, None, None, None, None];
const SERIAL_8250_PIO_IRQ: IrqNumber = IrqNumber::new(IoApic::VECTOR_BASE as u32 + 4);
impl Serial8250Manager {
#[allow(static_mut_refs)]
pub(super) fn bind_pio_ports(
@ -34,7 +58,7 @@ impl Serial8250Manager {
}
macro_rules! init_port {
($port_num:expr, $baudrate:expr) => {
($port_num:expr) => {
unsafe {
let port = Serial8250PIOPort::new(
match $port_num {
@ -48,12 +72,17 @@ macro_rules! init_port {
8 => Serial8250PortBase::COM8,
_ => panic!("invalid port number"),
},
BaudRate::new($baudrate),
crate::driver::serial::SERIAL_BAUDRATE,
);
if let Ok(port) = port {
if port.init().is_ok() {
PIO_PORTS[$port_num - 1] = Some(port);
true
} else {
false
}
} else {
false
}
}
};
@ -62,8 +91,9 @@ macro_rules! init_port {
/// 在内存管理初始化之前,初始化串口设备
pub(super) fn serial8250_pio_port_early_init() -> Result<(), SystemError> {
for i in 1..=8 {
init_port!(i, 115200);
init_port!(i);
}
return Ok(());
}
@ -100,7 +130,6 @@ impl Serial8250PIOPort {
}
let port = self.iobase as u16;
unsafe {
CurrentPortIOArch::out8(port + 1, 0x00); // Disable all interrupts
self.set_divisor(self.baudrate.load(Ordering::SeqCst))
@ -119,7 +148,9 @@ impl Serial8250PIOPort {
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
CurrentPortIOArch::out8(port + 4, 0x08);
CurrentPortIOArch::out8(port + 4, 0x0b);
CurrentPortIOArch::out8(port + 1, 0x01); // Enable interrupts
}
return Ok(());
@ -168,13 +199,12 @@ impl Serial8250PIOPort {
}
}
/// 读取一个字节
#[allow(dead_code)]
fn read_one_byte(&self) -> u8 {
while !self.serial_received() {
spin_loop();
/// 读取一个字节如果没有数据则返回None
fn read_one_byte(&self) -> Option<u8> {
if !self.serial_received() {
return None;
}
return self.serial_in(0) as u8;
return Some(self.serial_in(0) as u8);
}
}
@ -235,7 +265,14 @@ impl UartPort for Serial8250PIOPort {
}
fn handle_irq(&self) -> Result<(), SystemError> {
todo!("serial8250_pio::handle_irq")
if let Some(c) = self.read_one_byte() {
send_to_tty_refresh_thread(&[c]);
}
Ok(())
}
fn iobase(&self) -> Option<usize> {
Some(self.iobase as usize)
}
}
@ -280,8 +317,140 @@ pub enum Serial8250PortBase {
}
/// 临时函数用于向COM1发送数据
pub fn send_to_serial8250_pio_com1(s: &[u8]) {
pub fn send_to_default_serial8250_pio_port(s: &[u8]) {
if let Some(port) = unsafe { PIO_PORTS[0].as_ref() } {
port.send_bytes(s);
}
}
#[derive(Debug)]
pub(super) struct Serial8250PIOTtyDriverInner;
impl Serial8250PIOTtyDriverInner {
pub fn new() -> Self {
Self
}
fn do_install(
&self,
driver: Arc<TtyDriver>,
tty: Arc<TtyCore>,
vc: Arc<VirtConsole>,
) -> Result<(), SystemError> {
driver.standard_install(tty.clone())?;
vc.port().setup_internal_tty(Arc::downgrade(&tty));
tty.set_port(vc.port());
vc.devfs_setup()?;
Ok(())
}
}
impl TtyOperation for Serial8250PIOTtyDriverInner {
fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> {
Ok(())
}
fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
let index = tty.index();
if tty.index() >= unsafe { PIO_PORTS.len() } {
return Err(SystemError::ENODEV);
}
let pio_port = unsafe { PIO_PORTS[index].as_ref() }.ok_or(SystemError::ENODEV)?;
pio_port.send_bytes(&buf[..nr]);
Ok(nr)
}
fn flush_chars(&self, _tty: &TtyCoreData) {}
fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
self.write(tty, &[ch], 1).map(|_| ())
}
fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> {
Err(SystemError::ENOIOCTLCMD)
}
fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> {
Ok(())
}
fn resize(&self, tty: Arc<TtyCore>, winsize: WindowSize) -> Result<(), SystemError> {
*tty.core().window_size_write() = winsize;
Ok(())
}
fn install(&self, driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
if tty.core().index() >= unsafe { PIO_PORTS.len() } {
return Err(SystemError::ENODEV);
}
let vc = VirtConsole::new(None);
let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
self.do_install(driver, tty, vc.clone()).inspect_err(|_| {
vc_manager().free(vc_index);
})?;
Ok(())
}
}
pub(super) fn serial_8250_pio_register_tty_devices() -> Result<(), SystemError> {
let (_, driver) = TtyDriverManager::lookup_tty_driver(DeviceNumber::new(
Major::TTY_MAJOR,
Serial8250Manager::TTY_SERIAL_MINOR_START,
))
.ok_or(SystemError::ENODEV)?;
for (i, port) in unsafe { PIO_PORTS.iter() }.enumerate() {
if let Some(port) = port {
let core = driver.init_tty_device(Some(i)).inspect_err(|_| {
log::error!(
"failed to init tty device for serial 8250 pio port {}, port iobase: {:?}",
i,
port.iobase
);
})?;
core.resize( core.clone(), WindowSize::DEFAULT)
.inspect_err(|_| {
log::error!(
"failed to resize tty device for serial 8250 pio port {}, port iobase: {:?}",
i,
port.iobase
);
})?;
}
}
irq_manager()
.request_irq(
SERIAL_8250_PIO_IRQ,
"serial8250_pio".to_string(),
&Serial8250IrqHandler,
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_TRIGGER_RISING,
Some(DeviceId::new(Some("serial8250_pio"), None).unwrap()),
)
.inspect_err(|e| {
log::error!("failed to request irq for serial 8250 pio: {:?}", e);
})?;
Ok(())
}
#[derive(Debug)]
struct Serial8250IrqHandler;
impl IrqHandler for Serial8250IrqHandler {
fn handle(
&self,
_irq: IrqNumber,
_static_data: Option<&dyn IrqHandlerData>,
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
) -> Result<IrqReturn, SystemError> {
for port in unsafe { PIO_PORTS.iter() }.flatten() {
port.handle_irq()?;
}
Ok(IrqReturn::Handled)
}
}

View File

@ -1,13 +1,20 @@
use alloc::sync::Arc;
use system_error::SystemError;
use super::virtual_terminal::virtual_console::{
CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity,
use super::virtual_terminal::{
virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity},
VirtConsole,
};
/// 终端切换相关的回调
pub trait ConsoleSwitch: Sync + Send {
/// 初始化会对vc_data进行一系列初始化操作
fn con_init(&self, vc_data: &mut VirtualConsoleData, init: bool) -> Result<(), SystemError>;
fn con_init(
&self,
vc: &Arc<VirtConsole>,
vc_data: &mut VirtualConsoleData,
init: bool,
) -> Result<(), SystemError>;
/// 进行释放等系列操作,目前未使用
#[allow(dead_code)]

View File

@ -5,7 +5,7 @@ use kdepends::thingbuf::StaticThingBuf;
use crate::{
arch::CurrentIrqArch,
driver::tty::virtual_terminal::virtual_console::CURRENT_VCNUM,
driver::tty::virtual_terminal::vc_manager,
exception::InterruptArch,
process::{
kthread::{KernelThreadClosure, KernelThreadMechanism},
@ -14,8 +14,6 @@ use crate::{
sched::{schedule, SchedMode},
};
use super::tty_port::current_tty_port;
/// 用于缓存键盘输入的缓冲区
static KEYBUF: StaticThingBuf<u8, 512> = StaticThingBuf::new();
@ -51,8 +49,10 @@ fn tty_refresh_thread() -> i32 {
*item = KEYBUF.pop().unwrap();
}
if CURRENT_VCNUM.load(core::sync::atomic::Ordering::SeqCst) != -1 {
let _ = current_tty_port().receive_buf(&data[0..to_dequeue], &[], to_dequeue);
if let Some(cur_vc) = vc_manager().current_vc() {
let _ = cur_vc
.port()
.receive_buf(&data[0..to_dequeue], &[], to_dequeue);
} else {
// 这里由于stdio未初始化所以无法找到port
// TODO: 考虑改用双端队列,能够将丢失的输入插回

View File

@ -253,6 +253,7 @@ pub fn pty_init() -> Result<(), SystemError> {
TtyDriverType::Pty,
*TTY_STD_TERMIOS,
Arc::new(Unix98PtyDriverInner::new()),
None,
);
ptm_driver.set_subtype(TtyDriverSubType::PtyMaster);
let term = ptm_driver.init_termios_mut();
@ -273,6 +274,7 @@ pub fn pty_init() -> Result<(), SystemError> {
TtyDriverType::Pty,
*TTY_STD_TERMIOS,
Arc::new(Unix98PtyDriverInner::new()),
None,
);
pts_driver.set_subtype(TtyDriverSubType::PtySlave);
let term = pts_driver.init_termios_mut();

View File

@ -263,7 +263,7 @@ pub fn ptmx_open(
let index = fsinfo.alloc_index()?;
let tty = TtyDriver::init_tty_device(ptm_driver(), index)?;
let tty = ptm_driver().init_tty_device(Some(index))?;
// 设置privdata
*data = FilePrivateData::Tty(TtyFilePrivateData {

View File

@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType;
/// ## 窗口大小
#[repr(C)]
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct WindowSize {
/// 行
pub row: u16,
@ -15,7 +15,8 @@ pub struct WindowSize {
}
impl WindowSize {
pub fn new(row: u16, col: u16, xpixel: u16, ypixel: u16) -> Self {
pub const DEFAULT: WindowSize = WindowSize::new(24, 80, 1, 1);
pub const fn new(row: u16, col: u16, xpixel: u16, ypixel: u16) -> Self {
Self {
row,
col,
@ -25,6 +26,12 @@ impl WindowSize {
}
}
impl Default for WindowSize {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Debug, Clone, Copy)]
pub struct Termios {
pub input_mode: InputMode,
@ -63,7 +70,6 @@ impl PosixTermios {
}
}
#[allow(dead_code)]
pub fn to_kernel_termios(self) -> Termios {
// TODO这里没有考虑非规范模式
Termios {

View File

@ -11,7 +11,7 @@ use alloc::{
use system_error::SystemError;
use crate::{
driver::{serial::serial8250::send_to_default_serial8250_port, tty::pty::ptm_driver},
driver::{base::device::device_number::DeviceNumber, tty::pty::ptm_driver},
libs::{
rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard},
spinlock::{SpinLock, SpinLockGuard},
@ -25,13 +25,13 @@ use crate::{
use super::{
termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize},
tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
tty_driver::{TtyCorePrivateField, TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
tty_ldisc::{
ntty::{NTtyData, NTtyLinediscipline},
TtyLineDiscipline,
},
tty_port::TtyPort,
virtual_terminal::{virtual_console::VirtualConsoleData, VIRT_CONSOLES},
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData},
};
#[derive(Debug)]
@ -52,6 +52,9 @@ impl Drop for TtyCore {
impl TtyCore {
pub fn new(driver: Arc<TtyDriver>, index: usize) -> Arc<Self> {
let name = driver.tty_line_name(index);
let device_number = driver
.device_number(index)
.expect("Get tty device number failed.");
let termios = driver.init_termios();
let core = TtyCoreData {
tty_driver: driver,
@ -64,11 +67,14 @@ impl TtyCore {
write_wq: EventWaitQueue::new(),
port: RwLock::new(None),
index,
vc_index: AtomicUsize::new(usize::MAX),
ctrl: SpinLock::new(TtyContorlInfo::default()),
closing: AtomicBool::new(false),
flow: SpinLock::new(TtyFlowState::default()),
link: RwLock::default(),
epitems: SpinLock::new(LinkedList::new()),
device_number,
privete_fields: SpinLock::new(None),
};
return Arc::new(Self {
@ -84,6 +90,14 @@ impl TtyCore {
return &self.core;
}
pub fn private_fields(&self) -> Option<Arc<dyn TtyCorePrivateField>> {
self.core.privete_fields.lock().clone()
}
pub fn set_private_fields(&self, fields: Arc<dyn TtyCorePrivateField>) {
*self.core.privete_fields.lock() = Some(fields);
}
#[inline]
pub fn ldisc(&self) -> Arc<dyn TtyLineDiscipline> {
self.line_discipline.clone()
@ -231,7 +245,7 @@ impl TtyCore {
Ok(0)
}
pub fn set_termios_next(tty: Arc<TtyCore>, new_termios: Termios) -> Result<(), SystemError> {
fn set_termios_next(tty: Arc<TtyCore>, new_termios: Termios) -> Result<(), SystemError> {
let mut termios = tty.core().termios_write();
let old_termios = *termios;
@ -252,7 +266,7 @@ impl TtyCore {
drop(termios);
let ld = tty.ldisc();
ld.set_termios(tty, Some(old_termios))?;
ld.set_termios(tty, Some(old_termios)).ok();
Ok(())
}
@ -292,6 +306,7 @@ pub struct TtyCoreData {
flags: RwLock<TtyFlag>,
/// 在初始化时即确定不会更改,所以这里不用加锁
index: usize,
vc_index: AtomicUsize,
count: AtomicUsize,
/// 窗口大小
window_size: RwLock<WindowSize>,
@ -311,12 +326,16 @@ pub struct TtyCoreData {
link: RwLock<Weak<TtyCore>>,
/// epitems
epitems: SpinLock<LinkedList<Arc<EPollItem>>>,
/// 设备号
device_number: DeviceNumber,
privete_fields: SpinLock<Option<Arc<dyn TtyCorePrivateField>>>,
}
impl TtyCoreData {
#[inline]
pub fn driver(&self) -> Arc<TtyDriver> {
self.tty_driver.clone()
pub fn driver(&self) -> &Arc<TtyDriver> {
&self.tty_driver
}
#[inline]
@ -335,8 +354,12 @@ impl TtyCoreData {
}
#[inline]
pub fn name(&self) -> String {
self.name.clone()
pub fn name(&self) -> &String {
&self.name
}
pub fn device_number(&self) -> &DeviceNumber {
&self.device_number
}
#[inline]
@ -412,8 +435,20 @@ impl TtyCoreData {
}
#[inline]
pub fn vc_data_irqsave(&self) -> SpinLockGuard<VirtualConsoleData> {
VIRT_CONSOLES[self.index].lock_irqsave()
pub fn vc_data(&self) -> Option<Arc<SpinLock<VirtualConsoleData>>> {
vc_manager().get(self.vc_index()?).unwrap().vc_data()
}
pub fn set_vc_index(&self, index: usize) {
self.vc_index.store(index, Ordering::SeqCst);
}
pub fn vc_index(&self) -> Option<usize> {
let x = self.vc_index.load(Ordering::SeqCst);
if x == usize::MAX {
return None;
}
return Some(x);
}
#[inline]
@ -469,7 +504,6 @@ impl TtyOperation for TtyCore {
#[inline]
fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
send_to_default_serial8250_port(buf);
return self.core().tty_driver.driver_funcs().write(tty, buf, nr);
}

View File

@ -45,7 +45,7 @@ use super::{
sysfs::sys_class_tty_instance,
termios::WindowSize,
tty_core::{TtyCore, TtyFlag, TtyIoctlCmd},
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverSubType, TtyDriverType, TtyOperation},
tty_driver::{TtyDriverManager, TtyDriverSubType, TtyDriverType, TtyOperation},
tty_job_control::TtyJobCtrlManager,
virtual_terminal::vty_init,
};
@ -126,6 +126,10 @@ impl TtyDevice {
pub fn inner_write(&self) -> RwLockWriteGuard<InnerTtyDevice> {
self.inner.write()
}
pub fn name_ref(&self) -> &str {
&self.name
}
}
impl IndexNode for TtyDevice {
@ -145,7 +149,7 @@ impl IndexNode for TtyDevice {
let (index, driver) =
TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?;
let tty = TtyDriver::open_tty(index, driver)?;
let tty = driver.open_tty(Some(index))?;
// 设置privdata
*data = FilePrivateData::Tty(TtyFilePrivateData {
@ -592,15 +596,6 @@ impl TtyFilePrivateData {
#[unified_init(INITCALL_DEVICE)]
#[inline(never)]
pub fn tty_init() -> Result<(), SystemError> {
let tty = TtyDevice::new(
"tty0".to_string(),
IdTable::new(
String::from("tty0"),
Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
),
TtyType::Tty,
);
let console = TtyDevice::new(
"console".to_string(),
IdTable::new(
@ -610,34 +605,8 @@ pub fn tty_init() -> Result<(), SystemError> {
TtyType::Tty,
);
// 注册tty设备
// CharDevOps::cdev_add(
// tty.clone() as Arc<dyn CharDevice>,
// IdTable::new(
// String::from("tty0"),
// Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 0)),
// ),
// 1,
// )?;
// CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTYAUX_MAJOR, 0), 1, "/dev/tty")?;
// 注册console设备
// CharDevOps::cdev_add(
// console.clone() as Arc<dyn CharDevice>,
// IdTable::new(
// String::from("console"),
// Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 1)),
// ),
// 1,
// )?;
// CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTYAUX_MAJOR, 1), 1, "/dev/tty")?;
// 将这两个设备注册到devfsTODO这里console设备应该与tty在一个设备group里面
device_register(tty.clone())?;
// 将设备注册到devfsTODO这里console设备应该与tty在一个设备group里面
device_register(console.clone())?;
devfs_register(&tty.name.clone(), tty)?;
devfs_register(&console.name.clone(), console)?;
serial_init()?;

View File

@ -6,6 +6,7 @@ use alloc::{
vec::Vec,
};
use hashbrown::HashMap;
use ida::IdAllocator;
use log::warn;
use system_error::SystemError;
@ -15,13 +16,17 @@ use crate::{
char::CharDevOps,
device::{
device_number::{DeviceNumber, Major},
device_register,
driver::Driver,
IdTable,
},
kobject::KObject,
},
tty::tty_port::TtyPortState,
},
filesystem::devfs::devfs_register,
libs::{
lazy_init::Lazy,
rwlock::RwLock,
spinlock::{SpinLock, SpinLockGuard},
},
@ -30,6 +35,7 @@ use crate::{
use super::{
termios::{Termios, WindowSize},
tty_core::{TtyCore, TtyCoreData},
tty_device::TtyDevice,
tty_ldisc::TtyLdiscManager,
tty_port::{DefaultTtyPort, TtyPort},
};
@ -79,6 +85,7 @@ impl TtyDriverManager {
// 加入全局TtyDriver表
let driver = Arc::new(driver);
driver.self_ref.init(Arc::downgrade(&driver));
TTY_DRIVERS.lock().push(driver.clone());
// TODO: 加入procfs?
@ -87,6 +94,10 @@ impl TtyDriverManager {
}
}
/// tty 驱动程序的与设备相关的数据
pub trait TtyDriverPrivateField: Debug + Send + Sync {}
pub trait TtyCorePrivateField: Debug + Send + Sync {}
#[allow(dead_code)]
#[derive(Debug)]
#[cast_to([sync] Driver)]
@ -121,7 +132,11 @@ pub struct TtyDriver {
ttys: SpinLock<HashMap<usize, Arc<TtyCore>>>,
/// 管理的端口列表
ports: RwLock<Vec<Arc<dyn TtyPort>>>,
// procfs入口?
/// 与设备相关的私有数据
private_field: Option<Arc<dyn TtyDriverPrivateField>>,
/// id分配器
ida: SpinLock<IdAllocator>,
self_ref: Lazy<Weak<Self>>,
}
impl TtyDriver {
@ -135,6 +150,7 @@ impl TtyDriver {
tty_driver_type: TtyDriverType,
default_termios: Termios,
driver_funcs: Arc<dyn TtyOperation>,
private_field: Option<Arc<dyn TtyDriverPrivateField>>,
) -> Self {
let mut ports: Vec<Arc<dyn TtyPort>> = Vec::with_capacity(count as usize);
for _ in 0..count {
@ -156,6 +172,9 @@ impl TtyDriver {
ttys: SpinLock::new(HashMap::new()),
saved_termios: Vec::with_capacity(count as usize),
ports: RwLock::new(ports),
private_field,
ida: SpinLock::new(IdAllocator::new(0, count as usize).unwrap()),
self_ref: Lazy::new(),
}
}
@ -179,6 +198,22 @@ impl TtyDriver {
self.driver_funcs.clone()
}
/// ## 获取该驱动对应的设备的设备号
#[inline]
pub fn device_number(&self, index: usize) -> Option<DeviceNumber> {
if index >= self.device_count as usize {
return None;
}
Some(DeviceNumber::new(
self.major,
self.minor_start + index as u32,
))
}
fn self_ref(&self) -> Arc<Self> {
self.self_ref.get().upgrade().unwrap()
}
#[inline]
pub fn init_termios(&self) -> Termios {
self.init_termios
@ -230,7 +265,7 @@ impl TtyDriver {
ret.ok()
}
fn standard_install(&self, tty_core: Arc<TtyCore>) -> Result<(), SystemError> {
pub fn standard_install(&self, tty_core: Arc<TtyCore>) -> Result<(), SystemError> {
let tty = tty_core.core();
tty.init_termios();
// TODO:设置termios波特率
@ -242,59 +277,81 @@ impl TtyDriver {
Ok(())
}
fn driver_install_tty(driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
let res = tty.install(driver.clone(), tty.clone());
fn driver_install_tty(&self, tty: Arc<TtyCore>) -> Result<(), SystemError> {
let res = tty.install(self.self_ref(), tty.clone());
if let Err(err) = res {
if err == SystemError::ENOSYS {
return driver.standard_install(tty);
return self.standard_install(tty);
} else {
return Err(err);
}
}
driver.add_tty(tty);
self.add_tty(tty);
Ok(())
}
pub fn init_tty_device(
driver: Arc<TtyDriver>,
index: usize,
) -> Result<Arc<TtyCore>, SystemError> {
let tty = TtyCore::new(driver.clone(), index);
pub fn init_tty_device(&self, index: Option<usize>) -> Result<Arc<TtyCore>, SystemError> {
// 如果传入的index为None那么就自动分配index
let idx: usize;
if let Some(i) = index {
if self.ida.lock().exists(i) {
return Err(SystemError::EINVAL);
}
idx = i;
} else {
idx = self.ida.lock().alloc().ok_or(SystemError::EBUSY)?;
}
Self::driver_install_tty(driver.clone(), tty.clone())?;
let tty = TtyCore::new(self.self_ref(), idx);
self.driver_install_tty(tty.clone())?;
let core = tty.core();
if core.port().is_none() {
let ports = driver.ports.read();
let ports = self.ports.read();
ports[core.index()].setup_internal_tty(Arc::downgrade(&tty));
tty.set_port(ports[core.index()].clone());
}
TtyLdiscManager::ldisc_setup(tty.clone(), tty.core().link())?;
// 在devfs创建对应的文件
let device = TtyDevice::new(
core.name().clone(),
IdTable::new(self.tty_line_name(idx), Some(*core.device_number())),
super::tty_device::TtyType::Tty,
);
devfs_register(device.name_ref(), device.clone())?;
device_register(device)?;
Ok(tty)
}
/// ## 通过设备号找到对应驱动并且初始化Tty
pub fn open_tty(index: usize, driver: Arc<TtyDriver>) -> Result<Arc<TtyCore>, SystemError> {
let tty = match driver.lookup_tty(index) {
Some(tty) => {
// TODO: 暂时这么写因为还没写TtyPort
if tty.core().port().is_none() {
warn!("{} port is None", tty.core().name());
} else if tty.core().port().unwrap().state() == TtyPortState::KOPENED {
pub fn open_tty(&self, index: Option<usize>) -> Result<Arc<TtyCore>, SystemError> {
let mut tty: Option<Arc<TtyCore>> = None;
if index.is_some() {
if let Some(t) = self.lookup_tty(index.unwrap()) {
if t.core().port().is_none() {
warn!("{} port is None", t.core().name());
} else if t.core().port().unwrap().state() == TtyPortState::KOPENED {
return Err(SystemError::EBUSY);
}
tty.reopen()?;
tty
t.reopen()?;
tty = Some(t);
}
None => Self::init_tty_device(driver, index)?,
};
}
if tty.is_none() {
tty = Some(self.init_tty_device(index)?);
}
let tty = tty.ok_or(SystemError::ENODEV)?;
return Ok(tty);
}
@ -447,7 +504,9 @@ pub trait TtyOperation: Sync + Send + Debug {
fn close(&self, tty: Arc<TtyCore>) -> Result<(), SystemError>;
fn resize(&self, _tty: Arc<TtyCore>, _winsize: WindowSize) -> Result<(), SystemError>;
fn resize(&self, _tty: Arc<TtyCore>, _winsize: WindowSize) -> Result<(), SystemError> {
Err(SystemError::ENOSYS)
}
}
#[allow(dead_code)]

View File

@ -1209,7 +1209,8 @@ impl NTtyData {
if termios.output_mode.contains(OutputMode::OCRNL) {
break;
}
self.canon_cursor_column = self.cursor_column;
self.cursor_column = 0;
self.canon_cursor_column = 0;
}
'\t' => {
break;

View File

@ -1,4 +1,4 @@
use core::{fmt::Debug, sync::atomic::Ordering};
use core::fmt::Debug;
use alloc::sync::{Arc, Weak};
use kdepends::thingbuf::mpsc;
@ -6,26 +6,10 @@ use system_error::SystemError;
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use super::{
tty_core::TtyCore,
virtual_terminal::{virtual_console::CURRENT_VCNUM, VIRT_CONSOLES},
};
use super::tty_core::TtyCore;
const TTY_PORT_BUFSIZE: usize = 4096;
/// 获取当前tty port
#[inline]
pub fn current_tty_port() -> Arc<dyn TtyPort> {
VIRT_CONSOLES[CURRENT_VCNUM.load(Ordering::SeqCst) as usize]
.lock_irqsave()
.port()
}
#[inline]
pub fn tty_port(index: usize) -> Arc<dyn TtyPort> {
VIRT_CONSOLES[index].lock_irqsave().port()
}
#[allow(dead_code)]
#[derive(Debug)]
pub struct TtyPortData {

View File

@ -1,22 +1,28 @@
use core::{fmt::Formatter, sync::atomic::Ordering};
use core::fmt::Formatter;
use alloc::{
string::{String, ToString},
sync::Arc,
vec::Vec,
};
use hashbrown::HashMap;
use ida::IdAllocator;
use system_error::SystemError;
use unified_init::macros::unified_init;
use crate::{
driver::base::device::{
device_number::{DeviceNumber, Major},
device_register, IdTable,
driver::{
base::device::{
device_number::{DeviceNumber, Major},
device_register, IdTable,
},
serial::serial8250::send_to_default_serial8250_port,
},
filesystem::devfs::devfs_register,
libs::spinlock::SpinLock,
filesystem::devfs::{devfs_register, devfs_unregister},
init::initcall::INITCALL_LATE,
libs::{lazy_init::Lazy, rwlock::RwLock, spinlock::SpinLock},
};
use self::virtual_console::{VirtualConsoleData, CURRENT_VCNUM};
use self::virtual_console::VirtualConsoleData;
use super::{
console::ConsoleSwitch,
@ -24,12 +30,13 @@ use super::{
tty_core::{TtyCore, TtyCoreData},
tty_device::{TtyDevice, TtyType},
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation},
tty_port::{DefaultTtyPort, TtyPort},
};
pub mod console_map;
pub mod virtual_console;
pub const MAX_NR_CONSOLES: u32 = 63;
pub const MAX_NR_CONSOLES: u32 = 64;
pub const VC_MAXCOL: usize = 32767;
pub const VC_MAXROW: usize = 32767;
@ -48,14 +55,190 @@ pub const DEFAULT_BLUE: [u16; 16] = [
pub const COLOR_TABLE: &[u8] = &[0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15];
lazy_static! {
pub static ref VIRT_CONSOLES: Vec<Arc<SpinLock<VirtualConsoleData>>> = {
let mut v = Vec::with_capacity(MAX_NR_CONSOLES as usize);
for i in 0..MAX_NR_CONSOLES as usize {
v.push(Arc::new(SpinLock::new(VirtualConsoleData::new(i))));
static ref VC_MANAGER: VirtConsoleManager = VirtConsoleManager::new();
}
/// 获取虚拟终端管理器
#[inline]
pub fn vc_manager() -> &'static VirtConsoleManager {
&VC_MANAGER
}
pub struct VirtConsole {
vc_data: Option<Arc<SpinLock<VirtualConsoleData>>>,
port: Arc<dyn TtyPort>,
index: Lazy<usize>,
inner: SpinLock<InnerVirtConsole>,
}
struct InnerVirtConsole {
vcdev: Option<Arc<TtyDevice>>,
}
impl VirtConsole {
pub fn new(vc_data: Option<Arc<SpinLock<VirtualConsoleData>>>) -> Arc<Self> {
Arc::new(Self {
vc_data,
port: Arc::new(DefaultTtyPort::new()),
index: Lazy::new(),
inner: SpinLock::new(InnerVirtConsole { vcdev: None }),
})
}
pub fn vc_data(&self) -> Option<Arc<SpinLock<VirtualConsoleData>>> {
self.vc_data.clone()
}
pub fn port(&self) -> Arc<dyn TtyPort> {
self.port.clone()
}
pub fn index(&self) -> Option<usize> {
self.index.try_get().cloned()
}
pub fn devfs_setup(&self) -> Result<(), SystemError> {
let tty_core = self
.port
.port_data()
.internal_tty()
.ok_or(SystemError::ENODEV)?;
let tty_core_data = tty_core.core();
let devnum = *tty_core_data.device_number();
let vcname = format!("vc{}", self.index.get());
// 注册虚拟终端设备并将虚拟终端设备加入到文件系统
let vcdev = TtyDevice::new(
vcname.clone(),
IdTable::new(vcname, Some(devnum)),
TtyType::Tty,
);
device_register(vcdev.clone())?;
devfs_register(vcdev.name_ref(), vcdev.clone())?;
tty_core_data.set_vc_index(*self.index.get());
self.inner.lock().vcdev = Some(vcdev);
Ok(())
}
fn devfs_remove(&self) {
let vcdev = self.inner.lock().vcdev.take();
if let Some(vcdev) = vcdev {
devfs_unregister(vcdev.name_ref(), vcdev.clone())
.inspect_err(|e| {
log::error!("virt console: devfs_unregister failed: {:?}", e);
})
.ok();
}
}
}
struct InnerVirtConsoleManager {
consoles: HashMap<usize, Arc<VirtConsole>>,
ida: IdAllocator,
}
pub struct VirtConsoleManager {
inner: SpinLock<InnerVirtConsoleManager>,
current_vc: RwLock<Option<(Arc<VirtConsole>, usize)>>,
}
impl VirtConsoleManager {
pub const DEFAULT_VC_NAMES: [&'static str; 4] = ["tty0", "ttyS0", "tty1", "ttyS1"];
pub fn new() -> Self {
let ida = IdAllocator::new(0, MAX_NR_CONSOLES as usize).unwrap();
let consoles = HashMap::new();
Self {
inner: SpinLock::new(InnerVirtConsoleManager { consoles, ida }),
current_vc: RwLock::new(None),
}
}
pub fn get(&self, index: usize) -> Option<Arc<VirtConsole>> {
let inner = self.inner.lock();
inner.consoles.get(&index).cloned()
}
pub fn alloc(&self, vc: Arc<VirtConsole>) -> Option<usize> {
let mut inner = self.inner.lock();
let index = inner.ida.alloc()?;
vc.index.init(index);
if let Some(vc_data) = vc.vc_data.as_ref() {
vc_data.lock().vc_index = index;
}
v
};
inner.consoles.insert(index, vc);
Some(index)
}
/// 释放虚拟终端
pub fn free(&self, index: usize) {
let mut inner = self.inner.lock();
if let Some(vc) = inner.consoles.remove(&index) {
vc.devfs_remove();
}
inner.ida.free(index);
}
/// 获取当前虚拟终端
pub fn current_vc(&self) -> Option<Arc<VirtConsole>> {
self.current_vc.read().as_ref().map(|(vc, _)| vc.clone())
}
pub fn current_vc_index(&self) -> Option<usize> {
self.current_vc.read().as_ref().map(|(_, index)| *index)
}
pub fn current_vc_tty_name(&self) -> Option<String> {
self.current_vc()
.and_then(|vc| vc.port().port_data().internal_tty())
.map(|tty| tty.core().name().to_string())
}
/// 设置当前虚拟终端
pub fn set_current_vc(&self, vc: Arc<VirtConsole>) {
let index = *vc.index.get();
*self.current_vc.write() = Some((vc, index));
}
/// 通过tty名称查找虚拟终端
///
/// # Arguments
///
/// * `name` - tty名称 (如ttyS0)
pub fn lookup_vc_by_tty_name(&self, name: &str) -> Option<Arc<VirtConsole>> {
let inner = self.inner.lock();
for (_index, vc) in inner.consoles.iter() {
let found = vc
.port
.port_data()
.internal_tty()
.map(|tty| tty.core().name().as_str() == name)
.unwrap_or(false);
if found {
return Some(vc.clone());
}
}
None
}
pub fn setup_default_vc(&self) {
// todo: 从内核启动参数中获取
for name in Self::DEFAULT_VC_NAMES.iter() {
if let Some(vc) = self.lookup_vc_by_tty_name(name) {
log::info!("Set default vc with tty device: {}", name);
self.set_current_vc(vc);
return;
}
}
panic!("virt console: setup default vc failed");
}
}
#[derive(Debug, Clone, Copy, Default)]
@ -119,7 +302,8 @@ impl TtyConsoleDriverInner {
fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
// 关闭中断
let mut vc_data = tty.vc_data_irqsave();
let vc_data = tty.vc_data().unwrap();
let mut vc_data_guard = vc_data.lock_irqsave();
let mut offset = 0;
@ -130,7 +314,7 @@ impl TtyConsoleDriverInner {
let mut draw = DrawRegion::default();
// 首先隐藏光标再写
vc_data.hide_cursor();
vc_data_guard.hide_cursor();
while nr != 0 {
if !rescan {
@ -139,7 +323,7 @@ impl TtyConsoleDriverInner {
nr -= 1;
}
let (tc, rescan_last) = vc_data.translate(&mut ch);
let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
if tc.is_none() {
// 表示未转换完成
continue;
@ -148,30 +332,30 @@ impl TtyConsoleDriverInner {
let tc = tc.unwrap();
rescan = rescan_last;
if vc_data.is_control(tc, ch) {
vc_data.flush(&mut draw);
vc_data.do_control(ch);
if vc_data_guard.is_control(tc, ch) {
vc_data_guard.flush(&mut draw);
vc_data_guard.do_control(ch);
continue;
}
if !vc_data.console_write_normal(tc, ch, &mut draw) {
if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
continue;
}
}
vc_data.flush(&mut draw);
vc_data_guard.flush(&mut draw);
// TODO: notify update
return Ok(offset);
}
}
impl TtyOperation for TtyConsoleDriverInner {
fn install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
let tty_core = tty.core();
let mut vc_data = VIRT_CONSOLES[tty_core.index()].lock();
self.console.con_init(&mut vc_data, true)?;
let binding = vc.vc_data().unwrap();
let mut vc_data = binding.lock();
self.console.con_init(vc, &mut vc_data, true)?;
if vc_data.complement_mask == 0 {
vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
}
@ -206,11 +390,24 @@ impl TtyOperation for TtyConsoleDriverInner {
}
// 设置tty的端口为vc端口
vc_data.port().setup_internal_tty(Arc::downgrade(&tty));
tty.set_port(vc_data.port());
vc.port().setup_internal_tty(Arc::downgrade(&tty));
tty.set_port(vc.port());
vc.devfs_setup()?;
// 加入sysfs
CURRENT_VCNUM.store(tty_core.index() as isize, Ordering::SeqCst);
Ok(())
}
}
impl TtyOperation for TtyConsoleDriverInner {
fn install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
let vc = VirtConsole::new(Some(Arc::new(SpinLock::new(VirtualConsoleData::new(
usize::MAX,
)))));
vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
self.do_install(tty, &vc)
.inspect_err(|_| vc_manager().free(vc.index().unwrap()))?;
Ok(())
}
@ -228,6 +425,7 @@ impl TtyOperation for TtyConsoleDriverInner {
// if String::from_utf8_lossy(buf) == "Hello world!\n" {
// loop {}
// }
send_to_default_serial8250_port(buf);
let ret = self.do_write(tty, buf, nr);
self.flush_chars(tty);
ret
@ -235,8 +433,9 @@ impl TtyOperation for TtyConsoleDriverInner {
#[inline(never)]
fn flush_chars(&self, tty: &TtyCoreData) {
let mut vc_data = tty.vc_data_irqsave();
vc_data.set_cursor();
let vc_data = tty.vc_data().unwrap();
let mut vc_data_guard = vc_data.lock_irqsave();
vc_data_guard.set_cursor();
}
fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
@ -295,49 +494,34 @@ pub struct DrawRegion {
// 初始化虚拟终端
#[inline(never)]
pub fn vty_init() -> Result<(), SystemError> {
// 注册虚拟终端设备并将虚拟终端设备加入到文件系统
let vc0 = TtyDevice::new(
"vc0".to_string(),
IdTable::new(
String::from("vc0"),
Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
),
TtyType::Tty,
);
// 注册tty设备
// CharDevOps::cdev_add(
// vc0.clone() as Arc<dyn CharDevice>,
// IdTable::new(
// String::from("vc0"),
// Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
// ),
// 1,
// )?;
if let Ok(tty_console_driver_inner) = TtyConsoleDriverInner::new() {
let console_driver = TtyDriver::new(
MAX_NR_CONSOLES,
"tty",
0,
Major::TTY_MAJOR,
0,
TtyDriverType::Console,
*TTY_STD_TERMIOS,
Arc::new(tty_console_driver_inner),
None,
);
// CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTY_MAJOR, 0), 1, "/dev/vc/0")?;
device_register(vc0.clone())?;
devfs_register("vc0", vc0)?;
// vcs_init?
let console_driver = TtyDriver::new(
MAX_NR_CONSOLES,
"tty",
1,
Major::TTY_MAJOR,
0,
TtyDriverType::Console,
*TTY_STD_TERMIOS,
Arc::new(TtyConsoleDriverInner::new()?),
);
TtyDriverManager::tty_register_driver(console_driver)?;
CURRENT_VCNUM.store(0, Ordering::SeqCst);
// 初始化键盘?
// TODO: 为vc
TtyDriverManager::tty_register_driver(console_driver).inspect(|_| {
log::error!("tty console: register driver failed");
})?;
}
Ok(())
}
#[unified_init(INITCALL_LATE)]
fn vty_late_init() -> Result<(), SystemError> {
let (_, console_driver) =
TtyDriverManager::lookup_tty_driver(DeviceNumber::new(Major::TTY_MAJOR, 0))
.ok_or(SystemError::ENODEV)?;
console_driver.init_tty_device(None)?;
vc_manager().setup_default_vc();
Ok(())
}

View File

@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
use core::sync::atomic::{AtomicBool, Ordering};
use alloc::{
sync::{Arc, Weak},
@ -10,11 +10,7 @@ use log::warn;
use crate::{
driver::{
serial::serial8250::send_to_default_serial8250_port,
tty::{
console::ConsoleSwitch,
tty_port::{DefaultTtyPort, TtyPort},
ConsoleFont, KDMode,
},
tty::{console::ConsoleSwitch, ConsoleFont, KDMode},
},
libs::{font::FontDesc, rwlock::RwLock},
process::Pid,
@ -22,7 +18,8 @@ use crate::{
use super::{
console_map::{TranslationMap, TranslationMapType},
Color, DrawRegion, VtMode, VtModeData, COLOR_TABLE, DEFAULT_BLUE, DEFAULT_GREEN, DEFAULT_RED,
vc_manager, Color, DrawRegion, VtMode, VtModeData, COLOR_TABLE, DEFAULT_BLUE, DEFAULT_GREEN,
DEFAULT_RED,
};
pub(super) const NPAR: usize = 16;
@ -34,14 +31,12 @@ lazy_static! {
}
pub static CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1);
pub static CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false);
/// ## 虚拟控制台的信息
#[derive(Debug, Clone)]
pub struct VirtualConsoleData {
pub num: usize,
pub vc_index: usize,
pub state: VirtualConsoleInfo,
pub saved_state: VirtualConsoleInfo,
/// 最大列数
@ -146,9 +141,6 @@ pub struct VirtualConsoleData {
/// 对应的Console Driver funcs
driver_funcs: Option<Weak<dyn ConsoleSwitch>>,
/// 对应端口
port: Arc<dyn TtyPort>,
}
impl VirtualConsoleData {
@ -210,16 +202,10 @@ impl VirtualConsoleData {
screen_buf: Default::default(),
driver_funcs: None,
cursor_type: VcCursor::empty(),
num,
port: Arc::new(DefaultTtyPort::new()),
vc_index: num,
}
}
#[inline]
pub fn port(&self) -> Arc<dyn TtyPort> {
self.port.clone()
}
pub(super) fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
if let Some(rows) = rows {
self.rows = rows;
@ -245,12 +231,11 @@ impl VirtualConsoleData {
}
pub fn is_visible(&self) -> bool {
let cur_vc = CURRENT_VCNUM.load(Ordering::SeqCst);
if cur_vc == -1 {
return false;
if let Some(cur_vc) = vc_manager().current_vc_index() {
cur_vc == self.vc_index
} else {
false
}
cur_vc as usize == self.num
}
fn driver_funcs(&self) -> Arc<dyn ConsoleSwitch> {

View File

@ -5,7 +5,10 @@ use crate::driver::tty::{
console::ConsoleSwitch,
termios::WindowSize,
tty_driver::TtyOperation,
virtual_terminal::virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData},
virtual_terminal::{
virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData},
VirtConsole,
},
};
lazy_static! {
@ -49,14 +52,19 @@ impl ConsoleSwitch for DummyConsole {
) -> Result<u8, SystemError> {
Ok(0)
}
fn con_init(&self, vc_data: &mut VirtualConsoleData, init: bool) -> Result<(), SystemError> {
fn con_init(
&self,
vc: &Arc<VirtConsole>,
vc_data: &mut VirtualConsoleData,
init: bool,
) -> Result<(), SystemError> {
vc_data.color_mode = true;
if init {
vc_data.cols = Self::COLUNMS;
vc_data.rows = Self::ROWS;
} else {
let tty = vc_data.port().port_data().tty().unwrap();
let tty = vc.port().port_data().tty().unwrap();
tty.resize(
tty.clone(),
WindowSize::new(Self::ROWS as u16, Self::COLUNMS as u16, 0, 0),

View File

@ -8,7 +8,7 @@ use crate::{
console::ConsoleSwitch,
virtual_terminal::{
virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
Color,
Color, VirtConsole,
},
},
video::fbdev::base::{
@ -174,6 +174,7 @@ impl BlittingFbConsole {
impl ConsoleSwitch for BlittingFbConsole {
fn con_init(
&self,
_vc: &Arc<VirtConsole>,
vc_data: &mut VirtualConsoleData,
init: bool,
) -> Result<(), system_error::SystemError> {

View File

@ -156,7 +156,7 @@ impl IrqManager {
*action_guard.flags_mut() = flags;
*action_guard.dev_id_mut() = dev_id;
drop(action_guard);
debug!("to inner_setup_irq");
debug!("to inner_setup_irq: {irq:?}");
return self.inner_setup_irq(irq, irqaction, desc);
}

View File

@ -50,7 +50,7 @@ impl DevPtsFs {
let root_inode = Arc::new(LockedDevPtsFSInode::new());
let ret = Arc::new(Self {
root_inode,
pts_ida: SpinLock::new(IdAllocator::new(1, NR_UNIX98_PTY_MAX as usize).unwrap()),
pts_ida: SpinLock::new(IdAllocator::new(0, NR_UNIX98_PTY_MAX as usize).unwrap()),
pts_count: AtomicU32::new(0),
});

View File

@ -1,7 +1,6 @@
use crate::{
driver::{
serial::serial8250::send_to_default_serial8250_port,
tty::{tty_port::tty_port, virtual_terminal::virtual_console::CURRENT_VCNUM},
serial::serial8250::send_to_default_serial8250_port, tty::virtual_terminal::vc_manager,
video::video_refresh_manager,
},
libs::{
@ -1031,8 +1030,7 @@ where
#[no_mangle]
pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst);
if current_vcnum != -1 {
if let Some(current_vc) = vc_manager().current_vc() {
// tty已经初始化了之后才输出到屏幕
let fr = (fr_color & 0x00ff0000) >> 16;
let fg = (fr_color & 0x0000ff00) >> 8;
@ -1044,7 +1042,7 @@ pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32)
"\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m",
character as char
);
let port = tty_port(current_vcnum as usize);
let port = current_vc.port();
let tty = port.port_data().internal_tty();
if let Some(tty) = tty {
send_to_default_serial8250_port(&[character]);

View File

@ -1,7 +1,4 @@
use core::{
fmt::{self, Write},
sync::atomic::Ordering,
};
use core::fmt::{self, Write};
use alloc::string::ToString;
use log::{info, Level, Log};
@ -9,10 +6,7 @@ use log::{info, Level, Log};
use super::lib_ui::textui::{textui_putstr, FontColor};
use crate::{
driver::tty::{
tty_driver::TtyOperation, tty_port::tty_port,
virtual_terminal::virtual_console::CURRENT_VCNUM,
},
driver::tty::{tty_driver::TtyOperation, virtual_terminal::vc_manager},
filesystem::procfs::{
kmsg::KMSG,
log::{LogLevel, LogMessage},
@ -44,10 +38,9 @@ impl PrintkWriter {
/// 并输出白底黑字
/// @param str: 要写入的字符
pub fn __write_string(&mut self, s: &str) {
let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst);
if current_vcnum != -1 {
if let Some(current_vc) = vc_manager().current_vc() {
// tty已经初始化了之后才输出到屏幕
let port = tty_port(current_vcnum as usize);
let port = current_vc.port();
let tty = port.port_data().internal_tty();
if let Some(tty) = tty {
let _ = tty.write(tty.core(), s.as_bytes(), s.len());

View File

@ -1,6 +1,7 @@
use system_error::SystemError;
use crate::{
driver::tty::virtual_terminal::vc_manager,
filesystem::vfs::{
file::{File, FileMode},
ROOT_INODE,
@ -13,9 +14,16 @@ pub fn stdio_init() -> Result<(), SystemError> {
if ProcessManager::current_pcb().pid() != Pid(1) {
return Err(SystemError::EPERM);
}
let tty_path = format!(
"/dev/{}",
vc_manager()
.current_vc_tty_name()
.expect("Init stdio: can't get tty name")
);
let tty_inode = ROOT_INODE()
.lookup("/dev/tty0")
.expect("Init stdio: can't find tty0");
.lookup(&tty_path)
.unwrap_or_else(|_| panic!("Init stdio: can't find {}", tty_path));
let stdin =
File::new(tty_inode.clone(), FileMode::O_RDONLY).expect("Init stdio: can't create stdin");
let stdout =

View File

@ -77,6 +77,7 @@ QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
QEMU_ACCELARATE=""
QEMU_ARGUMENT=""
QEMU_DEVICES=""
BIOS_TYPE=""
#这个变量为true则使用virtio磁盘
VIRTIO_BLK_DEVICE=false
# 如果qemu_accel不为空
@ -109,6 +110,35 @@ if [ ${ARCH} == "riscv64" ]; then
QEMU_SERIAL=""
fi
while true;do
case "$1" in
--bios)
case "$2" in
uefi) #uefi启动新增ovmf.fd固件
BIOS_TYPE=uefi
;;
legacy)
BIOS_TYPE=legacy
;;
esac;shift 2;;
--display)
case "$2" in
vnc)
QEMU_ARGUMENT+=" -display vnc=:00"
;;
window)
;;
nographic)
QEMU_SERIAL=" -serial mon:stdio "
QEMU_MONITOR=""
QEMU_ARGUMENT+=" --nographic "
;;
esac;shift 2;;
*) break
esac
done
# ps: 下面这条使用tap的方式无法dhcp获取到ip暂时不知道为什么
# QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 "
@ -149,28 +179,7 @@ install_riscv_uboot()
if [ $flag_can_run -eq 1 ]; then
while true;do
case "$1" in
--bios)
case "$2" in
uefi) #uefi启动新增ovmf.fd固件
BIOS_TYPE=uefi
;;
legacy)
BIOS_TYPE=legacy
;;
esac;shift 2;;
--display)
case "$2" in
vnc)
QEMU_ARGUMENT+=" -display vnc=:00"
;;
window)
;;
esac;shift 2;;
*) break
esac
done
# 删除共享内存
sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND}