ソースを参照

feat: poll() and llseek() for busybox shell

update init_script so that we use busybox shell

we now support .profile so we don't need to type busybox ls now!
greatbridf 11 ヶ月 前
コミット
7efa80fa12
6 ファイル変更145 行追加3 行削除
  1. 35 0
      gblibc/include/poll.h
  2. 2 0
      gblibc/include/sys/types.h
  3. 3 0
      include/kernel/tty.hpp
  4. 15 1
      init_script.sh
  5. 71 0
      src/kernel/syscall.cpp
  6. 19 2
      src/kernel/tty.cpp

+ 35 - 0
gblibc/include/poll.h

@@ -0,0 +1,35 @@
+#ifndef __GBLIBC_POLL_H_
+#define __GBLIBC_POLL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int nfds_t;
+
+#define POLLIN          0x0001          /* any readable data available */
+#define POLLPRI         0x0002          /* OOB/Urgent readable data */
+#define POLLOUT         0x0004          /* file descriptor is writeable */
+#define POLLRDNORM      0x0040          /* non-OOB/URG data available */
+#define POLLWRNORM      POLLOUT         /* no write type differentiation */
+#define POLLRDBAND      0x0080          /* OOB/Urgent readable data */
+#define POLLWRBAND      0x0100          /* OOB/Urgent data can be written */
+
+#define POLLERR         0x0008          /* some poll error occurred */
+#define POLLHUP         0x0010          /* file descriptor was "hung up" */
+#define POLLNVAL        0x0020          /* requested events "invalid" */
+
+#define POLLSTANDARD    (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|\
+	                 POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
+
+struct pollfd {
+	int     fd;
+	short   events;
+	short   revents;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 2 - 0
gblibc/include/sys/types.h

@@ -19,6 +19,8 @@ typedef unsigned long nlink_t;
 typedef uint64_t ino64_t;
 typedef int64_t off64_t;
 
+typedef off64_t loff_t;
+
 #ifdef __cplusplus
 }
 #endif

+ 3 - 0
include/kernel/tty.hpp

@@ -38,6 +38,9 @@ public:
 
     void clear_read_buf(void);
 
+    // TODO: formal poll support
+    int poll();
+
     constexpr void set_pgrp(pid_t pgid)
     {
         fg_pgroup = pgid;

+ 15 - 1
init_script.sh

@@ -22,5 +22,19 @@ cat > /etc/group <<EOF
 root:x:0:root
 EOF
 
-exec /mnt/init /mnt/busybox_ sh \
+cat > /root/.profile <<EOF
+export PATH=/mnt
+export HOME=/root
+
+export BUSYBOX=/mnt/busybox
+
+alias ls="$BUSYBOX ls "
+alias ll="$BUSYBOX ls -l "
+alias la="$BUSYBOX ls -la "
+
+alias cat="$BUSYBOX cat "
+alias clear="$BUSYBOX clear "
+EOF
+
+exec /mnt/init /mnt/busybox sh -l \
     < /dev/console > /dev/console 2> /dev/console

+ 71 - 0
src/kernel/syscall.cpp

@@ -3,6 +3,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <poll.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -1065,6 +1066,74 @@ int _syscall_mknod(interrupt_stack* data)
     return fs::vfs_mknode(dent, filename.c_str(), mode, dev);
 }
 
+int _syscall_poll(interrupt_stack* data)
+{
+    SYSCALL_ARG1(struct pollfd* __user, fds);
+    SYSCALL_ARG2(nfds_t, nfds);
+    SYSCALL_ARG3(int, timeout);
+
+    if (nfds == 0)
+        return 0;
+
+    if (nfds > 1) {
+        NOT_IMPLEMENTED;
+        return -EINVAL;
+    }
+
+    // TODO: handle timeout
+    // if (timeout != -1) {
+    // }
+
+    // for now, we will poll from console only
+    int ret = console->poll();
+    if (ret < 0)
+        return ret;
+
+    fds[0].revents = POLLIN;
+    return ret;
+
+    // TODO: check address validity
+    // TODO: poll multiple fds and other type of files
+    // for (nfds_t i = 0; i < nfds; ++i) {
+    //     auto& pfd = fds[i];
+
+    //     auto* file = current_process->files[pfd.fd];
+    //     if (!file || !S_ISCHR(file->mode))
+    //         return -EINVAL;
+
+    //     // poll the fds
+    // }
+    //
+    // return 0;
+}
+
+int _syscall_llseek(interrupt_stack* data)
+{
+    SYSCALL_ARG1(unsigned int, fd);
+    SYSCALL_ARG2(unsigned long, offset_high);
+    SYSCALL_ARG3(unsigned long, offset_low);
+    SYSCALL_ARG4(loff_t*, result);
+    SYSCALL_ARG5(unsigned int, whence);
+
+    auto* file = current_process->files[fd];
+    if (!file)
+        return -EBADF;
+
+    if (!result)
+        return -EFAULT;
+
+    if (offset_high != 0 || offset_low != 0 || whence != SEEK_END) {
+        NOT_IMPLEMENTED;
+        return -EINVAL;
+    }
+
+    // the function is used for check file size for now
+    // we return all 0
+    *result = 0;
+
+    return 0;
+}
+
 extern "C" void syscall_entry(
     interrupt_stack* data,
     mmx_registers* mmxregs)
@@ -1124,9 +1193,11 @@ void init_syscall(void)
     syscall_handlers[0x72] = _syscall_wait4;
     syscall_handlers[0x7a] = _syscall_newuname;
     syscall_handlers[0x84] = _syscall_getpgid;
+    syscall_handlers[0x8c] = _syscall_llseek;
     syscall_handlers[0x8d] = _syscall_getdents;
     syscall_handlers[0x92] = _syscall_writev;
     syscall_handlers[0x93] = _syscall_getsid;
+    syscall_handlers[0xa8] = _syscall_poll;
     syscall_handlers[0xac] = _syscall_prctl;
     syscall_handlers[0xae] = _syscall_rt_sigaction;
     syscall_handlers[0xaf] = _syscall_rt_sigprocmask;

+ 19 - 2
src/kernel/tty.cpp

@@ -54,6 +54,19 @@ void tty::print(const char* str)
         this->putchar(*(str++));
 }
 
+int tty::poll()
+{
+    types::lock_guard lck(this->mtx_buf);
+    if (this->buf.empty()) {
+        bool interrupted = this->waitlist.wait(this->mtx_buf);
+
+        if (interrupted)
+            return -EINTR;
+    }
+
+    return 1;
+}
+
 size_t tty::read(char* buf, size_t buf_size, size_t n)
 {
     n = std::max(buf_size, n);
@@ -133,8 +146,9 @@ void tty::_real_commit_char(int c)
         if (TERMIOS_LSET(this->termio, ECHONL) || TERMIOS_LSET(this->termio, ECHO))
             this->_echo_char(c);
 
-        if (TERMIOS_LSET(this->termio, ICANON))
-            this->waitlist.notify_all();
+        // if ICANON is set, we notify all waiting processes
+        // if ICANON is not set, since there are data ready, we notify as well
+        this->waitlist.notify_all();
 
         break;
 
@@ -144,6 +158,9 @@ void tty::_real_commit_char(int c)
         if (TERMIOS_LSET(this->termio, ECHO))
             this->_echo_char(c);
 
+        if (!TERMIOS_LSET(this->termio, ICANON))
+            this->waitlist.notify_all();
+
         break;
     }
 }