Index: boot/arch/mips32/include/arch.h
===================================================================
--- boot/arch/mips32/include/arch.h	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ boot/arch/mips32/include/arch.h	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -40,5 +40,5 @@
 
 #define MSIM_VIDEORAM_ADDRESS  0xb0000000
-#define MSIM_DORDER_ADDRESS    0xb0000004
+#define MSIM_DORDER_ADDRESS    0xb0000100
 
 #ifndef __ASM__
Index: contrib/conf/msim.conf
===================================================================
--- contrib/conf/msim.conf	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ contrib/conf/msim.conf	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -16,3 +16,3 @@
 add dprinter printer 0x10000000
 add dkeyboard keyboard 0x10000000 2
-add dorder order 0x10000004 5
+add dorder order 0x10000100 5
Index: kernel/arch/mips32/src/exception.c
===================================================================
--- kernel/arch/mips32/src/exception.c	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ kernel/arch/mips32/src/exception.c	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -74,35 +74,35 @@
 void istate_decode(istate_t *istate)
 {
-	printf("epc=%p\tsta=%#0" PRIx32 "\t"
-	    "lo =%#0" PRIx32 "\thi =%#0" PRIx32 "\n",
+	printf("epc=%p\tsta=%#010" PRIx32 "\t"
+	    "lo =%#010" PRIx32 "\thi =%#010" PRIx32 "\n",
 	    (void *) istate->epc, istate->status,
 	    istate->lo, istate->hi);
 	
-	printf("a0 =%#0" PRIx32 "\ta1 =%#0" PRIx32 "\t"
-	    "a2 =%#0" PRIx32 "\ta3 =%#0" PRIx32 "\n",
+	printf("a0 =%#010" PRIx32 "\ta1 =%#010" PRIx32 "\t"
+	    "a2 =%#010" PRIx32 "\ta3 =%#010" PRIx32 "\n",
 	    istate->a0, istate->a1, istate->a2, istate->a3);
 	
-	printf("t0 =%#0" PRIx32 "\tt1 =%#0" PRIx32 "\t"
-	    "t2 =%#0" PRIx32 "\tt3 =%#0" PRIx32 "\n",
+	printf("t0 =%#010" PRIx32 "\tt1 =%#010" PRIx32 "\t"
+	    "t2 =%#010" PRIx32 "\tt3 =%#010" PRIx32 "\n",
 	    istate->t0, istate->t1, istate->t2, istate->t3);
 	
-	printf("t4 =%#0" PRIx32 "\tt5 =%#0" PRIx32 "\t"
-	    "t6 =%#0" PRIx32 "\tt7 =%#0" PRIx32 "\n",
+	printf("t4 =%#010" PRIx32 "\tt5 =%#010" PRIx32 "\t"
+	    "t6 =%#010" PRIx32 "\tt7 =%#010" PRIx32 "\n",
 	    istate->t4, istate->t5, istate->t6, istate->t7);
 	
-	printf("t8 =%#0" PRIx32 "\tt9 =%#0" PRIx32 "\t"
-	    "v0 =%#0" PRIx32 "\tv1 =%#0" PRIx32 "\n",
+	printf("t8 =%#010" PRIx32 "\tt9 =%#010" PRIx32 "\t"
+	    "v0 =%#010" PRIx32 "\tv1 =%#010" PRIx32 "\n",
 	    istate->t8, istate->t9, istate->v0, istate->v1);
 	
-	printf("s0 =%#0" PRIx32 "\ts1 =%#0" PRIx32 "\t"
-	    "s2 =%#0" PRIx32 "\ts3 =%#0" PRIx32 "\n",
+	printf("s0 =%#010" PRIx32 "\ts1 =%#010" PRIx32 "\t"
+	    "s2 =%#010" PRIx32 "\ts3 =%#010" PRIx32 "\n",
 	    istate->s0, istate->s1, istate->s2, istate->s3);
 	
-	printf("s4 =%#0" PRIx32 "\ts5 =%#0" PRIx32 "\t"
-	    "s6 =%#0" PRIx32 "\ts7 =%#0" PRIx32 "\n",
+	printf("s4 =%#010" PRIx32 "\ts5 =%#010" PRIx32 "\t"
+	    "s6 =%#010" PRIx32 "\ts7 =%#010" PRIx32 "\n",
 	    istate->s4, istate->s5, istate->s6, istate->s7);
 	
-	printf("s8 =%#0" PRIx32 "\tat =%#0" PRIx32 "\t"
-	    "kt0=%#0" PRIx32 "\tkt1=%#0" PRIx32 "\n",
+	printf("s8 =%#010" PRIx32 "\tat =%#010" PRIx32 "\t"
+	    "kt0=%#010" PRIx32 "\tkt1=%#010" PRIx32 "\n",
 	    istate->s8, istate->at, istate->kt0, istate->kt1);
 	
Index: kernel/arch/mips32/src/smp/dorder.c
===================================================================
--- kernel/arch/mips32/src/smp/dorder.c	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ kernel/arch/mips32/src/smp/dorder.c	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -37,5 +37,5 @@
 #include <arch/smp/dorder.h>
 
-#define MSIM_DORDER_ADDRESS  0xB0000004
+#define MSIM_DORDER_ADDRESS  0xB0000100
 
 #ifdef CONFIG_SMP
Index: tools/config.py
===================================================================
--- tools/config.py	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ tools/config.py	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -3,4 +3,5 @@
 # Copyright (c) 2006 Ondrej Palkovsky
 # Copyright (c) 2009 Martin Decky
+# Copyright (c) 2010 Jiri Svoboda
 # All rights reserved.
 #
@@ -40,10 +41,10 @@
 import xtui
 
-INPUT = sys.argv[1]
+RULES_FILE = sys.argv[1]
 MAKEFILE = 'Makefile.config'
 MACROS = 'config.h'
-PRECONF = 'defaults'
-
-def read_defaults(fname, defaults):
+PRESETS_DIR = 'defaults'
+
+def read_config(fname, config):
 	"Read saved values from last configuration run"
 	
@@ -52,18 +53,18 @@
 	for line in inf:
 		res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
-		if (res):
-			defaults[res.group(1)] = res.group(2)
+		if res:
+			config[res.group(1)] = res.group(2)
 	
 	inf.close()
 
-def check_condition(text, defaults, ask_names):
+def check_condition(text, config, rules):
 	"Check that the condition specified on input line is True (only CNF and DNF is supported)"
 	
 	ctype = 'cnf'
 	
-	if ((')|' in text) or ('|(' in text)):
+	if (')|' in text) or ('|(' in text):
 		ctype = 'dnf'
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		conds = text.split('&')
 	else:
@@ -71,23 +72,23 @@
 	
 	for cond in conds:
-		if (cond.startswith('(')) and (cond.endswith(')')):
+		if cond.startswith('(') and cond.endswith(')'):
 			cond = cond[1:-1]
 		
-		inside = check_inside(cond, defaults, ctype)
+		inside = check_inside(cond, config, ctype)
 		
 		if (ctype == 'cnf') and (not inside):
 			return False
 		
-		if (ctype == 'dnf') and (inside):
+		if (ctype == 'dnf') and inside:
 			return True
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		return True
 	return False
 
-def check_inside(text, defaults, ctype):
+def check_inside(text, config, ctype):
 	"Check for condition"
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		conds = text.split('|')
 	else:
@@ -96,5 +97,5 @@
 	for cond in conds:
 		res = re.match(r'^(.*?)(!?=)(.*)$', cond)
-		if (not res):
+		if not res:
 			raise RuntimeError("Invalid condition: %s" % cond)
 		
@@ -103,12 +104,12 @@
 		condval = res.group(3)
 		
-		if (not condname in defaults):
+		if not condname in config:
 			varval = ''
 		else:
-			varval = defaults[condname]
+			varval = config[condname]
 			if (varval == '*'):
 				varval = 'y'
 		
-		if (ctype == 'cnf'):
+		if ctype == 'cnf':
 			if (oper == '=') and (condval == varval):
 				return True
@@ -123,11 +124,11 @@
 				return False
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		return False
 	
 	return True
 
-def parse_config(fname, ask_names):
-	"Parse configuration file"
+def parse_rules(fname, rules):
+	"Parse rules file"
 	
 	inf = open(fname, 'r')
@@ -138,9 +139,9 @@
 	for line in inf:
 		
-		if (line.startswith('!')):
+		if line.startswith('!'):
 			# Ask a question
 			res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line)
 			
-			if (not res):
+			if not res:
 				raise RuntimeError("Weird line: %s" % line)
 			
@@ -149,10 +150,10 @@
 			vartype = res.group(3)
 			
-			ask_names.append((varname, vartype, name, choices, cond))
+			rules.append((varname, vartype, name, choices, cond))
 			name = ''
 			choices = []
 			continue
 		
-		if (line.startswith('@')):
+		if line.startswith('@'):
 			# Add new line into the 'choices' array
 			res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line)
@@ -164,10 +165,10 @@
 			continue
 		
-		if (line.startswith('%')):
+		if line.startswith('%'):
 			# Name of the option
 			name = line[1:].strip()
 			continue
 		
-		if ((line.startswith('#')) or (line == '\n')):
+		if line.startswith('#') or (line == '\n'):
 			# Comment or empty line
 			continue
@@ -181,5 +182,5 @@
 	"Return '*' if yes, ' ' if no"
 	
-	if (default == 'y'):
+	if default == 'y':
 		return '*'
 	
@@ -199,5 +200,5 @@
 	cnt = 0
 	for key, val in choices:
-		if ((default) and (key == default)):
+		if (default) and (key == default):
 			position = cnt
 		
@@ -207,22 +208,135 @@
 	(button, value) = xtui.choice_window(screen, name, 'Choose value', options, position)
 	
-	if (button == 'cancel'):
+	if button == 'cancel':
 		return None
 	
 	return choices[value][0]
 
-def check_choices(defaults, ask_names):
-	"Check whether all accessible variables have a default"
-	
-	for varname, vartype, name, choices, cond in ask_names:
-		if ((cond) and (not check_condition(cond, defaults, ask_names))):
+## Infer and verify configuration values.
+#
+# Augment @a config with values that can be inferred, purge invalid ones
+# and verify that all variables have a value (previously specified or inferred).
+#
+# @param config	Configuration to work on
+# @param rules	Rules
+#
+# @return	True if configuration is complete and valid, False
+#		otherwise.
+#
+def infer_verify_choices(config, rules):
+	"Infer and verify configuration values."
+	
+	for rule in rules:
+		varname, vartype, name, choices, cond = rule
+
+		if cond and (not check_condition(cond, config, rules)):
 			continue
 		
-		if (not varname in defaults):
+		if not varname in config:
+			value = None
+		else:
+			value = config[varname]
+
+		if not rule_value_is_valid(rule, value):
+			value = None
+
+		default = rule_get_default(rule)
+		if default != None:
+			config[varname] = default
+
+		if not varname in config:
 			return False
 	
 	return True
 
-def create_output(mkname, mcname, defaults, ask_names):
+## Get default value from a rule.
+def rule_get_default(rule):
+	varname, vartype, name, choices, cond = rule
+
+	default = None
+
+	if vartype == 'choice':
+		# If there is just one option, use it
+		if len(choices) == 1:
+			default = choices[0][0]
+	elif vartype == 'y':
+		default = '*'
+	elif vartype == 'n':
+		default = 'n'
+	elif vartype == 'y/n':
+		default = 'y'
+	elif vartype == 'n/y':
+		default = 'n'
+	else:
+		raise RuntimeError("Unknown variable type: %s" % vartype)
+
+	return default
+
+## Get option from a rule.
+#
+# @param rule	Rule for a variable
+# @param value	Current value of the variable
+#
+# @return Option (string) to ask or None which means not to ask.
+#
+def rule_get_option(rule, value):
+	varname, vartype, name, choices, cond = rule
+
+	option = None
+
+	if vartype == 'choice':
+		# If there is just one option, don't ask
+		if len(choices) != 1:
+			if (value == None):
+				option = "?     %s --> " % name
+			else:
+				option = "      %s [%s] --> " % (name, value)
+	elif vartype == 'y':
+		pass
+	elif vartype == 'n':
+		pass
+	elif vartype == 'y/n':
+		option = "  <%s> %s " % (yes_no(value), name)
+	elif vartype == 'n/y':
+		option ="  <%s> %s " % (yes_no(value), name)
+	else:
+		raise RuntimeError("Unknown variable type: %s" % vartype)
+
+	return option
+
+## Check if variable value is valid.
+#
+# @param rule	Rule for the variable
+# @param value	Value of the variable
+#
+# @return	True if valid, False if not valid.
+#
+def rule_value_is_valid(rule, value):
+	varname, vartype, name, choices, cond = rule
+	
+	if value == None:
+		return True
+
+	if vartype == 'choice':
+		if not value in [choice[0] for choice in choices]:
+			return False
+	elif vartype == 'y':
+		if value != 'y':
+			return False
+	elif vartype == 'n':
+		if value != 'n':
+			return False
+	elif vartype == 'y/n':
+		if not value in ['y', 'n']:
+			return False
+	elif vartype == 'n/y':
+		if not value in ['y', 'n']:
+			return False
+	else:
+		raise RuntimeError("Unknown variable type: %s" % vartype)
+
+	return True
+
+def create_output(mkname, mcname, config, rules):
 	"Create output configuration"
 	
@@ -238,7 +352,7 @@
 		sys.stderr.write("failed\n")
 	
-	if (len(version) == 3):
+	if len(version) == 3:
 		revision = version[1]
-		if (version[0] != 1):
+		if version[0] != 1:
 			revision += 'M'
 		revision += ' (%s)' % version[2]
@@ -259,26 +373,26 @@
 	defs = 'CONFIG_DEFS ='
 	
-	for varname, vartype, name, choices, cond in ask_names:
-		if ((cond) and (not check_condition(cond, defaults, ask_names))):
+	for varname, vartype, name, choices, cond in rules:
+		if cond and (not check_condition(cond, config, rules)):
 			continue
 		
-		if (not varname in defaults):
-			default = ''
+		if not varname in config:
+			value = ''
 		else:
-			default = defaults[varname]
-			if (default == '*'):
-				default = 'y'
-		
-		outmk.write('# %s\n%s = %s\n\n' % (name, varname, default))
-		
-		if ((vartype == "y") or (vartype == "n") or (vartype == "y/n") or (vartype == "n/y")):
-			if (default == "y"):
+			value = config[varname]
+			if (value == '*'):
+				value = 'y'
+		
+		outmk.write('# %s\n%s = %s\n\n' % (name, varname, value))
+		
+		if vartype in ["y", "n", "y/n", "n/y"]:
+			if value == "y":
 				outmc.write('/* %s */\n#define %s\n\n' % (name, varname))
 				defs += ' -D%s' % varname
 		else:
-			outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, default, varname, default))
-			defs += ' -D%s=%s -D%s_%s' % (varname, default, varname, default)
-	
-	if (revision is not None):
+			outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, value, varname, value))
+			defs += ' -D%s=%s -D%s_%s' % (varname, value, varname, value)
+	
+	if revision is not None:
 		outmk.write('REVISION = %s\n' % revision)
 		outmc.write('#define REVISION %s\n' % revision)
@@ -299,5 +413,7 @@
 	return list
 
-def read_preconfigured(root, fname, screen, defaults):
+## Choose a profile and load configuration presets.
+#
+def load_presets(root, fname, screen, config):
 	options = []
 	opt2path = {}
@@ -309,5 +425,5 @@
 		canon = os.path.join(path, fname)
 		
-		if ((os.path.isdir(path)) and (os.path.exists(canon)) and (os.path.isfile(canon))):
+		if os.path.isdir(path) and os.path.exists(canon) and os.path.isfile(canon):
 			subprofile = False
 			
@@ -317,5 +433,5 @@
 				subcanon = os.path.join(subpath, fname)
 				
-				if ((os.path.isdir(subpath)) and (os.path.exists(subcanon)) and (os.path.isfile(subcanon))):
+				if os.path.isdir(subpath) and os.path.exists(subcanon) and os.path.isfile(subcanon):
 					subprofile = True
 					options.append("%s (%s)" % (name, subname))
@@ -323,5 +439,5 @@
 					cnt += 1
 			
-			if (not subprofile):
+			if not subprofile:
 				options.append(name)
 				opt2path[cnt] = (canon, None)
@@ -330,31 +446,31 @@
 	(button, value) = xtui.choice_window(screen, 'Load preconfigured defaults', 'Choose configuration profile', options, None)
 	
-	if (button == 'cancel'):
+	if button == 'cancel':
 		return None
 	
-	read_defaults(opt2path[value][0], defaults)
-	if (opt2path[value][1] != None):
-		read_defaults(opt2path[value][1], defaults)
+	read_config(opt2path[value][0], config)
+	if opt2path[value][1] != None:
+		read_config(opt2path[value][1], config)
 
 def main():
-	defaults = {}
-	ask_names = []
-	
-	# Parse configuration file
-	parse_config(INPUT, ask_names)
-	
-	# Read defaults from previous run
+	config = {}
+	rules = []
+	
+	# Parse rules file
+	parse_rules(RULES_FILE, rules)
+	
+	# Read configuration from previous run
 	if os.path.exists(MAKEFILE):
-		read_defaults(MAKEFILE, defaults)
-	
-	# Default mode: only check defaults and regenerate configuration
-	if ((len(sys.argv) >= 3) and (sys.argv[2] == 'default')):
-		if (check_choices(defaults, ask_names)):
-			create_output(MAKEFILE, MACROS, defaults, ask_names)
+		read_config(MAKEFILE, config)
+	
+	# Default mode: only check values and regenerate configuration files
+	if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):
+		if (infer_verify_choices(config, rules)):
+			create_output(MAKEFILE, MACROS, config, rules)
 			return 0
 	
-	# Check mode: only check defaults
-	if ((len(sys.argv) >= 3) and (sys.argv[2] == 'check')):
-		if (check_choices(defaults, ask_names)):
+	# Check mode: only check configuration
+	if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'):
+		if infer_verify_choices(config, rules):
 			return 0
 		return 1
@@ -366,8 +482,8 @@
 		while True:
 			
-			# Cancel out all defaults which have to be deduced
-			for varname, vartype, name, choices, cond in ask_names:
-				if ((vartype == 'y') and (varname in defaults) and (defaults[varname] == '*')):
-					defaults[varname] = None
+			# Cancel out all values which have to be deduced
+			for varname, vartype, name, choices, cond in rules:
+				if (vartype == 'y') and (varname in config) and (config[varname] == '*'):
+					config[varname] = None
 			
 			options = []
@@ -377,50 +493,29 @@
 			options.append("  --- Load preconfigured defaults ... ")
 			
-			for varname, vartype, name, choices, cond in ask_names:
-				
-				if ((cond) and (not check_condition(cond, defaults, ask_names))):
+			for rule in rules:
+				varname, vartype, name, choices, cond = rule
+				
+				if cond and (not check_condition(cond, config, rules)):
 					continue
 				
-				if (varname == selname):
+				if varname == selname:
 					position = cnt
 				
-				if (not varname in defaults):
-					default = None
+				if not varname in config:
+					value = None
 				else:
-					default = defaults[varname]
-				
-				if (vartype == 'choice'):
-					# Check if the default is an acceptable value
-					if ((default) and (not default in [choice[0] for choice in choices])):
-						default = None
-						defaults.pop(varname)
-					
-					# If there is just one option, use it
-					if (len(choices) == 1):
-						defaults[varname] = choices[0][0]
-						continue
-					
-					if (default == None):
-						options.append("?     %s --> " % name)
-					else:
-						options.append("      %s [%s] --> " % (name, default))
-				elif (vartype == 'y'):
-					defaults[varname] = '*'
-					continue
-				elif (vartype == 'n'):
-					defaults[varname] = 'n'
-					continue
-				elif (vartype == 'y/n'):
-					if (default == None):
-						default = 'y'
-						defaults[varname] = default
-					options.append("  <%s> %s " % (yes_no(default), name))
-				elif (vartype == 'n/y'):
-					if (default == None):
-						default = 'n'
-						defaults[varname] = default
-					options.append("  <%s> %s " % (yes_no(default), name))
-				else:
-					raise RuntimeError("Unknown variable type: %s" % vartype)
+					value = config[varname]
+				
+				if not rule_value_is_valid(rule, value):
+					value = None
+
+				default = rule_get_default(rule)
+				if default != None:
+					value = default
+					config[varname] = default
+
+				option = rule_get_option(rule, value)
+				if option != None:
+					options.append(option)
 				
 				opt2row[cnt] = (varname, vartype, name, choices)
@@ -433,9 +528,9 @@
 			(button, value) = xtui.choice_window(screen, 'HelenOS configuration', 'Choose configuration option', options, position)
 			
-			if (button == 'cancel'):
+			if button == 'cancel':
 				return 'Configuration canceled'
 			
-			if (button == 'done'):
-				if (check_choices(defaults, ask_names)):
+			if button == 'done':
+				if (infer_verify_choices(config, rules)):
 					break
 				else:
@@ -443,31 +538,31 @@
 					continue
 			
-			if (value == 0):
-				read_preconfigured(PRECONF, MAKEFILE, screen, defaults)
+			if value == 0:
+				load_presets(PRESETS_DIR, MAKEFILE, screen, config)
 				position = 1
 				continue
 			
 			position = None
-			if (not value in opt2row):
+			if not value in opt2row:
 				raise RuntimeError("Error selecting value: %s" % value)
 			
 			(selname, seltype, name, choices) = opt2row[value]
 			
-			if (not selname in defaults):
-					default = None
+			if not selname in config:
+				value = None
 			else:
-				default = defaults[selname]
-			
-			if (seltype == 'choice'):
-				defaults[selname] = subchoice(screen, name, choices, default)
-			elif ((seltype == 'y/n') or (seltype == 'n/y')):
-				if (defaults[selname] == 'y'):
-					defaults[selname] = 'n'
+				value = config[selname]
+			
+			if seltype == 'choice':
+				config[selname] = subchoice(screen, name, choices, value)
+			elif (seltype == 'y/n') or (seltype == 'n/y'):
+				if config[selname] == 'y':
+					config[selname] = 'n'
 				else:
-					defaults[selname] = 'y'
+					config[selname] = 'y'
 	finally:
 		xtui.screen_done(screen)
 	
-	create_output(MAKEFILE, MACROS, defaults, ask_names)
+	create_output(MAKEFILE, MACROS, config, rules)
 	return 0
 
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ uspace/lib/block/libblock.c	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -66,4 +66,5 @@
 	fibril_mutex_t lock;
 	size_t lblock_size;		/**< Logical block size. */
+	unsigned blocks_cluster;	/**< Physical blocks per block_t */
 	unsigned block_count;		/**< Total number of blocks. */
 	unsigned blocks_cached;		/**< Number of cached blocks. */
@@ -90,4 +91,5 @@
 static int get_block_size(int dev_phone, size_t *bsize);
 static int get_num_blocks(int dev_phone, aoff64_t *nblocks);
+static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba);
 
 static devcon_t *devcon_search(devmap_handle_t devmap_handle)
@@ -259,5 +261,5 @@
 {
 	block_t *b = hash_table_get_instance(item, block_t, hash_link);
-	return b->boff == *key;
+	return b->lba == *key;
 }
 
@@ -292,6 +294,9 @@
 	cache->mode = mode;
 
-	/* No block size translation a.t.m. */
-	assert(cache->lblock_size == devcon->pblock_size);
+	/* Allow 1:1 or small-to-large block size translation */
+	if (cache->lblock_size % devcon->pblock_size != 0)
+		return ENOTSUP;
+
+	cache->blocks_cluster = cache->lblock_size / devcon->pblock_size;
 
 	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
@@ -329,10 +334,10 @@
 		if (b->dirty) {
 			memcpy(devcon->comm_area, b->data, b->size);
-			rc = write_blocks(devcon, b->boff, 1);
+			rc = write_blocks(devcon, b->pba, cache->blocks_cluster);
 			if (rc != EOK)
 				return rc;
 		}
 
-		unsigned long key = b->boff;
+		unsigned long key = b->lba;
 		hash_table_remove(&cache->block_hash, &key, 1);
 		
@@ -375,5 +380,5 @@
  * 				block pointer on success.
  * @param devmap_handle		Device handle of the block device.
- * @param boff			Block offset.
+ * @param ba			Block address (logical).
  * @param flags			If BLOCK_FLAGS_NOREAD is specified, block_get()
  * 				will not read the contents of the block from the
@@ -382,5 +387,5 @@
  * @return			EOK on success or a negative error code.
  */
-int block_get(block_t **block, devmap_handle_t devmap_handle, aoff64_t boff, int flags)
+int block_get(block_t **block, devmap_handle_t devmap_handle, aoff64_t ba, int flags)
 {
 	devcon_t *devcon;
@@ -388,5 +393,5 @@
 	block_t *b;
 	link_t *l;
-	unsigned long key = boff;
+	unsigned long key = ba;
 	int rc;
 	
@@ -465,5 +470,6 @@
 				fibril_mutex_lock(&devcon->comm_area_lock);
 				memcpy(devcon->comm_area, b->data, b->size);
-				rc = write_blocks(devcon, b->boff, 1);
+				rc = write_blocks(devcon, b->pba,
+				    cache->blocks_cluster);
 				fibril_mutex_unlock(&devcon->comm_area_lock);
 				if (rc != EOK) {
@@ -495,5 +501,5 @@
 			 */
 			list_remove(&b->free_link);
-			temp_key = b->boff;
+			temp_key = b->lba;
 			hash_table_remove(&cache->block_hash, &temp_key, 1);
 		}
@@ -502,5 +508,6 @@
 		b->devmap_handle = devmap_handle;
 		b->size = cache->lblock_size;
-		b->boff = boff;
+		b->lba = ba;
+		b->pba = ba_ltop(devcon, b->lba);
 		hash_table_insert(&cache->block_hash, &key, &b->hash_link);
 
@@ -519,5 +526,5 @@
 			 */
 			fibril_mutex_lock(&devcon->comm_area_lock);
-			rc = read_blocks(devcon, b->boff, 1);
+			rc = read_blocks(devcon, b->pba, cache->blocks_cluster);
 			memcpy(b->data, devcon->comm_area, cache->lblock_size);
 			fibril_mutex_unlock(&devcon->comm_area_lock);
@@ -580,5 +587,5 @@
 		fibril_mutex_lock(&devcon->comm_area_lock);
 		memcpy(devcon->comm_area, block->data, block->size);
-		rc = write_blocks(devcon, block->boff, 1);
+		rc = write_blocks(devcon, block->pba, cache->blocks_cluster);
 		fibril_mutex_unlock(&devcon->comm_area_lock);
 		block->dirty = false;
@@ -614,5 +621,5 @@
 			 * Take the block out of the cache and free it.
 			 */
-			unsigned long key = block->boff;
+			unsigned long key = block->lba;
 			hash_table_remove(&cache->block_hash, &key, 1);
 			free(block);
@@ -712,5 +719,5 @@
  *
  * @param devmap_handle	Device handle of the block device.
- * @param ba		Address of first block.
+ * @param ba		Address of first block (physical).
  * @param cnt		Number of blocks.
  * @param src		Buffer for storing the data.
@@ -740,5 +747,5 @@
  *
  * @param devmap_handle	Device handle of the block device.
- * @param ba		Address of first block.
+ * @param ba		Address of first block (physical).
  * @param cnt		Number of blocks.
  * @param src		The data to be written.
@@ -879,4 +886,11 @@
 }
 
+/** Convert logical block address to physical block address. */
+static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba)
+{
+	assert(devcon->cache != NULL);
+	return lba * devcon->cache->blocks_cluster;
+}
+
 /** @}
  */
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ uspace/lib/block/libblock.h	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -73,6 +73,8 @@
 	/** Handle of the device where the block resides. */
 	devmap_handle_t devmap_handle;
-	/** Block offset on the block device. Counted in 'size'-byte blocks. */
-	aoff64_t boff;
+	/** Logical block address */
+	aoff64_t lba;
+	/** Physical block address */
+	aoff64_t pba;
 	/** Size of the block. */
 	size_t size;
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision e28d228b1137cc0cbda02e837ac8fc3747165aff)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 35537a7e0a8620c3b6050f4f49acfece7b803be1)
@@ -56,5 +56,7 @@
 #define NAME "file_bd"
 
-static const size_t block_size = 512;
+#define DEFAULT_BLOCK_SIZE 512
+
+static size_t block_size;
 static aoff64_t num_blocks;
 static FILE *img;
@@ -63,4 +65,5 @@
 static fibril_mutex_t dev_lock;
 
+static void print_usage(void);
 static int file_bd_init(const char *fname);
 static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
@@ -71,20 +74,53 @@
 {
 	int rc;
+	char *image_name;
+	char *device_name;
 
 	printf(NAME ": File-backed block device driver\n");
 
-	if (argc != 3) {
-		printf("Expected two arguments (image name, device name).\n");
+	block_size = DEFAULT_BLOCK_SIZE;
+
+	++argv; --argc;
+	while (*argv != NULL && (*argv)[0] == '-') {
+		/* Option */
+		if (str_cmp(*argv, "-b") == 0) {
+			if (argc < 2) {
+				printf("Argument missing.\n");
+				print_usage();
+				return -1;
+			}
+
+			rc = str_size_t(argv[1], NULL, 10, true, &block_size);
+			if (rc != EOK || block_size == 0) {
+				printf("Invalid block size '%s'.\n", argv[1]);
+				print_usage();
+				return -1;
+			}
+			++argv; --argc;
+		} else {
+			printf("Invalid option '%s'.\n", *argv);
+			print_usage();
+			return -1;
+		}
+		++argv; --argc;
+	}
+
+	if (argc < 2) {
+		printf("Missing arguments.\n");
+		print_usage();
 		return -1;
 	}
 
-	if (file_bd_init(argv[1]) != EOK)
+	image_name = argv[0];
+	device_name = argv[1];
+
+	if (file_bd_init(image_name) != EOK)
 		return -1;
 
-	rc = devmap_device_register(argv[2], &devmap_handle);
+	rc = devmap_device_register(device_name, &devmap_handle);
 	if (rc != EOK) {
 		devmap_hangup_phone(DEVMAP_DRIVER);
-		printf(NAME ": Unable to register device %s.\n",
-			argv[2]);
+		printf(NAME ": Unable to register device '%s'.\n",
+			device_name);
 		return rc;
 	}
@@ -96,4 +132,9 @@
 	/* Not reached */
 	return 0;
+}
+
+static void print_usage(void)
+{
+	printf("Usage: " NAME " [-b <block_size>] <image_file> <device_name>\n");
 }
 
