make a spinmutex (and other things)
This commit is contained in:
parent
29878e42e6
commit
96cfda564c
1
Makefile
1
Makefile
@ -5,7 +5,6 @@ P=programs
|
|||||||
|
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$K/entry.o \
|
$K/entry.o \
|
||||||
$K/console.o \
|
|
||||||
$K/vm.o \
|
$K/vm.o \
|
||||||
$K/proc.o \
|
$K/proc.o \
|
||||||
$K/swtch.o \
|
$K/swtch.o \
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
//
|
|
||||||
// Console input and output, to the uart.
|
|
||||||
// Reads are line at a time.
|
|
||||||
// Implements special input characters:
|
|
||||||
// newline -- end of line
|
|
||||||
// control-h -- backspace
|
|
||||||
// control-u -- kill line
|
|
||||||
// control-d -- end of file
|
|
||||||
// control-p -- print process list
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "param.h"
|
|
||||||
#include "spinlock.h"
|
|
||||||
#include "sleeplock.h"
|
|
||||||
#include "fs.h"
|
|
||||||
#include "file.h"
|
|
||||||
#include "memlayout.h"
|
|
||||||
#include "riscv.h"
|
|
||||||
#include "defs.h"
|
|
||||||
#include "proc.h"
|
|
||||||
|
|
||||||
#define BACKSPACE 0x100
|
|
||||||
#define INPUT_BUF_SIZE 128
|
|
||||||
#define C(x) ((x)-'@') // Control-x
|
|
||||||
|
|
||||||
struct console {
|
|
||||||
struct spinlock lock;
|
|
||||||
|
|
||||||
// input
|
|
||||||
char buf[INPUT_BUF_SIZE];
|
|
||||||
uint r; // Read index
|
|
||||||
uint w; // Write index
|
|
||||||
uint e; // Edit index
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct console cons;
|
|
||||||
void consputc(int c);
|
|
||||||
int consolewrite(int user_src, uint64 src, int n);
|
|
||||||
int consoleread(int user_dst, uint64 dst, int n);
|
|
||||||
|
|
||||||
void consoleintr(int c)
|
|
||||||
{
|
|
||||||
acquire(&cons.lock);
|
|
||||||
|
|
||||||
switch(c){
|
|
||||||
case C('P'): // Print process list.
|
|
||||||
procdump();
|
|
||||||
break;
|
|
||||||
case C('U'): // Kill line.
|
|
||||||
while(cons.e != cons.w &&
|
|
||||||
cons.buf[(cons.e-1) % INPUT_BUF_SIZE] != '\n'){
|
|
||||||
cons.e--;
|
|
||||||
consputc(BACKSPACE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case C('H'): // Backspace
|
|
||||||
case '\x7f': // Delete key
|
|
||||||
if(cons.e != cons.w){
|
|
||||||
cons.e--;
|
|
||||||
consputc(BACKSPACE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(c != 0 && cons.e-cons.r < INPUT_BUF_SIZE){
|
|
||||||
c = (c == '\r') ? '\n' : c;
|
|
||||||
|
|
||||||
// echo back to the user.
|
|
||||||
consputc(c);
|
|
||||||
|
|
||||||
// store for consumption by consoleread().
|
|
||||||
cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;
|
|
||||||
|
|
||||||
if(c == '\n' || c == C('D') || cons.e-cons.r == INPUT_BUF_SIZE){
|
|
||||||
// wake up consoleread() if a whole line (or end-of-file)
|
|
||||||
// has arrived.
|
|
||||||
cons.w = cons.e;
|
|
||||||
wakeup(&cons.r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
release(&cons.lock);
|
|
||||||
}
|
|
@ -22,8 +22,8 @@ struct context {
|
|||||||
struct cpu {
|
struct cpu {
|
||||||
struct proc *proc; // The process running on this cpu, or null.
|
struct proc *proc; // The process running on this cpu, or null.
|
||||||
struct context context; // swtch() here to enter scheduler().
|
struct context context; // swtch() here to enter scheduler().
|
||||||
int noff; // Depth of push_off() nesting.
|
int interrupt_disable_layers; // Depth of push_off() nesting.
|
||||||
int intena; // Were interrupts enabled before push_off()?
|
int previous_interrupts_enabled; // Were interrupts enabled before push_off()?
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct cpu cpus[NCPU];
|
extern struct cpu cpus[NCPU];
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{fs::BSIZE, sleeplock::Sleeplock};
|
use crate::{fs::BSIZE, sync::sleeplock::Sleeplock};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Buf {
|
pub struct Buf {
|
||||||
|
@ -10,66 +10,73 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
file::{devsw, CONSOLE},
|
file::{devsw, CONSOLE},
|
||||||
proc::{killed, myproc, sleep},
|
proc::{killed, myproc, sleep_mutex, wakeup, procdump},
|
||||||
spinlock::{initlock, Spinlock},
|
sync::spinmutex::SpinMutex,
|
||||||
uart::{uartinit, uartputc, uartputc_sync},
|
uart::{uartinit, uartputc, uartputc_sync},
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
ffi::{c_void, CStr},
|
ffi::c_void,
|
||||||
ptr::addr_of_mut,
|
ptr::addr_of_mut,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn either_copyin(dst: *mut c_void, user_src: i32, src: u64, len: u64) -> i32;
|
fn either_copyin(dst: *mut c_void, user_src: i32, src: u64, len: u64) -> i32;
|
||||||
fn either_copyout(user_dst: i32, dst: u64, src: *mut c_void, len: u64) -> i32;
|
fn either_copyout(user_dst: i32, dst: u64, src: *mut c_void, len: u64) -> i32;
|
||||||
|
|
||||||
pub fn consoleintr(c: i32);
|
|
||||||
fn wakeup(chan: *mut c_void);
|
|
||||||
fn procdump();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const BACKSPACE: i32 = 0x100;
|
pub const BACKSPACE: u8 = 0x00;
|
||||||
pub const INPUT_BUF_SIZE: u64 = 128;
|
pub const INPUT_BUF_SIZE: usize = 128;
|
||||||
|
|
||||||
|
pub struct Console {
|
||||||
|
pub buffer: [u8; INPUT_BUF_SIZE],
|
||||||
|
pub read_index: usize,
|
||||||
|
pub write_index: usize,
|
||||||
|
pub edit_index: usize,
|
||||||
|
}
|
||||||
|
impl Console {
|
||||||
|
pub fn read_byte(&self) -> &u8 {
|
||||||
|
&self.buffer[self.read_index % self.buffer.len()]
|
||||||
|
}
|
||||||
|
pub fn write_byte(&mut self) -> &mut u8 {
|
||||||
|
let i = self.write_index % self.buffer.len();
|
||||||
|
&mut self.buffer[i]
|
||||||
|
}
|
||||||
|
pub fn edit_byte(&mut self) -> &mut u8 {
|
||||||
|
let i = self.edit_index % self.buffer.len();
|
||||||
|
&mut self.buffer[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut cons: Console = Console {
|
pub static cons: SpinMutex<Console> = SpinMutex::new(Console {
|
||||||
lock: unsafe { Spinlock::uninitialized() },
|
buffer: [0u8; INPUT_BUF_SIZE],
|
||||||
buffer: [0u8; INPUT_BUF_SIZE as usize],
|
|
||||||
read_index: 0,
|
read_index: 0,
|
||||||
write_index: 0,
|
write_index: 0,
|
||||||
edit_index: 0,
|
edit_index: 0,
|
||||||
};
|
});
|
||||||
|
|
||||||
/// ctrl-x
|
/// ctrl-x
|
||||||
fn ctrl_x(x: char) -> char {
|
const fn ctrl_x(x: u8) -> u8 {
|
||||||
((x as u8) - b'@') as char
|
x - b'@'
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send one character to the UART.
|
/// Send one character to the UART.
|
||||||
///
|
///
|
||||||
/// Called by printf(), and to echo input
|
/// Called by printf(), and to echo input
|
||||||
/// characters but not from write().
|
/// characters but not from write().
|
||||||
#[no_mangle]
|
pub fn consputc(c: u8) {
|
||||||
pub unsafe extern "C" fn consputc(c: i32) {
|
unsafe {
|
||||||
if c == BACKSPACE {
|
if c == BACKSPACE {
|
||||||
// If the user typed backspace, overwrite with a space.
|
// If the user typed backspace, overwrite with a space.
|
||||||
uartputc_sync('\x08' as i32);
|
uartputc_sync(0x08);
|
||||||
uartputc_sync(' ' as i32);
|
uartputc_sync(b' ');
|
||||||
uartputc_sync('\x08' as i32);
|
uartputc_sync(0x08);
|
||||||
} else {
|
} else {
|
||||||
uartputc_sync(c);
|
uartputc_sync(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Console {
|
|
||||||
pub lock: Spinlock,
|
|
||||||
pub buffer: [u8; INPUT_BUF_SIZE as usize],
|
|
||||||
pub read_index: u32,
|
|
||||||
pub write_index: u32,
|
|
||||||
pub edit_index: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User write()s to the console go here.
|
/// User write()s to the console go here.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn consolewrite(user_src: i32, src: u64, n: i32) -> i32 {
|
pub unsafe extern "C" fn consolewrite(user_src: i32, src: u64, n: i32) -> i32 {
|
||||||
@ -79,7 +86,7 @@ pub unsafe extern "C" fn consolewrite(user_src: i32, src: u64, n: i32) -> i32 {
|
|||||||
if either_copyin(addr_of_mut!(c).cast(), user_src, src + i as u64, 1) == -1 {
|
if either_copyin(addr_of_mut!(c).cast(), user_src, src + i as u64, 1) == -1 {
|
||||||
return i;
|
return i;
|
||||||
} else {
|
} else {
|
||||||
uartputc(c as i32);
|
uartputc(c as u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
@ -96,31 +103,32 @@ pub unsafe extern "C" fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) ->
|
|||||||
let mut c;
|
let mut c;
|
||||||
let mut cbuf;
|
let mut cbuf;
|
||||||
|
|
||||||
cons.lock.lock();
|
// cons.lock.lock();
|
||||||
|
let mut console = cons.lock();
|
||||||
|
|
||||||
while n > 0 {
|
while n > 0 {
|
||||||
// Wait until interrupt handler has put
|
// Wait until interrupt handler has put
|
||||||
// some input into cons.buffer.
|
// some input into cons.buffer.
|
||||||
while cons.read_index == cons.write_index {
|
while console.read_index == console.write_index {
|
||||||
if killed(myproc()) != 0 {
|
if killed(myproc()) != 0 {
|
||||||
cons.lock.unlock();
|
// cons.lock.unlock();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sleep(
|
sleep_mutex(
|
||||||
addr_of_mut!(cons.read_index).cast(),
|
addr_of_mut!(console.read_index).cast(),
|
||||||
addr_of_mut!(cons.lock),
|
&mut console,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
c = cons.buffer[(cons.read_index % INPUT_BUF_SIZE as u32) as usize];
|
c = *console.read_byte();
|
||||||
cons.read_index += 1;
|
console.read_index += 1;
|
||||||
|
|
||||||
// ctrl-D or EOF
|
// ctrl-D or EOF
|
||||||
if c == ctrl_x('D') as u8 {
|
if c == ctrl_x(b'D') {
|
||||||
if n < target {
|
if n < target {
|
||||||
// Save ctrl-D for next time, to make
|
// Save ctrl-D for next time, to make
|
||||||
// sure caller gets a 0-byte result.
|
// sure caller gets a 0-byte result.
|
||||||
cons.read_index -= 1;
|
console.read_index -= 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -141,81 +149,12 @@ pub unsafe extern "C" fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cons.lock.unlock();
|
// cons.lock.unlock();
|
||||||
|
|
||||||
target - n
|
target - n
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// The console input interrupt handler.
|
|
||||||
// ///
|
|
||||||
// /// uartintr() calls this for input character.
|
|
||||||
// /// Do erase/kill processing, then append to cons.buf.
|
|
||||||
// /// Wake up consoleread() if a whole line has arrived.
|
|
||||||
// #[no_mangle]
|
|
||||||
// pub unsafe extern "C" fn consoleintr(c: i32) {
|
|
||||||
// cons.lock.lock();
|
|
||||||
//
|
|
||||||
// let ctrl_p = ctrl_x('P') as u8 as i8 as i32;
|
|
||||||
// let ctrl_u = ctrl_x('P') as u8 as i8 as i32;
|
|
||||||
// let ctrl_h = ctrl_x('P') as u8 as i8 as i32;
|
|
||||||
// let ctrl_d = ctrl_x('D') as u8 as i8 as i32;
|
|
||||||
// let cr = '\r' as u8 as i8 as i32;
|
|
||||||
// let nl = '\n' as u8 as i8 as i32;
|
|
||||||
//
|
|
||||||
// match c {
|
|
||||||
// // Print process list.
|
|
||||||
// ctrl_p => procdump(),
|
|
||||||
// // Kill line
|
|
||||||
// ctrl_u => {
|
|
||||||
// while cons.edit_index != cons.write_index
|
|
||||||
// && cons.buffer[((cons.edit_index - 1) % INPUT_BUF_SIZE as u32) as usize]
|
|
||||||
// != '\n' as u8
|
|
||||||
// {
|
|
||||||
// cons.edit_index -= 1;
|
|
||||||
// consputc(BACKSPACE);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Backspace
|
|
||||||
// ctrl_h => {
|
|
||||||
// if cons.edit_index != cons.write_index {
|
|
||||||
// cons.edit_index -= 1;
|
|
||||||
// consputc(BACKSPACE);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// c => {
|
|
||||||
// if cons.edit_index - cons.read_index < INPUT_BUF_SIZE as u32 {
|
|
||||||
// let c = if c == cr { nl } else { c };
|
|
||||||
//
|
|
||||||
// // Echo back to the user.
|
|
||||||
// consputc(c);
|
|
||||||
//
|
|
||||||
// // Store for consumption by consoleread().
|
|
||||||
// cons.buffer[(cons.edit_index % INPUT_BUF_SIZE as u32) as usize] = c as i8 as u8;
|
|
||||||
// cons.edit_index += 1;
|
|
||||||
//
|
|
||||||
// if c == nl
|
|
||||||
// || c == ctrl_d
|
|
||||||
// || cons.edit_index - cons.read_index == INPUT_BUF_SIZE as u32
|
|
||||||
// {
|
|
||||||
// // Wake up consoleread() if a whole line (or EOF) has arrived.
|
|
||||||
// cons.write_index = cons.edit_index;
|
|
||||||
// wakeup(addr_of_mut!(cons.read_index).cast());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// cons.lock.unlock();
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub unsafe fn consoleinit() {
|
pub unsafe fn consoleinit() {
|
||||||
initlock(
|
|
||||||
addr_of_mut!(cons.lock),
|
|
||||||
CStr::from_bytes_with_nul(b"cons\0")
|
|
||||||
.unwrap()
|
|
||||||
.as_ptr()
|
|
||||||
.cast_mut(),
|
|
||||||
);
|
|
||||||
uartinit();
|
uartinit();
|
||||||
|
|
||||||
// Connect read and write syscalls
|
// Connect read and write syscalls
|
||||||
@ -223,3 +162,45 @@ pub unsafe fn consoleinit() {
|
|||||||
devsw[CONSOLE].read = consoleread as usize as *const i32;
|
devsw[CONSOLE].read = consoleread as usize as *const i32;
|
||||||
devsw[CONSOLE].write = consolewrite as usize as *const i32;
|
devsw[CONSOLE].write = consolewrite as usize as *const i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The console input interrupt handler.
|
||||||
|
///
|
||||||
|
/// uartintr() calls this for input character.
|
||||||
|
/// Do erase/kill processing, then append to cons.buf.
|
||||||
|
/// Wake up consoleread() if a whole line has arrived.
|
||||||
|
pub fn consoleintr(mut c: u8) {
|
||||||
|
// cons.lock.lock();
|
||||||
|
let mut console = cons.lock();
|
||||||
|
|
||||||
|
if c == ctrl_x(b'P') {
|
||||||
|
// Print process list.
|
||||||
|
unsafe { procdump() };
|
||||||
|
} else if c == ctrl_x(b'U') {
|
||||||
|
// Kill line.
|
||||||
|
while console.edit_index != console.write_index && console.buffer[(console.edit_index - 1) % INPUT_BUF_SIZE] != b'\n' {
|
||||||
|
console.edit_index -= 1;
|
||||||
|
consputc(BACKSPACE);
|
||||||
|
}
|
||||||
|
} else if c == ctrl_x(b'H') || c == 0x7f {
|
||||||
|
// Backspace or delete key.
|
||||||
|
if console.edit_index != console.write_index {
|
||||||
|
console.edit_index -= 1;
|
||||||
|
consputc(BACKSPACE);
|
||||||
|
}
|
||||||
|
} else if c != 0 && console.edit_index - console.read_index < INPUT_BUF_SIZE {
|
||||||
|
c = if c == b'\r' { b'\n' } else { c };
|
||||||
|
|
||||||
|
// Echo back to the user.
|
||||||
|
consputc(c);
|
||||||
|
|
||||||
|
// Store for consumption by consoleread().
|
||||||
|
*console.edit_byte() = c;
|
||||||
|
console.edit_index += 1;
|
||||||
|
|
||||||
|
if c == b'\n' || c == ctrl_x(b'D') || console.edit_index - console.read_index == INPUT_BUF_SIZE {
|
||||||
|
// Wake up consoleread() if a whole line (or EOF) has arrived.
|
||||||
|
console.write_index = console.edit_index;
|
||||||
|
unsafe { wakeup(addr_of_mut!(console.read_index).cast()) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
riscv::{memlayout::PHYSTOP, pg_round_up, PGSIZE},
|
riscv::{memlayout::PHYSTOP, pg_round_up, PGSIZE},
|
||||||
spinlock::Spinlock,
|
sync::spinlock::Spinlock,
|
||||||
string::memset,
|
string::memset,
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![allow(clippy::missing_safety_doc)]
|
#![allow(clippy::missing_safety_doc)]
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate core;
|
extern crate core;
|
||||||
@ -15,8 +16,7 @@ pub(crate) mod param;
|
|||||||
pub mod printf;
|
pub mod printf;
|
||||||
pub mod proc;
|
pub mod proc;
|
||||||
pub(crate) mod riscv;
|
pub(crate) mod riscv;
|
||||||
pub mod sleeplock;
|
pub mod sync;
|
||||||
pub mod spinlock;
|
|
||||||
pub mod start;
|
pub mod start;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
@ -35,7 +35,7 @@ extern "C" {
|
|||||||
pub fn fileinit();
|
pub fn fileinit();
|
||||||
pub fn virtio_disk_init();
|
pub fn virtio_disk_init();
|
||||||
pub fn userinit();
|
pub fn userinit();
|
||||||
pub fn scheduler();
|
// pub fn scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::{printf::print, proc::cpuid};
|
use crate::{printf::print, proc::cpuid};
|
||||||
@ -45,7 +45,7 @@ pub static mut STARTED: bool = false;
|
|||||||
pub static mut PANICKED: bool = false;
|
pub static mut PANICKED: bool = false;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn main() {
|
pub unsafe extern "C" fn main() -> ! {
|
||||||
if cpuid() == 0 {
|
if cpuid() == 0 {
|
||||||
console::consoleinit();
|
console::consoleinit();
|
||||||
printf::printfinit();
|
printf::printfinit();
|
||||||
@ -73,7 +73,7 @@ pub unsafe extern "C" fn main() {
|
|||||||
riscv::plic::plicinithart();
|
riscv::plic::plicinithart();
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler();
|
proc::scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
@ -85,7 +85,7 @@ fn panic_wrapper(panic_info: &core::panic::PanicInfo) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe { crate::PANICKED = true };
|
unsafe { crate::PANICKED = true };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
core::hint::spin_loop();
|
core::hint::spin_loop();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::spinlock::Spinlock;
|
use crate::sync::spinlock::Spinlock;
|
||||||
use core::ffi::{c_char, CStr};
|
use core::ffi::{c_char, CStr};
|
||||||
|
|
||||||
pub use crate::panic;
|
pub use crate::panic;
|
||||||
@ -25,7 +25,7 @@ macro_rules! print {
|
|||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
for c in s.as_bytes() {
|
for c in s.as_bytes() {
|
||||||
unsafe { $crate::console::consputc(*c as i8 as i32) };
|
$crate::console::consputc(*c);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { $crate::kalloc::kfree(buf.cast()) };
|
unsafe { $crate::kalloc::kfree(buf.cast()) };
|
||||||
|
@ -4,7 +4,8 @@ use crate::{
|
|||||||
kalloc::kfree,
|
kalloc::kfree,
|
||||||
param::*,
|
param::*,
|
||||||
riscv::{self, Pagetable, PTE_W},
|
riscv::{self, Pagetable, PTE_W},
|
||||||
spinlock::{pop_off, push_off, Spinlock},
|
sync::spinlock::{pop_off, push_off, Spinlock},
|
||||||
|
sync::spinmutex::SpinMutexGuard,
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
ffi::{c_char, c_void},
|
ffi::{c_char, c_void},
|
||||||
@ -29,20 +30,22 @@ extern "C" {
|
|||||||
pub fn fork() -> i32;
|
pub fn fork() -> i32;
|
||||||
pub fn exit(status: i32) -> !;
|
pub fn exit(status: i32) -> !;
|
||||||
pub fn wait(addr: u64) -> i32;
|
pub fn wait(addr: u64) -> i32;
|
||||||
|
pub fn procdump();
|
||||||
pub fn proc_pagetable(p: *mut Proc) -> Pagetable;
|
pub fn proc_pagetable(p: *mut Proc) -> Pagetable;
|
||||||
pub fn proc_freepagetable(pagetable: Pagetable, sz: u64);
|
pub fn proc_freepagetable(pagetable: Pagetable, sz: u64);
|
||||||
pub fn wakeup(chan: *mut c_void);
|
pub fn wakeup(chan: *const c_void);
|
||||||
pub fn allocproc() -> *mut Proc;
|
pub fn allocproc() -> *mut Proc;
|
||||||
// pub fn freeproc(p: *mut Proc);
|
// pub fn freeproc(p: *mut Proc);
|
||||||
pub fn uvmalloc(pagetable: Pagetable, oldsz: u64, newsz: u64, xperm: i32) -> u64;
|
pub fn uvmalloc(pagetable: Pagetable, oldsz: u64, newsz: u64, xperm: i32) -> u64;
|
||||||
pub fn uvmdealloc(pagetable: Pagetable, oldsz: u64, newsz: u64) -> u64;
|
pub fn uvmdealloc(pagetable: Pagetable, oldsz: u64, newsz: u64) -> u64;
|
||||||
// pub fn sched();
|
// pub fn sched();
|
||||||
|
pub fn scheduler() -> !;
|
||||||
pub fn swtch(a: *mut Context, b: *mut Context);
|
pub fn swtch(a: *mut Context, b: *mut Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Saved registers for kernel context switches.
|
/// Saved registers for kernel context switches.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub ra: u64,
|
pub ra: u64,
|
||||||
pub sp: u64,
|
pub sp: u64,
|
||||||
@ -61,26 +64,47 @@ pub struct Context {
|
|||||||
pub s10: u64,
|
pub s10: u64,
|
||||||
pub s11: u64,
|
pub s11: u64,
|
||||||
}
|
}
|
||||||
|
impl Context {
|
||||||
|
pub const fn new() -> Context {
|
||||||
|
Context {
|
||||||
|
ra: 0u64,
|
||||||
|
sp: 0u64,
|
||||||
|
s0: 0u64,
|
||||||
|
s1: 0u64,
|
||||||
|
s2: 0u64,
|
||||||
|
s3: 0u64,
|
||||||
|
s4: 0u64,
|
||||||
|
s5: 0u64,
|
||||||
|
s6: 0u64,
|
||||||
|
s7: 0u64,
|
||||||
|
s8: 0u64,
|
||||||
|
s9: 0u64,
|
||||||
|
s10: 0u64,
|
||||||
|
s11: 0u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Per-CPU state.
|
/// Per-CPU state.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub struct Cpu {
|
pub struct Cpu {
|
||||||
/// The process running on this cpu, or null.
|
|
||||||
pub proc: *mut Proc,
|
pub proc: *mut Proc,
|
||||||
/// swtch() here to enter scheduler()
|
/// swtch() here to enter scheduler()
|
||||||
pub context: Context,
|
pub context: Context,
|
||||||
/// Depth of push_off() nesting.
|
/// Depth of push_off() nesting.
|
||||||
pub noff: i32,
|
pub interrupt_disable_layers: i32,
|
||||||
/// Were interrupts enabled before push_off()?
|
/// Were interrupts enabled before push_off()?
|
||||||
pub intena: i32,
|
pub previous_interrupts_enabled: i32,
|
||||||
}
|
}
|
||||||
impl Default for Cpu {
|
impl Cpu {
|
||||||
fn default() -> Self {
|
pub const fn new() -> Cpu {
|
||||||
Cpu {
|
Cpu {
|
||||||
proc: null_mut(),
|
proc: null_mut(),
|
||||||
context: Context::default(),
|
// proc: None,
|
||||||
noff: 0,
|
context: Context::new(),
|
||||||
intena: 0,
|
interrupt_disable_layers: 0,
|
||||||
|
previous_interrupts_enabled: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,9 +384,9 @@ pub unsafe extern "C" fn r#yield() {
|
|||||||
|
|
||||||
/// Switch to scheduler. Must hold only p->lock
|
/// Switch to scheduler. Must hold only p->lock
|
||||||
/// and have changed proc->state. Saves and restores
|
/// and have changed proc->state. Saves and restores
|
||||||
/// intena because intena is a property of this
|
/// previous_interrupts_enabled because previous_interrupts_enabled is a property of this
|
||||||
/// kernel thread, not this CPU. It should
|
/// kernel thread, not this CPU. It should
|
||||||
/// be proc->intena and proc->noff, but that would
|
/// be proc->previous_interrupts_enabled and proc->interrupt_disable_layers, but that would
|
||||||
/// break in the few places where a lock is held but
|
/// break in the few places where a lock is held but
|
||||||
/// there's no process.
|
/// there's no process.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -372,7 +396,7 @@ pub unsafe extern "C" fn sched() {
|
|||||||
|
|
||||||
if !(*p).lock.held_by_current_cpu() {
|
if !(*p).lock.held_by_current_cpu() {
|
||||||
panic!("sched p->lock");
|
panic!("sched p->lock");
|
||||||
} else if (*c).noff != 1 {
|
} else if (*c).interrupt_disable_layers != 1 {
|
||||||
panic!("sched locks");
|
panic!("sched locks");
|
||||||
} else if (*p).state == ProcState::Running {
|
} else if (*p).state == ProcState::Running {
|
||||||
panic!("sched running");
|
panic!("sched running");
|
||||||
@ -380,9 +404,9 @@ pub unsafe extern "C" fn sched() {
|
|||||||
panic!("sched interruptible");
|
panic!("sched interruptible");
|
||||||
}
|
}
|
||||||
|
|
||||||
let intena = (*c).intena;
|
let previous_interrupts_enabled = (*c).previous_interrupts_enabled;
|
||||||
swtch(addr_of_mut!((*p).context), addr_of_mut!((*c).context));
|
swtch(addr_of_mut!((*p).context), addr_of_mut!((*c).context));
|
||||||
(*c).intena = intena;
|
(*c).previous_interrupts_enabled = previous_interrupts_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Atomically release lock and sleep on chan.
|
/// Atomically release lock and sleep on chan.
|
||||||
@ -415,6 +439,28 @@ pub unsafe extern "C" fn sleep(chan: *mut c_void, lock: *mut Spinlock) {
|
|||||||
(*lock).lock();
|
(*lock).lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn sleep_mutex<T>(chan: *mut c_void, mutex: &mut SpinMutexGuard<T>) {
|
||||||
|
let p = myproc();
|
||||||
|
let mutex = mutex.mutex;
|
||||||
|
|
||||||
|
(*p).lock.lock();
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
|
// Go to sleep.
|
||||||
|
(*p).chan = chan;
|
||||||
|
(*p).state = ProcState::Sleeping;
|
||||||
|
|
||||||
|
sched();
|
||||||
|
|
||||||
|
// Tidy up.
|
||||||
|
(*p).chan = null_mut();
|
||||||
|
|
||||||
|
// Reacquire original lock.
|
||||||
|
(*p).lock.unlock();
|
||||||
|
let guard = mutex.lock();
|
||||||
|
core::mem::forget(guard);
|
||||||
|
}
|
||||||
|
|
||||||
/// Kill the process with the given pid.
|
/// Kill the process with the given pid.
|
||||||
/// The victim won't exit until it tries to return
|
/// The victim won't exit until it tries to return
|
||||||
/// to user space (see usertrap() in trap.c).
|
/// to user space (see usertrap() in trap.c).
|
||||||
@ -453,3 +499,4 @@ pub unsafe extern "C" fn killed(p: *mut Proc) -> i32 {
|
|||||||
(*p).lock.unlock();
|
(*p).lock.unlock();
|
||||||
k
|
k
|
||||||
}
|
}
|
||||||
|
|
3
kernel/rustkernel/src/sync/mod.rs
Normal file
3
kernel/rustkernel/src/sync/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod sleeplock;
|
||||||
|
pub mod spinlock;
|
||||||
|
pub mod spinmutex;
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
proc::{myproc, sleep, wakeup},
|
proc::{myproc, sleep, wakeup},
|
||||||
spinlock::{self, Spinlock},
|
sync::spinlock::{self, Spinlock},
|
||||||
};
|
};
|
||||||
use core::{ffi::c_char, ptr::addr_of_mut};
|
use core::{ffi::c_char, ptr::addr_of_mut};
|
||||||
|
|
@ -23,7 +23,7 @@ impl Spinlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Initializes a `Spinlock`.
|
/// Initializes a `Spinlock`.
|
||||||
pub fn new(name: *mut c_char) -> Spinlock {
|
pub const fn new(name: *mut c_char) -> Spinlock {
|
||||||
Spinlock {
|
Spinlock {
|
||||||
locked: AtomicBool::new(false),
|
locked: AtomicBool::new(false),
|
||||||
cpu: null_mut(),
|
cpu: null_mut(),
|
||||||
@ -57,7 +57,7 @@ impl Spinlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.cpu = null_mut();
|
self.cpu = null_mut();
|
||||||
|
|
||||||
self.locked.store(false, Ordering::Release);
|
self.locked.store(false, Ordering::Release);
|
||||||
|
|
||||||
pop_off();
|
pop_off();
|
||||||
@ -94,24 +94,26 @@ pub unsafe extern "C" fn push_off() {
|
|||||||
let cpu = mycpu();
|
let cpu = mycpu();
|
||||||
|
|
||||||
riscv::intr_off();
|
riscv::intr_off();
|
||||||
if (*cpu).noff == 0 {
|
if (*cpu).interrupt_disable_layers == 0 {
|
||||||
(*cpu).intena = old;
|
(*cpu).previous_interrupts_enabled = old;
|
||||||
}
|
}
|
||||||
(*cpu).noff += 1;
|
(*cpu).interrupt_disable_layers += 1;
|
||||||
}
|
}
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn pop_off() {
|
pub unsafe extern "C" fn pop_off() {
|
||||||
let cpu = mycpu();
|
let cpu = mycpu();
|
||||||
|
|
||||||
if riscv::intr_get() == 1 {
|
if riscv::intr_get() == 1 {
|
||||||
|
// crate::panic_byte(b'0');
|
||||||
panic!("pop_off - interruptible");
|
panic!("pop_off - interruptible");
|
||||||
} else if (*cpu).noff < 1 {
|
} else if (*cpu).interrupt_disable_layers < 1 {
|
||||||
|
// crate::panic_byte(b'1');
|
||||||
panic!("pop_off");
|
panic!("pop_off");
|
||||||
}
|
}
|
||||||
|
|
||||||
(*cpu).noff -= 1;
|
(*cpu).interrupt_disable_layers -= 1;
|
||||||
|
|
||||||
if (*cpu).noff == 0 && (*cpu).intena == 1 {
|
if (*cpu).interrupt_disable_layers == 0 && (*cpu).previous_interrupts_enabled == 1 {
|
||||||
riscv::intr_on();
|
riscv::intr_on();
|
||||||
}
|
}
|
||||||
}
|
}
|
45
kernel/rustkernel/src/sync/spinmutex.rs
Normal file
45
kernel/rustkernel/src/sync/spinmutex.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use core::{cell::UnsafeCell, ops::{Deref, DerefMut, Drop}, sync::atomic::{AtomicBool, Ordering}};
|
||||||
|
|
||||||
|
pub struct SpinMutex<T> {
|
||||||
|
locked: AtomicBool,
|
||||||
|
pub inner: UnsafeCell<T>,
|
||||||
|
}
|
||||||
|
impl<T> SpinMutex<T> {
|
||||||
|
pub const fn new(value: T) -> SpinMutex<T> {
|
||||||
|
SpinMutex {
|
||||||
|
locked: AtomicBool::new(false),
|
||||||
|
inner: UnsafeCell::new(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn lock(&self) -> SpinMutexGuard<'_, T> {
|
||||||
|
while self.locked.swap(true, Ordering::Acquire) {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
SpinMutexGuard { mutex: &self }
|
||||||
|
}
|
||||||
|
pub unsafe fn unlock(&self) {
|
||||||
|
self.locked.store(false, Ordering::Release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl<T> Sync for SpinMutex<T> where T: Send {}
|
||||||
|
|
||||||
|
pub struct SpinMutexGuard<'m, T> {
|
||||||
|
pub mutex: &'m SpinMutex<T>,
|
||||||
|
}
|
||||||
|
impl<'m, T> Deref for SpinMutexGuard<'m, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { & *self.mutex.inner.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'m, T> DerefMut for SpinMutexGuard<'m, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { &mut *self.mutex.inner.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'m, T> Drop for SpinMutexGuard<'m, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.mutex.unlock() }
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
printf::print,
|
printf::print,
|
||||||
proc::{cpuid, wakeup},
|
proc::{cpuid, wakeup, mycpu},
|
||||||
riscv::*,
|
riscv::*,
|
||||||
spinlock::Spinlock,
|
sync::spinlock::Spinlock,
|
||||||
};
|
};
|
||||||
use core::{ffi::CStr, ptr::addr_of_mut};
|
use core::{ffi::CStr, ptr::addr_of_mut};
|
||||||
|
|
||||||
@ -142,3 +142,41 @@ pub unsafe extern "C" fn devintr() -> i32 {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InterruptBlocker;
|
||||||
|
impl InterruptBlocker {
|
||||||
|
pub fn new() {
|
||||||
|
unsafe {
|
||||||
|
let interrupts_before = intr_get();
|
||||||
|
let cpu = mycpu();
|
||||||
|
|
||||||
|
intr_off();
|
||||||
|
|
||||||
|
if (*cpu).interrupt_disable_layers == 0 {
|
||||||
|
(*cpu).previous_interrupts_enabled = interrupts_before;
|
||||||
|
}
|
||||||
|
(*cpu).interrupt_disable_layers += 1;
|
||||||
|
// crate::sync::spinlock::push_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl core::ops::Drop for InterruptBlocker {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let cpu = mycpu();
|
||||||
|
|
||||||
|
if intr_get() == 1 || (*cpu).interrupt_disable_layers < 1 {
|
||||||
|
// panic!("pop_off mismatched");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*cpu).interrupt_disable_layers -= 1;
|
||||||
|
|
||||||
|
if (*cpu).interrupt_disable_layers == 0 && (*cpu).previous_interrupts_enabled == 1 {
|
||||||
|
intr_on();
|
||||||
|
}
|
||||||
|
// crate::sync::spinlock::pop_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl !Send for InterruptBlocker {}
|
||||||
|
@ -3,85 +3,143 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
console::consoleintr,
|
console::consoleintr,
|
||||||
proc::{sleep, wakeup},
|
proc::{sleep, sleep_mutex, wakeup},
|
||||||
riscv::memlayout::UART0,
|
riscv::memlayout::UART0,
|
||||||
spinlock::{pop_off, push_off, Spinlock},
|
sync::spinlock::{pop_off, push_off, Spinlock},
|
||||||
|
sync::spinmutex::SpinMutex,
|
||||||
|
trap::InterruptBlocker,
|
||||||
};
|
};
|
||||||
use core::{ffi::CStr, ptr::addr_of_mut};
|
use core::{ffi::CStr, ptr::addr_of_mut};
|
||||||
|
|
||||||
/// The UART control registers are memory-mapped
|
enum Register {
|
||||||
/// at address UART0. This function returns the
|
ReceiveHolding,
|
||||||
/// address of one of the registers.
|
TransmitHolding,
|
||||||
#[inline(always)]
|
InterruptEnable,
|
||||||
fn get_register_addr<N: Into<u64>>(register: N) -> *mut u8 {
|
FIFOControl,
|
||||||
let register: u64 = register.into();
|
InterruptStatus,
|
||||||
(UART0 + register) as *mut u8
|
LineControl,
|
||||||
|
LineStatus,
|
||||||
|
}
|
||||||
|
impl Register {
|
||||||
|
pub fn as_ptr(&self) -> *mut u8 {
|
||||||
|
let addr = UART0 + match self {
|
||||||
|
Register::ReceiveHolding => 0,
|
||||||
|
Register::TransmitHolding => 0,
|
||||||
|
Register::InterruptEnable => 1,
|
||||||
|
Register::FIFOControl => 2,
|
||||||
|
Register::InterruptStatus => 2,
|
||||||
|
Register::LineControl => 2,
|
||||||
|
Register::LineStatus => 5,
|
||||||
|
};
|
||||||
|
addr as *mut u8
|
||||||
|
}
|
||||||
|
pub fn read(&self) -> u8 {
|
||||||
|
unsafe { self.as_ptr().read_volatile() }
|
||||||
|
}
|
||||||
|
pub fn write(&self, value: u8) {
|
||||||
|
unsafe { self.as_ptr().write_volatile(value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static uart: SpinMutex<Uart> = SpinMutex::new(Uart {
|
||||||
|
buffer: [0u8; UART_TX_BUF_SIZE],
|
||||||
|
write_index: 0,
|
||||||
|
read_index: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
pub struct Uart {
|
||||||
|
pub buffer: [u8; UART_TX_BUF_SIZE],
|
||||||
|
pub write_index: usize,
|
||||||
|
pub read_index: usize,
|
||||||
|
}
|
||||||
|
impl Uart {
|
||||||
|
pub fn write_byte_sync(x: u8) {
|
||||||
|
// let _ = InterruptBlocker::new();
|
||||||
|
unsafe { push_off(); }
|
||||||
|
|
||||||
|
if unsafe { crate::PANICKED } {
|
||||||
|
loop {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for Transmit Holding Empty to be set in LSR.
|
||||||
|
while Register::LineStatus.read() & LSR_TX_IDLE == 0 {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Register::TransmitHolding.write(x);
|
||||||
|
|
||||||
|
unsafe { pop_off(); }
|
||||||
|
}
|
||||||
|
/// If the UART is idle, and a character is
|
||||||
|
/// waiting in the transmit buffer, send it.
|
||||||
|
pub fn send_queued_bytes(&mut self) {
|
||||||
|
loop {
|
||||||
|
self.write_index %= self.buffer.len();
|
||||||
|
self.read_index %= self.buffer.len();
|
||||||
|
|
||||||
|
if self.write_index == self.read_index {
|
||||||
|
// Transmit buffer is ready.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = self.buffer[self.read_index];
|
||||||
|
self.read_index += 1;
|
||||||
|
|
||||||
|
// Maybe uartputc() is waiting for space in the buffer.
|
||||||
|
unsafe { wakeup(addr_of_mut!(self.read_index).cast()) };
|
||||||
|
|
||||||
|
Register::TransmitHolding.write(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The UART control registers.
|
// The UART control registers.
|
||||||
// Some have different meanings for read vs write.
|
// Some have different meanings for read vs write.
|
||||||
// See http://byterunner.com/16550.html
|
// See http://byterunner.com/16550.html
|
||||||
|
|
||||||
/// Receive Holding Register (for input bytes)
|
|
||||||
const RHR: u8 = 0;
|
|
||||||
/// Transmit Holding Register (for output bytes)
|
|
||||||
const THR: u8 = 0;
|
|
||||||
/// Interrupt Enable Register
|
/// Interrupt Enable Register
|
||||||
const IER: u8 = 1;
|
|
||||||
const IER_RX_ENABLE: u8 = 1 << 0;
|
const IER_RX_ENABLE: u8 = 1 << 0;
|
||||||
const IER_TX_ENABLE: u8 = 1 << 1;
|
const IER_TX_ENABLE: u8 = 1 << 1;
|
||||||
/// FIFO control register
|
|
||||||
const FCR: u8 = 2;
|
|
||||||
const FCR_FIFO_ENABLE: u8 = 1 << 0;
|
const FCR_FIFO_ENABLE: u8 = 1 << 0;
|
||||||
/// Clear the content of the two FIFOs.
|
/// Clear the content of the two FIFOs.
|
||||||
const FCR_FIFO_CLEAR: u8 = 3 << 1;
|
const FCR_FIFO_CLEAR: u8 = 3 << 1;
|
||||||
/// Interrupt Status Register
|
|
||||||
const ISR: u8 = 2;
|
|
||||||
/// Line Control Register
|
|
||||||
const LCR: u8 = 2;
|
|
||||||
const LCR_EIGHT_BITS: u8 = 3;
|
const LCR_EIGHT_BITS: u8 = 3;
|
||||||
/// Special mode to set baud rate
|
/// Special mode to set baud rate
|
||||||
const LCR_BAUD_LATCH: u8 = 1 << 7;
|
const LCR_BAUD_LATCH: u8 = 1 << 7;
|
||||||
/// Line Status Register
|
|
||||||
const LSR: u8 = 5;
|
|
||||||
/// Input is waiting to be read from RHR
|
/// Input is waiting to be read from RHR
|
||||||
const LSR_RX_READY: u8 = 1 << 0;
|
const LSR_RX_READY: u8 = 1 << 0;
|
||||||
/// THR can accept another character to send
|
/// THR can accept another character to send
|
||||||
const LSR_TX_IDLE: u8 = 1 << 5;
|
const LSR_TX_IDLE: u8 = 1 << 5;
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn read_register<N: Into<u64>>(register: N) -> u8 {
|
|
||||||
*get_register_addr(register)
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn write_register<N: Into<u64>>(register: N, value: u8) {
|
|
||||||
*get_register_addr(register) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut uart_tx_lock: Spinlock = unsafe { Spinlock::uninitialized() };
|
static mut uart_tx_lock: Spinlock = unsafe { Spinlock::uninitialized() };
|
||||||
const UART_TX_BUF_SIZE: u64 = 32;
|
const UART_TX_BUF_SIZE: usize = 32;
|
||||||
static mut uart_tx_buf: [u8; UART_TX_BUF_SIZE as usize] = [0u8; UART_TX_BUF_SIZE as usize];
|
static mut uart_tx_buf: [u8; UART_TX_BUF_SIZE] = [0u8; UART_TX_BUF_SIZE];
|
||||||
|
// static uart_tx_buf: SpinMutex<[u8; UART_TX_BUF_SIZE]> = SpinMutex::new([0u8; UART_TX_BUF_SIZE]);
|
||||||
/// Write next to uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE]
|
/// Write next to uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE]
|
||||||
static mut uart_tx_w: u64 = 0;
|
static mut uart_tx_w: usize = 0;
|
||||||
/// Read next from uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE]
|
/// Read next from uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE]
|
||||||
static mut uart_tx_r: u64 = 0;
|
static mut uart_tx_r: usize = 0;
|
||||||
|
|
||||||
pub(crate) unsafe fn uartinit() {
|
pub(crate) unsafe fn uartinit() {
|
||||||
// Disable interrupts.
|
// Disable interrupts.
|
||||||
write_register(IER, 0x00);
|
Register::InterruptEnable.write(0x00);
|
||||||
// Special mode to set baud rate.
|
// Special mode to set baud rate.
|
||||||
write_register(LCR, LCR_BAUD_LATCH);
|
Register::LineControl.write(LCR_BAUD_LATCH);
|
||||||
// LSB for baud rate of 38.4K.
|
unsafe {
|
||||||
write_register(0u8, 0x03);
|
// LSB for baud rate of 38.4K.
|
||||||
// MSB for baud rate of 38.4K.
|
*(UART0 as *mut u8) = 0x03;
|
||||||
write_register(1u8, 0x00);
|
// MSB for baud rate of 38.4K.
|
||||||
|
*((UART0 + 1) as *mut u8) = 0x00;
|
||||||
|
}
|
||||||
// Leave set-baud mode and set
|
// Leave set-baud mode and set
|
||||||
// word length to 8 bits, no parity.
|
// word length to 8 bits, no parity.
|
||||||
write_register(LCR, LCR_EIGHT_BITS);
|
Register::LineControl.write(LCR_EIGHT_BITS);
|
||||||
// Reset and enable FIFOs.
|
// Reset and enable FIFOs.
|
||||||
write_register(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
|
Register::FIFOControl.write(FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
|
||||||
// Enable transmit and receive interrupts.
|
// Enable transmit and receive interrupts.
|
||||||
write_register(IER, IER_TX_ENABLE | IER_RX_ENABLE);
|
Register::InterruptEnable.write(IER_TX_ENABLE | IER_RX_ENABLE);
|
||||||
|
|
||||||
uart_tx_lock = Spinlock::new(
|
uart_tx_lock = Spinlock::new(
|
||||||
CStr::from_bytes_with_nul(b"uart\0")
|
CStr::from_bytes_with_nul(b"uart\0")
|
||||||
@ -97,8 +155,10 @@ pub(crate) unsafe fn uartinit() {
|
|||||||
/// Because it may block, it can't be called
|
/// Because it may block, it can't be called
|
||||||
/// from interrupts, it's only suitable for use
|
/// from interrupts, it's only suitable for use
|
||||||
/// by write().
|
/// by write().
|
||||||
pub(crate) unsafe fn uartputc(c: i32) {
|
pub(crate) unsafe fn uartputc(c: u8) {
|
||||||
uart_tx_lock.lock();
|
uart_tx_lock.lock();
|
||||||
|
// let mut buf = uart_tx_buf.lock();
|
||||||
|
// let u = uart.lock();
|
||||||
|
|
||||||
if crate::PANICKED {
|
if crate::PANICKED {
|
||||||
loop {
|
loop {
|
||||||
@ -115,7 +175,7 @@ pub(crate) unsafe fn uartputc(c: i32) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_tx_buf[(uart_tx_w % UART_TX_BUF_SIZE) as usize] = c as i8 as u8;
|
uart_tx_buf[(uart_tx_w % UART_TX_BUF_SIZE) as usize] = c;
|
||||||
uart_tx_w += 1;
|
uart_tx_w += 1;
|
||||||
uartstart();
|
uartstart();
|
||||||
uart_tx_lock.unlock();
|
uart_tx_lock.unlock();
|
||||||
@ -125,21 +185,22 @@ pub(crate) unsafe fn uartputc(c: i32) {
|
|||||||
/// use interrupts, for use by kernel printf() and
|
/// use interrupts, for use by kernel printf() and
|
||||||
/// to echo characters. It spins waiting for the UART's
|
/// to echo characters. It spins waiting for the UART's
|
||||||
/// output register to be empty.
|
/// output register to be empty.
|
||||||
pub(crate) unsafe fn uartputc_sync(c: i32) {
|
pub(crate) unsafe fn uartputc_sync(c: u8) {
|
||||||
push_off();
|
push_off();
|
||||||
|
Uart::write_byte_sync(c);
|
||||||
|
|
||||||
if crate::PANICKED {
|
// if crate::PANICKED {
|
||||||
loop {
|
// loop {
|
||||||
core::hint::spin_loop();
|
// core::hint::spin_loop();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Wait for Transmit Holding Empty to be set in LSR.
|
// // Wait for Transmit Holding Empty to be set in LSR.
|
||||||
while read_register(LSR) & LSR_TX_IDLE == 0 {
|
// while Register::LineStatus.read() & LSR_TX_IDLE == 0 {
|
||||||
core::hint::spin_loop();
|
// core::hint::spin_loop();
|
||||||
}
|
// }
|
||||||
|
|
||||||
write_register(THR, c as i8 as u8);
|
// Register::TransmitHolding.write(c);
|
||||||
|
|
||||||
pop_off();
|
pop_off();
|
||||||
}
|
}
|
||||||
@ -154,47 +215,45 @@ unsafe fn uartstart() {
|
|||||||
// Transmit buffer is ready.
|
// Transmit buffer is ready.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if Register::LineStatus.read() & LSR_TX_IDLE == 0 {
|
||||||
if read_register(LSR) & LSR_TX_IDLE == 0 {
|
|
||||||
// The UART transmit holding register is full,
|
// The UART transmit holding register is full,
|
||||||
// so we cannot give it another byte.
|
// so we cannot give it another byte.
|
||||||
// It will interrupt when it's ready for a new byte.
|
// It will interrupt when it's ready for a new byte.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let buf = uart_tx_buf.lock();
|
||||||
let c = uart_tx_buf[(uart_tx_r % UART_TX_BUF_SIZE) as usize];
|
let c = uart_tx_buf[(uart_tx_r % UART_TX_BUF_SIZE) as usize];
|
||||||
uart_tx_r += 1;
|
uart_tx_r += 1;
|
||||||
|
|
||||||
// Maybe uartputc() is waiting for space in the buffer.
|
// Maybe uartputc() is waiting for space in the buffer.
|
||||||
wakeup(addr_of_mut!(uart_tx_r).cast());
|
wakeup(addr_of_mut!(uart_tx_r).cast());
|
||||||
|
|
||||||
write_register(THR, c);
|
Register::TransmitHolding.write(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read one input character from the UART.
|
/// Read one input byte from the UART.
|
||||||
/// Return -1 if nothing is waiting.
|
pub(crate) fn uartgetc() -> Option<u8> {
|
||||||
unsafe fn uartgetc() -> i32 {
|
if Register::LineStatus.read() & 0x01 != 0 {
|
||||||
if read_register(LSR) & 0x01 != 0 {
|
|
||||||
// Input data is ready.
|
// Input data is ready.
|
||||||
read_register(RHR) as i32
|
Some(Register::ReceiveHolding.read())
|
||||||
} else {
|
} else {
|
||||||
-1
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a UART interrupt, raised because input has
|
/// Handle a UART interrupt, raised because input has
|
||||||
/// arrived, or the uart is ready for more output, or
|
/// arrived, or the uart is ready for more output, or
|
||||||
/// both. Called from devintr().
|
/// both. Called from devintr().
|
||||||
#[no_mangle]
|
pub(crate) unsafe fn uartintr() {
|
||||||
pub unsafe extern "C" fn uartintr() {
|
|
||||||
// Read and process incoming characters.
|
// Read and process incoming characters.
|
||||||
loop {
|
loop {
|
||||||
let c = uartgetc();
|
if let Some(c) = uartgetc() {
|
||||||
if c == -1 {
|
consoleintr(c);
|
||||||
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
consoleintr(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send buffered characters.
|
// Send buffered characters.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user