Changes in / [61c91532:a65ccc4] in mainline


Ignore:
Files:
1 added
18 edited

Legend:

Unmodified
Added
Removed
  • abi/include/abi/syscall.h

    r61c91532 ra65ccc4  
    110110        SYS_DEBUG_CONSOLE,
    111111
    112         SYS_KLOG,
    113         SYS_KIO_READ,
     112        SYS_KLOG
    114113} syscall_t;
    115114
  • kernel/genarch/src/drivers/ega/ega.c

    r61c91532 ra65ccc4  
    6969        uint8_t *backbuf;
    7070        ioport8_t *base;
    71         mbstate_t mbstate;
    7271} ega_instance_t;
    7372
    74 static void ega_write(outdev_t *, const char *, size_t);
     73static void ega_putuchar(outdev_t *, char32_t);
    7574static void ega_redraw(outdev_t *);
    7675
    7776static outdev_operations_t egadev_ops = {
    78         .write = ega_write,
     77        .write = ega_putuchar,
    7978        .redraw = ega_redraw,
    8079        .scroll_up = NULL,
     
    539538}
    540539
    541 static void _putuchar(ega_instance_t *instance, char32_t ch)
    542 {
     540static void ega_putuchar(outdev_t *dev, char32_t ch)
     541{
     542        ega_instance_t *instance = (ega_instance_t *) dev->data;
     543
     544        irq_spinlock_lock(&instance->lock, true);
     545
    543546        switch (ch) {
    544547        case '\n':
     
    561564        ega_check_cursor(instance);
    562565        ega_move_cursor(instance);
    563 }
    564 
    565 static void ega_write(outdev_t *dev, const char *s, size_t n)
    566 {
    567         ega_instance_t *instance = (ega_instance_t *) dev->data;
    568 
    569         irq_spinlock_lock(&instance->lock, true);
    570 
    571         size_t offset = 0;
    572         char32_t ch;
    573 
    574         while ((ch = str_decode_r(s, &offset, n, U_SPECIAL, &instance->mbstate)))
    575                 _putuchar(instance, ch);
    576566
    577567        irq_spinlock_unlock(&instance->lock, true);
  • kernel/genarch/src/drivers/ns16550/ns16550.c

    r61c91532 ra65ccc4  
    112112}
    113113
    114 static void ns16550_write(outdev_t *dev, const char *s, size_t n)
     114static void ns16550_putuchar(outdev_t *dev, char32_t ch)
    115115{
    116116        ns16550_instance_t *instance = (ns16550_instance_t *) dev->data;
    117117
    118         if (instance->parea.mapped && !console_override)
    119                 return;
    120 
    121         const char *top = s + n;
    122         assert(top >= s);
    123 
    124         for (; s < top; s++) {
    125                 if (*s == '\n')
     118        if ((!instance->parea.mapped) || (console_override)) {
     119                if (ch == '\n')
    126120                        ns16550_sendb(instance, '\r');
    127121
    128                 ns16550_sendb(instance, (uint8_t) *s);
     122                if (ascii_check(ch))
     123                        ns16550_sendb(instance, (uint8_t) ch);
     124                else
     125                        ns16550_sendb(instance, U_SPECIAL);
    129126        }
    130127}
    131128
    132129static outdev_operations_t ns16550_ops = {
    133         .write = ns16550_write,
     130        .write = ns16550_putuchar,
    134131        .redraw = NULL
    135132};
  • kernel/genarch/src/drivers/pl011/pl011.c

    r61c91532 ra65ccc4  
    5656}
    5757
    58 static void pl011_uart_write(outdev_t *dev, const char *s, size_t n)
     58static void pl011_uart_putuchar(outdev_t *dev, char32_t ch)
    5959{
    6060        pl011_uart_t *uart = dev->data;
     
    6464                return;
    6565
    66         const char *top = s + n;
    67         assert(top >= s);
    68 
    69         for (; s < top; s++) {
    70                 if (*s == '\n')
    71                         pl011_uart_sendb(uart, '\r');
    72 
    73                 pl011_uart_sendb(uart, (uint8_t) *s);
     66        if (!ascii_check(ch))
     67                pl011_uart_sendb(uart, U_SPECIAL);
     68        else {
     69                if (ch == '\n')
     70                        pl011_uart_sendb(uart, (uint8_t) '\r');
     71                pl011_uart_sendb(uart, (uint8_t) ch);
    7472        }
    7573}
    7674
    7775static outdev_operations_t pl011_uart_ops = {
    78         .write = pl011_uart_write,
     76        .write = pl011_uart_putuchar,
    7977        .redraw = NULL,
    8078        .scroll_up = NULL,
  • kernel/genarch/src/fb/fb.c

    r61c91532 ra65ccc4  
    8181        ((glyph) * (instance)->glyphbytes + (y) * (instance)->glyphscanline)
    8282
    83 #define TAB_WIDTH 8
    84 
    8583typedef void (*rgb_conv_t)(void *, uint32_t);
    8684
     
    10199
    102100        /** Number of rows that fit on framebuffer */
    103         unsigned int screen_rows;
     101        unsigned int rowtrim;
    104102
    105103        unsigned int scanline;
     
    123121        /** Current backbuffer position */
    124122        unsigned int position;
    125 
    126         /** Partial character between writes */
    127         mbstate_t mbstate;
    128 
    129         unsigned int row;
    130         unsigned int column;
    131123} fb_instance_t;
    132124
    133 static void fb_write(outdev_t *, const char *, size_t);
     125static void fb_putuchar(outdev_t *, char32_t);
    134126static void fb_redraw(outdev_t *);
    135127static void fb_scroll_up(outdev_t *);
     
    137129
    138130static outdev_operations_t fbdev_ops = {
    139         .write = fb_write,
     131        .write = fb_putuchar,
    140132        .redraw = fb_redraw,
    141133        .scroll_up = fb_scroll_up,
     
    255247
    256248        unsigned int rel_row = row - instance->offset_row;
    257         if (rel_row >= instance->screen_rows)
     249        if (rel_row >= instance->rowtrim)
    258250                return;
    259251
     
    267259}
    268260
     261/** Scroll screen down by one row
     262 *
     263 */
     264static void screen_scroll(fb_instance_t *instance)
     265{
     266        if ((!instance->parea.mapped) || (console_override)) {
     267                for (unsigned int rel_row = 0; rel_row < instance->rowtrim; rel_row++) {
     268                        unsigned int y = ROW2Y(rel_row);
     269                        unsigned int row = rel_row + instance->offset_row;
     270
     271                        for (unsigned int yd = 0; yd < FONT_SCANLINES; yd++) {
     272                                unsigned int x;
     273                                unsigned int col;
     274                                size_t bb_pos = BB_POS(instance, 0, row);
     275                                size_t bb_pos1 = BB_POS(instance, 0, row + 1);
     276
     277                                for (col = 0, x = 0; col < instance->cols;
     278                                    col++, x += FONT_WIDTH) {
     279                                        uint16_t glyph;
     280
     281                                        if (row < instance->rows - 1) {
     282                                                if (instance->backbuf[bb_pos] ==
     283                                                    instance->backbuf[bb_pos1])
     284                                                        goto skip;
     285
     286                                                glyph = instance->backbuf[bb_pos1];
     287                                        } else
     288                                                glyph = 0;
     289
     290                                        memcpy(&instance->addr[FB_POS(instance, x, y + yd)],
     291                                            &instance->glyphs[GLYPH_POS(instance, glyph, yd)],
     292                                            instance->glyphscanline);
     293                                skip:
     294                                        BB_NEXT_COL(bb_pos);
     295                                        BB_NEXT_COL(bb_pos1);
     296                                }
     297                        }
     298                }
     299        }
     300
     301        /*
     302         * Implement backbuffer scrolling by wrapping around
     303         * the cyclic buffer.
     304         */
     305
     306        instance->start_row++;
     307        if (instance->start_row == instance->rows)
     308                instance->start_row = 0;
     309
     310        memsetw(&instance->backbuf[BB_POS(instance, 0, instance->rows - 1)],
     311            instance->cols, 0);
     312}
     313
    269314static void cursor_put(fb_instance_t *instance)
    270315{
    271         unsigned int col = instance->column;
    272         unsigned int row = instance->row;
     316        unsigned int col = instance->position % instance->cols;
     317        unsigned int row = instance->position / instance->cols;
    273318
    274319        glyph_draw(instance, fb_font_glyph(U_CURSOR), col, row, true);
     
    277322static void cursor_remove(fb_instance_t *instance)
    278323{
    279         unsigned int col = instance->column;
    280         unsigned int row = instance->row;
     324        unsigned int col = instance->position % instance->cols;
     325        unsigned int row = instance->position / instance->cols;
    281326
    282327        glyph_draw(instance, instance->backbuf[BB_POS(instance, col, row)],
     
    328373static void fb_redraw_internal(fb_instance_t *instance)
    329374{
    330         for (unsigned int rel_row = 0; rel_row < instance->screen_rows; rel_row++) {
     375        for (unsigned int rel_row = 0; rel_row < instance->rowtrim; rel_row++) {
    331376                unsigned int y = ROW2Y(rel_row);
    332377                unsigned int row = rel_row + instance->offset_row;
     
    359404        }
    360405
    361         if (ROW2Y(instance->screen_rows) < instance->yres) {
     406        if (ROW2Y(instance->rowtrim) < instance->yres) {
    362407                unsigned int y;
    363408
    364                 for (y = ROW2Y(instance->screen_rows); y < instance->yres; y++)
     409                for (y = ROW2Y(instance->rowtrim); y < instance->yres; y++)
    365410                        memcpy(&instance->addr[FB_POS(instance, 0, y)],
    366411                            instance->bgscan, instance->bgscanbytes);
     
    368413}
    369414
    370 /** Scroll screen down by one row
    371  *
    372  */
    373 static void screen_scroll(fb_instance_t *instance)
    374 {
    375         /*
    376          * Implement backbuffer scrolling by wrapping around
    377          * the cyclic buffer.
    378          */
    379 
    380         instance->start_row++;
    381         if (instance->start_row == instance->rows)
    382                 instance->start_row = 0;
    383 
    384         if ((!instance->parea.mapped) || (console_override)) {
    385                 fb_redraw_internal(instance);
    386         }
    387 }
    388 
    389 static void _advance_row(fb_instance_t *instance)
    390 {
    391         instance->column = 0;
    392         instance->row++;
    393 }
    394 
    395 static void _advance_column(fb_instance_t *instance)
    396 {
    397         instance->column++;
    398         if (instance->column == instance->cols)
    399                 _advance_row(instance);
    400 }
    401 
    402415/** Print character to screen
    403416 *
     
    405418 *
    406419 */
    407 static void _putuchar(fb_instance_t *instance, char32_t ch)
    408 {
     420static void fb_putuchar(outdev_t *dev, char32_t ch)
     421{
     422        fb_instance_t *instance = (fb_instance_t *) dev->data;
     423        spinlock_lock(&instance->lock);
     424
    409425        switch (ch) {
    410426        case '\n':
    411                 _advance_row(instance);
     427                cursor_remove(instance);
     428                instance->position += instance->cols;
     429                instance->position -= instance->position % instance->cols;
    412430                break;
    413431        case '\r':
    414                 instance->column = 0;
     432                cursor_remove(instance);
     433                instance->position -= instance->position % instance->cols;
    415434                break;
    416435        case '\b':
    417                 if (instance->column > 0)
    418                         instance->column--;
     436                cursor_remove(instance);
     437                if (instance->position % instance->cols)
     438                        instance->position--;
    419439                break;
    420440        case '\t':
     441                cursor_remove(instance);
    421442                do {
    422443                        glyph_draw(instance, fb_font_glyph(' '),
    423                             instance->column,
    424                             instance->row, false);
    425                         _advance_column(instance);
    426                 } while (instance->column % TAB_WIDTH != 0);
     444                            instance->position % instance->cols,
     445                            instance->position / instance->cols, false);
     446                        instance->position++;
     447                } while (((instance->position % instance->cols) % 8 != 0) &&
     448                    (instance->position < instance->cols * instance->rows));
    427449                break;
    428450        default:
    429451                glyph_draw(instance, fb_font_glyph(ch),
    430                     instance->column,
    431                     instance->row, false);
    432                 _advance_column(instance);
    433         }
    434 
    435         while (instance->row >= instance->rows) {
    436                 instance->row--;
     452                    instance->position % instance->cols,
     453                    instance->position / instance->cols, false);
     454                instance->position++;
     455        }
     456
     457        if (instance->position >= instance->cols * instance->rows) {
     458                instance->position -= instance->cols;
    437459                screen_scroll(instance);
    438460        }
    439 }
    440 
    441 static void fb_write(outdev_t *dev, const char *s, size_t n)
    442 {
    443         fb_instance_t *instance = (fb_instance_t *) dev->data;
    444 
    445         spinlock_lock(&instance->lock);
    446         cursor_remove(instance);
    447 
    448         size_t offset = 0;
    449         char32_t ch;
    450 
    451         while ((ch = str_decode_r(s, &offset, n, U_SPECIAL, &instance->mbstate)))
    452                 _putuchar(instance, ch);
    453461
    454462        cursor_put(instance);
     463
    455464        spinlock_unlock(&instance->lock);
    456465}
     
    464473        spinlock_lock(&instance->lock);
    465474
    466         if (instance->offset_row >= instance->screen_rows / 2)
    467                 instance->offset_row -= instance->screen_rows / 2;
     475        if (instance->offset_row >= instance->rowtrim / 2)
     476                instance->offset_row -= instance->rowtrim / 2;
    468477        else
    469478                instance->offset_row = 0;
     
    483492        spinlock_lock(&instance->lock);
    484493
    485         if (instance->offset_row + instance->screen_rows / 2 <=
    486             instance->rows - instance->screen_rows)
    487                 instance->offset_row += instance->screen_rows / 2;
     494        if (instance->offset_row + instance->rowtrim / 2 <=
     495            instance->rows - instance->rowtrim)
     496                instance->offset_row += instance->rowtrim / 2;
    488497        else
    489                 instance->offset_row = instance->rows - instance->screen_rows;
     498                instance->offset_row = instance->rows - instance->rowtrim;
    490499
    491500        fb_redraw_internal(instance);
     
    606615        instance->scanline = props->scan;
    607616
    608         instance->screen_rows = Y2ROW(instance->yres);
     617        instance->rowtrim = Y2ROW(instance->yres);
    609618
    610619        instance->cols = X2COL(instance->xres);
    611         instance->rows = FB_PAGES * instance->screen_rows;
    612 
    613         instance->start_row = instance->rows - instance->screen_rows;
     620        instance->rows = FB_PAGES * instance->rowtrim;
     621
     622        instance->start_row = instance->rows - instance->rowtrim;
    614623        instance->offset_row = instance->start_row;
    615         instance->row = instance->start_row;
    616         instance->column = 0;
     624        instance->position = instance->start_row * instance->cols;
    617625
    618626        instance->glyphscanline = FONT_WIDTH * instance->pixelbytes;
  • kernel/generic/include/console/chardev.h

    r61c91532 ra65ccc4  
    8181/** Output character device operations interface. */
    8282typedef struct {
    83         /** Write string to output. */
    84         void (*write)(struct outdev *, const char *, size_t);
     83        /** Write character to output. */
     84        void (*write)(struct outdev *, char32_t);
    8585
    8686        /** Redraw any previously cached characters. */
  • kernel/generic/include/console/console.h

    r61c91532 ra65ccc4  
    3636#define KERN_CONSOLE_H_
    3737
     38#include <typedefs.h>
     39#include <print.h>
    3840#include <console/chardev.h>
    3941#include <synch/spinlock.h>
     
    6466extern void kio_update(void *);
    6567extern void kio_flush(void);
    66 extern void kio_push_bytes(const char *, size_t);
    67 extern irq_spinlock_t kio_lock;
     68extern void kio_push_char(const char32_t);
     69SPINLOCK_EXTERN(kio_lock);
    6870
    69 extern sysarg_t sys_kio_read(uspace_addr_t buf, size_t size, size_t at);
    7071extern sys_errno_t sys_kio(int cmd, uspace_addr_t buf, size_t size);
    7172
     
    7879extern void console_unlock(void);
    7980
    80 extern void putstr(const char *s, size_t n);
    81 
    8281#endif /* KERN_CONSOLE_H_ */
    8382
  • kernel/generic/include/stdio.h

    r61c91532 ra65ccc4  
    3737
    3838#include <print.h>
     39#include <putchar.h>
    3940
    4041#endif
  • kernel/generic/src/console/console.c

    r61c91532 ra65ccc4  
    22 * Copyright (c) 2003 Josef Cejka
    33 * Copyright (c) 2005 Jakub Jermar
    4  * Copyright (c) 2025 Jiří Zárevúcky
    54 * All rights reserved.
    65 *
     
    3635
    3736#include <abi/kio.h>
     37#include <arch.h>
     38#include <assert.h>
     39#include <atomic.h>
    3840#include <console/chardev.h>
    3941#include <console/console.h>
     42#include <ddi/ddi.h>
     43#include <ddi/irq.h>
    4044#include <errno.h>
    4145#include <ipc/event.h>
    42 #include <log.h>
     46#include <ipc/irq.h>
     47#include <mm/frame.h> /* SIZE2FRAMES */
    4348#include <panic.h>
    4449#include <preemption.h>
    45 #include <proc/task.h>
     50#include <proc/thread.h>
     51#include <putchar.h>
    4652#include <stdatomic.h>
    4753#include <stdio.h>
     
    5056#include <synch/mutex.h>
    5157#include <synch/spinlock.h>
     58#include <synch/waitq.h>
    5259#include <syscall/copy.h>
    5360#include <sysinfo/sysinfo.h>
     61#include <typedefs.h>
    5462
    5563#define KIO_PAGES    8
    56 #define KIO_LENGTH   (KIO_PAGES * PAGE_SIZE)
     64#define KIO_LENGTH   (KIO_PAGES * PAGE_SIZE / sizeof(char32_t))
    5765
    5866/** Kernel log cyclic buffer */
    59 static char kio[KIO_LENGTH];
     67char32_t kio[KIO_LENGTH] __attribute__((aligned(PAGE_SIZE)));
    6068
    6169/** Kernel log initialized */
     
    6876static MUTEX_INITIALIZE(console_mutex, MUTEX_RECURSIVE);
    6977
    70 /** Number of characters written to buffer. Periodically overflows. */
    71 static size_t kio_written = 0;
    72 
    73 /** Number of characters written to output devices. Periodically overflows. */
    74 static size_t kio_processed = 0;
    75 
    76 /** Last notification sent to uspace. */
    77 static size_t kio_notified = 0;
     78/** First kernel log characters */
     79static size_t kio_start = 0;
     80
     81/** Number of valid kernel log characters */
     82static size_t kio_len = 0;
     83
     84/** Number of stored (not printed) kernel log characters */
     85static size_t kio_stored = 0;
     86
     87/** Number of stored kernel log characters for uspace */
     88static size_t kio_uspace = 0;
    7889
    7990/** Kernel log spinlock */
    80 IRQ_SPINLOCK_INITIALIZE(kio_lock);
    81 
    82 static IRQ_SPINLOCK_INITIALIZE(flush_lock);
    83 
    84 static IRQ_SPINLOCK_INITIALIZE(early_mbstate_lock);
    85 static mbstate_t early_mbstate;
     91SPINLOCK_INITIALIZE_NAME(kio_lock, "kio_lock");
     92
     93/** Physical memory area used for kio buffer */
     94static parea_t kio_parea;
    8695
    8796static indev_t stdin_sink;
     
    95104};
    96105
    97 static void stdout_write(outdev_t *, const char *, size_t);
     106static void stdout_write(outdev_t *, char32_t);
    98107static void stdout_redraw(outdev_t *);
    99108static void stdout_scroll_up(outdev_t *);
     
    148157}
    149158
    150 static void stdout_write(outdev_t *dev, const char *s, size_t n)
     159static void stdout_write(outdev_t *dev, char32_t ch)
    151160{
    152161        list_foreach(dev->list, link, outdev_t, sink) {
    153162                if ((sink) && (sink->op->write))
    154                         sink->op->write(sink, s, n);
     163                        sink->op->write(sink, ch);
    155164        }
    156165}
     
    181190
    182191/** Initialize kernel logging facility
     192 *
     193 * The shared area contains kernel cyclic buffer. Userspace application may
     194 * be notified on new data with indication of position and size
     195 * of the data within the circular buffer.
     196 *
    183197 */
    184198void kio_init(void)
    185199{
     200        void *faddr = (void *) KA2PA(kio);
     201
     202        assert((uintptr_t) faddr % FRAME_SIZE == 0);
     203
     204        ddi_parea_init(&kio_parea);
     205        kio_parea.pbase = (uintptr_t) faddr;
     206        kio_parea.frames = SIZE2FRAMES(sizeof(kio));
     207        kio_parea.unpriv = false;
     208        kio_parea.mapped = false;
     209        ddi_parea_register(&kio_parea);
     210
     211        sysinfo_set_item_val("kio.faddr", NULL, (sysarg_t) faddr);
     212        sysinfo_set_item_val("kio.pages", NULL, KIO_PAGES);
     213
    186214        event_set_unmask_callback(EVENT_KIO, kio_update);
    187215        atomic_store(&kio_inited, true);
     
    229257                return;
    230258
    231         irq_spinlock_lock(&kio_lock, true);
    232 
    233         if (kio_notified != kio_written) {
    234                 if (event_notify_1(EVENT_KIO, true, kio_written) == EOK)
    235                         kio_notified = kio_written;
    236         }
    237 
    238         irq_spinlock_unlock(&kio_lock, true);
     259        spinlock_lock(&kio_lock);
     260
     261        if (kio_uspace > 0) {
     262                if (event_notify_3(EVENT_KIO, true, kio_start, kio_len,
     263                    kio_uspace) == EOK)
     264                        kio_uspace = 0;
     265        }
     266
     267        spinlock_unlock(&kio_lock);
    239268}
    240269
     
    249278                return;
    250279
    251         irq_spinlock_lock(&kio_lock, true);
    252 
    253         if (!irq_spinlock_trylock(&flush_lock)) {
    254                 /* Someone is currently flushing. */
    255                 irq_spinlock_unlock(&kio_lock, true);
    256                 return;
    257         }
    258 
    259         /* A small-ish local buffer so that we can write to output in chunks. */
    260         char buffer[256];
     280        spinlock_lock(&kio_lock);
    261281
    262282        /* Print characters that weren't printed earlier */
    263         while (kio_written != kio_processed) {
    264                 size_t offset = kio_processed % KIO_LENGTH;
    265                 size_t len = min(kio_written - kio_processed, KIO_LENGTH - offset);
    266                 len = min(len, sizeof(buffer));
    267 
    268                 /* Take out a chunk of the big buffer. */
    269                 memcpy(buffer, &kio[offset], len);
    270                 kio_processed += len;
     283        while (kio_stored > 0) {
     284                char32_t tmp = kio[(kio_start + kio_len - kio_stored) % KIO_LENGTH];
     285                kio_stored--;
    271286
    272287                /*
    273                  * We need to give up the spinlock for the physical operation of writing
    274                  * out the buffer.
     288                 * We need to give up the spinlock for
     289                 * the physical operation of writing out
     290                 * the character.
    275291                 */
    276                 irq_spinlock_unlock(&kio_lock, true);
    277                 stdout->op->write(stdout, buffer, len);
    278                 irq_spinlock_lock(&kio_lock, true);
    279         }
    280 
    281         irq_spinlock_unlock(&flush_lock, false);
    282         irq_spinlock_unlock(&kio_lock, true);
    283 }
    284 
    285 void kio_push_bytes(const char *s, size_t n)
    286 {
    287         /* Skip the section we know we can't keep. */
    288         if (n > KIO_LENGTH) {
    289                 size_t lost = n - KIO_LENGTH;
    290                 kio_written += lost;
    291                 s += lost;
    292                 n -= lost;
    293         }
    294 
    295         size_t offset = kio_written % KIO_LENGTH;
    296         if (offset + n > KIO_LENGTH) {
    297                 size_t first = KIO_LENGTH - offset;
    298                 size_t last = n - first;
    299                 memcpy(kio + offset, s, first);
    300                 memcpy(kio, s + first, last);
    301         } else {
    302                 memcpy(kio + offset, s, n);
    303         }
    304 
    305         kio_written += n;
    306 }
    307 
    308 static void early_putstr(const char *s, size_t n)
    309 {
    310         irq_spinlock_lock(&early_mbstate_lock, true);
    311 
    312         size_t offset = 0;
    313         char32_t c;
    314 
    315         while ((c = str_decode_r(s, &offset, n, U_SPECIAL, &early_mbstate)))
    316                 early_putuchar(c);
    317 
    318         irq_spinlock_unlock(&early_mbstate_lock, true);
    319 }
    320 
    321 void putstr(const char *s, size_t n)
     292                spinlock_unlock(&kio_lock);
     293                stdout->op->write(stdout, tmp);
     294                spinlock_lock(&kio_lock);
     295        }
     296
     297        spinlock_unlock(&kio_lock);
     298}
     299
     300/** Put a character into the output buffer.
     301 *
     302 * The caller is required to hold kio_lock
     303 */
     304void kio_push_char(const char32_t ch)
     305{
     306        kio[(kio_start + kio_len) % KIO_LENGTH] = ch;
     307        if (kio_len < KIO_LENGTH)
     308                kio_len++;
     309        else
     310                kio_start = (kio_start + 1) % KIO_LENGTH;
     311
     312        if (kio_stored < kio_len)
     313                kio_stored++;
     314
     315        /* The character is stored for uspace */
     316        if (kio_uspace < kio_len)
     317                kio_uspace++;
     318}
     319
     320void putuchar(const char32_t ch)
    322321{
    323322        bool ordy = ((stdout) && (stdout->op->write));
    324323
    325         irq_spinlock_lock(&kio_lock, true);
    326         kio_push_bytes(s, n);
    327         irq_spinlock_unlock(&kio_lock, true);
     324        spinlock_lock(&kio_lock);
     325        kio_push_char(ch);
     326        spinlock_unlock(&kio_lock);
    328327
    329328        /* Output stored characters */
     
    341340                 * a no-op on certain hardware configurations.
    342341                 */
    343                 early_putstr(s, n);
    344         }
    345 
    346         /* Force notification when containing a newline */
    347         if (memchr(s, '\n', n) != NULL)
     342                early_putuchar(ch);
     343        }
     344
     345        /* Force notification on newline */
     346        if (ch == '\n')
    348347                kio_update(NULL);
    349 }
    350 
    351 /** Reads up to `size` characters from kio buffer starting at character `at`.
    352  *
    353  * @param size  Maximum number of characters that can be stored in buffer.
    354  *              Values greater than KIO_LENGTH are silently treated as KIO_LENGTH
    355  *              for the purposes of calculating the return value.
    356  * @return Number of characters read. Can be more than `size`.
    357  *         In that case, `size` characters are written to user buffer
    358  *         and the extra amount is the number of characters missed.
    359  */
    360 sysarg_t sys_kio_read(uspace_addr_t buf, size_t size, size_t at)
    361 {
    362         errno_t rc;
    363         size_t missed = 0;
    364 
    365         irq_spinlock_lock(&kio_lock, true);
    366 
    367         if (at == kio_written) {
    368                 irq_spinlock_unlock(&kio_lock, true);
    369                 return 0;
    370         }
    371 
    372         size_t readable_chars = kio_written - at;
    373         if (readable_chars > KIO_LENGTH) {
    374                 missed = readable_chars - KIO_LENGTH;
    375                 readable_chars = KIO_LENGTH;
    376         }
    377 
    378         size_t actual_read = min(readable_chars, size);
    379         size_t offset = (kio_written - readable_chars) % KIO_LENGTH;
    380 
    381         if (offset + actual_read > KIO_LENGTH) {
    382                 size_t first = KIO_LENGTH - offset;
    383                 size_t last = actual_read - first;
    384 
    385                 rc = copy_to_uspace(buf, &kio[offset], first);
    386                 if (rc == EOK)
    387                         rc = copy_to_uspace(buf + first, &kio[0], last);
    388         } else {
    389                 rc = copy_to_uspace(buf, &kio[offset], actual_read);
    390         }
    391 
    392         irq_spinlock_unlock(&kio_lock, true);
    393 
    394         if (rc != EOK) {
    395                 log(LF_OTHER, LVL_WARN,
    396                     "[%s(%" PRIu64 ")] Terminating due to invalid memory buffer"
    397                     " in SYS_KIO_READ.\n", TASK->name, TASK->taskid);
    398                 task_kill_self(true);
    399         }
    400 
    401         return actual_read + missed;
    402348}
    403349
  • kernel/generic/src/console/kconsole.c

    r61c91532 ra65ccc4  
    3939 */
    4040
     41#include <assert.h>
     42#include <console/kconsole.h>
     43#include <console/console.h>
     44#include <console/chardev.h>
     45#include <console/cmd.h>
     46#include <console/prompt.h>
     47#include <stdio.h>
     48#include <panic.h>
     49#include <typedefs.h>
    4150#include <adt/list.h>
    4251#include <arch.h>
    43 #include <assert.h>
    44 #include <console/chardev.h>
    45 #include <console/cmd.h>
    46 #include <console/console.h>
    47 #include <console/kconsole.h>
    48 #include <console/prompt.h>
     52#include <macros.h>
    4953#include <debug.h>
     54#include <halt.h>
     55#include <str.h>
     56#include <sysinfo/sysinfo.h>
     57#include <symtab.h>
    5058#include <errno.h>
    51 #include <halt.h>
    52 #include <macros.h>
    53 #include <panic.h>
    54 #include <stdio.h>
     59#include <putchar.h>
    5560#include <stdlib.h>
    56 #include <str.h>
    57 #include <symtab.h>
    58 #include <sysinfo/sysinfo.h>
    59 #include <typedefs.h>
    6061
    6162/** Simple kernel console.
     
    157158
    158159/** Print count times a character */
    159 _NO_TRACE static void print_cc(char ch, size_t count)
    160 {
    161         // FIXME: only lock once
    162 
    163         for (size_t i = 0; i < count; i++)
    164                 putstr(&ch, 1);
     160_NO_TRACE static void print_cc(char32_t ch, size_t count)
     161{
     162        size_t i;
     163        for (i = 0; i < count; i++)
     164                putuchar(ch);
    165165}
    166166
     
    347347                if (ch == '\n') {
    348348                        /* Enter */
    349                         putstr("\n", 1);
     349                        putuchar(ch);
    350350                        break;
    351351                }
     
    358358                        if (wstr_remove(current, position - 1)) {
    359359                                position--;
    360                                 putstr("\b", 1);
     360                                putuchar('\b');
    361361                                printf("%ls ", current + position);
    362362                                print_cc('\b', wstr_length(current) - position + 1);
     
    368368                        /* Tab completion */
    369369
    370                         size_t i = position;
    371                         while (current[i] && !isspace(current[i]))
    372                                 i++;
    373 
    374                         char32_t stash = current[i];
    375                         current[i] = 0;
    376                         printf("%ls", &current[position]);
    377                         current[i] = stash;
    378                         position = i;
     370                        /* Move to the end of the word */
     371                        for (; (current[position] != 0) && (!isspace(current[position]));
     372                            position++)
     373                                putuchar(current[position]);
    379374
    380375                        /*
     
    435430                         */
    436431                        size_t off = 0;
    437                         for (size_t i = 0; (ch = str_decode(tmp, &off, STR_NO_LIMIT)); i++)
     432                        size_t i = 0;
     433                        while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
    438434                                if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
    439435                                        break;
     436
     437                                i++;
     438                        }
    440439
    441440                        if (found > 1) {
     
    467466                        /* Left */
    468467                        if (position > 0) {
    469                                 putstr("\b", 1);
     468                                putuchar('\b');
    470469                                position--;
    471470                        }
     
    476475                        /* Right */
    477476                        if (position < wstr_length(current)) {
    478                                 printf("%lc", current[position]);
     477                                putuchar(current[position]);
    479478                                position++;
    480479                        }
  • kernel/generic/src/log/log.c

    r61c91532 ra65ccc4  
    4646#include <print.h>
    4747#include <printf_core.h>
     48#include <putchar.h>
    4849#include <stdarg.h>
    4950#include <stdlib.h>
     
    5960
    6061/** Cyclic buffer holding the data for kernel log */
    61 static uint8_t log_buffer[LOG_LENGTH] __attribute__((aligned(PAGE_SIZE)));
     62uint8_t log_buffer[LOG_LENGTH] __attribute__((aligned(PAGE_SIZE)));
    6263
    6364/** Kernel log initialized */
     
    6566
    6667/** Position in the cyclic buffer where the first log entry starts */
    67 static size_t log_start = 0;
     68size_t log_start = 0;
    6869
    6970/** Sum of length of all log entries currently stored in the cyclic buffer */
    70 static size_t log_used = 0;
     71size_t log_used = 0;
    7172
    7273/** Log spinlock */
    73 static IRQ_SPINLOCK_INITIALIZE(log_lock);
     74SPINLOCK_STATIC_INITIALIZE_NAME(log_lock, "log_lock");
    7475
    7576/** Overall count of logged messages, which may overflow as needed */
     
    151152{
    152153        console_lock();
    153         irq_spinlock_lock(&log_lock, true);
    154         irq_spinlock_lock(&kio_lock, true);
     154        spinlock_lock(&log_lock);
     155        spinlock_lock(&kio_lock);
    155156
    156157        log_current_start = (log_start + log_used) % LOG_LENGTH;
     
    178179        log_used += log_current_len;
    179180
    180         kio_push_bytes("\n", 1);
    181         irq_spinlock_unlock(&kio_lock, true);
    182         irq_spinlock_unlock(&log_lock, true);
     181        kio_push_char('\n');
     182        spinlock_unlock(&kio_lock);
     183        spinlock_unlock(&log_lock);
    183184
    184185        /* This has to be called after we released the locks above */
     
    194195                return;
    195196
    196         irq_spinlock_lock(&log_lock, true);
     197        spinlock_lock(&log_lock);
    197198        if (next_for_uspace < log_used)
    198199                event_notify_0(EVENT_KLOG, true);
    199         irq_spinlock_unlock(&log_lock, true);
     200        spinlock_unlock(&log_lock);
    200201}
    201202
    202203static int log_printf_str_write(const char *str, size_t size, void *data)
    203204{
    204         kio_push_bytes(str, size);
     205        size_t offset = 0;
     206
     207        while (offset < size)
     208                kio_push_char(str_decode(str, &offset, size));
     209
    205210        log_append((const uint8_t *)str, size);
     211
    206212        return EOK;
    207213}
     
    301307                rc = EOK;
    302308
    303                 irq_spinlock_lock(&log_lock, true);
     309                spinlock_lock(&log_lock);
    304310
    305311                while (next_for_uspace < log_used) {
     
    331337                }
    332338
    333                 irq_spinlock_unlock(&log_lock, true);
     339                spinlock_unlock(&log_lock);
    334340
    335341                if (rc != EOK) {
  • kernel/generic/src/printf/vprintf.c

    r61c91532 ra65ccc4  
    3737#include <print.h>
    3838#include <printf_core.h>
     39#include <putchar.h>
    3940#include <str.h>
    4041#include <synch/spinlock.h>
     
    4344static errno_t vprintf_str_write(const char *str, size_t size, void *data)
    4445{
    45         putstr(str, size);
     46        size_t offset = 0;
     47
     48        while (offset < size)
     49                putuchar(str_decode(str, &offset, size));
     50
    4651        return EOK;
    4752}
     
    4954int puts(const char *str)
    5055{
    51         size_t n = str_size(str);
    52         putstr(str, n);
    53         return n;
     56        size_t offset = 0;
     57        size_t chars = 0;
     58        char32_t uc;
     59
     60        console_lock();
     61
     62        while ((uc = str_decode(str, &offset, STR_NO_LIMIT)) != 0) {
     63                putuchar(uc);
     64                chars++;
     65        }
     66
     67        putuchar('\n');
     68
     69        console_unlock();
     70        return chars;
    5471}
    5572
  • kernel/generic/src/syscall/syscall.c

    r61c91532 ra65ccc4  
    137137
    138138        [SYS_KLOG] = (syshandler_t) sys_klog,
    139         [SYS_KIO_READ] = (syshandler_t) sys_kio_read,
    140139};
    141140
  • kernel/test/print/print4.c

    r61c91532 ra65ccc4  
    5050        }
    5151
    52         TPRINTF("\nExtended ASCII characters (160 - 255) using printf(\"%%lc\"):\n");
     52        TPRINTF("\nExtended ASCII characters (128 - 255) using printf(\"%%lc\"):\n");
    5353
    54         for (group = 5; group < 8; group++) {
     54        for (group = 4; group < 8; group++) {
    5555                TPRINTF("%#x: ", group << 5);
    5656
  • uspace/app/kio/kio.c

    r61c91532 ra65ccc4  
    11/*
    22 * Copyright (c) 2006 Ondrej Palkovsky
    3  * Copyright (c) 2025 Jiří Zárevúcky
    43 * All rights reserved.
    54 *
     
    3534 */
    3635
    37 #include <_bits/decls.h>
    38 #include <libarch/config.h>
    3936#include <stdio.h>
    4037#include <async.h>
     
    5047#include <adt/prodcons.h>
    5148#include <tinput.h>
    52 #include <uchar.h>
    5349#include <vfs/vfs.h>
    5450
     
    5955typedef struct {
    6056        link_t link;
    61         size_t bytes;
    62         char *data;
     57        size_t length;
     58        char32_t *data;
    6359} item_t;
    6460
    6561static prodcons_t pc;
     62
     63/* Pointer to kio area */
     64static char32_t *kio = (char32_t *) AS_AREA_ANY;
     65static size_t kio_length;
    6666
    6767/* Notification mutex */
    6868static FIBRIL_MUTEX_INITIALIZE(mtx);
    6969
    70 #define READ_BUFFER_SIZE PAGE_SIZE
    71 
    72 static size_t current_at;
    73 static char read_buffer[READ_BUFFER_SIZE];
    74 
    7570/** Klog producer
    7671 *
     
    8277 *
    8378 */
    84 static void producer(size_t bytes, char *data)
    85 {
    86         item_t *item = malloc(sizeof(item_t));
     79static void producer(size_t length, char32_t *data)
     80{
     81        item_t *item = (item_t *) malloc(sizeof(item_t));
    8782        if (item == NULL)
    8883                return;
    8984
    90         item->bytes = bytes;
    91         item->data = malloc(bytes);
    92         if (!item->data) {
     85        size_t sz = sizeof(char32_t) * length;
     86        char32_t *buf = (char32_t *) malloc(sz);
     87        if (buf == NULL) {
    9388                free(item);
    9489                return;
    9590        }
    9691
    97         memcpy(item->data, data, bytes);
     92        memcpy(buf, data, sz);
    9893
    9994        link_initialize(&item->link);
     95        item->length = length;
     96        item->data = buf;
    10097        prodcons_produce(&pc, &item->link);
    10198}
     
    123120                item_t *item = list_get_instance(link, item_t, link);
    124121
    125                 fwrite(item->data, 1, item->bytes, stdout);
    126 
    127                 if (log) {
    128                         fwrite(item->data, 1, item->bytes, log);
     122                for (size_t i = 0; i < item->length; i++)
     123                        putuchar(item->data[i]);
     124
     125                if (log != NULL) {
     126                        for (size_t i = 0; i < item->length; i++)
     127                                fputuc(item->data[i], log);
     128
    129129                        fflush(log);
    130130                        vfs_sync(fileno(log));
     
    149149static void kio_notification_handler(ipc_call_t *call, void *arg)
    150150{
    151         size_t kio_written = (size_t) ipc_get_arg1(call);
    152 
    153151        /*
    154152         * Make sure we process only a single notification
    155153         * at any time to limit the chance of the consumer
    156154         * starving.
     155         *
     156         * Note: Usually the automatic masking of the kio
     157         * notifications on the kernel side does the trick
     158         * of limiting the chance of accidentally copying
     159         * the same data multiple times. However, due to
     160         * the non-blocking architecture of kio notifications,
     161         * this possibility cannot be generally avoided.
    157162         */
    158163
    159164        fibril_mutex_lock(&mtx);
    160165
    161         while (current_at != kio_written) {
    162                 size_t read = kio_read(read_buffer, READ_BUFFER_SIZE, current_at);
    163                 if (read == 0)
    164                         break;
    165 
    166                 current_at += read;
    167 
    168                 if (read > READ_BUFFER_SIZE) {
    169                         /* We missed some data. */
    170                         // TODO: Send a message with the number of lost characters to the consumer.
    171                         read = READ_BUFFER_SIZE;
    172                 }
    173 
    174                 producer(read, read_buffer);
    175         }
     166        size_t kio_start = (size_t) ipc_get_arg1(call);
     167        size_t kio_len = (size_t) ipc_get_arg2(call);
     168        size_t kio_stored = (size_t) ipc_get_arg3(call);
     169
     170        size_t offset = (kio_start + kio_len - kio_stored) % kio_length;
     171
     172        /* Copy data from the ring buffer */
     173        if (offset + kio_stored >= kio_length) {
     174                size_t split = kio_length - offset;
     175
     176                producer(split, kio + offset);
     177                producer(kio_stored - split, kio);
     178        } else
     179                producer(kio_stored, kio + offset);
    176180
    177181        async_event_unmask(EVENT_KIO);
     
    181185int main(int argc, char *argv[])
    182186{
     187        size_t pages;
     188        errno_t rc = sysinfo_get_value("kio.pages", &pages);
     189        if (rc != EOK) {
     190                fprintf(stderr, "%s: Unable to get number of kio pages\n",
     191                    NAME);
     192                return rc;
     193        }
     194
     195        uintptr_t faddr;
     196        rc = sysinfo_get_value("kio.faddr", &faddr);
     197        if (rc != EOK) {
     198                fprintf(stderr, "%s: Unable to get kio physical address\n",
     199                    NAME);
     200                return rc;
     201        }
     202
     203        size_t size = pages * PAGE_SIZE;
     204        kio_length = size / sizeof(char32_t);
     205
     206        rc = physmem_map(faddr, pages, AS_AREA_READ | AS_AREA_CACHEABLE,
     207            (void *) &kio);
     208        if (rc != EOK) {
     209                fprintf(stderr, "%s: Unable to map kio\n", NAME);
     210                return rc;
     211        }
     212
    183213        prodcons_initialize(&pc);
    184         errno_t rc = async_event_subscribe(EVENT_KIO, kio_notification_handler, NULL);
     214        rc = async_event_subscribe(EVENT_KIO, kio_notification_handler, NULL);
    185215        if (rc != EOK) {
    186216                fprintf(stderr, "%s: Unable to register kio notifications\n",
  • uspace/app/trace/syscalls.c

    r61c91532 ra65ccc4  
    115115        [SYS_DEBUG_CONSOLE] = { "debug_console", 0, V_ERRNO },
    116116
    117         [SYS_KLOG] = { "klog", 5, V_ERRNO },
    118         [SYS_KIO_READ] = { "kio_read", 3, V_INTEGER },
     117        [SYS_KLOG] = { "klog", 5, V_ERRNO }
    119118};
    120119
  • uspace/lib/c/generic/io/kio.c

    r61c91532 ra65ccc4  
    3434 */
    3535
    36 #include <abi/syscall.h>
    3736#include <stddef.h>
    3837#include <libc.h>
     
    113112}
    114113
    115 size_t kio_read(char *buf, size_t n, size_t at)
    116 {
    117         return __SYSCALL3(SYS_KIO_READ, (sysarg_t) buf, n, at);
    118 }
    119 
    120114/** Print formatted text to kio.
    121115 *
  • uspace/lib/c/include/io/kio.h

    r61c91532 ra65ccc4  
    3636#define _LIBC_IO_KIO_H_
    3737
     38#include <stddef.h>
     39#include <stdarg.h>
     40#include <io/verify.h>
    3841#include <_bits/errno.h>
    3942#include <_bits/size_t.h>
    40 #include <io/verify.h>
    41 #include <stdarg.h>
    42 #include <stddef.h>
    43 #include <uchar.h>
    4443
    4544extern void __kio_init(void);
     
    5150    _HELENOS_PRINTF_ATTRIBUTE(1, 2);
    5251extern int kio_vprintf(const char *, va_list);
    53 
    54 extern size_t kio_read(char *buf, size_t n, size_t at);
    5552
    5653/*
Note: See TracChangeset for help on using the changeset viewer.