1/*
2 * Copyright 2013, winocm. <winocm@icloud.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 *   Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 *
11 *   Redistributions in binary form must reproduce the above copyright notice, this
12 *   list of conditions and the following disclaimer in the documentation and/or
13 *   other materials provided with the distribution.
14 *
15 *   If you are going to use this software in any form that does not involve
16 *   releasing the source to this project or improving it, let me know beforehand.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * PE kprintf interface
31 */
32
33#include <stdarg.h>
34#include <kern/debug.h>
35#include <kern/simple_lock.h>
36#include <mach/mach_types.h>
37#include <pexpert/pexpert.h>
38#include <pexpert/machine/protos.h>
39#include <pexpert/machine/boot.h>
40#include <machine/machine_routines.h>
41#include <machine/pal_routines.h>
42#include "semihost.h"
43
44#if DEBUG
45/* DEBUG kernel starts with true serial, but
46 * may later disable or switch to video
47 * console */
48unsigned int disable_serial_output = FALSE;
49#else
50unsigned int disable_serial_output = TRUE;
51#endif
52
53void (*PE_kputc) (char c);
54decl_simple_lock_data(static, kprintf_lock)
55
56/**
57 * PE_init_kprintf
58 *
59 * Initialize kprintf (for semihosting right now.)
60 */
61void PE_init_kprintf(boolean_t vm_initialized)
62{
63    unsigned int boot_arg;
64
65    if (PE_state.initialized == FALSE)
66        panic("Platform Expert not initialized");
67
68    if (!vm_initialized) {
69        unsigned int new_disable_serial_output = FALSE;
70
71        simple_lock_init(&kprintf_lock, 0);
72
73        if (PE_parse_boot_argn("debug", &boot_arg, sizeof(boot_arg)))
74            if (boot_arg & DB_KPRT)
75                new_disable_serial_output = FALSE;
76
77        /*
78         * If we are newly enabling serial, make sure we only
79         * * call pal_serial_init() if our previous state was
80         * * not enabled
81         */
82        if (!new_disable_serial_output && (!disable_serial_output || pal_serial_init()))
83            PE_kputc = PE_semihost_write_char;
84        else
85            PE_kputc = cnputc;
86
87        disable_serial_output = new_disable_serial_output;
88    }
89}
90
91/**
92 * kprintf
93 *
94 * Sort of like printf, but outputs wherever PE_kputc will send it to.
95 */
96void kprintf(const char *format, ...)
97{
98    va_list listp;
99
100    va_start(listp, format);
101    _doprnt(format, &listp, PE_kputc, 16);
102    va_end(listp);
103}
104