mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +00:00
vancouver: Disk support
Vancouver can now assign block devices to guests using the Block interface. The machine has to be configured to use a specified drive, which could be theoretically routed to different partitions or services via policy definitions. Currently the USB driver only supports one device. Genode's AHCI driver is untested. If the session quota is too low, random pagefaults can occur on the stack. According to @Nils-TUD, it is necessary to protect the DiskCommit messages with a lock against deadlocking with the timer. Observations showed that this mitigates some problems with Gentoo on real hardware.
This commit is contained in:
parent
1c447d98e9
commit
cbf4a7b0c3
@ -82,6 +82,8 @@ MODEL_INFO(pmtimer, "io_port")
|
||||
MODEL_INFO(pcihostbridge, "bus_num", "bus_count", "io_base", "mem_base")
|
||||
|
||||
MODEL_INFO(i82576vf, "promisc", "mem_mmio", "mem_msix", "txpoll_us", "rx_map")
|
||||
MODEL_INFO(ahci, "mem", "irq", "bdf")
|
||||
MODEL_INFO(drive, "sigma0drive", "controller", "port")
|
||||
|
||||
MODEL_INFO_NO_ARG(vbios_disk)
|
||||
MODEL_INFO_NO_ARG(vbios_keyboard)
|
||||
|
221
ports/src/vancouver/disk.cc
Normal file
221
ports/src/vancouver/disk.cc
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* \brief Block interface
|
||||
* \author Markus Partheymueller
|
||||
* \date 2012-09-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*
|
||||
* The code is partially based on the Vancouver VMM, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*
|
||||
* Modifications by Intel Corporation are contributed under the terms and
|
||||
* conditions of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/thread.h>
|
||||
#include <block_session/connection.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* local includes */
|
||||
#include <disk.h>
|
||||
|
||||
static Genode::Native_utcb utcb_backup;
|
||||
|
||||
extern Genode::Lock timeouts_lock;
|
||||
extern bool disk_init;
|
||||
|
||||
|
||||
Vancouver_disk::Vancouver_disk(Motherboard &mb,
|
||||
char * backing_store_base,
|
||||
char * backing_store_fb_base)
|
||||
:
|
||||
_mb(mb), _backing_store_base(backing_store_base),
|
||||
_backing_store_fb_base(backing_store_fb_base)
|
||||
{
|
||||
/* initialize struct with 0 size */
|
||||
for (int i=0; i < MAX_DISKS; i++) {
|
||||
_diskcon[i].blk_size = 0;
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
void Vancouver_disk::entry()
|
||||
{
|
||||
Logging::printf("Hello, this is Vancouver_disk.\n");
|
||||
|
||||
/* attach to disk bus */
|
||||
_mb.bus_disk.add(this, receive_static<MessageDisk>);
|
||||
|
||||
disk_init = true;
|
||||
}
|
||||
|
||||
|
||||
bool Vancouver_disk::receive(MessageDisk &msg)
|
||||
{
|
||||
utcb_backup = *Genode::Thread_base::myself()->utcb();
|
||||
|
||||
if (msg.disknr >= MAX_DISKS)
|
||||
Logging::panic("You configured more disks than supported.\n");
|
||||
|
||||
/*
|
||||
* If we receive a message for this disk the first time, create the
|
||||
* structure for it.
|
||||
*/
|
||||
char label[14];
|
||||
Genode::snprintf(label, 14, "VirtualDisk %2u", msg.disknr);
|
||||
|
||||
if (!_diskcon[msg.disknr].blk_size) {
|
||||
|
||||
Genode::Allocator_avl * block_alloc = new Genode::Allocator_avl(Genode::env()->heap());
|
||||
try {
|
||||
_diskcon[msg.disknr].blk_con = new Block::Connection(block_alloc, 4*512*1024, label);
|
||||
} catch (...) {
|
||||
|
||||
/* there is none. */
|
||||
return false;
|
||||
}
|
||||
|
||||
_diskcon[msg.disknr].blk_con->info(
|
||||
&_diskcon[msg.disknr].blk_cnt,
|
||||
&_diskcon[msg.disknr].blk_size,
|
||||
&_diskcon[msg.disknr].ops);
|
||||
|
||||
Logging::printf("Got info: %lu blocks (%u B), ops (R: %x, W:%x)\n ",
|
||||
_diskcon[msg.disknr].blk_cnt,
|
||||
_diskcon[msg.disknr].blk_size,
|
||||
_diskcon[msg.disknr].ops.supported(Block::Packet_descriptor::READ),
|
||||
_diskcon[msg.disknr].ops.supported(Block::Packet_descriptor::WRITE)
|
||||
);
|
||||
}
|
||||
|
||||
Block::Session::Tx::Source *source = _diskcon[msg.disknr].blk_con->tx();
|
||||
|
||||
switch (msg.type) {
|
||||
case MessageDisk::DISK_GET_PARAMS:
|
||||
{
|
||||
msg.error = MessageDisk::DISK_OK;
|
||||
msg.params->flags = DiskParameter::FLAG_HARDDISK;
|
||||
msg.params->sectors = _diskcon[msg.disknr].blk_cnt;
|
||||
msg.params->sectorsize = _diskcon[msg.disknr].blk_size;
|
||||
msg.params->maxrequestcount = _diskcon[msg.disknr].blk_cnt;
|
||||
memcpy(msg.params->name, label, strlen(label));
|
||||
msg.params->name[strlen(label)] = 0;
|
||||
}
|
||||
return true;
|
||||
case MessageDisk::DISK_READ:
|
||||
case MessageDisk::DISK_WRITE:
|
||||
{
|
||||
bool read = (msg.type == MessageDisk::DISK_READ);
|
||||
|
||||
if (!read && !_diskcon[msg.disknr].ops.supported(Block::Packet_descriptor::WRITE)) {
|
||||
MessageDiskCommit ro(msg.disknr, msg.usertag,
|
||||
MessageDisk::DISK_STATUS_DEVICE);
|
||||
_mb.bus_diskcommit.send(ro);
|
||||
*Genode::Thread_base::myself()->utcb() = utcb_backup;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long long sector = msg.sector;
|
||||
unsigned long total = DmaDescriptor::sum_length(msg.dmacount, msg.dma);
|
||||
unsigned long blocks = total/_diskcon[msg.disknr].blk_size;
|
||||
|
||||
if (blocks*_diskcon[msg.disknr].blk_size < total)
|
||||
blocks++;
|
||||
|
||||
Block::Session::Tx::Source *source = _diskcon[msg.disknr].blk_con->tx();
|
||||
Block::Packet_descriptor
|
||||
p(source->alloc_packet(blocks*_diskcon[msg.disknr].blk_size),
|
||||
(read) ? Block::Packet_descriptor::READ
|
||||
: Block::Packet_descriptor::WRITE,
|
||||
sector,
|
||||
blocks);
|
||||
|
||||
if (read) {
|
||||
source->submit_packet(p);
|
||||
p = source->get_acked_packet();
|
||||
}
|
||||
|
||||
if (!read || p.succeeded()) {
|
||||
char * source_addr = source->packet_content(p);
|
||||
|
||||
sector = (sector-p.block_number())*_diskcon[msg.disknr].blk_size;
|
||||
|
||||
for (int i=0; i< msg.dmacount; i++) {
|
||||
char * dma_addr = (char *) (msg.dma[i].byteoffset + msg.physoffset
|
||||
+ _backing_store_base);
|
||||
|
||||
/* check for bounds */
|
||||
if (dma_addr >= _backing_store_fb_base
|
||||
|| dma_addr < _backing_store_base)
|
||||
return false;
|
||||
|
||||
if (read)
|
||||
memcpy(dma_addr, source_addr+sector, msg.dma[i].bytecount);
|
||||
else
|
||||
memcpy(source_addr+sector, dma_addr, msg.dma[i].bytecount);
|
||||
|
||||
sector += msg.dma[i].bytecount;
|
||||
}
|
||||
|
||||
if (!read) {
|
||||
source->submit_packet(p);
|
||||
p = source->get_acked_packet();
|
||||
if (!p.succeeded()) {
|
||||
Logging::printf("Operation failed.\n");
|
||||
{
|
||||
Genode::Lock::Guard guard(timeouts_lock);
|
||||
MessageDiskCommit commit(msg.disknr, msg.usertag,
|
||||
MessageDisk::DISK_STATUS_DEVICE);
|
||||
_mb.bus_diskcommit.send(commit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Genode::Lock::Guard guard(timeouts_lock);
|
||||
MessageDiskCommit commit(msg.disknr, msg.usertag,
|
||||
MessageDisk::DISK_OK);
|
||||
_mb.bus_diskcommit.send(commit);
|
||||
}
|
||||
} else {
|
||||
|
||||
Logging::printf("Operation failed.\n");
|
||||
{
|
||||
Genode::Lock::Guard guard(timeouts_lock);
|
||||
MessageDiskCommit commit(msg.disknr, msg.usertag,
|
||||
MessageDisk::DISK_STATUS_DEVICE);
|
||||
_mb.bus_diskcommit.send(commit);
|
||||
}
|
||||
}
|
||||
|
||||
source->release_packet(p);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Logging::printf("Got MessageDisk type %x\n", msg.type);
|
||||
*Genode::Thread_base::myself()->utcb() = utcb_backup;
|
||||
return false;
|
||||
}
|
||||
*Genode::Thread_base::myself()->utcb() = utcb_backup;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Vancouver_disk::~Vancouver_disk()
|
||||
{
|
||||
/* XXX: Close all connections */
|
||||
}
|
71
ports/src/vancouver/disk.h
Normal file
71
ports/src/vancouver/disk.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* \brief Block interface
|
||||
* \author Markus Partheymueller
|
||||
* \date 2012-09-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*
|
||||
* The code is partially based on the Vancouver VMM, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*
|
||||
* Modifications by Intel Corporation are contributed under the terms and
|
||||
* conditions of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _DISK_H_
|
||||
#define _DISK_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/thread.h>
|
||||
#include <block_session/connection.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* NOVA userland includes */
|
||||
#include <nul/motherboard.h>
|
||||
#include <host/dma.h>
|
||||
|
||||
static const bool read_only = false;
|
||||
|
||||
|
||||
class Vancouver_disk : public Genode::Thread<8192>, public StaticReceiver<Vancouver_disk>
|
||||
{
|
||||
private:
|
||||
|
||||
enum { MAX_DISKS = 16 };
|
||||
struct {
|
||||
Block::Connection *blk_con;
|
||||
Block::Session::Operations ops;
|
||||
Genode::size_t blk_size;
|
||||
Genode::size_t blk_cnt;
|
||||
} _diskcon[MAX_DISKS];
|
||||
|
||||
Motherboard &_mb;
|
||||
char *_backing_store_base;
|
||||
char *_backing_store_fb_base;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Vancouver_disk(Motherboard &mb,
|
||||
char * backing_store_base,
|
||||
char * backing_store_fb_base);
|
||||
|
||||
~Vancouver_disk();
|
||||
|
||||
void entry();
|
||||
|
||||
bool receive(MessageDisk &msg);
|
||||
};
|
||||
|
||||
#endif /* _DISK_H_ */
|
@ -63,6 +63,7 @@
|
||||
#include <boot_module_provider.h>
|
||||
#include <console.h>
|
||||
#include <network.h>
|
||||
#include <disk.h>
|
||||
|
||||
enum {
|
||||
PAGE_SIZE_LOG2 = 12UL,
|
||||
@ -91,6 +92,7 @@ Genode::Lock global_lock(Genode::Lock::LOCKED);
|
||||
Genode::Lock timeouts_lock(Genode::Lock::UNLOCKED);
|
||||
|
||||
volatile bool console_init = false;
|
||||
volatile bool disk_init = false;
|
||||
|
||||
|
||||
/* Timer Service */
|
||||
@ -1558,8 +1560,12 @@ int main(int argc, char **argv)
|
||||
/* Create Console Thread */
|
||||
Vancouver_console vcon(machine.get_mb(), fb_size, guest_memory.fb_ds());
|
||||
|
||||
/* Create Disk Thread */
|
||||
Vancouver_disk vdisk(machine.get_mb(), guest_memory.backing_store_local_base(),
|
||||
guest_memory.backing_store_fb_local_base());
|
||||
|
||||
/* Wait for services */
|
||||
while (!console_init);
|
||||
while (!console_init || !disk_init);
|
||||
|
||||
machine.setup_devices(Genode::config()->xml_node().sub_node("machine"));
|
||||
|
||||
|
@ -12,7 +12,7 @@ endif
|
||||
|
||||
LIBS += cxx env blit thread alarm signal server
|
||||
SRC_CC = main.cc nova_user_env.cc device_model_registry.cc
|
||||
SRC_CC += console.cc keyboard.cc network.cc
|
||||
SRC_CC += console.cc keyboard.cc network.cc disk.cc
|
||||
SRC_BIN = mono.tff
|
||||
|
||||
MODEL_SRC_CC += $(notdir $(wildcard $(VANCOUVER_DIR)/model/*.cc))
|
||||
|
Loading…
Reference in New Issue
Block a user