diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | floppy.img | bin | 0 -> 1474560 bytes | |||
| -rw-r--r-- | include/kernel/fd.h | 12 | ||||
| -rw-r--r-- | include/kernel/fs.h | 10 | ||||
| -rw-r--r-- | include/string.h | 1 | ||||
| -rw-r--r-- | kernel/fd.c | 360 | ||||
| -rw-r--r-- | kernel/fd_s.s | 27 | ||||
| -rw-r--r-- | kernel/fs/block.c | 22 | ||||
| -rw-r--r-- | kernel/fs/buffer.c | 102 | ||||
| -rw-r--r-- | kernel/fs/fs.c | 2 | ||||
| -rw-r--r-- | kernel/fs/mount.c | 12 | ||||
| -rw-r--r-- | kernel/hd.c | 18 | ||||
| -rw-r--r-- | kernel/sched.c | 7 | ||||
| -rw-r--r-- | kernel/tty.c | 4 | ||||
| -rw-r--r-- | lib/string.c | 148 | ||||
| -rw-r--r-- | lib/vsprintf.c | 13 | ||||
| -rw-r--r-- | usrbin/main.c | 6 |
17 files changed, 672 insertions, 76 deletions
@@ -21,7 +21,7 @@ clean: rm -f $(TARGET) run: $(TARGET) - qemu-system-x86_64 -s -kernel $(TARGET) -serial stdio - #qemu-system-x86_64 -s -S -kernel $(TARGET) -drive file=hd.img,format=raw + qemu-system-i386 -s -kernel $(TARGET) -fda floppy.img -serial stdio + #qemu-system-i386 -s -S -kernel $(TARGET) -drive file=hd.img,format=raw .FORCE: diff --git a/floppy.img b/floppy.img Binary files differnew file mode 100644 index 0000000..b399a80 --- /dev/null +++ b/floppy.img diff --git a/include/kernel/fd.h b/include/kernel/fd.h new file mode 100644 index 0000000..07cf454 --- /dev/null +++ b/include/kernel/fd.h @@ -0,0 +1,12 @@ +#ifndef _FD_H +#define _FD_H + +#include <kernel/fs.h> +#include <stdint.h> +#include <sys/types.h> + +void fd_init(void); + +void fd_block_read(struct buffer*); + +#endif diff --git a/include/kernel/fs.h b/include/kernel/fs.h index 4ec4de1..1b4ed24 100644 --- a/include/kernel/fs.h +++ b/include/kernel/fs.h @@ -52,16 +52,20 @@ struct m_inode { struct buffer { void *b_data; + int b_present; uint16_t b_device; uint16_t b_block; + struct task_struct *b_wait; struct buffer *b_next; struct buffer *b_prev; -} __attribute__((packed)); +}; extern struct super_block sblocks[NRSUPER]; -int block_read(void*, size_t); -int block_write(void*, size_t); +void block_read(struct buffer*); +void block_write(struct buffer*); + +struct buffer *buffer_get_block(uint16_t, uint16_t); void mount_root(void); diff --git a/include/string.h b/include/string.h index d2f738b..88a6ac4 100644 --- a/include/string.h +++ b/include/string.h @@ -33,5 +33,6 @@ char *strpbrk(const char*, const char*); char *strstr(const char*, const char*); char *strtok(char*, const char*); size_t strxfrm(char*, const char*, size_t); +char *strerror(int); #endif diff --git a/kernel/fd.c b/kernel/fd.c new file mode 100644 index 0000000..19068c4 --- /dev/null +++ b/kernel/fd.c @@ -0,0 +1,360 @@ +#include <asm/interrupt.h> +#include <asm/io.h> +#include <errno.h> +#include <kernel/con.h> +#include <kernel/fs.h> +#include <kernel/kernel.h> +#include <kernel/sched.h> +#include <limits.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> + +#define FDBASE 0x3F0 + +#define FDSRA FDBASE +#define FDSRB (FDBASE + 1) +#define FDDOR (FDBASE + 2) +#define FDTDR (FDBASE + 3) +#define FDMSR (FDBASE + 4) +#define FDDRS (FDBASE + 4) +#define FDDATA (FDBASE + 5) +#define FDDIR (FDBASE + 7) +#define FDCCR (FDBASE + 7) + +#define SECTS(n) ((n) * (BLOCK_SIZE / 512)) +#define BLOCKS(n) ((n) / (BLOCK_SIZE / 512)) + +#define NTYPES (sizeof(ftypes) / sizeof(struct ftype)) +#define NFDS (sizeof(fd) / sizeof(struct fdrive)) + +/* helper macros for converting LBA into CHS */ +#define C(lba, ft) \ + (lba / (ft->h * ft->s)) +#define H(lba, ft) \ + ((lba / ft->s) % ft->h) +#define S(lba, ft) \ + ((lba % ft->s) + 1) + +#define PRESENT(fd) ((fd.type) && (fd.type != ftypes)) + +/* TODO: replace any delay loops with sleep_on() */ +/* TODO: implement a head scheduling algorithm */ +/* TODO: implement write functionality */ +/* TODO: implement access to multiple drives */ +/* TODO: seek before reading */ +/* TODO: check drive ready state in floppy driver (ensure the drive door is closed before any operation) */ +/* TODO: cut back on printk() usage */ + +/* TODO: implement a timeout to prevent system hangs */ +#define WAITIRQ(x) ({ \ + irq_fired = 0; \ + (x); \ + while(!irq_fired); \ + irq_fired = 0; \ + }) + +extern void fd_isr(void); + +struct sense_result { + uint8_t st0; + uint8_t cyl; +} __attribute__((packed)); + +struct ftype { + uint16_t c; + uint8_t h; + uint8_t s; + uint8_t drate; /* 0: 500Kb/s, 1: 300Kb/s, 2: 250Kb/s, 3: 1Mb/s */ + int delay; /* time to spin up (ms) */ + char *name; +}; + +struct fdrive { + struct ftype *type; + struct task_struct *seek_wait; + uint8_t cyl; + uint8_t st0; +}; + +/* possible floppy disk/drive configurations */ +static struct ftype ftypes[] = { + { 0, 0, 0, 0, 0, "none" }, + { 40, 2, 9, 1, 500, "360KB 5 1/4\"" }, + { 80, 2, 15, 0, 500, "1.2MB 5 1/4\"" }, + { 80, 2, 9, 2, 300, "720KB 3 1/2\"" }, + { 80, 2, 18, 0, 300, "1.44MB 3 1/2\"" }, + { 80, 2, 36, 3, 300, "2.88MB 3 1/2\"" } +}; + +static volatile int irq_fired; + +static struct fdrive fd[4]; + +static char buffer[512] __attribute__((aligned (0x10000))); + +static struct task_struct *read_wait; + +static ssize_t read_data(void *buf, size_t len) { + ssize_t c = 0; + uint8_t *p = buf; + + if(!buf) + return 0; + + if(len > SSIZE_MAX) + len = SSIZE_MAX; + + /* + * TODO: fix this. + * This entire routine really is garbage. + * It doesn't use a timeout (potentially + * hanging the entire system) and doesn't + * handle the DIO flag properly. + */ + while(len--) { + while(!(inb(FDMSR) & 0x80)); + + if(!(inb(FDMSR) & 0x40)) + break; + + *p++ = inb(FDDATA); + c++; + + /* delay */ + inb(0x80); + } + + /* empty out any remaining bytes the FDC may have for us */ + while((inb(FDMSR) & 0xC0) == 0xC0) + inb(FDDATA); + + if(!c) + return -1; + return c; +} + +static void write_data(void *buf, size_t len) { + uint8_t *p = buf; + + if(!buf) + return; + + /* TODO: timeout waiting for RQM flag */ + while(len--) { + while(!(inb(FDMSR) & 0x80)); + + if((inb(FDMSR) & 0x40)) { + printk("[fd] Expected DIO=0. Drive not ready for data!\n"); + panic(); + } + + outb(FDDATA, *p++); + + /* delay */ + inb(0x80); + } +} + +static int seek(uint8_t drive, int cyl) { + drive &= 3; + + char cmd_seek[] = { + 0x0F, + drive, + cyl + }; + + if(!PRESENT(fd[drive])) + return -EINVAL; + + WAITIRQ(write_data(cmd_seek, sizeof(cmd_seek))); + + /* wait for the seek command to finish */ + while((inb(FDMSR) & (1 << drive))); + + return 0; +} + +static int sense_intr(struct sense_result *sr) { + ssize_t in; + char cmd_sense[] = { 0x08 }; + + /* send the sense interrupt command */ + write_data(cmd_sense, sizeof(cmd_sense)); + in = read_data(sr, sizeof(struct sense_result)); + if(in < sizeof(struct sense_result)) + return -1; + + printk("[fd] Sense command success (Drive: %c:, CYL: 0x%02x, ST0: 0x%02x)\n", 'A' + (sr->st0 & 3), sr->cyl, sr->st0); + return 0; +} + +static void reset(void) { + int i; + int wait = 0; + ssize_t in; + struct sense_result sr; + + /* TODO: set timings depending on the drive */ + char cmd_specify[] = { + 0x03, + 0xDF, /* SRT: 3ms, HUT: 240ms */ + 0x02 /* HLT: 16ms, NDMA: 0 */ + }; + + char cmd_recalibrate[] = { 0x07, 0x00 }; + + /* disable interrupts and put the FDC into reset */ + /* TODO: store FDDOR as static variable as the register is write-only */ + printk("[fd] Resetting FDC...\n"); + outb(FDDOR, inb(FDDOR) & 0xF3); + + /* program the data-rate */ + /* TODO: set this depending on floppy type */ + outb(FDDRS, 0); + outb(FDCCR, 0); + + /* bring the FDC out of reset and re-enable interrupts */ + outb(FDDOR, inb(FDDOR) | 0x0C); + + /* the IRQ handler will issue a sense-interrupt for us */ + WAITIRQ(NULL); + + /* send the specify command */ + write_data(cmd_specify, sizeof(cmd_specify)); + + for(i = 0; i < NFDS; i++) { + if(!PRESENT(fd[i])) + continue; + printk("[fd] Recalibrating Drive %c:...\n", 'A' + i); + cmd_recalibrate[1] = i & 3; + write_data(cmd_recalibrate, sizeof(cmd_recalibrate)); + wait |= 1 << i; + } + + /* wait for all drives to finish recalibrating */ + while((inb(FDMSR) & wait)); +} + +int fd_read_sect(int sect) { + ssize_t in; + struct { + uint8_t st0; + uint8_t st1; + uint8_t st2; + uint8_t c; + uint8_t h; + uint8_t r; + uint8_t n; + } __attribute__((packed)) res; + + char cmd[] = { + 0x46, + H(sect, fd[0].type) << 2, + C(sect, fd[0].type), + H(sect, fd[0].type), + S(sect, fd[0].type), + 0x02, + S(sect, fd[0].type), + 0x1B, + 0xFF + }; + + cli(); + if(read_wait) + sleep_on(&read_wait); + sti(); + + printk("[fd] Reading sector 0x%01x (C: 0x%01x, H: 0x%01x, S: 0x%01x)\n", sect, cmd[2], cmd[3], cmd[4]); + + WAITIRQ(write_data(cmd, sizeof(cmd))); + + in = read_data(&res, sizeof(res)); + if(in == sizeof(res) && !(res.st0 & 0xC0)) { + printk("[fd] Successfully read a sector (ST0: 0x%02x, N: 0x%02x)!\n", res.st0, res.n); + printk(" DATA: %s\n", buffer); + return 0; + } + + printk("[fd] Read command failed!\n"); + return -1; +} + +void fd_interrupt(void) { + struct sense_result sr; + irq_fired = 1; + + wake_up(&read_wait); + + if((inb(FDMSR) & 0xC0) != 0x80) + return; + if(sense_intr(&sr) < sizeof(sr)) + return; + /* deposit result into current drive struct */ + fd[sr.cyl & 3].cyl = sr.cyl; + fd[sr.st0 & 3].st0 = sr.st0; +} + +void fd_block_read(struct buffer *b) { + int i; + void *p = b->b_data; + + for(i = SECTS(b->b_block); i < SECTS(b->b_block + 1); i++) { + if(fd_read_sect(i)) { + b->b_device = 0; + return; + } + memcpy(p, buffer, sizeof(buffer)); + p += 512; + } + + b->b_present = 1; +} + +void fd_init(void) { + int i; + int delay = 0; + uint8_t tmp; + + /* put the controller into reset */ + outb(FDDOR, 0); + + outb(0x70, 0x10); + tmp = inb(0x71); + + fd[0].type = &ftypes[(tmp >> 4) > NTYPES ? 0 : (tmp >> 4)]; + fd[1].type = &ftypes[(tmp & 0xF) > NTYPES ? 0 : (tmp & 0xF)]; + fd[2].type = ftypes; + fd[3].type = ftypes; + + /* setup the drive (motors A and B on) */ + /* TODO: motor timeout */ + outb(FDDOR, 0x3C); + + /* wait for all drives to spin up */ + for(i = 0; i < NFDS; i++) + if(PRESENT(fd[i])) + delay = fd[i].type->delay > delay ? fd[i].type->delay : delay; + delay = (delay / 10) + ticks; + while(ticks < delay); + + /* initialize the DMA controller */ + outb(0x0F, 0x0F); + outb(0x0C, 0xFF); + outb(0x04, (uint32_t) buffer); + outb(0x04, (uint32_t) buffer >> 8); + outb(0x0C, 0xFF); + outb(0x05, sizeof(buffer)); + outb(0x05, sizeof(buffer) >> 8); + outb(0x81, (uint32_t) buffer >> 16); + outb(0x0B, 0x56); + outb(0x0A, 0x02); + + register_isr(0x26, 0, &fd_isr); + irq_enable(0x40); + + reset(); + + printk("[fd] Floppy subsystem initialized (A: %s, B: %s)\n", fd[0].type->name, fd[1].type->name); +} diff --git a/kernel/fd_s.s b/kernel/fd_s.s new file mode 100644 index 0000000..a8acb5b --- /dev/null +++ b/kernel/fd_s.s @@ -0,0 +1,27 @@ +global fd_isr +extern printk + +extern fd_interrupt + +fd_isr: + pusha + mov ax, ds + push ax + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + call fd_interrupt + + mov al, 0x20 + out 0x20, al + + pop ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + popa + iret diff --git a/kernel/fs/block.c b/kernel/fs/block.c index caf97d2..8f9d907 100644 --- a/kernel/fs/block.c +++ b/kernel/fs/block.c @@ -1,9 +1,23 @@ +#include <kernel/fd.h> +#include <kernel/fs.h> #include <sys/types.h> -int block_read(void *buf, size_t block) { - return -1; +/* + * Minix Major Numbers: + * + * [0] NULL + * [1] /dev/mem + * [2] /dev/fdX + * [3] /dev/hdX + * [4] /dev/ttyX + * [5] /dev/tty + * [6] /dev/lpX + */ + +void block_read(struct buffer *b) { + fd_block_read(b); } -int block_write(void *buf, size_t block) { - return -1; +void block_write(struct buffer *b) { + b->b_device = 0; } diff --git a/kernel/fs/buffer.c b/kernel/fs/buffer.c index 7405738..99c3161 100644 --- a/kernel/fs/buffer.c +++ b/kernel/fs/buffer.c @@ -1,16 +1,76 @@ +#include <asm/interrupt.h> +#include <errno.h> #include <kernel/con.h> #include <kernel/fs.h> #include <stdint.h> #include <string.h> /* memory dedicated to the block cache */ +/* TODO: start buffers at kernel end not 512K */ #define BSTART 0x80000 #define BEND 0xA0000 static struct buffer *lru; static struct buffer *mru; -struct buffer *buffer_get_block(uint16_t device, uint16_t block); +struct buffer *buffer_get_block(uint16_t device, uint16_t block) { + struct buffer **p = &mru; + struct buffer *b; + + if(!device) + return NULL; + + /* check if the requested block is already in the cache */ + while(b = *p) { + if(b->b_device != device || b->b_block != block) + goto next; + /* remove the buffer from the list */ + if(lru == b && b->b_next) lru = b->b_next; + if(b->b_next) b->b_next->b_prev = b->b_prev; + if(b->b_prev) b->b_prev->b_next = b->b_next; + /* put the buffer back at the MRU end of the list */ + b->b_next = NULL; + b->b_prev = mru; + if(mru != b) + mru->b_next = b; + mru = b; + cli(); + /* if the buffer exists but isn't populated. wait on it */ + if(!b->b_present) { + sleep_on(&b->b_wait); + printk("[buf] Waiting for buffer %04x:%04x to be populated...\n", b->b_device, b->b_block); + } + sti(); + printk("[buf] Fetched block %04x:%04x from cache\n", b->b_device, b->b_block); + return b->b_device ? b : NULL; +next: + p = &b->b_prev; + } + + /* + * otherwise, iterate through the least recently used + * buffers, to find a buffer that isn't pending an + * I/O operation, and read into it. + */ + + p = &lru; + while(b = *p) { + if(b->b_present || !b->b_device) + break; + p = &(*p)->b_next; + } + + if(!b) + return NULL; + + b->b_device = device; + b->b_block = block; + b->b_present = 0; + block_read(b); + wake_up(&b->b_wait); + printk("[buf] Called driver to read block %04x:%04x\n", b->b_device, b->b_block); + return b->b_device ? b : NULL; +} void buffer_init(void) { int c = 0; @@ -40,43 +100,3 @@ void buffer_init(void) { printk("[buf] Buffers initialized (0x%x buffers in pool)\n", c); } - -struct buffer *buffer_get_block(uint16_t device, uint16_t block) { - int ret; - struct buffer **p = &mru; - struct buffer *b; - - /* check if the requested block is already in the cache */ - while(*p) { - if((*p)->b_device == device && (*p)->b_block == block) { - /* put the buffer back at the MRU end of the list */ - (*p)->b_next = NULL; - (*p)->b_prev = mru; - mru = *p; - return *p; - } - p = &(*p)->b_prev; - } - - /* find a buffer at the end of the LRU list */ - b = lru; - lru = lru->b_next; - lru->b_prev = NULL; - ret = block_read(b->b_data, block); - /* abort if we failed to read in the block */ - if(ret < 0) { - /* release the allocated buffer to the pool */ - lru->b_prev = b; - b->b_next = lru; - b->b_prev = NULL; - lru = b; - return NULL; - } - b->b_device = device; - b->b_block = block; - /* put the buffer back at the MRU end of the list */ - b->b_next = NULL; - b->b_prev = mru; - mru = b; - return b; -} diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c index 381f20a..e460a4a 100644 --- a/kernel/fs/fs.c +++ b/kernel/fs/fs.c @@ -1,5 +1,6 @@ #include <errno.h> #include <kernel/con.h> +#include <kernel/fd.h> #include <kernel/fs.h> #include <kernel/kernel.h> #include <kernel/sched.h> @@ -32,6 +33,7 @@ void fs_init(void) { buffer_init(); /* hd_init(); */ + fd_init(); mount_root(); } diff --git a/kernel/fs/mount.c b/kernel/fs/mount.c index 9cdf49b..e4d3636 100644 --- a/kernel/fs/mount.c +++ b/kernel/fs/mount.c @@ -7,15 +7,17 @@ struct super_block sblocks[NRSUPER]; void mount_root(void) { int ret; - char buf[BLOCK_SIZE]; - struct super_block *s = (void*) buf; + struct buffer *b; + struct super_block *s; - ret = block_read(buf, 1); - if(ret < 0) { + b = buffer_get_block(1, 1); + if(!b) { printk("[fs] Failed to read super block\n"); return; } + s = b->b_data; + if(s->s_magic != SUPER_MAGIC) { printk("[fs] Invalid magic number in super block!\n"); return; @@ -31,5 +33,5 @@ void mount_root(void) { printk(" Max file size: 0x%01x\n", s->s_max_size); /* copy the super block into the table */ - memcpy(sblocks, buf, ((unsigned) &s->s_imap - (unsigned) s)); + memcpy(sblocks, s, ((unsigned) &s->s_imap - (unsigned) s)); } diff --git a/kernel/hd.c b/kernel/hd.c index 2f680d1..83108dd 100644 --- a/kernel/hd.c +++ b/kernel/hd.c @@ -40,7 +40,7 @@ static int read_sect(void *buf, uint32_t lba) { outb(0x1F7, 0x20); /* wait for the drive */ - while(1) { + for(;;) { /* poll the drive's status */ s = inb(0x1F7); if(s & ST_DF) { @@ -81,7 +81,7 @@ static int write_sect(void *buf, uint32_t lba) { outb(0x1F7, 0x30); /* wait for the drive */ - while(1) { + for(;;) { /* poll the drive's status */ s = inb(0x1F7); if(s & ST_DF) { @@ -102,15 +102,13 @@ static int write_sect(void *buf, uint32_t lba) { return 0; } -int hd_read_block(void *buf, size_t block) { +int hd_read_block(void *buf, uint16_t block) { int ret; size_t i; uint32_t s = SECTS(block); uint32_t e = SECTS(block + 1); - if(nblocks <= s) - return -1; - if(nblocks <= e) + if(nblocks <= s || nblocks <= e) return -1; for(i = 0; i < (e - s); i++) { @@ -125,15 +123,13 @@ int hd_read_block(void *buf, size_t block) { return 0; } -int hd_write_block(void *buf, size_t block) { +int hd_write_block(void *buf, uint16_t block) { int ret; size_t i; uint32_t s = SECTS(block); uint32_t e = SECTS(block + 1); - if(nblocks <= s) - return -1; - if(nblocks <= e) + if(nblocks <= s || nblocks <= e) return -1; for(i = 0; i < (e - s); i++) { @@ -158,7 +154,7 @@ int hd_init(void) { /* send the IDENTIFY command */ outb(0x1F7, 0xEC); - while(1) { + for(;;) { s = inb(0x1F7); if(!s) { printk("[hd] Master drive not detected on primary bus!\n"); diff --git a/kernel/sched.c b/kernel/sched.c index da55fa3..ff2d036 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -85,7 +85,8 @@ struct task_struct *create_proc(void *bin, size_t len) { } } - /* here we allocate pages to setup the process' + /* + * here we allocate pages to setup the process' * address space. in addition to the pages that * will hold the binary image, the following * pages are allocated: @@ -222,7 +223,7 @@ void reschedule(void) { return; n = ctaskn; - while(1) { + for(;;) { /* check alarms and signals */ for(i = 0; i < NRTASKS; i++) { if(tasks[i].alarm && tasks[i].alarm < ticks) { @@ -288,7 +289,7 @@ void interruptible_sleep_on(struct task_struct **waiting) { t = *waiting; *waiting = ctask; - while(1) { + for(;;) { ctask->state = TSTATE_INTERRUPTIBLE; reschedule(); diff --git a/kernel/tty.c b/kernel/tty.c index 529d955..a17429f 100644 --- a/kernel/tty.c +++ b/kernel/tty.c @@ -20,7 +20,7 @@ static struct tty_struct *ttys[] = { /* check if a buffer's empty and if so, go to sleep */ static int sleep_while_empty(struct tty_queue *q) { cli(); - while(1) { + for(;;) { if(q->pread == q->pwrite) interruptible_sleep_on(&q->waiting); @@ -38,7 +38,7 @@ static int sleep_while_empty(struct tty_queue *q) { /* check if a buffer's full and if so, go to sleep */ static int sleep_while_full(struct tty_queue *q, struct tty_struct *tty) { cli(); - while(1) { + for(;;) { /* * if the buffer is full, first notify the * driver so it can try to remove some diff --git a/lib/string.c b/lib/string.c index e8659ad..99ffdf0 100644 --- a/lib/string.c +++ b/lib/string.c @@ -1,5 +1,144 @@ +#include <errno.h> #include <string.h> +static char *errors[] = { + [0] = "Success", + [EPERM] = "Operation not permitted", + [ENOENT] = "No such file or directory", + [ESRCH] = "No such process", + [EINTR] = "Interrupted system call", + [EIO] = "Input/output error", + [ENXIO] = "No such device or address", + [E2BIG] = "Argument list too long", + [ENOEXEC] = "Exec format error", + [EBADF] = "Bad file descriptor", + [ECHILD] = "No child processes", + [EAGAIN] = "Resource temporarily unavailable", + [EWOULDBLOCK] = "Resource temporarily unavailable", + [ENOMEM] = "Cannot allocate memory", + [EACCES] = "Permission denied", + [EFAULT] = "Bad address", + [ENOTBLK] = "Block device required", + [EBUSY] = "Device or resource busy", + [EEXIST] = "File exists", + [EXDEV] = "Invalid cross-device link", + [ENODEV] = "No such device", + [ENOTDIR] = "Not a directory", + [EISDIR] = "Is a directory", + [EINVAL] = "Invalid argument", + [ENFILE] = "Too many open files in system", + [EMFILE] = "Too many open files", + [ENOTTY] = "Inappropriate ioctl for device", + [ETXTBSY] = "Text file busy", + [EFBIG] = "File too large", + [ENOSPC] = "No space left on device", + [ESPIPE] = "Illegal seek", + [EROFS] = "Read-only file system", + [EMLINK] = "Too many links", + [EPIPE] = "Broken pipe", + [EDOM] = "Numerical argument out of domain", + [ERANGE] = "Numerical result out of range", + [EDEADLK] = "Resource deadlock avoided", + [EDEADLOCK] = "Resource deadlock avoided", + [ENAMETOOLONG] = "File name too long", + [ENOLCK] = "No locks available", + [ENOSYS] = "Function not implemented", + [ENOTEMPTY] = "Directory not empty", + [ELOOP] = "Too many levels of symbolic links", + [ENOMSG] = "No message of desired type", + [EIDRM] = "Identifier removed", + [ECHRNG] = "Channel number out of range", + [EL2NSYNC] = "Level 2 not synchronized", + [EL3HLT] = "Level 3 halted", + [EL3RST] = "Level 3 reset", + [ELNRNG] = "Link number out of range", + [EUNATCH] = "Protocol driver not attached", + [ENOCSI] = "No CSI structure available", + [EL2HLT] = "Level 2 halted", + [EBADE] = "Invalid exchange", + [EBADR] = "Invalid request descriptor", + [EXFULL] = "Exchange full", + [ENOANO] = "No anode", + [EBADRQC] = "Invalid request code", + [EBADSLT] = "Invalid slot", + [EBFONT] = "Bad font file format", + [ENOSTR] = "Device not a stream", + [ENODATA] = "No data available", + [ETIME] = "Timer expired", + [ENOSR] = "Out of streams resources", + [ENONET] = "Machine is not on the network", + [ENOPKG] = "Package not installed", + [EREMOTE] = "Object is remote", + [ENOLINK] = "Link has been severed", + [EADV] = "Advertise error", + [ESRMNT] = "Srmount error", + [ECOMM] = "Communication error on send", + [EPROTO] = "Protocol error", + [EMULTIHOP] = "Multihop attempted", + [EDOTDOT] = "RFS specific error", + [EBADMSG] = "Bad message", + [EOVERFLOW] = "Value too large for defined data type", + [ENOTUNIQ] = "Name not unique on network", + [EBADFD] = "File descriptor in bad state", + [EREMCHG] = "Remote address changed", + [ELIBACC] = "Can not access a needed shared library", + [ELIBBAD] = "Accessing a corrupted shared library", + [ELIBSCN] = ".lib section in a.out corrupted", + [ELIBMAX] = "Attempting to link in too many shared libraries", + [ELIBEXEC] = "Cannot exec a shared library directly", + [EILSEQ] = "Invalid or incomplete multibyte or wide character", + [ERESTART] = "Interrupted system call should be restarted", + [ESTRPIPE] = "Streams pipe error", + [EUSERS] = "Too many users", + [ENOTSOCK] = "Socket operation on non-socket", + [EDESTADDRREQ] = "Destination address required", + [EMSGSIZE] = "Message too long", + [EPROTOTYPE] = "Protocol wrong type for socket", + [ENOPROTOOPT] = "Protocol not available", + [EPROTONOSUPPORT] = "Protocol not supported", + [ESOCKTNOSUPPORT] = "Socket type not supported", + [ENOTSUP] = "Operation not supported", + [EOPNOTSUPP] = "Operation not supported", + [EPFNOSUPPORT] = "Protocol family not supported", + [EAFNOSUPPORT] = "Address family not supported by protocol", + [EADDRINUSE] = "Address already in use", + [EADDRNOTAVAIL] = "Cannot assign requested address", + [ENETDOWN] = "Network is down", + [ENETUNREACH] = "Network is unreachable", + [ENETRESET] = "Network dropped connection on reset", + [ECONNABORTED] = "Software caused connection abort", + [ECONNRESET] = "Connection reset by peer", + [ENOBUFS] = "No buffer space available", + [EISCONN] = "Transport endpoint is already connected", + [ENOTCONN] = "Transport endpoint is not connected", + [ESHUTDOWN] = "Cannot send after transport endpoint shutdown", + [ETOOMANYREFS] = "Too many references: cannot splice", + [ETIMEDOUT] = "Connection timed out", + [ECONNREFUSED] = "Connection refused", + [EHOSTDOWN] = "Host is down", + [EHOSTUNREACH] = "No route to host", + [EALREADY] = "Operation already in progress", + [EINPROGRESS] = "Operation now in progress", + [ESTALE] = "Stale file handle", + [EUCLEAN] = "Structure needs cleaning", + [ENOTNAM] = "Not a XENIX named type file", + [ENAVAIL] = "No XENIX semaphores available", + [EISNAM] = "Is a named type file", + [EREMOTEIO] = "Remote I/O error", + [EDQUOT] = "Disk quota exceeded", + [ENOMEDIUM] = "No medium found", + [EMEDIUMTYPE] = "Wrong medium type", + [ECANCELED] = "Operation canceled", + [ENOKEY] = "Required key not available", + [EKEYEXPIRED] = "Key has expired", + [EKEYREVOKED] = "Key has been revoked", + [EKEYREJECTED] = "Key was rejected by service", + [EOWNERDEAD] = "Owner died", + [ENOTRECOVERABLE] = "State not recoverable", + [ERFKILL] = "Operation not possible due to RF-kill", + [EHWPOISON] = "Memory page has hardware error", +}; + void *memchr(const void *s, int c, size_t n) { unsigned char *p = (unsigned char*) s; while(n--) { @@ -171,3 +310,12 @@ size_t strxfrm(char *dest, const char *src, size_t n) { if(n > n2) strcpy(dest, src); return n2; } + +char *strerror(int err) { + err = err < 0 ? -err : err; + + if(err > sizeof(errors) / sizeof(char*)) + return NULL; + + return errors[err]; +} diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a566b83..4188308 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -6,8 +6,9 @@ enum TYPE { TYPE_INT = 1, TYPE_UINT = 2, TYPE_HEX = 3, - TYPE_STRING = 4, - TYPE_PERCENT = 5 + TYPE_CHAR = 4, + TYPE_STRING = 5, + TYPE_PERCENT = 6 }; enum FLAGS { @@ -91,7 +92,7 @@ int vsprintf(char *str, char *fmt, va_list ap) { fwidth = 0; fmt++; - while(1) { + for(;;) { switch(*fmt) { case '#': flags |= FL_ALT; @@ -99,6 +100,9 @@ int vsprintf(char *str, char *fmt, va_list ap) { case '%': type = TYPE_PERCENT; goto done; + case 'c': + type = TYPE_CHAR; + goto done; case 's': type = TYPE_STRING; goto done; @@ -137,6 +141,9 @@ done: while(*s) *str++ = *s++; break; + case TYPE_CHAR: + *str++ = va_arg(ap, char); + break; case TYPE_HEX: x = va_arg(ap, int); hex(&str, flags, fwidth, 4, x); diff --git a/usrbin/main.c b/usrbin/main.c index c4a257c..f05cb84 100644 --- a/usrbin/main.c +++ b/usrbin/main.c @@ -1,7 +1,9 @@ #include <errno.h> +#include <kernel/fs.h> #include <signal.h> #include <stdint.h> #include <stdio.h> +#include <string.h> #include <time.h> #include <unistd.h> @@ -16,7 +18,7 @@ void pid1(void) { printf("We did it ma!\n"); signal(1, &sighandler); - while(1) { + for(;;) { in = read(STDIN_FILENO, buf, 1); if(in < 1) { if(in == -EINTR) { @@ -41,7 +43,7 @@ void pid2(void) { printf("We did it ma!\n"); - while(1) { + for(;;) { sleep(1); if(time() == 2) kill(1, 1); |
