mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat: 添加serial console,支持non-graphic启动 (#947)
Signed-off-by: longjin <longjin@dragonos.org>
This commit is contained in:
parent
103f13024b
commit
d031d46fd9
5
Makefile
5
Makefile
@ -91,6 +91,11 @@ write_diskimage-uefi:
|
|||||||
# 不编译,直接启动QEMU
|
# 不编译,直接启动QEMU
|
||||||
qemu:
|
qemu:
|
||||||
sh -c "cd tools && bash run-qemu.sh --bios=legacy --display=window && cd .."
|
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)
|
||||||
qemu-uefi:
|
qemu-uefi:
|
||||||
sh -c "cd tools && bash run-qemu.sh --bios=uefi --display=window && cd .."
|
sh -c "cd tools && bash run-qemu.sh --bios=uefi --display=window && cd .."
|
||||||
|
@ -242,6 +242,7 @@ make run-docker
|
|||||||
- Docker编译,并写入磁盘镜像,: `make docker`
|
- Docker编译,并写入磁盘镜像,: `make docker`
|
||||||
- Docker编译,写入磁盘镜像,并在QEMU中运行: `make run-docker`
|
- Docker编译,写入磁盘镜像,并在QEMU中运行: `make run-docker`
|
||||||
- 不编译,直接从已有的磁盘镜像启动: `make qemu`
|
- 不编译,直接从已有的磁盘镜像启动: `make qemu`
|
||||||
|
- 不编译,直接从已有的磁盘镜像启动(无图形模式): `make qemu-nographic`
|
||||||
- 清理编译产生的文件: `make clean`
|
- 清理编译产生的文件: `make clean`
|
||||||
- 编译文档: `make docs` (需要手动安装sphinx以及docs下的`requirements.txt`中的依赖)
|
- 编译文档: `make docs` (需要手动安装sphinx以及docs下的`requirements.txt`中的依赖)
|
||||||
- 清理文档: `make clean-docs`
|
- 清理文档: `make clean-docs`
|
||||||
|
@ -403,7 +403,7 @@ pub fn ioapic_init(ignore: &'static [IrqNumber]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 绑定irqchip
|
// 绑定irqchip
|
||||||
for i in 32..256 {
|
for i in IoApic::VECTOR_BASE as u32..256 {
|
||||||
let irq = IrqNumber::new(i);
|
let irq = IrqNumber::new(i);
|
||||||
|
|
||||||
if ignore.contains(&irq) {
|
if ignore.contains(&irq) {
|
||||||
|
@ -58,7 +58,6 @@ macro_rules! interrupt_handler {
|
|||||||
push rax
|
push rax
|
||||||
mov rsi, {irqnum}
|
mov rsi, {irqnum}
|
||||||
jmp x86_64_do_irq
|
jmp x86_64_do_irq
|
||||||
// jmp do_IRQ
|
|
||||||
"
|
"
|
||||||
),
|
),
|
||||||
irqnum = const($name),
|
irqnum = const($name),
|
||||||
|
@ -3,22 +3,27 @@ use core::{fmt::Debug, sync::atomic::AtomicU32};
|
|||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{driver::base::device::device_number::DeviceNumber, mm::VirtAddr};
|
use crate::mm::VirtAddr;
|
||||||
|
|
||||||
use self::serial8250::serial8250_manager;
|
use self::serial8250::serial8250_manager;
|
||||||
|
|
||||||
|
use super::tty::{
|
||||||
|
termios::{ControlMode, InputMode, LocalMode, OutputMode, Termios, INIT_CONTORL_CHARACTERS},
|
||||||
|
tty_ldisc::LineDisciplineType,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod serial8250;
|
pub mod serial8250;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub trait UartDriver: Debug + Send + Sync {
|
pub trait UartDriver: Debug + Send + Sync {
|
||||||
fn device_number(&self) -> DeviceNumber;
|
|
||||||
|
|
||||||
/// 获取最大的设备数量
|
/// 获取最大的设备数量
|
||||||
fn max_devs_num(&self) -> i32;
|
fn max_devs_num(&self) -> i32;
|
||||||
|
|
||||||
// todo: 获取指向console的指针(在我们系统里面,将来可能是改进后的Textui Window)
|
// todo: 获取指向console的指针(在我们系统里面,将来可能是改进后的Textui Window)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const SERIAL_BAUDRATE: BaudRate = BaudRate::new(115200);
|
||||||
|
|
||||||
/// 串口端口应当实现的trait
|
/// 串口端口应当实现的trait
|
||||||
///
|
///
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/serial_core.h#428
|
/// 参考 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!(BaudRate, AtomicBaudRate, u32, AtomicU32);
|
||||||
int_like!(DivisorFraction, u32);
|
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)]
|
#[inline(always)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(super) fn uart_manager() -> &'static UartManager {
|
pub(super) fn uart_manager() -> &'static UartManager {
|
||||||
&UartManager
|
&UartManager
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct UartManager;
|
pub(super) struct UartManager;
|
||||||
|
|
||||||
impl UartManager {
|
impl UartManager {
|
||||||
|
pub const NR_TTY_SERIAL_MAX: u32 = 128;
|
||||||
/// todo: 把uart设备注册到tty层
|
/// todo: 把uart设备注册到tty层
|
||||||
///
|
///
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/serial_core.c?fi=uart_register_driver#2720
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/serial/serial_core.c?fi=uart_register_driver#2720
|
||||||
|
@ -12,27 +12,35 @@ use log::error;
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::{
|
||||||
class::Class,
|
base::{
|
||||||
device::{
|
class::Class,
|
||||||
bus::Bus, device_manager, device_number::DeviceNumber, driver::Driver, Device,
|
device::{
|
||||||
DeviceCommonData, DeviceKObjType, DeviceState, DeviceType, IdTable,
|
bus::Bus, device_manager, device_number::Major, driver::Driver, Device,
|
||||||
},
|
DeviceCommonData, DeviceKObjType, DeviceState, DeviceType, IdTable,
|
||||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
},
|
||||||
kset::KSet,
|
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||||
platform::{
|
kset::KSet,
|
||||||
platform_device::{platform_device_manager, PlatformDevice},
|
platform::{
|
||||||
platform_driver::{platform_driver_manager, PlatformDriver},
|
platform_device::{platform_device_manager, PlatformDevice},
|
||||||
|
platform_driver::{platform_driver_manager, PlatformDriver},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
tty::tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType},
|
||||||
},
|
},
|
||||||
filesystem::kernfs::KernFSInode,
|
filesystem::kernfs::KernFSInode,
|
||||||
libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
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;
|
mod serial8250_pio;
|
||||||
|
|
||||||
static mut SERIAL8250_ISA_DEVICES: Option<Arc<Serial8250ISADevices>> = None;
|
static mut SERIAL8250_ISA_DEVICES: Option<Arc<Serial8250ISADevices>> = None;
|
||||||
@ -62,6 +70,8 @@ static mut INITIALIZED: bool = false;
|
|||||||
pub(super) struct Serial8250Manager;
|
pub(super) struct Serial8250Manager;
|
||||||
|
|
||||||
impl Serial8250Manager {
|
impl Serial8250Manager {
|
||||||
|
pub const TTY_SERIAL_MINOR_START: u32 = 64;
|
||||||
|
|
||||||
/// 初始化串口设备(在内存管理初始化之前)
|
/// 初始化串口设备(在内存管理初始化之前)
|
||||||
pub fn early_init(&self) -> Result<(), SystemError> {
|
pub fn early_init(&self) -> Result<(), SystemError> {
|
||||||
// todo: riscv64: 串口设备初始化
|
// todo: riscv64: 串口设备初始化
|
||||||
@ -109,6 +119,7 @@ impl Serial8250Manager {
|
|||||||
return e;
|
return e;
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
self.serial_tty_init()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
INITIALIZED = true;
|
INITIALIZED = true;
|
||||||
}
|
}
|
||||||
@ -116,6 +127,34 @@ impl Serial8250Manager {
|
|||||||
return Ok(());
|
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绑定
|
/// 把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
|
/// 参考 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>,
|
uart_driver: &Arc<Serial8250ISADriver>,
|
||||||
devs: &Arc<Serial8250ISADevices>,
|
devs: &Arc<Serial8250ISADevices>,
|
||||||
) {
|
) {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
self.bind_pio_ports(uart_driver, devs);
|
self.bind_pio_ports(uart_driver, devs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,10 +434,6 @@ impl Serial8250ISADriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UartDriver for Serial8250ISADriver {
|
impl UartDriver for Serial8250ISADriver {
|
||||||
fn device_number(&self) -> DeviceNumber {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_devs_num(&self) -> i32 {
|
fn max_devs_num(&self) -> i32 {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@ -522,7 +558,7 @@ impl KObject for Serial8250ISADriver {
|
|||||||
/// 临时函数,用于向默认的串口发送数据
|
/// 临时函数,用于向默认的串口发送数据
|
||||||
pub fn send_to_default_serial8250_port(s: &[u8]) {
|
pub fn send_to_default_serial8250_port(s: &[u8]) {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
send_to_serial8250_pio_com1(s);
|
send_to_default_serial8250_pio_port(s);
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
{
|
{
|
||||||
|
@ -5,11 +5,33 @@ use core::{
|
|||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloc::sync::{Arc, Weak};
|
use alloc::{
|
||||||
|
string::ToString,
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{io::PortIOArch, CurrentPortIOArch},
|
arch::{driver::apic::ioapic::IoApic, io::PortIOArch, CurrentPortIOArch},
|
||||||
driver::serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort},
|
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,
|
libs::rwlock::RwLock,
|
||||||
};
|
};
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
@ -19,6 +41,8 @@ use super::{Serial8250ISADevices, Serial8250ISADriver, Serial8250Manager, Serial
|
|||||||
static mut PIO_PORTS: [Option<Serial8250PIOPort>; 8] =
|
static mut PIO_PORTS: [Option<Serial8250PIOPort>; 8] =
|
||||||
[None, None, None, None, None, None, None, None];
|
[None, None, None, None, None, None, None, None];
|
||||||
|
|
||||||
|
const SERIAL_8250_PIO_IRQ: IrqNumber = IrqNumber::new(IoApic::VECTOR_BASE as u32 + 4);
|
||||||
|
|
||||||
impl Serial8250Manager {
|
impl Serial8250Manager {
|
||||||
#[allow(static_mut_refs)]
|
#[allow(static_mut_refs)]
|
||||||
pub(super) fn bind_pio_ports(
|
pub(super) fn bind_pio_ports(
|
||||||
@ -34,7 +58,7 @@ impl Serial8250Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! init_port {
|
macro_rules! init_port {
|
||||||
($port_num:expr, $baudrate:expr) => {
|
($port_num:expr) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
let port = Serial8250PIOPort::new(
|
let port = Serial8250PIOPort::new(
|
||||||
match $port_num {
|
match $port_num {
|
||||||
@ -48,12 +72,17 @@ macro_rules! init_port {
|
|||||||
8 => Serial8250PortBase::COM8,
|
8 => Serial8250PortBase::COM8,
|
||||||
_ => panic!("invalid port number"),
|
_ => panic!("invalid port number"),
|
||||||
},
|
},
|
||||||
BaudRate::new($baudrate),
|
crate::driver::serial::SERIAL_BAUDRATE,
|
||||||
);
|
);
|
||||||
if let Ok(port) = port {
|
if let Ok(port) = port {
|
||||||
if port.init().is_ok() {
|
if port.init().is_ok() {
|
||||||
PIO_PORTS[$port_num - 1] = Some(port);
|
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> {
|
pub(super) fn serial8250_pio_port_early_init() -> Result<(), SystemError> {
|
||||||
for i in 1..=8 {
|
for i in 1..=8 {
|
||||||
init_port!(i, 115200);
|
init_port!(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +130,6 @@ impl Serial8250PIOPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let port = self.iobase as u16;
|
let port = self.iobase as u16;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
CurrentPortIOArch::out8(port + 1, 0x00); // Disable all interrupts
|
CurrentPortIOArch::out8(port + 1, 0x00); // Disable all interrupts
|
||||||
self.set_divisor(self.baudrate.load(Ordering::SeqCst))
|
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
|
// If serial is not faulty set it in normal operation mode
|
||||||
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
|
// (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(());
|
return Ok(());
|
||||||
@ -168,13 +199,12 @@ impl Serial8250PIOPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 读取一个字节
|
/// 读取一个字节,如果没有数据则返回None
|
||||||
#[allow(dead_code)]
|
fn read_one_byte(&self) -> Option<u8> {
|
||||||
fn read_one_byte(&self) -> u8 {
|
if !self.serial_received() {
|
||||||
while !self.serial_received() {
|
return None;
|
||||||
spin_loop();
|
|
||||||
}
|
}
|
||||||
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> {
|
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发送数据
|
/// 临时函数,用于向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() } {
|
if let Some(port) = unsafe { PIO_PORTS[0].as_ref() } {
|
||||||
port.send_bytes(s);
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use super::virtual_terminal::virtual_console::{
|
use super::virtual_terminal::{
|
||||||
CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity,
|
virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData, VirtualConsoleIntensity},
|
||||||
|
VirtConsole,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 终端切换相关的回调
|
/// 终端切换相关的回调
|
||||||
pub trait ConsoleSwitch: Sync + Send {
|
pub trait ConsoleSwitch: Sync + Send {
|
||||||
/// 初始化,会对vc_data进行一系列初始化操作
|
/// 初始化,会对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)]
|
#[allow(dead_code)]
|
||||||
|
@ -5,7 +5,7 @@ use kdepends::thingbuf::StaticThingBuf;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::CurrentIrqArch,
|
arch::CurrentIrqArch,
|
||||||
driver::tty::virtual_terminal::virtual_console::CURRENT_VCNUM,
|
driver::tty::virtual_terminal::vc_manager,
|
||||||
exception::InterruptArch,
|
exception::InterruptArch,
|
||||||
process::{
|
process::{
|
||||||
kthread::{KernelThreadClosure, KernelThreadMechanism},
|
kthread::{KernelThreadClosure, KernelThreadMechanism},
|
||||||
@ -14,8 +14,6 @@ use crate::{
|
|||||||
sched::{schedule, SchedMode},
|
sched::{schedule, SchedMode},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::tty_port::current_tty_port;
|
|
||||||
|
|
||||||
/// 用于缓存键盘输入的缓冲区
|
/// 用于缓存键盘输入的缓冲区
|
||||||
static KEYBUF: StaticThingBuf<u8, 512> = StaticThingBuf::new();
|
static KEYBUF: StaticThingBuf<u8, 512> = StaticThingBuf::new();
|
||||||
|
|
||||||
@ -51,8 +49,10 @@ fn tty_refresh_thread() -> i32 {
|
|||||||
*item = KEYBUF.pop().unwrap();
|
*item = KEYBUF.pop().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if CURRENT_VCNUM.load(core::sync::atomic::Ordering::SeqCst) != -1 {
|
if let Some(cur_vc) = vc_manager().current_vc() {
|
||||||
let _ = current_tty_port().receive_buf(&data[0..to_dequeue], &[], to_dequeue);
|
let _ = cur_vc
|
||||||
|
.port()
|
||||||
|
.receive_buf(&data[0..to_dequeue], &[], to_dequeue);
|
||||||
} else {
|
} else {
|
||||||
// 这里由于stdio未初始化,所以无法找到port
|
// 这里由于stdio未初始化,所以无法找到port
|
||||||
// TODO: 考虑改用双端队列,能够将丢失的输入插回
|
// TODO: 考虑改用双端队列,能够将丢失的输入插回
|
||||||
|
@ -253,6 +253,7 @@ pub fn pty_init() -> Result<(), SystemError> {
|
|||||||
TtyDriverType::Pty,
|
TtyDriverType::Pty,
|
||||||
*TTY_STD_TERMIOS,
|
*TTY_STD_TERMIOS,
|
||||||
Arc::new(Unix98PtyDriverInner::new()),
|
Arc::new(Unix98PtyDriverInner::new()),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
ptm_driver.set_subtype(TtyDriverSubType::PtyMaster);
|
ptm_driver.set_subtype(TtyDriverSubType::PtyMaster);
|
||||||
let term = ptm_driver.init_termios_mut();
|
let term = ptm_driver.init_termios_mut();
|
||||||
@ -273,6 +274,7 @@ pub fn pty_init() -> Result<(), SystemError> {
|
|||||||
TtyDriverType::Pty,
|
TtyDriverType::Pty,
|
||||||
*TTY_STD_TERMIOS,
|
*TTY_STD_TERMIOS,
|
||||||
Arc::new(Unix98PtyDriverInner::new()),
|
Arc::new(Unix98PtyDriverInner::new()),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
pts_driver.set_subtype(TtyDriverSubType::PtySlave);
|
pts_driver.set_subtype(TtyDriverSubType::PtySlave);
|
||||||
let term = pts_driver.init_termios_mut();
|
let term = pts_driver.init_termios_mut();
|
||||||
|
@ -263,7 +263,7 @@ pub fn ptmx_open(
|
|||||||
|
|
||||||
let index = fsinfo.alloc_index()?;
|
let index = fsinfo.alloc_index()?;
|
||||||
|
|
||||||
let tty = TtyDriver::init_tty_device(ptm_driver(), index)?;
|
let tty = ptm_driver().init_tty_device(Some(index))?;
|
||||||
|
|
||||||
// 设置privdata
|
// 设置privdata
|
||||||
*data = FilePrivateData::Tty(TtyFilePrivateData {
|
*data = FilePrivateData::Tty(TtyFilePrivateData {
|
||||||
|
@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType;
|
|||||||
|
|
||||||
/// ## 窗口大小
|
/// ## 窗口大小
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct WindowSize {
|
pub struct WindowSize {
|
||||||
/// 行
|
/// 行
|
||||||
pub row: u16,
|
pub row: u16,
|
||||||
@ -15,7 +15,8 @@ pub struct WindowSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
Self {
|
||||||
row,
|
row,
|
||||||
col,
|
col,
|
||||||
@ -25,6 +26,12 @@ impl WindowSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for WindowSize {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Termios {
|
pub struct Termios {
|
||||||
pub input_mode: InputMode,
|
pub input_mode: InputMode,
|
||||||
@ -63,7 +70,6 @@ impl PosixTermios {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn to_kernel_termios(self) -> Termios {
|
pub fn to_kernel_termios(self) -> Termios {
|
||||||
// TODO:这里没有考虑非规范模式
|
// TODO:这里没有考虑非规范模式
|
||||||
Termios {
|
Termios {
|
||||||
|
@ -11,7 +11,7 @@ use alloc::{
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
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::{
|
libs::{
|
||||||
rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard},
|
rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard},
|
||||||
spinlock::{SpinLock, SpinLockGuard},
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
@ -25,13 +25,13 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize},
|
termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize},
|
||||||
tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
|
tty_driver::{TtyCorePrivateField, TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
|
||||||
tty_ldisc::{
|
tty_ldisc::{
|
||||||
ntty::{NTtyData, NTtyLinediscipline},
|
ntty::{NTtyData, NTtyLinediscipline},
|
||||||
TtyLineDiscipline,
|
TtyLineDiscipline,
|
||||||
},
|
},
|
||||||
tty_port::TtyPort,
|
tty_port::TtyPort,
|
||||||
virtual_terminal::{virtual_console::VirtualConsoleData, VIRT_CONSOLES},
|
virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -52,6 +52,9 @@ impl Drop for TtyCore {
|
|||||||
impl TtyCore {
|
impl TtyCore {
|
||||||
pub fn new(driver: Arc<TtyDriver>, index: usize) -> Arc<Self> {
|
pub fn new(driver: Arc<TtyDriver>, index: usize) -> Arc<Self> {
|
||||||
let name = driver.tty_line_name(index);
|
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 termios = driver.init_termios();
|
||||||
let core = TtyCoreData {
|
let core = TtyCoreData {
|
||||||
tty_driver: driver,
|
tty_driver: driver,
|
||||||
@ -64,11 +67,14 @@ impl TtyCore {
|
|||||||
write_wq: EventWaitQueue::new(),
|
write_wq: EventWaitQueue::new(),
|
||||||
port: RwLock::new(None),
|
port: RwLock::new(None),
|
||||||
index,
|
index,
|
||||||
|
vc_index: AtomicUsize::new(usize::MAX),
|
||||||
ctrl: SpinLock::new(TtyContorlInfo::default()),
|
ctrl: SpinLock::new(TtyContorlInfo::default()),
|
||||||
closing: AtomicBool::new(false),
|
closing: AtomicBool::new(false),
|
||||||
flow: SpinLock::new(TtyFlowState::default()),
|
flow: SpinLock::new(TtyFlowState::default()),
|
||||||
link: RwLock::default(),
|
link: RwLock::default(),
|
||||||
epitems: SpinLock::new(LinkedList::new()),
|
epitems: SpinLock::new(LinkedList::new()),
|
||||||
|
device_number,
|
||||||
|
privete_fields: SpinLock::new(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Arc::new(Self {
|
return Arc::new(Self {
|
||||||
@ -84,6 +90,14 @@ impl TtyCore {
|
|||||||
return &self.core;
|
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]
|
#[inline]
|
||||||
pub fn ldisc(&self) -> Arc<dyn TtyLineDiscipline> {
|
pub fn ldisc(&self) -> Arc<dyn TtyLineDiscipline> {
|
||||||
self.line_discipline.clone()
|
self.line_discipline.clone()
|
||||||
@ -231,7 +245,7 @@ impl TtyCore {
|
|||||||
Ok(0)
|
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 mut termios = tty.core().termios_write();
|
||||||
|
|
||||||
let old_termios = *termios;
|
let old_termios = *termios;
|
||||||
@ -252,7 +266,7 @@ impl TtyCore {
|
|||||||
|
|
||||||
drop(termios);
|
drop(termios);
|
||||||
let ld = tty.ldisc();
|
let ld = tty.ldisc();
|
||||||
ld.set_termios(tty, Some(old_termios))?;
|
ld.set_termios(tty, Some(old_termios)).ok();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -292,6 +306,7 @@ pub struct TtyCoreData {
|
|||||||
flags: RwLock<TtyFlag>,
|
flags: RwLock<TtyFlag>,
|
||||||
/// 在初始化时即确定不会更改,所以这里不用加锁
|
/// 在初始化时即确定不会更改,所以这里不用加锁
|
||||||
index: usize,
|
index: usize,
|
||||||
|
vc_index: AtomicUsize,
|
||||||
count: AtomicUsize,
|
count: AtomicUsize,
|
||||||
/// 窗口大小
|
/// 窗口大小
|
||||||
window_size: RwLock<WindowSize>,
|
window_size: RwLock<WindowSize>,
|
||||||
@ -311,12 +326,16 @@ pub struct TtyCoreData {
|
|||||||
link: RwLock<Weak<TtyCore>>,
|
link: RwLock<Weak<TtyCore>>,
|
||||||
/// epitems
|
/// epitems
|
||||||
epitems: SpinLock<LinkedList<Arc<EPollItem>>>,
|
epitems: SpinLock<LinkedList<Arc<EPollItem>>>,
|
||||||
|
/// 设备号
|
||||||
|
device_number: DeviceNumber,
|
||||||
|
|
||||||
|
privete_fields: SpinLock<Option<Arc<dyn TtyCorePrivateField>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TtyCoreData {
|
impl TtyCoreData {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn driver(&self) -> Arc<TtyDriver> {
|
pub fn driver(&self) -> &Arc<TtyDriver> {
|
||||||
self.tty_driver.clone()
|
&self.tty_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -335,8 +354,12 @@ impl TtyCoreData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn name(&self) -> String {
|
pub fn name(&self) -> &String {
|
||||||
self.name.clone()
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_number(&self) -> &DeviceNumber {
|
||||||
|
&self.device_number
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -412,8 +435,20 @@ impl TtyCoreData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn vc_data_irqsave(&self) -> SpinLockGuard<VirtualConsoleData> {
|
pub fn vc_data(&self) -> Option<Arc<SpinLock<VirtualConsoleData>>> {
|
||||||
VIRT_CONSOLES[self.index].lock_irqsave()
|
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]
|
#[inline]
|
||||||
@ -469,7 +504,6 @@ impl TtyOperation for TtyCore {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
|
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);
|
return self.core().tty_driver.driver_funcs().write(tty, buf, nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ use super::{
|
|||||||
sysfs::sys_class_tty_instance,
|
sysfs::sys_class_tty_instance,
|
||||||
termios::WindowSize,
|
termios::WindowSize,
|
||||||
tty_core::{TtyCore, TtyFlag, TtyIoctlCmd},
|
tty_core::{TtyCore, TtyFlag, TtyIoctlCmd},
|
||||||
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverSubType, TtyDriverType, TtyOperation},
|
tty_driver::{TtyDriverManager, TtyDriverSubType, TtyDriverType, TtyOperation},
|
||||||
tty_job_control::TtyJobCtrlManager,
|
tty_job_control::TtyJobCtrlManager,
|
||||||
virtual_terminal::vty_init,
|
virtual_terminal::vty_init,
|
||||||
};
|
};
|
||||||
@ -126,6 +126,10 @@ impl TtyDevice {
|
|||||||
pub fn inner_write(&self) -> RwLockWriteGuard<InnerTtyDevice> {
|
pub fn inner_write(&self) -> RwLockWriteGuard<InnerTtyDevice> {
|
||||||
self.inner.write()
|
self.inner.write()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name_ref(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexNode for TtyDevice {
|
impl IndexNode for TtyDevice {
|
||||||
@ -145,7 +149,7 @@ impl IndexNode for TtyDevice {
|
|||||||
let (index, driver) =
|
let (index, driver) =
|
||||||
TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?;
|
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
|
// 设置privdata
|
||||||
*data = FilePrivateData::Tty(TtyFilePrivateData {
|
*data = FilePrivateData::Tty(TtyFilePrivateData {
|
||||||
@ -592,15 +596,6 @@ impl TtyFilePrivateData {
|
|||||||
#[unified_init(INITCALL_DEVICE)]
|
#[unified_init(INITCALL_DEVICE)]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn tty_init() -> Result<(), SystemError> {
|
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(
|
let console = TtyDevice::new(
|
||||||
"console".to_string(),
|
"console".to_string(),
|
||||||
IdTable::new(
|
IdTable::new(
|
||||||
@ -610,34 +605,8 @@ pub fn tty_init() -> Result<(), SystemError> {
|
|||||||
TtyType::Tty,
|
TtyType::Tty,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 注册tty设备
|
// 将设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面
|
||||||
// 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")?;
|
|
||||||
|
|
||||||
// 将这两个设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面
|
|
||||||
device_register(tty.clone())?;
|
|
||||||
device_register(console.clone())?;
|
device_register(console.clone())?;
|
||||||
devfs_register(&tty.name.clone(), tty)?;
|
|
||||||
devfs_register(&console.name.clone(), console)?;
|
devfs_register(&console.name.clone(), console)?;
|
||||||
|
|
||||||
serial_init()?;
|
serial_init()?;
|
||||||
|
@ -6,6 +6,7 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
use ida::IdAllocator;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
@ -15,13 +16,17 @@ use crate::{
|
|||||||
char::CharDevOps,
|
char::CharDevOps,
|
||||||
device::{
|
device::{
|
||||||
device_number::{DeviceNumber, Major},
|
device_number::{DeviceNumber, Major},
|
||||||
|
device_register,
|
||||||
driver::Driver,
|
driver::Driver,
|
||||||
|
IdTable,
|
||||||
},
|
},
|
||||||
kobject::KObject,
|
kobject::KObject,
|
||||||
},
|
},
|
||||||
tty::tty_port::TtyPortState,
|
tty::tty_port::TtyPortState,
|
||||||
},
|
},
|
||||||
|
filesystem::devfs::devfs_register,
|
||||||
libs::{
|
libs::{
|
||||||
|
lazy_init::Lazy,
|
||||||
rwlock::RwLock,
|
rwlock::RwLock,
|
||||||
spinlock::{SpinLock, SpinLockGuard},
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
},
|
},
|
||||||
@ -30,6 +35,7 @@ use crate::{
|
|||||||
use super::{
|
use super::{
|
||||||
termios::{Termios, WindowSize},
|
termios::{Termios, WindowSize},
|
||||||
tty_core::{TtyCore, TtyCoreData},
|
tty_core::{TtyCore, TtyCoreData},
|
||||||
|
tty_device::TtyDevice,
|
||||||
tty_ldisc::TtyLdiscManager,
|
tty_ldisc::TtyLdiscManager,
|
||||||
tty_port::{DefaultTtyPort, TtyPort},
|
tty_port::{DefaultTtyPort, TtyPort},
|
||||||
};
|
};
|
||||||
@ -79,6 +85,7 @@ impl TtyDriverManager {
|
|||||||
|
|
||||||
// 加入全局TtyDriver表
|
// 加入全局TtyDriver表
|
||||||
let driver = Arc::new(driver);
|
let driver = Arc::new(driver);
|
||||||
|
driver.self_ref.init(Arc::downgrade(&driver));
|
||||||
TTY_DRIVERS.lock().push(driver.clone());
|
TTY_DRIVERS.lock().push(driver.clone());
|
||||||
|
|
||||||
// TODO: 加入procfs?
|
// TODO: 加入procfs?
|
||||||
@ -87,6 +94,10 @@ impl TtyDriverManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// tty 驱动程序的与设备相关的数据
|
||||||
|
pub trait TtyDriverPrivateField: Debug + Send + Sync {}
|
||||||
|
pub trait TtyCorePrivateField: Debug + Send + Sync {}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cast_to([sync] Driver)]
|
#[cast_to([sync] Driver)]
|
||||||
@ -121,7 +132,11 @@ pub struct TtyDriver {
|
|||||||
ttys: SpinLock<HashMap<usize, Arc<TtyCore>>>,
|
ttys: SpinLock<HashMap<usize, Arc<TtyCore>>>,
|
||||||
/// 管理的端口列表
|
/// 管理的端口列表
|
||||||
ports: RwLock<Vec<Arc<dyn TtyPort>>>,
|
ports: RwLock<Vec<Arc<dyn TtyPort>>>,
|
||||||
// procfs入口?
|
/// 与设备相关的私有数据
|
||||||
|
private_field: Option<Arc<dyn TtyDriverPrivateField>>,
|
||||||
|
/// id分配器
|
||||||
|
ida: SpinLock<IdAllocator>,
|
||||||
|
self_ref: Lazy<Weak<Self>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TtyDriver {
|
impl TtyDriver {
|
||||||
@ -135,6 +150,7 @@ impl TtyDriver {
|
|||||||
tty_driver_type: TtyDriverType,
|
tty_driver_type: TtyDriverType,
|
||||||
default_termios: Termios,
|
default_termios: Termios,
|
||||||
driver_funcs: Arc<dyn TtyOperation>,
|
driver_funcs: Arc<dyn TtyOperation>,
|
||||||
|
private_field: Option<Arc<dyn TtyDriverPrivateField>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut ports: Vec<Arc<dyn TtyPort>> = Vec::with_capacity(count as usize);
|
let mut ports: Vec<Arc<dyn TtyPort>> = Vec::with_capacity(count as usize);
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
@ -156,6 +172,9 @@ impl TtyDriver {
|
|||||||
ttys: SpinLock::new(HashMap::new()),
|
ttys: SpinLock::new(HashMap::new()),
|
||||||
saved_termios: Vec::with_capacity(count as usize),
|
saved_termios: Vec::with_capacity(count as usize),
|
||||||
ports: RwLock::new(ports),
|
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()
|
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]
|
#[inline]
|
||||||
pub fn init_termios(&self) -> Termios {
|
pub fn init_termios(&self) -> Termios {
|
||||||
self.init_termios
|
self.init_termios
|
||||||
@ -230,7 +265,7 @@ impl TtyDriver {
|
|||||||
ret.ok()
|
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();
|
let tty = tty_core.core();
|
||||||
tty.init_termios();
|
tty.init_termios();
|
||||||
// TODO:设置termios波特率?
|
// TODO:设置termios波特率?
|
||||||
@ -242,59 +277,81 @@ impl TtyDriver {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn driver_install_tty(driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
|
fn driver_install_tty(&self, tty: Arc<TtyCore>) -> Result<(), SystemError> {
|
||||||
let res = tty.install(driver.clone(), tty.clone());
|
let res = tty.install(self.self_ref(), tty.clone());
|
||||||
|
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
if err == SystemError::ENOSYS {
|
if err == SystemError::ENOSYS {
|
||||||
return driver.standard_install(tty);
|
return self.standard_install(tty);
|
||||||
} else {
|
} else {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
driver.add_tty(tty);
|
self.add_tty(tty);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_tty_device(
|
pub fn init_tty_device(&self, index: Option<usize>) -> Result<Arc<TtyCore>, SystemError> {
|
||||||
driver: Arc<TtyDriver>,
|
// 如果传入的index为None,那么就自动分配index
|
||||||
index: usize,
|
let idx: usize;
|
||||||
) -> Result<Arc<TtyCore>, SystemError> {
|
if let Some(i) = index {
|
||||||
let tty = TtyCore::new(driver.clone(), 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();
|
let core = tty.core();
|
||||||
|
|
||||||
if core.port().is_none() {
|
if core.port().is_none() {
|
||||||
let ports = driver.ports.read();
|
let ports = self.ports.read();
|
||||||
ports[core.index()].setup_internal_tty(Arc::downgrade(&tty));
|
ports[core.index()].setup_internal_tty(Arc::downgrade(&tty));
|
||||||
tty.set_port(ports[core.index()].clone());
|
tty.set_port(ports[core.index()].clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
TtyLdiscManager::ldisc_setup(tty.clone(), tty.core().link())?;
|
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)
|
Ok(tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## 通过设备号找到对应驱动并且初始化Tty
|
/// ## 通过设备号找到对应驱动并且初始化Tty
|
||||||
pub fn open_tty(index: usize, driver: Arc<TtyDriver>) -> Result<Arc<TtyCore>, SystemError> {
|
pub fn open_tty(&self, index: Option<usize>) -> Result<Arc<TtyCore>, SystemError> {
|
||||||
let tty = match driver.lookup_tty(index) {
|
let mut tty: Option<Arc<TtyCore>> = None;
|
||||||
Some(tty) => {
|
|
||||||
// TODO: 暂时这么写,因为还没写TtyPort
|
if index.is_some() {
|
||||||
if tty.core().port().is_none() {
|
if let Some(t) = self.lookup_tty(index.unwrap()) {
|
||||||
warn!("{} port is None", tty.core().name());
|
if t.core().port().is_none() {
|
||||||
} else if tty.core().port().unwrap().state() == TtyPortState::KOPENED {
|
warn!("{} port is None", t.core().name());
|
||||||
|
} else if t.core().port().unwrap().state() == TtyPortState::KOPENED {
|
||||||
return Err(SystemError::EBUSY);
|
return Err(SystemError::EBUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
tty.reopen()?;
|
t.reopen()?;
|
||||||
tty
|
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);
|
return Ok(tty);
|
||||||
}
|
}
|
||||||
@ -447,7 +504,9 @@ pub trait TtyOperation: Sync + Send + Debug {
|
|||||||
|
|
||||||
fn close(&self, tty: Arc<TtyCore>) -> Result<(), SystemError>;
|
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)]
|
#[allow(dead_code)]
|
||||||
|
@ -1209,7 +1209,8 @@ impl NTtyData {
|
|||||||
if termios.output_mode.contains(OutputMode::OCRNL) {
|
if termios.output_mode.contains(OutputMode::OCRNL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.canon_cursor_column = self.cursor_column;
|
self.cursor_column = 0;
|
||||||
|
self.canon_cursor_column = 0;
|
||||||
}
|
}
|
||||||
'\t' => {
|
'\t' => {
|
||||||
break;
|
break;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use core::{fmt::Debug, sync::atomic::Ordering};
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use alloc::sync::{Arc, Weak};
|
use alloc::sync::{Arc, Weak};
|
||||||
use kdepends::thingbuf::mpsc;
|
use kdepends::thingbuf::mpsc;
|
||||||
@ -6,26 +6,10 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||||
|
|
||||||
use super::{
|
use super::tty_core::TtyCore;
|
||||||
tty_core::TtyCore,
|
|
||||||
virtual_terminal::{virtual_console::CURRENT_VCNUM, VIRT_CONSOLES},
|
|
||||||
};
|
|
||||||
|
|
||||||
const TTY_PORT_BUFSIZE: usize = 4096;
|
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)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TtyPortData {
|
pub struct TtyPortData {
|
||||||
|
@ -1,22 +1,28 @@
|
|||||||
use core::{fmt::Formatter, sync::atomic::Ordering};
|
use core::fmt::Formatter;
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
vec::Vec,
|
|
||||||
};
|
};
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use ida::IdAllocator;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
use unified_init::macros::unified_init;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::device::{
|
driver::{
|
||||||
device_number::{DeviceNumber, Major},
|
base::device::{
|
||||||
device_register, IdTable,
|
device_number::{DeviceNumber, Major},
|
||||||
|
device_register, IdTable,
|
||||||
|
},
|
||||||
|
serial::serial8250::send_to_default_serial8250_port,
|
||||||
},
|
},
|
||||||
filesystem::devfs::devfs_register,
|
filesystem::devfs::{devfs_register, devfs_unregister},
|
||||||
libs::spinlock::SpinLock,
|
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::{
|
use super::{
|
||||||
console::ConsoleSwitch,
|
console::ConsoleSwitch,
|
||||||
@ -24,12 +30,13 @@ use super::{
|
|||||||
tty_core::{TtyCore, TtyCoreData},
|
tty_core::{TtyCore, TtyCoreData},
|
||||||
tty_device::{TtyDevice, TtyType},
|
tty_device::{TtyDevice, TtyType},
|
||||||
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation},
|
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation},
|
||||||
|
tty_port::{DefaultTtyPort, TtyPort},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod console_map;
|
pub mod console_map;
|
||||||
pub mod virtual_console;
|
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_MAXCOL: usize = 32767;
|
||||||
pub const VC_MAXROW: 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];
|
pub const COLOR_TABLE: &[u8] = &[0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15];
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref VIRT_CONSOLES: Vec<Arc<SpinLock<VirtualConsoleData>>> = {
|
static ref VC_MANAGER: VirtConsoleManager = VirtConsoleManager::new();
|
||||||
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))));
|
/// 获取虚拟终端管理器
|
||||||
|
#[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)]
|
#[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> {
|
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;
|
let mut offset = 0;
|
||||||
|
|
||||||
@ -130,7 +314,7 @@ impl TtyConsoleDriverInner {
|
|||||||
let mut draw = DrawRegion::default();
|
let mut draw = DrawRegion::default();
|
||||||
|
|
||||||
// 首先隐藏光标再写
|
// 首先隐藏光标再写
|
||||||
vc_data.hide_cursor();
|
vc_data_guard.hide_cursor();
|
||||||
|
|
||||||
while nr != 0 {
|
while nr != 0 {
|
||||||
if !rescan {
|
if !rescan {
|
||||||
@ -139,7 +323,7 @@ impl TtyConsoleDriverInner {
|
|||||||
nr -= 1;
|
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() {
|
if tc.is_none() {
|
||||||
// 表示未转换完成
|
// 表示未转换完成
|
||||||
continue;
|
continue;
|
||||||
@ -148,30 +332,30 @@ impl TtyConsoleDriverInner {
|
|||||||
let tc = tc.unwrap();
|
let tc = tc.unwrap();
|
||||||
rescan = rescan_last;
|
rescan = rescan_last;
|
||||||
|
|
||||||
if vc_data.is_control(tc, ch) {
|
if vc_data_guard.is_control(tc, ch) {
|
||||||
vc_data.flush(&mut draw);
|
vc_data_guard.flush(&mut draw);
|
||||||
vc_data.do_control(ch);
|
vc_data_guard.do_control(ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !vc_data.console_write_normal(tc, ch, &mut draw) {
|
if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vc_data.flush(&mut draw);
|
vc_data_guard.flush(&mut draw);
|
||||||
|
|
||||||
// TODO: notify update
|
// TODO: notify update
|
||||||
return Ok(offset);
|
return Ok(offset);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TtyOperation for TtyConsoleDriverInner {
|
fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
|
||||||
fn install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> {
|
|
||||||
let tty_core = tty.core();
|
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 {
|
if vc_data.complement_mask == 0 {
|
||||||
vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
|
vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
|
||||||
}
|
}
|
||||||
@ -206,11 +390,24 @@ impl TtyOperation for TtyConsoleDriverInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置tty的端口为vc端口
|
// 设置tty的端口为vc端口
|
||||||
vc_data.port().setup_internal_tty(Arc::downgrade(&tty));
|
vc.port().setup_internal_tty(Arc::downgrade(&tty));
|
||||||
tty.set_port(vc_data.port());
|
tty.set_port(vc.port());
|
||||||
|
vc.devfs_setup()?;
|
||||||
// 加入sysfs?
|
// 加入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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +425,7 @@ impl TtyOperation for TtyConsoleDriverInner {
|
|||||||
// if String::from_utf8_lossy(buf) == "Hello world!\n" {
|
// if String::from_utf8_lossy(buf) == "Hello world!\n" {
|
||||||
// loop {}
|
// loop {}
|
||||||
// }
|
// }
|
||||||
|
send_to_default_serial8250_port(buf);
|
||||||
let ret = self.do_write(tty, buf, nr);
|
let ret = self.do_write(tty, buf, nr);
|
||||||
self.flush_chars(tty);
|
self.flush_chars(tty);
|
||||||
ret
|
ret
|
||||||
@ -235,8 +433,9 @@ impl TtyOperation for TtyConsoleDriverInner {
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn flush_chars(&self, tty: &TtyCoreData) {
|
fn flush_chars(&self, tty: &TtyCoreData) {
|
||||||
let mut vc_data = tty.vc_data_irqsave();
|
let vc_data = tty.vc_data().unwrap();
|
||||||
vc_data.set_cursor();
|
let mut vc_data_guard = vc_data.lock_irqsave();
|
||||||
|
vc_data_guard.set_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
|
fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
|
||||||
@ -295,49 +494,34 @@ pub struct DrawRegion {
|
|||||||
// 初始化虚拟终端
|
// 初始化虚拟终端
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn vty_init() -> Result<(), SystemError> {
|
pub fn vty_init() -> Result<(), SystemError> {
|
||||||
// 注册虚拟终端设备并将虚拟终端设备加入到文件系统
|
if let Ok(tty_console_driver_inner) = TtyConsoleDriverInner::new() {
|
||||||
let vc0 = TtyDevice::new(
|
let console_driver = TtyDriver::new(
|
||||||
"vc0".to_string(),
|
MAX_NR_CONSOLES,
|
||||||
IdTable::new(
|
"tty",
|
||||||
String::from("vc0"),
|
0,
|
||||||
Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
|
Major::TTY_MAJOR,
|
||||||
),
|
0,
|
||||||
TtyType::Tty,
|
TtyDriverType::Console,
|
||||||
);
|
*TTY_STD_TERMIOS,
|
||||||
// 注册tty设备
|
Arc::new(tty_console_driver_inner),
|
||||||
// CharDevOps::cdev_add(
|
None,
|
||||||
// vc0.clone() as Arc<dyn CharDevice>,
|
);
|
||||||
// IdTable::new(
|
|
||||||
// String::from("vc0"),
|
|
||||||
// Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
|
|
||||||
// ),
|
|
||||||
// 1,
|
|
||||||
// )?;
|
|
||||||
|
|
||||||
// CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTY_MAJOR, 0), 1, "/dev/vc/0")?;
|
TtyDriverManager::tty_register_driver(console_driver).inspect(|_| {
|
||||||
device_register(vc0.clone())?;
|
log::error!("tty console: register driver failed");
|
||||||
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
|
|
||||||
|
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use core::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
@ -10,11 +10,7 @@ use log::warn;
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::{
|
driver::{
|
||||||
serial::serial8250::send_to_default_serial8250_port,
|
serial::serial8250::send_to_default_serial8250_port,
|
||||||
tty::{
|
tty::{console::ConsoleSwitch, ConsoleFont, KDMode},
|
||||||
console::ConsoleSwitch,
|
|
||||||
tty_port::{DefaultTtyPort, TtyPort},
|
|
||||||
ConsoleFont, KDMode,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
libs::{font::FontDesc, rwlock::RwLock},
|
libs::{font::FontDesc, rwlock::RwLock},
|
||||||
process::Pid,
|
process::Pid,
|
||||||
@ -22,7 +18,8 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
console_map::{TranslationMap, TranslationMapType},
|
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;
|
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);
|
pub static CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
/// ## 虚拟控制台的信息
|
/// ## 虚拟控制台的信息
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct VirtualConsoleData {
|
pub struct VirtualConsoleData {
|
||||||
pub num: usize,
|
pub vc_index: usize,
|
||||||
pub state: VirtualConsoleInfo,
|
pub state: VirtualConsoleInfo,
|
||||||
pub saved_state: VirtualConsoleInfo,
|
pub saved_state: VirtualConsoleInfo,
|
||||||
/// 最大列数
|
/// 最大列数
|
||||||
@ -146,9 +141,6 @@ pub struct VirtualConsoleData {
|
|||||||
|
|
||||||
/// 对应的Console Driver funcs
|
/// 对应的Console Driver funcs
|
||||||
driver_funcs: Option<Weak<dyn ConsoleSwitch>>,
|
driver_funcs: Option<Weak<dyn ConsoleSwitch>>,
|
||||||
|
|
||||||
/// 对应端口
|
|
||||||
port: Arc<dyn TtyPort>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualConsoleData {
|
impl VirtualConsoleData {
|
||||||
@ -210,16 +202,10 @@ impl VirtualConsoleData {
|
|||||||
screen_buf: Default::default(),
|
screen_buf: Default::default(),
|
||||||
driver_funcs: None,
|
driver_funcs: None,
|
||||||
cursor_type: VcCursor::empty(),
|
cursor_type: VcCursor::empty(),
|
||||||
num,
|
vc_index: num,
|
||||||
port: Arc::new(DefaultTtyPort::new()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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) {
|
pub(super) fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
|
||||||
if let Some(rows) = rows {
|
if let Some(rows) = rows {
|
||||||
self.rows = rows;
|
self.rows = rows;
|
||||||
@ -245,12 +231,11 @@ impl VirtualConsoleData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_visible(&self) -> bool {
|
pub fn is_visible(&self) -> bool {
|
||||||
let cur_vc = CURRENT_VCNUM.load(Ordering::SeqCst);
|
if let Some(cur_vc) = vc_manager().current_vc_index() {
|
||||||
if cur_vc == -1 {
|
cur_vc == self.vc_index
|
||||||
return false;
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_vc as usize == self.num
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn driver_funcs(&self) -> Arc<dyn ConsoleSwitch> {
|
fn driver_funcs(&self) -> Arc<dyn ConsoleSwitch> {
|
||||||
|
@ -5,7 +5,10 @@ use crate::driver::tty::{
|
|||||||
console::ConsoleSwitch,
|
console::ConsoleSwitch,
|
||||||
termios::WindowSize,
|
termios::WindowSize,
|
||||||
tty_driver::TtyOperation,
|
tty_driver::TtyOperation,
|
||||||
virtual_terminal::virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData},
|
virtual_terminal::{
|
||||||
|
virtual_console::{CursorOperation, ScrollDir, VirtualConsoleData},
|
||||||
|
VirtConsole,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -49,14 +52,19 @@ impl ConsoleSwitch for DummyConsole {
|
|||||||
) -> Result<u8, SystemError> {
|
) -> Result<u8, SystemError> {
|
||||||
Ok(0)
|
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;
|
vc_data.color_mode = true;
|
||||||
|
|
||||||
if init {
|
if init {
|
||||||
vc_data.cols = Self::COLUNMS;
|
vc_data.cols = Self::COLUNMS;
|
||||||
vc_data.rows = Self::ROWS;
|
vc_data.rows = Self::ROWS;
|
||||||
} else {
|
} else {
|
||||||
let tty = vc_data.port().port_data().tty().unwrap();
|
let tty = vc.port().port_data().tty().unwrap();
|
||||||
tty.resize(
|
tty.resize(
|
||||||
tty.clone(),
|
tty.clone(),
|
||||||
WindowSize::new(Self::ROWS as u16, Self::COLUNMS as u16, 0, 0),
|
WindowSize::new(Self::ROWS as u16, Self::COLUNMS as u16, 0, 0),
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
console::ConsoleSwitch,
|
console::ConsoleSwitch,
|
||||||
virtual_terminal::{
|
virtual_terminal::{
|
||||||
virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
|
virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
|
||||||
Color,
|
Color, VirtConsole,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
video::fbdev::base::{
|
video::fbdev::base::{
|
||||||
@ -174,6 +174,7 @@ impl BlittingFbConsole {
|
|||||||
impl ConsoleSwitch for BlittingFbConsole {
|
impl ConsoleSwitch for BlittingFbConsole {
|
||||||
fn con_init(
|
fn con_init(
|
||||||
&self,
|
&self,
|
||||||
|
_vc: &Arc<VirtConsole>,
|
||||||
vc_data: &mut VirtualConsoleData,
|
vc_data: &mut VirtualConsoleData,
|
||||||
init: bool,
|
init: bool,
|
||||||
) -> Result<(), system_error::SystemError> {
|
) -> Result<(), system_error::SystemError> {
|
||||||
|
@ -156,7 +156,7 @@ impl IrqManager {
|
|||||||
*action_guard.flags_mut() = flags;
|
*action_guard.flags_mut() = flags;
|
||||||
*action_guard.dev_id_mut() = dev_id;
|
*action_guard.dev_id_mut() = dev_id;
|
||||||
drop(action_guard);
|
drop(action_guard);
|
||||||
debug!("to inner_setup_irq");
|
debug!("to inner_setup_irq: {irq:?}");
|
||||||
return self.inner_setup_irq(irq, irqaction, desc);
|
return self.inner_setup_irq(irq, irqaction, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ impl DevPtsFs {
|
|||||||
let root_inode = Arc::new(LockedDevPtsFSInode::new());
|
let root_inode = Arc::new(LockedDevPtsFSInode::new());
|
||||||
let ret = Arc::new(Self {
|
let ret = Arc::new(Self {
|
||||||
root_inode,
|
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),
|
pts_count: AtomicU32::new(0),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::{
|
driver::{
|
||||||
serial::serial8250::send_to_default_serial8250_port,
|
serial::serial8250::send_to_default_serial8250_port, tty::virtual_terminal::vc_manager,
|
||||||
tty::{tty_port::tty_port, virtual_terminal::virtual_console::CURRENT_VCNUM},
|
|
||||||
video::video_refresh_manager,
|
video::video_refresh_manager,
|
||||||
},
|
},
|
||||||
libs::{
|
libs::{
|
||||||
@ -1031,8 +1030,7 @@ where
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
|
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 let Some(current_vc) = vc_manager().current_vc() {
|
||||||
if current_vcnum != -1 {
|
|
||||||
// tty已经初始化了之后才输出到屏幕
|
// tty已经初始化了之后才输出到屏幕
|
||||||
let fr = (fr_color & 0x00ff0000) >> 16;
|
let fr = (fr_color & 0x00ff0000) >> 16;
|
||||||
let fg = (fr_color & 0x0000ff00) >> 8;
|
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",
|
"\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m",
|
||||||
character as char
|
character as char
|
||||||
);
|
);
|
||||||
let port = tty_port(current_vcnum as usize);
|
let port = current_vc.port();
|
||||||
let tty = port.port_data().internal_tty();
|
let tty = port.port_data().internal_tty();
|
||||||
if let Some(tty) = tty {
|
if let Some(tty) = tty {
|
||||||
send_to_default_serial8250_port(&[character]);
|
send_to_default_serial8250_port(&[character]);
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
use core::{
|
use core::fmt::{self, Write};
|
||||||
fmt::{self, Write},
|
|
||||||
sync::atomic::Ordering,
|
|
||||||
};
|
|
||||||
|
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
use log::{info, Level, Log};
|
use log::{info, Level, Log};
|
||||||
@ -9,10 +6,7 @@ use log::{info, Level, Log};
|
|||||||
use super::lib_ui::textui::{textui_putstr, FontColor};
|
use super::lib_ui::textui::{textui_putstr, FontColor};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::tty::{
|
driver::tty::{tty_driver::TtyOperation, virtual_terminal::vc_manager},
|
||||||
tty_driver::TtyOperation, tty_port::tty_port,
|
|
||||||
virtual_terminal::virtual_console::CURRENT_VCNUM,
|
|
||||||
},
|
|
||||||
filesystem::procfs::{
|
filesystem::procfs::{
|
||||||
kmsg::KMSG,
|
kmsg::KMSG,
|
||||||
log::{LogLevel, LogMessage},
|
log::{LogLevel, LogMessage},
|
||||||
@ -44,10 +38,9 @@ impl PrintkWriter {
|
|||||||
/// 并输出白底黑字
|
/// 并输出白底黑字
|
||||||
/// @param str: 要写入的字符
|
/// @param str: 要写入的字符
|
||||||
pub fn __write_string(&mut self, s: &str) {
|
pub fn __write_string(&mut self, s: &str) {
|
||||||
let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst);
|
if let Some(current_vc) = vc_manager().current_vc() {
|
||||||
if current_vcnum != -1 {
|
|
||||||
// tty已经初始化了之后才输出到屏幕
|
// tty已经初始化了之后才输出到屏幕
|
||||||
let port = tty_port(current_vcnum as usize);
|
let port = current_vc.port();
|
||||||
let tty = port.port_data().internal_tty();
|
let tty = port.port_data().internal_tty();
|
||||||
if let Some(tty) = tty {
|
if let Some(tty) = tty {
|
||||||
let _ = tty.write(tty.core(), s.as_bytes(), s.len());
|
let _ = tty.write(tty.core(), s.as_bytes(), s.len());
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
driver::tty::virtual_terminal::vc_manager,
|
||||||
filesystem::vfs::{
|
filesystem::vfs::{
|
||||||
file::{File, FileMode},
|
file::{File, FileMode},
|
||||||
ROOT_INODE,
|
ROOT_INODE,
|
||||||
@ -13,9 +14,16 @@ pub fn stdio_init() -> Result<(), SystemError> {
|
|||||||
if ProcessManager::current_pcb().pid() != Pid(1) {
|
if ProcessManager::current_pcb().pid() != Pid(1) {
|
||||||
return Err(SystemError::EPERM);
|
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()
|
let tty_inode = ROOT_INODE()
|
||||||
.lookup("/dev/tty0")
|
.lookup(&tty_path)
|
||||||
.expect("Init stdio: can't find tty0");
|
.unwrap_or_else(|_| panic!("Init stdio: can't find {}", tty_path));
|
||||||
|
|
||||||
let stdin =
|
let stdin =
|
||||||
File::new(tty_inode.clone(), FileMode::O_RDONLY).expect("Init stdio: can't create stdin");
|
File::new(tty_inode.clone(), FileMode::O_RDONLY).expect("Init stdio: can't create stdin");
|
||||||
let stdout =
|
let stdout =
|
||||||
|
@ -77,6 +77,7 @@ QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
|
|||||||
QEMU_ACCELARATE=""
|
QEMU_ACCELARATE=""
|
||||||
QEMU_ARGUMENT=""
|
QEMU_ARGUMENT=""
|
||||||
QEMU_DEVICES=""
|
QEMU_DEVICES=""
|
||||||
|
BIOS_TYPE=""
|
||||||
#这个变量为true则使用virtio磁盘
|
#这个变量为true则使用virtio磁盘
|
||||||
VIRTIO_BLK_DEVICE=false
|
VIRTIO_BLK_DEVICE=false
|
||||||
# 如果qemu_accel不为空
|
# 如果qemu_accel不为空
|
||||||
@ -109,6 +110,35 @@ if [ ${ARCH} == "riscv64" ]; then
|
|||||||
QEMU_SERIAL=""
|
QEMU_SERIAL=""
|
||||||
fi
|
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,暂时不知道为什么
|
# 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 "
|
# 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
|
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}
|
sudo rm -rf ${QEMU_MEMORY_BACKEND_PATH_PREFIX}/${QEMU_MEMORY_BACKEND}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user