mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 11:27:29 +00:00
parent
35bb156972
commit
af86e33c3f
@ -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 {
|
||||
<config prio_levels="1" verbose="yes">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
@ -65,11 +57,16 @@ append config {
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="rom_blk">
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<provides><service name="Block"/></provides>
|
||||
<config file="ata.raw" block_size="512"/>
|
||||
</start>
|
||||
<start name="part_blk">
|
||||
<resource name="RAM" quantum="10M" />
|
||||
<provides><service name="Block" /></provides>
|
||||
<route>
|
||||
<any-service><child name="blk_drv"/> <parent/><any-child/></any-service>
|
||||
<any-service><child name="rom_blk"/> <parent/><any-child/></any-service>
|
||||
</route>
|
||||
<config>
|
||||
<policy label="test-part1" partition="6"/>
|
||||
@ -77,102 +74,33 @@ append config {
|
||||
</config>
|
||||
</start>
|
||||
<start name="test-part1">
|
||||
<binary name="test-part"/>
|
||||
<resource name="RAM" quantum="10M" />
|
||||
<binary name="test-blk-cli"/>
|
||||
<resource name="RAM" quantum="5M" />
|
||||
<route>
|
||||
<any-service> <child name="part_blk" /> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
<config pattern="0x44" />
|
||||
</start>
|
||||
<start name="test-part2">
|
||||
<binary name="test-part"/>
|
||||
<resource name="RAM" quantum="10M" />
|
||||
<binary name="test-blk-cli"/>
|
||||
<resource name="RAM" quantum="5M" />
|
||||
<route>
|
||||
<any-service> <child name="part_blk" /> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
<config pattern="0x33" />
|
||||
</start>
|
||||
}
|
||||
|
||||
append_if [have_spec acpi] config {
|
||||
<start name="acpi">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<binary name="acpi_drv"/>
|
||||
<provides>
|
||||
<service name="PCI"/>
|
||||
<service name="IRQ" />
|
||||
</provides>
|
||||
<route>
|
||||
<service name="PCI"> <any-child /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append_if [expr ![have_spec acpi] && [have_spec pci]] config {
|
||||
<start name="pci_drv">
|
||||
<resource name="RAM" quantum="5M"/>
|
||||
<provides><service name="PCI"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if $use_atapi_drv config {
|
||||
<start name="blk_drv">
|
||||
<binary name="atapi_drv"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Block"/> </provides>
|
||||
<config ata="yes" />
|
||||
</start>
|
||||
}
|
||||
|
||||
append_if $use_sd_card_drv config {
|
||||
<start name="blk_drv">
|
||||
<binary name="sd_card_drv"/>
|
||||
<resource name="RAM" quantum="1M" />
|
||||
<provides><service name="Block"/></provides>
|
||||
</start>
|
||||
}
|
||||
|
||||
append config {
|
||||
</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"
|
||||
|
@ -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 <base/allocator_avl.h>
|
||||
#include <base/semaphore.h>
|
||||
#include <block_session/connection.h>
|
||||
#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 <typename T>
|
||||
T addr() { return reinterpret_cast<T>(_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<Mbr *>();
|
||||
|
||||
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<Mbr *>());
|
||||
}
|
||||
|
||||
|
||||
void _io(unsigned long lba, unsigned long count, uint8_t *buf, bool write)
|
||||
{
|
||||
unsigned long bytes;
|
||||
|
||||
while (count) {
|
||||
|
||||
unsigned long curr_count = min<unsigned long>(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<void *>(), bytes);
|
||||
}
|
||||
else {
|
||||
memcpy(sec.addr<void *>(), 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);
|
||||
}
|
||||
}
|
292
os/src/server/part_blk/component.h
Normal file
292
os/src/server/part_blk/component.h
Normal file
@ -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 <base/exception.h>
|
||||
#include <root/component.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
|
||||
#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<Block::Session_component>::Element,
|
||||
public Block_dispatcher
|
||||
{
|
||||
private:
|
||||
|
||||
Ram_dataspace_capability _rq_ds;
|
||||
addr_t _rq_phys;
|
||||
Partition *_partition;
|
||||
Signal_dispatcher<Session_component> _sink_ack;
|
||||
Signal_dispatcher<Session_component> _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<Session_component>& wait_queue()
|
||||
{
|
||||
static List<Session_component> 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<Block::Session_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),
|
||||
"<unlabeled>");
|
||||
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_ */
|
155
os/src/server/part_blk/driver.h
Normal file
155
os/src/server/part_blk/driver.h
Normal file
@ -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 <base/env.h>
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/signal.h>
|
||||
#include <base/tslab.h>
|
||||
#include <util/list.h>
|
||||
#include <block_session/connection.h>
|
||||
|
||||
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<Request>::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<Request, BLK_SZ> _r_slab;
|
||||
Genode::List<Request> _r_list;
|
||||
Genode::Allocator_avl _block_alloc;
|
||||
Block::Connection _session;
|
||||
Block::sector_t _blk_cnt;
|
||||
Genode::size_t _blk_size;
|
||||
Genode::Signal_dispatcher<Driver> _source_ack;
|
||||
Genode::Signal_dispatcher<Driver> _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_ */
|
@ -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 <base/sleep.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <root/component.h>
|
||||
#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<Session_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), "<unlabeled>");
|
||||
|
||||
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<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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 <base/exception.h>
|
||||
#include <base/stdint.h>
|
||||
|
||||
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_ */
|
206
os/src/server/part_blk/partition_table.h
Normal file
206
os/src/server/part_blk/partition_table.h
Normal file
@ -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 <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <block_session/client.h>
|
||||
|
||||
#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 <typename T> T addr() {
|
||||
return reinterpret_cast<T>(_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<Mbr *>();
|
||||
|
||||
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<Mbr *>());
|
||||
|
||||
/*
|
||||
* 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_ */
|
@ -1,3 +1,3 @@
|
||||
TARGET = part_blk
|
||||
LIBS = base config
|
||||
SRC_CC = main.cc back_end.cc
|
||||
SRC_CC = main.cc
|
||||
|
@ -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 <base/allocator_avl.h>
|
||||
#include <block_session/connection.h>
|
||||
#include <os/config.h>
|
||||
|
||||
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 <typename T>
|
||||
T addr() { return reinterpret_cast<T>(_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<void *>(), pattern, _blk_size);
|
||||
s.submit_request();
|
||||
|
||||
Sector s_last(blk_count - 1, 1, true);
|
||||
memset(s_last.addr<void *>(), 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 *>();
|
||||
unsigned *val_last = s_last.addr<unsigned *>();
|
||||
|
||||
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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
TARGET = test-part
|
||||
SRC_CC = main.cc
|
||||
LIBS = base config
|
@ -35,3 +35,4 @@ seoul-auto
|
||||
resource_request
|
||||
resource_yield
|
||||
gdb_monitor
|
||||
part_blk
|
||||
|
Loading…
x
Reference in New Issue
Block a user