X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..21362eb3e66fd2c787aee132bce100a44d71a99c:/osfmk/console/i386/serial_console.c diff --git a/osfmk/console/i386/serial_console.c b/osfmk/console/i386/serial_console.c index e60c3e615..a4d0b5376 100644 --- a/osfmk/console/i386/serial_console.c +++ b/osfmk/console/i386/serial_console.c @@ -1,47 +1,209 @@ /* * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include +#include +#include #include +#include +#include +#include +#include + +static struct { + char *buffer; + int len; + int used; + char *write_ptr; + char *read_ptr; + decl_simple_lock_data(,read_lock); + decl_simple_lock_data(,write_lock); +} console_ring; + +typedef struct console_buf { + char *buf_base; + char *buf_end; + char *buf_ptr; +#define CPU_BUFFER_LEN (256 - 3*(sizeof(char*))) + char buf[CPU_BUFFER_LEN]; +} console_buf_t; void -cnputc(char c) +console_init(void) +{ + int ret; + + console_ring.len = PAGE_SIZE; + ret = kmem_alloc(kernel_map, (vm_offset_t *) &console_ring.buffer, + console_ring.len); + if (ret != KERN_SUCCESS) + panic("console_ring_init() " + "failed to allocate ring buffer, error %d\n", ret); + console_ring.used = 0; + console_ring.read_ptr = console_ring.buffer; + console_ring.write_ptr = console_ring.buffer; + simple_lock_init(&console_ring.read_lock, 0); + simple_lock_init(&console_ring.write_lock, 0); + +} + +void * +console_cpu_alloc(__unused boolean_t boot_processor) +{ + int ret; + console_buf_t *cbp; + + ret = kmem_alloc(kernel_map, (vm_offset_t *) &cbp, + sizeof(console_buf_t)); + if (ret != KERN_SUCCESS) { + printf("console_cpu_alloc() " + "failed to allocate cpu buffer, error=%d\n", ret); + return NULL; + } + + cbp->buf_base = (char *) &cbp->buf; + cbp->buf_ptr = cbp->buf_base; + cbp->buf_end = cbp->buf_base + CPU_BUFFER_LEN; + + return (void *) cbp; +} + +void +console_cpu_free(void *buf) +{ + if (buf != NULL) + kfree((void *) buf, sizeof(console_buf_t)); +} + +static boolean_t +console_ring_put(char ch) +{ + if (console_ring.used < console_ring.len) { + console_ring.used++;; + *console_ring.write_ptr++ = ch; + if (console_ring.write_ptr - console_ring.buffer + == console_ring.len) + console_ring.write_ptr = console_ring.buffer; + return TRUE; + } else { + return FALSE; + } +} + +static int +console_ring_get(void) +{ + char ch = 0; + + if (console_ring.used > 0) { + console_ring.used--; + ch = *console_ring.read_ptr++; + if (console_ring.read_ptr - console_ring.buffer + == console_ring.len) + console_ring.read_ptr = console_ring.buffer; + } + return (int) ch; +} + +static inline void +cpu_buffer_put(console_buf_t *cbp, char ch) +{ + if (cbp->buf_ptr < cbp->buf_end) + *(cbp->buf_ptr++) = ch; +} + +static inline void +_cnputc(char c) { - boolean_t nolock = mp_kdp_trap || !ml_get_interrupts_enabled(); - - /* - * Note: this lock prevents other cpus interferring with the - * output is this one character to the console (screen). It - * does not prevent multiple printfs being interleaved - that's - * the responsibility of the caller. Without this lock, - * an unreadable black-on-black or white-on-white display may result. - * We avoid taking this lock, however, if we're in the debugger or - * at interrupt level. - */ - if (!nolock) - simple_lock(&mp_putc_lock); vcputc(0, 0, c); if (c == '\n') vcputc(0, 0,'\r'); - if (!nolock) - simple_unlock(&mp_putc_lock); +} + +void +cnputcusr(char c) +{ + simple_lock(&console_ring.read_lock); + _cnputc(c); + simple_unlock(&console_ring.read_lock); +} + +void +cnputc(char c) +{ + console_buf_t *cbp; + + if (!(real_ncpus > 1)) { + _cnputc(c); + return; + } + + mp_disable_preemption(); + /* add to stack buf */ + cbp = (console_buf_t *) current_cpu_datap()->cpu_console_buf; + if (c != '\n') { + cpu_buffer_put(cbp, c); + } else { + boolean_t state; + char *cp; + + /* Here at end of printf -- time to try to output */ + + /* copy this buffer into the shared ring buffer */ + state = ml_set_interrupts_enabled(FALSE); + simple_lock(&console_ring.write_lock); + for (cp = cbp->buf_base; cp < cbp->buf_ptr; cp++) { + while (!console_ring_put(*cp)) + /* spin if share buffer full */ + cpu_pause(); + } + (void) console_ring_put('\n'); + simple_unlock(&console_ring.write_lock); + ml_set_interrupts_enabled(state); + cbp->buf_ptr = cbp->buf_base; + + /* + * Try to get the read lock on the ring buffer to empty it. + * If this fails someone else is already emptying... + */ + if (simple_lock_try(&console_ring.read_lock)) { + for (;;) { + char ch; + + simple_lock(&console_ring.write_lock); + ch = console_ring_get(); + simple_unlock(&console_ring.write_lock); + if (ch == 0) + break; + _cnputc(ch); + } + simple_unlock(&console_ring.read_lock); + } + } + mp_enable_preemption(); }