WIP 2
This commit is contained in:
@ -1,3 +1,3 @@
|
||||
%print "this is an init script!"
|
||||
%print 'this is an init script!'
|
||||
base:/bin/pctl ls
|
||||
base:/bin/tb -m interactive -preload base:/scripts/rc.tb
|
||||
|
@ -55,7 +55,6 @@ SRCFILES += $(call GRABSRC, \
|
||||
proc \
|
||||
proc/kproc \
|
||||
proc/ps2kbproc \
|
||||
proc/termproc \
|
||||
proc/serialproc \
|
||||
hal \
|
||||
hal/$(ARCH) \
|
||||
@ -67,6 +66,7 @@ SRCFILES += $(call GRABSRC, \
|
||||
rbuf \
|
||||
ipc/pipe \
|
||||
drivers/ps2kb \
|
||||
dev \
|
||||
)
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
|
@ -11,7 +11,7 @@ CFLAGS += -m64 \
|
||||
-mno-red-zone \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-O0 \
|
||||
-Os \
|
||||
|
||||
LDFLAGS += -m elf_x86_64 \
|
||||
-pie \
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <stdbool.h>
|
||||
#include "bitmap.h"
|
||||
#include "util/util.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
void *bitmap_toptr(BitMap *bm, size_t block) {
|
||||
uint8_t *ptr = (uint8_t *)(bm->mem_start + (block * BITMAP_BLOCK_SIZE));
|
||||
@ -104,13 +105,3 @@ void *bitmap_alloc(BitMap *bm, size_t blocks) {
|
||||
void bitmap_free(BitMap *bm, void *base, size_t blocks) {
|
||||
bitmap_markregion(bm, base, BITMAP_BLOCK_SIZE * blocks, 0);
|
||||
}
|
||||
|
||||
size_t bitmap_allocpageframe(BitMap *bm) {
|
||||
size_t pickedreg = bitmap_freeregion(bm, 1);
|
||||
bitmap_markblocks(bm, pickedreg, 1, 1);
|
||||
return (bm->mem_start + (pickedreg * BITMAP_BLOCK_SIZE));
|
||||
}
|
||||
|
||||
void bitmap_freepageframe(BitMap *bm, void *addr) {
|
||||
bitmap_markregion(bm, addr, BITMAP_BLOCK_SIZE * 1, 0);
|
||||
}
|
||||
|
@ -31,7 +31,5 @@ void bitmap_markregion(BitMap *bm, void *baseptr, size_t size, bool is_used);
|
||||
size_t bitmap_freeregion(BitMap *bm, size_t blocks);
|
||||
void *bitmap_alloc(BitMap *bm, size_t blocks);
|
||||
void bitmap_free(BitMap *bm, void *base, size_t blocks);
|
||||
size_t bitmap_allocpageframe(BitMap *bm);
|
||||
void bitmap_freepageframe(BitMap *bm, void *addr);
|
||||
|
||||
#endif // BITMAP_BITMAP_H_
|
||||
|
14
kernel/dev/dev.h
Normal file
14
kernel/dev/dev.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef DEV_DEV_H_
|
||||
#define DEV_DEV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DEV_FNS_MAX 32
|
||||
|
||||
typedef int32_t (*DevFn)(uint8_t *buffer, size_t len, void *extra);
|
||||
|
||||
typedef struct {
|
||||
DevFn fns[DEV_FNS_MAX];
|
||||
} Dev;
|
||||
|
||||
#endif // DEV_DEV_H_
|
19
kernel/dev/termdev.c
Normal file
19
kernel/dev/termdev.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
#include "termdev.h"
|
||||
#include "dev.h"
|
||||
#include "errors.h"
|
||||
|
||||
Dev TERMDEV;
|
||||
|
||||
int32_t termdev_putch(uint8_t *buffer, size_t len, void *extra) {
|
||||
kprintf("%.*s", (int)len, (char *)buffer);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
void termdev_init(void) {
|
||||
hal_memset(&TERMDEV, 0, sizeof(TERMDEV));
|
||||
TERMDEV.fns[0] = &termdev_putch;
|
||||
}
|
13
kernel/dev/termdev.h
Normal file
13
kernel/dev/termdev.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef DEV_TERMDEV_H_
|
||||
#define DEV_TERMDEV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "dev.h"
|
||||
|
||||
int32_t termdev_putch(uint8_t *buffer, size_t len, void *extra);
|
||||
void termdev_init(void);
|
||||
|
||||
extern Dev TERMDEV;
|
||||
|
||||
#endif // DEV_TERMDEV_H_
|
@ -49,7 +49,7 @@ int RELEASE_LOCK(SpinLock *sl) {
|
||||
}
|
||||
|
||||
int INITIAL_LOCK(SpinLock *sl) {
|
||||
spinlock_release(sl);
|
||||
spinlock_init(sl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define GDT_PRESENT 0x80
|
||||
#define GDT_TSS 0x89
|
||||
|
||||
#define KSTACK 8192
|
||||
#define KSTACK (1024*2*4096)
|
||||
ALIGNED(16) static uint8_t kernelstack[KSTACK];
|
||||
|
||||
typedef struct {
|
||||
|
@ -178,8 +178,6 @@ void hal_syscalldispatch(IntrStackFrame *frame) {
|
||||
frame->regs.rax = E_BADSYSCALL;
|
||||
return;
|
||||
}
|
||||
uint64_t cr3;
|
||||
asm volatile("mov %%cr3, %0" : "=r"(cr3));
|
||||
int32_t ret = fn(frame, frame->regs.rdi, frame->regs.rsi, frame->regs.rdx,
|
||||
frame->regs.r10, frame->regs.r8, frame->regs.r9);
|
||||
|
||||
@ -215,7 +213,7 @@ void intr_handleintr(IntrStackFrame *frame) {
|
||||
break;
|
||||
case INTR_IRQBASE+1:
|
||||
int32_t c = ps2kb_intr();
|
||||
if (c >= 0) {
|
||||
if (c >= 0 && PS2KB_BUF.init) {
|
||||
uint8_t b = c;
|
||||
spinlock_acquire(&PS2KB_BUF.spinlock);
|
||||
rbuf_push(&PS2KB_BUF.rbuf, b);
|
||||
|
@ -62,13 +62,13 @@
|
||||
.endm
|
||||
|
||||
.macro _vecintr_bodygen
|
||||
cli
|
||||
_push_regs
|
||||
cld
|
||||
mov %rsp, %rdi
|
||||
movq %rsp, %rdi
|
||||
call intr_handleintr
|
||||
_pop_regs
|
||||
add $0x10, %rsp
|
||||
|
||||
iretq
|
||||
.endm
|
||||
|
||||
|
@ -2,15 +2,11 @@
|
||||
|
||||
.global hal_switchproc
|
||||
hal_switchproc:
|
||||
mov %cr3, %rcx
|
||||
cmp %rsi, %rcx
|
||||
je .done
|
||||
mov %rsi, %cr3
|
||||
.done:
|
||||
testq %rsi, %rsi
|
||||
je 1f
|
||||
movq %rsi, %cr3
|
||||
1:
|
||||
mov %rdi, %rsp
|
||||
|
||||
_pop_regs
|
||||
add $0x10, %rsp
|
||||
|
||||
iretq
|
||||
|
||||
|
@ -29,12 +29,16 @@ PgIndex hal_vmm_pageindex(uint64_t vaddr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t *hal_vmm_nexttable(uint64_t *table, uint64_t ent) {
|
||||
uint64_t *hal_vmm_nexttable(uint64_t *table, uint64_t ent, bool alloc) {
|
||||
uint64_t entry = table[ent];
|
||||
uint64_t phys;
|
||||
if (entry & HAL_PG_PRESENT) {
|
||||
phys = entry & ~0xFFFULL;
|
||||
} else {
|
||||
if (!alloc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *newphys = pmm_alloc(1);
|
||||
phys = (uint64_t)newphys;
|
||||
hal_memset(VIRT(phys), 0, HAL_PAGE_SIZE);
|
||||
@ -47,9 +51,9 @@ void hal_vmm_map_page(uint64_t cr3phys, uint64_t virtaddr, uint64_t physaddr, ui
|
||||
uint64_t *pml4 = (uint64_t *)VIRT(cr3phys);
|
||||
PgIndex pi = hal_vmm_pageindex(virtaddr);
|
||||
|
||||
uint64_t *pml3 = hal_vmm_nexttable(pml4, pi.pml4);
|
||||
uint64_t *pml2 = hal_vmm_nexttable(pml3, pi.pml3);
|
||||
uint64_t *pml1 = hal_vmm_nexttable(pml2, pi.pml2);
|
||||
uint64_t *pml3 = hal_vmm_nexttable(pml4, pi.pml4, true);
|
||||
uint64_t *pml2 = hal_vmm_nexttable(pml3, pi.pml3, true);
|
||||
uint64_t *pml1 = hal_vmm_nexttable(pml2, pi.pml2, true);
|
||||
uint64_t *pte = &pml1[pi.pml1];
|
||||
|
||||
*pte = (physaddr & ~0xFFFULL) | ((uint64_t)flags & 0x7ULL);
|
||||
@ -59,9 +63,9 @@ void hal_vmm_unmap_page(uint64_t cr3phys, uint64_t virtaddr, uint64_t physaddr)
|
||||
uint64_t *pml4 = (uint64_t *)VIRT(cr3phys);
|
||||
PgIndex pi = hal_vmm_pageindex(virtaddr);
|
||||
|
||||
uint64_t *pml3 = hal_vmm_nexttable(pml4, pi.pml4);
|
||||
uint64_t *pml2 = hal_vmm_nexttable(pml3, pi.pml3);
|
||||
uint64_t *pml1 = hal_vmm_nexttable(pml2, pi.pml2);
|
||||
uint64_t *pml3 = hal_vmm_nexttable(pml4, pi.pml4, false);
|
||||
uint64_t *pml2 = hal_vmm_nexttable(pml3, pi.pml3, false);
|
||||
uint64_t *pml1 = hal_vmm_nexttable(pml2, pi.pml2, false);
|
||||
uint64_t *pte = &pml1[pi.pml1];
|
||||
|
||||
*pte &= ~HAL_PG_PRESENT;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "storedev/storedev.h"
|
||||
#include "util/util.h"
|
||||
#include "proc/proc.h"
|
||||
#include "dev/termdev.h"
|
||||
|
||||
const char *human_size(uint64_t bytes, char *buf, size_t bufsize) {
|
||||
static const char *units[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" };
|
||||
@ -64,6 +65,7 @@ void kmain(void) {
|
||||
storedev_init();
|
||||
baseimg_init();
|
||||
vfs_init();
|
||||
termdev_init();
|
||||
proc_init();
|
||||
|
||||
for(;;);
|
||||
|
@ -40,6 +40,9 @@ void pmm_init(void) {
|
||||
hal_memset(bm->map, 0xff, bm->nbytes);
|
||||
for (size_t i = 0; i < BOOT_INFO.memmap_entrycount; i++) {
|
||||
struct limine_memmap_entry *entry = BOOT_INFO.memmap_entries[i];
|
||||
if (entry == memmap_ent) {
|
||||
continue;
|
||||
}
|
||||
// mark usable as 0 and unusable as 1
|
||||
bitmap_markregion(bm, (void *)entry->base, entry->length, entry->type != LIMINE_MEMMAP_USABLE);
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "ipc/pipe/pipe.h"
|
||||
#include "kproc/kproc.h"
|
||||
#include "ps2kbproc/ps2kbproc.h"
|
||||
#include "termproc/termproc.h"
|
||||
#include "serialproc/serialproc.h"
|
||||
#include "sysdefs/processctl.h"
|
||||
|
||||
@ -181,6 +180,7 @@ Proc *proc_spawnuser(char *mountpoint, char *path) {
|
||||
proc->mman_map_base = PROC_MMAN_MAP_BASE;
|
||||
spinlock_init(&proc->bcast_pipes.spinlock);
|
||||
spinlock_init(&proc->pipes_spinlock);
|
||||
spinlock_init(&proc->devs_spinlock);
|
||||
|
||||
proc->pipes[0] = dlmalloc(sizeof(IpcPipe));
|
||||
ipc_pipeinit(proc->pipes[0], proc->pid);
|
||||
@ -308,26 +308,20 @@ void proc_init(void) {
|
||||
spinlock_init(&PROCS.spinlock);
|
||||
PROCS.procs = NULL;
|
||||
|
||||
kproc_init(proc_spawnkern(&kproc_fn, "kproc"));
|
||||
proc_register(KPROC);
|
||||
PROCS.current = KPROC;
|
||||
KPROC->state = PROC_READY;
|
||||
/* kproc_init(proc_spawnkern(&kproc_fn, "kproc")); */
|
||||
/* proc_register(KPROC); */
|
||||
/* PROCS.current = KPROC; */
|
||||
/* KPROC->state = PROC_READY; */
|
||||
|
||||
ps2kbproc_init(proc_spawnkern(&ps2kbproc_fn, "ps2kbproc"));
|
||||
proc_register(PS2KBPROC);
|
||||
PS2KBPROC->state = PROC_READY;
|
||||
|
||||
termproc_init(proc_spawnkern(&termproc_fn, "termproc"));
|
||||
proc_register(TERMPROC);
|
||||
TERMPROC->state = PROC_READY;
|
||||
/* ps2kbproc_init(proc_spawnkern(&ps2kbproc_fn, "ps2kbproc")); */
|
||||
/* proc_register(PS2KBPROC); */
|
||||
/* PS2KBPROC->state = PROC_READY; */
|
||||
|
||||
/* serialproc_init(proc_spawnkern(&serialproc_fn, "serialproc")); */
|
||||
/* proc_register(SERIALPROC); */
|
||||
|
||||
Proc *init = proc_spawnuser("base", "/bin/init");
|
||||
ipc_pipefree(init->pipes[0]);
|
||||
dlfree(init->pipes[0]);
|
||||
init->pipes[0] = TERMPROC->pipes[1];
|
||||
PROCS.current = init;
|
||||
proc_register(init);
|
||||
init->state = PROC_READY;
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "vfs/vfs.h"
|
||||
#include "ipc/pipe/pipe.h"
|
||||
#include "sysdefs/processctl.h"
|
||||
#include "dev/dev.h"
|
||||
|
||||
#define PROC_NAME_MAX 0x100
|
||||
|
||||
@ -18,9 +19,10 @@
|
||||
|
||||
#define PROC_VFSHANDLES_MAX 0x80
|
||||
#define PROC_PIPEHANDLES_MAX 0x20
|
||||
#define PROC_DEVHANDLES_MAX 0x20
|
||||
|
||||
#define PROC_MMAN_MAP_BASE 0x0000100000000000ULL
|
||||
#define PROC_USER_STACK_TOP 0x0000800000000000ULL
|
||||
#define PROC_USER_STACK_TOP 0x00007FFFFFFFF000ULL
|
||||
|
||||
typedef struct {
|
||||
IntrStackFrame trapframe;
|
||||
@ -56,12 +58,18 @@ typedef struct Proc {
|
||||
|
||||
VfsObj *vobjs[PROC_VFSHANDLES_MAX];
|
||||
uint64_t vobjcnt;
|
||||
|
||||
IpcPipe *pipes[PROC_PIPEHANDLES_MAX];
|
||||
SpinLock pipes_spinlock;
|
||||
|
||||
struct {
|
||||
IpcPipe *list;
|
||||
SpinLock spinlock;
|
||||
} bcast_pipes;
|
||||
|
||||
Dev *devs[PROC_DEVHANDLES_MAX];
|
||||
SpinLock devs_spinlock;
|
||||
|
||||
struct {
|
||||
ProcArg *list;
|
||||
size_t len;
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "ps2kbproc.h"
|
||||
|
||||
Proc *PS2KBPROC = NULL;
|
||||
Ps2KbFastBuf PS2KB_BUF;
|
||||
Ps2KbFastBuf PS2KB_BUF = {0};
|
||||
|
||||
void ps2kbproc_init(Proc *proc) {
|
||||
PS2KBPROC = proc;
|
||||
@ -17,22 +17,23 @@ void ps2kbproc_init(Proc *proc) {
|
||||
uint8_t *buf = dlmalloc(IPC_PIPE_MAX);
|
||||
rbuf_init(&PS2KB_BUF.rbuf, buf, IPC_PIPE_MAX);
|
||||
spinlock_init(&PS2KB_BUF.spinlock);
|
||||
PS2KB_BUF.init = true;
|
||||
}
|
||||
|
||||
void ps2kbproc_fn(void) {
|
||||
for (;;) {
|
||||
uint8_t b = 0;
|
||||
spinlock_acquire(&PS2KB_BUF.spinlock);
|
||||
if (rbuf_pop(&PS2KB_BUF.rbuf, &b) == 0) {
|
||||
spinlock_acquire(&PS2KBPROC->bcast_pipes.spinlock);
|
||||
IpcPipe *head = PS2KBPROC->bcast_pipes.list;
|
||||
while (head != NULL) {
|
||||
ipc_pipewrite(head, &b, 1);
|
||||
head = head->next;
|
||||
}
|
||||
spinlock_release(&PS2KBPROC->bcast_pipes.spinlock);
|
||||
}
|
||||
spinlock_release(&PS2KB_BUF.spinlock);
|
||||
/* uint8_t b = 0; */
|
||||
/* spinlock_acquire(&PS2KB_BUF.spinlock); */
|
||||
/* if (rbuf_pop(&PS2KB_BUF.rbuf, &b) == 0) { */
|
||||
/* spinlock_acquire(&PS2KBPROC->bcast_pipes.spinlock); */
|
||||
/* IpcPipe *head = PS2KBPROC->bcast_pipes.list; */
|
||||
/* while (head != NULL) { */
|
||||
/* ipc_pipewrite(head, &b, 1); */
|
||||
/* head = head->next; */
|
||||
/* } */
|
||||
/* spinlock_release(&PS2KBPROC->bcast_pipes.spinlock); */
|
||||
/* } */
|
||||
/* spinlock_release(&PS2KB_BUF.spinlock); */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
typedef struct {
|
||||
RBuf rbuf;
|
||||
SpinLock spinlock;
|
||||
bool init;
|
||||
} Ps2KbFastBuf;
|
||||
|
||||
extern Proc *PS2KBPROC;
|
||||
|
@ -1,25 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include "proc/proc.h"
|
||||
#include "ipc/pipe/pipe.h"
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
|
||||
Proc *TERMPROC;
|
||||
|
||||
void termproc_init(Proc *proc) {
|
||||
TERMPROC = proc;
|
||||
TERMPROC->pipes[1] = dlmalloc(sizeof(IpcPipe));
|
||||
ipc_pipeinit(TERMPROC->pipes[1], TERMPROC->pid);
|
||||
}
|
||||
|
||||
void termproc_fn(void) {
|
||||
for (;;) {
|
||||
char c = 0;
|
||||
int32_t read = ipc_piperead(TERMPROC->pipes[1], (uint8_t *)&c, 1);
|
||||
if (read > 0) {
|
||||
kprintf("%c", c);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#ifndef PROC_TERMPROC_TERMPROC_H_
|
||||
#define PROC_TERMPROC_TERMPROC_H_
|
||||
|
||||
#include "proc/proc.h"
|
||||
|
||||
extern Proc *TERMPROC;
|
||||
|
||||
void termproc_init(Proc *proc);
|
||||
void termproc_fn(void);
|
||||
|
||||
#endif // PROC_TERMPROC_TERMPROC_H_
|
@ -5,25 +5,62 @@
|
||||
#include "hal/hal.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
#define SPINLOCK_IRQ_DBG 1
|
||||
|
||||
#define SPINLOCK_HINT() asm volatile("pause")
|
||||
|
||||
struct {
|
||||
atomic_uint64_t irq_flags;
|
||||
atomic_int irq_nest;
|
||||
} IRQ_CTX;
|
||||
|
||||
void spinlock_init(SpinLock *sl) {
|
||||
atomic_store(&sl->lock, false);
|
||||
sl->flags = 0;
|
||||
}
|
||||
|
||||
uint64_t spinlock_irqsave(void) {
|
||||
uint64_t irqsave(void) {
|
||||
uint64_t flags;
|
||||
asm volatile("pushfq; cli; popq %0" : "=r"(flags) :: "memory");
|
||||
asm volatile("pushfq; cli; popq %0" : "=r"(flags) :: "memory", "cc");
|
||||
return flags;
|
||||
}
|
||||
|
||||
void spinlock_irqrestore(uint64_t flags) {
|
||||
void irqrestore(uint64_t flags) {
|
||||
if (flags & (1<<9)) {
|
||||
asm volatile("sti" ::: "memory");
|
||||
asm volatile("sti" ::: "memory", "cc");
|
||||
}
|
||||
}
|
||||
|
||||
void irqsave_nested(void) {
|
||||
if (atomic_load(&IRQ_CTX.irq_nest) == 0) {
|
||||
atomic_store(&IRQ_CTX.irq_flags, irqsave());
|
||||
}
|
||||
atomic_inc(&IRQ_CTX.irq_nest);
|
||||
|
||||
#if SPINLOCK_IRQ_DBG
|
||||
if (atomic_load(&IRQ_CTX.irq_nest) < 0) {
|
||||
kprintf("IRQ_CTX.irq_nest underflow\n");
|
||||
hal_hang();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void irqrestore_nested(void) {
|
||||
#if SPINLOCK_IRQ_DBG
|
||||
int irq_nest = atomic_load(&IRQ_CTX.irq_nest);
|
||||
if (irq_nest <= 0) {
|
||||
kprintf("spinlock: irqs restored too many times: %d\n", irq_nest);
|
||||
hal_hang();
|
||||
}
|
||||
#endif
|
||||
|
||||
atomic_dec(&IRQ_CTX.irq_nest);
|
||||
if (atomic_load(&IRQ_CTX.irq_nest) == 0) {
|
||||
irqrestore(atomic_load(&IRQ_CTX.irq_flags));
|
||||
}
|
||||
}
|
||||
|
||||
void spinlock_acquire(SpinLock *sl) {
|
||||
sl->flags = spinlock_irqsave();
|
||||
irqsave_nested();
|
||||
|
||||
while (atomic_test_and_set_explicit(&sl->lock, memory_order_acquire)) {
|
||||
SPINLOCK_HINT();
|
||||
@ -33,6 +70,6 @@ void spinlock_acquire(SpinLock *sl) {
|
||||
void spinlock_release(SpinLock *sl) {
|
||||
atomic_clear_flag_explicit(&sl->lock, memory_order_release);
|
||||
|
||||
spinlock_irqrestore(sl->flags);
|
||||
irqrestore_nested();
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,8 @@
|
||||
|
||||
typedef struct {
|
||||
atomic_bool lock;
|
||||
uint64_t flags;
|
||||
} SpinLock;
|
||||
|
||||
#define SPINLOCK_HINT() asm volatile("pause")
|
||||
|
||||
void spinlock_init(SpinLock *sl);
|
||||
void spinlock_acquire(SpinLock *sl);
|
||||
void spinlock_release(SpinLock *sl);
|
||||
|
65
kernel/syscall/devctl.c
Normal file
65
kernel/syscall/devctl.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "kprintf.h"
|
||||
#include "syscall.h"
|
||||
#include "errors.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "proc/proc.h"
|
||||
#include "sysdefs/devctl.h"
|
||||
#include "dev/termdev.h"
|
||||
#include "util/util.h"
|
||||
|
||||
Dev *DEVS[] = {
|
||||
[0x10] = &TERMDEV,
|
||||
};
|
||||
|
||||
int32_t SYSCALL5(sys_devctl, devh1, cmd1, buffer1, len1, extra1) {
|
||||
uint64_t *devh = (uint64_t *)devh1;
|
||||
uint64_t cmd = cmd1;
|
||||
int32_t ret = E_OK;
|
||||
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc = PROCS.current;
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
switch (cmd) {
|
||||
case DEVCTL_GET_HANDLE: {
|
||||
uint64_t devid = buffer1;
|
||||
if (devid >= LEN(DEVS)) {
|
||||
ret = E_INVALIDARGUMENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < PROC_DEVHANDLES_MAX; i++) {
|
||||
if (proc->devs[i] == NULL) {
|
||||
found = true;
|
||||
proc->devs[i] = DEVS[devid];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ret = E_NOENTRY;
|
||||
goto done;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
if (devh == NULL) {
|
||||
ret = E_INVALIDARGUMENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cmd >= DEV_FNS_MAX) {
|
||||
ret = E_INVALIDARGUMENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
Dev *dev = proc->devs[*devh];
|
||||
ret = dev->fns[cmd]((uint8_t *)buffer1, (size_t)len1, (void *)extra1);
|
||||
} break;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
9
kernel/syscall/devctl.h
Normal file
9
kernel/syscall/devctl.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef SYSCALL_DEVCTL_H_
|
||||
#define SYSCALL_DEVCTL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "syscall.h"
|
||||
|
||||
int32_t SYSCALL5(sys_devctl, devh1, cmd1, buffer1, len1, extra1);
|
||||
|
||||
#endif // SYSCALL_DEVCTL_H_
|
@ -10,6 +10,7 @@
|
||||
#include "sysdefs/mman.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
int32_t SYSCALL5(sys_mman_map, addr1, size1, prot1, flags1, out1) {
|
||||
uint8_t *addr = (uint8_t *)addr1;
|
||||
@ -27,9 +28,6 @@ int32_t SYSCALL5(sys_mman_map, addr1, size1, prot1, flags1, out1) {
|
||||
|
||||
size_t pages = _DIV_ROUNDUP(size, HAL_PAGE_SIZE);
|
||||
uint8_t *phys = (uint8_t *)pmm_alloc(pages);
|
||||
if (phys == NULL) {
|
||||
return E_NOMEMORY;
|
||||
}
|
||||
hal_memset(VIRT(phys), 0, pages * HAL_PAGE_SIZE);
|
||||
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
|
@ -63,9 +63,11 @@ int32_t SYSCALL5(sys_processctl, pid1, cmd1, arg1, arg2, arg3) {
|
||||
|
||||
size_t argslen = arg3;
|
||||
char *(*args)[] = (char *(*)[])arg2;
|
||||
if (args != NULL && argslen > 0) {
|
||||
for (size_t i = 0; i < argslen; i++) {
|
||||
PROC_ARG(newproc, (*args)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < PROC_PIPEHANDLES_MAX; i++) {
|
||||
if (newproc->pipes[i] != NULL) {
|
||||
|
@ -11,7 +11,7 @@ int32_t SYSCALL0(sys_schedrelease) {
|
||||
Proc *proc = PROCS.current;
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
proc_sched((void *)frame);
|
||||
/* proc_sched((void *)frame); */
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "ipcpipe.h"
|
||||
#include "mman.h"
|
||||
#include "sched.h"
|
||||
#include "devctl.h"
|
||||
|
||||
int32_t SYSCALL1(sys_debugprint, string) {
|
||||
char *p = (char *)string;
|
||||
@ -23,4 +24,5 @@ SyscallFn SYSCALL_TABLE[SYSCALLS_MAX] = {
|
||||
[SYS_MMAN_MAP] = &sys_mman_map,
|
||||
[SYS_MMAN_UNMAP] = &sys_mman_unmap,
|
||||
[SYS_SCHEDRELEASE] = &sys_schedrelease,
|
||||
[SYS_DEVCTL] = &sys_devctl,
|
||||
};
|
||||
|
@ -58,14 +58,14 @@
|
||||
} while(0)
|
||||
|
||||
#define LL_FOREACH_SAFE(head, var, tmp) \
|
||||
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
|
||||
for (var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL; \
|
||||
var = tmp, tmp = (var ? var->next : NULL) \
|
||||
)
|
||||
|
||||
#define LL_FOREACH_SAFE_IDX(head, var, tmp, idx) \
|
||||
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL && ((idx) = 0, 1); \
|
||||
for ((idx) = 0, var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL; \
|
||||
var = tmp, tmp = (var ? var->next : NULL), (idx)++)
|
||||
|
||||
#define LL_FOREACH_SAFE_IDX_LIMIT(head, var, tmp, idx, max) \
|
||||
|
@ -10,4 +10,7 @@ CFLAGS += -m64 \
|
||||
-fno-stack-check \
|
||||
-fno-builtin \
|
||||
-fno-omit-frame-pointer \
|
||||
-O0 \
|
||||
-fno-strict-aliasing \
|
||||
-O1 \
|
||||
-mno-tls-direct-seg-refs \
|
||||
#-fsanitize=undefined
|
||||
|
10
share/sysdefs/devctl.h
Normal file
10
share/sysdefs/devctl.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef SHARE_SYSDEFS_DEVCTL_H_
|
||||
#define SHARE_SYSDEFS_DEVCTL_H_
|
||||
|
||||
enum {
|
||||
DEVCTL_GET_HANDLE = 100,
|
||||
};
|
||||
|
||||
typedef uint64_t Dev_t;
|
||||
|
||||
#endif // SHARE_SYSDEFS_DEVCTL_H_
|
@ -1,7 +1,7 @@
|
||||
#ifndef SHARE_HDRS_PROCESSCTL_H_
|
||||
#define SHARE_HDRS_PROCESSCTL_H_
|
||||
|
||||
#define PROC_ARG_MAX 0x400
|
||||
#define PROC_ARG_MAX 128
|
||||
|
||||
enum {
|
||||
PCTL_KILL = 0,
|
||||
|
@ -9,6 +9,7 @@ enum {
|
||||
SYS_MMAN_MAP = 5,
|
||||
SYS_MMAN_UNMAP = 6,
|
||||
SYS_SCHEDRELEASE = 7,
|
||||
SYS_DEVCTL = 8,
|
||||
};
|
||||
|
||||
#endif // SHARE_HDRS_SYSCALL_H_
|
||||
|
@ -11,14 +11,14 @@
|
||||
#define atomic_load_explicit __atomic_load_n
|
||||
#define atomic_store_explicit __atomic_store_n
|
||||
|
||||
#define atomic_store(p, v) atomic_store_explicit(p, v, memory_order_relaxed)
|
||||
#define atomic_load(p) atomic_load_explicit(p, memory_order_relaxed)
|
||||
#define atomic_store(p, v) atomic_store_explicit(p, v, memory_order_seq_cst)
|
||||
#define atomic_load(p) atomic_load_explicit(p, memory_order_seq_cst)
|
||||
|
||||
#define atomic_compare_exchange_weak(p, old, new) \
|
||||
__atomic_compare_exchange_n(p, old, new, true, memory_order_relaxed, memory_order_relaxed)
|
||||
__atomic_compare_exchange_n(p, old, new, true, memory_order_seq_cst, memory_order_seq_cst)
|
||||
|
||||
#define atomic_compare_exchange_strong(p, old, new) \
|
||||
__atomic_compare_exchange_n(p, old, new, false, memory_order_relaxed, memory_order_relaxed)
|
||||
__atomic_compare_exchange_n(p, old, new, false, memory_order_seq_cst, memory_order_seq_cst)
|
||||
|
||||
#define atomic_test_and_set_explicit(p, memory_order) \
|
||||
__atomic_test_and_set(p, memory_order)
|
||||
@ -26,6 +26,28 @@
|
||||
#define atomic_clear_flag_explicit(p, memory_order) \
|
||||
__atomic_clear(p, memory_order)
|
||||
|
||||
#define atomic_inc_explicit(p, memory_order) \
|
||||
__atomic_fetch_add(p, 1, memory_order)
|
||||
|
||||
#define atomic_inc(p) \
|
||||
atomic_inc_explicit(p, memory_order_seq_cst)
|
||||
|
||||
#define atomic_dec_explicit(p, memory_order) \
|
||||
__atomic_fetch_sub(p, 1, memory_order)
|
||||
|
||||
#define atomic_dec(p) \
|
||||
atomic_dec_explicit(p, memory_order_seq_cst)
|
||||
|
||||
#define atomic_bool _Atomic(bool)
|
||||
#define atomic_int _Atomic(int)
|
||||
#define atomic_uint _Atomic(unsigned int)
|
||||
#define atomic_int8_t _Atomic(int8_t)
|
||||
#define atomic_uint8_t _Atomic(uint8_t)
|
||||
#define atomic_int16_t _Atomic(int16_t)
|
||||
#define atomic_uint16_t _Atomic(uint16_t)
|
||||
#define atomic_int32_t _Atomic(int32_t)
|
||||
#define atomic_uint32_t _Atomic(uint32_t)
|
||||
#define atomic_int64_t _Atomic(int64_t)
|
||||
#define atomic_uint64_t _Atomic(uint64_t)
|
||||
|
||||
#endif
|
||||
|
@ -14,6 +14,8 @@ SRCFILES := $(call GRABSRC, \
|
||||
sync \
|
||||
args \
|
||||
util \
|
||||
ubsan \
|
||||
write \
|
||||
)
|
||||
|
||||
CFLAGS += -isystem $(ROOT)/share -isystem $(ROOT)/ulib -isystem $(ROOT)/std/include \
|
||||
|
@ -2,10 +2,13 @@
|
||||
#include <stddef.h>
|
||||
#include <system/system.h>
|
||||
#include <sysdefs/processctl.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <errors.h>
|
||||
#include <dlmalloc/malloc.h>
|
||||
#include <uprintf.h>
|
||||
#include <log.h>
|
||||
#include <util/util.h>
|
||||
#include <devids.h>
|
||||
|
||||
extern void main(void);
|
||||
extern uint8_t _bss_start[];
|
||||
@ -18,24 +21,28 @@ void clearbss(void) {
|
||||
}
|
||||
}
|
||||
|
||||
char **_args;
|
||||
#define MAX_ARGS 15
|
||||
static char *_args[MAX_ARGS];
|
||||
|
||||
size_t _argslen;
|
||||
|
||||
char **args(void) {
|
||||
return _args;
|
||||
return (char **)_args;
|
||||
}
|
||||
|
||||
size_t argslen(void) {
|
||||
return _argslen;
|
||||
}
|
||||
|
||||
Dev_t termdev;
|
||||
|
||||
// ulib initialization goes here
|
||||
void _premain(void) {
|
||||
clearbss();
|
||||
|
||||
#define MAX_ARGS 30
|
||||
_args = (char **)dlmalloc(MAX_ARGS * sizeof(char *));
|
||||
for (size_t i = 0; i < MAX_ARGS; i++) {
|
||||
devctl(&termdev, DEVCTL_GET_HANDLE, (uint8_t *)DEV_TERMDEV, 0, 0);
|
||||
|
||||
for (size_t i = 0; i < ARRLEN(_args); i++) {
|
||||
_args[i] = dlmalloc(PROC_ARG_MAX);
|
||||
}
|
||||
|
||||
|
@ -5,35 +5,89 @@
|
||||
#include <string/conv.h>
|
||||
#include <string/string.h>
|
||||
#include <uprintf.h>
|
||||
#include <errors.h>
|
||||
|
||||
int32_t parse_args(char **argv, size_t argc, Arg *defs) {
|
||||
#define CONSUME_TK() i++
|
||||
|
||||
if (!argv || !defs) {
|
||||
return E_INVALIDARGUMENT;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
if (argv[i][0] == '-' && argv[i][1] != '\0') {
|
||||
char *optname = argv[i];
|
||||
char *arg = argv[i];
|
||||
if (!arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg[0] == '-' && arg[1] != '\0') {
|
||||
size_t j = 0;
|
||||
while (!defs[j].end) {
|
||||
Arg *def = &defs[j];
|
||||
if (string_strcmp(def->shortname, optname) == 0) {
|
||||
if (i < argc - 1) {
|
||||
|
||||
if (!def->shortname || !def->ptr) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string_strcmp(def->shortname, arg) == 0) {
|
||||
bool have_next = (i + 1) < argc && argv[i + 1] != NULL;
|
||||
char *nexttk = have_next ? argv[i + 1] : NULL;
|
||||
|
||||
if (nexttk && nexttk[0] == '-' && nexttk[1] != '\0') {
|
||||
have_next = false;
|
||||
nexttk = NULL;
|
||||
}
|
||||
|
||||
switch (def->expected_value) {
|
||||
case ARG_STRING:
|
||||
*((char **)def->ptr) = argv[i+1];
|
||||
if (!have_next) {
|
||||
break;
|
||||
}
|
||||
*((char **)def->ptr) = nexttk;
|
||||
CONSUME_TK();
|
||||
break;
|
||||
case ARG_BOOL:
|
||||
*((bool *)def->ptr) = string_strcmp(argv[i+1], "yes") == 0;
|
||||
if (!have_next) {
|
||||
*((bool *)def->ptr) = true;
|
||||
} else {
|
||||
if (string_strcmp(nexttk, "yes") == 0) {
|
||||
*((bool *)def->ptr) = true;
|
||||
CONSUME_TK();
|
||||
} else if (string_strcmp(nexttk, "no") == 0) {
|
||||
*((bool *)def->ptr) = false;
|
||||
CONSUME_TK();
|
||||
} else {
|
||||
*((bool *)def->ptr) = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ARG_INT:
|
||||
if (!have_next) {
|
||||
break;
|
||||
case ARG_INT: {
|
||||
char *end;
|
||||
*((int32_t *)def->ptr) = string_conv_strtol(argv[i+1], &end, 10);
|
||||
} break;
|
||||
}
|
||||
i++;
|
||||
char *endptr = NULL;
|
||||
long val = string_conv_strtol(nexttk, &endptr, 10);
|
||||
if (endptr == NULL) {
|
||||
break;
|
||||
}
|
||||
if (*endptr != '\0') {
|
||||
break;
|
||||
}
|
||||
*((int32_t *)def->ptr) = (int32_t)val;
|
||||
CONSUME_TK();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ARGP_OK;
|
||||
return E_OK;
|
||||
}
|
||||
|
@ -28,10 +28,6 @@ typedef struct {
|
||||
|
||||
#define ARG_END() ((Arg){ .end = true, })
|
||||
|
||||
enum {
|
||||
ARGP_OK = 0,
|
||||
};
|
||||
|
||||
int32_t parse_args(char **argv, size_t argc, Arg *defs);
|
||||
|
||||
#endif // ULIB_ARGS_H_
|
||||
|
15
ulib/assert.h
Normal file
15
ulib/assert.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef ULIB_ASSERT_H_
|
||||
#define ULIB_ASSERT_H_
|
||||
|
||||
#include <uprintf.h>
|
||||
#include <util/util.h>
|
||||
|
||||
#define ASSERT(X, fmt, ...) \
|
||||
do { \
|
||||
if (!(X)) { \
|
||||
uprintf("ASSERT %s:%d in %s "fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
quit(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif // ULIB_ASSERT_H_
|
8
ulib/devids.h
Normal file
8
ulib/devids.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef ULIB_DEVIDS_H_
|
||||
#define ULIB_DEVIDS_H_
|
||||
|
||||
enum {
|
||||
DEV_TERMDEV = 0x10,
|
||||
};
|
||||
|
||||
#endif // ULIB_DEVIDS_H_
|
@ -8,6 +8,7 @@
|
||||
#include <string/string.h>
|
||||
#include <sysdefs/mman.h>
|
||||
#include <system/system.h>
|
||||
#include <write/write.h>
|
||||
|
||||
#define USE_DL_PREFIX 1
|
||||
#define LACKS_SYS_TYPES_H 1
|
||||
@ -23,7 +24,7 @@
|
||||
#define LACKS_SCHED_H 1
|
||||
#define HAVE_MMAP 1
|
||||
#define HAVE_MORECORE 0
|
||||
#define ABORT uprintf("dlmalloc: Aborting...\n")
|
||||
#define ABORT writefmt("dlmalloc: Aborting...\n")
|
||||
#define MALLOC_FAILURE_ACTION
|
||||
#define USE_LOCKS 2
|
||||
#define malloc_getpagesize 0x1000
|
||||
@ -61,8 +62,9 @@ static size_t _roundpage(size_t sz) {
|
||||
#define O_RDWR 0
|
||||
|
||||
#define EMUL_DEV_ZERO_FD 123
|
||||
#define EMUL_MAP_FAILED ((void *)-1)
|
||||
|
||||
int open(char *path, int flags) {
|
||||
int open(const char *path, int flags, ...) {
|
||||
return EMUL_DEV_ZERO_FD;
|
||||
}
|
||||
|
||||
@ -73,7 +75,7 @@ void *mmap(void *addr, size_t len, int prot, int flags, int fd, int off) {
|
||||
|
||||
int32_t err = mman_map(NULL, need, MMAN_MAP_PF_RW, 0, &outaddr);
|
||||
if (err != E_OK || outaddr == NULL) {
|
||||
return NULL;
|
||||
return EMUL_MAP_FAILED;
|
||||
}
|
||||
|
||||
if (fd == EMUL_DEV_ZERO_FD) {
|
||||
|
@ -53,14 +53,14 @@
|
||||
} while(0)
|
||||
|
||||
#define LL_FOREACH_SAFE(head, var, tmp) \
|
||||
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
|
||||
for (var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL; \
|
||||
var = tmp, tmp = (var ? var->next : NULL) \
|
||||
)
|
||||
|
||||
#define LL_FOREACH_SAFE_IDX(head, var, tmp, idx) \
|
||||
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL && ((idx) = 0, 1); \
|
||||
for ((idx) = 0, var = (head), tmp = (var ? var->next : NULL); \
|
||||
var != NULL; \
|
||||
var = tmp, tmp = (var ? var->next : NULL), (idx)++)
|
||||
|
||||
#define LL_FOREACH_SAFE_IDX_LIMIT(head, var, tmp, idx, max) \
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define ULIB_LOG_H_
|
||||
|
||||
#include <uprintf.h>
|
||||
#include <write/write.h>
|
||||
|
||||
enum {
|
||||
LOG_ERR,
|
||||
@ -12,6 +13,6 @@ enum {
|
||||
|
||||
static const char *_LOG_STR[] = { "ERROR", "DEBUG", "INFO", "WARNING" };
|
||||
|
||||
#define LOG(mode, fmt, ...) uprintf("%s: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__);
|
||||
#define LOG(mode, fmt, ...) writefmt("{s}: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__);
|
||||
|
||||
#endif // ULIB_LOG_H_
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <system/system.h>
|
||||
#include <sysdefs/ipcpipe.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <printf/printf.h>
|
||||
|
||||
extern Dev_t termdev;
|
||||
|
||||
void putchar_(char c) {
|
||||
char buf = c;
|
||||
ipcpipe(IPCPIPE_SELFPID, IPCPIPE_OUT, IPCPIPE_WRITE, (uint8_t *)&buf, sizeof(buf));
|
||||
devctl(&termdev, 0x00, (uint8_t *)&c, 1, 0);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <stddef.h>
|
||||
#include <string/string.h>
|
||||
#include <dlmalloc/malloc.h>
|
||||
|
||||
size_t string_len(const char *s) {
|
||||
size_t l = 0;
|
||||
@ -130,3 +131,35 @@ int string_strncmp( const char * s1, const char * s2, size_t n )
|
||||
return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
|
||||
}
|
||||
}
|
||||
|
||||
#define STRING_TOKENIZEALLOC_TOK_SIZE 0xff
|
||||
|
||||
char *string_tokenizealloc(char *s, char *delim) {
|
||||
static int curridx = 0;
|
||||
if (!s || !delim || !s[curridx]) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *w = (char *)dlmalloc(sizeof(char) * STRING_TOKENIZEALLOC_TOK_SIZE);
|
||||
string_memset(w, 0, sizeof(char) * STRING_TOKENIZEALLOC_TOK_SIZE);
|
||||
int i = curridx, k = 0, j = 0;
|
||||
|
||||
while (s[i] != '\0') {
|
||||
j = 0;
|
||||
while (delim[j] != '\0') {
|
||||
if (s[i] != delim[j]) {
|
||||
w[k] = s[i];
|
||||
} else {
|
||||
goto it;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
it: {
|
||||
w[i] = 0;
|
||||
curridx = i + 1;
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ size_t string_strspn(const char *s, const char *accept);
|
||||
char *string_strcpy(char *dest, const char *src);
|
||||
char *string_strchr(const char *s, int c);
|
||||
int string_strncmp(const char * s1, const char * s2, size_t n);
|
||||
char *string_tokenizealloc(char *s, char *delim);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <stdint.h>
|
||||
#include <uprintf.h>
|
||||
|
||||
uint64_t syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
|
||||
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <sysdefs/ioctl.h>
|
||||
#include <sysdefs/processctl.h>
|
||||
#include <sysdefs/ipcpipe.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <uprintf.h>
|
||||
|
||||
void debugprint(const char *string) {
|
||||
@ -34,3 +35,7 @@ int32_t mman_unmap(uint8_t *addr) {
|
||||
int32_t schedrelease(void) {
|
||||
return syscall(SYS_SCHEDRELEASE, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int32_t devctl(Dev_t *devh, uint64_t cmd, uint8_t *buffer, size_t len, uint64_t extra) {
|
||||
return syscall(SYS_DEVCTL, (uint64_t)devh, cmd, (uint64_t)buffer, (uint64_t)len, (uint64_t)extra, 0);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
|
||||
void debugprint(const char *string);
|
||||
int32_t ioctl(uint64_t ioh, uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3);
|
||||
@ -11,5 +12,6 @@ int32_t ipcpipe(uint64_t pid, uint64_t pipenum, uint64_t cmd, uint8_t *buffer, s
|
||||
int32_t mman_map(uint8_t *addr, size_t size, uint64_t prot, uint64_t flags, uint8_t **out);
|
||||
int32_t mman_unmap(uint8_t *addr);
|
||||
int32_t schedrelease(void);
|
||||
int32_t devctl(Dev_t *devh, uint64_t cmd, uint8_t *buffer, size_t len, uint64_t extra);
|
||||
|
||||
#endif // ULIB_SYSTEM_SYSTEM_H_
|
||||
|
224
ulib/ubsan/ubsan.c
Normal file
224
ulib/ubsan/ubsan.c
Normal file
@ -0,0 +1,224 @@
|
||||
// REFERENCES:
|
||||
// https://wiki.osdev.org/Undefined_Behavior_Sanitization
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <uprintf.h>
|
||||
|
||||
struct source_location {
|
||||
const char *file;
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
|
||||
struct type_descriptor {
|
||||
uint16_t type_kind;
|
||||
uint16_t type_info;
|
||||
char *type_name;
|
||||
};
|
||||
|
||||
|
||||
struct type_mismatch_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
unsigned long alignment;
|
||||
unsigned char type_check_kind;
|
||||
};
|
||||
|
||||
|
||||
struct type_mismatch_data_v1 {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
unsigned char alignment;
|
||||
unsigned char type_check_kind;
|
||||
};
|
||||
|
||||
|
||||
struct overflow_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
|
||||
struct shift_out_of_bounds_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *lhs_type;
|
||||
struct type_descriptor *rhs_type;
|
||||
};
|
||||
|
||||
|
||||
struct out_of_bounds_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *array_type;
|
||||
struct type_descriptor *index_type;
|
||||
};
|
||||
|
||||
|
||||
struct unreachable_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
|
||||
struct vla_bound_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
|
||||
struct invalid_value_data {
|
||||
struct source_location loc;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
|
||||
struct nonnull_arg_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
|
||||
struct nonnull_return_data {
|
||||
struct source_location loc;
|
||||
struct source_location attr_loc;
|
||||
};
|
||||
|
||||
|
||||
struct invalid_builtin_data {
|
||||
struct source_location loc;
|
||||
uint8_t kind;
|
||||
};
|
||||
|
||||
|
||||
struct pointer_overflow_data {
|
||||
struct source_location loc;
|
||||
};
|
||||
|
||||
|
||||
static void ubsan_print(struct source_location *loc, const char *message)
|
||||
{
|
||||
uprintf("UBSAN error %s:%d:%d %s\n", loc->file, loc->line, loc->column, message);
|
||||
}
|
||||
|
||||
void __ubsan_handle_add_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "addition overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_sub_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "subtraction overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_mul_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "multiplication overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_divrem_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "division overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_negate_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "negation overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_pointer_overflow(struct overflow_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "pointer overflow");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "shift out of bounds");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "array out of bounds");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "invalid load value");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, uintptr_t ptr)
|
||||
{
|
||||
if (ptr == (uintptr_t)NULL) {
|
||||
ubsan_print(&data->loc, "null pointer access");
|
||||
}
|
||||
else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) {
|
||||
ubsan_print(&data->loc, "misaligned pointer is used");
|
||||
}
|
||||
else {
|
||||
ubsan_print(&data->loc, "insufficient space for an object");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, uintptr_t ptr)
|
||||
{
|
||||
if (ptr == (uintptr_t)NULL) {
|
||||
ubsan_print(&data->loc, "null pointer access");
|
||||
}
|
||||
else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) {
|
||||
ubsan_print(&data->loc, "misaligned pointer is used");
|
||||
}
|
||||
else {
|
||||
ubsan_print(&data->loc, "insufficient space for an object");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "variable-length argument out of bounds");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_nonnull_return_v1(struct nonnull_return_data *data, struct source_location *loc)
|
||||
{
|
||||
ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "non-null argument is null");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "unreachable code reached");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "invalid builtin");
|
||||
}
|
||||
|
||||
|
||||
void __ubsan_handle_missing_return(struct unreachable_data *data)
|
||||
{
|
||||
ubsan_print(&data->loc, "missing return value");
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <uprintf.h>
|
||||
#include <linklist.h>
|
||||
#include <log.h>
|
||||
#include <assert.h>
|
||||
#include <write/write.h>
|
||||
|
||||
#include <errors.h>
|
||||
#include <sysdefs/ioctl.h>
|
||||
|
@ -5,11 +5,7 @@
|
||||
|
||||
#define ARRLEN(X) (sizeof((X))/sizeof((X)[0]))
|
||||
|
||||
#define ZERO(X) \
|
||||
({ \
|
||||
string_memset((X), 0, sizeof(*(X))); \
|
||||
*(X); \
|
||||
}) \
|
||||
#define ZERO(X) string_memset((X), 0, sizeof(*(X)))
|
||||
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
|
161
ulib/write/write.c
Normal file
161
ulib/write/write.c
Normal file
@ -0,0 +1,161 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <system/system.h>
|
||||
#include <sysdefs/devctl.h>
|
||||
#include <write/write.h>
|
||||
|
||||
char *utoa(uintmax_t v, int base, bool uppercase) {
|
||||
if (base < 2 || base > 36) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char buf[sizeof(uintmax_t) * CHAR_BIT + 3];
|
||||
const char *digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
size_t i = sizeof(buf) - 1;
|
||||
buf[i] = '\0';
|
||||
|
||||
if (v == 0) {
|
||||
buf[--i] = '0';
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
while (v != 0) {
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
buf[--i] = digits[v % base];
|
||||
v /= base;
|
||||
}
|
||||
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
char *itoa(intmax_t v, int base, bool uppercase) {
|
||||
if (base < 2 || base > 36) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char buf[sizeof(uintmax_t) * CHAR_BIT + 3];
|
||||
const char *digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
size_t i = sizeof(buf) - 1;
|
||||
buf[i] = '\0';
|
||||
|
||||
if (v == 0) {
|
||||
buf[--i] = '0';
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
bool neg = (v < 0);
|
||||
uintmax_t u;
|
||||
if (neg) {
|
||||
u = (uintmax_t)(-(v + 1)) + 1;
|
||||
} else {
|
||||
u = (uintmax_t)v;
|
||||
}
|
||||
|
||||
while (u != 0) {
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
buf[--i] = digits[u % base];
|
||||
u /= base;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if (i == 0) {
|
||||
return NULL;
|
||||
}
|
||||
buf[--i] = '-';
|
||||
}
|
||||
|
||||
return &buf[i];
|
||||
}
|
||||
|
||||
#define FMTBUF_MAX 2048
|
||||
|
||||
extern Dev_t termdev;
|
||||
|
||||
enum {
|
||||
WRITE_FORMATMODE,
|
||||
WRITE_NORMALMODE,
|
||||
};
|
||||
|
||||
const char *convstr1 = "0123456789abcdef";
|
||||
const char *convstr2 = "0123456789ABCDEF";
|
||||
|
||||
void writefmt(char *fmt, ...) {
|
||||
va_list list;
|
||||
va_start(list, fmt);
|
||||
writevfmt(fmt, list);
|
||||
va_end(list);
|
||||
}
|
||||
|
||||
#define ITOA_BUF_SIZE 32
|
||||
|
||||
void writevsfmt(char *buf, char *fmt, va_list list) {
|
||||
size_t c = 0;
|
||||
int WRITE_STATE = WRITE_NORMALMODE;
|
||||
|
||||
for (size_t i = 0; fmt[i] != '\0'; i++) {
|
||||
if (WRITE_STATE == WRITE_NORMALMODE) {
|
||||
switch (fmt[i]) {
|
||||
case '{':
|
||||
WRITE_STATE = WRITE_FORMATMODE;
|
||||
break;
|
||||
default:
|
||||
buf[c++] = fmt[i];
|
||||
break;
|
||||
}
|
||||
} else if (WRITE_STATE == WRITE_FORMATMODE) {
|
||||
switch (fmt[i]) {
|
||||
case '}':
|
||||
WRITE_STATE = WRITE_NORMALMODE;
|
||||
break;
|
||||
case 's': {
|
||||
char *string = va_arg(list, char *);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'd': {
|
||||
int int1 = va_arg(list, int);
|
||||
char *string = itoa(int1, 10, false);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'x': {
|
||||
unsigned int int1 = va_arg(list, unsigned int);
|
||||
char *string = utoa(int1, 16, false);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'X': {
|
||||
unsigned int int1 = va_arg(list, unsigned int);
|
||||
char *string = utoa(int1, 16, true);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'p': {
|
||||
uintptr_t ptr = (uintptr_t)va_arg(list, void *);
|
||||
char *string = utoa(ptr, 16, false);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'P': {
|
||||
uintptr_t ptr = (uintptr_t)va_arg(list, void *);
|
||||
char *string = utoa(ptr, 16, true);
|
||||
while (*string) { buf[c++] = *string; string++; }
|
||||
} break;
|
||||
case 'c': {
|
||||
char c1 = (char)va_arg(list, char);
|
||||
buf[c++] = c1;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writevfmt(char *fmt, va_list list) {
|
||||
char buf[FMTBUF_MAX];
|
||||
writevsfmt(buf, fmt, list);
|
||||
devctl(&termdev, 0x00, buf, sizeof(buf), 0);
|
||||
}
|
10
ulib/write/write.h
Normal file
10
ulib/write/write.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef ULIB_WRITE_WRITE_H_
|
||||
#define ULIB_WRITE_WRITE_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void writefmt(char *fmt, ...);
|
||||
void writevfmt(char *fmt, va_list list);
|
||||
void writevsfmt(char *buf, char *fmt, va_list list);
|
||||
|
||||
#endif // ULIB_WRITE_WRITE_H_
|
@ -1,7 +1,7 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x400000;
|
||||
. = 0x1000;
|
||||
|
||||
.text ALIGN(4K):
|
||||
{
|
||||
@ -22,6 +22,7 @@ SECTIONS {
|
||||
{
|
||||
_bss_start = .;
|
||||
*(.bss .bss*)
|
||||
. = ALIGN(4K);
|
||||
_bss_end = .;
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,7 @@ void main(void) {
|
||||
|
||||
tb_runinitscript();
|
||||
|
||||
uprintf("Shell exited! Please reboot the system.\n");
|
||||
writefmt("Shell exited! Please reboot the system.\n");
|
||||
|
||||
for(;;);
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ void pctl_ls(void) {
|
||||
|
||||
uprintf("%-30s %s %-6s %-15s %-8s\n", "NAME", "PID", "TYPE", "MEMORY", "STATE");
|
||||
for (size_t i = 0; i < procslen; i++) {
|
||||
ProcStat stat = ZERO(&stat);
|
||||
ProcStat stat; ZERO(&stat);
|
||||
|
||||
string_memset(namebuf, 0, 34);
|
||||
string_memset(membuf, 0, 20);
|
||||
|
395
user/tb/interp.c
395
user/tb/interp.c
@ -9,183 +9,199 @@ extern uint64_t PID;
|
||||
|
||||
static InterpResult RES;
|
||||
|
||||
void tz_init(Tokenizer *tz, const char *str, size_t len) {
|
||||
void tz_init(Tokenizer *tz, char *str) {
|
||||
tz->str = str;
|
||||
tz->len = len;
|
||||
tz->pos = 0;
|
||||
tz->tokens = NULL;
|
||||
}
|
||||
|
||||
void tz_free(Tokenizer *tz) {
|
||||
Token *tk = tz->tokens;
|
||||
while (tk) {
|
||||
Token *tmp = tk;
|
||||
tk = tk->next;
|
||||
dlfree(tmp);
|
||||
Token *tk, *tktmp;
|
||||
LL_FOREACH_SAFE(tz->tokens, tk, tktmp) {
|
||||
dlfree(tk);
|
||||
}
|
||||
tz->tokens = NULL;
|
||||
}
|
||||
|
||||
int tz_next(Tokenizer *tz, Token *out) {
|
||||
while (tz->pos < tz->len && string_chr_isspace(tz->str[tz->pos])) {
|
||||
tz->pos++;
|
||||
}
|
||||
#define TZ_MAX_TK 1024
|
||||
|
||||
if (tz->pos >= tz->len) {
|
||||
return 0;
|
||||
void tz_tokenize(Tokenizer *tz) {
|
||||
size_t len = string_len(tz->str);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (tz->str[i] == '\'') {
|
||||
char *str = dlmalloc(TZ_MAX_TK);
|
||||
string_memset(str, 0, TZ_MAX_TK);
|
||||
i++;
|
||||
size_t j = 0;
|
||||
while (i < len && tz->str[i] != '\'') {
|
||||
str[j++] = tz->str[i++];
|
||||
}
|
||||
|
||||
size_t start = tz->pos;
|
||||
if (tz->str[start] == '"') {
|
||||
start++;
|
||||
tz->pos++;
|
||||
while (tz->pos < tz->len && tz->str[tz->pos] != '"') {
|
||||
tz->pos++;
|
||||
}
|
||||
|
||||
if (tz->pos >= tz->len) {
|
||||
out->ptr = tz->str + start;
|
||||
out->len = tz->len - start;
|
||||
tz->pos = tz->len;
|
||||
Token *tk = dlmalloc(sizeof(*tk));
|
||||
tk->str = str;
|
||||
tk->next = NULL;
|
||||
LL_APPEND(tz->tokens, tk);
|
||||
} else {
|
||||
out->ptr = tz->str + start;
|
||||
out->len = tz->pos - start;
|
||||
tz->pos++;
|
||||
char *tkstr = dlmalloc(TZ_MAX_TK);
|
||||
string_memset(tkstr, 0, TZ_MAX_TK);
|
||||
size_t j = 0;
|
||||
while (i < len && !string_chr_isspace(tz->str[i])) {
|
||||
tkstr[j++] = tz->str[i++];
|
||||
}
|
||||
} else {
|
||||
while (tz->pos < tz->len && !string_chr_isspace(tz->str[tz->pos])) {
|
||||
tz->pos++;
|
||||
Token *tk = dlmalloc(sizeof(*tk));
|
||||
tk->str = tkstr;
|
||||
tk->next = NULL;
|
||||
LL_APPEND(tz->tokens, tk);
|
||||
}
|
||||
out->ptr = tz->str + start;
|
||||
out->len = tz->pos - start;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void tz_classify(Tokenizer *tz) {
|
||||
const int tmpbufsz = 256;
|
||||
char *tmpbuf = dlmalloc(tmpbufsz);
|
||||
Token *tk = tz->tokens;
|
||||
while (tk) {
|
||||
if (tk->ptr[0] == '"' && tk->ptr[tk->len - 1] == '"') {
|
||||
tk->type = TOK_STRING;
|
||||
} else if (tk->ptr[0] == '%') {
|
||||
RtCmd *cmd = RTCMDS;
|
||||
while (cmd) {
|
||||
string_memset(tmpbuf, 0, tmpbufsz);
|
||||
usnprintf(tmpbuf, tmpbufsz, "%.*s", (int)tk->len, tk->ptr);
|
||||
if (string_strcmp(tmpbuf, cmd->cmdname) == 0) {
|
||||
tk->type = TOK_CMD;
|
||||
tk->cmd = cmd;
|
||||
break;
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
} else {
|
||||
tk->type = TOK_MISC;
|
||||
}
|
||||
tk = tk->next;
|
||||
}
|
||||
dlfree(tmpbuf);
|
||||
}
|
||||
|
||||
void tz_expandspecial(Tokenizer *tz) {
|
||||
Token *tk = tz->tokens;
|
||||
while (tk) {
|
||||
if (tk->ptr[0] == '$' && tk->len > 1) {
|
||||
char *aliasbuf = dlmalloc(RTALIAS_NAMEBUF_MAX);
|
||||
usnprintf(aliasbuf, RTALIAS_NAMEBUF_MAX, "%.*s", (int)tk->len-1, &tk->ptr[1]);
|
||||
RtAlias *alias = RTALIASES;
|
||||
while (alias) {
|
||||
if (string_strcmp(alias->namebuf, aliasbuf) == 0) {
|
||||
tk->ptr = alias->valbuf;
|
||||
tk->len = string_len(alias->valbuf);
|
||||
break;
|
||||
}
|
||||
alias = alias->next;
|
||||
}
|
||||
dlfree(aliasbuf);
|
||||
}
|
||||
tk = tk->next;
|
||||
}
|
||||
}
|
||||
|
||||
bool interp_readline(char *data, const char **bgptr, const char **endptr) {
|
||||
static char *nextstart;
|
||||
if (data) {
|
||||
nextstart = data;
|
||||
return true;
|
||||
}
|
||||
/* void tz_classify(Tokenizer *tz) { */
|
||||
/* const int tmpbufsz = 256; */
|
||||
/* char *tmpbuf = dlmalloc(tmpbufsz); */
|
||||
|
||||
if (*nextstart == '\0') {
|
||||
return false;
|
||||
}
|
||||
*bgptr = nextstart;
|
||||
const char *scn = nextstart;
|
||||
/* Token *tk, *tktmp; */
|
||||
/* LL_FOREACH_SAFE(tz->tokens, tk, tktmp) { */
|
||||
/* if (tk->ptr[0] == '"' && tk->ptr[tk->len - 1] == '"') { */
|
||||
/* tk->type = TOK_STRING; */
|
||||
/* } else if (tk->ptr[0] == '%') { */
|
||||
/* RtCmd *cmd, *cmdtmp; */
|
||||
/* LL_FOREACH_SAFE(RTCMDS, cmd, cmdtmp) { */
|
||||
/* string_memset(tmpbuf, 0, tmpbufsz); */
|
||||
/* string_memcpy(tmpbuf, tk->ptr, MIN(tk->len, tmpbufsz)); */
|
||||
/* if (string_strcmp(tmpbuf, cmd->cmdname) == 0) { */
|
||||
/* tk->type = TOK_CMD; */
|
||||
/* tk->cmd = cmd; */
|
||||
/* break; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } else { */
|
||||
/* tk->type = TOK_MISC; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* dlfree(tmpbuf); */
|
||||
/* } */
|
||||
|
||||
for (;;) {
|
||||
while (*scn != '\0' && *scn != '\n') {
|
||||
scn++;
|
||||
}
|
||||
if (*scn == '\n') {
|
||||
if (scn > *bgptr && *(scn - 1) == '\\') {
|
||||
scn--;
|
||||
nextstart = scn;
|
||||
*nextstart = ' ';
|
||||
scn++;
|
||||
if (*scn == '\n') {
|
||||
scn++;
|
||||
}
|
||||
nextstart = scn;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* void tz_expandspecial(Tokenizer *tz) { */
|
||||
/* Token *tk, *tktmp; */
|
||||
/* LL_FOREACH_SAFE(tz->tokens, tk, tktmp) { */
|
||||
/* if (tk->ptr[0] == '$' && tk->len > 1) { */
|
||||
/* char aliasbuf[RTALIAS_NAMEBUF_MAX]; */
|
||||
/* string_memset(aliasbuf, 0, sizeof(aliasbuf)); */
|
||||
/* string_memcpy(aliasbuf, &tk->ptr[1], MIN(tk->len - 1, RTALIAS_NAMEBUF_MAX)); */
|
||||
/* RtAlias *alias, *aliastmp; */
|
||||
/* LL_FOREACH_SAFE(RTALIASES, alias, aliastmp) { */
|
||||
/* if (string_strcmp(alias->namebuf, aliasbuf) == 0) { */
|
||||
/* tk->ptr = alias->valbuf; */
|
||||
/* tk->len = string_len(alias->valbuf); */
|
||||
/* break; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } */
|
||||
|
||||
*endptr = scn - 1;
|
||||
#define LINE_MAX 1024
|
||||
|
||||
while (string_chr_isspace(**bgptr) && *bgptr < *endptr) {
|
||||
(*bgptr)++;
|
||||
}
|
||||
|
||||
while (string_chr_isspace(**endptr) && *endptr >= *bgptr) {
|
||||
(*endptr)--;
|
||||
}
|
||||
|
||||
(*endptr)++;
|
||||
|
||||
if (*scn == '\n') {
|
||||
scn++;
|
||||
}
|
||||
nextstart = scn;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool interp_runstring(const char *string, InterpResult **res, bool logcmds, bool interactive) {
|
||||
bool interp_runstring(char *string, InterpResult **res, bool logcmds, bool interactive) {
|
||||
*res = &RES;
|
||||
string_memset(RES.errmsg, 0, sizeof(RES.errmsg));
|
||||
|
||||
rt_init();
|
||||
bool ok = true;
|
||||
const char *bg, *end;
|
||||
interp_readline((char *)string, NULL, NULL);
|
||||
while (interp_readline(NULL, &bg, &end)) {
|
||||
size_t linelen = end - bg;
|
||||
|
||||
char *line = string_tokenizealloc(string, "\n");
|
||||
while (line != NULL) {
|
||||
|
||||
if (logcmds) {
|
||||
uprintf("+ %.*s\n", (int)linelen, bg);
|
||||
writefmt("+{s}\n", line);
|
||||
}
|
||||
|
||||
Tokenizer tz = {0};
|
||||
tz_init(&tz, bg, linelen);
|
||||
Tokenizer tz; ZERO(&tz);
|
||||
tz_init(&tz, line);
|
||||
|
||||
Token toktmp = {0};
|
||||
tz_tokenize(&tz);
|
||||
/* Token tktmp; ZERO(&tktmp); */
|
||||
/* while (tz_next(&tz, &tktmp)) { */
|
||||
/* Token *tk = dlmalloc(sizeof(*tk)); */
|
||||
/* tk->ptr = tktmp.ptr; */
|
||||
/* tk->len = tktmp.len; */
|
||||
/* LL_APPEND(tz.tokens, tk); */
|
||||
/* } */
|
||||
|
||||
/* tz_classify(&tz); */
|
||||
/* tz_expandspecial(&tz); */
|
||||
|
||||
/* dlfree((void *)line); */
|
||||
line = string_tokenizealloc(NULL, "\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
char line[LINE_MAX];
|
||||
size_t pos = 0;
|
||||
while (string[pos] != '\0') {
|
||||
string_memset(line, 0, sizeof(line));
|
||||
size_t next = inter_readline(string, pos, line, sizeof(line));
|
||||
if (next == pos) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (logcmds) {
|
||||
uprintf("+%s\n", line);
|
||||
}
|
||||
|
||||
/* Tokenizer tz; ZERO(&tz); */
|
||||
/* tz_init(&tz, line, string_len(line)); */
|
||||
|
||||
/* Token tktmp; ZERO(&tktmp); */
|
||||
/* while (tz_next(&tz, &tktmp)) { */
|
||||
/* Token *tk = dlmalloc(sizeof(*tk)); */
|
||||
/* tk->ptr = tktmp.ptr; */
|
||||
/* tk->len = tktmp.len; */
|
||||
/* tk->next = NULL; */
|
||||
/* LL_APPEND(tz.tokens, tk); */
|
||||
/* } */
|
||||
|
||||
/* tz_classify(&tz); */
|
||||
/* tz_expandspecial(&tz); */
|
||||
|
||||
/* Token *cmdtk = tz.tokens; */
|
||||
/* if (cmdtk->type == TOK_CMD) { */
|
||||
/* ok = cmdtk->cmd->fn(cmdtk->next); */
|
||||
/* if (!ok) { */
|
||||
/* usprintf(RES.errmsg, "cmd %.*s failed", (int)cmdtk->len, cmdtk->ptr); */
|
||||
/* tz_free(&tz); */
|
||||
/* goto done; */
|
||||
/* } */
|
||||
/* } else if (cmdtk->type == TOK_MISC) { */
|
||||
|
||||
/* } */
|
||||
|
||||
/* nextline: { */
|
||||
/* tz_free(&tz); */
|
||||
pos = next;
|
||||
/* } */
|
||||
}
|
||||
|
||||
/* char *bg = NULL, *end = NULL; */
|
||||
/* interp_readline((char *)string, NULL, NULL); */
|
||||
/* while (interp_readline(NULL, &bg, &end)) { */
|
||||
/* size_t linelen = (size_t)(end - bg); */
|
||||
|
||||
/* if (logcmds) { */
|
||||
/* uprintf("+ %.*s\n", (int)linelen, bg); */
|
||||
/* } */
|
||||
|
||||
/* Tokenizer tz = {0}; */
|
||||
/* tz_init(&tz, bg, linelen); */
|
||||
|
||||
/* Token toktmp = {0}; */
|
||||
#if 0
|
||||
while (tz_next(&tz, &toktmp)) {
|
||||
Token *tok = dlmalloc(sizeof(*tok));
|
||||
tok->ptr = toktmp.ptr;
|
||||
tok->len = toktmp.len;
|
||||
tok->next = NULL;
|
||||
LL_APPEND(tz.tokens, tok);
|
||||
string_memset(&toktmp, 0, sizeof(toktmp));
|
||||
}
|
||||
|
||||
tz_classify(&tz);
|
||||
@ -193,67 +209,62 @@ bool interp_runstring(const char *string, InterpResult **res, bool logcmds, bool
|
||||
|
||||
Token *cmdtk = tz.tokens;
|
||||
if (cmdtk->type == TOK_CMD) {
|
||||
ok = cmdtk->cmd->fn(cmdtk->next);
|
||||
if (!ok) {
|
||||
ok = false;
|
||||
usprintf(RES.errmsg, "cmd %.*s failed", (int)cmdtk->len, cmdtk->ptr);
|
||||
tz_free(&tz);
|
||||
goto done;
|
||||
}
|
||||
/* ok = cmdtk->cmd->fn(cmdtk->next); */
|
||||
/* if (!ok) { */
|
||||
/* usprintf(RES.errmsg, "cmd %.*s failed", (int)cmdtk->len, cmdtk->ptr); */
|
||||
/* tz_free(&tz); */
|
||||
/* goto done; */
|
||||
/* } */
|
||||
} else if (cmdtk->type == TOK_MISC) {
|
||||
char *appname = dlmalloc(1024);
|
||||
usprintf(appname, "%.*s", (int)cmdtk->len, cmdtk->ptr);
|
||||
/* const int appname_max = 128; */
|
||||
/* char *appname = dlmalloc(appname_max); */
|
||||
/* string_memset(appname, 0, appname_max); */
|
||||
/* string_memcpy(appname, cmdtk->ptr, MIN(cmdtk->len, appname_max)); */
|
||||
/* usnprintf(appname, appname_max, "%.*s", (int)cmdtk->len, cmdtk->ptr); */
|
||||
|
||||
size_t argslen1 = 0;
|
||||
Token *argtk = cmdtk->next;
|
||||
while (argtk) {
|
||||
argslen1++;
|
||||
argtk = argtk->next;
|
||||
}
|
||||
/* size_t argslen1; */
|
||||
/* LL_FOREACH_SAFE_IDX(cmdtk->next, argtk, argtktmp, argslen1); */
|
||||
|
||||
char **args1 = (char **)dlmalloc(sizeof(char *) * argslen1);
|
||||
argtk = cmdtk->next;
|
||||
size_t i = 0;
|
||||
while (argtk) {
|
||||
args1[i] = (char *)dlmalloc(PROC_ARG_MAX);
|
||||
string_memset(args1[i], 0, PROC_ARG_MAX);
|
||||
string_memcpy(args1[i], argtk->ptr, argtk->len);
|
||||
i++;
|
||||
argtk = argtk->next;
|
||||
}
|
||||
/* size_t i; */
|
||||
/* char **args1 = (char **)dlmalloc(sizeof(char *) * argslen1); */
|
||||
/* LL_FOREACH_SAFE_IDX(cmdtk->next, argtk, argtktmp, i) { */
|
||||
/* args1[i] = (char *)dlmalloc(PROC_ARG_MAX); */
|
||||
/* string_memset(args1[i], 0, PROC_ARG_MAX); */
|
||||
/* string_memcpy(args1[i], argtk->ptr, argtk->len); */
|
||||
/* } */
|
||||
|
||||
int32_t app = processctl(-1, PCTL_SPAWN, (uint64_t)appname, (uint64_t)args1, argslen1);
|
||||
if (app < 0) {
|
||||
usprintf(RES.errmsg, "Could not run %s: %s\n", appname, ERRSTRING(app));
|
||||
ok = false;
|
||||
goto cleanup;
|
||||
}
|
||||
/* int32_t app = processctl(-1, PCTL_SPAWN, (uint64_t)appname, (uint64_t)args1, argslen1); */
|
||||
/* if (app < 0) { */
|
||||
/* usprintf(RES.errmsg, "Could not run %s: %s\n", appname, ERRSTRING(app)); */
|
||||
/* ok = false; */
|
||||
/* goto cleanup; */
|
||||
/* } */
|
||||
|
||||
processctl(app, PCTL_RUN, 0, 0, 0);
|
||||
/* processctl(app, PCTL_RUN, 0, 0, 0); */
|
||||
|
||||
uint8_t b;
|
||||
while(processctl(app, PCTL_POLLSTATE, 0, 0, 0) != 4) {
|
||||
if (interactive) {
|
||||
int32_t nrd = ipcpipe(PID, IPCPIPE_IN, IPCPIPE_READ, &b, 1);
|
||||
if (nrd > 0 && b == C('S')) {
|
||||
processctl(app, PCTL_KILL, 0, 0, 0);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
schedrelease();
|
||||
}
|
||||
/* uint8_t b; */
|
||||
/* while(processctl(app, PCTL_POLLSTATE, 0, 0, 0) != 4) { */
|
||||
/* if (interactive) { */
|
||||
/* int32_t nrd = ipcpipe(PID, IPCPIPE_IN, IPCPIPE_READ, &b, 1); */
|
||||
/* if (nrd > 0 && b == C('S')) { */
|
||||
/* processctl(app, PCTL_KILL, 0, 0, 0); */
|
||||
/* goto cleanup; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* schedrelease(); */
|
||||
/* } */
|
||||
|
||||
cleanup: {
|
||||
for (size_t j = 0; j < argslen1; j++) {
|
||||
dlfree(args1[j]);
|
||||
}
|
||||
dlfree(args1);
|
||||
dlfree(appname);
|
||||
/* for (size_t j = 0; j < argslen1; j++) dlfree(args1[j]); */
|
||||
/* dlfree(args1); */
|
||||
/* dlfree((void*)appname); */
|
||||
}
|
||||
}
|
||||
|
||||
tz_free(&tz);
|
||||
}
|
||||
#endif
|
||||
/* } */
|
||||
#endif
|
||||
done:
|
||||
return ok;
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ typedef struct {
|
||||
|
||||
typedef struct Token {
|
||||
struct Token *next;
|
||||
const char *ptr;
|
||||
size_t len;
|
||||
char *str;
|
||||
|
||||
enum {
|
||||
TOK_STRING,
|
||||
@ -26,13 +25,10 @@ typedef struct Token {
|
||||
} Token;
|
||||
|
||||
typedef struct {
|
||||
const char *str;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
|
||||
char *str;
|
||||
Token *tokens;
|
||||
} Tokenizer;
|
||||
|
||||
bool interp_runstring(const char *string, InterpResult **res, bool logcmds, bool interactive);
|
||||
bool interp_runstring(char *string, InterpResult **res, bool logcmds, bool interactive);
|
||||
|
||||
#endif // TB_INTERP_H_
|
||||
|
@ -32,7 +32,7 @@ void do_file(char *filepath);
|
||||
void set_config(void) {
|
||||
int32_t ret;
|
||||
if ((ret = parse_args(args(), argslen(), ARGS)) < 0) {
|
||||
uprintf("Could not parse args: %d\n", ret);
|
||||
writefmt("Could not parse args: {d}\n", ret);
|
||||
}
|
||||
|
||||
if (CONFIG.modestr != NULL) {
|
||||
@ -41,7 +41,7 @@ void set_config(void) {
|
||||
} else if (string_strcmp(CONFIG.modestr, "runfile") == 0) {
|
||||
CONFIG.mode = MODE_RUNFILE;
|
||||
} else {
|
||||
LOG(LOG_ERR, "Unknown mode %s\n", CONFIG.modestr);
|
||||
LOG(LOG_ERR, "Unknown mode {s}\n", CONFIG.modestr);
|
||||
}
|
||||
} else {
|
||||
CONFIG.mode = MODE_RUNFILE;
|
||||
@ -53,7 +53,7 @@ void do_file(char *filepath) {
|
||||
|
||||
int32_t ioh = ioctl(IOCTL_NOHANDLE, IOCTL_OPENF, (uint64_t)filepath, IOCTL_F_READ, 0);
|
||||
if (ioh < 0) {
|
||||
LOG(LOG_ERR, "Could not open %s: %s\n", filepath, ERRSTRING(ioh));
|
||||
LOG(LOG_ERR, "Could not open {s}: {s}\n", filepath, ERRSTRING(ioh));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -61,27 +61,27 @@ void do_file(char *filepath) {
|
||||
|
||||
ioctl(ioh, IOCTL_STAT, (uint64_t)&statbuf, 0, 0);
|
||||
if (statbuf.type != IOCTLSTAT_FILE) {
|
||||
LOG(LOG_ERR, "%s is not a file (%d)\n", filepath, statbuf.type);
|
||||
LOG(LOG_ERR, "{s} is not a file ({d})\n", filepath, statbuf.type);
|
||||
return;
|
||||
}
|
||||
uint8_t *buf = dlmalloc(statbuf.size+1);
|
||||
string_memset(buf, 0, statbuf.size+1);
|
||||
|
||||
if ((ret = ioctl(ioh, IOCTL_READ, (uint64_t)buf, statbuf.size, 0)) < 0) {
|
||||
LOG(LOG_ERR, "Could not read %s (%d): %s\n", filepath, ioh, ERRSTRING(ioh));
|
||||
LOG(LOG_ERR, "Could not read {s} ({d}): {s}\n", filepath, ioh, ERRSTRING(ioh));
|
||||
goto done;
|
||||
}
|
||||
|
||||
InterpResult *res;
|
||||
bool ok = interp_runstring((const char *)buf, &res, CONFIG.logcmds, CONFIG.mode == MODE_INTERACTIVE);
|
||||
bool ok = interp_runstring((char *)buf, &res, CONFIG.logcmds, CONFIG.mode == MODE_INTERACTIVE);
|
||||
if (!ok) {
|
||||
uprintf("Interpreter error:\n");
|
||||
uprintf("%s\n", res->errmsg);
|
||||
writefmt("Interpreter error:\n");
|
||||
writefmt("{s}\n", res->errmsg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
dlfree(buf);
|
||||
/* dlfree(buf); */
|
||||
ioctl(ioh, IOCTL_CLOSEF, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ void do_mode_interactive(void) {
|
||||
size_t cursor;
|
||||
for(;;) {
|
||||
begin:
|
||||
uprintf("tb# ");
|
||||
writefmt("tb# ");
|
||||
|
||||
cursor = 0;
|
||||
string_memset(linebuf, 0, LINEBUF_MAX);
|
||||
@ -102,12 +102,12 @@ void do_mode_interactive(void) {
|
||||
switch (b) {
|
||||
case C('C'):
|
||||
case 0xE9:
|
||||
uprintf("\n");
|
||||
writefmt("\n");
|
||||
goto begin;
|
||||
break;
|
||||
case C('L'):
|
||||
uprintf(ANSIQ_CUR_SET(0, 0));
|
||||
uprintf(ANSIQ_SCR_CLR_ALL);
|
||||
writefmt(ANSIQ_CUR_SET(0, 0));
|
||||
writefmt(ANSIQ_SCR_CLR_ALL);
|
||||
goto begin;
|
||||
break;
|
||||
}
|
||||
@ -118,7 +118,7 @@ void do_mode_interactive(void) {
|
||||
|
||||
if (string_chr_isascii(b) && b != 0 && cursor < LINEBUF_MAX) {
|
||||
linebuf[cursor++] = b;
|
||||
uprintf("%c", b);
|
||||
writefmt("{c}", b);
|
||||
}
|
||||
} else {
|
||||
schedrelease();
|
||||
@ -128,10 +128,10 @@ void do_mode_interactive(void) {
|
||||
if (cursor < LINEBUF_MAX) {
|
||||
linebuf[cursor] = '\0';
|
||||
}
|
||||
uprintf("\n");
|
||||
writefmt("\n");
|
||||
InterpResult *res;
|
||||
if (!interp_runstring(linebuf, &res, CONFIG.logcmds, CONFIG.mode == MODE_INTERACTIVE)) {
|
||||
LOG(LOG_ERR, "%s\n", res->errmsg);
|
||||
LOG(LOG_ERR, "{s}\n", res->errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,15 +142,15 @@ void main(void) {
|
||||
set_config();
|
||||
|
||||
if (CONFIG.preloadpath != NULL) {
|
||||
LOG(LOG_INF, "Preloading script: %s\n", CONFIG.preloadpath);
|
||||
LOG(LOG_INF, "Preloading script: {s}\n", CONFIG.preloadpath);
|
||||
do_file(CONFIG.preloadpath);
|
||||
}
|
||||
|
||||
if (CONFIG.mode == MODE_INTERACTIVE) {
|
||||
do_mode_interactive();
|
||||
/* do_mode_interactive(); */
|
||||
} else if (CONFIG.mode == MODE_RUNFILE) {
|
||||
if (CONFIG.filepath == NULL) {
|
||||
uprintf("No file provided\n");
|
||||
writefmt("No file provided\n");
|
||||
return;
|
||||
}
|
||||
do_file(CONFIG.filepath);
|
||||
|
@ -16,32 +16,31 @@ RtAlias *RTALIASES = NULL;
|
||||
} while(0)
|
||||
|
||||
bool rt_print(Token *tks) {
|
||||
Token *tk = tks;
|
||||
while (tk) {
|
||||
uprintf("%.*s", (int)tk->len, tk->ptr);
|
||||
Token *tk, *tktmp;
|
||||
LL_FOREACH_SAFE(tks, tk, tktmp) {
|
||||
writefmt("{s}", tk->str);
|
||||
if (tk->next != NULL) {
|
||||
uprintf(" ");
|
||||
writefmt(" ");
|
||||
}
|
||||
tk = tk->next;
|
||||
}
|
||||
uprintf("\n");
|
||||
writefmt("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rt_mkalias(Token *tks) {
|
||||
RtAlias *alias = dlmalloc(sizeof(*alias));
|
||||
string_memset(alias, 0, sizeof(*alias));
|
||||
Token *tk = tks;
|
||||
size_t i = 0;
|
||||
while (tk) {
|
||||
|
||||
size_t i;
|
||||
Token *tk, *tktmp;
|
||||
LL_FOREACH_SAFE_IDX(tks, tk, tktmp, i) {
|
||||
if (i == 0) {
|
||||
usprintf(alias->namebuf, "%.*s", (int)tk->len, tk->ptr);
|
||||
string_memcpy(alias->namebuf, tk->str, MIN(string_len(tk->str), RTALIAS_NAMEBUF_MAX));
|
||||
} else if (i == 1) {
|
||||
usprintf(alias->valbuf, "%.*s", (int)tk->len, tk->ptr);
|
||||
string_memcpy(alias->valbuf, tk->str, MIN(string_len(tk->str), RTALIAS_VALBUF_MAX));
|
||||
}
|
||||
i++;
|
||||
tk = tk->next;
|
||||
}
|
||||
|
||||
LL_APPEND(RTALIASES, alias);
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user