mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 12:16:31 +00:00
@ -146,11 +146,11 @@ void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs)
|
||||
unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
|
||||
ps2_keyboard_parse_keycode((uint8_t)x);
|
||||
uint8_t count = kfifo_in((struct kfifo_t *)buf_vaddr, &x, sizeof(unsigned char));
|
||||
if (count == 0)
|
||||
{
|
||||
kwarn("ps2 keyboard buffer full.");
|
||||
return;
|
||||
}
|
||||
// if (count == 0)
|
||||
// {
|
||||
// kwarn("ps2 keyboard buffer full.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
wait_queue_wakeup(&ps2_keyboard_wait_queue, PROC_UNINTERRUPTIBLE);
|
||||
|
||||
|
@ -3,6 +3,7 @@ use core::sync::atomic::AtomicI32;
|
||||
use alloc::sync::{Arc, Weak};
|
||||
|
||||
use crate::{
|
||||
driver::tty::tty_device::TTY_DEVICES,
|
||||
filesystem::{
|
||||
devfs::{devfs_register, DevFS, DeviceINode},
|
||||
vfs::{core::generate_inode_id, file::FileMode, FileType, IndexNode, Metadata, PollStatus},
|
||||
@ -17,7 +18,14 @@ use crate::{
|
||||
pub struct LockedPS2KeyBoardInode(RwLock<PS2KeyBoardInode>, AtomicI32); // self.1 用来记录有多少个文件打开了这个inode
|
||||
|
||||
lazy_static! {
|
||||
static ref PS2_KEYBOARD_FSM: SpinLock<TypeOneFSM> = SpinLock::new(TypeOneFSM::new());
|
||||
static ref PS2_KEYBOARD_FSM: SpinLock<TypeOneFSM> = {
|
||||
let tty0 = TTY_DEVICES
|
||||
.read()
|
||||
.get("tty0")
|
||||
.expect("Initializing PS2_KEYBOARD_FSM: Cannot found TTY0!")
|
||||
.clone();
|
||||
SpinLock::new(TypeOneFSM::new(tty0))
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -5,7 +5,7 @@ use thingbuf::mpsc::{
|
||||
errors::{TryRecvError, TrySendError},
|
||||
};
|
||||
|
||||
use crate::libs::rwlock::RwLock;
|
||||
use crate::{libs::rwlock::RwLock, kdebug};
|
||||
|
||||
pub mod tty_device;
|
||||
|
||||
@ -59,6 +59,7 @@ struct TtyCore {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum TtyError {
|
||||
/// 缓冲区满,返回成功传送的字节数
|
||||
BufferFull(usize),
|
||||
@ -281,6 +282,7 @@ impl TtyCore {
|
||||
|
||||
/// @brief 关闭输入回显
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn disable_echo(&self) {
|
||||
self.state.write().set(TtyCoreState::ECHO_ON, false);
|
||||
}
|
||||
@ -291,6 +293,7 @@ impl TtyCore {
|
||||
///
|
||||
/// @return false 未开启输入回显
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn echo_enabled(&self) -> bool {
|
||||
return self.state.read().contains(TtyCoreState::ECHO_ON);
|
||||
}
|
||||
|
@ -1,31 +1,62 @@
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
filesystem::{
|
||||
devfs::{DeviceINode, DevFS},
|
||||
vfs::{file::FileMode, FilePrivateData, IndexNode},
|
||||
devfs::{devfs_register, DevFS, DeviceINode},
|
||||
vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
|
||||
},
|
||||
kerror, libs::rwlock::RwLock, syscall::SystemError,
|
||||
include::bindings::bindings::{printk_color, textui_putchar, BLACK, WHITE},
|
||||
kdebug, kerror,
|
||||
libs::rwlock::RwLock,
|
||||
print,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use super::{TtyCore, TtyError, TtyFileFlag, TtyFilePrivateData};
|
||||
|
||||
lazy_static! {
|
||||
/// 所有TTY设备的B树。用于根据名字,找到Arc<TtyDevice>
|
||||
/// TODO: 待设备驱动模型完善,具有类似功能的机制后,删掉这里
|
||||
pub static ref TTY_DEVICES: RwLock<BTreeMap<String, Arc<TtyDevice>>> = RwLock::new(BTreeMap::new());
|
||||
}
|
||||
|
||||
/// @brief TTY设备
|
||||
#[derive(Debug)]
|
||||
pub struct TtyDevice {
|
||||
/// TTY核心
|
||||
core: TtyCore,
|
||||
fs: RwLock<Weak<DevFS>>
|
||||
/// TTY所属的文件系统
|
||||
fs: RwLock<Weak<DevFS>>,
|
||||
/// TTY设备私有信息
|
||||
private_data: RwLock<TtyDevicePrivateData>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TtyDevicePrivateData {
|
||||
/// TTY设备名(如tty1)
|
||||
name: String,
|
||||
/// TTY设备文件的元数据
|
||||
metadata: Metadata,
|
||||
// TODO: 增加指向输出端口连接的设备的指针
|
||||
}
|
||||
|
||||
impl TtyDevice {
|
||||
pub fn new() -> Arc<TtyDevice> {
|
||||
return Arc::new(TtyDevice {
|
||||
pub fn new(name: &str) -> Arc<TtyDevice> {
|
||||
let result = Arc::new(TtyDevice {
|
||||
core: TtyCore::new(),
|
||||
fs: RwLock::new(Weak::default()),
|
||||
private_data: TtyDevicePrivateData::new(name),
|
||||
});
|
||||
// 默认开启输入回显
|
||||
result.core.enable_echo();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief 判断文件私有信息是否为TTY的私有信息
|
||||
/// @brief 判断文件私有信息是否为TTY文件的私有信息
|
||||
#[inline]
|
||||
fn verify_file_private_data<'a>(
|
||||
&self,
|
||||
@ -36,6 +67,39 @@ impl TtyDevice {
|
||||
}
|
||||
return Err(SystemError::EIO);
|
||||
}
|
||||
|
||||
/// @brief 获取TTY设备名
|
||||
#[inline]
|
||||
pub fn name(&self) -> String {
|
||||
return self.private_data.read().name.clone();
|
||||
}
|
||||
|
||||
/// @brief 检查TTY文件的读写参数是否合法
|
||||
#[inline]
|
||||
pub fn check_rw_param(&self, len: usize, buf: &[u8]) -> Result<(), SystemError> {
|
||||
if len > buf.len() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// @brief 向TTY的输入端口导入数据
|
||||
pub fn input(&self, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let r: Result<usize, TtyError> = self.core.input(buf, false);
|
||||
if r.is_ok() {
|
||||
return Ok(r.unwrap());
|
||||
}
|
||||
|
||||
let r = r.unwrap_err();
|
||||
match r {
|
||||
TtyError::BufferFull(x) => return Ok(x),
|
||||
TtyError::Closed => return Err(SystemError::ENODEV),
|
||||
e => {
|
||||
kerror!("tty error occurred while writing data to its input port, msg={e:?}");
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceINode for TtyDevice {
|
||||
@ -45,15 +109,40 @@ impl DeviceINode for TtyDevice {
|
||||
}
|
||||
|
||||
impl IndexNode for TtyDevice {
|
||||
/// @brief 打开TTY设备
|
||||
///
|
||||
/// @param data 文件私有信息
|
||||
/// @param mode 打开模式
|
||||
///
|
||||
/// TTY设备通过mode来确定这个文件到底是stdin/stdout/stderr
|
||||
/// - mode的值为O_RDONLY时,表示这个文件是stdin
|
||||
/// - mode的值为O_WRONLY时,表示这个文件是stdout
|
||||
/// - mode的值为O_WRONLY | O_SYNC时,表示这个文件是stderr
|
||||
fn open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), SystemError> {
|
||||
let p = TtyFilePrivateData::default();
|
||||
let mut p = TtyFilePrivateData::default();
|
||||
|
||||
// 检查打开模式
|
||||
let accmode = mode.accmode();
|
||||
if accmode == FileMode::O_RDONLY.accmode() {
|
||||
p.flags.insert(TtyFileFlag::STDIN);
|
||||
} else if accmode == FileMode::O_WRONLY.accmode() {
|
||||
if mode.contains(FileMode::O_SYNC) {
|
||||
p.flags.insert(TtyFileFlag::STDERR);
|
||||
} else {
|
||||
p.flags.insert(TtyFileFlag::STDOUT);
|
||||
}
|
||||
} else {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 保存文件私有信息
|
||||
*data = FilePrivateData::Tty(p);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
_offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
data: &mut crate::filesystem::vfs::FilePrivateData,
|
||||
@ -65,9 +154,10 @@ impl IndexNode for TtyDevice {
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
self.check_rw_param(len, buf)?;
|
||||
|
||||
// 读取stdin队列
|
||||
let r: Result<usize, TtyError> = self.core.read_stdin(buf, true);
|
||||
let r: Result<usize, TtyError> = self.core.read_stdin(&mut buf[0..len], true);
|
||||
if r.is_ok() {
|
||||
return Ok(r.unwrap());
|
||||
}
|
||||
@ -76,6 +166,7 @@ impl IndexNode for TtyDevice {
|
||||
TtyError::EOF(n) => {
|
||||
return Ok(n);
|
||||
}
|
||||
|
||||
x => {
|
||||
kerror!("Error occurred when reading tty, msg={x:?}");
|
||||
return Err(SystemError::ECONNABORTED);
|
||||
@ -85,7 +176,7 @@ impl IndexNode for TtyDevice {
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
_offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
data: &mut crate::filesystem::vfs::FilePrivateData,
|
||||
@ -98,16 +189,19 @@ impl IndexNode for TtyDevice {
|
||||
}
|
||||
};
|
||||
|
||||
self.check_rw_param(len, buf)?;
|
||||
|
||||
// 根据当前文件是stdout还是stderr,选择不同的发送方式
|
||||
let r: Result<usize, TtyError> = if data.flags.contains(TtyFileFlag::STDOUT) {
|
||||
self.core.stdout(buf, true)
|
||||
self.core.stdout(&buf[0..len], true)
|
||||
} else if data.flags.contains(TtyFileFlag::STDERR) {
|
||||
self.core.stderr(buf, true)
|
||||
self.core.stderr(&buf[0..len], true)
|
||||
} else {
|
||||
return Err(SystemError::EPERM);
|
||||
};
|
||||
|
||||
if r.is_ok() {
|
||||
self.sync().expect("Failed to sync tty device!");
|
||||
return Ok(r.unwrap());
|
||||
}
|
||||
|
||||
@ -131,4 +225,94 @@ impl IndexNode for TtyDevice {
|
||||
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
|
||||
return Err(SystemError::ENOTSUP);
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata, SystemError> {
|
||||
return Ok(self.private_data.read().metadata.clone());
|
||||
}
|
||||
|
||||
fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn sync(&self) -> Result<(), SystemError> {
|
||||
// TODO: 引入IO重定向后,需要将输出重定向到对应的设备。
|
||||
// 目前只是简单的输出到屏幕(为了实现的简便)
|
||||
|
||||
loop {
|
||||
let mut buf = [0u8; 512];
|
||||
let r: Result<usize, TtyError> = self.core.read_output(&mut buf[0..511], false);
|
||||
let len;
|
||||
match r {
|
||||
Ok(x) => {
|
||||
len = x;
|
||||
}
|
||||
Err(TtyError::EOF(x)) | Err(TtyError::BufferEmpty(x)) => {
|
||||
len = x;
|
||||
}
|
||||
_ => return Err(SystemError::EIO),
|
||||
}
|
||||
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
// 输出到屏幕
|
||||
print!("{}", unsafe {
|
||||
core::str::from_utf8_unchecked(&buf[0..len])
|
||||
});
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
impl TtyDevicePrivateData {
|
||||
pub fn new(name: &str) -> RwLock<Self> {
|
||||
let mut metadata = Metadata::new(FileType::CharDevice, 0o755);
|
||||
metadata.size = TtyCore::STDIN_BUF_SIZE as i64;
|
||||
return RwLock::new(TtyDevicePrivateData {
|
||||
name: name.to_string(),
|
||||
metadata,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 导出到C的tty初始化函数
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_tty_init() -> i32 {
|
||||
let r = tty_init();
|
||||
if r.is_ok() {
|
||||
return 0;
|
||||
} else {
|
||||
return r.unwrap_err().to_posix_errno();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 初始化TTY设备
|
||||
pub fn tty_init() -> Result<(), SystemError> {
|
||||
let tty: Arc<TtyDevice> = TtyDevice::new("tty0");
|
||||
let devfs_root_inode = ROOT_INODE().lookup("/dev");
|
||||
if devfs_root_inode.is_err() {
|
||||
return Err(devfs_root_inode.unwrap_err());
|
||||
}
|
||||
// 当前关闭键盘输入回显
|
||||
// TODO: 完善Termios之后, 改为默认开启键盘输入回显.
|
||||
tty.core.disable_echo();
|
||||
let guard = TTY_DEVICES.upgradeable_read();
|
||||
|
||||
// 如果已经存在了这个设备
|
||||
if guard.contains_key("tty0") {
|
||||
return Err(SystemError::EEXIST);
|
||||
}
|
||||
|
||||
let mut guard = guard.upgrade();
|
||||
|
||||
guard.insert("tty0".to_string(), tty.clone());
|
||||
|
||||
drop(guard);
|
||||
|
||||
let r = devfs_register(&tty.name(), tty);
|
||||
if r.is_err() {
|
||||
return Err(devfs_root_inode.unwrap_err());
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ use super::vfs::{
|
||||
use crate::{
|
||||
kerror,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
time::TimeSpec, syscall::SystemError,
|
||||
syscall::SystemError,
|
||||
time::TimeSpec,
|
||||
};
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
@ -94,9 +95,14 @@ impl DevFS {
|
||||
///
|
||||
/// @param name 设备名称
|
||||
/// @param device 设备节点的结构体
|
||||
pub fn register_device<T: DeviceINode>(&self, name: &str, device: Arc<T>) -> Result<(), SystemError> {
|
||||
pub fn register_device<T: DeviceINode>(
|
||||
&self,
|
||||
name: &str,
|
||||
device: Arc<T>,
|
||||
) -> Result<(), SystemError> {
|
||||
let dev_root_inode: Arc<LockedDevFSInode> = self.root_inode.clone();
|
||||
match device.metadata().unwrap().file_type {
|
||||
let metadata = device.metadata()?;
|
||||
match metadata.file_type {
|
||||
// 字节设备挂载在 /dev/char
|
||||
FileType::CharDevice => {
|
||||
if let Err(_) = dev_root_inode.find("char") {
|
||||
@ -108,8 +114,13 @@ impl DevFS {
|
||||
.as_any_ref()
|
||||
.downcast_ref::<LockedDevFSInode>()
|
||||
.unwrap();
|
||||
|
||||
// 在 /dev/char 下创建设备节点
|
||||
dev_char_inode.add_dev(name, device.clone())?;
|
||||
|
||||
// 特殊处理 tty 设备,挂载在 /dev 下
|
||||
if name.starts_with("tty") && name.len() > 3 {
|
||||
dev_root_inode.add_dev(name, device.clone())?;
|
||||
}
|
||||
device.set_fs(dev_char_inode.0.lock().fs.clone());
|
||||
}
|
||||
FileType::BlockDevice => {
|
||||
@ -135,7 +146,11 @@ impl DevFS {
|
||||
}
|
||||
|
||||
/// @brief 卸载设备
|
||||
pub fn unregister_device<T: DeviceINode>(&self, name: &str, device: Arc<T>) -> Result<(), SystemError> {
|
||||
pub fn unregister_device<T: DeviceINode>(
|
||||
&self,
|
||||
name: &str,
|
||||
device: Arc<T>,
|
||||
) -> Result<(), SystemError> {
|
||||
let dev_root_inode: Arc<LockedDevFSInode> = self.root_inode.clone();
|
||||
match device.metadata().unwrap().file_type {
|
||||
// 字节设备挂载在 /dev/char
|
||||
@ -325,7 +340,11 @@ impl IndexNode for LockedDevFSInode {
|
||||
self
|
||||
}
|
||||
|
||||
fn open(&self, _data: &mut super::vfs::FilePrivateData, _mode: &FileMode) -> Result<(), SystemError> {
|
||||
fn open(
|
||||
&self,
|
||||
_data: &mut super::vfs::FilePrivateData,
|
||||
_mode: &FileMode,
|
||||
) -> Result<(), SystemError> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -459,6 +478,7 @@ impl IndexNode for LockedDevFSInode {
|
||||
_buf: &mut [u8],
|
||||
_data: &mut super::vfs::file::FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
kerror!("DevFS: read_at is not supported!");
|
||||
Err(SystemError::ENOTSUP)
|
||||
}
|
||||
|
||||
@ -511,4 +531,3 @@ pub fn devfs_register<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(),
|
||||
pub fn devfs_unregister<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(), SystemError> {
|
||||
return devfs_exact_ref!().unregister_device(name, device);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ bitflags! {
|
||||
const O_APPEND = 0o00002000;
|
||||
/// 非阻塞式IO模式
|
||||
const O_NONBLOCK = 0o00004000;
|
||||
/// used to be O_SYNC, see below
|
||||
/// 每次write都等待物理I/O完成,但是如果写操作不影响读取刚写入的数据,则不等待文件属性更新
|
||||
const O_DSYNC = 0o00010000;
|
||||
/// fcntl, for BSD compatibility
|
||||
const FASYNC = 0o00020000;
|
||||
@ -76,9 +76,18 @@ bitflags! {
|
||||
const O_NOATIME = 0o01000000;
|
||||
/// set close_on_exec
|
||||
const O_CLOEXEC = 0o02000000;
|
||||
/// 每次write都等到物理I/O完成,包括write引起的文件属性的更新
|
||||
const O_SYNC = 0o04000000;
|
||||
}
|
||||
}
|
||||
|
||||
impl FileMode {
|
||||
/// @brief 获取文件的访问模式的值
|
||||
#[inline]
|
||||
pub fn accmode(&self) -> u32 {
|
||||
return self.bits() & FileMode::O_ACCMODE.bits();
|
||||
}
|
||||
}
|
||||
/// @brief 抽象文件结构体
|
||||
#[derive(Debug)]
|
||||
pub struct File {
|
||||
@ -128,7 +137,6 @@ impl File {
|
||||
if buf.len() < len {
|
||||
return Err(SystemError::ENOBUFS);
|
||||
}
|
||||
|
||||
let len = self
|
||||
.inode
|
||||
.read_at(self.offset, len, buf, &mut self.private_data)?;
|
||||
@ -151,7 +159,7 @@ impl File {
|
||||
}
|
||||
let len = self
|
||||
.inode
|
||||
.write_at(self.offset, len, buf, &mut FilePrivateData::Unused)?;
|
||||
.write_at(self.offset, len, buf, &mut self.private_data)?;
|
||||
self.offset += len;
|
||||
return Ok(len);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use self::file::FileMode;
|
||||
use self::{core::generate_inode_id, file::FileMode};
|
||||
pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS};
|
||||
|
||||
/// vfs容许的最大的路径名称长度
|
||||
@ -332,6 +332,11 @@ pub trait IndexNode: Any + Sync + Send + Debug {
|
||||
fn truncate(&self, _len: usize) -> Result<(), SystemError> {
|
||||
return Err(SystemError::ENOTSUP);
|
||||
}
|
||||
|
||||
/// @brief 将当前inode的内容同步到具体设备上
|
||||
fn sync(&self) -> Result<(), SystemError> {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
impl dyn IndexNode {
|
||||
@ -516,3 +521,24 @@ pub struct Dirent {
|
||||
d_type: u8, // entry的类型
|
||||
d_name: u8, // 文件entry的名字(是一个零长数组), 本字段仅用于占位
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn new(file_type: FileType, mode: u32) -> Self {
|
||||
Metadata {
|
||||
dev_id: 0,
|
||||
inode_id: generate_inode_id(),
|
||||
size: 0,
|
||||
blk_size: 0,
|
||||
blocks: 0,
|
||||
atime: TimeSpec::default(),
|
||||
mtime: TimeSpec::default(),
|
||||
ctime: TimeSpec::default(),
|
||||
file_type,
|
||||
mode,
|
||||
nlinks: 1,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
raw_dev: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,11 +164,11 @@ impl IndexNode for MountFSInode {
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
_data: &mut FilePrivateData,
|
||||
data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
return self
|
||||
.inner_inode
|
||||
.write_at(offset, len, buf, &mut FilePrivateData::Unused);
|
||||
.write_at(offset, len, buf, data);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -26,22 +26,21 @@
|
||||
#include <common/printk.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/stdio.h>
|
||||
#include <common/string.h>
|
||||
#include <common/time.h>
|
||||
#include <common/unistd.h>
|
||||
#include <common/string.h>
|
||||
#include <driver/disk/ahci/ahci.h>
|
||||
#include <driver/disk/ahci/ahci_rust.h>
|
||||
#include <driver/pci/pci.h>
|
||||
#include <driver/virtio/virtio.h>
|
||||
#include <include/DragonOS/refcount.h>
|
||||
#include <include/DragonOS/signal.h>
|
||||
#include <libs/libUI/textui.h>
|
||||
#include <mm/mm-types.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/mmio.h>
|
||||
#include <mm/slab.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
#include <time/sleep.h>
|
||||
#include <mm/mm-types.h>
|
||||
#include <driver/pci/pci.h>
|
||||
#include <driver/virtio/virtio.h>
|
||||
#include <smp/smp.h>
|
||||
|
||||
#include <time/sleep.h>
|
||||
|
@ -39,7 +39,6 @@ extern crate alloc;
|
||||
extern crate bitflags;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
extern crate num;
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
@ -99,6 +98,5 @@ pub fn panic(info: &PanicInfo) -> ! {
|
||||
pub extern "C" fn __rust_demo_func() -> i32 {
|
||||
printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::kdebug;
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::driver::tty::tty_device::TtyDevice;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const NUM_SCAN_CODES: u8 = 0x80;
|
||||
@ -26,21 +28,25 @@ pub enum KeyFlag {
|
||||
pub struct TypeOneFSM {
|
||||
status: ScanCodeStatus,
|
||||
current_state: TypeOneFSMState,
|
||||
tty: Arc<TtyDevice>,
|
||||
}
|
||||
|
||||
impl TypeOneFSM {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Self {
|
||||
pub fn new(tty: Arc<TtyDevice>) -> Self {
|
||||
Self {
|
||||
status: ScanCodeStatus::new(),
|
||||
current_state: TypeOneFSMState::Start,
|
||||
tty,
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 解析扫描码
|
||||
#[allow(dead_code)]
|
||||
pub fn parse(&mut self, scancode: u8) -> TypeOneFSMState {
|
||||
self.current_state = self.current_state.parse(scancode, &mut self.status);
|
||||
self.current_state = self
|
||||
.current_state
|
||||
.parse(scancode, &mut self.status, &self.tty);
|
||||
self.current_state
|
||||
}
|
||||
}
|
||||
@ -63,30 +69,42 @@ pub enum TypeOneFSMState {
|
||||
|
||||
impl TypeOneFSMState {
|
||||
/// @brief 状态机总控程序
|
||||
fn parse(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState {
|
||||
fn parse(
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
// kdebug!("the code is {:#x}\n", scancode);
|
||||
match self {
|
||||
TypeOneFSMState::Start => {
|
||||
return self.handle_start(scancode, scancode_status);
|
||||
return self.handle_start(scancode, scancode_status, tty);
|
||||
}
|
||||
TypeOneFSMState::PauseBreak(n) => {
|
||||
return self.handle_pause_break(*n, scancode_status);
|
||||
return self.handle_pause_break(*n, scancode_status, tty);
|
||||
}
|
||||
TypeOneFSMState::Func0 => {
|
||||
return self.handle_func0(scancode, scancode_status);
|
||||
return self.handle_func0(scancode, scancode_status, tty);
|
||||
}
|
||||
TypeOneFSMState::Type3 => {
|
||||
return self.handle_type3(scancode, scancode_status);
|
||||
return self.handle_type3(scancode, scancode_status, tty);
|
||||
}
|
||||
TypeOneFSMState::PrtscPress(n) => {
|
||||
return self.handle_prtsc_press(*n, scancode_status, tty)
|
||||
}
|
||||
TypeOneFSMState::PrtscPress(n) => return self.handle_prtsc_press(*n, scancode_status),
|
||||
TypeOneFSMState::PrtscRelease(n) => {
|
||||
return self.handle_prtsc_release(*n, scancode_status)
|
||||
return self.handle_prtsc_release(*n, scancode_status, tty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 处理起始状态
|
||||
fn handle_start(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState {
|
||||
fn handle_start(
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
//kdebug!("in handle_start the code is {:#x}\n",scancode);
|
||||
match scancode {
|
||||
0xe1 => {
|
||||
@ -97,7 +115,7 @@ impl TypeOneFSMState {
|
||||
}
|
||||
_ => {
|
||||
//kdebug!("in _d the code is {:#x}\n",scancode);
|
||||
return TypeOneFSMState::Type3.handle_type3(scancode, scancode_status);
|
||||
return TypeOneFSMState::Type3.handle_type3(scancode, scancode_status, tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,16 +125,17 @@ impl TypeOneFSMState {
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
static PAUSE_BREAK_SCAN_CODE: [u8; 6] = [0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5];
|
||||
let i = match self {
|
||||
TypeOneFSMState::PauseBreak(i) => *i,
|
||||
_ => {
|
||||
return self.handle_type3(scancode, scancode_status);
|
||||
return self.handle_type3(scancode, scancode_status, tty);
|
||||
}
|
||||
};
|
||||
if scancode != PAUSE_BREAK_SCAN_CODE[i as usize] {
|
||||
return self.handle_type3(scancode, scancode_status);
|
||||
return self.handle_type3(scancode, scancode_status, tty);
|
||||
} else {
|
||||
if i == 5 {
|
||||
// 所有Pause Break扫描码都被清除
|
||||
@ -127,7 +146,12 @@ impl TypeOneFSMState {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_func0(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState {
|
||||
fn handle_func0(
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
//0xE0
|
||||
match scancode {
|
||||
0x2a => {
|
||||
@ -190,7 +214,7 @@ impl TypeOneFSMState {
|
||||
}
|
||||
0x53 => {
|
||||
scancode_status.del = true;
|
||||
Self::emit(127);
|
||||
Self::emit(tty, 127);
|
||||
}
|
||||
0xd3 => {
|
||||
scancode_status.del = false;
|
||||
@ -209,32 +233,32 @@ impl TypeOneFSMState {
|
||||
}
|
||||
0x48 => {
|
||||
scancode_status.arrow_u = true;
|
||||
Self::emit(224);
|
||||
Self::emit(72);
|
||||
Self::emit(tty, 224);
|
||||
Self::emit(tty, 72);
|
||||
}
|
||||
0xc8 => {
|
||||
scancode_status.arrow_u = false;
|
||||
}
|
||||
0x4b => {
|
||||
scancode_status.arrow_l = true;
|
||||
Self::emit(224);
|
||||
Self::emit(75);
|
||||
Self::emit(tty, 224);
|
||||
Self::emit(tty, 75);
|
||||
}
|
||||
0xcb => {
|
||||
scancode_status.arrow_l = false;
|
||||
}
|
||||
0x50 => {
|
||||
scancode_status.arrow_d = true;
|
||||
Self::emit(224);
|
||||
Self::emit(80);
|
||||
Self::emit(tty, 224);
|
||||
Self::emit(tty, 80);
|
||||
}
|
||||
0xd0 => {
|
||||
scancode_status.arrow_d = false;
|
||||
}
|
||||
0x4d => {
|
||||
scancode_status.arrow_r = true;
|
||||
Self::emit(224);
|
||||
Self::emit(77);
|
||||
Self::emit(tty, 224);
|
||||
Self::emit(tty, 77);
|
||||
}
|
||||
0xcd => {
|
||||
scancode_status.arrow_r = false;
|
||||
@ -245,14 +269,14 @@ impl TypeOneFSMState {
|
||||
scancode_status.kp_forward_slash = true;
|
||||
|
||||
let ch = '/' as u8;
|
||||
Self::emit(ch);
|
||||
Self::emit(tty, ch);
|
||||
}
|
||||
0xb5 => {
|
||||
scancode_status.kp_forward_slash = false;
|
||||
}
|
||||
0x1c => {
|
||||
scancode_status.kp_enter = true;
|
||||
Self::emit('\n' as u8);
|
||||
Self::emit(tty, '\n' as u8);
|
||||
}
|
||||
0x9c => {
|
||||
scancode_status.kp_enter = false;
|
||||
@ -264,7 +288,12 @@ impl TypeOneFSMState {
|
||||
return TypeOneFSMState::Start;
|
||||
}
|
||||
|
||||
fn handle_type3(&self, scancode: u8, scancode_status: &mut ScanCodeStatus) -> TypeOneFSMState {
|
||||
fn handle_type3(
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
// 判断按键是被按下还是抬起
|
||||
let flag_make = if (scancode & (TYPE1_KEYCODE_FLAG_BREAK as u8)) > 0 {
|
||||
false
|
||||
@ -311,13 +340,15 @@ impl TypeOneFSMState {
|
||||
}
|
||||
|
||||
if key != KeyFlag::NoneFlag {
|
||||
Self::emit(ch);
|
||||
Self::emit(tty, ch);
|
||||
}
|
||||
return TypeOneFSMState::Start;
|
||||
}
|
||||
|
||||
fn emit(_ch: u8) {
|
||||
// todo: 发送到tty
|
||||
#[inline(always)]
|
||||
fn emit(tty: &Arc<TtyDevice>, ch: u8) {
|
||||
// 发送到tty
|
||||
tty.input(&[ch]).ok();
|
||||
}
|
||||
|
||||
/// @brief 处理Prtsc按下事件
|
||||
@ -325,6 +356,7 @@ impl TypeOneFSMState {
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
static PRTSC_SCAN_CODE: [u8; 4] = [0xe0, 0x2a, 0xe0, 0x37];
|
||||
let i = match self {
|
||||
@ -336,7 +368,7 @@ impl TypeOneFSMState {
|
||||
return TypeOneFSMState::Start;
|
||||
}
|
||||
if scancode != PRTSC_SCAN_CODE[i as usize] {
|
||||
return self.handle_type3(scancode, scancode_status);
|
||||
return self.handle_type3(scancode, scancode_status, tty);
|
||||
} else {
|
||||
if i == 3 {
|
||||
// 成功解析出PrtscPress
|
||||
@ -352,6 +384,7 @@ impl TypeOneFSMState {
|
||||
&self,
|
||||
scancode: u8,
|
||||
scancode_status: &mut ScanCodeStatus,
|
||||
tty: &Arc<TtyDevice>,
|
||||
) -> TypeOneFSMState {
|
||||
static PRTSC_SCAN_CODE: [u8; 4] = [0xe0, 0xb7, 0xe0, 0xaa];
|
||||
let i = match self {
|
||||
@ -363,7 +396,7 @@ impl TypeOneFSMState {
|
||||
return TypeOneFSMState::Start;
|
||||
}
|
||||
if scancode != PRTSC_SCAN_CODE[i as usize] {
|
||||
return self.handle_type3(scancode, scancode_status);
|
||||
return self.handle_type3(scancode, scancode_status, tty);
|
||||
} else {
|
||||
if i == 3 {
|
||||
// 成功解析出PrtscRelease
|
||||
@ -446,7 +479,7 @@ const TYPE1_KEY_CODE_MAPTABLE: [u8; 256] = [
|
||||
/*0x08*/ '7' as u8, '&' as u8, /*0x09*/ '8' as u8, '*' as u8,
|
||||
/*0x0a*/ '9' as u8, '(' as u8, /*0x0b*/ '0' as u8, ')' as u8,
|
||||
/*0x0c*/ '-' as u8, '_' as u8, /*0x0d*/ '=' as u8, '+' as u8,
|
||||
/*0x0e*/ 0x0e as u8, 0x0e as u8, // BACKSPACE
|
||||
/*0x0e \b */ 8 as u8, 8 as u8, // BACKSPACE
|
||||
/*0x0f*/ '\t' as u8, '\t' as u8, // TAB
|
||||
/*0x10*/ 'q' as u8, 'Q' as u8, /*0x11*/ 'w' as u8, 'W' as u8,
|
||||
/*0x12*/ 'e' as u8, 'E' as u8, /*0x13*/ 'r' as u8, 'R' as u8,
|
||||
|
@ -36,6 +36,8 @@
|
||||
|
||||
#include <driver/interrupt/apic/apic_timer.h>
|
||||
|
||||
extern int rs_tty_init();
|
||||
|
||||
ul bsp_idt_size, bsp_gdt_size;
|
||||
|
||||
#pragma GCC push_options
|
||||
@ -135,6 +137,7 @@ void system_initialize()
|
||||
io_mfence();
|
||||
|
||||
vfs_init();
|
||||
rs_tty_init();
|
||||
|
||||
cpu_init();
|
||||
ps2_keyboard_init();
|
||||
|
@ -48,6 +48,7 @@ extern void process_exit_signal(struct process_control_block *pcb);
|
||||
extern void initial_proc_init_signal(struct process_control_block *pcb);
|
||||
extern void rs_process_exit_fpstate(struct process_control_block *pcb);
|
||||
extern int process_init_files();
|
||||
extern int rs_init_stdio();
|
||||
|
||||
// 设置初始进程的PCB
|
||||
#define INITIAL_PROC(proc) \
|
||||
@ -452,10 +453,6 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
|
||||
current_pcb->mm->brk_end = brk_start_addr;
|
||||
current_pcb->mm->stack_start = stack_start_addr;
|
||||
|
||||
// 关闭之前的文件描述符
|
||||
process_exit_files(current_pcb);
|
||||
process_init_files();
|
||||
|
||||
// 清除进程的vfork标志位
|
||||
current_pcb->flags &= ~PF_VFORK;
|
||||
|
||||
@ -540,9 +537,10 @@ struct process_control_block *process_init_rt_pcb(struct process_control_block *
|
||||
ul initial_kernel_thread(ul arg)
|
||||
{
|
||||
kinfo("initial proc running...\targ:%#018lx, vruntime=%d", arg, current_pcb->virtual_runtime);
|
||||
int val = 0;
|
||||
val = scm_enable_double_buffer();
|
||||
|
||||
scm_enable_double_buffer();
|
||||
|
||||
rs_init_stdio();
|
||||
// block_io_scheduler_init();
|
||||
ahci_init();
|
||||
mount_root_fs();
|
||||
|
@ -7,7 +7,7 @@ use alloc::boxed::Box;
|
||||
|
||||
use crate::{
|
||||
arch::{asm::current::current_pcb, fpu::FpState},
|
||||
filesystem::vfs::file::{File, FileDescriptorVec},
|
||||
filesystem::vfs::{file::{File, FileDescriptorVec, FileMode}, ROOT_INODE},
|
||||
include::bindings::bindings::{
|
||||
process_control_block, CLONE_FS, PROC_INTERRUPTIBLE,
|
||||
PROC_RUNNING, PROC_STOPPED, PROC_UNINTERRUPTIBLE,
|
||||
@ -350,4 +350,37 @@ pub extern "C" fn rs_process_exit_fpstate(pcb: &'static mut process_control_bloc
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_init_stdio() -> i32 {
|
||||
let r = init_stdio();
|
||||
if r.is_ok() {
|
||||
return 0;
|
||||
} else {
|
||||
return r.unwrap_err().to_posix_errno();
|
||||
}
|
||||
}
|
||||
// =========== 以上为导出到C的函数,在将来,进程管理模块被完全重构之后,需要删掉他们 END ============
|
||||
|
||||
/// @brief 初始化pid=1的进程的stdio
|
||||
pub fn init_stdio() -> Result<(), SystemError> {
|
||||
if current_pcb().pid != 1 {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
let tty_inode = ROOT_INODE()
|
||||
.lookup("/dev/tty0")
|
||||
.expect("Init stdio: can't find tty0");
|
||||
let stdin =
|
||||
File::new(tty_inode.clone(), FileMode::O_RDONLY).expect("Init stdio: can't create stdin");
|
||||
let stdout =
|
||||
File::new(tty_inode.clone(), FileMode::O_WRONLY).expect("Init stdio: can't create stdout");
|
||||
let stderr = File::new(tty_inode.clone(), FileMode::O_WRONLY | FileMode::O_SYNC)
|
||||
.expect("Init stdio: can't create stderr");
|
||||
|
||||
/*
|
||||
按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr
|
||||
*/
|
||||
assert_eq!(current_pcb().alloc_fd(stdin).unwrap(), 0);
|
||||
assert_eq!(current_pcb().alloc_fd(stdout).unwrap(), 1);
|
||||
assert_eq!(current_pcb().alloc_fd(stderr).unwrap(), 2);
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -6,3 +6,12 @@ pub struct TimeSpec {
|
||||
pub tv_sec: i64,
|
||||
pub tv_nsec: i64,
|
||||
}
|
||||
|
||||
impl TimeSpec {
|
||||
pub fn new(sec: i64, nsec: i64) -> TimeSpec {
|
||||
return TimeSpec {
|
||||
tv_sec: sec,
|
||||
tv_nsec: nsec,
|
||||
};
|
||||
}
|
||||
}
|
@ -309,6 +309,11 @@ int shell_cmd_cat(int argc, char **argv)
|
||||
|
||||
// 打开文件
|
||||
int fd = open(file_path, 0);
|
||||
if (fd <= 0)
|
||||
{
|
||||
printf("ERROR: Cannot open file: %s, fd=%d\n", file_path, fd);
|
||||
return -1;
|
||||
}
|
||||
// 获取文件总大小
|
||||
int file_size = lseek(fd, 0, SEEK_END);
|
||||
// 将文件指针切换回文件起始位置
|
||||
@ -320,6 +325,11 @@ int shell_cmd_cat(int argc, char **argv)
|
||||
{
|
||||
memset(buf, 0, 512);
|
||||
int l = read(fd, buf, 511);
|
||||
if (l < 0)
|
||||
{
|
||||
printf("ERROR: Cannot read file: %s\n", file_path);
|
||||
return -1;
|
||||
}
|
||||
buf[l] = '\0';
|
||||
|
||||
file_size -= l;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "cmd.h"
|
||||
#include <libKeyboard/keyboard.h>
|
||||
#include <fcntl.h>
|
||||
#include <libKeyboard/keyboard.h>
|
||||
#include <printf.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@ -90,14 +90,14 @@ void main_loop(int kb_fd)
|
||||
int main()
|
||||
{
|
||||
// 打开键盘文件
|
||||
char kb_file_path[] = "/dev/char/ps2_keyboard";
|
||||
// char kb_file_path[] = "/dev/char/ps2_keyboard";
|
||||
|
||||
int kb_fd = open(kb_file_path, 0);
|
||||
// int kb_fd = open(kb_file_path, 0);
|
||||
print_ascii_logo();
|
||||
// printf("before mkdir\n");
|
||||
// mkdir("/aaac", 0);
|
||||
// printf("after mkdir\n");
|
||||
main_loop(kb_fd);
|
||||
main_loop(0);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
@ -155,9 +155,18 @@ int shell_readline(int fd, char *buf)
|
||||
int count = 0;
|
||||
while (1)
|
||||
{
|
||||
key = keyboard_analyze_keycode(fd);
|
||||
// key = keyboard_analyze_keycode(fd);
|
||||
key = getchar();
|
||||
// printf("key = %d\n", key);
|
||||
if (key == 224)
|
||||
{
|
||||
key = getchar();
|
||||
// printf("key = %d\n", key);
|
||||
switch (key)
|
||||
{
|
||||
case 72:
|
||||
// 向上方向键
|
||||
if (count_history != 0 && key == 0xc8)
|
||||
if (count_history != 0)
|
||||
{
|
||||
// put_string(" ", COLOR_WHITE, COLOR_BLACK);
|
||||
printf("%c", '\b');
|
||||
@ -167,17 +176,27 @@ int shell_readline(int fd, char *buf)
|
||||
change_command(buf, 1);
|
||||
count = strlen(buf);
|
||||
}
|
||||
key = 0xc8;
|
||||
break;
|
||||
case 80:
|
||||
// 向下方向键
|
||||
if (count_history != 0 && key == 0x50)
|
||||
if (count_history != 0)
|
||||
{
|
||||
// put_string(" ", COLOR_WHITE, COLOR_BLACK);
|
||||
printf("%c", '\b');
|
||||
clear_command(count, buf);
|
||||
count = 0;
|
||||
//向现在
|
||||
// 向历史
|
||||
change_command(buf, -1);
|
||||
count = strlen(buf);
|
||||
}
|
||||
key = 0x50;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (key == '\n')
|
||||
{
|
||||
if (count > 0 && current_command_index >= count_history)
|
||||
|
@ -57,7 +57,7 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode);
|
||||
int fclose(FILE *stream);
|
||||
int puts(const char *s);
|
||||
int putchar(int c);
|
||||
|
||||
int getchar(void);
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include <printf.h>
|
||||
|
||||
#include <libsystem/syscall.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libsystem/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static char *write_num(char *str, uint64_t num, int base, int field_width, int precision, int flags);
|
||||
static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags);
|
||||
@ -46,7 +47,8 @@ int printf(const char *fmt, ...)
|
||||
|
||||
count = vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
put_string(buf, COLOR_WHITE, COLOR_BLACK);
|
||||
// put_string(buf, COLOR_WHITE, COLOR_BLACK);
|
||||
write(1, buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,13 @@ int fprintf(FILE *restrict stream, const char *restrict format, ...)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int getchar(void)
|
||||
{
|
||||
unsigned int c;
|
||||
read(0, &c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
int puts(const char *s)
|
||||
{
|
||||
return put_string(s, COLOR_WHITE, COLOR_BLACK);
|
||||
@ -47,17 +54,17 @@ int ferror(FILE *stream)
|
||||
|
||||
int fclose(FILE *stream)
|
||||
{
|
||||
int retval = close(stream->fd);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (stream->fd >= 3)
|
||||
{
|
||||
int retcval = close(stream->fd);
|
||||
free(stream);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: 请注意,这个函数的实现,没有遵照posix,行为也与Linux的不一致,请在将来用Rust重构时改变它,以使得它的行为与Linux的一致。
|
||||
// FIXME:
|
||||
// 请注意,这个函数的实现,没有遵照posix,行为也与Linux的不一致,请在将来用Rust重构时改变它,以使得它的行为与Linux的一致。
|
||||
FILE *fopen(const char *restrict pathname, const char *restrict mode)
|
||||
{
|
||||
FILE *stream = malloc(sizeof(FILE));
|
||||
|
Reference in New Issue
Block a user