**※:由于在`-O2`模式下,GCC会进行CSE优化,这导致LunaixOS会出现一些非常奇怪、离谱的bug,从而影响到基本运行。具体原因有待调查。**
+### 4.4 设置内核启动参数
+
+在 make 的时候通过`CMDLINE`变量可以设置内核启动参数列表。该列表可以包含多个参数,通过一个或多个空格来分割。每个参数可以为键值对 `<key>=<val>` 或者是开关标志位 `<flag>`。目前 Lunaix 支持以下参数:
+
++ `console=<dev>` 设置系统终端的输入输出设备(tty设备)。其中 `<dev>` 是设备文件路径 (注意,这里的设备文件路径是针对Lunaix,而非Linux)。关于LunaixOS设备文件系统的介绍可参考 Lunaix Wiki(WIP)
+
+如果`CMDLINE`未指定,则将会载入默认参数:
+
+```
+console=/dev/ttyFB0
+```
+
+其中,`/dev/ttyFB0` 指向基于VGA文本模式的tty设备,也就是平时启动QEMU时看到的黑色窗口。
+
+当然,读者也可以使用 `/dev/ttyS0` 来作为默认tty设备,来验证 Lunaix 的灵活性与兼容性。该路径指向第一个串口设备。可以通过telnet协议在`12345`端口上进行访问——端口号可以自行修改QEMU启动参数(位于:`makeinc/qemu.mkinc`)来变更。
+
+**注意:** 根据操作系统和键盘布局的不同,telnet客户端对一些关键键位的映射(如退格,回车)可能有所差别(如某些版本的Linux会将退格键映射为`0x7f`,也就是ASCII的`<DEL>`字符,而非我们熟知`0x08`)。如果读者想要通过串口方式把玩Lunaix,请修改`usr/init/init.c`里面的终端初始化代码,将`VERASE`设置为正确的映射(修改方式可以参考 POSIX termios 的使用方式。由于Lunaix的终端接口的实现是完全兼容POSIX的,读者可以直接去查阅Linux自带的帮助`man termios`,无需作任何的转换)
+
## 5. 运行,分支以及 Issue
### 5.1 虚拟磁盘(非必须)
timeout=0
menuentry "$_OS_NAME" {
- multiboot /boot/kernel.bin console=/dev/vcon
+ multiboot /boot/kernel.bin $KCMD
module --nounzip /boot/modksyms modksyms
}
\ No newline at end of file
#!/usr/bin/bash
-export _OS_NAME=$1
-
-cat GRUB_TEMPLATE | envsubst > "$2"
\ No newline at end of file
+cat GRUB_TEMPLATE | envsubst > "$1"
\ No newline at end of file
#include <sys/mm/mempart.h>
#include <hal/serial.h>
+#include <hal/term.h>
#define lock_sdev(sdev) device_lock((sdev)->dev)
#define unlock_sdev(sdev) device_unlock((sdev)->dev)
}
static int
-__serial_read(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_read(struct device* dev, void* buf, off_t fpos, size_t len)
{
- return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], len);
+ return serial_readbuf(serial_device(dev), (u8_t*)buf, len);
}
static int
-__serial_read_async(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_read_async(struct device* dev, void* buf, off_t fpos, size_t len)
{
return serial_readbuf_nowait(
- serial_device(dev), &((u8_t*)buf)[offset], len);
+ serial_device(dev), (u8_t*)buf, len);
}
static int
-__serial_read_page(struct device* dev, void* buf, size_t offset)
+__serial_read_page(struct device* dev, void* buf, off_t fpos)
{
- return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
+ return serial_readbuf(serial_device(dev), (u8_t*)buf, MEM_PAGE);
}
static int
-__serial_write(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_write(struct device* dev, void* buf, off_t fpos, size_t len)
{
- return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], len);
+ return serial_writebuf(serial_device(dev), (u8_t*)buf, len);
}
static int
-__serial_write_async(struct device* dev, void* buf, size_t offset, size_t len)
+__serial_write_async(struct device* dev, void* buf, off_t fpos, size_t len)
{
return serial_writebuf_nowait(
- serial_device(dev), &((u8_t*)buf)[offset], len);
+ serial_device(dev), (u8_t*)buf, len);
}
static int
-__serial_write_page(struct device* dev, void* buf, size_t offset)
+__serial_write_page(struct device* dev, void* buf, off_t fpos)
{
- return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
+ return serial_writebuf(serial_device(dev), (u8_t*)buf, MEM_PAGE);
}
static int
return sdev->dev->poll_evflags;
}
+static void sdev_execmd(struct serial_dev* sdev, u32_t req, ...)
+{
+ va_list args;
+ va_start(args, req);
+
+ sdev->exec_cmd(sdev, req, args);
+
+ va_end(args);
+}
+
+static void
+__serial_set_speed(struct device* dev, speed_t speed)
+{
+ struct serial_dev* sdev = serial_device(dev);
+ lock_sdev(sdev);
+
+ sdev_execmd(sdev, SERIO_SETBRDIV, speed);
+
+ unlock_sdev(sdev);
+}
+
+static void
+__serial_set_cntrl_mode(struct device* dev, tcflag_t cflag)
+{
+ struct serial_dev* sdev = serial_device(dev);
+ lock_sdev(sdev);
+
+ sdev_execmd(sdev, SERIO_SETCNTRLMODE, cflag);
+
+ unlock_sdev(sdev);
+}
+
#define RXBUF_SIZE 512
struct serial_dev*
dev->ops.write_page = __serial_write_page;
dev->ops.exec_cmd = __serial_exec_command;
dev->ops.poll = __serial_poll_event;
-
+
sdev->dev = dev;
dev->underlay = sdev;
+ struct termport_capability* tp_cap =
+ new_capability(TERMPORT_CAP, struct termport_capability);
+ tp_cap->set_speed = __serial_set_speed;
+ tp_cap->set_cntrl_mode = __serial_set_cntrl_mode;
+
waitq_init(&sdev->wq_rxdone);
waitq_init(&sdev->wq_txdone);
rbuffer_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE);
llist_append(&serial_devs, &sdev->sdev_list);
+
+ device_grant_capability(dev, cap_meta(tp_cap));
- register_device(dev, class, "port%s%d", if_ident, class->variant);
+ register_device(dev, class, "serial%d", class->variant);
- sdev->at_term = term_create(dev, if_ident);
+ term_create(dev, if_ident);
class->variant++;
return sdev;
#define UART_rIE_ELSI (1 << 2)
#define UART_rIE_EDSSI (1 << 3)
+#define UART_rLC_STOPB (1 << 2)
+#define UART_rLC_PAREN (1 << 3)
+#define UART_rLC_PAREVN (1 << 4)
+#define UART_rLC_SETBRK (1 << 6)
+
#define UART_rLS_THRE (1 << 5)
#define UART_rLS_DR 1
#define UART_rLS_BI (1 << 4)
u8_t rie;
u8_t rfc;
u8_t rmc;
+ u8_t rlc;
} cntl_save;
u32_t (*read_reg)(struct uart16550* uart, ptr_t regoff);
static inline void
uart_setie(struct uart16550* uart)
{
- uart->write_reg(uart, UART_rIE, uart->cntl_save.rie | 1);
+ uart->write_reg(uart, UART_rIE, uart->cntl_save.rie);
+}
+
+static inline void
+uart_setlc(struct uart16550* uart)
+{
+ uart->write_reg(uart, UART_rLC, uart->cntl_save.rlc);
}
struct uart16550*
#include <lunaix/status.h>
#include <usr/lunaix/serial.h>
+#include <usr/lunaix/term.h>
#include "16550.h"
return RXTX_DONE;
}
+static void
+uart_set_control_mode(struct uart16550* uart, tcflag_t cflags)
+{
+ uart->cntl_save.rie &= ~(UART_rIE_ERBFI | UART_rIE_EDSSI);
+ uart->cntl_save.rie |= (!(cflags & _CLOCAL)) * UART_rIE_EDSSI;
+ uart->cntl_save.rie |= (!!(cflags & _CREAD)) * UART_rIE_ERBFI;
+ uart_setie(uart);
+
+ uart->cntl_save.rlc &= ~(UART_rLC_STOPB | UART_rLC_PAREN | UART_rLC_PAREVN | 0b11);
+ uart->cntl_save.rlc |= (!!(cflags & _CSTOPB)) * UART_rLC_STOPB;
+ uart->cntl_save.rlc |= (!!(cflags & _CPARENB)) * UART_rLC_PAREN;
+ uart->cntl_save.rlc |= (!(cflags & _CPARODD)) * UART_rLC_PAREVN;
+ uart->cntl_save.rlc |= (cflags & _CSZ_MASK) >> 2;
+ uart_setlc(uart);
+}
+
int
uart_general_exec_cmd(struct serial_dev* sdev, u32_t req, va_list args)
{
case SERIO_RXDA:
uart_clrie(uart);
break;
+ case SERIO_SETBRDIV:
+ // TODO
+ break;
+ case SERIO_SETCNTRLMODE:
+ uart_set_control_mode(uart, va_arg(args, tcflag_t));
+ break;
default:
return ENOTSUP;
}
serial_accept_buffer(pos->sdev, tmpbuf, i);
serial_accept_one(pos->sdev, 0);
-
+
serial_end_recv(pos->sdev);
}
assert(device_addalias(NULL, dev_meta(dev), "tty"));
- // TODO implement capability list
- // for now, we just assume the parameter always pointed to valid device
+ if (!device_get_capability(dev, TERMIOS_CAP)) {
+ FATAL("not a terminal device: %s", console_dev);
+ }
+
+ INFO("system console: %s", console_dev);
+
sysconsole = dev;
}
lunaix_initfn(setup_default_tty, call_on_boot);
\ No newline at end of file
}
}
+ if (out) {
+ goto do_out;
+ }
+
if (c == '\n') {
latest_eol = cooked->ptr + 1;
- if (!out && (_lf & _ECHONL)) {
+ if ((_lf & _ECHONL)) {
rbuffer_put(output, c);
}
}
- if (out) {
- goto do_out;
- }
-
// For input procesing
if (c == '\n' || c == EOL) {
} else if (c == SUSP) {
raise_sig(tdev, lbuf, SIGSTOP);
} else if (c == ERASE) {
- rbuffer_erase(cooked);
+ if (!rbuffer_erase(cooked))
+ continue;
} else if (c == KILL) {
// TODO shrink the rbuffer
} else {
}
}
- if (!rbuffer_empty(output) && !(_lf & _NOFLSH)) {
+ if (!out && !rbuffer_empty(output) && !(_lf & _NOFLSH)) {
term_flush(tdev);
}
break;
}
case TDEV_TCGETATTR: {
- struct _termios* tios = va_arg(args, struct _termios*);
- *tios = (struct _termios){.c_oflag = term->oflags,
+ struct termios* tios = va_arg(args, struct termios*);
+ *tios = (struct termios){.c_oflag = term->oflags,
.c_iflag = term->iflags,
- .c_lflag = term->lflags};
+ .c_lflag = term->lflags,
+ .c_cflag = term->cflags};
memcpy(tios->c_cc, term->cc, _NCCS * sizeof(cc_t));
tios->c_baud = term->iospeed;
} break;
case TDEV_TCSETATTR: {
- struct _termios* tios = va_arg(args, struct _termios*);
+ struct termios* tios = va_arg(args, struct termios*);
term->iflags = tios->c_iflag;
term->oflags = tios->c_oflag;
term->lflags = tios->c_lflag;
memcpy(term->cc, tios->c_cc, _NCCS * sizeof(cc_t));
+ tcflag_t old_cf = term->cflags;
+ term->cflags = tios->c_cflag;
+
+ if (!term->tp_cap) {
+ goto done;
+ }
+
if (tios->c_baud != term->iospeed) {
term->iospeed = tios->c_baud;
- if (!term->chdev_ops.set_speed) {
- goto done;
- }
- term->chdev_ops.set_speed(term->chdev, tios->c_baud);
+ term->tp_cap->set_speed(term->chdev, tios->c_baud);
+ }
+
+ if (old_cf != tios->c_cflag) {
+ term->tp_cap->set_cntrl_mode(term->chdev, tios->c_cflag);
}
} break;
default:
}
static int
-tdev_do_write(struct device* dev, void* buf, size_t offset, size_t len)
+tdev_do_write(struct device* dev, void* buf, off_t fpos, size_t len)
{
struct term* tdev = termdev(dev);
lbuf_ref_t current = ref_current(&tdev->line_out);
size_t wrsz = 0;
while (wrsz < len) {
wrsz += rbuffer_puts(
- deref(current), &((char*)buf)[offset + wrsz], len - wrsz);
+ deref(current), &((char*)buf)[wrsz], len - wrsz);
if (rbuffer_full(deref(current))) {
term_flush(tdev);
}
static int
-tdev_do_read(struct device* dev, void* buf, size_t offset, size_t len)
+tdev_do_read(struct device* dev, void* buf, off_t fpos, size_t len)
{
struct term* tdev = termdev(dev);
lbuf_ref_t current = ref_current(&tdev->line_in);
}
rdsz += rbuffer_gets(
- deref(current), &((char*)buf)[offset + rdsz], len - rdsz);
+ deref(current), &((char*)buf)[rdsz], len - rdsz);
}
return rdsz;
terminal->dev->ops.read = tdev_do_read;
terminal->dev->ops.write = tdev_do_write;
+ terminal->dev->ops.exec_cmd = term_exec_cmd;
// TODO choice of lcntl can be flexible
terminal->lcntl = line_controls[ANSI_LCNTL];
register_device(terminal->dev, &termdev, "tty%d", termdev.variant++);
}
+ struct capability_meta* termport_cap = device_get_capability(chardev, TERMPORT_CAP);
+ if (termport_cap) {
+ terminal->tp_cap = get_capability(termport_cap, struct termport_capability);
+ }
+
+ struct capability_meta* term_cap = new_capability_marker(TERMIOS_CAP);
+ device_grant_capability(terminal->dev, term_cap);
+
load_default_setting(terminal);
return terminal;
max_lb_sz -= sz;
// TODO pass a flags to read to indicate it is non blocking ops
- sz += chdev->ops.read_async(chdev, inbuffer, sz, max_lb_sz);
+ sz += chdev->ops.read_async(chdev, &inbuffer[sz], 0, max_lb_sz);
}
rbuffer_puts(line_in->next, inbuffer, sz);
struct linebuffer* line_out = &tdev->line_out;
size_t xmit_len = line_out->current->len;
- void* xmit_buf = line_out->next->buffer;
+ char* xmit_buf = line_out->next->buffer;
rbuffer_gets(line_out->current, xmit_buf, xmit_len);
off_t off = 0;
int ret = 0;
while (xmit_len && ret >= 0) {
- ret = tdev->chdev->ops.write(tdev->chdev, xmit_buf, off, xmit_len);
+ ret = tdev->chdev->ops.write(tdev->chdev, &xmit_buf[off], 0, xmit_len);
xmit_len -= ret;
off += ret;
}
#include <lunaix/ds/waitq.h>
#include <lunaix/ds/rbuffer.h>
-#include <hal/term.h>
+#include <usr/lunaix/serial.h>
#define SERIAL_RW_RX 0x0
#define SERIAL_RW_TX 0x1
struct device* dev;
struct waitq wq_rxdone;
struct waitq wq_txdone;
- struct term* at_term;
void* backend;
struct rbuffer rxbuf;
int (*process_and_put)(struct term*, struct linebuffer*, char);
};
+/**
+ * @brief Communication port capability that a device is supported natively,
+ * or able to emulate low level serial transmission behaviour specify
+ * by POSIX1-2008, section 11.
+ *
+ */
+#define TERMPORT_CAP 0x4d524554U
+
+/**
+ * @brief A termios capability that a device provide interfaces which is
+ * compliant to POSIX1-2008
+ *
+ */
+#define TERMIOS_CAP 0x534f4954U
+
+struct termport_capability
+{
+ CAPABILITY_META;
+
+ void (*set_speed)(struct device*, speed_t);
+ void (*set_cntrl_mode)(struct device*, tcflag_t);
+};
+
struct term
{
struct device* dev;
struct linebuffer line_in;
pid_t fggrp;
- struct
- {
- int (*set_speed)(struct device*, speed_t);
- } chdev_ops;
+ struct termport_capability* tp_cap;
/* -- POSIX.1-2008 compliant fields -- */
tcflag_t iflags;
tcflag_t oflags;
tcflag_t lflags;
+ tcflag_t cflags;
cc_t cc[_NCCS];
speed_t iospeed;
};
#define DEV_IFSEQ 0x1 // sequential (character) device
#define DEV_IFSYS 0x3 // a system device
+struct capability_meta
+{
+ struct llist_header caps;
+ unsigned int cap_type;
+};
+
+#define CAPABILITY_META \
+ union { \
+ struct capability_meta cap_meta; \
+ struct { \
+ struct llist_header caps; \
+ unsigned int cap_type; \
+ }; \
+ }
+
+#define get_capability(cap, cap_type) \
+ container_of((cap), cap_type, cap_meta)
+#define cap_meta(cap) (&(cap)->cap_meta)
+
+typedef struct llist_header capability_list_t;
+
+
struct device_meta
{
u32_t magic;
DEVICE_METADATA;
+ capability_list_t capabilities;
+
/* -- device state -- */
mutex_t lock;
void
device_scan_drivers();
+/*------ Capability ------*/
+
+struct capability_meta*
+alloc_capability(int cap, unsigned int size);
+
+#define new_capability(cap_type, cap_impl)\
+ ((cap_impl*)alloc_capability((cap_type), sizeof(cap_impl)))
+
+#define new_capability_marker(cap_type)\
+ (alloc_capability((cap_type), sizeof(struct capability_meta)))
+
+void
+device_grant_capability(struct device* dev, struct capability_meta* cap);
+
+struct capability_meta*
+device_get_capability(struct device* dev, unsigned int cap_type);
/*------ Load hooks ------*/
void
}
#define DEBUG(fmt, ...) kprintf(KDEBUG fmt, ##__VA_ARGS__)
+#define INFO(fmt, ...) kprintf(KINFO fmt, ##__VA_ARGS__)
#define WARN(fmt, ...) kprintf(KWARN fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...) kprintf(KERROR fmt, ##__VA_ARGS__)
#define FATAL(fmt, ...) \
#define DT_FILE 0x0
#define DT_DIR 0x1
#define DT_SYMLINK 0x2
-#define DT_PIPE 0x2
+#define DT_PIPE 0x3
struct lx_dirent
{
#define SERIO_TXEN IOREQ(3, 0)
#define SERIO_TXDA IOREQ(4, 0)
+#define SERIO_SETBRDIV IOREQ(5, 0)
+#define SERIO_SETCNTRLMODE IOREQ(6, 0)
+
#endif /* __LUNAIX_USERIAL_H */
#define _B19200 19200
#define _B38400 38400
+#define _CLOCAL 1
+#define _CREAD (1 << 1)
+#define _CSZ_MASK (0b11 << 2)
+#define _CS5 (0b00 << 2)
+#define _CS6 (0b01 << 2)
+#define _CS7 (0b10 << 2)
+#define _CS8 (0b11 << 2)
+#define _CSTOPB (1 << 4)
+#define _CHUPCL (1 << 5)
+#define _CPARENB (1 << 6)
+#define _CPARODD (1 << 7)
+
#define _TCSANOW 1
#define _TCSADRAIN 2
#define _TCSAFLUSH 3
typedef char cc_t;
typedef unsigned int speed_t;
-struct _termios
+struct termios
{
tcflag_t c_iflag;
tcflag_t c_oflag;
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/mm/valloc.h>
+
+struct capability_meta*
+alloc_capability(int cap, unsigned int size)
+{
+ struct capability_meta* cm = (struct capability_meta*)vzalloc(size);
+
+ cm->cap_type = cap;
+
+ return cm;
+}
+
+void
+device_grant_capability(struct device* dev, struct capability_meta* cap)
+{
+ llist_append(&dev->capabilities, &cap->caps);
+}
+
+struct capability_meta*
+device_get_capability(struct device* dev, unsigned int cap_type)
+{
+ struct capability_meta *pos, *n;
+
+ llist_for_each(pos, n, &dev->capabilities, caps) {
+ if (pos->cap_type == cap_type){
+ return pos;
+ }
+ }
+
+ return NULL;
+}
\ No newline at end of file
dev->dev_type = type;
device_init_meta(dev_meta(dev), parent, DEV_STRUCT);
+ llist_init_head(&dev->capabilities);
mutex_init(&dev->lock);
iopoll_init_evt_q(&dev->pollers);
}
goto done;
}
- struct device* dev = (struct device*)fd_s->file->inode->data;
- if (valid_device_subtype_ref(dev, DEV_STRUCT)) {
- errno &= ENODEV;
+ struct device* dev = resolve_device(fd_s->file->inode->data);
+ if (!valid_device_subtype_ref(dev, DEV_STRUCT)) {
+ errno = ENODEV;
goto done;
}
}
if (!dev->ops.exec_cmd) {
- errno &= ENOTSUP;
+ errno = ENOTSUP;
goto done;
}
- errno &= dev->ops.exec_cmd(dev, req, args);
+ errno = dev->ops.exec_cmd(dev, req, args);
done:
return DO_STATUS_OR_RETURN(errno);
int
rbuffer_gets(struct rbuffer* rb, char* buf, size_t len)
{
- if (!len)
+ if (!len || !rb->len)
return 0;
size_t nlen = MIN(len, rb->len);
mnt_chillax(mnt->parent);
+ mnt->mnt_point->mnt = mnt->parent;
+
vfs_sb_free(sb);
atomic_fetch_sub(&mnt->mnt_point->ref_count, 1);
vfree(mnt);
goto done;
}
+ if (mnt->mnt->mnt_point == mnt) {
+ errno = EBUSY;
+ goto done;
+ }
+
// By our convention.
// XXX could we do better?
struct device* device = NULL;
file->inode->atime = clock_unixtime();
if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
- errno = file->ops->read(file->inode, buf, count, file->f_pos);
+ errno = file->ops->read(file->inode, buf, count, file->f_pos);
} else {
errno = pcache_read(file->inode, buf, count, file->f_pos);
}
int
vfs_get_dtype(int itype)
{
- if ((itype & VFS_IFSYMLINK)) {
+ if ((itype & VFS_IFSYMLINK) == VFS_IFSYMLINK) {
return DT_SYMLINK;
} else if (!(itype & VFS_IFFILE)) {
return DT_DIR;
goto done;
}
+ if (!(errno = vfs_walk(parent, name_value, &dir, NULL, 0))) {
+ errno = EEXIST;
+ goto done;
+ }
+
if ((errno = vfs_check_writable(parent))) {
goto done;
}
#include <lunaix/tty/console.h>
#include <lunaix/tty/tty.h>
+#include <hal/term.h>
+
static struct console lx_console;
int
console_flush();
static waitq_t lx_reader;
-static volatile char ttychr;
static volatile pid_t fg_pgid = 0;
-static inline void
-print_control_code(const char cntrl)
-{
- console_write_char('^');
- console_write_char(cntrl + 64);
-}
-
int
__lxconsole_listener(struct input_device* dev)
{
u32_t key = dev->current_pkt.sys_code;
u32_t type = dev->current_pkt.pkt_type;
kbd_kstate_t state = key >> 16;
- ttychr = key & 0xff;
+ u8_t ttychr = key & 0xff;
key = key & 0xffff;
if (type == PKT_RELEASE) {
goto done;
}
ttychr = cntrl - 'a' + 1;
- switch (ttychr) {
- case TCINTR:
- signal_send(-fg_pgid, _SIGINT);
- print_control_code(ttychr);
- break;
- case TCSTOP:
- signal_send(-fg_pgid, _SIGSTOP);
- print_control_code(ttychr);
- break;
- default:
- break;
- }
} else if (key == KEY_PG_UP) {
console_view_up();
goto done;
goto done;
}
+ fifo_putone(&lx_console.input, ttychr);
pwake_all(&lx_reader);
done:
struct console* console = (struct console*)dev->underlay;
size_t count = fifo_read(&console->input, buf, len);
- if (count > 0 && ((char*)buf)[count - 1] == '\n') {
+ if (count > 0) {
return count;
}
- while (count < len) {
- pwait(&lx_reader);
-
- if (ttychr < 0x1B) {
- // ASCII control codes
- switch (ttychr) {
- case TCINTR:
- fifo_clear(&console->input);
- return 0;
- case TCBS:
- if (fifo_backone(&console->input)) {
- console_write_char(ttychr);
- }
- continue;
- case TCLF:
- case TCCR:
- goto proceed;
- default:
- break;
- }
- print_control_code(ttychr);
- continue;
- }
-
- proceed:
- console_write_char(ttychr);
- if (!fifo_putone(&console->input, ttychr) || ttychr == '\n') {
- break;
- }
- }
+ pwait(&lx_reader);
return count + fifo_read(&console->input, buf + count, len - count);
}
register_device(tty_dev, &devdef->class, "vcon");
+ term_create(tty_dev, "FB");
+
return 0;
}
static struct device_def lxconsole_def = {
.name = "Lunaix Virtual Console",
- .class = DEVCLASSV(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN, 12),
+ .class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN),
.init = lxconsole_spawn_ttydev
};
// FIXME
DEPS := $(CC) $(LD) $(AR) xorriso grub-mkrescue
+CMDLINE ?= console=/dev/ttyFB0
+
kbuild_dir := build
kbin_dir := $(kbuild_dir)/bin
os_img_dir := $(kbuild_dir)/img
@$(MAKE) $(MKFLAGS) -I $(mkinc_dir) -f kernel.mk all
.PHONY: image
+export KCMD=$(CMDLINE)
+export _OS_NAME=$(OS_NAME)
image: usr/build kernel
$(call status,TASK,$(notdir $@))
- @./config-grub.sh ${OS_NAME} $(os_img_dir)/boot/grub/grub.cfg
+ @./config-grub.sh $(os_img_dir)/boot/grub/grub.cfg
@cp -r usr/build/* $(os_img_dir)/usr
@cp -r $(kbin_dir)/* $(os_img_dir)/boot
@grub-mkrescue -o $(kimg) $(os_img_dir) -- -volid "$(OS_ID) $(OS_VER)" -system_id "$(OS_NAME)"
@QMPORT=$(QEMU_MON_PORT) gdb $(kbin) -ex "target remote localhost:1234"
debug-qemu-vscode: all-debug
- @i686-elf-objcopy --only-keep-debug $(kbin) $(kbuild_dir)/kernel.dbg
@qemu-system-i386 $(call get_qemu_options,$(kimg))
@sleep 0.5
@telnet 127.0.0.1 $(QEMU_MON_PORT)
main(int argc, const char* argv[])
{
int fd = 0;
- unsigned int size = 0;
+ int size = 0;
+ struct file_stat stat;
for (int i = 1; i < argc; i++) {
fd = open(argv[i], FO_RDONLY);
+
if (fd < 0) {
printf("open failed: %s (error: %d)", argv[i], fd);
continue;
}
+ if (fstat(fd, &stat) < 0) {
+ printf("fail to get stat %d\n", errno);
+ return 1;
+ }
+
+ if (!(stat.mode & F_MFILE)) {
+ printf("%s is a directory", argv[i]);
+ return 1;
+ }
+
do {
size = read(fd, buffer, BUFSIZE);
write(stdout, buffer, size);
#include <fcntl.h>
#include <lunaix/lunaix.h>
#include <lunaix/mount.h>
+#include <termios.h>
#include <stdio.h>
#include <unistd.h>
} \
} while (0)
+#define check(statement) \
+ do { \
+ int err = 0; \
+ if ((err = (statement))) { \
+ syslog(2, #statement " failed: %d", err); \
+ return err; \
+ } \
+ } while (0)
+
+int
+init_termios(int fd) {
+ struct termios term;
+
+ check(tcgetattr(fd, &term));
+
+ term.c_lflag = ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHONL;
+ term.c_iflag = ICRNL | IGNBRK;
+ term.c_oflag = ONLCR | OPOST;
+ term.c_cflag = CREAD | CLOCAL | CS8 | CPARENB;
+ term.c_cc[VERASE] = 0x08;
+
+ check(tcsetattr(fd, 0, &term));
+
+ return 0;
+}
+
int
main(int argc, const char** argv)
{
return err;
}
+ check(init_termios(err));
+
if ((err = dup(err)) < 0) {
syslog(2, "fail to setup tty i/o (%d)\n", errno);
return err;
--- /dev/null
+#ifndef __LUNAIX_TERMIOS_H
+#define __LUNAIX_TERMIOS_H
+
+#include <lunaix/term.h>
+
+#define BRKINT _BRKINT
+#define ICRNL _ICRNL
+#define IGNBRK _IGNBRK
+#define IGNCR _IGNCR
+#define IGNPAR _IGNPAR
+#define INLCR _INLCR
+#define INPCK _INPCK
+#define ISTRIP _ISTRIP
+#define IUCLC _IUCLC
+#define IXANY _IXANY
+#define IXOFF _IXOFF
+#define IXON _IXON
+#define PARMRK _PARMRK
+
+#define OPOST _OPOST
+#define OCRNL _OCRNL
+
+// 2
+// 3
+// 4
+
+#define ONLRET _ONLRET
+#define ONLCR _ONLCR
+
+// 7
+
+#define OLCUC _OLCUC
+
+#define ECHO _ECHO
+#define ECHOE _ECHOE
+#define ECHOK _ECHOK
+#define ECHONL _ECHONL
+#define ICANON _ICANON
+#define ISIG _ISIG
+#define IEXTEN _IEXTEN
+#define NOFLSH _NOFLSH
+
+#define VEOF _VEOF
+#define VEOL _VEOL
+#define VERASE _VERASE
+#define VINTR _VINTR
+#define VKILL _VKILL
+#define VQUIT _VQUIT
+#define VSUSP _VSUSP
+#define VSTART _VSTART
+#define VSTOP _VSTOP
+#define VMIN _VMIN
+#define VTIME _VTIME
+#define NCCS _NCCS
+
+#define B50 _B50
+#define B75 _B75
+#define B110 _B110
+#define B134 _B134
+#define B150 _B150
+#define B200 _B200
+#define B300 _B300
+#define B600 _B600
+#define B1200 _B1200
+#define B1800 _B1800
+#define B2400 _B2400
+#define B4800 _B4800
+#define B9600 _B9600
+#define B19200 _B19200
+#define B38400 _B38400
+
+#define CLOCAL _CLOCAL
+#define CREAD _CREAD
+#define CS5 _CS5
+#define CS6 _CS6
+#define CS7 _CS7
+#define CS8 _CS8
+#define CSTOPB _CSTOPB
+#define CHUPCL _CHUPCL
+#define CPARENB _CPARENB
+#define CPARODD _CPARODD
+
+#define TCSANOW _TCSANOW
+#define TCSADRAIN _TCSADRAIN
+#define TCSAFLUSH _TCSAFLUSH
+
+static inline speed_t cfgetispeed(const struct termios* termios) { return termios->c_baud; }
+static inline speed_t cfgetospeed(const struct termios* termios) { return termios->c_baud; }
+
+static inline int cfsetispeed(struct termios* termios, speed_t baud)
+{
+ termios->c_baud = baud;
+ return 0;
+}
+
+static inline int cfsetospeed(struct termios* termios, speed_t baud)
+{
+ termios->c_baud = baud;
+ return 0;
+}
+
+
+// TODO
+//int tcdrain(int);
+//int tcflow(int, int);
+//int tcflush(int, int);
+// pid_t tcgetsid(int);
+
+int tcgetattr(int, struct termios *);
+int tcsendbreak(int, int);
+int tcsetattr(int, int, const struct termios *);
+
+
+#endif /* __LUNAIX_TERMIOS_H */
--- /dev/null
+#include <termios.h>
+#include <lunaix/ioctl.h>
+
+int
+tcgetattr(int fd, struct termios* termios_p)
+{
+ return ioctl(fd, TDEV_TCGETATTR, termios_p);
+}
+
+
+int
+tcsendbreak(int fd, int )
+{
+ // TODO
+ return 0;
+}
+
+int
+tcsetattr(int fd, int optional_actions, const struct termios* termios_p)
+{
+ return ioctl(fd, TDEV_TCSETATTR, termios_p);
+}
while ((dent = readdir(dir))) {
if (dent->d_type == DT_DIR) {
- printf(" \033[3m%s\033[39;49m\n", dent->d_name);
+ printf(" %s\n", dent->d_name);
} else if (dent->d_type == DT_SYMLINK) {
- printf(" \033[13m%s@\033[39;49m\n", dent->d_name);
+ printf(" %s@\n", dent->d_name);
} else {
printf(" %s\n", dent->d_name);
}
while (1) {
getcwd(pwd, 512);
- printf("[\033[2m%s\033[39;49m]$ ", pwd);
+ printf("[%s]$ ", pwd);
int sz = read(stdin, buf, 511);
if (sz < 0) {