Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5e2d7e1
Refactor traps module: centralize constants, remove duplicates, decou…
Yash-Rawat-IIT-D Feb 15, 2026
416b5f3
Updated TickCounter struct to pub
Yash-Rawat-IIT-D Feb 15, 2026
7066535
Cherrypicked Improvements from p3-pic
Yash-Rawat-IIT-D Mar 1, 2026
cf5aed9
Refleted panic changes of p3-pic
Yash-Rawat-IIT-D Mar 1, 2026
9d6fa5a
Fixed Scope Issues
Yash-Rawat-IIT-D Mar 1, 2026
09daea8
p5: add UART interrupt and console input support
ArinjaySinghal19 Feb 16, 2026
c31ec4a
Updated console::consputc function call API
Yash-Rawat-IIT-D Mar 2, 2026
e21d58f
Updated project level config.toml
Yash-Rawat-IIT-D Mar 2, 2026
09318fb
Accumulated older changes
Yash-Rawat-IIT-D Mar 2, 2026
b6642c8
Fixed static mutable warnings
Yash-Rawat-IIT-D Mar 2, 2026
ac785d1
p6: Fixed iderw to use interrupt-driven design
Yash-Rawat-IIT-D Mar 2, 2026
4feb566
Updated port exit status
Yash-Rawat-IIT-D Mar 2, 2026
30e13e2
Updated bootblock.ld
Yash-Rawat-IIT-D Mar 3, 2026
f8ccfd5
Updated bootblock.ld
Yash-Rawat-IIT-D Mar 3, 2026
375bdf6
p5: add UART interrupt and console input support
ArinjaySinghal19 Feb 16, 2026
f842518
Accumulated older changes
Yash-Rawat-IIT-D Mar 2, 2026
8ad812b
Fixed static mutable warnings
Yash-Rawat-IIT-D Mar 2, 2026
dc7eb6e
Fixed rebase duplication bugs
Yash-Rawat-IIT-D Mar 3, 2026
9fd14db
Merge history onto p5-input
Yash-Rawat-IIT-D Mar 3, 2026
7d3d6dc
Minor bug fixes in traps
Yash-Rawat-IIT-D Mar 3, 2026
3c1c7a4
Updated .S to remove ld GNU-stack warnings
Yash-Rawat-IIT-D Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[build]
target = "targets/i686.json"

[unstable]
build-std = ["core"]
build-std-features = ["compiler-builtins-mem"]
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "xv6"
version = "0.1.0"
edition = "2021"
autobins = false

[lib]
name = "kernel"
Expand Down
39 changes: 12 additions & 27 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,31 @@ TOOLPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/d
then echo ''; \
else echo "***" 1>&2; \
echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \
echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \
echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \
echo "*** prefix other than 'i386-jos-elf-', set your TOOLPREFIX" 1>&2; \
echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \
echo "***" 1>&2; exit 1; fi)
exit 1; fi)
endif

# If the makefile can't find QEMU, specify its path here
# QEMU = qemu-system-i386

# Try to infer the correct QEMU
ifndef QEMU
QEMU = $(shell if which qemu > /dev/null; \
then echo qemu; exit; \
elif which qemu-system-i386 > /dev/null; \
then echo qemu-system-i386; exit; \
elif which qemu-system-x86_64 > /dev/null; \
then echo qemu-system-x86_64; exit; \
else \
qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \
if test -x $$qemu; then echo $$qemu; exit; fi; fi; \
echo "***" 1>&2; \
echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
echo "*** or have you tried setting the QEMU variable in Makefile?" 1>&2; \
echo "***" 1>&2; exit 1)
else echo "*** Error: Couldn't find QEMU." 1>&2; exit 1; fi)
endif

CC = $(TOOLPREFIX)gcc
AS = $(TOOLPREFIX)gas
LD = $(TOOLPREFIX)ld
OBJCOPY = $(TOOLPREFIX)objcopy
OBJDUMP = $(TOOLPREFIX)objdump

CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)

ASFLAGS = -m32 -gdwarf-2 -Wa,-divide
LDFLAGS += -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1)

# Disable PIE when possible (for Ubuntu 16.10 toolchain)
ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
CFLAGS += -fno-pie -no-pie
endif
Expand All @@ -76,13 +61,12 @@ fs.img: welcome.txt
dd if=/dev/zero of=fs.img count=2
dd if=welcome.txt of=fs.img conv=notrunc

bootblock: bootasm.S bootmain.c
bootblock: bootasm.S bootmain.c linkers/bootblock.ld
$(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c
$(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S
$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
$(OBJDUMP) -S -D bootblock.o > bootblock.asm
$(OBJCOPY) -S -O binary -j .text bootblock.o bootblock
./sign.pl bootblock
$(LD) $(LDFLAGS) -T linkers/bootblock.ld -o bootblock.o bootasm.o bootmain.o
$(OBJDUMP) -S bootblock.o > bootblock.asm
$(OBJCOPY) -S -O binary bootblock.o bootblock

kernel.a: $(RS)
cargo build -Z build-std=core -Z build-std-features=compiler-builtins-mem -Z json-target-spec \
Expand All @@ -94,7 +78,7 @@ kernel.a: $(RS)


kernel: kernel.a $(OBJS) ./linkers/kernel.ld
ld -m elf_i386 -T ./linkers/kernel.ld -o kernel $(OBJS) kernel.a
$(LD) -m elf_i386 -T ./linkers/kernel.ld -o kernel $(OBJS) kernel.a
$(OBJDUMP) -S -D kernel > kernel.asm
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym

Expand All @@ -114,8 +98,9 @@ GDBPORT = $(shell expr `id -u` % 5000 + 25000)
QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
then echo "-gdb tcp::$(GDBPORT)"; \
else echo "-s -p $(GDBPORT)"; fi)

ifndef CPUS
CPUS := 1
CPUS := 1
endif

# Attach fs.img as disk1 (index=1), like the C version
Expand All @@ -131,4 +116,4 @@ qemu: xv6.img fs.img

qemu-gdb: xv6.img fs .gdbinit
@echo "*** Now run 'gdb'." 1>&2
$(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB)
$(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB)
4 changes: 3 additions & 1 deletion bootasm.S
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ gdt:

gdtdesc:
.word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
.long gdt # address gdt
.long gdt # address gdt

.section .note.GNU-stack,"",@progbits
3 changes: 3 additions & 0 deletions entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ entry:
call entryofrust

.comm stack, KSTACKSIZE

# Add .note.GNU-stack section for non-executable stack marking
.section .note.GNU-stack,"",@progbits
29 changes: 29 additions & 0 deletions linkers/bootblock.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(start)

SECTIONS
{
. = 0x7c00;

.text : {
*(.text .text.*)
}

.rodata : {
*(.rodata .rodata.*)
}

.data : {
*(.data .data.*)
}

/DISCARD/ : {
*(.eh_frame .note.GNU-stack .comment)
}

. = 0x7c00 + 510;
.signature : {
SHORT(0xaa55)
}
}
1 change: 1 addition & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[toolchain]
channel = "nightly"
components = ["rust-src"]
72 changes: 66 additions & 6 deletions src/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,80 @@ pub struct Console {}
impl Write for Console {
fn write_str(&mut self, s: &str) -> Result {
for c in s.chars() {
consputc(c);
consputc(c as i32);
}
Ok(())
}
}

const BACKSPACE: char = '\x08';
const BACKSPACE: i32 = 0x100;
const INPUT_BUF: usize = 128;
const CTRL_D: i32 = C('D');

pub fn consputc(c: char) {
#[allow(non_snake_case)]
const fn C(c: char) -> i32 {
(c as i32) - ('@' as i32)
}

#[derive(Clone, Copy)]
struct Input {
buf: [u8; INPUT_BUF],
r: usize,
w: usize,
e: usize,
}

static mut INPUT: Input = Input {
buf: [0; INPUT_BUF],
r: 0,
w: 0,
e: 0,
};

pub fn consputc(c: i32) {
if c == BACKSPACE {
uartputc(BACKSPACE);
uartputc(' ');
uartputc(BACKSPACE);
uartputc('\x08' as i32);
uartputc(' ' as i32);
uartputc('\x08' as i32);
} else {
uartputc(c);
}
}

pub fn consoleintr(getc: fn() -> i32) {
loop {
let c = getc();
if c < 0 {
break;
}

unsafe {
let input = &raw mut INPUT;
match c {
x if x == C('U') => {
while (*input).e != (*input).w && (*input).buf[((*input).e - 1) % INPUT_BUF] != b'\n' {
(*input).e -= 1;
consputc(BACKSPACE);
}
}
x if x == C('H') || x == 0x7f => {
if (*input).e != (*input).w {
(*input).e -= 1;
consputc(BACKSPACE);
}
}
_ => {
if c != 0 && (*input).e.wrapping_sub((*input).r) < INPUT_BUF {
let c = if c == '\r' as i32 { '\n' as i32 } else { c };
(*input).buf[(*input).e % INPUT_BUF] = c as u8;
(*input).e += 1;
consputc(c);
if c == '\n' as i32 || c == CTRL_D || (*input).e == (*input).r + INPUT_BUF {
(*input).w = (*input).e;
}
}
}
}
}
}
}
40 changes: 25 additions & 15 deletions src/ide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ pub fn ideintr() {
}
}

// ide.rs
// Sync buf with disk.
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
// Else if B_VALID is not set, read buf from disk, set B_VALID.
pub fn iderw(idx: usize) {
let b = crate::bio::buf_mut(idx);

Expand All @@ -148,23 +150,31 @@ pub fn iderw(idx: usize) {
}
}

// PURE POLLING: issue the command directly (no IDEQUEUE).
idestart(idx);

// Wait for completion.
if idewait(true) < 0 {
panic!("iderw: ide error");
// Append b to idequeue.
b.qnext = None;
unsafe {
let mut pp: *mut Option<usize> = &raw mut IDEQUEUE;
while let Some(next_idx) = *pp {
pp = &raw mut crate::bio::buf_mut(next_idx).qnext;
}
*pp = Some(idx);
}

// If it was a read, pull data now.
let flags_now = b.flags.load(Ordering::Acquire);
if (flags_now & B_DIRTY) == 0 {
unsafe {
crate::x86::insl(0x1F0, b.data.as_mut_ptr() as *mut u32, BSIZE / 4);
// Start disk if necessary.
unsafe {
if IDEQUEUE == Some(idx) {
idestart(idx);
}
}
// If it was a write, data was already pushed in idestart() via outsl().

b.flags.fetch_or(B_VALID, Ordering::AcqRel);
b.flags.fetch_and(!B_DIRTY, Ordering::AcqRel);
// Wait for request to finish.
// The interrupt handler will set B_VALID when done.
loop {
let flags = b.flags.load(Ordering::Acquire);
if (flags & (B_VALID | B_DIRTY)) == B_VALID {
break;
}
// Force compiler to re-read b->flags which is modified by ideintr()
x86::noop();
}
}
10 changes: 5 additions & 5 deletions src/ioapic.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::ptr::{read_volatile, write_volatile};
use crate::mp::MP_ONCE;
use crate::console::Console;
use core::fmt::Write;
// use crate::console::Console;
// use core::fmt::Write;
use crate::println;

// I/O APIC default physical address
Expand All @@ -14,9 +14,9 @@ const REG_TABLE: u32 = 0x10; // Redirection table base (0x10 / 4)

// Redirection table configuration bits
const INT_DISABLED: u32 = 0x00010000; // Interrupt disabled
const INT_LEVEL: u32 = 0x00008000; // Level-triggered
const INT_ACTIVELOW: u32 = 0x00002000; // Active low
const INT_LOGICAL: u32 = 0x00000800; // Destination is CPU ID
// const INT_LEVEL: u32 = 0x00008000; // Unused in p3 - Level-triggered
// const INT_ACTIVELOW: u32 = 0x00002000; // Unused in p3 - Active low
// const INT_LOGICAL: u32 = 0x00000800; // Unused in p3 - Destination is CPU ID

pub const T_IRQ0: u32 = 32;

Expand Down
16 changes: 8 additions & 8 deletions src/lapic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::ptr::{read_volatile, write_volatile};
use crate::mp::MP_ONCE;
use crate::traps::{T_IRQ0, IRQ_TIMER, IRQ_SPURIOUS, IRQ_ERROR};
use crate::constants::{IRQ_ERROR, IRQ_SPURIOUS, IRQ_TIMER, T_IRQ0};

const ID: isize = 0x0020 / 4;
const VER: isize = 0x0030 / 4;
Expand All @@ -14,14 +14,14 @@ const ESR: isize = 0x0280 / 4;
const ICRLO: isize = 0x0300 / 4;

const INIT: u32 = 0x00000500;
const STARTUP: u32 = 0x00000600;
// const STARTUP: u32 = 0x00000600; // Unused in p3 - for AP startup
const DELIVS: u32 = 0x00001000;
const ASSERT: u32 = 0x00004000;
const DEASSERT: u32 = 0x00000000;
// const ASSERT: u32 = 0x00004000; // Unused in p3 - for IPI
// const DEASSERT: u32 = 0x00000000; // Unused in p3 - for IPI
const LEVEL: u32 = 0x00008000;
const BCAST: u32 = 0x00080000;
const BUSY: u32 = 0x00001000;
const FIXED: u32 = 0x00000000;
// const BUSY: u32 = 0x00001000; // Unused in p3
// const FIXED: u32 = 0x00000000; // Unused in p3

const ICRHI: isize = 0x0310 / 4;
const TIMER: isize = 0x0320 / 4;
Expand All @@ -35,7 +35,7 @@ const ERROR: isize = 0x0370 / 4;
const MASKED: u32 = 0x00010000;

const TICR: isize = 0x0380 / 4;
const TCCR: isize = 0x0390 / 4;
// const TCCR: isize = 0x0390 / 4; // Unused in p3 - timer current count
const TDCR: isize = 0x03E0 / 4;

// Volatile write to LAPIC
Expand Down Expand Up @@ -70,7 +70,7 @@ pub fn lapicinit() {
// TICR would be calibrated using an external time source.
lapicw(TDCR, X1);
lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
lapicw(TICR, 1000000000);
lapicw(TICR, 10000000);


// Disable logical interrupt lines.
Expand Down
Loading