+ `vmrs [pid]` 列举进程`<pid>`的内存区域图(Memory Regions),如果`<pid>`未指定,则默认为正在运行的进程(smp=1)。
+ `proc [pid]` 打印进程`<pid>`的进程控制块状态,如果`<pid>`未指定,则默认为正在运行的进程(smp=1)。
+ `proc_table` 列举所有非终止的进程以及他们的状态。
++ `syslog` 打印到目前为止的系统日志。
该插件可以通过运行以下命令来进行安装:
timeout=0
menuentry "$_OS_NAME" {
- multiboot /boot/kernel.bin
+ multiboot /boot/kernel.bin console=/dev/vcon
module --nounzip /boot/modksyms modksyms
}
\ No newline at end of file
mb_memcpy(buffer, (u8_t*)cmdline, slen);
bhctx->kexec.len = slen;
+ bhctx->kexec.cmdline = buffer;
return slen;
}
devnull->ops.read_page = __null_rd_pg;
devnull->ops.read = __null_rd;
- device_register(devnull, &def->class, "null");
+ register_device(devnull, &def->class, "null");
return 0;
}
devzero->ops.read_page = __zero_rd_pg;
devzero->ops.read = __zero_rd;
- device_register(devzero, &def->class, "zero");
+ register_device(devzero, &def->class, "zero");
return 0;
}
rbuffer_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE);
llist_append(&serial_devs, &sdev->sdev_list);
- device_register(dev, class, "port%s%d", if_ident, class->variant);
+ register_device(dev, class, "port%s%d", if_ident, class->variant);
sdev->at_term = term_create(dev, if_ident);
DEFINE_LLIST(gfxa_flat);
DECLARE_HASHTABLE(gfxa_idset, 8);
-struct device* gfxa_devcat = NULL;
+struct device_cat* gfxa_devcat = NULL;
static int id = 0;
static struct devclass gfxa_class = DEVCLASS(DEV_BUILTIN, DEVFN_DISP, DEV_GFXA);
}
struct gfxa* gfxa = valloc(sizeof(struct gfxa));
- struct device* gfxa_dev = device_allocsys(gfxa_devcat, gfxa);
+ struct device* gfxa_dev = device_allocsys(dev_meta(gfxa_devcat), gfxa);
*gfxa = (struct gfxa){ .dev = gfxa_dev, .hw_obj = hw_obj };
llist_append(&gfxa_flat, &gfxa->gfxas);
hashtable_hash_in(gfxa_idset, &gfxa->gfxas_id, gfxa->id);
- device_register(gfxa->dev, &gfxa_class, "gfxa%d", gfxa->id);
+ register_device(gfxa->dev, &gfxa_class, "gfxa%d", gfxa->id);
}
struct gfxa*
static DEFINE_LLIST(pci_devices);
static DECLARE_HASHTABLE(pci_devcache, 8);
-static struct device* pcidev_cat;
+static struct device_cat* pcidev_cat;
static struct device_def pci_def;
void
device->cspace_base = pci_base;
device->intr_info = intr;
- device_create(&device->dev, pcidev_cat, DEV_IFSYS, NULL);
+ device_create(&device->dev, dev_meta(pcidev_cat), DEV_IFSYS, NULL);
pci_probe_msi_info(device);
pci_probe_bar_info(device);
llist_append(&pci_devices, &device->dev_chain);
- device_register(&device->dev, &pci_def.class, "%x", loc);
+ register_device(&device->dev, &pci_def.class, "%x", loc);
pci_def.class.variant++;
return device;
devrand->ops.read = __rand_rd;
devrand->ops.read_page = __rand_rd_pg;
- device_register(devrand, &devdef->class, "rand");
+ register_device(devrand, &devdef->class, "rand");
return 0;
}
}
class->variant = rtc->id;
- device_register(rtc->rtc_dev, class, "rtc%d", rtc->id);
+ register_device(rtc->rtc_dev, class, "rtc%d", rtc->id);
}
static void
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/owloysius.h>
+#include <lunaix/spike.h>
+#include <lunaix/kcmd.h>
+#include <lunaix/fs.h>
+#include <lunaix/syslog.h>
+
+#include <hal/term.h>
+
+LOG_MODULE("console")
+
+static void
+setup_default_tty()
+{
+ char* console_dev;
+ if(!kcmd_get_option("console", &console_dev)) {
+ FATAL("I am expecting a console!");
+ // should not reach
+ }
+
+ struct v_dnode* dn;
+ int err;
+
+ if ((err = vfs_walk(NULL, console_dev, &dn, NULL, 0))) {
+ FATAL("unable to set console: %s, err=%d", console_dev, err);
+ // should not reach
+ }
+
+ struct device* dev = resolve_device(dn->inode->data);
+ if (!dev) {
+ FATAL("not a device: %s", console_dev);
+ // should not reach
+ }
+
+ assert(device_addalias(NULL, dev_meta(dev), "tty"));
+
+ // TODO implement capability list
+ // for now, we just assume the parameter always pointed to valid device
+ sysconsole = dev;
+}
+lunaix_initfn(setup_default_tty, call_on_boot);
\ No newline at end of file
static struct devclass termdev = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM);
+struct device* sysconsole = NULL;
+
static int
term_exec_cmd(struct device* dev, u32_t req, va_list args)
{
goto done;
}
- struct device* cdev = device_cast(vfd->file->inode->data);
+ struct device* cdev = resolve_device(vfd->file->inode->data);
if (!cdev) {
err = ENOTDEV;
goto done;
term_flush(tdev);
}
}
-
+
+ if (!rbuffer_empty(deref(current))) {
+ term_flush(tdev);
+ }
return 0;
}
static cc_t default_cc[_NCCS] = {4, '\n', 0x7f, 3, 1, 24, 22, 0, 0, 1, 1};
+static void
+load_default_setting(struct term* tdev)
+{
+ tdev->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
+ tdev->iflags = _ICRNL | _IGNBRK;
+ tdev->oflags = _ONLCR | _OPOST;
+ memcpy(tdev->cc, default_cc, _NCCS * sizeof(cc_t));
+}
+
struct term*
term_create(struct device* chardev, char* suffix)
{
if (chardev) {
int cdev_var = DEV_VAR_FROM(chardev->ident.unique);
- device_register(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var);
+ register_device(terminal->dev, &termdev, "tty%s%d", suffix, cdev_var);
} else {
- device_register(terminal->dev, &termdev, "tty%d", termdev.variant++);
+ register_device(terminal->dev, &termdev, "tty%d", termdev.variant++);
}
- terminal->lflags = _ICANON | _IEXTEN | _ISIG | _ECHO | _ECHOE | _ECHONL;
- terminal->iflags = _ICRNL | _IGNBRK;
- terminal->oflags = _ONLCR | _OPOST;
- memcpy(terminal->cc, default_cc, _NCCS * sizeof(cc_t));
+ load_default_setting(terminal);
return terminal;
}
timerdev->ops.exec_cmd = __hwtimer_ioctl;
- device_register(timerdev, &hwt_ctx->class, hwt_ctx->name);
+ register_device(timerdev, &hwt_ctx->class, hwt_ctx->name);
}
\ No newline at end of file
speed_t iospeed;
};
+extern struct device* sysconsole;
+
struct term*
term_create(struct device* chardev, char* suffix);
#ifndef __LUNAIX_COMPILER_H
#define __LUNAIX_COMPILER_H
-#define likely(x) __builtin_expect((x), 1)
-#define unlikely(x) __builtin_expect((x), 0)
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
#define weak_alias(name) __attribute__((weak, alias(name)))
#define weak __attribute__((weak))
#define noret __attribute__((noreturn))
#define optimize(opt) __attribute__((optimize(opt)))
#define must_inline __attribute__((always_inline))
+#define must_emit __attribute__((used))
#define clz(bits) __builtin_clz(bits)
#define sadd_overflow(a, b, of) __builtin_sadd_overflow(a, b, of)
#define compact __attribute__((packed))
#define align(v) __attribute__((aligned (v)))
+#define export_symbol(domain, symbol)\
+ typeof(symbol)* must_emit __SYMEXPORT_Z##domain##_##symbol = &(symbol)
+
inline static void noret
spin()
{
.variant = (devvar) \
}
-#define DEV_STRUCT_MAGIC 0x5645444c
+#define DEV_STRUCT_MAGIC_MASK 0x56454440U
+#define DEV_STRUCT 0xc
+#define DEV_CAT 0xd
+#define DEV_ALIAS 0xf
+
+#define DEV_STRUCT_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_STRUCT)
+#define DEV_CAT_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_CAT)
+#define DEV_ALIAS_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_ALIAS)
#define DEV_MSKIF 0x00000003
#define DEV_IFVOL 0x0 // volumetric (block) device
#define DEV_IFSEQ 0x1 // sequential (character) device
-#define DEV_IFCAT 0x2 // a device category (as device groupping)
#define DEV_IFSYS 0x3 // a system device
-struct device
+struct device_meta
{
- /* -- device structing -- */
-
u32_t magic;
struct llist_header siblings;
struct llist_header children;
- struct device* parent;
+ struct device_meta* parent;
+ struct hstr name;
+
+ u32_t dev_uid;
+
+ char name_val[DEVICE_NAME_SIZE];
+};
+
+#define DEVICE_METADATA \
+ union { \
+ struct device_meta meta; \
+ struct { \
+ u32_t magic; \
+ struct llist_header siblings; \
+ struct llist_header children; \
+ struct device_meta* parent; \
+ struct hstr name; \
+ \
+ u32_t dev_uid; \
+ \
+ char name_val[DEVICE_NAME_SIZE]; \
+ }; \
+ }
+
+#define dev_meta(dev) (&(dev)->meta)
+#define to_dev(dev) (container_of(dev,struct device, meta))
+#define to_catdev(dev) (container_of(dev,struct device_cat, meta))
+#define to_aliasdev(dev) (container_of(dev,struct device_alias, meta))
+
+struct device_alias {
+ DEVICE_METADATA;
+ struct device_meta* alias;
+};
+
+struct device_cat {
+ DEVICE_METADATA;
+};
+
+struct device
+{
+ /* -- device structing -- */
+
+ DEVICE_METADATA;
/* -- device state -- */
mutex_t lock;
- struct hstr name;
- struct devident ident;
-
- u32_t dev_uid;
int dev_type;
- char name_val[DEVICE_NAME_SIZE];
+ struct devident ident;
void* underlay;
/* -- polling -- */
int (*free)(struct device_def*, void* instance);
};
+static inline bool must_inline
+valid_device_ref(void* maybe_dev) {
+ if (!maybe_dev)
+ return false;
+
+ unsigned int magic = ((struct device_meta*)maybe_dev)->magic;
+ return (magic ^ DEV_STRUCT_MAGIC_MASK) <= 0xfU;
+}
+
+static inline bool must_inline
+valid_device_subtype_ref(void* maybe_dev, unsigned int subtype) {
+ if (!maybe_dev)
+ return false;
+
+ unsigned int magic = ((struct device_meta*)maybe_dev)->magic;
+ return (magic ^ DEV_STRUCT_MAGIC_MASK) == subtype;
+}
+
+struct device*
+resolve_device(void* maybe_dev);
+
+struct device_meta*
+resolve_device_meta(void* maybe_dev);
+
#define mark_device_doing_write(dev_ptr) (dev_ptr)->poll_evflags &= ~_POLLOUT
#define mark_device_done_write(dev_ptr) (dev_ptr)->poll_evflags |= _POLLOUT
device_scan_drivers();
void
-device_setname_vargs(struct device* dev, char* fmt, va_list args);
+device_setname_vargs(struct device_meta* dev, char* fmt, va_list args);
void
-device_setname(struct device* dev, char* fmt, ...);
+device_setname(struct device_meta* dev, char* fmt, ...);
void
-device_register(struct device* dev, struct devclass* class, char* fmt, ...);
+device_register_generic(struct device_meta* dev, struct devclass* class, char* fmt, ...);
+
+#define register_device(dev, class, fmt, ...) \
+ device_register_generic(dev_meta(dev), class, fmt, ## __VA_ARGS__)
void
device_create(struct device* dev,
- struct device* parent,
+ struct device_meta* parent,
u32_t type,
void* underlay);
struct device*
-device_alloc(struct device* parent, u32_t type, void* underlay);
+device_alloc(struct device_meta* parent, u32_t type, void* underlay);
-static inline struct device*
-device_allocsys(struct device* parent, void* underlay)
+static inline struct device* must_inline
+device_allocsys(struct device_meta* parent, void* underlay)
{
return device_alloc(parent, DEV_IFSYS, underlay);
}
-static inline struct device*
-device_allocseq(struct device* parent, void* underlay)
+static inline struct device* must_inline
+device_allocseq(struct device_meta* parent, void* underlay)
{
return device_alloc(parent, DEV_IFSEQ, underlay);
}
-static inline struct device*
-device_allocvol(struct device* parent, void* underlay)
+static inline struct device* must_inline
+device_allocvol(struct device_meta* parent, void* underlay)
{
return device_alloc(parent, DEV_IFVOL, underlay);
}
-struct device*
-device_addcat(struct device* parent, char* name_fmt, ...);
+struct device_alias*
+device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...);
+
+struct device_cat*
+device_addcat(struct device_meta* parent, char* name_fmt, ...);
void
-device_remove(struct device* dev);
+device_remove(struct device_meta* dev);
-struct device*
+struct device_meta*
device_getbyid(struct llist_header* devlist, u32_t id);
-struct device*
-device_getbyhname(struct device* root_dev, struct hstr* name);
+struct device_meta*
+device_getbyhname(struct device_meta* root_dev, struct hstr* name);
-struct device*
-device_getbyname(struct device* root_dev, const char* name, size_t len);
-
-struct device*
-device_getbyoffset(struct device* root_dev, int pos);
+struct device_meta*
+device_getbyname(struct device_meta* root_dev, const char* name, size_t len);
-struct device*
-device_cast(void* obj);
+struct device_meta*
+device_getbyoffset(struct device_meta* root_dev, int pos);
struct hbucket*
device_definitions_byif(int if_type);
/*------ Load hooks ------*/
void
-device_onbooot_load();
+device_onboot_load();
void
device_postboot_load();
#define DEV_BUILTIN 0
#define DEV_BUILTIN_NULL 0
#define DEV_BUILTIN_ZERO 1
+#define DEV_BUILTIN_KMSG 2
#define DEV_VTERM 1
#define DEV_RNG 2
struct filesystem
{
+ struct llist_header fs_flat;
struct hlist_node fs_list;
struct hstr fs_name;
u32_t types;
--- /dev/null
+#ifndef __LUNAIX_OWLOYSIUS_H
+#define __LUNAIX_OWLOYSIUS_H
+
+#include <lunaix/ds/ldga.h>
+
+#define call_on_earlyboot c_earlyboot
+#define call_on_boot c_boot
+#define call_on_postboot c_postboot
+
+#define lunaix_initfn(func, call_stage) \
+ export_ldga_el(lunainit, func, ptr_t, func); \
+ export_ldga_el_sfx(lunainit, func##_##call_stage, ptr_t, func, call_stage);
+
+#define invoke_init_function(stage) ldga_invoke_fn0(lunainit##_##stage)
+
+#endif /* __LUNAIX_OWLOYSIUS_H */
#ifndef __LUNAIXOS_NASSERT__
#define assert(cond) \
- if (!(cond)) { \
- __assert_fail(#cond, __FILE__, __LINE__); \
- }
+ do { \
+ if (!(cond)) { \
+ __assert_fail(#cond, __FILE__, __LINE__); \
+ } \
+ } while(0)
#define assert_msg(cond, msg) \
- if (!(cond)) { \
- __assert_fail(msg, __FILE__, __LINE__); \
- }
+ do { \
+ if (!(cond)) { \
+ __assert_fail(msg, __FILE__, __LINE__); \
+ } \
+ } while(0)
+
+#define must_success(statement) \
+ do { \
+ int err = (statement); \
+ if (err) panickf(#statement "failed with errcode=%d", err); \
+ } while(0)
#define fail(msg) __assert_fail(msg, __FILE__, __LINE__);
static struct cake_pile* lbd_pile;
static struct block_dev** dev_registry;
static struct twifs_node* blk_sysroot;
-static struct device* blk_parent_dev;
+static struct device_cat* blk_parent_dev;
int free_slot = 0;
return 0;
}
- struct device* dev = device_allocvol(blk_parent_dev, bdev);
+ struct device* dev = device_allocvol(dev_meta(blk_parent_dev), bdev);
dev->ops.write = __block_write;
dev->ops.write_page = __block_write_page;
dev->ops.read = __block_read;
bdev->dev = dev;
- device_register(dev, bdev->class, "sd%c", 'a' + free_slot);
+ register_device(dev, bdev->class, "sd%c", 'a' + free_slot);
dev_registry[free_slot++] = bdev;
strcpy(bdev->bdev_id, dev->name_val);
llist_append(&bdev->parts, &pbdev->parts);
- device_register(dev, pbdev->class, "%sp%d", bdev->bdev_id, index + 1);
+ register_device(dev, pbdev->class, "%sp%d", bdev->bdev_id, index + 1);
return pbdev;
}
\ No newline at end of file
i++;
}
+ if (!valid_fp((ptr_t)frame)) {
+ frame = NULL;
+ }
+
if (last_fp) {
*last_fp = (ptr_t)frame;
}
static DECLARE_HASHTABLE(dev_byif, 8);
static DEFINE_LLIST(dev_registry_flat);
-static struct device* adhoc_devcat;
+static struct device_cat* adhoc_devcat;
static inline u32_t
hash_dev(u32_t fngrp, u32_t dev)
#define device_load_on_stage(stage) __device_load_on_stage(stage)
void
-device_onbooot_load()
+device_onboot_load()
{
device_load_on_stage(load_onboot);
}
ksnprintf(flags, 64, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
twimap_printf(mapping,
- "%xh:%d \"%s\" %s\n",
+ "%08xh:%04d \"%s\" %s\n",
def->class.fn_grp,
def->class.device,
def->name,
{
assert(inode->data);
- struct device* dev = (struct device*)inode->data;
+ struct device* dev = resolve_device(inode->data);
- if (!dev->ops.read) {
+ if (!dev || !dev->ops.read) {
return ENOTSUP;
}
{
assert(inode->data);
- struct device* dev = (struct device*)inode->data;
+ struct device* dev = resolve_device(inode->data);
- if (!dev->ops.write) {
+ if (!dev || !dev->ops.write) {
return ENOTSUP;
}
{
assert(inode->data);
- struct device* dev = (struct device*)inode->data;
+ struct device* dev = resolve_device(inode->data);
- if (!dev->ops.read_page) {
+ if (!dev || !dev->ops.read_page) {
return ENOTSUP;
}
{
assert(inode->data);
- struct device* dev = (struct device*)inode->data;
+ struct device* dev = resolve_device(inode->data);
- if (!dev->ops.read_page) {
+ if (!dev || !dev->ops.read_page) {
return ENOTSUP;
}
}
int
-devfs_get_itype(struct device* dev)
+devfs_get_itype(struct device_meta* dm)
{
int itype = VFS_IFFILE;
+
+ if (valid_device_subtype_ref(dm, DEV_CAT)) {
+ return VFS_IFDIR;
+ }
+
+ struct device* dev = resolve_device(dm);
int dev_if = dev->dev_type & DEV_MSKIF;
- if (dev_if == DEV_IFCAT) {
- itype = VFS_IFDIR;
- } else if (dev_if == DEV_IFVOL) {
+
+ if (dev_if == DEV_IFVOL) {
itype |= VFS_IFVOLDEV;
} else if (dev_if == DEV_IFSEQ) {
itype |= VFS_IFSEQDEV;
}
int
-devfs_get_dtype(struct device* dev)
+devfs_get_dtype(struct device_meta* dev)
{
- switch (dev->dev_type & DEV_MSKIF) {
- case DEV_IFCAT:
- return DT_DIR;
-
- default:
- return DT_FILE;
+ if (valid_device_subtype_ref(dev, DEV_CAT)) {
+ return DT_DIR;
}
+ return DT_FILE;
}
int
-devfs_mknod(struct v_dnode* dnode, struct device* dev)
+devfs_mknod(struct v_dnode* dnode, struct device_meta* dev)
{
assert(dev);
int
devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
{
- struct device* dev =
- device_getbyhname((struct device*)this->data, &dnode->name);
+ void* data = this->data;
+ struct device_meta* rootdev = resolve_device_meta(data);
+
+ if (data && !rootdev) {
+ return ENOTDIR;
+ }
+
+ struct device_meta* dev =
+ device_getbyhname(rootdev, &dnode->name);
+
if (!dev) {
return ENOENT;
}
+
return devfs_mknod(dnode, dev);
}
int
devfs_readdir(struct v_file* file, struct dir_context* dctx)
{
- struct device* dev =
- device_getbyoffset((struct device*)(file->inode->data), dctx->index);
+ void* data = file->inode->data;
+ struct device_meta* rootdev = resolve_device_meta(data);
+
+ if (data && !rootdev) {
+ return ENOTDIR;
+ }
+
+ struct device_meta* dev =
+ device_getbyoffset(rootdev, dctx->index);
+
if (!dev) {
return 0;
}
+
dctx->read_complete_callback(
dctx, dev->name.value, dev->name.len, devfs_get_dtype(dev));
return 1;
struct devclass default_devclass = {};
void
-device_setname_vargs(struct device* dev, char* fmt, va_list args)
+device_setname_vargs(struct device_meta* dev, char* fmt, va_list args)
{
size_t strlen = ksnprintfv(dev->name_val, fmt, DEVICE_NAME_SIZE, args);
}
void
-device_register(struct device* dev, struct devclass* class, char* fmt, ...)
+device_register_generic(struct device_meta* devm, struct devclass* class, char* fmt, ...)
{
va_list args;
va_start(args, fmt);
if (fmt) {
- device_setname_vargs(dev, fmt, args);
+ device_setname_vargs(devm, fmt, args);
}
- if (class) {
+ if (class && valid_device_subtype_ref(devm, DEV_STRUCT)) {
+ struct device* dev = to_dev(devm);
dev->ident = (struct devident){ .fn_grp = class->fn_grp,
.unique = DEV_UNIQUE(class->device,
class->variant) };
}
- dev->dev_uid = devid++;
+ devm->dev_uid = devid++;
- struct device* parent = dev->parent;
+ struct device_meta* parent = devm->parent;
if (parent) {
- assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT);
- llist_append(&parent->children, &dev->siblings);
+ assert(valid_device_subtype_ref(parent, DEV_CAT));
+ llist_append(&parent->children, &devm->siblings);
} else {
- llist_append(&root_list, &dev->siblings);
+ llist_append(&root_list, &devm->siblings);
}
va_end(args);
}
+static void
+device_init_meta(struct device_meta* dmeta, struct device_meta* parent, unsigned int subtype)
+{
+ dmeta->magic = DEV_STRUCT_MAGIC_MASK | subtype;
+ dmeta->parent = parent;
+
+ llist_init_head(&dmeta->children);
+}
+
void
device_create(struct device* dev,
- struct device* parent,
+ struct device_meta* parent,
u32_t type,
void* underlay)
{
dev->magic = DEV_STRUCT_MAGIC;
dev->underlay = underlay;
dev->dev_type = type;
- dev->parent = parent;
- llist_init_head(&dev->children);
+ device_init_meta(dev_meta(dev), parent, DEV_STRUCT);
mutex_init(&dev->lock);
iopoll_init_evt_q(&dev->pollers);
}
struct device*
-device_alloc(struct device* parent, u32_t type, void* underlay)
+device_alloc(struct device_meta* parent, u32_t type, void* underlay)
{
struct device* dev = vzalloc(sizeof(struct device));
return dev;
}
+struct device_alias*
+device_alloc_alias(struct device_meta* parent, struct device_meta* aliased)
+{
+ struct device_alias* dev = vzalloc(sizeof(struct device_alias));
+
+ if (!dev) {
+ return NULL;
+ }
+
+ device_init_meta(dev_meta(dev), parent, DEV_ALIAS);
+ dev->alias = aliased;
+
+ return dev;
+}
+
+struct device_cat*
+device_alloc_cat(struct device_meta* parent)
+{
+ struct device_cat* dev = vzalloc(sizeof(struct device_cat));
+
+ if (!dev) {
+ return NULL;
+ }
+
+ device_init_meta(dev_meta(dev), parent, DEV_CAT);
+
+ return dev;
+}
+
+
void
-device_setname(struct device* dev, char* fmt, ...)
+device_setname(struct device_meta* dev, char* fmt, ...)
{
va_list args;
va_start(args, fmt);
va_end(args);
}
-struct device*
-device_addcat(struct device* parent, char* name_fmt, ...)
+struct device_cat*
+device_addcat(struct device_meta* parent, char* name_fmt, ...)
{
va_list args;
va_start(args, name_fmt);
- struct device* dev = device_alloc(parent, DEV_IFCAT, NULL);
+ struct device_cat* dev = device_alloc_cat(parent);
- device_setname_vargs(dev, name_fmt, args);
- device_register(dev, NULL, NULL);
+ device_setname_vargs(dev_meta(dev), name_fmt, args);
+ device_register_generic(dev_meta(dev), NULL, NULL);
va_end(args);
return dev;
}
-struct device*
+struct device_alias*
+device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...)
+{
+ va_list args;
+ va_start(args, name_fmt);
+
+ struct device_alias* dev = device_alloc_alias(parent, aliased);
+
+ device_setname_vargs(dev_meta(dev), name_fmt, args);
+ device_register_generic(dev_meta(dev), NULL, NULL);
+
+ va_end(args);
+ return dev;
+}
+
+struct device_meta*
device_getbyid(struct llist_header* devlist, u32_t id)
{
devlist = devlist ? devlist : &root_list;
- struct device *pos, *n;
+ struct device_meta *pos, *n;
llist_for_each(pos, n, devlist, siblings)
{
if (pos->dev_uid == id) {
return NULL;
}
-struct device*
-device_getbyhname(struct device* root_dev, struct hstr* name)
+struct device_meta*
+device_getbyhname(struct device_meta* root_dev, struct hstr* name)
{
struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
- struct device *pos, *n;
+ struct device_meta *pos, *n;
llist_for_each(pos, n, devlist, siblings)
{
if (HSTR_EQ(&pos->name, name)) {
return NULL;
}
-struct device*
-device_getbyname(struct device* root_dev, const char* name, size_t len)
+struct device_meta*
+device_getbyname(struct device_meta* root_dev, const char* name, size_t len)
{
struct hstr hname = HSTR(name, len);
hstr_rehash(&hname, HSTR_FULL_HASH);
}
void
-device_remove(struct device* dev)
+device_remove(struct device_meta* dev)
{
llist_delete(&dev->siblings);
vfree(dev);
}
-struct device*
-device_getbyoffset(struct device* root_dev, int offset)
+struct device_meta*
+device_getbyoffset(struct device_meta* root_dev, int offset)
{
struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
- struct device *pos, *n;
+ struct device_meta *pos, *n;
int off = 0;
llist_for_each(pos, n, devlist, siblings)
{
devinfo->dev_name.buf[buflen - 1] = 0;
}
+struct device_meta*
+resolve_device_meta(void* maybe_dev) {
+ if (!valid_device_ref(maybe_dev)) {
+ return NULL;
+ }
+
+ struct device_meta* dm = (struct device_meta*)maybe_dev;
+ unsigned int subtype = dm->magic ^ DEV_STRUCT_MAGIC_MASK;
+
+ switch (subtype)
+ {
+ case DEV_STRUCT:
+ case DEV_CAT:
+ return dm;
+
+ case DEV_ALIAS: {
+ struct device_meta* aliased_dm = dm;
+
+ while(valid_device_subtype_ref(aliased_dm, DEV_ALIAS)) {
+ aliased_dm = to_aliasdev(aliased_dm)->alias;
+ }
+
+ return aliased_dm;
+ }
+ default:
+ return NULL;
+ }
+}
+
struct device*
-device_cast(void* obj)
-{
- struct device* dev = (struct device*)obj;
- if (dev && dev->magic == DEV_STRUCT_MAGIC) {
- return dev;
+resolve_device(void* maybe_dev) {
+ struct device_meta* dm = resolve_device_meta(maybe_dev);
+
+ if (!valid_device_subtype_ref(dm, DEV_STRUCT)) {
+ return NULL;
}
- return NULL;
+ return to_dev(dm);
}
void
}
struct device* dev = (struct device*)fd_s->file->inode->data;
- if (dev->magic != DEV_STRUCT_MAGIC) {
+ if (valid_device_subtype_ref(dev, DEV_STRUCT)) {
errno &= ENODEV;
goto done;
}
static DEFINE_LLIST(listener_chain);
-static struct device* input_devcat = NULL;
+static struct device_cat* input_devcat = NULL;
void
input_init()
va_list args;
va_start(args, name_fmt);
- struct device* dev = device_allocseq(input_devcat, idev);
+ struct device* dev = device_allocseq(dev_meta(input_devcat), idev);
- device_setname_vargs(dev, name_fmt, args);
- device_register(dev, class, NULL);
+ device_setname_vargs(dev_meta(dev), name_fmt, args);
+ register_device(dev, class, NULL);
idev->dev_if = dev;
dev->ops.read = __input_dev_read;
struct device* dev;
int evt = 0;
- if ((dev = device_cast(poller->file_ref->inode->data))) {
+ if ((dev = resolve_device(poller->file_ref->inode->data))) {
dev->ops.poll(dev);
} else {
// TODO handle generic file
return 0;
}
-#define fd2dev(fd) device_cast((fd)->file->inode->data)
+#define fd2dev(fd) resolve_device((fd)->file->inode->data)
static int
__alloc_pld()
#include <lunaix/fs.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/fs/twimap.h>
+#include <lunaix/fs/twifs.h>
+
#define HASH_BUCKET_BITS 4
#define HASH_BUCKET_NUM (1 << HASH_BUCKET_BITS)
+DEFINE_LLIST(fs_flatlist);
DECLARE_HASHTABLE(fs_registry, HASH_BUCKET_NUM);
void
{
hstr_rehash(&fs->fs_name, HSTR_FULL_HASH);
hashtable_hash_in(fs_registry, &fs->fs_list, fs->fs_name.hash);
+ llist_append(&fs_flatlist, &fs->fs_flat);
}
struct filesystem*
}
fs->fs_name = HHSTR(name, name_len, 0);
return fs;
-}
\ No newline at end of file
+}
+
+static void
+read_fslist(struct twimap *mapping)
+{
+ struct filesystem *pos, *n;
+ llist_for_each(pos, n, &fs_flatlist, fs_flat)
+ {
+ twimap_printf(mapping, "%s %d\n", pos->fs_name.value, pos->types);
+ }
+}
+
+static void
+fstab_twifs_plugin()
+{
+ struct twimap* map = twifs_mapping(NULL, NULL, "fstab");
+ map->read = read_fslist;
+}
+EXPORT_TWIFS_PLUGIN(fstab, fstab_twifs_plugin);
\ No newline at end of file
llist_append(&parent->submnts, &mnt->sibmnts);
mutex_unlock(&mnt->parent->lock);
}
-
+
atomic_fetch_add(&mnt_point->ref_count, 1);
return mnt;
mnt_chillax(mnt->parent);
vfs_sb_free(sb);
- vfs_d_free(mnt->mnt_point);
+ atomic_fetch_sub(&mnt->mnt_point->ref_count, 1);
vfree(mnt);
return errno;
struct device*
probe_boot_medium()
{
- struct device* block_cat = device_getbyname(NULL, "block", 5);
+ struct device_meta* block_cat = device_getbyname(NULL, "block", 5);
if (!block_cat) {
return NULL;
}
struct iso_vol_primary* volp = valloc(ISO9660_BLKSZ);
- struct device *pos, *n;
+ struct device* dev = NULL;
+ struct device_meta *pos, *n;
llist_for_each(pos, n, &block_cat->children, siblings)
{
+ dev = resolve_device(pos);
+ if (!dev) {
+ continue;
+ }
+
int errno =
- pos->ops.read(pos, (void*)volp, ISO9660_READ_OFF, ISO9660_BLKSZ);
+ dev->ops.read(dev, (void*)volp, ISO9660_READ_OFF, ISO9660_BLKSZ);
if (errno < 0) {
kprintf(KINFO "failed %xh:%xh, /dev/%s",
- pos->ident.fn_grp,
- pos->ident.unique,
- pos->name.value);
- pos = NULL;
+ dev->ident.fn_grp,
+ dev->ident.unique,
+ dev->name.value);
+ dev = NULL;
goto done;
}
if (*(u32_t*)volp->sys_id == LUNAIX_ID) {
kprintf(KINFO "%xh:%xh, /dev/%s, %s",
- pos->ident.fn_grp,
- pos->ident.unique,
- pos->name.value,
+ dev->ident.fn_grp,
+ dev->ident.unique,
+ dev->name.value,
(char*)volp->vol_id);
break;
}
done:
vfree(volp);
- return pos;
+ return dev;
}
\ No newline at end of file
vfs_ref_dnode(struct v_dnode* dnode)
{
atomic_fetch_add(&dnode->ref_count, 1);
- mnt_mkbusy(dnode->mnt);
+
+ if (dnode->mnt) {
+ mnt_mkbusy(dnode->mnt);
+ }
}
void
vfs_unref_dnode(struct v_dnode* dnode)
{
atomic_fetch_sub(&dnode->ref_count, 1);
- mnt_chillax(dnode->mnt);
+ if (dnode->mnt) {
+ mnt_chillax(dnode->mnt);
+ }
}
int
.st_blksize = vino->sb->blksize};
if (VFS_DEVFILE(vino->itype)) {
- struct device* rdev = (struct device*)vino->data;
+ struct device* rdev = resolve_device(vino->data);
if (!rdev || rdev->magic != DEV_STRUCT_MAGIC) {
errno = EINVAL;
goto done;
s->len = 0;
s->pos = i;
+ if (!ctx->cmdline[i]) {
+ return false;
+ }
+
while((c = ctx->cmdline[i++])) {
if (c == ' ') {
while ((c = ctx->cmdline[i++]) && c == ' ');
state = PARSE_VAL;
s = &ctx->val;
s->len = 0;
- s->pos = i + 1;
+ s->pos = i;
continue;
}
}
- while ((c = ctx->cmdline[i++]) && c != ' ') {
- s->len++;
- }
-
- i--;
+ s->len++;
}
- ctx->pos = i;
+ ctx->pos = i - 1;
- return !!c;
+ return true;
}
#define MAX_KEYSIZE 16
+#include <lunaix/types.h>
#include <lunaix/block.h>
#include <lunaix/boot_generic.h>
#include <lunaix/device.h>
#include <lunaix/spike.h>
#include <lunaix/trace.h>
#include <lunaix/tty/tty.h>
-#include <lunaix/types.h>
+#include <lunaix/owloysius.h>
#include <hal/acpi/acpi.h>
#include <hal/intc.h>
block_init();
sched_init();
- device_onbooot_load();
+ device_onboot_load();
/* the bare metal are now happy, let's get software over with */
- int errno = 0;
- if ((errno = vfs_mount_root("ramfs", NULL))) {
- panickf("Fail to mount root. (errno=%d)", errno);
- }
+ must_success(vfs_mount_root("ramfs", NULL));
+ must_success(vfs_mount("/dev", "devfs", NULL, 0));
+
+ invoke_init_function(call_on_boot);
+
+ must_success(vfs_unmount("/dev"));
/* Finish up bootstrapping sequence, we are ready to spawn the root process
* and start geting into uspace
ent->lvl = lvl;
ent->content = _content;
ent->time = clock_systime();
+ ent->len = len;
return ent;
}
\ No newline at end of file
int lvl;
time_t time;
char* content;
+ size_t len;
};
#define KP_ENT_SIZE sizeof(struct kp_entry)
#include <lunaix/fs/twimap.h>
#include <lunaix/syscall.h>
#include <lunaix/syslog.h>
+#include <lunaix/device.h>
+#include <lunaix/owloysius.h>
-#include <lunaix/lxconsole.h>
+#include <hal/term.h>
#include <klibc/strfmt.h>
.max_recs = MAX_KPENT_NUM,
.kp_ent_wp = &kprecs.kp_ents.ents
};
+export_symbol(debug, kprecs);
static char*
shift_level(const char* str, int* level)
kprintf_ml(const char* component, int level, const char* fmt, va_list args)
{
char* buf = &tmp_buf[MAX_BUFSZ_HLF];
- ksnprintf(buf, MAX_BUFSZ_HLF, "%s: %s", component, fmt);
+ ksnprintf(buf, MAX_BUFSZ_HLF, "%s: %s\n", component, fmt);
size_t sz = ksnprintfv(tmp_buf, buf, MAX_BUFSZ_HLF, args);
kprec_put(&kprecs, level, tmp_buf, sz);
- // FIXME temp measure, get some output
- console_write_str(tmp_buf);
- console_write_char('\n');
+ if (likely(sysconsole)) {
+ sysconsole->ops.write(sysconsole, tmp_buf, 0, sz);
+ }
}
void
static void
__twimap_kprintf_read(struct twimap* map)
{
- struct kp_records* kprecs = twimap_data(map, struct kp_records*);
+ struct kp_records* __kprecs = twimap_data(map, struct kp_records*);
/*
XXX we can foreach all records in a single twimap read call,
as records is monotonic increasing by design.
*/
struct kp_entry *pos, *n;
- llist_for_each(pos, n, kprecs->kp_ent_wp, ents)
+ llist_for_each(pos, n, __kprecs->kp_ent_wp, ents)
{
time_t s = pos->time / 1000;
time_t ms = pos->time % 1000;
}
EXPORT_TWIFS_PLUGIN(kprintf, kprintf_mapping_init);
+
+static void kprintf_init() {
+ if (unlikely(!sysconsole)) {
+ return;
+ }
+
+ struct kp_entry *pos, *n;
+ llist_for_each(pos, n, kprecs.kp_ent_wp, ents)
+ {
+ sysconsole->ops.write(sysconsole, pos->content, 0, pos->len);
+ }
+}
+lunaix_initfn(kprintf_init, call_on_postboot);
+
__DEFINE_LXSYSCALL3(void, syslog, int, level, const char*, fmt, va_list, args)
{
kprintf_ml("syslog", level, fmt, args);
-#include <lunaix/block.h>
#include <lunaix/boot_generic.h>
#include <lunaix/exec.h>
#include <lunaix/foptions.h>
#include <lunaix/fs.h>
#include <lunaix/fs/probe_boot.h>
#include <lunaix/fs/twifs.h>
-#include <lunaix/lxconsole.h>
-#include <lunaix/mm/cake.h>
-#include <lunaix/mm/pmm.h>
-#include <lunaix/mm/valloc.h>
-#include <lunaix/mm/vmm.h>
-#include <lunaix/peripheral/serial.h>
#include <lunaix/spike.h>
-#include <lunaix/syscall.h>
#include <lunaix/syslog.h>
#include <lunaix/types.h>
-
-#include <sdbg/protocol.h>
+#include <lunaix/owloysius.h>
#include <klibc/string.h>
init_proc_user_space(__current);
if (!mount_bootmedium() || !exec_initd()) {
- while (1) {
- asm("hlt");
- }
+ FATAL("failed to initd");
// should not reach
}
}
init_platform()
{
device_postboot_load();
+ invoke_init_function(call_on_postboot);
twifs_register_plugins();
// FIXME Re-design needed!!
// sdbg_init();
-
- // console
- console_start_flushing();
- console_flush();
}
\ No newline at end of file
return -1;
}
-send_grp:
+send_grp: ;
struct proc_info *pos, *n;
llist_for_each(pos, n, &proc->grp_member, grp_member)
{
waitq_init(&lx_reader);
input_add_listener(__lxconsole_listener);
- device_register(tty_dev, &devdef->class, "tty");
+ register_device(tty_dev, &devdef->class, "vcon");
return 0;
}
.class = DEVCLASSV(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN, 12),
.init = lxconsole_spawn_ttydev
};
+// FIXME
EXPORT_DEVICE(lxconsole, &lxconsole_def, load_onboot);
\ No newline at end of file
PROVIDE(__lga_fs_end = .);
+ /* ---- */
+
+ . = ALIGN(8);
+
+ PROVIDE(__lga_lunainit_call_on_boot_start = .);
+
+ KEEP(*(.lga.lunainit.c_boot));
+
+ PROVIDE(__lga_lunainit_call_on_boot_end = .);
+
+ /* ---- */
+
+ . = ALIGN(8);
+
+ PROVIDE(__lga_lunainit_call_on_postboot_start = .);
+
+ KEEP(*(.lga.lunainit.c_postboot));
+
+ PROVIDE(__lga_lunainit_call_on_postboot_end = .);
+
}
.bss BLOCK(4K) : AT ( ADDR(.bss) - 0xC0000000 ) {
instable: all
all-debug: bootable-debug
- @echo "Dumping the disassembled kernel code to $(kbuild_dir)/kdump.txt"
clean:
@rm -rf $(kbuild_dir) || exit 1
@i686-elf-objcopy --only-keep-debug $(kbin) $(kbuild_dir)/kernel.dbg
@qemu-system-i386 $(call get_qemu_options,$(kimg))
@sleep 1
- @QMPORT=$(QEMU_MON_PORT) gdb -s $(kbuild_dir)/kernel.dbg -ex "target remote localhost:1234"
+ @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
-fno-optimize-strlen\
-fno-inline-functions-called-once \
-fno-inline-small-functions \
- -fno-indirect-inlining
+ -fno-indirect-inlining\
+ -fno-omit-frame-pointer
CFLAGS := $(ARCH_OPT) -std=gnu99 -MMD $(OFLAGS) $(W)
-#!/usr/bin/env bash
+#!/bin/bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
echo "source \"${SCRIPT_DIR}/gdbinit.py\"" >> ~/.gdbinit
\ No newline at end of file
from .region_dump import MemoryRegionDump
from .proc_table_dump import ProcessDump, ProcessTableDump
+from .syslog import SysLogDump
def load_commands():
MemoryRegionDump()
ProcessTableDump()
- ProcessDump()
\ No newline at end of file
+ ProcessDump()
+ SysLogDump()
\ No newline at end of file
import gdb
-from .utils import pid_argument
+from .utils import pid_argument, llist_foreach
class MemoryRegionDump(gdb.Command):
"""Dump virtual memory regions associated with a process"""
def __init__(self) -> None:
super().__init__("vmrs", gdb.COMMAND_USER)
+ def region_callback(self, idx, region):
+ print(f"VMR #{idx}:")
+ print( " 0x%x...0x%x [0x%x]"%(
+ region['start'], region['end'],
+ region['end'] - region['start']))
+
+ attr = region["attr"]
+ attr_str = []
+ if (attr & (1 << 2)):
+ attr_str.append("R")
+ if (attr & (1 << 3)):
+ attr_str.append("W")
+ if (attr & (1 << 4)):
+ attr_str.append("X")
+ print( " attr: 0x%x (%s)"%(attr, "".join(attr_str)))
+
+ file = region["mfile"]
+ if file == 0:
+ print( " anonymous region")
+ else:
+ print( " file mapped:")
+ print( " dnode: %s @0x%x"%(file["dnode"]["name"]["value"].string(), file))
+ print( " frange: 0x%x+0x%x"%(region["foff"], region["flen"]))
+
def invoke(self, argument: str, from_tty: bool) -> None:
argument = pid_argument(argument)
print("VMRS (pid: %d)"%(pid))
- i = 0
- while(val["next"] != head):
- region = val["next"].cast(region_t)
- print(f"VMR #{i}:")
- print( " 0x%x...0x%x [0x%x]"%(
- region['start'], region['end'],
- region['end'] - region['start']))
-
- attr = region["attr"]
- attr_str = []
- if (attr & (1 << 2)):
- attr_str.append("R")
- if (attr & (1 << 3)):
- attr_str.append("W")
- if (attr & (1 << 4)):
- attr_str.append("X")
- print( " attr: 0x%x (%s)"%(attr, "".join(attr_str)))
-
- file = region["mfile"]
- if file == 0:
- print( " anonymous region")
- else:
- print( " file mapped:")
- print( " dnode: %s @0x%x"%(file["dnode"]["name"]["value"].string(), file))
- print( " frange: 0x%x+0x%x"%(region["foff"], region["flen"]))
-
- val = val["next"]
- i+=1
+ llist_foreach(val, region_t, lambda a,b: self.region_callback(a,b))
--- /dev/null
+import gdb
+from enum import StrEnum
+
+class SymbolDomain(StrEnum):
+ DEBUG = "debug"
+
+class LunaixSymbols:
+ class SymbolAccesser:
+ def __init__(self, sym) -> None:
+ self.sym = f"({sym})"
+
+ def deref_and_access(self, members):
+ return gdb.parse_and_eval(f"{self.sym}->{members}")
+
+ def access(self, members):
+ return gdb.parse_and_eval(f"{self.sym}.{members}")
+
+ @staticmethod
+ def exported(domain, sym_name):
+ name = f"*__SYMEXPORT_Z{domain.value}_{sym_name}"
+ return LunaixSymbols.SymbolAccesser(name)
\ No newline at end of file
--- /dev/null
+import gdb
+from .symbols import LunaixSymbols, SymbolDomain
+from .utils import llist_foreach
+
+class SysLogDump(gdb.Command):
+ """Dump the system log"""
+ def __init__(self) -> None:
+ super().__init__("syslog", gdb.COMMAND_USER)
+ self.log_level = ["debug", "info", "warn", "error", "fatal"]
+
+ def syslog_entry_callback(self, idx, ent):
+ time = ent["time"]
+ lvl = ent["lvl"]
+ log = ent["content"]
+
+ time_str = "%04d.%03d"%(int(time / 1000), time % 1000)
+ print(f"[{time_str}] <L{self.log_level[lvl]}> {log.string()}")
+
+ def invoke(self, argument: str, from_tty: bool) -> None:
+ log_recs = LunaixSymbols.exported(SymbolDomain.DEBUG, "kprecs")
+ head = log_recs.deref_and_access("kp_ents.ents").address
+
+ ent_type = gdb.lookup_type("struct kp_entry").pointer()
+ llist_foreach(head, ent_type, lambda a,b: self.syslog_entry_callback(a, b))
\ No newline at end of file
+import gdb
def pid_argument(argument):
if not argument:
return "__current"
else:
- return f"sched_ctx._procs[({argument})]"
\ No newline at end of file
+ return f"sched_ctx._procs[({argument})]"
+
+def llist_foreach(head, container_type, cb):
+ c = head
+ i = 0
+ while (c["next"] != head):
+ el = c["next"].cast(container_type)
+ cb(i, el)
+ c = c["next"]
+ i+=1
\ No newline at end of file