diff --git a/os/run/part_blk.run b/os/run/part_blk.run
index 3dd54e0a39..e7a8275087 100644
--- a/os/run/part_blk.run
+++ b/os/run/part_blk.run
@@ -2,48 +2,40 @@
# \brief Test of Block session interface provided by server/part_blk
#
-if {![have_spec x86] || ![is_qemu_available]} {
- puts "Run script is only supported on x86 and Qemu"; exit 0 }
-
set block_count 20480
-if { [file exists ata.raw] == 0 } then {
+if { [file exists bin/ata.raw] == 0 } then {
# create empty block device file
- catch { exec dd if=/dev/zero of=ata.raw bs=512 count=$block_count }
- # create to tro primary partitions (one is extented) and two logical paritions
+ catch { exec dd if=/dev/zero of=bin/ata.raw bs=512 count=$block_count }
+
+ if [catch { set sfdisk [ exec which sfdisk ] }] {
+ puts "sfdisk needs to be installed!"
+ exit 1
+ }
+
+ # create two primary partitions (one is extented) and two logical paritions
puts "using sfdisk to partition disk image, requires root privileges"
- catch { exec echo "2048,4096,c\n4096,16386,5\n0,0\n0,0\n6144,4096,c\n12288,8192,c\n" | sudo sfdisk -uS -f ata.raw }
+ catch { exec echo "2048,4096,c\n4096,16386,5\n0,0\n0,0\n6144,4096,c\n12288,8192,c\n" | $sfdisk -uS -f bin/ata.raw }
}
-set use_sd_card_drv [expr [have_spec omap4] || [have_spec exynos5] || [have_spec pl180]]
-set use_atapi_drv [have_spec x86]
-
-
#
# Build
#
-set build_components {
+build {
core init
drivers/timer
+ server/rom_blk
server/part_blk
- test/part_blk
+ test/blk/cli
}
-
-lappend_if [have_spec pci] build_components drivers/pci
-lappend_if [have_spec acpi] build_components drivers/acpi
-lappend_if $use_atapi_drv build_components drivers/atapi
-lappend_if $use_sd_card_drv build_components drivers/sd_card
-
-build $build_components
-
create_boot_directory
#
# Generate config
#
-append config {
+install_config {
@@ -65,11 +57,16 @@ append config {
+
+
+
+
+
-
+
@@ -77,102 +74,33 @@ append config {
-
-
+
+
-
-
-
+
+
-
-}
-
-append_if [have_spec acpi] config {
-
-
-
-
-
-
-
-
-
-
-
- }
-
-append_if [expr ![have_spec acpi] && [have_spec pci]] config {
-
-
-
- }
-
-append_if $use_atapi_drv config {
-
-
-
-
-
-
-}
-
-append_if $use_sd_card_drv config {
-
-
-
-
-
-}
-
-append config {
}
-install_config $config
-
#
# Boot modules
#
-set boot_modules {
- core init timer part_blk test-part
-}
-
-lappend_if [have_spec pci] boot_modules pci_drv
-lappend_if [have_spec acpi] boot_modules acpi_drv
-lappend_if $use_atapi_drv boot_modules atapi_drv
-lappend_if $use_sd_card_drv boot_modules sd_card_drv
-
-build_boot_image $boot_modules
+build_boot_image { core init timer rom_blk part_blk test-blk-cli ata.raw }
#
# Qemu
#
-append qemu_args " -nographic -m 64 "
-append_if $use_atapi_drv qemu_args " -boot d -hda ata.raw "
-append_if $use_sd_card_drv qemu_args " -drive file=ata.raw,if=sd "
+append qemu_args " -nographic -m 128 "
-run_genode_until "Success.*\n.*Success.*\n" 10
-
-# Check whether atapi_drv reports the right start and end sectors
-set sector_range [regexp -inline {First block: [0-9]+ last block [0-9]+} $output]
-set sector_range [regexp -all -inline {[0-9]+} $sector_range]
-if {[lindex $sector_range 0] != 0 || [lindex $sector_range 1] != [expr $block_count - 1]} {
- puts "Error: block range mismatch, expected \[0-$block_count), got \[[lindex $sector_range 0]-[lindex $sector_range 1])"
- exit 1
-}
-
-grep_output {^\[init -> test-part}
-unify_output {[0-9]} "x"
-
-compare_output_to {
-[init -> test-partx] Success
-[init -> test-partx] Success
-}
+run_genode_until "Tests finished successfully.*\n.*Tests finished successfully.*\n" 50
+exec rm bin/ata.raw
+puts "Test succeeded"
diff --git a/os/src/server/part_blk/back_end.cc b/os/src/server/part_blk/back_end.cc
deleted file mode 100644
index a9f7bbda7b..0000000000
--- a/os/src/server/part_blk/back_end.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * \brief Back end to other block interface
- * \author Sebsastian Sumpf
- * \date 2011-05-24
- */
-
-/*
- * Copyright (C) 2011-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.
- */
-#include
-#include
-#include
-#include "part_blk.h"
-
-using namespace Genode;
-
-/**
- * Used to block until a packet has been freed
- */
-static Semaphore _alloc_sem(0);
-
-namespace Partition {
-
- size_t _blk_cnt;
- size_t _blk_size;
-
- Allocator_avl _block_alloc(env()->heap());
- Block::Connection _blk(&_block_alloc, 4 * MAX_PACKET_SIZE);
-
- Partition *_part_list[MAX_PARTITIONS]; /* contains pointers to valid partittions or 0 */
-
- Partition *partition(int num) { return (num < MAX_PARTITIONS) ? _part_list[num] : 0; }
- size_t blk_size() { return _blk_size; }
- inline unsigned long max_packets() { return (MAX_PACKET_SIZE / _blk_size); }
- void sync() { _blk.sync(); }
-
- /**
- * Partition table entry format
- */
- struct Partition_record
- {
- enum { INVALID = 0, EXTENTED = 0x5 };
- uint8_t _unused[4];
- uint8_t _type; /* partition type */
- uint8_t _unused2[3];
- uint32_t _lba; /* logical block address */
- uint32_t _sectors; /* number of sectors */
-
- bool is_valid() { return _type != INVALID; }
- bool is_extented() { return _type == EXTENTED; }
- } __attribute__((packed));
-
-
- /**
- * Master/Extented boot record format
- */
- struct Mbr
- {
- uint8_t _unused[446];
- Partition_record _records[4];
- uint16_t _magic;
-
- bool is_valid()
- {
- /* magic number of partition table */
- enum { MAGIC = 0xaa55 };
- return _magic == MAGIC;
- }
- } __attribute__((packed));
-
-
- class Sector
- {
- private:
-
- Block::Packet_descriptor _p;
-
- protected:
-
- static Lock _lock;
-
- public:
-
- Sector(unsigned long blk_nr, unsigned long count, bool write = false)
- {
- using namespace Block;
- Lock::Guard guard(_lock);
- Block::Packet_descriptor::Opcode op = write ? Block::Packet_descriptor::WRITE
- : Block::Packet_descriptor::READ;
- _p = Block::Packet_descriptor(_blk.dma_alloc_packet(_blk_size * count),
- op, blk_nr, count);
- }
-
- void submit_request()
- {
- Lock::Guard guard(_lock);
- _blk.tx()->submit_packet(_p);
- _p = _blk.tx()->get_acked_packet();
-
- /* unblock clients that possibly wait for packet stream allocations */
- if (_alloc_sem.cnt() < 0)
- _alloc_sem.up();
-
- if (!_p.succeeded()) {
- PERR("Could not access block %llu", _p.block_number());
- throw Io_error();
- }
- }
-
- ~Sector()
- {
- Lock::Guard guard(_lock);
- _blk.tx()->release_packet(_p);
- }
-
- template
- T addr() { return reinterpret_cast(_blk.tx()->packet_content(_p)); }
- };
-
- Lock Sector::_lock;
-
-
- void parse_extented(Partition_record *record)
- {
- Partition_record *r = record;
- unsigned lba = r->_lba;
-
- /* first logical partition number */
- int nr = 5;
- do {
- Sector s(lba, 1);
- s.submit_request();
- Mbr *ebr = s.addr();
-
- if (!(ebr->is_valid()))
- throw Io_error();
-
- /* The first record is the actual logical partition. The lba of this
- * partition is relative to the lba of the current EBR */
- Partition_record *logical = &(ebr->_records[0]);
- if (logical->is_valid() && nr < MAX_PARTITIONS) {
- _part_list[nr++] = new (env()->heap()) Partition(logical->_lba + lba, logical->_sectors);
-
- PINF("Partition %d: LBA %u (%u blocks) type %x", nr - 1,
- logical->_lba + lba, logical->_sectors, logical->_type);
- }
-
- /* the second record points to the next EBR (relative form this EBR)*/
- r = &(ebr->_records[1]);
- lba += ebr->_records[1]._lba;
-
- } while (r->is_valid());
- }
-
-
- void parse_mbr(Mbr *mbr)
- {
- /* no partition table, use whole disc as partition 0 */
- if (!(mbr->is_valid()))
- _part_list[0] = new(env()->heap())Partition(0, _blk_cnt - 1);
-
- for (int i = 0; i < 4; i++) {
- Partition_record *r = &(mbr->_records[i]);
-
- if (r->is_valid())
- PINF("Partition %d: LBA %u (%u blocks) type: %x", i + 1, r->_lba,
- r->_sectors, r->_type);
- else
- continue;
-
- if (r->is_extented())
- parse_extented(r);
- else
- _part_list[i + 1] = new(env()->heap()) Partition(r->_lba, r->_sectors);
- }
- }
-
-
- void init()
- {
- Block::Session::Operations ops;
-
- /* device info */
- _blk.info(&_blk_cnt, &_blk_size, &ops);
-
- /* read MBR */
- Sector s(0, 1);
- s.submit_request();
- parse_mbr(s.addr());
- }
-
-
- void _io(unsigned long lba, unsigned long count, uint8_t *buf, bool write)
- {
- unsigned long bytes;
-
- while (count) {
-
- unsigned long curr_count = min(count, max_packets());
- bytes = curr_count * _blk_size;
- bool alloc = false;
- while (!alloc) {
- try {
- Sector sec(lba, curr_count, write);
-
- if (!write) {
- sec.submit_request();
- memcpy(buf, sec.addr(), bytes);
- }
- else {
- memcpy(sec.addr(), buf, bytes);
- sec.submit_request();
- }
-
- alloc = true;
- } catch (Block::Session::Tx::Source::Packet_alloc_failed) {
- /* block */
- _alloc_sem.down();
- }
- }
-
- lba += curr_count;
- count -= curr_count;
- buf += bytes;
- }
-
- /* zero out rest of page */
- bytes = (count * _blk_size) % 4096;
- if (bytes)
- memset(buf, 0, bytes);
- }
-
-
- void Partition::io(unsigned long block_nr, unsigned long count, void *buf, bool write)
- {
- if (block_nr + count > _sectors)
- throw Io_error();
-
- _io(_lba + block_nr, count, (uint8_t *)buf, write);
- }
-}
diff --git a/os/src/server/part_blk/component.h b/os/src/server/part_blk/component.h
new file mode 100644
index 0000000000..44bd007eb8
--- /dev/null
+++ b/os/src/server/part_blk/component.h
@@ -0,0 +1,292 @@
+/*
+ * \brief Block-session component for partition server
+ * \author Stefan Kalkowski
+ * \date 2013-12-04
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _PART_BLK__COMPONENT_H_
+#define _PART_BLK__COMPONENT_H_
+
+#include
+#include
+#include
+
+#include "partition_table.h"
+
+namespace Block {
+
+ using namespace Genode;
+
+ class Session_component;
+ class Root;
+};
+
+
+class Block::Session_component : public Block::Session_rpc_object,
+ public List::Element,
+ public Block_dispatcher
+{
+ private:
+
+ Ram_dataspace_capability _rq_ds;
+ addr_t _rq_phys;
+ Partition *_partition;
+ Signal_dispatcher _sink_ack;
+ Signal_dispatcher _sink_submit;
+ bool _req_queue_full;
+ bool _ack_queue_full;
+ Packet_descriptor _p_to_handle;
+ unsigned _p_in_fly;
+
+ /**
+ * Acknowledge a packet already handled
+ */
+ inline void _ack_packet(Packet_descriptor &packet)
+ {
+ if (!tx_sink()->ready_to_ack())
+ PERR("Not ready to ack!");
+
+ tx_sink()->acknowledge_packet(packet);
+ _p_in_fly--;
+ }
+
+ /**
+ * Range check packet request
+ */
+ inline bool _range_check(Packet_descriptor &p) {
+ return p.block_number() + p.block_count() <= _partition->sectors; }
+
+ /**
+ * Handle a single request
+ */
+ void _handle_packet(Packet_descriptor packet)
+ {
+ _p_to_handle = packet;
+ _p_to_handle.succeeded(false);
+
+ /* ignore invalid packets */
+ if (!packet.valid() || !_range_check(_p_to_handle)) {
+ _ack_packet(_p_to_handle);
+ return;
+ }
+
+ bool write = _p_to_handle.operation() == Packet_descriptor::WRITE;
+ sector_t off = _p_to_handle.block_number() + _partition->lba;
+ size_t cnt = _p_to_handle.block_count();
+ void* addr = tx_sink()->packet_content(_p_to_handle);
+ try {
+ Driver::driver().io(write, off, cnt, addr, *this, _p_to_handle);
+ } catch (Block::Session::Tx::Source::Packet_alloc_failed) {
+ _req_queue_full = true;
+ Session_component::wait_queue().insert(this);
+ }
+ }
+
+ /**
+ * Triggered when a packet was placed into the empty submit queue
+ */
+ void _packet_avail(unsigned)
+ {
+ _ack_queue_full = _p_in_fly >= tx_sink()->ack_slots_free();
+
+ /*
+ * as long as more packets are available, and we're able to ack
+ * them, and the driver's request queue isn't full,
+ * direct the packet request to the driver backend
+ */
+ for (; !_req_queue_full && tx_sink()->packet_avail() &&
+ !_ack_queue_full; _p_in_fly++,
+ _ack_queue_full = _p_in_fly >= tx_sink()->ack_slots_free())
+ _handle_packet(tx_sink()->get_packet());
+ }
+
+ /**
+ * Triggered when an ack got removed from the full ack queue
+ */
+ void _ready_to_ack(unsigned) { _packet_avail(0); }
+
+ public:
+
+ /**
+ * Constructor
+ */
+ Session_component(Ram_dataspace_capability rq_ds,
+ Partition *partition,
+ Rpc_entrypoint &ep,
+ Signal_receiver &receiver)
+ : Session_rpc_object(rq_ds, ep),
+ _rq_ds(rq_ds),
+ _rq_phys(Dataspace_client(_rq_ds).phys_addr()),
+ _partition(partition),
+ _sink_ack(receiver, *this, &Session_component::_ready_to_ack),
+ _sink_submit(receiver, *this, &Session_component::_packet_avail),
+ _req_queue_full(false),
+ _ack_queue_full(false),
+ _p_in_fly(0)
+ {
+ _tx.sigh_ready_to_ack(_sink_ack);
+ _tx.sigh_packet_avail(_sink_submit);
+ }
+
+ Partition *partition() { return _partition; }
+
+ void dispatch(Packet_descriptor &request, Packet_descriptor &reply)
+ {
+ if (request.operation() == Block::Packet_descriptor::READ) {
+ void *src =
+ Driver::driver().session().tx()->packet_content(reply);
+ Genode::size_t sz =
+ request.block_count() * Driver::driver().blk_size();
+ Genode::memcpy(tx_sink()->packet_content(request), src, sz);
+ }
+ request.succeeded(true);
+ _ack_packet(request);
+
+ if (_ack_queue_full)
+ _packet_avail(0);
+ }
+
+ static List& wait_queue()
+ {
+ static List l;
+ return l;
+ }
+
+ static void wake_up()
+ {
+ for (Session_component *c = wait_queue().first(); c; c = c->next())
+ {
+ wait_queue().remove(c);
+ c->_req_queue_full = false;
+ c->_handle_packet(c->_p_to_handle);
+ c->_packet_avail(0);
+ }
+ }
+
+ /*******************************
+ ** Block session interface **
+ *******************************/
+
+ void info(sector_t *blk_count, size_t *blk_size,
+ Operations *ops)
+ {
+ *blk_count = _partition->sectors;
+ *blk_size = Driver::driver().blk_size();
+ ops->set_operation(Packet_descriptor::READ);
+ ops->set_operation(Packet_descriptor::WRITE);
+ }
+
+ void sync() { Driver::driver().session().sync(); }
+};
+
+
+/**
+ * Root component, handling new session requests
+ */
+class Block::Root :
+ public Genode::Root_component
+{
+ private:
+
+ Rpc_entrypoint &_ep;
+ Signal_receiver &_receiver;
+
+ long _partition_num(const char *session_label)
+ {
+ long num = -1;
+
+ try {
+ using namespace Genode;
+
+ Xml_node policy = Genode::config()->xml_node().sub_node("policy");
+
+ for (;; policy = policy.next("policy")) {
+ char label_buf[64];
+ policy.attribute("label").value(label_buf, sizeof(label_buf));
+
+ if (Genode::strcmp(session_label, label_buf))
+ continue;
+
+ /* read partition attribute */
+ policy.attribute("partition").value(&num);
+ break;
+ }
+ } catch (...) {}
+
+ return num;
+ }
+
+ protected:
+
+ /**
+ * Always returns the singleton block-session component
+ */
+ Session_component *_create_session(const char *args)
+ {
+ size_t ram_quota =
+ Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
+ size_t tx_buf_size =
+ Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
+
+ /* delete ram quota by the memory needed for the session */
+ size_t session_size = max((size_t)4096,
+ sizeof(Session_component)
+ + sizeof(Allocator_avl));
+ if (ram_quota < session_size)
+ throw Root::Quota_exceeded();
+
+ /*
+ * Check if donated ram quota suffices for both
+ * communication buffers. Also check both sizes separately
+ * to handle a possible overflow of the sum of both sizes.
+ */
+ if (tx_buf_size > ram_quota - session_size) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, tx_buf_size + session_size);
+ throw Root::Quota_exceeded();
+ }
+
+ /* Search for configured partition number and the corresponding partition */
+ char label_buf[64];
+ Genode::Arg_string::find_arg(args,
+ "label").string(label_buf,
+ sizeof(label_buf),
+ "");
+ long num = _partition_num(label_buf);
+ if (num < 0) {
+ PERR("No confguration found for client: %s", label_buf);
+ throw Root::Invalid_args();
+ }
+
+ if (!Partition_table::table().partition(num)) {
+ PERR("Partition %ld unavailable", num);
+ throw Root::Unavailable();
+ }
+
+ Ram_dataspace_capability ds_cap;
+ ds_cap = Genode::env()->ram_session()->alloc(tx_buf_size, true);
+ return new (md_alloc())
+ Session_component(ds_cap,
+ Partition_table::table().partition(num),
+ _ep, _receiver);
+ }
+
+ public:
+
+ Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
+ Signal_receiver &receiver)
+ :
+ Root_component(session_ep, md_alloc),
+ _ep(*session_ep),
+ _receiver(receiver)
+ { }
+};
+
+#endif /* _PART_BLK__COMPONENT_H_ */
diff --git a/os/src/server/part_blk/driver.h b/os/src/server/part_blk/driver.h
new file mode 100644
index 0000000000..05e342ac51
--- /dev/null
+++ b/os/src/server/part_blk/driver.h
@@ -0,0 +1,155 @@
+/*
+ * \brief Block-session driver for partition server
+ * \author Stefan Kalkowski
+ * \date 2013-12-04
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _PART_BLK__DRIVER_H_
+#define _PART_BLK__DRIVER_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Block {
+ class Block_dispatcher;
+ class Driver;
+};
+
+
+class Block::Block_dispatcher
+{
+ public:
+
+ virtual void dispatch(Packet_descriptor&, Packet_descriptor&) = 0;
+};
+
+
+bool operator== (const Block::Packet_descriptor& p1,
+ const Block::Packet_descriptor& p2)
+{
+ return p1.operation() == p2.operation() &&
+ p1.block_number() == p2.block_number() &&
+ p1.block_count() == p2.block_count();
+}
+
+
+class Block::Driver
+{
+ public:
+
+ class Request : public Genode::List::Element
+ {
+ private:
+
+ Block_dispatcher &_dispatcher;
+ Packet_descriptor _cli;
+ Packet_descriptor _srv;
+
+ public:
+
+ Request(Block_dispatcher &d,
+ Packet_descriptor &cli,
+ Packet_descriptor &srv)
+ : _dispatcher(d), _cli(cli), _srv(srv) {}
+
+ bool handle(Packet_descriptor& reply)
+ {
+ bool ret = reply == _srv;
+ if (ret) _dispatcher.dispatch(_cli, reply);
+ return ret;
+ }
+ };
+
+ private:
+
+ enum { BLK_SZ = Session::TX_QUEUE_SIZE*sizeof(Request) };
+
+ Genode::Tslab _r_slab;
+ Genode::List _r_list;
+ Genode::Allocator_avl _block_alloc;
+ Block::Connection _session;
+ Block::sector_t _blk_cnt;
+ Genode::size_t _blk_size;
+ Genode::Signal_dispatcher _source_ack;
+ Genode::Signal_dispatcher _source_submit;
+
+ void _ready_to_submit(unsigned);
+
+ void _ack_avail(unsigned)
+ {
+ /* check for acknowledgements */
+ while (_session.tx()->ack_avail()) {
+ Packet_descriptor p = _session.tx()->get_acked_packet();
+ for (Request *r = _r_list.first(); r; r = r->next()) {
+ if (r->handle(p)) {
+ _r_list.remove(r);
+ Genode::destroy(&_r_slab, r);
+ break;
+ }
+ }
+ _session.tx()->release_packet(p);
+ }
+
+ _ready_to_submit(0);
+ }
+
+ public:
+
+ Driver(Genode::Signal_receiver &receiver)
+ : _r_slab(Genode::env()->heap()),
+ _block_alloc(Genode::env()->heap()),
+ _session(&_block_alloc, 4 * 1024 * 1024),
+ _source_ack(receiver, *this, &Driver::_ack_avail),
+ _source_submit(receiver, *this, &Driver::_ready_to_submit)
+ {
+ Block::Session::Operations ops;
+ _session.info(&_blk_cnt, &_blk_size, &ops);
+ }
+
+ Genode::size_t blk_size() { return _blk_size; }
+ Genode::size_t blk_cnt() { return _blk_cnt; }
+ Session_client& session() { return _session; }
+
+ void work_asynchronously()
+ {
+ _session.tx_channel()->sigh_ack_avail(_source_ack);
+ _session.tx_channel()->sigh_ready_to_submit(_source_submit);
+ }
+
+ static Driver& driver();
+
+ void io(bool write, sector_t nr, Genode::size_t cnt, void* addr,
+ Block_dispatcher &dispatcher, Packet_descriptor& cli)
+ {
+ if (!_session.tx()->ready_to_submit())
+ throw Block::Session::Tx::Source::Packet_alloc_failed();
+
+ Block::Packet_descriptor::Opcode op = write
+ ? Block::Packet_descriptor::WRITE
+ : Block::Packet_descriptor::READ;
+ Genode::size_t size = _blk_size * cnt;
+ Packet_descriptor p(_session.dma_alloc_packet(size),
+ op, nr, cnt);
+ Request *r = new (&_r_slab) Request(dispatcher, cli, p);
+ _r_list.insert(r);
+
+ if (write)
+ Genode::memcpy(_session.tx()->packet_content(p),
+ addr, size);
+
+ _session.tx()->submit_packet(p);
+ }
+};
+
+#endif /* _PART_BLK__DRIVER_H_ */
diff --git a/os/src/server/part_blk/main.cc b/os/src/server/part_blk/main.cc
index 8d14dddedb..b6a589b9a3 100644
--- a/os/src/server/part_blk/main.cc
+++ b/os/src/server/part_blk/main.cc
@@ -1,6 +1,7 @@
/*
* \brief Front end of the partition server
* \author Sebastian Sumpf
+ * \author Stefan Kalkowski
* \date 2011-05-30
*/
@@ -11,227 +12,47 @@
* under the terms of the GNU General Public License version 2.
*/
-#include
#include
#include
#include
-#include
-#include "part_blk.h"
-namespace Block {
+#include "driver.h"
+#include "partition_table.h"
+#include "component.h"
- long partition_num(const char *session_label)
- {
- long num = -1;
+static Genode::Signal_receiver receiver;
- try {
- using namespace Genode;
-
- Xml_node policy = Genode::config()->xml_node().sub_node("policy");
-
- for (;; policy = policy.next("policy")) {
- char label_buf[64];
- policy.attribute("label").value(label_buf, sizeof(label_buf));
-
- if (Genode::strcmp(session_label, label_buf))
- continue;
-
- /* read partition attribute */
- policy.attribute("partition").value(&num);
- break;
- }
- } catch (...) {}
-
- return num;
- }
-
-
- class Session_component : public Session_rpc_object
- {
- private:
-
- class Tx_thread : public Genode::Thread<8192>
- {
- private:
-
- Session_component *_session;
-
- public:
-
- Tx_thread(Session_component *session)
- : Thread("block_session_tx"), _session(session) { }
-
- void entry()
- {
- using namespace Genode;
-
- Session_component::Tx::Sink *tx_sink = _session->tx_sink();
- Block::Packet_descriptor packet;
-
- /* handle requests */
- while (true) {
-
- /* blocking get packet from client */
- packet = tx_sink->get_packet();
- if (!packet.valid()) {
- PWRN("received invalid packet");
- continue;
- }
-
- packet.succeeded(false);
- bool write = false;
-
- switch (packet.operation()) {
-
- case Block::Packet_descriptor::WRITE:
- write = true;
-
- case Block::Packet_descriptor::READ:
-
- try {
- _session->partition()->io(packet.block_number(),
- packet.block_count(),
- tx_sink->packet_content(packet),
- write);
- packet.succeeded(true);
- }
- catch (Partition::Io_error) {
- PWRN("Io error!");
- }
- break;
-
- default:
- PWRN("received invalid packet");
- continue;
- }
-
- /* acknowledge packet to the client */
- if (!tx_sink->ready_to_ack())
- PDBG("need to wait until ready-for-ack");
- tx_sink->acknowledge_packet(packet);
- }
- }
- };
-
- struct Partition::Partition *_partition; /* partition belonging to this session */
- Genode::Dataspace_capability _tx_ds; /* buffer for tx channel */
- Tx_thread _tx_thread;
-
- public:
-
- Session_component(Genode::Dataspace_capability tx_ds,
- Partition::Partition *partition,
- Genode::Rpc_entrypoint &ep)
- :
- Session_rpc_object(tx_ds, ep),
- _partition(partition), _tx_ds(tx_ds), _tx_thread(this)
- {
- _tx_thread.start();
- }
-
- void info(Genode::size_t *blk_count, Genode::size_t *blk_size, Operations *ops)
- {
- *blk_count = _partition->_sectors;
- *blk_size = Partition::blk_size();
- ops->set_operation(Packet_descriptor::READ);
- ops->set_operation(Packet_descriptor::WRITE);
- }
-
- void sync() { Partition::sync(); }
-
- Partition::Partition *partition() { return _partition; }
- };
-
-
- typedef Genode::Root_component Root_component;
-
- /**
- * Root component, handling new session requests
- */
- class Root : public Root_component
- {
- private:
-
- Genode::Rpc_entrypoint &_ep;
-
- protected:
-
- /**
- * Always returns
- */
- Session_component *_create_session(const char *args)
- {
- using namespace Genode;
-
- Genode::size_t ram_quota =
- Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- Genode::size_t tx_buf_size =
- Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
-
- /* delete ram quota by the memory needed for the session */
- Genode::size_t session_size = max((Genode::size_t)4096,
- sizeof(Session_component)
- + sizeof(Allocator_avl));
-
- if (ram_quota < session_size)
- throw Root::Quota_exceeded();
-
- /*
- * Check if donated ram quota suffices for both
- * communication buffers. Also check both sizes separately
- * to handle a possible overflow of the sum of both sizes.
- */
- if (tx_buf_size > ram_quota - session_size) {
- PERR("insufficient 'ram_quota', got %zd, need %zd",
- ram_quota, tx_buf_size + session_size);
- throw Root::Quota_exceeded();
- }
-
- /* Search for configured partition number and the corresponding partition */
- char label_buf[64];
-
- Genode::Arg_string::find_arg(args, "label").string(label_buf, sizeof(label_buf), "");
-
- long num = partition_num(label_buf);
- if (num < 0) {
- PERR("No confguration found for client: %s", label_buf);
- throw Root::Invalid_args();
- }
-
- if (!Partition::partition(num)) {
- PERR("Partition %ld unavailable", num);
- throw Root::Unavailable();
- }
-
- return new (md_alloc())
- Session_component(env()->ram_session()->alloc(tx_buf_size),
- Partition::partition(num), _ep);
- }
-
- public:
-
- Root(Genode::Rpc_entrypoint *session_ep, Genode::Allocator *md_alloc)
- : Root_component(session_ep, md_alloc), _ep(*session_ep) { }
- };
+Block::Driver& Block::Driver::driver()
+{
+ static Block::Driver driver(receiver);
+ return driver;
}
+void Block::Driver::_ready_to_submit(unsigned) {
+ Block::Session_component::wake_up(); }
+
+
int main()
{
using namespace Genode;
- try {
- Partition::init();
- } catch (Partition::Io_error) {
- return -1;
+ if (!Block::Partition_table::table().avail()) {
+ PERR("No valid partition table found");
+ return 1;
}
- enum { STACK_SIZE = 16384 };
+ enum { STACK_SIZE = 512 * sizeof(Genode::size_t) };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "part_ep");
- static Block::Root block_root(&ep, env()->heap());
+ static Block::Root block_root(&ep, env()->heap(), receiver);
env()->parent()->announce(ep.manage(&block_root));
- sleep_forever();
+
+ while (true) {
+ Signal s = receiver.wait_for_signal();
+ static_cast(s.context())->dispatch(s.num());
+ }
+
return 0;
}
diff --git a/os/src/server/part_blk/part_blk.h b/os/src/server/part_blk/part_blk.h
deleted file mode 100644
index a2ee96aff1..0000000000
--- a/os/src/server/part_blk/part_blk.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * \brief Back-end header
- * \author Sebastian Sumpf
- * \date 2011-05-30
- */
-
-/*
- * Copyright (C) 2011-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.
- */
-
-#ifndef _PART_BLK_H_
-#define _PART_BLK_H_
-
-#include
-#include
-
-namespace Partition {
-
- enum {
- MAX_PARTITIONS = 32, /* maximum supported paritions */
- MAX_PACKET_SIZE = 1024 * 1024
- };
-
- /**
- * The partition type
- */
- struct Partition
- {
- Genode::uint32_t _lba; /* logical block address on device */
- Genode::uint32_t _sectors; /* number of sectors in patitions */
-
- Partition(Genode::uint32_t lba, Genode::uint32_t sectors)
- : _lba(lba), _sectors(sectors) { }
-
- /**
- * Write/read blocks
- *
- * \param block_nr block number of partition to access
- * \param count number of blocks to read/write
- * \param buf buffer which containing the data to write or which is
- * filled by reads
- * \param write true for a write operations, false for a read
- * \throw Io_error
- */
- void io(unsigned long block_nr, unsigned long count, void *buf, bool write = false);
- };
-
- /**
- * Excpetions
- */
- class Io_error : public Genode::Exception {};
-
- /**
- * Initialize the back-end and parse partitions information
- *
- * \throw Io_error
- */
- void init();
-
- /**
- * Return partition information
- *
- * \param num partition number
- * \return pointer to partition if it could be found, zero otherwise
- */
- Partition *partition(int num);
-
- /**
- * Returns block size of back end
- */
- Genode::size_t blk_size();
-
- /**
- * Synchronize with backend device
- */
- void sync();
-}
-
-#endif /* _PART_BLK_H_ */
diff --git a/os/src/server/part_blk/partition_table.h b/os/src/server/part_blk/partition_table.h
new file mode 100644
index 0000000000..539adbe486
--- /dev/null
+++ b/os/src/server/part_blk/partition_table.h
@@ -0,0 +1,206 @@
+/*
+ * \brief Partition table definitions
+ * \author Sebastian Sumpf
+ * \author Stefan Kalkowski
+ * \date 2013-12-04
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef _PART_BLK__PARTITION_TABLE_H_
+#define _PART_BLK__PARTITION_TABLE_H_
+
+#include
+#include
+#include
+
+#include "driver.h"
+
+namespace Block {
+ struct Partition;
+ class Partition_table;
+}
+
+
+struct Block::Partition
+{
+ Genode::uint32_t lba; /* logical block address on device */
+ Genode::uint32_t sectors; /* number of sectors in patitions */
+
+ Partition(Genode::uint32_t l, Genode::uint32_t s)
+ : lba(l), sectors(s) { }
+};
+
+
+class Block::Partition_table
+{
+ private:
+
+ class Sector
+ {
+ private:
+
+ Session_client &_session;
+ Packet_descriptor _p;
+
+ public:
+
+ Sector(unsigned long blk_nr,
+ unsigned long count,
+ bool write = false)
+ : _session(Driver::driver().session()),
+ _p(_session.dma_alloc_packet(Driver::driver().blk_size() * count),
+ write ? Packet_descriptor::WRITE : Packet_descriptor::READ,
+ blk_nr, count)
+ {
+ _session.tx()->submit_packet(_p);
+ _p = _session.tx()->get_acked_packet();
+ if (!_p.succeeded())
+ PERR("Could not access block %llu", _p.block_number());
+ }
+
+ ~Sector() { _session.tx()->release_packet(_p); }
+
+ template T addr() {
+ return reinterpret_cast(_session.tx()->packet_content(_p)); }
+ };
+
+
+ /**
+ * Partition table entry format
+ */
+ struct Partition_record
+ {
+ enum { INVALID = 0, EXTENTED = 0x5 };
+ Genode::uint8_t _unused[4];
+ Genode::uint8_t _type; /* partition type */
+ Genode::uint8_t _unused2[3];
+ Genode::uint32_t _lba; /* logical block address */
+ Genode::uint32_t _sectors; /* number of sectors */
+
+ bool is_valid() { return _type != INVALID; }
+ bool is_extented() { return _type == EXTENTED; }
+ } __attribute__((packed));
+
+
+ /**
+ * Master/Extented boot record format
+ */
+ struct Mbr
+ {
+ Genode::uint8_t _unused[446];
+ Partition_record _records[4];
+ Genode::uint16_t _magic;
+
+ bool is_valid()
+ {
+ /* magic number of partition table */
+ enum { MAGIC = 0xaa55 };
+ return _magic == MAGIC;
+ }
+ } __attribute__((packed));
+
+
+ enum { MAX_PARTITIONS = 32 };
+
+ Partition *_part_list[MAX_PARTITIONS]; /* contains pointers to valid
+ partitions or 0 */
+
+ void _parse_extented(Partition_record *record)
+ {
+ Partition_record *r = record;
+ unsigned lba = r->_lba;
+
+ /* first logical partition number */
+ int nr = 5;
+ do {
+ Sector s(lba, 1);
+ Mbr *ebr = s.addr();
+
+ if (!(ebr->is_valid()))
+ return;
+
+ /* The first record is the actual logical partition. The lba of this
+ * partition is relative to the lba of the current EBR */
+ Partition_record *logical = &(ebr->_records[0]);
+ if (logical->is_valid() && nr < MAX_PARTITIONS) {
+ _part_list[nr++] = new (Genode::env()->heap())
+ Partition(logical->_lba + lba, logical->_sectors);
+
+ PINF("Partition %d: LBA %u (%u blocks) type %x", nr - 1,
+ logical->_lba + lba, logical->_sectors, logical->_type);
+ }
+
+ /*
+ * the second record points to the next EBR
+ * (relative form this EBR)
+ */
+ r = &(ebr->_records[1]);
+ lba += ebr->_records[1]._lba;
+
+ } while (r->is_valid());
+ }
+
+
+ void _parse_mbr(Mbr *mbr)
+ {
+ /* no partition table, use whole disc as partition 0 */
+ if (!(mbr->is_valid()))
+ _part_list[0] = new(Genode::env()->heap())
+ Partition(0, Driver::driver().blk_cnt() - 1);
+
+ for (int i = 0; i < 4; i++) {
+ Partition_record *r = &(mbr->_records[i]);
+
+ if (r->is_valid())
+ PINF("Partition %d: LBA %u (%u blocks) type: %x",
+ i + 1, r->_lba, r->_sectors, r->_type);
+ else
+ continue;
+
+ if (r->is_extented())
+ _parse_extented(r);
+ else
+ _part_list[i + 1] = new(Genode::env()->heap())
+ Partition(r->_lba, r->_sectors);
+ }
+ }
+
+ Partition_table()
+ {
+ Sector s(0, 1);
+ _parse_mbr(s.addr());
+
+ /*
+ * we read all partition information,
+ * now it's safe to turn in asynchronous mode
+ */
+ Driver::driver().work_asynchronously();
+ }
+
+ public:
+
+ Partition *partition(int num) {
+ return (num < MAX_PARTITIONS) ? _part_list[num] : 0; }
+
+ bool avail()
+ {
+ for (unsigned num = 0; num < MAX_PARTITIONS; num++)
+ if (_part_list[num])
+ return true;
+ return false;
+ }
+
+ static Partition_table& table()
+ {
+ static Partition_table table;
+ return table;
+ }
+};
+
+#endif /* _PART_BLK__PARTITION_TABLE_H_ */
diff --git a/os/src/server/part_blk/target.mk b/os/src/server/part_blk/target.mk
index 7653984545..c2965d314b 100644
--- a/os/src/server/part_blk/target.mk
+++ b/os/src/server/part_blk/target.mk
@@ -1,3 +1,3 @@
TARGET = part_blk
LIBS = base config
-SRC_CC = main.cc back_end.cc
+SRC_CC = main.cc
diff --git a/os/src/test/part_blk/main.cc b/os/src/test/part_blk/main.cc
deleted file mode 100644
index d7484e1e20..0000000000
--- a/os/src/test/part_blk/main.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * \brief Test that reads and writes the first and the last block of a given
- * block device
- * \author Sebastian Sumpf
- * \date 2011-05-30
- */
-
-/*
- * Copyright (C) 2011-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.
- */
-
-#include
-#include
-#include
-
-static const int verbose = 0;
-using namespace Genode;
-
-static Allocator_avl _block_alloc(env()->heap());
-static Block::Connection _blk(&_block_alloc);
-static size_t _blk_size;
-
-
-class Sector
-{
- private:
-
- Block::Packet_descriptor _p;
-
- public:
-
- Sector(unsigned long blk_nr, unsigned long count, bool write = false)
- {
- Block::Packet_descriptor::Opcode op = write ? Block::Packet_descriptor::WRITE
- : Block::Packet_descriptor::READ;
- try {
- _p = Block::Packet_descriptor( _blk.dma_alloc_packet(_blk_size * count),
- op, blk_nr, count);
- } catch (Block::Session::Tx::Source::Packet_alloc_failed) {
- PERR("Packet overrun!");
- _p = _blk.tx()->get_acked_packet();
- }
- }
-
- ~Sector() { _blk.tx()->release_packet(_p); }
-
- template
- T addr() { return reinterpret_cast(_blk.tx()->packet_content(_p)); }
-
- void submit_request()
- {
- _blk.tx()->submit_packet(_p);
- _p = _blk.tx()->get_acked_packet();
-
- if (!_p.succeeded())
- PERR("Could not access block %llu", _p.block_number());
- }
-
-};
-
-
-int main()
-{
- unsigned pattern;
- try {
- Genode::config()->xml_node().attribute("pattern").value(&pattern); }
- catch (...) { PERR("Test Failed"); return 1; }
-
- size_t blk_count;
- Block::Session::Operations ops;
- _blk.info(&blk_count, &_blk_size, &ops);
-
- if (verbose)
- printf("Found device %zu blocks of %zu bytes\n", blk_count, _blk_size);
-
- /* write first and last block of device useing 'pattern' */
- {
- Sector s(0, 1, true);
- memset(s.addr(), pattern, _blk_size);
- s.submit_request();
-
- Sector s_last(blk_count - 1, 1, true);
- memset(s_last.addr(), 2 * pattern, _blk_size);
- s_last.submit_request();
- }
-
- /* read first and last block from device and compare to 'pattern' */
- Sector s(0, 1);
- s.submit_request();
-
- Sector s_last(blk_count - 1, 1);
- s_last.submit_request();
-
- unsigned *val = s.addr();
- unsigned *val_last = s_last.addr();
-
- unsigned cmp_val, cmp_val_last;
- memset(&cmp_val, pattern, 4);
- memset(&cmp_val_last, 2 * pattern, 4);
-
- if (verbose) {
- printf("READ blk %05u: %x\n", 0, *val);
- printf("READ blk %05zu: %x\n", blk_count - 1, *val_last);
- }
-
- if (*val != cmp_val || *val_last != cmp_val_last)
- printf("Failed\n");
- else
- printf("Success\n");
-
- return 0;
-}
diff --git a/os/src/test/part_blk/target.mk b/os/src/test/part_blk/target.mk
deleted file mode 100644
index 521e963e08..0000000000
--- a/os/src/test/part_blk/target.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-TARGET = test-part
-SRC_CC = main.cc
-LIBS = base config
diff --git a/tool/autopilot.list b/tool/autopilot.list
index 628050be66..e21b850fb1 100644
--- a/tool/autopilot.list
+++ b/tool/autopilot.list
@@ -35,3 +35,4 @@ seoul-auto
resource_request
resource_yield
gdb_monitor
+part_blk