🆕 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

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ kernel/kernel
*.o *.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 timer.o: driver/timers/timer.c
gcc $(CFLAGS) -c driver/timers/timer.c -o driver/timers/timer.o 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 all: kernel

View File

@ -17,6 +17,7 @@
: "memory") //关闭外部中断 : "memory") //关闭外部中断
#define nop() __asm__ __volatile__("nop\n\t") #define nop() __asm__ __volatile__("nop\n\t")
#define hlt() __asm__ __volatile__("hlt\n\t") #define hlt() __asm__ __volatile__("hlt\n\t")
#define pause() asm volatile ("pause\n\t"); // 处理器等待一段时间
//内存屏障 //内存屏障
#define io_mfence() __asm__ __volatile__("mfence\n\t" :: \ #define io_mfence() __asm__ __volatile__("mfence\n\t" :: \

View File

@ -7,6 +7,8 @@
#include "../mm/mm.h" #include "../mm/mm.h"
#include "../process/spinlock.h" #include "../process/spinlock.h"
#include <driver/uart/uart.h>
//#include "linkage.h" //#include "linkage.h"
struct screen_info pos; struct screen_info pos;
@ -110,13 +112,16 @@ void auto_newline()
* @brief * @brief
* *
*/ */
if (pos.x > pos.max_x) if (pos.x > pos.max_x)
{ {
uart_send(COM1, '\n');
pos.x = 0; pos.x = 0;
++pos.y; ++pos.y;
} }
if (pos.y > pos.max_y) if (pos.y > pos.max_y)
{ {
uart_send(COM1, '\n');
pos.y = pos.max_y; pos.y = pos.max_y;
int lines_to_scroll = 1; int lines_to_scroll = 1;
scroll(true, lines_to_scroll * pos.char_size_y, false); 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 BKcolor
* @param font bitmap * @param font bitmap
*/ */
// 输出到串口
uart_send(COM1, font);
unsigned char *font_ptr = font_ascii[font]; unsigned char *font_ptr = font_ascii[font];
unsigned int *addr; 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/rtc/rtc.h>
#include <driver/timers/HPET/HPET.h> #include <driver/timers/HPET/HPET.h>
#include <driver/timers/timer.h> #include <driver/timers/timer.h>
#include <driver/uart/uart.h>
unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址 unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址
ul bsp_idt_size, bsp_gdt_size; ul bsp_idt_size, bsp_gdt_size;
@ -83,6 +84,7 @@ void system_initialize()
// 初始化printk // 初始化printk
printk_init(8, 16); printk_init(8, 16);
uart_init(COM1, 115200);
kinfo("Kernel Starting..."); kinfo("Kernel Starting...");
// 重新加载gdt和idt // 重新加载gdt和idt
@ -100,7 +102,6 @@ void system_initialize()
kdebug("cpu_core_info[0].tss_vaddr=%#018lx", cpu_core_info[0].tss_vaddr); 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); kdebug("cpu_core_info[0].stack_start%#018lx", cpu_core_info[0].stack_start);
// 初始化中断描述符表 // 初始化中断描述符表
sys_vector_init(); sys_vector_init();
@ -145,14 +146,10 @@ void system_initialize()
// test_slab(); // test_slab();
// test_mm(); // test_mm();
// process_init(); // process_init();
current_pcb->cpu_id = 0; current_pcb->cpu_id = 0;
current_pcb->preempt_count = 0; current_pcb->preempt_count = 0;
HPET_init(); HPET_init();
} }
//操作系统内核从这里开始执行 //操作系统内核从这里开始执行
@ -177,7 +174,6 @@ void Start_Kernel(void)
multiboot2_magic = (uint)mb2_magic; multiboot2_magic = (uint)mb2_magic;
multiboot2_boot_info_addr = mb2_info + PAGE_OFFSET; multiboot2_boot_info_addr = mb2_info + PAGE_OFFSET;
system_initialize(); 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 bochs -q -f ${bochsrc} -rc ./tools/bochsinit
else else
qemu-system-x86_64 -cdrom ${iso} -m 512M -smp 2,cores=2,threads=1,sockets=1 \ 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 \ -drive id=disk,file=bin/disk.img,if=none \
-device ahci,id=ahci \ -device ahci,id=ahci \
-device ide-hd,drive=disk,bus=ahci.0 \ -device ide-hd,drive=disk,bus=ahci.0 \