diff --git a/os/Cargo.toml b/os/Cargo.toml index d8f42164..fbcff883 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -10,10 +10,12 @@ edition = "2021" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" +bit_field = "0.10.0" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" } +lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" } easy-fs = { path = "../easy-fs" } embedded-graphics = "0.7.1" tinybmp = "0.3.1" diff --git a/os/Makefile b/os/Makefile index e02bc814..ac0fd273 100644 --- a/os/Makefile +++ b/os/Makefile @@ -24,7 +24,7 @@ ifeq ($(MODE), release) endif # KERNEL ENTRY -KERNEL_ENTRY_PA := 0x80200000 +KERNEL_ENTRY_PA := 0x80000000 # Binutils OBJDUMP := rust-objdump --arch-name=riscv64 @@ -73,6 +73,22 @@ disasm-vim: kernel run: run-inner +run-inner-none: build + @qemu-system-riscv64 \ + -M 128m \ + -machine virt \ + -bios none \ + $(GUI_OPTION) \ + -kernel $(KERNEL_ELF) \ + -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0 \ +# -device virtio-gpu-device \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -device virtio-net-device,netdev=net0 \ + -netdev user,id=net0,hostfwd=udp::6200-:2000 \ + -serial stdio + run-inner: build @qemu-system-riscv64 \ -M 128m \ @@ -85,12 +101,26 @@ run-inner: build -device virtio-gpu-device \ -device virtio-keyboard-device \ -device virtio-mouse-device \ + -device virtio-net-device,netdev=net0 \ + -netdev user,id=net0,hostfwd=udp::6200-:2000 \ -serial stdio fdt: @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out fdtdump virt.out +debug-none: build + @tmux new-session -d \ + "qemu-system-riscv64 -machine virt -nographic -bios none -kernel $(KERNEL_ELF) \ + -drive file=$(FS_IMG),if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0 \ + -device virtio-keyboard-device \ + -device virtio-mouse-device \ + -serial stdio \ + -s -S" && \ + tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \ + tmux -2 attach-session -d + debug: build @tmux new-session -d \ "qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index 0bc0f4c2..ffb88539 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -2,7 +2,7 @@ pub const CLOCK_FREQ: usize = 12500000; pub const MMIO: &[(usize, usize)] = &[ (0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine - (0x2000000, 0x10000), + (0x2000000, 0x10000), // core local interrupter (CLINT) (0xc000000, 0x210000), // VIRT_PLIC in virt machine (0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine ]; @@ -53,6 +53,58 @@ pub fn irq_handler() { plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id); } + +// core local interrupter (CLINT), which contains the timer +pub const CLINT: usize = 0x2000000; +// pub const fn clint_mtimecmp(hartid: usize) -> usize { +// CLINT + 0x4000 + 8 * hartid +// } +pub const CLINT_MTIME: usize = CLINT + 0xBFF8; // Cycles since boot. +pub const CLINT_MTIMECMP: usize = CLINT + 0x4000; + +#[naked] +#[repr(align(16))] // if miss this alignment, a load access fault will occur. +#[no_mangle] +pub unsafe extern "C" fn timervec() -> ! { + // start.rs has set up the memory that mscratch points to: + // scratch[0,8,16] : register save area. + // scratch[24] : address of CLINT's MTIMECMP register. + // scratch[32] : desired interval between interrupts. + + // Now, mscrach has a pointer to an additional scratch space. + // to aboid overwriting the contents of the integer registers, + // the prologue of an interrupts handler usually begins by swapping + // an integer register(say a0) with mscratch CSR. + // The interrupt handler stores the integer registers + // used for processing in this scratch space. + // a0 saved in mscrach, a1 ~ a3 saved in scratch space. + //loop {} + asm!( + "csrrw a0, mscratch, a0", + "sd a1, 0(a0)", + "sd a2, 8(a0)", + "sd a3, 16(a0)", + // schedule the next timer interrupt + // by adding interval to mtimecmp. + "ld a1, 24(a0)", // CLINT_MTIMECMP(hartid) contents + "ld a2, 32(a0)", // interval + "ld a3, 0(a1)", + "add a3, a3, a2", + "sd a3, 0(a1)", + // raise a supervisor software interrupt. + "li a1, 2", + "csrw sip, a1", + // restore and return + "ld a3, 16(a0)", + "ld a2, 8(a0)", + "ld a1, 0(a0)", + "csrrw a0, mscratch, a0", + "mret", + options(noreturn) + ); +} + + //ref:: https://github.com/andre-richter/qemu-exit use core::arch::asm; diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs index 6871eb87..d9a61219 100644 --- a/os/src/drivers/bus/virtio.rs +++ b/os/src/drivers/bus/virtio.rs @@ -1,6 +1,6 @@ use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, + StepByOne, VirtAddr, frame_alloc_more, }; use crate::sync::UPIntrFreeCell; use alloc::vec::Vec; @@ -16,15 +16,9 @@ pub struct VirtioHal; impl Hal for VirtioHal { fn dma_alloc(pages: usize) -> usize { - let mut ppn_base = PhysPageNum(0); - for i in 0..pages { - let frame = frame_alloc().unwrap(); - if i == 0 { - ppn_base = frame.ppn; - } - assert_eq!(frame.ppn.0, ppn_base.0 + i); - QUEUE_FRAMES.exclusive_access().push(frame); - } + let trakcers = frame_alloc_more(pages); + let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn; + QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap()); let pa: PhysAddr = ppn_base.into(); pa.0 } diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 57a15f03..e4f41724 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -3,6 +3,7 @@ pub mod bus; pub mod chardev; pub mod gpu; pub mod input; +pub mod net; pub mod plic; pub use block::BLOCK_DEVICE; @@ -10,3 +11,4 @@ pub use bus::*; pub use chardev::UART; pub use gpu::*; pub use input::*; +pub use net::*; \ No newline at end of file diff --git a/os/src/drivers/net/mod.rs b/os/src/drivers/net/mod.rs new file mode 100644 index 00000000..e1f76b00 --- /dev/null +++ b/os/src/drivers/net/mod.rs @@ -0,0 +1,41 @@ +use core::any::Any; + +use alloc::sync::Arc; +use lazy_static::*; +use virtio_drivers::{VirtIONet, VirtIOHeader}; +use crate::drivers::virtio::VirtioHal; +use crate::sync::UPIntrFreeCell; + +const VIRTIO8: usize = 0x10004000; + +lazy_static! { + pub static ref NET_DEVICE: Arc = Arc::new(VirtIONetWrapper::new()); +} + +pub trait NetDevice: Send + Sync + Any { + fn transmit(&self, data: &[u8]); + fn receive(&self, data: &mut [u8]) -> usize; +} + +pub struct VirtIONetWrapper(UPIntrFreeCell>); + +impl NetDevice for VirtIONetWrapper { + fn transmit(&self, data: &[u8]) { + self.0.exclusive_access().send(data).expect("can't send data") + } + + fn receive(&self, data: &mut [u8]) -> usize { + self.0.exclusive_access().recv(data).expect("can't receive data") + } +} + +impl VirtIONetWrapper { + pub fn new() -> Self { + unsafe { + let virtio = + VirtIONet::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) + .expect("can't create net device by virtio"); + VirtIONetWrapper(UPIntrFreeCell::new(virtio)) + } + } +} \ No newline at end of file diff --git a/os/src/entry.asm b/os/src/entry.asm index c32d68fd..1d1a1752 100644 --- a/os/src/entry.asm +++ b/os/src/entry.asm @@ -2,7 +2,7 @@ .globl _start _start: la sp, boot_stack_top - call rust_main + call rust_start .section .bss.stack .globl boot_stack_lower_bound diff --git a/os/src/linker-qemu.ld b/os/src/linker-qemu.ld index 5baafbd0..92dd51cd 100644 --- a/os/src/linker-qemu.ld +++ b/os/src/linker-qemu.ld @@ -1,6 +1,6 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0x80200000; +BASE_ADDRESS = 0x80000000; SECTIONS { diff --git a/os/src/main.rs b/os/src/main.rs index 1103c570..83554ae7 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -2,6 +2,8 @@ #![no_main] #![feature(panic_info_message)] #![feature(alloc_error_handler)] +#![feature(naked_functions)] +#![feature(fn_align)] //use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR}; use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; @@ -12,7 +14,7 @@ extern crate bitflags; #[path = "boards/qemu.rs"] mod board; - +use board::*; #[macro_use] mod console; mod config; @@ -26,9 +28,17 @@ mod syscall; mod task; mod timer; mod trap; +mod net; -use crate::drivers::chardev::CharDevice; -use crate::drivers::chardev::UART; +use riscv::register::*; +// mod riscvreg; +// use riscvreg::{ +// mstatus, mepc, satp, medeleg, mideleg, sie, mhartid, tp, clint, +// mscratch, mtvec, mie, sstatus +// }; +// use riscvregs::registers::*; +// use riscvregs::registers::pmpcfg0::*; +//use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -51,9 +61,198 @@ lazy_static! { unsafe { UPIntrFreeCell::new(false) }; } + +#[repr(C, align(16))] +struct Stack([u8; 4096 * 4 * 1]); + +#[no_mangle] +static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]); + +#[inline] +pub unsafe fn medeleg_write(medeleg: usize){ + core::arch::asm!("csrw medeleg, {}",in(reg)medeleg); +} + +pub unsafe fn mideleg_write(mideleg: usize) { + core::arch::asm!("csrw mideleg, {}", in(reg)mideleg); +} + +pub enum SIE { + SEIE = 1 << 9, // external + STIE = 1 << 5, // timer + SSIE = 1 << 1, // software +} + +#[inline] +pub unsafe fn sie_read() -> usize { + let ret:usize; + core::arch::asm!("csrr {}, sie", out(reg)ret); + ret +} + +#[inline] +pub unsafe fn sie_write(x:usize) { + core::arch::asm!("csrw sie, {}", in(reg)x); +} + +/// enable all software interrupts +/// still need to set SIE bit in sstatus +pub unsafe fn intr_on() { + let mut sie = sie_read(); + sie |= SIE::SSIE as usize | SIE::STIE as usize | SIE::SEIE as usize; + sie_write(sie); +} + +#[no_mangle] +pub unsafe fn rust_start() -> ! { + // set MPP mode to Supervisor, for mret + mstatus::set_mpp(mstatus::MPP::Supervisor); + + // set MEPC to main, for mret + mepc::write(rust_main as usize); + + // disable paging for now. + satp::write(0); + + // delegate all interrupts and exceptions to supervisor mode. + medeleg_write(0xffff); + mideleg_write(0xffff); + intr_on(); + + // configure Physical Memory Protection to give supervisor mode + // access to all of physical memory. + pmpaddr0::write(0x3fffffffffffff); + pmpcfg0::write(0xf); + //pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 + + // ask for clock interrupts. + timer_init(); + + // keep each CPU's hartid in its tp register, for cpuid(). + // let id = mhartid::read(); + // core::arch::asm!("mv tp, {0}", in(reg) id); + + // switch to supervisor mode and jump to main(). + core::arch::asm!("mret"); + + extern "C" { + fn rust_main() -> !; + } + core::hint::unreachable_unchecked(); +} + +use core::convert::Into; +use core::ptr; + +// a scratch area per CPU for machine-mode timer interrupts. +static mut TIMER_SCRATCH: [u64; 5] = [0; 5]; + +#[inline] +unsafe fn read_mtime() -> u64 { + ptr::read_volatile(Into::::into(CLINT_MTIME) as *const u64) +} + +unsafe fn write_mtimecmp(value: u64) { + let offset = Into::::into(CLINT_MTIMECMP); + ptr::write_volatile(offset as *mut u64, value); +} + +pub unsafe fn add_mtimecmp(interval:u64){ + let value = read_mtime(); + write_mtimecmp(value+interval); +} + +pub fn count_mtiecmp() -> usize{ + let ret:usize; + ret = Into::::into(CLINT) + 0x4000; + ret +} + +#[inline] +pub unsafe fn mtvec_write(x:usize){ + core::arch::asm!("csrw mtvec, {}",in(reg)x); +} + +use bit_field::BitField; + +#[inline] +unsafe fn mstatus_read() -> usize { + let ret:usize; + core::arch::asm!("csrr {}, mstatus",out(reg)ret); + ret +} + +#[inline] +unsafe fn mstatus_write(x: usize) { + core::arch::asm!("csrw mstatus, {}",in(reg)x); +} + +// enable machine-mode interrupts. +pub unsafe fn mstatus_enable_interrupt(){ + let mut mstatus = mstatus_read(); + mstatus.set_bit(3, true); + mstatus_write(mstatus); +} + + +pub enum MIE { + MEIE = 1 << 11, // external + MTIE = 1 << 7, // timer + MSIE = 1 << 3 // software +} + +#[inline] +pub unsafe fn mie_read() -> usize { + let ret:usize; + core::arch::asm!("csrr {}, mie", out(reg)ret); + ret +} + +#[inline] +pub unsafe fn mie_write(x:usize){ + core::arch::asm!("csrw mie, {}",in(reg)x); +} + +unsafe fn timer_init() { + clear_bss(); + // each CPU has a separate source of timer interrupts + //let id = mhartid::read(); + + // ask the CLINT for a timer interrupts + let interval = 1000000u64; // cycles; about 1/10th second in qemu. + add_mtimecmp(interval); + // let mtimecmp = board::clint_mtimecmp(0) as *mut u64; + // let mtime = board::CLINT_MTIME as *const u64; + // mtimecmp.write_volatile(mtime.read_volatile() + interval); + + // prepare information in scratch[] for timervec. + // scratch[0..2] : space for timervec to save registers. + // scratch[3] : address of CLINT MTIMECMP register. + // scratch[4] : desired interval (in cycles) between timer interrupts. + let scratch = &mut TIMER_SCRATCH; + scratch[3] = count_mtiecmp() as u64; + scratch[4] = interval; + mscratch::write(scratch.as_mut_ptr() as usize); + + // set the machine-mode trap handler + mtvec_write(timervec as usize); + //mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct); + + // enable machine-mode interrupts. + mstatus_enable_interrupt(); + //mstatus::set_mie(); + + // enable machine-mode timer interrupts. + mie_write(mie_read() | MIE::MTIE as usize); + //mie::set_mtimer(); +} + +use crate::drivers::chardev::CharDevice; +use crate::drivers::chardev::UART; #[no_mangle] pub fn rust_main() -> ! { - clear_bss(); + + //clear_bss(); mm::init(); UART.init(); println!("KERN: init gpu"); @@ -64,8 +263,8 @@ pub fn rust_main() -> ! { let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); - trap::enable_timer_interrupt(); - timer::set_next_trigger(); + //trap::enable_timer_interrupt(); + //timer::set_next_trigger(); board::device_init(); fs::list_apps(); task::add_initproc(); diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 1ecfe993..3635e18e 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -35,6 +35,7 @@ impl Drop for FrameTracker { trait FrameAllocator { fn new() -> Self; fn alloc(&mut self) -> Option; + fn alloc_more(&mut self, pages: usize) -> Option>; fn dealloc(&mut self, ppn: PhysPageNum); } @@ -69,6 +70,16 @@ impl FrameAllocator for StackFrameAllocator { Some((self.current - 1).into()) } } + fn alloc_more(&mut self, pages: usize) -> Option> { + if self.current + pages >= self.end { + None + } else { + self.current += pages; + let arr:Vec = (1..pages + 1).collect(); + let v = arr.iter().map(|x| (self.current - x).into()).collect(); + Some(v) + } + } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check @@ -104,6 +115,13 @@ pub fn frame_alloc() -> Option { .map(FrameTracker::new) } +pub fn frame_alloc_more(num: usize) -> Option> { + FRAME_ALLOCATOR + .exclusive_access() + .alloc_more(num) + .map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect()) +} + pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } @@ -125,3 +143,21 @@ pub fn frame_allocator_test() { drop(v); println!("frame_allocator_test passed!"); } + + +#[allow(unused)] +pub fn frame_allocator_alloc_more_test() { + let mut v: Vec = Vec::new(); + let frames = frame_alloc_more(5).unwrap(); + for frame in &frames { + println!("{:?}", frame); + } + v.extend(frames); + v.clear(); + let frames = frame_alloc_more(5).unwrap(); + for frame in &frames { + println!("{:?}", frame); + } + drop(v); + println!("frame_allocator_test passed!"); +} diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 77d62f49..574cea02 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -6,7 +6,7 @@ mod page_table; pub use address::VPNRange; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; -pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; +pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker}; pub use memory_set::remap_test; pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE}; use page_table::PTEFlags; diff --git a/os/src/net/mod.rs b/os/src/net/mod.rs new file mode 100644 index 00000000..57673d3e --- /dev/null +++ b/os/src/net/mod.rs @@ -0,0 +1,92 @@ +pub mod udp; +pub mod socket; + +pub use lose_net_stack::IPv4; + +use alloc::{vec, sync::Arc}; +use lose_net_stack::{LoseStack, MacAddress, results::Packet}; + +use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}}; + +pub struct NetStack(UPIntrFreeCell); + +impl NetStack { + pub fn new() -> Self { + unsafe { + NetStack(UPIntrFreeCell::new(LoseStack::new( + IPv4::new(10, 0, 2, 15), + MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]) + ))) + } + } +} + +lazy_static::lazy_static! { + static ref LOSE_NET_STACK: Arc = Arc::new(NetStack::new()); +} + + +pub fn net_interrupt_handler() { + let mut recv_buf = vec![0u8; 1024]; + + let len = NET_DEVICE.receive(&mut recv_buf); + + let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]); + + // println!("[kernel] receive a packet"); + // hexdump(&recv_buf[..len]); + + match packet { + Packet::ARP(arp_packet) => { + let lose_stack = LOSE_NET_STACK.0.exclusive_access(); + let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply"); + let reply_data = reply_packet.build_data(); + NET_DEVICE.transmit(&reply_data) + }, + + Packet::UDP(udp_packet) => { + let target = udp_packet.source_ip; + let lport = udp_packet.dest_port; + let rport = udp_packet.source_port; + + if let Some(socket_index) = get_socket(target, lport, rport) { + push_data(socket_index, udp_packet.data.to_vec()); + } + } + _ => {} + } +} + +#[allow(unused)] +pub fn hexdump(data: &[u8]) { + const PRELAND_WIDTH: usize = 70; + println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH); + for offset in (0..data.len()).step_by(16) { + print!("[kernel] "); + for i in 0..16 { + if offset + i < data.len() { + print!("{:02x} ", data[offset + i]); + } else { + print!("{:02} ", ""); + } + } + + print!("{:>6}", ' '); + + for i in 0..16 { + if offset + i < data.len() { + let c = data[offset + i]; + if c >= 0x20 && c <= 0x7e { + print!("{}", c as char); + } else { + print!("."); + } + } else { + print!("{:02} ", ""); + } + } + + println!(""); + } + println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH); +} \ No newline at end of file diff --git a/os/src/net/socket.rs b/os/src/net/socket.rs new file mode 100644 index 00000000..4e92a00e --- /dev/null +++ b/os/src/net/socket.rs @@ -0,0 +1,93 @@ +use alloc::collections::VecDeque; +use alloc::vec::Vec; +use lazy_static::lazy_static; +use lose_net_stack::IPv4; + +use crate::sync::UPIntrFreeCell; + + +// TODO: specify the protocol, TCP or UDP +pub struct Socket { + pub raddr: IPv4, // remote address + pub lport: u16, // local port + pub rport: u16, // rempote port + pub buffers: VecDeque> // datas +} + +lazy_static! { + static ref SOCKET_TABLE:UPIntrFreeCell>> = unsafe { + UPIntrFreeCell::new(Vec::new()) + }; +} + +pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + let socket_table = SOCKET_TABLE.exclusive_access(); + for i in 0..socket_table.len() { + let sock = &socket_table[i]; + if sock.is_none() { + continue; + } + + let sock = sock.as_ref().unwrap(); + if sock.raddr == raddr && sock.lport == lport && sock.rport == rport { + return Some(i) + } + } + None +} + +pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + if get_socket(raddr, lport, rport).is_some() { + return None; + } + + let mut socket_table = SOCKET_TABLE.exclusive_access(); + let mut index = usize::MAX; + for i in 0..socket_table.len() { + if socket_table[i].is_none() { + index = i; + break; + } + } + + let socket = Socket { + raddr, + lport, + rport, + buffers: VecDeque::new() + }; + + if index == usize::MAX { + socket_table.push(Some(socket)); + Some(socket_table.len() - 1) + } else { + socket_table[index] = Some(socket); + Some(index) + } +} + +pub fn remove_socket(index: usize) { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + + socket_table[index] = None; +} + +pub fn push_data(index: usize, data: Vec) { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + assert!(socket_table[index].is_some()); + + socket_table[index].as_mut().unwrap().buffers.push_back(data); +} + +pub fn pop_data(index: usize) -> Option> { + let mut socket_table = SOCKET_TABLE.exclusive_access(); + + assert!(socket_table.len() > index); + assert!(socket_table[index].is_some()); + + socket_table[index].as_mut().unwrap().buffers.pop_front() +} \ No newline at end of file diff --git a/os/src/net/udp.rs b/os/src/net/udp.rs new file mode 100644 index 00000000..afa26d0e --- /dev/null +++ b/os/src/net/udp.rs @@ -0,0 +1,94 @@ +use alloc::vec; +use lose_net_stack::MacAddress; +use lose_net_stack::packets::udp::UDPPacket; +use lose_net_stack::IPv4; +use crate::fs::File; +use super::net_interrupt_handler; +use super::socket::{add_socket, remove_socket, pop_data}; +use super::LOSE_NET_STACK; +use super::NET_DEVICE; + +pub struct UDP{ + pub target: IPv4, + pub sport: u16, + pub dport: u16, + pub socket_index: usize +} + +impl UDP { + pub fn new(target: IPv4, sport: u16, dport: u16) -> Self { + let index = add_socket(target, sport, dport).expect("can't add socket"); + + Self { + target, + sport, + dport, + socket_index: index + } + } +} + +impl File for UDP { + fn readable(&self) -> bool { + true + } + + fn writable(&self) -> bool { + true + } + + fn read(&self, mut buf: crate::mm::UserBuffer) -> usize { + loop { + if let Some(data) = pop_data(self.socket_index) { + let data_len = data.len(); + let mut left = 0; + for i in 0..buf.buffers.len() { + let buffer_i_len = buf.buffers[i].len().min(data_len - left); + + buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]); + + left += buffer_i_len; + if left == data_len { + break; + } + } + return left; + } else { + net_interrupt_handler(); + } + } + } + + fn write(&self, buf: crate::mm::UserBuffer) -> usize { + let lose_net_stack = LOSE_NET_STACK.0.exclusive_access(); + + let mut data = vec![0u8; buf.len()]; + + let mut left = 0; + for i in 0..buf.buffers.len() { + data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]); + left += buf.buffers[i].len(); + } + + let len = data.len(); + + let udp_packet = UDPPacket::new( + lose_net_stack.ip, + lose_net_stack.mac, + self.sport, + self.target, + MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), + self.dport, + len, + data.as_ref() + ); + NET_DEVICE.transmit(&udp_packet.build_data()); + len + } +} + +impl Drop for UDP { + fn drop(&mut self) { + remove_socket(self.socket_index) + } +} \ No newline at end of file diff --git a/os/src/riscvregs.rs b/os/src/riscvregs.rs new file mode 100644 index 00000000..18712422 --- /dev/null +++ b/os/src/riscvregs.rs @@ -0,0 +1,614 @@ +// RISC-V registers +pub mod registers { + // hart (core) id registers + pub mod mhartid { + use core::arch::asm; + + #[inline] + pub fn read() -> usize { + let id: usize; + unsafe { + asm!("csrr {}, mhartid", out(reg) id); + } + id + } + } + + // Machine Status Register, mstatus + pub mod mstatus { + use core::arch::asm; + + // Machine Status Register bit + const MPP_MASK: usize = 3 << 11; + const MIE: usize = 1 << 3; + + // Machine Previous Privilege mode + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum MPP { + Machine = 3, + Supervisor = 1, + User = 0, + } + + #[inline] + unsafe fn _read() -> usize { + let bits: usize; + asm!("csrr {}, mstatus", out(reg) bits); + bits + } + + #[inline] + unsafe fn _write(bits: usize) { + asm!("csrw mstatus, {}", in(reg) bits); + } + + // Machine Previous Privilege Mode + #[inline] + pub fn set_mpp(mpp: MPP) { + unsafe { + let mut value = _read(); + value &= !MPP_MASK; + value |= (mpp as usize) << 11; + _write(value); + } + } + + #[inline] + pub fn set_mie() { + unsafe { + asm!("csrs mstatus, {}", in(reg) MIE); + } + } + } + + // machine exception program counter, holds the + // instruction address to which a return from + // exception will go. + pub mod mepc { + use core::arch::asm; + + #[inline] + pub fn write(x: usize) { + unsafe { + asm!("csrw mepc, {}", in(reg) x); + } + } + } + + // Supervisor Status Register, sstatus + pub mod sstatus { + use core::arch::asm; + + // Supervisor Status Register bit + const SPP: usize = 1 << 8; // Previous mode, 1=Supervisor, 0=user + const SPIE: usize = 1 << 5; // Supervisor Previous Interrupt Enable + const SIE: usize = 1 << 1; // Supervisor Interrupt Enable + + #[derive(Clone, Copy, Debug)] + pub struct Sstatus { + bits: usize, + } + + impl Sstatus { + // Supervisor Interrupt Enable + #[inline] + pub(in crate::riscvregs) fn sie(&self) -> bool { + self.bits & SIE != 0 + } + + // Supervisor Previous Privilege mode + #[inline] + pub fn spp(&self) -> SPP { + match self.bits & SPP { + 0 => SPP::User, + _ => SPP::Supervisor, + } + } + + // restore status bits + #[inline] + pub fn restore(&self) { + unsafe { + _write(self.bits); + } + } + } + + // Supervisor Previous Privilege Mode + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum SPP { + Supervisor = 1, + User = 0, + } + + #[inline] + pub fn read() -> Sstatus { + let bits: usize; + unsafe { asm!("csrr {}, sstatus", out(reg) bits) } + Sstatus { bits } + } + + #[inline] + unsafe fn _write(bits: usize) { + asm!("csrw sstatus, {}", in(reg) bits); + } + + // bit set + #[inline] + unsafe fn _set(bits: usize) { + asm!("csrs sstatus, {}", in(reg) bits); + } + + // bit clear + #[inline] + unsafe fn _clear(bits: usize) { + asm!("csrc sstatus, {}", in(reg) bits); + } + + #[inline] + pub(in crate::riscvregs) unsafe fn set_sie() { + _set(SIE) + } + + #[inline] + pub(in crate::riscvregs) unsafe fn clear_sie() { + _clear(SIE) + } + + #[inline] + pub unsafe fn set_spie() { + _set(SPIE); + } + + #[inline] + pub unsafe fn set_spp(spp: SPP) { + match spp { + SPP::Supervisor => _set(SPP), + SPP::User => _clear(SPP), + } + } + } + + // Supervisor Interrupt Pending + pub mod sip { + use core::arch::asm; + + const SSIP: usize = 1 << 1; + + // Supervisor Software Interrupt Pending + #[inline] + pub unsafe fn clear_ssoft() { + asm!("csrc sip, {}", in(reg) SSIP); + } + } + + // Supervisor Interrupt Enable + pub mod sie { + use core::arch::asm; + + const SEIE: usize = 1 << 9; // external + const STIE: usize = 1 << 5; // timer + const SSIE: usize = 1 << 1; // software + + #[inline] + unsafe fn _set(bits: usize) { + asm!("csrs sie, {}", in(reg) bits); + } + + #[inline] + pub unsafe fn set_sext() { + _set(SEIE); + } + + #[inline] + pub unsafe fn set_stimer() { + _set(STIE); + } + + #[inline] + pub unsafe fn set_ssoft() { + _set(SSIE); + } + } + + // Machine-mode Interrupt Enable + pub mod mie { + use core::arch::asm; + + const MTIE: usize = 1 << 7; + + #[inline] + pub unsafe fn set_mtimer() { + asm!("csrs mie, {}", in(reg) MTIE); + } + } + + // supervisor exceptions program counter, holds the + // instruction address to which a return from + // exception will go. + pub mod sepc { + use core::arch::asm; + + #[inline] + pub fn read() -> usize { + let bits: usize; + unsafe { + asm!("csrr {}, sepc", out(reg) bits); + } + bits + } + + #[inline] + pub fn write(bits: usize) { + unsafe { + asm!("csrw sepc, {}", in(reg) bits); + } + } + } + + // Machine Exception Delegation + pub mod medeleg { + use core::arch::asm; + + pub unsafe fn set_all() { + asm!("csrw medeleg, {}", in(reg) 0xffff); + } + } + + // Machine Interrupt Delegation + pub mod mideleg { + use core::arch::asm; + + #[inline] + pub unsafe fn set_all() { + asm!("csrw mideleg, {}", in(reg) 0xffff); + } + } + + // Supervisor Trap-Vector Base Address + // low two bits are mode. + pub mod stvec { + pub use super::mtvec::TrapMode; + use core::arch::asm; + + #[inline] + pub unsafe fn write(addr: usize, mode: TrapMode) { + asm!("csrw stvec, {}", in(reg) addr + mode as usize); + } + } + + // Machine-mode interrupt vector + pub mod mtvec { + use core::arch::asm; + + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum TrapMode { + Direct = 0, + Vectored = 1, + } + + #[inline] + pub unsafe fn write(addr: usize, mode: TrapMode) { + asm!("csrw mtvec, {}", in(reg) addr + mode as usize); + } + } + + // Physical Memory Protection Configuration + pub mod pmpcfg0 { + use core::arch::asm; + + // Permission enum contains all possible permission modes for pmp registers + #[derive(Clone, Copy, Debug)] + pub enum Permission { + NONE = 0b000, + R = 0b001, + W = 0b010, + RW = 0b011, + X = 0b100, + RX = 0b101, + WX = 0b110, + RWX = 0b111, + } + + // Range enum contains all possible addressing modes for pmp registers + pub enum Range { + OFF = 0b00, + TOR = 0b01, + NA4 = 0b10, + NAPOT = 0b11, + } + + // Set the pmp configuration corresponging to the index + #[inline] + pub unsafe fn set_pmp(index: usize, range: Range, permission: Permission, locked: bool) { + assert!(index < 8); + let mut value = _read(); + let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize); + value |= byte << (8 * index); + _write(value); + } + + #[inline] + unsafe fn _read() -> usize { + let bits: usize; + asm!("csrr {}, pmpcfg0", out(reg) bits); + bits + } + + #[inline] + unsafe fn _write(bits: usize) { + asm!("csrw pmpcfg0, {}", in(reg) bits); + } + } + + // Physical memory protection address register + pub mod pmpaddr0 { + use core::arch::asm; + + pub fn write(bits: usize) { + unsafe { + asm!("csrw pmpaddr0, {}", in(reg) bits); + } + } + } + + // Supervisor address translation and protection; + // holds the address of the page table. + pub mod satp { + use core::arch::asm; + + // stap register + #[derive(Clone, Copy, Debug)] + pub struct Satp { + bits: usize, + } + + // 64-bit satp mode + pub enum Mode { + // No translation or protection + Bare = 0, + // Page-based 39-bit virtual addressing + Sv39 = 8, + // Page-based 48-bit virtual addressing + Sv48 = 9, + // Page-based 57-bit virtual addressing + Sv57 = 10, + // Page-based 64-bit virtual addressing + Sv64 = 11, + } + + impl Satp { + // Return the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + } + + #[inline] + pub unsafe fn read() -> Satp { + let bits: usize; + asm!("csrr {}, satp", out(reg) bits); + Satp { bits } + } + + #[inline] + pub unsafe fn write(bits: usize) { + asm!("csrw satp, {}", in(reg) bits); + } + + #[inline] + pub fn make(mode: Mode, asid: usize, ppn: usize) -> usize { + let mut bits: usize = 0; + bits |= (mode as usize) << 60; + bits |= asid << 44; + bits |= ppn >> 12; + bits + } + } + + // mscratch register + pub mod mscratch { + use core::arch::asm; + + #[inline] + pub fn write(bits: usize) { + unsafe { + asm!("csrw mscratch, {}", in(reg) bits); + } + } + } + + // Supervisor Trap Cause + pub mod scause { + use core::{arch::asm, mem::size_of}; + + // scause register + #[derive(Clone, Copy)] + pub struct Scause { + bits: usize, + } + + // Trap Cause + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum Trap { + Interrupt(Interrupt), + Exception(Exception), + } + + // Interrupt + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum Interrupt { + UserSoft, + SupervisorSoft, + UserTimer, + SupervisorTimer, + UserExternal, + SupervisorExternal, + Unknown, + } + + // Exception + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum Exception { + InstructionMisaligned, + InstructionFault, + IllegalInstruction, + Breakpoint, + LoadFault, + StoreMisaligned, + StoreFault, + UserEnvCall, + InstructionPageFault, + LoadPageFault, + StorePageFault, + Unknown, + } + + impl Interrupt { + #[inline] + pub fn from(nr: usize) -> Self { + match nr { + 0 => Interrupt::UserSoft, + 1 => Interrupt::SupervisorSoft, + 4 => Interrupt::UserTimer, + 5 => Interrupt::SupervisorTimer, + 8 => Interrupt::UserExternal, + 9 => Interrupt::SupervisorExternal, + _ => Interrupt::Unknown, + } + } + } + + impl Exception { + #[inline] + pub fn from(nr: usize) -> Self { + match nr { + 0 => Exception::InstructionMisaligned, + 1 => Exception::InstructionFault, + 2 => Exception::IllegalInstruction, + 3 => Exception::Breakpoint, + 5 => Exception::LoadFault, + 6 => Exception::StoreMisaligned, + 7 => Exception::StoreFault, + 8 => Exception::UserEnvCall, + 12 => Exception::InstructionPageFault, + 13 => Exception::LoadPageFault, + 15 => Exception::StorePageFault, + _ => Exception::Unknown, + } + } + } + + impl Scause { + // Returns the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + + // Returns the code field + #[inline] + pub fn code(&self) -> usize { + let bit = 1 << (size_of::() * 8 - 1); + self.bits & !bit + } + + // Trap cause + #[inline] + pub fn cause(&self) -> Trap { + if self.is_interrupt() { + Trap::Interrupt(Interrupt::from(self.code())) + } else { + Trap::Exception(Exception::from(self.code())) + } + } + + // Is trap cause an interrupt. + #[inline] + pub fn is_interrupt(&self) -> bool { + self.bits & (1 << (size_of::() * 8 - 1)) != 0 + } + + // Is trap cause an exception. + #[inline] + pub fn is_exception(&self) -> bool { + !self.is_interrupt() + } + } + + #[inline] + pub fn read() -> Scause { + let bits: usize; + unsafe { + asm!("csrr {}, scause", out(reg) bits); + } + Scause { bits } + } + } + + // Supervisor Trap Value + pub mod stval { + use core::arch::asm; + + #[inline] + pub fn read() -> usize { + let bits: usize; + unsafe { asm!("csrr {}, stval", out(reg) bits) } + bits + } + } +} + +use core::arch::asm; + +use registers::*; + +// enable device interrupts +#[inline] +pub fn intr_on() { + unsafe { + sstatus::set_sie(); + } +} + +// disable device interrupts +#[inline] +pub fn intr_off() { + unsafe { + sstatus::clear_sie(); + } +} + +// are device interrupts enabled? +#[inline] +pub fn intr_get() -> bool { + sstatus::read().sie() +} + +// flush the TLB. +#[inline] +pub unsafe fn sfence_vma() { + // the zero, zero means flush all TLB entries + asm!("sfence.vma zero, zero"); +} + +pub const PGSIZE: usize = 4096; // bytes per page +pub const PGSHIFT: usize = 12; // bits of offset within a page + +pub const fn pgroundup(sz: usize) -> usize { + (sz + PGSIZE - 1) & !(PGSIZE - 1) +} + +pub const fn pgrounddown(sz: usize) -> usize { + sz & !(PGSIZE - 1) +} + +// PTE flags +pub mod pteflags { + pub const PTE_V: usize = 1 << 0; // valid + pub const PTE_R: usize = 1 << 1; + pub const PTE_W: usize = 1 << 2; + pub const PTE_X: usize = 1 << 3; + pub const PTE_U: usize = 1 << 4; // user can access +} diff --git a/os/src/start.rs b/os/src/start.rs new file mode 100644 index 00000000..3a6d3912 --- /dev/null +++ b/os/src/start.rs @@ -0,0 +1,86 @@ +//use crate::kernelvec::*; +//use crate::memlayout::*; +//use crate::param::NCPU; +//use super::main::*; +//use crate::riscv::registers::{pmpcfg0::*, *}; +use core::arch::asm; +use core::hint::unreachable_unchecked; + +mod riscv; + +#[repr(C, align(16))] +struct Stack([u8; 4096 * 4 * NCPU]); + +#[no_mangle] +static mut STACK0: Stack = Stack([0; 4096 * 4 * NCPU]); + +#[no_mangle] +pub unsafe fn rust_start() -> ! { + // set MPP mode to Supervisor, for mret + mstatus::set_mpp(mstatus::MPP::Supervisor); + + // set MEPC to main, for mret + mepc::write(rust_main as usize); + + // disable paging for now. + satp::write(0); + + // delegate all interrupts and exceptions to supervisor mode. + medeleg::set_all(); + mideleg::set_all(); + sie::set_sext(); + sie::set_ssoft(); + sie::set_stimer(); + + // configure Physical Memory Protection to give supervisor mode + // access to all of physical memory. + pmpaddr0::write(0x3fffffffffffff); + pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 + + // ask for clock interrupts. + timerinit(); + + // keep each CPU's hartid in its tp register, for cpuid(). + let id = mhartid::read(); + asm!("mv tp, {0}", in(reg) id); + + // switch to supervisor mode and jump to main(). + asm!("mret"); + + extern "C" { + fn rust_main() -> !; + } + unreachable_unchecked(); +} + +// a scratch area per CPU for machine-mode timer interrupts. +static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1]; + +unsafe fn timerinit() { + // each CPU has a separate source of timer interrupts + let id = mhartid::read(); + + // ask the CLINT for a timer interrupts + let interval = 1000000u64; // cycles; about 1/10th second in qemu. + let mtimecmp = clint_mtimecmp(id) as *mut u64; + let mtime = CLINT_MTIME as *const u64; + mtimecmp.write_volatile(mtime.read_volatile() + interval); + + // prepare information in scratch[] for timervec. + // scratch[0..2] : space for timervec to save registers. + // scratch[3] : address of CLINT MTIMECMP register. + // scratch[4] : desired interval (in cycles) between timer interrupts. + let scratch = &mut TIMER_SCRATCH[id]; + scratch[3] = mtimecmp as u64; + scratch[4] = interval; + mscratch::write(scratch.as_mut_ptr() as usize); + + // set the machine-mode trap handler + mtvec::write(timervec as usize, mtvec::TrapMode::Direct); + + // enable machine-mode interrupts. + mstatus::set_mie(); + + // enable machime-mode timer interrupts. + mie::set_mtimer(); +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 4052cf53..a336a96f 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -36,6 +37,7 @@ mod input; mod process; mod sync; mod thread; +mod net; use fs::*; use gui::*; @@ -43,10 +45,12 @@ use input::*; use process::*; use sync::*; use thread::*; +use net::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { SYSCALL_DUP => sys_dup(args[0]), + SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), diff --git a/os/src/syscall/net.rs b/os/src/syscall/net.rs new file mode 100644 index 00000000..4ed4466d --- /dev/null +++ b/os/src/syscall/net.rs @@ -0,0 +1,14 @@ +use alloc::sync::Arc; +use crate::net::IPv4; +use crate::net::udp::UDP; +use crate::task::current_process; + +// just support udp +pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize { + let process = current_process(); + let mut inner = process.inner_exclusive_access(); + let fd = inner.alloc_fd(); + let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport); + inner.fd_table[fd] = Some(Arc::new(udp_node)); + fd as isize +} \ No newline at end of file diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index cb4a7add..6040c7fa 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -11,7 +11,7 @@ use core::arch::{asm, global_asm}; use riscv::register::{ mtvec::TrapMode, scause::{self, Exception, Interrupt, Trap}, - sie, sscratch, sstatus, stval, stvec, + sie, sscratch, sstatus, stval, stvec,sip }; global_asm!(include_str!("trap.S")); @@ -95,10 +95,20 @@ pub fn trap_handler() -> ! { Trap::Exception(Exception::IllegalInstruction) => { current_add_signal(SignalFlags::SIGILL); } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - set_next_trigger(); + // Trap::Interrupt(Interrupt::SupervisorTimer) => { + // set_next_trigger(); + // check_timer(); + // suspend_current_and_run_next(); + // } + Trap::Interrupt(Interrupt::SupervisorSoft) => { + //set_next_trigger(); + const SSIP: usize = 1 << 1; + unsafe { + asm!("csrc sip, {}", in(reg) SSIP); + } + //println!("TRAP: ssoft in Kern"); check_timer(); - suspend_current_and_run_next(); + // do not schedule now } Trap::Interrupt(Interrupt::SupervisorExternal) => { crate::board::irq_handler(); @@ -151,8 +161,18 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) { Trap::Interrupt(Interrupt::SupervisorExternal) => { crate::board::irq_handler(); } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - set_next_trigger(); + // Trap::Interrupt(Interrupt::SupervisorTimer) => { + // //set_next_trigger(); + // check_timer(); + // // do not schedule now + // } + Trap::Interrupt(Interrupt::SupervisorSoft) => { + //set_next_trigger(); + const SSIP: usize = 1 << 1; + unsafe { + asm!("csrc sip, {}", in(reg) SSIP); + } + //println!("TRAP: ssoft in Kern"); check_timer(); // do not schedule now } diff --git a/ping.py b/ping.py new file mode 100644 index 00000000..c68fc71d --- /dev/null +++ b/ping.py @@ -0,0 +1,18 @@ +import socket +import sys +import time + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +addr = ('localhost', 26099) +sock.bind(addr) + + +print("pinging...", file=sys.stderr) +while True: + buf, raddr = sock.recvfrom(4096) + print("receive: " + buf.decode("utf-8")) + buf = "this is a ping to port 6200!".encode('utf-8') + sock.sendto(buf, ("127.0.0.1", 6200)) + buf = "this is a ping to reply!".encode('utf-8') + sock.sendto(buf, raddr) + time.sleep(1) diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs new file mode 100644 index 00000000..dda60059 --- /dev/null +++ b/user/src/bin/udp.rs @@ -0,0 +1,45 @@ +#![no_std] +#![no_main] + +use alloc::string::String; +use user_lib::{connect, write, read}; + +#[macro_use] +extern crate user_lib; +#[macro_use] +extern crate alloc; + +#[no_mangle] +pub fn main() -> i32 { + println!("udp test open!"); + + let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099); + + if udp_fd < 0 { + println!("failed to create udp connection."); + return -1; + } + + let buf = "Hello rCoreOS user program!"; + + println!("send <{}>", buf); + + write(udp_fd as usize, buf.as_bytes()); + + println!("udp send done, waiting for reply."); + + let mut buf = vec![0u8; 1024]; + + let len = read(udp_fd as usize, &mut buf); + + if len < 0 { + println!("can't receive udp packet"); + return -1; + } + + let recv_str = String::from_utf8_lossy(&buf[..len as usize]); + + println!("receive reply <{}>", recv_str); + + 0 +} \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 87885f53..c5fb48dc 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -48,6 +49,10 @@ pub fn sys_dup(fd: usize) -> isize { syscall(SYSCALL_DUP, [fd, 0, 0]) } +pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize { + syscall(SYSCALL_CONNECT, [dest as usize, sport as usize, dport as usize]) +} + pub fn sys_open(path: &str, flags: u32) -> isize { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) } diff --git a/user/src/task.rs b/user/src/task.rs index 87d0ddaf..1f60e039 100644 --- a/user/src/task.rs +++ b/user/src/task.rs @@ -18,6 +18,9 @@ pub fn fork() -> isize { pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } +pub fn connect(raddr: u32, lport: u16, rport: u16) -> isize { + sys_connect(raddr, lport, rport) +} pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) {