Changes in / [a65ccc4:61c91532] in mainline


Ignore:
Files:
1 deleted
18 edited

Legend:

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

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

    ra65ccc4 r61c91532  
    6969        uint8_t *backbuf;
    7070        ioport8_t *base;
     71        mbstate_t mbstate;
    7172} ega_instance_t;
    7273
    73 static void ega_putuchar(outdev_t *, char32_t);
     74static void ega_write(outdev_t *, const char *, size_t);
    7475static void ega_redraw(outdev_t *);
    7576
    7677static outdev_operations_t egadev_ops = {
    77         .write = ega_putuchar,
     78        .write = ega_write,
    7879        .redraw = ega_redraw,
    7980        .scroll_up = NULL,
     
    538539}
    539540
    540 static 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 
     541static void _putuchar(ega_instance_t *instance, char32_t ch)
     542{
    546543        switch (ch) {
    547544        case '\n':
     
    564561        ega_check_cursor(instance);
    565562        ega_move_cursor(instance);
     563}
     564
     565static 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);
    566576
    567577        irq_spinlock_unlock(&instance->lock, true);
  • kernel/genarch/src/drivers/ns16550/ns16550.c

    ra65ccc4 r61c91532  
    112112}
    113113
    114 static void ns16550_putuchar(outdev_t *dev, char32_t ch)
     114static void ns16550_write(outdev_t *dev, const char *s, size_t n)
    115115{
    116116        ns16550_instance_t *instance = (ns16550_instance_t *) dev->data;
    117117
    118         if ((!instance->parea.mapped) || (console_override)) {
    119                 if (ch == '\n')
     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')
    120126                        ns16550_sendb(instance, '\r');
    121127
    122                 if (ascii_check(ch))
    123                         ns16550_sendb(instance, (uint8_t) ch);
    124                 else
    125                         ns16550_sendb(instance, U_SPECIAL);
     128                ns16550_sendb(instance, (uint8_t) *s);
    126129        }
    127130}
    128131
    129132static outdev_operations_t ns16550_ops = {
    130         .write = ns16550_putuchar,
     133        .write = ns16550_write,
    131134        .redraw = NULL
    132135};
  • kernel/genarch/src/drivers/pl011/pl011.c

    ra65ccc4 r61c91532  
    5656}
    5757
    58 static void pl011_uart_putuchar(outdev_t *dev, char32_t ch)
     58static void pl011_uart_write(outdev_t *dev, const char *s, size_t n)
    5959{
    6060        pl011_uart_t *uart = dev->data;
     
    6464                return;
    6565
    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);
     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);
    7274        }
    7375}
    7476
    7577static outdev_operations_t pl011_uart_ops = {
    76         .write = pl011_uart_putuchar,
     78        .write = pl011_uart_write,
    7779        .redraw = NULL,
    7880        .scroll_up = NULL,
  • kernel/genarch/src/fb/fb.c

    ra65ccc4 r61c91532  
    8181        ((glyph) * (instance)->glyphbytes + (y) * (instance)->glyphscanline)
    8282
     83#define TAB_WIDTH 8
     84
    8385typedef void (*rgb_conv_t)(void *, uint32_t);
    8486
     
    99101
    100102        /** Number of rows that fit on framebuffer */
    101         unsigned int rowtrim;
     103        unsigned int screen_rows;
    102104
    103105        unsigned int scanline;
     
    121123        /** Current backbuffer position */
    122124        unsigned int position;
     125
     126        /** Partial character between writes */
     127        mbstate_t mbstate;
     128
     129        unsigned int row;
     130        unsigned int column;
    123131} fb_instance_t;
    124132
    125 static void fb_putuchar(outdev_t *, char32_t);
     133static void fb_write(outdev_t *, const char *, size_t);
    126134static void fb_redraw(outdev_t *);
    127135static void fb_scroll_up(outdev_t *);
     
    129137
    130138static outdev_operations_t fbdev_ops = {
    131         .write = fb_putuchar,
     139        .write = fb_write,
    132140        .redraw = fb_redraw,
    133141        .scroll_up = fb_scroll_up,
     
    247255
    248256        unsigned int rel_row = row - instance->offset_row;
    249         if (rel_row >= instance->rowtrim)
     257        if (rel_row >= instance->screen_rows)
    250258                return;
    251259
     
    259267}
    260268
    261 /** Scroll screen down by one row
    262  *
    263  */
    264 static 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 
    314269static void cursor_put(fb_instance_t *instance)
    315270{
    316         unsigned int col = instance->position % instance->cols;
    317         unsigned int row = instance->position / instance->cols;
     271        unsigned int col = instance->column;
     272        unsigned int row = instance->row;
    318273
    319274        glyph_draw(instance, fb_font_glyph(U_CURSOR), col, row, true);
     
    322277static void cursor_remove(fb_instance_t *instance)
    323278{
    324         unsigned int col = instance->position % instance->cols;
    325         unsigned int row = instance->position / instance->cols;
     279        unsigned int col = instance->column;
     280        unsigned int row = instance->row;
    326281
    327282        glyph_draw(instance, instance->backbuf[BB_POS(instance, col, row)],
     
    373328static void fb_redraw_internal(fb_instance_t *instance)
    374329{
    375         for (unsigned int rel_row = 0; rel_row < instance->rowtrim; rel_row++) {
     330        for (unsigned int rel_row = 0; rel_row < instance->screen_rows; rel_row++) {
    376331                unsigned int y = ROW2Y(rel_row);
    377332                unsigned int row = rel_row + instance->offset_row;
     
    404359        }
    405360
    406         if (ROW2Y(instance->rowtrim) < instance->yres) {
     361        if (ROW2Y(instance->screen_rows) < instance->yres) {
    407362                unsigned int y;
    408363
    409                 for (y = ROW2Y(instance->rowtrim); y < instance->yres; y++)
     364                for (y = ROW2Y(instance->screen_rows); y < instance->yres; y++)
    410365                        memcpy(&instance->addr[FB_POS(instance, 0, y)],
    411366                            instance->bgscan, instance->bgscanbytes);
     
    413368}
    414369
     370/** Scroll screen down by one row
     371 *
     372 */
     373static 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
     389static void _advance_row(fb_instance_t *instance)
     390{
     391        instance->column = 0;
     392        instance->row++;
     393}
     394
     395static void _advance_column(fb_instance_t *instance)
     396{
     397        instance->column++;
     398        if (instance->column == instance->cols)
     399                _advance_row(instance);
     400}
     401
    415402/** Print character to screen
    416403 *
     
    418405 *
    419406 */
    420 static void fb_putuchar(outdev_t *dev, char32_t ch)
     407static void _putuchar(fb_instance_t *instance, char32_t ch)
     408{
     409        switch (ch) {
     410        case '\n':
     411                _advance_row(instance);
     412                break;
     413        case '\r':
     414                instance->column = 0;
     415                break;
     416        case '\b':
     417                if (instance->column > 0)
     418                        instance->column--;
     419                break;
     420        case '\t':
     421                do {
     422                        glyph_draw(instance, fb_font_glyph(' '),
     423                            instance->column,
     424                            instance->row, false);
     425                        _advance_column(instance);
     426                } while (instance->column % TAB_WIDTH != 0);
     427                break;
     428        default:
     429                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--;
     437                screen_scroll(instance);
     438        }
     439}
     440
     441static 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);
     453
     454        cursor_put(instance);
     455        spinlock_unlock(&instance->lock);
     456}
     457
     458/** Scroll the framebuffer up
     459 *
     460 */
     461static void fb_scroll_up(outdev_t *dev)
    421462{
    422463        fb_instance_t *instance = (fb_instance_t *) dev->data;
    423464        spinlock_lock(&instance->lock);
    424465
    425         switch (ch) {
    426         case '\n':
    427                 cursor_remove(instance);
    428                 instance->position += instance->cols;
    429                 instance->position -= instance->position % instance->cols;
    430                 break;
    431         case '\r':
    432                 cursor_remove(instance);
    433                 instance->position -= instance->position % instance->cols;
    434                 break;
    435         case '\b':
    436                 cursor_remove(instance);
    437                 if (instance->position % instance->cols)
    438                         instance->position--;
    439                 break;
    440         case '\t':
    441                 cursor_remove(instance);
    442                 do {
    443                         glyph_draw(instance, fb_font_glyph(' '),
    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));
    449                 break;
    450         default:
    451                 glyph_draw(instance, fb_font_glyph(ch),
    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;
    459                 screen_scroll(instance);
    460         }
    461 
     466        if (instance->offset_row >= instance->screen_rows / 2)
     467                instance->offset_row -= instance->screen_rows / 2;
     468        else
     469                instance->offset_row = 0;
     470
     471        fb_redraw_internal(instance);
    462472        cursor_put(instance);
    463473
     
    465475}
    466476
    467 /** Scroll the framebuffer up
    468  *
    469  */
    470 static void fb_scroll_up(outdev_t *dev)
     477/** Scroll the framebuffer down
     478 *
     479 */
     480static void fb_scroll_down(outdev_t *dev)
    471481{
    472482        fb_instance_t *instance = (fb_instance_t *) dev->data;
    473483        spinlock_lock(&instance->lock);
    474484
    475         if (instance->offset_row >= instance->rowtrim / 2)
    476                 instance->offset_row -= instance->rowtrim / 2;
     485        if (instance->offset_row + instance->screen_rows / 2 <=
     486            instance->rows - instance->screen_rows)
     487                instance->offset_row += instance->screen_rows / 2;
    477488        else
    478                 instance->offset_row = 0;
    479 
    480         fb_redraw_internal(instance);
    481         cursor_put(instance);
    482 
    483         spinlock_unlock(&instance->lock);
    484 }
    485 
    486 /** Scroll the framebuffer down
    487  *
    488  */
    489 static void fb_scroll_down(outdev_t *dev)
    490 {
    491         fb_instance_t *instance = (fb_instance_t *) dev->data;
    492         spinlock_lock(&instance->lock);
    493 
    494         if (instance->offset_row + instance->rowtrim / 2 <=
    495             instance->rows - instance->rowtrim)
    496                 instance->offset_row += instance->rowtrim / 2;
    497         else
    498                 instance->offset_row = instance->rows - instance->rowtrim;
     489                instance->offset_row = instance->rows - instance->screen_rows;
    499490
    500491        fb_redraw_internal(instance);
     
    615606        instance->scanline = props->scan;
    616607
    617         instance->rowtrim = Y2ROW(instance->yres);
     608        instance->screen_rows = Y2ROW(instance->yres);
    618609
    619610        instance->cols = X2COL(instance->xres);
    620         instance->rows = FB_PAGES * instance->rowtrim;
    621 
    622         instance->start_row = instance->rows - instance->rowtrim;
     611        instance->rows = FB_PAGES * instance->screen_rows;
     612
     613        instance->start_row = instance->rows - instance->screen_rows;
    623614        instance->offset_row = instance->start_row;
    624         instance->position = instance->start_row * instance->cols;
     615        instance->row = instance->start_row;
     616        instance->column = 0;
    625617
    626618        instance->glyphscanline = FONT_WIDTH * instance->pixelbytes;
  • kernel/generic/include/console/chardev.h

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

    ra65ccc4 r61c91532  
    3636#define KERN_CONSOLE_H_
    3737
    38 #include <typedefs.h>
    39 #include <print.h>
    4038#include <console/chardev.h>
    4139#include <synch/spinlock.h>
     
    6664extern void kio_update(void *);
    6765extern void kio_flush(void);
    68 extern void kio_push_char(const char32_t);
    69 SPINLOCK_EXTERN(kio_lock);
     66extern void kio_push_bytes(const char *, size_t);
     67extern irq_spinlock_t kio_lock;
    7068
     69extern sysarg_t sys_kio_read(uspace_addr_t buf, size_t size, size_t at);
    7170extern sys_errno_t sys_kio(int cmd, uspace_addr_t buf, size_t size);
    7271
     
    7978extern void console_unlock(void);
    8079
     80extern void putstr(const char *s, size_t n);
     81
    8182#endif /* KERN_CONSOLE_H_ */
    8283
  • kernel/generic/include/stdio.h

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

    ra65ccc4 r61c91532  
    22 * Copyright (c) 2003 Josef Cejka
    33 * Copyright (c) 2005 Jakub Jermar
     4 * Copyright (c) 2025 Jiří Zárevúcky
    45 * All rights reserved.
    56 *
     
    3536
    3637#include <abi/kio.h>
    37 #include <arch.h>
    38 #include <assert.h>
    39 #include <atomic.h>
    4038#include <console/chardev.h>
    4139#include <console/console.h>
    42 #include <ddi/ddi.h>
    43 #include <ddi/irq.h>
    4440#include <errno.h>
    4541#include <ipc/event.h>
    46 #include <ipc/irq.h>
    47 #include <mm/frame.h> /* SIZE2FRAMES */
     42#include <log.h>
    4843#include <panic.h>
    4944#include <preemption.h>
    50 #include <proc/thread.h>
    51 #include <putchar.h>
     45#include <proc/task.h>
    5246#include <stdatomic.h>
    5347#include <stdio.h>
     
    5650#include <synch/mutex.h>
    5751#include <synch/spinlock.h>
    58 #include <synch/waitq.h>
    5952#include <syscall/copy.h>
    6053#include <sysinfo/sysinfo.h>
    61 #include <typedefs.h>
    6254
    6355#define KIO_PAGES    8
    64 #define KIO_LENGTH   (KIO_PAGES * PAGE_SIZE / sizeof(char32_t))
     56#define KIO_LENGTH   (KIO_PAGES * PAGE_SIZE)
    6557
    6658/** Kernel log cyclic buffer */
    67 char32_t kio[KIO_LENGTH] __attribute__((aligned(PAGE_SIZE)));
     59static char kio[KIO_LENGTH];
    6860
    6961/** Kernel log initialized */
     
    7668static MUTEX_INITIALIZE(console_mutex, MUTEX_RECURSIVE);
    7769
    78 /** First kernel log characters */
    79 static size_t kio_start = 0;
    80 
    81 /** Number of valid kernel log characters */
    82 static size_t kio_len = 0;
    83 
    84 /** Number of stored (not printed) kernel log characters */
    85 static size_t kio_stored = 0;
    86 
    87 /** Number of stored kernel log characters for uspace */
    88 static size_t kio_uspace = 0;
     70/** Number of characters written to buffer. Periodically overflows. */
     71static size_t kio_written = 0;
     72
     73/** Number of characters written to output devices. Periodically overflows. */
     74static size_t kio_processed = 0;
     75
     76/** Last notification sent to uspace. */
     77static size_t kio_notified = 0;
    8978
    9079/** Kernel log spinlock */
    91 SPINLOCK_INITIALIZE_NAME(kio_lock, "kio_lock");
    92 
    93 /** Physical memory area used for kio buffer */
    94 static parea_t kio_parea;
     80IRQ_SPINLOCK_INITIALIZE(kio_lock);
     81
     82static IRQ_SPINLOCK_INITIALIZE(flush_lock);
     83
     84static IRQ_SPINLOCK_INITIALIZE(early_mbstate_lock);
     85static mbstate_t early_mbstate;
    9586
    9687static indev_t stdin_sink;
     
    10495};
    10596
    106 static void stdout_write(outdev_t *, char32_t);
     97static void stdout_write(outdev_t *, const char *, size_t);
    10798static void stdout_redraw(outdev_t *);
    10899static void stdout_scroll_up(outdev_t *);
     
    157148}
    158149
    159 static void stdout_write(outdev_t *dev, char32_t ch)
     150static void stdout_write(outdev_t *dev, const char *s, size_t n)
    160151{
    161152        list_foreach(dev->list, link, outdev_t, sink) {
    162153                if ((sink) && (sink->op->write))
    163                         sink->op->write(sink, ch);
     154                        sink->op->write(sink, s, n);
    164155        }
    165156}
     
    190181
    191182/** 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  *
    197183 */
    198184void kio_init(void)
    199185{
    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 
    214186        event_set_unmask_callback(EVENT_KIO, kio_update);
    215187        atomic_store(&kio_inited, true);
     
    257229                return;
    258230
    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);
     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);
    268239}
    269240
     
    278249                return;
    279250
    280         spinlock_lock(&kio_lock);
     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];
    281261
    282262        /* Print characters that weren't printed earlier */
    283         while (kio_stored > 0) {
    284                 char32_t tmp = kio[(kio_start + kio_len - kio_stored) % KIO_LENGTH];
    285                 kio_stored--;
     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;
    286271
    287272                /*
    288                  * We need to give up the spinlock for
    289                  * the physical operation of writing out
    290                  * the character.
     273                 * We need to give up the spinlock for the physical operation of writing
     274                 * out the buffer.
    291275                 */
    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  */
    304 void 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 
    320 void putuchar(const char32_t ch)
     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
     285void 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
     308static 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
     321void putstr(const char *s, size_t n)
    321322{
    322323        bool ordy = ((stdout) && (stdout->op->write));
    323324
    324         spinlock_lock(&kio_lock);
    325         kio_push_char(ch);
    326         spinlock_unlock(&kio_lock);
     325        irq_spinlock_lock(&kio_lock, true);
     326        kio_push_bytes(s, n);
     327        irq_spinlock_unlock(&kio_lock, true);
    327328
    328329        /* Output stored characters */
     
    340341                 * a no-op on certain hardware configurations.
    341342                 */
    342                 early_putuchar(ch);
    343         }
    344 
    345         /* Force notification on newline */
    346         if (ch == '\n')
     343                early_putstr(s, n);
     344        }
     345
     346        /* Force notification when containing a newline */
     347        if (memchr(s, '\n', n) != NULL)
    347348                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 */
     360sysarg_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;
    348402}
    349403
  • kernel/generic/src/console/kconsole.c

    ra65ccc4 r61c91532  
    3939 */
    4040
     41#include <adt/list.h>
     42#include <arch.h>
    4143#include <assert.h>
    42 #include <console/kconsole.h>
    43 #include <console/console.h>
    4444#include <console/chardev.h>
    4545#include <console/cmd.h>
     46#include <console/console.h>
     47#include <console/kconsole.h>
    4648#include <console/prompt.h>
     49#include <debug.h>
     50#include <errno.h>
     51#include <halt.h>
     52#include <macros.h>
     53#include <panic.h>
    4754#include <stdio.h>
    48 #include <panic.h>
     55#include <stdlib.h>
     56#include <str.h>
     57#include <symtab.h>
     58#include <sysinfo/sysinfo.h>
    4959#include <typedefs.h>
    50 #include <adt/list.h>
    51 #include <arch.h>
    52 #include <macros.h>
    53 #include <debug.h>
    54 #include <halt.h>
    55 #include <str.h>
    56 #include <sysinfo/sysinfo.h>
    57 #include <symtab.h>
    58 #include <errno.h>
    59 #include <putchar.h>
    60 #include <stdlib.h>
    6160
    6261/** Simple kernel console.
     
    158157
    159158/** Print count times a character */
    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);
     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);
    165165}
    166166
     
    347347                if (ch == '\n') {
    348348                        /* Enter */
    349                         putuchar(ch);
     349                        putstr("\n", 1);
    350350                        break;
    351351                }
     
    358358                        if (wstr_remove(current, position - 1)) {
    359359                                position--;
    360                                 putuchar('\b');
     360                                putstr("\b", 1);
    361361                                printf("%ls ", current + position);
    362362                                print_cc('\b', wstr_length(current) - position + 1);
     
    368368                        /* Tab completion */
    369369
    370                         /* Move to the end of the word */
    371                         for (; (current[position] != 0) && (!isspace(current[position]));
    372                             position++)
    373                                 putuchar(current[position]);
     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;
    374379
    375380                        /*
     
    430435                         */
    431436                        size_t off = 0;
    432                         size_t i = 0;
    433                         while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
     437                        for (size_t i = 0; (ch = str_decode(tmp, &off, STR_NO_LIMIT)); i++)
    434438                                if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
    435439                                        break;
    436 
    437                                 i++;
    438                         }
    439440
    440441                        if (found > 1) {
     
    466467                        /* Left */
    467468                        if (position > 0) {
    468                                 putuchar('\b');
     469                                putstr("\b", 1);
    469470                                position--;
    470471                        }
     
    475476                        /* Right */
    476477                        if (position < wstr_length(current)) {
    477                                 putuchar(current[position]);
     478                                printf("%lc", current[position]);
    478479                                position++;
    479480                        }
  • kernel/generic/src/log/log.c

    ra65ccc4 r61c91532  
    4646#include <print.h>
    4747#include <printf_core.h>
    48 #include <putchar.h>
    4948#include <stdarg.h>
    5049#include <stdlib.h>
     
    6059
    6160/** Cyclic buffer holding the data for kernel log */
    62 uint8_t log_buffer[LOG_LENGTH] __attribute__((aligned(PAGE_SIZE)));
     61static uint8_t log_buffer[LOG_LENGTH] __attribute__((aligned(PAGE_SIZE)));
    6362
    6463/** Kernel log initialized */
     
    6665
    6766/** Position in the cyclic buffer where the first log entry starts */
    68 size_t log_start = 0;
     67static size_t log_start = 0;
    6968
    7069/** Sum of length of all log entries currently stored in the cyclic buffer */
    71 size_t log_used = 0;
     70static size_t log_used = 0;
    7271
    7372/** Log spinlock */
    74 SPINLOCK_STATIC_INITIALIZE_NAME(log_lock, "log_lock");
     73static IRQ_SPINLOCK_INITIALIZE(log_lock);
    7574
    7675/** Overall count of logged messages, which may overflow as needed */
     
    152151{
    153152        console_lock();
    154         spinlock_lock(&log_lock);
    155         spinlock_lock(&kio_lock);
     153        irq_spinlock_lock(&log_lock, true);
     154        irq_spinlock_lock(&kio_lock, true);
    156155
    157156        log_current_start = (log_start + log_used) % LOG_LENGTH;
     
    179178        log_used += log_current_len;
    180179
    181         kio_push_char('\n');
    182         spinlock_unlock(&kio_lock);
    183         spinlock_unlock(&log_lock);
     180        kio_push_bytes("\n", 1);
     181        irq_spinlock_unlock(&kio_lock, true);
     182        irq_spinlock_unlock(&log_lock, true);
    184183
    185184        /* This has to be called after we released the locks above */
     
    195194                return;
    196195
    197         spinlock_lock(&log_lock);
     196        irq_spinlock_lock(&log_lock, true);
    198197        if (next_for_uspace < log_used)
    199198                event_notify_0(EVENT_KLOG, true);
    200         spinlock_unlock(&log_lock);
     199        irq_spinlock_unlock(&log_lock, true);
    201200}
    202201
    203202static int log_printf_str_write(const char *str, size_t size, void *data)
    204203{
    205         size_t offset = 0;
    206 
    207         while (offset < size)
    208                 kio_push_char(str_decode(str, &offset, size));
    209 
     204        kio_push_bytes(str, size);
    210205        log_append((const uint8_t *)str, size);
    211 
    212206        return EOK;
    213207}
     
    307301                rc = EOK;
    308302
    309                 spinlock_lock(&log_lock);
     303                irq_spinlock_lock(&log_lock, true);
    310304
    311305                while (next_for_uspace < log_used) {
     
    337331                }
    338332
    339                 spinlock_unlock(&log_lock);
     333                irq_spinlock_unlock(&log_lock, true);
    340334
    341335                if (rc != EOK) {
  • kernel/generic/src/printf/vprintf.c

    ra65ccc4 r61c91532  
    3737#include <print.h>
    3838#include <printf_core.h>
    39 #include <putchar.h>
    4039#include <str.h>
    4140#include <synch/spinlock.h>
     
    4443static errno_t vprintf_str_write(const char *str, size_t size, void *data)
    4544{
    46         size_t offset = 0;
    47 
    48         while (offset < size)
    49                 putuchar(str_decode(str, &offset, size));
    50 
     45        putstr(str, size);
    5146        return EOK;
    5247}
     
    5449int puts(const char *str)
    5550{
    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;
     51        size_t n = str_size(str);
     52        putstr(str, n);
     53        return n;
    7154}
    7255
  • kernel/generic/src/syscall/syscall.c

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

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

    ra65ccc4 r61c91532  
    11/*
    22 * Copyright (c) 2006 Ondrej Palkovsky
     3 * Copyright (c) 2025 Jiří Zárevúcky
    34 * All rights reserved.
    45 *
     
    3435 */
    3536
     37#include <_bits/decls.h>
     38#include <libarch/config.h>
    3639#include <stdio.h>
    3740#include <async.h>
     
    4750#include <adt/prodcons.h>
    4851#include <tinput.h>
     52#include <uchar.h>
    4953#include <vfs/vfs.h>
    5054
     
    5559typedef struct {
    5660        link_t link;
    57         size_t length;
    58         char32_t *data;
     61        size_t bytes;
     62        char *data;
    5963} item_t;
    6064
    6165static prodcons_t pc;
    62 
    63 /* Pointer to kio area */
    64 static char32_t *kio = (char32_t *) AS_AREA_ANY;
    65 static size_t kio_length;
    6666
    6767/* Notification mutex */
    6868static FIBRIL_MUTEX_INITIALIZE(mtx);
    6969
     70#define READ_BUFFER_SIZE PAGE_SIZE
     71
     72static size_t current_at;
     73static char read_buffer[READ_BUFFER_SIZE];
     74
    7075/** Klog producer
    7176 *
     
    7782 *
    7883 */
    79 static void producer(size_t length, char32_t *data)
    80 {
    81         item_t *item = (item_t *) malloc(sizeof(item_t));
     84static void producer(size_t bytes, char *data)
     85{
     86        item_t *item = malloc(sizeof(item_t));
    8287        if (item == NULL)
    8388                return;
    8489
    85         size_t sz = sizeof(char32_t) * length;
    86         char32_t *buf = (char32_t *) malloc(sz);
    87         if (buf == NULL) {
     90        item->bytes = bytes;
     91        item->data = malloc(bytes);
     92        if (!item->data) {
    8893                free(item);
    8994                return;
    9095        }
    9196
    92         memcpy(buf, data, sz);
     97        memcpy(item->data, data, bytes);
    9398
    9499        link_initialize(&item->link);
    95         item->length = length;
    96         item->data = buf;
    97100        prodcons_produce(&pc, &item->link);
    98101}
     
    120123                item_t *item = list_get_instance(link, item_t, link);
    121124
    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 
     125                fwrite(item->data, 1, item->bytes, stdout);
     126
     127                if (log) {
     128                        fwrite(item->data, 1, item->bytes, log);
    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
    151153        /*
    152154         * Make sure we process only a single notification
    153155         * at any time to limit the chance of the consumer
    154156         * 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.
    162157         */
    163158
    164159        fibril_mutex_lock(&mtx);
    165160
    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);
     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        }
    180176
    181177        async_event_unmask(EVENT_KIO);
     
    185181int main(int argc, char *argv[])
    186182{
    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 
    213183        prodcons_initialize(&pc);
    214         rc = async_event_subscribe(EVENT_KIO, kio_notification_handler, NULL);
     184        errno_t rc = async_event_subscribe(EVENT_KIO, kio_notification_handler, NULL);
    215185        if (rc != EOK) {
    216186                fprintf(stderr, "%s: Unable to register kio notifications\n",
  • uspace/app/trace/syscalls.c

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

    ra65ccc4 r61c91532  
    3434 */
    3535
     36#include <abi/syscall.h>
    3637#include <stddef.h>
    3738#include <libc.h>
     
    112113}
    113114
     115size_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
    114120/** Print formatted text to kio.
    115121 *
  • uspace/lib/c/include/io/kio.h

    ra65ccc4 r61c91532  
    3636#define _LIBC_IO_KIO_H_
    3737
    38 #include <stddef.h>
    39 #include <stdarg.h>
    40 #include <io/verify.h>
    4138#include <_bits/errno.h>
    4239#include <_bits/size_t.h>
     40#include <io/verify.h>
     41#include <stdarg.h>
     42#include <stddef.h>
     43#include <uchar.h>
    4344
    4445extern void __kio_init(void);
     
    5051    _HELENOS_PRINTF_ATTRIBUTE(1, 2);
    5152extern int kio_vprintf(const char *, va_list);
     53
     54extern size_t kio_read(char *buf, size_t n, size_t at);
    5255
    5356/*
Note: See TracChangeset for help on using the changeset viewer.