/* * \brief Block interface * \author Markus Partheymueller * \author Alexander Boettcher * \date 2012-09-15 */ /* * Copyright (C) 2012 Intel Corporation * Copyright (C) 2013-2017 Genode Labs GmbH * * This file 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 #include #include #include /* local includes */ #include "synced_motherboard.h" /* Seoul includes */ #include namespace Seoul { class Disk; class Disk_signal; } class Seoul::Disk_signal { private: Disk &_obj; unsigned _id; void _signal(); public: Genode::Signal_handler const sigh; Disk_signal(Genode::Entrypoint &ep, Disk &obj, Block::Connection &block, unsigned disk_nr) : _obj(obj), _id(disk_nr), sigh(ep, *this, &Disk_signal::_signal) { block.tx_channel()->sigh_ack_avail(sigh); block.tx_channel()->sigh_ready_to_submit(sigh); } }; class Seoul::Disk : public StaticReceiver { private: Genode::Env &_env; /* helper class to lookup a MessageDisk object */ class Avl_entry : public Genode::Avl_node { private: Genode::addr_t const _key; MessageDisk * const _msg; /* * Noncopyable */ Avl_entry(Avl_entry const &); Avl_entry &operator = (Avl_entry const &); public: Avl_entry(void * key, MessageDisk * const msg) : _key(reinterpret_cast(key)), _msg(msg) { } bool higher(Avl_entry *e) const { return e->_key > _key; } Avl_entry *find(Genode::addr_t ptr) { if (ptr == _key) return this; Avl_entry *obj = this->child(ptr > _key); return obj ? obj->find(ptr) : 0; } MessageDisk * msg() { return _msg; } }; /* block session used by disk models of VMM */ enum { MAX_DISKS = 4 }; struct disk_session { Block::Connection *blk_con; Block::Session::Info info; Disk_signal *signal; } _diskcon[MAX_DISKS] { }; Synced_motherboard &_motherboard; char * const _backing_store_base; size_t const _backing_store_size; /* slabs for temporary holding MessageDisk objects */ typedef Genode::Tslab MessageDisk_Slab; typedef Genode::Synced_allocator MessageDisk_Slab_Sync; MessageDisk_Slab_Sync _tslab_msg; /* Structure to find back the MessageDisk object out of a Block Ack */ typedef Genode::Tslab Avl_entry_slab; typedef Genode::Synced_allocator Avl_entry_slab_sync; Avl_entry_slab_sync _tslab_avl; Genode::Avl_tree _lookup_msg { }; Genode::Avl_tree _restart_msg { }; /* _alloc_lock protects both lists + alloc_packet/release_packet !!! */ Genode::Lock _alloc_lock { }; /* * Noncopyable */ Disk(Disk const &); Disk &operator = (Disk const &); void check_restart(); bool restart(struct disk_session const &, MessageDisk * const); bool execute(bool const write, struct disk_session const &, MessageDisk const &); template bool check_dma_descriptors(MessageDisk const * const msg, FN const &fn) { /* check bounds for read and write operations */ for (unsigned i = 0; i < msg->dmacount; i++) { char * const dma_addr = _backing_store_base + msg->dma[i].byteoffset + msg->physoffset; /* check for bounds */ if (dma_addr >= _backing_store_base + _backing_store_size || dma_addr < _backing_store_base) return false; if (!fn(dma_addr, i)) return false; } return true; } /* find the corresponding MessageDisk object */ Avl_entry * lookup_and_remove(Genode::Avl_tree &tree, void * specific_obj = nullptr) { Genode::Lock::Guard lock_guard(_alloc_lock); Avl_entry * obj = tree.first(); if (obj && specific_obj) obj = obj->find(reinterpret_cast(specific_obj)); if (obj) tree.remove(obj); return obj; } public: /** * Constructor */ Disk(Genode::Env &, Synced_motherboard &, char * backing_store_base, Genode::size_t backing_store_size); void handle_disk(unsigned); bool receive(MessageDisk &msg); void register_host_operations(Motherboard &); }; #endif /* _DISK_H_ */