#define ESRCH 3
#define EMFILE 24
#define ESPIPE 29
+#define ENOTTY 25
#define ENOSYS 38
#endif
struct process {
uint32_t pid;
uint32_t parent_pid;
+ uint32_t session_id;
+ uint32_t pgrp_id;
uintptr_t sp;
uintptr_t addr_space;
uint32_t* kernel_stack;
SYSCALL_POLL = 18,
SYSCALL_KILL = 19,
SYSCALL_SELECT = 20,
+ SYSCALL_IOCTL = 21,
+ SYSCALL_SETSID = 22,
+ SYSCALL_SETPGID = 23,
+ SYSCALL_GETPGRP = 24,
};
#endif
#include <stddef.h>
#include <stdint.h>
+struct termios {
+ uint32_t c_lflag;
+};
+
+enum {
+ TTY_ICANON = 0x0001,
+ TTY_ECHO = 0x0002,
+};
+
void tty_init(void);
int tty_read(void* user_buf, uint32_t len);
int tty_can_read(void);
int tty_can_write(void);
+int tty_ioctl(uint32_t cmd, void* user_arg);
+
void tty_input_char(char c);
#endif
uintptr_t vmm_as_clone_user(uintptr_t src_as) {
if (!src_as) return 0;
+ // Temporary kernel-only mapping in the last user PDE (pdi=767). This avoids touching
+ // shared higher-half kernel page tables copied from boot_pd.
+ const uintptr_t TMP_MAP_VA = 0xBFF00000U;
+
uintptr_t new_as = vmm_as_create_kernel_clone();
if (!new_as) return 0;
}
uint32_t* src_pd = (uint32_t*)P2V((uint32_t)src_as);
- const uint32_t* const boot_pd_virt = boot_pd;
- // Best-effort clone: copy present user mappings, ignore kernel half.
+ // Best-effort clone: copy present user mappings (USER PTEs), ignore kernel half.
for (uint32_t pdi = 0; pdi < 768; pdi++) {
uint32_t pde = src_pd[pdi];
if (!(pde & X86_PTE_PRESENT)) continue;
- // Skip if this PDE looks like a kernel mapping (shouldn't happen for pdi<768).
- if (boot_pd_virt[pdi] == pde) continue;
-
uint32_t src_pt_phys = pde & 0xFFFFF000;
uint32_t* src_pt = (uint32_t*)P2V(src_pt_phys);
for (uint32_t pti = 0; pti < 1024; pti++) {
uint32_t pte = src_pt[pti];
if (!(pte & X86_PTE_PRESENT)) continue;
+ if ((pte & X86_PTE_USER) == 0) continue;
const uint32_t x86_flags = pte & 0xFFF;
// Derive VMM flags.
return 0;
}
+ uint32_t src_frame = pte & 0xFFFFF000;
+
uintptr_t va = ((uintptr_t)pdi << 22) | ((uintptr_t)pti << 12);
vmm_as_map_page(new_as, (uint64_t)(uintptr_t)dst_frame, (uint64_t)va, flags);
- // Copy contents by temporarily switching address spaces.
+ // Copy contents by mapping frames into a temporary kernel VA under each address space.
uintptr_t old_as = hal_cpu_get_address_space();
-
vmm_as_activate(src_as);
- memcpy(tmp, (const void*)va, 4096);
+ vmm_map_page((uint64_t)src_frame, (uint64_t)TMP_MAP_VA, VMM_FLAG_PRESENT | VMM_FLAG_RW);
+ memcpy(tmp, (const void*)TMP_MAP_VA, 4096);
+ vmm_unmap_page((uint64_t)TMP_MAP_VA);
vmm_as_activate(new_as);
- memcpy((void*)va, tmp, 4096);
-
+ vmm_map_page((uint64_t)(uintptr_t)dst_frame, (uint64_t)TMP_MAP_VA, VMM_FLAG_PRESENT | VMM_FLAG_RW);
+ memcpy((void*)TMP_MAP_VA, tmp, 4096);
+ vmm_unmap_page((uint64_t)TMP_MAP_VA);
vmm_as_activate(old_as);
+
}
}
if (!buf) return NULL;
uint32_t rd = vfs_read(on->lower, 0, len, buf);
if (rd != len) {
- if (buf) kfree(buf);
+ kfree(buf);
return NULL;
}
}
proc->pid = next_pid++;
proc->parent_pid = current_process ? current_process->pid : 0;
+ proc->session_id = current_process ? current_process->session_id : proc->pid;
+ proc->pgrp_id = current_process ? current_process->pgrp_id : proc->pid;
proc->state = PROCESS_READY;
proc->addr_space = child_as;
proc->wake_at_tick = 0;
kernel_proc->pid = 0;
kernel_proc->parent_pid = 0;
+ kernel_proc->session_id = 0;
+ kernel_proc->pgrp_id = 0;
kernel_proc->state = PROCESS_RUNNING;
kernel_proc->wake_at_tick = 0;
kernel_proc->addr_space = hal_cpu_get_address_space();
proc->pid = next_pid++;
proc->parent_pid = current_process ? current_process->pid : 0;
+ proc->session_id = current_process ? current_process->session_id : proc->pid;
+ proc->pgrp_id = current_process ? current_process->pgrp_id : proc->pid;
proc->state = PROCESS_READY;
proc->addr_space = kernel_as ? kernel_as : (current_process ? current_process->addr_space : 0);
proc->wake_at_tick = 0;
if (!regs) return -EINVAL;
if (!current_process) return -EINVAL;
- uintptr_t child_as = vmm_as_clone_user(current_process->addr_space);
+ uintptr_t src_as = hal_cpu_get_address_space() & ~(uintptr_t)0xFFFU;
+ if (current_process->addr_space != src_as) {
+ current_process->addr_space = src_as;
+ }
+
+ uintptr_t child_as = vmm_as_clone_user(src_as);
if (!child_as) return -ENOMEM;
struct registers child_regs = *regs;
total += rd;
if (rd < chunk) break;
}
+
return (int)total;
}
+ if (f->node->flags != FS_FILE) return -ESPIPE;
+ if (!f->node->read) return -ESPIPE;
+
uint8_t kbuf[256];
uint32_t total = 0;
while (total < len) {
return -EFAULT;
}
- if (f->node->flags == FS_FILE) {
- f->offset += rd;
- }
+ f->offset += rd;
total += rd;
-
if (rd < chunk) break;
}
total += wr;
if (wr < chunk) break;
}
-
return (int)total;
}
+static int syscall_ioctl_impl(int fd, uint32_t cmd, void* user_arg) {
+ struct file* f = fd_get(fd);
+ if (!f || !f->node) return -EBADF;
+
+ fs_node_t* n = f->node;
+ if (n->flags != FS_CHARDEVICE) return -ENOTTY;
+ if (n->inode != 3) return -ENOTTY;
+
+ return tty_ioctl(cmd, user_arg);
+}
+
+static int syscall_setsid_impl(void) {
+ if (!current_process) return -EINVAL;
+ if (current_process->pid != 0 && current_process->pgrp_id == current_process->pid) return -EPERM;
+ current_process->session_id = current_process->pid;
+ current_process->pgrp_id = current_process->pid;
+ return (int)current_process->session_id;
+}
+
+static int syscall_setpgid_impl(int pid, int pgid) {
+ if (!current_process) return -EINVAL;
+ if (pid != 0 && pid != (int)current_process->pid) return -EINVAL;
+ if (pgid == 0) pgid = (int)current_process->pid;
+ if (pgid < 0) return -EINVAL;
+ current_process->pgrp_id = (uint32_t)pgid;
+ return 0;
+}
+
+static int syscall_getpgrp_impl(void) {
+ if (!current_process) return 0;
+ return (int)current_process->pgrp_id;
+}
+
static void syscall_handler(struct registers* regs) {
uint32_t syscall_no = regs->eax;
return;
}
+ if (syscall_no == SYSCALL_IOCTL) {
+ int fd = (int)regs->ebx;
+ uint32_t cmd = (uint32_t)regs->ecx;
+ void* arg = (void*)regs->edx;
+ regs->eax = (uint32_t)syscall_ioctl_impl(fd, cmd, arg);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_SETSID) {
+ regs->eax = (uint32_t)syscall_setsid_impl();
+ return;
+ }
+
+ if (syscall_no == SYSCALL_SETPGID) {
+ int pid = (int)regs->ebx;
+ int pgid = (int)regs->ecx;
+ regs->eax = (uint32_t)syscall_setpgid_impl(pid, pgid);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_GETPGRP) {
+ regs->eax = (uint32_t)syscall_getpgrp_impl();
+ return;
+ }
+
regs->eax = (uint32_t)-ENOSYS;
}
static uint32_t waitq_head = 0;
static uint32_t waitq_tail = 0;
+static uint32_t tty_lflag = TTY_ICANON | TTY_ECHO;
+
static int canon_empty(void) {
return canon_head == canon_tail;
}
}
}
+enum {
+ TTY_TCGETS = 0x5401,
+ TTY_TCSETS = 0x5402,
+ TTY_TIOCGPGRP = 0x540F,
+ TTY_TIOCSPGRP = 0x5410,
+};
+
+int tty_ioctl(uint32_t cmd, void* user_arg) {
+ if (!user_arg) return -EFAULT;
+
+ if (cmd == TTY_TIOCGPGRP) {
+ if (user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT;
+ int fg = 0;
+ if (copy_to_user(user_arg, &fg, sizeof(fg)) < 0) return -EFAULT;
+ return 0;
+ }
+
+ if (cmd == TTY_TIOCSPGRP) {
+ if (user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT;
+ int fg = 0;
+ if (copy_from_user(&fg, user_arg, sizeof(fg)) < 0) return -EFAULT;
+ if (fg != 0) return -EINVAL;
+ return 0;
+ }
+
+ if (user_range_ok(user_arg, sizeof(struct termios)) == 0) return -EFAULT;
+
+ if (cmd == TTY_TCGETS) {
+ struct termios t;
+ uintptr_t flags = spin_lock_irqsave(&tty_lock);
+ t.c_lflag = tty_lflag;
+ spin_unlock_irqrestore(&tty_lock, flags);
+ if (copy_to_user(user_arg, &t, sizeof(t)) < 0) return -EFAULT;
+ return 0;
+ }
+
+ if (cmd == TTY_TCSETS) {
+ struct termios t;
+ if (copy_from_user(&t, user_arg, sizeof(t)) < 0) return -EFAULT;
+ uintptr_t flags = spin_lock_irqsave(&tty_lock);
+ tty_lflag = t.c_lflag & (TTY_ICANON | TTY_ECHO);
+ spin_unlock_irqrestore(&tty_lock, flags);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
void tty_input_char(char c) {
uintptr_t flags = spin_lock_irqsave(&tty_lock);
+ uint32_t lflag = tty_lflag;
+
+ if ((lflag & TTY_ICANON) == 0) {
+ if (c == '\r') c = '\n';
+ canon_push(c);
+ tty_wake_one();
+ if (lflag & TTY_ECHO) {
+ uart_put_char(c);
+ }
+ spin_unlock_irqrestore(&tty_lock, flags);
+ return;
+ }
if (c == '\b') {
if (line_len > 0) {
line_len--;
- uart_print("\b \b");
+ if (lflag & TTY_ECHO) {
+ uart_print("\b \b");
+ }
}
spin_unlock_irqrestore(&tty_lock, flags);
return;
if (c == '\r') c = '\n';
if (c == '\n') {
- uart_put_char('\n');
+ if (lflag & TTY_ECHO) {
+ uart_put_char('\n');
+ }
for (uint32_t i = 0; i < line_len; i++) {
canon_push(line_buf[i]);
if (c >= ' ' && c <= '~') {
if (line_len + 1 < sizeof(line_buf)) {
line_buf[line_len++] = c;
- uart_put_char(c);
+ if (lflag & TTY_ECHO) {
+ uart_put_char(c);
+ }
}
}
SYSCALL_POLL = 18,
SYSCALL_KILL = 19,
SYSCALL_SELECT = 20,
+ SYSCALL_IOCTL = 21,
+ SYSCALL_SETSID = 22,
+ SYSCALL_SETPGID = 23,
+ SYSCALL_GETPGRP = 24,
+};
+
+enum {
+ TCGETS = 0x5401,
+ TCSETS = 0x5402,
+ TIOCGPGRP = 0x540F,
+ TIOCSPGRP = 0x5410,
+};
+
+enum {
+ ICANON = 0x0001,
+ ECHO = 0x0002,
+};
+
+struct termios {
+ uint32_t c_lflag;
};
struct pollfd {
return ret;
}
+static int sys_ioctl(int fd, uint32_t cmd, void* arg) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_IOCTL), "b"(fd), "c"(cmd), "d"(arg)
+ : "memory"
+ );
+ return ret;
+}
+
static int sys_kill(int pid, int sig) {
int ret;
__asm__ volatile(
return ret;
}
+static int sys_setsid(void) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_SETSID)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_setpgid(int pid, int pgid) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_SETPGID), "b"(pid), "c"(pgid)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_getpgrp(void) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_GETPGRP)
+ : "memory"
+ );
+ return ret;
+}
+
static int sys_getpid(void) {
int ret;
__asm__ volatile(
(uint32_t)(sizeof("[init] select(pipe) OK\n") - 1));
}
+ {
+ int fd = sys_open("/dev/tty", 0);
+ if (fd < 0) {
+ sys_write(1, "[init] ioctl(/dev/tty) open failed\n",
+ (uint32_t)(sizeof("[init] ioctl(/dev/tty) open failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int fg = -1;
+ if (sys_ioctl(fd, TIOCGPGRP, &fg) < 0 || fg != 0) {
+ sys_write(1, "[init] ioctl TIOCGPGRP failed\n",
+ (uint32_t)(sizeof("[init] ioctl TIOCGPGRP failed\n") - 1));
+ sys_exit(1);
+ }
+
+ fg = 0;
+ if (sys_ioctl(fd, TIOCSPGRP, &fg) < 0) {
+ sys_write(1, "[init] ioctl TIOCSPGRP failed\n",
+ (uint32_t)(sizeof("[init] ioctl TIOCSPGRP failed\n") - 1));
+ sys_exit(1);
+ }
+
+ fg = 1;
+ if (sys_ioctl(fd, TIOCSPGRP, &fg) >= 0) {
+ sys_write(1, "[init] ioctl TIOCSPGRP expected fail\n",
+ (uint32_t)(sizeof("[init] ioctl TIOCSPGRP expected fail\n") - 1));
+ sys_exit(1);
+ }
+
+ struct termios oldt;
+ if (sys_ioctl(fd, TCGETS, &oldt) < 0) {
+ sys_write(1, "[init] ioctl TCGETS failed\n",
+ (uint32_t)(sizeof("[init] ioctl TCGETS failed\n") - 1));
+ sys_exit(1);
+ }
+
+ struct termios t = oldt;
+ t.c_lflag &= ~(uint32_t)(ECHO | ICANON);
+ if (sys_ioctl(fd, TCSETS, &t) < 0) {
+ sys_write(1, "[init] ioctl TCSETS failed\n",
+ (uint32_t)(sizeof("[init] ioctl TCSETS failed\n") - 1));
+ sys_exit(1);
+ }
+
+ struct termios chk;
+ if (sys_ioctl(fd, TCGETS, &chk) < 0) {
+ sys_write(1, "[init] ioctl TCGETS2 failed\n",
+ (uint32_t)(sizeof("[init] ioctl TCGETS2 failed\n") - 1));
+ sys_exit(1);
+ }
+
+ if ((chk.c_lflag & (uint32_t)(ECHO | ICANON)) != 0) {
+ sys_write(1, "[init] ioctl verify failed\n",
+ (uint32_t)(sizeof("[init] ioctl verify failed\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_ioctl(fd, TCSETS, &oldt);
+ (void)sys_close(fd);
+
+ sys_write(1, "[init] ioctl(/dev/tty) OK\n",
+ (uint32_t)(sizeof("[init] ioctl(/dev/tty) OK\n") - 1));
+ }
+
{
int fd = sys_open("/dev/null", 0);
if (fd < 0) {
sys_write(1, "[init] poll(/dev/null) OK\n",
(uint32_t)(sizeof("[init] poll(/dev/null) OK\n") - 1));
}
+
+ {
+ sys_write(1, "[init] setsid test: before fork\n",
+ (uint32_t)(sizeof("[init] setsid test: before fork\n") - 1));
+ int pid = sys_fork();
+ if (pid < 0) {
+ sys_write(1, "[init] setsid test fork failed\n",
+ (uint32_t)(sizeof("[init] setsid test fork failed\n") - 1));
+ sys_exit(1);
+ }
+
+ if (pid == 0) {
+ sys_write(1, "[init] setsid test: child start\n",
+ (uint32_t)(sizeof("[init] setsid test: child start\n") - 1));
+ int me = sys_getpid();
+ int sid = sys_setsid();
+ if (sid != me) sys_exit(2);
+
+ int pg = sys_getpgrp();
+ if (pg != me) sys_exit(3);
+
+ int newpg = me + 1;
+ if (sys_setpgid(0, newpg) < 0) sys_exit(4);
+ if (sys_getpgrp() != newpg) sys_exit(5);
+
+ sys_exit(0);
+ }
+
+ sys_write(1, "[init] setsid test: parent waitpid\n",
+ (uint32_t)(sizeof("[init] setsid test: parent waitpid\n") - 1));
+ int st = 0;
+ int wp = sys_waitpid(pid, &st, 0);
+ if (wp != pid || st != 0) {
+ sys_write(1, "[init] setsid/setpgid/getpgrp failed\n",
+ (uint32_t)(sizeof("[init] setsid/setpgid/getpgrp failed\n") - 1));
+ sys_exit(1);
+ }
+
+ sys_write(1, "[init] setsid/setpgid/getpgrp OK\n",
+ (uint32_t)(sizeof("[init] setsid/setpgid/getpgrp OK\n") - 1));
+ }
}
fd = sys_open("/tmp/hello.txt", 0);