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;
}