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

Add virtio-gpu #2

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
Binary file added fw_payload.bin
Binary file not shown.
Binary file added rootfs.ext2
Binary file not shown.
106 changes: 106 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import li.cil.sedna.Sedna;
import li.cil.sedna.device.serial.UART16550A;
import li.cil.sedna.device.virtio.VirtIOMouseDevice;
import li.cil.sedna.device.virtio.gpu.VirtIOGPUDevice;
import li.cil.sedna.device.virtio.gpu.AbstractVirtIOGPUScanout;
import li.cil.sedna.api.device.PhysicalMemory;
import li.cil.sedna.device.block.ByteBufferBlockDevice;
import li.cil.sedna.device.memory.Memory;
import li.cil.sedna.device.virtio.VirtIOBlockDevice;
import li.cil.sedna.device.virtio.VirtIOFileSystemDevice;
import li.cil.sedna.device.virtio.VirtIOKeyboardDevice;
import li.cil.sedna.fs.HostFileSystem;
import li.cil.sedna.riscv.R5Board;

import javax.swing.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;

public class Main {

private void run() throws IOException {
Sedna.initialize();
// Load openSBI
PhysicalMemory rom = Memory.create(1024 * 1024 * 64);
Path p = Paths.get("fw_payload.bin");
rom.store(0, ByteBuffer.wrap(Files.readAllBytes(p)));

PhysicalMemory ram = Memory.create(1024 * 1024 * 32);

R5Board board = new R5Board();
board.addDevice(rom);
board.addDevice(ram);

File f = new File("rootfs.ext2");
//File f = new File("rootfs-fedora.ext2");
VirtIOBlockDevice fileSystemDevice = new VirtIOBlockDevice(board.getMemoryMap(), ByteBufferBlockDevice.createFromFile(f, f.length(), false));
VirtIOKeyboardDevice keyboardDevice = new VirtIOKeyboardDevice(board.getMemoryMap());
VirtIOMouseDevice mouseDevice = new VirtIOMouseDevice(board.getMemoryMap());
VirtIOFileSystemDevice hostFS = new VirtIOFileSystemDevice(board.getMemoryMap(), "rootfs", new HostFileSystem());
SwingVirtIOScanout scanout = new SwingVirtIOScanout(800, 600);
VirtIOGPUDevice gpuDevice = new VirtIOGPUDevice.Builder(board.getMemoryMap())
.setScanouts(new ArrayList<AbstractVirtIOGPUScanout>(){{
add(scanout.getScanout());
}})
.build();

JFrame frame = new JFrame();
frame.setContentPane(scanout.getComponent());
frame.pack();
frame.setVisible(true);

//UART16550A uart = new UART16550A();
board.addDevice(fileSystemDevice);
board.addDevice(gpuDevice);
board.addDevice(hostFS);
board.addDevice(keyboardDevice);
board.addDevice(mouseDevice);
//board.addDevice(uart);
//board.addDevice(0x09000000, uart);
//board.setStandardOutputDevice(uart);
board.setBootArguments("root=/dev/vda");
fileSystemDevice.getInterrupt().set(0x1, board.getInterruptController());
gpuDevice.getInterrupt().set(0x2, board.getInterruptController());
keyboardDevice.getInterrupt().set(0x3, board.getInterruptController());
hostFS.getInterrupt().set(0x4, board.getInterruptController());
mouseDevice.getInterrupt().set(0x5, board.getInterruptController());
//uart.getInterrupt().set(0x6, board.getInterruptController());
//
board.initialize();
board.setRunning(true);
System.out.println("freq: " + board.getCpu().getFrequency());

BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(System.in));

while (board.isRunning()) {
board.step(1);

/*while (true) {
int chr = uart.read();
if (chr == -1) {
break;
}
//
System.out.print((char) chr);
}
while (inputStreamReader.ready() && uart.canPutByte()) {
uart.putByte((byte) inputStreamReader.read());
}
*/
}

}

public static void main(String[] args) throws URISyntaxException, IOException {
new Main().run();
}

}
72 changes: 72 additions & 0 deletions src/main/java/SwingVirtIOScanout.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import li.cil.sedna.device.virtio.gpu.AbstractVirtIOGPUScanout;
import li.cil.sedna.device.virtio.gpu.VirtIOGPURect;
import li.cil.sedna.utils.ByteBufferInputStream;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

public class SwingVirtIOScanout {
private Component component;
private Scanout scanout;

public JPanel getComponent() {
return this.component;
}

public AbstractVirtIOGPUScanout getScanout() {
return this.scanout;
}

public SwingVirtIOScanout(final int width, final int height) {
this.component = new Component(width, height);
this.scanout = new Scanout(0, 0, width, height);
}

private class Component extends JPanel {
BufferedImage image;

private Component(int width, int height) {
this.image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
setMinimumSize(new Dimension(width, height));
}

void flush(ByteBuffer data) throws IOException {
data.rewind();
int[] array = new int[data.capacity()];
for (int i = 0; data.hasRemaining(); i++) {
array[i] = data.get() << 16 | data.get() << 8 | data.get();
data.get();
}
this.image.setRGB(0, 0, 800, 600, array, 0, 800);
repaint();
}

@Override
public void paint(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
if (image != null) {
g.drawImage(image, 0, 0, 800, 600, null);
}
}
}

private class Scanout extends AbstractVirtIOGPUScanout {
public Scanout(int x, int y, int width, int height) {
super(x, y, width, height);
}

@Override
public void flush(VirtIOGPURect rect) {
try {
component.flush(getResource().getBacking().duplicate());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/li/cil/sedna/device/virtio/VirtIOMouseDevice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package li.cil.sedna.device.virtio;

import li.cil.sedna.api.memory.MemoryMap;
import li.cil.sedna.device.virtio.AbstractVirtIOInputDevice;
import li.cil.sedna.evdev.EvdevEvents;

public class VirtIOMouseDevice extends AbstractVirtIOInputDevice {
private static final String NAME = "virtio_mouse";

private static final int REL_X = 0x00;
private static final int REL_Y = 0x01;
private static final int BTN_LEFT = 0x110;
private static final int BTN_RIGHT = 0x111;

public VirtIOMouseDevice(MemoryMap memoryMap) {
super(memoryMap);
}

public void sendRelEvent(double x, double y) {
putEvent(EvdevEvents.EV_REL, REL_X, (int) x);
putEvent(EvdevEvents.EV_REL, REL_Y, (int) y);
putSyn();
}

public void sendRightClick(boolean down) {
putEvent(EvdevEvents.EV_KEY, BTN_RIGHT, down ? 1 : 0);
putSyn();
}

public void sendLeftClick(boolean down) {
putEvent(EvdevEvents.EV_KEY, BTN_LEFT, down ? 1 : 0);
putSyn();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package li.cil.sedna.device.virtio.gpu;

import java.nio.ByteBuffer;

public abstract class AbstractVirtIOGPUScanout {
private int x;
private int y;
private int width;
private int height;

protected VirtIOGPUResource resource;

public AbstractVirtIOGPUScanout(final int x, final int y, final int width, final int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}

public abstract void flush(VirtIOGPURect rect);

public void setResource(VirtIOGPUResource resource) {
this.resource = resource;
}

public VirtIOGPUResource getResource() {
return this.resource;
}

public void appendToByteByteBuffer(ByteBuffer buffer) {
buffer.put(getRect().asByteBuffer());
// enabled
buffer.putInt(1);
// flags
buffer.putInt(0);
}

private VirtIOGPURect getRect() {
return new VirtIOGPURect(x, y, width, height);
}

/**
* @return how many bytes are read/written to buffers
*/
public static int getLengthInBytes() {
return 24;
}
}
78 changes: 78 additions & 0 deletions src/main/java/li/cil/sedna/device/virtio/gpu/BackingPages.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package li.cil.sedna.device.virtio.gpu;

import javafx.util.Pair;
import li.cil.sedna.api.memory.MemoryAccessException;
import li.cil.sedna.api.memory.MemoryMap;
import li.cil.sedna.memory.MemoryMaps;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

public final class BackingPages {
private final List<Pair<Long, Integer>> pages;
private final MemoryMap memoryMap;
/**
* @param pages list of address -> length mappings
*/
public BackingPages(MemoryMap memoryMap, List<Pair<Long, Integer>> pages) {
this.memoryMap = memoryMap;
this.pages = pages;
}

/**
* Joins the pages as one contiguous buffer
* @throws MemoryAccessException
*/
public ByteBuffer getAsByteBuffer() throws MemoryAccessException {
int length = pages.stream().mapToInt(Pair::getValue).sum();
ByteBuffer buffer = ByteBuffer.allocate(length);
buffer.order(ByteOrder.LITTLE_ENDIAN);
for (Pair<Long, Integer> page : pages) {
//TODO(Matrix89): add MemoryMaps.load(mm, add, len, bb)
byte[] tmpArray = new byte[page.getValue()];
MemoryMaps.load(memoryMap, page.getKey(), tmpArray, 0, page.getValue());
buffer.put(tmpArray);
}
buffer.flip();
return buffer;
}

public ByteBuffer getAsByteBuffer(int offset, int length) throws MemoryAccessException {
ByteBuffer buffer = ByteBuffer.allocate(length);
int poff = 0;
for (Pair<Long, Integer> page : pages) {
if (offset < poff + page.getValue()) {
int len = Math.min((poff + page.getValue()) - offset, length);
byte[] tmpArray = new byte[len];
MemoryMaps.load(memoryMap, page.getKey() + (offset - poff), tmpArray, 0, len);
buffer.put(tmpArray);
offset += len;
length -= len;
}
poff += page.getValue();
}

buffer.flip();

return buffer;
}

static class Builder {
private final MemoryMap memoryMap;
private final List<Pair<Long, Integer>> pages = new ArrayList<>();

public Builder(MemoryMap memoryMap) {
this.memoryMap = memoryMap;
}

public void addPage(long address, int length) {
pages.add(new Pair<>(address, length));
}

public BackingPages build() {
return new BackingPages(memoryMap, pages);
}
}
}
Loading