🆕 uart驱动

This commit is contained in:
fslongjin 2022-04-15 15:23:17 +08:00
parent be8ac71aa9
commit 22359344e4
8 changed files with 188 additions and 26 deletions

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ DragonOS.iso
kernel/kernel
*.o
*.s
*.s
serial_opt.txt

View File

@ -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

View File

@ -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" :: \

View File

@ -7,6 +7,8 @@
#include "../mm/mm.h"
#include "../process/spinlock.h"
#include <driver/uart/uart.h>
//#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;

88
kernel/driver/uart/uart.c Normal file
View File

@ -0,0 +1,88 @@
#include "uart.h"
#include <common/kprint.h>
#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);
}

64
kernel/driver/uart/uart.h Normal file
View File

@ -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 <common/glib.h>
#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);

View File

@ -27,6 +27,7 @@
#include <driver/timers/rtc/rtc.h>
#include <driver/timers/HPET/HPET.h>
#include <driver/timers/timer.h>
#include <driver/uart/uart.h>
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();
/*

2
run.sh
View File

@ -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 \