static fs_node_t g_dev_tty;
static fs_node_t g_dev_ptmx;
static fs_node_t g_dev_pts_dir;
-static fs_node_t g_dev_pts0;
static uint32_t g_devfs_inited = 0;
static uint32_t prng_state = 0x12345678;
}
static uint32_t dev_ptmx_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
- (void)node;
(void)offset;
- int rc = pty_master_read_kbuf(buffer, size);
+ int idx = pty_ino_to_idx(node->inode);
+ if (idx < 0) idx = 0;
+ int rc = pty_master_read_idx(idx, buffer, size);
if (rc < 0) return 0;
return (uint32_t)rc;
}
static uint32_t dev_ptmx_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
- (void)node;
- (void)offset;
- int rc = pty_master_write_kbuf(buffer, size);
- if (rc < 0) return 0;
- return (uint32_t)rc;
-}
-
-static uint32_t dev_pts0_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
- (void)node;
(void)offset;
- int rc = pty_slave_read_kbuf(buffer, size);
- if (rc < 0) return 0;
- return (uint32_t)rc;
-}
-
-static uint32_t dev_pts0_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
- (void)node;
- (void)offset;
- int rc = pty_slave_write_kbuf(buffer, size);
+ int idx = pty_ino_to_idx(node->inode);
+ if (idx < 0) idx = 0;
+ int rc = pty_master_write_idx(idx, buffer, size);
if (rc < 0) return 0;
return (uint32_t)rc;
}
static struct fs_node* devfs_pts_finddir_impl(struct fs_node* node, const char* name) {
(void)node;
if (!name || name[0] == 0) return 0;
- if (strcmp(name, "0") == 0) return &g_dev_pts0;
+ int count = pty_pair_count();
+ for (int i = 0; i < count; i++) {
+ char num[4];
+ num[0] = '0' + (char)i;
+ num[1] = '\0';
+ if (strcmp(name, num) == 0) {
+ return pty_get_slave_node(i);
+ }
+ }
return 0;
}
if (!inout_index || !buf) return -1;
if (buf_len < sizeof(struct vfs_dirent)) return -1;
+ int count = pty_pair_count();
uint32_t idx = *inout_index;
uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent);
struct vfs_dirent* ents = (struct vfs_dirent*)buf;
e.d_ino = 5; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".");
} else if (idx == 1) {
e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "..");
- } else if (idx == 2) {
- e.d_ino = 6; e.d_type = FS_CHARDEVICE; strcpy(e.d_name, "0");
} else {
- break;
+ int pi = (int)(idx - 2);
+ if (pi >= count) break;
+ e.d_ino = PTY_SLAVE_INO_BASE + (uint32_t)pi;
+ e.d_type = FS_CHARDEVICE;
+ e.d_name[0] = '0' + (char)pi;
+ e.d_name[1] = '\0';
}
e.d_reclen = (uint16_t)sizeof(e);
memset(&g_dev_ptmx, 0, sizeof(g_dev_ptmx));
strcpy(g_dev_ptmx.name, "ptmx");
g_dev_ptmx.flags = FS_CHARDEVICE;
- g_dev_ptmx.inode = 4;
- g_dev_ptmx.length = 0;
+ g_dev_ptmx.inode = PTY_MASTER_INO_BASE;
g_dev_ptmx.read = &dev_ptmx_read;
g_dev_ptmx.write = &dev_ptmx_write;
- g_dev_ptmx.open = 0;
- g_dev_ptmx.close = 0;
- g_dev_ptmx.finddir = 0;
memset(&g_dev_pts_dir, 0, sizeof(g_dev_pts_dir));
strcpy(g_dev_pts_dir.name, "pts");
g_dev_pts_dir.finddir = &devfs_pts_finddir_impl;
g_dev_pts_dir.readdir = &devfs_pts_readdir_impl;
- memset(&g_dev_pts0, 0, sizeof(g_dev_pts0));
- strcpy(g_dev_pts0.name, "0");
- g_dev_pts0.flags = FS_CHARDEVICE;
- g_dev_pts0.inode = 6;
- g_dev_pts0.length = 0;
- g_dev_pts0.read = &dev_pts0_read;
- g_dev_pts0.write = &dev_pts0_write;
- g_dev_pts0.open = 0;
- g_dev_pts0.close = 0;
- g_dev_pts0.finddir = 0;
}
fs_node_t* devfs_create_root(void) {
#include "process.h"
#include "spinlock.h"
#include "uaccess.h"
+#include "utils.h"
#include "hal/cpu.h"
#define PTY_BUF_CAP 1024
#define PTY_WAITQ_MAX 16
-static spinlock_t pty_lock = {0};
-
-static uint8_t m2s_buf[PTY_BUF_CAP];
-static uint32_t m2s_head = 0;
-static uint32_t m2s_tail = 0;
-
-static uint8_t s2m_buf[PTY_BUF_CAP];
-static uint32_t s2m_head = 0;
-static uint32_t s2m_tail = 0;
-
-static struct process* m2s_waitq[PTY_WAITQ_MAX];
-static uint32_t m2s_wq_head = 0;
-static uint32_t m2s_wq_tail = 0;
-
-static struct process* s2m_waitq[PTY_WAITQ_MAX];
-static uint32_t s2m_wq_head = 0;
-static uint32_t s2m_wq_tail = 0;
-
-static uint32_t pty_session_id = 0;
-static uint32_t pty_fg_pgrp = 0;
-
enum {
SIGTTIN = 21,
SIGTTOU = 22,
TTY_TIOCSPGRP = 0x5410,
};
+struct pty_pair {
+ uint8_t m2s_buf[PTY_BUF_CAP];
+ uint32_t m2s_head;
+ uint32_t m2s_tail;
+
+ uint8_t s2m_buf[PTY_BUF_CAP];
+ uint32_t s2m_head;
+ uint32_t s2m_tail;
+
+ struct process* m2s_waitq[PTY_WAITQ_MAX];
+ uint32_t m2s_wq_head;
+ uint32_t m2s_wq_tail;
+
+ struct process* s2m_waitq[PTY_WAITQ_MAX];
+ uint32_t s2m_wq_head;
+ uint32_t s2m_wq_tail;
+
+ uint32_t session_id;
+ uint32_t fg_pgrp;
+ int active;
+
+ fs_node_t master_node;
+ fs_node_t slave_node;
+};
+
+static spinlock_t pty_lock = {0};
+static struct pty_pair g_ptys[PTY_MAX_PAIRS];
+static int g_pty_count = 0;
+
static uint32_t rb_count(uint32_t head, uint32_t tail) {
if (head >= tail) return head - tail;
return (PTY_BUF_CAP - tail) + head;
}
}
+static uint32_t pty_master_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t pty_master_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+static uint32_t pty_slave_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t pty_slave_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+
+static void pty_init_pair(int idx) {
+ struct pty_pair* p = &g_ptys[idx];
+ memset(p, 0, sizeof(*p));
+ p->active = 1;
+
+ char name[8];
+ memset(&p->master_node, 0, sizeof(p->master_node));
+ strcpy(p->master_node.name, "ptmx");
+ p->master_node.flags = FS_CHARDEVICE;
+ p->master_node.inode = PTY_MASTER_INO_BASE + (uint32_t)idx;
+ p->master_node.read = &pty_master_read_fn;
+ p->master_node.write = &pty_master_write_fn;
+
+ memset(&p->slave_node, 0, sizeof(p->slave_node));
+ name[0] = '0' + (char)idx;
+ name[1] = '\0';
+ strcpy(p->slave_node.name, name);
+ p->slave_node.flags = FS_CHARDEVICE;
+ p->slave_node.inode = PTY_SLAVE_INO_BASE + (uint32_t)idx;
+ p->slave_node.read = &pty_slave_read_fn;
+ p->slave_node.write = &pty_slave_write_fn;
+}
+
void pty_init(void) {
spinlock_init(&pty_lock);
- m2s_head = m2s_tail = 0;
- s2m_head = s2m_tail = 0;
- m2s_wq_head = m2s_wq_tail = 0;
- s2m_wq_head = s2m_wq_tail = 0;
- pty_session_id = 0;
- pty_fg_pgrp = 0;
+ memset(g_ptys, 0, sizeof(g_ptys));
+ g_pty_count = 0;
+ pty_init_pair(0);
+ g_pty_count = 1;
+}
+
+int pty_alloc_pair(void) {
+ uintptr_t flags = spin_lock_irqsave(&pty_lock);
+ if (g_pty_count >= PTY_MAX_PAIRS) {
+ spin_unlock_irqrestore(&pty_lock, flags);
+ return -ENOMEM;
+ }
+ int idx = g_pty_count;
+ g_pty_count++;
+ spin_unlock_irqrestore(&pty_lock, flags);
+ pty_init_pair(idx);
+ return idx;
+}
+
+int pty_pair_count(void) {
+ return g_pty_count;
+}
+
+int pty_pair_active(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return 0;
+ return g_ptys[idx].active;
+}
+
+fs_node_t* pty_get_master_node(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return NULL;
+ return &g_ptys[idx].master_node;
+}
+
+fs_node_t* pty_get_slave_node(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return NULL;
+ return &g_ptys[idx].slave_node;
}
-static int pty_jobctl_write_check(void) {
- if (current_process && pty_session_id != 0 && current_process->session_id == pty_session_id &&
- pty_fg_pgrp != 0 && current_process->pgrp_id != pty_fg_pgrp) {
+static int pty_jobctl_write_check(struct pty_pair* p) {
+ if (current_process && p->session_id != 0 && current_process->session_id == p->session_id &&
+ p->fg_pgrp != 0 && current_process->pgrp_id != p->fg_pgrp) {
(void)process_kill(current_process->pid, SIGTTOU);
return -EINTR;
}
return 0;
}
-static int pty_jobctl_read_check(void) {
+static int pty_jobctl_read_check(struct pty_pair* p) {
if (!current_process) return -ECHILD;
- if (pty_session_id != 0 && current_process->session_id == pty_session_id &&
- pty_fg_pgrp != 0 && current_process->pgrp_id != pty_fg_pgrp) {
+ if (p->session_id != 0 && current_process->session_id == p->session_id &&
+ p->fg_pgrp != 0 && current_process->pgrp_id != p->fg_pgrp) {
(void)process_kill(current_process->pid, SIGTTIN);
return -EINTR;
}
return 0;
}
-int pty_master_can_read(void) {
+int pty_master_can_read_idx(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return 0;
+ struct pty_pair* p = &g_ptys[idx];
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- int ready = (rb_count(s2m_head, s2m_tail) != 0U) ? 1 : 0;
+ int ready = (rb_count(p->s2m_head, p->s2m_tail) != 0U) ? 1 : 0;
spin_unlock_irqrestore(&pty_lock, flags);
return ready;
}
-int pty_master_can_write(void) {
+int pty_master_can_write_idx(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return 0;
+ struct pty_pair* p = &g_ptys[idx];
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- int ready = (rb_free(m2s_head, m2s_tail) != 0U) ? 1 : 0;
+ int ready = (rb_free(p->m2s_head, p->m2s_tail) != 0U) ? 1 : 0;
spin_unlock_irqrestore(&pty_lock, flags);
return ready;
}
-int pty_slave_can_read(void) {
+int pty_slave_can_read_idx(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return 0;
+ struct pty_pair* p = &g_ptys[idx];
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- int ready = (rb_count(m2s_head, m2s_tail) != 0U) ? 1 : 0;
+ int ready = (rb_count(p->m2s_head, p->m2s_tail) != 0U) ? 1 : 0;
spin_unlock_irqrestore(&pty_lock, flags);
return ready;
}
-int pty_slave_can_write(void) {
+int pty_slave_can_write_idx(int idx) {
+ if (idx < 0 || idx >= g_pty_count) return 0;
+ struct pty_pair* p = &g_ptys[idx];
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- int ready = (rb_free(s2m_head, s2m_tail) != 0U) ? 1 : 0;
+ int ready = (rb_free(p->s2m_head, p->s2m_tail) != 0U) ? 1 : 0;
spin_unlock_irqrestore(&pty_lock, flags);
return ready;
}
-int pty_master_read_kbuf(void* kbuf, uint32_t len) {
+int pty_master_read_idx(int idx, void* kbuf, uint32_t len) {
+ if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+ struct pty_pair* p = &g_ptys[idx];
if (!kbuf) return -EFAULT;
if (len > 1024 * 1024) return -EINVAL;
- int jc = pty_jobctl_read_check();
+ int jc = pty_jobctl_read_check(p);
if (jc < 0) return jc;
while (1) {
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- uint32_t avail = rb_count(s2m_head, s2m_tail);
+ uint32_t avail = rb_count(p->s2m_head, p->s2m_tail);
if (avail != 0U) {
uint32_t to_read = len;
if (to_read > avail) to_read = avail;
for (uint32_t i = 0; i < to_read; i++) {
uint8_t c = 0;
- (void)rb_pop(s2m_buf, &s2m_head, &s2m_tail, &c);
+ (void)rb_pop(p->s2m_buf, &p->s2m_head, &p->s2m_tail, &c);
((uint8_t*)kbuf)[i] = c;
}
spin_unlock_irqrestore(&pty_lock, flags);
}
if (current_process) {
- if (waitq_push(s2m_waitq, &s2m_wq_head, &s2m_wq_tail, current_process) == 0) {
+ if (waitq_push(p->s2m_waitq, &p->s2m_wq_head, &p->s2m_wq_tail, current_process) == 0) {
current_process->state = PROCESS_BLOCKED;
}
}
}
}
-int pty_master_write_kbuf(const void* kbuf, uint32_t len) {
+int pty_master_write_idx(int idx, const void* kbuf, uint32_t len) {
+ if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+ struct pty_pair* p = &g_ptys[idx];
if (!kbuf) return -EFAULT;
if (len > 1024 * 1024) return -EINVAL;
- int jc = pty_jobctl_write_check();
+ int jc = pty_jobctl_write_check(p);
if (jc < 0) return jc;
enum { SIGINT_NUM = 2, SIGQUIT_NUM = 3, SIGTSTP_NUM = 20 };
if (ch == 0x03) sig = SIGINT_NUM;
else if (ch == 0x1C) sig = SIGQUIT_NUM;
else if (ch == 0x1A) sig = SIGTSTP_NUM;
- if (sig && pty_fg_pgrp != 0) {
- process_kill_pgrp(pty_fg_pgrp, sig);
+ if (sig && p->fg_pgrp != 0) {
+ process_kill_pgrp(p->fg_pgrp, sig);
}
}
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- uint32_t free = rb_free(m2s_head, m2s_tail);
+ uint32_t free_space = rb_free(p->m2s_head, p->m2s_tail);
uint32_t to_write = len;
- if (to_write > free) to_write = free;
+ if (to_write > free_space) to_write = free_space;
for (uint32_t i = 0; i < to_write; i++) {
- rb_push(m2s_buf, &m2s_head, &m2s_tail, ((const uint8_t*)kbuf)[i]);
+ rb_push(p->m2s_buf, &p->m2s_head, &p->m2s_tail, ((const uint8_t*)kbuf)[i]);
}
if (to_write) {
- waitq_wake_one(m2s_waitq, &m2s_wq_head, &m2s_wq_tail);
+ waitq_wake_one(p->m2s_waitq, &p->m2s_wq_head, &p->m2s_wq_tail);
}
spin_unlock_irqrestore(&pty_lock, flags);
return (int)to_write;
}
-int pty_slave_read_kbuf(void* kbuf, uint32_t len) {
+int pty_slave_read_idx(int idx, void* kbuf, uint32_t len) {
+ if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+ struct pty_pair* p = &g_ptys[idx];
if (!kbuf) return -EFAULT;
if (len > 1024 * 1024) return -EINVAL;
- int jc = pty_jobctl_read_check();
+ int jc = pty_jobctl_read_check(p);
if (jc < 0) return jc;
while (1) {
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- uint32_t avail = rb_count(m2s_head, m2s_tail);
+ uint32_t avail = rb_count(p->m2s_head, p->m2s_tail);
if (avail != 0U) {
uint32_t to_read = len;
if (to_read > avail) to_read = avail;
for (uint32_t i = 0; i < to_read; i++) {
uint8_t c = 0;
- (void)rb_pop(m2s_buf, &m2s_head, &m2s_tail, &c);
+ (void)rb_pop(p->m2s_buf, &p->m2s_head, &p->m2s_tail, &c);
((uint8_t*)kbuf)[i] = c;
}
spin_unlock_irqrestore(&pty_lock, flags);
}
if (current_process) {
- if (waitq_push(m2s_waitq, &m2s_wq_head, &m2s_wq_tail, current_process) == 0) {
+ if (waitq_push(p->m2s_waitq, &p->m2s_wq_head, &p->m2s_wq_tail, current_process) == 0) {
current_process->state = PROCESS_BLOCKED;
}
}
}
}
-int pty_slave_write_kbuf(const void* kbuf, uint32_t len) {
+int pty_slave_write_idx(int idx, const void* kbuf, uint32_t len) {
+ if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+ struct pty_pair* p = &g_ptys[idx];
if (!kbuf) return -EFAULT;
if (len > 1024 * 1024) return -EINVAL;
- int jc = pty_jobctl_write_check();
+ int jc = pty_jobctl_write_check(p);
if (jc < 0) return jc;
uintptr_t flags = spin_lock_irqsave(&pty_lock);
- uint32_t free = rb_free(s2m_head, s2m_tail);
+ uint32_t free_space = rb_free(p->s2m_head, p->s2m_tail);
uint32_t to_write = len;
- if (to_write > free) to_write = free;
+ if (to_write > free_space) to_write = free_space;
for (uint32_t i = 0; i < to_write; i++) {
- rb_push(s2m_buf, &s2m_head, &s2m_tail, ((const uint8_t*)kbuf)[i]);
+ rb_push(p->s2m_buf, &p->s2m_head, &p->s2m_tail, ((const uint8_t*)kbuf)[i]);
}
if (to_write) {
- waitq_wake_one(s2m_waitq, &s2m_wq_head, &s2m_wq_tail);
+ waitq_wake_one(p->s2m_waitq, &p->s2m_wq_head, &p->s2m_wq_tail);
}
spin_unlock_irqrestore(&pty_lock, flags);
return (int)to_write;
}
-int pty_slave_ioctl(uint32_t cmd, void* user_arg) {
+int pty_slave_ioctl_idx(int idx, uint32_t cmd, void* user_arg) {
+ if (idx < 0 || idx >= g_pty_count) return -ENODEV;
+ struct pty_pair* p = &g_ptys[idx];
if (!user_arg) return -EFAULT;
- if (current_process && pty_session_id == 0 && current_process->session_id != 0) {
- pty_session_id = current_process->session_id;
- pty_fg_pgrp = current_process->pgrp_id;
+ if (current_process && p->session_id == 0 && current_process->session_id != 0) {
+ p->session_id = current_process->session_id;
+ p->fg_pgrp = current_process->pgrp_id;
}
if (cmd == TTY_TIOCGPGRP) {
if (user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT;
- int fg = (int)pty_fg_pgrp;
+ int fg = (int)p->fg_pgrp;
if (copy_to_user(user_arg, &fg, sizeof(fg)) < 0) return -EFAULT;
return 0;
}
if (copy_from_user(&fg, user_arg, sizeof(fg)) < 0) return -EFAULT;
if (!current_process) return -EINVAL;
- if (pty_session_id == 0) {
+ if (p->session_id == 0) {
if (fg != 0) return -EPERM;
- pty_fg_pgrp = 0;
+ p->fg_pgrp = 0;
return 0;
}
- if (current_process->session_id != pty_session_id) return -EPERM;
+ if (current_process->session_id != p->session_id) return -EPERM;
if (fg < 0) return -EINVAL;
- pty_fg_pgrp = (uint32_t)fg;
+ p->fg_pgrp = (uint32_t)fg;
return 0;
}
return -EINVAL;
}
+
+static uint32_t pty_master_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
+ (void)offset;
+ int idx = pty_ino_to_idx(node->inode);
+ int rc = pty_master_read_idx(idx, buffer, size);
+ if (rc < 0) return 0;
+ return (uint32_t)rc;
+}
+
+static uint32_t pty_master_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
+ (void)offset;
+ int idx = pty_ino_to_idx(node->inode);
+ int rc = pty_master_write_idx(idx, buffer, size);
+ if (rc < 0) return 0;
+ return (uint32_t)rc;
+}
+
+static uint32_t pty_slave_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
+ (void)offset;
+ int idx = pty_ino_to_idx(node->inode);
+ int rc = pty_slave_read_idx(idx, buffer, size);
+ if (rc < 0) return 0;
+ return (uint32_t)rc;
+}
+
+static uint32_t pty_slave_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) {
+ (void)offset;
+ int idx = pty_ino_to_idx(node->inode);
+ int rc = pty_slave_write_idx(idx, buffer, size);
+ if (rc < 0) return 0;
+ return (uint32_t)rc;
+}
+
+int pty_master_can_read(void) { return pty_master_can_read_idx(0); }
+int pty_master_can_write(void) { return pty_master_can_write_idx(0); }
+int pty_slave_can_read(void) { return pty_slave_can_read_idx(0); }
+int pty_slave_can_write(void) { return pty_slave_can_write_idx(0); }
+
+int pty_master_read_kbuf(void* kbuf, uint32_t len) { return pty_master_read_idx(0, kbuf, len); }
+int pty_master_write_kbuf(const void* kbuf, uint32_t len) { return pty_master_write_idx(0, kbuf, len); }
+int pty_slave_read_kbuf(void* kbuf, uint32_t len) { return pty_slave_read_idx(0, kbuf, len); }
+int pty_slave_write_kbuf(const void* kbuf, uint32_t len) { return pty_slave_write_idx(0, kbuf, len); }
+int pty_slave_ioctl(uint32_t cmd, void* user_arg) { return pty_slave_ioctl_idx(0, cmd, user_arg); }