Changes in kernel/generic/src/console/console.c [28a5ebd:39e1b9a] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/console/console.c
r28a5ebd r39e1b9a 2 2 * Copyright (c) 2003 Josef Cejka 3 3 * Copyright (c) 2005 Jakub Jermar 4 * Copyright (c) 2025 Jiří Zárevúcky 4 5 * All rights reserved. 5 6 * … … 34 35 */ 35 36 36 #include <assert.h> 37 #include <abi/kio.h> 38 #include <console/chardev.h> 37 39 #include <console/console.h> 38 #include <console/chardev.h> 40 #include <errno.h> 41 #include <ipc/event.h> 42 #include <log.h> 43 #include <panic.h> 44 #include <preemption.h> 45 #include <proc/task.h> 46 #include <stdatomic.h> 47 #include <stdio.h> 48 #include <stdlib.h> /* malloc */ 49 #include <str.h> 50 #include <synch/mutex.h> 51 #include <synch/spinlock.h> 52 #include <syscall/copy.h> 39 53 #include <sysinfo/sysinfo.h> 40 #include <synch/waitq.h>41 #include <synch/spinlock.h>42 #include <typedefs.h>43 #include <ddi/irq.h>44 #include <ddi/ddi.h>45 #include <ipc/event.h>46 #include <ipc/irq.h>47 #include <arch.h>48 #include <panic.h>49 #include <stdio.h>50 #include <putchar.h>51 #include <atomic.h>52 #include <syscall/copy.h>53 #include <errno.h>54 #include <str.h>55 #include <stdatomic.h>56 #include <abi/kio.h>57 #include <mm/frame.h> /* SIZE2FRAMES */58 #include <stdlib.h> /* malloc */59 54 60 55 #define KIO_PAGES 8 61 #define KIO_LENGTH (KIO_PAGES * PAGE_SIZE / sizeof(char32_t))56 #define KIO_LENGTH (KIO_PAGES * PAGE_SIZE) 62 57 63 58 /** Kernel log cyclic buffer */ 64 char32_t kio[KIO_LENGTH] __attribute__((aligned(PAGE_SIZE)));59 static char kio[KIO_LENGTH]; 65 60 66 61 /** Kernel log initialized */ 67 62 static atomic_bool kio_inited = ATOMIC_VAR_INIT(false); 68 63 69 /** First kernel log characters */ 70 static size_t kio_start = 0; 71 72 /** Number of valid kernel log characters */ 73 static size_t kio_len = 0; 74 75 /** Number of stored (not printed) kernel log characters */ 76 static size_t kio_stored = 0; 77 78 /** Number of stored kernel log characters for uspace */ 79 static size_t kio_uspace = 0; 64 /** A mutex for preventing interleaving of output lines from different threads. 65 * May not be held in some circumstances, so locking of any internal shared 66 * structures is still necessary. 67 */ 68 static MUTEX_INITIALIZE(console_mutex, MUTEX_RECURSIVE); 69 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; 80 78 81 79 /** Kernel log spinlock */ 82 SPINLOCK_INITIALIZE_NAME(kio_lock, "kio_lock"); 83 84 /** Physical memory area used for kio buffer */ 85 static parea_t kio_parea; 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; 86 86 87 87 static indev_t stdin_sink; … … 95 95 }; 96 96 97 static void stdout_write(outdev_t *, c har32_t);97 static void stdout_write(outdev_t *, const char *, size_t); 98 98 static void stdout_redraw(outdev_t *); 99 99 static void stdout_scroll_up(outdev_t *); … … 148 148 } 149 149 150 static void stdout_write(outdev_t *dev, c har32_t ch)150 static void stdout_write(outdev_t *dev, const char *s, size_t n) 151 151 { 152 152 list_foreach(dev->list, link, outdev_t, sink) { 153 153 if ((sink) && (sink->op->write)) 154 sink->op->write(sink, ch);154 sink->op->write(sink, s, n); 155 155 } 156 156 } … … 181 181 182 182 /** Initialize kernel logging facility 183 *184 * The shared area contains kernel cyclic buffer. Userspace application may185 * be notified on new data with indication of position and size186 * of the data within the circular buffer.187 *188 183 */ 189 184 void kio_init(void) 190 185 { 191 void *faddr = (void *) KA2PA(kio);192 193 assert((uintptr_t) faddr % FRAME_SIZE == 0);194 195 ddi_parea_init(&kio_parea);196 kio_parea.pbase = (uintptr_t) faddr;197 kio_parea.frames = SIZE2FRAMES(sizeof(kio));198 kio_parea.unpriv = false;199 kio_parea.mapped = false;200 ddi_parea_register(&kio_parea);201 202 sysinfo_set_item_val("kio.faddr", NULL, (sysarg_t) faddr);203 sysinfo_set_item_val("kio.pages", NULL, KIO_PAGES);204 205 186 event_set_unmask_callback(EVENT_KIO, kio_update); 206 187 atomic_store(&kio_inited, true); … … 243 224 } 244 225 245 /** Get string from input character device.246 *247 * Read characters from input character device until first occurrence248 * of newline character.249 *250 * @param indev Input character device.251 * @param buf Buffer where to store string terminated by NULL.252 * @param buflen Size of the buffer.253 *254 * @return Number of characters read.255 *256 */257 size_t gets(indev_t *indev, char *buf, size_t buflen)258 {259 size_t offset = 0;260 size_t count = 0;261 buf[offset] = 0;262 263 char32_t ch;264 while ((ch = indev_pop_character(indev)) != '\n') {265 if (ch == '\b') {266 if (count > 0) {267 /* Space, backspace, space */268 putuchar('\b');269 putuchar(' ');270 putuchar('\b');271 272 count--;273 offset = str_lsize(buf, count);274 buf[offset] = 0;275 }276 }277 278 if (chr_encode(ch, buf, &offset, buflen - 1) == EOK) {279 putuchar(ch);280 count++;281 buf[offset] = 0;282 }283 }284 285 return count;286 }287 288 /** Get character from input device & echo it to screen */289 char32_t getc(indev_t *indev)290 {291 char32_t ch = indev_pop_character(indev);292 putuchar(ch);293 return ch;294 }295 296 226 void kio_update(void *event) 297 227 { … … 299 229 return; 300 230 301 spinlock_lock(&kio_lock); 302 303 if (kio_uspace > 0) { 304 if (event_notify_3(EVENT_KIO, true, kio_start, kio_len, 305 kio_uspace) == EOK) 306 kio_uspace = 0; 307 } 308 309 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); 310 239 } 311 240 … … 320 249 return; 321 250 322 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]; 323 261 324 262 /* Print characters that weren't printed earlier */ 325 while (kio_stored > 0) { 326 char32_t tmp = kio[(kio_start + kio_len - kio_stored) % KIO_LENGTH]; 327 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; 328 271 329 272 /* 330 * We need to give up the spinlock for 331 * the physical operation of writing out 332 * the character. 273 * We need to give up the spinlock for the physical operation of writing 274 * out the buffer. 333 275 */ 334 spinlock_unlock(&kio_lock); 335 stdout->op->write(stdout, tmp); 336 spinlock_lock(&kio_lock); 337 } 338 339 spinlock_unlock(&kio_lock); 340 } 341 342 /** Put a character into the output buffer. 343 * 344 * The caller is required to hold kio_lock 345 */ 346 void kio_push_char(const char32_t ch) 347 { 348 kio[(kio_start + kio_len) % KIO_LENGTH] = ch; 349 if (kio_len < KIO_LENGTH) 350 kio_len++; 351 else 352 kio_start = (kio_start + 1) % KIO_LENGTH; 353 354 if (kio_stored < kio_len) 355 kio_stored++; 356 357 /* The character is stored for uspace */ 358 if (kio_uspace < kio_len) 359 kio_uspace++; 360 } 361 362 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 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) 363 322 { 364 323 bool ordy = ((stdout) && (stdout->op->write)); 365 324 366 spinlock_lock(&kio_lock);367 kio_push_ char(ch);368 spinlock_unlock(&kio_lock);325 irq_spinlock_lock(&kio_lock, true); 326 kio_push_bytes(s, n); 327 irq_spinlock_unlock(&kio_lock, true); 369 328 370 329 /* Output stored characters */ … … 379 338 * The early_putuchar() function is used to output 380 339 * the character for low-level debugging purposes. 381 * Note that the early_put c() function might be340 * Note that the early_putuchar() function might be 382 341 * a no-op on certain hardware configurations. 383 342 */ 384 early_put uchar(ch);385 } 386 387 /* Force notification onnewline */388 if ( ch == '\n')343 early_putstr(s, n); 344 } 345 346 /* Force notification when containing a newline */ 347 if (memchr(s, '\n', n) != NULL) 389 348 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; 390 402 } 391 403 … … 425 437 } 426 438 data[size] = 0; 439 440 uint8_t substitute = '\x1a'; 441 str_sanitize(data, size, substitute); 427 442 428 443 switch (cmd) { … … 446 461 } 447 462 463 /** Lock console output, ensuring that lines from different threads don't 464 * interleave. Does nothing when preemption is disabled, so that debugging 465 * and error printouts in sensitive areas still work. 466 */ 467 void console_lock(void) 468 { 469 if (!PREEMPTION_DISABLED) 470 mutex_lock(&console_mutex); 471 } 472 473 /** Unlocks console output. See console_lock() 474 */ 475 void console_unlock(void) 476 { 477 if (!PREEMPTION_DISABLED) 478 mutex_unlock(&console_mutex); 479 } 480 448 481 /** @} 449 482 */
Note:
See TracChangeset
for help on using the changeset viewer.