Giter VIP home page Giter VIP logo

riscv7's Introduction

This is the (not-yet working) port of UNIXv7 system to RISC-V.

It's currently targeting the GD32V as found on the Longnan Nano, a
super-inexpensive ($5-ish) SBC that includes a full USB-C controller,
including OTG. This makes it possible to appear as a mass storage device,
a serial port, or other USB peripherals. This is more powerful than
devices like the K210 or BL602 which require an external USB->Serial
adapter that can support none of these. RISCv7 does not (yet) use any of
this awesomeness.

There are some remnanats in the code of me starting with the K210. That
is a 64-bit part that has 8MB of RAM and 2 cores. While I may go back to
that part some day (more RAM and protected mode would be nice) I learned
early on that there were a lot of structures with implicit sizes that
burst into flames with int > 32 bits. In the name of focus, I went down
to a single part.

An early design choice was to NOT design my own ABI and calling convention.
Nor did I choose to torture myself with ancient Make. Relying on a sane
GNU make on the host is fair game. It's easy to find riscv64-gcc in
prepackaged binaries (Mac: Homebrew. Debian has a package) where 32-bit
tools are harder to find. The tools support 32-bit modes so the convenience
of calling riscv32-gcc over riscv64-gcc with -march=rv32imac -mabi=ilp32 to
get 32-bit code isn't worth it[1]. The ABI is "whatever these tools do". Like
the early UNIXes, binary compatibilty isn't a concern; I may change system
call numbers or visible symbols pretty much at whim.

Similarly, I've not fought a fierce battle to keep the code K&R. As this
code is meant to be educational (it certainly has been for this author)
more than historical purity, familiarity with ANSI function declarations,
judicious use of declarations, va_arg, not relying on implicit int, the
presence of 'void', the absence of 'register' and so on are all considered
good taste. Indeed, especially with 64-bit being in sight, implicit int
and such can lead to really screwy stack frames so we're just trying to
head that off.

I started development thinking I would write ALL the code myself and not
rely on any namby-pamby vendor code. That quickly got old. In sys/n200
(another unfortunate naming choice) is code for the Nucleisys 200 core as
used in the GD32V, the Gigadevice libraries for interfacing with SPI, DMA,
and more, as well as some other third party libraries. There is evidence
in this directory of several failed experiments with different abstractions.


I've been happily using the SEGGER Mini EDU JTAG device. Using something
like Openocd with an FTDI board is probably possible, but that's what I
started with.

The best way to build the kernel is to be in usr/sys/conf and run make.
There is a convenience script named 'upload' which does the obvious thing,
calling Jlink with the appropriate fiddly parameters. 'run_nano' does a
build, uploads the kernel to the board, and starts a GDB server.

For debugging, there are x/ and z/ subdirectories (bad, I know...) that
have .gdbinits that offer convenience macros to reboot the kernel, reload
it (via GDB), start the remote debugging, and automatically have breakpoints
on panic and other places you hope to not be. These will probably need
customized to a developer's system and style.

Little attention has been given to user-space so far. I expect most of it
will fall into place. crt0.S for these parts is straight-forward. I just
need to work through things like the global for errno and the assembly
code that sets it, the header tension between usr/include and usr/sys/h,
and signal handlers that need to decode interrupted instructions so that
the $PC can be set right. There is also the need for standardized kernel
exception frames.



Status & Known problems:

Boot is working.

Timer interrupts are working.

The display is mostly working. It's too small to be really useful, but
displaying interrupt ticks or enter/exit style prints can still be handy.
The display is NOT hooked as a console device with ANSI escape sequences
nor is it even hooked as a serial console. It's shoved into putchar()
inside sc.c,.


Memory management is a mess.  The code I started from, Robert Nordier's
386 port of UNIXv7 has some hard coded page numbers in memory layout
in the kernel. This has proven hard to undo.

The code currently gets to the point where it trampolines the assembler
code to start an exec() to load and run.

Sometime the LCD doesn't wake properly. I think there's something missing
in the reset sequence. As embarrassing/ridiculous as this sounds, building
and running gd32vf103inator/examples/LonganNano will "fix" the display.
Once it's run and whacked the LCD (DMA? SPI?) once, the LCD will literally
run for days and across hundreds of load/run cycles.

The chip has a hardware scroll, but I cannot make it scroll in the axis it
needs to scroll. Horizontal scroll is not very useful in a UNIX console.
One possible way to implement scrolling is to define a text frame buffer
(maybe with 8-bit color like CGA or VGA) and fully redraw the screen on
a scroll. I'm not sure if that's a good use of our memory budget.

SD card support is working at a proof-of-concept level. I can open
a DOS-formattted memory card and read files and directories from it.
I've not implemented partition table support. With SD cards being so
cheap, I'm not sure it makes sense. More importantly, I've not implemented
any "real" UNIX-level disk support. Even being a serial device attached
to SPI, SD is so crazy fast relative to the VAX disk that I'm not sure
that just spin-waiting a DMA-driven interface isn't the way to go. Shimming
the code in tf_card.c for disk_read() and disk_write() for synchronous
reads and writes may be OK.

There is no root filesystem created by the build process. The kernel is
just injected into flash memory and executed. It works at a reasonable
speed because flash is copied to SRAM on boot. SRAM is apparently cheaper
than caches at this size. (!!)

Segger's equivalent of ARM's Semihosting would probably be good
to implement for debugging.

[1] For more info on RISC-V embedded chains, see 
  https://riscv.org/wp-content/uploads/2015/02/riscv-software-stack-tutorial-hpca2015.pdf
  https://github.com/riscv/riscv-gnu-toolchain

riscv7's People

Contributors

robertlipe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

riscv7's Issues

TODO: update kernel a.out to ELF reader

The GNU tools all fluently read and write ELF, so using that instead of a.out is a no-brainer for us.

I think most of our damage will be in sys1.c:getxfile(). ELF is well documented. This seems to be the code responsible for fondling the executable header, creating a mapping (or filling a buffer) to hold the executable, and keeping some sense of security around not executing garbage, not leaving partially filled pages in the programs address space, etc.

This could possibly developed before the filesystem code is in place by carefully creating an ELF executable in kernel address space, dummying up an inode, and calling it directly. Probably create a tiny "hello world" executable in user space, then use an #includebin to slurp it into kernel space during the build. Throw it in another section if you don't like it in .data, but be sure the linker script doesn't toss the section.

TODO: "real" trap frame handling into machdep:clock()

The predecessor code wanted a populated stack frame passed to clock. I dummied it up making a static frame with all members null since I didn't have user/system mode or other nuances bugging me. That has to go.

TODO: serial console

Current workarounds include the tiny display on longan nano and using gdb to p msgbuf on a crash or interrupt, but at time point we'll need to type things at the system and that needs input. Pick one or more options from:

SEGGER's version of SemiHosting
Use the real serial pins. (Abstract it to K210 and GD32V) Writing more tty drivers. Ugh.
For GD32V, I think we could treat it like a CDC(ACM) device so it would show up as a USB serial port. The libraries from GD are quite good, but that's a terrifying quantity of code to be spinning through that could be called pre-boot or during a panic handler,

TODO: kernel IPL handling

The VAX IPL levels map to x86 interrupts somewhat cleanly, but not so well to RISC-V. Once we really reach our stride of having disk, display, terminals, and such going, we need to preserve the spl(x) and split() functionality in a way that approximately maps to RISC-V interrupt controllers. (Bonus points for working on both GD32V and K210, even if only one core awake.)

The terms are described pretty well at http://osr600doc.sco.com/en/man/html.D3/spl.D3.html I think disk, tty, base, timeout, split are probably the highpoint.

TODO: disk and root filesystem

Using the code from GD that handled all the SPI dma/interrupt stuff (tf_card.c) and a third-party library for the filesystem (ff.c) I've demonstrated reading the directory of a DOS-formatted SD card and displaying the contents. The filesystem code Is used by many Arduino class projects and the trans flash code provides a very reasonable looking disk_read() and disk_write services that shim the SCSI (sigh) that's used In these memory cards.

If we want to share an SD card with a DOS filesystem, we'd need a small partition driver that read the MBR, walked the partitions, identified a UNIX (which?) partition ID and a DOS one and calculated the saved cylinder edges of those partitions. (Half the system will want to deal in CHS and half will want to deal in SCSI command blocks and half will just make no sense when pairing VAX-era code to a "disk" that would fit in your eye.) The OS reads and writes just get offset by the partition boundaries.

I have no idea how we populate the memfs that's present when we boot or how we fill the memory card with the binaries we build. We probably need a "vaxcp" or "vaxformat" (surely these exists) that can just treat a raw bag of bytes and put a V7 filesystem onto them so we can write /etc/init and /bin/sh and /usr/games/fortune and such. Needs research.

Since even a slow SPIO transfer is surely faster than mechanical heads seeking on a disk pack, it might not be crazy to just spin-wait the sector reads and writes at least on a per-sector basis and letting that be preempt able. There's code for tfcard_timer_irq() but it seems to have no callers.

References: https://minnie.tuhs.org/PUPS/Setup/v7_setup.html (thumbs-up for "Recompile kernel and all apps when changing TZ...) The browsable source archives of historic distributions are a treasure trove.

TODO: exec init, launch user space

I think I have newproc and sleep/wakeup working. I could be wrong.

sys/machdep.c has the starts of a promising technique of writing .S code naturally inlined to C.

main.c seems to be calling newproc successfully,. The copyout() that puts the init skeleton into user space is being called, but probably not with a real, suitable executable.

I've put in a moderate amount of scaffolding to prop up user space, but we still need to connect the ECALL handler to something that connects to sysent[] from the generated trap.

This is kind of the intersection of several sketched in components that aren't really tested.

Since we don't really have VM (unless we raise the hardware requirement to a device that support RV39) we'll have to think through what we want our memory map to look like and how to share kernel and user space (probably meaningless terms w/o MMU) to at least minimize the risk of them trampling each other.

We also have the landmine that the x86 port, whence this code came, hardcoded page numbers in several places that I've removed. Some surely remain. "We don't know what we don't know."

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.