mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-23 18:06:20 +04:00
Added comments and removed llvm_asm -- it looks like I'll have to use this in the future
This commit is contained in:
parent
018faea21e
commit
d86c65a380
@ -4,7 +4,6 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
#![feature(panic_info_message,
|
||||
llvm_asm,
|
||||
asm,
|
||||
global_asm,
|
||||
allocator_api,
|
||||
@ -124,6 +123,10 @@ extern "C" {
|
||||
fn switch_to_user(frame: usize) -> !;
|
||||
}
|
||||
|
||||
/// Switch to user is an assembly function that loads
|
||||
/// a frame. Since it will jump to another program counter,
|
||||
/// it will never return back here. We don't care if we leak
|
||||
/// the stack, since we will recapture the stack during m_trap.
|
||||
fn rust_switch_to_user(frame: usize) -> ! {
|
||||
unsafe {
|
||||
switch_to_user(frame);
|
||||
|
@ -184,6 +184,10 @@ impl FileSystem for MinixFileSystem {
|
||||
size
|
||||
};
|
||||
let mut bytes_read = 0u32;
|
||||
// The block buffer automatically drops when we quit early due to an error or we've read enough.
|
||||
// This will be the holding port when we go out and read a block. Recall that even if we want
|
||||
// 10 bytes, we have to read the entire block (really only 512 bytes of the block) first.
|
||||
// So, we use the block_buffer as the middle man, which is then copied into the buffer.
|
||||
let mut block_buffer = BlockBuffer::new(BLOCK_SIZE);
|
||||
|
||||
// ////////////////////////////////////////////
|
||||
@ -207,24 +211,39 @@ impl FileSystem for MinixFileSystem {
|
||||
// That makes it easy since all we have to do is multiply the block size
|
||||
// by whatever we get. If it's 0, we skip it and move on.
|
||||
let zone_offset = inode.zones[i] * BLOCK_SIZE;
|
||||
// We read the zone, which is where the data is located. The zone offset is simply the block
|
||||
// size times the zone number. This makes it really easy to read!
|
||||
syc_read(desc, block_buffer.get_mut(), BLOCK_SIZE, zone_offset);
|
||||
|
||||
// There's a little bit of math to see how much we need to read. We don't want to read
|
||||
// more than the buffer passed in can handle, and we don't want to read if we haven't
|
||||
// taken care of the offset. For example, an offset of 10000 with a size of 2 means we
|
||||
// can only read bytes 10,000 and 10,001.
|
||||
let read_this_many = if BLOCK_SIZE - offset_byte > bytes_left {
|
||||
bytes_left
|
||||
}
|
||||
else {
|
||||
BLOCK_SIZE - offset_byte
|
||||
};
|
||||
// Once again, here we actually copy the bytes into the final destination, the buffer. This memcpy
|
||||
// is written in cpu.rs.
|
||||
unsafe {
|
||||
memcpy(buffer.add(bytes_read as usize), block_buffer.get().add(offset_byte as usize), read_this_many as usize);
|
||||
}
|
||||
// Regardless of whether we have an offset or not, we reset the offset byte back to 0. This
|
||||
// probably will get set to 0 many times, but who cares?
|
||||
offset_byte = 0;
|
||||
// Reset the statistics to see how many bytes we've read versus how many are left.
|
||||
bytes_read += read_this_many;
|
||||
bytes_left -= read_this_many;
|
||||
// If no more bytes are left, then we're done.
|
||||
if bytes_left == 0 {
|
||||
return bytes_read;
|
||||
}
|
||||
}
|
||||
// The blocks_seen is for the offset. We need to skip a certain number of blocks FIRST before getting
|
||||
// to the offset. The reason we need to read the zones is because we need to skip zones of 0, and they
|
||||
// do not contribute as a "seen" block.
|
||||
blocks_seen += 1;
|
||||
}
|
||||
// ////////////////////////////////////////////
|
||||
@ -238,6 +257,7 @@ impl FileSystem for MinixFileSystem {
|
||||
syc_read(desc, indirect_buffer.get_mut(), BLOCK_SIZE, BLOCK_SIZE * inode.zones[7]);
|
||||
let izones = indirect_buffer.get() as *const u32;
|
||||
for i in 0..num_indirect_pointers {
|
||||
// Where do I put unsafe? Dereferencing the pointers and memcpy are the unsafe functions.
|
||||
unsafe {
|
||||
if izones.add(i).read() != 0 {
|
||||
if offset_block <= blocks_seen {
|
||||
@ -352,6 +372,8 @@ impl FileSystem for MinixFileSystem {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Anyone else love this stairstep style? I probably should put the pointers in a function by themselves,
|
||||
// but I think that'll make it more difficult to see what's actually happening.
|
||||
|
||||
bytes_read
|
||||
}
|
||||
@ -373,10 +395,16 @@ impl FileSystem for MinixFileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn syc_read(desc: &Descriptor, buffer: *mut u8, size: u32, offset: u32) -> u8 {
|
||||
/// This is a wrapper function around the syscall_block_read. This allows me to do
|
||||
/// other things before I call the system call (or after). However, all the things I
|
||||
/// wanted to do are no longer there, so this is a worthless function.
|
||||
fn syc_read(desc: &Descriptor, buffer: *mut u8, size: u32, offset: u32) -> u8 {
|
||||
syscall_block_read(desc.blockdev, buffer, size, offset)
|
||||
}
|
||||
|
||||
// We have to start a process when reading from a file since the block
|
||||
// device will block. We only want to block in a process context, not an
|
||||
// interrupt context.
|
||||
struct ProcArgs {
|
||||
pub pid: u16,
|
||||
pub dev: usize,
|
||||
@ -386,29 +414,42 @@ struct ProcArgs {
|
||||
pub node: u32,
|
||||
}
|
||||
|
||||
// This is the actual code ran inside of the read process.
|
||||
fn read_proc(args_addr: usize) {
|
||||
let args_ptr = args_addr as *mut ProcArgs;
|
||||
let args = unsafe { args_ptr.as_ref().unwrap() };
|
||||
|
||||
// The descriptor will come from the user after an open() call. However,
|
||||
// for now, all we really care about is args.dev, args.node, and args.pid.
|
||||
let desc = Descriptor { blockdev: args.dev,
|
||||
node: args.node,
|
||||
loc: 0,
|
||||
size: 500,
|
||||
pid: args.pid, };
|
||||
|
||||
// Start the read! Since we're in a kernel process, we can block by putting this
|
||||
// process into a waiting state and wait until the block driver returns.
|
||||
let bytes = MinixFileSystem::read(&desc, args.buffer, args.size, args.offset);
|
||||
|
||||
// Let's write the return result into regs[10], which is A0.
|
||||
let ptr = unsafe { get_by_pid(args.pid) };
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
unsafe {
|
||||
let ptr = get_by_pid(args.pid);
|
||||
if !ptr.is_null() {
|
||||
(*(*ptr).get_frame()).regs[10] = bytes as usize;
|
||||
}
|
||||
}
|
||||
// This is the process making the system call. The system itself spawns another process
|
||||
// which goes out to the block device. Since we're passed the read call, we need to awaken
|
||||
// the process and get it ready to go. The only thing this process needs to clean up is the
|
||||
// tfree(), but the user process doesn't care about that.
|
||||
set_running(args.pid);
|
||||
|
||||
// tfree() is used to free a pointer created by talloc.
|
||||
tfree(args_ptr);
|
||||
}
|
||||
|
||||
/// System calls will call process_read, which will spawn off a kernel process to read
|
||||
/// the requested data.
|
||||
pub fn process_read(pid: u16, dev: usize, node: u32, buffer: *mut u8, size: u32, offset: u32) {
|
||||
// println!("FS read {}, {}, 0x{:x}, {}, {}", pid, dev, buffer as usize, size, offset);
|
||||
let args = talloc::<ProcArgs>().unwrap();
|
||||
|
@ -6,19 +6,22 @@
|
||||
use crate::{block::block_op,
|
||||
cpu::TrapFrame,
|
||||
minixfs,
|
||||
process::{delete_process, set_sleeping, set_waiting}};
|
||||
page::{virt_to_phys, Table},
|
||||
process::{delete_process, get_by_pid, set_sleeping, set_waiting}};
|
||||
|
||||
pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
||||
/// do_syscall is called from trap.rs to invoke a system call. No discernment is
|
||||
/// made here whether this is a U-mode, S-mode, or M-mode system call.
|
||||
/// Since we can't do anything unless we dereference the passed pointer,
|
||||
/// I went ahead and made the entire function unsafe.
|
||||
pub unsafe fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
||||
let syscall_number;
|
||||
unsafe {
|
||||
// Libgloss expects the system call number in A7, so let's follow
|
||||
// their lead.
|
||||
// A7 is X17, so it's register number 17.
|
||||
syscall_number = (*frame).regs[17];
|
||||
}
|
||||
// Libgloss expects the system call number in A7, so let's follow
|
||||
// their lead.
|
||||
// A7 is X17, so it's register number 17.
|
||||
syscall_number = (*frame).regs[17];
|
||||
|
||||
match syscall_number {
|
||||
0 | 93 => unsafe {
|
||||
0 | 93 => {
|
||||
// Exit
|
||||
// Currently, we cannot kill a process, it runs forever. We will delete
|
||||
// the process later and free the resources, but for now, we want to get
|
||||
@ -30,30 +33,48 @@ pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
||||
println!("Test syscall");
|
||||
mepc + 4
|
||||
},
|
||||
2 => unsafe {
|
||||
2 => {
|
||||
// Sleep
|
||||
set_sleeping((*frame).pid as u16, (*frame).regs[10]);
|
||||
0
|
||||
},
|
||||
63 => unsafe {
|
||||
63 => {
|
||||
// Read system call
|
||||
// This is an asynchronous call. This will get the process going. We won't hear the answer until
|
||||
// we an interrupt back.
|
||||
// TODO: The buffer is a virtual memory address that needs to be translated to a physical memory
|
||||
// location.
|
||||
// This needs to be put into a process and ran.
|
||||
// The buffer (regs[12]) needs to be translated when ran from a user process using virt_to_phys.
|
||||
// If this turns out to be a page fault, we need to NOT proceed with the read!
|
||||
let mut physical_buffer = (*frame).regs[12];
|
||||
// If the MMU is turned on, we have to translate the address. Eventually, I will put this
|
||||
// code into a convenient function, but for now, it will show how translation will be done.
|
||||
if (*frame).satp != 0 {
|
||||
let p = get_by_pid((*frame).pid as u16);
|
||||
let table = ((*p).get_table_address() as *mut Table).as_ref().unwrap();
|
||||
let paddr = virt_to_phys(table, (*frame).regs[12]);
|
||||
if paddr.is_none() {
|
||||
(*frame).regs[10] = -1isize as usize;
|
||||
return mepc + 4;
|
||||
}
|
||||
physical_buffer = paddr.unwrap();
|
||||
}
|
||||
// TODO: Not only do we need to check the buffer, but it is possible that the buffer spans
|
||||
// multiple pages. We need to check all pages that this might span. We can't just do paddr
|
||||
// and paddr + size, since there could be a missing page somewhere in between.
|
||||
let _ = minixfs::process_read(
|
||||
(*frame).pid as u16,
|
||||
(*frame).regs[10] as usize,
|
||||
(*frame).regs[11] as u32,
|
||||
(*frame).regs[12] as *mut u8,
|
||||
(*frame).regs[13] as u32,
|
||||
(*frame).regs[14] as u32
|
||||
);
|
||||
(*frame).pid as u16,
|
||||
(*frame).regs[10] as usize,
|
||||
(*frame).regs[11] as u32,
|
||||
physical_buffer as *mut u8,
|
||||
(*frame).regs[13] as u32,
|
||||
(*frame).regs[14] as u32,
|
||||
);
|
||||
// If we return 0, the trap handler will schedule another process.
|
||||
0
|
||||
},
|
||||
180 => unsafe {
|
||||
180 => {
|
||||
// println!(
|
||||
// "Pid: {}, Dev: {}, Buffer: 0x{:x}, Size: {}, Offset: {}",
|
||||
// (*frame).pid,
|
||||
@ -63,14 +84,7 @@ pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
||||
// (*frame).regs[13]
|
||||
// );
|
||||
set_waiting((*frame).pid as u16);
|
||||
let _ = block_op((*frame).regs[10],
|
||||
(*frame).regs[11] as *mut u8,
|
||||
(*frame).regs[12] as u32,
|
||||
(*frame).regs[13] as u64,
|
||||
false,
|
||||
(*frame).pid as u16
|
||||
|
||||
);
|
||||
let _ = block_op((*frame).regs[10], (*frame).regs[11] as *mut u8, (*frame).regs[12] as u32, (*frame).regs[13] as u64, false, (*frame).pid as u16);
|
||||
0
|
||||
},
|
||||
_ => {
|
||||
@ -81,17 +95,15 @@ pub fn do_syscall(mepc: usize, frame: *mut TrapFrame) -> usize {
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn make_syscall(sysno: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize;
|
||||
fn make_syscall(sysno: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize;
|
||||
}
|
||||
|
||||
fn do_make_syscall(sysno: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize {
|
||||
unsafe {
|
||||
make_syscall(sysno, arg0, arg1, arg2, arg3, arg4, arg5)
|
||||
}
|
||||
unsafe { make_syscall(sysno, arg0, arg1, arg2, arg3, arg4, arg5) }
|
||||
}
|
||||
|
||||
pub fn syscall_exit() {
|
||||
let _ = do_make_syscall(93, 0, 0, 0, 0, 0, 0);
|
||||
let _ = do_make_syscall(93, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
pub fn syscall_fs_read(dev: usize, inode: u32, buffer: *mut u8, size: u32, offset: u32) -> usize {
|
||||
|
Loading…
Reference in New Issue
Block a user