diff --git a/kernel/pty/pty.cpp b/kernel/pty/pty.cpp index ea66ab14..d36fe95d 100644 --- a/kernel/pty/pty.cpp +++ b/kernel/pty/pty.cpp @@ -30,13 +30,6 @@ struct linux_termios { uint8_t c_cc[19]; }; -struct linux_winsize { - uint16_t ws_row; - uint16_t ws_col; - uint16_t ws_xpixel; - uint16_t ws_ypixel; -}; - __PRIVILEGED_BSS static uint32_t g_next_pty_id; __PRIVILEGED_CODE void pty_channel::ref_destroy(pty_channel* self) { @@ -237,29 +230,41 @@ static int32_t do_tcsets(pty_channel* chan, uint64_t arg) { return resource::OK; } -static int32_t do_tiocgwinsz(uint64_t arg) { - linux_winsize w = { 24, 80, 0, 0 }; +static int32_t do_tiocgwinsz(pty_channel* chan, uint64_t arg) { int32_t rc = mm::uaccess::copy_to_user( - reinterpret_cast(arg), &w, sizeof(w)); + reinterpret_cast(arg), &chan->m_winsize, sizeof(chan->m_winsize)); return (rc == mm::uaccess::OK) ? resource::OK : resource::ERR_INVAL; } +static int32_t do_tiocswinsz(pty_channel* chan, uint64_t arg) { + pty_winsize w = {}; + int32_t rc = mm::uaccess::copy_from_user( + &w, reinterpret_cast(arg), sizeof(w)); + if (rc != mm::uaccess::OK) { + return resource::ERR_INVAL; + } + + chan->m_winsize = w; + return resource::OK; +} + static int32_t pty_termios_ioctl(pty_channel* chan, uint32_t cmd, uint64_t arg) { switch (cmd) { case TCGETS: return do_tcgets(chan, arg); case TCSETS: case TCSETSW: case TCSETSF: return do_tcsets(chan, arg); - case TIOCGWINSZ: return do_tiocgwinsz(arg); - case TIOCSWINSZ: return resource::OK; + case TIOCGWINSZ: return do_tiocgwinsz(chan, arg); + case TIOCSWINSZ: return do_tiocswinsz(chan, arg); case terminal::STLX_TCSETS_RAW: case terminal::STLX_TCSETS_COOKED: return terminal::ld_set_mode(&chan->m_ld, cmd); default: return resource::ERR_INVAL; } } -static int32_t pty_slave_ioctl( +// Termios and winsize state is channel-level, shared by both endpoints +static int32_t pty_ioctl( resource::resource_object* obj, uint32_t cmd, uint64_t arg ) { if (!obj || !obj->impl) { @@ -301,7 +306,7 @@ static const resource::resource_ops g_pty_master_ops = { pty_master_read, pty_master_write, pty_master_close, - nullptr, + pty_ioctl, nullptr, nullptr, nullptr, @@ -319,7 +324,7 @@ static const resource::resource_ops g_pty_slave_ops = { pty_slave_read, pty_slave_write, pty_slave_close, - pty_slave_ioctl, + pty_ioctl, nullptr, nullptr, nullptr, @@ -364,6 +369,7 @@ __PRIVILEGED_CODE int32_t create_pair( chan->m_echo = { pty_echo_fn, chan.ptr() }; chan->m_id = __atomic_fetch_add(&g_next_pty_id, 1, __ATOMIC_RELAXED); chan->m_oflags = PTY_OFLAG_ONLCR; + chan->m_winsize = { 24, 80, 0, 0 }; auto* ep_master = heap::kalloc_new(); if (!ep_master) { diff --git a/kernel/pty/pty.h b/kernel/pty/pty.h index e1f80605..89fb8be1 100644 --- a/kernel/pty/pty.h +++ b/kernel/pty/pty.h @@ -18,6 +18,14 @@ constexpr size_t PTY_RING_CAPACITY = 4096; /** Output processing flags (applied in the slave→master direction). */ constexpr uint32_t PTY_OFLAG_ONLCR = (1u << 0); // map NL → CR+NL +/** Terminal geometry, Linux winsize layout. */ +struct pty_winsize { + uint16_t ws_row; + uint16_t ws_col; + uint16_t ws_xpixel; + uint16_t ws_ypixel; +}; + struct pty_channel : rc::ref_counted { ring_buffer* m_input_rb; // master write -> ld -> slave read ring_buffer* m_output_rb; // slave write -> master read @@ -25,6 +33,7 @@ struct pty_channel : rc::ref_counted { terminal::echo_target m_echo; uint32_t m_id; uint32_t m_oflags; // output processing flags + pty_winsize m_winsize; // set via TIOCSWINSZ from either end /** @note Privilege: **required** */ __PRIVILEGED_CODE static void ref_destroy(pty_channel* self);