Coder Social home page Coder Social logo

sedna's Introduction

Sedna RISC-V Emulator

Sedna is a 64-bit RISC-V emulator written purely in Java. It implements all extensions necessary to be considered "general purpose" plus supervisor mode, meaning it can boot Linux. At the time of writing (2020/12/06) Sedna passes all tests in the RISC-V test suite. It also supports serializing and deserializing machine state.

Structure

The code layout is relatively flat, with different parts of the emulator living in their respective packages. Here are some notable ones.

Package Description
li.cil.sedna.device Non-ISA specific device implementations.
li.cil.sedna.devicetree Utilities for constructing device trees.
li.cil.sedna.elf An ELF loader, currently only used to load tests.
li.cil.sedna.fs Virtual file system layer for VirtIO filesystem device.
li.cil.sedna.instruction Instruction loader and decoder generator.
li.cil.sedna.memory Memory map implementation and utilities.
li.cil.sedna.riscv RISC-V CPU and devices (CLINT, PLIC).

RISC-V Extensions

Sedna implements the G meta extension, i.e. the general purpose computing set of extensions: rv64imacfd and Zifencei. For the uninitiated, this means:

  • i: basic 64-bit integer ISA.
  • m: integer multiplication, division, etc.
  • a: atomic operations.
  • c: compressed instructions.
  • f: single precision (32-bit) floating-point operations.
  • d: double precision (64-bit) floating-point operations.
  • Zifencei: memory fence for instruction fetch.

This comes with a couple of caveats:

  • The FENCE and FENCE.I instructions are no-ops and atomic operations do not lock underlying memory. Multi-core setups will behave incorrectly.
  • Floating-point operations have been reimplemented in software for flag correctness. Meaning they're slow.

Instructions and decoding

Sedna uses run-time byte-code generation to create the decoder switch used by the instruction interpreter. This makes it very easy to add new instructions and to experiment with different switch layouts to improve performance. The instruction loader and switch generator are technically general purpose, i.e. they have no direct dependencies on the RISC-V part of this project. However, there are some assumptions on how instructions are defined and processed baked into their design.

The current set of supported RISC-V instructions is declared in this file.

Instruction implementations are defined in the RISC-V CPU class.

Endianness

The emulator presents itself as a little-endian system to code running inside it. This should also work correctly on big-endian host systems, but has not been tested.

Tests

Sedna tests ISA conformity using the RISC-V test suite. The tests are run using a simple JUnit test runner. The compiled test binaries are included in this repository and can be found here.

Note that an additional tests may be included from this fork: https://github.com/fnuecke/riscv-tests

  • A test for page misaligned access (e.g. loads spanning multiple pages) has been contributed by @ja2142 on branch page_misaligned_access_test.

Maven

Sedna can be included into a project via the Github Package Repository. See the documentation for more information on how to set that up. In short, you'll want to add your username and a public access token into your ~/.gradle/gradle.properties and use those variables in your repository declaration. Note that the public access token will need read:packages permissions.

For example, using Gradle:

repositories {
  maven {
    url = uri("https://maven.pkg.github.com/fnuecke/sedna")
    credentials {
      username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
      password = project.findProperty("gpr.key") ?: System.getenv("TOKEN")
    }
  }
}

dependencies {
  implementation 'li.cil.ceres:sedna:2.0.0'
}

sedna's People

Contributors

fnuecke avatar ja2142 avatar pufit avatar samuelwanderson45 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sedna's Issues

segfaults when running TCC on some inputs

This typically happens when trying to compile larger programs with TCC (such as the cJSON library). There also appear to happen segfaults in other applications. The TCC segfault does not happen when running the same rootfs and kernel image in qemu, leading me to suspect it's a bug in sedna somewhere. Could be the memory virtualization, could be an instruction not doing quite the right thing in some edge case, sadly no hard leads right now.

Networking doesnt work

Mod verson: oc2-1.18.2-forge-0.1.8+3feb69b
Sedna version: sedna-1.18.2-forge-1.0.14+21d424a

Wget commands and ping do not work
I tried on client and on websites where you can host servers

No links and no IPs work (including FTP)

I checked config but found nothing that could be enabling/disabling network

Instruction fetch bug in interpret() when crossing a page boundary between devices

In the logic for fetching a 32bit instruction that is split across two consecutive pages, there is a mistype:

final TLBEntry highCache = fetchPage(pc + 2);
final MemoryMappedDevice highDevice = cache.device;

A TLBEntry called highCache for the next page is retrieved but the next line uses the old cache var to assign highDevice.
This would only reveal itself if the consecutive pages were from different devices, which is fairly rare and probably explains why this was never caught in testing.

Incorrect floating point behaviour

Applications compiled with Clang/LLVM tend to have incorrect floating point behaviour when running under sedna
Attached is the source code for one such application (written against Zig 0.12.0-dev.1802+56deb5b05)
Archive.tar.gz
When run on real hardware against this file (run with ./minecraft-printer Sample.gcode.txt) it runs correctly with output that ends in

info: plot { 33, 41, 2 }
info: Moving head to position { 33, 42, 2 }
info: plot { 33, 42, 2 }
info: Moving head to position { 32, 43, 2 }
info: plot { 32, 43, 2 }
info: Moving head to position { 33, 43, 2 }
info: plot { 33, 43, 2 }
info: Setting extrude state to false
error: TODO: handle END_PRINT macro

When run under sedna, it gets stuck in an infinite loop due to incorrect math.
A temporary workaround is to use software-floats, which gets around the issue, but this heavily decreases performance.

Here is a copy of the compiled program which exhibits the issue
minecraft-printer.tar.gz

gdbstub direct reference to R5MemoryAccessException

Contents of the li.cil.sedna.riscv package are referenced from the following closely related part of the project:

  • Package li.cil.sedna.riscv
  • Test package li.cil.sedna.riscv
  • Class li.cil.sedna.Sedna
  • Class li.cil.sedna.serialization.serializers.R5CPUSerializer

Other than these, li.cil.sedna.riscv.exception.R5MemoryAccessException is also referenced by:

  • Class li.cil.sedna.gdbstub.GDBStub
  • Class li.cil.sedna.gdbstub.CPUDebugInterface

As far as I can tell adding an CPU-independent parent exception to use in these classes and making R5MemoryAccessException extend that would make li.cil.sedna.gdbstub reusable for other /CPUs/architectures.

Linux v5.15+ doesn't boot

Kernels v5.15 or newer don't boot in sedna. I bisected v5.14-5.15 to this single-line patch. After further investigation, changes near .Lsecondary_park may randomly prevent the kernel from booting.

For example, after reverting the patch the kernel boots.

.align 2
setup_trap_vector:
	/* Set trap vector to exception handler */
	la a0, handle_exception
	csrw CSR_TVEC, a0

	/*
	 * Set sup0 scratch register to 0, indicating to exception vector that
	 * we are presently executing in kernel.
	 */
	csrw CSR_SCRATCH, zero
	ret

//.align 2    // <-- This line is commented out
.Lsecondary_park:
	/* We lack SMP support or have too many harts, so park this hart */
	wfi
	j .Lsecondary_park

END(_start)

Let's add a ret after an existing one.

.align 2
setup_trap_vector:
	/* Set trap vector to exception handler */
	la a0, handle_exception
	csrw CSR_TVEC, a0

	/*
	 * Set sup0 scratch register to 0, indicating to exception vector that
	 * we are presently executing in kernel.
	 */
	csrw CSR_SCRATCH, zero
	ret
	ret   // <-- Here. It won't be executed as prev instr jumps out of the procedure

//.align 2
.Lsecondary_park:
	/* We lack SMP support or have too many harts, so park this hart */
	wfi
	j .Lsecondary_park

END(_start)

Doesn't work any more. What if we add another ret?

.align 2
setup_trap_vector:
	/* Set trap vector to exception handler */
	la a0, handle_exception
	csrw CSR_TVEC, a0

	/*
	 * Set sup0 scratch register to 0, indicating to exception vector that
	 * we are presently executing in kernel.
	 */
	csrw CSR_SCRATCH, zero
	ret
	ret   // <-- Previous ret
	ret   // <-- New ret

//.align 2
.Lsecondary_park:
	/* We lack SMP support or have too many harts, so park this hart */
	wfi
	j .Lsecondary_park

END(_start)

Now it boots all the way to the shell!

I'm going to focus on debugging the "double-ret" broken version. All testing was done in sedna-cli, I modified the R5MemoryAccessException constructor to print all memory faults to the console.

    public R5MemoryAccessException(final long address, final int type) {
        this.address = address;
        this.type = type;
        System.out.printf("FAULT %d @ %016X%n", type, address);
    }

This is the output of a fixed v5.15 kernel (.align was commented out)

OpenSBI v0.8
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name       : riscv-virtio,sedna
Platform Features   : timer,mfdeleg
Platform HART Count : 1
Boot HART ID        : 0
Boot HART ISA       : rv64imafdcsu
BOOT HART Features  : scounteren,mcounteren,time
BOOT HART PMP Count : 0
Firmware Base       : 0x80000000
Firmware Size       : 116 KB
Runtime SBI Version : 0.2

MIDELEG : 0x0000000000000222
MEDELEG : 0x000000000000b109
FAULT 12 @ 0000000080201064
FAULT 4 @ FFFFFFFF80CABAEA // Kernel was remapped
FAULT 4 @ FFFFFFFF80CABAEE
FAULT 4 @ FFFFFFFF80CABAF2
...

And this is with the "double-ret" kernel.

OpenSBI v0.8
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name       : riscv-virtio,sedna
Platform Features   : timer,mfdeleg
Platform HART Count : 1
Boot HART ID        : 0
Boot HART ISA       : rv64imafdcsu
BOOT HART Features  : scounteren,mcounteren,time
BOOT HART PMP Count : 0
Firmware Base       : 0x80000000
Firmware Size       : 116 KB
Runtime SBI Version : 0.2

MIDELEG : 0x0000000000000222
MEDELEG : 0x000000000000b109
FAULT 12 @ 0000000080201064
FAULT 12 @ 000000008020107C
FAULT 12 @ 000000008020107C // Loops to infinity

Kernel base address is 0x80200000, offset into the file is 0x107C or address 0xffffffff8000107c in the vmlinux binary.

ffffffff80001070:	10551073          	csrw	stvec,a0
ffffffff80001074:	14001073          	csrw	sscratch,zero
ffffffff80001078:	8082                	ret
ffffffff8000107a:	8082                	ret  // <-- ret that was added for testing
ffffffff8000107c:	10500073          	wfi  // <-- Instruction at fault
ffffffff80001080:	bff5                	j	ffffffff8000107c <setup_trap_vector+0x14>

Kernel with .align 2 loops with the same FAULT 12 @ 000000008020107C message at the same address and at the same instruction.

ffffffff80001070:	10551073          	csrw	stvec,a0
ffffffff80001074:	14001073          	csrw	sscratch,zero
ffffffff80001078:	8082                	ret
ffffffff8000107a:	0001                	nop  // <-- Added by .align
ffffffff8000107c:	10500073          	wfi  // <-- Instruction at fault
ffffffff80001080:	bff5                	j	ffffffff8000107c <setup_trap_vector+0x14>

This is as far as I could get with my skills and experience.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.