/* * Copyright (c) 2020 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ /** * @file: console.c * @brief: console file * @version: 1.0 * @author: AIIT XUOS Lab * @date: 2020/3/15 * */ #include #include #if defined(KERNEL_CONSOLE) static HardwareDevType _console = NONE; #endif /** * Obtain the console * */ HardwareDevType ObtainConsole(void) { #if defined(KERNEL_CONSOLE) return _console; #endif } /** * Setup a console * * * @param name console device name * */ HardwareDevType InstallConsole(const char *bus_name, const char *drv_name, const char *dev_name) { #if defined(KERNEL_CONSOLE) BusType console_bus; DriverType console_drv = NONE; HardwareDevType console = NONE; struct SerialDevParam *serial_dev_param = NONE; struct SerialCfgParam serial_cfg; struct BusConfigureInfo configure_info; NULL_PARAM_CHECK(bus_name); NULL_PARAM_CHECK(drv_name); NULL_PARAM_CHECK(dev_name); console_bus = BusFind(bus_name); console_drv = BusFindDriver(console_bus, drv_name); console = BusFindDevice(console_bus, dev_name); if (console != NONE) { if (_console != NONE) { BusDevClose(_console); } configure_info.configure_cmd = OPE_INT; memset(&serial_cfg, 0, sizeof(struct SerialCfgParam)); configure_info.private_data = &serial_cfg; BusDrvConfigure(console_drv, &configure_info); console_bus->match(console_drv, console); serial_dev_param = (struct SerialDevParam *)console->private_data; serial_dev_param->serial_set_mode = 0; serial_dev_param->serial_stream_mode = SIGN_OPER_STREAM; BusDevOpen(console); _console = console; } else { console = _console; } return console; #endif } #if defined(KERNEL_CONSOLE) static __inline x_bool IsDigit(char c) { return ((unsigned)((c) - '0') < 10); } static __inline unsigned int CharToNum(const char **s) { unsigned int i = 0; while (IsDigit(**s)) { i = i * 10 + **s - '0'; ++ *s; } return i; } #define ZEROPAD (1 << 0) #define LEFT (1 << 1) #define SIGN (1 << 2) #define SPACE (1 << 3) #define HASH (1 << 4) #define PRINTLONG (1 << 5) #define PRINTLONGLONG (1 << 6) #define PRINTSHORT (1 << 7) #define PRINTCHAR (1 << 8) #define CAPITAL (1 << 9) static size_t LongToChar(char* str, unsigned long value, uint32 flags, int32 precision, uint8 base, int32 width, x_bool minus, int32 pointer, int32 size) { char buff[KERNEL_CONSOLEBUF_SIZE/4] = {0}; int32 length = 0; if(!value) flags &= ~HASH; if(!(precision > 0) || value) { do { const char number = (char)(value % base); if(number < 10) { buff[length] = number + '0'; } else { if(flags & CAPITAL) buff[length] = 'A' + number - 10; else buff[length] = 'a' + number - 10; } ++ length; value /= base; } while (value && (length < KERNEL_CONSOLEBUF_SIZE/4)); } if(!(flags & LEFT)) { if(width && (minus || (flags & (SIGN | SPACE | ZEROPAD)))) -- width; while((length < precision) && (length < KERNEL_CONSOLEBUF_SIZE/4)) buff[length++] = '0'; while((length < width) && (flags & ZEROPAD) && (length < KERNEL_CONSOLEBUF_SIZE/4)) buff[length++] = '0'; } if((flags & HASH) && ((base == 8) || (base == 16))) { if(!(precision > 0) && length && ((length == precision) || (length == width))) { -- length; if(length && (base == 16)) -- length; } switch (base) { case 8: buff[length++] = '0'; break; case 16: if(flags & CAPITAL) { buff[length++] = 'X'; buff[length++] = '0'; } else { buff[length++] = 'x'; buff[length++] = '0'; } break; default: break; } } if(length < KERNEL_CONSOLEBUF_SIZE/4) { if(minus) buff[length++] = '-'; else if(flags & SIGN) buff[length++] = '+'; else if(flags & SPACE) buff[length++] = ' '; } const int32 index = pointer; if(!(flags & LEFT) && !(flags & ZEROPAD) && (length < width)) { for(int32 i = length; i < width; i++) { str[pointer++] = ' '; if(pointer >= size) { str[size - 1] = '\0'; return size; } } } while (length) { str[pointer++] = buff[--length]; if(pointer >= size) { str[size - 1] = '\0'; return size; } } if(flags & LEFT) { while (pointer - index < width) { str[pointer++] = ' '; if(pointer >= size) { str[size - 1] = '\0'; return size; } } } return pointer; } static size_t LonglongToChar(char* str, unsigned long long value, uint32 flags, int32 precision, uint8 base, int32 width, x_bool minus, int32 pointer, int32 size) { char buff[KERNEL_CONSOLEBUF_SIZE/4] = {0}; int32 length = 0; if(!value) flags &= ~HASH; if(!(precision > 0) || value){ do { const char number = (char)(value % base); if(number < 10) { buff[length] = number + '0'; } else { if(flags & CAPITAL) buff[length] = 'A' + number - 10; else buff[length] = 'a' + number - 10; } ++ length; value /= base; } while (value && (length < KERNEL_CONSOLEBUF_SIZE/4)); } if(!(flags & LEFT)) { if(width && (minus || (flags & (SIGN | SPACE | ZEROPAD)))) -- width; while((length < precision) && (length < KERNEL_CONSOLEBUF_SIZE/4)) buff[length++] = '0'; while((length < width) && (flags & ZEROPAD) && (length < KERNEL_CONSOLEBUF_SIZE/4)) buff[length++] = '0'; } if((flags & HASH) && ((base == 8) || (base == 16))) { if(!(precision > 0) && length && ((length == precision) || (length == width))) { -- length; if(length && (base == 16)) -- length; } switch (base) { case 8: buff[length++] = '0'; break; case 16: if(flags & CAPITAL) { buff[length++] = 'X'; buff[length++] = '0'; } else { buff[length++] = 'x'; buff[length++] = '0'; } break; default: break; } } if(length < KERNEL_CONSOLEBUF_SIZE/4) { if(minus) buff[length++] = '-'; else if(flags & SIGN) buff[length++] = '+'; else if(flags & SPACE) buff[length++] = ' '; } const int32 index = pointer; if(!(flags & LEFT) && !(flags & ZEROPAD) && (length < width)) { for(int32 i = length; i < width; i++) { str[pointer++] = ' '; if(pointer >= size) { str[size - 1] = '\0'; return size; } } } while (length) { str[pointer++] = buff[--length]; if(pointer >= size) { str[size - 1] = '\0'; return size; } } if(flags & LEFT) { while (pointer - index < width) { str[pointer++] = ' '; if(pointer >= size) { str[size - 1] = '\0'; return size; } } } return pointer; } int VsnPrintf(char *buf, int32 size, const char *fmt, va_list args) { NULL_PARAM_CHECK(buf); int32 pointer = 0; int32 len = 0; int32 i = 0; int32 width = 0; int32 precision = 0; uint32 flags = 0; uint8 base = 0; char c = 0; char *str = NONE; char *s = NONE; pointer = 0; str = buf; while(*fmt) { if (*fmt != '%') { buf[pointer++] = *fmt; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } ++ fmt; continue; } flags = 0; uint8 CheckFlags = 1; while (CheckFlags) { ++ fmt; switch (*fmt) { case '0': flags |= ZEROPAD; break; case '-': flags |= LEFT; break; case '+': flags |= SIGN; break; case ' ': flags |= SPACE; break; case '#': flags |= HASH; break; default: CheckFlags = 0; break; } } width = -1; if (IsDigit(*fmt)) width = CharToNum(&fmt); else if (*fmt == '*') { width = va_arg(args, int); if (width < 0) { width = -width; flags |= LEFT; } ++ fmt; } precision = -1; if (*fmt == '.') { ++ fmt; if (IsDigit(*fmt)) precision = CharToNum(&fmt); else if (*fmt == '*') { precision = va_arg(args, int); ++ fmt; } if (precision < 0) precision = 0; } if (*fmt == 'l') { ++ fmt; if (*fmt == 'l') { flags |= PRINTLONGLONG; ++ fmt; } else flags |= PRINTLONG; } else if(*fmt == 'h') { ++ fmt; if (*fmt == 'h') { flags |= PRINTCHAR; ++ fmt; } else flags |= PRINTSHORT; } base = 10; switch (*fmt) { case 'c': if (!(flags & LEFT)) { while (--width > 0) { buf[pointer++] = ' '; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } } } c = (char)va_arg(args, int); buf[pointer++] = c; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } while (--width > 0) { buf[pointer++] = ' '; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } } break; case 's': s = va_arg(args, char *); if (!s) s = "(NULL)"; len = strlen(s); if (precision > 0 && len > precision) len = precision; if (!(flags & LEFT)) { while (len < width--) { buf[pointer++] = ' '; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } } } for (i = 0; i < len; ++ i) { buf[pointer++] = *s; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } ++ s; } while (len < width--) { buf[pointer++] = ' '; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } } break; case 'p': width = sizeof(void *) * 2; flags |= ZEROPAD | CAPITAL; /* Determine the machine word length */ #ifdef ARCH_CPU_64BIT if(sizeof(long) == sizeof(long long)) pointer = LonglongToChar(buf, (unsigned long long)va_arg(args, void*), flags, precision, 16, width, 0, pointer, size); else #endif pointer = LongToChar(buf, (unsigned long)va_arg(args, void*), flags, precision, 16, width, 0, pointer, size); if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } break; case '%': buf[pointer] = '%'; ++ pointer; break; case 'o': flags &= ~SIGN; base = 8; if(flags & PRINTLONGLONG) pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size); else if(flags & PRINTLONG) pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size); else { if(flags & PRINTSHORT) { const unsigned int value = (unsigned short int)va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } else if(flags & PRINTCHAR) { const unsigned int value = (unsigned char)va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } else { const unsigned int value = va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } } if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } break; case 'X': flags |= CAPITAL; case 'x': flags &= ~SIGN; base = 16; if(flags & PRINTLONGLONG) pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size); else if(flags & PRINTLONG) pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size); else { if(flags & PRINTSHORT) { const unsigned int value = (unsigned short int)va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } else if(flags & PRINTCHAR) { const unsigned int value = (unsigned char)va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } else { const unsigned int value = va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } } if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } break; case 'u': flags &= ~SIGN; base = 10; flags &= ~HASH; if(flags & PRINTLONGLONG) pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size); else if(flags & PRINTLONG) pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size); else { if(flags & PRINTSHORT) { const unsigned int value = (unsigned short int)va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } else if(flags & PRINTCHAR) { const unsigned int value = (unsigned char)va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } else { const unsigned int value = va_arg(args, unsigned int); pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size); } } if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } break; case 'd': case 'i': base = 10; flags &= ~HASH; if(flags & PRINTLONGLONG) { const long long value = va_arg(args, long long); pointer = LonglongToChar(buf, (unsigned long long)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size); } else if(flags & PRINTLONG) { const long value = va_arg(args, long); pointer = LongToChar(buf, (unsigned long)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size); } else { if(flags & PRINTSHORT) { const int value = (short int)va_arg(args, int); pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size); } else if(flags & PRINTCHAR) { const int value = (char)va_arg(args, int); pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size); } else { const int value = va_arg(args, int); pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size); } } if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } break; default: buf[pointer++] = '%'; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } if (*fmt) { buf[pointer++] = *fmt; if(pointer >= size) { buf[size - 1] = '\0'; return size - 1; } } else { -- fmt; } break; } ++ fmt; } if(pointer > size) pointer = size - 1; buf[pointer] = '\0'; return pointer; } #endif void KPrintf(const char *fmt, ...) { #ifdef KERNEL_CONSOLE if(_console != NONE) { va_list args; x_size_t length = 0; static char logbuf[KERNEL_CONSOLEBUF_SIZE] = {0}; va_start(args, fmt); length = VsnPrintf(logbuf, sizeof(logbuf) - 1, fmt, args); if (length > KERNEL_CONSOLEBUF_SIZE - 1) length = KERNEL_CONSOLEBUF_SIZE - 1; struct BusBlockWriteParam write_param; write_param.pos = 0; write_param.buffer = (void *)logbuf; write_param.size = length; BusDevWriteData(_console, (void *)&write_param); va_end(args); } #endif }