From 22359344e4240ed614691d8d85fddffe29b6e91b Mon Sep 17 00:00:00 2001 From: fslongjin Date: Fri, 15 Apr 2022 15:23:17 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20uart=E9=A9=B1=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- kernel/Makefile | 5 +++ kernel/common/glib.h | 1 + kernel/common/printk.c | 7 ++++ kernel/driver/uart/uart.c | 88 +++++++++++++++++++++++++++++++++++++++ kernel/driver/uart/uart.h | 64 ++++++++++++++++++++++++++++ kernel/main.c | 44 +++++++++----------- run.sh | 2 +- 8 files changed, 188 insertions(+), 26 deletions(-) create mode 100644 kernel/driver/uart/uart.c create mode 100644 kernel/driver/uart/uart.h diff --git a/.gitignore b/.gitignore index 68cb16f7..c6727d73 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ DragonOS.iso kernel/kernel *.o -*.s \ No newline at end of file +*.s +serial_opt.txt \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index 089f09a4..fde76d4b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -125,6 +125,11 @@ HPET.o: driver/timers/HPET/HPET.c timer.o: driver/timers/timer.c gcc $(CFLAGS) -c driver/timers/timer.c -o driver/timers/timer.o +OBJ_LIST += uart.o +LD_LIST += driver/uart/uart.o +uart.o: driver/uart/uart.c + gcc $(CFLAGS) -c driver/uart/uart.c -o driver/uart/uart.o + all: kernel diff --git a/kernel/common/glib.h b/kernel/common/glib.h index e637e39b..d1fe2b4b 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -17,6 +17,7 @@ : "memory") //关闭外部中断 #define nop() __asm__ __volatile__("nop\n\t") #define hlt() __asm__ __volatile__("hlt\n\t") +#define pause() asm volatile ("pause\n\t"); // 处理器等待一段时间 //内存屏障 #define io_mfence() __asm__ __volatile__("mfence\n\t" :: \ diff --git a/kernel/common/printk.c b/kernel/common/printk.c index a91e937d..ee64b4af 100644 --- a/kernel/common/printk.c +++ b/kernel/common/printk.c @@ -7,6 +7,8 @@ #include "../mm/mm.h" #include "../process/spinlock.h" +#include + //#include "linkage.h" struct screen_info pos; @@ -110,13 +112,16 @@ void auto_newline() * @brief 超过每行最大字符数,自动换行 * */ + if (pos.x > pos.max_x) { + uart_send(COM1, '\n'); pos.x = 0; ++pos.y; } if (pos.y > pos.max_y) { + uart_send(COM1, '\n'); pos.y = pos.max_y; int lines_to_scroll = 1; scroll(true, lines_to_scroll * pos.char_size_y, false); @@ -625,6 +630,8 @@ static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, uns * @param BKcolor 背景颜色 * @param font 字符的bitmap */ + // 输出到串口 + uart_send(COM1, font); unsigned char *font_ptr = font_ascii[font]; unsigned int *addr; diff --git a/kernel/driver/uart/uart.c b/kernel/driver/uart/uart.c new file mode 100644 index 00000000..2001d28b --- /dev/null +++ b/kernel/driver/uart/uart.c @@ -0,0 +1,88 @@ +#include "uart.h" +#include + +#define UART_MAX_BITS_RATE 115200 + +/** + * @brief 当前是否有数据到达 + * + */ +#define serial_received(p) ((io_in8(p + 5) & 1)) + +/** + * @brief 当前是否有数据正等待发送 + * + */ +#define is_transmit_empty(p) ((io_in8(p + 5) & 0x20)) + +/** + * @brief 初始化com口 + * + * @param port com口的端口号 + * @param bits_rate 通信的比特率 + */ +int uart_init(uint32_t port, uint32_t bits_rate) +{ + // 错误的比特率 + if (bits_rate > UART_MAX_BITS_RATE || UART_MAX_BITS_RATE % bits_rate != 0) + return E_UART_BITS_RATE_ERROR; + + io_out8(port + 1, 0x00); // Disable all interrupts + io_out8(port + 3, 0x80); // Enable DLAB (set baud rate divisor) + + uint16_t divisor = E_UART_BITS_RATE_ERROR / bits_rate; + io_out8(port + 0, divisor & 0xff); // Set divisor (lo byte) + io_out8(port + 1, (divisor >> 8) & 0xff); // (hi byte) + io_out8(port + 3, 0x03); // 8 bits, no parity, one stop bit + io_out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + io_out8(port + 4, 0x0B); // IRQs enabled, RTS/DSR set + io_out8(port + 4, 0x1E); // Set in loopback mode, test the serial chip + io_out8(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if (io_in8(port + 0) != 0xAE) + { + return E_UART_SERIAL_FAULT; + } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + io_out8(port + 4, 0x0F); + return UART_SUCCESS; + + /* + Notice that the initialization code above writes to [PORT + 1] + twice with different values. This is once to write to the Divisor + register along with [PORT + 0] and once to write to the Interrupt + register as detailed in the previous section. + The second write to the Line Control register [PORT + 3] + clears the DLAB again as well as setting various other bits. + */ +} + +/** + * @brief 发送数据 + * + * @param port 端口号 + * @param c 要发送的数据 + */ +void uart_send(uint32_t port, char c) +{ + while (is_transmit_empty(port) == 0) + pause(); + io_out8(port, c); +} + +/** + * @brief 从uart接收数据 + * + * @param port 端口号 + * @return uchar 接收到的数据 + */ +uchar uart_read(uint32_t port) +{ + while (serial_received(port) == 0) + pause(); + + return io_in8(port); +} \ No newline at end of file diff --git a/kernel/driver/uart/uart.h b/kernel/driver/uart/uart.h new file mode 100644 index 00000000..c5442bd5 --- /dev/null +++ b/kernel/driver/uart/uart.h @@ -0,0 +1,64 @@ +/** + * @file uart.h + * @author longjin (longjin@RinGoTek.cn) + * @brief uart驱动程序 RS-232驱动 + * @version 0.1 + * @date 2022-04-15 + * + * @copyright Copyright (c) 2022 + * + */ +#pragma once + +#include + +#define UART_SUCCESS 0 +#define E_UART_BITS_RATE_ERROR 1 +#define E_UART_SERIAL_FAULT 2 +enum uart_port_io_addr +{ + COM1 = 0x3f8, + COM2 = 0x2f8, + COM3 = 0x3e8, + COM4 = 0x2e8, + COM5 = 0x5f8, + COM6 = 0x4f8, + COM7 = 0x5e8, + COM8 = 0x4E8, +}; + +enum uart_register_offset +{ + REG_DATA = 0, + REG_INTERRUPT_ENABLE = 1, + REG_II_FIFO = 2, // Interrupt Identification and FIFO control registers + REG_LINE_CONTROL = 3, + REG_MODEM_CONTROL = 4, + REG_LINE_STATUS = 5, + REG_MODEM_STATUE = 6, + REG_SCRATCH = 7 +}; + +/** + * @brief 初始化com口 + * + * @param port com口的端口号 + * @param bits_rate 通信的比特率 + */ +int uart_init(uint32_t port, uint32_t bits_rate); + +/** + * @brief 发送数据 + * + * @param port 端口号 + * @param c 要发送的数据 + */ +void uart_send(uint32_t port, char c); + +/** + * @brief 从uart接收数据 + * + * @param port 端口号 + * @return uchar 接收到的数据 + */ +uchar uart_read(uint32_t port); \ No newline at end of file diff --git a/kernel/main.c b/kernel/main.c index a7e9a48f..77729097 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -27,6 +27,7 @@ #include #include #include +#include unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址 ul bsp_idt_size, bsp_gdt_size; @@ -57,8 +58,8 @@ struct gdtr gdtp; struct idtr idtp; void reload_gdt() { - - gdtp.size = bsp_gdt_size-1; + + gdtp.size = bsp_gdt_size - 1; gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table); asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) @@ -67,11 +68,11 @@ void reload_gdt() void reload_idt() { - - idtp.size = bsp_idt_size-1; + + idtp.size = bsp_idt_size - 1; idtp.idt_vaddr = (ul)phys_2_virt((ul)&IDT_Table); - //kdebug("gdtvaddr=%#018lx", p.gdt_vaddr); - //kdebug("gdt size=%d", p.size); + // kdebug("gdtvaddr=%#018lx", p.gdt_vaddr); + // kdebug("gdt size=%d", p.size); asm volatile("lidt (%0) \n\t" ::"r"(&idtp) : "memory"); @@ -83,12 +84,13 @@ void system_initialize() // 初始化printk printk_init(8, 16); + uart_init(COM1, 115200); kinfo("Kernel Starting..."); // 重新加载gdt和idt - + ul tss_item_addr = (ul)phys_2_virt(0x7c00); - - _stack_start = head_stack_start; // 保存init proc的栈基地址(由于之后取消了地址重映射,因此必须在这里重新保存) + + _stack_start = head_stack_start; // 保存init proc的栈基地址(由于之后取消了地址重映射,因此必须在这里重新保存) kdebug("_stack_start=%#018lx", _stack_start); load_TR(10); // 加载TR寄存器 @@ -99,8 +101,7 @@ void system_initialize() cpu_core_info[0].tss_vaddr = (uint64_t)&initial_tss[0]; kdebug("cpu_core_info[0].tss_vaddr=%#018lx", cpu_core_info[0].tss_vaddr); kdebug("cpu_core_info[0].stack_start%#018lx", cpu_core_info[0].stack_start); - - + // 初始化中断描述符表 sys_vector_init(); @@ -108,8 +109,8 @@ void system_initialize() mm_init(); // =========== 重新设置initial_tss[0]的ist - uchar *ptr = (uchar*)kmalloc(STACK_SIZE, 0)+STACK_SIZE; - ((struct process_control_block*)(ptr-STACK_SIZE))->cpu_id = 0; + uchar *ptr = (uchar *)kmalloc(STACK_SIZE, 0) + STACK_SIZE; + ((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0; initial_tss[0].ist1 = (ul)ptr; initial_tss[0].ist2 = (ul)ptr; @@ -119,7 +120,7 @@ void system_initialize() initial_tss[0].ist6 = (ul)ptr; initial_tss[0].ist7 = (ul)ptr; // =========================== - + acpi_init(); // 初始化中断模块 @@ -127,12 +128,12 @@ void system_initialize() irq_init(); softirq_init(); - + // 先初始化系统调用模块 syscall_init(); // 再初始化进程模块。顺序不能调转 sched_init(); - + timer_init(); smp_init(); @@ -144,21 +145,17 @@ void system_initialize() ahci_init(); // test_slab(); // test_mm(); - - //process_init(); + // process_init(); current_pcb->cpu_id = 0; current_pcb->preempt_count = 0; HPET_init(); - - - } //操作系统内核从这里开始执行 void Start_Kernel(void) { - + // 获取multiboot2的信息 uint64_t mb2_info, mb2_magic; __asm__ __volatile__("movq %%r15, %0 \n\t" @@ -168,7 +165,7 @@ void Start_Kernel(void) : "=r"(mb2_info), "=r"(mb2_magic), "=r"(bsp_gdt_size), "=r"(bsp_idt_size)::"memory"); reload_gdt(); reload_idt(); - + // 重新设置TSS描述符 set_tss_descriptor(10, (void *)(&initial_tss[0])); @@ -177,7 +174,6 @@ void Start_Kernel(void) multiboot2_magic = (uint)mb2_magic; multiboot2_boot_info_addr = mb2_info + PAGE_OFFSET; - system_initialize(); /* diff --git a/run.sh b/run.sh index 4274c7c1..03068413 100644 --- a/run.sh +++ b/run.sh @@ -93,7 +93,7 @@ if [ $flag_can_run -eq 1 ]; then bochs -q -f ${bochsrc} -rc ./tools/bochsinit else qemu-system-x86_64 -cdrom ${iso} -m 512M -smp 2,cores=2,threads=1,sockets=1 \ - -monitor stdio -d cpu_reset,guest_errors,trace:check_exception,exec,cpu,out_asm,in_asm -s -S -cpu IvyBridge --enable-kvm -rtc clock=host,base=localtime \ + -monitor stdio -d cpu_reset,guest_errors,trace:check_exception,exec,cpu,out_asm,in_asm -s -S -cpu IvyBridge --enable-kvm -rtc clock=host,base=localtime -serial file:serial_opt.txt \ -drive id=disk,file=bin/disk.img,if=none \ -device ahci,id=ahci \ -device ide-hd,drive=disk,bus=ahci.0 \