Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/console/console.c

    r1db4e2ae r39e1b9a  
    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
Note: See TracChangeset for help on using the changeset viewer.