diff --git a/Makefile b/Makefile index 2484a8f..ffcb765 100644 --- a/Makefile +++ b/Makefile @@ -85,7 +85,7 @@ LibCSources = libc/atoi.c libc/itoa.c \ KernObj=$(patsubst %.c,$(KOBJDIR)/%.o,$(KernSources)) # Kernel sources -KernSources = libbuf/buf.c libbuf/bput.c \ +KernSources = libbuf/buf.c libbuf/bputc.c libbuf/bscroll.c \ libbuf/bprint.c kernel/cpu/cpuid.c \ kernel/cpu/idt.c kernel/init/init.c \ kernel/init/table.c kernel/io/cursor.c \ diff --git a/include/base/errno.h b/include/base/errno.h index a6e2d33..1ecfe37 100644 --- a/include/base/errno.h +++ b/include/base/errno.h @@ -78,6 +78,9 @@ // Alignment error #define EALIGN 257 +// End of file/stream +#define EENDF 258 + //------------------------------------------// #endif diff --git a/include/extras/buf.h b/include/extras/buf.h index 9d2ffc7..2920ac6 100644 --- a/include/extras/buf.h +++ b/include/extras/buf.h @@ -34,10 +34,15 @@ // enum { - BF_LINE = 1, // Line-buffered - BF_FILE = 2, // Linked to a file - BF_ALLOC = 4, // Buffer was malloc'd - BF_FONCLOSE = 8, // Don't flush on close + BF_LINE = 1, // Line-buffered + BF_FILE = 1<<1, // Linked to a file + BF_BALLOC = 1<<2, // Buffer structure was malloc'd + BF_SALLOC = 1<<3, // Internal buffer was malloc'd + BF_FONCLOSE = 1<<4, // Flush on close + BF_AUTOSCROLL = 1<<5, // Scroll-down automatically + + BF_EOF = 1<<6, // End of file reached + BF_ERR = 1<<7, // An error happened }; // @@ -46,8 +51,6 @@ enum enum { BS_CLOSED = 0, // Buffer closed (need allocation) - BS_EOF, // Buffer closed, or end of file reached - BS_ERR, // Buffer not ready, an error happened // Buffer ready for... BS_RDWR, // Both reading and writing @@ -56,6 +59,19 @@ enum }; typedef struct Buffer_t Buffer_t; + +// +// For line buffers, the flusher by bputc() is called every '\n' +// For pure buffers, the flusher is called by bputc() after it fills +// the buffer (unless flush-on-close is enabled) +// +// When a buffer is full, if the flusher doesn'tchange buf->wp and bputc() +// is called again, it will produce a EENDF error and set the BF_EOF flag +// +// Unless line buffering with auto-scrolldown enabled, nothing is +// removed from the buffer by the libbuf functions themselves, if you want +// the buffer to be emptied on flush then do that in the flusher +// typedef error_t (*BFlusher_t)(Buffer_t *); struct Buffer_t @@ -72,7 +88,7 @@ struct Buffer_t uchar *rp; // Read pointer uchar *wp; // Write pointer - BFlusher_t flusher; // Called for flushing + BFlusher_t flusher; // See above // The following parameters are only used in line buf mode @@ -84,16 +100,34 @@ struct Buffer_t extern Buffer_t *BStdOut, *BStdDbg; -error_t BCloseBuf(Buffer_t *buf); -void BFlushOnClose(Buffer_t *buf); +error_t BCloseBuf(Buffer_t *); +void BFlushOnClose(Buffer_t *); -Buffer_t *BOpenPureBuf(char *source, size_t size); +void BEnableAutoScroll(Buffer_t *); +void BDisableAutoScroll(Buffer_t *); + +// +// Buffer creation functions +// +// 'source' is the internal buffer, if you want +// to give it yourself +// +// If *pbuf==NULL, malloc's the structure +// If source==NULL, malloc's the buffer +// BCloseBuf() handles the de-allocations +// + +// Creates a pure buffer of a given size +error_t BOpenPureBuf(Buffer_t **pbuf, int mode, size_t size); +error_t BOpenPureBufEx(Buffer_t **, char *source, int mode, size_t, + BFlusher_t); // Creates a lined buffer of pbCount*nLines lines each // of lineLen length (pb = playback buffer, for scrolling up) -// If source==NULL, malloc the buffer -Buffer_t *BOpenLineBuf(char *source, int mode, int lineLen, - int nLines, int pbCount, BFlusher_t flusher); +error_t BOpenLineBuf(Buffer_t **pbuf, int mode, + int lineLen, int nLines, int pbCount); +error_t BOpenLineBufEx(Buffer_t **pbuf, char *source, int mode, + int lineLen, int nLines, int pbCount, BFlusher_t); int BGetFlags(Buffer_t *); int BGetState(Buffer_t *); @@ -105,6 +139,7 @@ void BUnlockBuf(Buffer_t *); bool BTrylockBuf(Buffer_t *); error_t BFlushBuf(Buffer_t *); +error_t BScrollDownBuf(Buffer_t *); error_t BPutOnBuf(Buffer_t *, uchar); error_t BPrintOnBuf(Buffer_t *, const char *fmt, ...); error_t BPrintOnBufV(Buffer_t *, const char *fmt, va_list); @@ -112,5 +147,6 @@ error_t BPrintOnBufV(Buffer_t *, const char *fmt, va_list); error_t bputc(Buffer_t *buf, uchar ch); error_t bprintf(Buffer_t *buf, const char *fmt, ...); error_t vbprintf(Buffer_t *buf, const char *fmt, va_list ap); +error_t bscrolldown(Buffer_t *buf); #endif diff --git a/include/kernel/base.h b/include/kernel/base.h index 1b9e585..3669e93 100644 --- a/include/kernel/base.h +++ b/include/kernel/base.h @@ -131,5 +131,16 @@ noreturn void KeStartPanic(const char *, ...); //------------------------------------------// +#define XBUG(c) do { \ + volatile ushort *_vga \ + =(volatile ushort*)0xB8000; \ + while(_vga<(volatile ushort*)(0xB8000+(80*25*2)) ) \ + *_vga++=(c|(0xf<<8)); \ + asm volatile("cli\nhlt"); \ +}while(0) +#define BUG() XBUG('B') +#define BUGON(x) if(x)BUG() +//------------------------------------------// + #endif diff --git a/kaleid/kernel/init/init.c b/kaleid/kernel/init/init.c index 484a8e1..18f977d 100644 --- a/kaleid/kernel/init/init.c +++ b/kaleid/kernel/init/init.c @@ -63,7 +63,9 @@ noreturn void BtStartKern(multiboot_info_t *mbInfo, uint mbMagic) MmInitMemoryMap(); MmInitHeap(); PsInitSched(); - + + int i=1; + for(;i<=25;i++)BUGON(KernLog("%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%4d%3d\n",i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i)); KernLog("Cursor test:"); // End this machine's suffering diff --git a/kaleid/kernel/io/vga.c b/kaleid/kernel/io/vga.c index 26190fd..788bccd 100644 --- a/kaleid/kernel/io/vga.c +++ b/kaleid/kernel/io/vga.c @@ -49,7 +49,7 @@ error_t bvgaflusher(Buffer_t *buf) uchar *currentLine = buf->wp - buf->lineLen - buf->lastLF; uchar *bufStart = (uchar *)lmax((size_t)buf->buf, (size_t)currentLine - - (buf->nLines - 1) * buf->lineLen); + - (buf->nLines - 2) * buf->lineLen); uchar *ptr = bufStart; @@ -76,7 +76,6 @@ error_t bvgaflusher(Buffer_t *buf) const ushort filler = VGA_ComputeEntry(' ', color); while (fbp < fbe) *fbp++ = filler; } - return EOK; } @@ -86,12 +85,18 @@ error_t bvgaflusher(Buffer_t *buf) // error_t IoInitVGABuffer(void) { - static char bvgabuffer[1 * MB]; + static char bvgabufsrc[1 * MB]; + static Buffer_t bvgabufstruct; + + BStdOut = &bvgabufstruct; - BStdOut = BOpenLineBuf(bvgabuffer, BS_WRONLY, + BOpenLineBufEx(&BStdOut, + bvgabufsrc, BS_WRONLY, BtVideoInfo.framebufferWidth, BtVideoInfo.framebufferHeight, - 8, bvgaflusher); + 1, bvgaflusher); + + BEnableAutoScroll(BStdOut); BStdDbg = BStdOut; diff --git a/kaleid/kernel/ke/panic.c b/kaleid/kernel/ke/panic.c index 83cac28..046b847 100644 --- a/kaleid/kernel/ke/panic.c +++ b/kaleid/kernel/ke/panic.c @@ -77,6 +77,8 @@ noreturn void KeStartPanic(const char *fmt, ...) vbprintf(BStdOut, fmt, ap); va_end(ap); + bputc(BStdOut, '\n'); + BStdOut->flusher(BStdOut); KeHaltCPU(); diff --git a/kaleid/kernel/mm/gdt.c b/kaleid/kernel/mm/gdt.c index 06cbc15..bc41b29 100644 --- a/kaleid/kernel/mm/gdt.c +++ b/kaleid/kernel/mm/gdt.c @@ -28,6 +28,7 @@ GdtEntry_t gdtEntries[5]; GdtPtr_t gdtPtr; +#if 0 static void SetGdtEntry(int index, uint base, uint limit, uchar access, uchar granularity) { @@ -41,7 +42,7 @@ static void SetGdtEntry(int index, uint base, uint limit, uchar access, gdtEntries[index].granularity |= granularity & 0xF0; gdtEntries[index].access = access; } - +#endif void MmInitGdt(void) diff --git a/kaleid/libbuf/bprint.c b/kaleid/libbuf/bprint.c index 51108fb..2fabdcb 100644 --- a/kaleid/libbuf/bprint.c +++ b/kaleid/libbuf/bprint.c @@ -134,6 +134,7 @@ error_t vbprintf(Buffer_t *buf, const char *fmt, va_list ap) assert(buf && buf->initDone == INITOK); if (!buf || !fmt) return EINVAL; + if (buf->flags & (BF_EOF|BF_ERR)) return EENDF; if (buf->state != BS_RDWR && buf->state != BS_WRONLY) { return EBADF; } diff --git a/kaleid/libbuf/bput.c b/kaleid/libbuf/bputc.c similarity index 72% rename from kaleid/libbuf/bput.c rename to kaleid/libbuf/bputc.c index 7997c9a..ba2ce00 100644 --- a/kaleid/libbuf/bput.c +++ b/kaleid/libbuf/bputc.c @@ -34,6 +34,7 @@ error_t BPutOnBuf(Buffer_t *buf, uchar ch) assert(buf && buf->initDone == INITOK); if (!buf) return EINVAL; + if (buf->flags & (BF_EOF|BF_ERR)) return EENDF; if (buf->state != BS_RDWR && buf->state != BS_WRONLY) { return EBADF; } @@ -50,7 +51,6 @@ error_t BPutOnBuf(Buffer_t *buf, uchar ch) error_t bputc(Buffer_t *buf, uchar ch) { error_t rc = EOK; - size_t bufSize, pbCount; // Implements playback / scrolling up when line buffering // Note that '\n', '\r' and '\t' can never occur in the buffer @@ -62,11 +62,6 @@ error_t bputc(Buffer_t *buf, uchar ch) if (ch == '\n') { assert(buf->lastLF < buf->lineLen); - // Make sure double \n's have effect - //if (buf->lastLF == 0) { - // buf->lastLF = buf->lineLen; - //} - int off = buf->lineLen - buf->lastLF; while (off > 0) { *buf->wp++ = ' '; @@ -74,7 +69,13 @@ error_t bputc(Buffer_t *buf, uchar ch) } buf->lastLF = 0; - if (buf->flusher) buf->flusher(buf); + + // Auto-scrolling + if (buf->wp == buf->buf + buf->size && buf->flags&BF_AUTOSCROLL) { + bscrolldown(buf); + } + + if (buf->flusher) buf->flusher(buf); } // Deal with carriage returns @@ -97,32 +98,9 @@ error_t bputc(Buffer_t *buf, uchar ch) // Just a regular character else { - // Do we have to scroll up? if (buf->wp == buf->buf + buf->size) { - // Yes, so we give up a whole playback buffer worth - // of lines so we don't have to do this too often - // (basically we make the current buffer a pb one) - bufSize = buf->nLines * buf->lineLen; - pbCount = (buf->size / bufSize) - 1; - - // Paranoia check - assert(buf->size >= (size_t)(buf->nLines * buf->lineLen)); - - // If we only have one playback buffer we just give up a line - if (pbCount == 0) { - // Use of memcpy() is safe because the source occur - // after the destination - memcpy(buf->buf, buf->buf + buf->lineLen, - buf->size - buf->lineLen); - buf->wp -= buf->lineLen; - } - - // We do have a playback buffer worth of lines to give up - else { - memcpy(buf->buf, buf->buf + bufSize, - buf->size - bufSize); - buf->wp -= bufSize; - } + buf->flags |= BF_EOF; + return EENDF; } // Write it @@ -132,18 +110,28 @@ error_t bputc(Buffer_t *buf, uchar ch) if (++buf->lastLF == buf->lineLen) { buf->lastLF = 0; } - } - return EOK; + // Auto-scrolling + if (buf->wp == buf->buf + buf->size && buf->flags&BF_AUTOSCROLL) { + bscrolldown(buf); + } + } } - // No scrolling up when not line-buffering + // Not line-buffering else { if (buf->wp == buf->buf + buf->size) { - buf->state = BS_EOF; + buf->flags |= BF_EOF; + return EENDF; } - return ENOSYS; + *buf->wp++ = ch; + + if (buf->wp == buf->buf + buf->size && !(buf->flags&BF_FONCLOSE)) { + buf->flusher(buf); + } } + + return EOK; } diff --git a/kaleid/libbuf/bscroll.c b/kaleid/libbuf/bscroll.c new file mode 100644 index 0000000..a9b7a15 --- /dev/null +++ b/kaleid/libbuf/bscroll.c @@ -0,0 +1,81 @@ +//----------------------------------------------------------------------------// +// GNU GPL OS/K // +// // +// Desc: Buffer library // +// // +// // +// Copyright © 2018-2019 The OS/K Team // +// // +// This file is part of OS/K. // +// // +// OS/K is free software: you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation, either version 3 of the License, or // +// any later version. // +// // +// OS/K is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY//without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with OS/K. If not, see . // +//----------------------------------------------------------------------------// + +#include +#include + +void BEnableAutoScroll(Buffer_t *buf) { buf->flags |= BF_AUTOSCROLL; } +void BDisableAutoScroll(Buffer_t *buf) { buf->flags &= ~BF_AUTOSCROLL; } + +error_t BScrollDownBuf(Buffer_t *buf) +{ + error_t rc; + assert(buf && buf->initDone == INITOK); + + if (!buf) return EINVAL; + if (buf->flags & (BF_EOF|BF_ERR)) return EENDF; + if (buf->state != BS_RDWR && buf->state != BS_WRONLY) { + return EBADF; + } + + ExAcquireLock(&buf->lock); + rc = bscrolldown(buf); + ExReleaseLock(&buf->lock); + return rc; +} + +error_t bscrolldown(Buffer_t *buf) +{ + size_t bufSize, pbCount; + + assert(buf->wp == buf->buf + buf->size); + + // We give up a whole playback buffer worth + // of lines so we don't have to do this too often + // (we make the current buffer a pb one) + bufSize = buf->nLines * buf->lineLen; + pbCount = (buf->size / bufSize) - 1; + + // Paranoia check + assert(buf->size >= (size_t)(buf->nLines * buf->lineLen)); + + // If we only have one playback buffer we just give up a line + if (pbCount == 0) { + // Use of memcpy() is safe because the source occur + // after the destination + memmove(buf->buf, buf->buf + buf->lineLen, + buf->size - buf->lineLen); + buf->wp -= buf->lineLen; + } + + // We do have a playback buffer worth of lines to give up + else { + memmove(buf->buf, buf->buf + bufSize, + buf->size - bufSize); + buf->wp -= bufSize; + } + + return EOK; +} + diff --git a/kaleid/libbuf/buf.c b/kaleid/libbuf/buf.c index 858c129..8af53eb 100644 --- a/kaleid/libbuf/buf.c +++ b/kaleid/libbuf/buf.c @@ -57,7 +57,7 @@ error_t BCloseBuf(Buffer_t *buf) BFlushBuf(buf); } - if (buf->flags & BF_ALLOC) { + if (buf->flags & BF_SALLOC && buf->buf) { KalFreeMemory(buf->buf); } @@ -65,53 +65,49 @@ error_t BCloseBuf(Buffer_t *buf) buf->initDone = buf->flags = buf->state = buf->size = 0; ExReleaseLock(&buf->lock); - KalFreeMemory(buf); + + if (buf->flags & BF_BALLOC) { + KalFreeMemory(buf); + } return EOK; } // -// Opens a pure text buffer (for WRITING only) -// If source==NULL, malloc's the internal buffer +// Creates an actual buffer // -#if 0 -Buffer_t *BOpenPureBuf(char *source, size_t size) +error_t BOpenPureBuf(Buffer_t **pbuf, int mode, size_t size) { - /*Buffer_t *buf = malloc(sizeof *buf); - buf->flags = 0; - ExInitLock(&buf->lock);*/ - - return NULL; + return BOpenPureBufEx(pbuf, NULL, mode, size, NULL); } -#endif -// -// Creates a lined buffer of (nLines + pbCount*nLines) lines each -// of lineLen length (pb = playback buffer, for scrolling up) -// -Buffer_t *BOpenLineBuf(char *source, int mode, - int lineLen, int nLines, int pbCount, BFlusher_t flusher) +error_t BOpenPureBufEx(Buffer_t **pbuf, char *source, int mode, size_t size, + BFlusher_t flusher) { - assert(lineLen > 0 && nLines > 0 && pbCount >= 0); + Buffer_t *buf; + assert(mode == BS_RDWR || mode == BS_RDONLY || mode == BS_WRONLY); - //Buffer_t *buf = malloc(sizeof *buf); - static Buffer_t __buf; - Buffer_t *buf = &__buf; - + if (!pbuf) return EINVAL; + if (!*pbuf) { + buf = malloc(sizeof *buf); + if (!buf) return ENOMEM; + buf->flags |= BF_BALLOC; + } + else { + buf = *pbuf; + buf->flags = 0; + } ExInitLock(&buf->lock, KLOCK_MUTEX); ExAcquireLock(&buf->lock); - buf->lastLF = 0; + buf->size = size; buf->state = mode; - buf->flags = BF_LINE; - buf->nLines = nLines; - buf->lineLen = lineLen; - buf->size = lineLen * nLines * (pbCount + 1); if (source == NULL) { KalAllocMemoryEx((void **)&buf->buf, buf->size, M_ZEROED, 0); + buf->flags |= BF_SALLOC; } else { buf->buf = (uchar *)source; } @@ -121,7 +117,45 @@ Buffer_t *BOpenLineBuf(char *source, int mode, buf->initDone = INITOK; ExReleaseLock(&buf->lock); - return buf; + + // Second allocation failed + if (buf->buf == NULL) { + BCloseBuf(buf); + return ENOMEM; + } + + *pbuf = buf; + return EOK; +} + +// +// Creates a line buffer of (nLines + pbCount*nLines) lines each +// of lineLen length (pb = playback buffer, for scrolling up) +// +error_t BOpenLineBuf(Buffer_t **pbuf, int mode, + int lineLen, int nLines, int pbCount) +{ + return BOpenLineBufEx(pbuf, NULL, mode, lineLen, nLines, pbCount, NULL); +} + +error_t BOpenLineBufEx(Buffer_t **pbuf, char *source, int mode, + int lineLen, int nLines, int pbCount, BFlusher_t flusher) +{ + error_t rc; + size_t size = lineLen * nLines * (pbCount + 1); + + assert(lineLen > 0 && nLines > 0 && pbCount >= 0); + + rc = BOpenPureBufEx(pbuf, source, mode, size, flusher); + + if (!rc) { + (*pbuf)->lastLF = 0; + (*pbuf)->nLines = nLines; + (*pbuf)->lineLen = lineLen; + (*pbuf)->flags |= BF_LINE; + } + + return rc; } // @@ -134,7 +168,10 @@ error_t BFlushBuf(Buffer_t *buf) assert(buf && buf->initDone == INITOK); if (!buf) return EINVAL; - if (!buf->flusher || buf->state == BS_EOF || buf->state == BS_ERR) { + if (buf->flags & (BF_EOF|BF_ERR)) { + return EENDF; + } + if (!buf->flusher) { return EBADF; } diff --git a/kaleid/libc/mem.c b/kaleid/libc/mem.c index 470afd3..836d9f7 100644 --- a/kaleid/libc/mem.c +++ b/kaleid/libc/mem.c @@ -178,6 +178,9 @@ void *memcpy(void *restrict dst, const void *restrict src, size_t bytes) const ulong *usrc = (const ulong *)src; ulong *udst = (ulong *)dst; + assert("Don't use this, use memmove()"); + assert((dst + bytes < src || src + bytes < dst) && "memcpy() overlap; use memmove()"); + if unlikely (bytes == 0) return dst; // Can align both src and dst at once at once? @@ -232,15 +235,17 @@ void *memmove(void *dst, const void *src, size_t bytes) const uchar *usrc = src; uchar *udst = dst; - // Can we use memcpy() safely? + // Can we safely go forward? if (udst < usrc) { - return memcpy(dst, src, bytes); + while (bytes--) *udst++ = *usrc++; } // No, so we go backwards - uchar *usrc_end = (uchar *)usrc + bytes - 1; - uchar *udst_end = udst + bytes - 1; - while (bytes--) *udst_end-- = *usrc_end--; + else { + const uchar *usrc_end = usrc + bytes - 1; + uchar *udst_end = udst + bytes - 1; + while (bytes--) *udst_end-- = *usrc_end--; + } return dst; }