Permalink
Browse files

Switch around stacks so of the 16KB assigned per-CPU, IRQ has the top…

… 8KB, boot has the lower 8KB. when startup is over, the IRQ handlers can consume all 16KB. also drop down the IRQ stack a few bytes to squeeze some per-CPU variables.
  • Loading branch information...
diodesign committed Nov 12, 2018
1 parent a7d7524 commit 0b195d7620dc90aa65c4ab227efbc6a58251d080
@@ -19,7 +19,7 @@ mod heap; /* manage machine kernel's heap memory */
mod irq; /* handle hw interrupts and sw exceptions, collectively known as IRQs */
mod physmem; /* manage physical memory */
/* funciton naming note: machine kernel entry points start with a k, such as kmain,
/* function naming note: machine kernel entry points start with a k, such as kmain,
kwait, kirq_handler. supervisor kernel entry points start with an s, such as smain.
generally, kernel = machine/hypervisor kernel, supervisor = supervisor kernel. */
@@ -55,6 +55,9 @@ pub extern "C" fn kmain(device_tree_buf: &u8)
return;
}
};
/* test kernel heap */
}
/* kwait
@@ -1,8 +1,7 @@
# kernel top page variables for RV32G targets
# machine kernel memory locations and layout for RV32G targets
#
# Top page is a 4KB (4096 byte) page of read-write DRAM
# It's the final 4KB page in the first 16MB of physical RAM,
# and placed right above the boot-time kernel stacks.
# placed right above the boot-time kernel stacks.
#
# (c) Chris Williams, 2018.
# See LICENSE for usage and copying.
@@ -13,9 +12,17 @@
# .
# . kernel text, data
# .
# __kernel_cpu_stack_base = base of space for CPU boot + exception stacks
# __kernel_cpu_stack_base = base of space for CPU boot + IRQ stacks + per-CPU variables
# .
# . N * 8KB * 2 stacks, one for boot, one for exceptions, N = max CPU cores
# . plus space for per-CPU variables. layout is as follows:
# .
# . variables
# . ~8KiB of interrupt/exception stack <--- mscratch always points here
# . 8KiB of boot stack
# .
# . once boot is over, and the CPU is running workloads, the IRQ stack rolls into the
# . boot stack, making it a per-CPU ~16KiB stack plus per-CPU globals at the top
# .
# __kernel_cpu_stack_top = top of stack space
# __kernel_top_page_base = base of 'top page', 4KB area for kernel variables
@@ -40,9 +47,19 @@
# number of bytes of physical RAM present in this system
.equ KERNEL_PHYS_RAM_SIZE, (5 * 4)
# each CPU boot stack is 16KB, top 8KB for normal operation.
# lower 8KB for the exception handler.
.equ KERNEL_BOOT_IRQ_STACK_OFFSET, 8 * 1024
# each CPU boot stack is 16KB, bottom 8KB used during startup
# higher 8KB for the interrupt/exception handler, minus space for per-CPU variables
# when startup is over, the IRQ handler can run into the lower 8KBs
.equ KERNEL_BOOT_STACK_OFFSET, (8 * 1024)
# sitting above the top of the per-CPU IRQ stack, pointed to by mscratch, are per-CPU global
# variables uded to store things like the per-CPU environment pointers, per-CPU heaps, etc
# basically, you load mscratch into sp and use it as the IRQ stack pointer, and also access
# variables above mscratch
.equ KERNEL_PER_CPU_VAR_SPACE, (1 * 4) # reserve 1 32-bit word
# offsets from top of IRQ stack into per-CPU variable space
.equ KERNEL_PER_CPU_HEAP_START, (0 * 4) # pointer to first page in per-CPU heap
# initialize the top page of variables
# corrupts t0, t1, t2
@@ -39,40 +39,53 @@ irq_early_init:
.align 4
# Entry point for machine-level handler of interrupts and exceptions
# interrupts are automatically disabled on entry.
# right now, IRQs are non-reentrant. if an IRQ handler is interrupted, the previous one will
# be discarded. do not enable hardware interrupts. any exceptions will be unfortunate.
irq_machine_handler:
# get exception handler stack from mscratch by swapping it for current sp
csrrw sp, mscratch, sp
csrrw sp, mscratch, sp
# now: sp = top of IRQ stack. mscratch = prev environment's sp
# save space to preserve all 32 GP registers
addi sp, sp, -(IRQ_REGISTER_FRAME_SIZE)
# skip x0 (zero), stack all 31 other registers
.set reg, 1
.rept 31
PUSH_REG %reg
.set reg, reg + 1
.endr
# right now mscratch is corrupt with the prev environment's sp.
# this means kernel functions relying on it will break unless it is restored.
# calculate original mscratch value into s11, and swap with mscratch
addi s11, sp, IRQ_REGISTER_FRAME_SIZE
csrrw s11, mscratch, s11
# now: s11 = prev environment's sp. mscratch = top of IRQ stack
# gather up the cause, faulting instruction address, memory address relevant to the exception or interrupt,
# and previous environment's stack pointer, and store on the IRQ handler's stack
addi sp, sp, -16
csrrs t0, mcause, x0 #
csrrs t1, mepc, x0 # just read from these special registers
csrrs t2, mtval, x0 # don't modify their contents, esp mscratch
csrrs t3, mscratch, x0 #
sw t0, 0(sp)
sw t1, 4(sp)
sw t2, 8(sp)
sw t3, 12(sp)
addi sp, sp, -16
csrrs t0, mcause, x0
csrrs t1, mepc, x0
csrrs t2, mtval, x0
sw t0, 0(sp) # mcause
sw t1, 4(sp) # mepc
sw t2, 8(sp) # mtval
sw s11, 12(sp) # prev environment's sp
# pass current sp to exception/hw handler as a pointer. this'll allow
# the higher-level kernel access the context of the IRQ
# the higher-level kernel access the context of the IRQ.
# it musn't corrupt s11, a callee-saved register
add a0, sp, x0
call kirq_handler
# swap back mscratch so prev environment's sp can be restored
csrrw s11, mscratch, s11
# now: mscratch = prev environment's sp. s11 = top of IRQ stack
# fix up the stack from the cause, epc, etc pushes
# then restore all 31 stacked registers, skipping zero (x0)
addi sp, sp, 16
# then restore all 31 stacked registers, skipping zero (x0)
.set reg, 31
.rept 31
PULL_REG %reg
@@ -82,6 +95,6 @@ irq_machine_handler:
# fix up exception handler sp
addi sp, sp, IRQ_REGISTER_FRAME_SIZE
# swap exception sp for original sp, and return
# swap top of IRQ sp for prev environment's sp, and return
csrrw sp, mscratch, sp
mret
@@ -21,7 +21,7 @@
# 0x10001000, size: 0x1000: Virtual IO
# 0x80000000: DRAM base (default 128MB, min 16MB) <-- kernel + entered loaded here
#
# see consts.s for CPU stack + top page of variables locations
# see consts.s for top page of global variables locations and other memory layout decisions
# the boot ROM drops us here with nothing setup
# this code is assumed to be loaded and running at 0x80000000
@@ -40,15 +40,22 @@ _start:
addi t1, t6, KERNEL_CPUS_ALIVE
amoadd.w x0, t0, (t1)
# set up a 16KB per-CPU core stack, calculated from top of the kernel boot stack, descending downwords.
# CPU 0 takes first 16KB from the top down, then CPU 1, CPU 2, etc. the 16KB stack space is 2 * 8KB areas.
# top 8KB for running boot code, bottom 8KB for exception/interrupt handling
# set up a ~16KB per-CPU core stack, calculated from top of the kernel boot stack,
# descending downwords. CPU 0 takes first 16KB from the top down, then CPU 1, CPU 2, etc.
# the ~16KB stack space is 2 * 8KB areas.
# top 8KB is for exception/interrupt handling, lower 8KB for startup code.
# when startup is over, the IRQ stack can fall down into the full 16KB space.
#
# it's not quite 16KB, though. sitting above the top of the stack are a few per-CPU variables.
# mscratch always points to the top of the IRQ stack.
slli t0, a0, 14 # t0 = (hart id) << 14 = (hart ID) * 16 * 1024
la sp, __kernel_cpu_stack_top
sub sp, sp, t0 # subtract per-cpu stack offset from top of stack
li t0, KERNEL_BOOT_IRQ_STACK_OFFSET
sub t0, sp, t0 # calculate top of IRQ handler stack with the 16KB reserved for this core
csrrw x0, mscratch, t0 # store exception/interrupt handler stack in mscratch
la t1, __kernel_cpu_stack_top
sub t1, t1, t0 # calculate top of the per-CPU stack area
li t2, KERNEL_BOOT_STACK_OFFSET
sub sp, t1, t2 # assign boot stack, 8KiB down from the top
# drop the IRQ stack down a few bytes to make room for variables
addi t1, t1, -(KERNEL_PER_CPU_VAR_SPACE)
csrrw x0, mscratch, t1 # store IRQ handler stack in mscratch
# set up early exception/interrupt handling
call irq_early_init
@@ -22,7 +22,7 @@
# 0x100900FC, size: 0x2000: Cadence GEM ethernet controller
# 0x80000000: DRAM base (default 128MB, min 16MB) <-- kernel + entered loaded here
#
# see consts.s for CPU stack + top page of variables location
# see consts.s for top page of global variables locations and other memory layout decisions
# the boot ROM drops us here with nothing setup
# this code is assumed to be loaded and running at 0x80000000
@@ -45,11 +45,13 @@ _start:
sw t0, (t1)
# set up a 16KB CPU core stack, descending downwords. the 16KB stack space is 2 * 8KB areas.
# top 8KB for running boot code, bottom 8KB for exception/interrupt handling
la sp, __kernel_cpu_stack_top
li t0, KERNEL_BOOT_IRQ_STACK_OFFSET
sub t0, sp, t0 # calculate top of exception/interrupt stack
csrrw x0, mscratch, t0 # store irq stack top in mscratch
# top 8KB for exception/interrupt handling and per-CPU variables, bottom 8KB for startup.
# when startup is over, then the IRQ stack can claim the boot area
la t0, __kernel_cpu_stack_top
li t1, KERNEL_BOOT_STACK_OFFSET
sub sp, t0, t1
addi t0, t0, -(KERNEL_PER_CPU_VAR_SPACE)
csrrw x0, mscratch, t0 # store irq stack top in mscratch
# set up top page and early exception handling
_KERNEL_TOP_PAGE_INIT

0 comments on commit 0b195d7

Please sign in to comment.