Changes in kernel/generic/src/console/console.c [39e1b9a:1db4e2ae] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/console/console.c
r39e1b9a r1db4e2ae 2 2 * Copyright (c) 2003 Josef Cejka 3 3 * Copyright (c) 2005 Jakub Jermar 4 * Copyright (c) 2025 Jiří Zárevúcky5 4 * All rights reserved. 6 5 * … … 36 35 37 36 #include <abi/kio.h> 37 #include <arch.h> 38 #include <assert.h> 39 #include <atomic.h> 38 40 #include <console/chardev.h> 39 41 #include <console/console.h> 42 #include <ddi/ddi.h> 43 #include <ddi/irq.h> 40 44 #include <errno.h> 41 45 #include <ipc/event.h> 42 #include <log.h> 46 #include <ipc/irq.h> 47 #include <mm/frame.h> /* SIZE2FRAMES */ 43 48 #include <panic.h> 44 49 #include <preemption.h> 45 #include <proc/task.h> 50 #include <proc/thread.h> 51 #include <putchar.h> 46 52 #include <stdatomic.h> 47 53 #include <stdio.h> … … 50 56 #include <synch/mutex.h> 51 57 #include <synch/spinlock.h> 58 #include <synch/waitq.h> 52 59 #include <syscall/copy.h> 53 60 #include <sysinfo/sysinfo.h> 61 #include <typedefs.h> 54 62 55 63 #define KIO_PAGES 8 56 #define KIO_LENGTH (KIO_PAGES * PAGE_SIZE )64 #define KIO_LENGTH (KIO_PAGES * PAGE_SIZE / sizeof(char32_t)) 57 65 58 66 /** Kernel log cyclic buffer */ 59 static char kio[KIO_LENGTH];67 char32_t kio[KIO_LENGTH] __attribute__((aligned(PAGE_SIZE))); 60 68 61 69 /** Kernel log initialized */ … … 68 76 static MUTEX_INITIALIZE(console_mutex, MUTEX_RECURSIVE); 69 77 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 */ 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; 78 89 79 90 /** 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; 91 SPINLOCK_INITIALIZE_NAME(kio_lock, "kio_lock"); 92 93 /** Physical memory area used for kio buffer */ 94 static parea_t kio_parea; 86 95 87 96 static indev_t stdin_sink; … … 95 104 }; 96 105 97 static void stdout_write(outdev_t *, c onst char *, size_t);106 static void stdout_write(outdev_t *, char32_t); 98 107 static void stdout_redraw(outdev_t *); 99 108 static void stdout_scroll_up(outdev_t *); … … 148 157 } 149 158 150 static void stdout_write(outdev_t *dev, c onst char *s, size_t n)159 static void stdout_write(outdev_t *dev, char32_t ch) 151 160 { 152 161 list_foreach(dev->list, link, outdev_t, sink) { 153 162 if ((sink) && (sink->op->write)) 154 sink->op->write(sink, s, n);163 sink->op->write(sink, ch); 155 164 } 156 165 } … … 181 190 182 191 /** 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 * 183 197 */ 184 198 void kio_init(void) 185 199 { 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 186 214 event_set_unmask_callback(EVENT_KIO, kio_update); 187 215 atomic_store(&kio_inited, true); … … 229 257 return; 230 258 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); 239 268 } 240 269 … … 249 278 return; 250 279 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); 261 281 262 282 /* 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--; 271 286 272 287 /* 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. 275 291 */ 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 */ 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) 322 321 { 323 322 bool ordy = ((stdout) && (stdout->op->write)); 324 323 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); 328 327 329 328 /* Output stored characters */ … … 341 340 * a no-op on certain hardware configurations. 342 341 */ 343 early_put str(s, n);344 } 345 346 /* Force notification when containing anewline */347 if ( memchr(s, '\n', n) != NULL)342 early_putuchar(ch); 343 } 344 345 /* Force notification on newline */ 346 if (ch == '\n') 348 347 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_LENGTH355 * 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 buffer358 * 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;402 348 } 403 349
Note:
See TracChangeset
for help on using the changeset viewer.