Ignore:
File:
1 edited

Legend:

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

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