Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix boot on newer qemu #62

Open
wants to merge 2 commits into
base: riscv
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 16 additions & 2 deletions kernel/kernelvec.S
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ kernelvec:
// return to whatever we were doing in the kernel.
sret

// help: if you hit these, an unexpected exception/interrupt happened in M-mode.
// use `info registers` in the qemu monitor to get the relevant CSRs.
unexpected_exc: j unexpected_exc
unexpected_int: j unexpected_int

#
# machine-mode timer interrupt.
#
Expand All @@ -95,12 +100,21 @@ timervec:
# scratch[0,8,16] : register save area.
# scratch[24] : address of CLINT's MTIMECMP register.
# scratch[32] : desired interval between interrupts.

csrrw a0, mscratch, a0
sd a1, 0(a0)
sd a2, 8(a0)
sd a3, 16(a0)

csrr a1, mcause
// we should not get exceptions in M-mode. if we do, something went
// very wrong and we should explicitly jump to an infinite loop for the
// purpose.
bgez a1, unexpected_exc
li a2, (1<<63 | 7)
// likewise for any interrupts that are not machine timer interrupts.
bne a1, a2, unexpected_int

# schedule the next timer interrupt
# by adding interval to mtimecmp.
ld a1, 24(a0) # CLINT_MTIMECMP(hart)
Expand All @@ -110,7 +124,7 @@ timervec:
sd a3, 0(a1)

# raise a supervisor software interrupt.
li a1, 2
li a1, 2
csrw sip, a1

ld a3, 16(a0)
Expand Down
23 changes: 23 additions & 0 deletions kernel/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,29 @@ w_mepc(uint64 x)
asm volatile("csrw mepc, %0" : : "r" (x));
}

// physical memory protection CSRs
#define PMP_R (1L << 0)
#define PMP_W (1L << 1)
#define PMP_X (1L << 2)
// naturally aligned power of two
#define PMP_MATCH_NAPOT (3L << 3)

// we only implement accessing one PMP register

// write to the first 8 PMP configuration registers
static inline void
w_pmpcfg0(uint64 x)
{
asm volatile("csrw pmpcfg0, %0" : : "r" (x));
}

// write to the address for PMP region 0
static inline void
w_pmpaddr0(uint64 x)
{
asm volatile("csrw pmpaddr0, %0" : : "r" (x));
}

// Supervisor Status Register, sstatus

#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
Expand Down
28 changes: 28 additions & 0 deletions kernel/start.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
void main();
void timerinit();

static void pmpinit();

// entry.S needs one stack per CPU.
__attribute__ ((aligned (16))) char stack0[4096 * NCPU];

Expand Down Expand Up @@ -45,10 +47,36 @@ start()
int id = r_mhartid();
w_tp(id);

// allow access to all physical memory by S mode
pmpinit();

// switch to supervisor mode and jump to main().
asm volatile("mret");
}

// configures the pmp registers trivially so we can boot. it is not permitted
// to jump to S mode without having these configured as instruction fetch will
// fail, however we do not actually use them for protection in xv6, so we just
// need to put something trivial there.
//
// see section 3.6.1 "Physical Memory Protection CSRs" in the RISC-V privileged
// specification (v20190608)
//
// "If no PMP entry matches an M-mode access, the access succeeds. If no PMP
// entry matches an S-mode or U-mode access, but at least one PMP entry is
// implemented, the access fails." (3.6.1)
static void
pmpinit()
{
// see figure 3.27 "PMP address register format, RV64" and table 3.10 "NAPOT
// range encoding in PMP address and configuration registers" in the RISC-V
// privileged specification
// we set the bits such that this matches any 56-bit physical address
w_pmpaddr0((~0ULL) >> 10);
// then we allow the access
w_pmpcfg0(PMP_R | PMP_W | PMP_X | PMP_MATCH_NAPOT);
}

// set up to receive timer interrupts in machine mode,
// which arrive at timervec in kernelvec.S,
// which turns them into software interrupts for
Expand Down